SQL
SQL
Table of contents
If you're viewing this document online, you can click any of the topics below to link directly to that section.
1. Before you start ................................................................................... 2 2. Introduction to embedded SQL programming ..................................... 5 3. Constructing an embedded SQL application ....................................... 8 4. Diagnostics and error handling.......................................................... 25 5. Creating executable applications....................................................... 30 6. Conclusion......................................................................................... 34
Page 1 of 36
http://www-136.ibm.com/developerworks/db2
This is the third in a series of seven tutorials that you can use to help prepare for the DB2 UDB V8.1 Family Application Development Certification exam (Exam 703). The material in this tutorial primarily covers the objectives in Section 3 of the exam, entitled "Embedded SQL programming." You can view these objectives at: http://www.ibm.com/certify/tests/obj703.shtml. You do not need a copy of DB2 Universal Database to complete this tutorial. However, you can download a free trial version of IBM DB2 Universal Database Enterprise Edition for reference.
Page 2 of 36
http://www-136.ibm.com/developerworks/db2
This tutorial is one of the tools that can help you prepare for Exam 703. You should also take advantage of the Resources on page 34 identified at the end of this tutorial for more information.
http://www-136.ibm.com/developerworks/db2
reserved. IBM, DB2, DB2 Universal Database, DB2 Information Integrator, WebSphere and WebSphere MQ are trademarks or registered trademarks of IBM Corporation in the United States, other countries, or both. Other company, product, and service names may be trademarks or service marks of others.
Page 4 of 36
http://www-136.ibm.com/developerworks/db2
Section 2. Introduction to embedded SQL programming Structured Query Language and embedded SQL
Structured Query Language (SQL) is a standardized language used to manipulate database objects and the data they contain. SQL is comprised of several different statements that are used to define, alter, and destroy database objects, as well as add, update, delete, and retrieve data values. However, SQL is nonprocedural, and therefore is not a general-purpose programming language. (SQL statements are executed by the DB2 Database Manager, not by the operating system.) As a result, database applications are usually developed by combining the decision and sequence control of a high-level programming language with the data storage, manipulation, and retrieval capabilities of SQL. Several methods are available for merging SQL with a high-level programming language, but the simplest approach is to embed SQL statements directly into the source code file(s) that will be used to create an application. This technique is referred to as embedded SQL programming. One of the drawbacks to developing applications using embedded SQL is that high-level programming language compilers do not recognize, and therefore cannot interpret, SQL statements encountered in a source code file. Because of this, source code files containing embedded SQL statements must be preprocessed (using a process known as precompiling) before they can be compiled (and linked) to produce a database application. To facilitate this preprocessing, each SQL statement coded in a high-level programming language source code file must be prefixed with the keywords EXEC SQL and terminated with either a semicolon (in C/C++ or FORTRAN) or the keywords END_EXEC (in COBOL). When the preprocessor (a special tool known as the SQL precompiler) encounters these keywords, it replaces the text that follows (until a semicolon (;) or the keywords END-EXEC is found) with a DB2 UDB-specific function call that forwards the specified SQL statement to the DB2 Database Manager for processing. Likewise, the DB2 Database Manager cannot work directly with high-level programming language variables. Instead, it must use special variables known as host variables to move data between an application and a database. (We will take a closer look at host variables in Declaring host variables on page 8.) Host variables look like any other high-level programming language variable; to be set apart, they must be defined within a special section known as a declare section. Also, in order for the SQL precompiler to distinguish host variables from other text in an SQL statement, all references to host variables must be preceded by a colon (:).
Static SQL
A static SQL statement is an SQL statement that can be hardcoded in an application program at development time because information about its
Embedded SQL programming Page 5 of 36
http://www-136.ibm.com/developerworks/db2
structure and the objects (i.e., tables, column, and data types) it is intended to interact with is known in advance. Since the details of a static SQL statement are known at development time, the work of analyzing the statement and selecting the optimum data access plan to use to execute the statement is performed by the DB2 optimizer as part of the development process. Because their operational form is stored in the database (as a package) and does not have to be generated at application run time, static SQL statements execute quickly. The downside to this approach is that all static SQL statements must be prepared (in other words, their access plans must be generated and stored in the database) before they can be executed. Furthermore, static SQL statements cannot be altered at run time, and each application that uses static SQL must bind its operational package(s) to every database with which the application will interact. Additionally, because static SQL applications require prior knowledge of database objects, changes made to those objects after an application has been developed can produce undesirable results. The following are examples of static SQL statements:
SELECT COUNT(*) FROM EMPLOYEE UPDATE EMPLOYEE SET LASTNAME = 'Jones' WHERE EMPID = '001' SELECT MAX(SALARY), MIN(SALARY) INTO :MaxSalary, :MinSalary FROM EMPLOYEE
Generally, static SQL statements are well suited for high-performance applications that execute predefined operations against a known set of database objects.
Dynamic SQL
Although static SQL statements are relatively easy to incorporate into an application, their use is somewhat limited because their format must be known in advance. Dynamic SQL statements, on the other hand, are much more flexible because they can be constructed at application run time; information about a dynamic SQL statement's structure and the objects with which it plans to interact does not have to be known in advance. Furthermore, because dynamic SQL statements do not have a precoded, fixed format, the data object(s) they reference can change each time the statement is executed. Even though dynamic SQL statements are generally more flexible than static SQL statements, they are usually more complicated to incorporate into an application. And because the work of analyzing the statement to select the best data access plan is performed at application run time (again, by the DB2 optimizer), dynamic SQL statements can take longer to execute than their static SQL counterparts. (Since dynamic SQL statements can take advantage of the database statistics available at application run time, there are some cases in
Page 6 of 36 Embedded SQL programming
http://www-136.ibm.com/developerworks/db2
which a dynamic SQL statement will execute faster than an equivalent static SQL statement, but those are the exception and not the norm.) The following are examples of dynamic SQL statements:
SELECT COUNT(*) FROM ? INSERT INTO EMPLOYEES VALUES (?, ?) DELETE FROM DEPARTMENT WHERE DEPTID = ?
Generally, dynamic SQL statements are well suited for applications that interact with a rapidly changing database or that allow users to define and execute ad-hoc queries.
Page 7 of 36
http://www-136.ibm.com/developerworks/db2
A declare section can be coded anywhere high-level programming language variable declarations can be coded in a source code file. Although a source code file typically contains only one declare section, multiple declare sections are allowed. Host variables that transfer data to a database are known as input host variables, while host variables that receive data from a database are known as output host variables. Regardless of whether a host variable is used for input or output, its attributes must be appropriate for the context in which it is used. Therefore, you must define host variables in such a way that their data types and lengths are compatible with the data types and lengths of the columns they are intended to work with: When deciding on the appropriate data type to assign to a host variable, you should obtain information about the column or special register that the variable will be associated with and refer to the conversion charts found in the IBM DB2 Universal Database Application Development Guide: Programming Client Applications documentation (see Resources on page 34). Also, keep in mind that each host variable used in an application must be assigned a unique name. Duplicate names in the same file are not allowed, even when the host variables are defined in different declare sections. A tool known as the Declaration Generator can be used to generate host variable declarations for the columns of a given table in a database. This tool creates embedded SQL declaration source code files, which can easily be inserted into C/C++, Java language, COBOL, and FORTRAN applications. For more information about this utility, refer to the db2dclgen command in the DB2 UDB Command Reference product documentation. How is a host variable used to move data between an application and a database? The easiest way to answer this question is by examining a simple embedded SQL source code fragment. The following C source code fragment
Page 8 of 36 Embedded SQL programming
http://www-136.ibm.com/developerworks/db2
An indicator variable is associated with a specific host variable when it follows the host variable in an SQL statement. Once an indicator variable has been associated with a host variable, it can be examined as soon as its corresponding host variable has been populated. If the indicator variable contains a negative value, a null value was found and the value of the corresponding host variable should be ignored. Otherwise, the value of the corresponding host variable is valid.
Page 9 of 36
http://www-136.ibm.com/developerworks/db2
Again, in order to understand how indicator variables are used, it helps to look at an example embedded SQL source code fragment. The following code, written in the C programming language, shows one example of how indicator variables are defined and used:
... // Define The SQL Host Variables Needed EXEC SQL BEGIN DECLARE SECTION; char EmployeeNo[7]; double Salary; // Salary - Used If SalaryNI Is // Positive ( >= 0 ) short SalaryNI; // Salary NULL Indicator - Used // To Determine If Salary // Value Should Be NULL EXEC SQL END DECLARE SECTION; ... // Declare A Static Cursor EXEC SQL DECLARE C1 CURSOR FOR SELECT EMPNO, DOUBLE(SALARY) FROM EMPLOYEE; // Open The Cursor EXEC SQL OPEN C1; // If The Cursor Was Opened Successfully, Retrieve And // Display All Records Available while (sqlca.sqlcode == SQL_RC_OK) { // Retrieve The Current Record From The Cursor EXEC SQL FETCH C1 INTO :EmployeeNo, :Salary :SalaryNI; // If The Salary Value For The Record Is NULL, ... if (SalaryNI < 0) { printf("No salary information is available for "); printf("employee %s\n", EmployeeNo); } } // Close The Open Cursor EXEC SQL CLOSE C1; ...
Indicator variables can also be used to send null values to a database when an insert or update operation is performed. When processing INSERT and UPDATE SQL statements, the DB2 Database Manager examines the value of any indicator variable provided first. If it contains a negative value, the DB2 Database Manager assigns a null value to the appropriate column, provided null values are allowed. (If the indicator variable is set to zero or contains a positive number, or if no indicator variable is used, the DB2 Database Manager assigns the value stored in the corresponding host variable to the appropriate column instead.) Thus, the code used in a C/C++ source code file to assign a null value to a column in a table would look something like:
ValueInd = -1; EXEC SQL INSERT INTO TAB1 VALUES (:Value :ValueInd);
Page 10 of 36
http://www-136.ibm.com/developerworks/db2
sqlcabc
INTEGER
sqlcode
INTEGER
sqlerrml
SMALLINT
sqlerrmc
CHAR(70)
http://www-136.ibm.com/developerworks/db2
This element is also used when a successful connection is established. sqlerrp CHAR(8) A diagnostic value that represents the type of DB2 server currently being used. This value begins with a 3-letter code identifying the product version and release, and is followed by 5 digits that identify the modification level of the product. For example, SQL08014 means DB2 Universal Database, version 8, release 1, modification level 4. If the sqlcode element contains a negative value, this element will contain an 8-character code that identifies the module that reported the error. An array of six integer values that provide additional diagnostic information when an error occurs. (Refer to the next table in this panel for more information about the diagnostic information that can be returned in this element.) An array of character values that serve as warning indicators; each element of the array contains either a blank or the letter W. If compound SQL was used, this field will contain an accumulation of the warning indicators that were set for all substatements executed in the compound SQL statement block. (Refer to the third table in this panel for more information about the types of warning information that can be returned in this element.) The SQLSTATE value that identifies the outcome of the most recently executed SQL statement. For more on SQLSTATE values, see SQLSTATEs on page29 .
sqlerrd
INTEGER ARRAY
sqlwarn
CHAR(11)
sqlstate
CHAR(5)
Now let's look at the elements of the sqlca.sqlerrd array: Array element sqlerrd[0] Description If a connection was successfully established, this element will contain the expected difference in length of mixed character data (CHAR data types) when it is converted from the application code page used to the database code page used. A value of 0 or 1 indicates that no expansion is anticipated; a positive value greater than 1 indicates a possible expansion in length; and a negative value indicates a possible reduction in length. If a connection was successfully established, this element will
Embedded SQL programming
sqlerrd[1]
Page 12 of 36
http://www-136.ibm.com/developerworks/db2
contain the expected difference in length of mixed character data (CHAR data types) when it is converted from the database code page used to the application code page used. A value of 0 or 1 indicates that no expansion is anticipated; a positive value greater than 1 indicates a possible expansion in length; and a negative value indicates a possible reduction in length. If the SQLCA data structure contains information for compound SQL, this element will contain the number of substatements that failed (if any). sqlerrd[2] If the SQLCA data structure contains information for a CONNECT SQL statement that executed successfully, this element will contain the value "1" if the connected database is updatable and the value "2" if the connected database is read-only. If the SQLCA data structure contains information for a PREPARE SQL statement that executed successfully, this element will contain an estimate of the number of rows that will be returned in a result data set when the prepared statement is executed. If the SQLCA data structure contains information for an INSERT, UPDATE, or DELETE SQL statement that executed successfully, this element will contain a count of the number of rows that were affected by the operation. If the SQLCA data structure contains information for compound SQL, this element will contain a count of the number of rows that were affected by the substatements in the compound SQL statement block. sqlerrd[3] If the SQLCA data structure contains information for a CONNECT SQL statement that executed successfully, this element will contain the value "0" if one-phase commit from a down-level client is being used, the value "1" if one-phase commit is being used, the value "2" if one-phase, read-only commit is being used, and the value "3" if two-phase commit is being used. If the SQLCA data structure contains information for a PREPARE SQL statement that executed successfully, this element will contain a relative cost estimate of the resources needed to prepare the statement specified. If the SQLCA data structure contains information for compound SQL, this element will contain a count of the number of substatements in the compound SQL statement block that executed successfully. sqlerrd[4] If the SQLCA data structure contains information for a CONNECT SQL statement that executed successfully, this element will contain the value "0" if server authentication is being used, the value "1" if client authentication is being used, the value "2" if authentication is being handled by DB2 Connect, the value "3" if authentication is being handled by
Page 13 of 36
http://www-136.ibm.com/developerworks/db2
DCE Security Services, and the value "255" if the way authentication is being handled cannot be determined. If the SQLCA data structure contains information for anything else, this element will contain a count of the total number of rows that were inserted, updated, or deleted as a result of the DELETE rule of one or more referential integrity constraints or the activation of one or more triggers. (If the SQLCA data structure contains information for compound SQL, this element will contain a count of all such rows for each substatement in the compound SQL statement block that executed successfully.) sqlerrd[5] For partitioned databases, this element contains the partition number of the partition that encountered an error or warning. If no errors or warnings were encountered, this element will contain the partition number of the partition that serves as the coordinator node.
And now let's look at the elements of the of the sqlca.sqlwarn array: Array element sqlwarn[0] Description This element is blank if all other elements in the array are blank; it contains the character W if one or more of the other elements available is not blank. This element contains the character W if the value for a column with a character string data type was truncated when it was assigned to a host variable; it contains the character N if the null-terminator for the string was truncated. This element contains the character W if null values were eliminated from the arguments passed to a function. This element contains the character W if the number of values retrieved does not equal the number of host variables provided. This element contains the character W if an UPDATE or DELETE SQL statement that does not contain a WHERE clause was prepared. This element is reserved for future use. This element contains the character W if the result of a date calculation was adjusted to avoid an invalid date value. This element is reserved for future use. This element contains the character W if a character that could not be converted was replaced with a substitution character. This element contains the character W if one or more errors in an arithmetic expression were ignored during column function processing. This element contains the character W if a conversion error
Embedded SQL programming
sqlwarn[1]
sqlwarn[2] sqlwarn[3]
sqlwarn[4]
sqlwarn[10]
Page 14 of 36
http://www-136.ibm.com/developerworks/db2
occurred while converting a character data value in another element of the SQLCA data structure variable.
sqldabc
INTEGER
sqln sqld
SMALLINT SMALLINT
sqlvar
STRUCTURE ARRAY
In addition to this basic information, an SQLDA data structure variable contains an arbitrary number of occurrences of sqlvar data structures (which are referred to as SQLVAR variables). The information stored in each SQLVAR variable depends on the location where the corresponding SQLDA data structure variable is used: When used with a PREPARE or a DESCRIBE SQL statement, each SQLVAR variable will contain information about a column that will exist in the result data set produced when the prepared SQL statement is executed. (If any of the columns have a large object (LOB) or user-defined data type, the number of SQLVAR variables used will be doubled and the seventh byte of the character string value stored in the sqldaid element of the SQLDA data structure variable will be assigned the value "2".) On the other hand, when the SQLDA data structure variable is used with an OPEN, FETCH, or EXECUTE SQL statement, each SQLVAR variable will contain information about
Embedded SQL programming Page 15 of 36
http://www-136.ibm.com/developerworks/db2
a host variable whose value is to be passed to the DB2 Database Manager. Two types of SQLVAR variables are used: base SQLVARs and secondary SQLVARs. Base SQLVARs contain basic information (such as data type code, length attribute, column name, host variable address, and indicator variable address) for result data set columns or host variables. The elements that make up a base SQLVAR data structure variable are shown in the following table. Element name sqltype Data type SMALLINT Description The data type of a host variable used, or the data type of a column in the result data set produced. The size (length), in bytes, of a host variable used, or the size of a column in the result data set produced. A pointer to a location in memory where the data for a host variable used is stored, or a pointer to a location in memory where data for a column in the result data set produced is to be stored. A pointer to a location in memory where the data for the null indicator variable associated with a host variable used is stored, or a pointer to a location in memory where the data for the null indicator variable associated with a column in the result data set produced is to be stored. The unqualified name of a host variable or a column in the result data set produced.
sqllen
SMALLINT
sqldata
Pointer
sqlind
Pointer
sqlname
VARCHAR(30)
On the other hand, secondary SQLVARs contain either the distinct data type name for distinct data types or the length attribute of the column or host variable and a pointer to the buffer that contains the actual length of the data for LOB data types. Secondary SQLVAR entries are only present if the number of SQLVAR entries is doubled because LOBs or distinct data types are used: If locators or file reference variables are used to represent LOB data types, secondary SQLVAR entries are not used. The information stored in an SQLDA data structure variable, along with the information stored in any corresponding SQLVAR variables, may be placed there manually (using the appropriate programming language statements), or can be generated automatically by executing the DESCRIBE SQL statement. Both an SQLCA data structure variable and an SQLDA data structure variable can be created by embedding the appropriate form of the INCLUDE SQL statement (INCLUDE SQLCA and INCLUDE SQLDA, respectively) within an embedded SQL source code file.
Page 16 of 36
http://www-136.ibm.com/developerworks/db2
http://www-136.ibm.com/developerworks/db2
data set that will be produced, if any, when the SQL statement is executed. The SQL statement EXECUTE IMMEDIATE is used to process dynamic SQL statements in this manner. Dynamic SQL statements that are prepared and executed (using either method) at run time are not allowed to contain references to host variables. They can, however, contain parameter markers in place of constants and/or expressions. Parameter markers are represented by the question mark (?) character. They indicate where in the SQL statement the current value of one or more host variables or elements of an SQLDA data structure variable are to be substituted when the statement is executed. (Parameter markers are typically used where a host variable would be referenced if the SQL statement being executed were static.) Two types of parameter markers are available: typed and untyped. A typed parameter marker is one that is specified along with its target data type. Typed parameter markers have this general form:
CAST(? AS DataType)
This notation does not imply that a function is called, but rather it promises that the data type of the value replacing the parameter marker at application run time will either be the data type specified or a data type that can be converted to the data type specified. For example, consider the following SQL statement:
UPDATE EMPLOYEE SET LASTNAME = CAST(? AS VARCHAR(12)) WHERE EMPNO = '000050'
Here, the value for the LASTNAME column is provided at application run time, and the data type of that value will be either VARCHAR(12) or a data type that can be converted to VARCHAR(12). An untyped parameter marker, on the other hand, is specified without a target data type and has the form of a single question mark (?). The data type of an untyped parameter marker is determined by the context in which it is used. For example, in the following SQL statement, the value for the LASTNAME column is provided at application run time, and it is assumed that the data type of that value will be compatible with the data type that has been assigned to the LASTNAME column of the EMPLOYEE table.
UPDATE EMPLOYEE SET LASTNAME = ? WHERE EMPNO = '000050'
When parameter markers are used in embedded SQL applications, values that are to be substituted for parameter markers placed in an SQL statement must be provided as additional parameters to the EXECUTE or the EXECUTE IMMEDIATE SQL statement when either is used to execute the SQL statement specified. The following example, written in the C programming language, illustrates how actual values would be provided for parameter markers that have been coded in a simple UPDATE SQL statement:
Page 18 of 36 Embedded SQL programming
http://www-136.ibm.com/developerworks/db2
... // Define The SQL Host Variables Needed EXEC SQL BEGIN DECLARE SECTION; char SQLStmt[80]; char JobType[10]; EXEC SQL END DECLARE SECTION; ... // Define A Dynamic UPDATE SQL Statement That Uses A // Parameter Marker strcpy(SQLStmt, "UPDATE EMPLOYEE SET JOB = ? "); strcat(SQLStmt, "WHERE JOB = 'DESIGNER'"); // Populate The Host Variable That Will Be Used In // Place Of The Parameter Marker strcpy(JobType, "MANAGER"); // Prepare The SQL Statement EXEC SQL PREPARE SQL_STMT FROM :SQLStmt; // Execute The SQL Statement EXEC SQL EXECUTE SQL_STMT USING :JobType; ...
http://www-136.ibm.com/developerworks/db2
3. Retrieve (fetch) each row in the result data set, one by one, until an end-of-data condition occurs. Each time a row is retrieved from the result data set, the cursor is automatically moved to the next row. This is done by repeatedly executing the FETCH statement; host variables or an SQLDA data structure variable are used in conjunction with a FETCH statement to extract a row of data from a result data set. 4. If appropriate, modify or delete the current row, but only if the cursor is an updatable cursor. This is done by executing the UPDATE statement or the DELETE statement. 5. Close the cursor. This action will cause the result data set that was produced when the corresponding query was executed to be deleted. This is done by executing the CLOSE statement. Now that we have seen the steps that must be performed in order to use a cursor, let's examine how these steps are coded in an application. The following example, written in the C programming language, illustrates how a cursor would be used to retrieve the results of a SELECT SQL statement:
... // Declare The SQL Host Memory Variables EXEC SQL BEGIN DECLARE SECTION; char EmployeeNo[7]; char LastName[16]; EXEC SQL END DECLARE SECTION; ... // Declare A Cursor EXEC SQL DECLARE C1 CURSOR FOR SELECT EMPNO, LASTNAME FROM EMPLOYEE WHERE JOB = 'DESIGNER'; // Open The Cursor EXEC SQL OPEN C1; // Fetch The Records while (sqlca.sqlcode == SQL_RC_OK) { // Retrieve A Record EXEC SQL FETCH C1 INTO :EmployeeNo, :LastName; // Process The Information Retrieved if (sqlca.sqlcode == SQL_RC_OK) ... } // Close The Cursor EXEC SQL CLOSE C1; ...
If you know in advance that only one row of data will be produced in response to a query, there are two other ways to copy the contents of that row to host variables within an application program, by executing either the SELECT INTO statement or the VALUES INTO statement. Like the SELECT SQL statement,
Page 20 of 36 Embedded SQL programming
http://www-136.ibm.com/developerworks/db2
the SELECT INTO statement can be used to construct complex queries. However, unlike the SELECT statement, the SELECT INTO statement requires a list of valid host variables to be supplied as part of its syntax; it cannot be used dynamically. Additionally, if the result data set produced when the SELECT INTO statement is executed contains more than one record, the operation will fail and an error will be generated. (If the result data set produced is empty, a NOT FOUND warning will be generated.) Like the SELECT INTO statement, the VALUES INTO statement can be used to retrieve the data associated with a single record and copy it to one or more host variables. And, like the SELECT INTO statement, when the VALUES INTO statement is executed, all data retrieved is stored in a result data set. If this result data set contains only one record, the first value in that record is copied to the first host variable specified, the second value is copied to the second host variable specified, and so on. However, the VALUES INTO statement cannot be used to construct complex queries in the same way that the SELECT INTO statement can. Again, if the result data set produced when the VALUES INTO statement is executed contains more than one record, the operation will fail and an error will be generated. (If the result data set produced is empty, a NOT FOUND warning will be generated.)
Managing transactions
A transaction (also known as a unit of work) is a sequence of one or more SQL operations grouped together as a single unit, usually within an application process. Such a unit is called atomic because it is indivisible -- either all of its work is carried out or none of its work is carried out. A given transaction can be comprised of any number of SQL operations, from a single operation to many hundreds or even thousands, depending upon what is considered a single step within your business logic. The initiation and termination of a single transaction define points of data consistency within a database: Either the effects of all operations performed within a transaction are applied to the database and made permanent (committed), or the effects of all operations performed are backed out (rolled back) and the database is returned to the state it was in before the transaction was initiated. In most cases, transactions are initiated the first time an executable SQL statement is executed after a connection to a database has been established, or immediately after a pre-existing transaction has been terminated. Once initiated, transactions can be implicitly terminated using the automatic commit feature. Using this feature, each executable SQL statement is treated as a single transaction. If the statement executes successfully, any changes made by that statement are applied to the database. If the statement fails, any changes are discarded. Transactions can also be explicitly terminated by executing either the COMMIT or the ROLLBACK SQL statement. In either case, all transactions associated with a particular database should be completed before the connection to that database is terminated.
Embedded SQL programming Page 21 of 36
http://www-136.ibm.com/developerworks/db2
Page 22 of 36
http://www-136.ibm.com/developerworks/db2
printf("%lf\n", Salary); else printf("Unknown\n"); } } // Close The Open Cursor EXEC SQL CLOSE C1; // Commit The Transaction EXEC SQL COMMIT; // Terminate The Database Connection EXEC SQL DISCONNECT CURRENT; // Return Control To The Operating System return(0); }
On the other hand, a simple embedded SQL application, written in the C programming language using dynamic SQL, that changes all job titles "designer" to "manager" might look something like:
#include <stdio.h> #include <string.h> #include <sql.h> int main() { // Include The SQLCA Data Structure Variable EXEC SQL INCLUDE SQLCA; // Define The SQL Host Variables Needed EXEC SQL BEGIN DECLARE SECTION; char SQLStmt[80]; char JobType[10]; EXEC SQL END DECLARE SECTION; // Connect To The Appropriate Database EXEC SQL CONNECT TO SAMPLE USER db2admin USING ibmdb2; // Define A Dynamic UPDATE SQL Statement That Uses A // Parameter Marker strcpy(SQLStmt, "UPDATE EMPLOYEE SET JOB = ? "); strcat(SQLStmt, "WHERE JOB = 'DESIGNER'"); // Populate The Host Variable That Will Be Used In // Place Of The Parameter Marker strcpy(JobType, "MANAGER"); // Prepare The SQL Statement EXEC SQL PREPARE SQL_STMT FROM :SQLStmt; // Execute The SQL Statement EXEC SQL EXECUTE SQL_STMT USING :JobType; // Commit The Transaction EXEC SQL COMMIT;
Page 23 of 36
http://www-136.ibm.com/developerworks/db2
// Terminate The Database Connection EXEC SQL DISCONNECT CURRENT; // Return Control To The Operating System return(0); }
Page 24 of 36
http://www-136.ibm.com/developerworks/db2
http://www-136.ibm.com/developerworks/db2
the next instruction in the application. A source code file can contain any combination of these four forms of the WHENEVER statement, and the order in which the first three forms appear is insignificant. However, once any form of the WHENEVER statement is used, the SQL return codes of all subsequent SQL statements executed will be evaluated and processed accordingly until the application ends or until another WHENEVER statement alters this behavior. The following example, written in the C programming language, illustrates how the WHENEVER statement could typically be used to trap and process out-of-data errors:
... // Include The SQLCA Data Structure Variable EXEC SQL INCLUDE SQLCA; // Set Up Error Handler EXEC SQL WHENEVER NOT FOUND GOTO NOT_FOUND_HANDLER; // Connect To The Appropriate Database EXEC SQL CONNECT TO SAMPLE USER db2admin USING ibmdb2; // Execute A SELECT INTO SQL Statement (If A "DATA NOT // FOUND" Situation Occurs, The Code Will Branch To // The NOT_FOUND_HANDLER Label) EXEC SQL SELECT EMPNO INTO :EmployeeNo FROM RSANDERS.EMPLOYEE WHERE JOB = 'CODER'; ... // Disable All Error Handling EXEC SQL WHENEVER NOT FOUND CONTINUE; // Prepare To Return To The Operating System goto EXIT; // Define A Generic "Data Not Found" Handler NOT_FOUND_HANDLER: printf("NOT FOUND: SQL Code = %d\n", sqlca.sqlcode); EXEC SQL ROLLBACK; goto EXIT; EXIT: // Terminate The Database Connection EXEC SQL DISCONNECT CURRENT; // Return Control To The Operating System return(0);
Unfortunately, the code that is generated when the WHENEVER SQL statement is used relies on GO TO branching instead of call/return interfaces to transfer control to the appropriate error handling section of an embedded SQL application. As a result, when control is passed to the source code that is used to process errors and warnings, the application has no way of knowing where
Page 26 of 36 Embedded SQL programming
http://www-136.ibm.com/developerworks/db2
control came from, nor does it have any way of knowing where it should return control to after the error or warning has been properly handled. For this reason, about the only thing an application can do when control is passed to a WHENEVER statement error handling label is to display the error code generated, roll back the current transaction, and return control to the operating system.
And here's the syntax for other high-level programming language applications:
sqlgintp (short short struct sqlca char sBufferSize, sLineWidth, *pSQLCA, *pBuffer);
Let's look at the components of the syntax in more detail: pBuffer: Identifies a location in memory where the Get Error Message API is to store any message text retrieved. sBufferSize: Identifies the size, in bytes, of the memory storage buffer to which any message text retrieved should be written. sLineWidth: Identifies the maximum number of characters that one line of
Page 27 of 36
http://www-136.ibm.com/developerworks/db2
message text should contain before a line break is inserted. A value of 0 indicates that the message text is to be returned without line breaks. pSQLCA: Identifies a location in memory where an SQL Communications Area (SQLCA) data structure variable is stored.
Each time the Get Error Message API is called, the value stored in the sqlcode element of the SQLCA data structure variable provided is used to locate and retrieve appropriate error message text from a message file that is shipped with DB2 UDB. The following example, written in the C programming language, illustrates how the Get Error Message API would typically be used to obtain and display the message associated with any SQL return code generated:
... // Include The SQLCA Data Structure Variable EXEC SQL INCLUDE SQLCA; // Declare The Local Memory Variables long RetCode = SQL_RC_OK; char ErrorMsg[1024]; ... // Perform Some SQL Operation ... // If An Error Occurred, Obtain And Display // Any Diagnostic Information Available if (sqlca.sqlcode != SQL_RC_OK) { // Retrieve The Error Message Text For The Error // Code Generated RetCode = sqlaintp(ErrorMsg, sizeof(ErrorMsg), 70, &sqlca); switch (RetCode) { case -1: printf("ERROR : Insufficient memory.\n"); break; case -3: printf("ERROR : Message file is inaccessible.\n"); break; case -5: printf("ERROR : Invalid SQLCA, bad buffer, "); printf("or bad buffer length specified.\n"); break; default: printf("%s\n", ErrorMsg); break; } } ...
As you can see in this example, when the Get Error Message API is called, it returns a value that indicates whether or not it executed successfully. In this case, the return code produced is checked. If an error did occur, a message is returned to the user explaining why the API failed. If the API was successful, the message retrieved is returned to the user instead.
Page 28 of 36 Embedded SQL programming
http://www-136.ibm.com/developerworks/db2
SQLSTATEs
DB2 UDB (as well as other relational database products) uses a set of error message codes known as SQLSTATEs to provide supplementary diagnostic information for warnings and errors. SQLSTATEs are alphanumeric strings that are five characters (bytes) in length and have the format ccsss, where cc indicates the error message class and sss indicates the error message subclass. Like SQL return code values, SQLSTATE values are written to an element (the sqlstate element) of an SQLCA data structure variable used each time an SQL statement is executed. And just as the Get Error Message API can be used to convert any SQL return code value generated into a meaningful description, another API -- the Get SQLSTATE Message API -- can be used to convert an SQLSTATE value into a meaningful description as well. By including either (or both) of these APIs in your embedded SQL applications, you can always return meaningful information to the end user whenever error and/or warning conditions occur.
Page 29 of 36
http://www-136.ibm.com/developerworks/db2
Page 30 of 36
http://www-136.ibm.com/developerworks/db2
http://www-136.ibm.com/developerworks/db2
themselves are commented out and DB2-specific function calls are stored in their place.) At the same time, a corresponding package that contains (among other things) the access plans that are to be used to process each static SQL statement embedded in the source code file is also produced. (Access plans contain optimized information that the DB2 Database Manager uses to execute SQL statements. Access plans for static SQL statements are produced at precompile time, while access plans for dynamic SQL statements are produced at application run time.) Packages produced by the SQL precompiler can be stored in the database being used by the precompiler as they are generated, or they can be written to an external bind file and bound to any valid DB2 UDB database later (the process of storing this package in the appropriate database is known as binding). By default, packages are automatically bound to the database used for precompiling during the precompile process. Unless otherwise specified, the SQL precompiler is also responsible for verifying that all database objects (such as tables and columns) that have been referenced in static SQL statements actually exist, and that all application data types used are compatible with their database counterparts (that's why you need a database connection in order to use the SQL precompiler.) Once a source code file containing embedded SQL statements has been processed by the SQL precompiler, the high-level programming language source code file that is produced -- and any other source code files used -- must be compiled by a high-level programming language compiler. This compiler is responsible for converting source code files into object modules that the linker can use to create an executable program. When all of the source code files needed to build an application have been compiled successfully, the resulting object module can be provided as input to the linker. The linker combines object modules, high-level programming language libraries, and DB2 UDB libraries to produce an executable application. In most cases, this executable application exists as an executable file. However, it can also exist as a shared library or a dynamic-link library (DLL) that is loaded and executed by other executable applications
http://www-136.ibm.com/developerworks/db2
complete the binding process at a later point in time, using a tool known as the DB2 Binder (or simply the Binder). This is referred to as deferred binding, and is preferable if you want to: Defer binding until you have an application program that compiles and links successfully. Create a package under a different schema or under multiple schemas. Run an application against a database using different options (isolation level, Explain on/off, etc.). By deferring the bind process, you can dynamically change things like the isolation level used without having to rebuild the application. Run an application against several different databases. By deferring the bind process, you can build your program once and bind it to any number of appropriate databases. Otherwise, you will have to rebuild the entire application each time you want to run it against a new database. Run an application against a database that has been duplicated on several different machines. By deferring the bind process, you can dynamically create your application database on each machine, and then bind your program to the newly created database (possibly as part of your application's installation process).
Page 33 of 36
http://www-136.ibm.com/developerworks/db2
Resources
For more information on DB2 Universal Database application development: DB2 Version 8 Administration Guide: Implementation, International Business Machines Corporation, 2002. DB2 Version 8 Application Development Guide: Programming Client Applications, International Business Machines Corporation, 2002. DB2 Version 8 Application Development Guide: Programming Server Applications, International Business Machines Corporation, 2002. DB2 Version 8 Application Development Guide: Building and Running Applications, International Business Machines Corporation, 2002. DB2 Version 8 SQL Reference Guide, Volume 1, International Business Machines Corporation, 2002. DB2 Version 8 SQL Reference Guide, Volume 2, International Business Machines Corporation, 2002.
For more information on the DB2 UDB V8.1 Family Application Development Certification exam (Exam 703): DB2 Universal Database v8.1 Certification Exam 703 Study Guide, Sanders, Roger E., International Business Machines Corporation, 2004. DB2 Universal Database v8 Application Development Certification Guide, Martineau, David and others, International Business Machines Corporation, 2003.
Embedded SQL programming
Page 34 of 36
http://www-136.ibm.com/developerworks/db2
IBM DB2 Information Management -- Training and certification (http://www.ibm.com/software/data/education//) for information on classes, certifications available and additional resources.
As mentioned earlier, this tutorial is just one tutorial in a series of seven to help you prepare for the DB2 UDB V8.1 Family Application Development Certification exam (Exam 703). The complete list of all tutorials in this series is provided below: 1. 2. 3. 4. 5. 6. 7. Database objects and Programming Methods Data Manipulation Embedded SQL Programming ODBC/CLI Programming Java Programming Advanced Programming User-Defined Routines
Before you take the certification exam (DB2 UDB V8.1 Application Development, Exam 703) for which this tutorial was created to help you prepare, you should have already taken and passed the DB2 V8.1 Family Fundamentals certification exam (Exam 700). Use the DB2 V8.1 Family Fundamentals certification prep tutorial series to prepare for that exam. A set of six tutorials covers the following topics: DB2 planning DB2 security Accessing DB2 UDB data Working with DB2 UDB data Working with DB2 UDB objects Data concurrency
Use the DB2 V8.1 Database Administration certification prep tutorial series to prepare for the DB2 UDB V8.1 for Linux, UNIX and Windows Database Administration certification exam (Exam 701). A set of six tutorials covers the following topics: Server management Data placement Database access Monitoring DB2 activity DB2 utilities Backup and recovery
Check out developerWorks Subscription for one-stop access to a comprehensive portfolio of the latest IBM software from DB2, Lotus, Rational, Tivoli, and WebSphere, allowing you to maximize ROI and lower your labor costs, leading to superior productivity.
Page 35 of 36
http://www-136.ibm.com/developerworks/db2
Feedback
Colophon
This tutorial was written entirely in XML, using the developerWorks Toot-O-Matic tutorial generator. The open source Toot-O-Matic tool is an XSLT stylesheet and several XSLT extension functions that convert an XML file into a number of HTML pages, a zip file, JPEG heading graphics, and two PDF files. Our ability to generate multiple text and binary formats from a single source file illustrates the power and flexibility of XML. (It also saves our production team a great deal of time and effort.) For more information about the Toot-O-Matic, visit www-106.ibm.com/developerworks/xml/library/x-toot/ .
Page 36 of 36