From 167a62a4b560025aead35e3ce0135a214ef53f86 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 24 Jul 2026 15:21:25 +0800 Subject: [PATCH] fix(kingbase): support compatibility-mode privilege queries --- .../database/databaseUserAdmin.spec.ts | 6 +++++ .../src/lib/database/databaseUserAdmin.ts | 27 ++++++++++--------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/apps/desktop/src/lib/__tests__/database/databaseUserAdmin.spec.ts b/apps/desktop/src/lib/__tests__/database/databaseUserAdmin.spec.ts index 157948741..5da41a696 100644 --- a/apps/desktop/src/lib/__tests__/database/databaseUserAdmin.spec.ts +++ b/apps/desktop/src/lib/__tests__/database/databaseUserAdmin.spec.ts @@ -115,6 +115,12 @@ describe("database user admin providers", () => { expect(sql).toContain("FROM sys_catalog.sys_auth_members m"); expect(sql).toContain("CROSS JOIN sys_catalog.sys_database d"); expect(sql).toContain("CROSS JOIN sys_catalog.sys_namespace n"); + expect(sql).toContain("FROM information_schema.table_privileges"); + expect(sql).toContain("CAST(privilege_type AS text)"); + expect(sql).toContain("CAST(is_grantable AS text)"); + expect(sql).toContain("concat('Table: '"); + expect(sql).not.toContain(" || "); + expect(sql).not.toContain("role_table_grants"); expect(sql).toContain("WHERE r.rolname = 'role''o'"); expect(sql).not.toContain("pg_catalog"); expect(sql).not.toContain("pg_roles"); diff --git a/apps/desktop/src/lib/database/databaseUserAdmin.ts b/apps/desktop/src/lib/database/databaseUserAdmin.ts index 5e6aa00e9..ff0dc6102 100644 --- a/apps/desktop/src/lib/database/databaseUserAdmin.ts +++ b/apps/desktop/src/lib/database/databaseUserAdmin.ts @@ -402,6 +402,9 @@ ORDER BY r.rolname;`.trim(); export function kingbaseShowGrantsSql(user: DatabaseUserIdentity): string { const role = quoteSqlString(user.user); + // SQL Server-compatible Kingbase omits role_table_grants, while + // table_privileges is available across modes; concat also avoids MySQL + // compatibility mode interpreting || as boolean OR. return ` WITH target AS ( SELECT oid, rolname, rolsuper, rolcreatedb, rolcreaterole, rolcanlogin, rolreplication, rolbypassrls @@ -410,46 +413,46 @@ WITH target AS ( ) SELECT line FROM ( - SELECT 1 AS sort, 'Role: ' || quote_ident(rolname) AS line + SELECT 1 AS sort, concat('Role: ', quote_ident(rolname)) AS line FROM target UNION ALL - SELECT 2, 'Attributes: ' || COALESCE(NULLIF(concat_ws(', ', + SELECT 2, concat('Attributes: ', COALESCE(NULLIF(concat_ws(', ', CASE WHEN rolsuper THEN 'SUPERUSER' END, CASE WHEN rolcreatedb THEN 'CREATEDB' END, CASE WHEN rolcreaterole THEN 'CREATEROLE' END, CASE WHEN rolcanlogin THEN 'LOGIN' ELSE 'NOLOGIN' END, CASE WHEN rolreplication THEN 'REPLICATION' END, CASE WHEN rolbypassrls THEN 'BYPASSRLS' END - ), ''), 'none') + ), ''), 'none')) FROM target UNION ALL - SELECT 10, 'Member of: ' || quote_ident(parent.rolname) || CASE WHEN m.admin_option THEN ' WITH ADMIN OPTION' ELSE '' END + SELECT 10, concat('Member of: ', quote_ident(parent.rolname), CASE WHEN m.admin_option THEN ' WITH ADMIN OPTION' ELSE '' END) FROM sys_catalog.sys_auth_members m JOIN target t ON t.oid = m.member JOIN sys_catalog.sys_roles parent ON parent.oid = m.roleid UNION ALL - SELECT 20, 'Has member: ' || quote_ident(member.rolname) || CASE WHEN m.admin_option THEN ' WITH ADMIN OPTION' ELSE '' END + SELECT 20, concat('Has member: ', quote_ident(member.rolname), CASE WHEN m.admin_option THEN ' WITH ADMIN OPTION' ELSE '' END) FROM sys_catalog.sys_auth_members m JOIN target t ON t.oid = m.roleid JOIN sys_catalog.sys_roles member ON member.oid = m.member UNION ALL - SELECT 30, 'Database: ' || quote_ident(d.datname) || ' = ' || + SELECT 30, concat('Database: ', quote_ident(d.datname), ' = ', concat_ws(', ', CASE WHEN has_database_privilege(t.rolname, d.oid, 'CONNECT') THEN 'CONNECT' END, CASE WHEN has_database_privilege(t.rolname, d.oid, 'CREATE') THEN 'CREATE' END, CASE WHEN has_database_privilege(t.rolname, d.oid, 'TEMPORARY') THEN 'TEMPORARY' END - ) + )) FROM target t CROSS JOIN sys_catalog.sys_database d WHERE has_database_privilege(t.rolname, d.oid, 'CONNECT') OR has_database_privilege(t.rolname, d.oid, 'CREATE') OR has_database_privilege(t.rolname, d.oid, 'TEMPORARY') UNION ALL - SELECT 40, 'Schema: ' || quote_ident(n.nspname) || ' = ' || + SELECT 40, concat('Schema: ', quote_ident(n.nspname), ' = ', concat_ws(', ', CASE WHEN has_schema_privilege(t.rolname, n.oid, 'USAGE') THEN 'USAGE' END, CASE WHEN has_schema_privilege(t.rolname, n.oid, 'CREATE') THEN 'CREATE' END - ) + )) FROM target t CROSS JOIN sys_catalog.sys_namespace n WHERE UPPER(n.nspname) <> 'INFORMATION_SCHEMA' @@ -457,9 +460,9 @@ FROM ( AND UPPER(n.nspname) NOT LIKE 'XLOG%' AND (has_schema_privilege(t.rolname, n.oid, 'USAGE') OR has_schema_privilege(t.rolname, n.oid, 'CREATE')) UNION ALL - SELECT 50, 'Table: ' || quote_ident(table_schema) || '.' || quote_ident(table_name) || ' = ' || - string_agg(privilege_type || CASE WHEN is_grantable = 'YES' THEN ' WITH GRANT OPTION' ELSE '' END, ', ' ORDER BY privilege_type) - FROM information_schema.role_table_grants + SELECT 50, concat('Table: ', quote_ident(table_schema), '.', quote_ident(table_name), ' = ', + string_agg(concat(CAST(privilege_type AS text), CASE WHEN CAST(is_grantable AS text) = 'YES' THEN ' WITH GRANT OPTION' ELSE '' END), ', ' ORDER BY CAST(privilege_type AS text))) + FROM information_schema.table_privileges WHERE grantee = ${role} AND UPPER(table_schema) <> 'INFORMATION_SCHEMA' AND UPPER(table_schema) NOT LIKE 'SYS%'