mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-29 22:49:41 +03:00 
			
		
		
		
	As proposed, here is the current version of PL/pgSQL. The
test isn't that complete up to now,  but  I  think  it  shows
    enough of the capabilities of the module.
    The  Makefile  assumes  it  is  located  in a directory under
    pgsql/src/pl.   Since   it   includes   Makefile.global   and
    Makefile.port  and doesn't use any own compiler/linker calls,
    it should build on most of our supported  platforms  (I  only
    tested  under Linux up to now).  It requires flex and bison I
    think. Maybe we should ship prepared gram.c etc. like for the
    main parser too?
Jan
			
			
This commit is contained in:
		| @@ -58,6 +58,10 @@ mSQL-interface - | |||||||
| noupdate - | noupdate - | ||||||
| 	trigger to prevent updates on single columns | 	trigger to prevent updates on single columns | ||||||
|  |  | ||||||
|  | plpgsql -  | ||||||
|  | 	Postgres procedural language | ||||||
|  | 	by Jan Wieck <jwieck@debis.com> | ||||||
|  |  | ||||||
| pginterface - | pginterface - | ||||||
| 	A crude C/4GL | 	A crude C/4GL | ||||||
| 	by Bruce Momjian <root@candle.pha.pa.us> | 	by Bruce Momjian <root@candle.pha.pa.us> | ||||||
|   | |||||||
							
								
								
									
										448
									
								
								contrib/plpgsql/doc/plpgsql.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										448
									
								
								contrib/plpgsql/doc/plpgsql.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,448 @@ | |||||||
|  |                                 PL/pgSQL | ||||||
|  |              A procedural language for the PostgreSQL RDBMS | ||||||
|  |  | ||||||
|  |                       Jan Wieck <jwieck@debis.com> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     Preface | ||||||
|  |  | ||||||
|  |         PL/pgSQL  is  a procedural language based on SQL designed for | ||||||
|  |         the PostgreSQL database system. | ||||||
|  |  | ||||||
|  |         The extensibility features of PostgreSQL are mostly based  on | ||||||
|  |         the  ability  to  define  functions  for  various operations. | ||||||
|  |         Functions could have been written in PostgreSQL's SQL dialect | ||||||
|  |         or  in the C programming language. Functions written in C are | ||||||
|  |         compiled into a shared object  and  loaded  by  the  database | ||||||
|  |         backend  process  on  demand.   Also  the trigger features of | ||||||
|  |         PostgreSQL are based on functions but required the use of the | ||||||
|  |         C language. | ||||||
|  |  | ||||||
|  |         Since  version  6.3  PostgreSQL  supports  the  definition of | ||||||
|  |         procedural languages. In the case of a  function  or  trigger | ||||||
|  |         procedure  defined in a procedural language, the database has | ||||||
|  |         no builtin knowlege how to  interpret  the  functions  source | ||||||
|  |         text. Instead, the function and trigger calls are passed into | ||||||
|  |         a handler that  knows  the  details  of  the  language.   The | ||||||
|  |         handler  itself  is  a function compiled into a shared object | ||||||
|  |         and loaded on demand. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     Overview | ||||||
|  |  | ||||||
|  |         The PL/pgSQL language is case insensitive. All  keywords  and | ||||||
|  |         identifiers can be used in upper-/lowercase mixed. | ||||||
|  |  | ||||||
|  |         PL/pgSQL is a block oriented language. A block is defined as | ||||||
|  |  | ||||||
|  |             [<<label>>] | ||||||
|  |             [DECLARE | ||||||
|  |                 -- declarations] | ||||||
|  |             BEGIN | ||||||
|  |                 -- statements | ||||||
|  |             END; | ||||||
|  |  | ||||||
|  |         There  can  be  any  number  of  subblocks  in the statements | ||||||
|  |         section of a block. Subblocks can be used to  hide  variables | ||||||
|  |         from  outside a block of statements (see Scope and visability | ||||||
|  |         below). The variables declared in  the  declarations  section | ||||||
|  |         preceding  a  block  are  initialized to their default values | ||||||
|  |         every time the block is entered, not only once  per  function | ||||||
|  |         call. | ||||||
|  |  | ||||||
|  |         It is important not to misunderstand the meaning of BEGIN/END | ||||||
|  |         for grouping statements in PL/pgSQL and the database commands | ||||||
|  |         for  transaction  control.  Functions  or  trigger procedures | ||||||
|  |         cannot  start   or   commit   transactions   and   PostgreSQL | ||||||
|  |         transactions cannot have subtransactions. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     Comments | ||||||
|  |  | ||||||
|  |         There  are  two  types of comments in PL/pgSQL. A double dash | ||||||
|  |         '--' starts a comment that extends to the end of the line.  A | ||||||
|  |         '/*'  starts  a  block comment that extends to the next '*/'. | ||||||
|  |         Block comments cannot be nested, but double dash comments can | ||||||
|  |         be  enclosed  into a block comment and double dashes can hide | ||||||
|  |         '/*' and '*/'. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     Declarations | ||||||
|  |  | ||||||
|  |         All variables, rows and records  used  in  a  block  or  it's | ||||||
|  |         subblocks must be declared in the declarations section of the | ||||||
|  |         block except for the loop variable of a  FOR  loop  iterating | ||||||
|  |         over  a range of integer values.  The parameters given to the | ||||||
|  |         function  are   automatically   declared   with   the   usual | ||||||
|  |         identifiers $n.  The declarations have the following syntax: | ||||||
|  |  | ||||||
|  |             <name> [CONSTANT] <type> [NOT NULL] | ||||||
|  |                                      [DEFAULT | := <value>]; | ||||||
|  |  | ||||||
|  |                 Declares  a  variable  of  the specified type. If the | ||||||
|  |                 variable is declared as CONSTANT, the value cannot be | ||||||
|  |                 changed. If NOT NULL is specified, an assignment of a | ||||||
|  |                 NULL value results in  a  runtime  error.  Since  the | ||||||
|  |                 default  value  of  a variable is the SQL NULL value, | ||||||
|  |                 all variables declared as NOT NULL must also  have  a | ||||||
|  |                 default value. | ||||||
|  |  | ||||||
|  |                 The default value is evaluated at the actual function | ||||||
|  |                 call. So  assigning  'now'  to  an  abstime  variable | ||||||
|  |                 causes  the  variable  to have the time of the actual | ||||||
|  |                 function call, not when  the  function  was  compiled | ||||||
|  |                 (during  it's  first  call  since the lifetime of the | ||||||
|  |                 database connection). | ||||||
|  |  | ||||||
|  |             <name> <class>%ROWTYPE; | ||||||
|  |  | ||||||
|  |                 Declares a row with the structure of the given class. | ||||||
|  |                 Class  must  be an existing table- or viewname of the | ||||||
|  |                 database. The fields of the row are accessed  in  the | ||||||
|  |                 dot  notation.  Parameters  to  a  procedure could be | ||||||
|  |                 tuple  types.  In   that   case   the   corresponding | ||||||
|  |                 identifier  $n  will  be  a  rowtype.  Only  the user | ||||||
|  |                 attributes of a tuple  are  accessible  in  the  row. | ||||||
|  |                 There  must  be no whitespaces between the classname, | ||||||
|  |                 the percent and the ROWTYPE keyword. | ||||||
|  |  | ||||||
|  |                 The  fields  of  the  rowtype  inherit   the   tables | ||||||
|  |                 fieldsizes  for  char()  etc.   data types (atttypmod | ||||||
|  |                 from pg_attribute). | ||||||
|  |  | ||||||
|  |             <name> RECORD; | ||||||
|  |  | ||||||
|  |                 Records are similar to rowtypes,  but  they  have  no | ||||||
|  |                 predefined  structure They are used in selections and | ||||||
|  |                 FOR loops to hold one actual database  tuple  from  a | ||||||
|  |                 select operation. One and the same record can be used | ||||||
|  |                 in different selections. Accessing  a  record  or  an | ||||||
|  |                 attempt  to  assign  a  value  to a record field when | ||||||
|  |                 there's no actual tuple in it results  in  a  runtime | ||||||
|  |                 error. | ||||||
|  |  | ||||||
|  |                 The  new  and old tuples in triggers are given to the | ||||||
|  |                 trigger procedure  as  records.  This  is  necessary, | ||||||
|  |                 because  under  PostgreSQL  one  and the same trigger | ||||||
|  |                 procedure can handle  trigger  events  for  different | ||||||
|  |                 tables. | ||||||
|  |  | ||||||
|  |             <name> ALIAS FOR $n; | ||||||
|  |  | ||||||
|  |                 For  better  readability of the code it's possible to | ||||||
|  |                 define an alias for a  positional  parameter  to  the | ||||||
|  |                 function. | ||||||
|  |  | ||||||
|  |             RENAME <oldname> TO <newname>; | ||||||
|  |  | ||||||
|  |                 Change  the  name  of  a variable, record or rowtype. | ||||||
|  |                 This is useful if new or old should be referenced  by | ||||||
|  |                 another name inside a trigger procedure. | ||||||
|  |  | ||||||
|  |     Datatypes | ||||||
|  |  | ||||||
|  |         The  type of a variable can be any of the existing data types | ||||||
|  |         of the database. <type> above is defined as: | ||||||
|  |  | ||||||
|  |                 postgesql-basetype | ||||||
|  |             or  variable%TYPE | ||||||
|  |             or  rowtype.field%TYPE | ||||||
|  |             or  class.field%TYPE | ||||||
|  |  | ||||||
|  |         As for the rowtype declaration, there must be no  whitespaces | ||||||
|  |         between the classname, the percent and the TYPE keyword. | ||||||
|  |  | ||||||
|  |     Expressions | ||||||
|  |  | ||||||
|  |         All  expressions  used  in  PL/pgSQL statements are processed | ||||||
|  |         using the backends executor. Since even  a  constant  looking | ||||||
|  |         expression  can  have  a  totally  different  meaning  for  a | ||||||
|  |         particular data type (as 'now' for abstime), it is impossible | ||||||
|  |         for  the  PL/pgSQL  parser  to  identify real constant values | ||||||
|  |         other than the NULL keyword. The expressions are evaluated by | ||||||
|  |         internally executing a query | ||||||
|  |  | ||||||
|  |             SELECT <expr> | ||||||
|  |  | ||||||
|  |         over  the  SPI  manager.  In  the  expression,  occurences of | ||||||
|  |         variable identifiers are substituted by  parameters  and  the | ||||||
|  |         actual  values  from the variables are passed to the executor | ||||||
|  |         as query parameters. All the expressions used in  a  PL/pgSQL | ||||||
|  |         function are only prepared and saved once. | ||||||
|  |  | ||||||
|  |         If   record  fields  are  used  in  expressions  or  database | ||||||
|  |         statements, the data types of the fields  should  not  change | ||||||
|  |         between  calls  of  one and the same expression. Keep this in | ||||||
|  |         mind when writing trigger procedures that handle  events  for | ||||||
|  |         more than one table. | ||||||
|  |  | ||||||
|  |     Statements | ||||||
|  |  | ||||||
|  |         Anything not understood by the parser as specified below will | ||||||
|  |         be put into a query and sent down to the database  engine  to | ||||||
|  |         execute.   The  resulting  query  should  not return any data | ||||||
|  |         (insert, update, delete queries and all utility  statements). | ||||||
|  |  | ||||||
|  |         Assignment | ||||||
|  |  | ||||||
|  |             An  assignment  of a value to a variable or rowtype field | ||||||
|  |             is written as: | ||||||
|  |  | ||||||
|  |                 <identifier> := <expr>; | ||||||
|  |  | ||||||
|  |             If the expressions result data  type  doesn't  match  the | ||||||
|  |             variables  data type, or the variables atttypmod value is | ||||||
|  |             known  (as  for  char(20)),  the  result  value  will  be | ||||||
|  |             implicitly  casted  by  the  PL/pgSQL  executor using the | ||||||
|  |             result  types  output-  and  the  variables  type  input- | ||||||
|  |             functions.   Note  that  this could potentially result in | ||||||
|  |             runtime errors generated by the types input functions. | ||||||
|  |  | ||||||
|  |             An assignment of a complete selection into  a  record  or | ||||||
|  |             rowtype can be done as: | ||||||
|  |  | ||||||
|  |                 SELECT expressions INTO <target> FROM fromlist; | ||||||
|  |  | ||||||
|  |             Target  can  be  a record or rowtype variable, or a comma | ||||||
|  |             separated list of variables and record/row fields. | ||||||
|  |  | ||||||
|  |             If a rowtype or a variable list is used  as  target,  the | ||||||
|  |             selected  values  must exactly match the structure of the | ||||||
|  |             target(s) or a runtime error occurs.  The fromlist can be | ||||||
|  |             followed  by  any  valid qualification, grouping, sorting | ||||||
|  |             etc. | ||||||
|  |  | ||||||
|  |             There is a special condition [NOT] FOUND that can be used | ||||||
|  |             immediately  after a SELECT INTO to check if the data has | ||||||
|  |             been found. | ||||||
|  |  | ||||||
|  |                 SELECT * INTO myrec FROM EMP WHERE empname = myname; | ||||||
|  |                 IF NOT FOUND THEN | ||||||
|  |                     RAISE EXCEPTION 'employee % not found', myname; | ||||||
|  |                 END IF; | ||||||
|  |  | ||||||
|  |             If the selection returns multiple rows, only the first is | ||||||
|  |             moved into the target fields. All others are discarded. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         Calling another function | ||||||
|  |  | ||||||
|  |             If  a function should be called, this is normally done by | ||||||
|  |             a SELECT query. But there are cases where  someone  isn't | ||||||
|  |             interested in the functions result. | ||||||
|  |  | ||||||
|  |                 PERFORM querystring; | ||||||
|  |  | ||||||
|  |             executes  a 'SELECT querystring' over the SPI manager and | ||||||
|  |             discards the result. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         Returning from the function | ||||||
|  |  | ||||||
|  |                 RETURN <expr>; | ||||||
|  |  | ||||||
|  |             The function terminates and the value of <expr>  will  be | ||||||
|  |             returned  to  the  upper executor.  The return value of a | ||||||
|  |             function cannot be undefined.  If control reaches the end | ||||||
|  |             of  the  toplevel block of the function without hitting a | ||||||
|  |             RETURN statement, a runtime error will occur. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         Aborting and messages | ||||||
|  |  | ||||||
|  |             As indicated above there is an RAISE statement  that  can | ||||||
|  |             throw messages into the PostgreSQL elog mechanism. | ||||||
|  |  | ||||||
|  |                 RAISE level 'format' [, identifier [...]]; | ||||||
|  |  | ||||||
|  |             Inside the format, % can be used as a placeholder for the | ||||||
|  |             following, comma separated identifiers.  The  identifiers | ||||||
|  |             must specify an existing variable or row/record field. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         Conditionals | ||||||
|  |  | ||||||
|  |                 IF <expr> THEN | ||||||
|  |                     -- statements | ||||||
|  |                 [ELSE | ||||||
|  |                     -- statements] | ||||||
|  |                 END IF; | ||||||
|  |  | ||||||
|  |             The  expression  <expr> must return a value that at least | ||||||
|  |             can be casted into a boolean. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         Loops | ||||||
|  |  | ||||||
|  |             There are multiple types of loops. | ||||||
|  |  | ||||||
|  |                 [<<label>>] | ||||||
|  |                 LOOP | ||||||
|  |                     -- statements | ||||||
|  |                 END LOOP; | ||||||
|  |  | ||||||
|  |             An unconditional loop that must be terminated  explicitly | ||||||
|  |             by  an  EXIT statement. The optional label can be used by | ||||||
|  |             EXIT statements of nested loops to specify which level of | ||||||
|  |             nesting should be terminated. | ||||||
|  |  | ||||||
|  |                 [<<label>>] | ||||||
|  |                 WHILE <expr> LOOP | ||||||
|  |                     -- statements | ||||||
|  |                 END LOOP; | ||||||
|  |  | ||||||
|  |             A  conditional  loop  that  is  executed  as  long as the | ||||||
|  |             evaluation of <expr> returns true. | ||||||
|  |  | ||||||
|  |                 [<<label>>] | ||||||
|  |                 FOR <name> IN [REVERSE] <expr>..<expr> LOOP | ||||||
|  |                     -- statements | ||||||
|  |                 END LOOP. | ||||||
|  |  | ||||||
|  |             A loop that iterates over a range of integer values.  The | ||||||
|  |             variable  <name> is automatically created as type integer | ||||||
|  |             and exists only inside  the  loop.  The  two  expressions | ||||||
|  |             giving  the  lower  and  upper  bound  of  the  range are | ||||||
|  |             evaluated only when entering the loop. The iteration step | ||||||
|  |             is 1. | ||||||
|  |  | ||||||
|  |                 FOR <recname|rowname> IN <select_clause> LOOP | ||||||
|  |                     -- statements | ||||||
|  |                 END LOOP; | ||||||
|  |  | ||||||
|  |             The record or row is assigned all the rows resulting from | ||||||
|  |             the select clause and the statements executed  for  each. | ||||||
|  |             If  the  loop  is  terminated with an EXIT statement, the | ||||||
|  |             last accessed row is still accessible in  the  record  or | ||||||
|  |             rowtype. | ||||||
|  |  | ||||||
|  |                 EXIT [label] [WHEN <expr>]; | ||||||
|  |  | ||||||
|  |             If  no  label given, the innermost loop is terminated and | ||||||
|  |             the statement following END LOOP  is  executed  next.  If | ||||||
|  |             label is given, it must be the label of the current or an | ||||||
|  |             upper level of nested loops or blocks.   Then  the  named | ||||||
|  |             loop  or  block  is terminated and control continues with | ||||||
|  |             the statement after the loops/blocks corresponding END. | ||||||
|  |  | ||||||
|  |     Trigger procedures | ||||||
|  |  | ||||||
|  |         PL/pgSQL can also be used to define trigger procedures.  They | ||||||
|  |         are  created  using  CREATE  FUNCTION  as  a function with no | ||||||
|  |         arguments and a return type of opaque. | ||||||
|  |  | ||||||
|  |         There are some PostgreSQL specific details in functions  used | ||||||
|  |         as trigger procedures. | ||||||
|  |  | ||||||
|  |         First  they  have  some  special  variables created above the | ||||||
|  |         toplevel statement block. These are: | ||||||
|  |  | ||||||
|  |             new (record) | ||||||
|  |                 The new database tuple on INSERT/UPDATE operations at | ||||||
|  |                 ROW level. | ||||||
|  |  | ||||||
|  |             old (record) | ||||||
|  |                 The old database tuple on UPDATE/DELETE operations at | ||||||
|  |                 ROW level. | ||||||
|  |  | ||||||
|  |             tg_name (type name) | ||||||
|  |                 The triggers name from pg_trigger. | ||||||
|  |  | ||||||
|  |             tg_when (type text) | ||||||
|  |                 A string of either 'BEFORE' or 'AFTER'  depending  on | ||||||
|  |                 the triggers definition. | ||||||
|  |  | ||||||
|  |             tg_level (type text) | ||||||
|  |                 A  string of either 'ROW' or 'STATEMENT' depending on | ||||||
|  |                 the triggers definition. | ||||||
|  |  | ||||||
|  |             tg_op (type text) | ||||||
|  |                 A string of 'INSERT', 'UPDATE'  or  'DELETE'  telling | ||||||
|  |                 for which operation the trigger is actually fired. | ||||||
|  |  | ||||||
|  |             tg_relid (type oid) | ||||||
|  |                 The  Oid  of  the  relation  for which the trigger is | ||||||
|  |                 actually fired. | ||||||
|  |  | ||||||
|  |             tg_relname (type name) | ||||||
|  |                 The relations name for which the trigger is  actually | ||||||
|  |                 fired. | ||||||
|  |  | ||||||
|  |             tg_nargs (type integer) | ||||||
|  |                 The   number   of  arguments  given  to  the  trigger | ||||||
|  |                 procedure in the CREATE TRIGGER statement. | ||||||
|  |  | ||||||
|  |             tg_argv[] (types text) | ||||||
|  |                 The arguments from the CREATE TRIGGER statement.  The | ||||||
|  |                 index  counts  from 0 and can be given as expression. | ||||||
|  |                 Invalid indices (< 0 or >= tg_nargs) result in a NULL | ||||||
|  |                 value. | ||||||
|  |  | ||||||
|  |         Second,  they  must  return  either NULL, or a record/rowtype | ||||||
|  |         containing exactly the structure of the table the trigger was | ||||||
|  |         fired  for.  Triggers  fired  AFTER might allways return NULL | ||||||
|  |         with no effect. Triggers  fired  BEFORE  signal  the  trigger | ||||||
|  |         manager  to  skip  the  operation  for  this  actual row when | ||||||
|  |         returning  NULL.  Otherwise,  the   returned   record/rowtype | ||||||
|  |         replaces  the  inserted/updated tuple in the operation. It is | ||||||
|  |         possible to replace single values directly in new and  return | ||||||
|  |         that, or to build a complete new record/rowtype to return. | ||||||
|  |  | ||||||
|  |     Exceptions | ||||||
|  |  | ||||||
|  |         PostgreSQL  doesn't  have  a  very  smart  exception handling | ||||||
|  |         model. Whenever the  parser,  planner/optimizer  or  executor | ||||||
|  |         decide  that  a statement cannot be processed any longer, the | ||||||
|  |         whole transaction gets aborted and the the system jumps  back | ||||||
|  |         into  the mainloop using longjmp() to get the next query from | ||||||
|  |         the client application. | ||||||
|  |  | ||||||
|  |         It is possible to hook into the longjmp() mechanism to notice | ||||||
|  |         that this happens. But currently it's impossible to tell what | ||||||
|  |         really  caused  the  abort  (input/output  conversion  error, | ||||||
|  |         floating point error, parse error) And it's possible that the | ||||||
|  |         backend  is  in  an  inconsistent  state  at  this  point  so | ||||||
|  |         returning  to  the  upper  executor  or issuing more commands | ||||||
|  |         might corrupt the whole database. | ||||||
|  |  | ||||||
|  |         Thus,  the  only  thing  PL/pgSQL  currently  does  when   it | ||||||
|  |         encounters an abort during execution of a function or trigger | ||||||
|  |         procedure is to write  some  additional  DEBUG  log  messages | ||||||
|  |         telling  in which function and where (line number and type of | ||||||
|  |         statement) this happened. | ||||||
|  |  | ||||||
|  |         This might change in the future. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								contrib/plpgsql/src/INSTALL
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								contrib/plpgsql/src/INSTALL
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | Installation of PL/pgSQL | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 1)	Type 'make' to build the shared plpgsql object. | ||||||
|  |  | ||||||
|  | 2)	Type 'make install' to install the shared object in | ||||||
|  | 	the PostgreSQL library directory. | ||||||
|  |  | ||||||
|  | 3)	Declare the PL/pgSQL procedural language in your | ||||||
|  | 	database by | ||||||
|  |  | ||||||
|  | 		psql dbname <mklang.sql | ||||||
|  |  | ||||||
|  | 	If the PostgreSQL library directory is different from | ||||||
|  | 	/usr/local/pgsql/lib you must edit mklang.sql prior. | ||||||
|  |  | ||||||
|  | 	If you declare the language in the template1 database, | ||||||
|  | 	any subsequently created database will have PL/pgSQL | ||||||
|  | 	support installed automatically. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										1460
									
								
								contrib/plpgsql/src/gram.y
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1460
									
								
								contrib/plpgsql/src/gram.y
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										14
									
								
								contrib/plpgsql/src/mklang.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								contrib/plpgsql/src/mklang.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | -- | ||||||
|  | -- PL/pgSQL language declaration | ||||||
|  | -- | ||||||
|  | -- $Header: /cvsroot/pgsql/contrib/plpgsql/src/Attic/mklang.sql,v 1.1 1998/08/22 12:38:31 momjian Exp $ | ||||||
|  | -- | ||||||
|  |  | ||||||
|  | create function plpgsql_call_handler() returns opaque | ||||||
|  | 	as '/usr/local/pgsql/lib/plpgsql.so' | ||||||
|  | 	language 'C'; | ||||||
|  |  | ||||||
|  | create trusted procedural language 'plpgsql' | ||||||
|  | 	handler plpgsql_call_handler | ||||||
|  | 	lancompiler 'PL/pgSQL'; | ||||||
|  |  | ||||||
							
								
								
									
										1313
									
								
								contrib/plpgsql/src/pl_comp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1313
									
								
								contrib/plpgsql/src/pl_comp.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2241
									
								
								contrib/plpgsql/src/pl_exec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2241
									
								
								contrib/plpgsql/src/pl_exec.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										675
									
								
								contrib/plpgsql/src/pl_funcs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										675
									
								
								contrib/plpgsql/src/pl_funcs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,675 @@ | |||||||
|  | /********************************************************************** | ||||||
|  |  * pl_funcs.c		- Misc functins for the PL/pgSQL | ||||||
|  |  *			  procedural language | ||||||
|  |  * | ||||||
|  |  * IDENTIFICATION | ||||||
|  |  *    $Header: /cvsroot/pgsql/contrib/plpgsql/src/Attic/pl_funcs.c,v 1.1 1998/08/22 12:38:32 momjian Exp $ | ||||||
|  |  * | ||||||
|  |  *    This software is copyrighted by Jan Wieck - Hamburg. | ||||||
|  |  * | ||||||
|  |  *    The author hereby grants permission  to  use,  copy,  modify, | ||||||
|  |  *    distribute,  and  license this software and its documentation | ||||||
|  |  *    for any purpose, provided that existing copyright notices are | ||||||
|  |  *    retained  in  all  copies  and  that  this notice is included | ||||||
|  |  *    verbatim in any distributions. No written agreement, license, | ||||||
|  |  *    or  royalty  fee  is required for any of the authorized uses. | ||||||
|  |  *    Modifications to this software may be  copyrighted  by  their | ||||||
|  |  *    author  and  need  not  follow  the licensing terms described | ||||||
|  |  *    here, provided that the new terms are  clearly  indicated  on | ||||||
|  |  *    the first page of each file where they apply. | ||||||
|  |  * | ||||||
|  |  *    IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY | ||||||
|  |  *    PARTY  FOR  DIRECT,   INDIRECT,   SPECIAL,   INCIDENTAL,   OR | ||||||
|  |  *    CONSEQUENTIAL   DAMAGES  ARISING  OUT  OF  THE  USE  OF  THIS | ||||||
|  |  *    SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN | ||||||
|  |  *    IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH | ||||||
|  |  *    DAMAGE. | ||||||
|  |  * | ||||||
|  |  *    THE  AUTHOR  AND  DISTRIBUTORS  SPECIFICALLY   DISCLAIM   ANY | ||||||
|  |  *    WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED | ||||||
|  |  *    WARRANTIES  OF  MERCHANTABILITY,  FITNESS  FOR  A  PARTICULAR | ||||||
|  |  *    PURPOSE,  AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON | ||||||
|  |  *    AN "AS IS" BASIS, AND THE AUTHOR  AND  DISTRIBUTORS  HAVE  NO | ||||||
|  |  *    OBLIGATION   TO   PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES, | ||||||
|  |  *    ENHANCEMENTS, OR MODIFICATIONS. | ||||||
|  |  * | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <ctype.h> | ||||||
|  |  | ||||||
|  | #include "plpgsql.h" | ||||||
|  | #include "pl.tab.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Local variables for the namestack handling | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | static PLpgSQL_ns		*ns_current = NULL; | ||||||
|  | static bool			ns_localmode = false; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_dstring_init			Dynamic string initialization | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | void plpgsql_dstring_init(PLpgSQL_dstring *ds) | ||||||
|  | { | ||||||
|  |     ds->value = palloc(ds->alloc = 512); | ||||||
|  |     ds->used = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_dstring_free			Dynamic string destruction | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | void plpgsql_dstring_free(PLpgSQL_dstring *ds) | ||||||
|  | { | ||||||
|  |     pfree(ds->value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_dstring_append		Dynamic string extending | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | void plpgsql_dstring_append(PLpgSQL_dstring *ds, char *str) | ||||||
|  | { | ||||||
|  |     int len = strlen(str); | ||||||
|  |  | ||||||
|  |     if (ds->used + len + 1 > ds->alloc) { | ||||||
|  |         ds->alloc *= 2; | ||||||
|  | 	ds->value = repalloc(ds->value, ds->alloc); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     strcpy(&(ds->value[ds->used]), str); | ||||||
|  |     ds->used += len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_dstring_get			Dynamic string get value | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | char *plpgsql_dstring_get(PLpgSQL_dstring *ds) | ||||||
|  | { | ||||||
|  |     return ds->value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_ns_init			Initialize the namestack | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | void plpgsql_ns_init(void) | ||||||
|  | { | ||||||
|  |     ns_current   = NULL; | ||||||
|  |     ns_localmode = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_ns_setlocal			Tell plpgsql_ns_lookup to or to | ||||||
|  |  *					not look into the current level | ||||||
|  |  *					only. | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | bool plpgsql_ns_setlocal(bool flag) | ||||||
|  | { | ||||||
|  |     bool oldstate; | ||||||
|  |  | ||||||
|  |     oldstate = ns_localmode; | ||||||
|  |     ns_localmode = flag; | ||||||
|  |     return oldstate; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_ns_push			Enter a new namestack level | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | void plpgsql_ns_push(char *label) | ||||||
|  | { | ||||||
|  |     PLpgSQL_ns	*new; | ||||||
|  |  | ||||||
|  |     new = palloc(sizeof(PLpgSQL_ns)); | ||||||
|  |     memset(new, 0, sizeof(PLpgSQL_ns)); | ||||||
|  |     new->upper = ns_current; | ||||||
|  |     ns_current = new; | ||||||
|  |  | ||||||
|  |     plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_ns_pop			Return to the previous level | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | void plpgsql_ns_pop() | ||||||
|  | { | ||||||
|  |     int		i; | ||||||
|  |     PLpgSQL_ns	*old; | ||||||
|  |  | ||||||
|  |     old = ns_current; | ||||||
|  |     ns_current = old->upper; | ||||||
|  |  | ||||||
|  |     for (i = 0; i < old->items_used; i++) { | ||||||
|  |         pfree(old->items[i]); | ||||||
|  |     } | ||||||
|  |     pfree(old->items); | ||||||
|  |     pfree(old); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_ns_additem			Add an item to the current | ||||||
|  |  *					namestack level | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | void plpgsql_ns_additem(int itemtype, int itemno, char *name) | ||||||
|  | { | ||||||
|  |     PLpgSQL_ns		*ns = ns_current; | ||||||
|  |     PLpgSQL_nsitem	*nse; | ||||||
|  |  | ||||||
|  |     if (name == NULL) | ||||||
|  | 	    name = ""; | ||||||
|  |  | ||||||
|  |     if (ns->items_used == ns->items_alloc) { | ||||||
|  | 	if (ns->items_alloc == 0) { | ||||||
|  | 	    ns->items_alloc = 32; | ||||||
|  | 	    ns->items = palloc(sizeof(PLpgSQL_nsitem *) * ns->items_alloc); | ||||||
|  | 	} else { | ||||||
|  | 	    ns->items_alloc *= 2; | ||||||
|  | 	    ns->items = repalloc(ns->items,  | ||||||
|  | 	    		sizeof(PLpgSQL_nsitem *) * ns->items_alloc); | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name)); | ||||||
|  |     nse->itemtype = itemtype; | ||||||
|  |     nse->itemno   = itemno; | ||||||
|  |     strcpy(nse->name, name); | ||||||
|  |     ns->items[ns->items_used++] = nse; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_ns_lookup			Lookup for a word in the namestack | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *label) | ||||||
|  | { | ||||||
|  |     PLpgSQL_ns	*ns; | ||||||
|  |     int		i; | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * If a label is specified, lookup only in that | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     if (label != NULL) { | ||||||
|  |         for (ns = ns_current; ns != NULL; ns = ns->upper) { | ||||||
|  | 	    if (!strcmp(ns->items[0]->name, label)) { | ||||||
|  | 	        for (i = 1; i < ns->items_used; i++) { | ||||||
|  | 		    if (!strcmp(ns->items[i]->name, name)) { | ||||||
|  | 		        return ns->items[i]; | ||||||
|  | 		    } | ||||||
|  | 		} | ||||||
|  | 		return NULL;	/* name not found in specified label */ | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  | 	return NULL;	/* label not found */ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * No label given, lookup for visible labels ignoring localmode | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     for (ns = ns_current; ns != NULL; ns = ns->upper) { | ||||||
|  | 	if (!strcmp(ns->items[0]->name, name)) { | ||||||
|  | 	    return ns->items[0]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Finally lookup name in the namestack | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     for (ns = ns_current; ns != NULL; ns = ns->upper) { | ||||||
|  | 	for (i = 1; i < ns->items_used; i++) { | ||||||
|  | 	    if (!strcmp(ns->items[i]->name, name)) | ||||||
|  | 		    return ns->items[i]; | ||||||
|  | 	} | ||||||
|  | 	if (ns_localmode) { | ||||||
|  | 	    return NULL;	/* name not found in current namespace */ | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_ns_rename			Rename a namespace entry | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | void plpgsql_ns_rename(char *oldname, char *newname) | ||||||
|  | { | ||||||
|  |     PLpgSQL_ns		*ns; | ||||||
|  |     PLpgSQL_nsitem	*newitem; | ||||||
|  |     int			i; | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Lookup in the current namespace only | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     /* ---------- | ||||||
|  |      * Lookup name in the namestack | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     for (ns = ns_current; ns != NULL; ns = ns->upper) { | ||||||
|  | 	for (i = 1; i < ns->items_used; i++) { | ||||||
|  | 	    if (!strcmp(ns->items[i]->name, oldname)) { | ||||||
|  | 		newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname)); | ||||||
|  | 		newitem->itemtype = ns->items[i]->itemtype; | ||||||
|  | 		newitem->itemno   = ns->items[i]->itemno; | ||||||
|  | 		strcpy(newitem->name, newname); | ||||||
|  |  | ||||||
|  | 		pfree(oldname); | ||||||
|  | 		pfree(newname); | ||||||
|  |  | ||||||
|  | 		pfree(ns->items[i]); | ||||||
|  | 		ns->items[i] = newitem; | ||||||
|  | 		return; | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     elog(ERROR, "there is no variable '%s' in the current block", oldname); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_tolower			Translate a string in place to | ||||||
|  |  *					lower case | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | char *plpgsql_tolower(char *s) | ||||||
|  | { | ||||||
|  |     char *cp; | ||||||
|  |  | ||||||
|  |     for (cp = s; *cp; cp++) { | ||||||
|  |         if (isupper(*cp)) *cp = tolower(*cp); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return s; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /********************************************************************** | ||||||
|  |  * Debug functions for analyzing the compiled code | ||||||
|  |  **********************************************************************/ | ||||||
|  | static int	dump_indent; | ||||||
|  |  | ||||||
|  | static void dump_ind(); | ||||||
|  | static void dump_stmt(PLpgSQL_stmt *stmt); | ||||||
|  | static void dump_block(PLpgSQL_stmt_block *block); | ||||||
|  | static void dump_assign(PLpgSQL_stmt_assign *stmt); | ||||||
|  | static void dump_if(PLpgSQL_stmt_if *stmt); | ||||||
|  | static void dump_loop(PLpgSQL_stmt_loop *stmt); | ||||||
|  | static void dump_while(PLpgSQL_stmt_while *stmt); | ||||||
|  | static void dump_fori(PLpgSQL_stmt_fori *stmt); | ||||||
|  | static void dump_fors(PLpgSQL_stmt_fors *stmt); | ||||||
|  | static void dump_select(PLpgSQL_stmt_select *stmt); | ||||||
|  | static void dump_exit(PLpgSQL_stmt_exit *stmt); | ||||||
|  | static void dump_return(PLpgSQL_stmt_return *stmt); | ||||||
|  | static void dump_raise(PLpgSQL_stmt_raise *stmt); | ||||||
|  | static void dump_execsql(PLpgSQL_stmt_execsql *stmt); | ||||||
|  | static void dump_expr(PLpgSQL_expr *expr); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void dump_ind() | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |     for (i = 0; i < dump_indent; i++) { | ||||||
|  |         printf(" "); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_stmt(PLpgSQL_stmt *stmt) | ||||||
|  | { | ||||||
|  |     printf("%3d:", stmt->lineno); | ||||||
|  |     switch (stmt->cmd_type) { | ||||||
|  |         case PLPGSQL_STMT_BLOCK: | ||||||
|  | 		dump_block((PLpgSQL_stmt_block *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_ASSIGN: | ||||||
|  | 		dump_assign((PLpgSQL_stmt_assign *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_IF: | ||||||
|  | 		dump_if((PLpgSQL_stmt_if *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_LOOP: | ||||||
|  | 		dump_loop((PLpgSQL_stmt_loop *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_WHILE: | ||||||
|  | 		dump_while((PLpgSQL_stmt_while *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_FORI: | ||||||
|  | 		dump_fori((PLpgSQL_stmt_fori *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_FORS: | ||||||
|  | 		dump_fors((PLpgSQL_stmt_fors *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_SELECT: | ||||||
|  | 		dump_select((PLpgSQL_stmt_select *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_EXIT: | ||||||
|  | 		dump_exit((PLpgSQL_stmt_exit *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_RETURN: | ||||||
|  | 		dump_return((PLpgSQL_stmt_return *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_RAISE: | ||||||
|  | 		dump_raise((PLpgSQL_stmt_raise *)stmt); | ||||||
|  | 		break; | ||||||
|  |         case PLPGSQL_STMT_EXECSQL: | ||||||
|  | 		dump_execsql((PLpgSQL_stmt_execsql *)stmt); | ||||||
|  | 		break; | ||||||
|  |         default: | ||||||
|  | 		elog(ERROR, "plpgsql_dump: unknown cmd_type %d\n", stmt->cmd_type); | ||||||
|  | 		break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_block(PLpgSQL_stmt_block *block) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |     char *name; | ||||||
|  |  | ||||||
|  |     if (block->label == NULL) { | ||||||
|  |         name = "*unnamed*"; | ||||||
|  |     } else { | ||||||
|  |         name = block->label; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("BLOCK <<%s>>\n", name); | ||||||
|  |  | ||||||
|  |     dump_indent += 2; | ||||||
|  |     for (i = 0; i < block->body->stmts_used; i++) { | ||||||
|  |         dump_stmt((PLpgSQL_stmt *)(block->body->stmts[i])); | ||||||
|  |     } | ||||||
|  |     dump_indent -= 2; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    END -- %s\n", name); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_assign(PLpgSQL_stmt_assign *stmt) | ||||||
|  | { | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("ASSIGN var %d := ", stmt->varno); | ||||||
|  |     dump_expr(stmt->expr); | ||||||
|  |     printf("\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_if(PLpgSQL_stmt_if *stmt) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("IF "); | ||||||
|  |     dump_expr(stmt->cond); | ||||||
|  |     printf(" THEN\n"); | ||||||
|  |  | ||||||
|  |     dump_indent += 2; | ||||||
|  |     for (i = 0; i < stmt->true_body->stmts_used; i++) { | ||||||
|  |         dump_stmt((PLpgSQL_stmt *)(stmt->true_body->stmts[i])); | ||||||
|  |     } | ||||||
|  |     dump_indent -= 2; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    ELSE\n"); | ||||||
|  |  | ||||||
|  |     dump_indent += 2; | ||||||
|  |     for (i = 0; i < stmt->false_body->stmts_used; i++) { | ||||||
|  |         dump_stmt((PLpgSQL_stmt *)(stmt->false_body->stmts[i])); | ||||||
|  |     } | ||||||
|  |     dump_indent -= 2; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    ENDIF\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_loop(PLpgSQL_stmt_loop *stmt) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("LOOP\n"); | ||||||
|  |  | ||||||
|  |     dump_indent += 2; | ||||||
|  |     for (i = 0; i < stmt->body->stmts_used; i++) { | ||||||
|  |         dump_stmt((PLpgSQL_stmt *)(stmt->body->stmts[i])); | ||||||
|  |     } | ||||||
|  |     dump_indent -= 2; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    ENDLOOP\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_while(PLpgSQL_stmt_while *stmt) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("WHILE "); | ||||||
|  |     dump_expr(stmt->cond); | ||||||
|  |     printf("\n"); | ||||||
|  |  | ||||||
|  |     dump_indent += 2; | ||||||
|  |     for (i = 0; i < stmt->body->stmts_used; i++) { | ||||||
|  |         dump_stmt((PLpgSQL_stmt *)(stmt->body->stmts[i])); | ||||||
|  |     } | ||||||
|  |     dump_indent -= 2; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    ENDWHILE\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_fori(PLpgSQL_stmt_fori *stmt) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL"); | ||||||
|  |  | ||||||
|  |     dump_indent += 2; | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    lower = "); | ||||||
|  |     dump_expr(stmt->lower); | ||||||
|  |     printf("\n"); | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    upper = "); | ||||||
|  |     dump_expr(stmt->upper); | ||||||
|  |     printf("\n"); | ||||||
|  |  | ||||||
|  |     for (i = 0; i < stmt->body->stmts_used; i++) { | ||||||
|  |         dump_stmt((PLpgSQL_stmt *)(stmt->body->stmts[i])); | ||||||
|  |     } | ||||||
|  |     dump_indent -= 2; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    ENDFORI\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_fors(PLpgSQL_stmt_fors *stmt) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname); | ||||||
|  |     dump_expr(stmt->query); | ||||||
|  |     printf("\n"); | ||||||
|  |  | ||||||
|  |     dump_indent += 2; | ||||||
|  |     for (i = 0; i < stmt->body->stmts_used; i++) { | ||||||
|  |         dump_stmt((PLpgSQL_stmt *)(stmt->body->stmts[i])); | ||||||
|  |     } | ||||||
|  |     dump_indent -= 2; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("    ENDFORS\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_select(PLpgSQL_stmt_select *stmt) | ||||||
|  | { | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("SELECT "); | ||||||
|  |     dump_expr(stmt->query); | ||||||
|  |     printf("\n"); | ||||||
|  |  | ||||||
|  |     dump_indent += 2; | ||||||
|  |     if (stmt->rec != NULL) { | ||||||
|  | 	dump_ind(); | ||||||
|  | 	printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname); | ||||||
|  |     } | ||||||
|  |     if (stmt->row != NULL) { | ||||||
|  | 	dump_ind(); | ||||||
|  | 	printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname); | ||||||
|  |     } | ||||||
|  |     dump_indent -= 2; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_exit(PLpgSQL_stmt_exit *stmt) | ||||||
|  | { | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("EXIT lbl='%s'", stmt->label); | ||||||
|  |     if (stmt->cond != NULL) { | ||||||
|  |         printf(" WHEN "); | ||||||
|  | 	dump_expr(stmt->cond); | ||||||
|  |     } | ||||||
|  |     printf("\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_return(PLpgSQL_stmt_return *stmt) | ||||||
|  | { | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("RETURN "); | ||||||
|  |     if (stmt->retrecno >= 0) { | ||||||
|  |         printf("record %d", stmt->retrecno); | ||||||
|  |     } else { | ||||||
|  | 	if (stmt->expr == NULL) { | ||||||
|  | 	    printf("NULL"); | ||||||
|  | 	} else { | ||||||
|  | 	    dump_expr(stmt->expr); | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |     printf("\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_raise(PLpgSQL_stmt_raise *stmt) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("RAISE '%s'", stmt->message); | ||||||
|  |     for (i = 0; i < stmt->nparams; i++) { | ||||||
|  |         printf(" %d", stmt->params[i]); | ||||||
|  |     } | ||||||
|  |     printf("\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_execsql(PLpgSQL_stmt_execsql *stmt) | ||||||
|  | { | ||||||
|  |     dump_ind(); | ||||||
|  |     printf("EXECSQL "); | ||||||
|  |     dump_expr(stmt->sqlstmt); | ||||||
|  |     printf("\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dump_expr(PLpgSQL_expr *expr) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |     printf("'%s", expr->query); | ||||||
|  |     if (expr->nparams > 0) { | ||||||
|  | 	printf(" {"); | ||||||
|  | 	for(i = 0; i < expr->nparams; i++) { | ||||||
|  | 	    if (i > 0) printf(", "); | ||||||
|  | 	    printf("$%d=%d", i+1, expr->params[i]); | ||||||
|  | 	} | ||||||
|  | 	printf("}"); | ||||||
|  |     } | ||||||
|  |     printf("'"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void plpgsql_dumptree(PLpgSQL_function *func) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |     PLpgSQL_datum *d; | ||||||
|  |  | ||||||
|  |     printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n", | ||||||
|  |     		func->fn_name); | ||||||
|  |  | ||||||
|  |     printf("\nFunctions data area:\n"); | ||||||
|  |     for (i = 0; i < func->ndatums; i++) { | ||||||
|  |     	d = func->datums[i]; | ||||||
|  |  | ||||||
|  | 	printf("    entry %d: ", i); | ||||||
|  | 	switch (d->dtype) { | ||||||
|  | 	    case PLPGSQL_DTYPE_VAR: | ||||||
|  | 		{ | ||||||
|  | 		    PLpgSQL_var *var = (PLpgSQL_var *)d; | ||||||
|  | 		    printf("VAR %-16s type %s (typoid %d) atttypmod %d\n", | ||||||
|  | 		    		var->refname, var->datatype->typname, | ||||||
|  | 				var->datatype->typoid, | ||||||
|  | 				var->datatype->atttypmod); | ||||||
|  | 		} | ||||||
|  | 	    	break; | ||||||
|  | 	    case PLPGSQL_DTYPE_ROW: | ||||||
|  | 	        { | ||||||
|  | 		    PLpgSQL_row *row = (PLpgSQL_row *)d; | ||||||
|  | 		    int i; | ||||||
|  | 		    printf("ROW %-16s fields", row->refname); | ||||||
|  | 		    for (i = 0; i < row->nfields; i++) { | ||||||
|  | 		        printf(" %s=var %d", row->fieldnames[i], | ||||||
|  | 					     row->varnos[i]); | ||||||
|  | 		    } | ||||||
|  | 		    printf("\n"); | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	    case PLPGSQL_DTYPE_REC: | ||||||
|  | 	    	printf("REC %s\n", ((PLpgSQL_rec *)d)->refname); | ||||||
|  | 	    	break; | ||||||
|  | 	    case PLPGSQL_DTYPE_RECFIELD: | ||||||
|  | 	    	printf("RECFIELD %-16s of REC %d\n", ((PLpgSQL_recfield *)d)->fieldname, ((PLpgSQL_recfield *)d)->recno); | ||||||
|  | 	    	break; | ||||||
|  | 	    case PLPGSQL_DTYPE_TRIGARG: | ||||||
|  | 	    	printf("TRIGARG "); | ||||||
|  | 		dump_expr(((PLpgSQL_trigarg *)d)->argnum); | ||||||
|  | 		printf("\n"); | ||||||
|  | 		break; | ||||||
|  | 	    default: | ||||||
|  | 	    	printf("??? unknown data type %d\n", d->dtype); | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |     printf("\nFunctions statements:\n"); | ||||||
|  |      | ||||||
|  |     dump_indent = 0; | ||||||
|  |     printf("%3d:", func->action->lineno); | ||||||
|  |     dump_block(func->action); | ||||||
|  |     printf("\nEnd of execution tree of function %s\n\n", func->fn_name); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										193
									
								
								contrib/plpgsql/src/pl_handler.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								contrib/plpgsql/src/pl_handler.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | |||||||
|  | /********************************************************************** | ||||||
|  |  * pl_handler.c		- Handler for the PL/pgSQL | ||||||
|  |  *			  procedural language | ||||||
|  |  * | ||||||
|  |  * IDENTIFICATION | ||||||
|  |  *    $Header: /cvsroot/pgsql/contrib/plpgsql/src/Attic/pl_handler.c,v 1.1 1998/08/22 12:38:32 momjian Exp $ | ||||||
|  |  * | ||||||
|  |  *    This software is copyrighted by Jan Wieck - Hamburg. | ||||||
|  |  * | ||||||
|  |  *    The author hereby grants permission  to  use,  copy,  modify, | ||||||
|  |  *    distribute,  and  license this software and its documentation | ||||||
|  |  *    for any purpose, provided that existing copyright notices are | ||||||
|  |  *    retained  in  all  copies  and  that  this notice is included | ||||||
|  |  *    verbatim in any distributions. No written agreement, license, | ||||||
|  |  *    or  royalty  fee  is required for any of the authorized uses. | ||||||
|  |  *    Modifications to this software may be  copyrighted  by  their | ||||||
|  |  *    author  and  need  not  follow  the licensing terms described | ||||||
|  |  *    here, provided that the new terms are  clearly  indicated  on | ||||||
|  |  *    the first page of each file where they apply. | ||||||
|  |  * | ||||||
|  |  *    IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY | ||||||
|  |  *    PARTY  FOR  DIRECT,   INDIRECT,   SPECIAL,   INCIDENTAL,   OR | ||||||
|  |  *    CONSEQUENTIAL   DAMAGES  ARISING  OUT  OF  THE  USE  OF  THIS | ||||||
|  |  *    SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN | ||||||
|  |  *    IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH | ||||||
|  |  *    DAMAGE. | ||||||
|  |  * | ||||||
|  |  *    THE  AUTHOR  AND  DISTRIBUTORS  SPECIFICALLY   DISCLAIM   ANY | ||||||
|  |  *    WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED | ||||||
|  |  *    WARRANTIES  OF  MERCHANTABILITY,  FITNESS  FOR  A  PARTICULAR | ||||||
|  |  *    PURPOSE,  AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON | ||||||
|  |  *    AN "AS IS" BASIS, AND THE AUTHOR  AND  DISTRIBUTORS  HAVE  NO | ||||||
|  |  *    OBLIGATION   TO   PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES, | ||||||
|  |  *    ENHANCEMENTS, OR MODIFICATIONS. | ||||||
|  |  * | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #include "plpgsql.h" | ||||||
|  | #include "pl.tab.h" | ||||||
|  |  | ||||||
|  | #include "executor/spi.h" | ||||||
|  | #include "commands/trigger.h" | ||||||
|  | #include "utils/elog.h" | ||||||
|  | #include "utils/builtins.h" | ||||||
|  | #include "fmgr.h" | ||||||
|  | #include "access/heapam.h" | ||||||
|  |  | ||||||
|  | #include "utils/syscache.h" | ||||||
|  | #include "catalog/pg_proc.h" | ||||||
|  | #include "catalog/pg_type.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static	PLpgSQL_function	*compiled_functions = NULL; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Datum plpgsql_call_handler(FmgrInfo *proinfo, | ||||||
|  | 	FmgrValues *proargs, bool *isNull); | ||||||
|  |  | ||||||
|  | static Datum plpgsql_func_handler(FmgrInfo *proinfo, | ||||||
|  | 	FmgrValues *proargs, bool *isNull); | ||||||
|  |  | ||||||
|  | static HeapTuple plpgsql_trigger_handler(FmgrInfo *proinfo); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_call_handler		- This is the only visible function | ||||||
|  |  *				  of the PL interpreter. The PostgreSQL | ||||||
|  |  *				  function manager and trigger manager | ||||||
|  |  *				  call this function for execution of | ||||||
|  |  *				  PL/pgSQL procedures. | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | Datum | ||||||
|  | plpgsql_call_handler(FmgrInfo	*proinfo, | ||||||
|  | 		FmgrValues	*proargs, | ||||||
|  | 		bool		*isNull) | ||||||
|  | { | ||||||
|  |     Datum	retval; | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Connect to SPI manager | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     if (SPI_connect() != SPI_OK_CONNECT) { | ||||||
|  |         elog(ERROR, "plpgsql: cannot connect to SPI manager"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Determine if called as function or trigger and | ||||||
|  |      * call appropriate subhandler | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     if (CurrentTriggerData == NULL) { | ||||||
|  | 	retval =  plpgsql_func_handler(proinfo, proargs, isNull); | ||||||
|  |     } else { | ||||||
|  | 	retval =  (Datum)plpgsql_trigger_handler(proinfo); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Disconnect from SPI manager | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     if (SPI_finish() != SPI_OK_FINISH) { | ||||||
|  |         elog(ERROR, "plpgsql: SPI_finish() failed"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return retval; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_func_handler()	- Handler for regular function calls | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | static Datum | ||||||
|  | plpgsql_func_handler(FmgrInfo	*proinfo, | ||||||
|  | 		FmgrValues	*proargs, | ||||||
|  | 		bool		*isNull) | ||||||
|  | { | ||||||
|  |     PLpgSQL_function	*func; | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Check if we already compiled this function | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     for (func = compiled_functions; func != NULL; func = func->next) { | ||||||
|  |         if (proinfo->fn_oid == func->fn_oid) | ||||||
|  | 	    break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * If not, do so and add it to the compiled ones | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     if (func == NULL) { | ||||||
|  | 	func = plpgsql_compile(proinfo->fn_oid, T_FUNCTION); | ||||||
|  |  | ||||||
|  | 	func->next = compiled_functions; | ||||||
|  | 	compiled_functions = func; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return plpgsql_exec_function(func, proargs, isNull); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * plpgsql_trigger_handler()	- Handler for trigger calls | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | static HeapTuple | ||||||
|  | plpgsql_trigger_handler(FmgrInfo *proinfo) | ||||||
|  | { | ||||||
|  |     TriggerData		*trigdata; | ||||||
|  |     PLpgSQL_function	*func; | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Save the current trigger data local | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     trigdata = CurrentTriggerData; | ||||||
|  |     CurrentTriggerData = NULL; | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Check if we already compiled this trigger procedure | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     for (func = compiled_functions; func != NULL; func = func->next) { | ||||||
|  |         if (proinfo->fn_oid == func->fn_oid) | ||||||
|  | 	    break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * If not, do so and add it to the compiled ones | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     if (func == NULL) { | ||||||
|  | 	func = plpgsql_compile(proinfo->fn_oid, T_TRIGGER); | ||||||
|  |  | ||||||
|  | 	func->next = compiled_functions; | ||||||
|  | 	compiled_functions = func; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return plpgsql_exec_trigger(func, trigdata); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										475
									
								
								contrib/plpgsql/src/plpgsql.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										475
									
								
								contrib/plpgsql/src/plpgsql.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,475 @@ | |||||||
|  | /********************************************************************** | ||||||
|  |  * plpgsql.h		- Definitions for the PL/pgSQL | ||||||
|  |  *			  procedural language | ||||||
|  |  * | ||||||
|  |  * IDENTIFICATION | ||||||
|  |  *    $Header: /cvsroot/pgsql/contrib/plpgsql/src/Attic/plpgsql.h,v 1.1 1998/08/22 12:38:33 momjian Exp $ | ||||||
|  |  * | ||||||
|  |  *    This software is copyrighted by Jan Wieck - Hamburg. | ||||||
|  |  * | ||||||
|  |  *    The author hereby grants permission  to  use,  copy,  modify, | ||||||
|  |  *    distribute,  and  license this software and its documentation | ||||||
|  |  *    for any purpose, provided that existing copyright notices are | ||||||
|  |  *    retained  in  all  copies  and  that  this notice is included | ||||||
|  |  *    verbatim in any distributions. No written agreement, license, | ||||||
|  |  *    or  royalty  fee  is required for any of the authorized uses. | ||||||
|  |  *    Modifications to this software may be  copyrighted  by  their | ||||||
|  |  *    author  and  need  not  follow  the licensing terms described | ||||||
|  |  *    here, provided that the new terms are  clearly  indicated  on | ||||||
|  |  *    the first page of each file where they apply. | ||||||
|  |  * | ||||||
|  |  *    IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY | ||||||
|  |  *    PARTY  FOR  DIRECT,   INDIRECT,   SPECIAL,   INCIDENTAL,   OR | ||||||
|  |  *    CONSEQUENTIAL   DAMAGES  ARISING  OUT  OF  THE  USE  OF  THIS | ||||||
|  |  *    SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN | ||||||
|  |  *    IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH | ||||||
|  |  *    DAMAGE. | ||||||
|  |  * | ||||||
|  |  *    THE  AUTHOR  AND  DISTRIBUTORS  SPECIFICALLY   DISCLAIM   ANY | ||||||
|  |  *    WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED | ||||||
|  |  *    WARRANTIES  OF  MERCHANTABILITY,  FITNESS  FOR  A  PARTICULAR | ||||||
|  |  *    PURPOSE,  AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON | ||||||
|  |  *    AN "AS IS" BASIS, AND THE AUTHOR  AND  DISTRIBUTORS  HAVE  NO | ||||||
|  |  *    OBLIGATION   TO   PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES, | ||||||
|  |  *    ENHANCEMENTS, OR MODIFICATIONS. | ||||||
|  |  * | ||||||
|  |  **********************************************************************/ | ||||||
|  | #ifndef PLPGSQL_H | ||||||
|  | #define PLPGSQL_H | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include "postgres.h" | ||||||
|  | #include "executor/spi.h" | ||||||
|  | #include "commands/trigger.h" | ||||||
|  | #include "fmgr.h" | ||||||
|  |  | ||||||
|  | /********************************************************************** | ||||||
|  |  * Definitions | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Compilers namestack item types | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | enum { | ||||||
|  |     PLPGSQL_NSTYPE_LABEL, | ||||||
|  |     PLPGSQL_NSTYPE_VAR, | ||||||
|  |     PLPGSQL_NSTYPE_ROW, | ||||||
|  |     PLPGSQL_NSTYPE_REC, | ||||||
|  |     PLPGSQL_NSTYPE_RECFIELD | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Datum array node types | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | enum { | ||||||
|  |     PLPGSQL_DTYPE_VAR, | ||||||
|  |     PLPGSQL_DTYPE_ROW, | ||||||
|  |     PLPGSQL_DTYPE_REC, | ||||||
|  |     PLPGSQL_DTYPE_RECFIELD, | ||||||
|  |     PLPGSQL_DTYPE_EXPR, | ||||||
|  |     PLPGSQL_DTYPE_TRIGARG | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Execution tree node types | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | enum { | ||||||
|  |     PLPGSQL_STMT_BLOCK, | ||||||
|  |     PLPGSQL_STMT_ASSIGN, | ||||||
|  |     PLPGSQL_STMT_IF, | ||||||
|  |     PLPGSQL_STMT_LOOP, | ||||||
|  |     PLPGSQL_STMT_WHILE, | ||||||
|  |     PLPGSQL_STMT_FORI, | ||||||
|  |     PLPGSQL_STMT_FORS, | ||||||
|  |     PLPGSQL_STMT_SELECT, | ||||||
|  |     PLPGSQL_STMT_EXIT, | ||||||
|  |     PLPGSQL_STMT_RETURN, | ||||||
|  |     PLPGSQL_STMT_RAISE, | ||||||
|  |     PLPGSQL_STMT_EXECSQL | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Execution node return codes | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | enum { | ||||||
|  |     PLPGSQL_RC_OK, | ||||||
|  |     PLPGSQL_RC_EXIT, | ||||||
|  |     PLPGSQL_RC_RETURN | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /********************************************************************** | ||||||
|  |  * Node and structure definitions | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Dynamic string control structure	*/ | ||||||
|  | 	int		alloc; | ||||||
|  | 	int		used; | ||||||
|  | 	char		*value; | ||||||
|  | } PLpgSQL_dstring; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Postgres base data type		*/ | ||||||
|  | 	char		*typname; | ||||||
|  | 	Oid		typoid; | ||||||
|  | 	FmgrInfo	typinput; | ||||||
|  | 	bool		typbyval; | ||||||
|  | 	int16		atttypmod; | ||||||
|  | } PLpgSQL_type; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Generic datum array item		*/ | ||||||
|  | 	int		dtype; | ||||||
|  | 	int		dno; | ||||||
|  | } PLpgSQL_datum; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* SQL Query to plan and execute	*/ | ||||||
|  | 	int		dtype; | ||||||
|  | 	int		exprno; | ||||||
|  | 	char		*query; | ||||||
|  | 	void		*plan; | ||||||
|  | 	Oid		*plan_argtypes; | ||||||
|  | 	int		nparams; | ||||||
|  | 	int		params[1]; | ||||||
|  | } PLpgSQL_expr; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Local variable			*/ | ||||||
|  | 	int		dtype; | ||||||
|  | 	int		varno; | ||||||
|  | 	char		*refname; | ||||||
|  | 	int		lineno; | ||||||
|  |  | ||||||
|  | 	PLpgSQL_type	*datatype; | ||||||
|  | 	int		isconst; | ||||||
|  | 	int		notnull; | ||||||
|  | 	PLpgSQL_expr	*default_val; | ||||||
|  |  | ||||||
|  | 	Datum		value; | ||||||
|  | 	bool		isnull; | ||||||
|  | 	int		shouldfree; | ||||||
|  | } PLpgSQL_var; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Rowtype				*/ | ||||||
|  | 	int		dtype; | ||||||
|  | 	int		rowno; | ||||||
|  | 	char		*refname; | ||||||
|  | 	int		lineno; | ||||||
|  | 	Oid		rowtypeclass; | ||||||
|  |  | ||||||
|  | 	int		nfields; | ||||||
|  | 	char		**fieldnames; | ||||||
|  | 	int		*varnos; | ||||||
|  | } PLpgSQL_row; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Record of undefined structure	*/ | ||||||
|  | 	int		dtype; | ||||||
|  | 	int		recno; | ||||||
|  | 	char		*refname; | ||||||
|  | 	int		lineno; | ||||||
|  |  | ||||||
|  | 	HeapTuple	tup; | ||||||
|  | 	TupleDesc	tupdesc; | ||||||
|  | } PLpgSQL_rec; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Field in record			*/ | ||||||
|  | 	int		dtype; | ||||||
|  | 	int		rfno; | ||||||
|  | 	char		*fieldname; | ||||||
|  | 	int		recno; | ||||||
|  | } PLpgSQL_recfield; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Positional argument to trigger	*/ | ||||||
|  | 	int		dtype; | ||||||
|  | 	int		dno; | ||||||
|  | 	PLpgSQL_expr	*argnum; | ||||||
|  | } PLpgSQL_trigarg; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Item in the compilers namestack	*/ | ||||||
|  | 	int		itemtype; | ||||||
|  | 	int		itemno; | ||||||
|  | 	char		name[1]; | ||||||
|  | } PLpgSQL_nsitem; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct PLpgSQL_ns {	/* Compiler namestack level		*/ | ||||||
|  | 	int		items_alloc; | ||||||
|  | 	int		items_used; | ||||||
|  | 	PLpgSQL_nsitem	**items; | ||||||
|  | 	struct PLpgSQL_ns *upper; | ||||||
|  | } PLpgSQL_ns; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* List of execution nodes		*/ | ||||||
|  | 	int		stmts_alloc; | ||||||
|  | 	int		stmts_used; | ||||||
|  | 	struct PLpgSQL_stmt	**stmts; | ||||||
|  | } PLpgSQL_stmts; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Generic execution node		*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | } PLpgSQL_stmt; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Block of statements			*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	char		*label; | ||||||
|  | 	PLpgSQL_stmts	*body; | ||||||
|  | 	int		n_initvars; | ||||||
|  | 	int		*initvarnos; | ||||||
|  | } PLpgSQL_stmt_block; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Assign statement			*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	int		varno; | ||||||
|  | 	PLpgSQL_expr	*expr; | ||||||
|  | } PLpgSQL_stmt_assign; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* IF statement				*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	PLpgSQL_expr	*cond; | ||||||
|  | 	PLpgSQL_stmts	*true_body; | ||||||
|  | 	PLpgSQL_stmts	*false_body; | ||||||
|  | } PLpgSQL_stmt_if; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Unconditional LOOP statement		*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	char		*label; | ||||||
|  | 	PLpgSQL_stmts	*body; | ||||||
|  | } PLpgSQL_stmt_loop; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* WHILE cond LOOP statement		*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	char		*label; | ||||||
|  | 	PLpgSQL_expr	*cond; | ||||||
|  | 	PLpgSQL_stmts	*body; | ||||||
|  | } PLpgSQL_stmt_while; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* FOR statement with integer loopvar	*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	char		*label; | ||||||
|  | 	PLpgSQL_var	*var; | ||||||
|  | 	PLpgSQL_expr	*lower; | ||||||
|  | 	PLpgSQL_expr	*upper; | ||||||
|  | 	int		reverse; | ||||||
|  | 	PLpgSQL_stmts	*body; | ||||||
|  | } PLpgSQL_stmt_fori; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* FOR statement running over SELECT	*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	char		*label; | ||||||
|  | 	PLpgSQL_rec	*rec; | ||||||
|  | 	PLpgSQL_row	*row; | ||||||
|  | 	PLpgSQL_expr	*query; | ||||||
|  | 	PLpgSQL_stmts	*body; | ||||||
|  | } PLpgSQL_stmt_fors; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* SELECT ... INTO statement		*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	PLpgSQL_rec	*rec; | ||||||
|  | 	PLpgSQL_row	*row; | ||||||
|  | 	PLpgSQL_expr	*query; | ||||||
|  | } PLpgSQL_stmt_select; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* EXIT statement			*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	char		*label; | ||||||
|  | 	PLpgSQL_expr	*cond; | ||||||
|  | } PLpgSQL_stmt_exit; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* RETURN statement			*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	bool		retistuple; | ||||||
|  | 	PLpgSQL_expr	*expr; | ||||||
|  | 	int		retrecno; | ||||||
|  | } PLpgSQL_stmt_return; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* RAISE statement			*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	int		elog_level; | ||||||
|  | 	char		*message; | ||||||
|  | 	int		nparams; | ||||||
|  | 	int		*params; | ||||||
|  | } PLpgSQL_stmt_raise; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {		/* Generic SQL statement to execute	*/ | ||||||
|  | 	int		cmd_type; | ||||||
|  | 	int		lineno; | ||||||
|  | 	PLpgSQL_expr	*sqlstmt; | ||||||
|  | } PLpgSQL_stmt_execsql; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct PLpgSQL_function { /* Complete compiled function		*/ | ||||||
|  | 	Oid			fn_oid; | ||||||
|  | 	char			*fn_name; | ||||||
|  | 	int			fn_functype; | ||||||
|  | 	Oid			fn_rettype; | ||||||
|  | 	int			fn_rettyplen; | ||||||
|  | 	bool			fn_retbyval; | ||||||
|  | 	FmgrInfo		fn_retinput; | ||||||
|  | 	bool			fn_retistuple; | ||||||
|  | 	bool			fn_retset; | ||||||
|  |  | ||||||
|  | 	int			fn_nargs; | ||||||
|  | 	int			fn_argvarnos[MAXFMGRARGS]; | ||||||
|  | 	int			found_varno; | ||||||
|  | 	int			new_varno; | ||||||
|  | 	int			old_varno; | ||||||
|  | 	int			tg_name_varno; | ||||||
|  | 	int			tg_when_varno; | ||||||
|  | 	int			tg_level_varno; | ||||||
|  | 	int			tg_op_varno; | ||||||
|  | 	int			tg_relid_varno; | ||||||
|  | 	int			tg_relname_varno; | ||||||
|  | 	int			tg_nargs_varno; | ||||||
|  |  | ||||||
|  | 	int			ndatums; | ||||||
|  | 	PLpgSQL_datum		**datums; | ||||||
|  | 	PLpgSQL_stmt_block	*action; | ||||||
|  | 	struct PLpgSQL_function	*next; | ||||||
|  | } PLpgSQL_function; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct {			/* Runtime execution data	*/ | ||||||
|  | 	Datum			retval; | ||||||
|  | 	bool			retisnull; | ||||||
|  | 	Oid			rettype; | ||||||
|  | 	bool			retistuple; | ||||||
|  | 	TupleDesc		rettupdesc; | ||||||
|  | 	bool			retisset; | ||||||
|  | 	char			*exitlabel; | ||||||
|  |  | ||||||
|  | 	int			trig_nargs; | ||||||
|  | 	Datum			*trig_argv; | ||||||
|  |  | ||||||
|  | 	int			found_varno; | ||||||
|  | 	int			ndatums; | ||||||
|  | 	PLpgSQL_datum		**datums; | ||||||
|  | } PLpgSQL_execstate; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /********************************************************************** | ||||||
|  |  * Global variable declarations | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  | extern	int		plpgsql_DumpExecTree; | ||||||
|  | extern	int		plpgsql_SpaceScanned; | ||||||
|  | extern	int		plpgsql_nDatums; | ||||||
|  | extern	PLpgSQL_datum	**plpgsql_Datums; | ||||||
|  |  | ||||||
|  | extern	int		plpgsql_error_lineno; | ||||||
|  | extern	char		*plpgsql_error_funcname; | ||||||
|  |  | ||||||
|  | extern	PLpgSQL_function *plpgsql_curr_compile; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /********************************************************************** | ||||||
|  |  * Function declarations | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | extern	char *pstrdup(char *s); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Functions in pl_comp.c | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | extern	PLpgSQL_function *plpgsql_compile(Oid fn_oid, int functype); | ||||||
|  | extern	int plpgsql_parse_word(char *word); | ||||||
|  | extern	int plpgsql_parse_dblword(char *string); | ||||||
|  | extern	int plpgsql_parse_tripword(char *string); | ||||||
|  | extern	int plpgsql_parse_wordtype(char *string); | ||||||
|  | extern	int plpgsql_parse_dblwordtype(char *string); | ||||||
|  | extern	int plpgsql_parse_wordrowtype(char *string); | ||||||
|  | extern	void plpgsql_adddatum(PLpgSQL_datum *new); | ||||||
|  | extern	int plpgsql_add_initdatums(int **varnos); | ||||||
|  | extern	void plpgsql_comperrinfo(void); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Functions in pl_exec.c | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | extern	Datum plpgsql_exec_function(PLpgSQL_function *func,  | ||||||
|  | 			FmgrValues *args, bool *isNull); | ||||||
|  | extern	HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func,  | ||||||
|  | 			TriggerData *trigdata); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Functions for the dynamic string handling in pl_funcs.c | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | extern	void plpgsql_dstring_init(PLpgSQL_dstring *ds); | ||||||
|  | extern	void plpgsql_dstring_free(PLpgSQL_dstring *ds); | ||||||
|  | extern	void plpgsql_dstring_append(PLpgSQL_dstring *ds, char *str); | ||||||
|  | extern	char *plpgsql_dstring_get(PLpgSQL_dstring *ds); | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Functions for the namestack handling in pl_funcs.c | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | extern	void plpgsql_ns_init(void); | ||||||
|  | extern	bool plpgsql_ns_setlocal(bool flag); | ||||||
|  | extern	void plpgsql_ns_push(char *label); | ||||||
|  | extern	void plpgsql_ns_pop(void); | ||||||
|  | extern	void plpgsql_ns_additem(int itemtype, int itemno, char *name); | ||||||
|  | extern	PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *nsname); | ||||||
|  | extern	void plpgsql_ns_rename(char *oldname, char *newname); | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Other functions in pl_funcs.c | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | extern	void plpgsql_dumptree(PLpgSQL_function *func); | ||||||
|  | extern	char *plpgsql_tolower(char *s); | ||||||
|  |  | ||||||
|  | /* ---------- | ||||||
|  |  * Externs in gram.y and scan.l | ||||||
|  |  * ---------- | ||||||
|  |  */ | ||||||
|  | extern	PLpgSQL_expr *plpgsql_read_expression(int until, char *s); | ||||||
|  | extern	void plpgsql_yyrestart(FILE *fp); | ||||||
|  | extern	int plpgsql_yylex(); | ||||||
|  | extern	void plpgsql_setinput(char *s, int functype); | ||||||
|  | extern	int plpgsql_yyparse(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif /* PLPGSQL_H */ | ||||||
							
								
								
									
										227
									
								
								contrib/plpgsql/src/scan.l
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								contrib/plpgsql/src/scan.l
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | |||||||
|  | %{ | ||||||
|  | /********************************************************************** | ||||||
|  |  * scan.l		- Scanner for the PL/pgSQL | ||||||
|  |  *			  procedural language | ||||||
|  |  * | ||||||
|  |  * IDENTIFICATION | ||||||
|  |  *    $Header: /cvsroot/pgsql/contrib/plpgsql/src/Attic/scan.l,v 1.1 1998/08/22 12:38:33 momjian Exp $ | ||||||
|  |  * | ||||||
|  |  *    This software is copyrighted by Jan Wieck - Hamburg. | ||||||
|  |  * | ||||||
|  |  *    The author hereby grants permission  to  use,  copy,  modify, | ||||||
|  |  *    distribute,  and  license this software and its documentation | ||||||
|  |  *    for any purpose, provided that existing copyright notices are | ||||||
|  |  *    retained  in  all  copies  and  that  this notice is included | ||||||
|  |  *    verbatim in any distributions. No written agreement, license, | ||||||
|  |  *    or  royalty  fee  is required for any of the authorized uses. | ||||||
|  |  *    Modifications to this software may be  copyrighted  by  their | ||||||
|  |  *    author  and  need  not  follow  the licensing terms described | ||||||
|  |  *    here, provided that the new terms are  clearly  indicated  on | ||||||
|  |  *    the first page of each file where they apply. | ||||||
|  |  * | ||||||
|  |  *    IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY | ||||||
|  |  *    PARTY  FOR  DIRECT,   INDIRECT,   SPECIAL,   INCIDENTAL,   OR | ||||||
|  |  *    CONSEQUENTIAL   DAMAGES  ARISING  OUT  OF  THE  USE  OF  THIS | ||||||
|  |  *    SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN | ||||||
|  |  *    IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH | ||||||
|  |  *    DAMAGE. | ||||||
|  |  * | ||||||
|  |  *    THE  AUTHOR  AND  DISTRIBUTORS  SPECIFICALLY   DISCLAIM   ANY | ||||||
|  |  *    WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED | ||||||
|  |  *    WARRANTIES  OF  MERCHANTABILITY,  FITNESS  FOR  A  PARTICULAR | ||||||
|  |  *    PURPOSE,  AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON | ||||||
|  |  *    AN "AS IS" BASIS, AND THE AUTHOR  AND  DISTRIBUTORS  HAVE  NO | ||||||
|  |  *    OBLIGATION   TO   PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES, | ||||||
|  |  *    ENHANCEMENTS, OR MODIFICATIONS. | ||||||
|  |  * | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  | static char	*plpgsql_source; | ||||||
|  | static int	plpgsql_bytes_left; | ||||||
|  | static int	scanner_functype; | ||||||
|  | static int	scanner_typereported; | ||||||
|  | int	plpgsql_SpaceScanned = 0; | ||||||
|  |  | ||||||
|  | static void plpgsql_input(char *buf, int *result, int max); | ||||||
|  | #define YY_INPUT(buf,res,max)	plpgsql_input(buf, &res, max) | ||||||
|  | %} | ||||||
|  |  | ||||||
|  | WS	[[:alpha:]_] | ||||||
|  | WC	[[:alnum:]_] | ||||||
|  |  | ||||||
|  | %x	IN_STRING IN_COMMENT | ||||||
|  |  | ||||||
|  | %% | ||||||
|  |     /* ---------- | ||||||
|  |      * Local variable in scanner to remember where | ||||||
|  |      * a string or comment started | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     int	start_lineno = 0; | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Reset the state when entering the scanner | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     BEGIN INITIAL; | ||||||
|  |     plpgsql_SpaceScanned = 0; | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * On the first call to a new source report the | ||||||
|  |      * functions type (T_FUNCTION or T_TRIGGER) | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  |     if (!scanner_typereported) { | ||||||
|  |         scanner_typereported = 1; | ||||||
|  | 	return scanner_functype; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * The keyword rules | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  | :=			{ return K_ASSIGN;			} | ||||||
|  | =			{ return K_ASSIGN;			} | ||||||
|  | \.\.			{ return K_DOTDOT;			} | ||||||
|  | alias			{ return K_ALIAS;			} | ||||||
|  | begin			{ return K_BEGIN;			} | ||||||
|  | bpchar			{ return T_BPCHAR;			} | ||||||
|  | char			{ return T_CHAR;			} | ||||||
|  | constant		{ return K_CONSTANT;			} | ||||||
|  | debug			{ return K_DEBUG;			} | ||||||
|  | declare			{ return K_DECLARE;			} | ||||||
|  | default			{ return K_DEFAULT;			} | ||||||
|  | else			{ return K_ELSE;			} | ||||||
|  | end			{ return K_END;				} | ||||||
|  | exception		{ return K_EXCEPTION;			} | ||||||
|  | exit			{ return K_EXIT;			} | ||||||
|  | for			{ return K_FOR;				} | ||||||
|  | from			{ return K_FROM;			} | ||||||
|  | if			{ return K_IF;				} | ||||||
|  | in			{ return K_IN;				} | ||||||
|  | into			{ return K_INTO;			} | ||||||
|  | loop			{ return K_LOOP;			} | ||||||
|  | not			{ return K_NOT;				} | ||||||
|  | notice			{ return K_NOTICE;			} | ||||||
|  | null			{ return K_NULL;			} | ||||||
|  | perform			{ return K_PERFORM;			} | ||||||
|  | raise			{ return K_RAISE;			} | ||||||
|  | record			{ return K_RECORD;			} | ||||||
|  | rename			{ return K_RENAME;			} | ||||||
|  | return			{ return K_RETURN;			} | ||||||
|  | reverse			{ return K_REVERSE;			} | ||||||
|  | select			{ return K_SELECT;			} | ||||||
|  | then			{ return K_THEN;			} | ||||||
|  | to			{ return K_TO;				} | ||||||
|  | type			{ return K_TYPE;			} | ||||||
|  | varchar			{ return T_VARCHAR;			} | ||||||
|  | when			{ return K_WHEN;			} | ||||||
|  | while			{ return K_WHILE;			} | ||||||
|  |  | ||||||
|  | ^#option		{ return O_OPTION;			} | ||||||
|  | dump			{ return O_DUMP;			} | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Special word rules | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  | {WS}{WC}*		{ return plpgsql_parse_word(yytext);	} | ||||||
|  | {WS}{WC}*\.{WS}{WC}*	{ return plpgsql_parse_dblword(yytext);	} | ||||||
|  | {WS}{WC}*\.{WS}{WC}*\.{WS}{WC}*	{ return plpgsql_parse_tripword(yytext); } | ||||||
|  | {WS}{WC}*%TYPE		{ return plpgsql_parse_wordtype(yytext);	} | ||||||
|  | {WS}{WC}*\.{WS}{WC}*%TYPE	{ return plpgsql_parse_dblwordtype(yytext); } | ||||||
|  | {WS}{WC}*%ROWTYPE	{ return plpgsql_parse_wordrowtype(yytext);	} | ||||||
|  |  | ||||||
|  | \$[0-9]+		{ return plpgsql_parse_word(yytext);	} | ||||||
|  | [0-9]+			{ return T_NUMBER;			} | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Ignore whitespaces but remember this happened | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  | [ \t\n]+		{ plpgsql_SpaceScanned = 1;		} | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Eat up comments | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  | --[^\n]*		; | ||||||
|  | \/\*			{ start_lineno = yylineno; | ||||||
|  | 			  BEGIN IN_COMMENT; | ||||||
|  | 			} | ||||||
|  | <IN_COMMENT>\*\/	{ BEGIN INITIAL;			} | ||||||
|  | <IN_COMMENT>\n		; | ||||||
|  | <IN_COMMENT>.		; | ||||||
|  | <IN_COMMENT><<EOF>>	{ plpgsql_comperrinfo(); | ||||||
|  | 			  elog(ERROR, "unterminated comment starting on line %d", | ||||||
|  | 				start_lineno); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Collect anything inside of ''s and return one STRING | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  | '			{ start_lineno = yylineno; | ||||||
|  | 			  BEGIN IN_STRING; | ||||||
|  | 			  yymore(); | ||||||
|  | 			} | ||||||
|  | <IN_STRING>\\.		| | ||||||
|  | <IN_STRING>''		{ yymore();				} | ||||||
|  | <IN_STRING>'		{ BEGIN INITIAL; | ||||||
|  | 			  return T_STRING; | ||||||
|  | 			} | ||||||
|  | <IN_STRING><<EOF>>	{ plpgsql_comperrinfo(); | ||||||
|  | 			  elog(ERROR, "unterminated string starting on line %d",  | ||||||
|  | 				start_lineno); | ||||||
|  | 			} | ||||||
|  | <IN_STRING>[^'\\]*	{ yymore();				} | ||||||
|  |  | ||||||
|  |     /* ---------- | ||||||
|  |      * Any unmatched character is returned as is | ||||||
|  |      * ---------- | ||||||
|  |      */ | ||||||
|  | .			{ return yytext[0];			} | ||||||
|  |  | ||||||
|  | %% | ||||||
|  |  | ||||||
|  | int yywrap() | ||||||
|  | { | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void plpgsql_input(char *buf, int *result, int max) | ||||||
|  | { | ||||||
|  |     int n = max; | ||||||
|  |     if (n > plpgsql_bytes_left) { | ||||||
|  |         n = plpgsql_bytes_left; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (n == 0) { | ||||||
|  |         *result = YY_NULL; | ||||||
|  | 	return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *result = n; | ||||||
|  |     memcpy(buf, plpgsql_source, n); | ||||||
|  |     plpgsql_source += n; | ||||||
|  |     plpgsql_bytes_left -= n; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void plpgsql_setinput(char *source, int functype) | ||||||
|  | { | ||||||
|  |     yyrestart(NULL); | ||||||
|  |     yylineno = 1; | ||||||
|  |  | ||||||
|  |     plpgsql_source = source; | ||||||
|  |     if (*plpgsql_source == '\n') | ||||||
|  |         plpgsql_source++; | ||||||
|  |     plpgsql_bytes_left = strlen(plpgsql_source); | ||||||
|  |  | ||||||
|  |     scanner_functype     = functype; | ||||||
|  |     scanner_typereported = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								contrib/plpgsql/test/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								contrib/plpgsql/test/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | Test suite for PL/pgSQL | ||||||
|  |  | ||||||
|  | Scenario: | ||||||
|  |  | ||||||
|  |     A building with a modern TP cabel installation where any | ||||||
|  |     of the wall connectors can be used to plug in phones, | ||||||
|  |     ethernet interfaces or local office hubs. The backside | ||||||
|  |     of the wall connectors is wired to one of several patch- | ||||||
|  |     fields in the building. | ||||||
|  |  | ||||||
|  |     In the patchfields, there are hubs and all the slots | ||||||
|  |     representing the wall connectors. In addition there are | ||||||
|  |     slots that can represent a phone line from the central | ||||||
|  |     phone system. | ||||||
|  |  | ||||||
|  |     Triggers ensure consistency of the patching information. | ||||||
|  |  | ||||||
|  |     Functions are used to build up powerful views that let | ||||||
|  |     you look behind the wall when looking at a patchfield | ||||||
|  |     or into a room. | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										63
									
								
								contrib/plpgsql/test/expected/tables.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								contrib/plpgsql/test/expected/tables.out
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | QUERY: create table Room ( | ||||||
|  |     roomno	char(8), | ||||||
|  |     comment	text | ||||||
|  | ); | ||||||
|  | QUERY: create unique index Room_rno on Room using btree (roomno bpchar_ops); | ||||||
|  | QUERY: create table WSlot ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     roomno	char(8), | ||||||
|  |     slotlink	char(20), | ||||||
|  |     backlink	char(20) | ||||||
|  | ); | ||||||
|  | QUERY: create unique index WSlot_name on WSlot using btree (slotname bpchar_ops); | ||||||
|  | QUERY: create table PField ( | ||||||
|  |     name	text, | ||||||
|  |     comment	text | ||||||
|  | ); | ||||||
|  | QUERY: create unique index PField_name on PField using btree (name text_ops); | ||||||
|  | QUERY: create table PSlot ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     pfname	text, | ||||||
|  |     slotlink	char(20), | ||||||
|  |     backlink	char(20) | ||||||
|  | ); | ||||||
|  | QUERY: create unique index PSlot_name on PSlot using btree (slotname bpchar_ops); | ||||||
|  | QUERY: create table PLine ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     phonenumber	char(20), | ||||||
|  |     comment	text, | ||||||
|  |     backlink	char(20) | ||||||
|  | ); | ||||||
|  | QUERY: create unique index PLine_name on PLine using btree (slotname bpchar_ops); | ||||||
|  | QUERY: create table Hub ( | ||||||
|  |     name	char(14), | ||||||
|  |     comment	text, | ||||||
|  |     nslots	integer | ||||||
|  | ); | ||||||
|  | QUERY: create unique index Hub_name on Hub using btree (name bpchar_ops); | ||||||
|  | QUERY: create table HSlot ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     hubname	char(14), | ||||||
|  |     slotno	integer, | ||||||
|  |     slotlink	char(20) | ||||||
|  | ); | ||||||
|  | QUERY: create unique index HSlot_name on HSlot using btree (slotname bpchar_ops); | ||||||
|  | QUERY: create index HSlot_hubname on HSlot using btree (hubname bpchar_ops); | ||||||
|  | QUERY: create table System ( | ||||||
|  |     name	text, | ||||||
|  |     comment	text | ||||||
|  | ); | ||||||
|  | QUERY: create unique index System_name on System using btree (name text_ops); | ||||||
|  | QUERY: create table IFace ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     sysname	text, | ||||||
|  |     ifname	text, | ||||||
|  |     slotlink	char(20) | ||||||
|  | ); | ||||||
|  | QUERY: create unique index IFace_name on IFace using btree (slotname bpchar_ops); | ||||||
|  | QUERY: create table PHone ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     comment	text, | ||||||
|  |     slotlink	char(20) | ||||||
|  | ); | ||||||
|  | QUERY: create unique index PHone_name on PHone using btree (slotname bpchar_ops); | ||||||
							
								
								
									
										473
									
								
								contrib/plpgsql/test/expected/test.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										473
									
								
								contrib/plpgsql/test/expected/test.out
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,473 @@ | |||||||
|  | QUERY: insert into Room values ('001', 'Entrance'); | ||||||
|  | QUERY: insert into Room values ('002', 'Office'); | ||||||
|  | QUERY: insert into Room values ('003', 'Office'); | ||||||
|  | QUERY: insert into Room values ('004', 'Technical'); | ||||||
|  | QUERY: insert into Room values ('101', 'Office'); | ||||||
|  | QUERY: insert into Room values ('102', 'Conference'); | ||||||
|  | QUERY: insert into Room values ('103', 'Restroom'); | ||||||
|  | QUERY: insert into Room values ('104', 'Technical'); | ||||||
|  | QUERY: insert into Room values ('105', 'Office'); | ||||||
|  | QUERY: insert into Room values ('106', 'Office'); | ||||||
|  | QUERY: insert into WSlot values ('WS.001.1a', '001', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.001.1b', '001', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.001.2a', '001', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.001.2b', '001', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.001.3a', '001', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.001.3b', '001', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.002.1a', '002', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.002.1b', '002', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.002.2a', '002', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.002.2b', '002', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.002.3a', '002', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.002.3b', '002', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.003.1a', '003', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.003.1b', '003', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.003.2a', '003', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.003.2b', '003', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.003.3a', '003', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.003.3b', '003', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.101.1a', '101', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.101.1b', '101', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.101.2a', '101', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.101.2b', '101', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.101.3a', '101', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.101.3b', '101', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.102.1a', '102', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.102.1b', '102', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.102.2a', '102', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.102.2b', '102', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.102.3a', '102', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.102.3b', '102', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.105.1a', '105', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.105.1b', '105', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.105.2a', '105', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.105.2b', '105', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.105.3a', '105', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.105.3b', '105', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.106.1a', '106', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.106.1b', '106', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.106.2a', '106', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.106.2b', '106', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.106.3a', '106', '', ''); | ||||||
|  | QUERY: insert into WSlot values ('WS.106.3b', '106', '', ''); | ||||||
|  | QUERY: insert into PField values ('PF0_1', 'Wallslots basement'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.a1', 'PF0_1', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.a2', 'PF0_1', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.a3', 'PF0_1', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.a4', 'PF0_1', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.a5', 'PF0_1', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.a6', 'PF0_1', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.b1', 'PF0_1', '', 'WS.002.1a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.b2', 'PF0_1', '', 'WS.002.1b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.b3', 'PF0_1', '', 'WS.002.2a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.b4', 'PF0_1', '', 'WS.002.2b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.b5', 'PF0_1', '', 'WS.002.3a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.b6', 'PF0_1', '', 'WS.002.3b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.c1', 'PF0_1', '', 'WS.003.1a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.c2', 'PF0_1', '', 'WS.003.1b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.c3', 'PF0_1', '', 'WS.003.2a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.c4', 'PF0_1', '', 'WS.003.2b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.c5', 'PF0_1', '', 'WS.003.3a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.c6', 'PF0_1', '', 'WS.003.3b'); | ||||||
|  | QUERY: insert into PField values ('PF0_X', 'Phonelines basement'); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.ta1', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.ta2', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.ta3', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.ta4', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.ta5', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.ta6', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.tb1', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.tb2', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.tb3', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.tb4', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.tb5', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.base.tb6', 'PF0_X', '', ''); | ||||||
|  | QUERY: insert into PField values ('PF1_1', 'Wallslots 1st floor'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.a1', 'PF1_1', '', 'WS.101.1a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.a2', 'PF1_1', '', 'WS.101.1b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.a3', 'PF1_1', '', 'WS.101.2a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.a4', 'PF1_1', '', 'WS.101.2b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.a5', 'PF1_1', '', 'WS.101.3a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.a6', 'PF1_1', '', 'WS.101.3b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.b1', 'PF1_1', '', 'WS.102.1a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.b2', 'PF1_1', '', 'WS.102.1b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.b3', 'PF1_1', '', 'WS.102.2a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.b4', 'PF1_1', '', 'WS.102.2b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.b5', 'PF1_1', '', 'WS.102.3a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.b6', 'PF1_1', '', 'WS.102.3b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.c1', 'PF1_1', '', 'WS.105.1a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.c2', 'PF1_1', '', 'WS.105.1b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.c3', 'PF1_1', '', 'WS.105.2a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.c4', 'PF1_1', '', 'WS.105.2b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.c5', 'PF1_1', '', 'WS.105.3a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.c6', 'PF1_1', '', 'WS.105.3b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.d1', 'PF1_1', '', 'WS.106.1a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.d2', 'PF1_1', '', 'WS.106.1b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.d3', 'PF1_1', '', 'WS.106.2a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.d4', 'PF1_1', '', 'WS.106.2b'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.d5', 'PF1_1', '', 'WS.106.3a'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.d6', 'PF1_1', '', 'WS.106.3b'); | ||||||
|  | QUERY: update PSlot set backlink = 'WS.001.1a' where slotname = 'PS.base.a1'; | ||||||
|  | QUERY: update PSlot set backlink = 'WS.001.1b' where slotname = 'PS.base.a3'; | ||||||
|  | QUERY: select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | slotname            |  roomno|            slotlink|backlink             | ||||||
|  | --------------------+--------+--------------------+-------------------- | ||||||
|  | WS.001.1a           |001     |                    |PS.base.a1           | ||||||
|  | WS.001.1b           |001     |                    |PS.base.a3           | ||||||
|  | WS.001.2a           |001     |                    |                     | ||||||
|  | WS.001.2b           |001     |                    |                     | ||||||
|  | WS.001.3a           |001     |                    |                     | ||||||
|  | WS.001.3b           |001     |                    |                     | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | slotname            |pfname|            slotlink|backlink             | ||||||
|  | --------------------+------+--------------------+-------------------- | ||||||
|  | PS.base.a1          |PF0_1 |                    |WS.001.1a            | ||||||
|  | PS.base.a2          |PF0_1 |                    |                     | ||||||
|  | PS.base.a3          |PF0_1 |                    |WS.001.1b            | ||||||
|  | PS.base.a4          |PF0_1 |                    |                     | ||||||
|  | PS.base.a5          |PF0_1 |                    |                     | ||||||
|  | PS.base.a6          |PF0_1 |                    |                     | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: update PSlot set backlink = 'WS.001.2a' where slotname = 'PS.base.a3'; | ||||||
|  | QUERY: select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | slotname            |  roomno|            slotlink|backlink             | ||||||
|  | --------------------+--------+--------------------+-------------------- | ||||||
|  | WS.001.1a           |001     |                    |PS.base.a1           | ||||||
|  | WS.001.1b           |001     |                    |                     | ||||||
|  | WS.001.2a           |001     |                    |PS.base.a3           | ||||||
|  | WS.001.2b           |001     |                    |                     | ||||||
|  | WS.001.3a           |001     |                    |                     | ||||||
|  | WS.001.3b           |001     |                    |                     | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | slotname            |pfname|            slotlink|backlink             | ||||||
|  | --------------------+------+--------------------+-------------------- | ||||||
|  | PS.base.a1          |PF0_1 |                    |WS.001.1a            | ||||||
|  | PS.base.a2          |PF0_1 |                    |                     | ||||||
|  | PS.base.a3          |PF0_1 |                    |WS.001.2a            | ||||||
|  | PS.base.a4          |PF0_1 |                    |                     | ||||||
|  | PS.base.a5          |PF0_1 |                    |                     | ||||||
|  | PS.base.a6          |PF0_1 |                    |                     | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: update PSlot set backlink = 'WS.001.1b' where slotname = 'PS.base.a2'; | ||||||
|  | QUERY: select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | slotname            |  roomno|            slotlink|backlink             | ||||||
|  | --------------------+--------+--------------------+-------------------- | ||||||
|  | WS.001.1a           |001     |                    |PS.base.a1           | ||||||
|  | WS.001.1b           |001     |                    |PS.base.a2           | ||||||
|  | WS.001.2a           |001     |                    |PS.base.a3           | ||||||
|  | WS.001.2b           |001     |                    |                     | ||||||
|  | WS.001.3a           |001     |                    |                     | ||||||
|  | WS.001.3b           |001     |                    |                     | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | slotname            |pfname|            slotlink|backlink             | ||||||
|  | --------------------+------+--------------------+-------------------- | ||||||
|  | PS.base.a1          |PF0_1 |                    |WS.001.1a            | ||||||
|  | PS.base.a2          |PF0_1 |                    |WS.001.1b            | ||||||
|  | PS.base.a3          |PF0_1 |                    |WS.001.2a            | ||||||
|  | PS.base.a4          |PF0_1 |                    |                     | ||||||
|  | PS.base.a5          |PF0_1 |                    |                     | ||||||
|  | PS.base.a6          |PF0_1 |                    |                     | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: update WSlot set backlink = 'PS.base.a4' where slotname = 'WS.001.2b'; | ||||||
|  | QUERY: update WSlot set backlink = 'PS.base.a6' where slotname = 'WS.001.3a'; | ||||||
|  | QUERY: select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | slotname            |  roomno|            slotlink|backlink             | ||||||
|  | --------------------+--------+--------------------+-------------------- | ||||||
|  | WS.001.1a           |001     |                    |PS.base.a1           | ||||||
|  | WS.001.1b           |001     |                    |PS.base.a2           | ||||||
|  | WS.001.2a           |001     |                    |PS.base.a3           | ||||||
|  | WS.001.2b           |001     |                    |PS.base.a4           | ||||||
|  | WS.001.3a           |001     |                    |PS.base.a6           | ||||||
|  | WS.001.3b           |001     |                    |                     | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | slotname            |pfname|            slotlink|backlink             | ||||||
|  | --------------------+------+--------------------+-------------------- | ||||||
|  | PS.base.a1          |PF0_1 |                    |WS.001.1a            | ||||||
|  | PS.base.a2          |PF0_1 |                    |WS.001.1b            | ||||||
|  | PS.base.a3          |PF0_1 |                    |WS.001.2a            | ||||||
|  | PS.base.a4          |PF0_1 |                    |WS.001.2b            | ||||||
|  | PS.base.a5          |PF0_1 |                    |                     | ||||||
|  | PS.base.a6          |PF0_1 |                    |WS.001.3a            | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: update WSlot set backlink = 'PS.base.a6' where slotname = 'WS.001.3b'; | ||||||
|  | QUERY: select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | slotname            |  roomno|            slotlink|backlink             | ||||||
|  | --------------------+--------+--------------------+-------------------- | ||||||
|  | WS.001.1a           |001     |                    |PS.base.a1           | ||||||
|  | WS.001.1b           |001     |                    |PS.base.a2           | ||||||
|  | WS.001.2a           |001     |                    |PS.base.a3           | ||||||
|  | WS.001.2b           |001     |                    |PS.base.a4           | ||||||
|  | WS.001.3a           |001     |                    |                     | ||||||
|  | WS.001.3b           |001     |                    |PS.base.a6           | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | slotname            |pfname|            slotlink|backlink             | ||||||
|  | --------------------+------+--------------------+-------------------- | ||||||
|  | PS.base.a1          |PF0_1 |                    |WS.001.1a            | ||||||
|  | PS.base.a2          |PF0_1 |                    |WS.001.1b            | ||||||
|  | PS.base.a3          |PF0_1 |                    |WS.001.2a            | ||||||
|  | PS.base.a4          |PF0_1 |                    |WS.001.2b            | ||||||
|  | PS.base.a5          |PF0_1 |                    |                     | ||||||
|  | PS.base.a6          |PF0_1 |                    |WS.001.3b            | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: update WSlot set backlink = 'PS.base.a5' where slotname = 'WS.001.3a'; | ||||||
|  | QUERY: select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | slotname            |  roomno|            slotlink|backlink             | ||||||
|  | --------------------+--------+--------------------+-------------------- | ||||||
|  | WS.001.1a           |001     |                    |PS.base.a1           | ||||||
|  | WS.001.1b           |001     |                    |PS.base.a2           | ||||||
|  | WS.001.2a           |001     |                    |PS.base.a3           | ||||||
|  | WS.001.2b           |001     |                    |PS.base.a4           | ||||||
|  | WS.001.3a           |001     |                    |PS.base.a5           | ||||||
|  | WS.001.3b           |001     |                    |PS.base.a6           | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | slotname            |pfname|            slotlink|backlink             | ||||||
|  | --------------------+------+--------------------+-------------------- | ||||||
|  | PS.base.a1          |PF0_1 |                    |WS.001.1a            | ||||||
|  | PS.base.a2          |PF0_1 |                    |WS.001.1b            | ||||||
|  | PS.base.a3          |PF0_1 |                    |WS.001.2a            | ||||||
|  | PS.base.a4          |PF0_1 |                    |WS.001.2b            | ||||||
|  | PS.base.a5          |PF0_1 |                    |WS.001.3a            | ||||||
|  | PS.base.a6          |PF0_1 |                    |WS.001.3b            | ||||||
|  | (6 rows) | ||||||
|  |  | ||||||
|  | QUERY: insert into PField values ('PF1_2', 'Phonelines 1st floor'); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.ta1', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.ta2', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.ta3', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.ta4', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.ta5', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.ta6', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.tb1', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.tb2', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.tb3', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.tb4', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.tb5', 'PF1_2', '', ''); | ||||||
|  | QUERY: insert into PSlot values ('PS.1st.tb6', 'PF1_2', '', ''); | ||||||
|  | QUERY: update PField set name = 'PF0_2' where name = 'PF0_X'; | ||||||
|  | QUERY: select * from PSlot order by slotname; | ||||||
|  | slotname            |pfname|            slotlink|backlink             | ||||||
|  | --------------------+------+--------------------+-------------------- | ||||||
|  | PS.1st.a1           |PF1_1 |                    |WS.101.1a            | ||||||
|  | PS.1st.a2           |PF1_1 |                    |WS.101.1b            | ||||||
|  | PS.1st.a3           |PF1_1 |                    |WS.101.2a            | ||||||
|  | PS.1st.a4           |PF1_1 |                    |WS.101.2b            | ||||||
|  | PS.1st.a5           |PF1_1 |                    |WS.101.3a            | ||||||
|  | PS.1st.a6           |PF1_1 |                    |WS.101.3b            | ||||||
|  | PS.1st.b1           |PF1_1 |                    |WS.102.1a            | ||||||
|  | PS.1st.b2           |PF1_1 |                    |WS.102.1b            | ||||||
|  | PS.1st.b3           |PF1_1 |                    |WS.102.2a            | ||||||
|  | PS.1st.b4           |PF1_1 |                    |WS.102.2b            | ||||||
|  | PS.1st.b5           |PF1_1 |                    |WS.102.3a            | ||||||
|  | PS.1st.b6           |PF1_1 |                    |WS.102.3b            | ||||||
|  | PS.1st.c1           |PF1_1 |                    |WS.105.1a            | ||||||
|  | PS.1st.c2           |PF1_1 |                    |WS.105.1b            | ||||||
|  | PS.1st.c3           |PF1_1 |                    |WS.105.2a            | ||||||
|  | PS.1st.c4           |PF1_1 |                    |WS.105.2b            | ||||||
|  | PS.1st.c5           |PF1_1 |                    |WS.105.3a            | ||||||
|  | PS.1st.c6           |PF1_1 |                    |WS.105.3b            | ||||||
|  | PS.1st.d1           |PF1_1 |                    |WS.106.1a            | ||||||
|  | PS.1st.d2           |PF1_1 |                    |WS.106.1b            | ||||||
|  | PS.1st.d3           |PF1_1 |                    |WS.106.2a            | ||||||
|  | PS.1st.d4           |PF1_1 |                    |WS.106.2b            | ||||||
|  | PS.1st.d5           |PF1_1 |                    |WS.106.3a            | ||||||
|  | PS.1st.d6           |PF1_1 |                    |WS.106.3b            | ||||||
|  | PS.1st.ta1          |PF1_2 |                    |                     | ||||||
|  | PS.1st.ta2          |PF1_2 |                    |                     | ||||||
|  | PS.1st.ta3          |PF1_2 |                    |                     | ||||||
|  | PS.1st.ta4          |PF1_2 |                    |                     | ||||||
|  | PS.1st.ta5          |PF1_2 |                    |                     | ||||||
|  | PS.1st.ta6          |PF1_2 |                    |                     | ||||||
|  | PS.1st.tb1          |PF1_2 |                    |                     | ||||||
|  | PS.1st.tb2          |PF1_2 |                    |                     | ||||||
|  | PS.1st.tb3          |PF1_2 |                    |                     | ||||||
|  | PS.1st.tb4          |PF1_2 |                    |                     | ||||||
|  | PS.1st.tb5          |PF1_2 |                    |                     | ||||||
|  | PS.1st.tb6          |PF1_2 |                    |                     | ||||||
|  | PS.base.a1          |PF0_1 |                    |WS.001.1a            | ||||||
|  | PS.base.a2          |PF0_1 |                    |WS.001.1b            | ||||||
|  | PS.base.a3          |PF0_1 |                    |WS.001.2a            | ||||||
|  | PS.base.a4          |PF0_1 |                    |WS.001.2b            | ||||||
|  | PS.base.a5          |PF0_1 |                    |WS.001.3a            | ||||||
|  | PS.base.a6          |PF0_1 |                    |WS.001.3b            | ||||||
|  | PS.base.b1          |PF0_1 |                    |WS.002.1a            | ||||||
|  | PS.base.b2          |PF0_1 |                    |WS.002.1b            | ||||||
|  | PS.base.b3          |PF0_1 |                    |WS.002.2a            | ||||||
|  | PS.base.b4          |PF0_1 |                    |WS.002.2b            | ||||||
|  | PS.base.b5          |PF0_1 |                    |WS.002.3a            | ||||||
|  | PS.base.b6          |PF0_1 |                    |WS.002.3b            | ||||||
|  | PS.base.c1          |PF0_1 |                    |WS.003.1a            | ||||||
|  | PS.base.c2          |PF0_1 |                    |WS.003.1b            | ||||||
|  | PS.base.c3          |PF0_1 |                    |WS.003.2a            | ||||||
|  | PS.base.c4          |PF0_1 |                    |WS.003.2b            | ||||||
|  | PS.base.c5          |PF0_1 |                    |WS.003.3a            | ||||||
|  | PS.base.c6          |PF0_1 |                    |WS.003.3b            | ||||||
|  | PS.base.ta1         |PF0_2 |                    |                     | ||||||
|  | PS.base.ta2         |PF0_2 |                    |                     | ||||||
|  | PS.base.ta3         |PF0_2 |                    |                     | ||||||
|  | PS.base.ta4         |PF0_2 |                    |                     | ||||||
|  | PS.base.ta5         |PF0_2 |                    |                     | ||||||
|  | PS.base.ta6         |PF0_2 |                    |                     | ||||||
|  | PS.base.tb1         |PF0_2 |                    |                     | ||||||
|  | PS.base.tb2         |PF0_2 |                    |                     | ||||||
|  | PS.base.tb3         |PF0_2 |                    |                     | ||||||
|  | PS.base.tb4         |PF0_2 |                    |                     | ||||||
|  | PS.base.tb5         |PF0_2 |                    |                     | ||||||
|  | PS.base.tb6         |PF0_2 |                    |                     | ||||||
|  | (66 rows) | ||||||
|  |  | ||||||
|  | QUERY: select * from WSlot order by slotname; | ||||||
|  | slotname            |  roomno|            slotlink|backlink             | ||||||
|  | --------------------+--------+--------------------+-------------------- | ||||||
|  | WS.001.1a           |001     |                    |PS.base.a1           | ||||||
|  | WS.001.1b           |001     |                    |PS.base.a2           | ||||||
|  | WS.001.2a           |001     |                    |PS.base.a3           | ||||||
|  | WS.001.2b           |001     |                    |PS.base.a4           | ||||||
|  | WS.001.3a           |001     |                    |PS.base.a5           | ||||||
|  | WS.001.3b           |001     |                    |PS.base.a6           | ||||||
|  | WS.002.1a           |002     |                    |PS.base.b1           | ||||||
|  | WS.002.1b           |002     |                    |PS.base.b2           | ||||||
|  | WS.002.2a           |002     |                    |PS.base.b3           | ||||||
|  | WS.002.2b           |002     |                    |PS.base.b4           | ||||||
|  | WS.002.3a           |002     |                    |PS.base.b5           | ||||||
|  | WS.002.3b           |002     |                    |PS.base.b6           | ||||||
|  | WS.003.1a           |003     |                    |PS.base.c1           | ||||||
|  | WS.003.1b           |003     |                    |PS.base.c2           | ||||||
|  | WS.003.2a           |003     |                    |PS.base.c3           | ||||||
|  | WS.003.2b           |003     |                    |PS.base.c4           | ||||||
|  | WS.003.3a           |003     |                    |PS.base.c5           | ||||||
|  | WS.003.3b           |003     |                    |PS.base.c6           | ||||||
|  | WS.101.1a           |101     |                    |PS.1st.a1            | ||||||
|  | WS.101.1b           |101     |                    |PS.1st.a2            | ||||||
|  | WS.101.2a           |101     |                    |PS.1st.a3            | ||||||
|  | WS.101.2b           |101     |                    |PS.1st.a4            | ||||||
|  | WS.101.3a           |101     |                    |PS.1st.a5            | ||||||
|  | WS.101.3b           |101     |                    |PS.1st.a6            | ||||||
|  | WS.102.1a           |102     |                    |PS.1st.b1            | ||||||
|  | WS.102.1b           |102     |                    |PS.1st.b2            | ||||||
|  | WS.102.2a           |102     |                    |PS.1st.b3            | ||||||
|  | WS.102.2b           |102     |                    |PS.1st.b4            | ||||||
|  | WS.102.3a           |102     |                    |PS.1st.b5            | ||||||
|  | WS.102.3b           |102     |                    |PS.1st.b6            | ||||||
|  | WS.105.1a           |105     |                    |PS.1st.c1            | ||||||
|  | WS.105.1b           |105     |                    |PS.1st.c2            | ||||||
|  | WS.105.2a           |105     |                    |PS.1st.c3            | ||||||
|  | WS.105.2b           |105     |                    |PS.1st.c4            | ||||||
|  | WS.105.3a           |105     |                    |PS.1st.c5            | ||||||
|  | WS.105.3b           |105     |                    |PS.1st.c6            | ||||||
|  | WS.106.1a           |106     |                    |PS.1st.d1            | ||||||
|  | WS.106.1b           |106     |                    |PS.1st.d2            | ||||||
|  | WS.106.2a           |106     |                    |PS.1st.d3            | ||||||
|  | WS.106.2b           |106     |                    |PS.1st.d4            | ||||||
|  | WS.106.3a           |106     |                    |PS.1st.d5            | ||||||
|  | WS.106.3b           |106     |                    |PS.1st.d6            | ||||||
|  | (42 rows) | ||||||
|  |  | ||||||
|  | QUERY: insert into PLine values ('PL.001', '-0', 'Central call', 'PS.base.ta1'); | ||||||
|  | QUERY: insert into PLine values ('PL.002', '-101', '', 'PS.base.ta2'); | ||||||
|  | QUERY: insert into PLine values ('PL.003', '-102', '', 'PS.base.ta3'); | ||||||
|  | QUERY: insert into PLine values ('PL.004', '-103', '', 'PS.base.ta5'); | ||||||
|  | QUERY: insert into PLine values ('PL.005', '-104', '', 'PS.base.ta6'); | ||||||
|  | QUERY: insert into PLine values ('PL.006', '-106', '', 'PS.base.tb2'); | ||||||
|  | QUERY: insert into PLine values ('PL.007', '-108', '', 'PS.base.tb3'); | ||||||
|  | QUERY: insert into PLine values ('PL.008', '-109', '', 'PS.base.tb4'); | ||||||
|  | QUERY: insert into PLine values ('PL.009', '-121', '', 'PS.base.tb5'); | ||||||
|  | QUERY: insert into PLine values ('PL.010', '-122', '', 'PS.base.tb6'); | ||||||
|  | QUERY: insert into PLine values ('PL.015', '-134', '', 'PS.1st.ta1'); | ||||||
|  | QUERY: insert into PLine values ('PL.016', '-137', '', 'PS.1st.ta3'); | ||||||
|  | QUERY: insert into PLine values ('PL.017', '-139', '', 'PS.1st.ta4'); | ||||||
|  | QUERY: insert into PLine values ('PL.018', '-362', '', 'PS.1st.tb1'); | ||||||
|  | QUERY: insert into PLine values ('PL.019', '-363', '', 'PS.1st.tb2'); | ||||||
|  | QUERY: insert into PLine values ('PL.020', '-364', '', 'PS.1st.tb3'); | ||||||
|  | QUERY: insert into PLine values ('PL.021', '-365', '', 'PS.1st.tb5'); | ||||||
|  | QUERY: insert into PLine values ('PL.022', '-367', '', 'PS.1st.tb6'); | ||||||
|  | QUERY: insert into PLine values ('PL.028', '-501', 'Fax entrance', 'PS.base.ta2'); | ||||||
|  | QUERY: insert into PLine values ('PL.029', '-502', 'Fax 1st floor', 'PS.1st.ta1'); | ||||||
|  | QUERY: insert into PHone values ('PH.hc001', 'Hicom standard', 'WS.001.1a'); | ||||||
|  | QUERY: update PSlot set slotlink = 'PS.base.ta1' where slotname = 'PS.base.a1'; | ||||||
|  | QUERY: insert into PHone values ('PH.hc002', 'Hicom standard', 'WS.002.1a'); | ||||||
|  | QUERY: update PSlot set slotlink = 'PS.base.ta5' where slotname = 'PS.base.b1'; | ||||||
|  | QUERY: insert into PHone values ('PH.hc003', 'Hicom standard', 'WS.002.2a'); | ||||||
|  | QUERY: update PSlot set slotlink = 'PS.base.tb2' where slotname = 'PS.base.b3'; | ||||||
|  | QUERY: insert into PHone values ('PH.fax001', 'Canon fax', 'WS.001.2a'); | ||||||
|  | QUERY: update PSlot set slotlink = 'PS.base.ta2' where slotname = 'PS.base.a3'; | ||||||
|  | QUERY: insert into Hub values ('base.hub1', 'Patchfield PF0_1 hub', 16); | ||||||
|  | QUERY: insert into System values ('orion', 'PC'); | ||||||
|  | QUERY: insert into IFace values ('IF', 'orion', 'eth0', 'WS.002.1b'); | ||||||
|  | QUERY: update PSlot set slotlink = 'HS.base.hub1.1' where slotname = 'PS.base.b2'; | ||||||
|  | QUERY: select * from PField_v1 where pfname = 'PF0_1' order by slotname; | ||||||
|  | pfname|slotname            |backside                                                |patch                                         | ||||||
|  | ------+--------------------+--------------------------------------------------------+--------------------------------------------- | ||||||
|  | PF0_1 |PS.base.a1          |WS.001.1a in room 001 -> Phone PH.hc001 (Hicom standard)|PS.base.ta1 -> Phone line -0 (Central call)   | ||||||
|  | PF0_1 |PS.base.a2          |WS.001.1b in room 001 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.a3          |WS.001.2a in room 001 -> Phone PH.fax001 (Canon fax)    |PS.base.ta2 -> Phone line -501 (Fax entrance) | ||||||
|  | PF0_1 |PS.base.a4          |WS.001.2b in room 001 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.a5          |WS.001.3a in room 001 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.a6          |WS.001.3b in room 001 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.b1          |WS.002.1a in room 002 -> Phone PH.hc002 (Hicom standard)|PS.base.ta5 -> Phone line -103                | ||||||
|  | PF0_1 |PS.base.b2          |WS.002.1b in room 002 -> orion IF eth0 (PC)             |Patchfield PF0_1 hub slot 1                   | ||||||
|  | PF0_1 |PS.base.b3          |WS.002.2a in room 002 -> Phone PH.hc003 (Hicom standard)|PS.base.tb2 -> Phone line -106                | ||||||
|  | PF0_1 |PS.base.b4          |WS.002.2b in room 002 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.b5          |WS.002.3a in room 002 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.b6          |WS.002.3b in room 002 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.c1          |WS.003.1a in room 003 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.c2          |WS.003.1b in room 003 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.c3          |WS.003.2a in room 003 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.c4          |WS.003.2b in room 003 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.c5          |WS.003.3a in room 003 -> -                              |-                                             | ||||||
|  | PF0_1 |PS.base.c6          |WS.003.3b in room 003 -> -                              |-                                             | ||||||
|  | (18 rows) | ||||||
|  |  | ||||||
|  | QUERY: select * from PField_v1 where pfname = 'PF0_2' order by slotname; | ||||||
|  | pfname|slotname            |backside                      |patch                                                                  | ||||||
|  | ------+--------------------+------------------------------+---------------------------------------------------------------------- | ||||||
|  | PF0_2 |PS.base.ta1         |Phone line -0 (Central call)  |PS.base.a1 -> WS.001.1a in room 001 -> Phone PH.hc001 (Hicom standard) | ||||||
|  | PF0_2 |PS.base.ta2         |Phone line -501 (Fax entrance)|PS.base.a3 -> WS.001.2a in room 001 -> Phone PH.fax001 (Canon fax)     | ||||||
|  | PF0_2 |PS.base.ta3         |Phone line -102               |-                                                                      | ||||||
|  | PF0_2 |PS.base.ta4         |-                             |-                                                                      | ||||||
|  | PF0_2 |PS.base.ta5         |Phone line -103               |PS.base.b1 -> WS.002.1a in room 002 -> Phone PH.hc002 (Hicom standard) | ||||||
|  | PF0_2 |PS.base.ta6         |Phone line -104               |-                                                                      | ||||||
|  | PF0_2 |PS.base.tb1         |-                             |-                                                                      | ||||||
|  | PF0_2 |PS.base.tb2         |Phone line -106               |PS.base.b3 -> WS.002.2a in room 002 -> Phone PH.hc003 (Hicom standard) | ||||||
|  | PF0_2 |PS.base.tb3         |Phone line -108               |-                                                                      | ||||||
|  | PF0_2 |PS.base.tb4         |Phone line -109               |-                                                                      | ||||||
|  | PF0_2 |PS.base.tb5         |Phone line -121               |-                                                                      | ||||||
|  | PF0_2 |PS.base.tb6         |Phone line -122               |-                                                                      | ||||||
|  | (12 rows) | ||||||
|  |  | ||||||
|  | QUERY: insert into PField values ('PF1_1', 'should fail due to unique index'); | ||||||
|  | ERROR:  Cannot insert a duplicate key into a unique index | ||||||
|  | QUERY: update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1'; | ||||||
|  | ERROR:  WS.not.there         does not exists | ||||||
|  | QUERY: update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1'; | ||||||
|  | ERROR:  illegal backlink beginning with XX | ||||||
|  | QUERY: update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1'; | ||||||
|  | ERROR:  PS.not.there         does not exists | ||||||
|  | QUERY: update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1'; | ||||||
|  | ERROR:  illegal slotlink beginning with XX | ||||||
|  | QUERY: insert into HSlot values ('HS', 'base.hub1', 1, ''); | ||||||
|  | ERROR:  Cannot insert a duplicate key into a unique index | ||||||
|  | QUERY: insert into HSlot values ('HS', 'base.hub1', 20, ''); | ||||||
|  | ERROR:  no manual manipulation of HSlot | ||||||
|  | QUERY: delete from HSlot; | ||||||
|  | ERROR:  no manual manipulation of HSlot | ||||||
|  | QUERY: insert into IFace values ('IF', 'notthere', 'eth0', ''); | ||||||
|  | ERROR:  system "notthere" does not exist | ||||||
|  | QUERY: insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', ''); | ||||||
|  | ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max) | ||||||
							
								
								
									
										680
									
								
								contrib/plpgsql/test/expected/triggers.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										680
									
								
								contrib/plpgsql/test/expected/triggers.out
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,680 @@ | |||||||
|  | QUERY: create function tg_room_au() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.roomno != old.roomno then | ||||||
|  |         update WSlot set roomno = new.roomno where roomno = old.roomno; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_room_au after update | ||||||
|  |     on Room for each row execute procedure tg_room_au(); | ||||||
|  | QUERY: create function tg_room_ad() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     delete from WSlot where roomno = old.roomno; | ||||||
|  |     return old; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_room_ad after delete | ||||||
|  |     on Room for each row execute procedure tg_room_ad(); | ||||||
|  | QUERY: create function tg_wslot_biu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if count(*) = 0 from Room where roomno = new.roomno then | ||||||
|  |         raise exception ''Room % does not exist'', new.roomno; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_wslot_biu before insert or update | ||||||
|  |     on WSlot for each row execute procedure tg_wslot_biu(); | ||||||
|  | QUERY: create function tg_pfield_au() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.name != old.name then | ||||||
|  |         update PSlot set pfname = new.name where pfname = old.name; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_pfield_au after update | ||||||
|  |     on PField for each row execute procedure tg_pfield_au(); | ||||||
|  | QUERY: create function tg_pfield_ad() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     delete from PSlot where pfname = old.name; | ||||||
|  |     return old; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_pfield_ad after delete | ||||||
|  |     on PField for each row execute procedure tg_pfield_ad(); | ||||||
|  | QUERY: create function tg_pslot_biu() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     pfrec	record; | ||||||
|  |     rename new to ps; | ||||||
|  | begin | ||||||
|  |     select into pfrec * from PField where name = ps.pfname; | ||||||
|  |     if not found then | ||||||
|  |         raise exception ''Patchfield "%" does not exist'', ps.pfname; | ||||||
|  |     end if; | ||||||
|  |     return ps; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_pslot_biu before insert or update | ||||||
|  |     on PSlot for each row execute procedure tg_pslot_biu(); | ||||||
|  | QUERY: create function tg_system_au() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.name != old.name then | ||||||
|  |         update IFace set sysname = new.name where sysname = old.name; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_system_au after update | ||||||
|  |     on System for each row execute procedure tg_system_au(); | ||||||
|  | QUERY: create function tg_iface_biu() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     sname	text; | ||||||
|  |     sysrec	record; | ||||||
|  | begin | ||||||
|  |     select into sysrec * from system where name = new.sysname; | ||||||
|  |     if not found then | ||||||
|  |         raise exception ''system "%" does not exist'', new.sysname; | ||||||
|  |     end if; | ||||||
|  |     sname := ''IF.'' || new.sysname; | ||||||
|  |     sname := sname || ''.''; | ||||||
|  |     sname := sname || new.ifname; | ||||||
|  |     if length(sname) > 20 then | ||||||
|  |         raise exception ''IFace slotname "%" too long (20 char max)'', sname; | ||||||
|  |     end if; | ||||||
|  |     new.slotname := sname; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_iface_biu before insert or update | ||||||
|  |     on IFace for each row execute procedure tg_iface_biu(); | ||||||
|  | QUERY: create function tg_hub_a() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     hname	text; | ||||||
|  |     dummy	integer; | ||||||
|  | begin | ||||||
|  |     if tg_op = ''INSERT'' then | ||||||
|  | 	dummy := tg_hub_adjustslots(new.name, 0, new.nslots); | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''UPDATE'' then | ||||||
|  | 	if new.name != old.name then | ||||||
|  | 	    update HSlot set hubname = new.name where hubname = old.name; | ||||||
|  | 	end if; | ||||||
|  | 	dummy := tg_hub_adjustslots(new.name, old.nslots, new.nslots); | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''DELETE'' then | ||||||
|  | 	dummy := tg_hub_adjustslots(old.name, old.nslots, 0); | ||||||
|  | 	return old; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_hub_a after insert or update or delete | ||||||
|  |     on Hub for each row execute procedure tg_hub_a(); | ||||||
|  | QUERY: create function tg_hub_adjustslots(bpchar, integer, integer) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     hname	alias for $1; | ||||||
|  |     oldnslots	alias for $2; | ||||||
|  |     newnslots	alias for $3; | ||||||
|  | begin | ||||||
|  |     if newnslots = oldnslots then | ||||||
|  |         return 0; | ||||||
|  |     end if; | ||||||
|  |     if newnslots < oldnslots then | ||||||
|  |         delete from HSlot where hubname = hname and slotno > newnslots; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     for i in oldnslots + 1 .. newnslots loop | ||||||
|  |         insert into HSlot (slotname, hubname, slotno, slotlink) | ||||||
|  | 		values (''HS.dummy'', hname, i, ''''); | ||||||
|  |     end loop; | ||||||
|  |     return 0; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create function tg_hslot_biu() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     sname	text; | ||||||
|  |     xname	HSlot.slotname%TYPE; | ||||||
|  |     hubrec	record; | ||||||
|  | begin | ||||||
|  |     select into hubrec * from Hub where name = new.hubname; | ||||||
|  |     if not found then | ||||||
|  |         raise exception ''no manual manipulation of HSlot''; | ||||||
|  |     end if; | ||||||
|  |     if new.slotno < 1 or new.slotno > hubrec.nslots then | ||||||
|  |         raise exception ''no manual manipulation of HSlot''; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''UPDATE'' then | ||||||
|  | 	if new.hubname != old.hubname then | ||||||
|  | 	    if count(*) > 0 from Hub where name = old.hubname then | ||||||
|  | 		raise exception ''no manual manipulation of HSlot''; | ||||||
|  | 	    end if; | ||||||
|  | 	end if; | ||||||
|  |     end if; | ||||||
|  |     sname := ''HS.'' || trim(new.hubname); | ||||||
|  |     sname := sname || ''.''; | ||||||
|  |     sname := sname || new.slotno::text; | ||||||
|  |     if length(sname) > 20 then | ||||||
|  |         raise exception ''HSlot slotname "%" too long (20 char max)'', sname; | ||||||
|  |     end if; | ||||||
|  |     new.slotname := sname; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_hslot_biu before insert or update | ||||||
|  |     on HSlot for each row execute procedure tg_hslot_biu(); | ||||||
|  | QUERY: create function tg_hslot_bd() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     hubrec	record; | ||||||
|  | begin | ||||||
|  |     select into hubrec * from Hub where name = old.hubname; | ||||||
|  |     if not found then | ||||||
|  |         return old; | ||||||
|  |     end if; | ||||||
|  |     if old.slotno > hubrec.nslots then | ||||||
|  |         return old; | ||||||
|  |     end if; | ||||||
|  |     raise exception ''no manual manipulation of HSlot''; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_hslot_bd before delete | ||||||
|  |     on HSlot for each row execute procedure tg_hslot_bd(); | ||||||
|  | QUERY: create function tg_chkslotname() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if substr(new.slotname, 1, 2) != tg_argv[0] then | ||||||
|  |         raise exception ''slotname must begin with %'', tg_argv[0]; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_chkslotname before insert | ||||||
|  |     on PSlot for each row execute procedure tg_chkslotname('PS'); | ||||||
|  | QUERY: create trigger tg_chkslotname before insert | ||||||
|  |     on WSlot for each row execute procedure tg_chkslotname('WS'); | ||||||
|  | QUERY: create trigger tg_chkslotname before insert | ||||||
|  |     on PLine for each row execute procedure tg_chkslotname('PL'); | ||||||
|  | QUERY: create trigger tg_chkslotname before insert | ||||||
|  |     on IFace for each row execute procedure tg_chkslotname('IF'); | ||||||
|  | QUERY: create trigger tg_chkslotname before insert | ||||||
|  |     on PHone for each row execute procedure tg_chkslotname('PH'); | ||||||
|  | QUERY: create function tg_chkslotlink() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotlink isnull then | ||||||
|  |         new.slotlink := ''''; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_chkslotlink before insert or update | ||||||
|  |     on PSlot for each row execute procedure tg_chkslotlink(); | ||||||
|  | QUERY: create trigger tg_chkslotlink before insert or update | ||||||
|  |     on WSlot for each row execute procedure tg_chkslotlink(); | ||||||
|  | QUERY: create trigger tg_chkslotlink before insert or update | ||||||
|  |     on IFace for each row execute procedure tg_chkslotlink(); | ||||||
|  | QUERY: create trigger tg_chkslotlink before insert or update | ||||||
|  |     on HSlot for each row execute procedure tg_chkslotlink(); | ||||||
|  | QUERY: create trigger tg_chkslotlink before insert or update | ||||||
|  |     on PHone for each row execute procedure tg_chkslotlink(); | ||||||
|  | QUERY: create function tg_chkbacklink() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.backlink isnull then | ||||||
|  |         new.backlink := ''''; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_chkbacklink before insert or update | ||||||
|  |     on PSlot for each row execute procedure tg_chkbacklink(); | ||||||
|  | QUERY: create trigger tg_chkbacklink before insert or update | ||||||
|  |     on WSlot for each row execute procedure tg_chkbacklink(); | ||||||
|  | QUERY: create trigger tg_chkbacklink before insert or update | ||||||
|  |     on PLine for each row execute procedure tg_chkbacklink(); | ||||||
|  | QUERY: create function tg_pslot_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from PSlot where slotname = old.slotname; | ||||||
|  | 	insert into PSlot ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    pfname, | ||||||
|  | 		    slotlink, | ||||||
|  | 		    backlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.pfname, | ||||||
|  | 		    new.slotlink, | ||||||
|  | 		    new.backlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_pslot_bu before update | ||||||
|  |     on PSlot for each row execute procedure tg_pslot_bu(); | ||||||
|  | QUERY: create function tg_wslot_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from WSlot where slotname = old.slotname; | ||||||
|  | 	insert into WSlot ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    roomno, | ||||||
|  | 		    slotlink, | ||||||
|  | 		    backlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.roomno, | ||||||
|  | 		    new.slotlink, | ||||||
|  | 		    new.backlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_wslot_bu before update | ||||||
|  |     on WSlot for each row execute procedure tg_Wslot_bu(); | ||||||
|  | QUERY: create function tg_pline_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from PLine where slotname = old.slotname; | ||||||
|  | 	insert into PLine ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    phonenumber, | ||||||
|  | 		    comment, | ||||||
|  | 		    backlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.phonenumber, | ||||||
|  | 		    new.comment, | ||||||
|  | 		    new.backlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_pline_bu before update | ||||||
|  |     on PLine for each row execute procedure tg_pline_bu(); | ||||||
|  | QUERY: create function tg_iface_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from IFace where slotname = old.slotname; | ||||||
|  | 	insert into IFace ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    sysname, | ||||||
|  | 		    ifname, | ||||||
|  | 		    slotlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.sysname, | ||||||
|  | 		    new.ifname, | ||||||
|  | 		    new.slotlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_iface_bu before update | ||||||
|  |     on IFace for each row execute procedure tg_iface_bu(); | ||||||
|  | QUERY: create function tg_hslot_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname or new.hubname != old.hubname then | ||||||
|  |         delete from HSlot where slotname = old.slotname; | ||||||
|  | 	insert into HSlot ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    hubname, | ||||||
|  | 		    slotno, | ||||||
|  | 		    slotlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.hubname, | ||||||
|  | 		    new.slotno, | ||||||
|  | 		    new.slotlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_hslot_bu before update | ||||||
|  |     on HSlot for each row execute procedure tg_hslot_bu(); | ||||||
|  | QUERY: create function tg_phone_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from PHone where slotname = old.slotname; | ||||||
|  | 	insert into PHone ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    comment, | ||||||
|  | 		    slotlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.comment, | ||||||
|  | 		    new.slotlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_phone_bu before update | ||||||
|  |     on PHone for each row execute procedure tg_phone_bu(); | ||||||
|  | QUERY: create function tg_backlink_a() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     dummy	integer; | ||||||
|  | begin | ||||||
|  |     if tg_op = ''INSERT'' then | ||||||
|  |         if new.backlink != '''' then | ||||||
|  | 	    dummy := tg_backlink_set(new.backlink, new.slotname); | ||||||
|  | 	end if; | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''UPDATE'' then | ||||||
|  |         if new.backlink != old.backlink then | ||||||
|  | 	    if old.backlink != '''' then | ||||||
|  | 	        dummy := tg_backlink_unset(old.backlink, old.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	    if new.backlink != '''' then | ||||||
|  | 	        dummy := tg_backlink_set(new.backlink, new.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	else | ||||||
|  | 	    if new.slotname != old.slotname and new.backlink != '''' then | ||||||
|  | 	        dummy := tg_slotlink_set(new.backlink, new.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	end if; | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''DELETE'' then | ||||||
|  |         if old.backlink != '''' then | ||||||
|  | 	    dummy := tg_backlink_unset(old.backlink, old.slotname); | ||||||
|  | 	end if; | ||||||
|  | 	return old; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_backlink_a after insert or update or delete | ||||||
|  |     on PSlot for each row execute procedure tg_backlink_a('PS'); | ||||||
|  | QUERY: create trigger tg_backlink_a after insert or update or delete | ||||||
|  |     on WSlot for each row execute procedure tg_backlink_a('WS'); | ||||||
|  | QUERY: create trigger tg_backlink_a after insert or update or delete | ||||||
|  |     on PLine for each row execute procedure tg_backlink_a('PL'); | ||||||
|  | QUERY: create function tg_backlink_set(bpchar, bpchar) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     myname	alias for $1; | ||||||
|  |     blname	alias for $2; | ||||||
|  |     mytype	char(2); | ||||||
|  |     link	char(4); | ||||||
|  |     rec		record; | ||||||
|  | begin | ||||||
|  |     mytype := substr(myname, 1, 2); | ||||||
|  |     link := mytype || substr(blname, 1, 2); | ||||||
|  |     if link = ''PLPL'' then | ||||||
|  |         raise exception | ||||||
|  | 		''backlink between two phone lines does not make sense''; | ||||||
|  |     end if; | ||||||
|  |     if link in (''PLWS'', ''WSPL'') then | ||||||
|  |         raise exception | ||||||
|  | 		''direct link of phone line to wall slot not permitted''; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PS'' then | ||||||
|  |         select into rec * from PSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink != blname then | ||||||
|  | 	    update PSlot set backlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink != blname then | ||||||
|  | 	    update WSlot set backlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PL'' then | ||||||
|  |         select into rec * from PLine where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink != blname then | ||||||
|  | 	    update PLine set backlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     raise exception ''illegal backlink beginning with %'', mytype; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create function tg_backlink_unset(bpchar, bpchar) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     myname	alias for $1; | ||||||
|  |     blname	alias for $2; | ||||||
|  |     mytype	char(2); | ||||||
|  |     rec		record; | ||||||
|  | begin | ||||||
|  |     mytype := substr(myname, 1, 2); | ||||||
|  |     if mytype = ''PS'' then | ||||||
|  |         select into rec * from PSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink = blname then | ||||||
|  | 	    update PSlot set backlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink = blname then | ||||||
|  | 	    update WSlot set backlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PL'' then | ||||||
|  |         select into rec * from PLine where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink = blname then | ||||||
|  | 	    update PLine set backlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create function tg_slotlink_a() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     dummy	integer; | ||||||
|  | begin | ||||||
|  |     if tg_op = ''INSERT'' then | ||||||
|  |         if new.slotlink != '''' then | ||||||
|  | 	    dummy := tg_slotlink_set(new.slotlink, new.slotname); | ||||||
|  | 	end if; | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''UPDATE'' then | ||||||
|  |         if new.slotlink != old.slotlink then | ||||||
|  | 	    if old.slotlink != '''' then | ||||||
|  | 	        dummy := tg_slotlink_unset(old.slotlink, old.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	    if new.slotlink != '''' then | ||||||
|  | 	        dummy := tg_slotlink_set(new.slotlink, new.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	else | ||||||
|  | 	    if new.slotname != old.slotname and new.slotlink != '''' then | ||||||
|  | 	        dummy := tg_slotlink_set(new.slotlink, new.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	end if; | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''DELETE'' then | ||||||
|  |         if old.slotlink != '''' then | ||||||
|  | 	    dummy := tg_slotlink_unset(old.slotlink, old.slotname); | ||||||
|  | 	end if; | ||||||
|  | 	return old; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on PSlot for each row execute procedure tg_slotlink_a('PS'); | ||||||
|  | QUERY: create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on WSlot for each row execute procedure tg_slotlink_a('WS'); | ||||||
|  | QUERY: create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on IFace for each row execute procedure tg_slotlink_a('IF'); | ||||||
|  | QUERY: create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on HSlot for each row execute procedure tg_slotlink_a('HS'); | ||||||
|  | QUERY: create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on PHone for each row execute procedure tg_slotlink_a('PH'); | ||||||
|  | QUERY: create function tg_slotlink_set(bpchar, bpchar) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     myname	alias for $1; | ||||||
|  |     blname	alias for $2; | ||||||
|  |     mytype	char(2); | ||||||
|  |     link	char(4); | ||||||
|  |     rec		record; | ||||||
|  | begin | ||||||
|  |     mytype := substr(myname, 1, 2); | ||||||
|  |     link := mytype || substr(blname, 1, 2); | ||||||
|  |     if link = ''PHPH'' then | ||||||
|  |         raise exception | ||||||
|  | 		''slotlink between two phones does not make sense''; | ||||||
|  |     end if; | ||||||
|  |     if link in (''PHHS'', ''HSPH'') then | ||||||
|  |         raise exception | ||||||
|  | 		''link of phone to hub does not make sense''; | ||||||
|  |     end if; | ||||||
|  |     if link in (''PHIF'', ''IFPH'') then | ||||||
|  |         raise exception | ||||||
|  | 		''link of phone to hub does not make sense''; | ||||||
|  |     end if; | ||||||
|  |     if link in (''PSWS'', ''WSPS'') then | ||||||
|  |         raise exception | ||||||
|  | 		''slotlink from patchslot to wallslot not permitted''; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PS'' then | ||||||
|  |         select into rec * from PSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update PSlot set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update WSlot set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''IF'' then | ||||||
|  |         select into rec * from IFace where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update IFace set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''HS'' then | ||||||
|  |         select into rec * from HSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update HSlot set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PH'' then | ||||||
|  |         select into rec * from PHone where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update PHone set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     raise exception ''illegal slotlink beginning with %'', mytype; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create function tg_slotlink_unset(bpchar, bpchar) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     myname	alias for $1; | ||||||
|  |     blname	alias for $2; | ||||||
|  |     mytype	char(2); | ||||||
|  |     rec		record; | ||||||
|  | begin | ||||||
|  |     mytype := substr(myname, 1, 2); | ||||||
|  |     if mytype = ''PS'' then | ||||||
|  |         select into rec * from PSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update PSlot set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update WSlot set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''IF'' then | ||||||
|  |         select into rec * from IFace where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update IFace set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''HS'' then | ||||||
|  |         select into rec * from HSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update HSlot set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PH'' then | ||||||
|  |         select into rec * from PHone where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update PHone set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
							
								
								
									
										120
									
								
								contrib/plpgsql/test/expected/views.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								contrib/plpgsql/test/expected/views.out
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | |||||||
|  | QUERY: create function pslot_backlink_view(bpchar) | ||||||
|  | returns text as ' | ||||||
|  | <<outer>> | ||||||
|  | declare | ||||||
|  |     rec		record; | ||||||
|  |     bltype	char(2); | ||||||
|  |     retval	text; | ||||||
|  | begin | ||||||
|  |     select into rec * from PSlot where slotname = $1; | ||||||
|  |     if not found then | ||||||
|  |         return ''''; | ||||||
|  |     end if; | ||||||
|  |     if rec.backlink = '''' then | ||||||
|  |         return ''-''; | ||||||
|  |     end if; | ||||||
|  |     bltype := substr(rec.backlink, 1, 2); | ||||||
|  |     if bltype = ''PL'' then | ||||||
|  |         declare | ||||||
|  | 	    rec		record; | ||||||
|  | 	begin | ||||||
|  | 	    select into rec * from PLine where slotname = outer.rec.backlink; | ||||||
|  | 	    retval := ''Phone line '' || trim(rec.phonenumber); | ||||||
|  | 	    if rec.comment != '''' then | ||||||
|  | 	        retval := retval || '' (''; | ||||||
|  | 		retval := retval || rec.comment; | ||||||
|  | 		retval := retval || '')''; | ||||||
|  | 	    end if; | ||||||
|  | 	    return retval; | ||||||
|  | 	end; | ||||||
|  |     end if; | ||||||
|  |     if bltype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = rec.backlink; | ||||||
|  | 	retval := trim(rec.slotname) || '' in room ''; | ||||||
|  | 	retval := retval || trim(rec.roomno); | ||||||
|  | 	retval := retval || '' -> ''; | ||||||
|  | 	return retval || wslot_slotlink_view(rec.slotname); | ||||||
|  |     end if; | ||||||
|  |     return rec.backlink; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create function pslot_slotlink_view(bpchar) | ||||||
|  | returns text as ' | ||||||
|  | declare | ||||||
|  |     psrec	record; | ||||||
|  |     sltype	char(2); | ||||||
|  |     retval	text; | ||||||
|  | begin | ||||||
|  |     select into psrec * from PSlot where slotname = $1; | ||||||
|  |     if not found then | ||||||
|  |         return ''''; | ||||||
|  |     end if; | ||||||
|  |     if psrec.slotlink = '''' then | ||||||
|  |         return ''-''; | ||||||
|  |     end if; | ||||||
|  |     sltype := substr(psrec.slotlink, 1, 2); | ||||||
|  |     if sltype = ''PS'' then | ||||||
|  | 	retval := trim(psrec.slotlink) || '' -> ''; | ||||||
|  | 	return retval || pslot_backlink_view(psrec.slotlink); | ||||||
|  |     end if; | ||||||
|  |     if sltype = ''HS'' then | ||||||
|  |         retval := comment from Hub H, HSlot HS | ||||||
|  | 			where HS.slotname = psrec.slotlink | ||||||
|  | 			  and H.name = HS.hubname; | ||||||
|  |         retval := retval || '' slot ''; | ||||||
|  | 	retval := retval || slotno::text from HSlot | ||||||
|  | 			where slotname = psrec.slotlink; | ||||||
|  | 	return retval; | ||||||
|  |     end if; | ||||||
|  |     return psrec.slotlink; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create function wslot_slotlink_view(bpchar) | ||||||
|  | returns text as ' | ||||||
|  | declare | ||||||
|  |     rec		record; | ||||||
|  |     sltype	char(2); | ||||||
|  |     retval	text; | ||||||
|  | begin | ||||||
|  |     select into rec * from WSlot where slotname = $1; | ||||||
|  |     if not found then | ||||||
|  |         return ''''; | ||||||
|  |     end if; | ||||||
|  |     if rec.slotlink = '''' then | ||||||
|  |         return ''-''; | ||||||
|  |     end if; | ||||||
|  |     sltype := substr(rec.slotlink, 1, 2); | ||||||
|  |     if sltype = ''PH'' then | ||||||
|  |         select into rec * from PHone where slotname = rec.slotlink; | ||||||
|  | 	retval := ''Phone '' || trim(rec.slotname); | ||||||
|  | 	if rec.comment != '''' then | ||||||
|  | 	    retval := retval || '' (''; | ||||||
|  | 	    retval := retval || rec.comment; | ||||||
|  | 	    retval := retval || '')''; | ||||||
|  | 	end if; | ||||||
|  | 	return retval; | ||||||
|  |     end if; | ||||||
|  |     if sltype = ''IF'' then | ||||||
|  | 	declare | ||||||
|  | 	    syrow	System%RowType; | ||||||
|  | 	    ifrow	IFace%ROWTYPE; | ||||||
|  |         begin | ||||||
|  | 	    select into ifrow * from IFace where slotname = rec.slotlink; | ||||||
|  | 	    select into syrow * from System where name = ifrow.sysname; | ||||||
|  | 	    retval := syrow.name || '' IF ''; | ||||||
|  | 	    retval := retval || ifrow.ifname; | ||||||
|  | 	    if syrow.comment != '''' then | ||||||
|  | 	        retval := retval || '' (''; | ||||||
|  | 		retval := retval || syrow.comment; | ||||||
|  | 		retval := retval || '')''; | ||||||
|  | 	    end if; | ||||||
|  | 	    return retval; | ||||||
|  | 	end; | ||||||
|  |     end if; | ||||||
|  |     return rec.slotlink; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  | QUERY: create view Pfield_v1 as select PF.pfname, PF.slotname, | ||||||
|  | 	pslot_backlink_view(PF.slotname) as backside, | ||||||
|  | 	pslot_slotlink_view(PF.slotname) as patch | ||||||
|  |     from PSlot PF; | ||||||
							
								
								
									
										14
									
								
								contrib/plpgsql/test/mklang.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								contrib/plpgsql/test/mklang.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | -- | ||||||
|  | -- PL/pgSQL language declaration | ||||||
|  | -- | ||||||
|  | -- $Header: /cvsroot/pgsql/contrib/plpgsql/test/Attic/mklang.sql,v 1.1 1998/08/22 12:38:36 momjian Exp $ | ||||||
|  | -- | ||||||
|  |  | ||||||
|  | create function plpgsql_call_handler() returns opaque | ||||||
|  | 	as '/usr/local/pgsql/lib/plpgsql.so' | ||||||
|  | 	language 'C'; | ||||||
|  |  | ||||||
|  | create trusted procedural language 'plpgsql' | ||||||
|  | 	handler plpgsql_call_handler | ||||||
|  | 	lancompiler 'PL/pgSQL'; | ||||||
|  |  | ||||||
							
								
								
									
										49
									
								
								contrib/plpgsql/test/runtest
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										49
									
								
								contrib/plpgsql/test/runtest
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | DB=plpgsql_test | ||||||
|  | export DB | ||||||
|  |  | ||||||
|  | FRONTEND="psql -n -e -q" | ||||||
|  | export FRONTEND | ||||||
|  |  | ||||||
|  | echo "*** destroy old $DB database ***" | ||||||
|  | destroydb $DB | ||||||
|  |  | ||||||
|  | echo "*** create new $DB database ***" | ||||||
|  | createdb $DB | ||||||
|  |  | ||||||
|  | echo "*** install PL/pgSQL ***" | ||||||
|  | $FRONTEND -f mklang.sql -d $DB >/dev/null 2>&1 | ||||||
|  |  | ||||||
|  | echo "*** create tables ***" | ||||||
|  | $FRONTEND -f tables.sql -d $DB >output/tables.out 2>&1 | ||||||
|  | if cmp -s output/tables.out expected/tables.out ; then | ||||||
|  |     echo "OK" | ||||||
|  | else | ||||||
|  |     echo "FAILED" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | echo "*** create triggers ***" | ||||||
|  | $FRONTEND -f triggers.sql -d $DB >output/triggers.out 2>&1 | ||||||
|  | if cmp -s output/triggers.out expected/triggers.out ; then | ||||||
|  |     echo "OK" | ||||||
|  | else | ||||||
|  |     echo "FAILED" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | echo "*** create views and support functions ***" | ||||||
|  | $FRONTEND -f views.sql -d $DB >output/views.out 2>&1 | ||||||
|  | if cmp -s output/views.out expected/views.out ; then | ||||||
|  |     echo "OK" | ||||||
|  | else | ||||||
|  |     echo "FAILED" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | echo "*** running tests ***" | ||||||
|  | $FRONTEND -f test.sql -d $DB >output/test.out 2>&1 | ||||||
|  | if cmp -s output/test.out expected/test.out ; then | ||||||
|  |     echo "OK" | ||||||
|  | else | ||||||
|  |     echo "FAILED" | ||||||
|  | fi | ||||||
|  |  | ||||||
							
								
								
									
										101
									
								
								contrib/plpgsql/test/tables.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								contrib/plpgsql/test/tables.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | -- ************************************************************ | ||||||
|  | -- *  | ||||||
|  | -- * Tables for the patchfield test of PL/pgSQL | ||||||
|  | -- *  | ||||||
|  | -- * $Header: /cvsroot/pgsql/contrib/plpgsql/test/Attic/tables.sql,v 1.1 1998/08/22 12:38:36 momjian Exp $ | ||||||
|  | -- *  | ||||||
|  | -- ************************************************************ | ||||||
|  |  | ||||||
|  | create table Room ( | ||||||
|  |     roomno	char(8), | ||||||
|  |     comment	text | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index Room_rno on Room using btree (roomno bpchar_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table WSlot ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     roomno	char(8), | ||||||
|  |     slotlink	char(20), | ||||||
|  |     backlink	char(20) | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index WSlot_name on WSlot using btree (slotname bpchar_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table PField ( | ||||||
|  |     name	text, | ||||||
|  |     comment	text | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index PField_name on PField using btree (name text_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table PSlot ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     pfname	text, | ||||||
|  |     slotlink	char(20), | ||||||
|  |     backlink	char(20) | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index PSlot_name on PSlot using btree (slotname bpchar_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table PLine ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     phonenumber	char(20), | ||||||
|  |     comment	text, | ||||||
|  |     backlink	char(20) | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index PLine_name on PLine using btree (slotname bpchar_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table Hub ( | ||||||
|  |     name	char(14), | ||||||
|  |     comment	text, | ||||||
|  |     nslots	integer | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index Hub_name on Hub using btree (name bpchar_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table HSlot ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     hubname	char(14), | ||||||
|  |     slotno	integer, | ||||||
|  |     slotlink	char(20) | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index HSlot_name on HSlot using btree (slotname bpchar_ops); | ||||||
|  | create index HSlot_hubname on HSlot using btree (hubname bpchar_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table System ( | ||||||
|  |     name	text, | ||||||
|  |     comment	text | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index System_name on System using btree (name text_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table IFace ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     sysname	text, | ||||||
|  |     ifname	text, | ||||||
|  |     slotlink	char(20) | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index IFace_name on IFace using btree (slotname bpchar_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create table PHone ( | ||||||
|  |     slotname	char(20), | ||||||
|  |     comment	text, | ||||||
|  |     slotlink	char(20) | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | create unique index PHone_name on PHone using btree (slotname bpchar_ops); | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										272
									
								
								contrib/plpgsql/test/test.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								contrib/plpgsql/test/test.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,272 @@ | |||||||
|  | -- | ||||||
|  | -- First we build the house - so we create the rooms | ||||||
|  | -- | ||||||
|  | insert into Room values ('001', 'Entrance'); | ||||||
|  | insert into Room values ('002', 'Office'); | ||||||
|  | insert into Room values ('003', 'Office'); | ||||||
|  | insert into Room values ('004', 'Technical'); | ||||||
|  | insert into Room values ('101', 'Office'); | ||||||
|  | insert into Room values ('102', 'Conference'); | ||||||
|  | insert into Room values ('103', 'Restroom'); | ||||||
|  | insert into Room values ('104', 'Technical'); | ||||||
|  | insert into Room values ('105', 'Office'); | ||||||
|  | insert into Room values ('106', 'Office'); | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Second we install the wall connectors | ||||||
|  | -- | ||||||
|  | insert into WSlot values ('WS.001.1a', '001', '', ''); | ||||||
|  | insert into WSlot values ('WS.001.1b', '001', '', ''); | ||||||
|  | insert into WSlot values ('WS.001.2a', '001', '', ''); | ||||||
|  | insert into WSlot values ('WS.001.2b', '001', '', ''); | ||||||
|  | insert into WSlot values ('WS.001.3a', '001', '', ''); | ||||||
|  | insert into WSlot values ('WS.001.3b', '001', '', ''); | ||||||
|  |  | ||||||
|  | insert into WSlot values ('WS.002.1a', '002', '', ''); | ||||||
|  | insert into WSlot values ('WS.002.1b', '002', '', ''); | ||||||
|  | insert into WSlot values ('WS.002.2a', '002', '', ''); | ||||||
|  | insert into WSlot values ('WS.002.2b', '002', '', ''); | ||||||
|  | insert into WSlot values ('WS.002.3a', '002', '', ''); | ||||||
|  | insert into WSlot values ('WS.002.3b', '002', '', ''); | ||||||
|  |  | ||||||
|  | insert into WSlot values ('WS.003.1a', '003', '', ''); | ||||||
|  | insert into WSlot values ('WS.003.1b', '003', '', ''); | ||||||
|  | insert into WSlot values ('WS.003.2a', '003', '', ''); | ||||||
|  | insert into WSlot values ('WS.003.2b', '003', '', ''); | ||||||
|  | insert into WSlot values ('WS.003.3a', '003', '', ''); | ||||||
|  | insert into WSlot values ('WS.003.3b', '003', '', ''); | ||||||
|  |  | ||||||
|  | insert into WSlot values ('WS.101.1a', '101', '', ''); | ||||||
|  | insert into WSlot values ('WS.101.1b', '101', '', ''); | ||||||
|  | insert into WSlot values ('WS.101.2a', '101', '', ''); | ||||||
|  | insert into WSlot values ('WS.101.2b', '101', '', ''); | ||||||
|  | insert into WSlot values ('WS.101.3a', '101', '', ''); | ||||||
|  | insert into WSlot values ('WS.101.3b', '101', '', ''); | ||||||
|  |  | ||||||
|  | insert into WSlot values ('WS.102.1a', '102', '', ''); | ||||||
|  | insert into WSlot values ('WS.102.1b', '102', '', ''); | ||||||
|  | insert into WSlot values ('WS.102.2a', '102', '', ''); | ||||||
|  | insert into WSlot values ('WS.102.2b', '102', '', ''); | ||||||
|  | insert into WSlot values ('WS.102.3a', '102', '', ''); | ||||||
|  | insert into WSlot values ('WS.102.3b', '102', '', ''); | ||||||
|  |  | ||||||
|  | insert into WSlot values ('WS.105.1a', '105', '', ''); | ||||||
|  | insert into WSlot values ('WS.105.1b', '105', '', ''); | ||||||
|  | insert into WSlot values ('WS.105.2a', '105', '', ''); | ||||||
|  | insert into WSlot values ('WS.105.2b', '105', '', ''); | ||||||
|  | insert into WSlot values ('WS.105.3a', '105', '', ''); | ||||||
|  | insert into WSlot values ('WS.105.3b', '105', '', ''); | ||||||
|  |  | ||||||
|  | insert into WSlot values ('WS.106.1a', '106', '', ''); | ||||||
|  | insert into WSlot values ('WS.106.1b', '106', '', ''); | ||||||
|  | insert into WSlot values ('WS.106.2a', '106', '', ''); | ||||||
|  | insert into WSlot values ('WS.106.2b', '106', '', ''); | ||||||
|  | insert into WSlot values ('WS.106.3a', '106', '', ''); | ||||||
|  | insert into WSlot values ('WS.106.3b', '106', '', ''); | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Now create the patch fields and their slots | ||||||
|  | -- | ||||||
|  | insert into PField values ('PF0_1', 'Wallslots basement'); | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- The cables for these will be made later, so they are unconnected for now | ||||||
|  | -- | ||||||
|  | insert into PSlot values ('PS.base.a1', 'PF0_1', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.a2', 'PF0_1', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.a3', 'PF0_1', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.a4', 'PF0_1', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.a5', 'PF0_1', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.a6', 'PF0_1', '', ''); | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- These are already wired to the wall connectors | ||||||
|  | -- | ||||||
|  | insert into PSlot values ('PS.base.b1', 'PF0_1', '', 'WS.002.1a'); | ||||||
|  | insert into PSlot values ('PS.base.b2', 'PF0_1', '', 'WS.002.1b'); | ||||||
|  | insert into PSlot values ('PS.base.b3', 'PF0_1', '', 'WS.002.2a'); | ||||||
|  | insert into PSlot values ('PS.base.b4', 'PF0_1', '', 'WS.002.2b'); | ||||||
|  | insert into PSlot values ('PS.base.b5', 'PF0_1', '', 'WS.002.3a'); | ||||||
|  | insert into PSlot values ('PS.base.b6', 'PF0_1', '', 'WS.002.3b'); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.base.c1', 'PF0_1', '', 'WS.003.1a'); | ||||||
|  | insert into PSlot values ('PS.base.c2', 'PF0_1', '', 'WS.003.1b'); | ||||||
|  | insert into PSlot values ('PS.base.c3', 'PF0_1', '', 'WS.003.2a'); | ||||||
|  | insert into PSlot values ('PS.base.c4', 'PF0_1', '', 'WS.003.2b'); | ||||||
|  | insert into PSlot values ('PS.base.c5', 'PF0_1', '', 'WS.003.3a'); | ||||||
|  | insert into PSlot values ('PS.base.c6', 'PF0_1', '', 'WS.003.3b'); | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- This patchfield will be renamed later into PF0_2 - so its | ||||||
|  | -- slots references in pfname should follow | ||||||
|  | -- | ||||||
|  | insert into PField values ('PF0_X', 'Phonelines basement'); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.base.ta1', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.ta2', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.ta3', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.ta4', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.ta5', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.ta6', 'PF0_X', '', ''); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.base.tb1', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.tb2', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.tb3', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.tb4', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.tb5', 'PF0_X', '', ''); | ||||||
|  | insert into PSlot values ('PS.base.tb6', 'PF0_X', '', ''); | ||||||
|  |  | ||||||
|  | insert into PField values ('PF1_1', 'Wallslots 1st floor'); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.1st.a1', 'PF1_1', '', 'WS.101.1a'); | ||||||
|  | insert into PSlot values ('PS.1st.a2', 'PF1_1', '', 'WS.101.1b'); | ||||||
|  | insert into PSlot values ('PS.1st.a3', 'PF1_1', '', 'WS.101.2a'); | ||||||
|  | insert into PSlot values ('PS.1st.a4', 'PF1_1', '', 'WS.101.2b'); | ||||||
|  | insert into PSlot values ('PS.1st.a5', 'PF1_1', '', 'WS.101.3a'); | ||||||
|  | insert into PSlot values ('PS.1st.a6', 'PF1_1', '', 'WS.101.3b'); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.1st.b1', 'PF1_1', '', 'WS.102.1a'); | ||||||
|  | insert into PSlot values ('PS.1st.b2', 'PF1_1', '', 'WS.102.1b'); | ||||||
|  | insert into PSlot values ('PS.1st.b3', 'PF1_1', '', 'WS.102.2a'); | ||||||
|  | insert into PSlot values ('PS.1st.b4', 'PF1_1', '', 'WS.102.2b'); | ||||||
|  | insert into PSlot values ('PS.1st.b5', 'PF1_1', '', 'WS.102.3a'); | ||||||
|  | insert into PSlot values ('PS.1st.b6', 'PF1_1', '', 'WS.102.3b'); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.1st.c1', 'PF1_1', '', 'WS.105.1a'); | ||||||
|  | insert into PSlot values ('PS.1st.c2', 'PF1_1', '', 'WS.105.1b'); | ||||||
|  | insert into PSlot values ('PS.1st.c3', 'PF1_1', '', 'WS.105.2a'); | ||||||
|  | insert into PSlot values ('PS.1st.c4', 'PF1_1', '', 'WS.105.2b'); | ||||||
|  | insert into PSlot values ('PS.1st.c5', 'PF1_1', '', 'WS.105.3a'); | ||||||
|  | insert into PSlot values ('PS.1st.c6', 'PF1_1', '', 'WS.105.3b'); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.1st.d1', 'PF1_1', '', 'WS.106.1a'); | ||||||
|  | insert into PSlot values ('PS.1st.d2', 'PF1_1', '', 'WS.106.1b'); | ||||||
|  | insert into PSlot values ('PS.1st.d3', 'PF1_1', '', 'WS.106.2a'); | ||||||
|  | insert into PSlot values ('PS.1st.d4', 'PF1_1', '', 'WS.106.2b'); | ||||||
|  | insert into PSlot values ('PS.1st.d5', 'PF1_1', '', 'WS.106.3a'); | ||||||
|  | insert into PSlot values ('PS.1st.d6', 'PF1_1', '', 'WS.106.3b'); | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Now we wire the wall connectors 1a-2a in room 001 to the | ||||||
|  | -- patchfield. In the second update we make an error, and | ||||||
|  | -- correct it after | ||||||
|  | -- | ||||||
|  | update PSlot set backlink = 'WS.001.1a' where slotname = 'PS.base.a1'; | ||||||
|  | update PSlot set backlink = 'WS.001.1b' where slotname = 'PS.base.a3'; | ||||||
|  | select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | update PSlot set backlink = 'WS.001.2a' where slotname = 'PS.base.a3'; | ||||||
|  | select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | update PSlot set backlink = 'WS.001.1b' where slotname = 'PS.base.a2'; | ||||||
|  | select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Same procedure for 2b-3b but this time updating the WSlot instead | ||||||
|  | -- of the PSlot. Due to the triggers the result is the same: | ||||||
|  | -- WSlot and corresponding PSlot point to each other. | ||||||
|  | -- | ||||||
|  | update WSlot set backlink = 'PS.base.a4' where slotname = 'WS.001.2b'; | ||||||
|  | update WSlot set backlink = 'PS.base.a6' where slotname = 'WS.001.3a'; | ||||||
|  | select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | update WSlot set backlink = 'PS.base.a6' where slotname = 'WS.001.3b'; | ||||||
|  | select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  | update WSlot set backlink = 'PS.base.a5' where slotname = 'WS.001.3a'; | ||||||
|  | select * from WSlot where roomno = '001' order by slotname; | ||||||
|  | select * from PSlot where slotname ~ 'PS.base.a' order by slotname; | ||||||
|  |  | ||||||
|  | insert into PField values ('PF1_2', 'Phonelines 1st floor'); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.1st.ta1', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.ta2', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.ta3', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.ta4', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.ta5', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.ta6', 'PF1_2', '', ''); | ||||||
|  |  | ||||||
|  | insert into PSlot values ('PS.1st.tb1', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.tb2', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.tb3', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.tb4', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.tb5', 'PF1_2', '', ''); | ||||||
|  | insert into PSlot values ('PS.1st.tb6', 'PF1_2', '', ''); | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Fix the wrong name for patchfield PF0_2 | ||||||
|  | -- | ||||||
|  | update PField set name = 'PF0_2' where name = 'PF0_X'; | ||||||
|  |  | ||||||
|  | select * from PSlot order by slotname; | ||||||
|  | select * from WSlot order by slotname; | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Install the central phone system and create the phone numbers. | ||||||
|  | -- They are weired on insert to the patchfields. Again the | ||||||
|  | -- triggers automatically tell the PSlots to update their | ||||||
|  | -- backlink field. | ||||||
|  | -- | ||||||
|  | insert into PLine values ('PL.001', '-0', 'Central call', 'PS.base.ta1'); | ||||||
|  | insert into PLine values ('PL.002', '-101', '', 'PS.base.ta2'); | ||||||
|  | insert into PLine values ('PL.003', '-102', '', 'PS.base.ta3'); | ||||||
|  | insert into PLine values ('PL.004', '-103', '', 'PS.base.ta5'); | ||||||
|  | insert into PLine values ('PL.005', '-104', '', 'PS.base.ta6'); | ||||||
|  | insert into PLine values ('PL.006', '-106', '', 'PS.base.tb2'); | ||||||
|  | insert into PLine values ('PL.007', '-108', '', 'PS.base.tb3'); | ||||||
|  | insert into PLine values ('PL.008', '-109', '', 'PS.base.tb4'); | ||||||
|  | insert into PLine values ('PL.009', '-121', '', 'PS.base.tb5'); | ||||||
|  | insert into PLine values ('PL.010', '-122', '', 'PS.base.tb6'); | ||||||
|  | insert into PLine values ('PL.015', '-134', '', 'PS.1st.ta1'); | ||||||
|  | insert into PLine values ('PL.016', '-137', '', 'PS.1st.ta3'); | ||||||
|  | insert into PLine values ('PL.017', '-139', '', 'PS.1st.ta4'); | ||||||
|  | insert into PLine values ('PL.018', '-362', '', 'PS.1st.tb1'); | ||||||
|  | insert into PLine values ('PL.019', '-363', '', 'PS.1st.tb2'); | ||||||
|  | insert into PLine values ('PL.020', '-364', '', 'PS.1st.tb3'); | ||||||
|  | insert into PLine values ('PL.021', '-365', '', 'PS.1st.tb5'); | ||||||
|  | insert into PLine values ('PL.022', '-367', '', 'PS.1st.tb6'); | ||||||
|  | insert into PLine values ('PL.028', '-501', 'Fax entrance', 'PS.base.ta2'); | ||||||
|  | insert into PLine values ('PL.029', '-502', 'Fax 1st floor', 'PS.1st.ta1'); | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Buy some phones, plug them into the wall and patch the | ||||||
|  | -- phone lines to the corresponding patchfield slots. | ||||||
|  | -- | ||||||
|  | insert into PHone values ('PH.hc001', 'Hicom standard', 'WS.001.1a'); | ||||||
|  | update PSlot set slotlink = 'PS.base.ta1' where slotname = 'PS.base.a1'; | ||||||
|  | insert into PHone values ('PH.hc002', 'Hicom standard', 'WS.002.1a'); | ||||||
|  | update PSlot set slotlink = 'PS.base.ta5' where slotname = 'PS.base.b1'; | ||||||
|  | insert into PHone values ('PH.hc003', 'Hicom standard', 'WS.002.2a'); | ||||||
|  | update PSlot set slotlink = 'PS.base.tb2' where slotname = 'PS.base.b3'; | ||||||
|  | insert into PHone values ('PH.fax001', 'Canon fax', 'WS.001.2a'); | ||||||
|  | update PSlot set slotlink = 'PS.base.ta2' where slotname = 'PS.base.a3'; | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Install a hub at one of the patchfields, plug a computers | ||||||
|  | -- ethernet interface into the wall and patch it to the hub. | ||||||
|  | -- | ||||||
|  | insert into Hub values ('base.hub1', 'Patchfield PF0_1 hub', 16); | ||||||
|  | insert into System values ('orion', 'PC'); | ||||||
|  | insert into IFace values ('IF', 'orion', 'eth0', 'WS.002.1b'); | ||||||
|  | update PSlot set slotlink = 'HS.base.hub1.1' where slotname = 'PS.base.b2'; | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Now we take a look at the patchfield | ||||||
|  | -- | ||||||
|  | select * from PField_v1 where pfname = 'PF0_1' order by slotname; | ||||||
|  | select * from PField_v1 where pfname = 'PF0_2' order by slotname; | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Finally we want errors | ||||||
|  | -- | ||||||
|  | insert into PField values ('PF1_1', 'should fail due to unique index'); | ||||||
|  | update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1'; | ||||||
|  | update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1'; | ||||||
|  | update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1'; | ||||||
|  | update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1'; | ||||||
|  | insert into HSlot values ('HS', 'base.hub1', 1, ''); | ||||||
|  | insert into HSlot values ('HS', 'base.hub1', 20, ''); | ||||||
|  | delete from HSlot; | ||||||
|  | insert into IFace values ('IF', 'notthere', 'eth0', ''); | ||||||
|  | insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', ''); | ||||||
							
								
								
									
										892
									
								
								contrib/plpgsql/test/triggers.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										892
									
								
								contrib/plpgsql/test/triggers.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,892 @@ | |||||||
|  | -- ************************************************************ | ||||||
|  | -- *  | ||||||
|  | -- * Trigger procedures and functions for the patchfield | ||||||
|  | -- * test of PL/pgSQL | ||||||
|  | -- *  | ||||||
|  | -- * $Header: /cvsroot/pgsql/contrib/plpgsql/test/Attic/triggers.sql,v 1.1 1998/08/22 12:38:37 momjian Exp $ | ||||||
|  | -- *  | ||||||
|  | -- ************************************************************ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * AFTER UPDATE on Room | ||||||
|  | -- *	- If room no changes let wall slots follow | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_room_au() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.roomno != old.roomno then | ||||||
|  |         update WSlot set roomno = new.roomno where roomno = old.roomno; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_room_au after update | ||||||
|  |     on Room for each row execute procedure tg_room_au(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * AFTER DELETE on Room | ||||||
|  | -- *	- delete wall slots in this room | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_room_ad() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     delete from WSlot where roomno = old.roomno; | ||||||
|  |     return old; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_room_ad after delete | ||||||
|  |     on Room for each row execute procedure tg_room_ad(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE INSERT or UPDATE on WSlot | ||||||
|  | -- *	- Check that room exists | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_wslot_biu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if count(*) = 0 from Room where roomno = new.roomno then | ||||||
|  |         raise exception ''Room % does not exist'', new.roomno; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_wslot_biu before insert or update | ||||||
|  |     on WSlot for each row execute procedure tg_wslot_biu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * AFTER UPDATE on PField | ||||||
|  | -- *	- Let PSlots of this field follow | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_pfield_au() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.name != old.name then | ||||||
|  |         update PSlot set pfname = new.name where pfname = old.name; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_pfield_au after update | ||||||
|  |     on PField for each row execute procedure tg_pfield_au(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * AFTER DELETE on PField | ||||||
|  | -- *	- Remove all slots of this patchfield | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_pfield_ad() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     delete from PSlot where pfname = old.name; | ||||||
|  |     return old; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_pfield_ad after delete | ||||||
|  |     on PField for each row execute procedure tg_pfield_ad(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE INSERT or UPDATE on PSlot | ||||||
|  | -- *	- Ensure that our patchfield does exist | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_pslot_biu() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     pfrec	record; | ||||||
|  |     rename new to ps; | ||||||
|  | begin | ||||||
|  |     select into pfrec * from PField where name = ps.pfname; | ||||||
|  |     if not found then | ||||||
|  |         raise exception ''Patchfield "%" does not exist'', ps.pfname; | ||||||
|  |     end if; | ||||||
|  |     return ps; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_pslot_biu before insert or update | ||||||
|  |     on PSlot for each row execute procedure tg_pslot_biu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * AFTER UPDATE on System | ||||||
|  | -- *	- If system name changes let interfaces follow | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_system_au() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.name != old.name then | ||||||
|  |         update IFace set sysname = new.name where sysname = old.name; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_system_au after update | ||||||
|  |     on System for each row execute procedure tg_system_au(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE INSERT or UPDATE on IFace | ||||||
|  | -- *	- set the slotname to IF.sysname.ifname | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_iface_biu() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     sname	text; | ||||||
|  |     sysrec	record; | ||||||
|  | begin | ||||||
|  |     select into sysrec * from system where name = new.sysname; | ||||||
|  |     if not found then | ||||||
|  |         raise exception ''system "%" does not exist'', new.sysname; | ||||||
|  |     end if; | ||||||
|  |     sname := ''IF.'' || new.sysname; | ||||||
|  |     sname := sname || ''.''; | ||||||
|  |     sname := sname || new.ifname; | ||||||
|  |     if length(sname) > 20 then | ||||||
|  |         raise exception ''IFace slotname "%" too long (20 char max)'', sname; | ||||||
|  |     end if; | ||||||
|  |     new.slotname := sname; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_iface_biu before insert or update | ||||||
|  |     on IFace for each row execute procedure tg_iface_biu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * AFTER INSERT or UPDATE or DELETE on Hub | ||||||
|  | -- *	- insert/delete/rename slots as required | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_hub_a() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     hname	text; | ||||||
|  |     dummy	integer; | ||||||
|  | begin | ||||||
|  |     if tg_op = ''INSERT'' then | ||||||
|  | 	dummy := tg_hub_adjustslots(new.name, 0, new.nslots); | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''UPDATE'' then | ||||||
|  | 	if new.name != old.name then | ||||||
|  | 	    update HSlot set hubname = new.name where hubname = old.name; | ||||||
|  | 	end if; | ||||||
|  | 	dummy := tg_hub_adjustslots(new.name, old.nslots, new.nslots); | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''DELETE'' then | ||||||
|  | 	dummy := tg_hub_adjustslots(old.name, old.nslots, 0); | ||||||
|  | 	return old; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_hub_a after insert or update or delete | ||||||
|  |     on Hub for each row execute procedure tg_hub_a(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * Support function to add/remove slots of Hub | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_hub_adjustslots(bpchar, integer, integer) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     hname	alias for $1; | ||||||
|  |     oldnslots	alias for $2; | ||||||
|  |     newnslots	alias for $3; | ||||||
|  | begin | ||||||
|  |     if newnslots = oldnslots then | ||||||
|  |         return 0; | ||||||
|  |     end if; | ||||||
|  |     if newnslots < oldnslots then | ||||||
|  |         delete from HSlot where hubname = hname and slotno > newnslots; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     for i in oldnslots + 1 .. newnslots loop | ||||||
|  |         insert into HSlot (slotname, hubname, slotno, slotlink) | ||||||
|  | 		values (''HS.dummy'', hname, i, ''''); | ||||||
|  |     end loop; | ||||||
|  |     return 0; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE INSERT or UPDATE on HSlot | ||||||
|  | -- *	- prevent from manual manipulation | ||||||
|  | -- *	- set the slotname to HS.hubname.slotno | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_hslot_biu() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     sname	text; | ||||||
|  |     xname	HSlot.slotname%TYPE; | ||||||
|  |     hubrec	record; | ||||||
|  | begin | ||||||
|  |     select into hubrec * from Hub where name = new.hubname; | ||||||
|  |     if not found then | ||||||
|  |         raise exception ''no manual manipulation of HSlot''; | ||||||
|  |     end if; | ||||||
|  |     if new.slotno < 1 or new.slotno > hubrec.nslots then | ||||||
|  |         raise exception ''no manual manipulation of HSlot''; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''UPDATE'' then | ||||||
|  | 	if new.hubname != old.hubname then | ||||||
|  | 	    if count(*) > 0 from Hub where name = old.hubname then | ||||||
|  | 		raise exception ''no manual manipulation of HSlot''; | ||||||
|  | 	    end if; | ||||||
|  | 	end if; | ||||||
|  |     end if; | ||||||
|  |     sname := ''HS.'' || trim(new.hubname); | ||||||
|  |     sname := sname || ''.''; | ||||||
|  |     sname := sname || new.slotno::text; | ||||||
|  |     if length(sname) > 20 then | ||||||
|  |         raise exception ''HSlot slotname "%" too long (20 char max)'', sname; | ||||||
|  |     end if; | ||||||
|  |     new.slotname := sname; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_hslot_biu before insert or update | ||||||
|  |     on HSlot for each row execute procedure tg_hslot_biu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE DELETE on HSlot | ||||||
|  | -- *	- prevent from manual manipulation | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_hslot_bd() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     hubrec	record; | ||||||
|  | begin | ||||||
|  |     select into hubrec * from Hub where name = old.hubname; | ||||||
|  |     if not found then | ||||||
|  |         return old; | ||||||
|  |     end if; | ||||||
|  |     if old.slotno > hubrec.nslots then | ||||||
|  |         return old; | ||||||
|  |     end if; | ||||||
|  |     raise exception ''no manual manipulation of HSlot''; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_hslot_bd before delete | ||||||
|  |     on HSlot for each row execute procedure tg_hslot_bd(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE INSERT on all slots | ||||||
|  | -- *	- Check name prefix | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_chkslotname() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if substr(new.slotname, 1, 2) != tg_argv[0] then | ||||||
|  |         raise exception ''slotname must begin with %'', tg_argv[0]; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotname before insert | ||||||
|  |     on PSlot for each row execute procedure tg_chkslotname('PS'); | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotname before insert | ||||||
|  |     on WSlot for each row execute procedure tg_chkslotname('WS'); | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotname before insert | ||||||
|  |     on PLine for each row execute procedure tg_chkslotname('PL'); | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotname before insert | ||||||
|  |     on IFace for each row execute procedure tg_chkslotname('IF'); | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotname before insert | ||||||
|  |     on PHone for each row execute procedure tg_chkslotname('PH'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE INSERT or UPDATE on all slots with slotlink | ||||||
|  | -- *	- Set slotlink to empty string if NULL value given | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_chkslotlink() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotlink isnull then | ||||||
|  |         new.slotlink := ''''; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotlink before insert or update | ||||||
|  |     on PSlot for each row execute procedure tg_chkslotlink(); | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotlink before insert or update | ||||||
|  |     on WSlot for each row execute procedure tg_chkslotlink(); | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotlink before insert or update | ||||||
|  |     on IFace for each row execute procedure tg_chkslotlink(); | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotlink before insert or update | ||||||
|  |     on HSlot for each row execute procedure tg_chkslotlink(); | ||||||
|  |  | ||||||
|  | create trigger tg_chkslotlink before insert or update | ||||||
|  |     on PHone for each row execute procedure tg_chkslotlink(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE INSERT or UPDATE on all slots with backlink | ||||||
|  | -- *	- Set backlink to empty string if NULL value given | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_chkbacklink() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.backlink isnull then | ||||||
|  |         new.backlink := ''''; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_chkbacklink before insert or update | ||||||
|  |     on PSlot for each row execute procedure tg_chkbacklink(); | ||||||
|  |  | ||||||
|  | create trigger tg_chkbacklink before insert or update | ||||||
|  |     on WSlot for each row execute procedure tg_chkbacklink(); | ||||||
|  |  | ||||||
|  | create trigger tg_chkbacklink before insert or update | ||||||
|  |     on PLine for each row execute procedure tg_chkbacklink(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE UPDATE on PSlot | ||||||
|  | -- *	- do delete/insert instead of update if name changes | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_pslot_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from PSlot where slotname = old.slotname; | ||||||
|  | 	insert into PSlot ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    pfname, | ||||||
|  | 		    slotlink, | ||||||
|  | 		    backlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.pfname, | ||||||
|  | 		    new.slotlink, | ||||||
|  | 		    new.backlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_pslot_bu before update | ||||||
|  |     on PSlot for each row execute procedure tg_pslot_bu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE UPDATE on WSlot | ||||||
|  | -- *	- do delete/insert instead of update if name changes | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_wslot_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from WSlot where slotname = old.slotname; | ||||||
|  | 	insert into WSlot ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    roomno, | ||||||
|  | 		    slotlink, | ||||||
|  | 		    backlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.roomno, | ||||||
|  | 		    new.slotlink, | ||||||
|  | 		    new.backlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_wslot_bu before update | ||||||
|  |     on WSlot for each row execute procedure tg_Wslot_bu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE UPDATE on PLine | ||||||
|  | -- *	- do delete/insert instead of update if name changes | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_pline_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from PLine where slotname = old.slotname; | ||||||
|  | 	insert into PLine ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    phonenumber, | ||||||
|  | 		    comment, | ||||||
|  | 		    backlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.phonenumber, | ||||||
|  | 		    new.comment, | ||||||
|  | 		    new.backlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_pline_bu before update | ||||||
|  |     on PLine for each row execute procedure tg_pline_bu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE UPDATE on IFace | ||||||
|  | -- *	- do delete/insert instead of update if name changes | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_iface_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from IFace where slotname = old.slotname; | ||||||
|  | 	insert into IFace ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    sysname, | ||||||
|  | 		    ifname, | ||||||
|  | 		    slotlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.sysname, | ||||||
|  | 		    new.ifname, | ||||||
|  | 		    new.slotlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_iface_bu before update | ||||||
|  |     on IFace for each row execute procedure tg_iface_bu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE UPDATE on HSlot | ||||||
|  | -- *	- do delete/insert instead of update if name changes | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_hslot_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname or new.hubname != old.hubname then | ||||||
|  |         delete from HSlot where slotname = old.slotname; | ||||||
|  | 	insert into HSlot ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    hubname, | ||||||
|  | 		    slotno, | ||||||
|  | 		    slotlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.hubname, | ||||||
|  | 		    new.slotno, | ||||||
|  | 		    new.slotlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_hslot_bu before update | ||||||
|  |     on HSlot for each row execute procedure tg_hslot_bu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * BEFORE UPDATE on PHone | ||||||
|  | -- *	- do delete/insert instead of update if name changes | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_phone_bu() returns opaque as ' | ||||||
|  | begin | ||||||
|  |     if new.slotname != old.slotname then | ||||||
|  |         delete from PHone where slotname = old.slotname; | ||||||
|  | 	insert into PHone ( | ||||||
|  | 		    slotname, | ||||||
|  | 		    comment, | ||||||
|  | 		    slotlink | ||||||
|  | 		) values ( | ||||||
|  | 		    new.slotname, | ||||||
|  | 		    new.comment, | ||||||
|  | 		    new.slotlink | ||||||
|  | 		); | ||||||
|  |         return null; | ||||||
|  |     end if; | ||||||
|  |     return new; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  | create trigger tg_phone_bu before update | ||||||
|  |     on PHone for each row execute procedure tg_phone_bu(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * AFTER INSERT or UPDATE or DELETE on slot with backlink | ||||||
|  | -- *	- Ensure that the opponent correctly points back to us | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_backlink_a() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     dummy	integer; | ||||||
|  | begin | ||||||
|  |     if tg_op = ''INSERT'' then | ||||||
|  |         if new.backlink != '''' then | ||||||
|  | 	    dummy := tg_backlink_set(new.backlink, new.slotname); | ||||||
|  | 	end if; | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''UPDATE'' then | ||||||
|  |         if new.backlink != old.backlink then | ||||||
|  | 	    if old.backlink != '''' then | ||||||
|  | 	        dummy := tg_backlink_unset(old.backlink, old.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	    if new.backlink != '''' then | ||||||
|  | 	        dummy := tg_backlink_set(new.backlink, new.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	else | ||||||
|  | 	    if new.slotname != old.slotname and new.backlink != '''' then | ||||||
|  | 	        dummy := tg_slotlink_set(new.backlink, new.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	end if; | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''DELETE'' then | ||||||
|  |         if old.backlink != '''' then | ||||||
|  | 	    dummy := tg_backlink_unset(old.backlink, old.slotname); | ||||||
|  | 	end if; | ||||||
|  | 	return old; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create trigger tg_backlink_a after insert or update or delete | ||||||
|  |     on PSlot for each row execute procedure tg_backlink_a('PS'); | ||||||
|  |  | ||||||
|  | create trigger tg_backlink_a after insert or update or delete | ||||||
|  |     on WSlot for each row execute procedure tg_backlink_a('WS'); | ||||||
|  |  | ||||||
|  | create trigger tg_backlink_a after insert or update or delete | ||||||
|  |     on PLine for each row execute procedure tg_backlink_a('PL'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * Support function to set the opponents backlink field | ||||||
|  | -- * if it does not already point to the requested slot | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_backlink_set(bpchar, bpchar) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     myname	alias for $1; | ||||||
|  |     blname	alias for $2; | ||||||
|  |     mytype	char(2); | ||||||
|  |     link	char(4); | ||||||
|  |     rec		record; | ||||||
|  | begin | ||||||
|  |     mytype := substr(myname, 1, 2); | ||||||
|  |     link := mytype || substr(blname, 1, 2); | ||||||
|  |     if link = ''PLPL'' then | ||||||
|  |         raise exception  | ||||||
|  | 		''backlink between two phone lines does not make sense''; | ||||||
|  |     end if; | ||||||
|  |     if link in (''PLWS'', ''WSPL'') then | ||||||
|  |         raise exception  | ||||||
|  | 		''direct link of phone line to wall slot not permitted''; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PS'' then | ||||||
|  |         select into rec * from PSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink != blname then | ||||||
|  | 	    update PSlot set backlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink != blname then | ||||||
|  | 	    update WSlot set backlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PL'' then | ||||||
|  |         select into rec * from PLine where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink != blname then | ||||||
|  | 	    update PLine set backlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     raise exception ''illegal backlink beginning with %'', mytype; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * Support function to clear out the backlink field if | ||||||
|  | -- * it still points to specific slot | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_backlink_unset(bpchar, bpchar) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     myname	alias for $1; | ||||||
|  |     blname	alias for $2; | ||||||
|  |     mytype	char(2); | ||||||
|  |     rec		record; | ||||||
|  | begin | ||||||
|  |     mytype := substr(myname, 1, 2); | ||||||
|  |     if mytype = ''PS'' then | ||||||
|  |         select into rec * from PSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink = blname then | ||||||
|  | 	    update PSlot set backlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink = blname then | ||||||
|  | 	    update WSlot set backlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PL'' then | ||||||
|  |         select into rec * from PLine where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.backlink = blname then | ||||||
|  | 	    update PLine set backlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * AFTER INSERT or UPDATE or DELETE on slot with slotlink | ||||||
|  | -- *	- Ensure that the opponent correctly points back to us | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_slotlink_a() returns opaque as ' | ||||||
|  | declare | ||||||
|  |     dummy	integer; | ||||||
|  | begin | ||||||
|  |     if tg_op = ''INSERT'' then | ||||||
|  |         if new.slotlink != '''' then | ||||||
|  | 	    dummy := tg_slotlink_set(new.slotlink, new.slotname); | ||||||
|  | 	end if; | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''UPDATE'' then | ||||||
|  |         if new.slotlink != old.slotlink then | ||||||
|  | 	    if old.slotlink != '''' then | ||||||
|  | 	        dummy := tg_slotlink_unset(old.slotlink, old.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	    if new.slotlink != '''' then | ||||||
|  | 	        dummy := tg_slotlink_set(new.slotlink, new.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	else | ||||||
|  | 	    if new.slotname != old.slotname and new.slotlink != '''' then | ||||||
|  | 	        dummy := tg_slotlink_set(new.slotlink, new.slotname); | ||||||
|  | 	    end if; | ||||||
|  | 	end if; | ||||||
|  | 	return new; | ||||||
|  |     end if; | ||||||
|  |     if tg_op = ''DELETE'' then | ||||||
|  |         if old.slotlink != '''' then | ||||||
|  | 	    dummy := tg_slotlink_unset(old.slotlink, old.slotname); | ||||||
|  | 	end if; | ||||||
|  | 	return old; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on PSlot for each row execute procedure tg_slotlink_a('PS'); | ||||||
|  |  | ||||||
|  | create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on WSlot for each row execute procedure tg_slotlink_a('WS'); | ||||||
|  |  | ||||||
|  | create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on IFace for each row execute procedure tg_slotlink_a('IF'); | ||||||
|  |  | ||||||
|  | create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on HSlot for each row execute procedure tg_slotlink_a('HS'); | ||||||
|  |  | ||||||
|  | create trigger tg_slotlink_a after insert or update or delete | ||||||
|  |     on PHone for each row execute procedure tg_slotlink_a('PH'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * Support function to set the opponents slotlink field | ||||||
|  | -- * if it does not already point to the requested slot | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_slotlink_set(bpchar, bpchar) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     myname	alias for $1; | ||||||
|  |     blname	alias for $2; | ||||||
|  |     mytype	char(2); | ||||||
|  |     link	char(4); | ||||||
|  |     rec		record; | ||||||
|  | begin | ||||||
|  |     mytype := substr(myname, 1, 2); | ||||||
|  |     link := mytype || substr(blname, 1, 2); | ||||||
|  |     if link = ''PHPH'' then | ||||||
|  |         raise exception  | ||||||
|  | 		''slotlink between two phones does not make sense''; | ||||||
|  |     end if; | ||||||
|  |     if link in (''PHHS'', ''HSPH'') then | ||||||
|  |         raise exception  | ||||||
|  | 		''link of phone to hub does not make sense''; | ||||||
|  |     end if; | ||||||
|  |     if link in (''PHIF'', ''IFPH'') then | ||||||
|  |         raise exception  | ||||||
|  | 		''link of phone to hub does not make sense''; | ||||||
|  |     end if; | ||||||
|  |     if link in (''PSWS'', ''WSPS'') then | ||||||
|  |         raise exception  | ||||||
|  | 		''slotlink from patchslot to wallslot not permitted''; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PS'' then | ||||||
|  |         select into rec * from PSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update PSlot set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update WSlot set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''IF'' then | ||||||
|  |         select into rec * from IFace where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update IFace set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''HS'' then | ||||||
|  |         select into rec * from HSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update HSlot set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PH'' then | ||||||
|  |         select into rec * from PHone where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    raise exception ''% does not exists'', myname; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink != blname then | ||||||
|  | 	    update PHone set slotlink = blname where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     raise exception ''illegal slotlink beginning with %'', mytype; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * Support function to clear out the slotlink field if | ||||||
|  | -- * it still points to specific slot | ||||||
|  | -- ************************************************************ | ||||||
|  | create function tg_slotlink_unset(bpchar, bpchar) | ||||||
|  | returns integer as ' | ||||||
|  | declare | ||||||
|  |     myname	alias for $1; | ||||||
|  |     blname	alias for $2; | ||||||
|  |     mytype	char(2); | ||||||
|  |     rec		record; | ||||||
|  | begin | ||||||
|  |     mytype := substr(myname, 1, 2); | ||||||
|  |     if mytype = ''PS'' then | ||||||
|  |         select into rec * from PSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update PSlot set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update WSlot set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''IF'' then | ||||||
|  |         select into rec * from IFace where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update IFace set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''HS'' then | ||||||
|  |         select into rec * from HSlot where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update HSlot set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  |     if mytype = ''PH'' then | ||||||
|  |         select into rec * from PHone where slotname = myname; | ||||||
|  | 	if not found then | ||||||
|  | 	    return 0; | ||||||
|  | 	end if; | ||||||
|  | 	if rec.slotlink = blname then | ||||||
|  | 	    update PHone set slotlink = '''' where slotname = myname; | ||||||
|  | 	end if; | ||||||
|  | 	return 0; | ||||||
|  |     end if; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										141
									
								
								contrib/plpgsql/test/views.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								contrib/plpgsql/test/views.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | -- ************************************************************ | ||||||
|  | -- * Describe the backside of a patchfield slot | ||||||
|  | -- ************************************************************ | ||||||
|  | create function pslot_backlink_view(bpchar) | ||||||
|  | returns text as ' | ||||||
|  | <<outer>> | ||||||
|  | declare | ||||||
|  |     rec		record; | ||||||
|  |     bltype	char(2); | ||||||
|  |     retval	text; | ||||||
|  | begin | ||||||
|  |     select into rec * from PSlot where slotname = $1; | ||||||
|  |     if not found then | ||||||
|  |         return ''''; | ||||||
|  |     end if; | ||||||
|  |     if rec.backlink = '''' then | ||||||
|  |         return ''-''; | ||||||
|  |     end if; | ||||||
|  |     bltype := substr(rec.backlink, 1, 2); | ||||||
|  |     if bltype = ''PL'' then | ||||||
|  |         declare | ||||||
|  | 	    rec		record; | ||||||
|  | 	begin | ||||||
|  | 	    select into rec * from PLine where slotname = outer.rec.backlink; | ||||||
|  | 	    retval := ''Phone line '' || trim(rec.phonenumber); | ||||||
|  | 	    if rec.comment != '''' then | ||||||
|  | 	        retval := retval || '' (''; | ||||||
|  | 		retval := retval || rec.comment; | ||||||
|  | 		retval := retval || '')''; | ||||||
|  | 	    end if; | ||||||
|  | 	    return retval; | ||||||
|  | 	end; | ||||||
|  |     end if; | ||||||
|  |     if bltype = ''WS'' then | ||||||
|  |         select into rec * from WSlot where slotname = rec.backlink; | ||||||
|  | 	retval := trim(rec.slotname) || '' in room ''; | ||||||
|  | 	retval := retval || trim(rec.roomno); | ||||||
|  | 	retval := retval || '' -> ''; | ||||||
|  | 	return retval || wslot_slotlink_view(rec.slotname); | ||||||
|  |     end if; | ||||||
|  |     return rec.backlink; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * Describe the front of a patchfield slot | ||||||
|  | -- ************************************************************ | ||||||
|  | create function pslot_slotlink_view(bpchar) | ||||||
|  | returns text as ' | ||||||
|  | declare | ||||||
|  |     psrec	record; | ||||||
|  |     sltype	char(2); | ||||||
|  |     retval	text; | ||||||
|  | begin | ||||||
|  |     select into psrec * from PSlot where slotname = $1; | ||||||
|  |     if not found then | ||||||
|  |         return ''''; | ||||||
|  |     end if; | ||||||
|  |     if psrec.slotlink = '''' then | ||||||
|  |         return ''-''; | ||||||
|  |     end if; | ||||||
|  |     sltype := substr(psrec.slotlink, 1, 2); | ||||||
|  |     if sltype = ''PS'' then | ||||||
|  | 	retval := trim(psrec.slotlink) || '' -> ''; | ||||||
|  | 	return retval || pslot_backlink_view(psrec.slotlink); | ||||||
|  |     end if; | ||||||
|  |     if sltype = ''HS'' then | ||||||
|  |         retval := comment from Hub H, HSlot HS | ||||||
|  | 			where HS.slotname = psrec.slotlink | ||||||
|  | 			  and H.name = HS.hubname; | ||||||
|  |         retval := retval || '' slot ''; | ||||||
|  | 	retval := retval || slotno::text from HSlot | ||||||
|  | 			where slotname = psrec.slotlink; | ||||||
|  | 	return retval; | ||||||
|  |     end if; | ||||||
|  |     return psrec.slotlink; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * Describe the front of a wall connector slot | ||||||
|  | -- ************************************************************ | ||||||
|  | create function wslot_slotlink_view(bpchar) | ||||||
|  | returns text as ' | ||||||
|  | declare | ||||||
|  |     rec		record; | ||||||
|  |     sltype	char(2); | ||||||
|  |     retval	text; | ||||||
|  | begin | ||||||
|  |     select into rec * from WSlot where slotname = $1; | ||||||
|  |     if not found then | ||||||
|  |         return ''''; | ||||||
|  |     end if; | ||||||
|  |     if rec.slotlink = '''' then | ||||||
|  |         return ''-''; | ||||||
|  |     end if; | ||||||
|  |     sltype := substr(rec.slotlink, 1, 2); | ||||||
|  |     if sltype = ''PH'' then | ||||||
|  |         select into rec * from PHone where slotname = rec.slotlink; | ||||||
|  | 	retval := ''Phone '' || trim(rec.slotname); | ||||||
|  | 	if rec.comment != '''' then | ||||||
|  | 	    retval := retval || '' (''; | ||||||
|  | 	    retval := retval || rec.comment; | ||||||
|  | 	    retval := retval || '')''; | ||||||
|  | 	end if; | ||||||
|  | 	return retval; | ||||||
|  |     end if; | ||||||
|  |     if sltype = ''IF'' then | ||||||
|  | 	declare | ||||||
|  | 	    syrow	System%RowType; | ||||||
|  | 	    ifrow	IFace%ROWTYPE; | ||||||
|  |         begin | ||||||
|  | 	    select into ifrow * from IFace where slotname = rec.slotlink; | ||||||
|  | 	    select into syrow * from System where name = ifrow.sysname; | ||||||
|  | 	    retval := syrow.name || '' IF ''; | ||||||
|  | 	    retval := retval || ifrow.ifname; | ||||||
|  | 	    if syrow.comment != '''' then | ||||||
|  | 	        retval := retval || '' (''; | ||||||
|  | 		retval := retval || syrow.comment; | ||||||
|  | 		retval := retval || '')''; | ||||||
|  | 	    end if; | ||||||
|  | 	    return retval; | ||||||
|  | 	end; | ||||||
|  |     end if; | ||||||
|  |     return rec.slotlink; | ||||||
|  | end; | ||||||
|  | ' language 'plpgsql'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ************************************************************ | ||||||
|  | -- * View of a patchfield describing backside and patches | ||||||
|  | -- ************************************************************ | ||||||
|  | create view Pfield_v1 as select PF.pfname, PF.slotname, | ||||||
|  | 	pslot_backlink_view(PF.slotname) as backside, | ||||||
|  | 	pslot_slotlink_view(PF.slotname) as patch | ||||||
|  |     from PSlot PF; | ||||||
|  |  | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user