Contents:
The Eloquence Odbc.DLL requires the following components to be installed:
This is a component which manages available ODBC data sources on a particular system.
On Windows, this is typically part of the operating system or installed with applications like Microsoft Office or the Microsoft SQL Server. Data sources are managed with the ODBC Data Sources applet in the Windows Control Panel. The Windows ODBC components (driver manager and commonly used ODBC driver for Microsoft Access etc.) are available for download at http://www.microsoft.com/data/.
On HP-UX and Linux, both the unixODBC and the iODBC open source ODBC driver managers are supported. However, using the iODBC is not recommended as it is no longer maintained.
The Eloquence Odbc.DLL on HP-UX and Linux expects to find the libodbc shared library (HP-UX: libodbc.sl.1, Linux: libodbc.so.1). If the library cannot be found because the unixODBC is installed in a nonstandard location, either the LD_LIBRARY_PATH environment variable may be set (for example LD_LIBRARY_PATH=/opt/unixODBC/lib) or a symbolic link may be created in /usr/lib to refer to the libodbc shared library. On Linux, ldconfig may be used to add the unixODBC lib directory to the dynamic linker's search path (see man ldconfig).
This is a database-specific component which interfaces the particular database you intend to use.
Examples for ODBC drivers are:
Drivers for other databases are either included with the particular database product or available as an option.
Before ODBC can be used, the appropriate data source(s) must be defined. A data source definition specifies:
Except for the name of the data source and the driver these parameters depend on the requirements of the particular database and must be correctly specified according to the database vendor's documentation.
After appropriate configuration, the data source(s) can be accessed with the DSN (data source name) as shown in the examples below.
On Windows, the ODBC Data Sources applet in the Windows Control Panel is used for data source administration. It supports three different types of data sources:
The Eloquence Odbc.DLL supports System and User data sources. File data sources cannot be used.
On HP-UX or Linux, the unixODBC driver manager uses two configuration files which are typically located either in the /etc or in the /etc/unixODBC or in the /etc/opt/unixODBC directory:
This configures the installed ODBC drivers. A driver's section starts with the driver name in square brackets, followed by a description and the location of the driver and setup shared libraries. The setup shared library is used with the unixODBC configuration GUI (if not supported by a driver, a default setup library can be used, as in the SQL/R example below). The FileUsage entry is used with the configuration GUI and should be set to 1.
For example:
[MySQL] Description = MySQL ODBC Driver Driver = /usr/lib/libmyodbc.so Setup = /usr/lib/libodbcmyS.so FileUsage = 1 [PostgreSQL] Description = PostgreSQL ODBC Driver Driver = /usr/lib/libodbcpsql.so Setup = /usr/lib/libodbcpsqlS.so FileUsage = 1 [SQL/R] Description = SQL/R ODBC Driver Driver = /opt/sqlr2/lib/libsqlrodbc.so Setup = /usr/lib/libodbcdrvcfg1S.so FileUsage = 1
This configures the available data sources. A data source section starts with the DSN in square brackets, followed by a description and a reference to the associated driver configured in the odbcinst.ini file. Driver specific entries may be added as in the example below (please refer to the database vendor's documentation).
The unixODBC driver manager first tries to locate a data source in a file named .odbc.ini in the current user's home directory (similar to the User data source concept on Windows). If this file does not exist or does not contain the specified data source, the global odbc.ini is searched (similar to the System data source concept on Windows).
Please note: Early unixODBC versions before 2.2 (a) created an empty .odbc.ini file in the current user's home directory if it did not yet exist and then (b) did not fallback to the global odbc.ini file. The result was that a data source could not be accessed even if it was configured correctly. To solve this issue, either configure any data sources in the user's .odbc.ini file or create a symbolic link named .odbc.ini in the current user's home directory to refer to the global odbc.ini file.
For example:
[MySQL-test] Description = A data source to test the MySQL ODBC driver Driver = MySQL Trace = Off TraceFile = /tmp/mysql-trace.log DATABASE = sample SERVER = 192.168.44.55 USER = jdoe PASSWORD = PORT = 3306 [PostgreSQL-test] Description = A data source to test the PostgreSQL ODBC driver Driver = PostgreSQL Trace = Off TraceFile = /tmp/postgresql-trace.log Database = sample Servername = 192.168.44.66 UserName = jdoe Password = Port = 5432 Protocol = 6.4 ReadOnly = No RowVersioning = No ShowSystemTables = No ShowOidColumn = No FakeOidIndex = No ConnSettings = [SQL/R-test] Description = A data source to test the SQL/R ODBC driver Driver = SQL/R Server = 192.168.44.77 Service = 8003 User = public Quoting = 0 Bulkfetch = 1
Please note: The SQL/R ODBC driver expects to find the data source either in the user's .odbc.ini file or in /etc/odbc.ini, otherwise it does not honor the Server, Service, User, Quoting or Bulkfetch options. If the global odbc.ini file is not located in /etc you could either symlink it to /etc/odbc.ini or set the ODBCINI environment variable, for example: ODBCINI=/etc/unixODBC/odbc.ini.
The Odbc.DLL must be loaded before it can be used in a program:
LOAD DLL Odbc,1024
This loads the Odbc.DLL from its default location and establishes a communication buffer of 1024 bytes. For details about the Eloquence LOAD DLL statement please refer to the Eloquence documentation.
The DEL DLL statement may be used to unload the DLL:
DEL DLL Odbc
The following procedures are available to return information on the Odbc.DLL or enable logging.
ODBC connections and statements
The supported options are driver specific. The following options are defined by the ODBC standard:
101 | ACCESS_MODE |
102 | AUTOCOMMIT |
103 | LOGIN_TIMEOUT |
104 | OPT_TRACE |
105 | OPT_TRACEFILE |
106 | TRANSLATE_DLL |
107 | TRANSLATE_OPTION |
108 | TXN_ISOLATION |
109 | CURRENT_QUALIFIER |
110 | ODBC_CURSORS |
111 | QUIET_MODE |
112 | PACKET_SIZE |
Parameters are embedded into the SQL statement by means of question mark characters. Example:
SELECT * FROM CUSTOMERS WHERE MATCHCODE>=? AND MATCHCODE<=?This embeds two parameters: #1 for the lower and #2 for the upper limit of the matchcodes to be queried. They are preset with the NULL value.
The values of these parameters can either be specified as arguments to the Execute call or explicitly set with SetParam.
The Owner argument can be used to limit information to a particular table owner (normally a database). With the Name argument a specific table name can be addressed. Both may contain or entirely consist of the % wildcard character.
Examples:
! Create a list of all tables in all databases CALL DLL Odbc("Tables",Conn_id,"","","","",Stmt_id) ! Create a list of all tables in the SAMPLE database CALL DLL Odbc("Tables",Conn_id,"","SAMPLE","","",Stmt_id) ! Create a list of all CUSTOMERS tables in all databases CALL DLL Odbc("Tables",Conn_id,"","","CUSTOMERS","",Stmt_id) ! Create a list containing the CUSTOMERS table in the SAMPLE database CALL DLL Odbc("Tables",Conn_id,"","SAMPLE","CUSTOMERS","",Stmt_id) ! Special enumeration mode: create a list of all databases CALL DLL Odbc("Tables",Conn_id,"","%","","",Stmt_id)
The resulting statement's columns are:
TABLE_QUALIFIER | - | Table qualifier (empty string if not supported by the driver) |
TABLE_OWNER | - | Owner of the table (aka. database) |
TABLE_NAME | - | Name of the table |
TABLE_TYPE | - | Usually TABLE or VIEW or which types the driver supports |
REMARKS | - | eg. usage notes for this table |
The Owner and Name arguments can be used to limit information to a particular table owner (normally a database) and/or table. With the Column argument a specific column name can be addressed. All arguments may contain or entirely consist of the % wildcard character.
Examples:
! Create a list of all columns in all tables in all databases CALL DLL Odbc("Columns",Conn_id,"","","","",Stmt_id) ! Create a list of all columns in all tables in the SAMPLE database CALL DLL Odbc("Columns",Conn_id,"","SAMPLE","","",Stmt_id) ! Create a list of all columns in all CUSTOMERS tables in all databases CALL DLL Odbc("Columns",Conn_id,"","","CUSTOMERS","",Stmt_id) ! Create a list of all columns in the CUSTOMERS table in the SAMPLE database CALL DLL Odbc("Columns",Conn_id,"","SAMPLE","CUSTOMERS","",Stmt_id) ! Create a list of all CUSTNO columns in all tables in all databases CALL DLL Odbc("Columns",Conn_id,"","","","CUSTNO",Stmt_id) ! Create a list of all CUSTNO columns in all tables in the SAMPLE database CALL DLL Odbc("Columns",Conn_id,"","SAMPLE","","CUSTNO",Stmt_id) ! Create a list of all CUSTNO columns in all CUSTOMERS tables in all databases CALL DLL Odbc("Columns",Conn_id,"","","CUSTOMERS","CUSTNO",Stmt_id) ! Create a list containing the CUSTNO column in the CUSTOMERS table in the SAMPLE database CALL DLL Odbc("Columns",Conn_id,"","SAMPLE","CUSTOMERS","CUSTNO",Stmt_id)
The resulting statement's columns are:
TABLE_QUALIFIER | - | Table qualifier (empty string if not supported by the driver) |
TABLE_OWNER | - | Owner of the table containing the column (aka. database) |
TABLE_NAME | - | Name of the table containing the column |
COLUMN_NAME | - | Name of the column |
DATA_TYPE | - | ODBC SQL data type (numerically encoded) |
TYPE_NAME | - | ODBC SQL data type name |
PRECISION | - | Display size (width) of the column |
LENGTH | - | Required size in bytes to store the value (includes terminating null byte for string data) |
SCALE | - | Number of column decimals if applicable |
RADIX | - | Precision/scale unit (if 10 or NULL unit is 'digits', if 2 unit is 'bits') |
NULLABLE | - | Nonzero if the column is nullable |
REMARKS | - | eg. usage notes for this column |
Example:
INTEGER Conn_id,Stmt1,Stmt2 DIM Dsn$[256],Sql$[256] ! Load the ODBC module LOAD DLL Odbc,1024 ! ! Connect to ODBC data source named 'SAMPLE' ! authorize with Login$ and Password$ Login$="mike" Password$="secret" Dsn$="DSN=SAMPLE;UID="&Login$&";PWD="&Password$ CALL DLL Odbc("Connect",Dsn$,Conn_id) ! Execute SQL statement Sql$="SELECT * FROM CUSTOMERS" CALL DLL Odbc("ExecDirect",Conn_id,Sql$,Stmt1) ! Prepare another SQL statement with two embedded parameters Sql$="SELECT * FROM CUSTOMERS WHERE MATCHCODE>=? AND MATCHCODE<=?" CALL DLL Odbc("Prepare",Conn_id,Sql$,Stmt2)
Once a statment id has been returned by the Odbc.DLL the following procedures may be called.
Statement parameter values may be set by providing the appropriate number of arguments. They should match the required parameter's data type (see the GetParamType below). Alternatively, the SetParam procedure may be used to set parameter values before execution. In this case, Execute should be called without specifying any param values.
Example:
! Using the first SQL statement from the previous example ! ! Sequentially fetch rows CALL DLL Odbc("GetNumColumns",Stmt_id,Num_columns) LOOP CALL DLL Odbc("Fetch",Stmt1,Has_data) EXIT IF NOT Has_data FOR Col=1 TO Num_columns CALL DLL Odbc("GetData",Stmt1,Col,Buf$) PRINT Buf$;"|"; NEXT Col PRINT END WHILE ! Using the second SQL statement from the previous example ! ! Query matchcodes from A to E CALL DLL Odbc("Execute",Stmt2,"A","E") ! ! Fetch the data as shown above LOOP CALL DLL Odbc("Fetch",Stmt2,Has_data) EXIT IF NOT Has_data ... END LOOP ! Now query customer numbers F to M using SetParam CALL DLL Odbc("SetParam",Stmt2,1,"F") CALL DLL Odbc("SetParam",Stmt2,2,"M") CALL DLL Odbc("Execute",Stmt2) LOOP CALL DLL Odbc("Fetch",Stmt2,Has_data) EXIT IF NOT Has_data ... END LOOP
Using the XPACK format to retrieve data
As an option, the Fetch procedure may return the data in XPACK format. In this case, the variables are equivalent to the statement's result columns. For example, the statement
SELECT CUSTNO, NAME1 FROM CUSTOMERSwould use the variable names Custno and Name1.
If a column title contains space or dot characters, they are replaced by underscores in the resulting variable name.
If a column title however cannot be transferred into a valid variable name (for example MIN(ORDER_DATE)) a generic variable name is used, artificial such as Column_1.
Example:
! Execute SQL statement Sql$="SELECT CUSTNO,NAME1 FROM CUSTOMERS" CALL DLL Odbc("ExecDirect",Conn_id,Sql$,Stmt) ! Sequentially fetch rows LOOP CALL DLL Odbc("Fetch",Stmt,Has_data,Xbuf$) EXIT IF NOT Has_data XUNPACK Xbuf$ PRINT Custno$,Name1$ END LOOP
The following procedures are available to retrieve information or change the data type on a result column of a statement. Column numbering starts at 1.
Note: Date, time and timestamp columns are currently delivered as INTEGER values. This is subject to change.
Note: This function does not check if a conversion to the specified data type is possible. Specifying an improper data type will probably result in unexpected column data.
Example:
! Execute SQL statement Sql$="SELECT * FROM CUSTOMERS" CALL DLL Odbc("ExecDirect",Conn_id,Sql$,Stmt_id) ! Print column titles CALL DLL Odbc("GetNumColumns",Stmt_id,Num_columns) FOR Col=1 TO Num_columns CALL DLL Odbc("GetColumnTitle",Stmt_id,Col,Col_title$) PRINT Col_title$, NEXT Col PRINT
The following procedures are available to retrieve information on statement parameters. Parameter numbering starts at 1.
Note: Date, time and timestamp columns are currently expected to be passed as INTEGER values. This is subject to change.
The Eloquence Odbc.DLL introduces the following new error codes:
1110 |
Failed to allocate ODBC resource.
The ODBC driver manager could not be loaded or ran out of internal resources. |
---|---|
1111 |
Internal ODBC failure.
An internal problem has occurred with the ODBC driver manager or the data source. |
1112 |
Function sequence error.
A function sequence has been executed in a wrong order (eg. data has not yet been fetched). |
1113 |
Failed to connect.
The ODBC driver could not be loaded, the data source does not exist or the authorization has failed. |
1114 |
Failed to disconnect.
An internal problem has occurred while disconnecting. |
1115 |
Already connected.
Tried to connect while a connection is already present. |
1116 |
Not connected.
Tried to disconnect while no connection is present. |
1117 |
Failed to prepare statement.
An invalid SQL statement has been provided. |
1118 |
Failed to execute statement.
The provided SQL statement cannot be executed. |
1119 |
Statement has not yet been prepared.
The provided SQL statement must be prepared before it can be executed. |
1120 |
Statement has no result.
Tried to fetch data from a statement which does not have any result. |
1121 |
Failed to fetch next row of data.
An internal problem has occurred while fetching the next row of data. |
1122 |
Invalid column or parameter number.
An invalid column or parameter number has been provided. |
The GetError procedure may be used to obtain detailed ODBC error information.
Executing an ODBC operation can cause errors of varying complexity. The problem may be recognized at different functional layers such as the ODBC driver manager or the database server involved in the particular operation.
Therefore, a single ODBC operation may provide information about multiple errors. After an ODBC function has failed, repeated use of the GetError procedure will sequentially obtain all error information.
Each error return consists of a text message, the ODBC SQL error code (called 'SQL state' according to the X/Open and SQL Access Group SQL CAE specifications) and the native error code which was returned by the particular ODBC driver.
CALL DLL Odbc("GetError",Message$,Sql_state$,Native_code,Has_data)
Example:
ON ERROR GOTO Error ... Error:! OFF ERROR PRINT ERRM$ IF (ERRN>=1110) AND (ERRN<=1122) THEN Odbc_error PRINT ERRMSG$(ERRN) STOP ! ! ODBC.DLL specific error codes ! Odbc_error:! DIM Sql_msg$[256],Sql_state$[16] INTEGER Sql_native_code,Sql_has_data RESTORE Odbc_error REPEAT READ Err,Sql_msg$ UNTIL NOT Err OR (Err=ERRN) IF Err THEN PRINT Sql_msg$ LOOP CALL DLL Odbc("GetError",Sql_msg$,Sql_state$,Sql_native_code,Sql_has_data) EXIT IF NOT Sql_has_data PRINT "ODBC Error: ";Sql_msg$ PRINT "SQL State: ";Sql_state$;", Native code: ";Sql_native_code END LOOP STOP ! DATA 1110,"ODBC resource failure (ERR_ODBCRESOURCE)" DATA 1111,"ODBC internal failure (ERR_ODBCINTERNAL)" DATA 1112,"Invalid call sequence (ERR_SEQUENCE)" DATA 1113,"Connection failed (ERR_CONNECT)" DATA 1114,"Disconnect failed (ERR_DISCONNECT)" DATA 1115,"Already connected (ERR_CONNECTED)" DATA 1116,"Not connected (ERR_NOTCONNECTED)" DATA 1117,"Statement preparation failed (ERR_PREPARE)" DATA 1118,"Statement execution failed (ERR_EXECUTE)" DATA 1119,"Statement not prepared (ERR_NOTPREPARED)" DATA 1120,"Statement has no result (ERR_NORESULT)" DATA 1121,"Failed to fetch next row (ERR_FETCH)" DATA 1122,"Column/parameter number out of range (ERR_INVALIDCOLUMN)" DATA 0,"Unknown error code"
The following examples document how the Odbc.DLL could be used in a program.
The first example illustrates how to retrieve data using Prepare/Execute. It is installed as ODBC1.PROG in the Eloquence share/example installation subdirectory.
! RE-STORE "ODBC1,EXAMPLE" ! ! Eloquence ODBC DLL example program ! Retrieve data from the SAMPLE DSN using Prepare/Execute ! DIM Buf$[256],Sql_msg$[256],Sql_state$[16] INTEGER Conn,Stmt,Col,Num_cols,Row,Has_data,Sql_native_code,Nrows,Col_type,Col_prec,Col_scale ON ERROR GOTO Error IF BACKGROUND THEN PRINTER IS STDOUT ! ! Load the Eloquence Odbc.DLL and print version number ! PRINT LIN(1);"** Loading the Eloquence Odbc.DLL" LOAD DLL Odbc,1024 CALL DLL Odbc("Revision",Buf$) PRINT "Revision ";Buf$ ! ! The Eloquence Odbc.DLL can setup a debug log ! By default only critical messages are output to stderr ! ! CALL DLL Odbc("LogFile","odbcdll.log") ! CALL DLL Odbc("LogFlags","*2") ! ! Connect to the data source ! Buf$="DSN=SAMPLE" PRINT LIN(1);"** Connecting to the data source ";Buf$ CALL DLL Odbc("Connect",Buf$,Conn) ! ! The completed connection string (by the ODBC driver manager) CALL DLL Odbc("GetConnection",Conn,Buf$) PRINT "Connection #"&VAL$(Conn)&": "&Buf$ ! ! Prepare a SQL statement ! PRINT LIN(1);"** Preparing SQL statement" Buf$="SELECT * FROM CUSTOMERS WHERE MATCHCODE LIKE ? ORDER BY CUSTNO" CALL DLL Odbc("Prepare",Conn,Buf$,Stmt) PRINT "Statement #"&VAL$(Stmt)&": "&Buf$ ! ! The prepared statement has a result set ! PRINT LIN(1);"** Result set" CALL DLL Odbc("GetNumColumns",Stmt,Num_cols) FOR Col=1 TO Num_cols PRINT "Col";Col;": "; CALL DLL Odbc("GetColumnTitle",Stmt,Col,Buf$) PRINT Buf$&" ["; CALL DLL Odbc("GetColumnVarName",Stmt,Col,Buf$) PRINT Buf$&"]"; CALL DLL Odbc("GetColumnType",Stmt,Col,Col_type) PRINT " Type=";VAL$(Col_type); CALL DLL Odbc("GetColumnPrecision",Stmt,Col,Col_prec) PRINT ",Prec=";VAL$(Col_prec); CALL DLL Odbc("GetColumnScale",Stmt,Col,Col_scale) PRINT ",Scale=";VAL$(Col_scale) NEXT Col ! ! Execute the prepared statement ! PRINT LIN(1);"** Executing prepared statement" ! The Execute call is used to specify any parameters (positional) ! Parameter not specified is assumed NULL ! CALL DLL Odbc("Execute",Stmt,"KEL%") ! ! As an alternative, the SetParam call may be used. ! CALL DLL Odbc("SetParam",Stmt,1,"KEL%") ! CALL DLL Odbc("Execute",Stmt) ! ! For some calls, the server may already know the number of results ! If the value returned is -1 then it is unknown ! CALL DLL Odbc("RowCount",Stmt,Nrows) PRINT Nrows;"results available" ! ! Retrieve the data ! PRINT LIN(1);"** Fetching results" Row=0 LOOP CALL DLL Odbc("Fetch",Stmt,Has_data) EXIT IF NOT Has_data Row=Row+1 PRINT "[";Row;"] "; CALL DLL Odbc("GetData",Stmt,1,Buf$) PRINT " "&CHR$(34)&Buf$&CHR$(34); CALL DLL Odbc("GetData",Stmt,2,Buf$) PRINT " "&CHR$(34)&Buf$&CHR$(34); CALL DLL Odbc("GetData",Stmt,3,Buf$) PRINT " "&CHR$(34)&Buf$&CHR$(34); CALL DLL Odbc("GetData",Stmt,9,Turnover) PRINT Turnover END LOOP PRINT Row;"rows fetched" ! PRINT LIN(1);"** Disconnecting" CALL DLL Odbc("DropStatement",Stmt) CALL DLL Odbc("Disconnect",Conn) PRINT "done." STOP ! ! Catch program error ! Error:! OFF ERROR PRINT ERRM$ IF (ERRN>=1110) AND (ERRN<=1122) THEN Odbc_error PRINT ERRMSG$(ERRN) STOP ! ! ODBC.DLL specific error codes ! Odbc_error:! ! PRINT "Problem detected by Odbc.DLL" RESTORE Odbc_error REPEAT READ Err,Sql_msg$ UNTIL NOT Err OR (Err=ERRN) IF Err THEN PRINT Sql_msg$ LOOP CALL DLL Odbc("GetError",Sql_msg$,Sql_state$,Sql_native_code,Has_data) EXIT IF NOT Has_data PRINT "ODBC Error: ";Sql_msg$ PRINT "SQL State: ";Sql_state$;", Native code: ";Sql_native_code END LOOP STOP ! DATA 1110,"ODBC resource failure (ERR_ODBCRESOURCE)" DATA 1111,"ODBC internal failure (ERR_ODBCINTERNAL)" DATA 1112,"Invalid call sequence (ERR_SEQUENCE)" DATA 1113,"Connection failed (ERR_CONNECT)" DATA 1114,"Disconnect failed (ERR_DISCONNECT)" DATA 1115,"Already connected (ERR_CONNECTED)" DATA 1116,"Not connected (ERR_NOTCONNECTED)" DATA 1117,"Statement preparation failed (ERR_PREPARE)" DATA 1118,"Statement execution failed (ERR_EXECUTE)" DATA 1119,"Statement not prepared (ERR_NOTPREPARED)" DATA 1120,"Statement has no result (ERR_NORESULT)" DATA 1121,"Failed to fetch next row (ERR_FETCH)" DATA 1122,"Column/parameter number out of range (ERR_INVALIDCOLUMN)" DATA 0,"Unknown error code"
The second example illustrates how to retrieve data using XPACK.
It is installed as ODBC2.PROG in the Eloquence share/example
installation subdirectory.
! RE-STORE "ODBC2,EXAMPLE" ! ! Eloquence ODBC DLL example program ! Retrieve data from the SAMPLE DSN using XPACK ! DIM Buf$[256],Sql_msg$[256],Sql_state$[16],Xbuf$[1024] INTEGER Conn,Stmt,Col,Num_cols,Row,Has_data,Sql_native_code DIM Custno$[6],Matchcode$[10],Name1$[32] REAL Turnover ON ERROR GOTO Error IF BACKGROUND THEN PRINTER IS STDOUT ! ! Load the Eloquence Odbc.DLL and print version number ! PRINT LIN(1);"** Loading the Eloquence Odbc.DLL" LOAD DLL Odbc,1024 CALL DLL Odbc("Revision",Buf$) PRINT "Revision ";Buf$ ! ! Connect to the data source ! Buf$="DSN=SAMPLE" PRINT LIN(1);"** Connecting to the data source ";Buf$ CALL DLL Odbc("Connect",Buf$,Conn) ! ! The completed connection string (by the ODBC driver manager) CALL DLL Odbc("GetConnection",Conn,Buf$) PRINT "Connection #"&VAL$(Conn)&": "&Buf$ ! ! Execute a SQL statement ! PRINT LIN(1);"** Executing SQL statement" Buf$="SELECT CUSTNO,MATCHCODE,NAME1,TURNOVER__1 Turnover FROM CUSTOMERS WHERE MATCHCODE LIKE 'KEL%'" CALL DLL Odbc("ExecDirect",Conn,Buf$,Stmt) PRINT "Statement #"&VAL$(Stmt)&": "&Buf$ ! ! The prepared statement has a result set ! PRINT LIN(1);"** Result set" CALL DLL Odbc("GetNumColumns",Stmt,Num_cols) FOR Col=1 TO Num_cols PRINT "Col";Col;": "; CALL DLL Odbc("GetColumnTitle",Stmt,Col,Buf$) PRINT Buf$&" ["; CALL DLL Odbc("GetColumnVarName",Stmt,Col,Buf$) PRINT Buf$&"]" NEXT Col ! ! Retrieve the data ! PRINT LIN(1);"** Fetching results" Row=0 LOOP ! The Fetch CALL returns all columns in the Xbuf$ variable in XPACK format CALL DLL Odbc("Fetch",Stmt,Has_data,Xbuf$) EXIT IF NOT Has_data Row=Row+1 ! Unpack the result variables XUNPACK Xbuf$ ! As an alternative the XUNPACK may also specify a subset of variables ! XUNPACK Buf$ FROM Custno$,Matchcode$,Name1$,Turnover PRINT "[";Row;"]"; PRINT " "&CHR$(34)&Custno$&CHR$(34); PRINT " "&CHR$(34)&Matchcode$&CHR$(34); PRINT " "&CHR$(34)&Name1$&CHR$(34); PRINT Turnover END LOOP PRINT Row;"rows fetched" ! PRINT LIN(1);"** Disconnecting" CALL DLL Odbc("DropStatement",Stmt) CALL DLL Odbc("Disconnect",Conn) PRINT "done." STOP ! ! Catch program error ! Error:! OFF ERROR PRINT ERRM$ IF (ERRN>=1110) AND (ERRN<=1122) THEN Odbc_error PRINT ERRMSG$(ERRN) STOP ! ! ODBC.DLL specific error codes ! Odbc_error:! ! PRINT "Problem detected by Odbc.DLL" RESTORE Odbc_error REPEAT READ Err,Sql_msg$ UNTIL NOT Err OR (Err=ERRN) IF Err THEN PRINT Sql_msg$ LOOP CALL DLL Odbc("GetError",Sql_msg$,Sql_state$,Sql_native_code,Has_data) EXIT IF NOT Has_data PRINT "ODBC Error: ";Sql_msg$ PRINT "SQL State: ";Sql_state$;", Native code: ";Sql_native_code END LOOP STOP ! DATA 1110,"ODBC resource failure (ERR_ODBCRESOURCE)" DATA 1111,"ODBC internal failure (ERR_ODBCINTERNAL)" DATA 1112,"Invalid call sequence (ERR_SEQUENCE)" DATA 1113,"Connection failed (ERR_CONNECT)" DATA 1114,"Disconnect failed (ERR_DISCONNECT)" DATA 1115,"Already connected (ERR_CONNECTED)" DATA 1116,"Not connected (ERR_NOTCONNECTED)" DATA 1117,"Statement preparation failed (ERR_PREPARE)" DATA 1118,"Statement execution failed (ERR_EXECUTE)" DATA 1119,"Statement not prepared (ERR_NOTPREPARED)" DATA 1120,"Statement has no result (ERR_NORESULT)" DATA 1121,"Failed to fetch next row (ERR_FETCH)" DATA 1122,"Column/parameter number out of range (ERR_INVALIDCOLUMN)" DATA 0,"Unknown error code"
The third example illustrated how to write data using a prepared statement.
It is installed as ODBC3.PROG in the Eloquence share/example
installation subdirectory.
! RE-STORE "ODBC3,EXAMPLE" ! ! Eloquence ODBC DLL example program ! Add data record using prepared statement ! DIM Buf$[256],Sql$[256],Sql_msg$[256],Sql_state$[16] INTEGER Conn,Stmt,Has_data,Sql_native_code,Cnt ON ERROR GOTO Error IF BACKGROUND THEN PRINTER IS STDOUT ! ! Load the Eloquence Odbc.DLL and print version number ! PRINT LIN(1);"** Loading the Eloquence Odbc.DLL" LOAD DLL Odbc,1024 CALL DLL Odbc("Revision",Buf$) PRINT "Revision ";Buf$ ! CALL DLL Odbc("LogFile","odbcdll.log") CALL DLL Odbc("LogFlags","*3") ! ! Connect to the data source ! Buf$="DSN=SAMPLE" PRINT LIN(1);"** Connecting to the data source ";Buf$ CALL DLL Odbc("Connect",Buf$,Conn) ! ! The completed connection string (by the ODBC driver manager) CALL DLL Odbc("GetConnection",Conn,Buf$) PRINT "Connection #"&VAL$(Conn)&": "&Buf$ ! ! Disable Autocommit ! CALL DLL Odbc("SetAutocommit",Conn,0) ! ! Prepare an INSERT SQL statement ! NOTE: All columns not specified will be set to NULL ! PRINT LIN(1);"** Preparing SQL statement" Sql$="INSERT INTO CUSTOMERS(CUSTNO,MATCHCODE,NAME1) VALUES (?,?,?)" CALL DLL Odbc("Prepare",Conn,Sql$,Stmt) PRINT "Statement #"&VAL$(Stmt)&": "&Buf$ ! ! Execute the prepared statement ! PRINT LIN(1);"** Add 3 customer records" CALL DLL Odbc("Execute",Stmt,"999990","TEST1","Test Name #1") CALL DLL Odbc("RowCount",Stmt,Cnt) PRINT "Affected rows:";Cnt CALL DLL Odbc("Execute",Stmt,"999991","TEST2","Test Name #2") CALL DLL Odbc("RowCount",Stmt,Cnt) PRINT "Affected rows:";Cnt CALL DLL Odbc("Execute",Stmt,"999992","TEST3","Test Name #3") CALL DLL Odbc("RowCount",Stmt,Cnt) PRINT "Affected rows:";Cnt ! ! Read new entries ! Sql$="SELECT COUNT(*) FROM CUSTOMERS WHERE CUSTNO IN('999990','999991','999992')" CALL DLL Odbc("ExecDirect",Conn,Sql$,Stmt) CALL DLL Odbc("Fetch",Stmt,Has_data) CALL DLL Odbc("GetData",Stmt,1,Cnt) PRINT "Found";Cnt;"entries" ! ! ROLLBACK transaction ! NOTE #1: COMMIT or ROLLBACK will reset all active cursors ! for the connection ! NOTE #2: The unixODBC driver manager has bug and also invalidates ! any prepared statements ! PRINT LIN(1);"** ROLLBACK transaction" CALL DLL Odbc("Rollback",Conn) ! ! Check again for the new entries ! CALL DLL Odbc("ExecDirect",Conn,Sql$,Stmt) CALL DLL Odbc("Fetch",Stmt,Has_data) CALL DLL Odbc("GetData",Stmt,1,Cnt) PRINT "Found";Cnt;"entries" ! PRINT LIN(1);"** Disconnecting" CALL DLL Odbc("DropStatement",Stmt) CALL DLL Odbc("Disconnect",Conn) PRINT "done." STOP ! ! Catch program error ! Error:! OFF ERROR PRINT ERRM$ IF (ERRN>=1110) AND (ERRN<=1122) THEN Odbc_error PRINT ERRMSG$(ERRN) STOP ! ! ODBC.DLL specific error codes ! Odbc_error:! ! PRINT "Problem detected by Odbc.DLL" RESTORE Odbc_error REPEAT READ Err,Sql_msg$ UNTIL NOT Err OR (Err=ERRN) IF Err THEN PRINT Sql_msg$ LOOP CALL DLL Odbc("GetError",Sql_msg$,Sql_state$,Sql_native_code,Has_data) EXIT IF NOT Has_data PRINT "ODBC Error: ";Sql_msg$ PRINT "SQL State: ";Sql_state$;", Native code: ";Sql_native_code END LOOP STOP ! DATA 1110,"ODBC resource failure (ERR_ODBCRESOURCE)" DATA 1111,"ODBC internal failure (ERR_ODBCINTERNAL)" DATA 1112,"Invalid call sequence (ERR_SEQUENCE)" DATA 1113,"Connection failed (ERR_CONNECT)" DATA 1114,"Disconnect failed (ERR_DISCONNECT)" DATA 1115,"Already connected (ERR_CONNECTED)" DATA 1116,"Not connected (ERR_NOTCONNECTED)" DATA 1117,"Statement preparation failed (ERR_PREPARE)" DATA 1118,"Statement execution failed (ERR_EXECUTE)" DATA 1119,"Statement not prepared (ERR_NOTPREPARED)" DATA 1120,"Statement has no result (ERR_NORESULT)" DATA 1121,"Failed to fetch next row (ERR_FETCH)" DATA 1122,"Column/parameter number out of range (ERR_INVALIDCOLUMN)" DATA 0,"Unknown error code"