REF ODBC                                            John Gibson Aug 1996

        COPYRIGHT University of Sussex 1996. All Rights Reserved.

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<                              >>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<     POPLOG INTERFACE TO      >>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<  OPEN DATABASE CONNECTIVITY  >>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<                              >>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

         CONTENTS - (Use <ENTER> g to access required sections)

  1   Introduction

  2   Differences from the C Interface
      2.1   Procedures
      2.2   INCLUDE ODBC
      2.3   SQL Data Types
      2.4   Pop Data Types
      2.5   Environment, Connection & Statement Handles

  3   Data Input/Output Modes
      3.1   false (Pop Value Mode)
      3.2   3-Element Vector (Byte Buffer Mode)
            ... Input
            ... Output
      3.3   Procedure (Byte Stream Mode)
            ... Input
            ... Output
      3.4   Special Data Values
            ... NULL Values
            ... Default Parameters in SQL Procedure Calls
      3.5   Extended Fetch and Update
            ... Pop Value mode
            ... Byte Buffer mode
            ... Byte Stream mode
            ... Unfetched Rows

  4   Connecting to a Data Source

  5   Driver/Data Source Information

  6   Driver Options

  7   Preparing SQL Requests

  8   Submitting Requests

  9   Retrieving Results & Result Information

 10   Data Source System Table Information

 11   Terminating Statements & Connections

 12   Asynchronous Statement Processing

 13   Examples
      13.1  Static SQL
      13.2  Ad Hoc Query
            ... Using sql_app_result_set



---------------
1  Introduction
---------------

LIB * ODBC is  a Pop-11  interface to  Microsoft's ODBC  (Open  DataBase
Connectivity), a  C language  API which  allows applications  to  access
database management systems using Structured Query Language (SQL).

Before using any procedures, the library must be loaded with

    uses odbc;

The  include   file  INCLUDE * ODBC defines  various   integer constants
and macros for use with these procedures:

    include odbc.ph;

LIB ODBC  assumes Extension  Level 1  conformance from  all drivers.  It
implements all Core and Level  1 functions, and (currently) all  Level 2
functions except the following:

    SQLParamOptions
    SQLMoreResults
    SQLProcedures
    SQLProcedureColumns

This file describes only the Pop interface to ODBC, and does not attempt
to provide a tutorial  on ODBC in general.  The description of LIB  ODBC
procedures  should   therefore  be   read  in   conjunction  with   ODBC
documentation for the C interface.

In all cases, the  descriptions of the  Pop procedures indicate  which C
functions they call.  Where a Pop  procedure is dependent  on a  Level 2
function, * sql_connect_functions  can  be  used  to  test  whether  the
particular driver supports that function or not.




-----------------------------------
2  Differences from the C Interface
-----------------------------------

2.1  Procedures
---------------
LIB ODBC is  a Pop-paradigm  implementation of the  C interface,  rather
than a literal one. Thus while the Pop procedures are roughly comparable
to the C ones, they are by no means identical.

For this reason,  the Pop procedures  have all-lowercase names  starting
with sql_, e.g.  sql_bind_parameter rather  than SQLBindParameter.  (The
Pop names are also generally  cleaner and more explicit. In  particular,
the names of all  procedures that return data  by creating a result  set
begin with sql_select_.)

Unlike the C  functions they  call, LIB  ODBC procedures  do not  return
status codes: they either return nothing, or (where appropriate)  return
data values directly.

Instead, when a LIB ODBC procedure  calls a C function which returns  an
error (return code  SQL_ERROR), the  Pop procedure will  raise a  mishap
with sys_raise_exception. If  a function returns  SQL_SUCCESS_WITH_INFO,
the Pop procedure will raise a warning and continue. In both cases,  the
exception message text is obtained from SQLError, and the exception  has
an id-string of the form

        odbc-funcname:exsys-odbc-sqlstate

where funcname is the name of  the C function being called and  sqlstate
is the SQLSTATE returned by SQLError.

All other C  return codes are  handled automatically by  LIB ODBC.  (The
only  procedure  which  effectively  hands  on  a  C  status  result  is
sql_fetch,     whose      true/false     result      corresponds      to
SQL_SUCCESS/SQL_NO_DATA_FOUND from SQLFetch.)

The following table summarises  the LIB ODBC  equivalent of each  ODBC C
function:

    C Interface             LIB ODBC
    -----------             --------
    SQLAllocConnect         Called automatically by * sql_connect.

    SQLAllocEnv             * sql_environment if  required,  but  called
                            automatically by * sql_connect.

    SQLAllocStmt            * sql_alloc_statement.

    SQLBindCol              * sql_bind_column.

    SQLBindParameter        * sql_bind_parameter.

    SQLBrowseConnect        * sql_connect.

    SQLCancel               Assigning false to * sql_statement_busy  for
                            a statement.

    SQLColAttributes        * sql_column_attribute.

    SQLColumnPrivileges     * sql_select_column_privileges.

    SQLColumns              * sql_select_columns.

    SQLConnect              * sql_connect.

    SQLDataSources          * sql_data_source_repeater.

    SQLDescribeCol          * sql_describe_column.

    SQLDescribeParam        * sql_describe_parameter.

    SQLDisconnect           * sql_disconnect (or GC destroy action).

    SQLDriverConnect        * sql_connect.

    SQLDrivers              * sql_driver_repeater.

    SQLError                Called  automatically  for  message  strings
                            when an exception is raised.

    SQLExecDirect           * sql_execute with optional SQL string.

    SQLExecute              * sql_execute.

    SQLExtendedFetch        * sql_extended_fetch.

    SQLFetch                * sql_fetch.

    SQLForeignKeys          * sql_select_foreign_keys.

    SQLFreeConnect          * sql_disconnect (or GC destroy action).

    SQLFreeEnv              GC destroy action.

    SQLFreeStmt             * sql_free_statement (or GC destroy action).

    SQLGetConnectOption     * sql_connect_option.

    SQLGetCursorName        * sql_cursor_name.

    SQLGetData              Called  automatically  by  * sql_fetch   and
                            * sql_extended_fetch.

    SQLGetFunctions         * sql_connect_functions.

    SQLGetInfo              * sql_connect_attribute.

    SQLGetStmtOption        * sql_statement_option.

    SQLGetTypeInfo          * sql_select_types.

    SQLNativeSql            * sql_native_sql.

    SQLNumParams            * sql_num_parameters.

    SQLNumResultCols        * sql_num_result_columns.

    SQLParamData            Called automatically  by  * sql_execute  and
                            * sql_set_position when necessary.

    SQLPrepare              * sql_prepare.

    SQLPrimaryKeys          * sql_select_primary_keys.

    SQLPutData              Called automatically  by  * sql_execute  and
                            * sql_set_position when necessary.

    SQLRowCount             * sql_row_count.

    SQLSetConnectOption     * sql_connect_option updater.

    SQLSetCursorName        * sql_cursor_name updater.

    SQLSetStmtOption        * sql_statement_option updater.

    SQLSetPos               * sql_set_position.

    SQLSpecialColumns       * sql_select_special_columns.

    SQLStatistics           * sql_select_statistics.

    SQLTablePrivileges      * sql_select_table_privileges.

    SQLTables               * sql_select_tables.

    SQLTransact             * sql_transact.




2.2  INCLUDE ODBC
-----------------
The file  INCLUDE * ODBC defines  a similar  set of  macros for  integer
constants as the corresponding C header file 'sql.h'.

However, whereas in C all these  macros have names beginning with  SQL_,
in LIB ODBC  some begin with  Sql_. In  all cases, Sql_  values are  the
corresponding SQL_ values shifted left  16 bits, with extra  information
encoded in the bottom part.

(If required, the inline macro SQL(Sql_value) can be applied to an  Sql_
value to get the SQL_ value, e.g.

        SQL(Sql_INTEGER)

is SQL_INTEGER. Note that  in general, INCLUDE  ODBC defines either  the
Sql_ or the SQL_ value, but not both.)

Most  of  the  Sql_  values  are  input  arguments  to  the   procedures
sql_connect_attribute,  sql_connect_option,   sql_statement_option   and
sql_column_attribute, where  they  specify  a  particular  attribute  or
option (and  where  the bottom  16  bits encode  the  data type  of  the
corresponding attribute/option value).


2.3  SQL Data Types
-------------------
ODBC SQL data types describe the represention of data by the driver.  In
LIB ODBC, they are Sql_  values in which the  bottom 16 bits encode  the
precision and  the  scale  of  the type,  and  additionally,  a  bit  to
differentiate between signed and unsigned for integer types.

The LIB ODBC SQL types are listed below, together with the corresponding
default Pop type for each (see next section).

For types whose precision and scale are variable, the Sql_ definition is
not a  single  value,  but  an  inline  macro  that  takes  one  or  two
parameters. These are

        SQL Type                            Default Pop Type
        --------                            ----------------
        Sql_CHAR(nbytes)                    Sql_P_string
        Sql_VARCHAR(max_nbytes)             Sql_P_string
        Sql_BINARY(nbytes)                  Sql_P_binary
        Sql_VARBINARY(max_nbytes)           Sql_P_binary
        Sql_NUMERIC(precision, scale)       Sql_P_string
        Sql_DECIMAL(precision, scale)       Sql_P_string

The non-parameterised types are

        SQL Type                            Default Pop Type
        --------                            ----------------
        Sql_BIT                             Sql_P_boolean
        Sql_TINYINT                         Sql_P_sbyte
        Sql_SMALLINT                        Sql_P_short
        Sql_INTEGER                         Sql_P_int
        Sql_BIGINT                          Sql_P_longlong
        Sql_REAL                            Sql_P_sfloat
        Sql_FLOAT                           Sql_P_dfloat
        Sql_DOUBLE                          Sql_P_dfloat
        Sql_DATE                            Sql_P_date
        Sql_TIME                            Sql_P_time
        Sql_TIMESTAMP                       Sql_P_timestamp
        Sql_LONGVARBINARY                   Sql_P_binary
        Sql_LONGVARCHAR                     Sql_P_string

The types Sql_TINYINT, Sql_SMALLINT, Sql_INTEGER and Sql_BIGINT indicate
signed integers, and each has a corresponding unsigned version:

        SQL Type                            Default Pop Type
        --------                            ----------------
        Sql_UTINYINT                        Sql_P_byte
        Sql_USMALLINT                       Sql_P_ushort
        Sql_UINTEGER                        Sql_P_uint
        Sql_UBIGINT                         Sql_P_ulonglong

The   above   SQL   type   encoding   simplifies   the   arguments    to
sql_bind_parameter,  by   condensing   three   of   the   arguments   to
SQLBindParameter into one (also three SQLDescribeColumn results into one
sql_describe_column result, etc).

The signed/unsigned distinction for  integer types makes it  unnecessary
to specify an  explicit Pop  type to sql_bind_parameter  merely for  the
purpose of indicating signed or unsigned.

Note that  the  parameters  to  types like  Sql_CHAR  are  evaluated  at
compile-time,  and  cannot  be   run-time  expressions.  The   following
procedures may be used to manipulate SQL type descriptors at run-time:


sql_cons_sql_type(stype, precision, scale, unsigned)         [procedure]
                                            -> sql_type
        Constructs a LIB ODBC SQL type descriptor sql_type (an integer).

        stype is the basic  ODBC SQL type; precision  and scale are  the
        precision and scale of the type. precision must range from 0  to
        255, and scale must range from 0 to precision.

        unsigned is a boolean  which if true  indicates that an  integer
        type (i.e.  stype =  SQL_TINYINT, SQL_SMALLINT,  SQL_INTEGER  or
        SQL_BIGINT) should be  considered unsigned  rather than  signed.
        (unsigned is ignored for other types.)

        Note that an sql_type descriptor  for a long data type  (stype =
        SQL_LONGVARCHAR or  SQL_LONGVARBINARY)  does not  represent  the
        maximum number  of bytes  allowed for  the type  (since this  is
        likely to be  a large  number such  as 2**31-1).  Hence in  this
        case, precision is ignored and set to 0 (and scale must be 0).


sql_dest_sql_type(sql_type)                                  [procedure]
                    -> (stype, precision, scale, unsigned)
        Given a  LIB  ODBC SQL  type  descriptor sql_type,  returns  the
        four component fields of the type.


The following  code fragment  illustrates the  use of  sql_dest_sql_type
(and the SQL inline  macro) to perform  a go_on on  the basic type  of a
given sql_type descriptor:

    sql_dest_sql_type(sql_type) -> (stype, precision, scale, unsigned);

    go_on stype to SType:
        SType SQL(Sql_CHAR(1)):
        SType SQL(Sql_VARCHAR(1)):
        SType SQL(Sql_BINARY(1)):
        SType SQL(Sql_VARBINARY(1)):
            <some code>
            goto SType end;

        SType SQL(Sql_TINYINT):
        SType SQL(Sql_SMALLINT):
        SType SQL(Sql_INTEGER):
        SType SQL(Sql_BIGINT):
            <some code>
            goto SType end;

        SType SQL(Sql_REAL):
        SType SQL(Sql_FLOAT):
        SType SQL(Sql_DOUBLE):
        SType SQL(Sql_DECIMAL(1,0)):
        SType SQL(Sql_NUMERIC(1,0)):
            <some code>
    endgo_on;

(Note that for the above, the parameterised Sql_ types can use any legal
parameter values, since the basic stype is not affected.)


2.4  Pop Data Types
-------------------
In the C interface, the ODBC C data types specify the representation  of
data required in the application program; when data is transferred,  the
driver converts  data  between  this representation  and  the  SQL  type
representation. Each SQL type has a corresponding default C type.

In LIB ODBC, the role played by  ODBC C data types is played instead  by
Sql_P_ Pop data types (the  SQL() values of which  are the C types  they
correspond to). Each SQL type has a corresponding default Pop type  (see
previous section).

Unlike the C interface, LIB ODBC provides three different mechanisms for
actually accessing data -- see Data Input/Output Modes below.

The Pop data types are

        Sql_P_boolean
        Sql_P_bit

        Sql_P_sbyte
        Sql_P_byte
        Sql_P_short
        Sql_P_ushort
        Sql_P_int
        Sql_P_uint
        Sql_P_longlong
        Sql_P_ulonglong
        Sql_P_sfloat
        Sql_P_dfloat

        Sql_P_bookmark

        Sql_P_date
        Sql_P_time
        Sql_P_timestamp

        Sql_P_string
        Sql_P_binary

The types Sql_P_sbyte through  Sql_P_dfloat represent storage  locations
as for  a  Pop  record  field  of  the  corresponding  type  (see  Field
Specifiers for Poplog Data in REF * KEYS).

The type  Sql_P_bit is  the same  as Sql_P_byte,  except that  only  the
bottom bit  is  significant; Sql_P_boolean  is  the same  as  Sql_P_bit,
except that the bit  value is converted to/from  a boolean in Pop  value
mode (see Data Input/Output Modes below).

Sql_P_bookmark is the same as Sql_P_uint (note that this is the  default
Pop type for * sql_bind_column on column number 0).

Sql_P_date, Sql_P_time and  Sql_P_timestamp represent storage  locations
for the  i_typespec  structures  sql_date,  sql_time  and  sql_timestamp
defined in INCLUDE * ODBC.

The types Sql_P_string and Sql_P_binary both represent storage locations
for data as a sequence  of bytes. (In the  C interface, these two  types
must be distinguished, because of  null-termination for strings. In  the
Pop interface this does not apply, and the only difference between  them
is that for input to non-LONG parameters (i.e. excluding Sql_LONGVARCHAR
or Sql_LONGVARBINARY parameters), Sql_P_string implies a maximum  length
of 254 bytes rather than 255 for Sql_P_binary.)


2.5  Environment, Connection & Statement Handles
------------------------------------------------
In LIB ODBC,  the C-interface handles  for the environment,  connections
and statements  are packaged  as external-pointer  class records  (whose
contents are otherwise opaque to the user).

Each record is given a garbage  collector destroy action, which will  be
called when the record becomes garbage.

Since there is  only one  environment handle, this  is never  explicitly
required as an argument to any procedure. It is created automatically by
* sql_connect if necessary, but may be explicitly created by referencing
the active variable * sql_environment.




--------------------------
3  Data Input/Output Modes
--------------------------

The DATA_BUFF argument  to sql_bind_parameter specifies  how data  for a
parameter is input when  sql_execute is called.  (It also specifies  how
data is output for an output parameter in an SQL procedure call, i.e. an
SQL call statement that calls a  named executable object defined by  the
data source.)

Similarily, the  DATA_BUFF  argument to  sql_bind_column  specifies  how
data for a column is output when sql_fetch is called.

In both  cases,  DATA_BUFF represents  either  one or  two  arguments: a
single identifier record main_id, optionally  followed by a second  item
mode.

The mode item controls the mode in which data is transferred, and may be

    # false (the default if omitted);
    # a 3-element vector;
    # a procedure.

Alternatively, mode may be another  identifier whose idval will  contain
one of those  three at  the time of  the sql_execute  or sql_fetch.  (In
other words, mode may be supplied as a bind-time constant, or through an
identifier    whose    value    can    change    between    calls     to
sql_execute/sql_fetch.)

The different modes (in order of increasing complexity) are as follows:


3.1  false (Pop Value Mode)
---------------------------
When mode  is false  (or omitted),  the data  value is  simply a  Poplog
object input from, or output to, the idval of main_id.

The Pop types Sql_P_sbyte through Sql_P_dfloat accept as input any  item
that can be assigned into a Pop  record field of that type, and  produce
as output the result of accessing such a field.

An input  value for  Sql_P_bit must  be either  0 or  1, with  the  same
produced on output; for Sql_P_boolean,  the truthvalue of an input  item
is converted to 0 or  1 (0 for false, 1  for anything else), and  output
produces false or true.

The types Sql_P_string and Sql_P_binary both accept or produce a string.

The  Pop  value   corresponding  to  the   Sql_P_date,  Sql_P_time   and
Sql_P_timestamp types is a full vector  whose first element is the  word
"sql_date", "sql_time" or "sql_timestamp", and whose remaining  elements
are integers:

        Type                Vector
        ----                ------
        Sql_P_date          {sql_date year month day}
        Sql_P_time          {sql_time hour minute second}
        Sql_P_timestamp     {sql_timestamp year month day
                                           hour minute second fraction}


3.2  3-Element Vector (Byte Buffer Mode)
----------------------------------------
When mode is a 3-element vector, it specifies a byte buffer in the form

        {start_bsub bytestruct max_nbytes}

where bytestruct is  any structure suitable  for use with  * move_bytes.
The buffer area starts at  byte subscript start_bsub within  bytestruct,
and has a maximum length of max_nbytes bytes.

...  Input
----------
For input parameter  data, you  must set  main_id to  the actual  number
nbytes of data bytes to be transferred before each call to  sql_execute.
The data is then taken from the buffer with

        move_bytes(start_bsub, bytestruct, ..., nbytes);

For all Pop types except Sql_P_string or Sql_P_binary, it is an error if
nbytes is  not the  exact number  of bytes  required for  the type.  For
Sql_P_string/Sql_P_binary, nbytes must be less than or equal to  254/255
unless  the   SQL  type   of  the   parameter  is   Sql_LONGVARCHAR   or
Sql_LONGVARBINARY.

...  Output
-----------
For output column data, each call of sql_fetch will transfer data to the
buffer with

        move_bytes(..., start_bsub, bytestruct, nbytes);

and set main_id  to the number  nbytes of bytes  transferred. (It is  an
error if the buffer is not large enough, i.e. if max_nbytes is less than
nbytes.) Similarily for output parameters from sql_execute.


3.3  Procedure (Byte Stream Mode)
---------------------------------
If mode  is a  procedure, mode  or  its updater  will be  called  inside
sql_execute or sql_fetch to transfer the data.

...  Input
----------
For input parameters, you must set main_id to the total number nbytes of
data bytes to be  transferred before each call  to sql_execute. (If  the
total is not known  in advance you  can set it  false; however, this  is
only allowable if the * sql_connect_attribute Sql_NEED_LONG_DATA_LEN  is
false.)

The updater of mode will then  be called inside sql_execute with  nbytes
and a procedure write_p as arguments:

        -> mode(nbytes, write_p)

The updater of mode must then call the procedure write_p to write chunks
of data as input, i.e.

        write_p(start_bsub, bytestruct, nb)

meaning take  nb  bytes  from  bytestruct  starting  at  byte  subscript
start_bsub (where bytestruct is any structure allowed by  * move_bytes).
The updater of mode may call write_p as many times as necessary to  pass
all the data for the parameter.

...  Output
-----------
For output column data, sql_fetch will  set main_id to the total  number
nbytes of data bytes  (or false if  this is not  known in advance),  and
then call the base procedure of mode with main_id and a procedure read_p
as arguments:

        mode(main_id, read_p)

mode must then  call the procedure  read_p to receive  chunks of  output
data, i.e.

        read_p(start_bsub, bytestruct, max_nb) -> nb

meaning read  at most  max_nb  bytes into  bytestruct starting  at  byte
subscript start_bsub (returning the actual  number of bytes read).  mode
must repeatedly call read_p to fetch all the data for the column; read_p
will return less than max_nb only at end-of-stream, and 0 when the  data
is exhausted.

(Note that mode  being called with  main_id as argument  gives mode  the
option of creating a structure for  the output data and assigning it  to
main_id. This is potentially useful with * sql_app_result_set, where the
main_id   identifiers   are   created   internally   and    dereferenced
automatically after calling sql_fetch.)

The situation is identical for  sql_execute output parameters, i.e.  the
base procedure of mode is called to read the data. (For parameters  that
are both input and output, the updater is called first to handle  input,
then the base procedure to handle output.)


3.4  Special Data Values
------------------------

...  NULL Values
----------------
NULL data values are represented in  the Pop interface by undef  records
(e.g. pop_undef).

To specify  that  the  value  of an  input  parameter  is  NULL,  assign
pop_undef to the value of main_id. The mode argument is then ignored.

When an  output column  or  parameter value  is  NULL, the  system  sets
main_id to pop_undef, and ignores mode.


...  Default Parameters in SQL Procedure Calls
----------------------------------------------
To specify that an SQL procedure  call should use the default value  for
an input parameter, set the value of main_id to the word "default". mode
is then ignored for input.



3.5  Extended Fetch and Update
------------------------------
The Level  2 procedure  sql_extended_fetch allows  multiple rows  to  be
fetched from a result set.  The number of rows  to be fetched is  called
the  rowset  size  (and  is  determined  by  the  * sql_statement_option
Sql_ROWSET_SIZE).

In  addition,  following  a  call  to  sql_extended_fetch,  the  Level 2
procedure sql_set_position may be  called (with operation =  SQL_UPDATE)
to update one or all of the fetched rows. (It may also be called to  add
new rows.)

To cope with multiple rows in  each column, the first DATA_BUFF item  to
sql_bind_column must be a full vector main_vec rather than an identifier
main_id. The R-th element  of main_vec is then  used instead of  main_id
for the R-th row of the rowset.  The length of the vector bound to  each
column must be  at least as  large as the  rowset size (identifiers  may
only be used with sql_extended_fetch if the rowset size is 1).

When main_vec is specified, the mode argument is similar, except that it
now applies to any row in the rowset instead of just one:

...  Pop Value mode
-------------------
The value item for  the R-th row  of the column is  assigned to (or  for
updating, taken from) main_vec(R).

...  Byte Buffer mode
---------------------
When mode  is a  3-element  vector {start_bsub  bytestruct  max_nbytes},
max_nbytes specifies the size of each  row part within the column.  Thus
the data area for the R-th row is assumed to start at

        start_bsub + (R-1)*max_nbytes

The actual number of bytes  nbytes for the R-th  row is assigned to  (or
for updating, taken from) main_vec(R).

...  Byte Stream mode
---------------------
When mode is a procedure, the base procedure is called once for each row
R within the column, with the  total number of bytes nbytes assigned  to
main_vec(R). mode is called with the row number R as an additional first
argument:

        mode(R, main_vec, read_p)

For updating, main_vec(R) must be set to the total number nbytes of data
bytes  to   be   transferred  for   each   row  before   the   call   to
sql_set_position. The updater of mode is  then called once for each  row
within the column with the row number R as an additional first argument:

        -> mode(R, nbytes, write_p)

...  Unfetched Rows
-------------------
When the actual  number of  rows fetched is  less than  the rowset  size
(e.g. at the end of the result  set), main_vec(R) is set to termin  (and
mode ignored) for any rows not  fetched. This also happens for any  rows
for  which   an   error   occurred,   or   which   were   deleted   (see
sql_extended_fetch).

For updating, any row for which main_vec(R) is termin will be ignored.




------------------------------
4  Connecting to a Data Source
------------------------------

sql_environment -> henv                                [active variable]
        This active variable returns  the current environment handle  if
        one  exists,  or  calls  SQLAllocEnv  to  allocate  a  new   one
        otherwise.

        Once created, sql_environment holds  on to the environment  only
        weakly via  a  temporary  property  entry,  which  means  that a
        garbage collection will reclaim it (and call SQLFreeEnv)  unless
        other references to it remain.

        Since the environment is not required as an argument by any  LIB
        ODBC procedure calls, there are  only two reasons for  accessing
        this variable explicitly, viz

          # To force the environment to be created at a particular  time
            (e.g. on program startup -- note that SQLAllocEnv reads  the
            file 'odbc.ini');

          # To save the environment in  your own variable to prevent  it
            being garbaged (you should always do this if you access it).

        Note that  all  connection  and  statement  handles  maintain a
        pointer to the environment, so  merely saving one of these  will
        also prevent the environment being garbaged.


sql_connect(conn_str, changes_p, retries, conn_mode) -> hdbc [procedure]
        Establishes  a  connection  to  a  data  source  and   returns a
        connection handle hdbc.

        This procedure provides  an interface  to both  SQLDriverConnect
        and SQLBrowseConnect (as well as the equivalent of  SQLConnect).
        It  performs   SQLAllocConnect   automatically   (and   accesses
        * sql_environment for the environment handle).

        Any of the  changes_p, retries  and conn_mode  arguments may  be
        omitted;  only  the  conn_str  argument  is  mandatory.   Unless
        conn_mode is  supplied  and  is a  reference  (see  below),  the
        connection is made using SQLDriverConnect.

        conn_str
            This is  the only  required argument,  and may  be a  single
            string, or a 0- to 3-element list of strings:

                [ ]
                [ data_source_name ]
                [ data_source_name user_name ]
                [ data_source_name user_name password ]

            The list elements  are converted  to a  string suitable  for
            SQLDriverConnect/SQLBrowseConnect, i.e.

                ''
                'DSN=data_source_name;'
                'DSN=data_source_name; UID=user_name;'
                'DSN=data_source_name; UID=user_name; PWD=password;'

            If conn_str  is  a single  string,  it is  interpreted  as a
            data_source_name (i.e.  equivalent  to  a  1-element  list),
            unless it contains a semicolon: in this case, it is  assumed
            to be a valid connection string for SQLDriverConnect, and is
            used unchanged.

        changes_p
            An   optional   procedure   argument   which   enables   any
            pre-connection setting of options with * sql_connect_option.
            If supplied, it is called on the newly-allocated  connection
            handle hdbc before making the actual connection, i.e.

                    changes_p(hdbc)

            (Note that this is only time user code is given access to an
            unconnected connection handle.)

        retries
            An optional  integer  retry count  for  connection  attempts
            (defaults to 5  if omitted). Connection  attempts that  fail
            because of communication-link  errors will  be retried  this
            many times.

        conn_mode
            This  optional  argument  is   either  a  pair   (specifying
            additional arguments for  SQLDriverConnect), or a  reference
            containing a  procedure  (specifying  that  SQLBrowseConnect
            should be used instead of SQLDriverConnect).

            If conn_mode  is a  pair,  the front  must contain  an  item
            suitable for the window handle argument to SQLDriverConnect,
            and the back  an integer  for the  'driver completion  flag'
            argument.   The    latter    is    one    of    the    codes
            SQL_DRIVER_NOPROMPT, SQL_DRIVER_COMPLETE,  SQL_DRIVER_PROMPT
            or SQL_DRIVER_COMPLETE_REQUIRED (defined in INCLUDE * ODBC),
            and defaults to SQL_DRIVER_NOPROMPT if conn_mode is omitted.

            To specify that SQLBrowseConnect  should be used,  conn_mode
            must be reference containing a procedure, i.e.

                    consref(browse_p)

            where browse_p is a procedure of the form

                browse_p(result_string, sqlstate_or_false)
                                            -> next_conn_string

            SQLBrowseConnect is  then called  repeatedly (starting  with
            the initial  conn_str  argument)  until  the  connection  is
            established. Each time it returns SQL_NEED_DATA  (indicating
            that more connection information  is required), browse_p  is
            called to supply the additional information.

            The two arguments  passed to  browse_p each  time depend  on
            whether the previous SQLBrowseConnect call had a recoverable
            error or not. If there was an error, the second argument  is
            the SQLSTATE string for the error, and result_string is  the
            associated error message obtained from SQLError.  Otherwise,
            the second  argument  is  false, and  result_string  is  the
            browse result connection string.

            In  either  case,  browse_p   must  return  an   appropriate
            next_conn_string  as   argument  for   the  next   call   to
            SQLBrowseConnect.




---------------------------------
5  Driver/Data Source Information
---------------------------------

sql_data_source_repeater() -> ds_rep                         [procedure]
        Returns  a   repeater   procedure   ds_rep   for   data   source
        specifications from the 'odbc.ini' file or registry.

        Each time ds_rep is called, it uses SQLDataSources to fetch  the
        next data source specification  as a pair  of strings, the  data
        source name and its associated driver description. That is,

            ds_rep() -> pair_or_termin

        where each pair has the form

            conspair(data_source_name, driver_description)

        ds_rep returns termin at end of stream.


sql_driver_repeater() -> dr_rep                              [procedure]
        Returns a repeater  procedure dr_rep  for driver  specifications
        from the odbc.ini file.

        Each time dr_rep is called, it uses SQLDrivers to fetch the next
        driver specification as a list of strings. The first element  of
        the list is the driver  description, and any remaining  elements
        are attributes in the form 'keyword=value'. That is,

            dr_rep() -> list_or_termin

        where each list has the form

            [ driver_description attribute1 attribute2 ... ]

        dr_rep returns termin at end of stream.


sql_connect_attribute(hdbc, conn_attr) -> value              [procedure]
        Calls SQLGetInfo to return the value of a specified attribute of
        the driver/data source associated with the connection hdbc.

        conn_attr specifies the attribute, and  must be one of the  Sql_
        descriptors listed below (defined in INCLUDE * ODBC).

        The table below indicates  the data type  of the value  returned
        for each attribute. Note that

          # type code means one of  a mutually exclusive set of  integer
            values defined  as  SQL_  constants by  INCLUDE  ODBC  (e.g.
            Sql_IDENTIFIER_CASE    returns    one    of    SQL_IC_UPPER,
            SQL_IC_LOWER, SQL_IC_SENSITIVE or SQL_IC_MIXED);

          # type bitmask means an  integer OR'ed from  a set of  bitmask
            values defined  as  SQL_  constants by  INCLUDE  ODBC  (e.g.
            Sql_ALTER_TABLE   has   zero   or    more   of   the    bits
            SQL_AT_ADD_COLUMN, SQL_AT_DROP_COLUMN set).

          # attributes for  which SQLGetInfo  returns a  Y/N string  are
            returned as booleans (true/false);

        See SQLGetInfo for a description of each attribute.

            conn_attr                           Type
            ---------                           ----
            Sql_ACCESSIBLE_PROCEDURES           boolean
            Sql_ACCESSIBLE_TABLES               boolean
            Sql_ACTIVE_CONNECTIONS              integer
            Sql_ACTIVE_STATEMENTS               integer
            Sql_ALTER_TABLE                     bitmask
            Sql_BOOKMARK_PERSISTENCE            bitmask
            Sql_COLUMN_ALIAS                    boolean
            Sql_CONCAT_NULL_BEHAVIOR            code
            Sql_CONVERT_BIGINT                  bitmask
            Sql_CONVERT_BINARY                  bitmask
            Sql_CONVERT_BIT                     bitmask
            Sql_CONVERT_CHAR                    bitmask
            Sql_CONVERT_DATE                    bitmask
            Sql_CONVERT_DECIMAL                 bitmask
            Sql_CONVERT_DOUBLE                  bitmask
            Sql_CONVERT_FLOAT                   bitmask
            Sql_CONVERT_FUNCTIONS               bitmask
            Sql_CONVERT_INTEGER                 bitmask
            Sql_CONVERT_LONGVARBINARY           bitmask
            Sql_CONVERT_LONGVARCHAR             bitmask
            Sql_CONVERT_NUMERIC                 bitmask
            Sql_CONVERT_REAL                    bitmask
            Sql_CONVERT_SMALLINT                bitmask
            Sql_CONVERT_TIME                    bitmask
            Sql_CONVERT_TIMESTAMP               bitmask
            Sql_CONVERT_TINYINT                 bitmask
            Sql_CONVERT_VARBINARY               bitmask
            Sql_CONVERT_VARCHAR                 bitmask
            Sql_CORRELATION_NAME                code
            Sql_CURSOR_COMMIT_BEHAVIOR          code
            Sql_CURSOR_ROLLBACK_BEHAVIOR        code
            Sql_DATA_SOURCE_NAME                string
            Sql_DATA_SOURCE_READ_ONLY           boolean
            Sql_DBMS_NAME                       string
            Sql_DBMS_VER                        string
            Sql_DEFAULT_TXN_ISOLATION           code
            Sql_DRIVER_NAME                     string
            Sql_DRIVER_ODBC_VER                 string
            Sql_DRIVER_VER                      string
            Sql_EXPRESSIONS_IN_ORDERBY          boolean
            Sql_FETCH_DIRECTION                 bitmask
            Sql_FILE_USAGE                      code
            Sql_GETDATA_EXTENSIONS              bitmask
            Sql_GROUP_BY                        code
            Sql_IDENTIFIER_CASE                 code
            Sql_IDENTIFIER_QUOTE_CHAR           string
            Sql_KEYWORDS                        string
            Sql_LIKE_ESCAPE_CLAUSE              boolean
            Sql_LOCK_TYPES                      bitmask
            Sql_MAX_BINARY_LITERAL_LEN          integer
            Sql_MAX_CHAR_LITERAL_LEN            integer
            Sql_MAX_COLUMNS_IN_GROUP_BY         integer
            Sql_MAX_COLUMNS_IN_INDEX            integer
            Sql_MAX_COLUMNS_IN_ORDER_BY         integer
            Sql_MAX_COLUMNS_IN_SELECT           integer
            Sql_MAX_COLUMNS_IN_TABLE            integer
            Sql_MAX_COLUMN_NAME_LEN             integer
            Sql_MAX_CURSOR_NAME_LEN             integer
            Sql_MAX_INDEX_SIZE                  integer
            Sql_MAX_OWNER_NAME_LEN              integer
            Sql_MAX_PROCEDURE_NAME_LEN          integer
            Sql_MAX_QUALIFIER_NAME_LEN          integer
            Sql_MAX_ROW_SIZE                    integer
            Sql_MAX_ROW_SIZE_INCLUDES_LONG      boolean
            Sql_MAX_STATEMENT_LEN               integer
            Sql_MAX_TABLES_IN_SELECT            integer
            Sql_MAX_TABLE_NAME_LEN              integer
            Sql_MAX_USER_NAME_LEN               integer
            Sql_MULTIPLE_ACTIVE_TXN             boolean
            Sql_MULT_RESULT_SETS                boolean
            Sql_NEED_LONG_DATA_LEN              boolean
            Sql_NON_NULLABLE_COLUMNS            boolean
            Sql_NULL_COLLATION                  code
            Sql_NUMERIC_FUNCTIONS               bitmask
            Sql_ODBC_API_CONFORMANCE            code
            Sql_ODBC_SAG_CLI_CONFORMANCE        code
            Sql_ODBC_SQL_CONFORMANCE            code
            Sql_ODBC_SQL_OPT_IEF                boolean
            Sql_ODBC_VER                        string
            Sql_OJ_CAPABILITIES                 bitmask
            Sql_ORDER_BY_COLUMNS_IN_SELECT      boolean
            Sql_OUTER_JOINS                     boolean
            Sql_OWNER_TERM                      string
            Sql_OWNER_USAGE                     bitmask
            Sql_POSITIONED_STATEMENTS           bitmask
            Sql_POS_OPERATIONS                  bitmask
            Sql_PROCEDURES                      boolean
            Sql_PROCEDURE_TERM                  string
            Sql_QUALIFIER_LOCATION              code
            Sql_QUALIFIER_NAME_SEPARATOR        string
            Sql_QUALIFIER_TERM                  string
            Sql_QUALIFIER_USAGE                 bitmask
            Sql_QUOTED_IDENTIFIER_CASE          code
            Sql_ROW_UPDATES                     boolean
            Sql_SCROLL_CONCURRENCY              bitmask
            Sql_SCROLL_OPTIONS                  bitmask
            Sql_SEARCH_PATTERN_ESCAPE           string
            Sql_SERVER_NAME                     string
            Sql_SPECIAL_CHARACTERS              string
            Sql_STATIC_SENSITIVITY              bitmask
            Sql_STRING_FUNCTIONS                bitmask
            Sql_SUBQUERIES                      bitmask
            Sql_SYSTEM_FUNCTIONS                bitmask
            Sql_TABLE_TERM                      string
            Sql_TIMEDATE_ADD_INTERVALS          bitmask
            Sql_TIMEDATE_DIFF_INTERVALS         bitmask
            Sql_TIMEDATE_FUNCTIONS              bitmask
            Sql_TXN_CAPABLE                     code
            Sql_TXN_ISOLATION_OPTION            bitmask
            Sql_UNION                           bitmask
            Sql_USER_NAME                       string


sql_connect_functions(hdbc) -> bitmask                       [procedure]
sql_connect_functions(hdbc, func_number) -> bool
        Calls  SQLGetFunctions  to  return  information  on  which  ODBC
        functions are supported by the driver on the connection hdbc.

        Each function is identified by a number from 1 to 100; constants
        for these numbers have  names of the form  SQL_API_functionname.
        Note that INCLUDE * ODBC defines these names only for  Extension
        Level 2 functions, since LIB ODBC assumes Level 1  functionality
        is always present.

        In the first  form, sql_connect_functions calls  SQLGetFunctions
        to get information  about all functions,  and returns this  as a
        biginteger bitmask in which bit N is set if the driver  supports
        function number N. bitmask can therefore be used with

            testbit(bitmask, func_number)

        to test for  an individual func_number.  (Note that the  bitmask
        result is  cached  inside  hdbc  so  that  subsequent  calls  to
        sql_connect_functions do not have to reconstruct it.)

        In the second form, sql_connect_functions returns a boolean bool
        pertaining to the individual function given by func_number.


sql_select_types(hstmt)                                      [procedure]
sql_select_types(hstmt, sql_type)
        Calls SQLGetTypeInfo to create a result set describing the  data
        types supported by a  data source. hstmt  is a statement  handle
        for the result set.

        If sql_type  is  supplied,  it  must be  a  LIB  ODBC  SQL  type
        descriptor (see SQL Data Types above); in this case, the  result
        set has rows only for  those data source types which  correspond
        to sql_type. If sql_type is omitted, all possible data types are
        enumerated.

        See SQLGetTypeInfo for details of the columns in each row of the
        result set.




-----------------
6  Driver Options
-----------------

sql_connect_option(hdbc, conn_option) -> value               [procedure]
value -> sql_connect_option(hdbc, conn_option)
        Calls  SQLGetConnectOption/SQLSetConnectOption   to  access   or
        update  the  value  of  a  specified  option  setting  for   the
        connection hdbc.

        conn_option specifies the option,  and must be  one of the  Sql_
        descriptors listed below  (and defined  in INCLUDE * ODBC).  For
        the updater only, conn_option  may also be  any valid option  to
        sql_statement_option (i.e.  to set  a statement  option for  all
        subsequently-created statements on hdbc).

        The table below indicates  the data type  of the value  returned
        for each option.  Note that type  code means one  of a  mutually
        exclusive set of  integer values  defined as  SQL_ constants  by
        INCLUDE   ODBC    (e.g.   Sql_ACCESS_MODE    returns   one    of
        SQL_MODE_READ_WRITE or SQL_MODE_READ_ONLY).

        Certain options  also have  a default  value defined  for  them:
        these are shown in the table. For any option whose value has not
        previously been set, sql_connect_option will return the  default
        if the option has one,  or pop_undef otherwise. In addition,  an
        option with  a default  value  may be  set  to that  default  by
        assigning the word "default" to the updater.

        See SQLSetConnectOption for a description of each option.

            conn_option             Type        Default
            -----------             ----        -------
            Sql_ACCESS_MODE         code        SQL_MODE_READ_WRITE
            Sql_AUTOCOMMIT          boolean     true
            Sql_CURRENT_QUALIFIER   string
            Sql_LOGIN_TIMEOUT       integer     15
            Sql_ODBC_CURSORS        code        SQL_CUR_USE_DRIVER
            Sql_OPT_TRACE           boolean     false
            Sql_OPT_TRACEFILE       string
            Sql_PACKET_SIZE         integer
            Sql_TRANSLATE_DLL       string
            Sql_TRANSLATE_OPTION    integer
            Sql_TXN_ISOLATION       code


sql_statement_option(hstmt, stmt_option) -> value            [procedure]
value -> sql_statement_option(hstmt, stmt_option)
        Calls SQLGetStmtOption/SQLSetStmtOption to access or update  the
        value of a specified option setting for the statement hstmt.

        stmt_option specifies the option,  and must be  one of the  Sql_
        descriptors listed below (and defined in INCLUDE * ODBC).

        The table below indicates  the data type  of the value  returned
        for each option.  Note that type  code means one  of a  mutually
        exclusive set of  integer values  defined as  SQL_ constants  by
        INCLUDE   ODBC    (e.g.   Sql_ACCESS_MODE    returns   one    of
        SQL_MODE_READ_WRITE or SQL_MODE_READ_ONLY).

        Certain options  also have  a default  value defined  for  them:
        these are shown in the table. For any option whose value has not
        previously  been  set,  sql_statement_option  will  return   the
        default if  the  option  has one,  or  pop_undef  otherwise.  In
        addition, an option  with a  default value  may be  set to  that
        default by assigning the word "default" to the updater.

        Note that the Sql_ASYNC_ENABLE option is special insofar as  its
        value is  false  or  a  procedure.  See  Asynchronous  Statement
        Processing below.

        See SQLSetStmtOption for a description of each option.

            stmt_option             Type        Default
            -----------             ----        -------
            Sql_ASYNC_ENABLE        boolean     false
            Sql_CONCURRENCY         code        SQL_CONCUR_READ_ONLY
            Sql_CURSOR_TYPE         code        SQL_CURSOR_FORWARD_ONLY
            Sql_KEYSET_SIZE         integer     0
            Sql_MAX_LENGTH          integer     0
            Sql_MAX_ROWS            integer     0
            Sql_NOSCAN              boolean     false
            Sql_QUERY_TIMEOUT       integer     0
            Sql_RETRIEVE_DATA       boolean     true
            Sql_ROWSET_SIZE         integer     1
            Sql_SIMULATE_CURSOR     code
            Sql_USE_BOOKMARKS       boolean     false

        The following options  are read-only (i.e.  may be accessed  but
        not set, see SQLGetStmtOption):

            Sql_GET_BOOKMARK        integer
            Sql_ROW_NUMBER          integer

        There is also the following option, which is special to LIB ODBC
        (and is  used by  * sql_extended_fetch when  Sql_ROWSET_SIZE  is
        greater than 1):

            Sql_LONG_DATA_MAX       integer     2047




-------------------------
7  Preparing SQL Requests
-------------------------

sql_alloc_statement(hdbc) -> hstmt                           [procedure]
        Calls SQLAllocStmt to allocate a  new statement handle hstmt  on
        the connection hdbc.


sql_prepare(hstmt, sql_string)                               [procedure]
        Calls SQLPrepare  to  prepare  the  SQL  string  sql_string  for
        execution on the statement hstmt. All parameters and columns  on
        hstmt are unbound first.


sql_num_parameters(hstmt) -> num_parameters                  [procedure]
        (Extension Level  2) Returns  the number  of parameters  in  the
        prepared statement hstmt (by calling SQLNumParams).


sql_describe_parameter(hstmt, N) -> (sql_type, nullable)     [procedure]
sql_describe_parameter(hstmt, N, unsigned)
                                 -> (sql_type, nullable)
        (Extension Level 2) Returns  the LIB ODBC SQL  type of the  N-th
        parameter  in   the  prepared   statement  hstmt   (by   calling
        SQLDescribeParam).

        The  nullable  result  is   one  of  the  values   SQL_NO_NULLS,
        SQL_NULLABLE     or     SQL_NULLABLE_UNKNOWN     (defined     in
        INCLUDE * ODBC).

        Because SQLDescribeParam  does  not provide  any  indication  of
        whether whether  an  integer type  is  signed or  unsigned,  the
        optional boolean  argument unsigned  may  be supplied:  this  is
        passed as  the last  argument  to * sql_cons_sql_type  when  the
        sql_type result is constructed (and defaults to false).



sql_bind_parameter(hstmt, N, DATA_BUFF, sql_type)            [procedure]
sql_bind_parameter(hstmt, N, DATA_BUFF, sql_type, pop_type)
sql_bind_parameter(hstmt, N, DATA_BUFF, sql_type, pop_type,
                                                param_type)
        Binds a  buffer for  the N-th  parameter marker  in a  statement
        hstmt (where N >= 1). This procedure calls SQLBindParameter.

        DATA_BUFF specifies the buffer mechanism, and represents  either
        one or two arguments. These  are described fully in the  section
        Data Input/Output Modes above.

        sql_type specifies the LIB ODBC  SQL type of the parameter,  and
        must be one of the Sql_ types listed under SQL Data Types above.

        pop_type is  an optional  Pop data  type for  the parameter;  if
        supplied, it must be  one of the Sql_P_  types listed under  Pop
        Data Types above.  If pop_type  is omitted, it  defaults to  the
        default Pop type for sql_type (see SQL Data Types).

        param_type is an optional parameter type, and must be one of the
        constants     SQL_PARAM_INPUT,     SQL_PARAM_INPUT_OUTPUT     or
        SQL_PARAM_OUTPUT  defined  in  INCLUDE * ODBC.  If  omitted,  it
        defaults  to  SQL_PARAM_INPUT.  (Note  that  if  param_type   is
        supplied, pop_type is mandatory; however, in this case  pop_type
        may be false to mean use the default Pop type for sql_type.)

        The form

                sql_bind_parameter(hstmt, "*", false);

        may also be used to unbind all parameters on hstmt (there is  no
        mechanism for unbinding a single parameter).


sql_cursor_name(hstmt) -> string_or_false                    [procedure]
string_or_false -> sql_cursor_name(hstmt)
        Returns or updates the  name of the  cursor associated with  the
        statement hstmt.

        The base procedure  call SQLGetCursorName to  access the  cursor
        name. false is returned if there is no open cursor on hstmt (and
        the updater has not been called to set an explicit name).

        If the updater is given  a string, it calls SQLSetCursorName  to
        associate a cursor name with hstmt (this may only be done before
        the cursor is opened, i.e. before the statement is executed).

        If the updater  is given  false, it calls  SQLFreeStmt with  the
        SQL_CLOSE option to close the cursor. (However, note that if  an
        explicit cursor name has been set, this remains associated  with
        hstmt even  though  there is  no  open cursor;  hence  the  base
        procedure will continue to return that name rather than false.)




----------------------
8  Submitting Requests
----------------------

sql_execute(hstmt)                                           [procedure]
sql_execute(hstmt, sql_string)
        In the first form, calls SQLExecute to execute an SQL  statement
        hstmt already prepared with  * sql_prepare. In the second  form,
        calls SQLExecDirect to execute the SQL statement sql_string.

        In both cases, the current  values of any parameters bound  with
        * sql_bind_parameter are  used for  the corresponding  parameter
        markers in the statement.


sql_native_sql(hdbc, sql_string) -> native_sql_string        [procedure]
        (Extension  Level  2)  Given  a  connection  hdbc,  returns  the
        driver's translation of the SQL statement string sql_string.




------------------------------------------
9  Retrieving Results & Result Information
------------------------------------------

sql_row_count(hstmt) -> row_count                            [procedure]
        Calls SQLRowCount to return  the number of  rows affected by  an
        UPDATE, INSERT or DELETE statement previously executed on  hstmt
        (or alternatively,  by  an SQL_UPDATE,  SQL_ADD,  or  SQL_DELETE
        operation with * sql_set_position).


sql_num_result_columns(hstmt) -> num_columns                 [procedure]
        Calls SQLNumResultCols to  return the number  of columns in  the
        result set associated with the (prepared or executed)  statement
        hstmt.

        0 is returned  if hstmt  is a  statement that  did not  create a
        result set.


sql_describe_column(hstmt, N) -> (name, sql_type, nullable)  [procedure]
        Returns the column name and LIB ODBC SQL type of the N-th column
        in  the  result   set  on  the   statement  hstmt  (by   calling
        SQLDescribeCol).

        The  nullable  result  is   one  of  the  values   SQL_NO_NULLS,
        SQL_NULLABLE     or     SQL_NULLABLE_UNKNOWN     (defined     in
        INCLUDE * ODBC).

        For integer types,  this procedure calls  * sql_column_attribute
        to determine the  Sql_COLUMN_UNSIGNED attribute  of the  column,
        which is then included in the sql_type result.


sql_column_attribute(hstmt, N, col_attr) -> value            [procedure]
        Calls SQLColAttributes  to  return  the  value  of  a  specified
        attribute of the N-th column in a result set.

        col_attr specifies the attribute,  and must be  one of the  Sql_
        descriptors listed below (and defined in INCLUDE * ODBC).

        The table below indicates  the data type  of the value  returned
        for each attribute. Note that type code means one of a  mutually
        exclusive set of  integer values  defined as  SQL_ constants  by
        INCLUDE  ODBC   (e.g.   Sql_COLUMN_NULLABLE   returns   one   of
        SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN).

        See SQLColAttributes for a description of each attribute.

            col_attr                        Type
            --------                        ----
            Sql_COLUMN_AUTO_INCREMENT       boolean
            Sql_COLUMN_CASE_SENSITIVE       boolean
            Sql_COLUMN_COUNT                integer
            Sql_COLUMN_DISPLAY_SIZE         integer
            Sql_COLUMN_LABEL                string
            Sql_COLUMN_LENGTH               integer
            Sql_COLUMN_MONEY                boolean
            Sql_COLUMN_NAME                 string
            Sql_COLUMN_NULLABLE             code
            Sql_COLUMN_OWNER_NAME           string
            Sql_COLUMN_PRECISION            integer
            Sql_COLUMN_QUALIFIER_NAME       string
            Sql_COLUMN_SCALE                integer
            Sql_COLUMN_SEARCHABLE           code
            Sql_COLUMN_TABLE_NAME           string
            Sql_COLUMN_TYPE                 integer
            Sql_COLUMN_TYPE_NAME            string
            Sql_COLUMN_UNSIGNED             boolean
            Sql_COLUMN_UPDATABLE            code


sql_bind_column(hstmt, N, DATA_BUFF)                         [procedure]
sql_bind_column(hstmt, N, DATA_BUFF, pop_type)
        Binds a buffer  for the  N-th column of  the result  set on  the
        statement hstmt (where N >= 0).

        DATA_BUFF specifies the buffer mechanism, and represents  either
        one or two arguments. These  are described fully in the  section
        Data Input/Output Modes above.

        pop_type is  an  optional  Pop  data type  for  the  column;  if
        supplied, it must be  one of the Sql_P_  types listed under  Pop
        Data Types above.  If pop_type  is omitted, it  defaults to  the
        default Pop type for  the SQL type of  the column (see SQL  Data
        Types). For N = 0  (i.e. binding the bookmark column),  pop_type
        defaults to Sql_P_bookmark.

        The forms

                sql_bind_column(hstmt, N, false);
                sql_bind_column(hstmt, "*", false);

        can also be used to unbind either a single column or all columns
        on hstmt.

        (N.B.  In  general,  sql_bind_column  does  not  actually   call
        SQLBindCol -- this is because sql_fetch uses SQLGetData to fetch
        the data  for  all  columns.  Hence any  errors  that  might  be
        expected from SQLBindCol  will instead  occur during  sql_fetch.
        The same is true for * sql_extended_fetch with a rowset size  of
        1; however, sql_extended_fetch with a rowset size greater than 1
        does call SQLBindCol.)


sql_fetch(hstmt) -> data_found                               [procedure]
        Calls SQLFetch to fetch the next row of data from the result set
        on the statement hstmt.

        If a row was fetched,  any columns bound with  * sql_bind_column
        have data transferred to their buffers (by calls to SQLGetData),
        and true is returned.

        false is returned when there are no rows left.


sql_app_result_set(hstmt, col_select, app_p)                 [procedure]
sql_app_result_set(hstmt, col_select, init_p, app_p)
        A convenience procedure that enables processing of a result  set
        without explicit  use  of  sql_bind_column  and  sql_fetch.  The
        procedure app_p is applied to every row of the result set on the
        statement hstmt.

        The  col_select  argument  selects  the  column  numbers  to  be
        processed,     which     can     range     between     1     and
        sql_num_result_columns(hstmt) inclusive. col_select is a list of
        column specifiers,

                [ col_spec1 col_spec2 ... col_specM ]

        where each  col_spec  is  either  a  col_num_spec  or  a  2-  or
        3-element full vector whose first element is a col_num_spec:

                { col_num_spec 1_or_2_bind_args }

        A col_num_spec is either

              # a single column number;

              # a 2-element list  [first_col last_col], meaning  columns
                first_col to last_col inclusive;

              # the word "*", meaning all remaining columns.

        (Note   that   column   numbers   outside   the   range   1   to
        sql_num_result_columns(hstmt) are ignored.)

        Every column  selected is  bound with  sql_bind_column. In  each
        case, the main_id  identifier for  the first  DATA_BUFF item  to
        sql_bind_column is generated automatically; if the col_spec that
        selected a column is a vector, the remaining one or two elements
        of  col_spec  are   passed  as  additional   arguments  to   the
        sql_bind_column  call  for  that  column.  These  elements  thus
        represent  the  mode  part  of  DATA_BUFF  and/or  the  pop_type
        arguments to sql_bind_column.

        For example, the col_select list

                [ 1 [3 5] {[7 10] ^Sql_P_int} {* ^Sql_P_string} ]

        selects columns 1,  3-5, 7-10  with pop_type  Sql_P_int, and  11
        onwards with pop_type Sql_P_string. (With all columns  returning
        data in Pop value mode.)

        sql_fetch is then called  to fetch each row  of the result  set.
        For each row,  app_p is  applied to the  set of  values for  the
        selected columns, together with the number of columns  selected.
        That is, if column numbers c1, ..., cN are selected, then  app_p
        is called as

            app_p(c1_val, c2_val, ..., cN_val, N);

        where each cI_val  is the  idval of the  main_id identifier  for
        that column.

        init_p Argument
        The optional  procedure  argument  init_p  allows  some  initial
        processing to be  done for  each selected  column. If  supplied,
        then before fetching any  rows, init_p is  called once for  each
        column c1,  ..., cN,  with hstmt  and the  column number  cI  as
        arguments:

                init_p(hstmt, cI) -> cI_results

        Any results returned by init_p for  column cI will be saved  and
        added as additional  (constant) arguments  following the  cI_val
        argument to every call of app_p.  That is, app_p will be  called
        as

            app_p(c1_val, c1_results, c2_val, c2_results, ...,
                                        cN_val, cN_results, nargs);

        where nargs is the total number of arguments.

        In addition, init_p is called an extra (N+1)-th time with  false
        for the column number (which call must not return any  results).
        This allows any final processing  to take place before  fetching
        the row data.


sql_extended_fetch(hstmt, fetch_type, row_num,               [procedure]
                        row_status_vec)  -> nrows_or_false
        (Extension Level 2)  Calls SQLExtendedFetch  to fetch  specified
        row(s) from the result set on the statement hstmt.

        The number of rows to be fetched is called the rowset size,  and
        is determined by the * sql_statement_option Sql_ROWSET_SIZE.

        Binding Buffers
        For each row fetched,  any columns bound with  * sql_bind_column
        have data transferred to  their buffers. If  the rowset size  is
        greater than 1, the DATA_BUFF arguments to sql_bind_column  must
        have supplied  full vectors  of appropriate  length rather  than
        identifiers -- see Extended Fetch and Update above.

        With a  rowset  size  of 1,  sql_extended_fetch  uses  the  same
        mechanism as  sql_fetch  for fetching  data  (i.e.  SQLGetData).
        However, with a rowset  size greater than  1, this mechanism  is
        problematical  and   so   (currently),   the   first   call   of
        sql_extended_fetch on an hstmt will cause all columns to  become
        bound  with   SQLBindCol   instead.  The   latter   necessitates
        allocating an internal buffer of sufficient size to hold all the
        data for each column, and forces sql_extended_fetch to  impose a
        limit on columns with LONG data types (i.e. Sql_LONGVARCHAR  and
        Sql_LONGVARBINARY). This  limit  is  specified  by  the  special
        * sql_statement_option  Sql_LONG_DATA_MAX,  and  represents  the
        maximum number of bytes that should be allowed for a LONG column
        of data  in a  single row.  Sql_LONG_DATA_MAX defaults  to  2047
        bytes.

        (Note: The row-wise binding facility of SQLExtendedFetch is  not
        supported by sql_extended_fetch.)

        fetch_type and row_num Arguments
        The position  of the  rowset fetched  within the  result set  is
        determined by  the  fetch_type  argument, either  alone,  or  in
        conjunction with  the current  cursor  position or  the  row_num
        argument, as shown below. (After a rowset is fetched, the cursor
        is positioned on the first row of the rowset.)

            fetch_type              Action
            ----------              ------
            SQL_FETCH_NEXT          Fetches  the  next  rowset.  If  the
                                    cursor  is  positioned  before   the
                                    start  of   the   result   set   (as
                                    initially),  this  is  the  same  as
                                    SQL_FETCH_FIRST.

            SQL_FETCH_PRIOR         Fetches the previous rowset. If  the
                                    cursor is positioned  after the  end
                                    of the result set, this is the  same
                                    as SQL_FETCH_LAST.

            SQL_FETCH_RELATIVE      Fetches the rowset row_num rows from
                                    the start of the current rowset;  if
                                    row_num is 0, the current rowset  is
                                    re-fetched.   If   the   cursor   is
                                    positioned before the  start of  the
                                    result set  and row_num  is  greater
                                    than  0,   or  if   the  cursor   is
                                    positioned  after  the  end  of  the
                                    result set and row_num is less  than
                                    0,   this    is    the    same    as
                                    SQL_FETCH_ABSOLUTE.

            SQL_FETCH_FIRST         Fetches  the  first  rowset  in  the
                                    result set.

            SQL_FETCH_LAST          Fetches the last complete rowset  in
                                    the result set.

            SQL_FETCH_ABSOLUTE      If  row_num  is   greater  than   0,
                                    fetches the rowset  starting at  row
                                    row_num; if row_num equals 0,  false
                                    is  returned  (and  the  cursor   is
                                    positioned before the  start of  the
                                    result set); if row_num is less than
                                    0, fetches  the rowset  starting  at
                                    row L+row_num+1, where L is the last
                                    row in the result set.

            SQL_FETCH_BOOKMARK      Fetches the rowset starting with the
                                    row whose bookmark is row_num.

        The row_num argument is ignored  for those values of  fetch_type
        that do  not require  it, and  may be  omitted in  these  cases;
        fetch_type itself may  be omitted (together  with row_num)  when
        the fetch type required is SQL_FETCH_NEXT.

        row_status_vec Argument
        The row_status_vec argument is optional; if supplied, it must be
        a full vector  of length  greater than  or equal  to the  rowset
        size. The elements  of this vector  are then set  to one of  the
        following integer status values for each row fetched:

                SQL_ROW_SUCCESS
                SQL_ROW_DELETED
                SQL_ROW_UPDATED
                SQL_ROW_ADDED
                SQL_ROW_ERROR

        Any remaining elements of row_status_vec for unfetched rows  (up
        to the rowset size) are  set to SQL_ROW_NOROW. (As mentioned  in
        Extended Fetch and Update above, rows with status SQL_ROW_NOROW,
        SQL_ROW_DELETED or  SQL_ROW_ERROR  have  their  main_id/main_vec
        column buffer entries set to termin.)

        Note that  row_status_vec  is saved  inside  hstmt so  that  its
        elements   may   be   modified   by   a   subsequent   call   to
        * sql_set_position.

        Result
        sql_extended_fetch returns the actual number of rows fetched, or
        false at end-of-stream in either direction.


sql_set_position(hstmt, row_num, operation, lock)            [procedure]
        (Extension Level 2) Following a call to * sql_extended_fetch  to
        fetch a rowset from  the statement hstmt, sql_set_position  sets
        the cursor position within the rowset, and allows an application
        to refresh,  update, delete  or add  data to  the rowset.  (This
        procedure calls SQLSetPos.)

        The row_num argument specifies the row number within the  rowset
        on which to  perform the  operation, or  is 0  if the  operation
        should be performed on  all rows in the  rowset (0 is not  valid
        for operation = SQL_POSITION).  Except for operation =  SQL_ADD,
        row_num must be less than or equal to the rowset size.

        The operation argument specifies the operation to be  performed,
        as follows:

            operation       Action
            ---------       ------
            SQL_POSITION    Sets the cursor on row number row_num.

            SQL_REFRESH     If row_num is  nonzero, sets  the cursor  on
                            row number row_num, and re-fetches the  data
                            for that row;  if row_num  is 0,  re-fetches
                            the data  for all  rows in  the rowset  (and
                            leaves the cursor position unchanged).

            SQL_UPDATE      If row_num is  nonzero, sets  the cursor  on
                            row number row_num, and then updates the row
                            from the column  buffers; if  row_num is  0,
                            updates all rows in  the rowset (and  leaves
                            the cursor  position unchanged).  Note  that
                            columns   whose   main_id/main_vec    buffer
                            entries for  the updated  row(s) are  termin
                            will be  ignored  (see  Extended  Fetch  and
                            Update above).

            SQL_DELETE      If row_num is  nonzero, sets  the cursor  on
                            row number  row_num,  and then  deletes  the
                            underlying row; if row_num is 0, deletes all
                            rows in the  rowset (and  leaves the  cursor
                            position unchanged).

            SQL_ADD         If row_num  is nonzero,  adds a  new row  of
                            data to the  data source,  using the  column
                            buffer entries  for  row_num (which  may  be
                            greater than the rowset size, providing  all
                            main_vec  buffers   have   a   corresponding
                            element). If row_num is 0, adds  rowset-size
                            new  rows.  Unbound   columns  (or   columns
                            containing  termin  for  a  row)  will   use
                            default or NULL values in the new row(s).

        The operation argument may be omitted provided the lock argument
        is also; in this case,  operation defaults to SQL_POSITION  (and
        lock to SQL_LOCK_NO_CHANGE).

        Note that if a row_status_vec was supplied to the preceding call
        of sql_extended_fetch,  all operations  except SQL_POSITION  may
        modify the elements of row_status_vec to reflect the new  status
        of row(s) affected by the operation.

        The lock argument is  optional; if supplied, it  must be one  of
        SQL_LOCK_NO_CHANGE   (the   default),   SQL_LOCK_EXCLUSIVE    or
        SQL_LOCK_UNLOCK. See SQLSetPos for more details.




----------------------------------------
10  Data Source System Table Information
----------------------------------------

sql_select_columns(hstmt, tab_qual, tab_owner, tab_name,     [procedure]
                                                col_name)
        Calls SQLColumns to create a  result set on the statement  hstmt
        describing the columns in specified tables on the data source.

        tab_qual, tab_owner, tab_name and col_name are respectively  the
        table qualifier name, table owner  name, table name, and  column
        name arguments to SQLColumns, and may each be a string or  false
        (the latter meaning pass a NULL pointer for the argument).

        See SQLColumns for more details.


sql_select_special_columns(hstmt, col_type, tab_qual,        [procedure]
                    tab_owner, tab_name, scope, nullable)
        Calls SQLSpecialColumns to create a result set on the  statement
        hstmt describing special columns in specified tables on the data
        source.

        col_type must be either SQL_BEST_ROWID or SQL_ROWVER.

        tab_qual, tab_owner  and  tab_name are  respectively  the  table
        qualifier name, table  owner name, and  table name arguments  to
        SQLSpecialColumns, and may each be a string or false (the latter
        meaning pass a NULL pointer for the argument).

        scope  is  one  of  SQL_SCOPE_CURROW,  SQL_SCOPE_TRANSACTION  or
        SQL_SCOPE_SESSION;   nullable   is   either   SQL_NO_NULLS    or
        SQL_NULLABLE.

        See SQLSpecialColumns for more details.


sql_select_statistics(hstmt, tab_qual, tab_owner, tab_name,  [procedure]
                                        unique, accuracy)
        Calls SQLStatistics  to create  a result  set on  the  statement
        hstmt describing statistics  and indexes for  a single table  on
        the data source.

        tab_qual, tab_owner,  and tab_name  are respectively  the  table
        qualifier name, table  owner name, and  table name arguments  to
        SQLStatistics. tab_qual and tab_owner may  be a string or  false
        (the latter  meaning  pass a  NULL  pointer for  the  argument);
        tab_name must be string.

        unique is either SQL_INDEX_UNIQUE or SQL_INDEX_ALL; accuracy  is
        either SQL_ENSURE or SQL_QUICK.

        See SQLStatistics for more details.


sql_select_tables(hstmt, tab_qual, tab_owner, tab_name,      [procedure]
                                                tab_type)
        Calls SQLTables to create  a result set  on the statement  hstmt
        listing the tables available on the data source.

        tab_qual, tab_owner, tab_name and tab_type are respectively  the
        table qualifier name,  table owner name,  table name, and  table
        type arguments to SQLTables, and may  each be a string or  false
        (the latter meaning pass a NULL pointer for the argument).

        See SQLTables for more details.


sql_select_column_privileges(hstmt, tab_qual, tab_owner,    [procedure]
                                    tab_name, col_name)
        (Extension Level 2) Calls SQLColumnPrivileges to create a result
        set on the statement hstmt describing the associated  privileges
        of columns in specified tables on the data source.

        tab_qual, tab_owner, tab_name and col_name are respectively  the
        table qualifier name, table owner  name, table name, and  column
        name arguments to SQLColumnPrivileges, and may each be a  string
        or false  (the  latter  meaning  pass a  NULL  pointer  for  the
        argument).

        See SQLColumnPrivileges for more details.


sql_select_table_privileges(hstmt, tab_qual, tab_owner,      [procedure]
                                                tab_name)
        (Extension Level 2) Calls SQLTablePrivileges to create a  result
        set on  the  statement hstmt  describing  privilege  information
        about tables on the data source.

        tab_qual, tab_owner  and  tab_name are  respectively  the  table
        qualifier name, table  owner name  and table  name arguments  to
        SQLTablePrivileges, and  may  each be  a  string or  false  (the
        latter meaning pass a NULL pointer for the argument).

        See SQLTablePrivileges for more details.


sql_select_primary_keys(hstmt, tab_qual, tab_owner,          [procedure]
                                                tab_name)
        (Extension Level 2) Calls SQLPrimaryKeys to create a result  set
        on the statement  hstmt listing the  column names that  comprise
        the primary key for a specified table.

        tab_qual, tab_owner,  and tab_name  are respectively  the  table
        qualifier name, table  owner name, and  table name arguments  to
        SQLPrimaryKeys . tab_qual and tab_owner may be a string or false
        (the latter  meaning  pass a  NULL  pointer for  the  argument);
        tab_name must be string.

        See SQLPrimaryKeys for more details.


sql_select_foreign_keys(hstmt,                               [procedure]
                        pktab_qual, pktab_owner, pktab_name,
                        fktab_qual, fktab_owner, fktab_name)
        (Extension Level 2) Calls SQLForeignKeys to create a result  set
        on the  statement  hstmt listing  foreign  keys in  a  specified
        table.

        pktab_qual, pktab_owner  and  pktab_name  are  respectively  the
        primary key table  qualifier name,  table owner  name and  table
        name arguments  to SQLForeignKeys;  fktab_qual, fktab_owner  and
        fktab_name are  respectively  the foreign  key  table  qualifier
        name,  table   owner   name   and  table   name   arguments   to
        SQLForeignKeys.

        All these arguments may be a string or false (the latter meaning
        pass a  NULL  pointer  for the  argument),  except  that  either
        pktab_name or fktab_name (or both) must be a string.

        See SQLForeignKeys for more details.




----------------------------------------
11  Terminating Statements & Connections
----------------------------------------

sql_transact(hdbc)                                           [procedure]
sql_transact(hdbc, commit)
        Calls SQLTransact to commit or rollback all active operations on
        all statements associated with the connection hdbc.

        The optional boolean argument commit  is true for commit,  false
        for rollback, and defaults to true if omitted.

        The form

                sql_transact(false, commit);

        may also be used to  perform a commit/rollback operation on  all
        current connections.

        Note that  the * sql_connect_option  SQL_AUTOCOMMIT is  true  by
        default on any  connection, and  causes all  transactions to  be
        committed automatically. See SQLTransact for further details.


sql_free_statement(hstmt)                                    [procedure]
        Calls  SQLFreeStmt  (with  operation   SQL_DROP)  to  free   the
        statement hstmt  and  release all  associated  resources.  (This
        procedure is the * sys_process_destroy_action of every hstmt.)


sql_disconnect(hdbc)                                         [procedure]
        Calls SQLDisconnect to close the connection hdbc and release all
        associated     resources.     (This     procedure     is     the
        * sys_process_destroy_action of every hdbc.)




-------------------------------------
12  Asynchronous Statement Processing
-------------------------------------

Providing a given  driver supports  it, the  Sql_ASYNC_ENABLE option  to
* sql_statement_option enables  processing  on  a  statement  to  happen
asynchronously.

In this mode, calls to certain ODBC C functions (such as SQLExecute  and
SQLFetch) initiate  an operation  on  a statement  and then  return  the
status code  SQL_STILL_EXECUTING.  The  function  must  then  be  called
repeatedly to  determine whether  processing  has finished  (i.e.  until
something other than SQL_STILL_EXECUTING is returned).

The corresponding LIB ODBC procedures handle this by repeatedly  calling
the underlying  C function  in a  loop, with  a 'wait'  procedure  being
called each time the function returns SQL_STILL_EXECUTING.

The wait procedure used is the value of the Sql_ASYNC_ENABLE option  for
the hstmt.  If true  is  assigned to  the  option value,  the  procedure
defaults to syssleep(%1%), but any suitable procedure can be used.

In particular,  either  an individual  LIB  ODBC procedure  or  a  whole
application can be  run as a  process (see REF * PROCESS),  with a  wait
procedure that suspends the process. A timer can then resume the process
at appropriate intervals, or (more efficiently), use  sql_statement_busy
to test  if the  statement has  finished executing  before resuming  the
process.


sql_statement_busy(hstmt) -> busy                            [procedure]
false -> sql_statement_busy(hstmt)
        The base procedure returns true if the statement hstmt is  busy,
        i.e. has an asynchronous operation  still in progress. false  is
        returned otherwise.

        The  updater  is  an  interface  to  SQLCancel,  and  allows  an
        asynchronous operation  on hstmt  to be  cancelled by  assigning
        false (any other value is ignored).


The LIB ODBC procedures that can  call a wait procedure if  asynchronous
processing has been enabled on their hstmt argument are listed below.

    * sql_app_result_set
    * sql_column_attribute
    * sql_describe_column
    * sql_describe_parameter
    * sql_execute
    * sql_extended_fetch
    * sql_fetch
    * sql_num_parameters
    * sql_num_result_columns
    * sql_prepare
    * sql_select_column_privileges
    * sql_select_columns
    * sql_select_foreign_keys
    * sql_select_primary_keys
    * sql_select_special_columns
    * sql_select_statistics
    * sql_select_table_privileges
    * sql_select_tables
    * sql_select_types
    * sql_set_position




------------
13  Examples
------------

The following two examples are Pop-11 translations of the the C examples
given in Chapter 10 of ODBC SDK Programmer's Reference.


13.1  Static SQL
----------------

include odbc.ph;

define example1(conn_str);
    lvars   ID, Name, hdbc, hstmt;

    ;;; Connect to conn_str (which may be a string in DriverConnect
    ;;; format, or a list [^server ^user ^password] etc).

    sql_connect(conn_str) -> hdbc;

    ;;; allocate a statement handle

    sql_alloc_statement(hdbc) -> hstmt;

    ;;; EXEC SQL CREATE TABLE NAMEID (ID integer, NAME varchar(50));
    ;;; Execute the SQL statement

    sql_execute(hstmt,
                  'CREATE TABLE NAMEID (ID INTEGER, NAME VARCHAR(50))');

    ;;; EXEC SQL COMMIT WORK;
    ;;; Commit the table creation.
    ;;; (Note that the default transaction mode is auto-commit
    ;;; and sql_transact has no effect.)

    sql_transact(hdbc);

    ;;; EXEC SQL INSERT INTO NAMEID VALUES (:id, :name);
    ;;; Show the use of the sql_prepare/sql_execute method:
    ;;; Prepare the insertion and bind parameters;
    ;;; Assign parameter values;

    sql_prepare(hstmt, 'INSERT INTO NAMEID VALUES (?, ?)');
    sql_bind_parameter(hstmt, 1, ident ID,   Sql_INTEGER);
    sql_bind_parameter(hstmt, 2, ident Name, Sql_VARCHAR(50));

    ;;; Execute the insertions.

    (500, 'Babbage') -> (ID, Name);
    sql_execute(hstmt);
    (600, 'Turing') -> (ID, Name);
    sql_execute(hstmt);

    ;;; EXEC SQL COMMIT WORK;
    ;;; Commit the insertions

    sql_transact(hdbc);

    ;;; EXEC SQL DECLARE c1 CURSOR FOR SELECT ID, NAME FROM NAMEID;
    ;;; EXEC SQL OPEN c1;
    ;;; Show the use of the sql_execute direct method.
    ;;; Execute the selection.
    ;;; (Note that the application does not declare a cursor name.)

    sql_execute(hstmt, 'SELECT ID, NAME FROM NAMEID');

    ;;; EXEC SQL FETCH c1 INTO :id, :name;
    ;;; Bind the columns of the result set with sql_bind_column.
    ;;; Fetch and print all rows.

    sql_bind_column(hstmt, 1, ident ID);
    sql_bind_column(hstmt, 2, ident Name);

    while sql_fetch(hstmt) do
        [ID ^ID Name ^Name] ==>
    endwhile;

    sql_transact(hdbc);
    sql_disconnect(hdbc);
enddefine;


13.2  Ad Hoc Query
------------------

include odbc.ph;

define example2(conn_str, sql_string);
    lvars   nresultcols, rowcount, N, id, name, dsize, col_list, col,
            hdbc, hstmt;

    sql_connect(conn_str) -> hdbc;
    sql_alloc_statement(hdbc) -> hstmt;

    ;;; Execute the given SQL statement

    sql_execute(hstmt, sql_string);

    ;;; See what kind of statement it was. If there are no result
    ;;; columns, the statement is not a SELECT. If the number of
    ;;; affected rows is greater than 0, the statement was probably an
    ;;; UPDATE, INSERT or DELETE, so print the number of affected rows.
    ;;; If the  number of affected rows is 0, print that the operation
    ;;; was successful and commit it.

    sql_num_result_columns(hstmt) -> nresultcols;

    if nresultcols == 0 then
        sql_row_count(hstmt) -> rowcount;
        if rowcount == 0 then
            printf('%p rows affected.\n', [^rowcount])
        else
            printf('Operation successful.\n')
        endif;

    ;;; Otherwise, use sql_column_attribute to get and display the
    ;;; column names of the result set, and also to find the display
    ;;; size needed for each column. Then bind each column (specifying
    ;;; that all data should be converted to string format), and make a
    ;;; list of columns in which each element contains the id and the
    ;;; display size for that column. Finally, fetch and print each row.

    else
        [%  for N to nresultcols do
                sql_column_attribute(hstmt, N, Sql_COLUMN_NAME) -> name;
                sql_column_attribute(hstmt, N, Sql_COLUMN_DISPLAY_SIZE)
                                                    -> dsize;
                max(dsize, datalength(name)) + 1 -> dsize;
                pr_field(name, dsize, false, `\s`);
                consident(0, 0, "lex") -> id;
                sql_bind_column(hstmt, N, id, Sql_P_string);
                [^id ^dsize]
            endfor
        %] -> col_list;
        cucharout(`\n`);

        while sql_fetch(hstmt) do
            for col in col_list do
                dl(col) -> (id, dsize);
                pr_field(idval(id), dsize, false, `\s`);
            endfor;
            cucharout(`\n`)
        endwhile
    endif;

    sql_transact(hdbc);
    sql_disconnect(hdbc)
enddefine;


...  Using sql_app_result_set
-----------------------------
Another version of example2, but using * sql_app_result_set.


define example2(conn_str, sql_string);
    lvars   nresultcols, rowcount, hdbc, hstmt;

    sql_connect(conn_str) -> hdbc;
    sql_alloc_statement(hdbc) -> hstmt;
    sql_execute(hstmt, sql_string);
    sql_num_result_columns(hstmt) -> nresultcols;

    if nresultcols == 0 then
        sql_row_count(hstmt) -> rowcount;
        if rowcount == 0 then
            printf('%p rows affected.\n', [^rowcount])
        else
            printf('Operation successful.\n')
        endif;

    else
        define init_col(hstmt, N);
            lvars name, dsize;
            if N then
                sql_column_attribute(hstmt, N, Sql_COLUMN_NAME) -> name;
                sql_column_attribute(hstmt, N, Sql_COLUMN_DISPLAY_SIZE)
                                                -> dsize;
                max(dsize, datalength(name)) + 1 -> dsize;
                pr_field(name, dsize, false, `\s`);
                dsize;      ;;; return dsize
            else
                cucharout(`\n`)
            endif
        enddefine;

        ;;; For each row, this procedure will be given nresultcols * 2
        ;;; arguments, the column value and dsize for each column
        define pr_col(nargs);
            lvars i;
            for i from nargs by -2 to 2 do
                pr_field(subscr_stack(i), subscr_stack(i), false, `\s`)
            endfor;
            erasenum(nargs);
            cucharout(`\n`)
        enddefine;

        sql_app_result_set(hstmt, [{* ^Sql_P_string}], init_col,
                                                            pr_col);
    endif;

    sql_transact(hdbc);
    sql_disconnect(hdbc)
enddefine;




--- C.all/ref/odbc
--- Copyright University of Sussex 1996. All rights reserved.
