Dynamic SQL

7.3.2 Dynamic SQL

Dynamic SQL statements include parameters whose values are not known until runtime, when they are supplied as input to the application. Dynamic SQL statements are very

Chapter 7 – Using SQL in an application 169 common for user-driven interactive applications where the user provides most of the

information required to construct the exact SQL. Consider the application depicted in Figure 7.3, "Employee finder tool", which could be part of a larger HR application in a company.

Figure 7.3 - An Employee finder tool

The above tool allows a user to get details about an employee’s designation. The search arguments are either the Employee Name or the Employee Id. For this type of applications, the exact SQL that would need to be issued cannot be known until execution time. This is an example where Dynamic SQL is required.

Contrary to the static SQL technique, the access plans for dynamic SQL queries can only

be generated at runtime.

7.3.2.1 Embedded SQL application structure

Listing 7.3 provides the code corresponding to the Employee Finder Tool shown in Figure

7.3. It demonstrates how to execute an SQL statement dynamically from an embedded SQL C application.

Database Fundamentals 170 int findEmployee(char * field, char * value, char * emp_name, char *

emp_id, char * emp_desig) {

int ret_code = 1; char sqlstmt[250] = {0}; EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION; char name_hv[129] = {0}; // employee name char desig_hv[129] = {0}; // employee designation char id_hv[10] = {0};

// employee id

char value_hv[250] = {0}; // Field value EXEC SQL END DECLARE SECTION; // Copy the Search Field passed to this function into // the sqlstmt string sprintf(sqlstmt,”SELECT emp_name, emp_id, emp_desig

FROM employee.details WHERE %s = ?”,field); // Copy the field value passed to this function into the // host variable

strcpy(value_hv,value) ;

// Prepare the dynamic SQL statement first. This statement would // create the access plan at runtime

EXEC SQL PREPARE dynsqlstmt FROM :sqlstmt; if (SQLCODE <0) {

printf(“\n Error during Prepare statement:%ld”,SQLCODE); ret_code = 0; //error

} else {

EXEC SQL DECLARE cur1 CURSOR FOR :dynsqlstmt; if (SQLCODE <0) {

printf(“\n Error during Declare Cursor:%ld”,SQLCODE); ret_code = 0; //error } else {

EXEC SQL OPEN cur1 USING :value_hv; if (SQLCODE <0) {

printf(“\n Error during Open Cursor:%ld”,SQLCODE); ret_code = 0; //error

Chapter 7 – Using SQL in an application 171 }

else {

EXEC SQL FETCH cur1 INTO :name_hv, :id_hv, :design_hv; if (SQLCODE <0) {

printf(“\n Error during Fetch cursor:%ld”,SQLCODE); ret_code = 0; //error

} else {

EXEC SQL CLOSE cur1; if (SQLCODE <0) {

printf(“\n Error during Close cursor:%ld”,SQLCODE); Ret_code = 0; //error

} else {

// Copy the fetched results into the target variables strcpy(emp_name,:name_hv); strcpy(emp_id,:id_hv); strcpy(emp_desig,:desig_hv);

} } } } } return ret_code; }

Listing 7.3 - Embedded SQL C with static and dynamic SQL

In the above listing, the information pertaining to the Search Field of the Employee Finder Tool (which the user provides at runtime) is first captured in a variable called field. This information is copied into the SQL statement which is then stored in a string variable (see sqlstmt above).

Let’s say the user selected Employee Id as the search field. In that case, the SQL statement (without the predicate values) would look like this:

SELECT emp_name, emp_id, emp_desig from employee.details WHERE emp_id =? The question mark (?) used in the statement is referred to as a parameter marker. These

markers are used in place of predicate values, which indicate that the actual values will be provided later at runtime. Since the exact predicate values are not necessary for access plan generation, the complete SQL information is available at this point-of-time to generate

Database Fundamentals 172 an access plan. The access plan is generated by ‘preparing’ the dynamic SQL statement

(see EXEC SQL PREPARE in the code listing above). Had the user selected Employee Name as the search field, the SQL would have become:

SELECT emp_name, emp_id, emp_desig from employee.details WHERE emp_name =?

Thus, the exact SQL that needs to be issued is generated only at execution time and the preparation of this SQL statement would have led to a different access plan than the previous one.

Once the statement is prepared successfully, it is possible to execute it using the predicate values provided by the user. In case of a SELECT statement, this is achieved by first declaring a cursor for the SQL statement, then opening it with the predicate values provided and then fetching the results of the query into the host variables. The cursor needs to be closed eventually.

5. The above code snippet still contains some static SQL statements needed for statement preparation, cursor declarations, and so on. This would mean that such applications would also require pre-compilation or SQL translation (for SQLJ applications), since they are still not totally free from static SQL statements.

6. If there is a way to replace all such static SQL statements by equivalent APIs, the pre-compilation/SQL translation of the application would not be required at all. The question now arises about how to write such dynamic SQL applications which do not have any static SQL statements (even for PREPARE, EXECUTE, CURSOR declaration, and so on). The answer to this question is provided in subsequent sections.