Dynamic SQL
Dynamic SQL
The dynamic SQL component of SQL allows programs to construct and submit SQL queries at run time. In contrast, embedded SQL statements must be completely present at compile time; they are compiled by the embedded SQL preprocessor. Using dy- namic SQL, programs can create SQL queries as strings at run time (perhaps based on input from the user) and can either have them executed immediately or have them prepared for subsequent use. Preparing a dynamic SQL statement compiles it, and subsequent uses of the prepared statement use the compiled version.
SQL defines standards for embedding dynamic SQL calls in a host language, such as C, as in the following example.
The dynamic SQL program contains a ?, which is a place holder for a value that is provided when the SQL program is executed.
However, the syntax above requires extensions to the language or a preprocessor for the extended language. An alternative that is very widely used is to use an application program interface to send SQL queries or updates to a database system, and not make any changes in the programming language itself.
In the rest of this section, we look at two standards for connecting to an SQL database and performing queries and updates. One, ODBC, is an application pro- gram interface for the C language, while the other, JDBC, is an application program interface for the Java language.
To understand these standards, we need to understand the concept of SQL sessions. The user or application connects to an SQL server, establishing a session; exe- cutes a series of statements; and finally disconnects the session. Thus, all activities of the user or application are in the context of an SQL session. In addition to the normal SQL commands, a session can also contain commands to commit the work carried out in the session, or to rollback the work carried out in the session.
ODBC∗∗
The Open DataBase Connectivity (ODBC) standard defines a way for an application program to communicate with a database server. ODBC defines an application pro- gram interface (API) that applications can use to open a connection with a database, send queries and updates, and get back results. Applications such as graphical user interfaces, statistics packages, and spreadsheets can make use of the same ODBC API to connect to any database server that supports ODBC.
Each database system supporting ODBC provides a library that must be linked with the client program. When the client program makes an ODBC API call, the code in the library communicates with the server to carry out the requested action, and fetch results.
Figure 4.9 shows an example of C code using the ODBC API. The first step in using ODBC to communicate with a server is to set up a connection with the server. To do so, the program first allocates an SQL environment, then a database connection handle. ODBC defines the types HENV, HDBC, and RETCODE. The program then opens the database connection by using SQLConnect. This call takes several parameters, in-
cluding the connection handle, the server to which to connect, the user identifier, and the password for the database. The constant SQL NTS denotes that the previous argument is a null-terminated string.
Once the connection is set up, the program can send SQL commands to the database by using SQLExecDirect C language variables can be bound to attributes of the query result, so that when a result tuple is fetched using SQLFetch, its attribute values are stored in corresponding C variables. The SQLBindCol function does this task; the sec- ond argument identifies the position of the attribute in the query result, and the third argument indicates the type conversion required from SQL to C. The next argument gives the address of the variable. For variable-length types like character arrays, the last two arguments give the maximum length of the variable and a location where the actual length is to be stored when a tuple is fetched. A negative value returned for the length field indicates that the value is null.
The SQLFetch statement is in a while loop that gets executed until SQLFetch re- turns a value other than SQL SUCCESS. On each fetch, the program stores the values in C variables as specified by the calls on SQLBindCol and prints out these values.
At the end of the session, the program frees the statement handle, disconnects from the database, and frees up the connection and SQL environment handles. Good programming style requires that the result of every function call must be checked to make sure there are no errors; we have omitted most of these checks for brevity.
It is possible to create an SQL statement with parameters; for example, consider the statement insert into account values(?,?,?). The question marks are placeholders for values which will be supplied later. The above statement can be “prepared,” that is, compiled at the database, and repeatedly executed by providing actual values for the placeholders — in this case, by providing an account number, branch name, and balance for the relation account.
ODBC defines functions for a variety of tasks, such as finding all the relations in the database and finding the names and types of columns of a query result or a relation in the database.
By default, each SQL statement is treated as a separate transaction that is committed automatically. The call SQLSetConnectOption(conn, SQL AUTOCOMMIT, 0) turns off automatic commit on connection conn, and transactions must then be committed explicitly by SQLTransact(conn, SQL COMMIT) or rolled back by SQLTransact(conn, SQL ROLLBACK).
The more recent versions of the ODBC standard add new functionality. Each version defines conformance levels, which specify subsets of the functionality defined by the standard. An ODBC implementation may provide only core level features, or it may provide more advanced (level 1 or level 2) features. Level 1 requires support for fetching information about the catalog, such as information about what relations are present and the types of their attributes. Level 2 requires further features, such as ability to send and retrieve arrays of parameter values and to retrieve more detailed catalog information.
The more recent SQL standards (SQL-92 and SQL:1999) define a call level interface (CLI) that is similar to the ODBC interface, but with some minor differences.
JDBC∗∗
The JDBC standard defines an API that Java programs can use to connect to database servers. (The word JDBC was originally an abbreviation for “Java Database Connectivity”, but the full form is no longer used.) Figure 4.10 shows an example Java pro- gram that uses the JDBC interface. The program must first open a connection to a database, and can then execute SQL statements, but before opening a connection, it loads the appropriate drivers for the database by using Class.for Name. The first parameter to the get Connection call specifies the machine name where the server
runs (in our example, aura.bell-labs.com), the port number it uses for communication (in our example, 2000). The parameter also specifies which schema on the server is to be used (in our example, bankdb), since a database server may support multiple schemas. The first parameter also specifies the protocol to be used to communicate with the database (in our example, jdbc:oracle:thin:). Note that JDBC specifies only the API, not the communication protocol. A JDBC driver may support multiple protocols, and we must specify one supported by both the database and the driver. The other two arguments to get Connection are a user identifier and a password.
The program then creates a statement handle on the connection and uses it to execute an SQL statement and get back results. In our example, stmt.execute Update executes an update statement. The try { ... } catch { ... } construct permits us to
catch any exceptions (error conditions) that arise when JDBC calls are made, and print an appropriate message to the user.
The program can execute a query by using stmt.execute Query. It can retrieve the set of rows in the result into a Result Set and fetch them one tuple at a time using the next() function on the result set. Figure 4.10 shows two ways of retrieving the values of attributes in a tuple: using the name of the attribute (branch-name) and using the position of the attribute (2, to denote the second attribute).
We can also create a prepared statement in which some values are replaced by “?”, thereby specifying that actual values will be provided later. We can then provide the values by using setString(). The database can compile the query when it is prepared, and each time it is executed (with new values), the database can reuse the previously compiled form of the query. The code fragment in Figure 4.11 shows how prepared statements can be used.
JDBC provides a number of other features, such as updatable result sets. It can create an updatable result set from a query that performs a selection and/or a projection on a database relation. An update to a tuple in the result set then results in an update to the corresponding tuple of the database relation. JDBC also provides an API to examine database schemas and to find the types of attributes of a result set.
For more information about JDBC, refer to the bibliographic information at the end of the chapter.
Comments
Post a Comment