Маташин А.В. Текст процедуры был опубликован у Вас в разделе полезных запросов к системным таблицам. Предлагаю их усоверщеноствования 1) Измененный текст, не дублирующий права пользователя (процедуру можно вызывать повторно, добавление происходит только 1 раз) create procedure COPY_USER ( OLDUSER Varchar(32), NEWUSER Varchar(32) ) as begin if (OLDUSER <> NEWUSER) then insert into RDB$USER_PRIVILEGES RDB$USER, RDB$GRANTOR, RDB$PRIVILEGE, RDB$GRANT_OPTION, RDB$RELATION_NAME, RDB$FIELD_NAME, RDB$USER_TYPE, RDB$OBJECT_TYPE) select :NEWUSER, RDB$GRANTOR, RDB$PRIVILEGE, RDB$GRANT_OPTION, RDB$RELATION_NAME, RDB$FIELD_NAME, RDB$USER_TYPE, RDB$OBJECT_TYPE from RDB$USER_PRIVILEGES P1 where (RDB$USER = :OLDUSER) AND NOT (EXISTS(select * from rdb$user_privileges P2 WHERE P2.RDB$USER=:NEWUSER AND P2.RDB$GRANTOR=P1.RDB$GRANTOR AND P2.RDB$PRIVILEGE=P1.RDB$PRIVILEGE AND P2.RDB$RELATION_NAME=P1.RDB$RELATION_NAME AND ((P2.RDB$FIELD_NAME=P1.RDB$FIELD_NAME)OR(P1.RDB$FIELD_NAME IS NULL)))); end 2) Процедура анализа различий прав между двумя пользователями. Выдает перечень прав которых нет у пользователя NEW по отношению к пользователю OLD. create procedure GET_GRANT_ADD ( OLD Varchar(32), NEW Varchar(32) ) returns ( PRIVILEGE Char(6), RELATION_NAME Char(31), FIELD_NAME Char(31) ) as BEGIN /* OLD - Old user name */ /* NEW - New user name */ OLD=UPPER(OLD); NEW=UPPER(NEW); FOR SELECT RDB$PRIVILEGE, RDB$RELATION_NAME, RDB$FIELD_NAME from RDB$USER_PRIVILEGES P1 where (RDB$USER = :OLD) AND NOT (EXISTS(select * from rdb$user_privileges P2 WHERE P2.RDB$USER=:NEW AND P2.RDB$GRANTOR=P1.RDB$GRANTOR AND P2.RDB$PRIVILEGE=P1.RDB$PRIVILEGE AND P2.RDB$RELATION_NAME=P1.RDB$RELATION_NAME AND ((P2.RDB$FIELD_NAME=P1.RDB$FIELD_NAME)OR(P1.RDB$FIELD_NAME IS NULL)))) INTO :PRIVILEGE,:RELATION_NAME,:FIELD_NAME DO BEGIN SUSPEND; END END ------------------------------------ Необходимо предварительно создать : create view VIEW_TABLES ( TABLE_NAME ) AS SELECT RDB$RELATION_NAME TABLE_NAME FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG=0 AND RDB$VIEW_SOURCE IS NULL GROUP BY RDB$RELATION_NAME; create view TABLES_REF ( REF_NAME, START, FINISH ) AS SELECT RC.RDB$CONSTRAINT_NAME,RC.RDB$RELATION_NAME, CAST((SELECT IND1.RDB$RELATION_NAME FROM RDB$INDICES IND1 WHERE IND.RDB$FOREIGN_KEY=IND1.RDB$INDEX_NAME) AS VARCHAR(32)) FROM RDB$RELATION_CONSTRAINTS RC,RDB$INDICES IND WHERE RC.RDB$INDEX_NAME=IND.RDB$INDEX_NAME AND RDB$CONSTRAINT_TYPE="FOREIGN KEY"; 1)Возвращает перечень ссылок между таблицами(необходима другим моим процедурам) create procedure GET_TABLESREF returns ( TABLE_NAME Varchar(32), PARENT_TABLE_NAME Varchar(32), CONST_NAME Varchar(32) ) as DECLARE VARIABLE START VARCHAR(32); DECLARE VARIABLE FINISH VARCHAR(32); BEGIN /* root */ PARENT_TABLE_NAME=''; FOR SELECT TABLE_NAME FROM VIEW_TABLES INTO :TABLE_NAME DO BEGIN SUSPEND; END /* */ FOR SELECT REF_NAME,START,FINISH FROM TABLES_REF INTO :CONST_NAME,:TABLE_NAME,:PARENT_TABLE_NAME DO BEGIN IF (:TABLE_NAME<>:PARENT_TABLE_NAME) THEN SUSPEND; END END 2)Рекурсивная процедура , возвращающая перечень таблиц базы с указанием уровня ссылки на таблицу. create procedure GET_TABLESREF_RECURSE ( PARENT_TABLE_NAME Varchar(32), LEV SmallInt ) returns ( TABLE_NAME Varchar(32), LEVEL_NUM SmallInt ) as BEGIN IF (LEV>100) THEN BEGIN EXCEPTION VERY_DEEP_ENCLOSURE; EXIT; END FOR SELECT TABLE_NAME FROM GET_TABLESREF WHERE PARENT_TABLE_NAME = :PARENT_TABLE_NAME INTO :TABLE_NAME DO BEGIN level_num = lev; SUSPEND; FOR SELECT TABLE_NAME, level_num FROM GET_TABLESREF_RECURSE(:TABLE_NAME, :lev+1) INTO :TABLE_NAME, :level_num DO SUSPEND; END EXIT; END 3) Отсортированная выборка из предыдущей таблици. create procedure GET_TABLESREF_LEVEL returns ( TABLE_NAME Varchar(32), LEV Integer ) as BEGIN FOR SELECT TABLE_NAME,MAX(LEVEL_NUM) FROM GET_TABLESREF_RECURSE('',0) GROUP BY TABLE_NAME ORDER BY 2 INTO :TABLE_NAME,:LEV DO SUSPEND; END Приведенные выше процедуры позволяют определить ссылочную зависимость между таблицами (необходимо при анализе, и репликации). Процедуры генерации SQL запросов (текстов) по имени таблици: (В них используются UDF функции CHR - символ ASCIШ по коду, TRIM - Удалет начальные и концевые пробелы. Их использование позволяет получить более удобный для чтения текст, но можно обойтись и без них) 4)DELETE create procedure GET_SQL_DELETE ( TN Varchar(32) ) returns ( SQL Varchar(16000) ) as DECLARE VARIABLE PFIELD VARCHAR(32); DECLARE VARIABLE LF VARCHAR(1); BEGIN LF=CHR(10); SQL = 'DELETE FROM'||LF||' '||TN; PFIELD=NULL; SELECT PRIMARY_KEY FROM REPLICATIONS WHERE TABLE_NAME=:TN INTO :PFIELD; IF (PFIELD IS NOT NULL) THEN SQL=SQL||LF||'WHERE'||LF||' '||PFIELD||' = :ID'; ELSE SQL=NULL; SUSPEND; END 5)INSERT create procedure GET_SQL_INSERT ( TN Varchar(32) ) returns ( SQL Varchar(16000) ) as DECLARE VARIABLE FIELDNAME VARCHAR(100); DECLARE VARIABLE TEMPNAME VARCHAR(100); DECLARE VARIABLE FNAME VARCHAR(8192); DECLARE VARIABLE PNAME VARCHAR(8192); DECLARE VARIABLE FLAG INTEGER; DECLARE VARIABLE LF VARCHAR(1); BEGIN LF=CHR(10); FNAME=''; PNAME=''; FLAG=0; SQL = 'INSERT INTO '||TN||LF||' ('; TEMPNAME = NULL; FOR SELECT FL.FIELD_NAME FROM FIELD_LIST FL WHERE FL.TABLE_NAME=:TN AND NOT EXISTS(SELECT RF.RDB$FIELD_NAME FROM RDB$RELATION_FIELDS RF, RDB$FIELDS F WHERE RF.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME AND NOT(F.RDB$COMPUTED_SOURCE IS NULL) AND RF.RDB$FIELD_NAME = FL.FIELD_NAME) INTO :FIELDNAME DO BEGIN IF (TEMPNAME IS NOT NULL) THEN BEGIN IF (FLAG<>1) THEN BEGIN FNAME = FNAME||' '||TRIM(TempName)||','||LF; PNAME = PNAME||' :'||TRIM(TempName)||','||LF; END IF (FLAG=1) THEN BEGIN FNAME = FNAME||TRIM(TempName)||','||LF; PNAME = PNAME||':'||TRIM(TempName)||','||LF; END END TempName = FieldName; FLAG=FLAG+1; END IF (TempName is not null) THEN FNAME=FNAME||' '||TRIM(TempName); IF (TempName is not null) THEN PNAME=PNAME||' :'||TRIM(TempName); IF (TempName is not null) THEN SQL=SQL||FNAME||')'||LF||'VALUES'||LF||' ('||PNAME||')'; SUSPEND; END 6)SELECT create procedure GET_SQL_SELECT ( TN Varchar(32) ) returns ( SQL Varchar(16000) ) as DECLARE VARIABLE FIELDNAME VARCHAR(100); DECLARE VARIABLE TEMPNAME VARCHAR(100); DECLARE VARIABLE PFIELD VARCHAR(32); DECLARE VARIABLE LF VARCHAR(1); BEGIN LF=CHR(10); SQL = 'SELECT '; TEMPNAME = NULL; FOR SELECT FIELD_NAME FROM FIELD_LIST WHERE TABLE_NAME=:TN INTO :FIELDNAME DO BEGIN IF (TEMPNAME IS NOT NULL) THEN SQL = SQL||LF||' '||TRIM(TempName)||','; TempName = FieldName; END IF (TempName is not null) THEN SQL = SQL||LF||' '||TRIM(TempName)||LF||'FROM '||LF||' '||TN; IF (TempName is not null) THEN BEGIN PFIELD=NULL; SELECT PRIMARY_KEY FROM REPLICATIONS WHERE TABLE_NAME=:TN INTO :PFIELD; IF (PFIELD IS NOT NULL) THEN SQL=SQL||LF||'WHERE'||LF||' '||PFIELD||' = :ID'; ELSE SQL=NULL; END SUSPEND; END 7)UPDATE create procedure GET_SQL_UPDATE ( TN Varchar(32) ) returns ( SQL Varchar(16000) ) as DECLARE VARIABLE FIELDNAME VARCHAR(100); DECLARE VARIABLE TEMPNAME VARCHAR(100); DECLARE VARIABLE FNAME VARCHAR(8192); DECLARE VARIABLE PFIELD VARCHAR(32); DECLARE VARIABLE LF VARCHAR(1); BEGIN LF=CHR(10); FNAME=''; SQL = 'UPDATE '||LF||' '||TN||LF||'SET '; TEMPNAME = NULL; FOR SELECT FL.FIELD_NAME FROM FIELD_LIST FL WHERE FL.TABLE_NAME=:TN AND NOT EXISTS(SELECT RF.RDB$FIELD_NAME FROM RDB$RELATION_FIELDS RF, RDB$FIELDS F WHERE RF.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME AND NOT(F.RDB$COMPUTED_SOURCE IS NULL) AND RF.RDB$FIELD_NAME = FL.FIELD_NAME) INTO :FIELDNAME DO BEGIN IF (TEMPNAME IS NOT NULL) THEN BEGIN FNAME = FNAME||LF||' '||TRIM(TempName)||' = :'||TRIM(TempName)||','; END TempName = FieldName; END IF (TempName is not null) THEN FNAME = FNAME||LF||' '||TRIM(TempName)||' = :'||TRIM(TempName); IF (TempName is not null) THEN BEGIN PFIELD=NULL; SELECT PRIMARY_KEY FROM REPLICATIONS WHERE TABLE_NAME=:TN INTO :PFIELD; IF (PFIELD IS NOT NULL) THEN SQL=SQL||FNAME||LF||'WHERE'||LF||' '||PFIELD||' = :ID'; ELSE SQL=NULL; END SUSPEND; END