iberrorcodes

sergq
Дата: 02.06.2012 16:43:05
Здравствуйте.

Возник такой вопрос.
Как в программе, при получении ошибки 335544347 получить имя ограничения, которое его вызвало.
Стандартно выводится validation error for column F1, value "*** null ***".
И непонятно к какой таблице относится F1.


Спасибо
Таблоид
Дата: 02.06.2012 17:04:12
sergq
И непонятно к какой таблице относится F1.
Объявляйте констрейнты явно, т.е. вот так:
SQL> create table t001(f01 int not null, f02 int, constraint t001_f02_nn check(f02 is not null));
SQL> create table t002(f01 int not null, f02 int, constraint t002_f02_nn check(f02 is not null));
SQL> commit;
SQL> insert into t001(f01, f02) values(null, 1);
Statement failed, SQLSTATE = 23000
validation error for column F01, value "*** null ***" -- :-(
SQL> insert into t002(f01, f02) values(null, 1);
Statement failed, SQLSTATE = 23000
validation error for column F01, value "*** null ***" -- :-(
SQL> insert into t001(f01, f02) values(1, null);
Statement failed, SQLSTATE = 23000
Operation violates CHECK constraint T001_F02_NN on view or table T001 -- :-)
-At trigger 'CHECK_5'
SQL> insert into t002(f01, f02) values(1, null);
Statement failed, SQLSTATE = 23000
Operation violates CHECK constraint T002_F02_NN on view or table T002 -- :-)
-At trigger 'CHECK_7'
sergq
Дата: 02.06.2012 17:55:01
Таблоид,


Действительно. Спасибо )

Подскажите еще как получить имя поля, на котором check сработал.

Этим запросом
SELECT RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_NAME,
       RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_TYPE,
       RDB$RELATION_CONSTRAINTS.RDB$RELATION_NAME,
       RDB$CHECK_CONSTRAINTS.RDB$TRIGGER_NAME
FROM RDB$RELATION_CONSTRAINTS
   INNER JOIN RDB$CHECK_CONSTRAINTS ON
        (RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_NAME = 
          RDB$CHECK_CONSTRAINTS.RDB$CONSTRAINT_NAME)
WHERE 
   ((RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_TYPE = 'CHECK'));

можно найти имя таблицы. А вот имя поля?
Таблоид
Дата: 02.06.2012 19:08:52
sergq
Подскажите еще как получить имя поля, на котором check сработал.
check может быть установлен на несколько полей, какое тогда выводить ?
Правильнее выводить условие этого чека (проверяемое выражение).
Кроме того, надо знать "механику" чеков. все они, за исключением not null-кляуз при определении полей, реализованы как триггеры с именами 'CHECK_nnn', срабатываемые before insert or update. А это значит, что в таблице rdb$triggers для каждого такого чека будет не одна, а две записи. И для вывода уникального списка потребуется применить distinct или group by.
Пример (not_null-кляузы здесь названы "внутренними", а check-констрейнты - "внешними" чеками)):
 -- самый простой чек, "внутренний" (не виден в rdb$triggers):
recreate table t0a(f01 int not null);
-- этот чек уже виден в rdb$triggers, причем как два before-триггера: на insert и на update:
recreate table t0b(f02 int check(f02>0)); 
-- здесь поле проверяется уже два раза: 1) на not null, 2) на соотв-вие чеку:
recreate table t0c(f03 int not null check(f03>1)); 
-- проверка каждого из полей только на not null и двух полей вместе - на условие "внешнего" чека:
recreate table t0d(fd1 int not null, fd2 int not null, check(fd1+fd2 between 100 and 200)); 
-- то же самое, только "внешний" чек - именованный:
recreate table t0e(fe1 int not null, fe2 int not null, constraint t0e_chk check(fe1+fe2 between 123 and 456)); 
recreate table t0f(
  ff1 int not null
  ,ff2 int not null
  ,constraint t0ff1_chk check(ff1 between 1 and 7)
  ,constraint t0ff2_chk check(ff2 between 1 and 7)
  ,constraint t0ff_both check( abs(ff1-ff2) between 0 and 2)
); -- более сложный вариант проверки: несколько "внешних" чеков на два not_null-поля
commit;

Query:
with c0 as(
  select
   rc.rdb$relation_name rel_name
  ,rc.rdb$constraint_name chk_name
  ,rc.rdb$constraint_type chk_type
  --,'#'l
  ,cc.*
  --,'#'ll,rt.rdb$trigger_sequence trg_seq,rt.rdb$trigger_type trg_type
  ,cast(tt.rdb$type_name as varchar(255)) trg_event
  ,iif(upper(rc.rdb$constraint_type)=upper('NOT NULL'),
       lower(trim(cc.rdb$trigger_name)||' is '||rc.rdb$constraint_type),
       cast(rt.rdb$trigger_source as varchar(255))
      ) check_condition
  from rdb$relation_constraints rc
  left join rdb$check_constraints cc on rc.rdb$constraint_name=cc.rdb$constraint_name
  left join rdb$triggers rt on cc.rdb$trigger_name=rt.rdb$trigger_name
  left join rdb$types tt on tt.rdb$field_name='RDB$TRIGGER_TYPE' and tt.rdb$type=rt.rdb$trigger_type
)
select distinct rel_name, chk_name, check_condition
from c0
Result:
REL_NAMEtCHK_NAMEtCHECK_CONDITION
T0AtINTEG_109tf01 is not null
T0BtINTEG_110tcheck(f02>0)
T0CtINTEG_111tf03 is not null
T0CtINTEG_112tcheck(f03>1)
T0DtINTEG_113tfd1 is not null
T0DtINTEG_114tfd2 is not null
T0DtINTEG_115tcheck(fd1+fd2 between 100 and 200)
T0EtINTEG_116tfe1 is not null
T0EtINTEG_117tfe2 is not null
T0EtT0E_CHKtcheck(fe1+fe2 between 123 and 456)
T0FtINTEG_118tff1 is not null
T0FtINTEG_119tff2 is not null
T0FtT0FF1_CHKtcheck(ff1 between 1 and 7)
T0FtT0FF2_CHKtcheck(ff2 between 1 and 7)
T0FtT0FF_BOTHtcheck( abs(ff1-ff2) between 0 and 2)