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

数据库系统

开发平台:

Unix_Linux

  1. .pl 27.0c
  2. .ll 17.0c
  3. .po 2.0c
  4. .nf
  5. .nh
  6. .de HD
  7. .sp 2m
  8. ..
  9. .de FT
  10. .sp 2m
  11. .tl _PL/Tcl_A PostgreSQL PL_Page %
  12. ..
  13. .wh 0 HD
  14. .wh -3 FT
  15. .sp 5m
  16. .ce 1000
  17. PL/Tcl
  18. A procedural language for the
  19. PostgreSQL
  20. database system
  21. .ce 0
  22. .sp 5m
  23. .fi
  24. .in +4
  25. PL/Tcl is a dynamic loadable extension for the PostgreSQL database system
  26. that enables the Tcl language to be used to create functions and
  27. trigger-procedures. It offers most of the capabilities a function
  28. writer has in the C language, except for some restrictions.
  29. The good restriction is, that everything is executed in a safe
  30. Tcl-interpreter. In addition to the limited command set of safe Tcl, only
  31. a few commands are available to access the database over SPI and to raise
  32. messages via elog(). There is no way to access internals of the
  33. database backend or gaining OS-level access under the permissions of the
  34. PostgreSQL user ID like in C. Thus, any unprivileged user may be
  35. permitted to use this language.
  36. The other, internal given, restriction is, that Tcl procedures cannot
  37. be used to create input-/output-functions for new data types.
  38. .bp
  39. .ti -4
  40. Data type conversions
  41. PostgreSQL has a rich set of builtin data types. And new data types can
  42. be defined. The trick is, that PostgreSQL doesn't really know much about
  43. the internals of a data type. It just offers a container for storing the
  44. values and knows some functions to call to convert between the external
  45. string representation and the internal container format. In addition, it
  46. knows which functions to call to compare containers or to do some 
  47. arithmetics on them for sorting, indexing and calculations.
  48. Tcl on the other hand stores all values as strings.
  49. These two different concepts meet perfectly for what we need. A PostgreSQL
  50. function has a return value and up to 9 arguments. The data types appear
  51. in the pg_type system catalog, where we find their type specific regproc's
  52. responsible for input-/output-conversion from/to strings.
  53. A special case are set values, which can appear as arguments to a
  54. function. A set value is like a structure containing all the fields
  55. of a table as it's elements. 
  56. C functions cannot have sets as return values. So we cannot do this in
  57. Tcl either.
  58. .ti -4
  59. PostgreSQL functions and Tcl procedure names
  60. In PostgreSQL, one and the same function name can be used for
  61. different functions as long as the number of arguments or their types
  62. differ. This would collide with Tcl procedure names. To offer the same
  63. flexibility in PL/Tcl, the internal Tcl procedure names contain the object
  64. ID of the procedures pg_proc row as part of their name. Thus, different
  65. argtype versions of the same PostgreSQL function are different for Tcl too.
  66. .bp
  67. .ti -4
  68. Defining PostgreSQL functions in PL/Tcl
  69. The following assumes, that the PL/Tcl language is created by the
  70. administrator of the database with the language name 'pltcl'. See the
  71. installation instructions to do that.
  72. To create a function in the PL/Tcl language, use the known syntax:
  73. .nf
  74.     CREATE FUNCTION funcname ([typename [...]])
  75. .in +4
  76.     RETURNS typename AS '
  77. .in +4
  78.     PL/Tcl procedure body
  79. .in -4
  80.     ' LANGUAGE 'pltcl';
  81. .in -4
  82. .fi
  83. When calling this function in a query, the arguments are given as
  84. variables $1 ... $n to the procedure body. So a little max function
  85. returning the higher of two int4 values would be created as:
  86. .nf
  87.     create function max (int4, int4)
  88. .in +4
  89.     returns int4 as '
  90. .in +4
  91.     if {$1 > $2} {return $1}
  92.     return $2
  93. .in -4
  94.     ' language 'pltcl';
  95. .in -4
  96. .fi
  97. Set arguments are given to the procedure as Tcl arrays. The element names
  98. in the array are the field names of the set. If a field in the actual set
  99. has the NULL value, it will not appear in the array! The overpaid_2 sample
  100. from the CREATE FUNCTION section of the manual would be defined in Tcl as
  101. .nf
  102.     create function overpaid_2 (EMP)
  103. .in +4
  104.     returns bool as '
  105. .in +4
  106.     if {200000.0 < $1(salary)} {
  107. .in +4
  108.     return 't'
  109. .in -4
  110.     }
  111.     if {$1(age) < 30 && 100000.0 < $1(salary)} {
  112. .in +4
  113.     return 't'
  114. .in -4
  115.     }
  116.     return 'f'
  117. .in -4
  118.     ' language 'pltcl';
  119. .in -4
  120. .fi
  121. Sometimes (especially when using the SPI functions described later) it
  122. is useful to have some global status data that is held between two
  123. calls to a procedure. To protect PL/Tcl procedures from side effects,
  124. an array is made available to each procedure via the upvar
  125. command. The global name of this variable is the procedures internal
  126. name and the local name is GD.
  127. .bp
  128. .ti -4
  129. Defining trigger procedures in PL/Tcl
  130. Trigger procedures are defined in PostgreSQL as functions without
  131. arguments and a return type of opaque. And so are they in the PL/Tcl
  132. language.
  133. The informations from the trigger manager are given to the procedure body
  134. in the following variables:
  135. .in +4
  136. .ti -4
  137. $TG_name
  138. .br
  139. The name of the trigger from the CREATE TRIGGER statement
  140. .ti -4
  141. $TG_relid
  142. .br
  143. The Object ID of the table that caused the trigger procedure to be
  144. called.
  145. .ti -4
  146. $TG_relatts
  147. .br
  148. A Tcl list of the tables field names prefixed with an empty list element.
  149. So looking up an element name in the list with the lsearch Tcl command
  150. returns the same positive number starting from 1 as the fields are numbered
  151. in the pg_attribute system catalog.
  152. .ti -4
  153. $TG_when
  154. .br
  155. The string BEFORE or AFTER, depending on the event of the trigger call.
  156. .ti -4
  157. $TG_level
  158. .br
  159. The string ROW or STATEMENT, depending on the event of the trigger call.
  160. .ti -4
  161. $TG_op
  162. .br
  163. The string INSERT, UPDATE or DELETE, depending on the event of the trigger 
  164. call.
  165. .ti -4
  166. $NEW
  167. .br
  168. An array containing the values of the new table row on INSERT/UPDATE
  169. actions, or empty on DELETE.
  170. .ti -4
  171. $OLD
  172. .br
  173. An array containing the values of the old table row on UPDATE/DELETE
  174. actions, or empty on INSERT.
  175. .ti -4
  176. $GD
  177. .br
  178. The global status data array as described in the functions section of this
  179. document.
  180. .ti -4
  181. $args
  182. .br
  183. A Tcl list of the arguments to the procedure as given in the
  184. CREATE TRIGGER statement. The arguments are also accessible as $1 ... $n
  185. in the procedure body.
  186. .bp
  187. .in -4
  188. The return value from a trigger procedure is one of the strings OK or SKIP,
  189. or a list as returned by the 'array get' Tcl command. If the return value
  190. is OK, the normal operation (INSERT/UPDATE/DELETE) that fired this trigger
  191. will take place. Obviously, SKIP tells the trigger manager to silently
  192. suppress the operation. The list from 'array get' tells PL/Tcl
  193. to return a modified row to the trigger manager that will be inserted instead
  194. of the one given in $NEW (INSERT/UPDATE only). Needless to say that all
  195. this is only meaningful when the trigger is BEFORE and FOR EACH ROW.
  196. Here's a little example trigger procedure that forces an integer value
  197. in a table to keep track of the # of updates that are performed on the
  198. row. For new row's inserted, the value is initialized to 0 and then
  199. incremented on every update operation:
  200. .nf
  201. .in +4
  202. create function trigfunc_modcount() returns opaque as '
  203.     switch $TG_op {
  204.         INSERT {
  205.             set NEW($1) 0
  206.         }
  207.         UPDATE {
  208.             set NEW($1) $OLD($1)
  209.             incr NEW($1)
  210.         }
  211.         default {
  212.             return OK
  213.         }
  214.     }
  215.     return [array get NEW]
  216. .ti -1
  217.  ' language 'pltcl';
  218. create table T1 (key int4, modcnt int4, desc text);
  219. create trigger trig_T1_modcount before insert or update
  220.     on T1 for each row execute procedure
  221.     trigfunc_modcount('modcnt');
  222. .in -4
  223. .fi
  224. .bp
  225. .ti -4
  226. PostgreSQL database access from PL/Tcl
  227. The following commands are available to access the database from
  228. the body of a PL/Tcl procedure:
  229. .in +4
  230. .ti -4
  231. elog level msg
  232. .br
  233. Fire a log message. Possible levels are NOTICE, WARN, ERROR, 
  234. FATAL, DEBUG and NOIND
  235. like for the elog() C function.
  236. .ti -4
  237. quote string
  238. .br
  239. Duplicates all occurences of single quote and backslash characters.
  240. It should be used when variables are used in the query string given
  241. to spi_exec or spi_prepare (not for the value list on spi_execp). 
  242. Think about a query string like
  243. .ti +4
  244. select '$val' as ret
  245. where the Tcl variable actually contains "doesn't". This would result
  246. in the final query string 
  247. .ti +4
  248. select 'doesn't' as ret
  249. what's wrong. It should contain
  250. .ti +4
  251. select 'doesn''t'
  252. and should be written as
  253. .ti +4
  254. select '[quote $val]' as ret
  255. to work.
  256. .ti -4
  257. spi_exec ?-count n? ?-array name? query ?loop-body?
  258. .br
  259. Call parser/planner/optimizer/executor for query. 
  260. The optional -count value tells spi_exec the maximum number of rows
  261. to be processed by the query.
  262. If the query is
  263. a SELECT statement and the optional loop-body (a body of Tcl commands
  264. like in a foreach statement) is given, it is evaluated for each 
  265. row selected and behaves like expected on continue/break. The values
  266. of selected fields are put into variables named as the column names. So a
  267. .ti +2
  268. spi_exec "select count(*) as cnt from pg_proc"
  269. will set the variable $cnt to the number of rows in the pg_proc system
  270. catalog. If the option -array is given, the column values are stored
  271. in the associative array named 'name' indexed by the column name
  272. instead of individual variables.
  273. .in +2
  274. .nf
  275. spi_exec -array C "select * from pg_class" {
  276.     elog DEBUG "have table $C(relname)"
  277. }
  278. .fi
  279. .in -2
  280. will print a DEBUG log message for every row of pg_class. The return value
  281. of spi_exec is the number of rows affected by query as found in
  282. the global variable SPI_processed.
  283. .ti -4
  284. spi_prepare query typelist
  285. .br
  286. Prepares AND SAVES a query plan for later execution. It is a bit different
  287. from the C level SPI_prepare in that the plan is automatically copied to the
  288. toplevel memory context. Thus, there is currently no way of preparing a
  289. plan without saving it.
  290. If the query references arguments, the type names must be given as a Tcl
  291. list. The return value from spi_prepare is a query ID to be used in
  292. subsequent calls to spi_execp. See spi_execp for a sample.
  293. .ti -4
  294. spi_execp ?-count n? ?-array name? ?-nulls str? queryid ?values? ?loop-body?
  295. Execute a prepared plan from spi_prepare with variable substitution. 
  296. The optional -count value tells spi_execp the maximum number of rows
  297. to be processed by the query.
  298. The optional value for -nulls is a string of spaces and 'n' characters
  299. telling spi_execp which of the values are NULL's. If given, it must
  300. have exactly the length of the number of values.
  301. The queryid is the ID returned by the spi_prepare call.
  302. If there was a typelist given to spi_prepare, a Tcl list of values of
  303. exactly the same length must be given to spi_execp after the query. If
  304. the type list on spi_prepare was empty, this argument must be omitted.
  305. If the query is a SELECT statement, the same as described for spi_exec
  306. happens for the loop-body and the variables for the fields selected.
  307. Here's an example for a PL/Tcl function using a prepared plan:
  308. .in +4
  309. .nf
  310. create table T1 (key int4, val text);
  311. create function T1_count(int4) returns int4 as '
  312.     if {![info exists GD]} {
  313.         # prepare the plan on the first call
  314.         set GD(plan) [spi_prepare \\
  315.           "select count(*) as cnt from T1 where key = \\$1" \\
  316.           int4]
  317.     }
  318.     spi_execp -count 1 $GD(plan) [list $1]
  319.     return $cnt
  320. .ti -1
  321.  ' language 'pltcl';
  322. .fi
  323. .in -4
  324. Note that each backslash that Tcl should see must be doubled in
  325. the query creating the function, since the PostgreSQL parser processes
  326. backslashes too.
  327. .bp
  328. .ti -4
  329. Modules and the unknown command
  330. PL/Tcl has a special support for things often used. It recognizes two
  331. magic tables, pltcl_modules and pltcl_modfuncs.
  332. If these exist, the module 'unknown' is loaded into the interpreter
  333. right after creation. Whenever an unknown Tcl procedure is called,
  334. the unknown proc is called to check if the procedure is defined in one
  335. of the modules. If this is true, the module is loaded on demand.
  336. See the documentation in the modules subdirectory for detailed
  337. information.
  338. .in -4
  339. Now enjoy PL/Tcl.
  340. jwieck@debis.com (Jan Wieck)