22.8 SQL Library: The SQL Structure
SML# provides the types and functions related to SQL as a library. All of them are included in the SQL structure provided by the sql.smi interface file. An SML# source file that uses the SQL feature must include the following lines in its interface file so that it refers to sql.smi:
_require "sql.smi"
The following is the signature of the SQL structure:
structure SQL : sig
type bool3
type numeric
type decimal = numeric
type backend
type ’a server
type ’a conn
type ’a cursor
type (’a, ’b) exp
type (’a, ’b) whr
type (’a, ’b) from
type (’a, ’b) orderby
type (’a, ’b, ’c) select
type (’a, ’b) query
type (’a, ’b) command
type (’a, ’b) db
exception Exec
exception Connect
exception Link
val postgresql : string -> backend
val mysql : string -> backend
val odbc : string -> backend
val sqlite3 : string -> backend
structure SQLite3 : (see Section 22.8.1)
val connect : ’a server -> ’a conn
val connectAndCreate : ’a server -> ’a conn
val closeConn : ’a conn -> unit
val fetch : ’a cursor -> ’a option
val fetchAll : ’a cursor -> ’a list
val closeCursor : ’a cursor -> unit
val queryCommand : (’a list, ’b) query -> (’a cursor, ’b) command
val toy : ((’a, ’c) db -> (’b, ’c) query) -> ’a -> ’b
val commandToString : ((’a,’c) db -> (’b,’c) command) -> string
val queryToString : ((’a,’c) db -> (’b,’c) query) -> string
val expToString : (’a,’c) exp -> string
Structure Op : (see Section 22.9)
Structure Numeric : see Section 22.9
Structure Decimal = Numeric
end
These definitions are categorized by their purposes. Each of the following subsections describes the definitions belonging to a category.
22.8.1 Connecting to a database server
-
•
exception Connect of string
The exception of a database connection error. string is the error message.
-
•
exception Link of string
The exception indicating the mismatch of database schema and SML# programs. string is the error message.
-
•
type backend
The type of the untyped connection information to a database, which is a part of the _sqlserver expression. One of the following function can be used to write an expression of this type.
-
•
val postgresql : string -> backend
SQL.postgresql param returns an connection information to a PostgreSQL server. The string param is the connection string of libpq, the PostgreSQL library. See the PostgreSQL manual for defails of the connection string. If param is not valid, the SQL.Connect exception is raised.
The correspondence between the PostgreSQL and SML# types is the following:
PostgreSQL SML# INT, INT4 int BOOLEAN bool TEXT, VARCHAR string FLOAT8 real FLOAT4 real32 -
•
val mysql : string -> backend
SQL.mysql param returns a connection information to a MySQL server. The string param consists of the sequences of “key=value” separated by whitespaces. The keys avaliable and their meanings are the following:
Key Description host The hostname of a MySQL server port The port number of a MySQL server user The user name to log in a MySQL server password The password of the user dbname The name of the target database unix_socket The filename of a UNIX socket flags The flags of the communication protocol in decimal dbname is mandatory. See the MySQL manual for details of these parameters. If param is not valid, the SQL.Connect exception is raised.
The correspondence between the MySQL and SML# types are the following:
MySQL SML# TINYINT, SMALLINT, MEDIUMINT, INT int TINYTEXT, TEXT, VARCHAR string DOUBLE real FLOAT real32 -
•
val sqlite3 : string -> backend
val sqlite3’ : SQL.SQLite3.flags * string -> backendSQL.sqlite3 filename and SQL.sqlite3 (flags, filename) return a connection information to an SQLite3 database file. The string filename indicates the filename. Note that SQLite3 interprets the filenames beginning with “:” in a special way.
flags is a record consisting of the following four fields:
-
–
mode: the open mode of the file, which is one of the following:
-
*
SQL.SQLite3.SQLITE_OPEN_READONLY
-
*
SQL.SQLite3.SQLITE_OPEN_READWRITE
-
*
SQL.SQLite3.SQLITE_OPEN_READWRITE_CREATE
-
*
-
–
threading: the threading mode, which is one of the following:
-
*
SQL.SQLite3.SQLITE_OPEN_NOMUTEX
-
*
SQL.SQLite3.SQLITE_OPEN_FULLMUTEX
-
*
-
–
cache: the cache mode, which is one of the following:
-
*
SQL.SQLite3.SQLITE_OPEN_SHAREDCACHE
-
*
SQL.SQLite3.SQLITE_OPEN_PRIVATECACHE
-
*
-
–
uri: the way to interpret the filename, which may be the following:
-
*
SQL.SQLite3.SQLITE_OPEN_URI
-
*
See the SQLite3 C/C++ API manual for details of these flags. These constants are defined in the SQL.SQLite3 structure. In addition, SQL.SQLite3 provides the default flag SQL.SQLite3.flags, which is used if flags is omitted. A partially modified version of SQL.SQLite3.flags can be obatained by using the field update expression.
The correspondence between SQLite3’s type affinities and SML#’s type is the following:
Type affinity SML# INT int REAL real STRING string NUMERIC numeric BLOB (unsupported) Each type of columns specified in CREATE TABLE statement is interpreted to a type affinity as described in the SQLite3 manual.
-
–
-
•
val odbc : string -> backen
SQL.odbc param returns a connection information to an ODBC server. The string param consists of a DSN name, user name, and password in this order separated by whitespaces. If param is not valid, the SQL.Connect exception is raised.
The correspondence between the ODBC and SML# types is the following
ODBC SML# CHAR string INTEGER, SMALLINT int FLOAT real32 DOUBLE real VARCHAR, LONGVARCHAR, NVARCHAR string -
•
val connect : ’a server -> ’a conn
SQL.connect server establishes a connection to the server indicated by the connection description server. If the connection is established and the schema of the connected database subsumes the schema represented by server, it returns a connection handle. If a connection error occurs, the SQL.Exec exception is raised. If the two schemas are not matched, the SQL.Link exception is raised.
The type of the connection description server represts the type of the tables and views that the SML# program deals with through this connection. SQL.connect checks the system catalog of the database so that all tables and views in the type of server exists in the database. The names of tables and views are case-insensitive during this check. The database may contain tables and views other than those specified in the type of server. In contrast, for each table in server, its column set must exactly matches with the actual table definition.
At the first time to connect to a database server, an external library is dynamically linked according to the kind of the database server. The default name of such libraries are hard-coded. If the library name is not appropriate, it can be changed by setting environment variables. The following table shows the default name and environment vairable name for each server kind:
Database Library name Environment variable PostgreSQL libpq.so.5 SMLSHARP_LIBPQ MySQL libmysqlclient.16.so SMLSHARP_LIBMYSQLCLIENT ODBC libodbc.so.2 SMLSHARP_LIBODBC SQLite3 libsqlite3.so.0 SMLSHARP_LIBSQLITE3 -
•
val connectAndCreate : ’a server -> ’a conn
Same as SQL.connect except for the following: SQL.connectAndCreate creates the tables that are indicated in the argument type but do not exist in the database by issueing the CREATE TABLE commands. If a table to be created includes an unsupported type, it raises the SQL.Link exception. If a CREATE TABLE command fails, it raises the SQL.Exec exception.
-
•
val closeConn : ’a conn -> unit
SQL.closeConn conn closes a database connection. Any connection established by SQL.connect must be closed by SQL.closeConn.
22.8.2 executing SQL queries and retrieving their results
-
•
exception Exec of string
The exception indicating that an error occur during a query execution on a database server. string is the error message.
-
•
val fetch : ’a cursor -> ’a option
SQL.fetch cursor reads one row pointed by the cursor cursor and move the cursor to the next row. If the cursor reaches to the end of a table, it returns NONE. If the cursor is already closed, the SQL.Exec exception is raised.
-
•
val fetchAll : ’a cursor -> ’a list
SQL.fetchAll cursor reads all rows between the cursor cursor and the end of the table and closes the cursor. If the cursor is already closed, the SQL.Exec exception is raised.
-
•
closeCursor : ’a cursor -> unit
closeCursor cursor closes the given cursor. All cursors must be closed by this function or fetchAll.
22.8.3 Utilities for SQL Queries
-
•
val queryCommand : (’a list, ’b) query -> (’a cursor, ’b) command
SQL.queryCommand query converts the given SELECT query to a SQL command. This function performs the same thing as what an SQL execution function _sql pat => select...(exp) does for a query (see Section 22.7) except for the query execution.
-
•
val toy : ((’a, ’c) db -> (’b, ’c) query) -> ’a -> ’b
SQL.toy query data regards data as a database and evaluates the query query on it. The evaluation is carried out in SML# without involving any server communication. This function executes a toy program that the SML# compiler generates for the typecheck of SQL queries. Note that the performance of the toy program is not considered and therefore this function may be seriously slow.
-
•
val commandToString : ((’a,’c) db -> (’b,’c) command) -> string
SQL.commandToString command returns the serialized string of the SQL command the function command returns. The string this function returns is identical to the string sent to the server when the command is executed.
-
•
val queryToString : ((’a,’c) db -> (’b,’c) query) -> string
SQL.queryToString query returns the serialized string of the SELECT query the function query returns. The string this function returns is identical to the string sent to the server when the query is executed.
-
•
val expToString : (’a,’c) exp -> string
SQL.expToString exp returns the serialized string of the SQL value expression exp.