test_setup.sql
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:9k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. --
  2. -- Create the tables used in the test queries
  3. --
  4. -- T_pkey1 is the primary key table for T_dta1. Entries from T_pkey1
  5. -- Cannot be changed or deleted if they are referenced from T_dta1.
  6. --
  7. -- T_pkey2 is the primary key table for T_dta2. If the key values in
  8. -- T_pkey2 are changed, the references in T_dta2 follow. If entries
  9. -- are deleted, the referencing entries from T_dta2 are deleted too.
  10. -- The values for field key2 in T_pkey2 are silently converted to
  11. -- upper case on insert/update.
  12. --
  13. create table T_pkey1 (
  14.     key1 int4,
  15.     key2 char(20),
  16.     txt char(40)
  17. );
  18. create table T_pkey2 (
  19.     key1 int4,
  20.     key2 char(20),
  21.     txt char(40)
  22. );
  23. create table T_dta1 (
  24.     tkey char(10),
  25.     ref1 int4,
  26.     ref2 char(20)
  27. );
  28. create table T_dta2 (
  29.     tkey char(10),
  30.     ref1 int4,
  31.     ref2 char(20)
  32. );
  33. --
  34. -- Function to check key existance in T_pkey1
  35. --
  36. create function check_pkey1_exists(int4, bpchar) returns bool as '
  37.     if {![info exists GD]} {
  38.         set GD(plan) [spi_prepare \
  39.     "select 1 from T_pkey1 \
  40.         where key1 = \$1 and key2 = \$2" \
  41.          {int4 bpchar}]
  42.     }
  43.     
  44.     set n [spi_execp -count 1 $GD(plan) [list $1 $2]]
  45.     if {$n > 0} {
  46.         return "t"
  47.     }
  48.     return "f"
  49. ' language 'pltcl';
  50. --
  51. -- Trigger function on every change to T_pkey1
  52. --
  53. create function trig_pkey1_before() returns opaque as '
  54.     #
  55.     # Create prepared plans on the first call
  56.     #
  57.     if {![info exists GD]} {
  58. #
  59. # Plan to check for duplicate key in T_pkey1
  60. #
  61.         set GD(plan_pkey1) [spi_prepare \
  62.     "select check_pkey1_exists(\$1, \$2) as ret" \
  63.     {int4 bpchar}]
  64. #
  65. # Plan to check for references from T_dta1
  66. #
  67.         set GD(plan_dta1) [spi_prepare \
  68.     "select 1 from T_dta1 \
  69.         where ref1 = \$1 and ref2 = \$2" \
  70.     {int4 bpchar}]
  71.     }
  72.     #
  73.     # Initialize flags
  74.     #
  75.     set check_old_ref 0
  76.     set check_new_dup 0
  77.     switch $TG_op {
  78.         INSERT {
  79.     #
  80.     # Must check for duplicate key on INSERT
  81.     #
  82.     set check_new_dup 1
  83. }
  84. UPDATE {
  85.     #
  86.     # Must check for duplicate key on UPDATE only if
  87.     # the key changes. In that case we must check for
  88.     # references to OLD values too.
  89.     #
  90.     if {[string compare $NEW(key1) $OLD(key1)] != 0} {
  91.         set check_old_ref 1
  92. set check_new_dup 1
  93.     }
  94.     if {[string compare $NEW(key2) $OLD(key2)] != 0} {
  95.         set check_old_ref 1
  96. set check_new_dup 1
  97.     }
  98. }
  99. DELETE {
  100.     #
  101.     # Must only check for references to OLD on DELETE
  102.     #
  103.     set check_old_ref 1
  104. }
  105.     }
  106.     if {$check_new_dup} {
  107. #
  108. # Check for duplicate key
  109. #
  110.         spi_execp -count 1 $GD(plan_pkey1) [list $NEW(key1) $NEW(key2)]
  111. if {$ret == "t"} {
  112.     elog WARN \
  113.         "duplicate key ''$NEW(key1)'', ''$NEW(key2)'' for T_pkey1"
  114. }
  115.     }
  116.     if {$check_old_ref} {
  117. #
  118. # Check for references to OLD
  119. #
  120.         set n [spi_execp -count 1 $GD(plan_dta1) [list $OLD(key1) $OLD(key2)]]
  121. if {$n > 0} {
  122.     elog WARN \
  123.         "key ''$OLD(key1)'', ''$OLD(key2)'' referenced by T_dta1"
  124. }
  125.     }
  126.     #
  127.     # Anything is fine - let operation pass through
  128.     #
  129.     return OK
  130. ' language 'pltcl';
  131. create trigger pkey1_before before insert or update or delete on T_pkey1
  132. for each row execute procedure
  133. trig_pkey1_before();
  134. --
  135. -- Trigger function to check for duplicate keys in T_pkey2
  136. -- and to force key2 to be upper case only without leading whitespaces
  137. --
  138. create function trig_pkey2_before() returns opaque as '
  139.     #
  140.     # Prepare plan on first call
  141.     #
  142.     if {![info exists GD]} {
  143.         set GD(plan_pkey2) [spi_prepare \
  144.     "select 1 from T_pkey2 \
  145.         where key1 = \$1 and key2 = \$2" \
  146.     {int4 bpchar}]
  147.     }
  148.     #
  149.     # Convert key2 value
  150.     #
  151.     set NEW(key2) [string toupper [string trim $NEW(key2)]]
  152.     #
  153.     # Check for duplicate key
  154.     #
  155.     set n [spi_execp -count 1 $GD(plan_pkey2) [list $NEW(key1) $NEW(key2)]]
  156.     if {$n > 0} {
  157. elog WARN \
  158.     "duplicate key ''$NEW(key1)'', ''$NEW(key2)'' for T_pkey2"
  159.     }
  160.     #
  161.     # Return modified tuple in NEW
  162.     #
  163.     return [array get NEW]
  164. ' language 'pltcl';
  165. create trigger pkey2_before before insert or update on T_pkey2
  166. for each row execute procedure
  167. trig_pkey2_before();
  168. --
  169. -- Trigger function to force references from T_dta2 follow changes
  170. -- in T_pkey2 or be deleted too. This must be done AFTER the changes
  171. -- in T_pkey2 are done so the trigger for primkey check on T_dta2
  172. -- fired on our updates will see the new key values in T_pkey2.
  173. --
  174. create function trig_pkey2_after() returns opaque as '
  175.     #
  176.     # Prepare plans on first call
  177.     #
  178.     if {![info exists GD]} {
  179. #
  180. # Plan to update references from T_dta2
  181. #
  182.         set GD(plan_dta2_upd) [spi_prepare \
  183.     "update T_dta2 set ref1 = \$3, ref2 = \$4 \
  184.         where ref1 = \$1 and ref2 = \$2" \
  185.     {int4 bpchar int4 bpchar}]
  186. #
  187. # Plan to delete references from T_dta2
  188. #
  189.         set GD(plan_dta2_del) [spi_prepare \
  190.     "delete from T_dta2  \
  191.         where ref1 = \$1 and ref2 = \$2" \
  192.     {int4 bpchar}]
  193.     }
  194.     #
  195.     # Initialize flags
  196.     #
  197.     set old_ref_follow 0
  198.     set old_ref_delete 0
  199.     switch $TG_op {
  200. UPDATE {
  201.     #
  202.     # On update we must let old references follow
  203.     #
  204.     set NEW(key2) [string toupper $NEW(key2)]
  205.     if {[string compare $NEW(key1) $OLD(key1)] != 0} {
  206.         set old_ref_follow 1
  207.     }
  208.     if {[string compare $NEW(key2) $OLD(key2)] != 0} {
  209.         set old_ref_follow 1
  210.     }
  211. }
  212. DELETE {
  213.     #
  214.     # On delete we must delete references too
  215.     #
  216.     set old_ref_delete 1
  217. }
  218.     }
  219.     if {$old_ref_follow} {
  220. #
  221. # Let old references follow and fire NOTICE message if
  222. # there where some
  223. #
  224.         set n [spi_execp $GD(plan_dta2_upd) \
  225.     [list $OLD(key1) $OLD(key2) $NEW(key1) $NEW(key2)]]
  226. if {$n > 0} {
  227.     elog NOTICE \
  228. "updated $n entries in T_dta2 for new key in T_pkey2"
  229.         }
  230.     }
  231.     if {$old_ref_delete} {
  232. #
  233. # delete references and fire NOTICE message if
  234. # there where some
  235. #
  236.         set n [spi_execp $GD(plan_dta2_del) \
  237.     [list $OLD(key1) $OLD(key2)]]
  238. if {$n > 0} {
  239.     elog NOTICE \
  240. "deleted $n entries from T_dta2"
  241.         }
  242.     }
  243.     return OK
  244. ' language 'pltcl';
  245. create trigger pkey2_after after update or delete on T_pkey2
  246. for each row execute procedure
  247. trig_pkey2_after();
  248. --
  249. -- Generic trigger function to check references in T_dta1 and T_dta2
  250. --
  251. create function check_primkey() returns opaque as '
  252.     #
  253.     # For every trigger/relation pair we create
  254.     # a saved plan and hold them in GD
  255.     #
  256.     set plankey [list "plan" $TG_name $TG_relid]
  257.     set planrel [list "relname" $TG_relid]
  258.     #
  259.     # Extract the pkey relation name
  260.     #
  261.     set keyidx [expr [llength $args] / 2]
  262.     set keyrel [string tolower [lindex $args $keyidx]]
  263.     if {![info exists GD($plankey)]} {
  264. #
  265. # We must prepare a new plan. Build up a query string
  266. # for the primary key check.
  267. #
  268. set keylist [lrange $args [expr $keyidx + 1] end]
  269.         set query "select 1 from $keyrel"
  270. set qual " where"
  271. set typlist ""
  272. set idx 1
  273. foreach key $keylist {
  274.     set key [string tolower $key]
  275.     #
  276.     # Add the qual part to the query string
  277.     #
  278.     append query "$qual $key = \$$idx"
  279.     set qual " and"
  280.     #
  281.     # Lookup the fields type in pg_attribute
  282.     #
  283.     set n [spi_exec "select T.typname \
  284.         from pg_type T, pg_attribute A, pg_class C \
  285. where C.relname  = ''[quote $keyrel]'' \
  286.   and C.oid      = A.attrelid \
  287.   and A.attname  = ''[quote $key]'' \
  288.   and A.atttypid = T.oid"]
  289.     if {$n != 1} {
  290.         elog WARN "table $keyrel doesn''t have a field named $key"
  291.     }
  292.     #
  293.     # Append the fields type to the argument type list
  294.     #
  295.     lappend typlist $typname
  296.     incr idx
  297. }
  298. #
  299. # Prepare the plan
  300. #
  301. set GD($plankey) [spi_prepare $query $typlist]
  302. #
  303. # Lookup and remember the table name for later error messages
  304. #
  305. spi_exec "select relname from pg_class \
  306. where oid = ''$TG_relid''::oid"
  307. set GD($planrel) $relname
  308.     }
  309.     #
  310.     # Build the argument list from the NEW row
  311.     #
  312.     incr keyidx -1
  313.     set arglist ""
  314.     foreach arg [lrange $args 0 $keyidx] {
  315.         lappend arglist $NEW($arg)
  316.     }
  317.     #
  318.     # Check for the primary key
  319.     #
  320.     set n [spi_execp -count 1 $GD($plankey) $arglist]
  321.     if {$n <= 0} {
  322.         elog WARN "key for $GD($planrel) not in $keyrel"
  323.     }
  324.     #
  325.     # Anything is fine
  326.     #
  327.     return OK
  328. ' language 'pltcl';
  329. create trigger dta1_before before insert or update on T_dta1
  330. for each row execute procedure
  331. check_primkey('ref1', 'ref2', 'T_pkey1', 'key1', 'key2');
  332. create trigger dta2_before before insert or update on T_dta2
  333. for each row execute procedure
  334. check_primkey('ref1', 'ref2', 'T_pkey2', 'key1', 'key2');
  335. create function tcl_int4add(int4,int4) returns int4 as '
  336.     return [expr $1 + $2]
  337. ' language 'pltcl';
  338. create function tcl_int4div(int4,int4) returns int4 as '
  339.     return [expr $1 / $2]
  340. ' language 'pltcl';
  341. create function tcl_int4inc(int4) returns int4 as '
  342.     return [expr $1 + 1]
  343. ' language 'pltcl';
  344. create aggregate tcl_avg (
  345. sfunc1 = tcl_int4add,
  346. basetype = int4,
  347. stype1 = int4,
  348. sfunc2 = tcl_int4inc,
  349. stype2 = int4,
  350. finalfunc = tcl_int4div,
  351. initcond2 = '0'
  352. );
  353. create aggregate tcl_sum (
  354. sfunc1 = tcl_int4add,
  355. basetype = int4,
  356. stype1 = int4,
  357. initcond1 = '0'
  358. );
  359. create function tcl_int4lt(int4,int4) returns bool as '
  360.     if {$1 < $2} {
  361.         return t
  362.     }
  363.     return f
  364. ' language 'pltcl';
  365. create operator @< (
  366. leftarg = int4,
  367. rightarg = int4,
  368. procedure = tcl_int4lt
  369. );