mirror of https://github.com/postgres/postgres
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? Janpull/50/head
parent
212f7bdfe3
commit
863a62064c
@ -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. |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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. |
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -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'; |
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -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 */ |
@ -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; |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -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. |
||||||
|
|
||||||
|
|
@ -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); |
@ -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) |
@ -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'; |
@ -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; |
@ -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'; |
||||||
|
|
@ -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 |
||||||
|
|
@ -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); |
||||||
|
|
||||||
|
|
@ -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', ''); |
@ -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'; |
||||||
|
|
||||||
|
|
@ -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; |
||||||
|
|
||||||
|
|
Loading…
Reference in new issue