You are on page 1of 133

Overview of PSQL Stored Procedures A PSQL stored procedure is a self-contained program written in Firebird's PSQL language, and stored

as part of a the database metadata. Once you have created a stored procedure, you can invoke it directly from an application, or substitute the procedure for a table or view in a SELECT statement. Stored procedures can receive input parameters from and return values to applications. Firebird's PSQL language includes the standard SQL data manipulation statements and some powerful procedural extensions, such as assignments, flow control, cursors, exceptions, and error handling. The PSQL language is very similar, but not identical, to the PSM (Persistent Stored Modules) extension of the SQL200x standard. The advantages of using stored procedures include: Modular design Applications that access the same database can share stored procedures, eliminating duplicate code and reducing the size of the applications. Streamlined maintenance When a procedure is updated, the changes are automatically reflected in all applications that use it without the need to recompile and relink them; applications are compiled and optimized only once for each client Improved performance Stored procedures are executed by the server, not the client, which reduces network traffic, and improves performanceespecially for remote client access

Calling stored procedures Stored procedures can be used both from applications using dynamic SQL access (such as applications using the ODBC, JDBC or ADO.Net technologies) and from applications using embedded SQL statements (as was common in applications written before the mid-nineties). For more information on calling stored procedures from the latter type of applications, see the Embedded SQL Manual. There are two types of stored procedures: Executable procedures that an application can call directly with the EXECUTE PROCEDURE statement. An executable procedure can optionally return values to the calling program. SELECT procedures that an application can use in place of a table or view in a SELECT statement. A select procedure must be defined to return one or more values (output parameters), or an error results.

Both kinds of procedures are defined with the CREATE PROCEDURE statement and have essentially the same syntax. The difference is in how the procedure is written and how it is intended to be used. Select procedures can return more than one row, so that to the calling program they appear as a table or view. Executable procedures are routines invoked by the calling program, which can optionally return values. In fact, a single procedure can be used as a select procedure or as an executable procedure, but in general a procedure is written specifically to be used in a SELECT statement (a select procedure) or to be used in an EXECUTE PROCEDURE statement (an executable procedure). Privileges for stored procedures

To use a stored procedure, a user must be the creator of the procedure or must be given EXECUTE privilege for it. A procedure executes with the privileges of the user and role currently associated with the connection (session). Stored procedures themselves sometimes need access to tables or views for which a user does not or should not have privileges. For such cases the procedure can be granted privileges itself. These privileges are also available to the procedure during its execution, in addition to the privileges of the user/role invoking the procedure. Creating nested and recursive procedures A stored procedure can itself execute a stored procedure. Each time a stored procedure calls another procedure, the call is said to be nested because it occurs in the context of a previous and still active call to the first procedure. A stored procedure called by another stored procedure is known as a nested procedure. If a procedure calls itself, it is recursive. Recursive procedures are useful for tasks that involve repetitive steps. Each invocation of a procedure is referred to as an instance, since each procedure call is a separate entity that performs as if called from an application, reserving memory and stack space as required to perform its tasks. Error behaviour When a procedure encounters an error either a system error or a user-defined exception all statements since the last SUSPEND are undone. Since select procedures can have multiple SUSPENDs, possibly inside a loop statement, only the actions since the last SUSPEND are undone. Since executable procedures should not use SUSPEND, when an error occurs the entire executable procedure is undone (if EXIT is used, as recommended). Altering and dropping procedures in use You must make special considerations when making changes to stored procedures that are currently in use by other requests. A procedure is in use when it is currently executing, or if it has been compiled internally to the metadata cache by a request. Changes to procedures are not visible to client applications until they disconnect and reconnect to the database; triggers and procedures that invoke altered procedures dont have access to the new version until there is a point in which all clients are disconnected. To simplify the task of altering or dropping stored procedures, it is highly recommended to perform this task during a maintenance period when no client applications are connected to the database. By doing this, all client applications see the same version of a stored procedure before and after you make an alteration.

CREATE PROCEDURE Purpose Use CREATE PROCEDURE to create a new stored procedure, and define its input and output parameters, and body. Security and prerequisites To use a stored procedure, a user must be the creator of the procedure or must be given EXECUTE privilege for it. Firebird limits changes to database objects that currently existing procedures depend on. Syntax
<create_proc_stmt> ::= CREATE [ OR ALTER ] PROCEDURE <proc_name> [ ( <input_params> ) ] [ RETURNS ( <output_params> ) ] AS <psql_body> <proc_name> ::= <identifier>

Element
proc_name

Description Name of the procedure. Must be unique among procedure, table, and view names in the database List of input parameters as described on the next pages. List of output parameters as described on the next pages. A PSQL program

input_params output_params psql_body

Semantics CREATE PROCEDURE defines a new stored procedure to a database. A stored procedure is a self-contained program written in the PSQL language, and stored as part of a database's metadata. Stored procedures can receive input parameters from and return values to applications. If the optional OR ALTER clause is pecified, the statement that will either create a new procedure (if it does not already exist) or alter it (if it already exists) and recompile it. The CREATE OR ALTER syntax preserves existing dependencies and privileges. Examples The following procedure, SUB_TOT_BUDGET, takes a department number as its input parameter, and returns the total, average, minimum, and maximum budgets of departments with the specified HEAD_DEPT.
/* Compute total, average, smallest, and largest department budget. *Parameters: * department id * *Returns:

* * * *

total budget average budget min budget max budget */

CREATE PROCEDURE SUB_TOT_BUDGET (HEAD_DEPT CHAR(3)) RETURNS (tot_budget DECIMAL(12, 2), avg_budget DECIMAL(12, 2), min_budget DECIMAL(12, 2), max_budget DECIMAL(12, 2)) AS BEGIN SELECT SUM(BUDGET), AVG(BUDGET), MIN(BUDGET), MAX(BUDGET) FROM DEPARTMENT WHERE HEAD_DEPT = :head_dept INTO :tot_budget, :avg_budget, :min_budget, :max_budget; EXIT; END

See also PROCEDURES INPUT PARAMETERS, PROCEDURES OUTPUT PARAMETERS, ALTER PROCEDURE, DROP PROCEDURE

PROCEDURES INPUT PARAMETERS Purpose Use input parameters to specify input values to the procedure. Syntax
<input_params> ::= <input_param> | <input_param> , <input_params> <input_param> ::= <param_name> <psql_type> [ { = | DEFAULT } <param_default> ] <param_name> ::= <identifier>

<param_default> ::= <psql_constant> | <psql_sys_fun>

Semantics Input parameters are local variables that contain copies of values passed to it in the procedure call. New values assigned to input parameters during execution of the body are local to that body and not visible to the caller. Arguments with default values must be last in the argument list; that is, you cannot declare an argument that has no default value after any arguments that have been declared with default values. The caller must supply the values for all of the arguments preceding any that are to use their defaults. Substitution of default values occurs at run-time. If you define a procedure with defaults (say P1), call it from another procedure (say P2) and skip some final, defaulted arguments, then the default values for P1 will be substituted by the engine at time execution P1 starts. This means that, if you change the default values for P1, it is not necessary to recompile P2. Examples The following procedure logs an error description, or the text 'Undefined error' if no description is given in the procedure call.
CREATE PROCEDURE fac ( n CHAR(128) = 'Undefined error' ) AS BEGIN INSERT INTO log VALUES ( :n ); END;

See Also CREATE PROCEDURE, ALTER PROCEDURE

PROCEDURES OUTPUT PARAMETERS Purpose Use output parameters to specify placeholders for the values that the procedure returns to the caller. Syntax
<output_params> ::= <output_param> | <output_param> , <output_params> <output_param> ::= <param_name> ::= <param_name> <psql_type> <identifier>

Semantics Output parameters are local variables that are placeholders for the values that the procedure body returns to the caller. When a SUSPEND statement is enountered, the values in the the output parameters are copied to the calling statement and control is temporarily returned to the caller. Examples The following procedure definition computes a factorial:
CREATE PROCEDURE fac ( n BIGINT ) RETURNS m BIGINT AS BEGIN IF (n=1) THEN m=1; ELSE EXECUTE PROCEDURE fac(n-1) INTO :m; END;

See Also CREATE PROCEDURE, ALTER PROCEDURE

ALTER PROCEDURE Purpose Use ALTER PROCEDURE to change the definition of an existing stored procedure. Security and prerequisites A procedure can be altered by its creator, the SYSDBA user, and any users with operating system root privileges. Syntax
<alter_proc_stmt> ::= ALTER PROCEDURE <proc_name> [ ( <input_params> ) ] [ RETURNS ( <output_params> ) ] AS <psql_body> <proc_name> ::= <identifier>

Element
proc_name

Description Name of the procedure. Must be unique among procedure, table, and view names in the database List of input parameters as described on the next pages. List of output parameters as described on the next pages. A PSQL program body

input_params output_params psql_body

Semantics ALTER PROCEDURE changes an existing stored procedure without affecting its dependencies. It can modify a procedure's input parameters, output parameters, and body. The complete procedure header and body must be included in the ALTER PROCEDURE statement. The syntax is exactly the same as CREATE PROCEDURE, except CREATE is replaced by ALTER. Note: Be careful about changing the type, number, and order of input and output parameters to a procedure, since existing application code may assume the procedure has its original format. Procedures in use are not altered until they are no longer in use. ALTER PROCEDURE changes take effect when they are committed. Changes are then reflected in all applications that use the procedure without recompiling or relinking. Examples The following statements alter the GET_EMP_PROJ procedure, changing the return parameter to have a datatype of VARCHAR(20):
ALTER PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) RETURNS (PROJ_ID VARCHAR(20)) AS BEGIN

FOR SELECT PROJ_ID FROM EMPLOYEE_PROJECT WHERE EMP_NO = :emp_no INTO :proj_id DO SUSPEND; END

See Also CREATE PROCEDURE, DROP PROCEDURE

DROP PROCEDURE Purpose Use the DROP PROCEDURE statement to delete an existing stored procedure from a database. Security and prerequisites The following restrictions apply to dropping procedures: You cant drop a procedure used by other procedures, triggers, or views; alter the other database object so that it does not reference the procedure, then drop the procedure. You cant drop a procedure that is recursive or in a cyclical dependency with another procedure; you must ALTER the procedure to remove the cyclical dependency, then drop the procedure. You cant drop a procedure that is currently in use by an active transaction; commit the transaction, then drop the procedure.

A procedure can be dropped by its creator, the SYSDBA user, and any users with operating system root privileges. Syntax
<drop_proc_stmt> ::= DROP PROCEDURE <proc_name> <proc_name> ::= <identifier>

Element
proc_name

Description Name of an existing stored procedure

Semantics DROP PROCEDURE removes an existing stored procedure definition from a database. You cannot drop a procedure if another database object depends on it. Use the isql SHOW PROCEDURE command to display a list of a procedure's dependencies. Examples The following statement deletes a procedure:
DROP PROCEDURE GET_EMP_PROJ;

See Also ALTER PROCEDURE, CREATE PROCEDURE Overview of PSQL Triggers A trigger is a self-contained PSQL routine associated with a table or view that automatically performs an action when a row in the table or view is inserted, updated, or deleted.

A trigger is never called directly. Instead, when an application or user attempts to INSERT, UPDATE, or DELETE a row in a table or view, any triggers associated with that table or view, and that operation are automatically executed, or fired. Triggers can make use of exceptions. When an exception is raised by a trigger, it returns an error message, terminates the trigger, and undoes any changes made by the trigger, unless the exception is handled by an exception handler in the trigger's PSQL main body routine. The advantages of using triggers are: Automatic enforcement of data restrictions Triggers make it possible to ensure that application programs enter only valid values into columns. Reduced application maintenance Changes to a trigger are automatically reflected in all applications that use the associated table without the need to recompile and relink. Automatic logging of changes to tables An application can keep a running log of changes with a trigger that fires whenever a table is modified. Automatic notification of changes to the database With event alerters in triggers an application can be notified automatically when certain changes to the database take place.

Triggers are database objects, like tables, views, stored procedures, exceptions, etc. Execution of triggers A trigger is never explicitly called. Rather, an active trigger automatically fires when the specified action occurs on the specified table. If a trigger performs an action that causes it to fire again or fires another trigger that performs an action that causes it to fire an infinite loop results. For this reason, it is important to ensure that a triggers actions never cause the trigger to fire, even indirectly. For example, an endless loop will occur if a trigger fires on INSERT to a table and then performs an INSERT into the same table. Triggers and transactions Triggers operate within the context of the transaction in the program where they are fired. Triggers are considered part of the calling programs current unit of work. If triggers are fired in a transaction, and the transaction is rolled back, then any actions performed by the triggers are also rolled back. Triggers and security Triggers can be granted privileges on tables and views, just as users or procedures can be granted privileges. Use the GRANT statement to grant privileges to triggers and the REVOKE statement to revoke them again.For more information about GRANT and REVOKE, see the SQL Reference Manual. When a user performs an action that fires a trigger, the trigger will have privileges to perform its actions if either the trigger has privileges for the action, or

the user has privileges for the action

So, for example, if a user performs an UPDATE of table A, which fires a trigger, and the trigger performs an INSERT on table B, the INSERT will occur if: the user has insert privileges on table B, or the trigger has insert privileges on table B.

If there are insufficient privileges for a trigger to perform its actions, Firebird will set the appropriate error number. The trigger program can handle this error with an error handler. If the trigger program does not handle the error, an error message will be returned to the application, and the actions of the trigger and the user application statement which led to the trigger to be fired will be undone. The NEW and OLD pseudo tables Triggers can use two pseudo tables in their PSQL body routines, OLD, and NEW: the OLD pseudo table refers to the current values in a row being updated or deleted. OLD is not used for inserts. The NEW pseudo table refers the set of INSERT or UPDATE values for a row. If a BEFORE trigger updates the NEW pseudo table, those updated values will used. Changing the NEW pseudo table in a AFTER trigger has no effect. The NEW pseudo table is not used for deletes.

Pseudo tables are often used to compare the values of a column before and after it is modified, or to validate the new values. Trigger predicates Triggers can use three pseudo variables, the so-called trigger predicates. The three variables are: INSERTING. This pseudo variable evaluates to true when the trigger is fired as a result of an INSERT action on the base table or view, and to false otherwise. UPDATING. This pseudo variable evaluates to true when the trigger is fired as a result of an UPDATE action to the base table or view, and to false otherwise. DELETING. This pseudo variable evaluates to true when the trigger is fired as a result of an DELETETE action to the base table or view, and to false otherwise.

Trigger predicates are particularly useful when in the PSQL routine bodies of multi-action triggers, i.e. triggers that can fire as the result of more than one type of action on the base table. Updating views with triggers Views that are based on joins and on aggregates cannot be updated directly. You can, however, write triggers that will perform the correct writes to the base tables when a DELETE, UPDATE, or INSERT is performed on the view. This Firebird feature turns non-updatable views into updatable views. You can specify non default behavior for updatable views, as well. Firebird does not perform write-throughs on any view that has one or more triggers defined on it. This means that you can have complete control of what happens to any base table when users modify a view based on it.

CREATE TRIGGER Purpose Use CREATE TRIGGER to create or optionally alter a trigger, including when it fires, and what actions it performs. Security and prerequisites To create a trigger the user must be SYSDBA or have full privileges on the underlying table or view. Syntax
<create_trigger_stmt> ::= CREATE [ OR ALTER ] TRIGGER <tigger_name> FOR <relation_name> [ACTIVE | INACTIVE] <trigger_action_clause> [ <trigger_position_clause> ] AS <psql_body> <trigger_name> ::= <relation_name> ::= <identifier> <identifier>

Element
trigger_name relation_name

Description Name of the trigger; must be unique in the database Name of the table or view that causes the trigger to fire when the specified action occurs on the table or view

Semantics CREATE TRIGGER defines a new trigger to a database. A trigger is a self-contained program associated with a table or view that automatically performs an action when a row in the table or view is inserted, updated, or deleted. A trigger is never called directly. Instead, when an application or user attempts to INSERT, UPDATE, or DELETE a row in a table, any triggers associated with that table and operation automatically execute, or fire. Triggers defined for UPDATE on non-updatable views fire even if no update occurs. If the optional OR ALTER clause is pecified, the statement that will either create a new trigger (if it does not already exist) or alter it (if it already exists) and recompile it. The CREATE OR ALTER syntax preserves existing dependencies and privileges. Examples The following trigger, SAVE_SALARY_CHANGE, makes correlated updates to the SALARY_HISTORY table when a change is made to an employee's salary in the EMPLOYEE table:
CREATE TRIGGER SAVE_SALARY_CHANGE FOR EMPLOYEE AFTER UPDATE AS BEGIN IF (OLD.SALARY <> NEW.SALARY) THEN INSERT INTO SALARY_HISTORY

(EMP_NO, CHANGE_DATE, UPDATER_ID, OLD_SALARY, PERCENT_CHANGE ) VALUES ( OLD.EMP_NO, 'now', USER, OLD.SALARY, (NEW.SALARY/OLD.SALARY-1) * 100 ); END;

The following trigger, SET_CUST_NO, uses a generator to create unique customer numbers when a new customer record is inserted in the CUSTOMER table:
CREATE TRIGGER SET_CUST_NO FOR CUSTOMER BEFORE INSERT AS BEGIN NEW.CUST_NO = GEN_ID(CUST_NO_GEN, 1); END;

The following trigger, POST_NEW_ORDER, posts an event named "new_order" whenever a new record is inserted in the SALES table:
CREATE TRIGGER POST_NEW_ORDER FOR SALES AFTER INSERT AS BEGIN POST_EVENT 'new_order'; END;

See also ALTER TRIGGER, DROP TRIGGER

TRIGGER ACTION CLAUSE Purpose Use the action clause to specify which actions cause the trigger to fire Syntax
<trigger_action_clause> ::= { BEFORE | AFTER } <trigger_action> [OR <trigger_action> [OR <trigger_action>]] <trigger_action ::= INSERT | UPDATE | DELETE

Semantics The trigger action clause specifies when a tirgger will fire. A trigger can fire before or after the changes to the underlying table occurs. This is specified with the BEFORE or AFTER keyword and specifying one of the two is obligatory. A trigger can fire on either an INSERT, UPDATE or DELETE operation on the base table or view, or on a combination of two or three of these. The pseudo boolean variables INSERTING, UPDATING and DELETING are available in the trigger body to let the code determine which operation caused the trigger to fire.

If the trigger is based on a view, then no automatic update to the underlying tables occur, even if the view is updateable. In this casse BEFORE is identical to AFTER, other than that all BEFORE triggers run before the AFTER triggers. Examples The below trigger action clause specifies that the trigger should fire before the change to the base table in case of insert and update operations:
BEFORE INSERT OR UPDATE

See also CREATE TRIGGER, ALTER TRIGGER

TRIGGER - POSITION CLAUSE Purpose Use the POSITION clause to specify the order in which multiple triggers on the same table fire. Syntax
<trigger_position_clause> ::= POSITION <psql_integer>

Element
psql_integer

Description Integer number between 0 and 32767

Sematics Specifies firing order for triggers before the same action or after the same action; the position number must be an integer between 0 and 32767. The default position is zero, which is the first position to fire. Triggers fire in order of ascending position numbers. Trigger numbers for a table and action need not be consecutive; triggers on the same action with the same position number will fire in random order. Examples The following four fragments of trigger headers demonstrate how the POSITION option determines trigger firing order:
CREATE TRIGGER A FOR accounts BEFORE UPDATE POSITION 5 ... /*Trigger body follows*/ CREATE TRIGGER B FOR accounts BEFORE UPDATE POSITION 0 ... /*Trigger body follows*/ CREATE TRIGGER C FOR accounts AFTER UPDATE POSITION 5 ... /*Trigger body follows*/ CREATE TRIGGER D FOR accounts AFTER UPDATE POSITION 3 ... /*Trigger body follows*/

When this update takes place:


UPDATE accounts SET account_status = 'on_hold' WHERE account_balance <0;

The triggers fire in this order: 1. Trigger B fires. 2. Trigger A fires. 3. The update occurs. 4. Trigger D fires. 5. Trigger C fires.

See Also CREATE TRIGGER, ALTER TRIGGER

ALTER TRIGGER Purpose Use ALTER TRIGGER to change any part of an existing trigger. Security and prerequisites A trigger can be altered by its creator, the SYSDBA user, and any users with operating system root privileges. Syntax
<alter_trigger_stmt> ::= ALTER TRIGGER <trigger_name> [ACTIVE | INACTIVE] <trigger_action_clause> [ <trigger_position_clause> ] [AS <psql_body>] <trigger_name> ::= <identifier>

Semantics ALTER TRIGGER changes the definition of an existing trigger. If any of the arguments to ALTER TRIGGER are omitted, then they default to their current values, that is the value specified by CREATE TRIGGER, or the last ALTER TRIGGER. ALTER TRIGGER can change: Header information only, including the trigger activation status, when it performs its actions, the event that fires the trigger, and the order in which the trigger fires compared to other triggers. Body information only, the trigger statements that follow the AS clause. Header and trigger body information. In this case, the new trigger definition replaces the old trigger definition.

Note: To alter a trigger defined automatically by a CHECK constraint on a table, use ALTER TABLE to change the constraint definition. Examples The following statement modifies the trigger, SET_CUST_NO, to be inactive:
ALTER TRIGGER SET_CUST_NO INACTIVE

The next statement modifies the trigger, SET_CUST_NO, to insert a row into the table, NEW_CUSTOMERS, for each new customer:
ALTER TRIGGER SET_CUST_NO FOR CUSTOMER BEFORE INSERT AS BEGIN NEW.CUST_NO = GEN_ID(CUST_NO_GEN, 1); INSERT INTO NEW_CUSTOMERS(NEW.CUST_NO, TODAY) END

See Also CREATE TRIGGER, DROP TRIGGER

DROP TRIGGER Purpose Use DROP TRIGGER to delete an existing user-defined trigger. Security and prerequisites A trigger can be altered by its creator, the SYSDBA user, and any users with operating system root privileges. Syntax
<drop_trigger_stmt> ::= DROP TRIGGER <trigger_name> <trigger_name> ::= <identifier>

Element
trigger_name

Description Name of an existing trigger

Semantics DROP TRIGGER removes a user-defined trigger definition from the database. System-defined triggers, such as those created for CHECK constraints, cannot be dropped. Use ALTER TABLE to drop the CHECK clause that defines the trigger. Triggers used by an active transaction cannot be dropped until the transaction is terminated. To inactivate a trigger temporarily, use ALTER TRIGGER and specify INACTIVE in the header. Examples The following statement drops the trigger ADD_NEW_COMPONENT:
DROP TRIGGER ADD_NEW_COMPONENT;

See Also ALTER TRIGGER, CREATE TRIGGER Overview of PSQL Exceptions An exception is a named user error message that can be raised from within a PSQL program. Exceptions are created with CREATE EXCEPTION, modified with ALTER EXCEPTION, and dropped with DROP EXCEPTION. A stored procedure raises an exception with the EXCEPTION statement. The advantages of using named user exceptions are: Easier code maintenance Working with named exceptions makes the PSQL code more readable to database application maintainers and helps in standardising error conditions within the application.

Improved error reporting System errors like Foreign key violation can be caught and reraised with a more descriptive user exception, e.g. Unkown employee number. Easier internationalisation of applications Error messages can be tailored to foreign languages by simply altering the named exceptions. The PSQL program code does not need to be changed, does not even have to be available.

Like for instance tables and stored procedures, exceptions are global database objects and once defined can be used by any PSQL program that needs them. However, exceptions must be created and committed before they can be raised. Exceptions and transactions Exceptions are user error conditions that Firebird handles the same as system exceptions, i.e. unless caught by an exception handler, all actions by the PSQL routine raising the exception are rolled back. The exception is then passed up to the PSQL routine's caller, where the same mechanism applies. If anexception reaches the outermost PSQL routine, the error condition is passed back to the application and the entire statement that called the PSQL routine is rolled back. For more information on catching and handling exceptions inside PSQL routines, see Chapter 4, PSQL Programs. Differences between user exceptions and system exceptions In many ways, user defined exceptions and system exceptions behave in the same way, and are often handled similarly in PSQL programs and in applications programs. There are, however, the following differences: System exceptions have numbers (the SQLCODE and the GDSCODE) and user exceptions have identifiers (i.e. names) The message associated with a system exception are stored in a system-wide error message database, whereas the message associated with a user exception are stored as database objects.

CREATE EXCEPTION Purpose Use CREATE EXCEPTION to create a used-defined error along with an associated message for use PSQL programs. Security and prerequisites Exceptions are global database objects (like tables, views, stored procedures, etc.). Exception names must be unique. Syntax
<create_exception_stmt> ::= CREATE EXCEPTION <exception_name> <psql_expr> <exeption_name> ::= <identifier>

Element
exception_name psql_expr

Description Name of the exception Expression evaluating to a text message associated with the exception condition

Semantics CREATE EXCEPTION creates an exception, a user-defined error with an associated message. Once created, exceptions may be raised in PSQL programs with the EXCEPTION statement. Examples This SQL statement creates the exception, BAD_EMP_ID:
CREATE EXCEPTION BAD_EMP_ID 'Invalid employee number.'

See Also ALTER EXCEPTION, DROP EXCEPTION

ALTER EXCEPTION Purpose Use ALTER EXCEPTION to changes the message associated with an existing exception. Security and prerequisites An exception can be altered by its creator, the SYSDBA user, and any users with operating system root privileges. You can alter an exception even when a stored procedure or a trigger is dependent on it Syntax
<alter_exception_stmt> ::= ALTER EXCEPTION <exception_name> <plsql_expr> <exeption_name> ::= <identifier>

Element
exception_name psql_expr

Description Name of an existing exception Expression evaluating to a text value

Semantics ALTER EXCEPTION changes the text of the associated message of a user exception. Examples This statement alters the English associated message of the exception in the CREATE EXCEPTION example into the Dutch equivalent.
ALTER EXCEPTION BAD_EMP_ID 'Werknemersnummer onbekend'

See Also CREATE EXCEPTION, DROP EXCEPTION

DROP EXCEPTION Purpose Use DROP EXCEPTION to delete an exception from a database. Security and prerequisites The following restrictions apply to dropping exceptions: Exceptions used in existing procedures and triggers cannot be dropped. Exceptions currently in use cannot be dropped.

An exception can be dropped by its creator, the SYSDBA user, and any users with operating system root privileges. Syntax
<drop_exception_stmt> ::= DROP EXCEPTION <execption_name> <exception_name> ::= <identifier>

Element
exception_name

Description Name of an existing exception

Semantics DROP EXCEPTION removes an exception from a database. Exceptions used in existing procedures and triggers cannot be dropped. Note: In the isql tool, the SHOW EXCEPTION command displays a list of the exceptions' dependencies, i.e. the procedures and triggers that use the exception. Examples This SQL statement drops an exception:
DROP EXCEPTION BAD_EMP_ID;

See Also CREATE EXCEPTION, ALTER EXCEPTION Overview of PSQL Programs A PSQL program is a self contained program unit that forms the body of a stored procedure or trigger. In this manual PSQL programs are also refered to as PSQL routines and PSQL procedure/tirgger bodies: these terms are used interchangeably. A PSQL program consists of three parts:

A variable declaration section PSQL programs can declare local variables. Local variables have datatypes that match the Firebird SQL types of the same name. This section is optional. An executable statement section The executable section consists of a series of statements. PSQL statements are a mix of traditional procedural statements, relational SQL statements and powerful cursor processing statements. A PSQL program must contain at least one statement. An exception handler section PSQL has full throw/catch exeption handling. The executable section can raise exceptions, which can optionally be handled by an exception handler. If desired, the handler can re-raise the exception. Defining exception handlers is optional.

Persistent PSQL Programs can only exist as the body part of a stored procedure or trigger. However, the SQL statement EXECUTE BLOCK allows the dynamic execution of a client defined PSQL Program. Events Firebird events are named messages that the server can send to client applications that have registered an interest in such events. Events are used to announce the occurrence of a specified condition or action, usually a database change such as an INSERT, UPDATE, or DELETE. The Firebird event mechanism enables applications to respond to actions and database changes made by other, concurrently running applications without the need for those applications to communicate directly with one another, and without incurring the expense of CPU time required for periodic polling to determine if an event has occurred. The Firebird event mechanism consists of four parts: A PSQL program that posts an event (to the event manager) An event manager that maintains an event queue and notifies applications when an event is committed. A first client application (or application thread) that registers interest in the event and waits for it to occur. A second client application (or application thread) that uses the event-posting PSQL routine (i.e. calls a procedure or causes a trigger to fire) so that the first client (thread) can resume processing.

Events are not database objects and do not have to be declared or created before use. Event names are restricted to 78 characters in size. Events are under transaction control. This is implemented thtough an event manager: an event is a message passed by a PSQL program to the event manager. The event manager queues the event messages for later processing: The event manager maintains a list of events posted to it by PSQL programs. If the transaction in which the event posting took place is commited, the event is passed on to the client application(s). If that transaction is rolled back, the posting is removed from the queue. Within a single transaction all postings of the same event are merged, i.e. Multiple postings of the same event within a single transaction are reported to the relevant clients as a single event when the transaction is committed.

The event manager also maintains a list of applications that have registered an interest in events. Each time a new event is committed, the event manager notifies interested applications that the event has occurred. After the interested application(s) have been notified (possibly none), the event is removed from the queue.

In general, client applications work with events in a three step process. Indicating an interest in specific named events to the event manager. Waiting for event notification, or setting up an asynchroneous notification. Determining which event occurred and processing that event.

The precise mechanics of handling events is described in the various language interface manuals, such as the Firebird C/C++ Programming Manual.

PSQL Programs Purpose Use a PSQL program to define the actions that a stored procedure or trigger will have. PSQL programs can also be contained in the EXECUTE BLOCK SQL statement. Security and prerequisites PSQL programs execute within their privileges. A PSQL program gets privileges from two sources: privileges of the user application invoking or triggering the program privileges specifically granted to the enclosing stored procedure or trigger.

The total set of privileges is the sum of of both sets of privileges. Syntax
<psql_body> ::= [ <var_decl_list> ] BEGIN <stmt_list> [ <excep_handlers> ] END;

Element
var_decl_list

Description A list of variable declarations, as further defined elsewhere in this chapter. A list of PSQL statements as described in Chapter 7, Statements. A list of exception handlers, as futher described elsewhere in this chapter.

stmt_list

excep_handlers

Semantics The body contains an optional list of local variables and their datatypes, followed by a block of statements bracketed by BEGIN and END. The block can itself include compound statements, so that there may be many levels of BEGIN/END nesting. The final END statement terminates the routine. The final actions taken depend on the context of the PSQL program: In a trigger, it terminates the trigger and processing continues with the next trigger (if any) or the original action firing the trigger. If no more work is to be done, control is returned to the application. In an executable procedure, the final END statement returns control and current values of output parameters, if any, to the calling application. In a selectable procedure, the final END statement returns control to the application and sets SQLCODE to 100, which indicates there are no more rows to retrieve.

Comments

PSQL code should be commented to aid debugging and application development. Comments are especially important in stored procedures and triggers, since they are global to the database and can be used by many different application developers. Comments in stored procedure definitions use one of two syntaxes:
<comment> ::= /* comment_text */ -- comment till end of current line

The comment_text can be any number of lines of text. A comment can appear on the same line as code. Example The below example shows a basic PSQL program:
/* * Example routine with no useful functionality */ DECLARE A INTEGER = 0; BEGIN WHILE (a<1000) DO BEGIN a = a + 1; END WHEN SQLCODE -902 DO INSERT INTO err_log VALUES (CURRENT_TIME, 'Unexpected error'); END;

See also EXIT statement, SUSPEND statement.

IDENTIFIERS IN PSQL Purpose Use identifiers to refer to parameters, local variables and database objects. Syntax
<identifier> ::= <unquoted_identifier> ! <quoted_identifier> <unquoted_identifier> ::= a name starting with an alphabetic character (A-Z, a-z), restricted to 31 characters, including dollar signs ('$'), underscores ('_'), 0 to 9, A to Z, and a to z. <quoted_identifier> ::= a name enclosed in double quotes (), containing up to 31 characters.

Semantics Unquoted identifiers are case insensitive, in the sense that Firebird will automatically convert the identifier to upper case. Use quoted identifiers if you want to include spaces or other characters that are not permitted in unquoted identifiers. You can also quote an identifier if the unquoted version conflicts with a Firebird reserved keyword. Quoted identifiers are case sensitive. Examples Below are a few examples of valid identifiers:
table1 rdb$relations id with spaces value

See also VARIABLE DECLARATIONS

VARIABLE DECLARATIONS Purpose Use variable declarations to create local variables to hold intermediate numerical or text values, or to create local cursor definitions. Syntax
<var_decl_list> ::= <var_decl> | <var_decl> <var_decl_list> <var_decl> ::= <scalar_declaration> | <cursor_declaration

Semantics Local variables are declared and used within a PSQL routine. They have no meaning outside the routine. Local variables must be declared at the beginning of a PSQL program before they can be used. Each local variable requires a separate declaration statement. Local variables come in two types: Scalar local variables These are variables that hold a single numerical or text value of the specified type. Cursor local variables These define local queries. The program body can open the query, fetch its result set, and close the result set after processing.

See also Scalar variable declarations, Cursor variable declarations

VARIABLE DECLARATIONS SCALAR Purpose Use the scalar variable declaration syntax to define numeric or text variables. Syntax
<scalar_declaration> ::= DECLARE [VARIABLE] <var_name> <psql_datatype> [= <psql_expr>]; <var_name> ::= <identifier>

Element
var_name

Description Name of a variable. Variable names and parameter names must be unique. The datatype of the variable. The variable cannot be an array type or a blob type. Expression with a datatype matching the variable. The expression can only refer to parameters or variables defined earlier.

psql_datatype

psql_expr

Semantics Local scalar variables are declared with a specific numerical or text datatype. When values are assigned to the variable, the value is cast to the declared type of the variable. Local variables cannot have ARRAY or BLOB types. Local scalar variables can optionally be initialised as part of the declaration. If not explicitly initialised, local variables will be initialised to the NULL value. The values of local variables are discarded at the end of the PSQL program, unless previously assigned to an output parameter. Note: PSQL programs can contain embedded SQL statements. In such statements, precede variables with a colon (:) to signify that they are variables rather than column names. In all other PSQL statements, you need not precede variables with a colon. See also Cursor variable declarations

VARIABLE DECLARATIONS CURSOR Purpose Use the cursor variable declaration syntax to define a cursor that can executed and processed in the PSQL program. Syntax
<cursor_declaration> ::= DECLARE [VARIABLE] <cursor_name> CURSOR FOR ( <select_stmt> ); <cursor_name> ::= <identifier>

Element
cursor_name select_stmt

Description Name of the cursor A select statement as defined in the SQL Reference manual

Semantics Cursor names are required to be unique in the given context. Within a single PSQL program cursor declarations must use unique names, and they must also not conflict with the name of a cursor that is "named", via the AS CURSOR clause in a FOR SELECT statement. However, a cursor can share its name with a scalar variable in the same PSQL program, since the operations available to each are different. When a cursor is open, updates and deletes using the WHERE CURRENT OF clause can be used to affect the current row of the cursor, so called positioned updates and deletes. All cursors which were not explicitly closed will be closed automatically on exit from the current PSQL program. Examples The following declaration defines a local cursor named C
DECLARE C CURSOR FOR ( SELECT RDB$RELATION_NAME FROM RDB$RELATIONS );

See also OPEN statement, FETCH statement, CLOSE statement, WHERE CURRENT OF clause in the SQL Reference Manual.

EXCEPTION HANDLERS Purpose Use exception handlers to catch error conditions in a PSQL program or in a specific compound statement block. Syntax
<excep_handlers> ::= <excep_handler> ! <excep_handler> <excep_handlers> <excep_handler> ::= WHEN <error_list> DO <psql_statement>; <error_list> ::= <error> ! <error> , <error_list> <error> ::= <sqlcode_error> ! <gdscode_error> ! <user_error> ! ANY

Element
psql_statement

Description A PSQL statement, typically a compound statement block

Semantics Instead of terminating when an exception occurs, a PSQL program or compound statement block can respond to and perhaps correct the error condition by handling the exception, through a WHEN exception handler. A WHEN exception handler is specific to one or more error conditions. Which error conditions the handler catches is defined by the error list following the WHEN keyword. Exceptions can be defined in one of four ways: By refering to the SQL error code of a system exception By refering to the name of a system exception By refering to the name of a user exception Or by specifying ANY to create a catch all exception handler

When an exception is raised within a block, Firebird: Seeks a handler for the exception in the current block. If no such handler is found: it undoes any actions performed in the block; backs out one level to the enclosing block and seeks a handler there. Firebird continues backing out levels and undoing actions until a handler is found. If no suitable handler is found, the PSQL program is terminated and the exception is reported to the caller. If a handler for the exception is found in the current or an enclosing block:

the error handling statement or block of statements specified in the handler are executed and processing continues at the statement that follows the block with the exception handler. If the handler was in the outermost block (i.e. the PSQL program body), control is returned to the calling application.

An exception that has been handled does not report the exception to the calling application, i.e. it does not return an error message. Examples The below example shows some valid exception handling clauses:
DECLARE a INTEGER; BEGIN a = 23 / a; WHEN SQLCODE -802 DO BEGIN a = 12; END WHEN GDSCODE arith_except DO BEGIN EXEPTION; END WHEN EXCEPTION my_error DO BEGIN EXEPTION my_error 'User defined error raised'; END WHEN ANY DO BEGIN a = 12; EXEPTION; END END;

See also EXCEPTION statement

EXCEPTION HANDLERS WHEN GDSCODE Purpose Use the GDSCODE error specification to create an error handler for a specific Firebird error condition. Syntax
<gdscode_error> ::= GDSCODE <gds_error_name> <gds_error_name> ::= <identifier>

Element
gds_error_name

Description The name of a Firebird system error

Semantics GDS codes are Firebird system error codes. The abbreviation GDS comes from Groton Database Systems, the company that in the early eighties developed the first versions of what currently is the Firebird code base. GDS error codes are more fine-grained then SQL error codes. See Appendix A for a list of GDS error codes and their meaning. Examples The below example shows a WHEN GDSCODE based handler:
DECLARE a INTEGER; BEGIN a = 23 / a; WHEN GDSCODE arith_except DO BEGIN EXEPTION; END END;

See also Exception handlers, WHEN SQLCODE, WHEN EXCEPTION

EXCEPTION HANDLERS WHEN SQLCODE Purpose Use the SQLCODE error specification to create an error handler for a specific SQL error condition. SQL codes are intended to be portable between relational SQL databases. Syntax
<gdscode_error> ::= GDSCODE <sql_error_number> <sql_error_number> ::= <psql_integer>

Element
sql_error_number

Description A short, signed PSQL integer value

Semantics SQL error codes are notionally standardised between database systems and vendors. For instance, error code 100 (NO DATA FOUND) always has the meaning that the last row of a result set has already been retrieved and that a next row is not available. The below table summarizes the types of SQLCODE that a handler can process: SQLCODE <0 0 +199 +100 Condition SQLERROR SUCCESS SQLWARNING NOT FOUND Meaning Error: The statement did not complete Successful completion System warning or informational message No more rows found

See Appendix A for a list of SQL error numbers and their meaning.

Examples The below example shows a WHEN SQLCODE based handler:


DECLARE a INTEGER; BEGIN a = 23 / a; WHEN SQLCODE -802 DO BEGIN a = 17; END END;

See also Exception handlers, WHEN GDSCODE, WHEN EXCEPTION

EXCEPTION HANDLERS WHEN EXCEPTION Purpose Use the EXCEPTION error specification to create an error handler for a named user-defined error condition. Syntax
<user_error> ::= EXCEPTION <exception_name> <exception_name> ::= <identifier>

Element
exception_name

Description The name of a user defined exception

Semantics Named, user-defined exceptions are global database objects that are created with the CREATE EXCEPTION statement. After creation, a PSQL routine can raise the exception condition by issuing a EXEPTION statement. Such user exceptions can be caught in an exception handler by using the WHEN EXCEPTION syntax. In all other aspects, user exceptions are handled identically to system errors. User-defined exceptions have a SQLCODE and GDSCODE equal to zero and cannot be caught using the WHEN SQLCODE or WHEN GDSCODE syntax. Examples The below example shows a WHEN SQLCODE based handler:
DECLARE a INTEGER; BEGIN a = 23 / a; WHEN SQLCODE -802 DO BEGIN a = 17; END END;

See also Exception handlers, WHEN GDSCODE, WHEN SQLCODE Overview of PSQL datatypes PSQL has a varied set of datatypes, that is a subset of the types supported by Firebird's SQL language: the BLOB and ARRAY datatypes are available only in SQL and not in PSQL. Syntax
<psql_datatype> ::= <sql_basic_type>

<sql_basic_type> ::= <int_type> | <scaled_type> | <float_type> | <char_type> | <varchar_type> | <datetime_type>

Sematics The various types are individually discussed on the next pages. Examples Below are some examples of valid PSQL data type specifications used in variable declarations:
DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE DECLARE i j k l m n o INTEGER; BIGINT; DECIMAL(5,2); DOUBLE PRECISION; CHAR(64) CHARACTER SET DOS403; NATIONAL VARCHAR(2000); TIMESTAMP;

See also VARIABLE DECLARATIONS

INTEGER DATATYPES Purpose Use integer datatypes to represent values consisting of whole numbers. Syntax
<int_type> ::= SMALLINT | INTEGER | BIGINT

Semantics Integers are whole numbers. Firebird supports three integer datatypes, which differ in their size, i.e. In the range of numbers they can hold: SMALLINT is a signed 16-bit integer (range /+ 32,768) INTEGER is a signed 32-bit integer (range /+ 2,147,483,648) BIGINT is a signed 64-bit integer (range -/+ 9,223,372,036,854,775,807)

Attempting to store a value in an integer variable that is too small to hold the value results in a value overflow exception. Examples The below example declares a variable of type INTEGER:
DECLARE a INTEGER;

See also SCALED DATATYPE, FLOAT DATATYPE

SCALED DATATYPES Purpose Use a scaled datatype to hold numbers with fixed size fractions. Syntax
<scaled_type> ::= {DECIMAL | NUMERIC} [(precision [, scale])]

Semantics Firebird supports two scaled datatypes, NUMERIC and DECIMAL, for handling numeric data with a fixed decimal point, such as monetary values. You can specify optional precision and scale factors for both datatypes: Precision is the total number or maximum number of digits, both significant and fractional, that can appear in a column of these datatypes. The allowable range for precision is from 1 to a maximum of 18. Scale is the number of digits to the right of the decimal point that comprise the fractional portion of the number. The allowable range for scale is from zero to precision; in other words, scale must be less than or equal to precision.

NUMERIC and DECIMAL differ subtly in the way they handle numbers larger than the specified size. NUMERIC defines a datatype that holds a maximum of precision digits, whereas DECIMAL defines a datatype that holds at least that number of digits, and possibly more. You can specify NUMERIC and DECIMAL datatypes without precision, in which case they are identical to INTEGER. The default value for scale is zero. The below example declares a variable of type NUMERIC:
DECLARE a NUMERIC(5,3);

See also INTEGER DATATYPE, FLOAT DATATYPE

FLOAT DATATYPES Purpose Use floating datatypes to hold floating point numbers, i.e. variable size numbers. Syntax
<float_type> ::= FLOAT | DOUBLE PRECISION

Semantics Firebird provides two floating-point datatypes, FLOAT and DOUBLE PRECISION; the only difference is their size: FLOAT specifies a single-precision, 32-bit datatype with a precision of approximately 7 decimal digits. DOUBLE PRECISION specifies a double-precision, 64-bit datatype with a precision of approximately 15 decimal digits.

The precision of FLOAT and DOUBLE PRECISION is fixed by their size, but the scale is not, and you cannot control the formatting of the scale. Use floating-point numbers when you expect the placement of the decimal point to vary, and for applications where the data values have a very wide range, such as in scientific calculations. If the value stored is outside of the range of the precision of the floating-point number, then it is stored only approximately, with its least-significant digits treated as zeros. For example, if the type is FLOAT, you are limited to 7 digits of precision. If you insert a 10-digit number 25.33333312 into the column, it is stored as 25.33333. Examples The below example declares a variable of type FLOAT:
DECLARE a FLOAT;

See also SCALED DATATYPE, INTEGER DATATYPE

(N)CHAR DATATYPES Purpose Use the CHAR and NCHAR datatypes to hold text values of a fixed length. Syntax
<char_type> ::= <char_keyword> [ ( <psql_integer> ) ] [ <char_set_spec> ] | <nchar_keyword> [ ( <psql_integer> ) ] [ <char_set_spec> ] <char_keyword> ::= CHAR | CHARACTER <nchar_keyword> ::= NCHAR | NATIONAL CHARACTER | NATIONAL CHAR <char_set> ::= CHARACTER SET <identifier>

Semantics The CHAR(n) datatype contains character strings with a fixed length of n characters. The maximum size is 32,767 bytes, which can be 10,992 to 32,767 characters, depending on the character size (1..3 bytes). If you do not supply n, it will default to 1, so CHAR is the same as CHAR(1). When the string to be stored or read contains less than n characters, blanks make up the difference. If the string is larger than n, then the value is truncated. NCHAR(n) is exactly the same as CHAR(n), except that it uses the ISO8859_1 character set by definition. Using NCHAR(n) is a shortcut for using the CHARACTER SET clause to specify the ISO8859_1 character set. Examples The below examples define a type to hold 32 characters in Unicode and a type to hold 128 characters in the ISO8859_1 character set (a.k.a. latin1):
CHAR(32) CHARACTER SET UNICODE_FSS NCHAR(128)

See also Character sets and collation orders in the SQL Reference Manual

(N)VARCHAR DATATYPES Purpose Use the VARCHAR and NCHAR VARYING datatypes to hold text values of a variable length. Syntax
<varchar_type> ::= <varchar_keyword> ( <psql_integer> ) [ <char_set> ] | <nvarchar_keyword> ( <psql_integer> ) <varchar_keyword> ::= CHARACTER VARYING | VARCHAR <nvarchar_keyword> ::= NCHAR VARYING | NATIONAL CHARACTER VARYING | NATIONAL CHAR VARYING <char_set> ::= CHARACTER SET <identifier>

Semantics The VARCHAR(n) datatype contains text of varying length, up to a maximum of n characters. The maximum size is 32,767 bytes, which can be 10,992 to 32,767 characters, depending on the character size (1..3 bytes). You must supply n; there is no default to 1. Firebird converts from variable-length character data to fixed-length character data by adding spaces to the value in the varying column until the column reaches its maximum length n. In the reverse conversion, trailing blanks are removed from the text. The main advantage of using the VARCHAR(n) datatype are that it saves memory space during the execution of PSQL programs. Examples The below examples define a type to hold 32 characters in Unicode and a type to hold 128 characters in the ISO8859_1 character set (a.k.a. latin1):
VARCHAR(32) CHARACTER SET UNICODE_FSS NCHAR VARYING (128)

See also Character sets and collation orders in the SQL Reference Manual

DATE/TIME DATATYPES Purpose Use the date and time types to hold dates, times and timestamps. Syntax
<datetime_type> DATE | TIME | TIMESTAMP

Semantics Firebird supports three different date/time datatypes: DATE stores a date as a 32-bit longword. Valid dates are from January 1, 100 a.d. to February 29, 32768 a.d. TIME stores time as a 32-bit longword. Valid times are from 00:00 to 23:59.9999. TIMESTAMP is stored as two 32-bit longwords and is a combination of DATE and TIME.

Firebird always stores the full year value in a DATE or TIMESTAMP column, never a two-digit abbreviated value. When a client application enters a two-digit year value, Firebird uses the sliding window algorithm to make an inference about the century: compare the two-digit year number entered to the current year modulo 100 If the absolute difference is greater than 50, then infer that the century of the number entered is 20, otherwise it is 19. Examples The below example declares a variable 'birthdate' of type DATE:
DECLATE birthdate DATE;

See also N/A Overview of PSQL expressions PSQL has a rich expression syntax, that is similar to the features found in most modern procedural languages. Through the system supplied standard UDF library, PSQL has access to a wide range of numerical and string functions. Syntax
<psql_expr_list> ::= <psql_expr> ! <psql_expr> , <psql_expr_list> <psql_expr> ::= <psql_factor>

| <psql_binop_expr> <psql_factor> ::= - <psql_expr> | ( <psql_expr> ) | ( <select_stmt> ) | <psql_variable> | <psql_array_element> | <psql_constant> | <psql_case_expr> | <psql_cast_expr> | <psql_sequence_expr> | <psql_function> | <psql_sys_info>

Semantics The various expression types are documented on the next pages. Examples See the individual system function descriptions for usage examples. See also N/A

USING VARIABLES IN PSQL Purpose Use variable identifiers to reference parameters and local variables. Syntax
<psql_variable> ::= <identifier> | : <identifier>

Semantics PSQL programs can contain embedded SQL statements. In such statements, precede variables with a colon (':') to signify that they are variables rather than column names. In all other PSQL statements, you need not precede variables with a colon, although you optionally can. Examples The below example shows how variable references are preceded by a colon in embedded SQL statements:
DECLARE start AS TIMESTAMP; DECLARE i AS INTEGER; DECLARE elapsed AS NUMERIC(9,3); DECLARE test_id AS INTEGER; BEGIN i = 100000; start = CURRENT_TIMESTAMP; WHILE (i>0) DO i = i 1; elapsed = CURRENT_TIMESTAMP start; test_id = 43 UPDATE scores SET elapsed = :elapsed WHERE id = :test_id; IF (ROW_COUNT = 0) THEN INSERT INTO scores VALUES (:elapsed, :test_id); END

See also IDENTIFERS IN PSQL

USING ARRAYS IN PSQL Purpose Use the array element syntax to reference individual elements from the SQL array datatype. Syntax
<psql_array_element> ::= <identifier> '[' <expr_list> ']'

Semantics The PSQL language does not support the ARRAY and BLOB datatypes as found in the SQL language. However, it can access individual elements of an array, which will be scalar types that it can handle. Examples
DECLARE element CHAR(32); BEGIN SELECT my_array[2,5] FROM table1 INTO :element; INSERT INTO table2 VALUES (:element); END

See also Chapter 4, PSQL Datatypes

LITERALS Purpose Use any of the four syntax options to define literal, constant values in your PSQL programs. Syntax
<psql_constant> ::= NULL | <psql_numerical_constant> | <psql_text_constant> | <psql_datetime_constant>

Semantics PSQL allows values to be specified as literals. A special literal is NULL, often refered to as UNKOWN. This value can be used to signal that a data item is not available or unkown. Note that most expressions using NULL will evaluate to NULL, because if one of the elements of the expression is unknown, then the whole expression outcome is unknown. Examples The below statement inserts a row with three values, the third of which is unkown.
INSERT INTO employees VALUES ( 'Paul', 123, NULL );

See also IS NULL, IS DISTINCT FROM, Numerical literals, Text literals, Date & time literals

NUMERICAL LITERALS Purpose Use the numerical constant syntax to specify numerical literals in your PSQL program. Syntax
<psql_numerical_constant> ::= <psql_integer> | <psql_scaled_int> | <psql_float> <psql_integer> ::= a string of digits whose value fits into 64 bits. <psql_scaled_int> ::= a string of digits and a single '.', where the digits represent a value which fits into 64 bits. <psql_float> ::= a string of digits with an optional '.', and followed by an e" or "E" and an optionally signed exponent, which fits into a 64 bit IEEE standard floating point representation.

Semantics A numerical constant specifief using the integer syntax is of type INTEGER. A numerical constant specified using the scaled integer syntax is of type NUMERIC, with a precision equal to the number of digits and a scale equal to the number of digits after the decimal separator ('.'). Examples Below are three examples of valid Firebird numerical constants, all equal to 1234. The first is of type INTEGER, the second of type NUMERIC(5,1) and the third of type FLOAT.
1234 1234.0 1.234E3

See also CAST EXPRESSION

TEXT LITERALS Purpose Use the text constant syntax to define literal strings in your PSQL program, possibly specifying a specific character set for the constant. Syntax
<psql_text_constant ::= <psql_string> | <introducer> <psql_string> <psql_string> ::= a string of characters in the database character set enclosed in single quotes; within the string two adjacent quotes are taken to mean a single embedded single quote. <introducer> ::= an underscore character ('_') followed by a character set name. Example: _ISO8859_1 ''

Semantics A text literal must be enclosed in single quotation marks. Note that this differs from languages such as C/C++, Java and Basic, which enclose text strings in double quotation marks. Within expressions and conditions, Firebird treats text literals as though they have the datatype CHAR by comparing them using blank-padded comparison semantics. Examples
'this is a string' 'this string contains a line break' 'this is how to write it''s in a string' _ISO8859_1 'this is a string in charset ISO 8859_1'

See also CAST EXPRESSION

DATE, TIME AND TIMESTAMP LITERALS Purpose Use the date and time constant syntax to define date, time and timestamp literals in your PSQL programs. Syntax
<psql_datetime_constant> ::= DATE <psql_string> | TIME <psql_string> | TIMESTAMP <psql_string>

Semantics By prefixing a literal string with one of the DATE, TIME or TIMESTAMP keywords one can specify time and date literals. The strings must be of the following format: For the DATE form: 'mm/dd/yyyy' For the TIME form: 'hh:mm:ss' For the TIMESTAMP form: 'mm/dd/yyyy hh:mm:ss'

Time values are expressed using a 24-hour clock. Using a 12-hour clock and the AM and PM specifiers is not supported. Examples The below examples show literals of various time types can specified using their string equivalents.
DATE '04/14/2006' TIME '13:34:12' TIMESTAMP '04/14/2006 13:34:12'

See also CAST EXPRESSION

BINARY OPERATORS Purpose Use binary operators to perform arithmetic or string concatenation. Syntax
<psql_binop_expr> ::= <psql_add_binop> | <psql_mul_binop> | <psql_concat_binop> | <psql_collate_binop>

Semantics The below table lists the levels of precedence among binary operators from high to low. Conditions listed in the same row have the same precedence. As the table indicates, expression factors are evaluated before binary operators. Element
factor

Description Literals, variable names, (system) functions, sequence operators, unary minus, subexpression, singleton select. *, / +, !! COLLATE

mul_op add_binop concat collate

Binary operators are left associative, i.e. operators of equal precendence are evaluated left to right. If either operand is NULL, the result is NULL as well. Examples These two expressions are equivalent:
1 + 2 + 3 (1 + 2) + 3

See also Detailed binary operator descriptions on the next pages.

ADDITIVE OPERATORS Purpose Use the plus and minus operator to perform addition and subtraction. Syntax
<psql_add_binop> ::= <psql_expr> + <psql_expr> | <psql_expr> - <psql_expr>

Semantics The plus ('+') operator adds two numerical values or adds an interval to a date/time value. The minus ('-') operator subtracts two numerical values, subtracts an interval from a date/time value, or calculates the interval between two date/time values. If both operands are integer, the result is integer. If one or both are scaled values, the result is a scaled value with the combined presicion and scale. If one or both are float values, the result is a float value. If one of the two operands are date/time values, the result is a timestamp value. When subtracting two date/time values, the result is a float. Intervals are expressed as a floating point number, representing the number of days in the interval. Fractions are used to represent intervals shorter than a day, e.g. an interval of 0.5 represents 12 hous, a half day. Examples The below example shows various uses of the additive operators.
DECLARE a AS INTEGER; DECLARE b AS FLOAT; DECLARE c AS TIMESTAMP; BEGIN a = 2; b = a + 0.5; c = CURRENT_TIMESTAMP + b; b = c CURRENT_DATE; END;

See also MULTIPLICATIVE OPERATORS

MULTIPLICATIVE OPERATORS Purpose Use the times and divide operator to perform multiplication and division. Syntax
<psql_mul_binop> ::= <psql_expr> * <psql_expr> | <psql_expr> / <psql_expr>

Semantics The times ('*') operator multiplies two numerical values. The divide ('/') operator divides two numerical values. If both operands are integer, the result is integer. If one or both are scaled values, the result is a scaled value with the combined presicion and scale. If one or both are float values, the result is a float value. Examples The below example multiplies two scaled numbers and assigns the result to a variable with sufficient scaling to hold the result.
DECLARE a AS NUMERIC(3,1) DECLARE a AS NUMERIC(3,2) DECLARE a AS NUMERIC(6,3) BEGIN a = 20.0; b = 3.14; c = a * b; END;

See also ADDITIVE OPERATORS

CONCATENATION OPERATOR Purpose Use the concatenation operator to concatenate two text strings. Syntax
<psql_concat_binop> ::= <psql_expr> || <psql_expr>

Semantics The concatenation ('||') operator concatenates two text values. Operands will NOT automatically be converted to text by this operator: use an explicit CAST instead. If either operand is NULL, the concatenation evaluates to NULL as well. Note for Oracle users: this is different from the Oracle behaviour, which treats a NULL value as identical to an empty string. The result has type VARCHAR, with a length sufficient to hold the result. Examples The below example creates a message from the concatenation of a CHAR field and a literal string:
SELECT TRIM(rdb$relation_name) || ' is a system table' FROM rdb$relations WHERE rdb$system_flag = 1;

See also SUBSTRING

COLLATION ORDER OPERATOR Purpose Use the collation operator to cast a text string to a specific collation order. Syntax
<psql_collation_binop> ::= <psql_expr> COLLATE <collation_name> <collation_name> ::= <identifier>

Semantics If no collation order is specified, Firebird sorts text values by their binary order. This is the same as alphabetic order for ASCII texts. In other character sets binary ordering may not be appropiate and characters like 'e', '', '', '' and '' should all appear together or in sequence. This can be achieved by specifying a collation order for the character set. Because PSQL currently only has scalar datatypes which are not ordered, specifyin a collation for a text value has no discernable effect. Of course, collation orders can be gainfully used in SQL statements that are embedded in PSQL programs. See the SQL Reference Manual for details. Examples The below example shows a valid use of the COLLATION operator. In this context it has no effect, because only a single text value is involved.
IF ( last_name = _ISO8851_1 'Paul' COLLATE 'DE_DE' ) THEN i=i+1;

See also CAST Expression

BUILT-IN FUNCTIONS Purpose The PSQL language supports a broad range of functions. Most of these are supported in the form of a standard system library, much like C/C++. Syntax
<psql_function> ::= <psql_udf_call> | <psql_context_fun> | <psql_extract_fun> | <psql_length_fun> | <psql_upper_fun> | <psql_lower_fun> | <psql_substr_fun> | <psql_trim_fun>

Semantics Next to the standard library functions, there are ten built-in functions which can be used even if the Firebird standard library is not available: Two context functions allow access to context variables One function to work with date and time elements Three length functions allow access to string length in various metrics Four frequently used string functions are built-in for convenience

The built-in functions are documented individually on the next pages. Examples See the individual system function descriptions for usage examples. See also Please refer to the SQL Reference Manual for a description of the Firebird standard function library.

STANDARD LIBRARY FUNCTIONS Purpose Most functions commonly found in relational database systems are supported through the Firebird standard UDF library. Calling such functions always follows the same syntax. Syntax
<psql_udf_call> ::= <udf_name> ( <psql_expr_list> )

Semantics The standard function library is documented in the SQL Reference Manual. Examples See the individual function descriptions in the SQL Reference Manual for usage examples. See also Please refer to the SQL Reference Manual

CONTEXT VARIABLE FUNCTIONS Purpose Use the get/set context variable functions to access and set context variables. Context variables are variables that are associated with either the current connection or the current transaction. Security and prerequisites To avoid DoS attacks against the Firebird Server, the number of variables stored for each transaction or session context is limited to 1000. Syntax
<psql_context_fun> ::= RDB$GET_CONTEXT ( <psql_namespace>, <psql_var_name> ) ! RDB$SET_CONTEXT ( <psql_namespace>, <psql_var_name>, <psql_new_val ) <psql_namespace> ::= <psql_varname> ::= <psql_new_val> ::= <psql_expr> <psql_expr> <psql_expr>

Element
psql_namespace psql_varname psql_new_val

Description A PSQL expression evaluating to text A PSQL expression evaluating to text A PSQL expression of any type, which will be cast to VARCHAR(255)

Semantics The functions RDB$SET_CONTEXT and RDB$GET_CONTEXT set and retrieve the current value of a context variable. Groups of context variables with similar properties are identified by namespace identifiers. RDB$GET_CONTEXT retrieves current value of a variable. If the variable does not exist in namespace, the function returns NULL. RDB$SET_CONTEXT sets a value for specific variable, if it is writable. The function returns a value of 1 if the variable existed before the call and 0 otherwise. To delete a variable from a context, set its value to NULL.

The namespace determines the usage rules, such as whether the variables may be read and written to, and by whom. Currently three namespaces have been defined: 'USER_SESSION' 'USER_TRANSACTION' 'SYSTEM'

The 'USER_SESSION' namespace is persistent for the duration of the current session (i.e. as long as the current connection is maintained). Variables can be freely created in this namespace and are read/write in nature. The 'USER_TRANSACTION' namespace is persistent for the duration of the current transaction (i.e. as long as the current transaction is not committed or rolled back). Variables can be freely created in this namespace and are read/write in nature. The 'SYSTEM' namespace allows read-only access to a specific set of system variables: Variable 'CLIENT_ADDRESS' Description The wire protocol address of the remote client, represented as a string. The value is an IP address in form "xxx.xxx.xxx.xxx" for TCPv4 protocol; the local process ID forXNET protocol; and NULL for any other protocol. Canonical name of the current database. It is either the alias name (if connection via file names is disallowed DatabaseAccess = NONE) or, otherwise, the fully expanded database file name. The isolation level of the current transaction. The returned value will be one of 'READ COMMITTED', 'SNAPSHOT', 'CONSISTENCY'. The numeric ID of the current transaction. The returned value is the same as would be returned by the CURRENT_TRANSACTION system function. The numeric ID of the current session. The returned value is the same as would be returned by the CURRENT_CONNECTION system function. The current user. The returned value is the same as would be returned by the CURRENT_USER or USER system functions. Current role for the connection. Returns the same value as the CURRENT_ROLE system function.

'DB_NAME'

'ISOLATION_LEVEL'

'TRANSACTION_ID'

'SESSION_ID'

'CURRENT_USER'

'CURRENT_ROLE'

Note that the namespace and variable names are case-sensitive. Variable values are stored with datatype VARCHAR(255). The return type of the set context function is INTEGER. The return type of the get context function is VARCHAR(255). Examples The below example shows how context variables can be used to simplify the creating of an audit log.
CREATE PROCEDURE set_context(User_ID VARCHAR(40), Trn_ID INTEGER) AS BEGIN RDB$SET_CONTEXT('USER_TRANSACTION', 'Trn_ID', Trn_ID); RDB$SET_CONTEXT('USER_TRANSACTION', 'User_ID', User_ID); END; CREATE TABLE journal ( jrn_id integer not null primary key,

jrn_lastuser varchar(40), jrn_lastaddr varchar(255), jrn_lasttransaction integer ); CREATE TRIGGER ui_jounal FOR journal AFTER INSERT OR UPDATE AS BEGIN new.jrn_lastuser = rdb$get_context('USER_TRANSACTION', 'User_ID'); new.jrn_lastaddr = rdb$get_context('SYSTEM', 'CLIENT_ADDRESS'); new.jrn_lasttransaction = rdb$get_context('USER_TRANSACTION', 'Trn_ID'); END; EXECUTE PROCEDURE set_context('skidder', 1); INSERT INTO journal(jrn_id) VALUES (0);

See also CURRENT_USER, CURRENT_ROLE, CURRENT_CONNECTION and CURRENT_TRANSACTION

EXTRACT FUNCTION Purpose Use the EXTRACT function to extract various time and date elements from a date, time or timestamp value. Syntax
<psql_extract> ::= EXTRACT ( <timestamp_part> FROM <psql_expr> ) <timestamp_part> ::= YEAR | MONTH | DAY | HOUR | MINUTE | SECOND | WEEKDAY | YEARDAY

Element
psql_expr

Description A PSQL expression evaluating to a date/time type

Semantics The extract function selects various specific elements from a date, time or timestamp value: YEAR: the year as a 4-digit number MONTH: the month, January equals 1 DAY: the day of the month, an integer in the range 1 to 31 HOUR: the hour of the day, an integer in the range 0 to 23 MINUTE: the minute of the hour, an integer in the range 0 to 59 SECOND: the second of the minute, an integer in the range 0 to 59 WEEKDAY: the day of the week, Sunday equals 1

The return type of the EXTRACT function is INTEGER.

Examples The below example extracts the day of the week number from the current date:
DECLARE DoW AS INTEGER; BEGIN DoW = EXTRACT( WEEKDAY FROM CURRENT_DATE ); END

See also N/A

LENGTH FUNCTIONS Purpose Use the length functions to calculate the length of a text string under various metrics. Syntax
<psql_length_fun> ::= CHAR_LENGTH ( <psql_expr> ) | CHARACTER_LENGTH ( <psql_expr> ) | OCTET_LENGTH ( <psql_expr> ) | BIT_LENGTH ( <psql_expr> )

Element
psql_expr

Description A PSQL expression evaluating to text

Semantics These functions return information about the size of strings: BIT_LENGTH returns the length of a string in bits CHAR_LENGTH and CHARACTER_LENGTH return the length of a string in characters OCTET_LENGTH returns the length of a string in bytes

In character sets other than ASCII, the character length can differ from the octet length. Examples
SELECT rdb$relation_name, CHAR_LENGTH(rdb$relation_name), CHAR_LENGTH(TRIM(rdb$relation_name)) FROM rdb$relations;

See also SUBSTRING FUNCTION

UPPER EXPRESSION Purpose Use the UPPER function to change a text value to upper case. Syntax
<psql_lower_fun> ::= UPPER ( <psql_expr> )

Element
psql_expr

Description A PSQL expression evaluating to text

Semantics The UPPER function returns the input argument converted to all upper-case characters, according to the character set of its argument. The return type of the UPPER function is the same type as its argument. In case the argument was not a text value, the return type is CHAR(64). Examples The below example shows how UPPER converts characters in character set DOS850:
isql -q -ch dos850 SQL> SQL> SQL> SQL> SQL> SQL> SQL> create create insert insert insert insert select database 'test.fdb' user 'SYDBA' password 'masterkey'; table t (c char(1) character set dos850); into t values ('A'); into t values ('E'); into t values ('');; into t values (''); c, upper(c) from t;

C UPPER ====== ====== a A e E

See also LOWER

LOWER FUNCTION Purpose Use the LOWER function to change a text value to lower case. Syntax
<psql_lower_fun> ::= LOWER ( <psql_expr> )

Element
psql_expr

Description A PSQL expression evaluating to text

Semantics The LOWER function returns the input argument converted to all lower-case characters, according to the character set of its argument. The return type of the LOWER function is the same type as its argument. In case the argument was not a text value, the return type is CHAR(64). Examples The below example shows how LOWER converts characters in character set DOS850:
isql -q -ch dos850 SQL> SQL> SQL> SQL> SQL> SQL> SQL> create create insert insert insert insert select database 'test.fdb' user 'SYDBA' password 'masterkey'; table t (c char(1) character set dos850); into t values ('A'); into t values ('E'); into t values ('');; into t values (''); c, lower(c) from t;

C LOWER ====== ====== A a E e

See also UPPER

SUBSTRING FUNCTION Purpose Use the substring function to select a part of a text string. Syntax
<psql_substring_fun> ::= SUBSTRING ( <psql_text> FROM <psql_pos> [FOR <psql_len>] ) <psql_text> ::= <psql_expr> <psql_pos> ::= <psql_expr> <psel_len>::= <psql_expr>

Element
psql_text psql_pos psql_len

Description A PSQL expression evaluating to text A PSQL expression evaluating to integer A PSQL expression evaluating to integer

Semantics The substring function will return a string consisting of the character at position <pos> and all subsequent bytes up to the end of the string. If the optional FOR clause is specified, it will return the lesser of <len> characters or the number of characters up to the end of the input string. The first argument can be any expression, constant or identifier that evaluates to a string. <pos> starts at 1, like other SQL commands. The <text> element can be a binary blob, or a sub_type 1 text blob with an underlying one-byteper-character charset. Because <pos> and <length> are byte positions in this case,the function currently does not handle text blobs with Chinese or Unicode character sets. Examples The below example strips the first three characters from a table's column:
UPDATE table SET col_b = SUBSTRING(col_b FROM 4)

See also N/A

TRIM FUNCTION Purpose Use the TRIM function to trim leading and/or trailing characters from text values. Syntax
<psql_trim_function> ::= TRIM ( [<trim_spec>] [<psql_trim> FROM] <psql_text> ) <trim_spec> ::= LEADING | TRAILING |! BOTH <psql_trim> ::= <psql_text> ::= <psql_expr> <psql_expr>

Element
psql_trim psql_text

Description A PSQL expression evaluating to text A PSQL expression evaluating to text

Semantics The TRIM function trims characters from a text string. The default character that is being trimmed away are spaces (' '), but can be set to any character using the FROM element. The optional trim spec parameter allows the specifaction of what to trim from the text value: If LEADING is specified, the action is to trim the leading (left) characters If TRAILING is specified, the action is to trim the trailing (right) characters If BOTH is specified, the action is to trim both leading characters and trailing characters from the text string.

The default trim specification is BOTH. The return type of the TRIM function is the same as the type of the text that is being trimmed (i.e. the type of the <psql_text> expression).

Examples The below two examples show how TRIM may be used to trim spaces of CHAR fields or preand postfixes from strings:
SELECT TRIM(rdb$relation_name) || ' is a system table' FROM rdb$relations WHERE rdb$system_flag = 1; SELECT rdb$relation_name, trim(leading 'RDB$' FROM rdb$relation_name) FROM rdb$relations WHERE rdb$relation_name STARTING WITH 'RDB$';

See also N/A

CASE EXPRESSION Purpose Use CASE statement to let the result of an expression to be determined by the outcome of a group of exclusive conditions. Syntax
<psql_case_expr> ::= <psql_case_short_from> | <psql_simple_case> | <psql_searched_case> <psql_case_short_form> ::= <psql_nullif> | <psql_coalesce> | <psql_iif> <psql_simple_case> ::= CASE <psql_expr> <psql_simple_when> END | CASE <psql_expr> <psql_simple_when> ELSE <psql_expr> END <psql_simple_when> ::= WHEN <psql_expr> THEN <psql_expr> | <psql_simple_when> WHEN <psql_expr> THEN <psql_expr> <psql_searched_case> ::= CASE <psql_searched_when> END | CASE <psql_searched_when> ELSE <psql_expr> END <psql_searched_when> ::= WHEN <psql_condition> THEN <psql_expr> | <psql_searched_when> WHEN <psql_condition> THEN <psql_expr>

Semantics In a simple CASE expression, Firebird searches for the first WHEN ... THEN pair for which the CASE expression is equal to the WHEN expression and returns the THEN expression. If none of the WHEN ... THEN pairs meet this condition, and an ELSE clause exists, then Firebird returns the ELSE expression. Otherwise, the case expression returns null. You cannot specify the literal NULL for all the THEN expressions and the ELSE expression. Note that a WHEN NULL clause in a simple case statement is never true: use a searched case and the IS NULL condition instead. In a searched CASE expression, Firebird searches from left to right until it finds anoccurrence of condition that is true, and then returns the THEN expression. If no condition is found to be true, and an ELSE clause exists, Firebird returns the ELSE expression. Otherwise, the case expression returns null.

Example Below is an example of a simple case statement. It decodes the value of the 'status' column into a number of text values:
SELECT o.ID, o.Description, CASE o.Status WHEN 1 THEN 'confirmed' WHEN 2 THEN 'in production' WHEN 3 THEN 'ready' WHEN 4 THEN 'shipped' ELSE 'unknown status ''' || o.Status || '''' END FROM Orders o;

Below is an example of a searched case statement. It is functionally the same as the previous example, except in that it also handles the value NULL.
SELECT o.ID, o.Description, CASE WHEN (o.Status IS NULL) THEN 'new' WHEN (o.Status = 1) THEN 'confirmed' WHEN (o.Status = 3) THEN 'in production' WHEN (o.Status = 4) THEN 'ready' WHEN (o.Status = 5) THEN 'shipped' ELSE 'unknown status ''' || o.Status || '''' END FROM Orders o;

See also IIF, NULLIF, COALESCE


The result datatype is determined by the following rules: Function: Specify the result data type of the result of an aggregation over values of compatible data types, such as case expressions and columns at the same position in a union query expression. Syntax Rules: 1) Let DTS be the set of data types over which we must determine the final result data type. 2) All of the data types in DTS shall be comparable. 3) Case: a) If any of the data types in DTS is character string, then: 1) If any of the data types in DTS is variable-length character string, then the result data type is variable-length character string with maximum length in characters equal to the maximum of the lengths in characters and maximum lengths in characters of the data types in DTS. 2) Otherwise, the result data type is fixed-length character string with length in characters equal to the maximum of the lengths in characters of the data types in DTS. 3) The characterset/collation is used from the first character string data type in DTS. b) If all of the data types in DTS are exact numeric, then the result data

type is exact numeric with scale equal to the maximum of the scales of the data types in DTS and the maximum precision of all data types in DTS. c) If any data type in DTS is approximate numeric, then each data type in DTS shall be numeric else an error is thrown. d) If some data type in DTS is a datetime data type, then every data type in DTS shall be a datetime data type having the same datetime type. e) If any data type in DTS is BLOB, then each data type in DTS shall be BLOB and all with the same sub-type.

NULLIF EXPRESSION Purpose Use NULLIF to more easily handle NULL values in a database. Syntax
<psql_nullif> ::= NULLIF ( <psql_expr>, <psql_expr> )

Semantics Returns NULL for a sub-expression if it has a specific value, otherwise returns the value of the subexpression. NULLIF (V1, V2) is equivalent to the following case statement: CASE WHEN V1 = V2 THEN NULL ELSE V1 END Example
UPDATE PRODUCTS SET STOCK = NULLIF(STOCK,0)

See also

IIF, COALESCE, IS IDENTICAL TO

IIF EXPRESSION Purpose Use the IIF (in-line IF) expression to select one of two sub-expressions based on a condition. Syntax
<psql_nullif> ::= IIF ( <psql_condition>, <psql_expression>, <psql_expression> )

Semantics It returns the value of the first sub-expression if the given condition evaluates to TRUE, otherwise it returns a value of the second sub-expression. IIF (<search_condition>, <value1>, <value2>) is a shorthand form for: CASE WHEN <search_condition> THEN <value1> ELSE <value2> END Example The below assignment statement places the absolute value of the variable 'val' into the variable 'abs_val':
abs_val = IIF( val<0, -val, val);

See also NULLIF, COALESCE, IS IDENTICAL TO

COALESCE EXPRESSION Purpose Use the coalesce expression to select the first non-NULL expression from a list. Syntax
<psql_coalesce> ::= COALESCE ( <psql_expr_list> )

Semantics Allows a column value to be calculated by a number of expressions, from which the first expression to return a non-NULL value is returned as the output value. The coalesce function is a shorthand for the following case expressions: COALESCE (V1, V2) is equivalent to the following: CASE WHEN V1 IS NOT NULL THEN V1 ELSE V2 END COALESCE (V1, V2,..., Vn), for n >= 3, is equivalent to the following: CASE WHEN V1 IS NOT NULL THEN V1 ELSE COALESCE (V2,...,Vn) END

Examples
UPDATE PRODUCTS SET STOCK = COALESCE(STOCK,0)

See also IIF, NULLIF, IS IDENTICAL TO

CAST EXPRESSION Purpose Use the CAST expression to convert an expression to another datatype. Syntax
<psql_cast_expr> ::= CAST ( <psql_expr> AS <psql_datatype> )

Semantics CAST() allows mixing of numerics and characters in a single expression by converting an expression to a specified datatype. Normally, only similar datatypes can be compared in search conditions. CAST() can be used in search conditions to translate one datatype into another for comparison purposes. Examples The first example shows how a text value can be cast to a date value. The second example shows how CAST can be used to declare the type of a parameter.
SELECT * FROM employees WHERE hire_date < CAST( '04/14/2006' AS DATE ); SELECT * FROM employees WHERE hire_date < CAST( ? AS DATE );

See also Chapter 4, PSQL Datatypes

SEQUENCE EXPRESSIONS Purpose Use a sequence expression to generate the next value from a sequence. Syntax
<psql_sequence_expr> ::= GEN_ID ( <sequence_name>, <psql_expr> ) | NEXT VALUE FOR <sequence_name> <sequence_name> ::= <identifier>

Semantics The GEN_ID() function: increments the current value of the specified sequence by the amount specified in its second argument returns the new value of the specified generator.

GEN_ID() is useful for automatically producing unique values that can be inserted into a UNIQUE or PRIMARY KEY column. GEN_ID(<name>, 0) allows you to retrieve the current sequence value, but it should never be used in insert/update statements, as it produces a high risk of uniqueness violations in a concurrent environment. Firebird 2.0 added the SQL-99 compliant NEXT VALUE FOR expression as a synonym for GEN_ID(<generator-name>, 1). Examples The first example inserts a new employee into the employees table, adding the next available employee number from the the employee ID sequence. The second example initialises the employee ID sequence to the next available starting point from a master sequence, reserving 10,000 elements in the master sequence.
INSERT INTO employees VALUES ( 'Paul', NEXT VALUE FOR EMP_ID_SEQ ) SET SEQUENCE EMP_ID_SEQ TO GEN_ID(ID_SEQ, 10000)

See also CREATE SEQUENCE

SYSTEM INFORMATION FUNCTIONS Purpose Use the system information functions to retrieve information about the current state of the system. Syntax
<psql_sys_info> ::= <current_user> | <current_role> | <current_connection> | <current_transaction> | <current_date> | <current_time> | <current_timestamp> | <gdscode> | <sqlcode> | <row_count>

Semantics The system information functions return information about the current state of the system. There are five categories of system functions: The current user and current role functions return information about the security identity associated with the current connection. The current connection and current transaction functions return the system identifiers of the current connection and transaction, for amongst others logging and audit purposes. The date, time and timestamp functions return the current system date and time, aiding use of a single time standard across clients The gds and sql code functions return error information when used inside of exception handlers The row count function returns the number of rows affected by the last SQL statement on the current connection.

The system functions are documented individually on the next pages. Examples See the individual system function descriptions for usage examples. See also N/A

CURRENT_USER, USER FUNCTION Purpose Use the current user functions to retrieve the name of the user associated with the current connection. Syntax
<current_user> ::= USER | CURRENT_USER

Semantics Use the current user functions to retrieve the name of the user associated with the current connection. The return type of the CURRENT_USER and USER system functions is CHAR(31). Examples The below program block tests if the current user is SYSDBA, and if it is not throws a userdefined exception.
BEGIN IF CURRENT_USER != 'SYSDBA' THEN EXCEPTION NOT_AUTH 'Not authorised for this action'; END

See also CURRENT_CONNECTION FUNCTION, CONTEXT VARIABLE FUNCTIONS

CURRENT_ROLE FUNCTION Purpose Use the current role function to retrieve the name of the role associated with the current connection. Syntax
<current_user> ::= CURRENT_ROLE

Semantics Use the current role function to retrieve the name of the user associated with the current connection. The return type of the CURRENT_ROLE system function is CHAR(31). Examples The below program block tests if the current role is ADMIN, and if it is not throws a user-defined exception.
BEGIN IF CURRENT_ROLE != 'ADMIN' THEN EXCEPTION NOT_AUTH 'Not authorised for this action'; END

See also CURRENT_CONNECTION FUNCTION, CONTEXT VARIABLE FUNCTIONS

CURRENT_CONNECTION FUNCTION Purpose Use the current connection system function to retrieve the system identifier of the current connection. Syntax
<current_connection> ::= CURRENT_CONNECTION

Semantics The CURRENT_CONNECTION system function returns the system identifier of the active connection. The return type is INTEGER. Note: Because this value is stored on the database header page, it will be reset after a database restore. Examples The below example passes the current connection handle to a stored procedure.
EXECUTE PROCEDURE P_LOGIN(CURRENT_CONNECTION);

See also CURRENT_TRANSACTION

CURRENT_TRANSACTION FUNCTION Purpose Use the current transaction system function to retrieve the system identifier of the transaction connection. Syntax
<current_connection> ::= CURRENT_TRANSACTION

Semantics The CURRENT_TRANSACTION system function returns the system identifier of the active connection. The return type is INTEGER. Note: Because this value is stored on the database header page, it will be reset after a database restore. Examples The below example logs the transaction handle in a log table:
CREATE TRIGGER LOGGER ON TABLE ACTION_LOG BEFORE INSERT AS BEGIN NEW.TXN_ID = CURRENT_TRANSACTION; END

See also CURRENT_CONNECTION

CURRENT_DATE FUNCTION Purpose Use the current date system function to retrieve the current system date, Syntax
<current_date> ::= CURRENT_DATE

Semantics The CURRENT_DATE system function returns the current system date, i.e. the date of the system that is running the Firebird server. There is no time zone associated with the current system date. The return type of the CURRENT_DATE function is DATE. Examples The below examples calculates somebody's age in days by subtracting the birth date from the current date.
age_in_days = (CURRENT_DATE birth_date);

See also CURRENT_TIME, CURRENT_TIMESTAMP.

CURRENT_TIME FUNCTION Purpose Use the current time system function to retrieve the current system time. Syntax
<current_date> ::= CURRENT_TIME [ (<precision>) ] <precision> ::= { 0 ! 1 ! 2 ! 3 }

Semantics The CURRENT_TIME system function returns the current system time, i.e. the time of the system that is running the Firebird server. There is no time zone associated with the current system time. The optional precision parameter specifies the number of fractional digits in the seconds part of the returned time. The default is zero, i.e. time is rounded to a full second. The maximum precision is 3, which is rounding to a milli-second. The return type of the CURRENT_TIME function is TIME. Examples The below examples calculates the time in seconds to excute a short loop:
DECLARE start AS TIME; DECLARE i AS INTEGER; DECLARE elapsed AS INTEGER; BEGIN i = 1000; start = CURRENT_TIME; WHILE (i>0) DO i = i 1; elapsed = CURRENT_TIME start; END

See also CURRENT_DATE, CURRENT_TIMESTAMP.

CURRENT_TIMESTAMP FUNCTION Purpose Use the current timestamp system function to retrieve the current system timestamp. Syntax
<current_date> ::= CURRENT_TIMESTAMP [ (<precision>) ] <precision> ::= { 0 ! 1 ! 2 ! 3 }

Semantics The CURRENT_TIMESTAMP system function returns the current system date and time, i.e. the date and time of the system that is running the Firebird server. There is no time zone associated with the current system timestamp. The optional precision parameter specifies the number of fractional digits in the seconds part of the returned time. The maximum precision is 3, which is rounding to a milli-second. This is also the default precision. The return type of the CURRENT_TIMESTAMP function is TIMESTAMP. Examples The below examples times a long loop with millisecond precision:
DECLARE start AS TIMESTAMP; DECLARE i AS INTEGER; DECLARE elapsed AS NUMERIC(9,3); BEGIN i = 100000; start = CURRENT_TIMESTAMP; WHILE (i>0) DO i = i 1; elapsed = CURRENT_TIMESTAMP start; END

See also CURRENT_DATE, CURRENT_TIME

GDSCODE FUNCTION Purpose Use the GDSCODE system function to retrieve the Firebird native error number of the current system exception, if any. Syntax
<gdscode> ::= GDSCODE

Semantics The GDSCODE system function returns an integer which is the numeric native error code for the active exception. It is available within the scope of a WHEN GDSCODE exception handling block. It will evaluate to zero elsewhere. The GDSCODE variable returns a numeric representation of the GDS error code, e.g. 335544349L will return 335544349. A 'WHEN SQLCODE' or WHEN ANY exception block will catch a non-zero value for the SQLCODE variable and return zero for GDSCODE. Only a WHEN GDSCODE block can catch a non-zero GDSCODE variable (and will return zero in SQLCODE). If a user-defined exception is thrown, the GDSCODE system function contain zero, regardless of the exception handling block type. The return type of the GDSCODE system function is INTEGER. Examples The below example logs occurences of errors 335544349 and 335544350 into an error log table:
WHEN GDSCODE 335544349, GDSCODE 335544350 DO BEGIN INSERT INTO ERROR_LOG VALUES (GDSCODE); EXCEPTION; END

See also SQLCODE, EXCEPTION HANDLERS

SQLCODE FUNCTION Purpose Use the SQLCODE system function to retrieve the standardised SQL error number of the current system exception, if any. Syntax
<gdscode> ::= SQLCODE

Semantics The SQLCODE system function returns an integer which is the numeric SQL error code for the active exception. It is available within the scope of a WHEN SQLCODE or WHEN ANY exception handling block. It will evaluate to zero elsewhere. A 'WHEN SQLCODE' or WHEN ANY exception block will catch a non-zero value for the SQLCODE variable and return zero for GDSCODE. Only a WHEN GDSCODE block can catch a non-zero GDSCODE variable (and will return zero in SQLCODE). If a user-defined exception is thrown, the SQLCODE system function contain zero, regardless of the exception handling block type. The return type of the SQLCODE system function is INTEGER. Examples The below example logs the SQL code of all errors into an error log table:
WHEN ANY DO BEGIN INSERT INTO ERROR_LOG VALUES (SQLCODE); EXCEPTION; END

See also GDSCODE, EXCEPTION HANDLERS

ROW_COUNT FUNCTION Purpose Use the ROW_COUNT system function to retrieve the number of rows affected by the last SQL statement. Syntax
<row_count> ::= ROW_COUNT

Semantics The ROW_COUNT system function returns the number of rows affected by the last SQL statement on the current connection. If used within a SELECT statement, it returns the number of rows returned so far. The return type of the ROW_COUNT system function is INTEGER. Examples The first example tries to update a table. If the record is not found, a new record is inserted instead. The second example keeps a running total of the number of rows returned.
UPDATE TABLE1 SET FIELD1 = 0 WHERE ID = :ID; IF (ROW_COUNT = 0) THEN INSERT INTO TABLE1 (ID, FIELD1) VALUES (:ID, 0); SELECT ROW_COUNT, RDB$RELATION_NAME FROM RDB$RELATIONS;

See also N/A Overview of PSQL conditions PSQL has a rich set of conditional tests to control program flow in a PSQL routine, for example through the IF THEN ELSE or WHILE DO statements. In general, the conditional constructs in PSQL exactly match the constructs available in the WHERE clause in SQL statements. Syntax
<psql_condition> ::= <psql_simple_condition> | NOT <psql_condition> | ( <psql_condition> ) | ( <psql_and_condition> | ( <psql_or_condition> <psql_simple_condition ::= <sql_predicate> | <trigger_predicate> <sql_predicate> ::= <comparison_predicate> | <quantified_predicate> | <null_predicate> | <between_predicate> | <in_predicate>

| | | | |

<like_predicate> <starting_predicate> <containing_predicate> <exists_predicate> <unique_predicate>

<trigger_predicate> ::= INSERTING | UPDATING | DELETING

Note: Trigger predicates are only valid inside the body of trigger definitions. Using trigger predicates in a procedure definition will cause a syntax error. See the chapter on working with triggers for more information about tigger predicates. Semantics Precedence is the order in which Firebird evaluates different conditions in the same expression. When evaluating an expression containing multiple conditions, Firebird evaluates conditions with higher precedence before evaluating those with lower precedence. Conditions with equal precedence are evaluated from left to right within an expression. The below table lists the levels of precedence among SQL condition from high to low. Conditions listed in the same row have the same precedence. As the table indicates, expression are evaluated operators before conditions. Element
expression operators

Defining keywords Expression operators (+, - , etc.) are evaluated before all condition operators. INSERTING, UPDATING, DELETING =, |=, <, >, <=, >=; possibly in combination with ALL, SOME or ANY IS [NOT] NULL, [NOT] LIKE, CONTAINING, STARTING, [NOT] BETWEEN, [NOT] IN, EXISTS, UNIQUE

trigger_predicate comparison predicate, quantified_predicate between_predicate, like_predicate, in_predicate, null_predicate, exists_predicate, containing_predicate, starting_predicate, unique_predicate

negation

NOT

and_condition

AND

or_condition

OR

Element

Defining keywords

Examples The following code snippet tests both if variable A is larger than 23 and that table RDB$DATABASE has exactly one row:
A>23 AND SINGULAR(SELECT * FROM RDB$DATABASE)

See also IF THEN ELSE, WHILE DO

AND CONDITION Pupose Use the AND condition clause to test if two conditions are met simultaneously. Syntax
<psql_unique_clause ::= <psql_condition> AND <psql_condition>

Semantics The AND condition tests if two subconditions are true at the same time. If either subcondition evaluates to NULL, then the AND condition evaluates to NULL as well. This is known as 'tristate logic'. The below truth table shows the result of applying AND to two conditions: AND True False Null True True False Null False False False False Null Null False Null

The AND condition uses shortcut evaluation: if the left hand condition is FALSE, the result is FALSE and the right hand side is not evaluated at all. Examples The following code snippet will never generate a division-by-zero exception, even if variable 'a' equals zero:
IF ( A!=0 AND (5/A)>3 ) THEN EXCEPTION DIV_BY_ZERO;

See also OR CONDITION

OR CONDITION Pupose Use the OR condition clause to test if either of two conditions are met. Syntax
<psql_unique_clause ::= <psql_condition> OR <psql_condition>

Semantics The OR condition tests if either of two subconditions are true. If either subcondition evaluates to NULL, then the OR condition evaluates to NULL as well. This is known as 'tri-state logic'. The below truth table shows the result of applying OR to two conditions: OR True False Null True True True True False True False Null Null True Null Null

The AND condition uses shortcut evaluation: if the left hand condition is TRUE, the result is TRUE and the right hand side is not evaluated at all. Examples The following code snippet will never generate a division-by-zero exception, even if variable 'a' equals zero:
IF ( A=0 OR (5/A)>3 ) THEN EXCEPTION OUT_OF_RANGE;

See also AND CONDITION

SCALAR COMPARISON CONDITION Pupose Use the scalar comparison operators to compare two numerical or text expressions. Syntax
<comparison_predicate> ::= <psql_expr> <compare_op> <psql_expr> <compare_op> ::= = | < | > | <= | !> | >= | !< | <> | !=

Semantics The comparison operators compare two values and tests for a certain relationship between the two. The test performed is specified in the below table. Operator
= <>, != < > <=, !> >=, !<

Tests for Equality Inequality Less than Greater then Not greater than Not less than

If either of the two expressions evaluates to NULL, than the result of the the test is also NULL. This also means that the (in-)equality operator cannot be used to test for NULL-ness, use the IS NULL operator instead. The two expressions should normally be of the same type. If the types differ, the types are automatically cast to types that can be compared: integer and scaled result in a scaled comparison integer/scaled and float result in a comparison of floats numeric and date/time results in a comparison of timestamps text and non-text results in a comparison of texts; a date string counts as date, not text.

Examples The following are examples of valid comparisons:


a <> 23 birth_day <= 'today'

name = 'John Smith'

See also IF NULL, Group Comparison Conditions

GROUP COMPARISON CONDITION Pupose Use the group comparison operators to compare a single value with the result set of a single column query. Syntax
<psql_quantified_clause> ::= <psql_expr> <compare_op> <group_op> <select_stmt> <compare_op> ::= = | < | > | <= | !> | >= | !< | <> | != <group_op> ::= ALL | { ANY ! SOME }

Note: The select statement must have exactly one item in its select list, i.e. The result set must exist of exactly one column. Semantics The group comparison operators compare a value with the entire result set of a single column query and tests for a certain relationship between the value and each row of the result set. If the ALL keyword is specified, then every row must pass the test for the group to pass the test. If the ANY or the SOME keyword is specified, then only at least one row must pass the test for the group to pass the test. The test performed is specified in the below table. Operator
= <>, != < > <=, !> >=, !<

Tests for Equality Inequality Less than Greater then Not greater than Not less than

If the left hand expression evaluates to NULL, than the result of the the test is also NULL. If the result set of the subquery has zero rows then the result of the test is also NULL. The two expressions should normally be of the same type. If the types differ, the types are automatically cast to types that can be compared:

integer and scaled result in a scaled comparison integer/scaled and float result in a comparison of floats numeric and date/time results in a comparison of timestamps text and non-text results in a comparison of texts; a date string counts as date, not text.

Examples The following are examples of valid group comparison statements:


a < ANY (SELECT col_a FROM mytable) b = ALL (SELECT col_b FROM mystable WHERE col_b=:b)

See also Scalar Comparison Conditions

IS NULL CONDITION Pupose Use the IS NULL predicate to test if a value is NULL or not NULL. Syntax
<null_predicate ::= <psql_expr> IS [NOT] NULL

Semantics To test for nulls, use only the comparison conditions IS NULL and IS NOT NULL. If you use any other condition with nulls and the result depends on the value of the null, then the result is NULL. Because null represents a lack of data, a null cannot be equal or unequal to any value or to another null. Examples At the end of the following routine variable 'a' will have value 4, not value 3:
DECLARE a INTEGER; BEGIN IF (a=NULL) THEN a = 3; IF (a IS NULL) THEN a = 4; END

See also IS DISTINCT FROM

IS DISTINCT FROM CONDITION Pupose Use the IS DISTINCT FROM predicate to test if a value is identical to another value. Syntax
<null_predicate ::= <psql_expr> IS [NOT] DISTINCT FROM <psql_expr>

Semantics The IS DISTINCT FROM tests if two values are identical, either because both are known (i.e. not NULL) and the same, or because both are unknown. Examples At the end of the following routine variable 'a' will have value 3, not value 4:
DECLARE a INTEGER; BEGIN IF (a IS NOT DISTINCT FROM NULL) THEN a = 3; IF (a IS DISTINCT FROM 3) THEN a = 4; IF (a IS NULL) THEN a = 4; END

See also IS NULL

BETWEEN CONDITION Pupose Use the BETWEEN predicate to test if a value is within a certain range. Syntax
<between_predicate> ::= <psql_expr> BETWEEN <psql_expr> AND <psql_expr> | <psql_expr> NOT BETWEEN <psql_expr> AND <psql_expr>

Semantics The BETWEEN predicate test if a value lies in certain range, inclusive of the limits of the range. The following two conditions are logically equivalent: a BETWEEN b AND c a >= b AND a<=c And the following two conditions are also logically equivalent: a NOT BETWEEN b AND c a <b OR a>c If any of the three expressions in a [NOT] BETWEEN condition is NULL, then the entire condition evaluates to NULL. The three expressions should normally be of the same type. If the types differ, the types are automatically casted to types that can be compared. The rules for this are the same as for scalar comparisons. Examples The below are examples of valid BETWEEN predicates:
a BETWEEN 23 AND 46 order_date NOT BETWEEN DATE 'today' AND DATE 'today'-366

See also Scalar Comparison Conditions

IN CONDITION Pupose Use the IN predicate to test if a value is within a group of values. The group can either be a list of values or the result set of a single column query. Syntax
<in_predicate> ::= <psql_expr> [NOT] IN ( psql_expr_list ) | <psql_expr> [NOT] IN ( select_stmt )

Semantics The IN predicate tests for membership of a value in a list of values or a result set of values: IN is equivalent with the = ANY group comaprison NOT in is equivalent with != ALL group comparison

If any item in the list following a NOT IN operation evaluates to null, then the entire condition evaluates to NULL. This is because the condition is internally calculated as a series of AND conditions, which cannot be short-cut evaluated. Examples The following are valid examples of IN usage:
disciple IN ('John', 'Paul') rank NOT IN (1, 2, 3)

The following statement returns no rows:


SELECT True FROM employees WHERE department_id NOT IN (10, 20, NULL);

The preceding example returns no rows because the WHERE clause condition evaluates to: department_id != 10 AND department_id != 20 AND department_id != NULL. Because the third condition compares department_id with a NULL, it results in a NULL, so the entire expression results in NULL. This behavior can easily be overlooked, especially when the NOT IN operator references a subquery. See also Group Comparison Conditions

LIKE CONDITION Pupose Use the LIKE predicate to test a text value for similarity to a specified text pattern. Syntax
<like_predicate> ::= <match> LIKE <pattern> [ ESCAPE <escape> ] | <match> NOT LIKE <pattern> [ ESCAPE <escape> ] <match> ::= <pattern> ::= <escape> ::= <psql_expr> <psql_expr> <psql_expr>

Element
match pattern escape

Description An expression evaluating to text An expression evaluating to text An expression evaluating to a single character text

Semantics The LIKE condition specifies a test involving pattern matching. Whereas the equality operator (=) exactly matches one character value to another, the LIKE conditions match a portion of one character value to another by searching the first value for the pattern specified by the second. LIKE compares strings using characters as defined by the input character set and matching is case sensitive. If the escape clause is ommitted, then there is no default escape character. If any of the three expressions is NULL, then the result is NULL. The escape character, if specified, must be a character string of length 1. The pattern can contain the special pattern-matching characters: '%' matches any string of any length (including length 0) '_' matches any single character.

To search for the characters '%' and '_', precede them by the escape character. For example, if the escape character is '@', then you can use '@%' to search for '%', and '@_' to search for '_'. To search for the escape character, repeat it. For example, if '@' is the escape character, then you can use '@@' to search for '@'. In the pattern, the escape character should be followed by one of '%', '_', or the escape character itself. The escape character cannot be '%' or '_'. In Firebird, LIKE conditions used in SQL statement WHERE conditions are not index optimised, and the variant form STARTING WITH exists. In PSQL, where we work with scalar values, there is no performance differnce betweeb LIKE and STARTING WITH.

Examples The below are examples of valid LIKE expressions. The third example finds all names that contain the string 'A_B':
last_name LIKE 'Ma%' last_name LIKE 'Smith_' last_name LIKE '%A\_B%' ESCAPE '\'

See also CONTAINING, STARTING WITH

CONTAINING CONDITION Pupose Use the CONTAINING predicate to test if a text value is contained in another text value. Syntax
<containing_predicate ::= <psql_match> [ NOT ] CONTAINING <psql_pattern> <match> ::= <pattern> ::= <psql_expr> <psql_expr>

Element
match pattern

Description An expression evaluating to text An expression evaluating to text

Semantics The CONTAINING condition search a text for a sequence of characters equal to the pattern. The search is case insensitive, i.e. the pattern 'Peter' matches all of 'peter', 'Peter', 'PETER', 'PeTeR', etc. If match evaluates to a non-text value, it is cast to the text equivalent and the result is used in the search. Examples The below are examples of valid CONTAINING conditions:
last_name CONTAINING 'a_b' last_name CONTAINING 'Smith' hire_date CONTAINING '1998'

See also LIKE Condition, STARTING WITH Condition

STARTING WITH CONDITION Pupose Use the STARTING WITH predicate to test if a text value starts with a certain text value. Syntax
<starting_predicate ::= <psql_match> [ NOT ] STARTING [ WITH ] <psql_pattern> <match> ::= <pattern> ::= <psql_expr> <psql_expr>

Element
match pattern

Description An expression evaluating to text An expression evaluating to text

Semantics The STARTING WITH condition specifies a test involving a search for text starting with the pattern string. STARTING WITH 'text' is equivalent to LIKE 'text%'. STARTING WITH compares strings using characters as defined by the input character set and matching is case sensitive. Examples The following are examples of valid use of STARTING WITH:
last_name STARTING WITH 'Smi' last_name STARTING 'Smi' last_name NOT STARTING WITH 'Smi'

See also LIKE Condition, CONTAINING Condition

EXISTS CONDITION Pupose Use the EXISTS predicate to test if a query has a result set with at least one row. Syntax
<exists_predicate> ::= EXISTS ( <select_stmt> ) | NOT EXISTS ( <select_stmt> )

Element
select_stmt

Description A SELECT statement as defined in the SQL Reference Manual

Semantics The EXISTS condition is a fast way of testing if a certain row exists. The similar test (SELECT COUNT(*) FROM ...) >0 is by comparison far more expensive, because all rows must be traversed in order to get to an accurate count. Examples The below are examples of valid use of the EXISTS condtion. Both examples return FALSE:
EXISTS( SELECT * FROM rdb$database WHERE 1=0 ) NOT EXISTS( SELECT * FROM rdb$relations )

See also SINGULAR Condition

SINGULAR CONDITION Pupose Use the SINGULAR predicate to test if the result set of a query has exactly one result row. Syntax
<unique_predicate ::= SINGULAR ( <select_stmt> ) | NOT SINGULAR ( <select_stmt> )

Element
select_stmt

Description A SELECT statement as defined in the SQL Reference Manual

Semantics The SINGULAR condition tests if the result set of the select statement has exactly one result row. Firebird traverses the result set until the end is reached or until two result rows are found. On a large base table where there is likely to be one result, it hence can be an expensive operation, because all rows must be traversed in order to get to an accurate count. Examples The below are examples of valid use of the SINGULAR condtion. Both examples return TRUE:
SINGULAR( SELECT * FROM rdb$database ) NOT SINGULAR( SELECT * FROM rdb$relations )

See also EXISTS Condition Overview of PSQL Statements PSQL has a full set of statements, blending the best from traditional procedural languages like C or Pascal and from the SQL relational language: From standard procedural languages: variable assignment, calling functions and procedures, flow control through IF THEN ELSE, WHILE DO and BREAK, structured exception handling, with throw and catch From the SQL language: embedded forms of SELECT, INSERT, UPDATE and DELETE; excution of SQL statements dynamically created at runtime And to top it of: high performance cursor processing, for cursors originating from a SELECT query and for cursors originating from a selectable stored procedure.

Because PSQL programs run on the server, data transfer between the relational core and the PSQL engine is very fast, much faster than transfer to a client application. Syntax overview
<psql_statement> ::= assignment_stmt

| | | | | | | | | | | | | | | | | | | |

close_stmt compound_stmt psql_delete_stmt exception_stmt fetch_stmt raise_stmt exec_procedure_stmt exec_sql_stmt exit_stmt for_exec_into_stmt for_select_stmt if_then_else_stmt psql_insert_stmt leave_stmt open_stmt post_event_stmt psql_select_stmt psql_update_stmt while_stmt suspend_stmt

ASSIGNMENT STATEMENT Pupose Use the assignment statement: to assign the value of expression to variable, a local variable, input parameter, output parameter, or in the case of a trigger a context variable. Syntax
<assignment_stmt> ::= <identifier> = <psql_expression>;

Element
identifier psql_expression

Description Name of a variable or parameter Expression with a datatype matching the variable

Semantics An assignment statement sets the value of a local variable, input parameter, or output parameter. Variables must be declared before they can be used in assignment statements. Examples
i = i + 23; lbl = 'Sales by state';

See also VARIABLE DECLARATIONS

COMPOUND STATEMENT Pupose Use a compound statement to defines a block of statements that executes as one. Syntax
<compound_stmt> ::= BEGIN <stmt_list> [ <excep_handlers> ] END <stmt_list> ::= <psql_statement> | <psql_statement> <stmt_list>

Note: unlike all other PSQL statements, a BEGIN .. END block is not followed by a semicolon.

Element
excep_handlers psql_statement

Description Optional exception handlers for the block A single PSQL statement; see the STATEMENTS sections for an overview of statement types.

Semantics Each block of statements in the procedure body starts with a BEGIN statement and ends with an END statement. A compound statement can itself contain other compound statements, so there may be many levels of nesting. A compound statement can have its own error handlers. See the section on exception handlers for information about how exceptions are handled. Examples The below is an example of a valid block:
BEGIN a = 10 / b; WHEN GDSCODE arith_except DO a = 0; END

See also PSQL Programs

DELETE STATEMENT Pupose Use the delete statement to delete a number of rows from a table. The PSQL delete statement is identical to the SQL delete statement followed by a semicolon. Syntax
<psql_delete_stmt> ::= <delete_stmt> ;

Element
delete_statement

Description A SQL delete statement as defined in the SQL Reference manual.

Semantics See the SQL Reference Manual for a description of the delete statement. Examples The below is an example of a valid DELETE statement in PSQL:
DELETE FROM table1 WHERE id = :emp_id

See also INSERT, UPDATE and SELECT

EXCEPTION STATEMENT Pupose Use this statement to raise a named exception or re-raise an active exception from within an exception handler. Syntax
<exception_stmt> ::= EXCEPTION <exception_name>; | EXCEPTION <exception_name> <psql_expr>; | EXCEPTION; <exception_name> ::= <identifier>

Element
identifier psql_expr

Description Name of a defined exception. Text expression, overriding the predefined associated message for the named exception.

Semantics Raises the named exception: an exception is a user-defined error that returns an error message to the calling application unless handled by a WHEN statement. The third syntax form EXCEPTION without an exception name - re-raises the current exception is only valid from within an exception handler. It has no effect when used in the statement part of a block. Examples The below examples show valid uses of the EXCEPTION statement:
EXCEPTION bad_data_found; EXCEPTION user_error 'Value must be smaller than 100'; WHEN ANY IF SQLCODE <> -802 THEN EXCEPTION;

See also EXCEPTION HANDLERS

EXECUTE PROCEDURE STATEMENT Pupose Executes a stored procedure with the listed input arguments, returning values in the listed output arguments following RETURNING_VALUES. Syntax
<exec_procedure_stmt> ::= EXECUTE PROCEDURE <proc_name> [ <input_params> | ( <input_params> ) ] [ RETURNING_VALUES [ <var_list> | ( <var_list> ) ]] ; <input_params> ::= <psql_expr_list>

<var_list> ::= <variable_name> | <variable_name> , <var_list> <variable_name> ::= <identifier>

Element
psql_expr_list

Description A comma separated list of PSQL expressions; see the EXPRESSIONS section for a detailed discussion. The name of a local variable of the enclosing body or of a parameter of the enclosing procedure definition.

variable_name

Semantics EXECUTE PROCEDURE calls the specified stored procedure. If the procedure requires input parameters, the number of expressions passed in must match the number of formal parameters. Expressions are always passed by value, i.e. The called procedure works with local copies of the values passed in. If a procedure returns output parameters to a PSQL routine, receiving variables must be supplied in the RETURNING_VALUES clause to hold the values returned. The variables can be either local variables or in the case of a procedure body, parameters of the defining procedure. A stored procedure can itself execute a stored procedure. Each time a stored procedure calls another procedure, the call is said to be nested because it occurs in the context of a previous and still active call to the first procedure. Stored procedures can be nested up to 1,000 levels deep. This limitation helps to prevent infinite loops that can occur when a recursive procedure provides no absolute terminating condition. Nested procedure calls may be restricted to fewer than 1,000 levels by memory and stack limitations of the server. Examples The below examples show valid uses of the EXECUTE PROCEDURE statement:
EXECUTE PROCEDURE log_error('SYS2307', 'No such employee'); EXECUTE PROCEDURE fac( 23 ) RETURNING_VALUES :factorial;

See also DEFINING PROCEDURES

EXECUTE SQL STATEMENT Pupose The execute sql statement allows the excution of a possibly dynamically created - SQL statement, contained in a string expression. Syntax
<exec_sql_stmt> ::= EXECUTE STATEMENT <psql_expr> [ INTO <var_list> ] ; <var_list> ::= <variable_name> | <variable_name> , <var_list> <variable_name> ::= <identifier>

Element
psql_expr

Description A PSQL expression evaluating to a string containing a valid SQL statement. The name of a local variable of the enclosing body or of a parameter of the enclosing procedure definition.

variable_name

Semantics The execute SQL statement allows the execution of SQL statements that are not also PSQL statements (i.e. SELECT, INSERT, DELETE and UPDATE), for example a SET STATISTICS statement. It also allows the excution of dynamically constructed SQL statements. Note that not all SQL statements are allowed. Statements that alter the state of the current transaction (such as COMMIT and ROLLBACK) are not allowed and will cause a runtime error. The INTO clause is only meaningful if the SQL statement returns values, such as SELECT, INSERT ... RETURNING or UPDATE ... RETURNING. If the SQL statement is a SELECT statement, it must be a 'singleton' SELECT, i.e. it must return exactly one row. To work with SELECT statements that return multiple rows, use the FOR EXECUTE INTO statement. It is not possible to use parameter markers ('?') in the SQL statement, as there is no way to specify the input actuals. Rather than using parameter markers, dynamically construct the SQL statement, using the input actuals as part of the construction process. Examples The below examples show valid uses of the EXECUTE STATEMENT statement:
EXECUTE STATEMENT 'SET STATISTICS INDEX emp_id_idx'; EXECUTE STATEMENT 'SELECT 3 FROM rdb$database' INTO :a;

See also

FOR EXECUTE INTO, and the PSQL statements SELECT, UPDATE, INSERT and DELETE for using SQL directly in your PSQL routine. See the SQL Reference Manual for a full discussion of SQL statements.

EXIT STATEMENT Pupose Use EXIT to terminate a PSQL routine from any place in its code. Syntax
<exit_stmt> ::= EXIT ;

Semantics The EXIT statement jumps to the final END statement in the PSQL body, at wich time the usual clean up actions occur. See the Procedure/Trigger Body section for a discussion of these actions. EXIT is most commonly used inside a complex routine to signal the end of a code path. Using EXIT usually allows for easier to read code in such circumstances. Examples The below example shows a loop that potentially has a thousand itterations. After itteration 13 the loop is terminated and the PSQL program finishes.
DECLARE i INTEGER; BEGIN WHILE (i<1000) DO BEGIN i = i + 1; IF (i=13) THEN EXIT; END END;

See also LEAVE statement

FETCH CURSOR STATEMENT Pupose Use the FETCH statement to open a local cursor. Syntax
<open_stmt> ::= FETCH <cursor_name> INTO <var_list>; <cursor_name> ::= <identifier> <var_list> ::= <variable_name> | <variable_name> , <var_list> <variable_name> ::= <identifier>

Element
cursor_name variable_name

Description Name of a local cursor The name of a local variable or of a parameter of the enclosing procedure definition.

Semantics The FETCH statement retrieves a row of the cursor result set into local variables for further processing. The cursor must have been declared in the declarations section of the PSQL program, and previously opened with an OPEN statement. Fetching rows beyond the last row will not raise a NOT_FOUND exception, but is silently ignored. Use the ROW_COUNT function to test if values were returned from the result set. Attempts to fetch from a cursor that is closed, or attempts to fetch from a named FOR SELECT cursor will fail and generate a run-time exception. Examples The following PSQL program opens a cursor, fetches all rows and then closes the cursor:
DECLARE SYS_TAB_CNT INTEGER = 0; DECLARE FLAG INTEGER; DECLARE C CURSOR FOR (SELECT COALESCE(RDB$SYSTEM_FLAG, 0) FROM RDB$RELATIONS ); BEGIN OPEN C; WHILE (1 = 1) DO BEGIN FETCH C INTO :FLAG; IF (ROW_COUNT = 0) THEN LEAVE; IF (FLAG=1) THEN SYS_TAB_CNT = SYS_TAB_CNT + 1 END CLOSE C; END

See also

OPEN statement, CLOSE statement, FOR SELECT statement.

FOR EXECUTE INTO STATEMENT Pupose Use the FOR EXECUTE INTO statement to execute a possibly dynamically created SELECT statement contained in a string and process all its result rows. Syntax
<for_exec_stmt> ::= [ <label> : ] FOR EXECUTE <psql_expr> INTO <var_list> DO <psql_statement> <label> ::= <identifier>

<var_list> ::= <variable_name> | <variable_name> , <var_list> <variable_name> ::= <identifier>

Element
label psql_expr

Description A label naming the loop A PSQL expression evaluating to a string containing a valid SQL statement. A PSQL statement. Typically this will be a compund statement. The name of a local variable of the enclosing body or of a parameter of the enclosing procedure definition.

psql_statement variable_name

Semantics The execute SQL statement allows the execution of dynamically constructed SELECT statements. The rows of the result set are sequentially assigned to the variables specified in the INTO clause, and for each row the statement in the DO clause is executed. To work with SELECT statements that return only a single row, consider using the EXECUTE INTO statement. It is not possible to use parameter markers ('?') in the SELECT statement, as there is no way to specify the input actuals. Rather than using parameter markers, dynamically construct the SELECT statement, using the input actuals as part of the construction process. Examples The below examples shows a valid use of the FOR EXECUTE statement:
FOR EXECUTE 'SELECT ROW_COUNT FROM rdb$relations' INTO :i DO BEGIN INSERT INTO my_log VALUES( :i ); END

See also

EXECUTE INTO statement, SELECT INTO statement, BREAK statement. See the SQL Reference Manual for a full discussion of SQL statements.

FOR SELECT DO STATEMENT Pupose Repeats the statement or block following DO for every row retrieved by the select statement. Syntax
<for_select_stmt> ::= [ <label> : ] FOR <select_stmt> INTO <var_list> [ AS CURSOR <cursor_name> ] DO <psql_statement> <label> ::= cursor_name ::= <identifier> <identifier>

<var_list> ::= <variable_name> | <variable_name> , <var_list> <variable_name> ::= <identifier>

Element
label select_stmt

Description A label naming the loop A regular SQL select statement. See the SQL Reference manual for details about this element. A PSQL statement. Typically this body will be a compound statement. The name of a local variable of the enclosing body or of a parameter of the enclosing procedure definition. The name of a local variable of the enclosing body or of a parameter of the enclosing procedure definition.

psql_statement

cursor_name

variable_name

Semantics The FOR SELECT DO statement allows the compact processing of a SELECT statement. The rows of the result set are sequentially assigned to the variables specified in the INTO clause, and for each row the statement in the DO clause is executed. If the AS CURSOR clause is present, the select statement is assigned a cursor name. The current row being processed by the FOR SELECT DO statement can be referred to in DELETE and UPDATE statements in the body of the FOR SELECT DO by using the WHERE CURRENT OF clause of those statements. Examples In the below example, the code considers each row contained in table 'mytable' and proceeds to delete those rows where col1 is equal to 23:
DECLARE a INTEGER; BEGIN FOR SELECT col1 FROM mytable INTO :a CURSOR del_list DO BEGIN IF (a=23) THEN

DELETE FROM mytable WHERE CURRENT OF del_list; END END;

See also Refer to the SQL Reference Manual for details about the SELECT statement and about using the WHERE CURRENT OF syntax.

IF THEN ELSE STATEMENT Pupose Tests a condition, and if it evaluates to TRUE performs the statement or block following THEN; otherwise, it performs the statement or block following ELSE, if present. Syntax
<if_then_else_stmt> ::= IF <psql_condition> THEN <psql_statement> [ ELSE <psql_statement> ]

Element
psql_condition

Description A PSQL condition. See the section on Conditions for more information. A PSQL statement. Often this will be a compound statement.

psql_statement

Semantics The condition is evaluated and if it evaluates to TRUE the statement in the THEN clause is executed. If it is not TRUE, i.e. It evaluates to FALSE or to NULL, and an ELSE clause is present, then the statement in the ELSE clause is executed. IF statements can be nested, i.e. The statements in the THEN or ELSE clauses can be IF statements also. If the THEN clause contains a IF THEN ELSE statement, then that ELSE clause is deemed to be part of the nested IF, just as in nearly all other programming languages. Enclose the nested if in a compound statement if you want the ELSE clause to refer to the enclosing IF statement. Examples The below examples show valid uses of the IF statement:
IF (a>23) THEN a = a 1; IF (myname='Paul') THEN a = a + 1; ELSE a = i;

See also WHEN DO statement

INSERT STATEMENT Pupose Use the INSERT statement to insert new rows into a table. The PSQL insert statement is identical to the SQL insert statement followed by a semicolon. Syntax
<psql_insert_stmt> ::= <insert_stmt> ;

Element
insert_stmt

Description A SQL insert statement as defined in the SQL Reference manual.

Semantics See the SQL Reference Manual for a description of the insert statement. Examples The below is an example of a valid INSERT statement in PSQL:
INSERT INTO table1 VALUES ( :emp_id );

See also DELETE, UPDATE and SELECT

LEAVE (BREAK) STATEMENT Pupose Use the LEAVE statement to force an exit from a looping construct. Syntax
<break_stmt> ::= { BREAK ! LEAVE } [ <label> ]

Semantics The LEAVE statement terminates the flow in a loop, causing flow of control to move to the statement following the END statement that completes that loop. It is available inside of WHILE, FOR SELECT and FOR EXECUTE statements only, otherwise a syntax error will be thrown. The LEAVE <label> syntax allows PSQL loops to be marked with labels and terminated in Java style. The purpose is to stop execution of the current block and unwind back to the specified label. After that execution resumes at the statement following the terminated loop. Note that LEAVE without an explicit label means interrupting the current (most inner) loop. The SQL-99 standard keyword LEAVE deprecates the existing BREAK, so in new code the use of LEAVE is preferred. Examples The following example shows how the LEAVE statement can be used to force an exit to a FOR SELECT loop in the middle of processing the result set:
FOR SELECT COALESCE(RDB$SYSTEM_FLAG, 0), RDB$RELATION_NAME FROM RDB$RELATIONS ORDER BY 1 INTO :RTYPE, :RNAME DO BEGIN IF (RTYPE = 0) THEN SUSPEND; ELSE LEAVE; -- exits current loop END

The following trivial example shows how a named WHILE loop can be aborted:
CNT = 100; L1: WHILE (CNT >= 0) DO BEGIN IF (CNT < 50) THEN LEAVE L1; -- exists WHILE loop CNT = CNT l; END

The last example shows how LEAVE may be used to exit nested loops:
STMT1 = 'SELECT RDB$RELATION_NAME FROM RDB$RELATIONS'; L1: FOR EXECUTE STATEMENT :STMT1 INTO :RNAME DO

BEGIN STMT2 = 'SELECT RDB$FIELD_NAME FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = '; L2: FOR EXECUTE STATEMENT :STMT2 || :RNAME INTO :FNAME DO BEGIN IF (RNAME = 'RDB$DATABASE') THEN LEAVE L1; -- exits the outer loop ELSE IF (RNAME = 'RDB$RELATIONS') THEN LEAVE L2; -- exits the inner loop ELSE SUSPEND; END END

See also WHILE DO statement, FOR SELECT DO statement, FOR EXECUTE DO statement.

OPEN CURSOR STATEMENT Pupose Use the OPEN statement to open a local cursor. Syntax
<open_stmt> ::= OPEN <cursor_name>; <cursor_name> ::= <identifier>

Element
cursor_name

Description Name of a local cursor

Semantics The OPEN statement opens a local cursor. Opening a cursor means that the associated query is executed and the that the result set is kept available for subsequent processing by the FETCH statement. The cursor must have been declared in the declarations section of the PSQL program. Attempts to open a cursor that is already open, or attempts to open a named FOR SELECT cursor will fail and generate a run-time exception. All cursors which were not explicitly closed will be closed automatically on exit from the current PSQL program. Examples The following PSQL program opens a cursor, fetches a single row and then closes the cursor:
DECLARE RNAME CHAR(31); DECLARE C CURSOR FOR (SELECT RDB$RELATION_NAME FROM RDB$RELATIONS); BEGIN OPEN C; FETCH C INTO :RNAME; CLOSE C; END

See also CLOSE statement, FETCH statement.

POST_EVENT STATEMENT Pupose Use the POST_EVENT statement to signal a named event to the user application. Syntax
<post_event_stmt> ::= POST_EVENT <psql_expr>;

Element
psql_expr

Description A PSQL expression evaluating to a string value

Semantics POST_EVENT posts an event to the event manager. When an event occurs, this statement will notify the event manager, which alerts applications waiting for the named event. The event name can be a maximum of 78 characters in length. Examples The below example shows a valid use of the POST_EVENT statement:
POST_EVENT 'currency_table_updated'

See also See the C/C++ Programming Manual for more information on handling events received by your application.

SELECT INTO STATEMENT Pupose Use the SELECT INTO statement to retrieve a single row from a table. The PSQL select statement is identical to the SQL select statement followed by an INTO clause and a semicolon. Syntax
<psql_select_stmt> ::= <select_stmt> INTO <var_list> ; <var_list> ::= <variable_name> | <variable_name> , <var_list> <variable_name> ::= <identifier>

Element
select_stmt

Description A SQL insert statement as defined in the SQL Reference manual. The name of a local variable of the enclosing body or of a parameter of the enclosing procedure definition.

variable_name

Semantics See the SQL Reference Manual for a description of the select statement. The select statement must return exactly one row. If it returns zero or more than one row, a runtime error occurs. Examples The below is an example of a valid INSERT statement in PSQL:
SELECT COUNT(*) FROM rdb$relations INTO :table_count

See also DELETE, UPDATE and INSERT

SUSPEND STATEMENT Pupose Use SUSPEND to return a row of data from a procedure to its caller. Syntax
<suspend_stmt> ::= SUSPEND ;

Semantics Suspends execution of a PSQL routine until the next value is requested by the calling application, and returns output values, if any, to the calling application. If the procedure is called from a select statement, processing will continue at the statement following SUSPEND when the next row of data is needed. Use the EXIT statement or let the code path end at the final END of the body to signal that there are no more rows to return. If the procedure is called from a EXECUTE PROCEDURE statement, then SUSPEND has the same effect as EXIT. This usage is legal, but not recommended. Examples The below creates a procedure that returns the a series of integers and stops as soon as a value larger than 1000 has been reached.
CREATE PROCEDURE range RETURNING ( a INTEGER ) AS DECLARE i INTEGER = 1; DECLARE j INTEGER = 1; BEGIN a = i + j; i = j; j = a; IF (a>1000) THEN EXIT; SUSPEND; END;

See also EXIT statement; PSQL Programs; See the SQL Reference Manual for a description of using procedures in SELECT statements.

UPDATE STATEMENT Pupose Use the UPDATE statement to update new rows into a table. The PSQL update statement is identical to the SQL update statement followed by a semicolon. Syntax
<psql_update_stmt> ::= <update_stmt> ;

Element
update_stmt

Description A SQL update statement as defined in the SQL Reference manual.

Semantics See the SQL Reference Manual for a description of the update statement. Examples The below is an example of a valid UPDATE statement in PSQL:
UPDATE table1 SET salary = :new_sal WHERE id = :emp_id;

See also DELETE, INSERT and SELECT

WHILE DO STATEMENT Pupose Use the WHILE DO statement to repeat a PSQL statement as long as a condition holds true. Syntax
<while_stmt> ::= [ <label : ] WHILE ( <psql_condition> ) DO <psql_statement> <label> ::= <identifier>

Element
label psql_condition

Description A label naming the loop A PSQL condition. See the section on Conditions for more information. A PSQL statement. Often this will be a compound statement.

psql_statement

Semantics The WHILE DO statement is a looping construct that repeats a statement usually a compund statement as long as a condition is true. The condition is tested at the start of each loop. Examples The below example shows a valid use of the WHEN DO statement:
WHILE (i<23) DO i=i+1;

See also LEAVE statement

Legal information
Unless otherwise indicated, this Web Site and its contents are the property of Janus Ventures BV ("Janus"). The copyright and all other intellectual property rights in the material contained on this Web Site belongs to Janus or its licensors. The trademarks appearing on this Web Site are protected by the laws of the Netherlands and international trademark laws. In accessing this Web Site, you agree that the Web Site is made available for your personal, non-commercial use only. Unless you have Janus' prior written permission, you are not permitted to copy, broadcast, make available to the public, download, store (in any medium), transmit, show or play in public, adapt or change in any way the material (or any part of it) contained on this Web Site for any purpose whatsoever. THIS WEB SITE AND ITS CONTENT IS PROVIDED FOR USE "AS IS". JANUS MAKES NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THIS WEB SITE OR ITS CONTENTS, ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF SATISFACTORY QUALITY AND FITNESS FOR PURPOSE RELATING TO THIS WEB SITE AND/OR ITS CONTENT AND/OR ANY WEB SITE TO WHICH IS LINKED ARE HEREBY TO THE FULLEST EXTENT PERMITTED BY LAW EXCLUDED. NO REPRESENTATIONS OR WARRANTIES ARE GIVEN AS TO THE ACCURACY OR COMPLETENESS OF THE INFORMATION PROVIDED ON THIS WEB SITE, OR ANY WEB SITE TO WHICH IT IS LINKED. In no event shall Janus or its employees, agents, suppliers, or contractors be liable for any damages of any nature, including without limitation any consequential loss, loss of income or profit, loss of or damage to property, claims of third parties, or any other loss, cost, claim or expense of any kind or character arising out of or in connection with the use of this Web Site, its content or any Web Site with which it is linked. This exclusion and limitation only applies to the extent permitted by law.

You might also like