Embedded SQL

This section provides an overview of commonly used Embedded SQL constructs. All Embedded SQL statements follow the basic form:

EXEC SQL <SQL Statement>;

Including Files

A program that uses Embedded SQL can include other Embedded SQL files with the EXEC SQL INCLUDE command:

EXEC SQL INCLUDE file;

When the source code that contains the EXEC SQL INCLUDE file is parsed by ecpg, the files to be included will be parsed by ecpg and then included. If file is not found, ecpg will attempt to include the file.h file

Note that ecpg parses the file included by EXEC SQL INCLUDE statements in a case-sensitive manner. For example,

EXEC SQL INCLUDE my_file.h

includes the my_file.h file, while

EXEC SQL INCLUDE MY_FILE.h

includes the MY_FILE.h file. EXEC SQL INCLUDE can be used to include other header files as long as case sensitivity is observed. Be aware that:

EXEC SQL INCLUDE file.h

is not the same as:

#include <file.h>

In the former, file.h is parsed by ecpg and the resultant code is included. The latter include statement is ignored by ecpg and picked up by the C preprocessor during the compile stage.

Variable Declaration

All variables that will be shared between normal host code and SQL code must be defined in a variable declaration section that begins with

EXEC SQL BEGIN DECLARE SECTION;

and ends with

EXEC SQL END DECLARE SECTION;

Variables declared within this section are called "host variables"; they are declared in C format. For example:

EXEC SQL BEGIN DECLARE SECTION;
int fooBar;
char dooDad[16];
EXEC SQL END DECLARE SECTION;

A special type, VARCHAR, corresponds to the SQL VARCHAR type and can be declared in the variable declaration section:

VARCHAR name[len];

For example:

VARCHAR foo[100];

The VARCHAR type is converted by ecpg to a structure that contains two members; a character array of the specified length (arr) and an int that is used to store the number of characters in the array (len). Thus, the declaration

VARCHAR foo[100];

is converted to:

struct varchar_foo{
   int len;
   char arr[100];
} foo;

The variable declaration section should be set in the same places as normal C variable declarations.

When a host variable is referenced in an Embedded SQL statement, it must be prefixed by a colon (':'). For example:

EXEC SQL BEGIN DECLARE SECTION;
char *con = "db@machine";
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO :con as conname;

Connecting to a Database

The following is used to connect to a database:

EXEC SQL CONNECT TO connection_target
   [AS connection_name]
   [USER username]
   [USING password];

connection_target can be specified in one of the following ways:

database[@server][:port]

Connect to the given database on the given server and port, if specified. If server is not specified, then localhost is assumed. If port is not specified, then the port to connect to will be the default, 5432.

tcp:postgresql://server[:port][/database]

Connect to a remote database server using TCP/IP sockets. If database is not specified then the default database will be used.

unix:postgresql://server[:port][/dbname]

Connect to a database using UNIX domain sockets.

default

Connect to the database specified by the PGDATABASE environment variable.

:host_variable

Shared variable of char * type that contains connection information in one of the above four forms.

username can be specified in any of the following ways:

where username, userid, and password can all be character host variables.

Disconnecting from a Database

Disconnecting from a database can be done with the following Embedded SQL statement:

EXEC SQL DISCONNECT connection_target

where connection_target is either:

ValueDescription
connection_nameA named connection.
defaultThe default connection.
currentThe current connection.
allAll connections.

SQL Commands

In general, any normal SQL statement can be embedded in your C code. Here are some examples:

Create:

EXEC SQL CREATE TABLE foo (number integer, ascii char(16));
EXEC SQL CREATE UNIQUE INDEX num1 ON foo(number);

Insert:

EXEC SQL INSERT INTO foo(number, ascii) VALUES (9999, 'doodad');

Delete:

EXEC SQL DELETE FROM foo WHERE number = 9999;

Singleton Select:

EXEC SQL SELECT number INTO :num FROM foo WHERE ascii = 'doodad';

Cursors:

EXEC SQL DECLARE foo_bar CURSOR FOR
         SELECT number, ascii FROM foo
         ORDER BY ascii;
EXEC SQL FETCH foo_bar INTO :fooBar, :dooDad;
EXEC SQL CLOSE foo_bar;

Updates:

EXEC SQL UPDATE foo SET ascii = 'foobar' WHERE number = 9999;

When selecting data from a database, it is generally easier to use SELECT statements when one view is expected, and cursors when more than one is expected.

SELECT a1, a2, ..., an FROM t1, t2, ..., tn INTO :host1, :host2, ..., :hostn retrieves columns a1 to an, storing a1 in the host variable host1, a2 in the host variable host2, and so on.

FETCH cursor INTO :host1, :host2, ..., :hostn works in a similar fashion, except that using the cursor cursor to retrieve the next row. Refer to the Red Hat Database SQL Guide and Reference for more information on cursors.

Error Handling

Error handling is done via the SQL Communication Area (SQLCA). The SQLCA is defined with the following Embedded SQL statement:

EXEC SQL INCLUDE sqlca;

Note that "sqlca" is in lowercase.

Including sqlca defines a struct called sqlca and declares a variable sqlca of type struct sqlca. The definition of struct sqlca is:

struct sqlca
{
   char         sqlcaid[8];
   long         sqlabc;
   long         sqlcode;
   struct
   {
      int          sqlerrml;
      char         sqlerrmc[SQLERRMC_LEN];
   } sqlerrm;
   char         sqlerrp[8];
   long         sqlerrd[6];

   /* Element 0: empty
    * 1: OID of processed tuple if applicable
    * 2: number of rows processed	after an INSERT,
    * UPDATE or DELETE statement
    * 3: empty
    * 4: empty
    * 5: empty
    */
   char         sqlwarn[8];

   /* Element 0: set to 'W' if at least one other is 'W'
    * 1: if 'W' then at least one character string
    * value was truncated when it was
    * stored into a host variable.
    * 2: if 'W' then a (hopefully) non-fatal notice occurred
    * 3: empty
    * 4: empty
    * 5: empty
    * 6: empty
    * 7: empty
    */
   char         sqlext[8];
};

If an error occurred in the last executed SQL statement, then sqlca.sqlcode will be set to a non-zero value. A value less than zero means that the error is a serious error, such as the database definition does not match the query given. A value larger than zero indicates a normal error such as the table did not contain the requested row. A list of error codes follows:

Error CodeDescription
-12Out of memory.
-200The preprocessor has likely generated something that the library does not know about.
-201Too many arguments. The database backend returned more arguments than expected. Most likely caused by too few host variables in an INTO :var1,:var2, ... list.
-202Too few arguments. The database backend returned fewer arguments than expected. Most likely caused by too many host variables in an INTO :var1,:var2, ... list.
-203Too many matches. A query has returned several rows but the host variables specified to receive the data are not arrays.
-204A host variable was expecting to have an int value placed in it but the populating field in the database is of another type and contains a value that cannot be interpreted as an int.
-205A host variable was expecting to have an unsigned int value placed in it but the populating field in the database is of another type and contains a value that cannot be interpreted as an unsigned int.
-206A host variable was expecting to have a float value placed in it but the populating field in the database is of another type and contains a value that cannot be interpreted as a float.
-207A host variable was expecting to have a bool type placed in it but the populating field in the database is of a different type and contains a value that is neither "t" nor "f".
-208An empty query was sent to the database backend.
-220The program tried to access a nonexistent connection.
-221The program tried to access a valid, but unopened, connection.
-230Execution of a unknown prepared statement was attempted.
-400An error occurred in the database backend. The message contains the error message sent from the backend.
-401An error occurred during a BEGIN, COMMIT, or ROLLBACK.
-402A connection to a database could not be opened.
100No data was returned by a query or a cursor has no more data to return.

sqlca.sqlerrm.sqlerrmc will contain a string that describes the error. The string ends with the line number in the source file where the error occurred.

To turn on error handling, the following can be done after sqlca has been included:

EXEC SQL WHENEVER condition action;

where condition is one of the following:

ConditionDescription
SQLERRORA fatal error has occurred.
SQLWARNINGA non-fatal error has occurred.
NOT FOUNDNo data was returned by a query.

and action is one of the following:

ActionDescription
SQLPRINTPrint the error message to standard error.
DO c_functionExecute the given C function.
GOTO labelGo to the given label in the program.
CONTINUEDo nothing (default).

For example:

EXEC SQL WHENEVER SQLERROR GOTO error;
/* ... program code ...*/
error:
   fprintf(stderr, "an error occurred\n");

Example Program

Suppose that we have a database called user on the computer called box, and that this database contains one table called emp that contains the name and ID of all employees. Let emp be defined by:

CREATE TABLE emp (id INTEGER, name TEXT);

The following Embedded SQL program opens a connection to the database server (running on toolittle) and retrieves the ID number of the employee called "fred".

#include <stdio.h>

/* include SQL Communication Area code */
EXEC SQL INCLUDE sqlca;

/* shared variables */
EXEC SQL BEGIN DECLARE SECTION;
int id;
char *name = "fred";
char *db = "user@box";
EXEC SQL END DECLARE SECTION;

/* print all fatal errors */
EXEC SQL WHENEVER SQLERROR SQLPRINT;
EXEC SQL WHENEVER NOT FOUND DO print_not_found();

void print_not_found()
{
	printf("No results were returned.\n");
}

int main()
{
/* open a database connection */
EXEC SQL CONNECT TO :db AS conn;
if (!ECPGstatus(__LINE__, "conn"))
{
	fprintf(stderr, "Unable to connect to database.\n");
	return(1);
}

/* execute query */
EXEC SQL SELECT id INTO :id FROM emp WHERE name = :name;

	if (sqlca.sqlcode == 0)
		printf("ID of %s: %d\n", name, id);

/* disconnect */
EXEC SQL DISCONNECT conn;

	return(0);
}