Skip to content

1. The C/C++ Precompiler#

Introduction and Concepts#

Introduction#

APRE (the Altibase C/C++ Precompiler) is a programming tool that accepts source code containing embedded SQL as input, translates the embedded SQL statements into standard runtime library calls, and generates a modified source program that can be compiled in the host language and executed.

APRE makes it easy for users to write and precompile applications that contain embedded SQL statements.

By embedding SQL statements into applications, users can create applications that have all of the functionality that is available when creating a program using the ODBC API, and can do so much more easily.

Precompiler Environment Settings#

The following environment settings are required in order to compile and link a file that is output by APRE:

Required Header File

  • The ulpLibInterface.h header file is necessary. It is located in the $ALTIBASE_HOME/include directory.

  • In order to compile an application that was precompiled with APRE, it will be necessary to use the following option in your C/C++ compiler: -I $ALTIBASE_HOME/include

Required Library Files

  • The library files libapre.a and libodbccli.a (or apre.lib and odbccli.lib in Windows) are also necessary. They are located in the $ALTIBASE_HOME/lib directory.
  • In order to link a compiled application program with these libraries, it is necessary to use all of the following options:

    -L $ALTIBASE_HOME/lib -lapre, -lodbccli, -lpthread
    

Notes:

The Altibase client library is not safe for system signal generation.

Therefore, when the network connection is terminated due to an external cause, an application in progress may be forcibly terminated by receiving a SIGPIPE signal. To prevent this forced termination, the SIGPIPE signal must be handled by the user application. However, a function is called in the Altibase client library while processing SIGPIP signals, it should not call it because the program may stopped.

However, after signal processing, it is possible to call functions from the Altibase client library.

The Precompilation Process#

APRE is used to precompile a program that was written in C or C++ and includes embedded SQL statements. It outputs a C or C++ program in which the embedded SQL has been converted into a form that is understandable by the C or C++ compiler. The input file is a text file containing C or C++ source code, and must have the .sc extension. The file output by APRE can have either the .c or .cpp extension. The user can choose the desired filename extension using the -t command-line argument. If this is omitted, the default extension is .c.

Executing the Precompile Command

apre [ <apre-options> ] <filename>

APRE Command-Line Options

  • <filename>
    This is a text file that contains C or C++ source code, including embedded SQL statements. The filename extension must be .sc. It is possible to specify more than one file, in which case all of them will be preprocessed individually. When specifying multiple files, the asterisk ("*") wildcard character is useful.

[Example 1] Precompile a program that was written in C. The precompilation operation creates the sample1.c file.

$ apre sample1.sc

[Example 2] Precompile multiple programs that were written in C. Note the use of the asterisk ("*") wildcard character in the second example.

$ apre sample1.sc sample2.sc 
$ apre *.sc
  • <apre-options>
    APRE*C/C++ command-line options are specified here, before the name of the file(s) to precompile. For details, please refer to the next section,Command-Line Options.

Precompile Messages

The screen that is displayed when APRE is executed is shown below.

$ apre sample1.sc
--------------------------------------------------------
  APRE C/C++ Precompiler.
  Release Version 7.1.0.0.0
  Copyright 2000, Altibase Corporation or its subsidiaries.
  All rights reserved.
--------------------------------------------------------

Command-Line Options#

The following command-line options can be used when precompiling applications. This section explains each of the command-line options in detail.

Run option

-h

When this option is used, the precompile operation is not performed, and APRE help information is displayed. The following screen will be shown:

$ apre -h
===========================================================
APRE (Altibase Precompiler) C/C++ Precompiler HELP Screen
===========================================================
Usage  :  apre [<options>] <filename>

-h               : Display this help information.
-t <c|cpp>       : Specify the file extension for the output file.
                   c   - File extension is '.c' (default)
                   cpp - File extension is '.cpp'
-o <output_path> : Specify the directory path for the output file.
                   (default : current directory)
-mt              : When precompiling a multithreaded application,
                   this option must be specified.
-I<include_path> : Specify the directory paths for files included using APRE C/C++.
                   (default : current directory)
-parse <none|partial|full>
                 : Control which non-SQL code is parsed.
-D<define_name>  : Use to define a preprocessor symbol.
-v               : Output the version of APRE.
-n               : Specify when CHAR variables are not null-padded.
-unsafe_null     : Specify to suppress errors when NULL values are fetched
                   and indicator variables are not used.
-align           : Specify when using alignment in AIX.
-spill <values>  : Specify the register allocation spill area size.
-keyword         : Display all reserved keywords.
-debug <macro|symbol>
                 : Use for debugging.
                   macro   - Display macro table.
                   symbol  - Display symbol table.
-nchar_var <variable_name_list>
                 : Process the specified variables using
                   the Altibase national character set.
-nchar_utf16     : Set client nchar encoding to UTF-16.
-lines           : Add #line directives to the generated code.
-silent          : No display Copyright.
================================================

-t <c|cpp>#

This is used to choose the filename extension of the file created as a result of the APRE precompiling operation. When this option is set to "c", the filename extension will be ".c", whereas when this option is set to "cpp", the filename extension will be ".cpp". If neither extension is specified, the filename extension will be ".c".

Example

Use the -t option to precompile a program written in C++. After APRE has executed the command, a file named "sample1.cpp" will be created.

$ apre -t cpp sample1.sc

-o <output_path>#

This is used to specify the location of the file(s) created by APRE. If this option is omitted, the resultant file(s) will be created in the current directory. Only one path can be specified. That is, when precompiling and creating multiple files, the resultant files must all be created in the same directory.

-mt#

If the file to be preprocessed is a multi-threaded program, this option must be specified. this This option cannot be applied to each source file (.sc), so an executable program is created by preprocessing more than one source file, this option must be applied to all source files.

EXEC SQL OPTION(THREADS=TRUE);

This can be replaced with the embedded SQL statement. That is, if the embedded SQL statement is declared within the file which will be precompiled, this option can be omitted. However, in the case of precompiling multiple files, this options is preferentially applied than the embedded SQL. Thus, if this option is selected, the precompiling files are applied all as well.

Refer refer to Chapter6: Embedded SQL Statements on in-depth information on the OPTION statement.

-I<include_path>#

This option is used to specify the location(s) of the header file(s) to be used in the precompiling operation. Both absolute and relative paths can be specified. APRE will always look for the header file in the current directory first, followed by the directories specified here.

In order to specify multiple locations, the -I option can be specified multiple times.

Example

Use the -I option to specify the location of header files to be used for precompiling. When this option is specified as shown, APRE will look for the header file in the current directory first, and will then look in the /include directory.

$ apre -I. -I/include sample1.sc

-parse <none|partial|full>#

This option is used to specify the range within the source file(s), which are specified within the source code using the #include directive, that is parsed by the precompiler. When this option is not specified, it defaults to partial.

none

If this option is set to none, the precompiler processes only the macro commands and host variable declarations that are found within the EXEC SQL BEGIN/END DECLARE SECTION block, and ignores any macro commands and host variable declarations that are not found within that block. However, all embedded SQL statements found within the source file(s) are processed.

partial

If this option is set to partial, the precompiler processes all macro commands, but processes only the host variable declarations that are found within the EXEC SQL BEGIN/END DECLARE SECTION block. Additionally, the macro commands that are found in the header files that are included using the #include directive are processed, whereas the host variables found within these files are not. However, as with the none option, all embedded SQL statements found within the source file(s) are processed.

full

If this option is set to full, the precompiler executes an internal C parser and processes all host variables, regardless of whether they were declared inside or outside the EXEC SQL BEGIN/END DECLARE SECTION block, and all macro commands. Furthermore, not only all macro commands but also all host variables found within the header files included using the #include directive are also processed. Finally, all embedded SQL statements are then precompiled.

However, since performance loss can occur - regardless of this option being specified - the ALTIBASE precompiler does not parse the system header files that are included using the #include directive. Thus, an error is raised when types defined in the system header files are used as host variables. To avoid this, the user must define the desired type in the $ALTIBASE_HOME/include/aprePredefinedTypes.h file which is provided by Altibase.

In the "*.sc" source file, however, the system header files must be included using the #include directive, instead of the aprePredefinedTypes.h file. This is because the aprePredefinedTypes.h file is automatically referenced at APRE precompilation; at compilation, however, the system header files must be referenced.

Note:

Because APRE's internal C parser is activated when the -parse option is set to full, an error will be raised if any C++ source code is encountered during the precompile operation. Therefore, when precompiling C++ source code, either avoid the use of the -parse option, or set it to partial or none.

Example

$ apre -parse none -t cpp sample1.sc
$ apre -parse partial -t cpp sample1.sc
$ apre -parse full -t cpp sample1.sc

-D<define_name>#

This option is used to specify the name of a macro during the precompile operation. This command has the same function as using the #define preprocessor directive in your code.

Example

Set the command-line option as shown below to define a macro named ALTIBASE when precompiling sample1.sc.

$ apre -DAltibase -t cpp sample1.sc

-v#

This displays the version of APRE.

Example

Check the version of the APRE C/C++ precompiler:

$ apre -v
Altibase Precompiler2(APRE) Ver. 7.1.0.0.1 XEON_LINUX_redhat_Enterprise_AS4-64bit-7.1.0.0.1-release-GCC3.4.6 (xeon-redhat-linux-gnu) Oct 23 2013 09:28:30

-n#

This option is used to indicate that any host variables of type CHAR are not null-padded. This option should be applied into all the necessary source files when creating an execution program through precompiling multiple source files(.sc) The length of a CHAR type input host variable must be the same as or shorter than that of the column in the database.

-unsafe_null#

This option is used to prevent an error from being raised even when a NULL value is fetched. This option should be applied to all the necessary source files when creating an executing program with precompiling multiple source files(.sc).

An error occurs if the value of a column on which a SELECT or FETCH operation is executed is NULL in case that an indicator variable is not specified.

-spill <values>#

This option is specified only when precompiling in an AIX environment. This is the same as using the #pragma directive, as shown below:

#pragma options spill=<values>

-keyword#

The -keyword displays the list of reserved words in relation to embedded SQL.

Example

$ apre -keyword

:: Keywords for C code ::
:: Keywords for C code ::
ALTIBASE_APRE APRE_BINARY APRE_BINARY2 APRE_BIT APRE_BLOB APRE_BLOB_LOCATOR APRE_BYTES APRE_CLOB APRE_CLOB_LOCATOR APRE_DUPKEY_ERR APRE_INTEGER APRE_NIBBLE APRE_NUMERIC APRE_VARBYTES MAX_CHAR_PTR SESC_DECLARE SESC_INCLUDE SES_BINARY SES_BIT SES_BLOB SES_BLOB_LOCATOR SES_BYTES SES_CLOB SES_CLOB_LOCATOR SES_DUPKEY_ERR SES_INTEGER SES_NIBBLE SES_NUMERIC SES_VARBYTES SQLFailOverCallback SQLLEN SQL_DATE_STRUCT SQL_TIMESTAMP_STRUCT SQL_TIME_STRUCT SQL_NUMERIC_STRUCT VARCHAR

:: Keywords for Embedded SQL statement ::
ABSOLUTE ADD AFTER AGER ALL ALLOCATE ALTER AND ANY ARCHIVE ARCHIVELOG AS ASC ASENSITIVE AT AUTOCOMMIT BACKUP BATCH BEFORE BEGIN BETWEEN BLOB_FILE BREAK BY CASCADE CASE CAST CLEAR_RECPTRS CLOB_FILE CLOSE COALESCE COLUMN COMMIT COMPILE CONNECT CONSTANT CONSTRAINT CONSTRAINTS CONTINUE CREATE CUBE CURSOR CYCLE DATABASE DEALLOCATE DECLARE DEFAULT DELETE DEQUEUE DESC DESCRIPTOR DIRECTORY DISABLE DISABLE_RECPTR DISCONNECT DISTINCT DO DROP EACH ELSE ELSEIF ELSIF ENABLE ENABLEALL_RECPTRS ENABLE_RECPTR END ENQUEUE ESCAPE EXCEPTION EXEC EXECUTE EXISTS EXIT EXTENTSIZE FALSE FETCH FIFO FIRST FIXED FLUSH FOR FOREIGN FOUND FREE FROM FULL FUNCTION GOTO GRANT GROUP GROUPING HAVING HOLD IDENTIFIED IF IMMEDIATE IN INDEX INDICATOR INNER INSENSITIVE INSERT INTERSECT INTO IS ISOLATION JOIN KEY LAST LEFT LESS LEVEL LIFO LIKE LIMIT LOB LOCAL LOCK LOGANCHOR LOOP MAXROWS MERGE MINUS MODE MOVE MOVEMENT NEW NEXT NOARCHIVELOG NOCYCLE NOPARALLEL NOT NULL OF OFF OFFLINE OLD ON ONERR ONLINE ONLY OPEN OPTION OR ORDER OTHERS OUT OUTER PARALLEL PARTITION PARTITIONS PREPARE PRIMARY PRIOR PRIVILEGES PROCEDURE PUBLIC QUEUE RAISE READ REBUILD RECOVER REFERENCES REFERENCING RELATIVE RELEASE RENAME REPLACE REPLICATION RESTRICT RETURN REVERSE REVOKE RIGHT ROLLBACK ROLLUP ROW ROWCOUNT ROWTYPE SAVEPOINT SCROLL SELECT SENSITIVE SEQUENCE SESSION SET SETS SOME SPLIT SQLCODE SQLERRM SQLERROR SQLLEN START STATEMENT STEP STORE SYNONYM TABLE TABLESPACE TEMPORARY THAN THEN THREADS TO TRIGGER TRUE TRUNCATE TYPE TYPESET UNION UNIQUE UNTIL UPDATE USER USING VALUES VARCHAR VARIABLE VIEW VOLATILE WAIT WAKEUP_RECPTR WHEN WHENEVER WHERE WHILE WITH WORK WRITE

-debug <macro|symbol>#

When this option is used, a symbol table containing the names of macros or declared variables in the source code is output. This option is provided for use in debugging source code.

macro

If -debug macro is specified, a macro list containing the names of all defined macros is output.

symbol

If -debug symbol is specified, a list of information about declared variables is output.

Example

Create the sample1.c file and output a macro list containing the names of all defined macros.

$ apre -debug macro sample1.sc

Create the sample1.c file and output a list of information about declared variables.

$ apre -debug symbol sample1.sc

Print both macros and variables.

$ apre -debug macro symbol sample1.sc

-lines#

The contents of the source file '* .sc' can be compared through specifying #line to be inserted into .c or .cpp file created by preprocessing

Example

It can be verified that there is #line after creating sample.sc file with preprocessing.

$ apre -debug macro symbol sample1.sc

-nchar_utf16#

When this option is used, national character type data are encoded as UTF-16 during the precompile operation. Since this option cannot be applied into each source file(.sc), this option should be applied into all the source files in the case of creating an execution program with precompiling two or more source files. The national character type data are encoded in the format specified by the ALTIBASE_NLS_USE property.

However, when using the encoding method specified in the ALTIBASE_NLS_USE property, the potential data loss might be occurred since the Unicode values stored in the database cannot be accurately expressed when executing a query expression.

Example

Preprocess the program with UTF-16.

$ apre -nchar_utf16 -t cpp sample.sc

-nchar_var <variable_name_list>#

When this option is used, APRE processes the specified variables using the national character set of Altibase. Blanks between variable names are not allowed. Additionally, variables within structures cannot be specified.

-silent#

This is an option to turn on silent mode. Turning on silent mode will not show additional description such as Copryright.

Programming using Embedded SQL Statements#

In this section, a brief explanation of the general flow of applications containing embedded SQL statements is provided, as well as a description of how to approach writing such applications.

Generally, the order in which an application is authored should mirror the general flow of execution of the application, which is as follows:

Declaring Host Variables#

When writing a program, it is first necessary to declare the host variables and indicator variables that will be used. Host variables must be declared in the host variable declaration section if the -partial precompiler option is not set to "full".

For more information about host variables and indicator variables, please refer to Chapter 2: Host Variables and Indicator Variables.

Considerations when Declaring Host Variables

  • Nested structures cannot be used as host variables. In other words, a structure cannot be an element of another structure.
  • When declaring array-type host variables, macros can be used only to specify the number of array elements. Macro definitions cannot be used, for example, to specify the location at which the value of a host variable is to be substituted in an embedded SQL statement.
  • When declaring a character-type (i.e. char or varchar) output host variable, the length of the host variable must be defined so that it is at least one byte longer than the size of the corresponding column. Otherwise, when a SELECT or FETCH statement is executed, the value in the column will be truncated. In this case, the value returned in sqlca.sqlcode will be SQL_SUCCESS_WITH_INFO.

Special Considerations when Declaring Array-Type Host Variables

For complete information about using arrays with embedded SQL statements, please refer to Chapter 9: Using Arrays in Embedded SQL Statements.

  • Array-type host variables can only be one-dimensional arrays. The exception is that two-dimensional char and varchar type arrays are allowed.
  • An indicator variable cannot be used with a host variable that is an array of structures.
  • When an array of structures is used as an output host variable in the INTO clause of a SELECT or FETCH statement, only one output host variable can be used. In other words, the array of structures cannot be used with other output host variables. Therefore, if the output host variable to be used in the INTO clause is an array of structures, the number of elements in the structure must be the same as the number of columns in the select list.
  • When an array of structures is used as an insert host variable in the VALUES clause of an INSERT statement, only one input host variable can be used. In other words, the array of structures cannot be used with other input host variables. Therefore, if the input host variable to be used in the VALUES clause is an array of structures, the number of elements in the structure must be the same as the number of columns in the INSERT statement.
  • Internally, the varchar type is handled as a kind of structure, so it is subject to the above limitations.
  • Array-type host variables must not be used together with non-array type host variables in INSERT, UPDATE or DELETE statements.
  • If an array-type output host variable is used when a SELECT or FETCH statement is executed, and the number of returned records is smaller than the array size, the value of sqlca.sqlcode will be SQL_SUCCESS.
  • Array-type input host variables cannot be used with SELECT statements or cursor-related statements.
  • The FOR clause can be used with array-type input host variables to execute an embedded INSERT, UPDATE, DELETE statements, but can be used with array-type output host variables to execute an embedded FETCH statement.
  • When working with array-type host variables in AUTOCOMMIT mode, a "transaction" is not the totality of operations performed using the entire array. Rather, the operations corresponding to each element are individual transactions, and thus they are committed separately from one another.
  • Arrays of pointers cannot be declared or used as host variables.

Considerations When Declaring Indicator Variables

  • The data type of indicator variables must be int.
  • When using the varchar type as an input host variable without a separately defined indicator variable, it is necessary to specify the value of len, which is one of the elements of the varchar structure. If the value of the varchar array is not NULL, set the value of len to the length of the arr element. If the varchar array is NULL, set len to -1.
  • For numeric type host variables, indicator variable values other than -1 are meaningless.
  • Indicator variables must be used when working with binary type host variables.

Host Variable Declaration Section

For complete information about the host variable declaration section, please refer to Chapter 3: Host Variable Declaration Section.

  • Definitions of data types (typedef) to be used as host variable data types must be made in the host variable declaration section.

Example

The following is an example of a host variable declaration section:

< Sample program: insert.sc >

/* declare host variables */
EXEC SQL BEGIN DECLARE SECTION;
char usr[10];
char pwd[10];
char    s_gno[10+1];
char    s_gname[20+1];
char    s_goods_location[9+1];
int     s_stock;
double  s_price;
EXEC SQL END DECLARE SECTION;

Connecting to a Database Server#

After the host variables have been declared, it is necessary to connect to a database server before any SQL statements can be executed.

After a connection with a database server has been successfully established, it will then be possible to execute all embedded SQL statements.

For detailed instructions on how to connect to database servers, please refer to Chapter 6: Embedded SQL Statements.

About Connections, Multiple Connections, and Sessions

  • To establish a new connection using the same name as an existing connection, it is first necessary to execute the DISCONNECT statement to terminate the existing connection.

  • If the connection method (CONNTYPE) is set to 2 or 3 in the connection string in a USING clause, the DSN and PORT_NO options will be ignored even if they are set, and an attempt will be made to connect with the local database server.  When two sets of connection options are specified and a connection is successfully established using the first set of options, the value returned in sqlca.sqlcode is SQL_SUCCESS. If the connection attempt using the first set of options fails, but a connection is then successfully established using the second set of options, the value returned in sqlca.sqlcode is SQL_SUCCES_WITH_INFO. If a connection cannot be established using either set of options, the value returned in sqlca.sqlcode is SQL_ERROR.

  • A maximum of 1024 embedded SQL statements can be executed per connection.

  • In a session in which AUTOCOMMIT is set to OFF, if an application is shut down in the state in which uncommitted transactions exist, all transactions that were not committed at the time that the application is shut down will be rolled back. However, if the DISCONNECT statement is executed before the application is shut down, all pending transactions will be committed.

  • The AT clause cannot be used in the following types of embedded SQL:

    INCLUDE statement: EXEC SQL INCLUDE …
    OPTION statement: EXEC SQL OPTION …
    WHENEVER statement: EXEC SQL WHENEVER …

Example

The following example shows how to connect to a database server:

< Sample Program : connect1.sc >

/* declare host variables */
EXEC SQL BEGIN DECLARE SECTION;
char usr[10];
char pwd[10];
EXEC SQL END DECLARE SECTION;

/* set username */
strcpy(usr, "SYS");
/* set password */
strcpy(pwd, "MANAGER");

EXEC SQL CONNECT :usr IDENTIFIED BY :pwd;  
if (sqlca.sqlcode == SQL_SUCCESS) /* check sqlca.sqlcode */
{
    printf("Success connection to altibase server\n\n");
}
else
{
    printf("Error : [%d] %s\n\n", SQLCODE, sqlca.sqlerrm.sqlerrmc);
    exit(1);
}

Executing Embedded SQL Statements#

After a connection with a database server has been successfully established, it is possible to execute embedded SQL statements. The term "embedded SQL statements" encompasses DML statements such as the SELECT and INSERT statements, DDL statements such as object creation statements, system control statements, cursor-related SQL statements, dynamic SQL statements, and all other SQL statements of Altibase.

For more information about using each of the various kinds of embedded SQL statements, please refer to Chapters 6 , 8 , 9 , 10 , and 11.

Examples

What follows are examples of the use of various kinds of embedded SQL statements.

[Example 1] The following is an example of an UPDATE statement:

< Sample Program : update.sc >

/* declare host variables */
EXEC SQL BEGIN DECLARE SECTION;
int      s_eno;
short    s_dno;
varchar  s_emp_job[15+1];
EXEC SQL END DECLARE SECTION;

s_eno = 2;
s_dno = 1001;
strcpy(s_emp_job.arr, "ENGINEER");
s_emp_job.len = strlen(s_emp_job.arr);

EXEC SQL UPDATE EMPLOYEES 
SET DNO     = :s_dno,
                EMP_JOB = :s_emp_job
            WHERE ENO = :s_eno;

[Example 2] The following is an example of the use of cursor control statements:

< Sample Program : hostvar.h >

EXEC SQL BEGIN DECLARE SECTION;
typedef struct department
{
    short dno; 
    char  dname[30+1];
    char  dep_location[9+1];
    int   mgr_no;
} department;

typedef struct dept_ind
{
    int dno; 
    int dname;
    int dep_location;
    int mgr_no;
} dept_ind;
EXEC SQL END DECLARE SECTION;

< Sample Program : cursor1.sc >

/* specify path of header file */
EXEC SQL OPTION (INCLUDE=./include);
/* include header file for precompile */
EXEC SQL INCLUDE hostvar.h;

/* declare host variables */
EXEC SQL BEGIN DECLARE SECTION;
/* structure host variables */
department s_department;
/* structure indicator variables */
dept_ind s_dept_ind;
EXEC SQL END DECLARE SECTION;

/* declare cursor */
EXEC SQL DECLARE DEPT_CUR CURSOR FOR 
             SELECT *
             FROM DEPARTMENTS; 

/* open cursor */
EXEC SQL OPEN DEPT_CUR;

/* fetch cursor in loop */
while(1)
{
    /* use indicator variables to check null value */
    EXEC SQL FETCH DEPT_CUR INTO :s_department :s_dept_ind;
    if (sqlca.sqlcode == SQL_SUCCESS) /* check sqlca.sqlcode */
    {
    printf("%d     %s %s          %d\n", 
              s_department.dno, s_department.dname, 
              s_department.dep_location, 
s_department.mgr_no);
}
else if (sqlca.sqlcode == SQL_NO_DATA)
{
    break;
}
else 
{
    printf("Error : [%d] %s\n", SQLCODE, sqlca.sqlerrm.sqlerrmc);
    break;
}
}

/* close cursor */
EXEC SQL CLOSE DEPT_CUR;

Handling Runtime Errors#

After every embedded SQL statement has been executed, it is necessary to check the result of execution. The result of execution of embedded SQL statements is stored in the variable sqlca.sqlcode, and, depending on the value of sqlca.sqlcode, the variables SQLSTATE, SQLCODE, etc. can be checked to obtain more information about the result of execution.

For detailed information about all of the variables that can be checked to determine the result of execution of an embedded SQL statement, please refer to Chapter 7: Handling Runtime Errors.

Considerations when Handling Runtime Errors

The following are some considerations to keep in mind when using SQLCA, SQLCODE, SQLSTATE and WHENEVER to handle run-time errors.

  • Every time an embedded SQL statement is executed, be sure to check the value of sqlca.sqlcode so that any errors that occurred will be processed appropriately.
  • When a SELECT statement is executed, if the size of an output host variable is smaller than the size of the corresponding character-type column, the data will be truncated so that they can be saved in the host variable. When this happens, the value of sqlca.sqlcode will be SQL_SUCCESS_WITH_INFO.
  • If no records are affected by an UPDATE or DELETE operation, the value of sqlca.sqlcode will be SQL_NO_DATA. To determine the number of records that were affected by an UPDATE or DELETE operation, check the value of sqlca.sqlerrd[2]. If no records were affected, this value will be 0.
  • The SQLCODE error code values are negative decimal integers. However, the error codes in the Error Message Reference are positive hexadecimal values. Therefore, when referring to the Error Message Reference, convert the absolute values of SQLCODE error codes into hexadecimal values.
  • The scope of applicability of a WHENEVER statement is not the same as the overall program flow. In particular, a WHENEVER statement applies only to the file in which it is found.
  • The WHENEVER statement must precede any embedded SQL statements to which it is intended to apply.
  • WHENEVER statements are connection-independent. In other words, a WHENEVER statement in an application with more than one connection affects all embedded SQL statements within its scope of applicability, regardless of the connection to which the embedded SQL statements pertain.

Example

In this example, the variables in the sqlca structure are checked to determine the result of execution of an embedded SQL statement.

< Sample Program : delete.sc >

/* declare host variables */
EXEC SQL BEGIN DECLARE SECTION;
int      s_eno;
short    s_dno;
EXEC SQL END DECLARE SECTION;

s_eno = 5;
s_dno = 1000;

EXEC SQL DELETE FROM EMPLOYEES 
WHERE ENO > :s_eno AND 
DNO > :s_dno AND 
EMP_JOB LIKE 'P%';

/* check sqlca.sqlcode */
if (sqlca.sqlcode == SQL_SUCCESS) 
{
    /* sqlca.sqlerrd[2] holds the 
rows-processed(deleted) count */
    printf("%d rows deleted\n\n", sqlca.sqlerrd[2]);
}
else 
{
    printf("Error : [%d] %s\n\n", 
SQLCODE, sqlca.sqlerrm.sqlerrmc);
}

Disconnecting from the Database Server#

After all embedded SQL statements have been executed, it will be necessary to disconnect from the database server before shutting down the application. Disconnecting from the database server frees all resources that were allocated for the connection. After disconnecting from the database server, it is of course impossible to execute any more embedded SQL statements.

For detailed information about how to connect to and disconnect from database servers, please refer to Chapter6: Embedded SQL Statements.

Example

The following example shows how to disconnect from a database server:

< Sample Program : connect1.sc >

EXEC SQL DISCONNECT;

The Precompile Operation#

This is how to execute the precompiling operation using the APRE precompiler:

apre [<apre - option>] <filename>

Example

In the following example, the connect1.sc file is precompiled:

$ apre connect1.sc