powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / IBM DB2, WebSphere, IMS, U2 [игнор отключен] [закрыт для гостей] / updated columns in trigger
25 сообщений из 28, страница 1 из 2
updated columns in trigger
    #33272183
Lepsik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
занимаюсь тем что проверяю функциональную идеинтичность триггеров для DB/2 8.2 и MS SQL2000 для продукта, работающего с обоими платформами.

Если в DB/2 что нибудь типа как бинарная переменная в MSSQL содержащая взведенные биты для измененных колонок - уж больно тоскливо видеть сотни строк кода делающих тоже самое пyтем дублирования для каждого поля конструкций типа :

Код: plaintext
1.
2.
3.
4.
5.
if o.fld <> n.fld or 
        (o.fld is null and n.fld is not null) or 
        (o.fld is not null and n.fld is null)
    then 
        set @Details = (values @Details concat ' fld');
    end if;  
...
Рейтинг: 0 / 0
updated columns in trigger
    #33272256
Lepsik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если точнее сформулировать, то нужно составить в триггере список изменных колонок
...
Рейтинг: 0 / 0
updated columns in trigger
    #33272795
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
есть тип данных:
CHAR(n) FOR BIT DATA
ты это имел в виду?
...
Рейтинг: 0 / 0
updated columns in trigger
    #33273432
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нету.

Вот как делал аудит я:
...
Рейтинг: 0 / 0
updated columns in trigger
    #33273437
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
/* 
16,12,1997 
  ä«íáó½Ñ¡« »«½Ñ CHANGEOPERATION ó ¿¡ñÑ¬ß Γáí½¿µδ ¿ßΓ«α¿¿ 


-------------------------------- 
¥Γ«Γ ß¬α¿»Γ »αÑñ¡áº¡áτÑ¡ ñ½∩ ºáóÑñÑ¡¿∩ Γáí½¿µ ¿ßΓ«α¿¿ «í¡«ó½Ñ¡¿⌐. á óσ«ñÑ Ñ¼π 
π¬áºδóáεΓ 
Γáí½¿µδ, ñ½∩ ¬«Γ«αδσ ªÑ½áΓѽ∞¡« ºáóÑñÑ¡¿Ñ ¿ßΓ«α¿¿ (»« ¼á߬ἠ¿¼Ñ¡¿ ¿ ßσѼδ). 
á óδσ«ñÑ ¼δ »«½πτáѼ ß¬α¿»Γ, ¬«Γ«αδ⌐: 


1). ä«íáó½∩ÑΓ φΓ¿¼ Γáí½¿µá¼ »«½∩ 
  X_ADDSTAMP TIMESTAMP NOT NULL WITH DEFAULT CURRENT TIMESTAMP, 
  X_ADDUSER  CHAR(8)   NOT NULL WITH DEFAULT USER, 
  Ñß½¿ Γᬫóδσ »«½Ñ⌐ ¡Ñ ¡áΦ½«ß∞. 


2). âÑ¡Ñα¿απεΓ Γáí½¿µδ ¿ßΓ«α¿¿. ¥Γ¿ Γáí½¿µδ ¿¼ÑεΓ ΓÑ ªÑ »«½∩ + »«½Ñ 
  CHANGEOPERATION CHAR(1) NOT NULL CHECK (CHANGEOPERATION IN ('U", 'D')) 
  ê¼∩ Γáí½¿µδ «ßΓáÑΓß∩ íѺ ¿º¼Ñ¡Ñ¡¿⌐, ¬ ßσÑ¼Ñ Γáí½¿µδ ß½Ñóá ñ«íáó½∩ÑΓß∩ Z 
(τΓ«íδ 
  »α¿ ß«αΓ¿α«ó¬Ñ «¡¿ «¬áºδó὿ß∞ 󡿺π ß»¿ß¬á) ß ó«º¼«ª¡δ¼ πßÑτÑ¡¿Ñ¼ ¿¼Ñ¡¿ ñ« 8 
ß¿¼ó«½«ó. 
  è½ετ Γáí½¿µδ ¿ßΓ«α¿¿ = ¬½ετπ ßΓáα«⌐ + ADDSTAMP (Ñß½¿ Ñú« ¡Ñ í佫 ó ¬½ετÑ). 


3). âÑ¡Ñα¿απεΓ Γα¿úúÑαδ ¡á ¿ßσ«ñ¡δÑ Γáí½¿µδ: 
  ÅÑαÑñ «í¡«ó½Ñ¡¿Ñ¼ (ºá¼Ñ¡á ADDSTAMP ¿ ADDUSER ¡á ΓѬπΘ¿Ñ) 
  Å«ß½Ñ «í¡«ó½Ñ¡¿∩ (ºá»¿ß∞ ßΓáαδσ º¡áτÑ¡¿⌐ + 'U') 
  Å«ß½Ñ πñá½Ñ¡¿∩ (ºá»¿ß∞ ßΓáαδσ º¡áτÑ¡¿⌐ + 'D') 
*/ 


call rxfuncadd 'sqlexec', 'db2ar', 'sqlexec' 
call rxfuncadd 'sqldbs',  'db2ar', 'sqldbs' 

/* Å«½∩, αÑñá¬Γ¿απѼδÑ »«½∞º«óáΓѽѼ ß¬α¿»Γá: */ 
base='tickproc' 
user='***'
using='****'
whereSchema = "where (tabschema like 'FFP_REPL%')" 
andWhereTabName="and not (tabname like '%TABLE%')" 
/* ******************************-************ */ 


/*****************************-******************************-*************/ 


st. 1  = "select distinct tabschema from syscat.tables "whereSchema" order by tabschema" 
st. 2  = "select tabname, colcount from syscat.tables where (type='T') AND (tabschema=?) "andWhereTabname' order by tabname' 
st. 3  = 'select colname, typename, length, scale, default, nulls, remarks from SYSCAT.COLUMNS where (tabschema=?) and (tabname=?) order by colname' 
st. 4  = 'select colnames from SYSCAT.INDEXES where (tabschema=?) and (tabname=?) and '|| "(uniquerule='P')" 
cnt =  4  


call sqlexek 'connect to 'base 'user 'user 'using 'using
do i= 1  to cnt 
  ss = st.i 
  call sqlexek 'prepare s'i' from :ss' 
  call sqlexek 'declare c'i' cursor for s'i 
end 


call sqlexek 'open c1' 
do forever /* ä½∩ ¬áªñ«⌐ ßσѼδ */ 
  call sqlexek 'FETCH c1 INTO :tabschema' 
  if sqlca.sqlcode <> 0  then leave 
  call sqlexek 'open c2 using :tabschema' /* ä½∩ ¬áªñ«⌐ ßσѼδ */ 
  do forever 
    call sqlexek 'fetch c2 into :tabname, :colcount' 
    if sqlca.sqlcode <> 0  then leave 
    haveAddStamp =  0  
    haveAddUser  =  0  
    curcolumn =  1  
    newTabSchema = strip(tabschema)'_Z'
/*
    if length(newTabSchema)>8 then newTabSchema = left(newTabSchema,8) 
*/
    call sqlexek 'open c3 using :tabschema, :tabname' 
    do forever 
      call sqlexek 'fetch c3 into :colname, :typename, :l :li, :sc :sc_i, :dflt :dflt_i, :nulls, :remarks :remarks_i' 
      if sqlca.sqlcode <> 0  then leave 
      if (typename='BLOB')      | (typename='CLOB')    then typename=typename'('l')' 
      if (typename='CHARACTER') | (typename='VARCHAR') then typename=typename'('l')' 
      if (typename='DECIMAL') then typename=typename'('l','sc')' 
      s = '  '||left('"'colname'"', 40 ) 
      if nulls='N' then s = s left(typename, 17 )' NOT NULL' 
        else s = s strip(typename) 
      if dflt_i>= 0  then s = s||' WITH DEFAULT 'dflt 
      columns.curcolumn.def = s 
      columns.curcolumn.clm = colname 
      curcolumn=curcolumn+ 1  
      if colname = 'X_ADDSTAMP' then haveAddStamp =  1  
      if colname = 'X_ADDUSER'  then haveAddUser  =  1  
    end 
    call sqlexek 'close c3' 
    if \haveAddStamp then do 
      t = '  X_ADDSTAMP TIMESTAMP NOT NULL WITH DEFAULT' 
      columns.curcolumn.def = t 
      columns.curcolumn.clm = 'X_ADDSTAMP' 
      curcolumn=curcolumn+ 1  
      say 'ALTER TABLE "'strip(tabschema)'"."'tabname'"' 
      say '  ADD COLUMN 't';' 
      say 
    end 
    if \haveAddUser then do 
      t = '  X_ADDUSER VARCHAR(32) NOT NULL WITH DEFAULT USER' 
      columns.curcolumn.def = t 
      columns.curcolumn.clm = 'X_ADDUSER' 
      curcolumn=curcolumn+ 1  
      say 'ALTER TABLE "'strip(tabschema)'"."'tabname'"' 
      say '  ADD COLUMN 't';' 
      say 
    end 
    say 'CREATE TABLE "'newTabSchema'"."'tabname'"(' 
    do i =  1  to curcolumn- 1  
      say columns.i.def',' 
    end 
    say '  CHANGEOPERATION CHAR(1) NOT NULL,' 
    say "  CHECK(CHANGEOPERATION IN ('U', 'D'))" 
    say ');' 
    say 
    call sqlexek 'open c4 using :tabschema, :tabname' 
    do forever 
      call sqlexek 'FETCH c4 INTO :colnames' 
      if sqlca.sqlcode <> 0  then leave 
      colnames = translate(colnames,',','+') 
      colnames = right(colnames, length(colnames)- 1 ) 
      if pos('X_ADDSTAMP', colnames)= 0  then colnames=colnames||',X_ADDSTAMP' 
      colnames=colnames||',CHANGEOPERATION' 
      say 'ALTER TABLE "'newTabSchema'"."'tabname'"' 
      say '  ADD PRIMARY KEY('colnames');' 
      say 
    end 
    call sqlexek 'close c4' 
    xtabname = strip(/*left*/(tabname /*,16*/)) 
    say 'CREATE TRIGGER "'newTabSchema'"."'xtabname||'_BU" NO CASCADE BEFORE UPDATE' 
    say 'ON "'strip(TabSchema)'"."'tabname'"' 
    say 'REFERENCING OLD AS O NEW AS N' 
    say 'FOR EACH ROW MODE DB2SQL' 
    say 'SET N.X_ADDSTAMP = CURRENT TIMESTAMP, N.X_ADDUSER = USER;' 
    say 
    collist1 = '' 
    collist2 = '' 
    do i =  1  to curcolumn- 1  
      collist1 = collist1||'  "'columns.i.clm'", ' 
      collist2 = collist2||'O."'columns.i.clm'", ' 
    end 
    collist1 = collist1 || 'CHANGEOPERATION' 
    collist3 = collist2 || "'D'" 
    collist2 = collist2 || "'U'" 
    say 'CREATE TRIGGER "'newTabSchema'"."'xtabname||'_AU" AFTER UPDATE' 
    say 'ON "'strip(TabSchema)'"."'tabname'"' 
    say 'REFERENCING OLD AS O ' 
    say 'FOR EACH ROW MODE DB2SQL' 
    say 'INSERT INTO "'newTabSchema'"."'tabname'"' 
    say '('collist1')' 
    say 'VALUES' 
    say '('collist2');' 
    say 
    say 'CREATE TRIGGER "'newTabSchema'"."'xtabname||'_AD" AFTER DELETE' 
    say 'ON "'strip(TabSchema)'"."'tabname'"' 
    say 'REFERENCING OLD AS O ' 
    say 'FOR EACH ROW MODE DB2SQL' 
    say 'INSERT INTO "'newTabSchema'"."'tabname'"' 
    say '('collist1')' 
    say 'VALUES' 
    say '('collist3');' 
    say 
  end 
  call sqlexek 'close c2' 
end 
call sqlexek 'close c1' 


return 


SQLEXEK: 
  parse arg qqqq 
  call SQLEXEC qqqq 
  call CHECKERR qqqq 
return 


CHECKERR: 
  arg errloc 


  if  ( SQLCA.SQLCODE >=  0  ) then 
    return  0  
  else do 
    say '--- error report ---' 
    say 'ERROR occured :' errloc 
    say 'SQLCODE :' SQLCA.SQLCODE 


    /*****************************-*\ 
    * GET ERROR MESSAGE API called * 
    \*****************************-*/ 
    call SQLDBS 'GET MESSAGE INTO :errmsg LINEWIDTH 80' 
    say errmsg 
    say '--- end error report ---' 


    if (SQLCA.SQLCODE <  0  ) then 
      exit 
    else do 
      say 'WARNING - CONTINUING PROGRAM WITH ERRORS' 
      return  0  
    end 
  end 
return  0  

...
Рейтинг: 0 / 0
updated columns in trigger
    #33273445
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
то есть так
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
/* 
16,12,1997 
  Добавлено поле CHANGEOPERATION в индекс таблицы истории 


-------------------------------- 
Этот скрипт предназначен для заведения таблиц истории обновлений. а входе ему 
указывают 
таблицы, для которых желательно заведение истории (по маскам имени и схемы). 
а выходе мы получаем скрипт, который: 


1). Добавляет этим таблицам поля 
  X_ADDSTAMP TIMESTAMP NOT NULL WITH DEFAULT CURRENT TIMESTAMP, 
  X_ADDUSER  CHAR(8)   NOT NULL WITH DEFAULT USER, 
  если таковых полей не нашлось. 


2). Генерируют таблицы истории. Эти таблицы имеют те же поля + поле 
  CHANGEOPERATION CHAR(1) NOT NULL CHECK (CHANGEOPERATION IN ('U", 'D')) 
  Имя таблицы остается без изменений, к схеме таблицы слева добавляется Z 
(чтобы 
  при сортировке они оказывались внизу списка) с возможным усечением имени до 8 
символов. 
  Ключ таблицы истории = ключу старой + ADDSTAMP (если его не было в ключе). 


3). Генерируют триггеры на исходные таблицы: 
  Перед обновлением (замена ADDSTAMP и ADDUSER на текущие) 
  После обновления (запись старых значений + 'U') 
  После удаления (запись старых значений + 'D') 
*/ 


call rxfuncadd 'sqlexec', 'db2ar', 'sqlexec' 
call rxfuncadd 'sqldbs',  'db2ar', 'sqldbs' 

/* Поля, редактируемые пользователем скрипта: */ 
base='tickproc' 
user='***'
using='****'
whereSchema = "where (tabschema like 'FFP_REPL%')" 
andWhereTabName="and not (tabname like '%TABLE%')" 
/* ******************************-************ */ 


/*****************************-******************************-*************/ 


st. 1  = "select distinct tabschema from syscat.tables "whereSchema" order by tabschema" 
st. 2  = "select tabname, colcount from syscat.tables where (type='T') AND (tabschema=?) "andWhereTabname' order by tabname' 
st. 3  = 'select colname, typename, length, scale, default, nulls, remarks from SYSCAT.COLUMNS where (tabschema=?) and (tabname=?) order by colname' 
st. 4  = 'select colnames from SYSCAT.INDEXES where (tabschema=?) and (tabname=?) and '|| "(uniquerule='P')" 
cnt =  4  


call sqlexek 'connect to 'base 'user 'user 'using 'using
do i= 1  to cnt 
  ss = st.i 
  call sqlexek 'prepare s'i' from :ss' 
  call sqlexek 'declare c'i' cursor for s'i 
end 


call sqlexek 'open c1' 
do forever /* Для каждой схемы */ 
  call sqlexek 'FETCH c1 INTO :tabschema' 
  if sqlca.sqlcode <> 0  then leave 
  call sqlexek 'open c2 using :tabschema' /* Для каждой схемы */ 
  do forever 
    call sqlexek 'fetch c2 into :tabname, :colcount' 
    if sqlca.sqlcode <> 0  then leave 
    haveAddStamp =  0  
    haveAddUser  =  0  
    curcolumn =  1  
    newTabSchema = strip(tabschema)'_Z'
/*
    if length(newTabSchema)>8 then newTabSchema = left(newTabSchema,8) 
*/
    call sqlexek 'open c3 using :tabschema, :tabname' 
    do forever 
      call sqlexek 'fetch c3 into :colname, :typename, :l :li, :sc :sc_i, :dflt :dflt_i, :nulls, :remarks :remarks_i' 
      if sqlca.sqlcode <> 0  then leave 
      if (typename='BLOB')      | (typename='CLOB')    then typename=typename'('l')' 
      if (typename='CHARACTER') | (typename='VARCHAR') then typename=typename'('l')' 
      if (typename='DECIMAL') then typename=typename'('l','sc')' 
      s = '  '||left('"'colname'"', 40 ) 
      if nulls='N' then s = s left(typename, 17 )' NOT NULL' 
        else s = s strip(typename) 
      if dflt_i>= 0  then s = s||' WITH DEFAULT 'dflt 
      columns.curcolumn.def = s 
      columns.curcolumn.clm = colname 
      curcolumn=curcolumn+ 1  
      if colname = 'X_ADDSTAMP' then haveAddStamp =  1  
      if colname = 'X_ADDUSER'  then haveAddUser  =  1  
    end 
    call sqlexek 'close c3' 
    if \haveAddStamp then do 
      t = '  X_ADDSTAMP TIMESTAMP NOT NULL WITH DEFAULT' 
      columns.curcolumn.def = t 
      columns.curcolumn.clm = 'X_ADDSTAMP' 
      curcolumn=curcolumn+ 1  
      say 'ALTER TABLE "'strip(tabschema)'"."'tabname'"' 
      say '  ADD COLUMN 't';' 
      say 
    end 
    if \haveAddUser then do 
      t = '  X_ADDUSER VARCHAR(32) NOT NULL WITH DEFAULT USER' 
      columns.curcolumn.def = t 
      columns.curcolumn.clm = 'X_ADDUSER' 
      curcolumn=curcolumn+ 1  
      say 'ALTER TABLE "'strip(tabschema)'"."'tabname'"' 
      say '  ADD COLUMN 't';' 
      say 
    end 
    say 'CREATE TABLE "'newTabSchema'"."'tabname'"(' 
    do i =  1  to curcolumn- 1  
      say columns.i.def',' 
    end 
    say '  CHANGEOPERATION CHAR(1) NOT NULL,' 
    say "  CHECK(CHANGEOPERATION IN ('U', 'D'))" 
    say ');' 
    say 
    call sqlexek 'open c4 using :tabschema, :tabname' 
    do forever 
      call sqlexek 'FETCH c4 INTO :colnames' 
      if sqlca.sqlcode <> 0  then leave 
      colnames = translate(colnames,',','+') 
      colnames = right(colnames, length(colnames)- 1 ) 
      if pos('X_ADDSTAMP', colnames)= 0  then colnames=colnames||',X_ADDSTAMP' 
      colnames=colnames||',CHANGEOPERATION' 
      say 'ALTER TABLE "'newTabSchema'"."'tabname'"' 
      say '  ADD PRIMARY KEY('colnames');' 
      say 
    end 
    call sqlexek 'close c4' 
    xtabname = strip(/*left*/(tabname /*,16*/)) 
    say 'CREATE TRIGGER "'newTabSchema'"."'xtabname||'_BU" NO CASCADE BEFORE UPDATE' 
    say 'ON "'strip(TabSchema)'"."'tabname'"' 
    say 'REFERENCING OLD AS O NEW AS N' 
    say 'FOR EACH ROW MODE DB2SQL' 
    say 'SET N.X_ADDSTAMP = CURRENT TIMESTAMP, N.X_ADDUSER = USER;' 
    say 
    collist1 = '' 
    collist2 = '' 
    do i =  1  to curcolumn- 1  
      collist1 = collist1||'  "'columns.i.clm'", ' 
      collist2 = collist2||'O."'columns.i.clm'", ' 
    end 
    collist1 = collist1 || 'CHANGEOPERATION' 
    collist3 = collist2 || "'D'" 
    collist2 = collist2 || "'U'" 
    say 'CREATE TRIGGER "'newTabSchema'"."'xtabname||'_AU" AFTER UPDATE' 
    say 'ON "'strip(TabSchema)'"."'tabname'"' 
    say 'REFERENCING OLD AS O ' 
    say 'FOR EACH ROW MODE DB2SQL' 
    say 'INSERT INTO "'newTabSchema'"."'tabname'"' 
    say '('collist1')' 
    say 'VALUES' 
    say '('collist2');' 
    say 
    say 'CREATE TRIGGER "'newTabSchema'"."'xtabname||'_AD" AFTER DELETE' 
    say 'ON "'strip(TabSchema)'"."'tabname'"' 
    say 'REFERENCING OLD AS O ' 
    say 'FOR EACH ROW MODE DB2SQL' 
    say 'INSERT INTO "'newTabSchema'"."'tabname'"' 
    say '('collist1')' 
    say 'VALUES' 
    say '('collist3');' 
    say 
  end 
  call sqlexek 'close c2' 
end 
call sqlexek 'close c1' 


return 


SQLEXEK: 
  parse arg qqqq 
  call SQLEXEC qqqq 
  call CHECKERR qqqq 
return 


CHECKERR: 
  arg errloc 


  if  ( SQLCA.SQLCODE >=  0  ) then 
    return  0  
  else do 
    say '--- error report ---' 
    say 'ERROR occured :' errloc 
    say 'SQLCODE :' SQLCA.SQLCODE 


    /*****************************-*\ 
    * GET ERROR MESSAGE API called * 
    \*****************************-*/ 
    call SQLDBS 'GET MESSAGE INTO :errmsg LINEWIDTH 80' 
    say errmsg 
    say '--- end error report ---' 


    if (SQLCA.SQLCODE <  0  ) then 
      exit 
    else do 
      say 'WARNING - CONTINUING PROGRAM WITH ERRORS' 
      return  0  
    end 
  end 
return  0  

...
Рейтинг: 0 / 0
updated columns in trigger
    #33273453
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пусть исходная таблица такая:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
CREATE TABLE "FFP_REPL"."ADM_USERS"(
  "DEPARTMENT_ID"                          INTEGER            NOT NULL,
  "FIRST_NAME"                             VARCHAR( 35 ),
  "LAST_NAME"                              VARCHAR( 35 ),
  "PASSWORD"                               VARCHAR( 30 ),
  "USE_USER_ID"                            INTEGER,
  "USER_ID"                                INTEGER           NOT NULL,
  "USER_NAME"                              VARCHAR( 30 )       NOT NULL
);

ALTER TABLE "FFP_REPL"."ADM_USERS"
  ADD PRIMARY KEY(USER_ID);
...
Рейтинг: 0 / 0
updated columns in trigger
    #33273465
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Скрипт к ней прибавит:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
ALTER TABLE "FFP_REPL"."ADM_USERS"
  ADD COLUMN   X_ADDSTAMP TIMESTAMP NOT NULL WITH DEFAULT;

ALTER TABLE "FFP_REPL"."ADM_USERS"
  ADD COLUMN   X_ADDUSER VARCHAR( 32 ) NOT NULL WITH DEFAULT USER;

CREATE TABLE "FFP_REPL_Z"."ADM_USERS"(
  "DEPARTMENT_ID"                          INTEGER            NOT NULL,
  "FIRST_NAME"                             VARCHAR( 35 ),
  "LAST_NAME"                              VARCHAR( 35 ),
  "PASSWORD"                               VARCHAR( 30 ),
  "USE_USER_ID"                            INTEGER,
  "USER_ID"                                INTEGER            NOT NULL,
  "USER_NAME"                              VARCHAR( 30 )       NOT NULL,
  X_ADDSTAMP TIMESTAMP NOT NULL WITH DEFAULT,
  X_ADDUSER VARCHAR( 32 ) NOT NULL WITH DEFAULT USER,
  CHANGEOPERATION CHAR( 1 ) NOT NULL,
  CHECK(CHANGEOPERATION IN ('U', 'D'))
);

ALTER TABLE "FFP_REPL_Z"."ADM_USERS"
  ADD PRIMARY KEY(USER_ID,X_ADDSTAMP,CHANGEOPERATION);

CREATE TRIGGER "FFP_REPL_Z"."ADM_USERS_BU" NO CASCADE BEFORE UPDATE
ON "FFP_REPL"."ADM_USERS"
REFERENCING OLD AS O NEW AS N
FOR EACH ROW MODE DB2SQL
SET N.X_ADDSTAMP = CURRENT TIMESTAMP, N.X_ADDUSER = USER;

CREATE TRIGGER "FFP_REPL_Z"."ADM_USERS_AU" AFTER UPDATE
ON "FFP_REPL"."ADM_USERS"
REFERENCING OLD AS O 
FOR EACH ROW MODE DB2SQL
INSERT INTO "FFP_REPL_Z"."ADM_USERS"
(  "DEPARTMENT_ID",   "FIRST_NAME",   "LAST_NAME",   "PASSWORD",   "USE_USER_ID",   "USER_ID",   "USER_NAME",   "X_ADDSTAMP",   "X_ADDUSER", CHANGEOPERATION)
VALUES
(O."DEPARTMENT_ID", O."FIRST_NAME", O."LAST_NAME", O."PASSWORD", O."USE_USER_ID", O."USER_ID", O."USER_NAME", O."X_ADDSTAMP", O."X_ADDUSER", 'U');
...
Рейтинг: 0 / 0
updated columns in trigger
    #33273474
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
CREATE TRIGGER "FFP_REPL_Z"."ADM_USERS_AD" AFTER DELETE
ON "FFP_REPL"."ADM_USERS"
REFERENCING OLD AS O 
FOR EACH ROW MODE DB2SQL
INSERT INTO "FFP_REPL_Z"."ADM_USERS"
(  "DEPARTMENT_ID",   "FIRST_NAME",   "LAST_NAME",   "PASSWORD",   "USE_USER_ID",   "USER_ID",   "USER_NAME",   "X_ADDSTAMP",   "X_ADDUSER", CHANGEOPERATION)
VALUES
(O."DEPARTMENT_ID", O."FIRST_NAME", O."LAST_NAME", O."PASSWORD", O."USE_USER_ID", O."USER_ID", O."USER_NAME", O."X_ADDSTAMP", O."X_ADDUSER", 'D');
...
Рейтинг: 0 / 0
updated columns in trigger
    #33274352
Lepsik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Victor MetelitsaНету.

Вот как делал аудит я:

спасибо - это не совсем аудит - скорее консолидированная таблица изменений в базе, для того чтобы сервера приложений не сканили периодически все таблицы, а читали только те изменения в которых заинтересованы на основании этой таблицы изменений.

Поэтому на ряде таблиц стоят триггера на изменения, а поскольку полей десятки у ряда таблиц, того коду приходится генерировать море.

И что самое противное на каждое блобное поле приходится заводит отдельный триггер. Что-то совсем тоскливо в DB2 :(
...
Рейтинг: 0 / 0
updated columns in trigger
    #33274565
Lepsik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот что ответили в IBM

IBM is aware of this and supposedly is high on their customer wish list

нетороплива дела делают в голубом гиганте. в мелкософта это было еще в предидущей версии
...
Рейтинг: 0 / 0
updated columns in trigger
    #33274669
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Lepsik
спасибо - это не совсем аудит - скорее консолидированная таблица изменений в базе, для того чтобы сервера приложений не сканили периодически все таблицы, а читали только те изменения в которых заинтересованы на основании этой таблицы изменений.

... какие-то непривычные (для меня) сервера ...
... а репликация "не-DB2"->"что-то" (DB2 или не-DB2) в Information Integrator у IBM сделана на таком же принципе (генерируются примерно такие же триггеры и таблицы) ...

И что самое противное на каждое блобное поле приходится заводит отдельный триггер.

Почему?

Что-то совсем тоскливо в DB2 :(

Потому что вы смотрите с точки зрения "есть в MSSQL - нет в DB2", и не изучаете обратное?
...
Рейтинг: 0 / 0
updated columns in trigger
    #33274670
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Lepsikвот что ответили в IBM

IBM is aware of this and supposedly is high on their customer wish list

нетороплива дела делают в голубом гиганте. в мелкософта это было еще в предидущей версии

А в мелкософте уже появились рекурсивные запросы? В DB2 (в той, что ранее Common Server, теперь UDB for LUW) это было ещё во второй версии (а может, было даже в первой). И как там Юкон поживает?
...
Рейтинг: 0 / 0
updated columns in trigger
    #33276385
ggv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ggv
Гость
Я, конечно, могу сильно ошибаться, но imho задачу можног решить Q Replication Event Publishing.
Это дает возможность публиковать в виде XML через MQ message изменения строк (всех или по условию WHERE), изменение отдельных колонок, изменение строки при изменении колонок которые не мониторятся, before and after значение и многое еще чего.
Любое приложение может subscribe на интересующие его публикуемые изменения.
Полученую инфу приложение может хоть в базу (учитывая, что это все-таки XA compliant среда) под управлением транзакции.
...
Рейтинг: 0 / 0
updated columns in trigger
    #33277439
Astron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Я конечно не спец по DB2, но в ней есть
CREATE EVENT MONITOR
который вроде как и предназначен для аудита. Количество возможных опций у этого оператора наводит на мысль, что триггер писать не придется....
...
Рейтинг: 0 / 0
updated columns in trigger
    #33277493
ggv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ggv
Гость
ну тогда надо сперва выяснить - надо изменившиеся данные захватывать, или аудит.
Все-таки разные задачи.
...
Рейтинг: 0 / 0
updated columns in trigger
    #33282563
Lepsik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Victor Metelitsa
... какие-то непривычные (для меня) сервера ...
... а репликация "не-DB2"->"что-то" (DB2 или не-DB2) в Information Integrator у IBM сделана на таком же принципе (генерируются примерно такие же триггеры и таблицы) ...


это наши, доморощенные сервера - почту обрабатывают.


И что самое противное на каждое блобное поле приходится заводит отдельный триггер.


это наш db2 девелопер так утверждает. что у clob/blob полей другая специфика и сравнивать вот таким способом :

Код: plaintext
1.
2.
3.
4.
5.
    if o.CalendarEnableState <> n.CalendarEnableState or 
        (o.CalendarEnableState is null and n.CalendarEnableState is not null) or 
        (o.CalendarEnableState is not null and n.CalendarEnableState is null)
    then 
        set @Details = (values @Details concat ' CalendarEnableState');
    end if;

не получится


Потому что вы смотрите с точки зрения "есть в MSSQL - нет в DB2", и не изучаете обратное?

в db2 есть много хороших вещей, но это как бы очевидная потребность.

--И как там Юкон поживает?

Юкон довольно хорош. Одно из приложений заставил подключится к Юкону - заработало как с родным, без всякого шаманства.

--ggv
--Сообщений: 854 Я, конечно, могу сильно ошибаться, но imho задачу можног решить Q Replication Event Publishing.

для данной задачи это будет уже стрельбой из пушек по воробьям.
Хотя в другой задаче - у меня используется встроенная система нотификации сервером об изменениих в базе - но там это решаемо, потому как его триггера генерятся для заданного набора таблиц скриптом и загенерить список полей не проблема.

-CREATE EVENT MONITOR

спасибо посмотрю
...
Рейтинг: 0 / 0
updated columns in trigger
    #33284792
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, BLOB'ы так легко не сравниваются, но зачем другие триггера?. А написать пару UDF на C - и они будут сравниваться ещё проще ;-).

if my_blob_equals(f1,f2)<>0 then ...

Впрочем, с BLOB'ами я дел не имел - мог что-то упустить.
...
Рейтинг: 0 / 0
updated columns in trigger
    #33284827
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Посмотрел доку по триггерам - упоминаний про LOB'ы нет вообще. А что может быть запихнуто в несколько триггеров, может быть запихнуто и в один.

Не представляю себе задачу с вашими триггерами. Подозреваю, что делал бы её как-то по другому, и знание, какое поле изменилось, просто бы не понадобилось. Интересно было бы также посчитать нагрузку на диски и сетевой трафик в вариантах, когда
1) проверяют, какие поля изменились
2) не проверяют - достаточно факта изменения записи.
...
Рейтинг: 0 / 0
updated columns in trigger
    #33284851
Lepsik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Victor MetelitsaДа, BLOB'ы так легко не сравниваются, но зачем другие триггера?. А написать пару UDF на C - и они будут сравниваться ещё проще ;-).

if my_blob_equals(f1,f2)<>0 then ...
Впрочем, с BLOB'ами я дел не имел - мог что-то упустить.

то есть если блобы по паре гиг кажный, мне нужно сравнить 2 потока чтобы понять менял ли их сервер ? не проще ли серверу хранить флажки где и чего он там менял. Чего же уж проще можно придумать ?
...
Рейтинг: 0 / 0
updated columns in trigger
    #33285067
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ночью я таки догадался, зачем ваш db2 девелопер использует для LOB'ов отдельные триггеры.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>-CREATE TRIGGER--trigger-name--+-NO CASCADE BEFORE-+---------->
                                 +-AFTER-------------+
                                 '-INSTEAD OF--------'

>--+-INSERT--------------------------+--ON--+-table-name-+------>
   +-DELETE--------------------------+      '-view-name--'
   '-UPDATE--+---------------------+-'
             |     .-,-----------. |
             |     V             | |
             '-OF----column-name-+-'
Он указывает всего одну колонку, поэтому ему не надо сравнивать старое и новое содержимое. Очевидно, для не-LOB-колонок это тоже должно работать.

Чего я не понимаю, это
a) что есть @Details в
Код: plaintext
1.
2.
3.
   then 
        set @Details = (values @Details concat ' fld');
    end if; 
и что с этим @Details произойдет позднее

b) зачем нужно изменять LOB'ы и отслеживать это.
...
Рейтинг: 0 / 0
updated columns in trigger
    #33285101
Lepsik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Victor MetelitsaНочью я таки догадался, зачем ваш db2 девелопер использует для LOB'ов отдельные триггеры.


дак естественно, но уж больно громозко получается.

Чего я не понимаю, это
a) что есть @Details в
Код: plaintext
1.
2.
3.
   then 
        set @Details = (values @Details concat ' fld');
    end if; 
и что с этим @Details произойдет позднее

это просто сливаются в строчку имена проапдейтеных колонок.
скорее для аудита, чем для работы. Хотя я логику приложений не смотрел - может кто и парсит

b) зачем нужно изменять LOB'ы и отслеживать это.

у нас они мелкие пароли храним закодированые, да всякую мелкую бинарную информацию.
...
Рейтинг: 0 / 0
updated columns in trigger
    #33285234
Victor Metelitsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И всё-таки? @Details это переменная - куда она (её содержимое) потом девается? Как осуществляется взаимодействие между триггерами (в контексте использования @Details)? Зачем нужно держать пароли в LOB'ах, когда есть CHAR/VARCHAR FOR BIT DATA?
...
Рейтинг: 0 / 0
updated columns in trigger
    #33285412
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
updated columns in trigger
    #33289317
Lepsik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Victor MetelitsaИ всё-таки? @Details это переменная - куда она (её содержимое) потом девается?

в поле таблицы изменений вставляется, приложения смотрят последние изменения в базе и анализируют что нужно читать и откуда.

-- Как осуществляется взаимодействие между триггерами (в контексте использования @Details)?

никак.

--Зачем нужно держать пароли в LOB'ах, когда есть CHAR/VARCHAR FOR BIT DATA?

да, пароли в CHAR/VARCHAR FOR BIT , документы, графику и прочее подобное в блобах
...
Рейтинг: 0 / 0
25 сообщений из 28, страница 1 из 2
Форумы / IBM DB2, WebSphere, IMS, U2 [игнор отключен] [закрыт для гостей] / updated columns in trigger
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]