Oracle PL/SQL不支持静态GRANT语句,硬写会报PLS-00103错误;必须用动态SQL逐条查询DBA_SYS_PRIVS、DBA_TAB_PRIVS等视图获取权限,再通过EXECUTE IMMEDIATE执行,并严格处理大小写、双引号、WITH OPTION及异常捕获。
为什么不能直接用 GRANT 写在存储过程里
oracle pl/sql 不允许在块中写静态 grant 语句,硬写会报 pls-00103 错误。所谓“用存储过程同步权限”,本质是查出源用户权限、拼成字符串、再用 execute immediate 执行——不是语法糖,是唯一可行路径。
必须分开查三类权限:系统权限、对象权限、角色
混查会漏授权,尤其容易忽略列级权限和 WITH GRANT OPTION:
-
DBA_SYS_PRIVS查系统权限(如CREATE SESSION),注意ADMIN_OPTION字段是否为'YES' -
DBA_TAB_PRIVS查表/视图级对象权限;DBA_COL_PRIVS查列级权限(比如只授SELECT(name));DBA_SEQ_PRIVS查序列权限 -
DBA_ROLE_PRIVS查角色,注意ADMIN_OPTION和DEFAULT_ROLE,目标用户是否要默认启用该角色
拼 SQL 时大小写和双引号是最大陷阱
Oracle 默认把未加引号的标识符转大写,但实际对象名可能含小写或特殊字符(如 "my_table" 或 "Log-Date")。不处理就执行失败:
- 所有
OWNER、TABLE_NAME、COLUMN_NAME值,只要来源字段可能含小写或非字母数字,一律用双引号包裹:'GRANT SELECT ON "' || owner || '"."' || table_name || '" TO "' || target_user || '"' - 查
DBA_USERS.username确认目标用户名原始大小写,TO app_dev和TO "app_dev"在小写创建用户时效果完全不同 - 不要盲目用
UPPER(),先确认元数据里存的就是大写——否则越转越错
每条 EXECUTE IMMEDIATE 必须独立 try-catch
一条失败不能中断整个同步流程,否则后续权限全丢:
- 不能把多条
GRANT拼成一个字符串用分号连起来执行——Oracle 不支持 - 必须用游标循环,每条生成的语句单独套
BEGIN ... EXCEPTION WHEN OTHERS THEN NULL; END; - 加
DBMS_OUTPUT.PUT_LINE(v_sql)输出日志,测试阶段先注释掉EXECUTE IMMEDIATE,人工核对生成语句是否合法 - 特别注意对象存在性:目标用户没建同名表、序列不存在、视图依赖失效,都会让
GRANT失败,得提前校验或容忍
真正难的不是写出来,是判断哪些权限该同步、哪些该过滤——比如 SELECT ANY TABLE 这种高危系统权限,或者带 WITH ADMIN OPTION 的角色,无差别复制等于放大风险。











