From e79bf9478f85a4b8bcb0702e6aff9427f9925a31 Mon Sep 17 00:00:00 2001 From: Josh Heyer Date: Tue, 25 Jul 2023 15:43:56 +0000 Subject: [PATCH 01/24] Begin fork of EPAS 16 docs --- .../07_reference.mdx | 1257 +++++++++++++++++ 1 file changed, 1257 insertions(+) create mode 100644 product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx diff --git a/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx b/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx new file mode 100644 index 00000000000..4e1811f9467 --- /dev/null +++ b/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx @@ -0,0 +1,1257 @@ +--- +title: "Language element reference" +description: "Description of the ECPGPlus language elements" +legacyRedirectsGenerated: + # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.55.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.56.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.57.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.23.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.49.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.51.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.28.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.24.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.27.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.48.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.29.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.25.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.30.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.47.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.31.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.46.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.32.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.45.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.33.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.44.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.34.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.26.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.43.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.35.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.52.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.50.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.42.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.53.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.54.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.36.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.59.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.58.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.41.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.37.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.40.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.38.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.39.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.093.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.058.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.031.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.033.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.085.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.087.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.082.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.088.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.349.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.351.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.352.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.350.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.348.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.114.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.119.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.113.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.111.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.108.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.086.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.063.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.061.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.103.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.104.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.100.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.102.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.101.html" +redirects: + - /epas/latest/ecpgplus_guide/07_reference/ #generated for docs/epas/reorg-role-use-case-mode + - ../../../application_programming/ecpgplus_guide/07_reference/ +--- + + + +An embedded SQL statement allows your client application to interact with the server. An embedded directive is an instruction to the ECPGPlus compiler. + +You can embed any EDB Postgres Advanced Server SQL statement in a C program. Each statement must begin with the keywords `EXEC SQL` and must be terminated with a semi-colon (;). In the C program, a SQL statement takes the form: + +```sql +EXEC SQL ; +``` + +Where `sql_command_body` represents a standard SQL statement. You can use a host variable anywhere that the SQL statement expects a value expression. For more information about substituting host variables for value expressions, see [Declaring host variables](/epas/latest/application_programming/ecpgplus_guide/03_using_embedded_sql/#declaring-host-variables). + +ECPGPlus extends the PostgreSQL server-side syntax for some statements. Syntax differences are noted in the reference information that follows. For a complete reference to the supported syntax of other SQL commands, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-commands.html). + +## ALLOCATE DESCRIPTOR + +Use the `ALLOCATE DESCRIPTOR` statement to allocate an SQL descriptor area: + +```sql +EXEC SQL [FOR ] ALLOCATE DESCRIPTOR + [WITH MAX ]; +``` + +Where: + +- `array_size` is a variable that specifies the number of array elements to allocate for the descriptor. `array_size` can be an `INTEGER` value or a host variable. +- `descriptor_name` is the host variable that contains the name of the descriptor or the name of the descriptor. This value can take the form of an identifier, a quoted string literal, or of a host variable. +- `variable_count` specifies the maximum number of host variables in the descriptor. The default value of `variable_count` is `100`. + +The following code fragment allocates a descriptor named `emp_query` that can be processed as an array `(emp_array)`: + +```sql +EXEC SQL FOR :emp_array ALLOCATE DESCRIPTOR emp_query; +``` + +## CALL + +Use the `CALL` statement to invoke a procedure or function on the server. The `CALL` statement works only on EDB Postgres Advanced Server. The `CALL` statement comes in two forms. The first form is used to call a function: + +```sql +EXEC SQL CALL '('[]')' + INTO [[:][: ]]; +``` + +The second form is used to call a procedure: + +```sql +EXEC SQL CALL '('[]')'; +``` + +Where: + +- `program_name` is the name of the stored procedure or function that the `CALL` statement invokes. The program name can be schema qualified, package qualified, or both. If you don't specify the schema or package in which the program resides, ECPGPlus uses the value of `search_path` to locate the program. +- `actual_arguments` specifies a comma-separated list of arguments required by the program. Each `actual_argument` corresponds to a formal argument expected by the program. Each formal argument can be an `IN` parameter, an `OUT` parameter, or an `INOUT` parameter. +- `:ret_variable` specifies a host variable that receives the value returned if the program is a function. +- `:ret_indicator` specifies a host variable that receives the indicator value returned if the program is a function. + +For example, the following statement invokes the `get_job_desc` function with the value contained in the `:ename` host variable and captures the value returned by that function in the `:job` host variable: + +```sql +EXEC SQL CALL get_job_desc(:ename) + INTO :job; +``` + +## CLOSE + +Use the `CLOSE` statement to close a cursor and free any resources currently in use by the cursor. A client application can't fetch rows from a closed cursor. The syntax of the `CLOSE` statement is: + +```sql +EXEC SQL CLOSE []; +``` + +Where `cursor_name` is the name of the cursor closed by the statement. The cursor name can take the form of an identifier or of a host variable. + +The `OPEN` statement initializes a cursor. Once initialized, a cursor result set remains unchanged unless the cursor is reopened. You don't need to `CLOSE` a cursor before reopening it. + +To manually close a cursor named `emp_cursor`, use the command: + +```sql +EXEC SQL CLOSE emp_cursor; +``` + +A cursor is automatically closed when an application terminates. + +## COMMIT + +Use the `COMMIT` statement to complete the current transaction, making all changes permanent and visible to other users. The syntax is: + +```sql +EXEC SQL [AT ] COMMIT [WORK] + [COMMENT <'text'>] [COMMENT <'text'> RELEASE]; +``` + +Where `database_name` is the name of the database or host variable that contains the name of the database in which the work resides. This value can take the form of an unquoted string literal or of a host variable. + +For compatibility, ECPGPlus accepts the `COMMENT` clause without error but doesn't store any text included with the `COMMENT` clause. + +Include the `RELEASE` clause to close the current connection after performing the commit. + +For example, the following command commits all work performed on the `dept` database and closes the current connection: + +```sql +EXEC SQL AT dept COMMIT RELEASE; +``` + +By default, statements are committed only when a client application performs a `COMMIT` statement. Include the `-t` option when invoking ECPGPlus to specify for a client application to invoke `AUTOCOMMIT` functionality. You can also control `AUTOCOMMIT` functionality in a client application with the following statements: + +```sql +EXEC SQL SET AUTOCOMMIT TO ON +``` + +and + +```sql +EXEC SQL SET AUTOCOMMIT TO OFF +``` + +## CONNECT + +Use the `CONNECT` statement to establish a connection to a database. The `CONNECT` statement is available in two forms. One form is compatible with Oracle databases, and the other is not. + +The first form is compatible with Oracle databases: + +```sql +EXEC SQL CONNECT + {{: IDENTIFIED BY :} | :} + [AT ] + [USING :database_string] + [ALTER AUTHORIZATION :new_password]; +``` + +Where: + +- `user_name` is a host variable that contains the role that the client application uses to connect to the server. +- `password` is a host variable that contains the password associated with that role. +- `connection_id` is a host variable that contains a slash-delimited user name and password used to connect to the database. + +Include the `AT` clause to specify the database to which the connection is established. `database_name` is the name of the database to which the client is connecting. Specify the value in the form of a variable or as a string literal. + +Include the `USING` clause to specify a host variable that contains a null-terminated string identifying the database to which to establish the connection. + +The `ALTER AUTHORIZATION` clause is supported for syntax compatibility only. ECPGPlus parses the `ALTER AUTHORIZATION` clause and reports a warning. + +Using the first form of the `CONNECT` statement, a client application might establish a connection with a host variable named `user` that contains the identity of the connecting role and a host variable named `password` that contains the associated password using the following command: + +```text +EXEC SQL CONNECT :user IDENTIFIED BY :password; +``` + +A client application can also use the first form of the `CONNECT` statement to establish a connection using a single host variable named `:connection_id`. In the following example, `connection_id` contains the slash-delimited role name and associated password for the user: + +```sql +EXEC SQL CONNECT :connection_id; +``` + +The syntax of the second form of the `CONNECT` statement is: + +```sql +EXEC SQL CONNECT TO +[AS ] []; +``` + +Where `credentials` is one of the following: + +```sql +USER user_name password +USER user_name IDENTIFIED BY password +USER user_name USING password +``` + +In the second form: + +`database_name` is the name or identity of the database to which the client is connecting. Specify `database_name` as a variable or as a string literal in one of the following forms: + +```text +[@][:] + +tcp:postgresql://[:][/][options] + +unix:postgresql://[:][/][options] +``` + +Where: + +- `hostname` is the name or IP address of the server on which the database resides. +- `port` is the port on which the server listens. + + You can also specify a value of `DEFAULT` to establish a connection with the default database, using the default role name. If you specify `DEFAULT` as the target database, don't include a `connection_name` or `credentials`. + +- `connection_name` is the name of the connection to the database. `connection_name` takes the form of an identifier (that is, not a string literal or a variable). You can open multiple connections by providing a unique `connection_name` for each connection. + + If you don't specify a name for a connection, `ecpglib` assigns a name of `DEFAULT` to the connection. You can refer to the connection by name (`DEFAULT`) in any `EXEC SQL` statement. + +- `CURRENT` is the most recently opened or the connection mentioned in the most-recent `SET CONNECTION TO` statement. If you don't refer to a connection by name in an `EXEC SQL` statement, ECPG assumes the name of the connection to be `CURRENT`. + +- `user_name` is the role used to establish the connection with the EDB Postgres Advanced Server database. The privileges of the specified role are applied to all commands performed through the connection. + +- `password` is the password associated with the specified `user_name`. + +The following code fragment uses the second form of the `CONNECT` statement to establish a connection to a database named `edb` using the role `alice` and the password associated with that role, `1safepwd`: + +```sql +EXEC SQL CONNECT TO edb AS acctg_conn + USER 'alice' IDENTIFIED BY '1safepwd'; +``` + +The name of the connection is `acctg_conn`. You can use the connection name when changing the connection name using the `SET CONNECTION` statement. + +## DEALLOCATE DESCRIPTOR + +Use the `DEALLOCATE DESCRIPTOR` statement to free memory in use by an allocated descriptor. The syntax of the statement is: + +```sql +EXEC SQL DEALLOCATE DESCRIPTOR +``` + +Where `descriptor_name` is the name of the descriptor. This value can take the form of a quoted string literal or of a host variable. + +The following example deallocates a descriptor named `emp_query`: + +```sql +EXEC SQL DEALLOCATE DESCRIPTOR emp_query; +``` + +## DECLARE CURSOR + +Use the `DECLARE CURSOR` statement to define a cursor. The syntax of the statement is: + +```sql +EXEC SQL [AT ] DECLARE CURSOR FOR +( | ); +``` + +Where: + +- `database_name` is the name of the database on which the cursor operates. This value can take the form of an identifier or of a host variable. If you don't specify a database name, the default value of `database_name` is the default database. +- `cursor_name` is the name of the cursor. +- `select_statement` is the text of the `SELECT` statement that defines the cursor result set. The `SELECT` statement can't contain an `INTO` clause. +- `statement_name` is the name of a SQL statement or block that defines the cursor result set. + +The following example declares a cursor named `employees`: + +```sql +EXEC SQL DECLARE employees CURSOR FOR + SELECT + empno, ename, sal, comm + FROM + emp; +``` + +The cursor generates a result set that contains the employee number, employee name, salary, and commission for each employee record that's stored in the `emp` table. + +## DECLARE DATABASE + +Use the `DECLARE DATABASE` statement to declare a database identifier for use in subsequent SQL statements (for example, in a `CONNECT` statement). The syntax is: + +```sql +EXEC SQL DECLARE DATABASE; +``` + +Where `database_name` specifies the name of the database. + +The following example shows declaring an identifier for the `acctg` database: + +```sql +EXEC SQL DECLARE acctg DATABASE; +``` + +After invoking the command declaring `acctg` as a database identifier, you can reference the `acctg` database by name when establishing a connection or in `AT` clauses. + +This statement has no effect and is provided for Pro\*C compatibility only. + +## DECLARE STATEMENT + +Use the `DECLARE STATEMENT` directive to declare an identifier for an SQL statement. EDB Postgres Advanced Server supports two versions of the `DECLARE STATEMENT` directive: + +```sql +EXEC SQL [] DECLARE STATEMENT; +``` + +and + +```sql +EXEC SQL DECLARE STATEMENT ; +``` + +Where: + +- `statement_name` specifies the identifier associated with the statement. +- `database_name` specifies the name of the database. This value may take the form of an identifier or of a host variable that contains the identifier. + +A typical usage sequence that includes the `DECLARE STATEMENT` directive is: + +```sql +EXEC SQL DECLARE give_raise STATEMENT; // give_raise is now a statement +handle (not prepared) +EXEC SQL PREPARE give_raise FROM :stmtText; // give_raise is now associated +with a statement +EXEC SQL EXECUTE give_raise; +``` + +This statement has no effect and is provided for Pro\*C compatibility only. + +## DELETE + +Use the `DELETE` statement to delete one or more rows from a table. The syntax for the ECPGPlus `DELETE` statement is the same as the syntax for the SQL statement, but you can use parameter markers and host variables any place that an expression is allowed. The syntax is: + +```sql +[FOR ] DELETE FROM [ONLY] [[AS] ] + [USING ] + [WHERE | WHERE CURRENT OF ] + [{RETURNING|RETURN} * | [[AS] ] +[, ...] INTO ] +``` + +- Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `VALUES` clause references an array or a pointer to an array. +- `table` is the name (optionally schema qualified) of an existing table. Include the `ONLY` clause to limit processing to the specified table. If you don't include the `ONLY` clause, any tables inheriting from the named table are also processed. +- `alias` is a substitute name for the target table. +- `using_list` is a list of table expressions, allowing columns from other tables to appear in the `WHERE` condition. +- Include the `WHERE` clause to specify the rows to delete. If you don't include a `WHERE` clause in the statement, `DELETE` deletes all rows from the table, leaving the table definition intact. +- `condition` is an expression, host variable, or parameter marker that returns a value of type `BOOLEAN`. Those rows for which `condition` returns true are deleted. +- `cursor_name` is the name of the cursor to use in the `WHERE CURRENT OF` clause. The row to be deleted is the one most recently fetched from this cursor. The cursor must be a nongrouping query on the `DELETE` statements target table. You can't specify `WHERE CURRENT OF` in a `DELETE` statement that includes a Boolean condition. + +The `RETURN/RETURNING` clause specifies an `output_expression` or `host_variable_list` that's returned by the `DELETE` command after each row is deleted: + + - `output_expression` is an expression to be computed and returned by the `DELETE` command after each row is deleted. `output_name` is the name of the returned column. Include \* to return all columns. + - `host_variable_list` is a comma-separated list of host variables and optional indicator variables. Each host variable receives a corresponding value from the `RETURNING` clause. + +For example, the following statement deletes all rows from the `emp` table, where the `sal` column contains a value greater than the value specified in the host variable, `:max_sal:` + +```sql +DELETE FROM emp WHERE sal > :max_sal; +``` + +For more information about using the `DELETE` statement, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-delete.html). + +## DESCRIBE + +Use the `DESCRIBE` statement to find the number of input values required by a prepared statement or the number of output values returned by a prepared statement. The `DESCRIBE` statement is used to analyze a SQL statement whose shape is unknown at the time you write your application. + +The `DESCRIBE` statement populates an `SQLDA` descriptor. To populate a SQL descriptor, use the `ALLOCATE DESCRIPTOR` and `DESCRIBE...DESCRIPTOR` statements. + +```sql +EXEC SQL DESCRIBE BIND VARIABLES FOR INTO ; +``` + + +```sql +EXEC SQL DESCRIBE SELECT LIST FOR INTO ; +``` + +Where: + +- `statement_name` is the identifier associated with a prepared SQL statement or PL/SQL block. +- `descriptor` is the name of C variable of type `SQLDA*`. You must allocate the space for the descriptor by calling `sqlald()` and initialize the descriptor before executing the `DESCRIBE` statement. + +When you execute the first form of the `DESCRIBE` statement, ECPG populates the given descriptor with a description of each input variable *required* by the statement. For example, given two descriptors: + +```sql +SQLDA *query_values_in; +SQLDA *query_values_out; +``` + +You might prepare a query that returns information from the `emp` table: + +```sql +EXEC SQL PREPARE get_emp FROM + "SELECT ename, empno, sal FROM emp WHERE empno = ?"; +``` + +The command requires one input variable for the parameter marker (?). + +```sql +EXEC SQL DESCRIBE BIND VARIABLES + FOR get_emp INTO query_values_in; +``` + +After describing the bind variables for this statement, you can examine the descriptor to find the number of variables required and the type of each variable. + +When you execute the second form, ECPG populates the given descriptor with a description of each value returned by the statement. For example, the following statement returns three values: + +```sql +EXEC SQL DESCRIBE SELECT LIST + FOR get_emp INTO query_values_out; +``` + +After describing the select list for this statement, you can examine the descriptor to find the number of returned values and the name and type of each value. + +Before executing the statement, you must bind a variable for each input value and a variable for each output value. The variables that you bind for the input values specify the actual values used by the statement. The variables that you bind for the output values tell ECPGPlus where to put the values when you execute the statement. + +This is alternative Pro\*C-compatible syntax for the `DESCRIBE DESCRIPTOR` statement. + +## DESCRIBE DESCRIPTOR + +Use the `DESCRIBE DESCRIPTOR` statement to retrieve information about a SQL statement and store that information in a SQL descriptor. Before using `DESCRIBE DESCRIPTOR`, you must allocate the descriptor with the `ALLOCATE DESCRIPTOR` statement. The syntax is: + +```sql +EXEC SQL DESCRIBE [INPUT | OUTPUT] + USING [SQL] DESCRIPTOR ; +``` + +Where: + +- `statement_name` is the name of a prepared SQL statement. +- `descriptor_name` is the name of the descriptor. `descriptor_name` can be a quoted string value or a host variable that contains the name of the descriptor. + +If you include the `INPUT` clause, ECPGPlus populates the given descriptor with a description of each input variable required by the statement. + +For example, given two descriptors: + +```sql +EXEC SQL ALLOCATE DESCRIPTOR query_values_in; +EXEC SQL ALLOCATE DESCRIPTOR query_values_out; +``` + +You might prepare a query that returns information from the `emp` table: + +```sql +EXEC SQL PREPARE get_emp FROM + "SELECT ename, empno, sal FROM emp WHERE empno = ?"; +``` + +The command requires one input variable for the parameter marker (?). + +```sql +EXEC SQL DESCRIBE INPUT get_emp USING 'query_values_in'; +``` + +After describing the bind variables for this statement, you can examine the descriptor to find the number of variables required and the type of each variable. + +If you don't specify the `INPUT` clause, `DESCRIBE DESCRIPTOR` populates the specified descriptor with the values returned by the statement. + +If you include the `OUTPUT` clause, ECPGPlus populates the given descriptor with a description of each value returned by the statement. + +For example, the following statement returns three values: + +```sql +EXEC SQL DESCRIBE OUTPUT FOR get_emp USING 'query_values_out'; +``` + +After describing the select list for this statement, you can examine the descriptor to find the number of returned values and the name and type of each value. + +## DISCONNECT + +Use the `DISCONNECT` statement to close the connection to the server. The syntax is: + +```sql +EXEC SQL DISCONNECT [][CURRENT][DEFAULT][ALL]; +``` + +Where `connection_name` is the connection name specified in the `CONNECT` statement used to establish the connection. If you don't specify a connection name, the current connection is closed. + +Include the `CURRENT` keyword to specify for ECPGPlus to close the connection used most recently. + +Include the `DEFAULT` keyword to specify for ECPGPlus to close the connection named `DEFAULT`. If you don't specify a name when opening a connection, ECPGPlus assigns the name `DEFAULT` to the connection. + +Include the `ALL` keyword to close all active connections. + +The following example creates a connection named `hr_connection` that connects to the `hr` database and then disconnects from the connection: + +```c +/* client.pgc*/ +int main() +{ + EXEC SQL CONNECT TO hr AS connection_name; + EXEC SQL DISCONNECT connection_name; + return(0); +} +``` + +## EXECUTE + +Use the `EXECUTE` statement to execute a statement previously prepared using an `EXEC SQL PREPARE` statement. The syntax is: + +```sql +EXEC SQL [FOR ] EXECUTE + [USING {DESCRIPTOR + |: [[INDICATOR] :]}]; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `statement_name` specifies the name assigned to the statement when the statement was created using the `EXEC SQL PREPARE` statement. + +Include the `USING` clause to supply values for parameters in the prepared statement: + +- Include the `DESCRIPTOR` `SQLDA_descriptor` clause to provide an SQLDA descriptor value for a parameter. +- Use a `host_variable` (and an optional `indicator_variable`) to provide a user-specified value for a parameter. + +The following example creates a prepared statement that inserts a record into the `emp` table: + +```sql +EXEC SQL PREPARE add_emp (numeric, text, text, numeric) AS + INSERT INTO emp VALUES($1, $2, $3, $4); +``` + +Each time you invoke the prepared statement, provide fresh parameter values for the statement: + +```sql +EXEC SQL EXECUTE add_emp USING 8000, 'DAWSON', 'CLERK', 7788; +EXEC SQL EXECUTE add_emp USING 8001, 'EDWARDS', 'ANALYST', 7698; +``` + +## EXECUTE DESCRIPTOR + +Use the `EXECUTE` statement to execute a statement previously prepared by an `EXEC SQL PREPARE` statement, using an SQL descriptor. The syntax is: + +```sql +EXEC SQL [FOR ] EXECUTE + [USING [SQL] DESCRIPTOR ] + [INTO [SQL] DESCRIPTOR ]; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `statement_identifier` specifies the identifier assigned to the statement with the `EXEC SQL PREPARE` statement. +- `descriptor_name` specifies the name of a descriptor (as a single-quoted string literal), or a host variable that contains the name of a descriptor. + +Include the `USING` clause to specify values for any input parameters required by the prepared statement. + +Include the `INTO` clause to specify a descriptor into which the `EXECUTE` statement writes the results returned by the prepared statement. + +The following example executes the prepared statement, `give_raise`, using the values contained in the descriptor `stmtText:` + +```sql +EXEC SQL PREPARE give_raise FROM :stmtText; +EXEC SQL EXECUTE give_raise USING DESCRIPTOR :stmtText; +``` + +## EXECUTE...END EXEC + +Use the `EXECUTE…END-EXEC` statement to embed an anonymous block into a client application. The syntax is: + +```sql +EXEC SQL [AT ] EXECUTE END-EXEC; +``` + +Where: + +- `database_name` is the database identifier or a host variable that contains the database identifier. If you omit the `AT` clause, the statement executes on the current default database. +- `anonymous_block` is an inline sequence of PL/pgSQL or SPL statements and declarations. You can include host variables and optional indicator variables in the block. Each such variable is treated as an `IN/OUT` value. + +The following example executes an anonymous block: + +```sql +EXEC SQL EXECUTE + BEGIN + IF (current_user = :admin_user_name) THEN + DBMS_OUTPUT.PUT_LINE('You are an administrator'); + END IF; +END-EXEC; +``` + +!!! Note + The `EXECUTE…END EXEC` statement is supported only by EDB Postgres Advanced Server. + +## EXECUTE IMMEDIATE + +Use the `EXECUTE IMMEDIATE` statement to execute a string that contains a SQL command. The syntax is: + +```sql +EXEC SQL [AT ] EXECUTE IMMEDIATE ; +``` + +Where: + +- `database_name` is the database identifier or a host variable that contains the database identifier. If you omit the `AT` clause, the statement executes on the current default database. +- `command_text` is the command executed by the `EXECUTE IMMEDIATE` statement. + +This dynamic SQL statement is useful when you don't know the text of an SQL statement when writing a client application. For example, a client application might prompt a trusted user for a statement to execute. After the user provides the text of the statement as a string value, the statement is then executed with an `EXECUTE IMMEDIATE` command. + +The statement text can't contain references to host variables. If the statement might contain parameter markers or returns one or more values, use the `PREPARE` and `DESCRIBE` statements. + +The following example executes the command contained in the `:command_text` host variable: + +```sql +EXEC SQL EXECUTE IMMEDIATE :command_text; +``` + +## FETCH + +Use the `FETCH` statement to return rows from a cursor into an SQLDA descriptor or a target list of host variables. Before using a `FETCH` statement to retrieve information from a cursor, you must prepare the cursor using `DECLARE` and `OPEN` statements. The statement syntax is: + +```sql +EXEC SQL [FOR ] FETCH + { USING DESCRIPTOR }|{ INTO }; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `cursor` is the name of the cursor from which rows are being fetched or a host variable that contains the name of the cursor. + +If you include a `USING` clause, the `FETCH` statement populates the specified SQLDA descriptor with the values returned by the server. + +If you include an `INTO` clause, the `FETCH` statement populates the host variables (and optional indicator variables) specified in the `target_list`. + +The following code fragment declares a cursor named `employees` that retrieves the `employee number`, `name`, and `salary` from the `emp` table: + +```sql +EXEC SQL DECLARE employees CURSOR FOR + SELECT empno, ename, esal FROM emp; +EXEC SQL OPEN emp_cursor; +EXEC SQL FETCH emp_cursor INTO :emp_no, :emp_name, :emp_sal; +``` + +## FETCH DESCRIPTOR + +Use the `FETCH DESCRIPTOR` statement to retrieve rows from a cursor into an SQL descriptor. The syntax is: + +```sql +EXEC SQL [FOR ] FETCH + INTO [SQL] DESCRIPTOR ; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `cursor` is the name of the cursor from which rows are fetched or a host variable that contains the name of the cursor. The client must `DECLARE` and `OPEN` the cursor before calling the `FETCH DESCRIPTOR` statement. +- `descriptor_name` specifies the name of a descriptor (as a single-quoted string literal) or a host variable that contains the name of a descriptor. Prior to use, the descriptor must be allocated using an `ALLOCATE DESCRIPTOR` statement. + +Include the `INTO` clause to specify a SQL descriptor into which the `EXECUTE` statement writes the results returned by the prepared statement. + +The following example allocates a descriptor named `row_desc` that holds the description and the values of a specific row in the result set. It then declares and opens a cursor for a prepared statement (`my_cursor`), before looping through the rows in result set, using a `FETCH` to retrieve the next row from the cursor into the descriptor: + +```sql +EXEC SQL ALLOCATE DESCRIPTOR 'row_desc'; +EXEC SQL DECLARE my_cursor CURSOR FOR query; +EXEC SQL OPEN my_cursor; + +for( row = 0; ; row++ ) +{ + EXEC SQL BEGIN DECLARE SECTION; + int col; +EXEC SQL END DECLARE SECTION; +EXEC SQL FETCH my_cursor INTO SQL DESCRIPTOR 'row_desc'; +``` + +## GET DESCRIPTOR + +Use the `GET DESCRIPTOR` statement to retrieve information from a descriptor. The `GET DESCRIPTOR` statement comes in two forms. The first form returns the number of values (or columns) in the descriptor. + +```sql +EXEC SQL GET DESCRIPTOR + : = COUNT; +``` + +The second form returns information about a specific value (specified by the `VALUE column_number` clause): + +```sql +EXEC SQL [FOR ] GET DESCRIPTOR + VALUE {: = {,…}}; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you specify an `array_size`, the `host_variable` must be an array of that size. For example, if `array_size` is `10`, `:host_variable` must be a 10-member array of `host_variables`. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `descriptor_name` specifies the name of a descriptor as a single-quoted string literal or a host variable that contains the name of a descriptor. + +Include the `VALUE` clause to specify the information retrieved from the descriptor. + +- `column_number` identifies the position of the variable in the descriptor. +- `host_variable` specifies the name of the host variable that receives the value of the item. +- `descriptor_item` specifies the type of the retrieved descriptor item. + +ECPGPlus implements the following `descriptor_item` types: + +- `TYPE` +- `LENGTH` +- `OCTET_LENGTH` +- `RETURNED_LENGTH` +- `RETURNED_OCTET_LENGTH` +- `PRECISION` +- `SCALE` +- `NULLABLE` +- `INDICATOR` +- `DATA` +- `NAME` + +The following code fragment shows using a `GET DESCRIPTOR` statement to obtain the number of columns entered in a user-provided string: + +```sql +EXEC SQL ALLOCATE DESCRIPTOR parse_desc; +EXEC SQL PREPARE query FROM :stmt; +EXEC SQL DESCRIBE query INTO SQL DESCRIPTOR parse_desc; +EXEC SQL GET DESCRIPTOR parse_desc :col_count = COUNT; +``` + +The example allocates an SQL descriptor named `parse_desc` before using a `PREPARE` statement to check the syntax of the string provided by the user `:stmt`. A `DESCRIBE` statement moves the user-provided string into the descriptor, `parse_desc`. The call to `EXEC SQL GET DESCRIPTOR` interrogates the descriptor to discover the number of columns `(:col_count)` in the result set. + +## INSERT + +Use the `INSERT` statement to add one or more rows to a table. The syntax for the ECPGPlus `INSERT` statement is the same as the syntax for the SQL statement, but you can use parameter markers and host variables any place that a value is allowed. The syntax is: + +```sql +[FOR ] INSERT INTO
[( [, ...])] + {DEFAULT VALUES | + VALUES ({ | DEFAULT} [, ...])[, ...] | } + [RETURNING * | [[ AS ] ] [, ...]] +``` + +Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `VALUES` clause references an array or a pointer to an array. + +- `table` specifies the (optionally schema-qualified) name of an existing table. +- `column` is the name of a column in the table. The column name can be qualified with a subfield name or array subscript. Specify the `DEFAULT VALUES` clause to use default values for all columns. +- `expression` is the expression, value, host variable, or parameter marker that's assigned to the corresponding column. Specify `DEFAULT` to fill the corresponding column with its default value. +- `query` specifies a `SELECT` statement that supplies the rows to insert. +- `output_expression` is an expression that's computed and returned by the `INSERT` command after each row is inserted. The expression can refer to any column in the table. Specify \* to return all columns of the inserted rows. +- `output_name` specifies a name to use for a returned column. + +The following example adds a row to the `employees` table: + +```sql +INSERT INTO emp (empno, ename, job, hiredate) + VALUES ('8400', :ename, 'CLERK', '2011-10-31'); +``` + +!!! Note + The `INSERT` statement uses a host variable `:ename` to specify the value of the `ename` column. + +For more information about using the `INSERT` statement, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-insert.html). + +## OPEN + +Use the `OPEN` statement to open a cursor. The syntax is: + +```sql +EXEC SQL [FOR ] OPEN [USING ]; +``` + +`parameters` is one of the following: + +```sql +DESCRIPTOR +``` + +or + +```sql + [ [ INDICATOR ] , … ] +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `cursor` is the name of the cursor being opened. +- `parameters` is either `DESCRIPTOR SQLDA_descriptor` or a comma-separated list of `host variables` and optional `indicator variables` that initialize the cursor. If specifying an `SQLDA_descriptor`, the descriptor must be initialized with a `DESCRIBE` statement. + +The `OPEN` statement initializes a cursor using the values provided in `parameters`. Once initialized, the cursor result set remains unchanged unless the cursor is closed and reopened. A cursor is automatically closed when an application terminates. + +The following example declares a cursor named `employees` that queries the `emp` table. It returns the `employee number`, `name`, `salary`, and `commission` of an employee whose name matches a user-supplied value stored in the host variable `:emp_name`. + +```sql +EXEC SQL DECLARE employees CURSOR FOR + SELECT + empno, ename, sal, comm  + FROM  + emp + WHERE ename = :emp_name; +EXEC SQL OPEN employees; +... +``` + +After declaring the cursor, the example uses an `OPEN` statement to make the contents of the cursor available to a client application. + +## OPEN DESCRIPTOR + +Use the `OPEN DESCRIPTOR` statement to open a cursor with a SQL descriptor. The syntax is: + +```sql +EXEC SQL [FOR ] OPEN + [USING [SQL] DESCRIPTOR ] + [INTO [SQL] DESCRIPTOR ]; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `cursor` is the name of the cursor being opened. +- `descriptor_name` specifies the name of an SQL descriptor in the form of a single-quoted string literal or a host variable that contains the name of an SQL descriptor that contains the query that initializes the cursor. + +For example, the following statement opens a cursor named `emp_cursor` using the host variable `:employees`: + +```sql +EXEC SQL OPEN emp_cursor USING DESCRIPTOR :employees; +``` + +## PREPARE + +Prepared statements are useful when a client application must perform a task multiple times. The statement is parsed, written, and planned only once rather than each time the statement is executed. This approach saves repetitive processing time. + +Use the `PREPARE` statement to prepare a SQL statement or PL/pgSQL block for execution. The statement is available in two forms. The first form is: + +```sql +EXEC SQL [AT ] PREPARE + FROM ; +``` + +The second form is: + +```sql +EXEC SQL [AT ] PREPARE + AS ; +``` + +Where: + +- `database_name` is the database identifier or a host variable that contains the database identifier against which the statement executes. If you omit the `AT` clause, the statement executes against the current default database. +- `statement_name` is the identifier associated with a prepared SQL statement or PL/SQL block. +- `sql_statement` can take the form of a `SELECT` statement, a single-quoted string literal, or a host variable that contains the text of an SQL statement. + +To include variables in a prepared statement, substitute placeholders (`$1, $2, $3`, and so on) for statement values that might change when you `PREPARE` the statement. When you `EXECUTE` the statement, provide a value for each parameter. Provide the values in the order in which they replace placeholders. + +The following example creates a prepared statement named `add_emp` that inserts a record into the `emp` table: + +```sql +EXEC SQL PREPARE add_emp (int, text, text, numeric) AS + INSERT INTO emp VALUES($1, $2, $3, $4); +``` + +Each time you invoke the statement, provide fresh parameter values for the statement: + +```sql +EXEC SQL EXECUTE add_emp(8003, 'Davis', 'CLERK', 2000.00); +EXEC SQL EXECUTE add_emp(8004, 'Myer', 'CLERK', 2000.00); +``` + +!!! Note + A client application must issue a `PREPARE` statement in each session in which a statement executes. Prepared statements persist only for the duration of the current session. + +## ROLLBACK + +Use the `ROLLBACK` statement to abort the current transaction and discard any updates made by the transaction. The syntax is: + +```sql +EXEC SQL [AT ] ROLLBACK [WORK] + [ { TO [SAVEPOINT] } | RELEASE ] +``` + +Where `database_name` is the database identifier or a host variable that contains the database identifier against which the statement executes. If you omit the `AT` clause, the statement executes against the current default database. + +Include the `TO` clause to abort any commands that executed after the specified `savepoint`. Use the `SAVEPOINT` statement to define the `savepoint`. If you omit the `TO` clause, the `ROLLBACK` statement aborts the transaction, discarding all updates. + +Include the `RELEASE` clause to cause the application to execute an `EXEC SQL COMMIT RELEASE` and close the connection. + +Use the following statement to roll back a complete transaction: + +```sql +EXEC SQL ROLLBACK; +``` + +Invoking this statement aborts the transaction, undoing all changes, erasing any savepoints, and releasing all transaction locks. Suppose you include a savepoint (`my_savepoint` in the following example): + +```sql +EXEC SQL ROLLBACK TO SAVEPOINT my_savepoint; +``` + +Only the portion of the transaction that occurred after the `my_savepoint` is rolled back. `my_savepoint` is retained, but any savepoints created after `my_savepoint` are erased. + +Rolling back to a specified savepoint releases all locks acquired after the savepoint. + +## SAVEPOINT + +Use the `SAVEPOINT` statement to define a *savepoint*. A savepoint is a marker in a transaction. You can use a `ROLLBACK` statement to abort the current transaction, returning the state of the server to its condition prior to the specified savepoint. The syntax of a `SAVEPOINT` statement is: + +```sql +EXEC SQL [AT ] SAVEPOINT +``` + +Where: + +- `database_name` is the database identifier or a host variable that contains the database identifier against which the savepoint resides. If you omit the `AT` clause, the statement executes against the current default database. +- `savepoint_name` is the name of the savepoint. If you reuse a `savepoint_name`, the original savepoint is discarded. + +You can establish savepoints only in a transaction block. A transaction block can contain multiple savepoints. + +To create a savepoint named `my_savepoint`, include the statement: + +```sql +EXEC SQL SAVEPOINT my_savepoint; +``` + +## SELECT + +ECPGPlus extends support of the `SQL SELECT` statement by providing the `INTO host_variables` clause. The clause allows you to select specified information from an EDB Postgres Advanced Server database into a host variable. The syntax for the `SELECT` statement is: + +```sql +EXEC SQL [AT ] +SELECT + [ ] + [ ALL | DISTINCT [ ON( , ...) ]] + select_list INTO + + [ FROM from_item [, from_item ]...] + [ WHERE condition ] + [ hierarchical_query_clause ] + [ GROUP BY expression [, ...]] + [ HAVING condition ] + [ { UNION [ ALL ] | INTERSECT | MINUS } (subquery) ] + [ ORDER BY expression [order_by_options]] + [ LIMIT { count | ALL }] + [ OFFSET start [ ROW | ROWS ] ] + [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ] + [ FOR { UPDATE | SHARE } [OF table_name [, ...]][NOWAIT ][...]] +``` + +Where: + +- `database_name` is the name of the database or host variable that contains the name of the database in which the table resides. This value can take the form of an unquoted string literal or of a host variable. +- `host_variables` is a list of host variables populated by the `SELECT` statement. If the `SELECT` statement returns more than a single row, `host_variables` must be an array. + +ECPGPlus provides support for the additional clauses of the SQL `SELECT` statement as documented in the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-select.html). + +To use the `INTO host_variables` clause, include the names of defined host variables when specifying the `SELECT` statement. For example, the following `SELECT` statement populates the `:emp_name` and `:emp_sal` host variables with a list of employee names and salaries: + +```sql +EXEC SQL SELECT ename, sal + INTO :emp_name, :emp_sal + FROM emp + WHERE empno = 7988; +``` + +The enhanced `SELECT` statement also allows you to include parameter markers (question marks) in any clause where a value is allowed. For example, the following query contains a parameter marker in the `WHERE` clause: + +```sql +SELECT * FROM emp WHERE dept_no = ?; +``` + +This `SELECT` statement allows you to provide a value at runtime for the `dept_no` parameter marker. + +## SET CONNECTION + +There are at least three reasons you might need more than one connection in a given client application: + +- You might want different privileges for different statements. +- You might need to interact with multiple databases in the same client. +- Multiple threads of execution in a client application can't share a connection concurrently. + +The syntax for the `SET CONNECTION` statement is: + +```sql +EXEC SQL SET CONNECTION ; +``` + +Where `connection_name` is the name of the connection to the database. + +To use the `SET CONNECTION` statement, open the connection to the database using the second form of the `CONNECT` statement. Include the `AS` clause to specify a `connection_name`. + +By default, the current thread uses the current connection. Use the `SET CONNECTION` statement to specify a default connection for the current thread to use. The default connection is used only when you execute an `EXEC SQL` statement that doesn't explicitly specify a connection name. For example, the following statement uses the default connection because it doesn't include an `AT connection_name` clause: + +```sql +EXEC SQL DELETE FROM emp; +``` + +This statement doesn't use the default connection because it specifies a connection name using the `AT connection_name` clause: + +```sql +EXEC SQL AT acctg_conn DELETE FROM emp; +``` + +For example, suppose a client application creates and maintains multiple connections using either of the following approaches: + +```sql +EXEC SQL CONNECT TO edb AS acctg_conn + USER 'alice' IDENTIFIED BY 'acctpwd'; +``` + + +```sql +EXEC SQL CONNECT TO edb AS hr_conn + USER 'bob' IDENTIFIED BY 'hrpwd'; +``` + +It can change between the connections with the `SET CONNECTION` statement: + +```sql +SET CONNECTION acctg_conn; +``` + +or + +```sql +SET CONNECTION hr_conn; +``` + +The server uses the privileges associated with the connection when determining the privileges available to the connecting client. When using the `acctg_conn` connection, the client has the privileges associated with the role `alice`. When connected using `hr_conn`, the client has the privileges associated with `bob`. + +## SET DESCRIPTOR + +Use the `SET DESCRIPTOR` statement to assign a value to a descriptor area using information provided by the client application in the form of a host variable or an integer value. The statement comes in two forms. The first form is: + +```sql +EXEC SQL [FOR ] SET DESCRIPTOR + VALUE = ; +``` + +The second form is: + +```sql +EXEC SQL [FOR ] SET DESCRIPTOR + COUNT = integer; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement executes once for each member of the array. +- `descriptor_name` specifies the name of a descriptor as a single-quoted string literal or a host variable that contains the name of a descriptor. + +Include the `VALUE` clause to describe the information stored in the descriptor. + +- `column_number` identifies the position of the variable within the descriptor. +- `descriptor_item` specifies the type of the descriptor item. +- `host_variable` specifies the name of the host variable that contains the value of the item. + +ECPGPlus implements the following `descriptor_item` types: + +- `TYPE` +- `LENGTH` +- `[REF] INDICATOR` +- `[REF] DATA` +- `[REF] RETURNED LENGTH` + +For example, a client application might prompt a user for a dynamically created query: + +```c +query_text = promptUser("Enter a query"); +``` + +To execute a dynamically created query, you must first prepare the query (parsing and validating the syntax of the query) and then describe the input parameters found in the query using the `EXEC SQL DESCRIBE INPUT` statement. + +```sql +EXEC SQL ALLOCATE DESCRIPTOR query_params; +EXEC SQL PREPARE emp_query FROM :query_text; + +EXEC SQL DESCRIBE INPUT emp_query + USING SQL DESCRIPTOR 'query_params'; +``` + +After describing the query, the `query_params` descriptor contains information about each parameter required by the query. + +For this example, assume that the user entered: + +```sql +SELECT ename FROM emp WHERE sal > ? AND job = ?;, +``` + +In this case, the descriptor describes two parameters, one for `sal > ?` and one for `job = ?`. + +To discover the number of parameter markers (question marks) in the query and therefore the number of values you must provide before executing the query, use: + +```sql +EXEC SQL GET DESCRIPTOR … :host_variable = COUNT; +``` + +Then, you can use `EXEC SQL GET DESCRIPTOR` to retrieve the name of each parameter. You can also use `EXEC SQL GET DESCRIPTOR` to retrieve the type of each parameter from the descriptor, along with the number of parameters. Or you can supply each `value` in the form of a character string and ECPG converts that string into the required data type. + +The data type of the first parameter is `numeric`. The type of the second parameter is `varchar`. The name of the first parameter is `sal`. The name of the second parameter is `job`. + +Next, loop through each parameter, prompting the user for a value, and store those values in host variables. You can use `GET DESCRIPTOR … COUNT` to find the number of parameters in the query. + +```sql +EXEC SQL GET DESCRIPTOR 'query_params' + :param_count = COUNT; + +for(param_number = 1; + param_number <= param_count; + param_number++) +{ +``` + +Use `GET DESCRIPTOR` to copy the name of the parameter into the `param_name` host variable: + +```sql +EXEC SQL GET DESCRIPTOR 'query_params' + VALUE :param_number :param_name = NAME; + +reply = promptUser(param_name); +if (reply == NULL) + reply_ind = 1; /* NULL */ +else + reply_ind = 0; /* NOT NULL */ +``` + +To associate a `value` with each parameter, you use the `EXEC SQL SET DESCRIPTOR` statement. For example: + +```sql +EXEC SQL SET DESCRIPTOR 'query_params' + VALUE :param_number DATA = :reply; +EXEC SQL SET DESCRIPTOR 'query_params' + VALUE :param_number INDICATOR = :reply_ind; +} +``` + +Now, you can use the `EXEC SQL EXECUTE DESCRIPTOR` statement to execute the prepared statement on the server. + +## UPDATE + +Use an `UPDATE` statement to modify the data stored in a table. The syntax is: + +```sql +EXEC SQL [AT ][FOR ] + UPDATE [ ONLY ] table [ [ AS ] alias ] + SET {column = { expression | DEFAULT } | + (column [, ...]) = ({ expression|DEFAULT } [, ...])} [, ...] + [ FROM from_list ] + [ WHERE condition | WHERE CURRENT OF cursor_name ] + [ RETURNING * | output_expression [[ AS ] output_name] [, ...] ] +``` + +Where `database_name` is the name of the database or host variable that contains the name of the database in which the table resides. This value can take the form of an unquoted string literal or of a host variable. + +Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `SET` or `WHERE` clause contains an array. + +ECPGPlus provides support for the additional clauses of the SQL `UPDATE` statement as documented in the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-update.html). + +You can use a host variable in any clause that specifies a value. To use a host variable, substitute a defined variable for any value associated with any of the documented `UPDATE` clauses. + +The following `UPDATE` statement changes the job description of an employee (identified by the `:ename` host variable) to the value contained in the `:new_job` host variable. It increases the employees salary by multiplying the current salary by the value in the `:increase` host variable: + +```sql +EXEC SQL UPDATE emp + SET job = :new_job, sal = sal * :increase + WHERE ename = :ename; +``` + +The enhanced `UPDATE` statement also allows you to include parameter markers (question marks) in any clause where an input value is permitted. For example, we can write the same update statement with a parameter marker in the `WHERE` clause: + +```sql +EXEC SQL UPDATE emp + SET job = ?, sal = sal * ? + WHERE ename = :ename; +``` + +This `UPDATE` statement allows you to prompt the user for a new value for the `job` column and provide the amount by which the `sal` column is incremented for the employee specified by `:ename`. + +## WHENEVER + +Use the `WHENEVER` statement to specify the action taken by a client application when it encounters an SQL error or warning. The syntax is: + +```sql +EXEC SQL WHENEVER ; +``` + +The following table describes the different conditions that might trigger an `action`. + +| Condition | Description | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `NOT FOUND` | The server returns a `NOT FOUND` condition when it encounters a `SELECT` that returns no rows or when a `FETCH` reaches the end of a result set. | +| `SQLERROR` | The server returns an `SQLERROR` condition when it encounters a serious error returned by an SQL statement. | +| `SQLWARNING` | The server returns an `SQLWARNING` condition when it encounters a nonfatal warning returned by an SQL statement. | + +The following table describes the actions that result from a client encountering a `condition`. + +| Action | Description | +| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `CALL function [([args])]` | Call the named `function`. | +| `CONTINUE` | Proceed to the next statement. | +| `DO BREAK` | Emit a C break statement. A break statement can appear in a `loop` or a `switch` statement. If executed, the break statement terminates the `loop` or the `switch` statement. | +| `DO CONTINUE` | Emit a C `continue` statement. A `continue` statement can exist only in a loop. If executed, it causes the flow of control to return to the top of the loop. | +| `DO function ([args])` | Call the named `function`. | +| `GOTO label` or `GO TO label` | Proceed to the statement that contains the label. | +| `SQLPRINT` | Print a message to standard error. | +| `STOP` | Stop executing. | + +The following code fragment prints a message if the client application encounters a warning and aborts the application if it encounters an error: + +```sql +EXEC SQL WHENEVER SQLWARNING SQLPRINT; +EXEC SQL WHENEVER SQLERROR STOP; +``` + +Include the following code to specify for a client to continue processing after warning a user of a problem: + +```sql +EXEC SQL WHENEVER SQLWARNING SQLPRINT; +``` + +Include the following code to call a function if a query returns no rows or when a cursor reaches the end of a result set: + +```sql +EXEC SQL WHENEVER NOT FOUND CALL error_handler(__LINE__); +``` From 322631c2de12559b29f8288d81ec2a14bb083eb5 Mon Sep 17 00:00:00 2001 From: drothery-edb Date: Wed, 6 Sep 2023 13:18:30 -0400 Subject: [PATCH 02/24] EPAS: v16 rel notes --- .../07_reference.mdx | 1257 ----------------- 1 file changed, 1257 deletions(-) delete mode 100644 product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx diff --git a/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx b/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx deleted file mode 100644 index 4e1811f9467..00000000000 --- a/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx +++ /dev/null @@ -1,1257 +0,0 @@ ---- -title: "Language element reference" -description: "Description of the ECPGPlus language elements" -legacyRedirectsGenerated: - # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.55.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.56.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.57.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.23.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.49.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.51.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.28.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.24.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.27.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.48.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.29.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.25.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.30.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.47.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.31.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.46.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.32.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.45.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.33.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.44.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.34.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.26.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.43.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.35.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.52.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.50.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.42.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.53.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.54.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.36.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.59.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.58.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.41.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.37.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.40.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.38.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.39.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.093.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.058.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.031.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.033.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.085.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.087.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.082.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.088.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.349.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.351.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.352.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.350.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.348.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.114.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.119.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.113.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.111.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.108.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.086.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.063.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.061.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.103.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.104.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.100.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.102.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.101.html" -redirects: - - /epas/latest/ecpgplus_guide/07_reference/ #generated for docs/epas/reorg-role-use-case-mode - - ../../../application_programming/ecpgplus_guide/07_reference/ ---- - - - -An embedded SQL statement allows your client application to interact with the server. An embedded directive is an instruction to the ECPGPlus compiler. - -You can embed any EDB Postgres Advanced Server SQL statement in a C program. Each statement must begin with the keywords `EXEC SQL` and must be terminated with a semi-colon (;). In the C program, a SQL statement takes the form: - -```sql -EXEC SQL ; -``` - -Where `sql_command_body` represents a standard SQL statement. You can use a host variable anywhere that the SQL statement expects a value expression. For more information about substituting host variables for value expressions, see [Declaring host variables](/epas/latest/application_programming/ecpgplus_guide/03_using_embedded_sql/#declaring-host-variables). - -ECPGPlus extends the PostgreSQL server-side syntax for some statements. Syntax differences are noted in the reference information that follows. For a complete reference to the supported syntax of other SQL commands, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-commands.html). - -## ALLOCATE DESCRIPTOR - -Use the `ALLOCATE DESCRIPTOR` statement to allocate an SQL descriptor area: - -```sql -EXEC SQL [FOR ] ALLOCATE DESCRIPTOR - [WITH MAX ]; -``` - -Where: - -- `array_size` is a variable that specifies the number of array elements to allocate for the descriptor. `array_size` can be an `INTEGER` value or a host variable. -- `descriptor_name` is the host variable that contains the name of the descriptor or the name of the descriptor. This value can take the form of an identifier, a quoted string literal, or of a host variable. -- `variable_count` specifies the maximum number of host variables in the descriptor. The default value of `variable_count` is `100`. - -The following code fragment allocates a descriptor named `emp_query` that can be processed as an array `(emp_array)`: - -```sql -EXEC SQL FOR :emp_array ALLOCATE DESCRIPTOR emp_query; -``` - -## CALL - -Use the `CALL` statement to invoke a procedure or function on the server. The `CALL` statement works only on EDB Postgres Advanced Server. The `CALL` statement comes in two forms. The first form is used to call a function: - -```sql -EXEC SQL CALL '('[]')' - INTO [[:][: ]]; -``` - -The second form is used to call a procedure: - -```sql -EXEC SQL CALL '('[]')'; -``` - -Where: - -- `program_name` is the name of the stored procedure or function that the `CALL` statement invokes. The program name can be schema qualified, package qualified, or both. If you don't specify the schema or package in which the program resides, ECPGPlus uses the value of `search_path` to locate the program. -- `actual_arguments` specifies a comma-separated list of arguments required by the program. Each `actual_argument` corresponds to a formal argument expected by the program. Each formal argument can be an `IN` parameter, an `OUT` parameter, or an `INOUT` parameter. -- `:ret_variable` specifies a host variable that receives the value returned if the program is a function. -- `:ret_indicator` specifies a host variable that receives the indicator value returned if the program is a function. - -For example, the following statement invokes the `get_job_desc` function with the value contained in the `:ename` host variable and captures the value returned by that function in the `:job` host variable: - -```sql -EXEC SQL CALL get_job_desc(:ename) - INTO :job; -``` - -## CLOSE - -Use the `CLOSE` statement to close a cursor and free any resources currently in use by the cursor. A client application can't fetch rows from a closed cursor. The syntax of the `CLOSE` statement is: - -```sql -EXEC SQL CLOSE []; -``` - -Where `cursor_name` is the name of the cursor closed by the statement. The cursor name can take the form of an identifier or of a host variable. - -The `OPEN` statement initializes a cursor. Once initialized, a cursor result set remains unchanged unless the cursor is reopened. You don't need to `CLOSE` a cursor before reopening it. - -To manually close a cursor named `emp_cursor`, use the command: - -```sql -EXEC SQL CLOSE emp_cursor; -``` - -A cursor is automatically closed when an application terminates. - -## COMMIT - -Use the `COMMIT` statement to complete the current transaction, making all changes permanent and visible to other users. The syntax is: - -```sql -EXEC SQL [AT ] COMMIT [WORK] - [COMMENT <'text'>] [COMMENT <'text'> RELEASE]; -``` - -Where `database_name` is the name of the database or host variable that contains the name of the database in which the work resides. This value can take the form of an unquoted string literal or of a host variable. - -For compatibility, ECPGPlus accepts the `COMMENT` clause without error but doesn't store any text included with the `COMMENT` clause. - -Include the `RELEASE` clause to close the current connection after performing the commit. - -For example, the following command commits all work performed on the `dept` database and closes the current connection: - -```sql -EXEC SQL AT dept COMMIT RELEASE; -``` - -By default, statements are committed only when a client application performs a `COMMIT` statement. Include the `-t` option when invoking ECPGPlus to specify for a client application to invoke `AUTOCOMMIT` functionality. You can also control `AUTOCOMMIT` functionality in a client application with the following statements: - -```sql -EXEC SQL SET AUTOCOMMIT TO ON -``` - -and - -```sql -EXEC SQL SET AUTOCOMMIT TO OFF -``` - -## CONNECT - -Use the `CONNECT` statement to establish a connection to a database. The `CONNECT` statement is available in two forms. One form is compatible with Oracle databases, and the other is not. - -The first form is compatible with Oracle databases: - -```sql -EXEC SQL CONNECT - {{: IDENTIFIED BY :} | :} - [AT ] - [USING :database_string] - [ALTER AUTHORIZATION :new_password]; -``` - -Where: - -- `user_name` is a host variable that contains the role that the client application uses to connect to the server. -- `password` is a host variable that contains the password associated with that role. -- `connection_id` is a host variable that contains a slash-delimited user name and password used to connect to the database. - -Include the `AT` clause to specify the database to which the connection is established. `database_name` is the name of the database to which the client is connecting. Specify the value in the form of a variable or as a string literal. - -Include the `USING` clause to specify a host variable that contains a null-terminated string identifying the database to which to establish the connection. - -The `ALTER AUTHORIZATION` clause is supported for syntax compatibility only. ECPGPlus parses the `ALTER AUTHORIZATION` clause and reports a warning. - -Using the first form of the `CONNECT` statement, a client application might establish a connection with a host variable named `user` that contains the identity of the connecting role and a host variable named `password` that contains the associated password using the following command: - -```text -EXEC SQL CONNECT :user IDENTIFIED BY :password; -``` - -A client application can also use the first form of the `CONNECT` statement to establish a connection using a single host variable named `:connection_id`. In the following example, `connection_id` contains the slash-delimited role name and associated password for the user: - -```sql -EXEC SQL CONNECT :connection_id; -``` - -The syntax of the second form of the `CONNECT` statement is: - -```sql -EXEC SQL CONNECT TO -[AS ] []; -``` - -Where `credentials` is one of the following: - -```sql -USER user_name password -USER user_name IDENTIFIED BY password -USER user_name USING password -``` - -In the second form: - -`database_name` is the name or identity of the database to which the client is connecting. Specify `database_name` as a variable or as a string literal in one of the following forms: - -```text -[@][:] - -tcp:postgresql://[:][/][options] - -unix:postgresql://[:][/][options] -``` - -Where: - -- `hostname` is the name or IP address of the server on which the database resides. -- `port` is the port on which the server listens. - - You can also specify a value of `DEFAULT` to establish a connection with the default database, using the default role name. If you specify `DEFAULT` as the target database, don't include a `connection_name` or `credentials`. - -- `connection_name` is the name of the connection to the database. `connection_name` takes the form of an identifier (that is, not a string literal or a variable). You can open multiple connections by providing a unique `connection_name` for each connection. - - If you don't specify a name for a connection, `ecpglib` assigns a name of `DEFAULT` to the connection. You can refer to the connection by name (`DEFAULT`) in any `EXEC SQL` statement. - -- `CURRENT` is the most recently opened or the connection mentioned in the most-recent `SET CONNECTION TO` statement. If you don't refer to a connection by name in an `EXEC SQL` statement, ECPG assumes the name of the connection to be `CURRENT`. - -- `user_name` is the role used to establish the connection with the EDB Postgres Advanced Server database. The privileges of the specified role are applied to all commands performed through the connection. - -- `password` is the password associated with the specified `user_name`. - -The following code fragment uses the second form of the `CONNECT` statement to establish a connection to a database named `edb` using the role `alice` and the password associated with that role, `1safepwd`: - -```sql -EXEC SQL CONNECT TO edb AS acctg_conn - USER 'alice' IDENTIFIED BY '1safepwd'; -``` - -The name of the connection is `acctg_conn`. You can use the connection name when changing the connection name using the `SET CONNECTION` statement. - -## DEALLOCATE DESCRIPTOR - -Use the `DEALLOCATE DESCRIPTOR` statement to free memory in use by an allocated descriptor. The syntax of the statement is: - -```sql -EXEC SQL DEALLOCATE DESCRIPTOR -``` - -Where `descriptor_name` is the name of the descriptor. This value can take the form of a quoted string literal or of a host variable. - -The following example deallocates a descriptor named `emp_query`: - -```sql -EXEC SQL DEALLOCATE DESCRIPTOR emp_query; -``` - -## DECLARE CURSOR - -Use the `DECLARE CURSOR` statement to define a cursor. The syntax of the statement is: - -```sql -EXEC SQL [AT ] DECLARE CURSOR FOR -( | ); -``` - -Where: - -- `database_name` is the name of the database on which the cursor operates. This value can take the form of an identifier or of a host variable. If you don't specify a database name, the default value of `database_name` is the default database. -- `cursor_name` is the name of the cursor. -- `select_statement` is the text of the `SELECT` statement that defines the cursor result set. The `SELECT` statement can't contain an `INTO` clause. -- `statement_name` is the name of a SQL statement or block that defines the cursor result set. - -The following example declares a cursor named `employees`: - -```sql -EXEC SQL DECLARE employees CURSOR FOR - SELECT - empno, ename, sal, comm - FROM - emp; -``` - -The cursor generates a result set that contains the employee number, employee name, salary, and commission for each employee record that's stored in the `emp` table. - -## DECLARE DATABASE - -Use the `DECLARE DATABASE` statement to declare a database identifier for use in subsequent SQL statements (for example, in a `CONNECT` statement). The syntax is: - -```sql -EXEC SQL DECLARE DATABASE; -``` - -Where `database_name` specifies the name of the database. - -The following example shows declaring an identifier for the `acctg` database: - -```sql -EXEC SQL DECLARE acctg DATABASE; -``` - -After invoking the command declaring `acctg` as a database identifier, you can reference the `acctg` database by name when establishing a connection or in `AT` clauses. - -This statement has no effect and is provided for Pro\*C compatibility only. - -## DECLARE STATEMENT - -Use the `DECLARE STATEMENT` directive to declare an identifier for an SQL statement. EDB Postgres Advanced Server supports two versions of the `DECLARE STATEMENT` directive: - -```sql -EXEC SQL [] DECLARE STATEMENT; -``` - -and - -```sql -EXEC SQL DECLARE STATEMENT ; -``` - -Where: - -- `statement_name` specifies the identifier associated with the statement. -- `database_name` specifies the name of the database. This value may take the form of an identifier or of a host variable that contains the identifier. - -A typical usage sequence that includes the `DECLARE STATEMENT` directive is: - -```sql -EXEC SQL DECLARE give_raise STATEMENT; // give_raise is now a statement -handle (not prepared) -EXEC SQL PREPARE give_raise FROM :stmtText; // give_raise is now associated -with a statement -EXEC SQL EXECUTE give_raise; -``` - -This statement has no effect and is provided for Pro\*C compatibility only. - -## DELETE - -Use the `DELETE` statement to delete one or more rows from a table. The syntax for the ECPGPlus `DELETE` statement is the same as the syntax for the SQL statement, but you can use parameter markers and host variables any place that an expression is allowed. The syntax is: - -```sql -[FOR ] DELETE FROM [ONLY]
[[AS] ] - [USING ] - [WHERE | WHERE CURRENT OF ] - [{RETURNING|RETURN} * | [[AS] ] -[, ...] INTO ] -``` - -- Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `VALUES` clause references an array or a pointer to an array. -- `table` is the name (optionally schema qualified) of an existing table. Include the `ONLY` clause to limit processing to the specified table. If you don't include the `ONLY` clause, any tables inheriting from the named table are also processed. -- `alias` is a substitute name for the target table. -- `using_list` is a list of table expressions, allowing columns from other tables to appear in the `WHERE` condition. -- Include the `WHERE` clause to specify the rows to delete. If you don't include a `WHERE` clause in the statement, `DELETE` deletes all rows from the table, leaving the table definition intact. -- `condition` is an expression, host variable, or parameter marker that returns a value of type `BOOLEAN`. Those rows for which `condition` returns true are deleted. -- `cursor_name` is the name of the cursor to use in the `WHERE CURRENT OF` clause. The row to be deleted is the one most recently fetched from this cursor. The cursor must be a nongrouping query on the `DELETE` statements target table. You can't specify `WHERE CURRENT OF` in a `DELETE` statement that includes a Boolean condition. - -The `RETURN/RETURNING` clause specifies an `output_expression` or `host_variable_list` that's returned by the `DELETE` command after each row is deleted: - - - `output_expression` is an expression to be computed and returned by the `DELETE` command after each row is deleted. `output_name` is the name of the returned column. Include \* to return all columns. - - `host_variable_list` is a comma-separated list of host variables and optional indicator variables. Each host variable receives a corresponding value from the `RETURNING` clause. - -For example, the following statement deletes all rows from the `emp` table, where the `sal` column contains a value greater than the value specified in the host variable, `:max_sal:` - -```sql -DELETE FROM emp WHERE sal > :max_sal; -``` - -For more information about using the `DELETE` statement, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-delete.html). - -## DESCRIBE - -Use the `DESCRIBE` statement to find the number of input values required by a prepared statement or the number of output values returned by a prepared statement. The `DESCRIBE` statement is used to analyze a SQL statement whose shape is unknown at the time you write your application. - -The `DESCRIBE` statement populates an `SQLDA` descriptor. To populate a SQL descriptor, use the `ALLOCATE DESCRIPTOR` and `DESCRIBE...DESCRIPTOR` statements. - -```sql -EXEC SQL DESCRIBE BIND VARIABLES FOR INTO ; -``` - - -```sql -EXEC SQL DESCRIBE SELECT LIST FOR INTO ; -``` - -Where: - -- `statement_name` is the identifier associated with a prepared SQL statement or PL/SQL block. -- `descriptor` is the name of C variable of type `SQLDA*`. You must allocate the space for the descriptor by calling `sqlald()` and initialize the descriptor before executing the `DESCRIBE` statement. - -When you execute the first form of the `DESCRIBE` statement, ECPG populates the given descriptor with a description of each input variable *required* by the statement. For example, given two descriptors: - -```sql -SQLDA *query_values_in; -SQLDA *query_values_out; -``` - -You might prepare a query that returns information from the `emp` table: - -```sql -EXEC SQL PREPARE get_emp FROM - "SELECT ename, empno, sal FROM emp WHERE empno = ?"; -``` - -The command requires one input variable for the parameter marker (?). - -```sql -EXEC SQL DESCRIBE BIND VARIABLES - FOR get_emp INTO query_values_in; -``` - -After describing the bind variables for this statement, you can examine the descriptor to find the number of variables required and the type of each variable. - -When you execute the second form, ECPG populates the given descriptor with a description of each value returned by the statement. For example, the following statement returns three values: - -```sql -EXEC SQL DESCRIBE SELECT LIST - FOR get_emp INTO query_values_out; -``` - -After describing the select list for this statement, you can examine the descriptor to find the number of returned values and the name and type of each value. - -Before executing the statement, you must bind a variable for each input value and a variable for each output value. The variables that you bind for the input values specify the actual values used by the statement. The variables that you bind for the output values tell ECPGPlus where to put the values when you execute the statement. - -This is alternative Pro\*C-compatible syntax for the `DESCRIBE DESCRIPTOR` statement. - -## DESCRIBE DESCRIPTOR - -Use the `DESCRIBE DESCRIPTOR` statement to retrieve information about a SQL statement and store that information in a SQL descriptor. Before using `DESCRIBE DESCRIPTOR`, you must allocate the descriptor with the `ALLOCATE DESCRIPTOR` statement. The syntax is: - -```sql -EXEC SQL DESCRIBE [INPUT | OUTPUT] - USING [SQL] DESCRIPTOR ; -``` - -Where: - -- `statement_name` is the name of a prepared SQL statement. -- `descriptor_name` is the name of the descriptor. `descriptor_name` can be a quoted string value or a host variable that contains the name of the descriptor. - -If you include the `INPUT` clause, ECPGPlus populates the given descriptor with a description of each input variable required by the statement. - -For example, given two descriptors: - -```sql -EXEC SQL ALLOCATE DESCRIPTOR query_values_in; -EXEC SQL ALLOCATE DESCRIPTOR query_values_out; -``` - -You might prepare a query that returns information from the `emp` table: - -```sql -EXEC SQL PREPARE get_emp FROM - "SELECT ename, empno, sal FROM emp WHERE empno = ?"; -``` - -The command requires one input variable for the parameter marker (?). - -```sql -EXEC SQL DESCRIBE INPUT get_emp USING 'query_values_in'; -``` - -After describing the bind variables for this statement, you can examine the descriptor to find the number of variables required and the type of each variable. - -If you don't specify the `INPUT` clause, `DESCRIBE DESCRIPTOR` populates the specified descriptor with the values returned by the statement. - -If you include the `OUTPUT` clause, ECPGPlus populates the given descriptor with a description of each value returned by the statement. - -For example, the following statement returns three values: - -```sql -EXEC SQL DESCRIBE OUTPUT FOR get_emp USING 'query_values_out'; -``` - -After describing the select list for this statement, you can examine the descriptor to find the number of returned values and the name and type of each value. - -## DISCONNECT - -Use the `DISCONNECT` statement to close the connection to the server. The syntax is: - -```sql -EXEC SQL DISCONNECT [][CURRENT][DEFAULT][ALL]; -``` - -Where `connection_name` is the connection name specified in the `CONNECT` statement used to establish the connection. If you don't specify a connection name, the current connection is closed. - -Include the `CURRENT` keyword to specify for ECPGPlus to close the connection used most recently. - -Include the `DEFAULT` keyword to specify for ECPGPlus to close the connection named `DEFAULT`. If you don't specify a name when opening a connection, ECPGPlus assigns the name `DEFAULT` to the connection. - -Include the `ALL` keyword to close all active connections. - -The following example creates a connection named `hr_connection` that connects to the `hr` database and then disconnects from the connection: - -```c -/* client.pgc*/ -int main() -{ - EXEC SQL CONNECT TO hr AS connection_name; - EXEC SQL DISCONNECT connection_name; - return(0); -} -``` - -## EXECUTE - -Use the `EXECUTE` statement to execute a statement previously prepared using an `EXEC SQL PREPARE` statement. The syntax is: - -```sql -EXEC SQL [FOR ] EXECUTE - [USING {DESCRIPTOR - |: [[INDICATOR] :]}]; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `statement_name` specifies the name assigned to the statement when the statement was created using the `EXEC SQL PREPARE` statement. - -Include the `USING` clause to supply values for parameters in the prepared statement: - -- Include the `DESCRIPTOR` `SQLDA_descriptor` clause to provide an SQLDA descriptor value for a parameter. -- Use a `host_variable` (and an optional `indicator_variable`) to provide a user-specified value for a parameter. - -The following example creates a prepared statement that inserts a record into the `emp` table: - -```sql -EXEC SQL PREPARE add_emp (numeric, text, text, numeric) AS - INSERT INTO emp VALUES($1, $2, $3, $4); -``` - -Each time you invoke the prepared statement, provide fresh parameter values for the statement: - -```sql -EXEC SQL EXECUTE add_emp USING 8000, 'DAWSON', 'CLERK', 7788; -EXEC SQL EXECUTE add_emp USING 8001, 'EDWARDS', 'ANALYST', 7698; -``` - -## EXECUTE DESCRIPTOR - -Use the `EXECUTE` statement to execute a statement previously prepared by an `EXEC SQL PREPARE` statement, using an SQL descriptor. The syntax is: - -```sql -EXEC SQL [FOR ] EXECUTE - [USING [SQL] DESCRIPTOR ] - [INTO [SQL] DESCRIPTOR ]; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `statement_identifier` specifies the identifier assigned to the statement with the `EXEC SQL PREPARE` statement. -- `descriptor_name` specifies the name of a descriptor (as a single-quoted string literal), or a host variable that contains the name of a descriptor. - -Include the `USING` clause to specify values for any input parameters required by the prepared statement. - -Include the `INTO` clause to specify a descriptor into which the `EXECUTE` statement writes the results returned by the prepared statement. - -The following example executes the prepared statement, `give_raise`, using the values contained in the descriptor `stmtText:` - -```sql -EXEC SQL PREPARE give_raise FROM :stmtText; -EXEC SQL EXECUTE give_raise USING DESCRIPTOR :stmtText; -``` - -## EXECUTE...END EXEC - -Use the `EXECUTE…END-EXEC` statement to embed an anonymous block into a client application. The syntax is: - -```sql -EXEC SQL [AT ] EXECUTE END-EXEC; -``` - -Where: - -- `database_name` is the database identifier or a host variable that contains the database identifier. If you omit the `AT` clause, the statement executes on the current default database. -- `anonymous_block` is an inline sequence of PL/pgSQL or SPL statements and declarations. You can include host variables and optional indicator variables in the block. Each such variable is treated as an `IN/OUT` value. - -The following example executes an anonymous block: - -```sql -EXEC SQL EXECUTE - BEGIN - IF (current_user = :admin_user_name) THEN - DBMS_OUTPUT.PUT_LINE('You are an administrator'); - END IF; -END-EXEC; -``` - -!!! Note - The `EXECUTE…END EXEC` statement is supported only by EDB Postgres Advanced Server. - -## EXECUTE IMMEDIATE - -Use the `EXECUTE IMMEDIATE` statement to execute a string that contains a SQL command. The syntax is: - -```sql -EXEC SQL [AT ] EXECUTE IMMEDIATE ; -``` - -Where: - -- `database_name` is the database identifier or a host variable that contains the database identifier. If you omit the `AT` clause, the statement executes on the current default database. -- `command_text` is the command executed by the `EXECUTE IMMEDIATE` statement. - -This dynamic SQL statement is useful when you don't know the text of an SQL statement when writing a client application. For example, a client application might prompt a trusted user for a statement to execute. After the user provides the text of the statement as a string value, the statement is then executed with an `EXECUTE IMMEDIATE` command. - -The statement text can't contain references to host variables. If the statement might contain parameter markers or returns one or more values, use the `PREPARE` and `DESCRIBE` statements. - -The following example executes the command contained in the `:command_text` host variable: - -```sql -EXEC SQL EXECUTE IMMEDIATE :command_text; -``` - -## FETCH - -Use the `FETCH` statement to return rows from a cursor into an SQLDA descriptor or a target list of host variables. Before using a `FETCH` statement to retrieve information from a cursor, you must prepare the cursor using `DECLARE` and `OPEN` statements. The statement syntax is: - -```sql -EXEC SQL [FOR ] FETCH - { USING DESCRIPTOR }|{ INTO }; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `cursor` is the name of the cursor from which rows are being fetched or a host variable that contains the name of the cursor. - -If you include a `USING` clause, the `FETCH` statement populates the specified SQLDA descriptor with the values returned by the server. - -If you include an `INTO` clause, the `FETCH` statement populates the host variables (and optional indicator variables) specified in the `target_list`. - -The following code fragment declares a cursor named `employees` that retrieves the `employee number`, `name`, and `salary` from the `emp` table: - -```sql -EXEC SQL DECLARE employees CURSOR FOR - SELECT empno, ename, esal FROM emp; -EXEC SQL OPEN emp_cursor; -EXEC SQL FETCH emp_cursor INTO :emp_no, :emp_name, :emp_sal; -``` - -## FETCH DESCRIPTOR - -Use the `FETCH DESCRIPTOR` statement to retrieve rows from a cursor into an SQL descriptor. The syntax is: - -```sql -EXEC SQL [FOR ] FETCH - INTO [SQL] DESCRIPTOR ; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `cursor` is the name of the cursor from which rows are fetched or a host variable that contains the name of the cursor. The client must `DECLARE` and `OPEN` the cursor before calling the `FETCH DESCRIPTOR` statement. -- `descriptor_name` specifies the name of a descriptor (as a single-quoted string literal) or a host variable that contains the name of a descriptor. Prior to use, the descriptor must be allocated using an `ALLOCATE DESCRIPTOR` statement. - -Include the `INTO` clause to specify a SQL descriptor into which the `EXECUTE` statement writes the results returned by the prepared statement. - -The following example allocates a descriptor named `row_desc` that holds the description and the values of a specific row in the result set. It then declares and opens a cursor for a prepared statement (`my_cursor`), before looping through the rows in result set, using a `FETCH` to retrieve the next row from the cursor into the descriptor: - -```sql -EXEC SQL ALLOCATE DESCRIPTOR 'row_desc'; -EXEC SQL DECLARE my_cursor CURSOR FOR query; -EXEC SQL OPEN my_cursor; - -for( row = 0; ; row++ ) -{ - EXEC SQL BEGIN DECLARE SECTION; - int col; -EXEC SQL END DECLARE SECTION; -EXEC SQL FETCH my_cursor INTO SQL DESCRIPTOR 'row_desc'; -``` - -## GET DESCRIPTOR - -Use the `GET DESCRIPTOR` statement to retrieve information from a descriptor. The `GET DESCRIPTOR` statement comes in two forms. The first form returns the number of values (or columns) in the descriptor. - -```sql -EXEC SQL GET DESCRIPTOR - : = COUNT; -``` - -The second form returns information about a specific value (specified by the `VALUE column_number` clause): - -```sql -EXEC SQL [FOR ] GET DESCRIPTOR - VALUE {: = {,…}}; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you specify an `array_size`, the `host_variable` must be an array of that size. For example, if `array_size` is `10`, `:host_variable` must be a 10-member array of `host_variables`. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `descriptor_name` specifies the name of a descriptor as a single-quoted string literal or a host variable that contains the name of a descriptor. - -Include the `VALUE` clause to specify the information retrieved from the descriptor. - -- `column_number` identifies the position of the variable in the descriptor. -- `host_variable` specifies the name of the host variable that receives the value of the item. -- `descriptor_item` specifies the type of the retrieved descriptor item. - -ECPGPlus implements the following `descriptor_item` types: - -- `TYPE` -- `LENGTH` -- `OCTET_LENGTH` -- `RETURNED_LENGTH` -- `RETURNED_OCTET_LENGTH` -- `PRECISION` -- `SCALE` -- `NULLABLE` -- `INDICATOR` -- `DATA` -- `NAME` - -The following code fragment shows using a `GET DESCRIPTOR` statement to obtain the number of columns entered in a user-provided string: - -```sql -EXEC SQL ALLOCATE DESCRIPTOR parse_desc; -EXEC SQL PREPARE query FROM :stmt; -EXEC SQL DESCRIBE query INTO SQL DESCRIPTOR parse_desc; -EXEC SQL GET DESCRIPTOR parse_desc :col_count = COUNT; -``` - -The example allocates an SQL descriptor named `parse_desc` before using a `PREPARE` statement to check the syntax of the string provided by the user `:stmt`. A `DESCRIBE` statement moves the user-provided string into the descriptor, `parse_desc`. The call to `EXEC SQL GET DESCRIPTOR` interrogates the descriptor to discover the number of columns `(:col_count)` in the result set. - -## INSERT - -Use the `INSERT` statement to add one or more rows to a table. The syntax for the ECPGPlus `INSERT` statement is the same as the syntax for the SQL statement, but you can use parameter markers and host variables any place that a value is allowed. The syntax is: - -```sql -[FOR ] INSERT INTO
[( [, ...])] - {DEFAULT VALUES | - VALUES ({ | DEFAULT} [, ...])[, ...] | } - [RETURNING * | [[ AS ] ] [, ...]] -``` - -Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `VALUES` clause references an array or a pointer to an array. - -- `table` specifies the (optionally schema-qualified) name of an existing table. -- `column` is the name of a column in the table. The column name can be qualified with a subfield name or array subscript. Specify the `DEFAULT VALUES` clause to use default values for all columns. -- `expression` is the expression, value, host variable, or parameter marker that's assigned to the corresponding column. Specify `DEFAULT` to fill the corresponding column with its default value. -- `query` specifies a `SELECT` statement that supplies the rows to insert. -- `output_expression` is an expression that's computed and returned by the `INSERT` command after each row is inserted. The expression can refer to any column in the table. Specify \* to return all columns of the inserted rows. -- `output_name` specifies a name to use for a returned column. - -The following example adds a row to the `employees` table: - -```sql -INSERT INTO emp (empno, ename, job, hiredate) - VALUES ('8400', :ename, 'CLERK', '2011-10-31'); -``` - -!!! Note - The `INSERT` statement uses a host variable `:ename` to specify the value of the `ename` column. - -For more information about using the `INSERT` statement, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-insert.html). - -## OPEN - -Use the `OPEN` statement to open a cursor. The syntax is: - -```sql -EXEC SQL [FOR ] OPEN [USING ]; -``` - -`parameters` is one of the following: - -```sql -DESCRIPTOR -``` - -or - -```sql - [ [ INDICATOR ] , … ] -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `cursor` is the name of the cursor being opened. -- `parameters` is either `DESCRIPTOR SQLDA_descriptor` or a comma-separated list of `host variables` and optional `indicator variables` that initialize the cursor. If specifying an `SQLDA_descriptor`, the descriptor must be initialized with a `DESCRIBE` statement. - -The `OPEN` statement initializes a cursor using the values provided in `parameters`. Once initialized, the cursor result set remains unchanged unless the cursor is closed and reopened. A cursor is automatically closed when an application terminates. - -The following example declares a cursor named `employees` that queries the `emp` table. It returns the `employee number`, `name`, `salary`, and `commission` of an employee whose name matches a user-supplied value stored in the host variable `:emp_name`. - -```sql -EXEC SQL DECLARE employees CURSOR FOR - SELECT - empno, ename, sal, comm  - FROM  - emp - WHERE ename = :emp_name; -EXEC SQL OPEN employees; -... -``` - -After declaring the cursor, the example uses an `OPEN` statement to make the contents of the cursor available to a client application. - -## OPEN DESCRIPTOR - -Use the `OPEN DESCRIPTOR` statement to open a cursor with a SQL descriptor. The syntax is: - -```sql -EXEC SQL [FOR ] OPEN - [USING [SQL] DESCRIPTOR ] - [INTO [SQL] DESCRIPTOR ]; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `cursor` is the name of the cursor being opened. -- `descriptor_name` specifies the name of an SQL descriptor in the form of a single-quoted string literal or a host variable that contains the name of an SQL descriptor that contains the query that initializes the cursor. - -For example, the following statement opens a cursor named `emp_cursor` using the host variable `:employees`: - -```sql -EXEC SQL OPEN emp_cursor USING DESCRIPTOR :employees; -``` - -## PREPARE - -Prepared statements are useful when a client application must perform a task multiple times. The statement is parsed, written, and planned only once rather than each time the statement is executed. This approach saves repetitive processing time. - -Use the `PREPARE` statement to prepare a SQL statement or PL/pgSQL block for execution. The statement is available in two forms. The first form is: - -```sql -EXEC SQL [AT ] PREPARE - FROM ; -``` - -The second form is: - -```sql -EXEC SQL [AT ] PREPARE - AS ; -``` - -Where: - -- `database_name` is the database identifier or a host variable that contains the database identifier against which the statement executes. If you omit the `AT` clause, the statement executes against the current default database. -- `statement_name` is the identifier associated with a prepared SQL statement or PL/SQL block. -- `sql_statement` can take the form of a `SELECT` statement, a single-quoted string literal, or a host variable that contains the text of an SQL statement. - -To include variables in a prepared statement, substitute placeholders (`$1, $2, $3`, and so on) for statement values that might change when you `PREPARE` the statement. When you `EXECUTE` the statement, provide a value for each parameter. Provide the values in the order in which they replace placeholders. - -The following example creates a prepared statement named `add_emp` that inserts a record into the `emp` table: - -```sql -EXEC SQL PREPARE add_emp (int, text, text, numeric) AS - INSERT INTO emp VALUES($1, $2, $3, $4); -``` - -Each time you invoke the statement, provide fresh parameter values for the statement: - -```sql -EXEC SQL EXECUTE add_emp(8003, 'Davis', 'CLERK', 2000.00); -EXEC SQL EXECUTE add_emp(8004, 'Myer', 'CLERK', 2000.00); -``` - -!!! Note - A client application must issue a `PREPARE` statement in each session in which a statement executes. Prepared statements persist only for the duration of the current session. - -## ROLLBACK - -Use the `ROLLBACK` statement to abort the current transaction and discard any updates made by the transaction. The syntax is: - -```sql -EXEC SQL [AT ] ROLLBACK [WORK] - [ { TO [SAVEPOINT] } | RELEASE ] -``` - -Where `database_name` is the database identifier or a host variable that contains the database identifier against which the statement executes. If you omit the `AT` clause, the statement executes against the current default database. - -Include the `TO` clause to abort any commands that executed after the specified `savepoint`. Use the `SAVEPOINT` statement to define the `savepoint`. If you omit the `TO` clause, the `ROLLBACK` statement aborts the transaction, discarding all updates. - -Include the `RELEASE` clause to cause the application to execute an `EXEC SQL COMMIT RELEASE` and close the connection. - -Use the following statement to roll back a complete transaction: - -```sql -EXEC SQL ROLLBACK; -``` - -Invoking this statement aborts the transaction, undoing all changes, erasing any savepoints, and releasing all transaction locks. Suppose you include a savepoint (`my_savepoint` in the following example): - -```sql -EXEC SQL ROLLBACK TO SAVEPOINT my_savepoint; -``` - -Only the portion of the transaction that occurred after the `my_savepoint` is rolled back. `my_savepoint` is retained, but any savepoints created after `my_savepoint` are erased. - -Rolling back to a specified savepoint releases all locks acquired after the savepoint. - -## SAVEPOINT - -Use the `SAVEPOINT` statement to define a *savepoint*. A savepoint is a marker in a transaction. You can use a `ROLLBACK` statement to abort the current transaction, returning the state of the server to its condition prior to the specified savepoint. The syntax of a `SAVEPOINT` statement is: - -```sql -EXEC SQL [AT ] SAVEPOINT -``` - -Where: - -- `database_name` is the database identifier or a host variable that contains the database identifier against which the savepoint resides. If you omit the `AT` clause, the statement executes against the current default database. -- `savepoint_name` is the name of the savepoint. If you reuse a `savepoint_name`, the original savepoint is discarded. - -You can establish savepoints only in a transaction block. A transaction block can contain multiple savepoints. - -To create a savepoint named `my_savepoint`, include the statement: - -```sql -EXEC SQL SAVEPOINT my_savepoint; -``` - -## SELECT - -ECPGPlus extends support of the `SQL SELECT` statement by providing the `INTO host_variables` clause. The clause allows you to select specified information from an EDB Postgres Advanced Server database into a host variable. The syntax for the `SELECT` statement is: - -```sql -EXEC SQL [AT ] -SELECT - [ ] - [ ALL | DISTINCT [ ON( , ...) ]] - select_list INTO - - [ FROM from_item [, from_item ]...] - [ WHERE condition ] - [ hierarchical_query_clause ] - [ GROUP BY expression [, ...]] - [ HAVING condition ] - [ { UNION [ ALL ] | INTERSECT | MINUS } (subquery) ] - [ ORDER BY expression [order_by_options]] - [ LIMIT { count | ALL }] - [ OFFSET start [ ROW | ROWS ] ] - [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ] - [ FOR { UPDATE | SHARE } [OF table_name [, ...]][NOWAIT ][...]] -``` - -Where: - -- `database_name` is the name of the database or host variable that contains the name of the database in which the table resides. This value can take the form of an unquoted string literal or of a host variable. -- `host_variables` is a list of host variables populated by the `SELECT` statement. If the `SELECT` statement returns more than a single row, `host_variables` must be an array. - -ECPGPlus provides support for the additional clauses of the SQL `SELECT` statement as documented in the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-select.html). - -To use the `INTO host_variables` clause, include the names of defined host variables when specifying the `SELECT` statement. For example, the following `SELECT` statement populates the `:emp_name` and `:emp_sal` host variables with a list of employee names and salaries: - -```sql -EXEC SQL SELECT ename, sal - INTO :emp_name, :emp_sal - FROM emp - WHERE empno = 7988; -``` - -The enhanced `SELECT` statement also allows you to include parameter markers (question marks) in any clause where a value is allowed. For example, the following query contains a parameter marker in the `WHERE` clause: - -```sql -SELECT * FROM emp WHERE dept_no = ?; -``` - -This `SELECT` statement allows you to provide a value at runtime for the `dept_no` parameter marker. - -## SET CONNECTION - -There are at least three reasons you might need more than one connection in a given client application: - -- You might want different privileges for different statements. -- You might need to interact with multiple databases in the same client. -- Multiple threads of execution in a client application can't share a connection concurrently. - -The syntax for the `SET CONNECTION` statement is: - -```sql -EXEC SQL SET CONNECTION ; -``` - -Where `connection_name` is the name of the connection to the database. - -To use the `SET CONNECTION` statement, open the connection to the database using the second form of the `CONNECT` statement. Include the `AS` clause to specify a `connection_name`. - -By default, the current thread uses the current connection. Use the `SET CONNECTION` statement to specify a default connection for the current thread to use. The default connection is used only when you execute an `EXEC SQL` statement that doesn't explicitly specify a connection name. For example, the following statement uses the default connection because it doesn't include an `AT connection_name` clause: - -```sql -EXEC SQL DELETE FROM emp; -``` - -This statement doesn't use the default connection because it specifies a connection name using the `AT connection_name` clause: - -```sql -EXEC SQL AT acctg_conn DELETE FROM emp; -``` - -For example, suppose a client application creates and maintains multiple connections using either of the following approaches: - -```sql -EXEC SQL CONNECT TO edb AS acctg_conn - USER 'alice' IDENTIFIED BY 'acctpwd'; -``` - - -```sql -EXEC SQL CONNECT TO edb AS hr_conn - USER 'bob' IDENTIFIED BY 'hrpwd'; -``` - -It can change between the connections with the `SET CONNECTION` statement: - -```sql -SET CONNECTION acctg_conn; -``` - -or - -```sql -SET CONNECTION hr_conn; -``` - -The server uses the privileges associated with the connection when determining the privileges available to the connecting client. When using the `acctg_conn` connection, the client has the privileges associated with the role `alice`. When connected using `hr_conn`, the client has the privileges associated with `bob`. - -## SET DESCRIPTOR - -Use the `SET DESCRIPTOR` statement to assign a value to a descriptor area using information provided by the client application in the form of a host variable or an integer value. The statement comes in two forms. The first form is: - -```sql -EXEC SQL [FOR ] SET DESCRIPTOR - VALUE = ; -``` - -The second form is: - -```sql -EXEC SQL [FOR ] SET DESCRIPTOR - COUNT = integer; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement executes once for each member of the array. -- `descriptor_name` specifies the name of a descriptor as a single-quoted string literal or a host variable that contains the name of a descriptor. - -Include the `VALUE` clause to describe the information stored in the descriptor. - -- `column_number` identifies the position of the variable within the descriptor. -- `descriptor_item` specifies the type of the descriptor item. -- `host_variable` specifies the name of the host variable that contains the value of the item. - -ECPGPlus implements the following `descriptor_item` types: - -- `TYPE` -- `LENGTH` -- `[REF] INDICATOR` -- `[REF] DATA` -- `[REF] RETURNED LENGTH` - -For example, a client application might prompt a user for a dynamically created query: - -```c -query_text = promptUser("Enter a query"); -``` - -To execute a dynamically created query, you must first prepare the query (parsing and validating the syntax of the query) and then describe the input parameters found in the query using the `EXEC SQL DESCRIBE INPUT` statement. - -```sql -EXEC SQL ALLOCATE DESCRIPTOR query_params; -EXEC SQL PREPARE emp_query FROM :query_text; - -EXEC SQL DESCRIBE INPUT emp_query - USING SQL DESCRIPTOR 'query_params'; -``` - -After describing the query, the `query_params` descriptor contains information about each parameter required by the query. - -For this example, assume that the user entered: - -```sql -SELECT ename FROM emp WHERE sal > ? AND job = ?;, -``` - -In this case, the descriptor describes two parameters, one for `sal > ?` and one for `job = ?`. - -To discover the number of parameter markers (question marks) in the query and therefore the number of values you must provide before executing the query, use: - -```sql -EXEC SQL GET DESCRIPTOR … :host_variable = COUNT; -``` - -Then, you can use `EXEC SQL GET DESCRIPTOR` to retrieve the name of each parameter. You can also use `EXEC SQL GET DESCRIPTOR` to retrieve the type of each parameter from the descriptor, along with the number of parameters. Or you can supply each `value` in the form of a character string and ECPG converts that string into the required data type. - -The data type of the first parameter is `numeric`. The type of the second parameter is `varchar`. The name of the first parameter is `sal`. The name of the second parameter is `job`. - -Next, loop through each parameter, prompting the user for a value, and store those values in host variables. You can use `GET DESCRIPTOR … COUNT` to find the number of parameters in the query. - -```sql -EXEC SQL GET DESCRIPTOR 'query_params' - :param_count = COUNT; - -for(param_number = 1; - param_number <= param_count; - param_number++) -{ -``` - -Use `GET DESCRIPTOR` to copy the name of the parameter into the `param_name` host variable: - -```sql -EXEC SQL GET DESCRIPTOR 'query_params' - VALUE :param_number :param_name = NAME; - -reply = promptUser(param_name); -if (reply == NULL) - reply_ind = 1; /* NULL */ -else - reply_ind = 0; /* NOT NULL */ -``` - -To associate a `value` with each parameter, you use the `EXEC SQL SET DESCRIPTOR` statement. For example: - -```sql -EXEC SQL SET DESCRIPTOR 'query_params' - VALUE :param_number DATA = :reply; -EXEC SQL SET DESCRIPTOR 'query_params' - VALUE :param_number INDICATOR = :reply_ind; -} -``` - -Now, you can use the `EXEC SQL EXECUTE DESCRIPTOR` statement to execute the prepared statement on the server. - -## UPDATE - -Use an `UPDATE` statement to modify the data stored in a table. The syntax is: - -```sql -EXEC SQL [AT ][FOR ] - UPDATE [ ONLY ] table [ [ AS ] alias ] - SET {column = { expression | DEFAULT } | - (column [, ...]) = ({ expression|DEFAULT } [, ...])} [, ...] - [ FROM from_list ] - [ WHERE condition | WHERE CURRENT OF cursor_name ] - [ RETURNING * | output_expression [[ AS ] output_name] [, ...] ] -``` - -Where `database_name` is the name of the database or host variable that contains the name of the database in which the table resides. This value can take the form of an unquoted string literal or of a host variable. - -Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `SET` or `WHERE` clause contains an array. - -ECPGPlus provides support for the additional clauses of the SQL `UPDATE` statement as documented in the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-update.html). - -You can use a host variable in any clause that specifies a value. To use a host variable, substitute a defined variable for any value associated with any of the documented `UPDATE` clauses. - -The following `UPDATE` statement changes the job description of an employee (identified by the `:ename` host variable) to the value contained in the `:new_job` host variable. It increases the employees salary by multiplying the current salary by the value in the `:increase` host variable: - -```sql -EXEC SQL UPDATE emp - SET job = :new_job, sal = sal * :increase - WHERE ename = :ename; -``` - -The enhanced `UPDATE` statement also allows you to include parameter markers (question marks) in any clause where an input value is permitted. For example, we can write the same update statement with a parameter marker in the `WHERE` clause: - -```sql -EXEC SQL UPDATE emp - SET job = ?, sal = sal * ? - WHERE ename = :ename; -``` - -This `UPDATE` statement allows you to prompt the user for a new value for the `job` column and provide the amount by which the `sal` column is incremented for the employee specified by `:ename`. - -## WHENEVER - -Use the `WHENEVER` statement to specify the action taken by a client application when it encounters an SQL error or warning. The syntax is: - -```sql -EXEC SQL WHENEVER ; -``` - -The following table describes the different conditions that might trigger an `action`. - -| Condition | Description | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| `NOT FOUND` | The server returns a `NOT FOUND` condition when it encounters a `SELECT` that returns no rows or when a `FETCH` reaches the end of a result set. | -| `SQLERROR` | The server returns an `SQLERROR` condition when it encounters a serious error returned by an SQL statement. | -| `SQLWARNING` | The server returns an `SQLWARNING` condition when it encounters a nonfatal warning returned by an SQL statement. | - -The following table describes the actions that result from a client encountering a `condition`. - -| Action | Description | -| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `CALL function [([args])]` | Call the named `function`. | -| `CONTINUE` | Proceed to the next statement. | -| `DO BREAK` | Emit a C break statement. A break statement can appear in a `loop` or a `switch` statement. If executed, the break statement terminates the `loop` or the `switch` statement. | -| `DO CONTINUE` | Emit a C `continue` statement. A `continue` statement can exist only in a loop. If executed, it causes the flow of control to return to the top of the loop. | -| `DO function ([args])` | Call the named `function`. | -| `GOTO label` or `GO TO label` | Proceed to the statement that contains the label. | -| `SQLPRINT` | Print a message to standard error. | -| `STOP` | Stop executing. | - -The following code fragment prints a message if the client application encounters a warning and aborts the application if it encounters an error: - -```sql -EXEC SQL WHENEVER SQLWARNING SQLPRINT; -EXEC SQL WHENEVER SQLERROR STOP; -``` - -Include the following code to specify for a client to continue processing after warning a user of a problem: - -```sql -EXEC SQL WHENEVER SQLWARNING SQLPRINT; -``` - -Include the following code to call a function if a query returns no rows or when a cursor reaches the end of a result set: - -```sql -EXEC SQL WHENEVER NOT FOUND CALL error_handler(__LINE__); -``` From e6e8f3cf69adb516024d8db19157ae6c75cce45c Mon Sep 17 00:00:00 2001 From: Josh Heyer Date: Tue, 25 Jul 2023 15:43:56 +0000 Subject: [PATCH 03/24] Begin fork of EPAS 16 docs --- .../07_reference.mdx | 1257 +++++++++++++++++ 1 file changed, 1257 insertions(+) create mode 100644 product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx diff --git a/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx b/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx new file mode 100644 index 00000000000..4e1811f9467 --- /dev/null +++ b/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx @@ -0,0 +1,1257 @@ +--- +title: "Language element reference" +description: "Description of the ECPGPlus language elements" +legacyRedirectsGenerated: + # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.55.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.56.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.57.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.23.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.49.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.51.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.28.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.24.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.27.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.48.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.29.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.25.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.30.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.47.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.31.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.46.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.32.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.45.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.33.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.44.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.34.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.26.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.43.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.35.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.52.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.50.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.42.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.53.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.54.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.36.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.59.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.58.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.41.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.37.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.40.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.38.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.39.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.093.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.058.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.031.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.033.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.085.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.087.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.082.html" + - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.088.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.349.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.351.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.352.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.350.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.348.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.114.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.119.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.113.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.111.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.108.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.086.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.063.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.061.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.103.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.104.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.100.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.102.html" + - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.101.html" +redirects: + - /epas/latest/ecpgplus_guide/07_reference/ #generated for docs/epas/reorg-role-use-case-mode + - ../../../application_programming/ecpgplus_guide/07_reference/ +--- + + + +An embedded SQL statement allows your client application to interact with the server. An embedded directive is an instruction to the ECPGPlus compiler. + +You can embed any EDB Postgres Advanced Server SQL statement in a C program. Each statement must begin with the keywords `EXEC SQL` and must be terminated with a semi-colon (;). In the C program, a SQL statement takes the form: + +```sql +EXEC SQL ; +``` + +Where `sql_command_body` represents a standard SQL statement. You can use a host variable anywhere that the SQL statement expects a value expression. For more information about substituting host variables for value expressions, see [Declaring host variables](/epas/latest/application_programming/ecpgplus_guide/03_using_embedded_sql/#declaring-host-variables). + +ECPGPlus extends the PostgreSQL server-side syntax for some statements. Syntax differences are noted in the reference information that follows. For a complete reference to the supported syntax of other SQL commands, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-commands.html). + +## ALLOCATE DESCRIPTOR + +Use the `ALLOCATE DESCRIPTOR` statement to allocate an SQL descriptor area: + +```sql +EXEC SQL [FOR ] ALLOCATE DESCRIPTOR + [WITH MAX ]; +``` + +Where: + +- `array_size` is a variable that specifies the number of array elements to allocate for the descriptor. `array_size` can be an `INTEGER` value or a host variable. +- `descriptor_name` is the host variable that contains the name of the descriptor or the name of the descriptor. This value can take the form of an identifier, a quoted string literal, or of a host variable. +- `variable_count` specifies the maximum number of host variables in the descriptor. The default value of `variable_count` is `100`. + +The following code fragment allocates a descriptor named `emp_query` that can be processed as an array `(emp_array)`: + +```sql +EXEC SQL FOR :emp_array ALLOCATE DESCRIPTOR emp_query; +``` + +## CALL + +Use the `CALL` statement to invoke a procedure or function on the server. The `CALL` statement works only on EDB Postgres Advanced Server. The `CALL` statement comes in two forms. The first form is used to call a function: + +```sql +EXEC SQL CALL '('[]')' + INTO [[:][: ]]; +``` + +The second form is used to call a procedure: + +```sql +EXEC SQL CALL '('[]')'; +``` + +Where: + +- `program_name` is the name of the stored procedure or function that the `CALL` statement invokes. The program name can be schema qualified, package qualified, or both. If you don't specify the schema or package in which the program resides, ECPGPlus uses the value of `search_path` to locate the program. +- `actual_arguments` specifies a comma-separated list of arguments required by the program. Each `actual_argument` corresponds to a formal argument expected by the program. Each formal argument can be an `IN` parameter, an `OUT` parameter, or an `INOUT` parameter. +- `:ret_variable` specifies a host variable that receives the value returned if the program is a function. +- `:ret_indicator` specifies a host variable that receives the indicator value returned if the program is a function. + +For example, the following statement invokes the `get_job_desc` function with the value contained in the `:ename` host variable and captures the value returned by that function in the `:job` host variable: + +```sql +EXEC SQL CALL get_job_desc(:ename) + INTO :job; +``` + +## CLOSE + +Use the `CLOSE` statement to close a cursor and free any resources currently in use by the cursor. A client application can't fetch rows from a closed cursor. The syntax of the `CLOSE` statement is: + +```sql +EXEC SQL CLOSE []; +``` + +Where `cursor_name` is the name of the cursor closed by the statement. The cursor name can take the form of an identifier or of a host variable. + +The `OPEN` statement initializes a cursor. Once initialized, a cursor result set remains unchanged unless the cursor is reopened. You don't need to `CLOSE` a cursor before reopening it. + +To manually close a cursor named `emp_cursor`, use the command: + +```sql +EXEC SQL CLOSE emp_cursor; +``` + +A cursor is automatically closed when an application terminates. + +## COMMIT + +Use the `COMMIT` statement to complete the current transaction, making all changes permanent and visible to other users. The syntax is: + +```sql +EXEC SQL [AT ] COMMIT [WORK] + [COMMENT <'text'>] [COMMENT <'text'> RELEASE]; +``` + +Where `database_name` is the name of the database or host variable that contains the name of the database in which the work resides. This value can take the form of an unquoted string literal or of a host variable. + +For compatibility, ECPGPlus accepts the `COMMENT` clause without error but doesn't store any text included with the `COMMENT` clause. + +Include the `RELEASE` clause to close the current connection after performing the commit. + +For example, the following command commits all work performed on the `dept` database and closes the current connection: + +```sql +EXEC SQL AT dept COMMIT RELEASE; +``` + +By default, statements are committed only when a client application performs a `COMMIT` statement. Include the `-t` option when invoking ECPGPlus to specify for a client application to invoke `AUTOCOMMIT` functionality. You can also control `AUTOCOMMIT` functionality in a client application with the following statements: + +```sql +EXEC SQL SET AUTOCOMMIT TO ON +``` + +and + +```sql +EXEC SQL SET AUTOCOMMIT TO OFF +``` + +## CONNECT + +Use the `CONNECT` statement to establish a connection to a database. The `CONNECT` statement is available in two forms. One form is compatible with Oracle databases, and the other is not. + +The first form is compatible with Oracle databases: + +```sql +EXEC SQL CONNECT + {{: IDENTIFIED BY :} | :} + [AT ] + [USING :database_string] + [ALTER AUTHORIZATION :new_password]; +``` + +Where: + +- `user_name` is a host variable that contains the role that the client application uses to connect to the server. +- `password` is a host variable that contains the password associated with that role. +- `connection_id` is a host variable that contains a slash-delimited user name and password used to connect to the database. + +Include the `AT` clause to specify the database to which the connection is established. `database_name` is the name of the database to which the client is connecting. Specify the value in the form of a variable or as a string literal. + +Include the `USING` clause to specify a host variable that contains a null-terminated string identifying the database to which to establish the connection. + +The `ALTER AUTHORIZATION` clause is supported for syntax compatibility only. ECPGPlus parses the `ALTER AUTHORIZATION` clause and reports a warning. + +Using the first form of the `CONNECT` statement, a client application might establish a connection with a host variable named `user` that contains the identity of the connecting role and a host variable named `password` that contains the associated password using the following command: + +```text +EXEC SQL CONNECT :user IDENTIFIED BY :password; +``` + +A client application can also use the first form of the `CONNECT` statement to establish a connection using a single host variable named `:connection_id`. In the following example, `connection_id` contains the slash-delimited role name and associated password for the user: + +```sql +EXEC SQL CONNECT :connection_id; +``` + +The syntax of the second form of the `CONNECT` statement is: + +```sql +EXEC SQL CONNECT TO +[AS ] []; +``` + +Where `credentials` is one of the following: + +```sql +USER user_name password +USER user_name IDENTIFIED BY password +USER user_name USING password +``` + +In the second form: + +`database_name` is the name or identity of the database to which the client is connecting. Specify `database_name` as a variable or as a string literal in one of the following forms: + +```text +[@][:] + +tcp:postgresql://[:][/][options] + +unix:postgresql://[:][/][options] +``` + +Where: + +- `hostname` is the name or IP address of the server on which the database resides. +- `port` is the port on which the server listens. + + You can also specify a value of `DEFAULT` to establish a connection with the default database, using the default role name. If you specify `DEFAULT` as the target database, don't include a `connection_name` or `credentials`. + +- `connection_name` is the name of the connection to the database. `connection_name` takes the form of an identifier (that is, not a string literal or a variable). You can open multiple connections by providing a unique `connection_name` for each connection. + + If you don't specify a name for a connection, `ecpglib` assigns a name of `DEFAULT` to the connection. You can refer to the connection by name (`DEFAULT`) in any `EXEC SQL` statement. + +- `CURRENT` is the most recently opened or the connection mentioned in the most-recent `SET CONNECTION TO` statement. If you don't refer to a connection by name in an `EXEC SQL` statement, ECPG assumes the name of the connection to be `CURRENT`. + +- `user_name` is the role used to establish the connection with the EDB Postgres Advanced Server database. The privileges of the specified role are applied to all commands performed through the connection. + +- `password` is the password associated with the specified `user_name`. + +The following code fragment uses the second form of the `CONNECT` statement to establish a connection to a database named `edb` using the role `alice` and the password associated with that role, `1safepwd`: + +```sql +EXEC SQL CONNECT TO edb AS acctg_conn + USER 'alice' IDENTIFIED BY '1safepwd'; +``` + +The name of the connection is `acctg_conn`. You can use the connection name when changing the connection name using the `SET CONNECTION` statement. + +## DEALLOCATE DESCRIPTOR + +Use the `DEALLOCATE DESCRIPTOR` statement to free memory in use by an allocated descriptor. The syntax of the statement is: + +```sql +EXEC SQL DEALLOCATE DESCRIPTOR +``` + +Where `descriptor_name` is the name of the descriptor. This value can take the form of a quoted string literal or of a host variable. + +The following example deallocates a descriptor named `emp_query`: + +```sql +EXEC SQL DEALLOCATE DESCRIPTOR emp_query; +``` + +## DECLARE CURSOR + +Use the `DECLARE CURSOR` statement to define a cursor. The syntax of the statement is: + +```sql +EXEC SQL [AT ] DECLARE CURSOR FOR +( | ); +``` + +Where: + +- `database_name` is the name of the database on which the cursor operates. This value can take the form of an identifier or of a host variable. If you don't specify a database name, the default value of `database_name` is the default database. +- `cursor_name` is the name of the cursor. +- `select_statement` is the text of the `SELECT` statement that defines the cursor result set. The `SELECT` statement can't contain an `INTO` clause. +- `statement_name` is the name of a SQL statement or block that defines the cursor result set. + +The following example declares a cursor named `employees`: + +```sql +EXEC SQL DECLARE employees CURSOR FOR + SELECT + empno, ename, sal, comm + FROM + emp; +``` + +The cursor generates a result set that contains the employee number, employee name, salary, and commission for each employee record that's stored in the `emp` table. + +## DECLARE DATABASE + +Use the `DECLARE DATABASE` statement to declare a database identifier for use in subsequent SQL statements (for example, in a `CONNECT` statement). The syntax is: + +```sql +EXEC SQL DECLARE DATABASE; +``` + +Where `database_name` specifies the name of the database. + +The following example shows declaring an identifier for the `acctg` database: + +```sql +EXEC SQL DECLARE acctg DATABASE; +``` + +After invoking the command declaring `acctg` as a database identifier, you can reference the `acctg` database by name when establishing a connection or in `AT` clauses. + +This statement has no effect and is provided for Pro\*C compatibility only. + +## DECLARE STATEMENT + +Use the `DECLARE STATEMENT` directive to declare an identifier for an SQL statement. EDB Postgres Advanced Server supports two versions of the `DECLARE STATEMENT` directive: + +```sql +EXEC SQL [] DECLARE STATEMENT; +``` + +and + +```sql +EXEC SQL DECLARE STATEMENT ; +``` + +Where: + +- `statement_name` specifies the identifier associated with the statement. +- `database_name` specifies the name of the database. This value may take the form of an identifier or of a host variable that contains the identifier. + +A typical usage sequence that includes the `DECLARE STATEMENT` directive is: + +```sql +EXEC SQL DECLARE give_raise STATEMENT; // give_raise is now a statement +handle (not prepared) +EXEC SQL PREPARE give_raise FROM :stmtText; // give_raise is now associated +with a statement +EXEC SQL EXECUTE give_raise; +``` + +This statement has no effect and is provided for Pro\*C compatibility only. + +## DELETE + +Use the `DELETE` statement to delete one or more rows from a table. The syntax for the ECPGPlus `DELETE` statement is the same as the syntax for the SQL statement, but you can use parameter markers and host variables any place that an expression is allowed. The syntax is: + +```sql +[FOR ] DELETE FROM [ONLY]
[[AS] ] + [USING ] + [WHERE | WHERE CURRENT OF ] + [{RETURNING|RETURN} * | [[AS] ] +[, ...] INTO ] +``` + +- Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `VALUES` clause references an array or a pointer to an array. +- `table` is the name (optionally schema qualified) of an existing table. Include the `ONLY` clause to limit processing to the specified table. If you don't include the `ONLY` clause, any tables inheriting from the named table are also processed. +- `alias` is a substitute name for the target table. +- `using_list` is a list of table expressions, allowing columns from other tables to appear in the `WHERE` condition. +- Include the `WHERE` clause to specify the rows to delete. If you don't include a `WHERE` clause in the statement, `DELETE` deletes all rows from the table, leaving the table definition intact. +- `condition` is an expression, host variable, or parameter marker that returns a value of type `BOOLEAN`. Those rows for which `condition` returns true are deleted. +- `cursor_name` is the name of the cursor to use in the `WHERE CURRENT OF` clause. The row to be deleted is the one most recently fetched from this cursor. The cursor must be a nongrouping query on the `DELETE` statements target table. You can't specify `WHERE CURRENT OF` in a `DELETE` statement that includes a Boolean condition. + +The `RETURN/RETURNING` clause specifies an `output_expression` or `host_variable_list` that's returned by the `DELETE` command after each row is deleted: + + - `output_expression` is an expression to be computed and returned by the `DELETE` command after each row is deleted. `output_name` is the name of the returned column. Include \* to return all columns. + - `host_variable_list` is a comma-separated list of host variables and optional indicator variables. Each host variable receives a corresponding value from the `RETURNING` clause. + +For example, the following statement deletes all rows from the `emp` table, where the `sal` column contains a value greater than the value specified in the host variable, `:max_sal:` + +```sql +DELETE FROM emp WHERE sal > :max_sal; +``` + +For more information about using the `DELETE` statement, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-delete.html). + +## DESCRIBE + +Use the `DESCRIBE` statement to find the number of input values required by a prepared statement or the number of output values returned by a prepared statement. The `DESCRIBE` statement is used to analyze a SQL statement whose shape is unknown at the time you write your application. + +The `DESCRIBE` statement populates an `SQLDA` descriptor. To populate a SQL descriptor, use the `ALLOCATE DESCRIPTOR` and `DESCRIBE...DESCRIPTOR` statements. + +```sql +EXEC SQL DESCRIBE BIND VARIABLES FOR INTO ; +``` + + +```sql +EXEC SQL DESCRIBE SELECT LIST FOR INTO ; +``` + +Where: + +- `statement_name` is the identifier associated with a prepared SQL statement or PL/SQL block. +- `descriptor` is the name of C variable of type `SQLDA*`. You must allocate the space for the descriptor by calling `sqlald()` and initialize the descriptor before executing the `DESCRIBE` statement. + +When you execute the first form of the `DESCRIBE` statement, ECPG populates the given descriptor with a description of each input variable *required* by the statement. For example, given two descriptors: + +```sql +SQLDA *query_values_in; +SQLDA *query_values_out; +``` + +You might prepare a query that returns information from the `emp` table: + +```sql +EXEC SQL PREPARE get_emp FROM + "SELECT ename, empno, sal FROM emp WHERE empno = ?"; +``` + +The command requires one input variable for the parameter marker (?). + +```sql +EXEC SQL DESCRIBE BIND VARIABLES + FOR get_emp INTO query_values_in; +``` + +After describing the bind variables for this statement, you can examine the descriptor to find the number of variables required and the type of each variable. + +When you execute the second form, ECPG populates the given descriptor with a description of each value returned by the statement. For example, the following statement returns three values: + +```sql +EXEC SQL DESCRIBE SELECT LIST + FOR get_emp INTO query_values_out; +``` + +After describing the select list for this statement, you can examine the descriptor to find the number of returned values and the name and type of each value. + +Before executing the statement, you must bind a variable for each input value and a variable for each output value. The variables that you bind for the input values specify the actual values used by the statement. The variables that you bind for the output values tell ECPGPlus where to put the values when you execute the statement. + +This is alternative Pro\*C-compatible syntax for the `DESCRIBE DESCRIPTOR` statement. + +## DESCRIBE DESCRIPTOR + +Use the `DESCRIBE DESCRIPTOR` statement to retrieve information about a SQL statement and store that information in a SQL descriptor. Before using `DESCRIBE DESCRIPTOR`, you must allocate the descriptor with the `ALLOCATE DESCRIPTOR` statement. The syntax is: + +```sql +EXEC SQL DESCRIBE [INPUT | OUTPUT] + USING [SQL] DESCRIPTOR ; +``` + +Where: + +- `statement_name` is the name of a prepared SQL statement. +- `descriptor_name` is the name of the descriptor. `descriptor_name` can be a quoted string value or a host variable that contains the name of the descriptor. + +If you include the `INPUT` clause, ECPGPlus populates the given descriptor with a description of each input variable required by the statement. + +For example, given two descriptors: + +```sql +EXEC SQL ALLOCATE DESCRIPTOR query_values_in; +EXEC SQL ALLOCATE DESCRIPTOR query_values_out; +``` + +You might prepare a query that returns information from the `emp` table: + +```sql +EXEC SQL PREPARE get_emp FROM + "SELECT ename, empno, sal FROM emp WHERE empno = ?"; +``` + +The command requires one input variable for the parameter marker (?). + +```sql +EXEC SQL DESCRIBE INPUT get_emp USING 'query_values_in'; +``` + +After describing the bind variables for this statement, you can examine the descriptor to find the number of variables required and the type of each variable. + +If you don't specify the `INPUT` clause, `DESCRIBE DESCRIPTOR` populates the specified descriptor with the values returned by the statement. + +If you include the `OUTPUT` clause, ECPGPlus populates the given descriptor with a description of each value returned by the statement. + +For example, the following statement returns three values: + +```sql +EXEC SQL DESCRIBE OUTPUT FOR get_emp USING 'query_values_out'; +``` + +After describing the select list for this statement, you can examine the descriptor to find the number of returned values and the name and type of each value. + +## DISCONNECT + +Use the `DISCONNECT` statement to close the connection to the server. The syntax is: + +```sql +EXEC SQL DISCONNECT [][CURRENT][DEFAULT][ALL]; +``` + +Where `connection_name` is the connection name specified in the `CONNECT` statement used to establish the connection. If you don't specify a connection name, the current connection is closed. + +Include the `CURRENT` keyword to specify for ECPGPlus to close the connection used most recently. + +Include the `DEFAULT` keyword to specify for ECPGPlus to close the connection named `DEFAULT`. If you don't specify a name when opening a connection, ECPGPlus assigns the name `DEFAULT` to the connection. + +Include the `ALL` keyword to close all active connections. + +The following example creates a connection named `hr_connection` that connects to the `hr` database and then disconnects from the connection: + +```c +/* client.pgc*/ +int main() +{ + EXEC SQL CONNECT TO hr AS connection_name; + EXEC SQL DISCONNECT connection_name; + return(0); +} +``` + +## EXECUTE + +Use the `EXECUTE` statement to execute a statement previously prepared using an `EXEC SQL PREPARE` statement. The syntax is: + +```sql +EXEC SQL [FOR ] EXECUTE + [USING {DESCRIPTOR + |: [[INDICATOR] :]}]; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `statement_name` specifies the name assigned to the statement when the statement was created using the `EXEC SQL PREPARE` statement. + +Include the `USING` clause to supply values for parameters in the prepared statement: + +- Include the `DESCRIPTOR` `SQLDA_descriptor` clause to provide an SQLDA descriptor value for a parameter. +- Use a `host_variable` (and an optional `indicator_variable`) to provide a user-specified value for a parameter. + +The following example creates a prepared statement that inserts a record into the `emp` table: + +```sql +EXEC SQL PREPARE add_emp (numeric, text, text, numeric) AS + INSERT INTO emp VALUES($1, $2, $3, $4); +``` + +Each time you invoke the prepared statement, provide fresh parameter values for the statement: + +```sql +EXEC SQL EXECUTE add_emp USING 8000, 'DAWSON', 'CLERK', 7788; +EXEC SQL EXECUTE add_emp USING 8001, 'EDWARDS', 'ANALYST', 7698; +``` + +## EXECUTE DESCRIPTOR + +Use the `EXECUTE` statement to execute a statement previously prepared by an `EXEC SQL PREPARE` statement, using an SQL descriptor. The syntax is: + +```sql +EXEC SQL [FOR ] EXECUTE + [USING [SQL] DESCRIPTOR ] + [INTO [SQL] DESCRIPTOR ]; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `statement_identifier` specifies the identifier assigned to the statement with the `EXEC SQL PREPARE` statement. +- `descriptor_name` specifies the name of a descriptor (as a single-quoted string literal), or a host variable that contains the name of a descriptor. + +Include the `USING` clause to specify values for any input parameters required by the prepared statement. + +Include the `INTO` clause to specify a descriptor into which the `EXECUTE` statement writes the results returned by the prepared statement. + +The following example executes the prepared statement, `give_raise`, using the values contained in the descriptor `stmtText:` + +```sql +EXEC SQL PREPARE give_raise FROM :stmtText; +EXEC SQL EXECUTE give_raise USING DESCRIPTOR :stmtText; +``` + +## EXECUTE...END EXEC + +Use the `EXECUTE…END-EXEC` statement to embed an anonymous block into a client application. The syntax is: + +```sql +EXEC SQL [AT ] EXECUTE END-EXEC; +``` + +Where: + +- `database_name` is the database identifier or a host variable that contains the database identifier. If you omit the `AT` clause, the statement executes on the current default database. +- `anonymous_block` is an inline sequence of PL/pgSQL or SPL statements and declarations. You can include host variables and optional indicator variables in the block. Each such variable is treated as an `IN/OUT` value. + +The following example executes an anonymous block: + +```sql +EXEC SQL EXECUTE + BEGIN + IF (current_user = :admin_user_name) THEN + DBMS_OUTPUT.PUT_LINE('You are an administrator'); + END IF; +END-EXEC; +``` + +!!! Note + The `EXECUTE…END EXEC` statement is supported only by EDB Postgres Advanced Server. + +## EXECUTE IMMEDIATE + +Use the `EXECUTE IMMEDIATE` statement to execute a string that contains a SQL command. The syntax is: + +```sql +EXEC SQL [AT ] EXECUTE IMMEDIATE ; +``` + +Where: + +- `database_name` is the database identifier or a host variable that contains the database identifier. If you omit the `AT` clause, the statement executes on the current default database. +- `command_text` is the command executed by the `EXECUTE IMMEDIATE` statement. + +This dynamic SQL statement is useful when you don't know the text of an SQL statement when writing a client application. For example, a client application might prompt a trusted user for a statement to execute. After the user provides the text of the statement as a string value, the statement is then executed with an `EXECUTE IMMEDIATE` command. + +The statement text can't contain references to host variables. If the statement might contain parameter markers or returns one or more values, use the `PREPARE` and `DESCRIBE` statements. + +The following example executes the command contained in the `:command_text` host variable: + +```sql +EXEC SQL EXECUTE IMMEDIATE :command_text; +``` + +## FETCH + +Use the `FETCH` statement to return rows from a cursor into an SQLDA descriptor or a target list of host variables. Before using a `FETCH` statement to retrieve information from a cursor, you must prepare the cursor using `DECLARE` and `OPEN` statements. The statement syntax is: + +```sql +EXEC SQL [FOR ] FETCH + { USING DESCRIPTOR }|{ INTO }; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `cursor` is the name of the cursor from which rows are being fetched or a host variable that contains the name of the cursor. + +If you include a `USING` clause, the `FETCH` statement populates the specified SQLDA descriptor with the values returned by the server. + +If you include an `INTO` clause, the `FETCH` statement populates the host variables (and optional indicator variables) specified in the `target_list`. + +The following code fragment declares a cursor named `employees` that retrieves the `employee number`, `name`, and `salary` from the `emp` table: + +```sql +EXEC SQL DECLARE employees CURSOR FOR + SELECT empno, ename, esal FROM emp; +EXEC SQL OPEN emp_cursor; +EXEC SQL FETCH emp_cursor INTO :emp_no, :emp_name, :emp_sal; +``` + +## FETCH DESCRIPTOR + +Use the `FETCH DESCRIPTOR` statement to retrieve rows from a cursor into an SQL descriptor. The syntax is: + +```sql +EXEC SQL [FOR ] FETCH + INTO [SQL] DESCRIPTOR ; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `cursor` is the name of the cursor from which rows are fetched or a host variable that contains the name of the cursor. The client must `DECLARE` and `OPEN` the cursor before calling the `FETCH DESCRIPTOR` statement. +- `descriptor_name` specifies the name of a descriptor (as a single-quoted string literal) or a host variable that contains the name of a descriptor. Prior to use, the descriptor must be allocated using an `ALLOCATE DESCRIPTOR` statement. + +Include the `INTO` clause to specify a SQL descriptor into which the `EXECUTE` statement writes the results returned by the prepared statement. + +The following example allocates a descriptor named `row_desc` that holds the description and the values of a specific row in the result set. It then declares and opens a cursor for a prepared statement (`my_cursor`), before looping through the rows in result set, using a `FETCH` to retrieve the next row from the cursor into the descriptor: + +```sql +EXEC SQL ALLOCATE DESCRIPTOR 'row_desc'; +EXEC SQL DECLARE my_cursor CURSOR FOR query; +EXEC SQL OPEN my_cursor; + +for( row = 0; ; row++ ) +{ + EXEC SQL BEGIN DECLARE SECTION; + int col; +EXEC SQL END DECLARE SECTION; +EXEC SQL FETCH my_cursor INTO SQL DESCRIPTOR 'row_desc'; +``` + +## GET DESCRIPTOR + +Use the `GET DESCRIPTOR` statement to retrieve information from a descriptor. The `GET DESCRIPTOR` statement comes in two forms. The first form returns the number of values (or columns) in the descriptor. + +```sql +EXEC SQL GET DESCRIPTOR + : = COUNT; +``` + +The second form returns information about a specific value (specified by the `VALUE column_number` clause): + +```sql +EXEC SQL [FOR ] GET DESCRIPTOR + VALUE {: = {,…}}; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you specify an `array_size`, the `host_variable` must be an array of that size. For example, if `array_size` is `10`, `:host_variable` must be a 10-member array of `host_variables`. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `descriptor_name` specifies the name of a descriptor as a single-quoted string literal or a host variable that contains the name of a descriptor. + +Include the `VALUE` clause to specify the information retrieved from the descriptor. + +- `column_number` identifies the position of the variable in the descriptor. +- `host_variable` specifies the name of the host variable that receives the value of the item. +- `descriptor_item` specifies the type of the retrieved descriptor item. + +ECPGPlus implements the following `descriptor_item` types: + +- `TYPE` +- `LENGTH` +- `OCTET_LENGTH` +- `RETURNED_LENGTH` +- `RETURNED_OCTET_LENGTH` +- `PRECISION` +- `SCALE` +- `NULLABLE` +- `INDICATOR` +- `DATA` +- `NAME` + +The following code fragment shows using a `GET DESCRIPTOR` statement to obtain the number of columns entered in a user-provided string: + +```sql +EXEC SQL ALLOCATE DESCRIPTOR parse_desc; +EXEC SQL PREPARE query FROM :stmt; +EXEC SQL DESCRIBE query INTO SQL DESCRIPTOR parse_desc; +EXEC SQL GET DESCRIPTOR parse_desc :col_count = COUNT; +``` + +The example allocates an SQL descriptor named `parse_desc` before using a `PREPARE` statement to check the syntax of the string provided by the user `:stmt`. A `DESCRIBE` statement moves the user-provided string into the descriptor, `parse_desc`. The call to `EXEC SQL GET DESCRIPTOR` interrogates the descriptor to discover the number of columns `(:col_count)` in the result set. + +## INSERT + +Use the `INSERT` statement to add one or more rows to a table. The syntax for the ECPGPlus `INSERT` statement is the same as the syntax for the SQL statement, but you can use parameter markers and host variables any place that a value is allowed. The syntax is: + +```sql +[FOR ] INSERT INTO
[( [, ...])] + {DEFAULT VALUES | + VALUES ({ | DEFAULT} [, ...])[, ...] | } + [RETURNING * | [[ AS ] ] [, ...]] +``` + +Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `VALUES` clause references an array or a pointer to an array. + +- `table` specifies the (optionally schema-qualified) name of an existing table. +- `column` is the name of a column in the table. The column name can be qualified with a subfield name or array subscript. Specify the `DEFAULT VALUES` clause to use default values for all columns. +- `expression` is the expression, value, host variable, or parameter marker that's assigned to the corresponding column. Specify `DEFAULT` to fill the corresponding column with its default value. +- `query` specifies a `SELECT` statement that supplies the rows to insert. +- `output_expression` is an expression that's computed and returned by the `INSERT` command after each row is inserted. The expression can refer to any column in the table. Specify \* to return all columns of the inserted rows. +- `output_name` specifies a name to use for a returned column. + +The following example adds a row to the `employees` table: + +```sql +INSERT INTO emp (empno, ename, job, hiredate) + VALUES ('8400', :ename, 'CLERK', '2011-10-31'); +``` + +!!! Note + The `INSERT` statement uses a host variable `:ename` to specify the value of the `ename` column. + +For more information about using the `INSERT` statement, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-insert.html). + +## OPEN + +Use the `OPEN` statement to open a cursor. The syntax is: + +```sql +EXEC SQL [FOR ] OPEN [USING ]; +``` + +`parameters` is one of the following: + +```sql +DESCRIPTOR +``` + +or + +```sql + [ [ INDICATOR ] , … ] +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `cursor` is the name of the cursor being opened. +- `parameters` is either `DESCRIPTOR SQLDA_descriptor` or a comma-separated list of `host variables` and optional `indicator variables` that initialize the cursor. If specifying an `SQLDA_descriptor`, the descriptor must be initialized with a `DESCRIBE` statement. + +The `OPEN` statement initializes a cursor using the values provided in `parameters`. Once initialized, the cursor result set remains unchanged unless the cursor is closed and reopened. A cursor is automatically closed when an application terminates. + +The following example declares a cursor named `employees` that queries the `emp` table. It returns the `employee number`, `name`, `salary`, and `commission` of an employee whose name matches a user-supplied value stored in the host variable `:emp_name`. + +```sql +EXEC SQL DECLARE employees CURSOR FOR + SELECT + empno, ename, sal, comm  + FROM  + emp + WHERE ename = :emp_name; +EXEC SQL OPEN employees; +... +``` + +After declaring the cursor, the example uses an `OPEN` statement to make the contents of the cursor available to a client application. + +## OPEN DESCRIPTOR + +Use the `OPEN DESCRIPTOR` statement to open a cursor with a SQL descriptor. The syntax is: + +```sql +EXEC SQL [FOR ] OPEN + [USING [SQL] DESCRIPTOR ] + [INTO [SQL] DESCRIPTOR ]; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. +- `cursor` is the name of the cursor being opened. +- `descriptor_name` specifies the name of an SQL descriptor in the form of a single-quoted string literal or a host variable that contains the name of an SQL descriptor that contains the query that initializes the cursor. + +For example, the following statement opens a cursor named `emp_cursor` using the host variable `:employees`: + +```sql +EXEC SQL OPEN emp_cursor USING DESCRIPTOR :employees; +``` + +## PREPARE + +Prepared statements are useful when a client application must perform a task multiple times. The statement is parsed, written, and planned only once rather than each time the statement is executed. This approach saves repetitive processing time. + +Use the `PREPARE` statement to prepare a SQL statement or PL/pgSQL block for execution. The statement is available in two forms. The first form is: + +```sql +EXEC SQL [AT ] PREPARE + FROM ; +``` + +The second form is: + +```sql +EXEC SQL [AT ] PREPARE + AS ; +``` + +Where: + +- `database_name` is the database identifier or a host variable that contains the database identifier against which the statement executes. If you omit the `AT` clause, the statement executes against the current default database. +- `statement_name` is the identifier associated with a prepared SQL statement or PL/SQL block. +- `sql_statement` can take the form of a `SELECT` statement, a single-quoted string literal, or a host variable that contains the text of an SQL statement. + +To include variables in a prepared statement, substitute placeholders (`$1, $2, $3`, and so on) for statement values that might change when you `PREPARE` the statement. When you `EXECUTE` the statement, provide a value for each parameter. Provide the values in the order in which they replace placeholders. + +The following example creates a prepared statement named `add_emp` that inserts a record into the `emp` table: + +```sql +EXEC SQL PREPARE add_emp (int, text, text, numeric) AS + INSERT INTO emp VALUES($1, $2, $3, $4); +``` + +Each time you invoke the statement, provide fresh parameter values for the statement: + +```sql +EXEC SQL EXECUTE add_emp(8003, 'Davis', 'CLERK', 2000.00); +EXEC SQL EXECUTE add_emp(8004, 'Myer', 'CLERK', 2000.00); +``` + +!!! Note + A client application must issue a `PREPARE` statement in each session in which a statement executes. Prepared statements persist only for the duration of the current session. + +## ROLLBACK + +Use the `ROLLBACK` statement to abort the current transaction and discard any updates made by the transaction. The syntax is: + +```sql +EXEC SQL [AT ] ROLLBACK [WORK] + [ { TO [SAVEPOINT] } | RELEASE ] +``` + +Where `database_name` is the database identifier or a host variable that contains the database identifier against which the statement executes. If you omit the `AT` clause, the statement executes against the current default database. + +Include the `TO` clause to abort any commands that executed after the specified `savepoint`. Use the `SAVEPOINT` statement to define the `savepoint`. If you omit the `TO` clause, the `ROLLBACK` statement aborts the transaction, discarding all updates. + +Include the `RELEASE` clause to cause the application to execute an `EXEC SQL COMMIT RELEASE` and close the connection. + +Use the following statement to roll back a complete transaction: + +```sql +EXEC SQL ROLLBACK; +``` + +Invoking this statement aborts the transaction, undoing all changes, erasing any savepoints, and releasing all transaction locks. Suppose you include a savepoint (`my_savepoint` in the following example): + +```sql +EXEC SQL ROLLBACK TO SAVEPOINT my_savepoint; +``` + +Only the portion of the transaction that occurred after the `my_savepoint` is rolled back. `my_savepoint` is retained, but any savepoints created after `my_savepoint` are erased. + +Rolling back to a specified savepoint releases all locks acquired after the savepoint. + +## SAVEPOINT + +Use the `SAVEPOINT` statement to define a *savepoint*. A savepoint is a marker in a transaction. You can use a `ROLLBACK` statement to abort the current transaction, returning the state of the server to its condition prior to the specified savepoint. The syntax of a `SAVEPOINT` statement is: + +```sql +EXEC SQL [AT ] SAVEPOINT +``` + +Where: + +- `database_name` is the database identifier or a host variable that contains the database identifier against which the savepoint resides. If you omit the `AT` clause, the statement executes against the current default database. +- `savepoint_name` is the name of the savepoint. If you reuse a `savepoint_name`, the original savepoint is discarded. + +You can establish savepoints only in a transaction block. A transaction block can contain multiple savepoints. + +To create a savepoint named `my_savepoint`, include the statement: + +```sql +EXEC SQL SAVEPOINT my_savepoint; +``` + +## SELECT + +ECPGPlus extends support of the `SQL SELECT` statement by providing the `INTO host_variables` clause. The clause allows you to select specified information from an EDB Postgres Advanced Server database into a host variable. The syntax for the `SELECT` statement is: + +```sql +EXEC SQL [AT ] +SELECT + [ ] + [ ALL | DISTINCT [ ON( , ...) ]] + select_list INTO + + [ FROM from_item [, from_item ]...] + [ WHERE condition ] + [ hierarchical_query_clause ] + [ GROUP BY expression [, ...]] + [ HAVING condition ] + [ { UNION [ ALL ] | INTERSECT | MINUS } (subquery) ] + [ ORDER BY expression [order_by_options]] + [ LIMIT { count | ALL }] + [ OFFSET start [ ROW | ROWS ] ] + [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ] + [ FOR { UPDATE | SHARE } [OF table_name [, ...]][NOWAIT ][...]] +``` + +Where: + +- `database_name` is the name of the database or host variable that contains the name of the database in which the table resides. This value can take the form of an unquoted string literal or of a host variable. +- `host_variables` is a list of host variables populated by the `SELECT` statement. If the `SELECT` statement returns more than a single row, `host_variables` must be an array. + +ECPGPlus provides support for the additional clauses of the SQL `SELECT` statement as documented in the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-select.html). + +To use the `INTO host_variables` clause, include the names of defined host variables when specifying the `SELECT` statement. For example, the following `SELECT` statement populates the `:emp_name` and `:emp_sal` host variables with a list of employee names and salaries: + +```sql +EXEC SQL SELECT ename, sal + INTO :emp_name, :emp_sal + FROM emp + WHERE empno = 7988; +``` + +The enhanced `SELECT` statement also allows you to include parameter markers (question marks) in any clause where a value is allowed. For example, the following query contains a parameter marker in the `WHERE` clause: + +```sql +SELECT * FROM emp WHERE dept_no = ?; +``` + +This `SELECT` statement allows you to provide a value at runtime for the `dept_no` parameter marker. + +## SET CONNECTION + +There are at least three reasons you might need more than one connection in a given client application: + +- You might want different privileges for different statements. +- You might need to interact with multiple databases in the same client. +- Multiple threads of execution in a client application can't share a connection concurrently. + +The syntax for the `SET CONNECTION` statement is: + +```sql +EXEC SQL SET CONNECTION ; +``` + +Where `connection_name` is the name of the connection to the database. + +To use the `SET CONNECTION` statement, open the connection to the database using the second form of the `CONNECT` statement. Include the `AS` clause to specify a `connection_name`. + +By default, the current thread uses the current connection. Use the `SET CONNECTION` statement to specify a default connection for the current thread to use. The default connection is used only when you execute an `EXEC SQL` statement that doesn't explicitly specify a connection name. For example, the following statement uses the default connection because it doesn't include an `AT connection_name` clause: + +```sql +EXEC SQL DELETE FROM emp; +``` + +This statement doesn't use the default connection because it specifies a connection name using the `AT connection_name` clause: + +```sql +EXEC SQL AT acctg_conn DELETE FROM emp; +``` + +For example, suppose a client application creates and maintains multiple connections using either of the following approaches: + +```sql +EXEC SQL CONNECT TO edb AS acctg_conn + USER 'alice' IDENTIFIED BY 'acctpwd'; +``` + + +```sql +EXEC SQL CONNECT TO edb AS hr_conn + USER 'bob' IDENTIFIED BY 'hrpwd'; +``` + +It can change between the connections with the `SET CONNECTION` statement: + +```sql +SET CONNECTION acctg_conn; +``` + +or + +```sql +SET CONNECTION hr_conn; +``` + +The server uses the privileges associated with the connection when determining the privileges available to the connecting client. When using the `acctg_conn` connection, the client has the privileges associated with the role `alice`. When connected using `hr_conn`, the client has the privileges associated with `bob`. + +## SET DESCRIPTOR + +Use the `SET DESCRIPTOR` statement to assign a value to a descriptor area using information provided by the client application in the form of a host variable or an integer value. The statement comes in two forms. The first form is: + +```sql +EXEC SQL [FOR ] SET DESCRIPTOR + VALUE = ; +``` + +The second form is: + +```sql +EXEC SQL [FOR ] SET DESCRIPTOR + COUNT = integer; +``` + +Where: + +- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement executes once for each member of the array. +- `descriptor_name` specifies the name of a descriptor as a single-quoted string literal or a host variable that contains the name of a descriptor. + +Include the `VALUE` clause to describe the information stored in the descriptor. + +- `column_number` identifies the position of the variable within the descriptor. +- `descriptor_item` specifies the type of the descriptor item. +- `host_variable` specifies the name of the host variable that contains the value of the item. + +ECPGPlus implements the following `descriptor_item` types: + +- `TYPE` +- `LENGTH` +- `[REF] INDICATOR` +- `[REF] DATA` +- `[REF] RETURNED LENGTH` + +For example, a client application might prompt a user for a dynamically created query: + +```c +query_text = promptUser("Enter a query"); +``` + +To execute a dynamically created query, you must first prepare the query (parsing and validating the syntax of the query) and then describe the input parameters found in the query using the `EXEC SQL DESCRIBE INPUT` statement. + +```sql +EXEC SQL ALLOCATE DESCRIPTOR query_params; +EXEC SQL PREPARE emp_query FROM :query_text; + +EXEC SQL DESCRIBE INPUT emp_query + USING SQL DESCRIPTOR 'query_params'; +``` + +After describing the query, the `query_params` descriptor contains information about each parameter required by the query. + +For this example, assume that the user entered: + +```sql +SELECT ename FROM emp WHERE sal > ? AND job = ?;, +``` + +In this case, the descriptor describes two parameters, one for `sal > ?` and one for `job = ?`. + +To discover the number of parameter markers (question marks) in the query and therefore the number of values you must provide before executing the query, use: + +```sql +EXEC SQL GET DESCRIPTOR … :host_variable = COUNT; +``` + +Then, you can use `EXEC SQL GET DESCRIPTOR` to retrieve the name of each parameter. You can also use `EXEC SQL GET DESCRIPTOR` to retrieve the type of each parameter from the descriptor, along with the number of parameters. Or you can supply each `value` in the form of a character string and ECPG converts that string into the required data type. + +The data type of the first parameter is `numeric`. The type of the second parameter is `varchar`. The name of the first parameter is `sal`. The name of the second parameter is `job`. + +Next, loop through each parameter, prompting the user for a value, and store those values in host variables. You can use `GET DESCRIPTOR … COUNT` to find the number of parameters in the query. + +```sql +EXEC SQL GET DESCRIPTOR 'query_params' + :param_count = COUNT; + +for(param_number = 1; + param_number <= param_count; + param_number++) +{ +``` + +Use `GET DESCRIPTOR` to copy the name of the parameter into the `param_name` host variable: + +```sql +EXEC SQL GET DESCRIPTOR 'query_params' + VALUE :param_number :param_name = NAME; + +reply = promptUser(param_name); +if (reply == NULL) + reply_ind = 1; /* NULL */ +else + reply_ind = 0; /* NOT NULL */ +``` + +To associate a `value` with each parameter, you use the `EXEC SQL SET DESCRIPTOR` statement. For example: + +```sql +EXEC SQL SET DESCRIPTOR 'query_params' + VALUE :param_number DATA = :reply; +EXEC SQL SET DESCRIPTOR 'query_params' + VALUE :param_number INDICATOR = :reply_ind; +} +``` + +Now, you can use the `EXEC SQL EXECUTE DESCRIPTOR` statement to execute the prepared statement on the server. + +## UPDATE + +Use an `UPDATE` statement to modify the data stored in a table. The syntax is: + +```sql +EXEC SQL [AT ][FOR ] + UPDATE [ ONLY ] table [ [ AS ] alias ] + SET {column = { expression | DEFAULT } | + (column [, ...]) = ({ expression|DEFAULT } [, ...])} [, ...] + [ FROM from_list ] + [ WHERE condition | WHERE CURRENT OF cursor_name ] + [ RETURNING * | output_expression [[ AS ] output_name] [, ...] ] +``` + +Where `database_name` is the name of the database or host variable that contains the name of the database in which the table resides. This value can take the form of an unquoted string literal or of a host variable. + +Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `SET` or `WHERE` clause contains an array. + +ECPGPlus provides support for the additional clauses of the SQL `UPDATE` statement as documented in the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-update.html). + +You can use a host variable in any clause that specifies a value. To use a host variable, substitute a defined variable for any value associated with any of the documented `UPDATE` clauses. + +The following `UPDATE` statement changes the job description of an employee (identified by the `:ename` host variable) to the value contained in the `:new_job` host variable. It increases the employees salary by multiplying the current salary by the value in the `:increase` host variable: + +```sql +EXEC SQL UPDATE emp + SET job = :new_job, sal = sal * :increase + WHERE ename = :ename; +``` + +The enhanced `UPDATE` statement also allows you to include parameter markers (question marks) in any clause where an input value is permitted. For example, we can write the same update statement with a parameter marker in the `WHERE` clause: + +```sql +EXEC SQL UPDATE emp + SET job = ?, sal = sal * ? + WHERE ename = :ename; +``` + +This `UPDATE` statement allows you to prompt the user for a new value for the `job` column and provide the amount by which the `sal` column is incremented for the employee specified by `:ename`. + +## WHENEVER + +Use the `WHENEVER` statement to specify the action taken by a client application when it encounters an SQL error or warning. The syntax is: + +```sql +EXEC SQL WHENEVER ; +``` + +The following table describes the different conditions that might trigger an `action`. + +| Condition | Description | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `NOT FOUND` | The server returns a `NOT FOUND` condition when it encounters a `SELECT` that returns no rows or when a `FETCH` reaches the end of a result set. | +| `SQLERROR` | The server returns an `SQLERROR` condition when it encounters a serious error returned by an SQL statement. | +| `SQLWARNING` | The server returns an `SQLWARNING` condition when it encounters a nonfatal warning returned by an SQL statement. | + +The following table describes the actions that result from a client encountering a `condition`. + +| Action | Description | +| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `CALL function [([args])]` | Call the named `function`. | +| `CONTINUE` | Proceed to the next statement. | +| `DO BREAK` | Emit a C break statement. A break statement can appear in a `loop` or a `switch` statement. If executed, the break statement terminates the `loop` or the `switch` statement. | +| `DO CONTINUE` | Emit a C `continue` statement. A `continue` statement can exist only in a loop. If executed, it causes the flow of control to return to the top of the loop. | +| `DO function ([args])` | Call the named `function`. | +| `GOTO label` or `GO TO label` | Proceed to the statement that contains the label. | +| `SQLPRINT` | Print a message to standard error. | +| `STOP` | Stop executing. | + +The following code fragment prints a message if the client application encounters a warning and aborts the application if it encounters an error: + +```sql +EXEC SQL WHENEVER SQLWARNING SQLPRINT; +EXEC SQL WHENEVER SQLERROR STOP; +``` + +Include the following code to specify for a client to continue processing after warning a user of a problem: + +```sql +EXEC SQL WHENEVER SQLWARNING SQLPRINT; +``` + +Include the following code to call a function if a query returns no rows or when a cursor reaches the end of a result set: + +```sql +EXEC SQL WHENEVER NOT FOUND CALL error_handler(__LINE__); +``` From 707c083b5ee2d23659ca20e53272056ce6968640 Mon Sep 17 00:00:00 2001 From: francoughlin Date: Thu, 10 Aug 2023 15:38:08 -0400 Subject: [PATCH 04/24] Edits for Working with Oracle Data section Also includes some edits for tools and utilities --- .../02_enhanced_compatibility_features.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product_docs/docs/epas/16/working_with_oracle_data/02_enhanced_compatibility_features.mdx b/product_docs/docs/epas/16/working_with_oracle_data/02_enhanced_compatibility_features.mdx index e22b9e455dc..3a784c9c938 100644 --- a/product_docs/docs/epas/16/working_with_oracle_data/02_enhanced_compatibility_features.mdx +++ b/product_docs/docs/epas/16/working_with_oracle_data/02_enhanced_compatibility_features.mdx @@ -99,7 +99,7 @@ EDB Postgres Advanced Server supports a number of built-in packages that provide | `DBMS_PROFILER` | Collects and stores performance information about the PL/pgSQL and SPL statements that are executed during a performance profiling session. | | `DBMS_RANDOM` | Provides methods to generate random values. | | `DBMS_REDACT` | Enables redacting or masking data that's returned by a query. | -| `DBMS_RLS` | Enables implementating Virtual Private Database on certain EDB Postgres Advanced Server database objects. | +| `DBMS_RLS` | Enables implementing Virtual Private Database on certain EDB Postgres Advanced Server database objects. | | `DBMS_SCHEDULER` | Lets you create and manage jobs, programs, and job schedules. | | `DBMS_SESSION` | Provides support for the `DBMS_SESSION.SET_ROLE` procedure. | | `DBMS_SQL` | Provides an application interface to the EDB dynamic SQL functionality. | From 17be6efd1dff75648fd3ea6793cc629a5510b8f6 Mon Sep 17 00:00:00 2001 From: francoughlin Date: Tue, 15 Aug 2023 14:48:53 -0400 Subject: [PATCH 05/24] Fixes for duplicate redirects --- .../04_case_expression/01_selector_case_expression.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product_docs/docs/epas/16/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/04_case_expression/01_selector_case_expression.mdx b/product_docs/docs/epas/16/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/04_case_expression/01_selector_case_expression.mdx index 9c6ff4815a3..7c8ad14c3a6 100644 --- a/product_docs/docs/epas/16/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/04_case_expression/01_selector_case_expression.mdx +++ b/product_docs/docs/epas/16/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/04_case_expression/01_selector_case_expression.mdx @@ -2,7 +2,7 @@ title: "Selector CASE expression" redirects: - /epas/latest/epas_compat_spl/05_control_structures/04_case_expression/01_selector_case_expression/ #generated for docs/epas/reorg-role-use-case-mode - - /epas/latest/application_programming/epas_compat_spl/05_control_structures/04_case_expression/01_selector_case_expression/ + - /epas/latest/application_programming/epas_compat_spl/05_control_structures/04_case_expression/02_searched_case_expression/ --- From e2a12e169eadc7183a1195ca00110f926b6b010d Mon Sep 17 00:00:00 2001 From: francoughlin Date: Tue, 15 Aug 2023 16:31:01 -0400 Subject: [PATCH 06/24] Additional redirect fixes --- .../04_case_expression/01_selector_case_expression.mdx | 2 +- .../epas_compat_tools_guide/index.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/product_docs/docs/epas/16/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/04_case_expression/01_selector_case_expression.mdx b/product_docs/docs/epas/16/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/04_case_expression/01_selector_case_expression.mdx index 7c8ad14c3a6..9c6ff4815a3 100644 --- a/product_docs/docs/epas/16/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/04_case_expression/01_selector_case_expression.mdx +++ b/product_docs/docs/epas/16/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/04_case_expression/01_selector_case_expression.mdx @@ -2,7 +2,7 @@ title: "Selector CASE expression" redirects: - /epas/latest/epas_compat_spl/05_control_structures/04_case_expression/01_selector_case_expression/ #generated for docs/epas/reorg-role-use-case-mode - - /epas/latest/application_programming/epas_compat_spl/05_control_structures/04_case_expression/02_searched_case_expression/ + - /epas/latest/application_programming/epas_compat_spl/05_control_structures/04_case_expression/01_selector_case_expression/ --- diff --git a/product_docs/docs/epas/16/tools_utilities_and_components/epas_compat_tools_guide/index.mdx b/product_docs/docs/epas/16/tools_utilities_and_components/epas_compat_tools_guide/index.mdx index 173e95f0c75..0a2abf3efc2 100644 --- a/product_docs/docs/epas/16/tools_utilities_and_components/epas_compat_tools_guide/index.mdx +++ b/product_docs/docs/epas/16/tools_utilities_and_components/epas_compat_tools_guide/index.mdx @@ -8,7 +8,7 @@ legacyRedirectsGenerated: - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-tools-and-utilities-guide/9.6/toc.html" redirects: - /epas/latest/epas_compat_tools_guide/ #generated for docs/epas/reorg-role-use-case-mode - - ../../epas_compat_tools_guide/ + - ../../epas_compat_ora_dev_guide/ --- From 5e061d9782a009b0b42429fc7a9782f84e23c00e Mon Sep 17 00:00:00 2001 From: francoughlin Date: Tue, 15 Aug 2023 17:43:08 -0400 Subject: [PATCH 07/24] Redirect fix --- .../epas_compat_tools_guide/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product_docs/docs/epas/16/tools_utilities_and_components/epas_compat_tools_guide/index.mdx b/product_docs/docs/epas/16/tools_utilities_and_components/epas_compat_tools_guide/index.mdx index 0a2abf3efc2..173e95f0c75 100644 --- a/product_docs/docs/epas/16/tools_utilities_and_components/epas_compat_tools_guide/index.mdx +++ b/product_docs/docs/epas/16/tools_utilities_and_components/epas_compat_tools_guide/index.mdx @@ -8,7 +8,7 @@ legacyRedirectsGenerated: - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-tools-and-utilities-guide/9.6/toc.html" redirects: - /epas/latest/epas_compat_tools_guide/ #generated for docs/epas/reorg-role-use-case-mode - - ../../epas_compat_ora_dev_guide/ + - ../../epas_compat_tools_guide/ --- From 278fcd1f3c20aa57dee923c1f3dcb2f482ec86cd Mon Sep 17 00:00:00 2001 From: nidhibhammar <59045594+nidhibhammar@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:16:57 +0530 Subject: [PATCH 08/24] Added 07_reference folder from v15 to v16 --- .../07_reference.mdx | 1257 ----------------- .../07_reference/ecpgplus_statements.mdx | 3 + 2 files changed, 3 insertions(+), 1257 deletions(-) delete mode 100644 product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx diff --git a/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx b/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx deleted file mode 100644 index 4e1811f9467..00000000000 --- a/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference.mdx +++ /dev/null @@ -1,1257 +0,0 @@ ---- -title: "Language element reference" -description: "Description of the ECPGPlus language elements" -legacyRedirectsGenerated: - # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.55.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.56.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.57.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.23.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.49.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.51.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.28.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.24.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.27.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.48.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.29.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.25.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.30.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.47.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.31.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.46.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.32.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.45.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.33.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.44.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.34.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.26.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.43.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.35.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.52.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.50.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.42.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.53.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.54.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.36.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.59.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.58.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.41.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.37.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.40.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.38.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/ecpgplus-guide/9.6/EDB_Postgres_Advanced_Server_ecpgPlus_Guide.1.39.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.093.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.058.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.031.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.033.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.085.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.087.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.082.html" - - "/edb-docs/d/edb-postgres-advanced-server/reference/database-compatibility-for-oracle-developers-reference-guide/9.6/Database_Compatibility_for_Oracle_Developers_Reference_Guide.1.088.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.349.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.351.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.352.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.350.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.348.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.114.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.119.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.113.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.111.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.108.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.086.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.063.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.061.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.103.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.104.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.100.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.102.html" - - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.101.html" -redirects: - - /epas/latest/ecpgplus_guide/07_reference/ #generated for docs/epas/reorg-role-use-case-mode - - ../../../application_programming/ecpgplus_guide/07_reference/ ---- - - - -An embedded SQL statement allows your client application to interact with the server. An embedded directive is an instruction to the ECPGPlus compiler. - -You can embed any EDB Postgres Advanced Server SQL statement in a C program. Each statement must begin with the keywords `EXEC SQL` and must be terminated with a semi-colon (;). In the C program, a SQL statement takes the form: - -```sql -EXEC SQL ; -``` - -Where `sql_command_body` represents a standard SQL statement. You can use a host variable anywhere that the SQL statement expects a value expression. For more information about substituting host variables for value expressions, see [Declaring host variables](/epas/latest/application_programming/ecpgplus_guide/03_using_embedded_sql/#declaring-host-variables). - -ECPGPlus extends the PostgreSQL server-side syntax for some statements. Syntax differences are noted in the reference information that follows. For a complete reference to the supported syntax of other SQL commands, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-commands.html). - -## ALLOCATE DESCRIPTOR - -Use the `ALLOCATE DESCRIPTOR` statement to allocate an SQL descriptor area: - -```sql -EXEC SQL [FOR ] ALLOCATE DESCRIPTOR - [WITH MAX ]; -``` - -Where: - -- `array_size` is a variable that specifies the number of array elements to allocate for the descriptor. `array_size` can be an `INTEGER` value or a host variable. -- `descriptor_name` is the host variable that contains the name of the descriptor or the name of the descriptor. This value can take the form of an identifier, a quoted string literal, or of a host variable. -- `variable_count` specifies the maximum number of host variables in the descriptor. The default value of `variable_count` is `100`. - -The following code fragment allocates a descriptor named `emp_query` that can be processed as an array `(emp_array)`: - -```sql -EXEC SQL FOR :emp_array ALLOCATE DESCRIPTOR emp_query; -``` - -## CALL - -Use the `CALL` statement to invoke a procedure or function on the server. The `CALL` statement works only on EDB Postgres Advanced Server. The `CALL` statement comes in two forms. The first form is used to call a function: - -```sql -EXEC SQL CALL '('[]')' - INTO [[:][: ]]; -``` - -The second form is used to call a procedure: - -```sql -EXEC SQL CALL '('[]')'; -``` - -Where: - -- `program_name` is the name of the stored procedure or function that the `CALL` statement invokes. The program name can be schema qualified, package qualified, or both. If you don't specify the schema or package in which the program resides, ECPGPlus uses the value of `search_path` to locate the program. -- `actual_arguments` specifies a comma-separated list of arguments required by the program. Each `actual_argument` corresponds to a formal argument expected by the program. Each formal argument can be an `IN` parameter, an `OUT` parameter, or an `INOUT` parameter. -- `:ret_variable` specifies a host variable that receives the value returned if the program is a function. -- `:ret_indicator` specifies a host variable that receives the indicator value returned if the program is a function. - -For example, the following statement invokes the `get_job_desc` function with the value contained in the `:ename` host variable and captures the value returned by that function in the `:job` host variable: - -```sql -EXEC SQL CALL get_job_desc(:ename) - INTO :job; -``` - -## CLOSE - -Use the `CLOSE` statement to close a cursor and free any resources currently in use by the cursor. A client application can't fetch rows from a closed cursor. The syntax of the `CLOSE` statement is: - -```sql -EXEC SQL CLOSE []; -``` - -Where `cursor_name` is the name of the cursor closed by the statement. The cursor name can take the form of an identifier or of a host variable. - -The `OPEN` statement initializes a cursor. Once initialized, a cursor result set remains unchanged unless the cursor is reopened. You don't need to `CLOSE` a cursor before reopening it. - -To manually close a cursor named `emp_cursor`, use the command: - -```sql -EXEC SQL CLOSE emp_cursor; -``` - -A cursor is automatically closed when an application terminates. - -## COMMIT - -Use the `COMMIT` statement to complete the current transaction, making all changes permanent and visible to other users. The syntax is: - -```sql -EXEC SQL [AT ] COMMIT [WORK] - [COMMENT <'text'>] [COMMENT <'text'> RELEASE]; -``` - -Where `database_name` is the name of the database or host variable that contains the name of the database in which the work resides. This value can take the form of an unquoted string literal or of a host variable. - -For compatibility, ECPGPlus accepts the `COMMENT` clause without error but doesn't store any text included with the `COMMENT` clause. - -Include the `RELEASE` clause to close the current connection after performing the commit. - -For example, the following command commits all work performed on the `dept` database and closes the current connection: - -```sql -EXEC SQL AT dept COMMIT RELEASE; -``` - -By default, statements are committed only when a client application performs a `COMMIT` statement. Include the `-t` option when invoking ECPGPlus to specify for a client application to invoke `AUTOCOMMIT` functionality. You can also control `AUTOCOMMIT` functionality in a client application with the following statements: - -```sql -EXEC SQL SET AUTOCOMMIT TO ON -``` - -and - -```sql -EXEC SQL SET AUTOCOMMIT TO OFF -``` - -## CONNECT - -Use the `CONNECT` statement to establish a connection to a database. The `CONNECT` statement is available in two forms. One form is compatible with Oracle databases, and the other is not. - -The first form is compatible with Oracle databases: - -```sql -EXEC SQL CONNECT - {{: IDENTIFIED BY :} | :} - [AT ] - [USING :database_string] - [ALTER AUTHORIZATION :new_password]; -``` - -Where: - -- `user_name` is a host variable that contains the role that the client application uses to connect to the server. -- `password` is a host variable that contains the password associated with that role. -- `connection_id` is a host variable that contains a slash-delimited user name and password used to connect to the database. - -Include the `AT` clause to specify the database to which the connection is established. `database_name` is the name of the database to which the client is connecting. Specify the value in the form of a variable or as a string literal. - -Include the `USING` clause to specify a host variable that contains a null-terminated string identifying the database to which to establish the connection. - -The `ALTER AUTHORIZATION` clause is supported for syntax compatibility only. ECPGPlus parses the `ALTER AUTHORIZATION` clause and reports a warning. - -Using the first form of the `CONNECT` statement, a client application might establish a connection with a host variable named `user` that contains the identity of the connecting role and a host variable named `password` that contains the associated password using the following command: - -```text -EXEC SQL CONNECT :user IDENTIFIED BY :password; -``` - -A client application can also use the first form of the `CONNECT` statement to establish a connection using a single host variable named `:connection_id`. In the following example, `connection_id` contains the slash-delimited role name and associated password for the user: - -```sql -EXEC SQL CONNECT :connection_id; -``` - -The syntax of the second form of the `CONNECT` statement is: - -```sql -EXEC SQL CONNECT TO -[AS ] []; -``` - -Where `credentials` is one of the following: - -```sql -USER user_name password -USER user_name IDENTIFIED BY password -USER user_name USING password -``` - -In the second form: - -`database_name` is the name or identity of the database to which the client is connecting. Specify `database_name` as a variable or as a string literal in one of the following forms: - -```text -[@][:] - -tcp:postgresql://[:][/][options] - -unix:postgresql://[:][/][options] -``` - -Where: - -- `hostname` is the name or IP address of the server on which the database resides. -- `port` is the port on which the server listens. - - You can also specify a value of `DEFAULT` to establish a connection with the default database, using the default role name. If you specify `DEFAULT` as the target database, don't include a `connection_name` or `credentials`. - -- `connection_name` is the name of the connection to the database. `connection_name` takes the form of an identifier (that is, not a string literal or a variable). You can open multiple connections by providing a unique `connection_name` for each connection. - - If you don't specify a name for a connection, `ecpglib` assigns a name of `DEFAULT` to the connection. You can refer to the connection by name (`DEFAULT`) in any `EXEC SQL` statement. - -- `CURRENT` is the most recently opened or the connection mentioned in the most-recent `SET CONNECTION TO` statement. If you don't refer to a connection by name in an `EXEC SQL` statement, ECPG assumes the name of the connection to be `CURRENT`. - -- `user_name` is the role used to establish the connection with the EDB Postgres Advanced Server database. The privileges of the specified role are applied to all commands performed through the connection. - -- `password` is the password associated with the specified `user_name`. - -The following code fragment uses the second form of the `CONNECT` statement to establish a connection to a database named `edb` using the role `alice` and the password associated with that role, `1safepwd`: - -```sql -EXEC SQL CONNECT TO edb AS acctg_conn - USER 'alice' IDENTIFIED BY '1safepwd'; -``` - -The name of the connection is `acctg_conn`. You can use the connection name when changing the connection name using the `SET CONNECTION` statement. - -## DEALLOCATE DESCRIPTOR - -Use the `DEALLOCATE DESCRIPTOR` statement to free memory in use by an allocated descriptor. The syntax of the statement is: - -```sql -EXEC SQL DEALLOCATE DESCRIPTOR -``` - -Where `descriptor_name` is the name of the descriptor. This value can take the form of a quoted string literal or of a host variable. - -The following example deallocates a descriptor named `emp_query`: - -```sql -EXEC SQL DEALLOCATE DESCRIPTOR emp_query; -``` - -## DECLARE CURSOR - -Use the `DECLARE CURSOR` statement to define a cursor. The syntax of the statement is: - -```sql -EXEC SQL [AT ] DECLARE CURSOR FOR -( | ); -``` - -Where: - -- `database_name` is the name of the database on which the cursor operates. This value can take the form of an identifier or of a host variable. If you don't specify a database name, the default value of `database_name` is the default database. -- `cursor_name` is the name of the cursor. -- `select_statement` is the text of the `SELECT` statement that defines the cursor result set. The `SELECT` statement can't contain an `INTO` clause. -- `statement_name` is the name of a SQL statement or block that defines the cursor result set. - -The following example declares a cursor named `employees`: - -```sql -EXEC SQL DECLARE employees CURSOR FOR - SELECT - empno, ename, sal, comm - FROM - emp; -``` - -The cursor generates a result set that contains the employee number, employee name, salary, and commission for each employee record that's stored in the `emp` table. - -## DECLARE DATABASE - -Use the `DECLARE DATABASE` statement to declare a database identifier for use in subsequent SQL statements (for example, in a `CONNECT` statement). The syntax is: - -```sql -EXEC SQL DECLARE DATABASE; -``` - -Where `database_name` specifies the name of the database. - -The following example shows declaring an identifier for the `acctg` database: - -```sql -EXEC SQL DECLARE acctg DATABASE; -``` - -After invoking the command declaring `acctg` as a database identifier, you can reference the `acctg` database by name when establishing a connection or in `AT` clauses. - -This statement has no effect and is provided for Pro\*C compatibility only. - -## DECLARE STATEMENT - -Use the `DECLARE STATEMENT` directive to declare an identifier for an SQL statement. EDB Postgres Advanced Server supports two versions of the `DECLARE STATEMENT` directive: - -```sql -EXEC SQL [] DECLARE STATEMENT; -``` - -and - -```sql -EXEC SQL DECLARE STATEMENT ; -``` - -Where: - -- `statement_name` specifies the identifier associated with the statement. -- `database_name` specifies the name of the database. This value may take the form of an identifier or of a host variable that contains the identifier. - -A typical usage sequence that includes the `DECLARE STATEMENT` directive is: - -```sql -EXEC SQL DECLARE give_raise STATEMENT; // give_raise is now a statement -handle (not prepared) -EXEC SQL PREPARE give_raise FROM :stmtText; // give_raise is now associated -with a statement -EXEC SQL EXECUTE give_raise; -``` - -This statement has no effect and is provided for Pro\*C compatibility only. - -## DELETE - -Use the `DELETE` statement to delete one or more rows from a table. The syntax for the ECPGPlus `DELETE` statement is the same as the syntax for the SQL statement, but you can use parameter markers and host variables any place that an expression is allowed. The syntax is: - -```sql -[FOR ] DELETE FROM [ONLY]
[[AS] ] - [USING ] - [WHERE | WHERE CURRENT OF ] - [{RETURNING|RETURN} * | [[AS] ] -[, ...] INTO ] -``` - -- Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `VALUES` clause references an array or a pointer to an array. -- `table` is the name (optionally schema qualified) of an existing table. Include the `ONLY` clause to limit processing to the specified table. If you don't include the `ONLY` clause, any tables inheriting from the named table are also processed. -- `alias` is a substitute name for the target table. -- `using_list` is a list of table expressions, allowing columns from other tables to appear in the `WHERE` condition. -- Include the `WHERE` clause to specify the rows to delete. If you don't include a `WHERE` clause in the statement, `DELETE` deletes all rows from the table, leaving the table definition intact. -- `condition` is an expression, host variable, or parameter marker that returns a value of type `BOOLEAN`. Those rows for which `condition` returns true are deleted. -- `cursor_name` is the name of the cursor to use in the `WHERE CURRENT OF` clause. The row to be deleted is the one most recently fetched from this cursor. The cursor must be a nongrouping query on the `DELETE` statements target table. You can't specify `WHERE CURRENT OF` in a `DELETE` statement that includes a Boolean condition. - -The `RETURN/RETURNING` clause specifies an `output_expression` or `host_variable_list` that's returned by the `DELETE` command after each row is deleted: - - - `output_expression` is an expression to be computed and returned by the `DELETE` command after each row is deleted. `output_name` is the name of the returned column. Include \* to return all columns. - - `host_variable_list` is a comma-separated list of host variables and optional indicator variables. Each host variable receives a corresponding value from the `RETURNING` clause. - -For example, the following statement deletes all rows from the `emp` table, where the `sal` column contains a value greater than the value specified in the host variable, `:max_sal:` - -```sql -DELETE FROM emp WHERE sal > :max_sal; -``` - -For more information about using the `DELETE` statement, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-delete.html). - -## DESCRIBE - -Use the `DESCRIBE` statement to find the number of input values required by a prepared statement or the number of output values returned by a prepared statement. The `DESCRIBE` statement is used to analyze a SQL statement whose shape is unknown at the time you write your application. - -The `DESCRIBE` statement populates an `SQLDA` descriptor. To populate a SQL descriptor, use the `ALLOCATE DESCRIPTOR` and `DESCRIBE...DESCRIPTOR` statements. - -```sql -EXEC SQL DESCRIBE BIND VARIABLES FOR INTO ; -``` - - -```sql -EXEC SQL DESCRIBE SELECT LIST FOR INTO ; -``` - -Where: - -- `statement_name` is the identifier associated with a prepared SQL statement or PL/SQL block. -- `descriptor` is the name of C variable of type `SQLDA*`. You must allocate the space for the descriptor by calling `sqlald()` and initialize the descriptor before executing the `DESCRIBE` statement. - -When you execute the first form of the `DESCRIBE` statement, ECPG populates the given descriptor with a description of each input variable *required* by the statement. For example, given two descriptors: - -```sql -SQLDA *query_values_in; -SQLDA *query_values_out; -``` - -You might prepare a query that returns information from the `emp` table: - -```sql -EXEC SQL PREPARE get_emp FROM - "SELECT ename, empno, sal FROM emp WHERE empno = ?"; -``` - -The command requires one input variable for the parameter marker (?). - -```sql -EXEC SQL DESCRIBE BIND VARIABLES - FOR get_emp INTO query_values_in; -``` - -After describing the bind variables for this statement, you can examine the descriptor to find the number of variables required and the type of each variable. - -When you execute the second form, ECPG populates the given descriptor with a description of each value returned by the statement. For example, the following statement returns three values: - -```sql -EXEC SQL DESCRIBE SELECT LIST - FOR get_emp INTO query_values_out; -``` - -After describing the select list for this statement, you can examine the descriptor to find the number of returned values and the name and type of each value. - -Before executing the statement, you must bind a variable for each input value and a variable for each output value. The variables that you bind for the input values specify the actual values used by the statement. The variables that you bind for the output values tell ECPGPlus where to put the values when you execute the statement. - -This is alternative Pro\*C-compatible syntax for the `DESCRIBE DESCRIPTOR` statement. - -## DESCRIBE DESCRIPTOR - -Use the `DESCRIBE DESCRIPTOR` statement to retrieve information about a SQL statement and store that information in a SQL descriptor. Before using `DESCRIBE DESCRIPTOR`, you must allocate the descriptor with the `ALLOCATE DESCRIPTOR` statement. The syntax is: - -```sql -EXEC SQL DESCRIBE [INPUT | OUTPUT] - USING [SQL] DESCRIPTOR ; -``` - -Where: - -- `statement_name` is the name of a prepared SQL statement. -- `descriptor_name` is the name of the descriptor. `descriptor_name` can be a quoted string value or a host variable that contains the name of the descriptor. - -If you include the `INPUT` clause, ECPGPlus populates the given descriptor with a description of each input variable required by the statement. - -For example, given two descriptors: - -```sql -EXEC SQL ALLOCATE DESCRIPTOR query_values_in; -EXEC SQL ALLOCATE DESCRIPTOR query_values_out; -``` - -You might prepare a query that returns information from the `emp` table: - -```sql -EXEC SQL PREPARE get_emp FROM - "SELECT ename, empno, sal FROM emp WHERE empno = ?"; -``` - -The command requires one input variable for the parameter marker (?). - -```sql -EXEC SQL DESCRIBE INPUT get_emp USING 'query_values_in'; -``` - -After describing the bind variables for this statement, you can examine the descriptor to find the number of variables required and the type of each variable. - -If you don't specify the `INPUT` clause, `DESCRIBE DESCRIPTOR` populates the specified descriptor with the values returned by the statement. - -If you include the `OUTPUT` clause, ECPGPlus populates the given descriptor with a description of each value returned by the statement. - -For example, the following statement returns three values: - -```sql -EXEC SQL DESCRIBE OUTPUT FOR get_emp USING 'query_values_out'; -``` - -After describing the select list for this statement, you can examine the descriptor to find the number of returned values and the name and type of each value. - -## DISCONNECT - -Use the `DISCONNECT` statement to close the connection to the server. The syntax is: - -```sql -EXEC SQL DISCONNECT [][CURRENT][DEFAULT][ALL]; -``` - -Where `connection_name` is the connection name specified in the `CONNECT` statement used to establish the connection. If you don't specify a connection name, the current connection is closed. - -Include the `CURRENT` keyword to specify for ECPGPlus to close the connection used most recently. - -Include the `DEFAULT` keyword to specify for ECPGPlus to close the connection named `DEFAULT`. If you don't specify a name when opening a connection, ECPGPlus assigns the name `DEFAULT` to the connection. - -Include the `ALL` keyword to close all active connections. - -The following example creates a connection named `hr_connection` that connects to the `hr` database and then disconnects from the connection: - -```c -/* client.pgc*/ -int main() -{ - EXEC SQL CONNECT TO hr AS connection_name; - EXEC SQL DISCONNECT connection_name; - return(0); -} -``` - -## EXECUTE - -Use the `EXECUTE` statement to execute a statement previously prepared using an `EXEC SQL PREPARE` statement. The syntax is: - -```sql -EXEC SQL [FOR ] EXECUTE - [USING {DESCRIPTOR - |: [[INDICATOR] :]}]; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `statement_name` specifies the name assigned to the statement when the statement was created using the `EXEC SQL PREPARE` statement. - -Include the `USING` clause to supply values for parameters in the prepared statement: - -- Include the `DESCRIPTOR` `SQLDA_descriptor` clause to provide an SQLDA descriptor value for a parameter. -- Use a `host_variable` (and an optional `indicator_variable`) to provide a user-specified value for a parameter. - -The following example creates a prepared statement that inserts a record into the `emp` table: - -```sql -EXEC SQL PREPARE add_emp (numeric, text, text, numeric) AS - INSERT INTO emp VALUES($1, $2, $3, $4); -``` - -Each time you invoke the prepared statement, provide fresh parameter values for the statement: - -```sql -EXEC SQL EXECUTE add_emp USING 8000, 'DAWSON', 'CLERK', 7788; -EXEC SQL EXECUTE add_emp USING 8001, 'EDWARDS', 'ANALYST', 7698; -``` - -## EXECUTE DESCRIPTOR - -Use the `EXECUTE` statement to execute a statement previously prepared by an `EXEC SQL PREPARE` statement, using an SQL descriptor. The syntax is: - -```sql -EXEC SQL [FOR ] EXECUTE - [USING [SQL] DESCRIPTOR ] - [INTO [SQL] DESCRIPTOR ]; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `statement_identifier` specifies the identifier assigned to the statement with the `EXEC SQL PREPARE` statement. -- `descriptor_name` specifies the name of a descriptor (as a single-quoted string literal), or a host variable that contains the name of a descriptor. - -Include the `USING` clause to specify values for any input parameters required by the prepared statement. - -Include the `INTO` clause to specify a descriptor into which the `EXECUTE` statement writes the results returned by the prepared statement. - -The following example executes the prepared statement, `give_raise`, using the values contained in the descriptor `stmtText:` - -```sql -EXEC SQL PREPARE give_raise FROM :stmtText; -EXEC SQL EXECUTE give_raise USING DESCRIPTOR :stmtText; -``` - -## EXECUTE...END EXEC - -Use the `EXECUTE…END-EXEC` statement to embed an anonymous block into a client application. The syntax is: - -```sql -EXEC SQL [AT ] EXECUTE END-EXEC; -``` - -Where: - -- `database_name` is the database identifier or a host variable that contains the database identifier. If you omit the `AT` clause, the statement executes on the current default database. -- `anonymous_block` is an inline sequence of PL/pgSQL or SPL statements and declarations. You can include host variables and optional indicator variables in the block. Each such variable is treated as an `IN/OUT` value. - -The following example executes an anonymous block: - -```sql -EXEC SQL EXECUTE - BEGIN - IF (current_user = :admin_user_name) THEN - DBMS_OUTPUT.PUT_LINE('You are an administrator'); - END IF; -END-EXEC; -``` - -!!! Note - The `EXECUTE…END EXEC` statement is supported only by EDB Postgres Advanced Server. - -## EXECUTE IMMEDIATE - -Use the `EXECUTE IMMEDIATE` statement to execute a string that contains a SQL command. The syntax is: - -```sql -EXEC SQL [AT ] EXECUTE IMMEDIATE ; -``` - -Where: - -- `database_name` is the database identifier or a host variable that contains the database identifier. If you omit the `AT` clause, the statement executes on the current default database. -- `command_text` is the command executed by the `EXECUTE IMMEDIATE` statement. - -This dynamic SQL statement is useful when you don't know the text of an SQL statement when writing a client application. For example, a client application might prompt a trusted user for a statement to execute. After the user provides the text of the statement as a string value, the statement is then executed with an `EXECUTE IMMEDIATE` command. - -The statement text can't contain references to host variables. If the statement might contain parameter markers or returns one or more values, use the `PREPARE` and `DESCRIBE` statements. - -The following example executes the command contained in the `:command_text` host variable: - -```sql -EXEC SQL EXECUTE IMMEDIATE :command_text; -``` - -## FETCH - -Use the `FETCH` statement to return rows from a cursor into an SQLDA descriptor or a target list of host variables. Before using a `FETCH` statement to retrieve information from a cursor, you must prepare the cursor using `DECLARE` and `OPEN` statements. The statement syntax is: - -```sql -EXEC SQL [FOR ] FETCH - { USING DESCRIPTOR }|{ INTO }; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `cursor` is the name of the cursor from which rows are being fetched or a host variable that contains the name of the cursor. - -If you include a `USING` clause, the `FETCH` statement populates the specified SQLDA descriptor with the values returned by the server. - -If you include an `INTO` clause, the `FETCH` statement populates the host variables (and optional indicator variables) specified in the `target_list`. - -The following code fragment declares a cursor named `employees` that retrieves the `employee number`, `name`, and `salary` from the `emp` table: - -```sql -EXEC SQL DECLARE employees CURSOR FOR - SELECT empno, ename, esal FROM emp; -EXEC SQL OPEN emp_cursor; -EXEC SQL FETCH emp_cursor INTO :emp_no, :emp_name, :emp_sal; -``` - -## FETCH DESCRIPTOR - -Use the `FETCH DESCRIPTOR` statement to retrieve rows from a cursor into an SQL descriptor. The syntax is: - -```sql -EXEC SQL [FOR ] FETCH - INTO [SQL] DESCRIPTOR ; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `cursor` is the name of the cursor from which rows are fetched or a host variable that contains the name of the cursor. The client must `DECLARE` and `OPEN` the cursor before calling the `FETCH DESCRIPTOR` statement. -- `descriptor_name` specifies the name of a descriptor (as a single-quoted string literal) or a host variable that contains the name of a descriptor. Prior to use, the descriptor must be allocated using an `ALLOCATE DESCRIPTOR` statement. - -Include the `INTO` clause to specify a SQL descriptor into which the `EXECUTE` statement writes the results returned by the prepared statement. - -The following example allocates a descriptor named `row_desc` that holds the description and the values of a specific row in the result set. It then declares and opens a cursor for a prepared statement (`my_cursor`), before looping through the rows in result set, using a `FETCH` to retrieve the next row from the cursor into the descriptor: - -```sql -EXEC SQL ALLOCATE DESCRIPTOR 'row_desc'; -EXEC SQL DECLARE my_cursor CURSOR FOR query; -EXEC SQL OPEN my_cursor; - -for( row = 0; ; row++ ) -{ - EXEC SQL BEGIN DECLARE SECTION; - int col; -EXEC SQL END DECLARE SECTION; -EXEC SQL FETCH my_cursor INTO SQL DESCRIPTOR 'row_desc'; -``` - -## GET DESCRIPTOR - -Use the `GET DESCRIPTOR` statement to retrieve information from a descriptor. The `GET DESCRIPTOR` statement comes in two forms. The first form returns the number of values (or columns) in the descriptor. - -```sql -EXEC SQL GET DESCRIPTOR - : = COUNT; -``` - -The second form returns information about a specific value (specified by the `VALUE column_number` clause): - -```sql -EXEC SQL [FOR ] GET DESCRIPTOR - VALUE {: = {,…}}; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value that specifies the number of rows to process. If you specify an `array_size`, the `host_variable` must be an array of that size. For example, if `array_size` is `10`, `:host_variable` must be a 10-member array of `host_variables`. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `descriptor_name` specifies the name of a descriptor as a single-quoted string literal or a host variable that contains the name of a descriptor. - -Include the `VALUE` clause to specify the information retrieved from the descriptor. - -- `column_number` identifies the position of the variable in the descriptor. -- `host_variable` specifies the name of the host variable that receives the value of the item. -- `descriptor_item` specifies the type of the retrieved descriptor item. - -ECPGPlus implements the following `descriptor_item` types: - -- `TYPE` -- `LENGTH` -- `OCTET_LENGTH` -- `RETURNED_LENGTH` -- `RETURNED_OCTET_LENGTH` -- `PRECISION` -- `SCALE` -- `NULLABLE` -- `INDICATOR` -- `DATA` -- `NAME` - -The following code fragment shows using a `GET DESCRIPTOR` statement to obtain the number of columns entered in a user-provided string: - -```sql -EXEC SQL ALLOCATE DESCRIPTOR parse_desc; -EXEC SQL PREPARE query FROM :stmt; -EXEC SQL DESCRIBE query INTO SQL DESCRIPTOR parse_desc; -EXEC SQL GET DESCRIPTOR parse_desc :col_count = COUNT; -``` - -The example allocates an SQL descriptor named `parse_desc` before using a `PREPARE` statement to check the syntax of the string provided by the user `:stmt`. A `DESCRIBE` statement moves the user-provided string into the descriptor, `parse_desc`. The call to `EXEC SQL GET DESCRIPTOR` interrogates the descriptor to discover the number of columns `(:col_count)` in the result set. - -## INSERT - -Use the `INSERT` statement to add one or more rows to a table. The syntax for the ECPGPlus `INSERT` statement is the same as the syntax for the SQL statement, but you can use parameter markers and host variables any place that a value is allowed. The syntax is: - -```sql -[FOR ] INSERT INTO
[( [, ...])] - {DEFAULT VALUES | - VALUES ({ | DEFAULT} [, ...])[, ...] | } - [RETURNING * | [[ AS ] ] [, ...]] -``` - -Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `VALUES` clause references an array or a pointer to an array. - -- `table` specifies the (optionally schema-qualified) name of an existing table. -- `column` is the name of a column in the table. The column name can be qualified with a subfield name or array subscript. Specify the `DEFAULT VALUES` clause to use default values for all columns. -- `expression` is the expression, value, host variable, or parameter marker that's assigned to the corresponding column. Specify `DEFAULT` to fill the corresponding column with its default value. -- `query` specifies a `SELECT` statement that supplies the rows to insert. -- `output_expression` is an expression that's computed and returned by the `INSERT` command after each row is inserted. The expression can refer to any column in the table. Specify \* to return all columns of the inserted rows. -- `output_name` specifies a name to use for a returned column. - -The following example adds a row to the `employees` table: - -```sql -INSERT INTO emp (empno, ename, job, hiredate) - VALUES ('8400', :ename, 'CLERK', '2011-10-31'); -``` - -!!! Note - The `INSERT` statement uses a host variable `:ename` to specify the value of the `ename` column. - -For more information about using the `INSERT` statement, see the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-insert.html). - -## OPEN - -Use the `OPEN` statement to open a cursor. The syntax is: - -```sql -EXEC SQL [FOR ] OPEN [USING ]; -``` - -`parameters` is one of the following: - -```sql -DESCRIPTOR -``` - -or - -```sql - [ [ INDICATOR ] , … ] -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `cursor` is the name of the cursor being opened. -- `parameters` is either `DESCRIPTOR SQLDA_descriptor` or a comma-separated list of `host variables` and optional `indicator variables` that initialize the cursor. If specifying an `SQLDA_descriptor`, the descriptor must be initialized with a `DESCRIBE` statement. - -The `OPEN` statement initializes a cursor using the values provided in `parameters`. Once initialized, the cursor result set remains unchanged unless the cursor is closed and reopened. A cursor is automatically closed when an application terminates. - -The following example declares a cursor named `employees` that queries the `emp` table. It returns the `employee number`, `name`, `salary`, and `commission` of an employee whose name matches a user-supplied value stored in the host variable `:emp_name`. - -```sql -EXEC SQL DECLARE employees CURSOR FOR - SELECT - empno, ename, sal, comm  - FROM  - emp - WHERE ename = :emp_name; -EXEC SQL OPEN employees; -... -``` - -After declaring the cursor, the example uses an `OPEN` statement to make the contents of the cursor available to a client application. - -## OPEN DESCRIPTOR - -Use the `OPEN DESCRIPTOR` statement to open a cursor with a SQL descriptor. The syntax is: - -```sql -EXEC SQL [FOR ] OPEN - [USING [SQL] DESCRIPTOR ] - [INTO [SQL] DESCRIPTOR ]; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement is executed once for each member of the array. -- `cursor` is the name of the cursor being opened. -- `descriptor_name` specifies the name of an SQL descriptor in the form of a single-quoted string literal or a host variable that contains the name of an SQL descriptor that contains the query that initializes the cursor. - -For example, the following statement opens a cursor named `emp_cursor` using the host variable `:employees`: - -```sql -EXEC SQL OPEN emp_cursor USING DESCRIPTOR :employees; -``` - -## PREPARE - -Prepared statements are useful when a client application must perform a task multiple times. The statement is parsed, written, and planned only once rather than each time the statement is executed. This approach saves repetitive processing time. - -Use the `PREPARE` statement to prepare a SQL statement or PL/pgSQL block for execution. The statement is available in two forms. The first form is: - -```sql -EXEC SQL [AT ] PREPARE - FROM ; -``` - -The second form is: - -```sql -EXEC SQL [AT ] PREPARE - AS ; -``` - -Where: - -- `database_name` is the database identifier or a host variable that contains the database identifier against which the statement executes. If you omit the `AT` clause, the statement executes against the current default database. -- `statement_name` is the identifier associated with a prepared SQL statement or PL/SQL block. -- `sql_statement` can take the form of a `SELECT` statement, a single-quoted string literal, or a host variable that contains the text of an SQL statement. - -To include variables in a prepared statement, substitute placeholders (`$1, $2, $3`, and so on) for statement values that might change when you `PREPARE` the statement. When you `EXECUTE` the statement, provide a value for each parameter. Provide the values in the order in which they replace placeholders. - -The following example creates a prepared statement named `add_emp` that inserts a record into the `emp` table: - -```sql -EXEC SQL PREPARE add_emp (int, text, text, numeric) AS - INSERT INTO emp VALUES($1, $2, $3, $4); -``` - -Each time you invoke the statement, provide fresh parameter values for the statement: - -```sql -EXEC SQL EXECUTE add_emp(8003, 'Davis', 'CLERK', 2000.00); -EXEC SQL EXECUTE add_emp(8004, 'Myer', 'CLERK', 2000.00); -``` - -!!! Note - A client application must issue a `PREPARE` statement in each session in which a statement executes. Prepared statements persist only for the duration of the current session. - -## ROLLBACK - -Use the `ROLLBACK` statement to abort the current transaction and discard any updates made by the transaction. The syntax is: - -```sql -EXEC SQL [AT ] ROLLBACK [WORK] - [ { TO [SAVEPOINT] } | RELEASE ] -``` - -Where `database_name` is the database identifier or a host variable that contains the database identifier against which the statement executes. If you omit the `AT` clause, the statement executes against the current default database. - -Include the `TO` clause to abort any commands that executed after the specified `savepoint`. Use the `SAVEPOINT` statement to define the `savepoint`. If you omit the `TO` clause, the `ROLLBACK` statement aborts the transaction, discarding all updates. - -Include the `RELEASE` clause to cause the application to execute an `EXEC SQL COMMIT RELEASE` and close the connection. - -Use the following statement to roll back a complete transaction: - -```sql -EXEC SQL ROLLBACK; -``` - -Invoking this statement aborts the transaction, undoing all changes, erasing any savepoints, and releasing all transaction locks. Suppose you include a savepoint (`my_savepoint` in the following example): - -```sql -EXEC SQL ROLLBACK TO SAVEPOINT my_savepoint; -``` - -Only the portion of the transaction that occurred after the `my_savepoint` is rolled back. `my_savepoint` is retained, but any savepoints created after `my_savepoint` are erased. - -Rolling back to a specified savepoint releases all locks acquired after the savepoint. - -## SAVEPOINT - -Use the `SAVEPOINT` statement to define a *savepoint*. A savepoint is a marker in a transaction. You can use a `ROLLBACK` statement to abort the current transaction, returning the state of the server to its condition prior to the specified savepoint. The syntax of a `SAVEPOINT` statement is: - -```sql -EXEC SQL [AT ] SAVEPOINT -``` - -Where: - -- `database_name` is the database identifier or a host variable that contains the database identifier against which the savepoint resides. If you omit the `AT` clause, the statement executes against the current default database. -- `savepoint_name` is the name of the savepoint. If you reuse a `savepoint_name`, the original savepoint is discarded. - -You can establish savepoints only in a transaction block. A transaction block can contain multiple savepoints. - -To create a savepoint named `my_savepoint`, include the statement: - -```sql -EXEC SQL SAVEPOINT my_savepoint; -``` - -## SELECT - -ECPGPlus extends support of the `SQL SELECT` statement by providing the `INTO host_variables` clause. The clause allows you to select specified information from an EDB Postgres Advanced Server database into a host variable. The syntax for the `SELECT` statement is: - -```sql -EXEC SQL [AT ] -SELECT - [ ] - [ ALL | DISTINCT [ ON( , ...) ]] - select_list INTO - - [ FROM from_item [, from_item ]...] - [ WHERE condition ] - [ hierarchical_query_clause ] - [ GROUP BY expression [, ...]] - [ HAVING condition ] - [ { UNION [ ALL ] | INTERSECT | MINUS } (subquery) ] - [ ORDER BY expression [order_by_options]] - [ LIMIT { count | ALL }] - [ OFFSET start [ ROW | ROWS ] ] - [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ] - [ FOR { UPDATE | SHARE } [OF table_name [, ...]][NOWAIT ][...]] -``` - -Where: - -- `database_name` is the name of the database or host variable that contains the name of the database in which the table resides. This value can take the form of an unquoted string literal or of a host variable. -- `host_variables` is a list of host variables populated by the `SELECT` statement. If the `SELECT` statement returns more than a single row, `host_variables` must be an array. - -ECPGPlus provides support for the additional clauses of the SQL `SELECT` statement as documented in the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-select.html). - -To use the `INTO host_variables` clause, include the names of defined host variables when specifying the `SELECT` statement. For example, the following `SELECT` statement populates the `:emp_name` and `:emp_sal` host variables with a list of employee names and salaries: - -```sql -EXEC SQL SELECT ename, sal - INTO :emp_name, :emp_sal - FROM emp - WHERE empno = 7988; -``` - -The enhanced `SELECT` statement also allows you to include parameter markers (question marks) in any clause where a value is allowed. For example, the following query contains a parameter marker in the `WHERE` clause: - -```sql -SELECT * FROM emp WHERE dept_no = ?; -``` - -This `SELECT` statement allows you to provide a value at runtime for the `dept_no` parameter marker. - -## SET CONNECTION - -There are at least three reasons you might need more than one connection in a given client application: - -- You might want different privileges for different statements. -- You might need to interact with multiple databases in the same client. -- Multiple threads of execution in a client application can't share a connection concurrently. - -The syntax for the `SET CONNECTION` statement is: - -```sql -EXEC SQL SET CONNECTION ; -``` - -Where `connection_name` is the name of the connection to the database. - -To use the `SET CONNECTION` statement, open the connection to the database using the second form of the `CONNECT` statement. Include the `AS` clause to specify a `connection_name`. - -By default, the current thread uses the current connection. Use the `SET CONNECTION` statement to specify a default connection for the current thread to use. The default connection is used only when you execute an `EXEC SQL` statement that doesn't explicitly specify a connection name. For example, the following statement uses the default connection because it doesn't include an `AT connection_name` clause: - -```sql -EXEC SQL DELETE FROM emp; -``` - -This statement doesn't use the default connection because it specifies a connection name using the `AT connection_name` clause: - -```sql -EXEC SQL AT acctg_conn DELETE FROM emp; -``` - -For example, suppose a client application creates and maintains multiple connections using either of the following approaches: - -```sql -EXEC SQL CONNECT TO edb AS acctg_conn - USER 'alice' IDENTIFIED BY 'acctpwd'; -``` - - -```sql -EXEC SQL CONNECT TO edb AS hr_conn - USER 'bob' IDENTIFIED BY 'hrpwd'; -``` - -It can change between the connections with the `SET CONNECTION` statement: - -```sql -SET CONNECTION acctg_conn; -``` - -or - -```sql -SET CONNECTION hr_conn; -``` - -The server uses the privileges associated with the connection when determining the privileges available to the connecting client. When using the `acctg_conn` connection, the client has the privileges associated with the role `alice`. When connected using `hr_conn`, the client has the privileges associated with `bob`. - -## SET DESCRIPTOR - -Use the `SET DESCRIPTOR` statement to assign a value to a descriptor area using information provided by the client application in the form of a host variable or an integer value. The statement comes in two forms. The first form is: - -```sql -EXEC SQL [FOR ] SET DESCRIPTOR - VALUE = ; -``` - -The second form is: - -```sql -EXEC SQL [FOR ] SET DESCRIPTOR - COUNT = integer; -``` - -Where: - -- `array_size` is an integer value or a host variable that contains an integer value specifying the number of rows to fetch. If you omit the `FOR` clause, the statement executes once for each member of the array. -- `descriptor_name` specifies the name of a descriptor as a single-quoted string literal or a host variable that contains the name of a descriptor. - -Include the `VALUE` clause to describe the information stored in the descriptor. - -- `column_number` identifies the position of the variable within the descriptor. -- `descriptor_item` specifies the type of the descriptor item. -- `host_variable` specifies the name of the host variable that contains the value of the item. - -ECPGPlus implements the following `descriptor_item` types: - -- `TYPE` -- `LENGTH` -- `[REF] INDICATOR` -- `[REF] DATA` -- `[REF] RETURNED LENGTH` - -For example, a client application might prompt a user for a dynamically created query: - -```c -query_text = promptUser("Enter a query"); -``` - -To execute a dynamically created query, you must first prepare the query (parsing and validating the syntax of the query) and then describe the input parameters found in the query using the `EXEC SQL DESCRIBE INPUT` statement. - -```sql -EXEC SQL ALLOCATE DESCRIPTOR query_params; -EXEC SQL PREPARE emp_query FROM :query_text; - -EXEC SQL DESCRIBE INPUT emp_query - USING SQL DESCRIPTOR 'query_params'; -``` - -After describing the query, the `query_params` descriptor contains information about each parameter required by the query. - -For this example, assume that the user entered: - -```sql -SELECT ename FROM emp WHERE sal > ? AND job = ?;, -``` - -In this case, the descriptor describes two parameters, one for `sal > ?` and one for `job = ?`. - -To discover the number of parameter markers (question marks) in the query and therefore the number of values you must provide before executing the query, use: - -```sql -EXEC SQL GET DESCRIPTOR … :host_variable = COUNT; -``` - -Then, you can use `EXEC SQL GET DESCRIPTOR` to retrieve the name of each parameter. You can also use `EXEC SQL GET DESCRIPTOR` to retrieve the type of each parameter from the descriptor, along with the number of parameters. Or you can supply each `value` in the form of a character string and ECPG converts that string into the required data type. - -The data type of the first parameter is `numeric`. The type of the second parameter is `varchar`. The name of the first parameter is `sal`. The name of the second parameter is `job`. - -Next, loop through each parameter, prompting the user for a value, and store those values in host variables. You can use `GET DESCRIPTOR … COUNT` to find the number of parameters in the query. - -```sql -EXEC SQL GET DESCRIPTOR 'query_params' - :param_count = COUNT; - -for(param_number = 1; - param_number <= param_count; - param_number++) -{ -``` - -Use `GET DESCRIPTOR` to copy the name of the parameter into the `param_name` host variable: - -```sql -EXEC SQL GET DESCRIPTOR 'query_params' - VALUE :param_number :param_name = NAME; - -reply = promptUser(param_name); -if (reply == NULL) - reply_ind = 1; /* NULL */ -else - reply_ind = 0; /* NOT NULL */ -``` - -To associate a `value` with each parameter, you use the `EXEC SQL SET DESCRIPTOR` statement. For example: - -```sql -EXEC SQL SET DESCRIPTOR 'query_params' - VALUE :param_number DATA = :reply; -EXEC SQL SET DESCRIPTOR 'query_params' - VALUE :param_number INDICATOR = :reply_ind; -} -``` - -Now, you can use the `EXEC SQL EXECUTE DESCRIPTOR` statement to execute the prepared statement on the server. - -## UPDATE - -Use an `UPDATE` statement to modify the data stored in a table. The syntax is: - -```sql -EXEC SQL [AT ][FOR ] - UPDATE [ ONLY ] table [ [ AS ] alias ] - SET {column = { expression | DEFAULT } | - (column [, ...]) = ({ expression|DEFAULT } [, ...])} [, ...] - [ FROM from_list ] - [ WHERE condition | WHERE CURRENT OF cursor_name ] - [ RETURNING * | output_expression [[ AS ] output_name] [, ...] ] -``` - -Where `database_name` is the name of the database or host variable that contains the name of the database in which the table resides. This value can take the form of an unquoted string literal or of a host variable. - -Include the `FOR exec_count` clause to specify the number of times the statement executes. This clause is valid only if the `SET` or `WHERE` clause contains an array. - -ECPGPlus provides support for the additional clauses of the SQL `UPDATE` statement as documented in the [PostgreSQL core documentation](https://www.postgresql.org/docs/current/static/sql-update.html). - -You can use a host variable in any clause that specifies a value. To use a host variable, substitute a defined variable for any value associated with any of the documented `UPDATE` clauses. - -The following `UPDATE` statement changes the job description of an employee (identified by the `:ename` host variable) to the value contained in the `:new_job` host variable. It increases the employees salary by multiplying the current salary by the value in the `:increase` host variable: - -```sql -EXEC SQL UPDATE emp - SET job = :new_job, sal = sal * :increase - WHERE ename = :ename; -``` - -The enhanced `UPDATE` statement also allows you to include parameter markers (question marks) in any clause where an input value is permitted. For example, we can write the same update statement with a parameter marker in the `WHERE` clause: - -```sql -EXEC SQL UPDATE emp - SET job = ?, sal = sal * ? - WHERE ename = :ename; -``` - -This `UPDATE` statement allows you to prompt the user for a new value for the `job` column and provide the amount by which the `sal` column is incremented for the employee specified by `:ename`. - -## WHENEVER - -Use the `WHENEVER` statement to specify the action taken by a client application when it encounters an SQL error or warning. The syntax is: - -```sql -EXEC SQL WHENEVER ; -``` - -The following table describes the different conditions that might trigger an `action`. - -| Condition | Description | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| `NOT FOUND` | The server returns a `NOT FOUND` condition when it encounters a `SELECT` that returns no rows or when a `FETCH` reaches the end of a result set. | -| `SQLERROR` | The server returns an `SQLERROR` condition when it encounters a serious error returned by an SQL statement. | -| `SQLWARNING` | The server returns an `SQLWARNING` condition when it encounters a nonfatal warning returned by an SQL statement. | - -The following table describes the actions that result from a client encountering a `condition`. - -| Action | Description | -| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `CALL function [([args])]` | Call the named `function`. | -| `CONTINUE` | Proceed to the next statement. | -| `DO BREAK` | Emit a C break statement. A break statement can appear in a `loop` or a `switch` statement. If executed, the break statement terminates the `loop` or the `switch` statement. | -| `DO CONTINUE` | Emit a C `continue` statement. A `continue` statement can exist only in a loop. If executed, it causes the flow of control to return to the top of the loop. | -| `DO function ([args])` | Call the named `function`. | -| `GOTO label` or `GO TO label` | Proceed to the statement that contains the label. | -| `SQLPRINT` | Print a message to standard error. | -| `STOP` | Stop executing. | - -The following code fragment prints a message if the client application encounters a warning and aborts the application if it encounters an error: - -```sql -EXEC SQL WHENEVER SQLWARNING SQLPRINT; -EXEC SQL WHENEVER SQLERROR STOP; -``` - -Include the following code to specify for a client to continue processing after warning a user of a problem: - -```sql -EXEC SQL WHENEVER SQLWARNING SQLPRINT; -``` - -Include the following code to call a function if a query returns no rows or when a cursor reaches the end of a result set: - -```sql -EXEC SQL WHENEVER NOT FOUND CALL error_handler(__LINE__); -``` diff --git a/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference/ecpgplus_statements.mdx b/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference/ecpgplus_statements.mdx index ec4a5dcb04a..4e1811f9467 100644 --- a/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference/ecpgplus_statements.mdx +++ b/product_docs/docs/epas/16/reference/application_programmer_reference/07_reference/ecpgplus_statements.mdx @@ -66,6 +66,9 @@ legacyRedirectsGenerated: - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.100.html" - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.102.html" - "/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/9.5/EDB_Postgres_Enterprise_Guide.1.101.html" +redirects: + - /epas/latest/ecpgplus_guide/07_reference/ #generated for docs/epas/reorg-role-use-case-mode + - ../../../application_programming/ecpgplus_guide/07_reference/ --- From 08eea79cab26f823f9e41d92a64da573e6aac36d Mon Sep 17 00:00:00 2001 From: Chris Estes <106166814+ccestes@users.noreply.github.com> Date: Thu, 7 Sep 2023 12:58:32 -0400 Subject: [PATCH 09/24] EDB SPL Check content added SPL Check to home page and nav feedback from Suraj further feedback --- advocacy_docs/pg_extensions/index.mdx | 1 + advocacy_docs/pg_extensions/index.mdx.in | 1 + .../pg_extensions/spl_check/configuring.mdx | 233 ++++++++++++++ .../pg_extensions/spl_check/index.mdx | 20 ++ .../spl_check/using/dependency_list.mdx | 29 ++ .../pg_extensions/spl_check/using/index.mdx | 289 ++++++++++++++++++ .../pg_extensions/spl_check/using/pragma.mdx | 71 +++++ .../spl_check/using/profiler.mdx | 117 +++++++ .../pg_extensions/spl_check/using/tracer.mdx | 115 +++++++ src/pages/index.js | 12 +- 10 files changed, 884 insertions(+), 4 deletions(-) create mode 100644 advocacy_docs/pg_extensions/spl_check/configuring.mdx create mode 100644 advocacy_docs/pg_extensions/spl_check/index.mdx create mode 100644 advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx create mode 100644 advocacy_docs/pg_extensions/spl_check/using/index.mdx create mode 100644 advocacy_docs/pg_extensions/spl_check/using/pragma.mdx create mode 100644 advocacy_docs/pg_extensions/spl_check/using/profiler.mdx create mode 100644 advocacy_docs/pg_extensions/spl_check/using/tracer.mdx diff --git a/advocacy_docs/pg_extensions/index.mdx b/advocacy_docs/pg_extensions/index.mdx index 07e91c593bf..2520c1e050d 100644 --- a/advocacy_docs/pg_extensions/index.mdx +++ b/advocacy_docs/pg_extensions/index.mdx @@ -6,6 +6,7 @@ navigation: - advanced_storage_pack - ldap_sync - pg_tuner + - spl_check - query_advisor - wait_states - pg_failover_slots diff --git a/advocacy_docs/pg_extensions/index.mdx.in b/advocacy_docs/pg_extensions/index.mdx.in index 2e17e7f9918..45a6be5fbf5 100644 --- a/advocacy_docs/pg_extensions/index.mdx.in +++ b/advocacy_docs/pg_extensions/index.mdx.in @@ -6,6 +6,7 @@ navigation: - advanced_storage_pack - ldap_sync - pg_tuner + - spl_check - query_advisor - wait_states - pg_failover_slots diff --git a/advocacy_docs/pg_extensions/spl_check/configuring.mdx b/advocacy_docs/pg_extensions/spl_check/configuring.mdx new file mode 100644 index 00000000000..7fc6a10828c --- /dev/null +++ b/advocacy_docs/pg_extensions/spl_check/configuring.mdx @@ -0,0 +1,233 @@ +--- +title: Configuring EDB SPL Check +navTitle: Configuring +--- + +To run EDB SPL Check, run the `CREATE EXTENSION` command: + +```sql +CREATE EXTENSION spl_check +``` + +EDB SPL Check can be run in active mode or passive mode. In active mode, you can run checks with functions APIs such as `spl_check_function`. In passive mode, functions are checked when executed. + +## Active mode + +In active mode, checks are started by running function APIs such as `spl_check_function`. Active mode is the default behavior for EDB SPL Check. However, you can change this with the `spl_check.mode` setting. See [Configuring passive mode](#configuring-passive-mode) for more information. + +Additionally, you can use the function APIs `spl_check_package`, `spl_check_objecttype`, and `spl_check_trigger` to validate your code. See [Using EDB SPL Check](using) for more information. + +### Example + +The SQL statements inside SPL functions are checked by the validator for semantic errors: + +```sql +postgres=# CREATE TABLE t1(a int, b int); +CREATE TABLE + +postgres=# +CREATE OR REPLACE FUNCTION public.f1() +RETURNS void +LANGUAGE edbspl +AS $function$ +DECLARE r record; +BEGIN + FOR r IN SELECT * FROM t1 + LOOP + RAISE NOTICE '%', r.c; + END LOOP; +END; +$function$; + +CREATE FUNCTION +``` + +`RAISE NOTICE '%', r.c;` indicates that there is a bug, which is table `t1` is missing a `c` column. However, the `CREATE FUNCTION` command doesn't identify there is a bug because table `t1` is empty: + +```sql +postgres=# select f1(); +__OUTPUT__ + f1 + ──── + + (1 row) +``` + + +You can view the bug and other semantic errors by running `spl_check_function`: + +```sql +postgres=# \x +Expanded display is on. +postgres=# select * from spl_check_function_tb('f1()'); +─[ RECORD 1 ]─────────────────────────── +functionid │ f1 +lineno │ 6 +statement │ RAISE +sqlstate │ 42703 +message │ record "r" has no field "c" +detail │ [null] +hint │ [null] +level │ error +position │ 0 +query │ [null] +``` + +`spl_check_function()`'s three possible output formats are text, json, and xml: + +```sql +select * from spl_check_function('f1()', fatal_errors := false); + spl_check_function +------------------------------------------------------------------------ + error:42703:4:SQL statement:column "c" of relation "t1" does not exist + Query: update t1 set c = 30 + -- ^ + error:42P01:7:RAISE:missing FROM-clause entry for table "r" + Query: SELECT r.c + -- ^ + error:42601:7:RAISE:too few parameters specified for RAISE +(7 rows) + +postgres=# select * from spl_check_function('fx()', format:='xml'); + spl_check_function +──────────────────────────────────────────────────────────────── + ↵ + ↵ + error ↵ + 42P01 ↵ + relation "foo111" does not exist ↵ + RETURN ↵ + SELECT (select a from foo111)↵ + ↵ + + (1 row) + ``` + +### Setting the level of warnings + +You can set the level of warnings with the function's parameters. + +#### Required arguments + +`funcoid oid` — The function name or function signature, as functions require a function specification. A oid, a name, or a signature can specify any function in PostgreSQL. Once you know a the oid or a complete function's signature, you can use a regprocedure like `'fx()'::regprocedure` or `16799::regprocedure`. A possible alternative is to use only a name when the function's name is unique (like `'fx'`). If the name isn't unique or the doesn't exist, it raises an error. + +#### Optional arguments + +`relid DEFAULT 0` — The oid of the relation assigned to the trigger function. It's necessary to check the trigger function because you are sending the table which the trigger operates on. + +`fatal_errors boolean DEFAULT true` — Stop on the first error. This argument prevents massive error reports. + +`other_warnings boolean DEFAULT true` — Shows warnings like different attribute numbers on the left and right side of assignment, the variable overlaps the function's parameter, unused variables, unwanted casting, etc. + +`extra_warnings boolean DEFAULT true` — Shows warnings like a missing `RETURN`, shadowed variables, dead code, never read (unused) function parameter, unmodified variables, modified auto variables, etc. + +`performance_warnings boolean DEFAULT false` — Shows performance-related warnings like the declared type with type modifier, casting, implicit casts in the `WHERE` clause (which can be the reason why an index isn't used), etc. + +`security_warnings boolean DEFAULT false` — Shows security-related checks like SQL injection vulnerability detection. + +`compatibility_warnings boolean DEFAULT false` — Shows compatibility-related checks like the obsolete explicit setting internal cursor names in refcursor's or cursor's variables. + +`anyelementtype regtype DEFAULT 'int'` — Actual type to use when testing the `anyelementtype`. + +`anyenumtype regtype DEFAULT '-'` — Actual type to be used when testing the `anyenumtype`. + +`anyrangetype regtype DEFAULT 'int4range'` — Actual type to be used when testing the `anyrangetype`. + +`anycompatibletype DEFAULT 'int'` — Actual type to be used when testing the `anycompatibletype`. + +`anycompatiblerangetype DEFAULT 'int4range'` — Actual type to be used when testing the `anycompatiblerangetype`. + +`without_warnings DEFAULT false` — Disables all warnings by ignoring `xxxx_warning` parameters, which is a quick override. + +`all_warnings DEFAULT false` — Enables all warnings by ignoring other `xxxx_warning` parameters, which is a quick positive. + +`newtable DEFAULT NULL`, `oldtable DEFAULT NULL` — The names of `NEW` or `OLD` transition tables. When transition tables are used in trigger functions, these parameters are required. + +`use_incomment_options DEFAULT true` — When set to `true`, activates in-comment options. + +`incomment_options_usage_warning DEFAULT false` — When set to `true`, raises a warning when in-comment options are used. + + +### Compatibility warnings + +PostgreSQL cursor's and refcursor's variables are enhanced string variables that hold unique names for their respective portal. Prior to PostgreSQL version 16, the portal had the same name as the cursor variable. In PostgreSQL versions 16 and later, the portal has a unique name. + +With this change, the refursor's variable takes the value from another refcursor variable or from a cursor variable when the cursor is opened. For example: + +```sql +-- obsolete pattern +DECLARE + cur CURSOR FOR SELECT 1; + rcur refcursor; +BEGIN + rcur := 'cur'; + OPEN cur; + ... + +-- new pattern +DECLARE + cur CURSOR FOR SELECT 1; + rcur refcursor; +BEGIN + OPEN cur; + rcur := cur; + ... +``` + +When the `compatibility_warnings` flag is active, EDB SPL Check tries to identify incorrect assigning to refcursor's variable or returning of refcursor's variables: + +```sql +CREATE OR REPLACE FUNCTION public.foo() + RETURNS refcursor +AS $$ +declare + c cursor for select 1; + r refcursor; +begin + open c; + r := 'c'; + return r; +end; +$$ LANGUAGE edbspl; + +select * from spl_check_function('foo', extra_warnings =>false, compatibility_warnings => true); +┌───────────────────────────────────────────────────────────────────────────────────┐ +│ spl_check_function │ +╞═══════════════════════════════════════════════════════════════════════════════════╡ +│ compatibility:00000:6:assignment:obsolete setting of refcursor or cursor variable │ +│ Detail: Internal name of cursor should not be specified by users. │ +│ Context: at assignment to variable "r" declared on line 3 │ +└───────────────────────────────────────────────────────────────────────────────────┘ +(3 rows) +``` + +## Passive mode + +You can have your functions be checked upon execution by EDB SPL Check when it is in passive mode. The EDB SPL Check module must be loaded with `postgres.conf`. + +!!! Note + Passive mode is recommended only for development or preproduction use. + +### Configuring passive mode + +These are EDB SPL Check's settings: + +```ini +spl_check.mode = [ disabled | by_function | fresh_start | every_start ] +spl_check.fatal_errors = [ yes | no ] + +spl_check.show_nonperformance_warnings = false +spl_check.show_performance_warnings = false +``` + +By default, `spl_check.mode` is set to `by_function`, which means that checks are only done in active mode by using `spl_check_function`. `fresh_start` means cold start, so function's called first. + +Enable passive mode by doing the following: + +```sql +load 'edb-spl'; -- 1.1 and higher doesn't need it +load 'spl_check'; +set spl_check.mode = 'every_start'; -- This scans all code before it is executed + +SELECT fx(10); -- run functions - function is checked before runtime starts it +``` diff --git a/advocacy_docs/pg_extensions/spl_check/index.mdx b/advocacy_docs/pg_extensions/spl_check/index.mdx new file mode 100644 index 00000000000..3cb85e6be6c --- /dev/null +++ b/advocacy_docs/pg_extensions/spl_check/index.mdx @@ -0,0 +1,20 @@ +--- +title: EDB SPL Check +--- + +EDB SPL Check is a code analysis tool for SPL on EDB Postgres Advanced Server. Using only the internal PostgreSQL parser, it identifies errors that can occur at runtime. In addition, it parses the SQL inside your routines and identifies errors that are usually missed when executing `CREATE PROCEDURE/FUNCTION/PACKAGE`. Similarly, it identifies errors that are usually missed when executing `CREATE PACKAGE/OBJECT TYPES/COMPOUND TRIGGER`. + +You can control the levels of many warnings and hints. For instance, you can add `PRAGAMA` type markers to turn certain aspects off or on, allowing you to hide messages you're already aware of or keep ones you'd like to be reminded of. + +EDB SPL Check is supported on EDB Postgres Advanced Server versions 12 through 16. + +Some of the key features of EDB SPL Check include the following: + +- Checks fields of referenced database objects and types inside embedded SQL +- Validates you're using the correct types for function parameters +- Identifies unused variables and function arguments as well as unmodified `OUT` arguments +- Partially detects dead code, which is code after an unqualified `RETURN` command +- Detects missing `RETURN` commands in functions, which are common after exception handlers or complex logic +- Tries to identify unwanted hidden casts, which can be a performance issues like unused indexes +- Collects relations and functions used by a function +- Checks `EXECUTE` statements against SQL injection vulnerability \ No newline at end of file diff --git a/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx b/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx new file mode 100644 index 00000000000..7d4c4fafea3 --- /dev/null +++ b/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx @@ -0,0 +1,29 @@ +--- +title: Dependency list +--- + +The function `spl_show_dependency_tb` shows all the functions, operators, and relations used inside a processed function. For example: + +```sql +postgres=# select * from spl_show_dependency_tb('testfunc(int,float)'); +__OUTPUT__ +┌──────────┬───────┬────────┬─────────┬────────────────────────────┐ +│ type │ oid │ schema │ name │ params │ +╞══════════╪═══════╪════════╪═════════╪════════════════════════════╡ +│ FUNCTION │ 36008 │ public │ myfunc1 │ (integer,double precision) │ +│ FUNCTION │ 35999 │ public │ myfunc2 │ (integer,double precision) │ +│ OPERATOR │ 36007 │ public │ ** │ (integer,integer) │ +│ RELATION │ 36005 │ public │ myview │ │ +│ RELATION │ 36002 │ public │ mytable │ │ +└──────────┴───────┴────────┴─────────┴────────────────────────────┘ +(4 rows) +``` + +Optional arguments for `spl_show_dependency_tb` include: + +- `relid` +- `anyelementtype` +- `enumtype` +- `anyrangetype` +- `anycompatibletype` +- `anycompatiblerangetype` \ No newline at end of file diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx new file mode 100644 index 00000000000..5290dd6d7b5 --- /dev/null +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -0,0 +1,289 @@ +--- +title: Using EDB SPL Check +navTitle: Using +--- + +EDB SPL Check allows you to find errors in EDB Stored Procedure that a `CREATE PROCEDURE/FUNCTION` can miss. The following are some methods to check your code with EDB SPL Check. + +## Checking triggers + +To check any trigger, enter a relation that is used together with the trigger function. For example: + +```sql +CREATE TABLE bar(a int, b int); + +postgres=# \sf+ foo_trg + CREATE OR REPLACE FUNCTION public.foo_trg() + RETURNS trigger + LANGUAGE edbspl +1 AS $function$ +2 BEGIN +3 NEW.c := NEW.a + NEW.b; +4 RETURN NEW; +5 END; +6 $function$ +``` + +The following is returned when there is no specified relation for the trigger: + +```sql +postgres=# select * from spl_check_function('foo_trg()'); +ERROR: missing trigger relation +HINT: Trigger relation oid must be valid +``` + +The following is returned when the trigger is checked successfully with a specified relation: + +```sql +postgres=# select * from spl_check_function('foo_trg()', 'bar'); +__OUTPUT__ + spl_check_function +-------------------------------------------------------- + error:42703:3:assignment:record "new" has no field "c" +(1 row) +``` + +For triggers with transitive tables, set the `oldtable` and `newtable` parameters: + +```sql +create or replace function footab_trig_func() +returns trigger as $$ +declare x int; +begin + if false then + -- should be ok; + select count(*) from newtab into x; + + -- should fail; + select count(*) from newtab where d = 10 into x; + end if; + return null; +end; +$$ language edbspl; + +select * from spl_check_function('footab_trig_func','footab', newtable := 'newtab'); +``` + +## Validating compound triggers + +Another way to verify a trigger function is to use `spl_check_trigger()` by providing the the trigger name and (optionally) the relation name. This method is useful for redwood-style triggers and compound triggers where there are trigger functions created internally. For example: + +```sql +create table tab(a int); +create or replace trigger tg1 before insert on tab +for each row +begin + NEW.a := NEW.b; +end; + +select * from spl_check_trigger('tg1'); +__OUTPUT__ + spl_check_trigger +---------------------------------------------------- + error:42703:2:assignment:record "new" has no field "b" + Context: PL/pgSQL assignment "NEW.a := NEW.b" +(2 rows) +``` + +## Validating packages + +A package can have multiple functions/procedures. To validate all of your functions/procedures at once, you can use `spl_check_package()`. Similarly, use `spl_check_package_tb()` to view the output in tabular format. + +You can also validate individual package functions/procedures using `spl_check_function()`. For example: + +```sql +select * from spl_check_package(''); +``` + +## Validating object types + +Object types can have one or more member functions. To validate all the functions at once, use `spl_check_objecttype()`. Similarly, use `spl_check_objecttype_tb()` to view the output in tabular format. + +You can also validate individual object type member functions using `spl_check_function()`. For example: + +```sql +select * from spl_check_objecttype(''); +``` + +## Setting in-comment options + +EDB SPL Check allows persistent setting written in-comments. These options are taken from a function's source code before checking. The syntax is: + +```sql +@spl_check_option: optioname [=] value [, optname [=] value ...] +``` + +The settings from comment options has top priority, but generally it can be disabled by setting `use_incomment_options` to `false`. For example: + +```sql +create or replace function fx(anyelement) +returns text as $$ +begin + /* + * rewrite default polymorphic type to text + * @spl_check_options: anyelementtype = text + */ + return $1; +end; +$$ language edbspl; +``` + +## Checking all your code + +Use the `spl_check_function()` to check all of your functions/procedures and to check all your triggers. + +To check all non-trigger `edbspl` functions, do the following: + +```sql +SELECT p.oid, p.proname, spl_check_function(p.oid) + FROM pg_catalog.pg_namespace n + JOIN pg_catalog.pg_proc p ON pronamespace = n.oid + JOIN pg_catalog.pg_language l ON p.prolang = l.oid + WHERE l.lanname = 'edbspl' AND p.prorettype <> 2279; +``` + +To check all trigger `edbspl` functions, do the following: + +```sql +SELECT p.proname, tgrelid::regclass, cf.* + FROM pg_proc p + JOIN pg_trigger t ON t.tgfoid = p.oid + JOIN pg_language l ON p.prolang = l.oid + JOIN pg_namespace n ON p.pronamespace = n.oid, + LATERAL spl_check_function(p.oid, t.tgrelid) cf + WHERE n.nspname = 'public' and l.lanname = 'edbspl'; +``` + +To check all `edbspl` functions (including functions or trigger functions with defined triggers), do the following: + +```sql +SELECT + (pcf).functionid::regprocedure, (pcf).lineno, (pcf).statement, + (pcf).sqlstate, (pcf).message, (pcf).detail, (pcf).hint, (pcf).level, + (pcf)."position", (pcf).query, (pcf).context +FROM +( + SELECT + spl_check_function_tb(pg_proc.oid, COALESCE(pg_trigger.tgrelid, 0)) AS pcf + FROM pg_proc + LEFT JOIN pg_trigger + ON (pg_trigger.tgfoid = pg_proc.oid) + WHERE + prolang = (SELECT lang.oid FROM pg_language lang WHERE lang.lanname = 'edbspl') AND + pronamespace <> (SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = 'pg_catalog') AND + -- ignore unused triggers + (pg_proc.prorettype <> (SELECT typ.oid FROM pg_type typ WHERE typ.typname = 'trigger') OR + pg_trigger.tgfoid IS NOT NULL) + OFFSET 0 +) ss +ORDER BY (pcf).functionid::regprocedure::text, (pcf).lineno; +``` + +## Limitations + +EDB SPL Check finds almost all errors on static code. However, when using PL/pgSQL's dynamic features like dynamic SQL or record data data type, false positives are possible. In these cases, it's recommended that the affected function be rewritten or EDB SPL Check disabled for the function. For example: + +```sql +CREATE OR REPLACE FUNCTION f1() +RETURNS void AS $$ +DECLARE r record; +BEGIN + FOR r IN EXECUTE 'SELECT * FROM t1' + LOOP + RAISE NOTICE '%', r.c; + END LOOP; +END; +$$ LANGUAGE edbspl SET edbspl.enable_check TO false; +``` + +!!!Note + When passive mode is enabled, usage of EDB SPL Check adds a small overhead and it is recommended that the setting's used only in development or preproduction environments. + +### Dynamic SQL + +This module doesn't check queries that are assembled in runtime because it's not possible to identify the results of dynamic queries. Therefore, EDB SPL Check can't set the correct type to record variables and can't check a dependent SQLs or expressions. + +When the type of a record's variable is unknown, you can explicitly assign it with pragma `type`. For example: + +```sql +DECLARE r record; +BEGIN + EXECUTE format('SELECT * FROM %I', _tablename) INTO r; + PERFORM spl_check_pragma('type: r (id int, processed bool)'); + IF NOT r.processed THEN + ... +``` + +!!! Warning + The SQL injection check can't be used for a security audit. This tool detects only some SQL injection vulnerabilities, so some issues might not be detected. It can also raise false alarms. + +### Refcursors + +EDB SPL Check can't be used to detect the structure of referenced cursors. A reference on a cursor in `edbspl` is implemented as the name of a global cursor. During the check, the name is usually unknown and the global cursor doesn't exist. This issue is significant when performing any static analysis. `edbspl` is unable to set the correct type for the record variable and can't check the dependent SQL statements or expressions. The solution is the same for dynamic SQL. + +As a solution, do one of the following: + +- Don't use the the record variable as a target when you use a `refcursor` type +- Disable `spl_check` for the affected functions + +For example: + +```sql +CREATE OR REPLACE FUNCTION foo(refcur_var refcursor) +RETURNS void AS $$ +DECLARE + rec_var record; +BEGIN + FETCH refcur_var INTO rec_var; -- this is STOP for spl_check + RAISE NOTICE '%', rec_var; -- record rec_var is not assigned yet error +``` + +In the following case, don't use a record type and instead use a known `rowtype`: + +```sql +CREATE OR REPLACE FUNCTION foo(refcur_var refcursor) +RETURNS void AS $$ +DECLARE + rec_var some_rowtype; +BEGIN + FETCH refcur_var INTO rec_var; + RAISE NOTICE '%', rec_var; +``` + +### Temporary tables + +EDB SPL Check can't verify queries over temporary tables that are created in `edbspl`'s function runtime. + +As a solution, do one of the following: +- Create a fake temporary table +- Disable EDB SQL Check for this function + +Temporary tables are stored in your own schema with higher priority than persistent tables. So, you can perform this workaround safely: + +```sql +CREATE OR REPLACE FUNCTION public.disable_dml() +RETURNS trigger +LANGUAGE edbspl AS $function$ +BEGIN + RAISE EXCEPTION SQLSTATE '42P01' + USING message = format('this instance of %I table doesn''t allow any DML operation', TG_TABLE_NAME), + hint = format('you should use "CREATE TEMP TABLE %1$I(LIKE %1$I INCLUDING ALL);" statement', + TG_TABLE_NAME); + RETURN NULL; +END; +$function$; + +CREATE TABLE foo(a int, b int); -- doesn't hold data, ever +CREATE TRIGGER foo_disable_dml + BEFORE INSERT OR UPDATE OR DELETE ON foo + EXECUTE PROCEDURE disable_dml(); + +postgres=# INSERT INTO foo VALUES(10,20); +ERROR: this instance of foo table doesn't allow any DML operation +HINT: you should to run "CREATE TEMP TABLE foo(LIKE foo INCLUDING ALL);" statement +postgres=# + +CREATE TABLE +postgres=# INSERT INTO foo VALUES(10,20); +INSERT 0 1 +``` \ No newline at end of file diff --git a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx new file mode 100644 index 00000000000..f40f73c4d10 --- /dev/null +++ b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx @@ -0,0 +1,71 @@ +--- +title: Pragma +--- + +You can configure EDB SPL Check's behavior inside a checked function with a pragma function. This is an analogy of PL/SQL or ADA language of a pragma feature. PL/pgSQL doesn't support pragma, but EDB SPL Check detects functions named `spl_check_pragma` and takes options from the parameters of the function. These EDB SPL Check options are valid to the end of this group of statements: + +```sql +CREATE OR REPLACE FUNCTION test() +RETURNS void AS $$ +BEGIN + ... + -- for following statements disable check + PERFORM spl_check_pragma('disable:check'); + ... + -- enable check again + PERFORM spl_check_pragma('enable:check'); + ... +END; +$$ LANGUAGE edbspl; +``` + +The function `spl_check_pragma` is an immutable function that returns one. It is defined by EDB SPL Check. You can declare alternative `spl_check_pragma` functions like: + +```sql +CREATE OR REPLACE FUNCTION spl_check_pragma(VARIADIC args[]) +RETURNS int AS $$ +SELECT 1 +$$ LANGUAGE sql IMMUTABLE; +``` + +You can use a pragma function when declaring a part of the top block sets options on function level: + +```sql +CREATE OR REPLACE FUNCTION test() +RETURNS void AS $$ +DECLARE + aux int := spl_check_pragma('disable:extra_warnings'); + ... +``` + +And, you can use shorter syntax with pragmas: + +```sql +CREATE OR REPLACE FUNCTION test() +RETURNS void AS $$ +DECLARE r record; +BEGIN + PERFORM 'PRAGMA:TYPE:r (a int, b int)'; + PERFORM 'PRAGMA:TABLE: x (like pg_class)'; + ... +``` + +## Supported pragmas + +`echo:str` — Prints the string for testing. Within the string use variables like `@@id`, `@@name`, or `@@signature`. + +`status:check`, `status:tracer`, `status:other_warnings`, `status:performance_warnings`, `status:extra_warnings`, `status:security_warnings` — Outputs the current value. + +`enable:other_warnings`, `enable:performance_warnings`, `enable:extra_warnings`, `enable:security_warnings` — Enables warnings. + +`disable:check,disable:tracer`, `disable:other_warnings`, `disable:performance_warnings`, `disable:extra_warnings`, `disable:security_warnings`— Disables the hint returning from an `anyelement` function. Place the pragma before the `RETURN` statement. + +`type:varname typename` or `type:varname (fieldname type, ...)` — Sets type to the record type variable. + +`table: name (column_name type, ...)` or `table: name (like tablename)` — Creates an ephemeral temporary table. If you want to specify schema, it allows only `pg_temp` schema. + +`sequence: name` — Creates an ephemeral temporary sequence. + +!!! Note +Pragmas `enable:tracer` and `disable:tracer` are active for Postgres versions 12 and later. +!!! \ No newline at end of file diff --git a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx new file mode 100644 index 00000000000..e9dcdccd77e --- /dev/null +++ b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx @@ -0,0 +1,117 @@ +--- +title: Profiler +--- + +EDB SPL Check contains a simple profiler of `edbspl` functions and procedures. It can work with or without access to shared memory and depends on the `shared_preload_libraries` config. + +When EDB SPL Check is initialized by `shared_preload_libraries`, it can allocate shared memory and stores function's profiles. When EDB SPL Check can't allocate shared memory, the profile is stored in session memory. + +Due to dependencies, `shared_preload_libraries` must contain `edbspl` first: + +```sql +postgres=# show shared_preload_libraries ; +__OUTPUT__ +┌──────────────────────────┐ +│ shared_preload_libraries │ +╞══════════════════════════╡ +│ edb-spl,spl_check │ +└──────────────────────────┘ +(1 row) +``` + +The profiler becomes active when the GUC `spl_check.profiler` is on. The profiler doesn't required shared memory, but if there's not enough shared memory, then the profiler is limited to an active session. + +Activate the profiler by calling the function `spl_check_profiler(true)`. Deactivate the profiler by calling the same function but with a `false` argument (or `off` with literals). + +When `shared_preload_libraries` initializes EDB SPL Check, the GUC `spl_check.profiler_max_shared_chunks` becomes available to configure the amount of shared memory used by the profiler. This GUC defines the maximum number of statement chunks that can be stored in the shared memory. For each `edbspl` function/procedure, the whole content is split into chunks of 30 statements. If needed, multiple chunks can be used to store the whole content of a single function. A single chunk is 1704 bytes. + +The default value for `spl_check.profiler_max_shared_chunks` is 15000, which is usually enough for big projects that contain hundred of thousands of statements in `edbspl` and consume about 24MB of memory. + +If your project requires less, you can set the value for `spl_check.profiler_max_shared_chunks` to a smaller number to decrease the memory usage. + +The minimum value is 50, which usually consumes about 83kB of memory. The maximum value is 100000, which usually consumes about 163MB of memory. Changing `spl_check.profiler_max_shared_chunks` requires a PostgreSQL restart. + +The profiler also retrieves the query identifier for each instruction that contains an expression or optimizable statement. However, `pg_stat_statements` (or another similar third-party extensions) must be installed. + +There following are limitations of the query identifier retrieval: + +- If a `edbspl` expression contains underlying statements, only the top level query identifier is retrieved. +- The profiler doesn't compute the query identifier and instead relies on the external extension, like `pg_stat_statements`. Depending on the external extension's behavior, a query identifier may not show for some statements. For example, `pg_stat_statements` doesn't show the query identifier for queries with DDL statements. +- The profiler retrieves a query identifier only for instructions containing expressions. So, the function `spl_check.profiler_max_shared_chunks` can report less query identifiers than instructions on a single line. + +!!! Note + Updates on shared profiles can decrease the performance on servers under higher loads. + +Display the profile with `spl_profiler_function_tb`: + +```sql +postgres=# select lineno, avg_time, source from spl_profiler_function_tb('fx(int)'); +__OUTPUT__ +┌────────┬──────────┬───────────────────────────────────────────────────────────────────┐ +│ lineno │ avg_time │ source │ +╞════════╪══════════╪═══════════════════════════════════════════════════════════════════╡ +│ 1 │ │ │ +│ 2 │ │ declare result int = 0; │ +│ 3 │ 0.075 │ begin │ +│ 4 │ 0.202 │ for i in 1..$1 loop │ +│ 5 │ 0.005 │ select result + i into result; select result + i into result; │ +│ 6 │ │ end loop; │ +│ 7 │ 0 │ return result; │ +│ 8 │ │ end; │ +└────────┴──────────┴───────────────────────────────────────────────────────────────────┘ +(9 rows) +``` + +Display the profile per statements with `spl_profiler_function_statements_tb`: + +```sql + CREATE OR REPLACE FUNCTION public.fx1(a integer) + RETURNS integer + LANGUAGE spl +1 AS $function$ +2 begin +3 if a > 10 then +4 raise notice 'ahoj'; +5 return -1; +6 else +7 raise notice 'nazdar'; +8 return 1; +9 end if; +10 end; +11 $function$ + +postgres=# select stmtid, parent_stmtid, parent_note, lineno, exec_stmts, stmtname + from spl_profiler_function_statements_tb('fx1'); +__OUTPUT__ +┌────────┬───────────────┬─────────────┬────────┬────────────┬─────────────────┐ +│ stmtid │ parent_stmtid │ parent_note │ lineno │ exec_stmts │ stmtname │ +╞════════╪═══════════════╪═════════════╪════════╪════════════╪═════════════════╡ +│ 0 │ ∅ │ ∅ │ 2 │ 0 │ statement block │ +│ 1 │ 0 │ body │ 3 │ 0 │ IF │ +│ 2 │ 1 │ then body │ 4 │ 0 │ RAISE │ +│ 3 │ 1 │ then body │ 5 │ 0 │ RETURN │ +│ 4 │ 1 │ else body │ 7 │ 0 │ RAISE │ +│ 5 │ 1 │ else body │ 8 │ 0 │ RETURN │ +└────────┴───────────────┴─────────────┴────────┴────────────┴─────────────────┘ +(6 rows) +``` + +Display all stored profiles with `spl_profiler_functions_all`: + +```sql +postgres=# select * from spl_profiler_functions_all(); +__OUTPUT__ +┌───────────────────────┬────────────┬────────────┬──────────┬─────────────┬──────────┬──────────┐ +│ funcoid │ exec_count │ total_time │ avg_time │ stddev_time │ min_time │ max_time │ +╞═══════════════════════╪════════════╪════════════╪══════════╪═════════════╪══════════╪══════════╡ +│ fxx(double precision) │ 1 │ 0.01 │ 0.01 │ 0.00 │ 0.01 │ 0.01 │ +└───────────────────────┴────────────┴────────────┴──────────┴─────────────┴──────────┴──────────┘ +(1 row) +``` + +## Coverage metrics + +EDB SPL Check provides two functions: + +- `spl_coverage_statements(name)` +- `spl_coverage_branches(name)` \ No newline at end of file diff --git a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx new file mode 100644 index 00000000000..5845a347546 --- /dev/null +++ b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx @@ -0,0 +1,115 @@ +--- +title: Tracer +--- +EDB SPL Check provides a tracing option where you can see notices on start or end functions (terse and default verbosity) and start or end statements (verbose verbosity). For default and verbose verbosity, this option displays the content of function arguments. The content of related variables diplay when verbosity is verbose. For example: + +```sql +postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +NOTICE: #0 ->> start of inline_code_block (Oid=0) +NOTICE: #2 ->> start of function fx(integer,integer,date,text) (Oid=16405) +NOTICE: #2 call by inline_code_block line 1 at PERFORM +NOTICE: #2 "a" => '10', "b" => null, "c" => '2020-08-03', "d" => 'stěhule' +NOTICE: #4 ->> start of function fx(integer) (Oid=16404) +NOTICE: #4 call by fx(integer,integer,date,text) line 1 at PERFORM +NOTICE: #4 "a" => '10' +NOTICE: #4 <<- end of function fx (elapsed time=0.098 ms) +NOTICE: #2 <<- end of function fx (elapsed time=0.399 ms) +NOTICE: #0 <<- end of block (elapsed time=0.754 ms) +``` + +The number that follows `#` is the execution frame counter. This number is related to the depth of the error context stack. It allows you to pair the start and end of a function. + +## Using the tracer + +To enable tracing, set `spl_check.tracer` to `on`. + +!!!Warning + Enabling tracing can have a significant impact on performance. + + To prevent performance issues, you can set a level for outputs used by the tracer with `spl_check.tracer_errlevel` (the default is `notice`). And, the output content can be limited according to the length specified with the `spl_check.tracer_variable_max_length` configuration variable. + +As a security safeguard, we recommend that the usage of the tracer be enabled by a superuser by setting `spl_check.enable_tracer` to `on` or `spl_check.enable_tracer` to `on` in `postgresql.conf`. Because the tracer shows the content of EDB SPL Check's variables, some sensitive security information can display for an unprivileged user. + +We also recommend that the extension `spl_check` is loaded. You can execute some `spl_check` function or explicitly with the `load 'spl_check';`. You can use the configuration's option `shared_preload_libraries`, `local_preload_libraries`, or `session_preload_libraries`. + +In terse verbose mode the output is reduced: + +```sql +postgres=# set spl_check.tracer_verbosity TO terse; +SET +postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +NOTICE: #0 start of inline code block (oid=0) +NOTICE: #2 start of fx (oid=16405) +NOTICE: #4 start of fx (oid=16404) +NOTICE: #4 end of fx +NOTICE: #2 end of fx +NOTICE: #0 end of inline code block +``` + +In verbose mode the output is extended with statement details: + +```sql +postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +NOTICE: #0 ->> start of block inline_code_block (oid=0) +NOTICE: #0.1 1 --> start of PERFORM +NOTICE: #2 ->> start of function fx(integer,integer,date,text) (oid=16405) +NOTICE: #2 call by inline_code_block line 1 at PERFORM +NOTICE: #2 "a" => '10', "b" => null, "c" => '2020-08-04', "d" => 'stěhule' +NOTICE: #2.1 1 --> start of PERFORM +NOTICE: #2.1 "a" => '10' +NOTICE: #4 ->> start of function fx(integer) (oid=16404) +NOTICE: #4 call by fx(integer,integer,date,text) line 1 at PERFORM +NOTICE: #4 "a" => '10' +NOTICE: #4.1 6 --> start of assignment +NOTICE: #4.1 "a" => '10', "b" => '20' +NOTICE: #4.1 <-- end of assignment (elapsed time=0.076 ms) +NOTICE: #4.1 "res" => '130' +NOTICE: #4.2 7 --> start of RETURN +NOTICE: #4.2 "res" => '130' +NOTICE: #4.2 <-- end of RETURN (elapsed time=0.054 ms) +NOTICE: #4 <<- end of function fx (elapsed time=0.373 ms) +NOTICE: #2.1 <-- end of PERFORM (elapsed time=0.589 ms) +NOTICE: #2 <<- end of function fx (elapsed time=0.727 ms) +NOTICE: #0.1 <-- end of PERFORM (elapsed time=1.147 ms) +NOTICE: #0 <<- end of block (elapsed time=1.286 ms) +``` + +A special feature of the tracer is the tracing of the `ASSERT` statement when `spl_check.trace_assert` is `on`. When `spl_check.trace_assert_verbosity` is `DEFAULT` and the `ASSERT` statement is `false`, all functions' or procedures' variables are displayed. When this configuration is `VERBOSE`, all variables from all EDB SPL frames are displayed. This behavior is independent of the `spl.check_asserts` value. It can be used, but the assertions are disabled during EDB SPL runtime. For example: + +```sql +postgres=# set spl_check.tracer to off; +postgres=# set spl_check.trace_assert_verbosity TO verbose; + +postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +NOTICE: #4 PLpgSQL assert expression (false) on line 12 of fx(integer) is false +NOTICE: "a" => '10', "res" => null, "b" => '20' +NOTICE: #2 PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM +NOTICE: "a" => '10', "b" => null, "c" => '2020-08-05', "d" => 'stěhule' +NOTICE: #0 PL/pgSQL function inline_code_block line 1 at PERFORM +ERROR: assertion failed +CONTEXT: PL/pgSQL function fx(integer) line 12 at ASSERT +SQL statement "SELECT fx(a)" +PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM +SQL statement "SELECT fx(10,null, 'now', e'stěhule')" +PL/pgSQL function inline_code_block line 1 at PERFORM + +postgres=# set spl.check_asserts to off; +SET +postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +NOTICE: #4 PLpgSQL assert expression (false) on line 12 of fx(integer) is false +NOTICE: "a" => '10', "res" => null, "b" => '20' +NOTICE: #2 PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM +NOTICE: "a" => '10', "b" => null, "c" => '2020-08-05', "d" => 'stěhule' +NOTICE: #0 PL/pgSQL function inline_code_block line 1 at PERFORM +DO +``` + +## plugin_debugger + +If you plan to use `plugin_debugger` (plpgsql debugger) with EDB SPL Check, we recommend that you initialize `plugin_debugger` first. `plugin_debugger` doesn't support the sharing of PL/pgSQL's debug API. + +For example: + +```ini +shared_preload_libraries = 'plugin_debugger,edb-spl,spl_check' +``` \ No newline at end of file diff --git a/src/pages/index.js b/src/pages/index.js index 2efd46d417f..b0698d2b033 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -167,6 +167,10 @@ const Page = () => ( EDB Postgres Tuner + + EDB SPL Check + + EDB Query Advisor @@ -175,14 +179,14 @@ const Page = () => ( EDB Wait States - - PG Failover Slots - - EDB SQL Patch + + PG Failover Slots + + Language Pack From 82b0e2f65ba0e6f7cb24fe0a95e25f0f020d14b9 Mon Sep 17 00:00:00 2001 From: Betsy Gitelman <93718720+ebgitelman@users.noreply.github.com> Date: Tue, 19 Sep 2023 14:27:47 -0400 Subject: [PATCH 10/24] edits to EDB SPL Check content --- .../pg_extensions/spl_check/configuring.mdx | 111 ++++++++++++------ .../pg_extensions/spl_check/index.mdx | 12 +- .../pg_extensions/spl_check/using/index.mdx | 48 ++++---- .../pg_extensions/spl_check/using/pragma.mdx | 38 ++++-- .../spl_check/using/profiler.mdx | 27 +++-- .../pg_extensions/spl_check/using/tracer.mdx | 16 +-- 6 files changed, 161 insertions(+), 91 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/configuring.mdx b/advocacy_docs/pg_extensions/spl_check/configuring.mdx index 7fc6a10828c..75ae5c56eed 100644 --- a/advocacy_docs/pg_extensions/spl_check/configuring.mdx +++ b/advocacy_docs/pg_extensions/spl_check/configuring.mdx @@ -3,23 +3,25 @@ title: Configuring EDB SPL Check navTitle: Configuring --- -To run EDB SPL Check, run the `CREATE EXTENSION` command: +To run EDB SPL Check, use the `CREATE EXTENSION` command: ```sql CREATE EXTENSION spl_check ``` -EDB SPL Check can be run in active mode or passive mode. In active mode, you can run checks with functions APIs such as `spl_check_function`. In passive mode, functions are checked when executed. +You can run EDB SPL Check in active mode or passive mode. In active mode, you can run checks with API functions like `spl_check_function`. In passive mode, functions are checked when executed. + ## Active mode -In active mode, checks are started by running function APIs such as `spl_check_function`. Active mode is the default behavior for EDB SPL Check. However, you can change this with the `spl_check.mode` setting. See [Configuring passive mode](#configuring-passive-mode) for more information. +In active mode, start checks by running API functions like `spl_check_function`. Active mode is the default behavior for EDB SPL Check. However, you can change this mode with the `spl_check.mode` setting. See [Configuring passive mode](#configuring-passive-mode) for more information. + -Additionally, you can use the function APIs `spl_check_package`, `spl_check_objecttype`, and `spl_check_trigger` to validate your code. See [Using EDB SPL Check](using) for more information. +You can also use the functions `spl_check_package`, `spl_check_objecttype`, and `spl_check_trigger` to validate your code. See [Using EDB SPL Check](using) for more information. ### Example -The SQL statements inside SPL functions are checked by the validator for semantic errors: +The validator checks the SQL statements inside SPL functions for semantic errors: ```sql postgres=# CREATE TABLE t1(a int, b int); @@ -42,7 +44,7 @@ $function$; CREATE FUNCTION ``` -`RAISE NOTICE '%', r.c;` indicates that there is a bug, which is table `t1` is missing a `c` column. However, the `CREATE FUNCTION` command doesn't identify there is a bug because table `t1` is empty: +`RAISE NOTICE '%', r.c;` indicates that there's a bug, which is that table `t1` is missing a `c` column. However, the `CREATE FUNCTION` command doesn't identify there's a bug because table `t1` is empty: ```sql postgres=# select f1(); @@ -73,7 +75,7 @@ position │ 0 query │ [null] ``` -`spl_check_function()`'s three possible output formats are text, json, and xml: +`spl_check_function()` has three possible output formats, which are text, json, and xml: ```sql select * from spl_check_function('f1()', fatal_errors := false); @@ -105,54 +107,95 @@ postgres=# select * from spl_check_function('fx()', format:='xml'); ### Setting the level of warnings -You can set the level of warnings with the function's parameters. +You can use the function's parameters to set the level of warnings. #### Required arguments -`funcoid oid` — The function name or function signature, as functions require a function specification. A oid, a name, or a signature can specify any function in PostgreSQL. Once you know a the oid or a complete function's signature, you can use a regprocedure like `'fx()'::regprocedure` or `16799::regprocedure`. A possible alternative is to use only a name when the function's name is unique (like `'fx'`). If the name isn't unique or the doesn't exist, it raises an error. +`funcoid oid` + +The function name or function signature, as functions require a function specification. An oid, a name, or a signature can specify any function in PostgreSQL. Once you know the oid or a function's complete signature, you can use a `regprocedure` like `'fx()'::regprocedure` or `16799::regprocedure`. A possible alternative is to use only a name when the function's name is unique, like `'fx'`. If the name isn't unique or doesn't exist, the function raises an error. #### Optional arguments -`relid DEFAULT 0` — The oid of the relation assigned to the trigger function. It's necessary to check the trigger function because you are sending the table which the trigger operates on. +`relid DEFAULT 0` + +The oid of the relation assigned to the trigger function. You need to check the trigger function because you're sending the table that the trigger operates on. + +`fatal_errors boolean DEFAULT true` + +Stop on the first error. This argument prevents massive error reports. + +`other_warnings boolean DEFAULT true` -`fatal_errors boolean DEFAULT true` — Stop on the first error. This argument prevents massive error reports. +Show warnings for conditions, for example: -`other_warnings boolean DEFAULT true` — Shows warnings like different attribute numbers on the left and right side of assignment, the variable overlaps the function's parameter, unused variables, unwanted casting, etc. +- Different attribute numbers are on the left and right side of assignment +- The variable overlaps the function's parameter +- Unused variables +- Unwanted casting -`extra_warnings boolean DEFAULT true` — Shows warnings like a missing `RETURN`, shadowed variables, dead code, never read (unused) function parameter, unmodified variables, modified auto variables, etc. +`extra_warnings boolean DEFAULT true` + +Show warnings for conditions such as a missing `RETURN`, shadowed variables, dead code, never read (unused) function parameter, unmodified variables, and modified auto variables. -`performance_warnings boolean DEFAULT false` — Shows performance-related warnings like the declared type with type modifier, casting, implicit casts in the `WHERE` clause (which can be the reason why an index isn't used), etc. +`performance_warnings boolean DEFAULT false` + +Show performance-related warnings for conditions such as the declared type with type modifier, casting, and implicit casts in the `WHERE` clause (which can be the reason why an index isn't used). + +`security_warnings boolean DEFAULT false` + +Show security-related checks like SQL-injection vulnerability detection. + +`compatibility_warnings boolean DEFAULT false` -`security_warnings boolean DEFAULT false` — Shows security-related checks like SQL injection vulnerability detection. +Show compatibility-related checks like the obsolete explicit setting internal cursor names in refcursor or cursor variables. -`compatibility_warnings boolean DEFAULT false` — Shows compatibility-related checks like the obsolete explicit setting internal cursor names in refcursor's or cursor's variables. +`anyelementtype regtype DEFAULT 'int'` -`anyelementtype regtype DEFAULT 'int'` — Actual type to use when testing the `anyelementtype`. +Actual type to use when testing the `anyelementtype`. -`anyenumtype regtype DEFAULT '-'` — Actual type to be used when testing the `anyenumtype`. +`anyenumtype regtype DEFAULT '-'` -`anyrangetype regtype DEFAULT 'int4range'` — Actual type to be used when testing the `anyrangetype`. +Actual type to use when testing the `anyenumtype`. -`anycompatibletype DEFAULT 'int'` — Actual type to be used when testing the `anycompatibletype`. +`anyrangetype regtype DEFAULT 'int4range'` -`anycompatiblerangetype DEFAULT 'int4range'` — Actual type to be used when testing the `anycompatiblerangetype`. +Actual type to use when testing the `anyrangetype`. -`without_warnings DEFAULT false` — Disables all warnings by ignoring `xxxx_warning` parameters, which is a quick override. +`anycompatibletype DEFAULT 'int'` -`all_warnings DEFAULT false` — Enables all warnings by ignoring other `xxxx_warning` parameters, which is a quick positive. +Actual type to use when testing the `anycompatibletype`. -`newtable DEFAULT NULL`, `oldtable DEFAULT NULL` — The names of `NEW` or `OLD` transition tables. When transition tables are used in trigger functions, these parameters are required. +`anycompatiblerangetype DEFAULT 'int4range'` -`use_incomment_options DEFAULT true` — When set to `true`, activates in-comment options. +Actual type to use when testing the `anycompatiblerangetype`. -`incomment_options_usage_warning DEFAULT false` — When set to `true`, raises a warning when in-comment options are used. +`without_warnings DEFAULT false` + +Disable all warnings by ignoring `xxxx_warning` parameters, which is a quick override. + +`all_warnings DEFAULT false` + +Enable all warnings by ignoring other `xxxx_warning` parameters, which is a quick positive. + +`newtable DEFAULT NULL`, `oldtable DEFAULT NULL` + +The names of `NEW` or `OLD` transition tables. When transition tables are used in trigger functions, these parameters are required. + +`use_incomment_options DEFAULT true` + +When set to `true`, activates in-comment options. + +`incomment_options_usage_warning DEFAULT false` + +When set to `true`, raises a warning when in-comment options are used. ### Compatibility warnings -PostgreSQL cursor's and refcursor's variables are enhanced string variables that hold unique names for their respective portal. Prior to PostgreSQL version 16, the portal had the same name as the cursor variable. In PostgreSQL versions 16 and later, the portal has a unique name. +PostgreSQL cursor and refcursor variables are enhanced string variables that hold unique names for their respective portal. Before PostgreSQL version 16, the portal had the same name as the cursor variable. In PostgreSQL versions 16 and later, the portal has a unique name. -With this change, the refursor's variable takes the value from another refcursor variable or from a cursor variable when the cursor is opened. For example: +With this change, the refursor variable takes the value from another refcursor variable or from a cursor variable when the cursor is opened. For example: ```sql -- obsolete pattern @@ -174,7 +217,7 @@ BEGIN ... ``` -When the `compatibility_warnings` flag is active, EDB SPL Check tries to identify incorrect assigning to refcursor's variable or returning of refcursor's variables: +When the `compatibility_warnings` flag is active, EDB SPL Check tries to identify incorrect assigning to a refcursor variable or returning of a refcursor variable: ```sql CREATE OR REPLACE FUNCTION public.foo() @@ -203,14 +246,14 @@ select * from spl_check_function('foo', extra_warnings =>false, compatibility_wa ## Passive mode -You can have your functions be checked upon execution by EDB SPL Check when it is in passive mode. The EDB SPL Check module must be loaded with `postgres.conf`. +In passive mode, EDB SPL Check can check your functions upon execution. Load the EDB SPL Check module with `postgres.conf`. !!! Note Passive mode is recommended only for development or preproduction use. ### Configuring passive mode -These are EDB SPL Check's settings: +These are the EDB SPL Check settings: ```ini spl_check.mode = [ disabled | by_function | fresh_start | every_start ] @@ -220,9 +263,11 @@ spl_check.show_nonperformance_warnings = false spl_check.show_performance_warnings = false ``` -By default, `spl_check.mode` is set to `by_function`, which means that checks are only done in active mode by using `spl_check_function`. `fresh_start` means cold start, so function's called first. +By default, `spl_check.mode` is set to `by_function`, which means that checks are done only in active mode by using `spl_check_function`. `fresh_start` means cold start, so function's called first. + + -Enable passive mode by doing the following: +To enable passive mode: ```sql load 'edb-spl'; -- 1.1 and higher doesn't need it diff --git a/advocacy_docs/pg_extensions/spl_check/index.mdx b/advocacy_docs/pg_extensions/spl_check/index.mdx index 3cb85e6be6c..64a4c85d92d 100644 --- a/advocacy_docs/pg_extensions/spl_check/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/index.mdx @@ -4,17 +4,19 @@ title: EDB SPL Check EDB SPL Check is a code analysis tool for SPL on EDB Postgres Advanced Server. Using only the internal PostgreSQL parser, it identifies errors that can occur at runtime. In addition, it parses the SQL inside your routines and identifies errors that are usually missed when executing `CREATE PROCEDURE/FUNCTION/PACKAGE`. Similarly, it identifies errors that are usually missed when executing `CREATE PACKAGE/OBJECT TYPES/COMPOUND TRIGGER`. -You can control the levels of many warnings and hints. For instance, you can add `PRAGAMA` type markers to turn certain aspects off or on, allowing you to hide messages you're already aware of or keep ones you'd like to be reminded of. +You can control the levels of many warnings and hints. For instance, you can add `PRAGAMA` type markers to turn certain aspects off or on, allowing you to hide messages you're already aware of or keep ones you want to be reminded of. -EDB SPL Check is supported on EDB Postgres Advanced Server versions 12 through 16. +EDB SPL Check is supported on EDB Postgres Advanced Server versions 12 and later. + -Some of the key features of EDB SPL Check include the following: +These are some of the key features of EDB SPL Check: - Checks fields of referenced database objects and types inside embedded SQL -- Validates you're using the correct types for function parameters +- Validates you're using the correct types for function parameters - Identifies unused variables and function arguments as well as unmodified `OUT` arguments -- Partially detects dead code, which is code after an unqualified `RETURN` command +- Partially detects dead code, that is, code after an unqualified `RETURN` command - Detects missing `RETURN` commands in functions, which are common after exception handlers or complex logic - Tries to identify unwanted hidden casts, which can be a performance issues like unused indexes + - Collects relations and functions used by a function - Checks `EXECUTE` statements against SQL injection vulnerability \ No newline at end of file diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx index 5290dd6d7b5..4dfca882919 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -3,11 +3,11 @@ title: Using EDB SPL Check navTitle: Using --- -EDB SPL Check allows you to find errors in EDB Stored Procedure that a `CREATE PROCEDURE/FUNCTION` can miss. The following are some methods to check your code with EDB SPL Check. +EDB SPL Check helps you to find errors in an EDB stored procedure that a `CREATE PROCEDURE/FUNCTION` can miss. The following are some methods to check your code with EDB SPL Check. ## Checking triggers -To check any trigger, enter a relation that is used together with the trigger function. For example: +To check any trigger, enter a relation that's used with the trigger function. For example: ```sql CREATE TABLE bar(a int, b int); @@ -24,7 +24,7 @@ postgres=# \sf+ foo_trg 6 $function$ ``` -The following is returned when there is no specified relation for the trigger: +When there's no specified relation for the trigger, the following is returned: ```sql postgres=# select * from spl_check_function('foo_trg()'); @@ -32,7 +32,7 @@ ERROR: missing trigger relation HINT: Trigger relation oid must be valid ``` -The following is returned when the trigger is checked successfully with a specified relation: +When the trigger is checked successfully with a specified relation, the following is returned: ```sql postgres=# select * from spl_check_function('foo_trg()', 'bar'); @@ -66,7 +66,7 @@ select * from spl_check_function('footab_trig_func','footab', newtable := 'newta ## Validating compound triggers -Another way to verify a trigger function is to use `spl_check_trigger()` by providing the the trigger name and (optionally) the relation name. This method is useful for redwood-style triggers and compound triggers where there are trigger functions created internally. For example: +Another way to verify a trigger function is to use `spl_check_trigger()` by providing the trigger name and, optionally, the relation name. This method is useful for redwood-style triggers and compound triggers where trigger functions are created internally. For example: ```sql create table tab(a int); @@ -107,13 +107,13 @@ select * from spl_check_objecttype(''); ## Setting in-comment options -EDB SPL Check allows persistent setting written in-comments. These options are taken from a function's source code before checking. The syntax is: +EDB SPL Check allows persistent-setting, written in-comments. These options are taken from a function's source code before checking. The syntax is: ```sql @spl_check_option: optioname [=] value [, optname [=] value ...] ``` -The settings from comment options has top priority, but generally it can be disabled by setting `use_incomment_options` to `false`. For example: +The settings from comment options have top priority, but generally they can be disabled by setting `use_incomment_options` to `false`. For example: ```sql create or replace function fx(anyelement) @@ -132,7 +132,7 @@ $$ language edbspl; Use the `spl_check_function()` to check all of your functions/procedures and to check all your triggers. -To check all non-trigger `edbspl` functions, do the following: +To check all nontrigger EDB SPL Check functions: ```sql SELECT p.oid, p.proname, spl_check_function(p.oid) @@ -142,7 +142,7 @@ SELECT p.oid, p.proname, spl_check_function(p.oid) WHERE l.lanname = 'edbspl' AND p.prorettype <> 2279; ``` -To check all trigger `edbspl` functions, do the following: +To check all trigger EDB SPL Check functions: ```sql SELECT p.proname, tgrelid::regclass, cf.* @@ -154,7 +154,7 @@ SELECT p.proname, tgrelid::regclass, cf.* WHERE n.nspname = 'public' and l.lanname = 'edbspl'; ``` -To check all `edbspl` functions (including functions or trigger functions with defined triggers), do the following: +To check all EDB SPL Check functions, including functions or trigger functions with defined triggers: ```sql SELECT @@ -181,7 +181,8 @@ ORDER BY (pcf).functionid::regprocedure::text, (pcf).lineno; ## Limitations -EDB SPL Check finds almost all errors on static code. However, when using PL/pgSQL's dynamic features like dynamic SQL or record data data type, false positives are possible. In these cases, it's recommended that the affected function be rewritten or EDB SPL Check disabled for the function. For example: +EDB SPL Check finds almost all errors on static code. However, when using PL/pgSQL's dynamic features like dynamic SQL or the record-data data type, false positives are possible. In these cases, we recommend that you rewrite the affected function or disable EDB SPL Check for the function. For example: + ```sql CREATE OR REPLACE FUNCTION f1() @@ -197,11 +198,12 @@ $$ LANGUAGE edbspl SET edbspl.enable_check TO false; ``` !!!Note - When passive mode is enabled, usage of EDB SPL Check adds a small overhead and it is recommended that the setting's used only in development or preproduction environments. + When passive mode is enabled, using EDB SPL Check adds a small overhead. We recommend that you use the setting only in development or preproduction environments. ### Dynamic SQL -This module doesn't check queries that are assembled in runtime because it's not possible to identify the results of dynamic queries. Therefore, EDB SPL Check can't set the correct type to record variables and can't check a dependent SQLs or expressions. +This module doesn't check queries that are assembled in runtime because you can't identify the results of dynamic queries. Therefore, EDB SPL Check can't set the correct type to record variables and can't check a dependent SQL's or expressions. + When the type of a record's variable is unknown, you can explicitly assign it with pragma `type`. For example: @@ -215,16 +217,16 @@ BEGIN ``` !!! Warning - The SQL injection check can't be used for a security audit. This tool detects only some SQL injection vulnerabilities, so some issues might not be detected. It can also raise false alarms. + You can't use the SQL injection check for a security audit. This tool detects only some SQL injection vulnerabilities, so it might not detect some issues. It can also raise false alarms. ### Refcursors -EDB SPL Check can't be used to detect the structure of referenced cursors. A reference on a cursor in `edbspl` is implemented as the name of a global cursor. During the check, the name is usually unknown and the global cursor doesn't exist. This issue is significant when performing any static analysis. `edbspl` is unable to set the correct type for the record variable and can't check the dependent SQL statements or expressions. The solution is the same for dynamic SQL. +You can't use EDB SPL Check to detect the structure of referenced cursors. A reference on a cursor in EDB SPL Check is implemented as the name of a global cursor. During the check, the name is usually unknown, and the global cursor doesn't exist. This issue is significant when performing any static analysis. EDB SPL Check can't set the correct type for the record variable and can't check the dependent SQL statements or expressions. The solution is the same for dynamic SQL. -As a solution, do one of the following: +You can use either of these solutions: -- Don't use the the record variable as a target when you use a `refcursor` type -- Disable `spl_check` for the affected functions +- Don't use the the record variable as a target when you use a `refcursor` type. +- Disable `spl_check` for the affected functions. For example: @@ -238,7 +240,7 @@ BEGIN RAISE NOTICE '%', rec_var; -- record rec_var is not assigned yet error ``` -In the following case, don't use a record type and instead use a known `rowtype`: +In this example, don't use a record type. Instead use a known `rowtype`: ```sql CREATE OR REPLACE FUNCTION foo(refcur_var refcursor) @@ -252,11 +254,11 @@ BEGIN ### Temporary tables -EDB SPL Check can't verify queries over temporary tables that are created in `edbspl`'s function runtime. +EDB SPL Check can't verify queries over temporary tables that are created in the `edbspl` function runtime. -As a solution, do one of the following: -- Create a fake temporary table -- Disable EDB SQL Check for this function +As a solution, you can either: +- Create a fake temporary table. +- Disable EDB SQL Check for this function. Temporary tables are stored in your own schema with higher priority than persistent tables. So, you can perform this workaround safely: diff --git a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx index f40f73c4d10..ad52f8ce167 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx @@ -2,7 +2,9 @@ title: Pragma --- -You can configure EDB SPL Check's behavior inside a checked function with a pragma function. This is an analogy of PL/SQL or ADA language of a pragma feature. PL/pgSQL doesn't support pragma, but EDB SPL Check detects functions named `spl_check_pragma` and takes options from the parameters of the function. These EDB SPL Check options are valid to the end of this group of statements: +You can configure EDB SPL Check's behavior inside a checked function with a pragma function. This is an analogy of PL/SQL or ADA language of a pragma feature. PL/pgSQL doesn't support pragma, but EDB SPL Check detects functions named `spl_check_pragma` and takes options from the parameters of the function. These EDB SPL Check options are valid to add to the end of this group of statements: + + ```sql CREATE OR REPLACE FUNCTION test() @@ -19,7 +21,7 @@ END; $$ LANGUAGE edbspl; ``` -The function `spl_check_pragma` is an immutable function that returns one. It is defined by EDB SPL Check. You can declare alternative `spl_check_pragma` functions like: +The function `spl_check_pragma` is an immutable function that returns 1. It's defined by EDB SPL Check. You can declare alternative `spl_check_pragma` functions like: ```sql CREATE OR REPLACE FUNCTION spl_check_pragma(VARIADIC args[]) @@ -28,7 +30,7 @@ SELECT 1 $$ LANGUAGE sql IMMUTABLE; ``` -You can use a pragma function when declaring a part of the top block sets options on function level: +You can use a pragma function when declaring a part of the top block sets options on a function level: ```sql CREATE OR REPLACE FUNCTION test() @@ -38,7 +40,7 @@ DECLARE ... ``` -And, you can use shorter syntax with pragmas: +You can also use a shorter syntax with pragmas: ```sql CREATE OR REPLACE FUNCTION test() @@ -52,19 +54,33 @@ BEGIN ## Supported pragmas -`echo:str` — Prints the string for testing. Within the string use variables like `@@id`, `@@name`, or `@@signature`. +`echo:str` + +Prints the string for testing. In the string, use variables like `@@id`, `@@name`, or `@@signature`. + +`status:check`, `status:tracer`, `status:other_warnings`, `status:performance_warnings`, `status:extra_warnings`, `status:security_warnings` + +Outputs the current value. + +`enable:other_warnings`, `enable:performance_warnings`, `enable:extra_warnings`, `enable:security_warnings` + +Enables warnings. + +`disable:check,disable:tracer`, `disable:other_warnings`, `disable:performance_warnings`, `disable:extra_warnings`, `disable:security_warnings` + +Disables the hint returning from an `anyelement` function. Place the pragma before the `RETURN` statement. -`status:check`, `status:tracer`, `status:other_warnings`, `status:performance_warnings`, `status:extra_warnings`, `status:security_warnings` — Outputs the current value. +`type:varname typename` or `type:varname (fieldname type, ...)` -`enable:other_warnings`, `enable:performance_warnings`, `enable:extra_warnings`, `enable:security_warnings` — Enables warnings. +Sets type to the record-type variable. -`disable:check,disable:tracer`, `disable:other_warnings`, `disable:performance_warnings`, `disable:extra_warnings`, `disable:security_warnings`— Disables the hint returning from an `anyelement` function. Place the pragma before the `RETURN` statement. +`table: name (column_name type, ...)` or `table: name (like tablename)` -`type:varname typename` or `type:varname (fieldname type, ...)` — Sets type to the record type variable. +Creates an ephemeral temporary table. If you want to specify a schema, it allows only the`pg_temp` schema. -`table: name (column_name type, ...)` or `table: name (like tablename)` — Creates an ephemeral temporary table. If you want to specify schema, it allows only `pg_temp` schema. +`sequence: name` -`sequence: name` — Creates an ephemeral temporary sequence. +Creates an ephemeral temporary sequence. !!! Note Pragmas `enable:tracer` and `disable:tracer` are active for Postgres versions 12 and later. diff --git a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx index e9dcdccd77e..4661fa42c30 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx @@ -4,10 +4,12 @@ title: Profiler EDB SPL Check contains a simple profiler of `edbspl` functions and procedures. It can work with or without access to shared memory and depends on the `shared_preload_libraries` config. -When EDB SPL Check is initialized by `shared_preload_libraries`, it can allocate shared memory and stores function's profiles. When EDB SPL Check can't allocate shared memory, the profile is stored in session memory. +When EDB SPL Check is initialized by `shared_preload_libraries`, it can allocate shared memory and stores function profiles. When EDB SPL Check can't allocate shared memory, the profile is stored in session memory. Due to dependencies, `shared_preload_libraries` must contain `edbspl` first: + + ```sql postgres=# show shared_preload_libraries ; __OUTPUT__ @@ -19,25 +21,28 @@ __OUTPUT__ (1 row) ``` -The profiler becomes active when the GUC `spl_check.profiler` is on. The profiler doesn't required shared memory, but if there's not enough shared memory, then the profiler is limited to an active session. +The profiler becomes active when the GUC `spl_check.profiler` is on. The profiler doesn't require shared memory. However, if there's not enough shared memory, then the profiler is limited to an active session. Activate the profiler by calling the function `spl_check_profiler(true)`. Deactivate the profiler by calling the same function but with a `false` argument (or `off` with literals). -When `shared_preload_libraries` initializes EDB SPL Check, the GUC `spl_check.profiler_max_shared_chunks` becomes available to configure the amount of shared memory used by the profiler. This GUC defines the maximum number of statement chunks that can be stored in the shared memory. For each `edbspl` function/procedure, the whole content is split into chunks of 30 statements. If needed, multiple chunks can be used to store the whole content of a single function. A single chunk is 1704 bytes. +When `shared_preload_libraries` initializes EDB SPL Check, the GUC `spl_check.profiler_max_shared_chunks` becomes available to configure the amount of shared memory used by the profiler. This GUC defines the maximum number of statement chunks that can be stored in the shared memory. For each EDB SPL Check function/procedure, the whole content is split into chunks of 30 statements. If needed, you can use multiple chunks to store the whole content of a single function. A single chunk is 1704 bytes. + +The default value for `spl_check.profiler_max_shared_chunks` is 15000. This number is usually enough for big projects that contain hundred of thousands of statements and consume about 24MB of memory. -The default value for `spl_check.profiler_max_shared_chunks` is 15000, which is usually enough for big projects that contain hundred of thousands of statements in `edbspl` and consume about 24MB of memory. +If your project requires fewer statement chunks, you can set the value for `spl_check.profiler_max_shared_chunks` to a smaller number to decrease the memory usage. -If your project requires less, you can set the value for `spl_check.profiler_max_shared_chunks` to a smaller number to decrease the memory usage. +The minimum value is 50, which usually consumes about 83kB of memory. The maximum value is 100000, which usually consumes about 163MB of memory. -The minimum value is 50, which usually consumes about 83kB of memory. The maximum value is 100000, which usually consumes about 163MB of memory. Changing `spl_check.profiler_max_shared_chunks` requires a PostgreSQL restart. +!!! Note + Changing `spl_check.profiler_max_shared_chunks` requires a PostgreSQL restart. -The profiler also retrieves the query identifier for each instruction that contains an expression or optimizable statement. However, `pg_stat_statements` (or another similar third-party extensions) must be installed. +The profiler also retrieves the query identifier for each instruction that contains an expression or optimizable statement. However, `pg_stat_statements` (or another, similar third-party extension) must be installed. -There following are limitations of the query identifier retrieval: +The following are limitations of the query identifier retrieval: -- If a `edbspl` expression contains underlying statements, only the top level query identifier is retrieved. -- The profiler doesn't compute the query identifier and instead relies on the external extension, like `pg_stat_statements`. Depending on the external extension's behavior, a query identifier may not show for some statements. For example, `pg_stat_statements` doesn't show the query identifier for queries with DDL statements. -- The profiler retrieves a query identifier only for instructions containing expressions. So, the function `spl_check.profiler_max_shared_chunks` can report less query identifiers than instructions on a single line. +- If a `EDB SPL Check expression contains underlying statements, only the top-level query identifier is retrieved. +- The profiler doesn't compute the query identifier and instead relies on the external extension, like `pg_stat_statements`. Depending on the external extension's behavior, a query identifier might not show for some statements. For example, `pg_stat_statements` doesn't show the query identifier for queries with DDL statements. +- The profiler retrieves a query identifier only for instructions containing expressions. So, the function `spl_check.profiler_max_shared_chunks` can report fewer query identifiers than instructions on a single line. !!! Note Updates on shared profiles can decrease the performance on servers under higher loads. diff --git a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx index 5845a347546..3d23ab5024c 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx @@ -24,15 +24,15 @@ The number that follows `#` is the execution frame counter. This number is relat To enable tracing, set `spl_check.tracer` to `on`. !!!Warning - Enabling tracing can have a significant impact on performance. + Enabling tracing can have a significant impact on performance. To prevent performance issues, you can set a level for outputs used by the tracer with `spl_check.tracer_errlevel`. (The default is `notice`.) You can limit the output content according to the length specified with the `spl_check.tracer_variable_max_length` configuration variable. - To prevent performance issues, you can set a level for outputs used by the tracer with `spl_check.tracer_errlevel` (the default is `notice`). And, the output content can be limited according to the length specified with the `spl_check.tracer_variable_max_length` configuration variable. +As a security safeguard, we recommend that the use of the tracer be enabled by a superuser by setting `spl_check.enable_tracer` to `on` or `spl_check.enable_tracer` to `on` in `postgresql.conf`. Because the tracer shows the content of EDB SPL Check's variables, some sensitive security information can display for an unprivileged user. -As a security safeguard, we recommend that the usage of the tracer be enabled by a superuser by setting `spl_check.enable_tracer` to `on` or `spl_check.enable_tracer` to `on` in `postgresql.conf`. Because the tracer shows the content of EDB SPL Check's variables, some sensitive security information can display for an unprivileged user. +We also recommend that you load the extension `spl_check`. You can execute some `spl_check` functions explicitly with `load 'spl_check';`. You can use the configuration's `shared_preload_libraries`, `local_preload_libraries`, or `session_preload_libraries` option. -We also recommend that the extension `spl_check` is loaded. You can execute some `spl_check` function or explicitly with the `load 'spl_check';`. You can use the configuration's option `shared_preload_libraries`, `local_preload_libraries`, or `session_preload_libraries`. +] -In terse verbose mode the output is reduced: +In terse verbose mode, the output is reduced: ```sql postgres=# set spl_check.tracer_verbosity TO terse; @@ -46,7 +46,7 @@ NOTICE: #2 end of fx NOTICE: #0 end of inline code block ``` -In verbose mode the output is extended with statement details: +In verbose mode, the output is extended with statement details: ```sql postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; @@ -74,7 +74,7 @@ NOTICE: #0.1 <-- end of PERFORM (elapsed time=1.147 ms) NOTICE: #0 <<- end of block (elapsed time=1.286 ms) ``` -A special feature of the tracer is the tracing of the `ASSERT` statement when `spl_check.trace_assert` is `on`. When `spl_check.trace_assert_verbosity` is `DEFAULT` and the `ASSERT` statement is `false`, all functions' or procedures' variables are displayed. When this configuration is `VERBOSE`, all variables from all EDB SPL frames are displayed. This behavior is independent of the `spl.check_asserts` value. It can be used, but the assertions are disabled during EDB SPL runtime. For example: +A special feature of the tracer is the tracing of the `ASSERT` statement when `spl_check.trace_assert` is `on`. When `spl_check.trace_assert_verbosity` is `DEFAULT` and the `ASSERT` statement is `false`, all function or procedure variables are displayed. When this configuration is `VERBOSE`, all variables from all EDB SPL frames are displayed. This behavior is independent of the `spl.check_asserts` value. It can be used, but the assertions are disabled during EDB SPL runtime. For example: ```sql postgres=# set spl_check.tracer to off; @@ -106,7 +106,7 @@ DO ## plugin_debugger -If you plan to use `plugin_debugger` (plpgsql debugger) with EDB SPL Check, we recommend that you initialize `plugin_debugger` first. `plugin_debugger` doesn't support the sharing of PL/pgSQL's debug API. +If you plan to use `plugin_debugger` (the plpgsql debugger) with EDB SPL Check, we recommend that you initialize `plugin_debugger` first. `plugin_debugger` doesn't support sharing the PL/pgSQL debug API. For example: From 2bc781c3fc4a22c5fd832b4a1ee32c806de1be9f Mon Sep 17 00:00:00 2001 From: Betsy Gitelman <93718720+ebgitelman@users.noreply.github.com> Date: Tue, 19 Sep 2023 14:38:49 -0400 Subject: [PATCH 11/24] Update index.mdx --- advocacy_docs/pg_extensions/spl_check/using/index.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx index 4dfca882919..ef791b7472b 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -1,4 +1,4 @@ ---- +S--- title: Using EDB SPL Check navTitle: Using --- @@ -202,7 +202,7 @@ $$ LANGUAGE edbspl SET edbspl.enable_check TO false; ### Dynamic SQL -This module doesn't check queries that are assembled in runtime because you can't identify the results of dynamic queries. Therefore, EDB SPL Check can't set the correct type to record variables and can't check a dependent SQL's or expressions. +This module doesn't check queries that are assembled in runtime because you can't identify the results of dynamic queries. Therefore, EDB SPL Check can't set the correct type to record variables and can't check a dependent SQL `or` expressions. When the type of a record's variable is unknown, you can explicitly assign it with pragma `type`. For example: @@ -288,4 +288,4 @@ postgres=# CREATE TABLE postgres=# INSERT INTO foo VALUES(10,20); INSERT 0 1 -``` \ No newline at end of file +``` From 4ae3eb51aab05f8712c85ae3ec3cd3df2f057946 Mon Sep 17 00:00:00 2001 From: Betsy Gitelman <93718720+ebgitelman@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:11:11 -0400 Subject: [PATCH 12/24] Update configuring.mdx --- advocacy_docs/pg_extensions/spl_check/configuring.mdx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/configuring.mdx b/advocacy_docs/pg_extensions/spl_check/configuring.mdx index 75ae5c56eed..2c5e20022b0 100644 --- a/advocacy_docs/pg_extensions/spl_check/configuring.mdx +++ b/advocacy_docs/pg_extensions/spl_check/configuring.mdx @@ -10,12 +10,10 @@ CREATE EXTENSION spl_check ``` You can run EDB SPL Check in active mode or passive mode. In active mode, you can run checks with API functions like `spl_check_function`. In passive mode, functions are checked when executed. - ## Active mode In active mode, start checks by running API functions like `spl_check_function`. Active mode is the default behavior for EDB SPL Check. However, you can change this mode with the `spl_check.mode` setting. See [Configuring passive mode](#configuring-passive-mode) for more information. - You can also use the functions `spl_check_package`, `spl_check_objecttype`, and `spl_check_trigger` to validate your code. See [Using EDB SPL Check](using) for more information. @@ -265,8 +263,6 @@ spl_check.show_performance_warnings = false By default, `spl_check.mode` is set to `by_function`, which means that checks are done only in active mode by using `spl_check_function`. `fresh_start` means cold start, so function's called first. - - To enable passive mode: ```sql From dcabb8c4c4d7ef030d70f57a284b42a473025cf3 Mon Sep 17 00:00:00 2001 From: Betsy Gitelman <93718720+ebgitelman@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:11:52 -0400 Subject: [PATCH 13/24] Update index.mdx --- advocacy_docs/pg_extensions/spl_check/index.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/index.mdx b/advocacy_docs/pg_extensions/spl_check/index.mdx index 64a4c85d92d..15e2b979606 100644 --- a/advocacy_docs/pg_extensions/spl_check/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/index.mdx @@ -7,7 +7,6 @@ EDB SPL Check is a code analysis tool for SPL on EDB Postgres Advanced Server. U You can control the levels of many warnings and hints. For instance, you can add `PRAGAMA` type markers to turn certain aspects off or on, allowing you to hide messages you're already aware of or keep ones you want to be reminded of. EDB SPL Check is supported on EDB Postgres Advanced Server versions 12 and later. - These are some of the key features of EDB SPL Check: @@ -17,6 +16,5 @@ These are some of the key features of EDB SPL Check: - Partially detects dead code, that is, code after an unqualified `RETURN` command - Detects missing `RETURN` commands in functions, which are common after exception handlers or complex logic - Tries to identify unwanted hidden casts, which can be a performance issues like unused indexes - - Collects relations and functions used by a function -- Checks `EXECUTE` statements against SQL injection vulnerability \ No newline at end of file +- Checks `EXECUTE` statements against SQL injection vulnerability From dd3d513e25663d74c39897969a001c2197d9e681 Mon Sep 17 00:00:00 2001 From: Betsy Gitelman <93718720+ebgitelman@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:13:18 -0400 Subject: [PATCH 14/24] Update index.mdx --- advocacy_docs/pg_extensions/spl_check/using/index.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx index ef791b7472b..4582b477dac 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -182,7 +182,6 @@ ORDER BY (pcf).functionid::regprocedure::text, (pcf).lineno; ## Limitations EDB SPL Check finds almost all errors on static code. However, when using PL/pgSQL's dynamic features like dynamic SQL or the record-data data type, false positives are possible. In these cases, we recommend that you rewrite the affected function or disable EDB SPL Check for the function. For example: - ```sql CREATE OR REPLACE FUNCTION f1() @@ -203,7 +202,6 @@ $$ LANGUAGE edbspl SET edbspl.enable_check TO false; ### Dynamic SQL This module doesn't check queries that are assembled in runtime because you can't identify the results of dynamic queries. Therefore, EDB SPL Check can't set the correct type to record variables and can't check a dependent SQL `or` expressions. - When the type of a record's variable is unknown, you can explicitly assign it with pragma `type`. For example: From d04f90b205ed3154c5aeb1bb8944619ffb8c4960 Mon Sep 17 00:00:00 2001 From: Betsy Gitelman <93718720+ebgitelman@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:13:51 -0400 Subject: [PATCH 15/24] Update pragma.mdx --- advocacy_docs/pg_extensions/spl_check/using/pragma.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx index ad52f8ce167..b2460c91ee4 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx @@ -4,8 +4,6 @@ title: Pragma You can configure EDB SPL Check's behavior inside a checked function with a pragma function. This is an analogy of PL/SQL or ADA language of a pragma feature. PL/pgSQL doesn't support pragma, but EDB SPL Check detects functions named `spl_check_pragma` and takes options from the parameters of the function. These EDB SPL Check options are valid to add to the end of this group of statements: - - ```sql CREATE OR REPLACE FUNCTION test() RETURNS void AS $$ @@ -84,4 +82,4 @@ Creates an ephemeral temporary sequence. !!! Note Pragmas `enable:tracer` and `disable:tracer` are active for Postgres versions 12 and later. -!!! \ No newline at end of file +!!! From 49f80249ad04cff2c28661c57df1a1b3fd7863fd Mon Sep 17 00:00:00 2001 From: Betsy Gitelman <93718720+ebgitelman@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:14:31 -0400 Subject: [PATCH 16/24] Update profiler.mdx --- advocacy_docs/pg_extensions/spl_check/using/profiler.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx index 4661fa42c30..f768b81cdb1 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx @@ -8,8 +8,6 @@ When EDB SPL Check is initialized by `shared_preload_libraries`, it can allocate Due to dependencies, `shared_preload_libraries` must contain `edbspl` first: - - ```sql postgres=# show shared_preload_libraries ; __OUTPUT__ @@ -119,4 +117,4 @@ __OUTPUT__ EDB SPL Check provides two functions: - `spl_coverage_statements(name)` -- `spl_coverage_branches(name)` \ No newline at end of file +- `spl_coverage_branches(name)` From b698293c36e804477417dcc7ef4d18c35f2ef5e4 Mon Sep 17 00:00:00 2001 From: Betsy Gitelman <93718720+ebgitelman@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:15:04 -0400 Subject: [PATCH 17/24] Update tracer.mdx --- advocacy_docs/pg_extensions/spl_check/using/tracer.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx index 3d23ab5024c..79714ce247c 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx @@ -30,8 +30,6 @@ As a security safeguard, we recommend that the use of the tracer be enabled by a We also recommend that you load the extension `spl_check`. You can execute some `spl_check` functions explicitly with `load 'spl_check';`. You can use the configuration's `shared_preload_libraries`, `local_preload_libraries`, or `session_preload_libraries` option. -] - In terse verbose mode, the output is reduced: ```sql @@ -112,4 +110,4 @@ For example: ```ini shared_preload_libraries = 'plugin_debugger,edb-spl,spl_check' -``` \ No newline at end of file +``` From c18fe1050fc8ba6599702c154d1f6173fb2c4c50 Mon Sep 17 00:00:00 2001 From: Chris Estes <106166814+ccestes@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:09:04 -0400 Subject: [PATCH 18/24] triveni feedback --- .../pg_extensions/spl_check/configuring.mdx | 29 +++++++------ .../pg_extensions/spl_check/index.mdx | 4 +- .../spl_check/using/dependency_list.mdx | 2 +- .../pg_extensions/spl_check/using/index.mdx | 12 ++++-- .../spl_check/using/profiler.mdx | 14 +++---- .../pg_extensions/spl_check/using/tracer.mdx | 41 ++++++++++--------- 6 files changed, 56 insertions(+), 46 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/configuring.mdx b/advocacy_docs/pg_extensions/spl_check/configuring.mdx index 2c5e20022b0..ca067ca1075 100644 --- a/advocacy_docs/pg_extensions/spl_check/configuring.mdx +++ b/advocacy_docs/pg_extensions/spl_check/configuring.mdx @@ -6,7 +6,7 @@ navTitle: Configuring To run EDB SPL Check, use the `CREATE EXTENSION` command: ```sql -CREATE EXTENSION spl_check +CREATE EXTENSION spl_check; ``` You can run EDB SPL Check in active mode or passive mode. In active mode, you can run checks with API functions like `spl_check_function`. In passive mode, functions are checked when executed. @@ -22,10 +22,11 @@ You can also use the functions `spl_check_package`, `spl_check_objecttype`, and The validator checks the SQL statements inside SPL functions for semantic errors: ```sql -postgres=# CREATE TABLE t1(a int, b int); +CREATE TABLE t1(a int, b int); +__OUTPUT__ CREATE TABLE - -postgres=# +``` +```sql CREATE OR REPLACE FUNCTION public.f1() RETURNS void LANGUAGE edbspl @@ -45,21 +46,20 @@ CREATE FUNCTION `RAISE NOTICE '%', r.c;` indicates that there's a bug, which is that table `t1` is missing a `c` column. However, the `CREATE FUNCTION` command doesn't identify there's a bug because table `t1` is empty: ```sql -postgres=# select f1(); +select f1(); __OUTPUT__ - f1 - ──── +f1 +──── - (1 row) +(1 row) ``` You can view the bug and other semantic errors by running `spl_check_function`: ```sql -postgres=# \x -Expanded display is on. -postgres=# select * from spl_check_function_tb('f1()'); +select * from spl_check_function_tb('f1()'); +__OUTPUT__ ─[ RECORD 1 ]─────────────────────────── functionid │ f1 lineno │ 6 @@ -77,6 +77,7 @@ query │ [null] ```sql select * from spl_check_function('f1()', fatal_errors := false); +__OUTPUT__ spl_check_function ------------------------------------------------------------------------ error:42703:4:SQL statement:column "c" of relation "t1" does not exist @@ -87,8 +88,11 @@ select * from spl_check_function('f1()', fatal_errors := false); -- ^ error:42601:7:RAISE:too few parameters specified for RAISE (7 rows) +``` -postgres=# select * from spl_check_function('fx()', format:='xml'); +```sql +select * from spl_check_function('fx()', format:='xml'); +__OUTPUT__ spl_check_function ──────────────────────────────────────────────────────────────── ↵ @@ -232,6 +236,7 @@ end; $$ LANGUAGE edbspl; select * from spl_check_function('foo', extra_warnings =>false, compatibility_warnings => true); +__OUTPUT__ ┌───────────────────────────────────────────────────────────────────────────────────┐ │ spl_check_function │ ╞═══════════════════════════════════════════════════════════════════════════════════╡ diff --git a/advocacy_docs/pg_extensions/spl_check/index.mdx b/advocacy_docs/pg_extensions/spl_check/index.mdx index 15e2b979606..cd1b518dc34 100644 --- a/advocacy_docs/pg_extensions/spl_check/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/index.mdx @@ -4,7 +4,7 @@ title: EDB SPL Check EDB SPL Check is a code analysis tool for SPL on EDB Postgres Advanced Server. Using only the internal PostgreSQL parser, it identifies errors that can occur at runtime. In addition, it parses the SQL inside your routines and identifies errors that are usually missed when executing `CREATE PROCEDURE/FUNCTION/PACKAGE`. Similarly, it identifies errors that are usually missed when executing `CREATE PACKAGE/OBJECT TYPES/COMPOUND TRIGGER`. -You can control the levels of many warnings and hints. For instance, you can add `PRAGAMA` type markers to turn certain aspects off or on, allowing you to hide messages you're already aware of or keep ones you want to be reminded of. +You can control the levels of many warnings and hints. For instance, you can add `PRAGMA` type markers to turn certain aspects off or on, allowing you to hide messages you're already aware of or keep ones you want to be reminded of. EDB SPL Check is supported on EDB Postgres Advanced Server versions 12 and later. @@ -17,4 +17,4 @@ These are some of the key features of EDB SPL Check: - Detects missing `RETURN` commands in functions, which are common after exception handlers or complex logic - Tries to identify unwanted hidden casts, which can be a performance issues like unused indexes - Collects relations and functions used by a function -- Checks `EXECUTE` statements against SQL injection vulnerability +- Checks `EXECUTE` statements against SQL injection vulnerability \ No newline at end of file diff --git a/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx b/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx index 7d4c4fafea3..ac06006d381 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx @@ -5,7 +5,7 @@ title: Dependency list The function `spl_show_dependency_tb` shows all the functions, operators, and relations used inside a processed function. For example: ```sql -postgres=# select * from spl_show_dependency_tb('testfunc(int,float)'); +select * from spl_show_dependency_tb('testfunc(int,float)'); __OUTPUT__ ┌──────────┬───────┬────────┬─────────┬────────────────────────────┐ │ type │ oid │ schema │ name │ params │ diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx index 4582b477dac..b8165205733 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -1,4 +1,4 @@ -S--- +--- title: Using EDB SPL Check navTitle: Using --- @@ -12,7 +12,9 @@ To check any trigger, enter a relation that's used with the trigger function. Fo ```sql CREATE TABLE bar(a int, b int); -postgres=# \sf+ foo_trg +CREATE OR REPLACE FUNCTION public.foo(); + +\sf+ foo_trg CREATE OR REPLACE FUNCTION public.foo_trg() RETURNS trigger LANGUAGE edbspl @@ -27,7 +29,8 @@ postgres=# \sf+ foo_trg When there's no specified relation for the trigger, the following is returned: ```sql -postgres=# select * from spl_check_function('foo_trg()'); +select * from spl_check_function('foo_trg()'); +__OUTPUT__ ERROR: missing trigger relation HINT: Trigger relation oid must be valid ``` @@ -35,7 +38,7 @@ HINT: Trigger relation oid must be valid When the trigger is checked successfully with a specified relation, the following is returned: ```sql -postgres=# select * from spl_check_function('foo_trg()', 'bar'); +select * from spl_check_function('foo_trg()', 'bar'); __OUTPUT__ spl_check_function -------------------------------------------------------- @@ -287,3 +290,4 @@ CREATE TABLE postgres=# INSERT INTO foo VALUES(10,20); INSERT 0 1 ``` + diff --git a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx index f768b81cdb1..c83c305382a 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx @@ -2,19 +2,19 @@ title: Profiler --- -EDB SPL Check contains a simple profiler of `edbspl` functions and procedures. It can work with or without access to shared memory and depends on the `shared_preload_libraries` config. +EDB SPL Check contains a simple profiler of SPL functions and procedures. It can work with or without access to shared memory and depends on the `shared_preload_libraries` config. When EDB SPL Check is initialized by `shared_preload_libraries`, it can allocate shared memory and stores function profiles. When EDB SPL Check can't allocate shared memory, the profile is stored in session memory. -Due to dependencies, `shared_preload_libraries` must contain `edbspl` first: +Due to dependencies, `shared_preload_libraries` must contain `edb-spl` first: ```sql -postgres=# show shared_preload_libraries ; +show shared_preload_libraries ; __OUTPUT__ ┌──────────────────────────┐ │ shared_preload_libraries │ ╞══════════════════════════╡ -│ edb-spl,spl_check │ +│ edb-spl,spl_check │ └──────────────────────────┘ (1 row) ``` @@ -48,7 +48,7 @@ The following are limitations of the query identifier retrieval: Display the profile with `spl_profiler_function_tb`: ```sql -postgres=# select lineno, avg_time, source from spl_profiler_function_tb('fx(int)'); +select lineno, avg_time, source from spl_profiler_function_tb('fx(int)'); __OUTPUT__ ┌────────┬──────────┬───────────────────────────────────────────────────────────────────┐ │ lineno │ avg_time │ source │ @@ -83,7 +83,7 @@ Display the profile per statements with `spl_profiler_function_statements_tb`: 10 end; 11 $function$ -postgres=# select stmtid, parent_stmtid, parent_note, lineno, exec_stmts, stmtname +select stmtid, parent_stmtid, parent_note, lineno, exec_stmts, stmtname from spl_profiler_function_statements_tb('fx1'); __OUTPUT__ ┌────────┬───────────────┬─────────────┬────────┬────────────┬─────────────────┐ @@ -102,7 +102,7 @@ __OUTPUT__ Display all stored profiles with `spl_profiler_functions_all`: ```sql -postgres=# select * from spl_profiler_functions_all(); +select * from spl_profiler_functions_all(); __OUTPUT__ ┌───────────────────────┬────────────┬────────────┬──────────┬─────────────┬──────────┬──────────┐ │ funcoid │ exec_count │ total_time │ avg_time │ stddev_time │ min_time │ max_time │ diff --git a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx index 79714ce247c..9b116ff6cc5 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx @@ -4,7 +4,7 @@ title: Tracer EDB SPL Check provides a tracing option where you can see notices on start or end functions (terse and default verbosity) and start or end statements (verbose verbosity). For default and verbose verbosity, this option displays the content of function arguments. The content of related variables diplay when verbosity is verbose. For example: ```sql -postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; NOTICE: #0 ->> start of inline_code_block (Oid=0) NOTICE: #2 ->> start of function fx(integer,integer,date,text) (Oid=16405) NOTICE: #2 call by inline_code_block line 1 at PERFORM @@ -33,9 +33,13 @@ We also recommend that you load the extension `spl_check`. You can execute some In terse verbose mode, the output is reduced: ```sql -postgres=# set spl_check.tracer_verbosity TO terse; +set spl_check.tracer_verbosity TO terse; +__OUTPUT__ SET -postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +``` +```sql +do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +__OUTPUT__ NOTICE: #0 start of inline code block (oid=0) NOTICE: #2 start of fx (oid=16405) NOTICE: #4 start of fx (oid=16404) @@ -47,7 +51,8 @@ NOTICE: #0 end of inline code block In verbose mode, the output is extended with statement details: ```sql -postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +__OUTPUT__ NOTICE: #0 ->> start of block inline_code_block (oid=0) NOTICE: #0.1 1 --> start of PERFORM NOTICE: #2 ->> start of function fx(integer,integer,date,text) (oid=16405) @@ -75,10 +80,11 @@ NOTICE: #0 <<- end of block (elapsed time=1.286 ms) A special feature of the tracer is the tracing of the `ASSERT` statement when `spl_check.trace_assert` is `on`. When `spl_check.trace_assert_verbosity` is `DEFAULT` and the `ASSERT` statement is `false`, all function or procedure variables are displayed. When this configuration is `VERBOSE`, all variables from all EDB SPL frames are displayed. This behavior is independent of the `spl.check_asserts` value. It can be used, but the assertions are disabled during EDB SPL runtime. For example: ```sql -postgres=# set spl_check.tracer to off; -postgres=# set spl_check.trace_assert_verbosity TO verbose; +set spl_check.tracer to off; +set spl_check.trace_assert_verbosity TO verbose; -postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +__OUTPUT__ NOTICE: #4 PLpgSQL assert expression (false) on line 12 of fx(integer) is false NOTICE: "a" => '10', "res" => null, "b" => '20' NOTICE: #2 PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM @@ -90,10 +96,15 @@ SQL statement "SELECT fx(a)" PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM SQL statement "SELECT fx(10,null, 'now', e'stěhule')" PL/pgSQL function inline_code_block line 1 at PERFORM - -postgres=# set spl.check_asserts to off; +``` +```sql +set spl.check_asserts to off; +__OUTPUT__ SET -postgres=# do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +``` +```sql +do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +__OUTPUT__ NOTICE: #4 PLpgSQL assert expression (false) on line 12 of fx(integer) is false NOTICE: "a" => '10', "res" => null, "b" => '20' NOTICE: #2 PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM @@ -101,13 +112,3 @@ NOTICE: "a" => '10', "b" => null, "c" => '2020-08-05', "d" => 'stěhule' NOTICE: #0 PL/pgSQL function inline_code_block line 1 at PERFORM DO ``` - -## plugin_debugger - -If you plan to use `plugin_debugger` (the plpgsql debugger) with EDB SPL Check, we recommend that you initialize `plugin_debugger` first. `plugin_debugger` doesn't support sharing the PL/pgSQL debug API. - -For example: - -```ini -shared_preload_libraries = 'plugin_debugger,edb-spl,spl_check' -``` From c56cb9fc5fc0aa4964c556294070e7da2ffc0394 Mon Sep 17 00:00:00 2001 From: Chris Estes <106166814+ccestes@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:30:19 -0400 Subject: [PATCH 19/24] Betsy feedback remaining Betsy feedback --- advocacy_docs/pg_extensions/spl_check/configuring.mdx | 2 +- advocacy_docs/pg_extensions/spl_check/index.mdx | 2 +- advocacy_docs/pg_extensions/spl_check/using/index.mdx | 2 +- advocacy_docs/pg_extensions/spl_check/using/tracer.mdx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/configuring.mdx b/advocacy_docs/pg_extensions/spl_check/configuring.mdx index ca067ca1075..832091831d3 100644 --- a/advocacy_docs/pg_extensions/spl_check/configuring.mdx +++ b/advocacy_docs/pg_extensions/spl_check/configuring.mdx @@ -266,7 +266,7 @@ spl_check.show_nonperformance_warnings = false spl_check.show_performance_warnings = false ``` -By default, `spl_check.mode` is set to `by_function`, which means that checks are done only in active mode by using `spl_check_function`. `fresh_start` means cold start, so function's called first. +By default, `spl_check.mode` is set to `by_function`, which means that checks are done only in active mode by using `spl_check_function`. `fresh_start` means cold start, so the function is called first. To enable passive mode: diff --git a/advocacy_docs/pg_extensions/spl_check/index.mdx b/advocacy_docs/pg_extensions/spl_check/index.mdx index cd1b518dc34..d0c91ba5fe8 100644 --- a/advocacy_docs/pg_extensions/spl_check/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/index.mdx @@ -15,6 +15,6 @@ These are some of the key features of EDB SPL Check: - Identifies unused variables and function arguments as well as unmodified `OUT` arguments - Partially detects dead code, that is, code after an unqualified `RETURN` command - Detects missing `RETURN` commands in functions, which are common after exception handlers or complex logic -- Tries to identify unwanted hidden casts, which can be a performance issues like unused indexes +- Tries to identify unwanted hidden casts, which can cause performance issues like unused indexes - Collects relations and functions used by a function - Checks `EXECUTE` statements against SQL injection vulnerability \ No newline at end of file diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx index b8165205733..1a875db599c 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -184,7 +184,7 @@ ORDER BY (pcf).functionid::regprocedure::text, (pcf).lineno; ## Limitations -EDB SPL Check finds almost all errors on static code. However, when using PL/pgSQL's dynamic features like dynamic SQL or the record-data data type, false positives are possible. In these cases, we recommend that you rewrite the affected function or disable EDB SPL Check for the function. For example: +EDB SPL Check finds almost all errors on static code. However, when using PL/pgSQL's dynamic features like dynamic SQL or the record data type, false positives are possible. In these cases, we recommend that you rewrite the affected function or disable EDB SPL Check for the function. For example: ```sql CREATE OR REPLACE FUNCTION f1() diff --git a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx index 9b116ff6cc5..c0110c36509 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx @@ -28,7 +28,7 @@ To enable tracing, set `spl_check.tracer` to `on`. As a security safeguard, we recommend that the use of the tracer be enabled by a superuser by setting `spl_check.enable_tracer` to `on` or `spl_check.enable_tracer` to `on` in `postgresql.conf`. Because the tracer shows the content of EDB SPL Check's variables, some sensitive security information can display for an unprivileged user. -We also recommend that you load the extension `spl_check`. You can execute some `spl_check` functions explicitly with `load 'spl_check';`. You can use the configuration's `shared_preload_libraries`, `local_preload_libraries`, or `session_preload_libraries` option. +We also recommend that you load the extension `spl_check`. You can execute some `spl_check` functions explicitly with `load 'spl_check';`. You can also set the configuration options in `shared_preload_libraries`, `local_preload_libraries`, or `session_preload_libraries` options to load `spl_check`. In terse verbose mode, the output is reduced: From b045230a10b8ce84df625378d1d530d5db57bc73 Mon Sep 17 00:00:00 2001 From: nidhibhammar <59045594+nidhibhammar@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:02:49 +0530 Subject: [PATCH 20/24] Capitalised the keywords in the code block and formatted the output --- .../pg_extensions/spl_check/index.mdx | 2 + .../pg_extensions/spl_check/using/index.mdx | 56 +++++++++---------- .../spl_check/using/profiler.mdx | 8 +-- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/index.mdx b/advocacy_docs/pg_extensions/spl_check/index.mdx index d0c91ba5fe8..2617410ea94 100644 --- a/advocacy_docs/pg_extensions/spl_check/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/index.mdx @@ -1,5 +1,7 @@ --- title: EDB SPL Check +directoryDefaults: + product: EDB SPL Check --- EDB SPL Check is a code analysis tool for SPL on EDB Postgres Advanced Server. Using only the internal PostgreSQL parser, it identifies errors that can occur at runtime. In addition, it parses the SQL inside your routines and identifies errors that are usually missed when executing `CREATE PROCEDURE/FUNCTION/PACKAGE`. Similarly, it identifies errors that are usually missed when executing `CREATE PACKAGE/OBJECT TYPES/COMPOUND TRIGGER`. diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx index 1a875db599c..7945e16c730 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -15,21 +15,21 @@ CREATE TABLE bar(a int, b int); CREATE OR REPLACE FUNCTION public.foo(); \sf+ foo_trg - CREATE OR REPLACE FUNCTION public.foo_trg() - RETURNS trigger - LANGUAGE edbspl -1 AS $function$ -2 BEGIN -3 NEW.c := NEW.a + NEW.b; -4 RETURN NEW; -5 END; -6 $function$ +CREATE OR REPLACE FUNCTION public.foo_trg() + RETURNS trigger + LANGUAGE edbspl + AS $function$ + BEGIN + NEW.c := NEW.a + NEW.b; + RETURN NEW; + END; +$function$ ``` When there's no specified relation for the trigger, the following is returned: ```sql -select * from spl_check_function('foo_trg()'); +SELECT * FROM spl_check_function('foo_trg()'); __OUTPUT__ ERROR: missing trigger relation HINT: Trigger relation oid must be valid @@ -38,7 +38,7 @@ HINT: Trigger relation oid must be valid When the trigger is checked successfully with a specified relation, the following is returned: ```sql -select * from spl_check_function('foo_trg()', 'bar'); +SELECT * FROM spl_check_function('foo_trg()', 'bar'); __OUTPUT__ spl_check_function -------------------------------------------------------- @@ -49,22 +49,22 @@ __OUTPUT__ For triggers with transitive tables, set the `oldtable` and `newtable` parameters: ```sql -create or replace function footab_trig_func() -returns trigger as $$ -declare x int; -begin - if false then +CREATE OR REPLACE FUNCTION footab_trig_func() +RETURNS trigger as $$ +DECLARE x int; +BEGIN + IF false THEN -- should be ok; - select count(*) from newtab into x; + SELECT COUNT(*) FROM newtab INTO x; -- should fail; - select count(*) from newtab where d = 10 into x; - end if; - return null; -end; -$$ language edbspl; + SELECT COUNT(*) FROM newtab WHERE d = 10 into x; + END If; + RETURN null; +END; +$$ LANGUAGE edbspl; -select * from spl_check_function('footab_trig_func','footab', newtable := 'newtab'); +SELECT * FROM spl_check_function('footab_trig_func','footab', newtable := 'newtab'); ``` ## Validating compound triggers @@ -72,12 +72,12 @@ select * from spl_check_function('footab_trig_func','footab', newtable := 'newta Another way to verify a trigger function is to use `spl_check_trigger()` by providing the trigger name and, optionally, the relation name. This method is useful for redwood-style triggers and compound triggers where trigger functions are created internally. For example: ```sql -create table tab(a int); -create or replace trigger tg1 before insert on tab -for each row -begin +CREATE TABLE tab(a int); +CREATE or REPLACE trigger tg1 before insert on tab +FOR EACH ROW +BEGIN NEW.a := NEW.b; -end; +END; select * from spl_check_trigger('tg1'); __OUTPUT__ diff --git a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx index c83c305382a..668cbb343d3 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx @@ -11,11 +11,9 @@ Due to dependencies, `shared_preload_libraries` must contain `edb-spl` first: ```sql show shared_preload_libraries ; __OUTPUT__ -┌──────────────────────────┐ -│ shared_preload_libraries │ -╞══════════════════════════╡ -│ edb-spl,spl_check │ -└──────────────────────────┘ + shared_preload_libraries +---------------------------- + edb-spl,spl_check (1 row) ``` From 2052e667463192c134e3dda7717398edb0e7f96e Mon Sep 17 00:00:00 2001 From: Chris Estes <106166814+ccestes@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:39:31 -0400 Subject: [PATCH 21/24] code block fixes cont. --- .../pg_extensions/spl_check/configuring.mdx | 79 +++++++----- .../spl_check/using/dependency_list.mdx | 10 +- .../pg_extensions/spl_check/using/index.mdx | 113 +++++++++--------- .../spl_check/using/profiler.mdx | 101 ++++++++-------- .../pg_extensions/spl_check/using/tracer.mdx | 42 ++++--- 5 files changed, 189 insertions(+), 156 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/configuring.mdx b/advocacy_docs/pg_extensions/spl_check/configuring.mdx index 832091831d3..67c27b767cf 100644 --- a/advocacy_docs/pg_extensions/spl_check/configuring.mdx +++ b/advocacy_docs/pg_extensions/spl_check/configuring.mdx @@ -23,7 +23,9 @@ The validator checks the SQL statements inside SPL functions for semantic errors ```sql CREATE TABLE t1(a int, b int); -__OUTPUT__ +``` +``` +OUTPUT CREATE TABLE ``` ```sql @@ -33,22 +35,26 @@ LANGUAGE edbspl AS $function$ DECLARE r record; BEGIN - FOR r IN SELECT * FROM t1 - LOOP - RAISE NOTICE '%', r.c; - END LOOP; +FOR r IN SELECT * FROM t1 +LOOP + RAISE NOTICE '%', r.c; +END LOOP; END; $function$; - +``` +``` +OUTPUT CREATE FUNCTION ``` `RAISE NOTICE '%', r.c;` indicates that there's a bug, which is that table `t1` is missing a `c` column. However, the `CREATE FUNCTION` command doesn't identify there's a bug because table `t1` is empty: ```sql -select f1(); -__OUTPUT__ -f1 +SELECT f1(); +``` +``` +OUTPUT + f1 ──── (1 row) @@ -58,8 +64,10 @@ f1 You can view the bug and other semantic errors by running `spl_check_function`: ```sql -select * from spl_check_function_tb('f1()'); -__OUTPUT__ +SELECT * FROM spl_check_function_tb('f1()'); +``` +``` +OUTPUT ─[ RECORD 1 ]─────────────────────────── functionid │ f1 lineno │ 6 @@ -76,8 +84,10 @@ query │ [null] `spl_check_function()` has three possible output formats, which are text, json, and xml: ```sql -select * from spl_check_function('f1()', fatal_errors := false); -__OUTPUT__ +SELECT * FROM spl_check_function('f1()', fatal_errors := false); +``` +``` +OUTPUT spl_check_function ------------------------------------------------------------------------ error:42703:4:SQL statement:column "c" of relation "t1" does not exist @@ -91,8 +101,10 @@ __OUTPUT__ ``` ```sql -select * from spl_check_function('fx()', format:='xml'); -__OUTPUT__ +SELECT * FROM spl_check_function('fx()', format:='xml'); +``` +``` +OUTPUT spl_check_function ──────────────────────────────────────────────────────────────── ↵ @@ -225,25 +237,26 @@ When the `compatibility_warnings` flag is active, EDB SPL Check tries to identif CREATE OR REPLACE FUNCTION public.foo() RETURNS refcursor AS $$ -declare - c cursor for select 1; +DECLARE + c cursor FOR SELECT 1; r refcursor; -begin - open c; +BEGIN + OPEN c; r := 'c'; - return r; -end; + RETURN r; +END; $$ LANGUAGE edbspl; -select * from spl_check_function('foo', extra_warnings =>false, compatibility_warnings => true); -__OUTPUT__ -┌───────────────────────────────────────────────────────────────────────────────────┐ -│ spl_check_function │ -╞═══════════════════════════════════════════════════════════════════════════════════╡ -│ compatibility:00000:6:assignment:obsolete setting of refcursor or cursor variable │ -│ Detail: Internal name of cursor should not be specified by users. │ -│ Context: at assignment to variable "r" declared on line 3 │ -└───────────────────────────────────────────────────────────────────────────────────┘ +SELECT * FROM spl_check_function('foo', extra_warnings =>false, compatibility_warnings => true); +``` +``` +OUTPUT + spl_check_function +----------------------------------------------------------------------------------- + compatibility:00000:6:assignment:obsolete setting of refcursor or cursor variable + Detail: Internal name of cursor should not be specified by users. + Context: at assignment to variable "r" declared on line 3 + (3 rows) ``` @@ -271,9 +284,9 @@ By default, `spl_check.mode` is set to `by_function`, which means that checks ar To enable passive mode: ```sql -load 'edb-spl'; -- 1.1 and higher doesn't need it -load 'spl_check'; -set spl_check.mode = 'every_start'; -- This scans all code before it is executed +LOAD 'edb-spl'; -- 1.1 and higher doesn't need it +LOAD 'spl_check'; +SET spl_check.mode = 'every_start'; -- This scans all code before it is executed SELECT fx(10); -- run functions - function is checked before runtime starts it ``` diff --git a/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx b/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx index ac06006d381..d7ce0636d76 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx @@ -5,17 +5,17 @@ title: Dependency list The function `spl_show_dependency_tb` shows all the functions, operators, and relations used inside a processed function. For example: ```sql -select * from spl_show_dependency_tb('testfunc(int,float)'); -__OUTPUT__ -┌──────────┬───────┬────────┬─────────┬────────────────────────────┐ +SELECT * FROM spl_show_dependency_tb('testfunc(int,float)'); +``` +``` +OUTPUT │ type │ oid │ schema │ name │ params │ -╞══════════╪═══════╪════════╪═════════╪════════════════════════════╡ +|----------|-------|--------|---------|----------------------------| │ FUNCTION │ 36008 │ public │ myfunc1 │ (integer,double precision) │ │ FUNCTION │ 35999 │ public │ myfunc2 │ (integer,double precision) │ │ OPERATOR │ 36007 │ public │ ** │ (integer,integer) │ │ RELATION │ 36005 │ public │ myview │ │ │ RELATION │ 36002 │ public │ mytable │ │ -└──────────┴───────┴────────┴─────────┴────────────────────────────┘ (4 rows) ``` diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx index 7945e16c730..cb6121276b2 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -12,9 +12,7 @@ To check any trigger, enter a relation that's used with the trigger function. Fo ```sql CREATE TABLE bar(a int, b int); -CREATE OR REPLACE FUNCTION public.foo(); -\sf+ foo_trg CREATE OR REPLACE FUNCTION public.foo_trg() RETURNS trigger LANGUAGE edbspl @@ -30,7 +28,9 @@ When there's no specified relation for the trigger, the following is returned: ```sql SELECT * FROM spl_check_function('foo_trg()'); -__OUTPUT__ +``` +``` +OUTPUT ERROR: missing trigger relation HINT: Trigger relation oid must be valid ``` @@ -39,7 +39,9 @@ When the trigger is checked successfully with a specified relation, the followin ```sql SELECT * FROM spl_check_function('foo_trg()', 'bar'); -__OUTPUT__ +``` +``` +OUTPUT spl_check_function -------------------------------------------------------- error:42703:3:assignment:record "new" has no field "c" @@ -79,8 +81,10 @@ BEGIN NEW.a := NEW.b; END; -select * from spl_check_trigger('tg1'); -__OUTPUT__ +SELECT * FROM spl_check_trigger('tg1'); +``` +``` +OUTPUT spl_check_trigger ---------------------------------------------------- error:42703:2:assignment:record "new" has no field "b" @@ -95,7 +99,7 @@ A package can have multiple functions/procedures. To validate all of your functi You can also validate individual package functions/procedures using `spl_check_function()`. For example: ```sql -select * from spl_check_package(''); +SELECT * FROM spl_check_package(''); ``` ## Validating object types @@ -105,7 +109,7 @@ Object types can have one or more member functions. To validate all the function You can also validate individual object type member functions using `spl_check_function()`. For example: ```sql -select * from spl_check_objecttype(''); +SELECT * FROM spl_check_objecttype(''); ``` ## Setting in-comment options @@ -119,16 +123,16 @@ EDB SPL Check allows persistent-setting, written in-comments. These options are The settings from comment options have top priority, but generally they can be disabled by setting `use_incomment_options` to `false`. For example: ```sql -create or replace function fx(anyelement) -returns text as $$ -begin +CREATE OR REPLACE FUNCTION fx(anyelement) +RETURNS TEXT AS $$ +BEGIN /* * rewrite default polymorphic type to text * @spl_check_options: anyelementtype = text */ - return $1; -end; -$$ language edbspl; +RETURN $1; +END; +$$ LANGUAGE edbspl; ``` ## Checking all your code @@ -139,22 +143,22 @@ To check all nontrigger EDB SPL Check functions: ```sql SELECT p.oid, p.proname, spl_check_function(p.oid) - FROM pg_catalog.pg_namespace n - JOIN pg_catalog.pg_proc p ON pronamespace = n.oid - JOIN pg_catalog.pg_language l ON p.prolang = l.oid - WHERE l.lanname = 'edbspl' AND p.prorettype <> 2279; +FROM pg_catalog.pg_namespace n +JOIN pg_catalog.pg_proc p ON pronamespace = n.oid +JOIN pg_catalog.pg_language l ON p.prolang = l.oid +WHERE l.lanname = 'edbspl' AND p.prorettype <> 2279; ``` To check all trigger EDB SPL Check functions: ```sql SELECT p.proname, tgrelid::regclass, cf.* - FROM pg_proc p - JOIN pg_trigger t ON t.tgfoid = p.oid - JOIN pg_language l ON p.prolang = l.oid - JOIN pg_namespace n ON p.pronamespace = n.oid, - LATERAL spl_check_function(p.oid, t.tgrelid) cf - WHERE n.nspname = 'public' and l.lanname = 'edbspl'; +FROM pg_proc p +JOIN pg_trigger t ON t.tgfoid = p.oid +JOIN pg_language l ON p.prolang = l.oid +JOIN pg_namespace n ON p.pronamespace = n.oid, +LATERAL spl_check_function(p.oid, t.tgrelid) cf +WHERE n.nspname = 'public' and l.lanname = 'edbspl'; ``` To check all EDB SPL Check functions, including functions or trigger functions with defined triggers: @@ -166,18 +170,18 @@ SELECT (pcf)."position", (pcf).query, (pcf).context FROM ( - SELECT - spl_check_function_tb(pg_proc.oid, COALESCE(pg_trigger.tgrelid, 0)) AS pcf - FROM pg_proc - LEFT JOIN pg_trigger - ON (pg_trigger.tgfoid = pg_proc.oid) - WHERE - prolang = (SELECT lang.oid FROM pg_language lang WHERE lang.lanname = 'edbspl') AND - pronamespace <> (SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = 'pg_catalog') AND - -- ignore unused triggers - (pg_proc.prorettype <> (SELECT typ.oid FROM pg_type typ WHERE typ.typname = 'trigger') OR - pg_trigger.tgfoid IS NOT NULL) - OFFSET 0 +SELECT + spl_check_function_tb(pg_proc.oid, COALESCE(pg_trigger.tgrelid, 0)) AS pcf +FROM pg_proc +LEFT JOIN pg_trigger +ON (pg_trigger.tgfoid = pg_proc.oid) +WHERE + prolang = (SELECT lang.oid FROM pg_language lang WHERE lang.lanname = 'edbspl') AND + pronamespace <> (SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = 'pg_catalog') AND + -- ignore unused triggers + (pg_proc.prorettype <> (SELECT typ.oid FROM pg_type typ WHERE typ.typname = 'trigger') OR + pg_trigger.tgfoid IS NOT NULL) +OFFSET 0 ) ss ORDER BY (pcf).functionid::regprocedure::text, (pcf).lineno; ``` @@ -211,10 +215,10 @@ When the type of a record's variable is unknown, you can explicitly assign it wi ```sql DECLARE r record; BEGIN - EXECUTE format('SELECT * FROM %I', _tablename) INTO r; - PERFORM spl_check_pragma('type: r (id int, processed bool)'); - IF NOT r.processed THEN - ... +EXECUTE format('SELECT * FROM %I', _tablename) INTO r; +PERFORM spl_check_pragma('type: r (id int, processed bool)'); +IF NOT r.processed THEN + ... ``` !!! Warning @@ -237,8 +241,8 @@ RETURNS void AS $$ DECLARE rec_var record; BEGIN - FETCH refcur_var INTO rec_var; -- this is STOP for spl_check - RAISE NOTICE '%', rec_var; -- record rec_var is not assigned yet error +FETCH refcur_var INTO rec_var; -- this is STOP for spl_check +RAISE NOTICE '%', rec_var; -- record rec_var is not assigned yet error ``` In this example, don't use a record type. Instead use a known `rowtype`: @@ -249,8 +253,8 @@ RETURNS void AS $$ DECLARE rec_var some_rowtype; BEGIN - FETCH refcur_var INTO rec_var; - RAISE NOTICE '%', rec_var; +FETCH refcur_var INTO rec_var; +RAISE NOTICE '%', rec_var; ``` ### Temporary tables @@ -268,26 +272,27 @@ CREATE OR REPLACE FUNCTION public.disable_dml() RETURNS trigger LANGUAGE edbspl AS $function$ BEGIN - RAISE EXCEPTION SQLSTATE '42P01' - USING message = format('this instance of %I table doesn''t allow any DML operation', TG_TABLE_NAME), - hint = format('you should use "CREATE TEMP TABLE %1$I(LIKE %1$I INCLUDING ALL);" statement', - TG_TABLE_NAME); - RETURN NULL; +RAISE EXCEPTION SQLSTATE '42P01' +USING message = format('this instance of %I table doesn''t allow any DML operation', TG_TABLE_NAME), + hint = format('you should use "CREATE TEMP TABLE %1$I(LIKE %1$I INCLUDING ALL);" statement', + TG_TABLE_NAME); +RETURN NULL; END; $function$; CREATE TABLE foo(a int, b int); -- doesn't hold data, ever CREATE TRIGGER foo_disable_dml - BEFORE INSERT OR UPDATE OR DELETE ON foo - EXECUTE PROCEDURE disable_dml(); +BEFORE INSERT OR UPDATE OR DELETE ON foo +EXECUTE PROCEDURE disable_dml(); -postgres=# INSERT INTO foo VALUES(10,20); +INSERT INTO foo VALUES(10,20); ERROR: this instance of foo table doesn't allow any DML operation HINT: you should to run "CREATE TEMP TABLE foo(LIKE foo INCLUDING ALL);" statement -postgres=# + +CREATE TEMP TABLE foo(LIKE foo INCLUDING ALL); CREATE TABLE -postgres=# INSERT INTO foo VALUES(10,20); +INSERT INTO foo VALUES(10,20); INSERT 0 1 ``` diff --git a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx index 668cbb343d3..f22fb52004c 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx @@ -9,8 +9,10 @@ When EDB SPL Check is initialized by `shared_preload_libraries`, it can allocate Due to dependencies, `shared_preload_libraries` must contain `edb-spl` first: ```sql -show shared_preload_libraries ; -__OUTPUT__ +SHOW shared_preload_libraries ; +``` +``` +OUTPUT shared_preload_libraries ---------------------------- edb-spl,spl_check @@ -46,67 +48,68 @@ The following are limitations of the query identifier retrieval: Display the profile with `spl_profiler_function_tb`: ```sql -select lineno, avg_time, source from spl_profiler_function_tb('fx(int)'); -__OUTPUT__ -┌────────┬──────────┬───────────────────────────────────────────────────────────────────┐ -│ lineno │ avg_time │ source │ -╞════════╪══════════╪═══════════════════════════════════════════════════════════════════╡ -│ 1 │ │ │ -│ 2 │ │ declare result int = 0; │ -│ 3 │ 0.075 │ begin │ -│ 4 │ 0.202 │ for i in 1..$1 loop │ -│ 5 │ 0.005 │ select result + i into result; select result + i into result; │ -│ 6 │ │ end loop; │ -│ 7 │ 0 │ return result; │ -│ 8 │ │ end; │ -└────────┴──────────┴───────────────────────────────────────────────────────────────────┘ +SELECT lineno, avg_time, source FROM spl_profiler_function_tb('fx(int)'); +``` +``` +OUTPUT +| lineno │ avg_time │ source | +|--------|----------|--------------------------------------------------------------------| +| 1 │ │ | +| 2 │ │ declare result int = 0; | +| 3 │ 0.075 │ begin | +| 4 │ 0.202 │ for i in 1..$1 loop | +| 5 │ 0.005 │ select result + i into result; select result + i into result; | +| 6 │ │ end loop; | +| 7 │ 0 │ return result; | +| 8 │ │ end; | + (9 rows) ``` Display the profile per statements with `spl_profiler_function_statements_tb`: ```sql - CREATE OR REPLACE FUNCTION public.fx1(a integer) - RETURNS integer - LANGUAGE spl -1 AS $function$ -2 begin -3 if a > 10 then -4 raise notice 'ahoj'; -5 return -1; -6 else -7 raise notice 'nazdar'; -8 return 1; -9 end if; -10 end; -11 $function$ - -select stmtid, parent_stmtid, parent_note, lineno, exec_stmts, stmtname - from spl_profiler_function_statements_tb('fx1'); -__OUTPUT__ -┌────────┬───────────────┬─────────────┬────────┬────────────┬─────────────────┐ -│ stmtid │ parent_stmtid │ parent_note │ lineno │ exec_stmts │ stmtname │ -╞════════╪═══════════════╪═════════════╪════════╪════════════╪═════════════════╡ -│ 0 │ ∅ │ ∅ │ 2 │ 0 │ statement block │ -│ 1 │ 0 │ body │ 3 │ 0 │ IF │ -│ 2 │ 1 │ then body │ 4 │ 0 │ RAISE │ -│ 3 │ 1 │ then body │ 5 │ 0 │ RETURN │ -│ 4 │ 1 │ else body │ 7 │ 0 │ RAISE │ -│ 5 │ 1 │ else body │ 8 │ 0 │ RETURN │ -└────────┴───────────────┴─────────────┴────────┴────────────┴─────────────────┘ +CREATE OR REPLACE FUNCTION public.fx1(a integer) + RETURNS integer + LANGUAGE spl + AS $function$ + BEGIN + IF a > 10 THEN + RAISE NOTICE 'ahoj'; + RETURN -1; + ELSE + RAISE NOTICE 'nazdar'; + RETURN 1; + END IF; + END; +$function$ + +SELECT stmtid, parent_stmtid, parent_note, lineno, exec_stmts, stmtname + FROM spl_profiler_function_statements_tb('fx1'); +``` +``` +OUTPUT +| stmtid │ parent_stmtid │ parent_note │ lineno │ exec_stmts │ stmtname │ +|--------|---------------|-------------|--------|------------|-----------------| +| 0 │ ∅ │ ∅ │ 2 │ 0 │ statement block │ +| 1 │ 0 │ body │ 3 │ 0 │ IF │ +| 2 │ 1 │ then body │ 4 │ 0 │ RAISE │ +| 3 │ 1 │ then body │ 5 │ 0 │ RETURN │ +| 4 │ 1 │ else body │ 7 │ 0 │ RAISE │ +| 5 │ 1 │ else body │ 8 │ 0 │ RETURN │ (6 rows) ``` Display all stored profiles with `spl_profiler_functions_all`: ```sql -select * from spl_profiler_functions_all(); -__OUTPUT__ -┌───────────────────────┬────────────┬────────────┬──────────┬─────────────┬──────────┬──────────┐ +SELECT * FROM spl_profiler_functions_all(); +``` +``` +OUTPUT │ funcoid │ exec_count │ total_time │ avg_time │ stddev_time │ min_time │ max_time │ -╞═══════════════════════╪════════════╪════════════╪══════════╪═════════════╪══════════╪══════════╡ +|-----------------------|------------|------------|----------|-------------|----------|----------| │ fxx(double precision) │ 1 │ 0.01 │ 0.01 │ 0.00 │ 0.01 │ 0.01 │ -└───────────────────────┴────────────┴────────────┴──────────┴─────────────┴──────────┴──────────┘ (1 row) ``` diff --git a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx index c0110c36509..1af564f6993 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx @@ -4,7 +4,7 @@ title: Tracer EDB SPL Check provides a tracing option where you can see notices on start or end functions (terse and default verbosity) and start or end statements (verbose verbosity). For default and verbose verbosity, this option displays the content of function arguments. The content of related variables diplay when verbosity is verbose. For example: ```sql -do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; +DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; NOTICE: #0 ->> start of inline_code_block (Oid=0) NOTICE: #2 ->> start of function fx(integer,integer,date,text) (Oid=16405) NOTICE: #2 call by inline_code_block line 1 at PERFORM @@ -33,13 +33,17 @@ We also recommend that you load the extension `spl_check`. You can execute some In terse verbose mode, the output is reduced: ```sql -set spl_check.tracer_verbosity TO terse; -__OUTPUT__ +SET spl_check.tracer_verbosity TO terse; +``` +``` +OUTPUT SET ``` ```sql -do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; -__OUTPUT__ +DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; +``` +``` +OUTPUT NOTICE: #0 start of inline code block (oid=0) NOTICE: #2 start of fx (oid=16405) NOTICE: #4 start of fx (oid=16404) @@ -51,8 +55,10 @@ NOTICE: #0 end of inline code block In verbose mode, the output is extended with statement details: ```sql -do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; -__OUTPUT__ +DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; +``` +``` +OUTPUT NOTICE: #0 ->> start of block inline_code_block (oid=0) NOTICE: #0.1 1 --> start of PERFORM NOTICE: #2 ->> start of function fx(integer,integer,date,text) (oid=16405) @@ -80,11 +86,13 @@ NOTICE: #0 <<- end of block (elapsed time=1.286 ms) A special feature of the tracer is the tracing of the `ASSERT` statement when `spl_check.trace_assert` is `on`. When `spl_check.trace_assert_verbosity` is `DEFAULT` and the `ASSERT` statement is `false`, all function or procedure variables are displayed. When this configuration is `VERBOSE`, all variables from all EDB SPL frames are displayed. This behavior is independent of the `spl.check_asserts` value. It can be used, but the assertions are disabled during EDB SPL runtime. For example: ```sql -set spl_check.tracer to off; -set spl_check.trace_assert_verbosity TO verbose; +SET spl_check.tracer TO off; +SET spl_check.trace_assert_verbosity TO verbose; -do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; -__OUTPUT__ +DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; +``` +``` +OUTPUT NOTICE: #4 PLpgSQL assert expression (false) on line 12 of fx(integer) is false NOTICE: "a" => '10', "res" => null, "b" => '20' NOTICE: #2 PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM @@ -98,13 +106,17 @@ SQL statement "SELECT fx(10,null, 'now', e'stěhule')" PL/pgSQL function inline_code_block line 1 at PERFORM ``` ```sql -set spl.check_asserts to off; -__OUTPUT__ +SET spl.check_asserts TO off; +``` +``` +OUTPUT SET ``` ```sql -do $$ begin perform fx(10,null, 'now', e'stěhule'); end; $$; -__OUTPUT__ +DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; +``` +``` +OUTPUT NOTICE: #4 PLpgSQL assert expression (false) on line 12 of fx(integer) is false NOTICE: "a" => '10', "res" => null, "b" => '20' NOTICE: #2 PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM From f8d49e755925d9a5953b508fd2693722da632b58 Mon Sep 17 00:00:00 2001 From: Chris Estes <106166814+ccestes@users.noreply.github.com> Date: Mon, 25 Sep 2023 11:51:19 -0400 Subject: [PATCH 22/24] fixed sentence on pragma page --- advocacy_docs/pg_extensions/spl_check/using/pragma.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx index b2460c91ee4..12f21c47afe 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx @@ -2,7 +2,7 @@ title: Pragma --- -You can configure EDB SPL Check's behavior inside a checked function with a pragma function. This is an analogy of PL/SQL or ADA language of a pragma feature. PL/pgSQL doesn't support pragma, but EDB SPL Check detects functions named `spl_check_pragma` and takes options from the parameters of the function. These EDB SPL Check options are valid to add to the end of this group of statements: +You can configure EDB SPL Check's behavior inside a checked function with a pragma function. Like the pragma feature for PL/SQL or ADA languages, EDB SPL Check provides analogous pragma functionality and APIs. PL/pgSQL doesn't support pragma, but EDB SPL Check detects functions named `spl_check_pragma` and takes options from the parameters of the function. These EDB SPL Check options are valid to add to the end of this group of statements: ```sql CREATE OR REPLACE FUNCTION test() From fd5f109671e44b1f9363170028a3f7abca684850 Mon Sep 17 00:00:00 2001 From: Chris Estes <106166814+ccestes@users.noreply.github.com> Date: Tue, 26 Sep 2023 08:11:47 -0400 Subject: [PATCH 23/24] updated pragma intro --- advocacy_docs/pg_extensions/spl_check/using/pragma.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx index 12f21c47afe..ddf32d5cf31 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/pragma.mdx @@ -2,7 +2,7 @@ title: Pragma --- -You can configure EDB SPL Check's behavior inside a checked function with a pragma function. Like the pragma feature for PL/SQL or ADA languages, EDB SPL Check provides analogous pragma functionality and APIs. PL/pgSQL doesn't support pragma, but EDB SPL Check detects functions named `spl_check_pragma` and takes options from the parameters of the function. These EDB SPL Check options are valid to add to the end of this group of statements: +You can configure EDB SPL Check's behavior inside a checked function with a pragma function. Like the pragma feature for PL/SQL or ADA languages, EDB SPL Check provides pragma functionality. EDB SPL Check detects functions named `spl_check_pragma` and takes options from the parameters of the function. These EDB SPL Check options are valid to add to the end of this group of statements: ```sql CREATE OR REPLACE FUNCTION test() From 8786789daa3ff7c6a9c39d75c907807f18c8db9f Mon Sep 17 00:00:00 2001 From: nidhibhammar <59045594+nidhibhammar@users.noreply.github.com> Date: Tue, 26 Sep 2023 18:16:39 +0530 Subject: [PATCH 24/24] Formatted the code blocks --- .../pg_extensions/spl_check/configuring.mdx | 37 +++++-------- .../spl_check/using/dependency_list.mdx | 4 +- .../pg_extensions/spl_check/using/index.mdx | 53 +++++++++++++------ .../spl_check/using/profiler.mdx | 18 ++----- .../pg_extensions/spl_check/using/tracer.mdx | 24 +++------ 5 files changed, 60 insertions(+), 76 deletions(-) diff --git a/advocacy_docs/pg_extensions/spl_check/configuring.mdx b/advocacy_docs/pg_extensions/spl_check/configuring.mdx index 67c27b767cf..c0d2f0d9ce7 100644 --- a/advocacy_docs/pg_extensions/spl_check/configuring.mdx +++ b/advocacy_docs/pg_extensions/spl_check/configuring.mdx @@ -23,9 +23,7 @@ The validator checks the SQL statements inside SPL functions for semantic errors ```sql CREATE TABLE t1(a int, b int); -``` -``` -OUTPUT +__OUTPUT__ CREATE TABLE ``` ```sql @@ -41,9 +39,7 @@ LOOP END LOOP; END; $function$; -``` -``` -OUTPUT +__OUTPUT__ CREATE FUNCTION ``` @@ -51,12 +47,10 @@ CREATE FUNCTION ```sql SELECT f1(); -``` -``` -OUTPUT +__OUTPUT__ f1 -──── - +──── + (1 row) ``` @@ -65,9 +59,7 @@ You can view the bug and other semantic errors by running `spl_check_function`: ```sql SELECT * FROM spl_check_function_tb('f1()'); -``` -``` -OUTPUT +__OUTPUT__ ─[ RECORD 1 ]─────────────────────────── functionid │ f1 lineno │ 6 @@ -85,9 +77,7 @@ query │ [null] ```sql SELECT * FROM spl_check_function('f1()', fatal_errors := false); -``` -``` -OUTPUT +__OUTPUT__ spl_check_function ------------------------------------------------------------------------ error:42703:4:SQL statement:column "c" of relation "t1" does not exist @@ -102,9 +92,7 @@ OUTPUT ```sql SELECT * FROM spl_check_function('fx()', format:='xml'); -``` -``` -OUTPUT +__OUTPUT__ spl_check_function ──────────────────────────────────────────────────────────────── ↵ @@ -116,7 +104,7 @@ OUTPUT SELECT (select a from foo111)↵ ↵ - (1 row) +(1 row) ``` ### Setting the level of warnings @@ -246,11 +234,10 @@ BEGIN RETURN r; END; $$ LANGUAGE edbspl; - -SELECT * FROM spl_check_function('foo', extra_warnings =>false, compatibility_warnings => true); -``` ``` -OUTPUT +```sql +SELECT * FROM spl_check_function('foo', extra_warnings =>false, compatibility_warnings => true); +__OUTPUT__ spl_check_function ----------------------------------------------------------------------------------- compatibility:00000:6:assignment:obsolete setting of refcursor or cursor variable diff --git a/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx b/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx index d7ce0636d76..821b931e8f4 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/dependency_list.mdx @@ -6,9 +6,7 @@ The function `spl_show_dependency_tb` shows all the functions, operators, and re ```sql SELECT * FROM spl_show_dependency_tb('testfunc(int,float)'); -``` -``` -OUTPUT +__OUTPUT__ │ type │ oid │ schema │ name │ params │ |----------|-------|--------|---------|----------------------------| │ FUNCTION │ 36008 │ public │ myfunc1 │ (integer,double precision) │ diff --git a/advocacy_docs/pg_extensions/spl_check/using/index.mdx b/advocacy_docs/pg_extensions/spl_check/using/index.mdx index cb6121276b2..5997bd6941a 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/index.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/index.mdx @@ -11,8 +11,11 @@ To check any trigger, enter a relation that's used with the trigger function. Fo ```sql CREATE TABLE bar(a int, b int); +__OUTPUT__ +CREATE TABLE +``` - +```sql CREATE OR REPLACE FUNCTION public.foo_trg() RETURNS trigger LANGUAGE edbspl @@ -22,15 +25,15 @@ CREATE OR REPLACE FUNCTION public.foo_trg() RETURN NEW; END; $function$ +__OUTPUT__ +CREATE FUNCTION ``` When there's no specified relation for the trigger, the following is returned: ```sql SELECT * FROM spl_check_function('foo_trg()'); -``` -``` -OUTPUT +__OUTPUT__ ERROR: missing trigger relation HINT: Trigger relation oid must be valid ``` @@ -39,9 +42,7 @@ When the trigger is checked successfully with a specified relation, the followin ```sql SELECT * FROM spl_check_function('foo_trg()', 'bar'); -``` -``` -OUTPUT +__OUTPUT__ spl_check_function -------------------------------------------------------- error:42703:3:assignment:record "new" has no field "c" @@ -65,7 +66,8 @@ BEGIN RETURN null; END; $$ LANGUAGE edbspl; - +``` +```sql SELECT * FROM spl_check_function('footab_trig_func','footab', newtable := 'newtab'); ``` @@ -80,11 +82,10 @@ FOR EACH ROW BEGIN NEW.a := NEW.b; END; - -SELECT * FROM spl_check_trigger('tg1'); -``` ``` -OUTPUT +```sql +SELECT * FROM spl_check_trigger('tg1'); +__OUTPUT__ spl_check_trigger ---------------------------------------------------- error:42703:2:assignment:record "new" has no field "b" @@ -117,7 +118,7 @@ SELECT * FROM spl_check_objecttype(''); EDB SPL Check allows persistent-setting, written in-comments. These options are taken from a function's source code before checking. The syntax is: ```sql -@spl_check_option: optioname [=] value [, optname [=] value ...] +@spl_check_option: optionname [=] value [, optname [=] value ...] ``` The settings from comment options have top priority, but generally they can be disabled by setting `use_incomment_options` to `false`. For example: @@ -158,7 +159,7 @@ JOIN pg_trigger t ON t.tgfoid = p.oid JOIN pg_language l ON p.prolang = l.oid JOIN pg_namespace n ON p.pronamespace = n.oid, LATERAL spl_check_function(p.oid, t.tgrelid) cf -WHERE n.nspname = 'public' and l.lanname = 'edbspl'; +WHERE n.nspname = 'public' AND l.lanname = 'edbspl'; ``` To check all EDB SPL Check functions, including functions or trigger functions with defined triggers: @@ -279,20 +280,38 @@ USING message = format('this instance of %I table doesn''t allow any DML operati RETURN NULL; END; $function$; - +__OUTPUT__ +CREATE FUNCTION +``` +```sql CREATE TABLE foo(a int, b int); -- doesn't hold data, ever +__OUTPUT__ +CREATE TABLE +``` +```sql CREATE TRIGGER foo_disable_dml BEFORE INSERT OR UPDATE OR DELETE ON foo EXECUTE PROCEDURE disable_dml(); +__OUTPUT__ +CREATE TRIGGER +``` +```sql INSERT INTO foo VALUES(10,20); +__OUTPUT__ ERROR: this instance of foo table doesn't allow any DML operation HINT: you should to run "CREATE TEMP TABLE foo(LIKE foo INCLUDING ALL);" statement +``` +```sql CREATE TEMP TABLE foo(LIKE foo INCLUDING ALL); - +__OUTPUT__ CREATE TABLE -INSERT INTO foo VALUES(10,20); +``` + +```sql +INSERT INTO foo VALUES(10,20); +__OUTPUT__ INSERT 0 1 ``` diff --git a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx index f22fb52004c..24c5c6bfd22 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/profiler.mdx @@ -10,9 +10,7 @@ Due to dependencies, `shared_preload_libraries` must contain `edb-spl` first: ```sql SHOW shared_preload_libraries ; -``` -``` -OUTPUT +__OUTPUT__ shared_preload_libraries ---------------------------- edb-spl,spl_check @@ -49,9 +47,7 @@ Display the profile with `spl_profiler_function_tb`: ```sql SELECT lineno, avg_time, source FROM spl_profiler_function_tb('fx(int)'); -``` -``` -OUTPUT +__OUTPUT__ | lineno │ avg_time │ source | |--------|----------|--------------------------------------------------------------------| | 1 │ │ | @@ -86,9 +82,7 @@ $function$ SELECT stmtid, parent_stmtid, parent_note, lineno, exec_stmts, stmtname FROM spl_profiler_function_statements_tb('fx1'); -``` -``` -OUTPUT +__OUTPUT__ | stmtid │ parent_stmtid │ parent_note │ lineno │ exec_stmts │ stmtname │ |--------|---------------|-------------|--------|------------|-----------------| | 0 │ ∅ │ ∅ │ 2 │ 0 │ statement block │ @@ -104,12 +98,10 @@ Display all stored profiles with `spl_profiler_functions_all`: ```sql SELECT * FROM spl_profiler_functions_all(); -``` -``` -OUTPUT +__OUTPUT__ │ funcoid │ exec_count │ total_time │ avg_time │ stddev_time │ min_time │ max_time │ |-----------------------|------------|------------|----------|-------------|----------|----------| -│ fxx(double precision) │ 1 │ 0.01 │ 0.01 │ 0.00 │ 0.01 │ 0.01 │ +│ fxx(DOUBLE PRECISION) │ 1 │ 0.01 │ 0.01 │ 0.00 │ 0.01 │ 0.01 │ (1 row) ``` diff --git a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx index 1af564f6993..8d2c6562c1b 100644 --- a/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx +++ b/advocacy_docs/pg_extensions/spl_check/using/tracer.mdx @@ -34,16 +34,12 @@ In terse verbose mode, the output is reduced: ```sql SET spl_check.tracer_verbosity TO terse; -``` -``` -OUTPUT +__OUTPUT__ SET ``` ```sql DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; -``` -``` -OUTPUT +__OUTPUT__ NOTICE: #0 start of inline code block (oid=0) NOTICE: #2 start of fx (oid=16405) NOTICE: #4 start of fx (oid=16404) @@ -56,9 +52,7 @@ In verbose mode, the output is extended with statement details: ```sql DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; -``` -``` -OUTPUT +__OUTPUT__ NOTICE: #0 ->> start of block inline_code_block (oid=0) NOTICE: #0.1 1 --> start of PERFORM NOTICE: #2 ->> start of function fx(integer,integer,date,text) (oid=16405) @@ -90,9 +84,7 @@ SET spl_check.tracer TO off; SET spl_check.trace_assert_verbosity TO verbose; DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; -``` -``` -OUTPUT +__OUTPUT__ NOTICE: #4 PLpgSQL assert expression (false) on line 12 of fx(integer) is false NOTICE: "a" => '10', "res" => null, "b" => '20' NOTICE: #2 PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM @@ -107,16 +99,12 @@ PL/pgSQL function inline_code_block line 1 at PERFORM ``` ```sql SET spl.check_asserts TO off; -``` -``` -OUTPUT +__OUTPUT__ SET ``` ```sql DO $$ BEGIN PERFORM fx(10,null, 'now', e'stěhule'); END; $$; -``` -``` -OUTPUT +__OUTPUT__ NOTICE: #4 PLpgSQL assert expression (false) on line 12 of fx(integer) is false NOTICE: "a" => '10', "res" => null, "b" => '20' NOTICE: #2 PL/pgSQL function fx(integer,integer,date,text) line 1 at PERFORM