ODBCStmt¶
A simple API for performing SQL queries using ODBC for maximum portability.
This is a synchronous API so its use should bear that in mind. An asynchronous API will follow later.
Prerequisites¶
This API handles queries. Before you can execute a query, you need to connect to a database. Before you can connect to a database, you need an Environment.
See the documentation of ODBCDbc and ODBCEnv for more detail one what these two objects are and how they are used. The example below is barebones for those objects.
Usage¶
The simplest case is when your query doesn't take any parameters or return a data set. For example, a table creation. In this case, we can simply prepare the statement and directly execute it:
var stm: ODBCStmt = dbc.stmt()?
stm
.> prepare("create table demotable (myint integer unique, mystr varchar(400))")?
.> execute()?
Inserting Data¶
In order to insert data into this table we prepare the insert into SQL
statement and provide the values (parameters) to be inserted into the
columns, later. In our statement, we use ? as placeholders for these
values:
A prepared statement can be executed any number of times, but each execution will likely have different values to be populated for each row.
So before we can pass values to our prepared statement, we have to create pony objects to represent them. In our table above we have a SQLInteger (I32), and a SQLVarchar(400). For some types we have to specify the size of the buffer, for others such as SQLInteger, we don't as their sizes are known.
NOTE: If your buffer is too small, your statement will fail.
Once defined we bind them to the correct parameter by adding them in order:
The prepared statement can now be executed any number of times. In this example we'll execute it ten times:
for cnt in Range[I32](1,10) do
myint.write(cnt)
mystr.write("This is a string with a number: " + cnt.string())
stm.execute()?
end
Querying Data¶
In order to query data, we prepare and bind_parameters as before:
var intin: SQLInteger = SQLInteger
stm
.> prepare("select myint, mystr from demotable where myint > ?")?
.> bind_parameter(intin)?
But we also need to provide buffers for output:
var intout: SQLInteger = SQLInteger
var strout: SQLVarchar = SQLVarchar(400)
stm
.> bind_column(intout)?
.> bind_column(strout)?
Once these buffers are all allocated, we can execute our query:
intin.write(8)
while (stm.fetch_scroll(SqlFetchNext)?) do
Debug.out("myint: " + intout.read()?.string() +
"mystr: " + strout.read())
end
Handling Errors¶
In this API, we use partial functions in all our functions to indicate if a call failed. If a call failed, we can determine why by examining the contents of the field errtext.
Notes¶
Some rough edges: - This is a synchronous API. This could cause you problems. It is however a prerequisite for an asynchronous API which is better suited to pony. - The API is likely to change.
Implements¶
- SqlState ref
Public fields¶
var strict: Bool val¶
Public Functions¶
alloc¶
fun ref alloc()
: (SQLSuccess val | SQLSuccessWithInfo val | SQLStillExecuting val |
SQLError val | SQLInvalidHandle val | SQLNeedData val |
PonyDriverError val | SQLNoData val)
Returns¶
- (SQLSuccess val | SQLSuccessWithInfo val | SQLStillExecuting val | SQLError val | SQLInvalidHandle val | SQLNeedData val | PonyDriverError val | SQLNoData val)
sqlstates¶
Returns an array of SQL States.
Returns¶
prepare¶
Used to 'prepare' a SQL statement.
Any response from the ODBC driver other than a non-warning success will result in a thrown error.
Parameters¶
Returns¶
- Bool val ?
bind_parameter¶
Used to bind a parameter to a prepared query.
All parameters in this API are passed via SQLType objects. This object represents a textual buffer. You must allocate sufficient space in this buffer before you bind it to a column.
Parameters must be bound in order.
Any response from the ODBC driver other than a non-warning success will result in a thrown error.
Parameters¶
Returns¶
- Bool val ?
bind_column¶
Used to bind a column in a result-set for the prepared query.
All columns in this API are received via SQLType objects. This object represents a textual buffer. For efficiency reasons you should allocate sufficient space in this buffer before you bind it to a column.
"Should", because this API will resize a buffer if it determines that the buffer was insufficiently sized.
Columns must be bound in order.
Any response from the ODBC driver other than a non-warning success will result in a thrown error.
Parameters¶
Returns¶
- Bool val ?
execute¶
Before executing your prepared command you should populate your parameters with the necessary data.
Any response from the ODBC driver other than a non-warning success will result in a thrown error.
Parameters¶
- sl: SourceLoc val = __loc
Returns¶
- Bool val ?
direct_exec¶
Directly executes the provided statement.
Any response from the ODBC driver other than a non-warning success will result in a thrown error.
Parameters¶
Returns¶
- Bool val ?
rowcount¶
Warning: The ODBC standard does not mandate this function's correctness.
This call should return the number of affected rows.
Any response from the ODBC driver other than a non-warning success will result in a thrown error.
Parameters¶
- sl: SourceLoc val = __loc
Returns¶
- I64 val ?
num_result_cols¶
Warning: The ODBC standard does not mandate this function's correctness.
Any response from the ODBC driver other than a non-warning success will result in a thrown error.
Parameters¶
Returns¶
- Bool val ?
get_type_info¶
Calls the ODBC API SQLGetTypeInfo. If you don't provide a type ID it will default to SQL_ALL_TYPES.
After executing this you will need to bind columns and use fetch to fetch the data.
Parameters¶
Returns¶
- Bool val ?
columns¶
See the ODBC API documentation for SQLColumns for a full description.
fun ref columns(
catalog: String val = "",
schema: String val = "",
table: String val = "",
column: String val = "",
sl: SourceLoc val = __loc)
: Bool val ?
Parameters¶
- catalog: String val = ""
- schema: String val = ""
- table: String val = ""
- column: String val = ""
- sl: SourceLoc val = __loc
Returns¶
- Bool val ?
get_data¶
See SQLGetData for more information.
This is used if you decide to read data directly as opposed to binding columns and populating buffers automatically. The main reason to choose this approach is for huge columns or if you need more direct control.
Parameters¶
Returns¶
- Bool val ?
fetch¶
Fetches a row of data from the result set.
This function returns true is there are more rows, false if this
was the last row in the set.
Parameters¶
- sl: SourceLoc val = __loc
Returns¶
- Bool val ?
fetch_scroll¶
This function causes the ODBC driver to populate your buffers with the specified row of your result set. The default behaviour SqlFetchNext, the next row in your result set.
Any response from the ODBC driver other than a non-warning success will result in a thrown error.
This function returns true is there are more rows, false if this
was the last row in the set.
fun ref fetch_scroll(
d: (SqlFetchNext val | SqlFetchFirst val | SqlFetchLast val |
SqlFetchPrior val | SqlFetchAbsolute val | SqlFetchRelative val |
SqlFetchBookmark val) = reference,
offset: I64 val = 0,
sl: SourceLoc val = __loc)
: Bool val ?
Parameters¶
- d: (SqlFetchNext val | SqlFetchFirst val | SqlFetchLast val | SqlFetchPrior val | SqlFetchAbsolute val | SqlFetchRelative val | SqlFetchBookmark val) = reference
- offset: I64 val = 0
- sl: SourceLoc val = __loc
Returns¶
- Bool val ?
finish¶
Closes the result-set using SQLFreeStmt.
Parameters¶
- sl: SourceLoc val = __loc
Returns¶
- Bool val ?
get_sth¶
Returns¶
- ODBCHandleStmt tag