scsh-0.5/scsh/odbc/odbc.txt

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].