555 lines
24 KiB
Plaintext
555 lines
24 KiB
Plaintext
Sam Thibault
|
|
ODBC interface for scsh
|
|
Spring 1999
|
|
|
|
1 Scsh ODBC
|
|
|
|
Scsh ODBC is an ODBC interface for scsh providing the complete
|
|
functionality for all ODBC Core 1.0 functions. The procedures that
|
|
Scsh ODBC exports allow a clean, scheme-style interface for executing
|
|
SQL statements with a RDBMS. The tools include simple management of
|
|
open connections, SQL statement execution with or without parameters,
|
|
and multiple fetch operations. Scsh ODBC also possesses a small error
|
|
system that raises conditions specific to ODBC errors and errors
|
|
returned from the RDBMS.
|
|
|
|
2 Exported Interface
|
|
|
|
The procedures and syntaxes exported by Scsh ODBC provide all the functionality
|
|
neccesary to conduct SQL interaction with a RDBMS.
|
|
|
|
2.1 A Note on Data Types
|
|
|
|
Scsh ODBC makes use of three abstract data types to keep the interface clean and
|
|
straight-forward. These three data types are explained here:
|
|
|
|
db:
|
|
A DB is an opened connection to a RDBMS. In addition, Scsh ODBC also
|
|
allows a program to keep track of a "current db". The current db
|
|
will be used as the default connection in some procedure calls where
|
|
the db argument is optional.
|
|
|
|
command:
|
|
The COMMAND data type keeps track of an SQL statement (e.g. "select *
|
|
from foo"), its associated statement handle, the preparation state
|
|
of the command, and allows statement handle re-use (see CURSORS
|
|
below). In Scsh ODBC a command can be passed to procedures executing
|
|
SQL statements rather than just a string. This helps performance for
|
|
SQL statements that are repeatedly executed.
|
|
|
|
cursor:
|
|
After executing a select statement, Scsh ODBC will return a CURSOR.
|
|
The cursor may then be passed to a fetching procedure to get values
|
|
from a result table. Once all the resulting rows have been fetched
|
|
or the cursor has bee closed (by calling close-cursor), the cursor's
|
|
associated statement handle will be freed and cycled into the
|
|
originating command for re-use.
|
|
|
|
2.2 Managing Connections
|
|
|
|
(open-db host user password) => db procedure
|
|
|
|
This procedure opens a connection to a RDBMS. The arguments passed are
|
|
all strings. HOST will probably contain port information, such as:
|
|
|
|
"my-rdbms.foo.bar tcpip 1313"
|
|
|
|
USER is the username you would like to use for this connection;
|
|
PASSWORD is the password for the username given.
|
|
|
|
The return value DB is an abstract data type that will be passed to the
|
|
other procedures at this level.
|
|
|
|
(set-current-db! db) => undefined procedure
|
|
|
|
Once a connection has been opened, it can be set as the "current-db".
|
|
Any procedure with an optional db argument will use this current-db if
|
|
the db argument is not supplied. (see close-db below)
|
|
|
|
(current-db) => db | #f procedure
|
|
|
|
Calling this procedure will return the current-db if one has been set. If
|
|
a current-db has not been set, this procedure returns #f.
|
|
|
|
(close-db [db]) => #t procedure
|
|
|
|
This procedure is used to close an opened connection DB. If a db is
|
|
supplied in DB, that connection will be closed. Otherwise, close-db
|
|
will close the db assigned to be the current db.
|
|
|
|
(call/db host user password proc) => value(s) of proc procedure
|
|
|
|
This procedure opens a connection with the HOST USER and PASSWORD
|
|
provided (see open-db). PROC is then called with one argument, the newly
|
|
opened connection. The connections is closed when the value(s) of proc
|
|
are returned.
|
|
|
|
(with-current-db* db thunk) => value(s) of thunk procedure
|
|
|
|
This procedure evaluates THUNK within a dynamic scope that binds the
|
|
connection DB to be the current db. The value of (CURRENT-DB) returns to
|
|
its previous value when this procedure returns. In the event of a
|
|
non-local exit (throwing to an outer continuation, or raising an
|
|
exception), the current db is also reset.
|
|
|
|
(with-open-db* host user password thunk) => value(s) of thunk procedure
|
|
|
|
This procedure opens a connection with the HOST USER and PASSWORD
|
|
provided (see open-db). THUNK is then evaluated within a scope that
|
|
binds the newly opened connection to be the current-db. The connection
|
|
is closed when the value(s) are returned. Like with-current-db*, the
|
|
current-db resumes its prior value.
|
|
|
|
(with-current-db db body1 body2 ...) => value(s) of body syntax
|
|
(with-open-db host user password body1 body2 ...) => value(s) of body syntax
|
|
|
|
These two syntaxes are macro versions of with-current-db* and
|
|
with-open-db*.
|
|
|
|
2.3 Executing SQL Statements
|
|
|
|
(string->sql-command sql-string) => command procedure
|
|
|
|
This procedure will create an abstract "command" datatype from the given
|
|
string. A command record is useful because the SQL string passed
|
|
will only be prepared once. If the SQL statement contains parameters,
|
|
the new parameter arguments can be supplied again without re-preparing
|
|
the SQL string.
|
|
|
|
(execute-sql command [db params]) => #t | integer | cursor procedure
|
|
|
|
This procedure will execute any SQL command. The COMMAND argument can
|
|
be either a command record (made with sql->command) or a string
|
|
containing a properly formed SQL statement. A connection may be supplied
|
|
in DB. If no connection is given, the current-db will be used.
|
|
Any number of parameters for the SQL statement may then be given.
|
|
|
|
The value returned by execute-sql depends on the type of SQL statement.
|
|
Commands such as "create" or "drop" will return #t. Commands modifying
|
|
rows, like "insert" "update" or "delete", will return an integer - the
|
|
number of rows modified. A select statement will cause execute-sql
|
|
to return a cursor record. This cursor record may be passed to any of
|
|
the fetch procedures (fetch-row, fetch-rows, fetch-all) to retrieve
|
|
data from the selected table.
|
|
|
|
Recycling of statements...
|
|
|
|
2.4 Fetching Results
|
|
|
|
(fetch-row cursor) => vector | #f procedure
|
|
(fetch-rows cursor nrows) => list of vectors | #f procedure
|
|
(fetch-all cursor) => list of vectors | #f procedure
|
|
|
|
These fetch operations will retrieve data from a table using a cursor
|
|
record returned from execute-sql. If there are no more rows in the table
|
|
these procedures will return #f. Otherwise, fetch-row will return the
|
|
first row of data in the result set. Fetch-rows will return NROWS rows
|
|
from the table (NROWS is an integer) or all remaining rows if less than
|
|
NROWS rows remain in the result set. Fetch-all will return all the
|
|
remaining rows in the result set. If all rows in a cursor have been
|
|
fetched, close-cursor will be called on CURSOR.
|
|
|
|
Each row is returned as a vector; each element of the vector corresponds
|
|
to a column of the table. The element's order matches the order of the
|
|
the columns in the result set. Vectors in a list (of multiple fetched
|
|
rows) are in fetched order, with the first row fetched begin the first row
|
|
in the list.
|
|
|
|
2.5 Cursors
|
|
|
|
(close-cursor cursor) => #t procedure
|
|
|
|
This procedure calls free-stmt/close on the cursor's associated statement
|
|
handle. Next, it will recycle the statement back into the originating
|
|
command for reuse. If the command already has a statament handle for use,
|
|
the freed statement handle will be discarded.
|
|
|
|
(cursor-name? cursor) => string procedure
|
|
|
|
This procedure returns the cursor name associated with CURSOR.
|
|
|
|
(set-cursor-name cursor name-string) => undefined procedure
|
|
|
|
Set-cursor-name associates the cursor name [name-string] with the active
|
|
statement handle [odbc-hstmt]. If an application does not call
|
|
set-cursor-name, the driver generates cursor names as needed for SQL
|
|
statement processing.
|
|
|
|
2.6 Transaction Control
|
|
|
|
(cancel command) => #t procedure
|
|
|
|
This procedure cancels all processing on the statement handle associated
|
|
with COMMAND.
|
|
|
|
(commit db) => #t procedure
|
|
|
|
This procedure performs a commit operation for all active operations on
|
|
all statement handles associated with the connection DB.
|
|
|
|
(rollback db) => #t procedure
|
|
|
|
This procedure performs a rollback operation for all active operations on
|
|
all statement handles associated with the connection DB.
|
|
|
|
2.7 Column Information and Binding
|
|
|
|
(bind-col command icol type precision) => c-storage procedure
|
|
|
|
Bind-col allocates a storage buffer to receieve data returned in fetches
|
|
from a result set. The buffer will correspond to the select performed
|
|
using the statement handle COMMAND, and a particular column of that
|
|
select as specified by ICOL, an integer value. The size of the buffer
|
|
will depend on the final two arguments. TYPE is one of the data type
|
|
symbols such as 'sql/integer' (not a string), and PRECISION is an
|
|
integer that the table should have defined for that column. The ODBC
|
|
documentation specifies how the precision value relates to each ODBC
|
|
data type.
|
|
|
|
(bind-parameter command icol data-type
|
|
precision scale param) => #t procedure
|
|
|
|
Bind-parameter creates a storage buffer containing the value of a
|
|
parameter for an SQL statement associated with the statement handle
|
|
COMMAND. The ICOL argument names the parameter corresponding to
|
|
this buffer. So if ICOL is the value '2', this buffer will hold the
|
|
value for the second parameter argument ('?') in the SQL statement.
|
|
DATA_TYPE is one of the defined data-type symbols like 'SQL/Integer'.
|
|
PRECISION and SCALE are integer arguments that affect different
|
|
data types in the manner specified by the ODBC documentation. PARAM
|
|
is the actual string, integer, etc. that will be bound and used in the
|
|
execution of the SQL statement.
|
|
|
|
(describe-col command icol)
|
|
=> values: name name-size data-type precision scale nullable procedure
|
|
|
|
Describe-col returns information about one column (specified by ICOL)
|
|
in the result set associated with the statement handle of COMMAND.
|
|
|
|
All the return values are integers, except for the column name which is a
|
|
string. The interpretation of the integer arguments is specified in the
|
|
ODBC documentation concerning data types.
|
|
|
|
(describe-param command icol)
|
|
=> values: data-type precision scale nullable procedure
|
|
|
|
Describe-param returns the description of a parameter marker (specified by
|
|
the integer ICOL) associated with the SQL statement prepared using the
|
|
statement handle command. The return values are all integers.
|
|
|
|
(num-result-cols command) => integer procedure
|
|
|
|
This procedure returns the number of columns in the result set associated
|
|
with the statement handle [odbc-hstmt].
|
|
|
|
(row-count command) => integer procedure
|
|
|
|
Row-count returns the number of rows affected by the UPDATE, INSERT, or
|
|
DELETE statement associated with the statement handle of COMMAND.
|
|
|
|
2.8 Freeing Resources
|
|
|
|
(free-env) => #t procedure
|
|
|
|
Free-env frees the environment handle and frees all memory associated
|
|
with the environment handle. This procedure should only be called
|
|
after the application is completely finished and *all* connections have
|
|
been closed.
|
|
|
|
3 Error System
|
|
|
|
3.1 Calling ODBC Functions
|
|
|
|
When a call to an ODBC function occurs - whether initiated from a
|
|
top-level or mid-level procedure - the ODBC function has the possibility of
|
|
raising several different error conditions. The Scsh ODBC interface provides
|
|
procedures to handle the possible conditions that may arise. Below are the
|
|
error conditions associated with each ODBC return value:
|
|
|
|
odbc return type = scheme condition
|
|
----------------------=--------------------
|
|
SQL_INVALID_HANDLE = sql-invalid-error
|
|
SQL_ERROR = sql-error
|
|
SQL_SUCCESS = #t
|
|
SQL_SUCCESS_WITH_INFO = sql-info-warning
|
|
SQL_STILL_EXECUTING = sql-busy-exception
|
|
SQL_NEED_DATA = sql-param-exception
|
|
SQL_NO_DATA_FOUND = #f
|
|
----------------------=--------------------
|
|
|
|
SQL_INVALID_HANDLE:
|
|
Function failed due to invalid environment, connection, or statement
|
|
handles. This indicates a programming error.
|
|
|
|
SQL_ERROR:
|
|
Function failed. The error message and error code will be returned in
|
|
the condition raised.
|
|
|
|
SQL_SUCCESS:
|
|
Function completed successfully; no additional information is
|
|
available.
|
|
|
|
SQL_SUCCESS_WITH_INFO:
|
|
Function completed successfully; possibly with a nonfatal error. The
|
|
warning message and error code can be caught using
|
|
with-sql-info-handler* described below.
|
|
|
|
SQL_STILL_EXECUTING:
|
|
A function that was started asynchronously is still executing.
|
|
|
|
SQL_NEED_DATA:
|
|
The application failed to send parameter data values for the statement
|
|
being processed.
|
|
|
|
SQL_NO_DATA_FOUND:
|
|
All rows from the result set have been fetched.
|
|
|
|
3.2 Scheme Error Procedures
|
|
|
|
(sql-invalid-error? condition) => boolean procedure
|
|
(sql-error? condition) => boolean procedure
|
|
(sql-info-warning? condition) => boolean procedure
|
|
(sql-busy-exception? condition) => boolean procedure
|
|
(sql-param-exception? condition) => boolean procedure
|
|
|
|
These five procedures check a condition to see if it corresponds to the
|
|
particular condition contained in the procedure name. (sql-invalid-error
|
|
for example)
|
|
|
|
(with-sql-invalid-handler* handler thunk) => value(s) of thunk procedure
|
|
(with-sql-error-handler* handler thunk) => value(s) of thunk procedure
|
|
(with-sql-info-handler* handler thunk) => value(s) of thunk procedure
|
|
(with-sql-busy-handler* handler thunk) => value(s) of thunk procedure
|
|
(with-sql-param-handler* handler thunk) => value(s) of thunk procedure
|
|
|
|
Programs can use the five procedures above to handle the specific
|
|
condition specified in the name of the handler. (sql-invalid-error for
|
|
example) If the specific condition is signalled while the thunk is
|
|
executing, handler will be called with six arguments:
|
|
|
|
(handler function error-code error-message henv hdbc hstmt)
|
|
|
|
The ERROR-CODE and ERROR-MESSAGE are strings automatically retrieved by
|
|
Scsh ODBC. The [function] is a symbol name of the ODBC function in which
|
|
the error occured, such as 'Execute.
|
|
|
|
(with-sql-handler* handler thunk) => value(s) of thunk procedure
|
|
|
|
With-sql-handler* will call the handler for all of the five conditions
|
|
above.
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
4 Other Stuff
|
|
|
|
4.1 Notes About this Level
|
|
|
|
This level of the interface contains all of the ODBC Core 1.0 functions.
|
|
Each ODBC function has been wrapped up inside a Scheme procedure which
|
|
manages all the neccesary resources for the ODBC function (by allocating
|
|
memory and converting datatypes using procedure in the Low Level Scsh ODBC
|
|
Interface) and then calls the ODBC function (these procedures actually call
|
|
procedures in the Low Level Interface that link to C stubs that call to the
|
|
ODBC library). These Scheme "wrappers" will raise any conditions resulting
|
|
from the ODBC call (see Error System below). Finally these procedures will
|
|
return a useful Scheme value approproate to the ODBC function called.
|
|
|
|
4.2 ODBC Core 1.0
|
|
|
|
|
|
sql/char
|
|
sql/numeric
|
|
sql/decimal
|
|
sql/integer
|
|
sql/smallint
|
|
sql/float
|
|
sql/real
|
|
sql/double
|
|
sql/varchar
|
|
sql/date
|
|
sql/time
|
|
sql/timestamp
|
|
sql/longvarchar
|
|
sql/binary
|
|
sql/varbinary
|
|
sql/longvarbinary
|
|
sql/bigint
|
|
sql/tinyint
|
|
sql/bit
|
|
|
|
(type-val->string type) procedure
|
|
|
|
This procedure merely returns a string representation of the given data
|
|
type such as "sql/integer" useful for error messages.
|
|
|
|
(col-attributes odbc-hstmt icol descriptor-type) => integer | string procedure
|
|
|
|
Col-attributes returns information about one attribute associated with
|
|
a column (selected by the integer ICOL) in a result set. (specified
|
|
by the statement handle ODBC-HSTMT). The desired attribute is
|
|
specified in DESCRIPTOR-TYPE using one of the following defined symbols:
|
|
|
|
column-auto-increment
|
|
column-case-sensitive
|
|
column-count
|
|
column-display-size
|
|
column-length
|
|
column-money
|
|
column-name
|
|
column-nullable
|
|
column-precision
|
|
column-scale
|
|
column-searchable
|
|
column-type
|
|
column-type-name
|
|
column-unsigned
|
|
column-updatable
|
|
|
|
(describe-col odbc-hstmt icol)
|
|
=> values: name name-size data-type precision scale nullable procedure
|
|
|
|
Describe-col returns information about one column (specified by ICOL)
|
|
in the result set associated with the statement handle ODBC-HSTMT.
|
|
|
|
All the return values are integers, except for the column name which is a
|
|
string. The interpretation of the integer arguments is specified in the
|
|
ODBC documentation concerning data types.
|
|
|
|
(describe-param odbc-hstmt icol)
|
|
=> values: data-type precision scale nullable procedure
|
|
|
|
Describe-param returns the description of a parameter marker (specified by
|
|
the integer ICOL) associated with the SQL statement prepared using the
|
|
statement handle odbc-hstmt. The return values are all integers.
|
|
|
|
(num-result-cols odbc-hstmt) => integer procedure
|
|
|
|
This procedure returns the number of columns in the result set associated
|
|
with the statement handle [odbc-hstmt].
|
|
|
|
(row-count odbc-hstmt) => integer procedure
|
|
|
|
Row-count returns the number of rows affected by the UPDATE, INSERT, or
|
|
DELETE statement associated with the statement handle [odbc-hstmt].
|
|
|
|
(alloc-connect) => odbc-hdbc procedure
|
|
|
|
This procedure allocates space for a new database connection without
|
|
performing the actual connection. The new connection handle, the
|
|
ODBC-HDBC that is returned, is allocated within the allocated
|
|
environment. If the environment handle has not yet been created,
|
|
alloc-connect will create the environment handle by calling server-env.
|
|
|
|
(alloc-stmt odbc-hdbc) => odbc-hstmt procedure
|
|
|
|
This procedure allocates a new statement handle using the supplied
|
|
connection handle. The newly allocated statement handle is then returned.
|
|
|
|
(bind-col odbc-hstmt icol type precision) => c-storage procedure
|
|
|
|
Bind-col allocates a storage buffer to receieve data returned in fetches
|
|
from a result set. The buffer will correspond to the select performed
|
|
using the statement handle ODBC-HSTMT, and a particular column of that
|
|
select as specified by ICOL, an integer value. The size of the buffer
|
|
will depend on the final two arguments. TYPE is one of the data type
|
|
symbols such as 'sql/integer' (not a string), and PRECISION is an
|
|
integer that the table should have defined for that column. The ODBC
|
|
documentation specifies how the precision value relates to each ODBC
|
|
data type.
|
|
|
|
(bind-parameter odbc-hstmt icol data-type
|
|
precision scale param) => #t procedure
|
|
|
|
Bind-parameter creates a storage buffer containing the value of a
|
|
parameter for an SQL statement associated with the statement handle
|
|
ODBC-HSTMT. The ICOL argument names the parameter corresponding to
|
|
this buffer. So if ICOL is the value '2', this buffer will hold the
|
|
value for the second parameter argument ('?') in the SQL statement.
|
|
DATA_TYPE is one of the defined data-type symbols like 'SQL/Integer'.
|
|
PRECISION and SCALE are integer arguments that affect different
|
|
data types in the manner specified by the ODBC documentation. PARAM
|
|
is the actual string, integer, etc. that will be bound and used in the
|
|
execution of the SQL statement.
|
|
|
|
(connect host user password) => odbc-hdbc procedure
|
|
|
|
Connect allocates a new connection handle (using alloc-connect) and opens
|
|
a connection to the data source specified by the three string arguments
|
|
HOST, USER, and PASSWORD. The connection handle associated with
|
|
the newly opened connection is returned.
|
|
|
|
(connect! odbc-hdbc host user password) => undefined procedure
|
|
|
|
Connect! uses the already allocated connection handle given in ODBC-HDBC
|
|
and connects to the data source specified by the three string arguments
|
|
HOST, USER, and PASSWORD.
|
|
|
|
(disconnect odbc-hdbc) => #t procedure
|
|
|
|
Disconnect closes the connection associated with the connection handle
|
|
ODBC-HDBC.
|
|
|
|
(exec-direct odbc-hstmt sql-string) => #t procedure
|
|
|
|
Given an allocated statement handle ODBC-HSTMT, exec-direct executes
|
|
the preparable SQL statement given as a string in SQL-STRING.
|
|
|
|
(execute odbc-hstmt) => #t procedure
|
|
|
|
This procedure executes the prepared SQL statment associated with the
|
|
statement handle ODBC-HSTMT.
|
|
|
|
(fetch cursor-record) => vector | #f procedure
|
|
|
|
Fetch retrieves a row of data from a result set using the information in
|
|
the given CURSOR-RECORD. The driver returns data for all columns that
|
|
were bound to storage locations with bind-col and combines the returned
|
|
values in a vector. If there were no more rows to be fetched, #f is
|
|
returned.
|
|
|
|
Note: Fetch needs to be changed so it acts like the other mid-level
|
|
functions. Right now it is exactly fetch-row.
|
|
|
|
(free-connection odbc-hdbc) => #t procedure
|
|
|
|
Free-connection releases the connection handle [odbc-hdbc] and frees all
|
|
the memory associated with that connection handle.
|
|
|
|
(free-stmt/close cursor) => #t procedure
|
|
(free-stmt/drop (command | cursor)) => #t procedure
|
|
(free-stmt/unbind command) => #t procedure
|
|
(free-stmt/reset command) => #t procedure
|
|
|
|
These procedures stop processing associated with a specific statement
|
|
handle, close any open cursors, discards pending results, and, optionally,
|
|
frees all resources associated with the statement handle. The four
|
|
options for this ODBC function have been separated into four different
|
|
procedures as described below:
|
|
|
|
free-stmt/close: Closes the cursor associated with the given CURSOR,
|
|
discarding pending results. The cursor may be reopened
|
|
by executing a "select" statement.
|
|
|
|
free-stmt/drop: Frees all resorces associated with the COMMAND or
|
|
CURSOR's statement handle. The statement handle will
|
|
no longer be accesible.
|
|
|
|
free-stmt/unbind: Any buffers bound to ODBC-HSTMT using bind-col are
|
|
released.
|
|
|
|
free-stmt/reset: Any buffers bound to ODBC-HSTMT using bind-param are
|
|
released.
|
|
|
|
(prepare sql-string [db]) => odbc-hstmt procedure
|
|
|
|
Prepare uses the given DB, and opens a connction to the
|
|
data source specified by [host], [user], and [password]. Then prepare
|
|
allocates a statement handle and prepares the statement given as
|
|
[sql-string] for execution. The new statement handle is returned.
|
|
|
|
(prepare! odbc-hstmt sql-string) => undefined procedure
|
|
|
|
Using the connection handle given as [odbc-hstmt], this procedure prepares
|
|
the sql-string given as [sql-string].
|
|
|