./ruby-odbc-0.99998/ 0040755 0000764 0000144 00000000000 13051023710 012450 5 ustar chw users ./ruby-odbc-0.99998/doc/ 0040755 0000764 0000144 00000000000 13051023710 013215 5 ustar chw users ./ruby-odbc-0.99998/doc/odbc.html 0100644 0000764 0000144 00000161714 13051021740 015022 0 ustar chw users
Ruby ODBC Reference
Last update: Wed, 15 February 2017
The module to encapsulate the Ruby ODBC binding.
module functions:
datasources
Returns an array of ODBC::DSN s, i.e. all
known data source names.
drivers
Returns an array of ODBC::Driver s,
i.e. all known ODBC drivers.
error
Returns the last error messages (String array) or nil.
The layout of the warning/error messages
is described here .
Retrieving this message as well as subsequent succeeding ODBC
method invocations do not clear the message. Use the
clear_error
method
for that purpose.
info
Returns the last driver/driver manager warning messages
(String array) or nil.
The layout of the warning/error messages
is described here .
Retrieving this message as well as subsequent succeeding ODBC
method invocations do not clear the message. Use the
clear_error
method
for that purpose.
clear_error
Resets the last driver/driver manager error and warning messages
to nil.
raise(value )
Raises an ODBC::Error exception with
String error message value .
newenv
Returns a new ODBC::Environment .
connection_pooling[=value ]
Gets or sets the process-wide connection pooling attribute.
to_time(timestamp )
to_time(date ,[time ])
to_time(time ,[date ])
Creates a Time
object from the specified arguments,
which must be ODBC::Date ,
ODBC::Time , or
ODBC::TimeStamp objects.
to_date(timestamp )
to_date(date )
Creates a Date
object from the specified arguments,
which must be ODBC::Date , or
ODBC::TimeStamp objects.
connect(dsn ,[user ,passwd ])
[{|dbc | block }]
If no block is specified, a connection to the given data source
is established and a ODBC::Database
object is returned, identifying that connection. Otherwise,
the block is executed with the database object. When the block
is finished, the connection is automatically released.
Options are:
dsn : Data source name (String or
ODBC::DSN )
user : Login user name (String)
passwd : Login password (String)
constants:
The boolean constant UTF8 reports the character encoding
of the module. If it is true
, the UTF-8 variant of
the module is in use, and string data is automatically converted
to/from Unicode.
Some constants of the ODBC API are defined in order to set connection
options, to deal with SQL data types, and to obtain database meta data.
Cursor behaviour:
SQL_CURSOR_FORWARD_ONLY ,
SQL_CURSOR_KEYSET_DRIVEN ,
SQL_CURSOR_DYNAMIC ,
SQL_CURSOR_STATIC
Concurrency (transactions):
SQL_CONCUR_READ_ONLY ,
SQL_CONCUR_LOCK ,
SQL_CONCUR_ROWVER ,
SQL_CONCUR_VALUES
Fetch direction:
SQL_FETCH_NEXT ,
SQL_FETCH_FIRST ,
SQL_FETCH_LAST ,
SQL_FETCH_PRIOR ,
SQL_FETCH_ABSOLUTE ,
SQL_FETCH_RELATIVE
Data types:
SQL_UNKNOWN_TYPE ,
SQL_CHAR ,
SQL_NUMERIC ,
SQL_DECIMAL ,
SQL_INTEGER ,
SQL_SMALLINT ,
SQL_FLOAT ,
SQL_REAL ,
SQL_DOUBLE ,
SQL_VARCHAR ,
SQL_DATETIME ,
SQL_DATE ,
SQL_TYPE_DATE ,
SQL_TIME ,
SQL_TYPE_TIME ,
SQL_TIMESTAMP ,
SQL_TYPE_TIMESTAMP ,
SQL_LONGVARCHAR ,
SQL_BINARY ,
SQL_VARBINARY ,
SQL_LONGVARBINARY ,
SQL_BIGINT ,
SQL_TINYINT ,
SQL_BIT ,
SQL_GUID
Parameter related:
SQL_PARAM_TYPE_UNKNOWN ,
SQL_PARAM_INPUT ,
SQL_PARAM_OUTPUT ,
SQL_PARAM_INPUT_OUTPUT ,
SQL_DEFAULT_PARAM
SQL_RETURN_VALUE
Procedure related:
SQL_RESULT_COL ,
SQL_PT_UNKNOWN ,
SQL_PT_PROCEDURE ,
SQL_PT_FUNCTION
Environment attributes:
SQL_CP_OFF ,
SQL_CP_ONE_PER_DRIVER ,
SQL_CP_ONE_PER_HENV ,
SQL_CP_DEFAULT ,
SQL_CP_STRICT_MATCH ,
SQL_CP_RELAXED_MATCH ,
SQL_CP_MATCH_DEFAULT ,
SQL_OV_ODBC2 ,
SQL_OV_ODBC3
Info types for
ODBC::Database.get_info
yielding integer results:
SQL_ACTIVE_ENVIRONMENTS ,
SQL_ACTIVE_CONNECTIONS ,
SQL_ACTIVE_STATEMENTS ,
SQL_ASYNC_MODE ,
SQL_CATALOG_LOCATION ,
SQL_CONCAT_NULL_BEHAVIOR ,
SQL_CORRELATION_NAME ,
SQL_CURSOR_COMMIT_BEHAVIOR ,
SQL_CURSOR_ROLLBACK_BEHAVIOR ,
SQL_CURSOR_SENSITIVITY ,
SQL_DDL_INDEX ,
SQL_DEFAULT_TXN_ISOLATION ,
SQL_DRIVER_HDBC ,
SQL_DRIVER_HENV ,
SQL_DRIVER_HDESC ,
SQL_DRIVER_HLIB ,
SQL_DRIVER_HSTMT ,
SQL_FILE_USAGE ,
SQL_GROUP_BY ,
SQL_IDENTIFIER_CASE ,
SQL_MAX_ASYNC_CONCURRENT_STATEMENTS ,
SQL_MAX_BINARY_LITERAL_LEN ,
SQL_MAX_CATALOG_NAME_LEN ,
SQL_MAX_CHAR_LITERAL_LEN ,
SQL_MAX_COLUMN_NAME_LEN ,
SQL_MAX_COLUMNS_IN_GROUP_BY ,
SQL_MAX_COLUMNS_IN_INDEX ,
SQL_MAX_COLUMNS_IN_ORDER_BY ,
SQL_MAX_COLUMNS_IN_SELECT ,
SQL_MAX_COLUMNS_IN_TABLE ,
SQL_MAX_CONCURRENT_ACTIVITIES ,
SQL_MAX_CURSOR_NAME_LEN ,
SQL_MAX_DRIVER_CONNECTIONS ,
SQL_MAX_IDENTIFIER_LEN ,
SQL_MAX_INDEX_SIZE ,
SQL_MAX_OWNER_NAME_LEN ,
SQL_MAX_PROCEDURE_NAME_LEN ,
SQL_MAX_QUALIFIER_NAME_LEN ,
SQL_MAX_ROW_SIZE ,
SQL_MAX_SCHEMA_NAME_LEN ,
SQL_MAX_STATEMENT_LEN ,
SQL_MAX_TABLE_NAME_LEN ,
SQL_MAX_TABLES_IN_SELECT ,
SQL_MAX_USER_NAME_LEN ,
SQL_NON_NULLABLE_COLUMNS ,
SQL_NULL_COLLATION ,
SQL_ODBC_API_CONFORMANCE ,
SQL_ODBC_INTERFACE_CONFORMANCE ,
SQL_ODBC_SAG_CLI_CONFORMANCE ,
SQL_ODBC_SQL_CONFORMANCE ,
SQL_PARAM_ARRAY_ROW_COUNTS ,
SQL_PARAM_ARRAY_SELECTS ,
SQL_QUALIFIER_LOCATION ,
SQL_QUOTED_IDENTIFIER_CASE ,
SQL_SQL_CONFORMANCE ,
SQL_TXN_CAPABLE
Info types for
ODBC::Database.get_info
yielding bitmasks (integer results):
SQL_AGGREGATE_FUNCTIONS ,
SQL_ALTER_DOMAIN ,
SQL_ALTER_TABLE ,
SQL_BATCH_ROW_COUNT ,
SQL_BATCH_SUPPORT ,
SQL_BOOKMARK_PERSISTENCE ,
SQL_CATALOG_USAGE ,
SQL_CONVERT_BINARY ,
SQL_CONVERT_BIT ,
SQL_CONVERT_CHAR ,
SQL_CONVERT_GUID ,
SQL_CONVERT_DATE ,
SQL_CONVERT_DECIMAL ,
SQL_CONVERT_DOUBLE ,
SQL_CONVERT_FLOAT ,
SQL_CONVERT_FUNCTIONS ,
SQL_CONVERT_INTEGER ,
SQL_CONVERT_INTERVAL_YEAR_MONTH ,
SQL_CONVERT_INTERVAL_DAY_TIME ,
SQL_CONVERT_LONGVARBINARY ,
SQL_CONVERT_LONGVARCHAR ,
SQL_CONVERT_NUMERIC ,
SQL_CONVERT_REAL ,
SQL_CONVERT_SMALLINT ,
SQL_CONVERT_TIME ,
SQL_CONVERT_TIMESTAMP ,
SQL_CONVERT_TINYINT ,
SQL_CONVERT_VARBINARY ,
SQL_CONVERT_VARCHAR ,
SQL_CONVERT_WCHAR ,
SQL_CONVERT_WLONGVARCHAR ,
SQL_CONVERT_WVARCHAR ,
SQL_CREATE_ASSERTION ,
SQL_CREATE_CHARACTER_SET ,
SQL_CREATE_COLLATION ,
SQL_CREATE_DOMAIN ,
SQL_CREATE_SCHEMA ,
SQL_CREATE_TABLE ,
SQL_CREATE_TRANSLATION ,
SQL_CREATE_VIEW ,
SQL_DATETIME_LITERALS ,
SQL_DROP_ASSERTION ,
SQL_DROP_CHARACTER_SET ,
SQL_DROP_COLLATION ,
SQL_DROP_DOMAIN ,
SQL_DROP_SCHEMA ,
SQL_DROP_TABLE ,
SQL_DROP_TRANSLATION ,
SQL_DROP_VIEW ,
SQL_DTC_TRANSITION_COST ,
SQL_DYNAMIC_CURSOR_ATTRIBUTES1 ,
SQL_DYNAMIC_CURSOR_ATTRIBUTES2 ,
SQL_FETCH_DIRECTION ,
SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 ,
SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 ,
SQL_GETDATA_EXTENSIONS ,
SQL_KEYSET_CURSOR_ATTRIBUTES1 ,
SQL_KEYSET_CURSOR_ATTRIBUTES2 ,
SQL_INDEX_KEYWORDS ,
SQL_INFO_SCHEMA_VIEWS ,
SQL_INSERT_STATEMENT ,
SQL_LOCK_TYPES ,
SQL_NUMERIC_FUNCTIONS ,
SQL_OJ_CAPABILITIES ,
SQL_OWNER_USAGE ,
SQL_POS_OPERATIONS ,
SQL_POSITIONED_STATEMENTS ,
SQL_QUALIFIER_USAGE ,
SQL_SCHEMA_USAGE ,
SQL_SCROLL_CONCURRENCY ,
SQL_SCROLL_OPTIONS ,
SQL_SQL92_DATETIME_FUNCTIONS ,
SQL_SQL92_FOREIGN_KEY_DELETE_RULE ,
SQL_SQL92_FOREIGN_KEY_UPDATE_RULE ,
SQL_SQL92_GRANT ,
SQL_SQL92_NUMERIC_VALUE_FUNCTIONS ,
SQL_SQL92_PREDICATES ,
SQL_SQL92_RELATIONAL_JOIN_OPERATORS ,
SQL_SQL92_REVOKE ,
SQL_SQL92_ROW_VALUE_CONSTRUCTOR ,
SQL_SQL92_STRING_FUNCTIONS ,
SQL_SQL92_VALUE_EXPRESSIONS ,
SQL_STANDARD_CLI_CONFORMANCE ,
SQL_STATIC_CURSOR_ATTRIBUTES1 ,
SQL_STATIC_CURSOR_ATTRIBUTES2 ,
SQL_STATIC_SENSITIVITY ,
SQL_STRING_FUNCTIONS ,
SQL_SUBQUERIES ,
SQL_SYSTEM_FUNCTIONS ,
SQL_TIMEDATE_ADD_INTERVALS ,
SQL_TIMEDATE_DIFF_INTERVALS ,
SQL_TIMEDATE_FUNCTIONS ,
SQL_TXN_ISOLATION_OPTION ,
SQL_UNION
Info types for
ODBC::Database.get_info
yielding strings:
SQL_ACCESSIBLE_PROCEDURES ,
SQL_ACCESSIBLE_TABLES ,
SQL_CATALOG_NAME ,
SQL_CATALOG_NAME_SEPARATOR ,
SQL_CATALOG_TERM ,
SQL_COLLATION_SEQ ,
SQL_COLUMN_ALIAS ,
SQL_DATA_SOURCE_NAME ,
SQL_DATA_SOURCE_READ_ONLY ,
SQL_DATABASE_NAME ,
SQL_DBMS_NAME ,
SQL_DBMS_VER ,
SQL_DESCRIBE_PARAMETER ,
SQL_DM_VER ,
SQL_DRIVER_NAME ,
SQL_DRIVER_ODBC_VER ,
SQL_DRIVER_VER ,
SQL_EXPRESSIONS_IN_ORDERBY ,
SQL_IDENTIFIER_QUOTE_CHAR ,
SQL_INTEGRITY ,
SQL_KEYWORDS ,
SQL_LIKE_ESCAPE_CLAUSE ,
SQL_MAX_ROW_SIZE_INCLUDES_LONG ,
SQL_MULT_RESULT_SETS ,
SQL_MULTIPLE_ACTIVE_TXN ,
SQL_NEED_LONG_DATA_LEN ,
SQL_ODBC_SQL_OPT_IEF ,
SQL_ODBC_VER ,
SQL_ORDER_BY_COLUMNS_IN_SELECT ,
SQL_OUTER_JOINS ,
SQL_OWNER_TERM ,
SQL_PROCEDURE_TERM ,
SQL_PROCEDURES ,
SQL_QUALIFIER_NAME_SEPARATOR ,
SQL_QUALIFIER_TERM ,
SQL_ROW_UPDATES ,
SQL_SCHEMA_TERM ,
SQL_SEARCH_PATTERN_ESCAPE ,
SQL_SERVER_NAME ,
SQL_SPECIAL_CHARACTERS ,
SQL_TABLE_TERM ,
SQL_USER_NAME ,
SQL_XOPEN_CLI_YEAR
Options for
ODBC::Database.get_option
,
ODBC::Database.set_option
,
ODBC::Statement.get_option
,
and
ODBC::Statement.set_option
yielding integers:
SQL_AUTOCOMMIT ,
SQL_CONCURRENCY ,
SQL_QUERY_TIMEOUT ,
SQL_MAX_ROWS ,
SQL_MAX_LENGTH ,
SQL_NOSCAN ,
SQL_ROWSET_SIZE ,
SQL_CURSOR_TYPE
The class to represent the root of all other ODBC related objects.
super class:
Object
methods:
error
Returns the last error message (String) or nil. For further
information see ODBC::error .
info
Returns the last driver/driver manager warning messages
(String array) or nil.
For further information see
ODBC::error .
clear_error
Resets the last driver/driver manager error and warning messages
to nil.
raise(value )
Raises an ODBC::Error exception with
String error message value .
singleton methods:
error
Returns the last error message (String array) or nil.
For further information see
ODBC::error .
info
Returns the last driver/driver manager warning messages
(String array) or nil.
For further information see
ODBC::error .
clear_error
Resets the last driver/driver manager error and warning messages
to nil.
raise(value )
Raises an ODBC::Error exception with
String error message value .
The class to represent a connection to an ODBC data source.
When underlying ODBC SQL functions report an error,
an ODBC::Error
exception with a corresponding error message from the ODBC
driver manager and/or driver is raised.
super class:
ODBC::Environment
methods:
connected?
Returns true
when the object is in connected
state, false otherwise.
drvconnect(drv )
Connect to a data source specified by drv
(ODBC::Driver ).
disconnect(no_drop=false )
Disconnects from the data source, all active statements for the
connection are dropped except when the no_drop argument
is true. The method returns true when the connection was released,
false otherwise.
newstmt
Returns a new ODBC::Statement
object without preparing or executing a SQL statement. This allows
to use
ODBC::Statement.set_option
to set special options on the statement before actual execution.
tables([pattern ])
Returns an ODBC::Statement with
information of all or some (pattern String given)
tables of the data source.
columns([table [,column ]])
Returns an ODBC::Statement
with column information
of the given table (String) and optional
column (String).
indexes([table [,unique ]])
Returns an ODBC::Statement
with index information
of the given table (String). If unique
is given and true, information for unique indexes only is
returned.
types([tcode ])
Returns an ODBC::Statement
with type information
of the numeric SQL type tcode or all types if
tcode is omitted.
primary_keys([table ])
Returns an ODBC::Statement
with primary key information of the given table (String).
foreign_keys([table ])
Returns an ODBC::Statement
with foreign key information of the given table (String).
table_privileges([table ])
Returns an ODBC::Statement
with owner/right information of the given table (String).
procedures([p ])
Returns an ODBC::Statement
with information about stored procedures.
procedure_columns([p ])
Returns an ODBC::Statement
with information about stored procedures.
special_columns([table [,id ,scope ]])
Returns an ODBC::Statement
with column information
of the given table (String) indicating the
optimal unique or identifying columns.
id may
be specified as ODBC::SQL_BEST_ROWID
or
ODBC::SQL_ROW_VER
. scope may be
specified as ODBC::SQL_SCOPE_CURROW
,
ODBC::SQL_SCOPE_TRANSACTION
, or
ODBC::SQL_SCOPE_SESSION
. If omitted the
defaults are ODBC::SQL_BEST_ROWID
and
ODBC::SQL_SCOPE_CURROW
.
get_info(info_type [,sql_type ])
Retrieves database meta data according to info_type
and returns numbers or strings. info_type may be specified
as integer or string. To force interpretation of the return value
of the underlying ODBC function SQLGetInfo()
as a
specific Ruby type the optional parameter sql_type
can be given as e.g.
ODBC::SQL_SMALLINT
(yielding integer),
ODBC::SQL_INTEGER
(yielding integer), and
ODBC::SQL_CHAR
(yielding string).
run(sql [,args... ])
Prepares and executes the query specified by sql
with parameters bound from args and returns an
ODBC::Statement or nil, if
the query did not produce a result set, e.g. when executing
SQL insert, delete, or update statements.
do(sql [,args... ])
Prepares and executes the query as in
run
,
but returns the number of result rows and automatically drops
the statement. Useful for SQL insert, delete, or update statements.
prepare(sql )
Prepares the query specified by sql and returns
an ODBC::Statement .
proc(sql ,[type ,size [,n =1]])
{|stmt | block }
Prepares the query specified by sql within a
ODBCProc and returns that procedure.
When the procedure is called, the statement is executed with
the procedure's arguments bound to the statement's parameters
and the statement is bound as parameter in the block, e.g.
# add customer given name and id
# and return number of affected rows
addcust = dbc.proc("insert into customer values(?, ?)") { |stmt|
stmt.nrows
}
addcust.call("J.R. User", 9999)
# alternative to call: addcust["J.R. User", 9999]
The optional arguments type , size , and
n ,
make the n-th statement parameter into an output parameter
with that given ODBC data type and size. That statement
parameter must be omitted when the ODBCProc
is called. This can be useful for wrapping stored procedures, e.g.
# wrap statement with output parameter
aproc = dbc.proc("{ ? = call stored_proc(?) }", ODBC::SQL_INTEGER, 4) {}
# call this statement/procedure, output parameter is result
result = aproc.call(99)
# alternative to call: result = aproc[99]
Finalization of an ODBCProc can be
done according to this code snippet
# aproc is wrapped statement, finalize it now
aproc.statement.drop
get_option(option )
Gets a connection level option. option can be a
module constant, e.g. SQL_MAX_ROWS , a number, or a
string. This method returns the integer value of that option.
set_option(option ,intval )
Sets a connection level option. option can be a
module constant, e.g. SQL_MAX_ROWS , a number, or a
string. The second parameter intval can be used to
set driver-specific statement options.
autocommit[=bool ]
Sets or queries the autocommit option of the connection.
concurrency[=intval ]
Sets or queries the concurrency mode of cursors opened on
the connection.
maxrows[=intval ]
Sets or queries the maximum rows returned in result sets from
the connection.
timeout[=intval ]
Sets or queries the number of seconds to wait for queries to
execute on the connection before returning.
maxlength[=intval ]
Sets or queries the maximum amount of data that will be returned
from a character or binary column.
cursortype[=intval ]
Sets or queries the cursor type used for fetches.
noscan[=bool ]
Sets or queries whether the driver scans SQL strings for ODBC
escape clauses.
rowsetsize
Returns the number of rows in a rowset fetched internally by a
call o SQLExtendedFetch (hardcoded to 1).
ignorecase[=bool ]
Sets or queries the uppercase conversion for column names. If
turned on (bool is true),
ODBC::Statement s
created by database methods will report column names in
ODBC::Column
or in the statement fetch methods
as uppercase strings. Otherwise (the default) column names are
passed unmodified.
drop_all
Releases the resources of all open
ODBC::Statement s in this
database connection.
use_time[=bool ]
Sets or queries the mapping of SQL_DATE, SQL_TIME, and
SQL_TIMESTAMP data types to Ruby objects. When true,
SQL_DATE is mapped to Ruby Date objects, SQL_TIME and
SQL_TIMESTAMP are mapped to Ruby Time objects. Otherwise (default)
ODBC::Date ,
ODBC::Time , and
ODBC::TimeStamp are used.
use_utc[=bool ]
Sets or queries the timezone applied on SQL_DATE, SQL_TIME, and
SQL_TIMESTAMP data types to Ruby objects. When true,
Ruby Date and Time objects are represented in UTC, when
false (default) in the local timezone.
use_sql_column_name[=bool ]
Sets or queries the flag controlling how column names are
read from the data source. When false (default), the ODBC
API SQLColAttributes(SQL_COLUMN_LABEL)
is used,
otherwise SQLColAttributes(SQL_COLUMN_NAME)
is used.
singleton methods:
new
Creates an unconnected ODBC object, e.g. for a later
drvconnect
method call.
new(dsn ,[user ,passwd ])
Connect to an ODBC data source. Options are:
dsn : Data source name (String or
ODBC::DSN )
user : Login user name (String)
passwd : Login password (String)
Remarks:
The
run
,
prepare
,
do
, and info methods
(e.g.
tables
)
can be invoked with a block. In this case the block is executed with
the
ODBC::Statement as parameter. The
run
and
do
methods use the ODBC API
function
SQLExecDirect()
when the SQL statement has no
parameters.
The class to represent a query and its query result.
The object of this class is created as the result of every query.
You may need to invoke the close
or drop
methods for the
finished object for better memory performance.
When underlying ODBC SQL functions report an error,
an ODBC::Error
exception with a corresponding error message from the ODBC driver
manager and/or driver is raised.
ODBC to Ruby type mapping:
ODBC Ruby
SQL_SMALLINT, SQL_INTEGER, SQL_TINYINT, SQL_BIT
T_FIXNUM, T_BIGNUM
SQL_FLOAT, SQL_DOUBLE, SQL_REAL T_FLOAT
SQL_DATE, SQL_TYPE_DATE
ODBC::Date or Date,
see ODBC::Database.use_time
SQL_TIME, SQL_TYPE_TIME
ODBC::Time or Time,
see ODBC::Database.use_time
SQL_TIMESTAMP, SQL_TYPE_TIMESTAMP
ODBC::TimeStamp or Time,
see ODBC::Database.use_time
all others T_STRING
super class:
ODBC::Database
mixins:
Enumerable
methods:
cancel
Cancel and close the
ODBC::Statement .
close
Close the ODBC::Statement .
drop
Close and free the ODBC::Statement .
column(n )
Returns information of the n-th column of the query result
as ODBC::Column .
columns(as_ary=false )
Returns a hash of column information keyed by column names
(Strings) of the query result. If as_ary is true,
an array is returned. In both cases the elements are
ODBC::Column s. If the hash keys
happen to be not unique later columns get their column number
appended, e.g. FOOBAR
, FOOBAR#1
.
columns
{|col | block }
Iterates over the columns of the query result with col
bound to each ODBC::Column .
ncols
Returns the number of columns of the query result.
nrows
Returns the number of rows of the query result.
cursorname[=name ]
Returns or sets the cursor name of the statement.
ignorecase[=bool ]
Same as
ODBC::Database.ignorecase
but affecting this statement only.
Inherited by the current state of the
ODBC::Database at the time the
statement is created.
fetch
Returns the next row of the query result as an array.
fetch_first
Returns the first row of the query result as an array.
fetch_scroll(direction ,
offset=1 )
Returns the row addressed by direction , e.g.
SQL_FETCH_LAST
as an array. offset is
used for SQL_FETCH_RELATIVE
and
SQL_FETCH_ABSOLUTE
.
fetch_many(count )
Returns an array of the next count rows of the query
result, where each row is an array.
fetch_all
Same as fetch_many
except that all remaining rows
are returned.
fetch_hash(with_table_names=false ,use_sym=false )
Returns the next row of the query result as a hash keyed by
column names. If with_table_names is true,
the keys are combined table/column names. For uniqueness of keys
the same rules as in the columns
method are applied. If use_sym is true,
the keys are formed by intern'ing the (table and) column names.
Alternatively, one hash argument can be presented to
fetch_hash
, e.g.
{ :key => :Symbol, :table_names => false }
or
{ :key => :String, :table_names => true }
or
{ :key => :Fixnum }
.
each {|row |
block }
Iterates over the query result, performing a fetch
for each row.
each_hash(with_table_names=false ,use_sym=false )
{|row | block }
Iterates over the query result, performing a
fetch_hash
for each row. The same
rules for arguments as in fetch_hash
apply.
execute([args... ])
Binds args to current query and executes it.
run(sql [,args... ])
Prepares and executes the query specified by sql
with parameters bound from args .
prepare(sql )
Prepares the query specified by sql .
more_results
Returns true and switches over to the next result set,
if the query produced more than one result set. Otherwise
returns false.
get_option(option )
Gets a statement level option. option can be a
module constant, e.g. SQL_MAX_ROWS , a number, or a
string. This method returns the integer value of that option.
set_option(option ,intval )
Sets a statement level option. option can be a
module constant, e.g. SQL_MAX_ROWS , a number, or a
string. The second parameter intval can be used to
set driver-specific statement options.
concurrency[=intval ]
Sets or queries the concurrency mode of cursors opened on
the statement.
maxrows[=intval ]
Sets or queries the maximum rows returned by the statement.
timeout[=intval ]
Sets or queries the number of seconds to wait for the statement
to execute before returning.
maxlength[=intval ]
Sets or queries the maximum amount of data that will be returned
from a character or binary column.
cursortype[=intval ]
Sets or queries the cursor type used for fetches.
noscan[=bool ]
Sets or queries whether the driver scans SQL strings for ODBC
escape clauses.
rowsetsize
Returns the number of rows in a rowset fetched internally by
a call to SQLExtendedFetch (hardcoded to 1).
nparams
Returns the number of parameters of the statement.
parameter(n )
Returns information of the n-th parameter of the query
as ODBC::Parameter .
parameters
Returns an array of
ODBC::Parameter s describing
all parameters of the query.
param_type(n [,type ,coldef ,scale ])
Allows to override the type of parameter n
and returns the current type. This can be useful
when the ODBC driver does not provide proper type information
on SQLDescribeParam .
param_iotype(n [,iotype ])
Allows to change the input/output type of parameter n
and returns the current input/output type. By
default, all parameters are ODBC::SQL_PARAM_INPUT .
When calling a stored procedure in the statement, the output
parameter must be altered using this method, e.g.
# assume 1st parameter is input, 2nd is output
stmt = conn.prepare("call stored_proc( ?, ?)")
# setup 2nd for output of an integer
stmt.param_iotype(2, ODBC::SQL_PARAM_OUTPUT)
stmt.param_output_type(2, ODBC::SQL_INTEGER)
stmt.param_output_size(2, 4)
# execute stmt and retrieve value of output parameter
stmt.execute(42, nil)
stmt.fetch_all
out_value = stmt.param_output_value(2);
param_output_type(n [,type ])
Allows to change the SQL type of output parameter n
and returns the current type. For further
information see the sample code in the
param_iotype
method.
param_output_size(n [,size ])
Allows to change the byte size of the buffer for output parameter
n and returns the current size.
For further information see the sample code in the
param_iotype
method.
param_output_value(n )
Returns the value of the output parameter n .
For further information see the sample code in the
param_iotype
method.
make_proc([n ])
Wraps the statement into a ODBCProc object
and returns that object. The optional n argument is
the parameter number of the statement which is used as output
parameter in the wrapped ODBCProc . For
further information refer to the samples in the description of
ODBC::Database.proc
.
singleton methods:
make_proc(stmt ,[n ])
Wraps the statement stmt into a
ODBCProc object
and returns that object. The optional n argument is
the parameter number of the statement which is used as output
parameter in the wrapped ODBCProc . For
further information refer to the samples in the description of
ODBC::Database.proc
.
Remarks:
The
fetch
,
fetch_hash
,
and
execute
methods can be invoked with a block. In this case the block is
executed with one row of the result set (
fetch
and
fetch_hash
) or with the
ODBC::Statement (
execute
)
as parameter.
If the ignorecase
option
is turned on, all column names used in the column
,
columns
, and *_hash
methods are converted to
upper case.
The class to represent (read-only) information of a column of a query.
Objects of this class are created as result of the
column
and columns
methods of
ODBC::Statement .
super class:
ODBC::Object
methods:
name
Returns the column name (String).
table
Returns the table name (String).
length
Returns the length of the column (Integer).
nullable
Returns the nullable state of the column (Boolean).
searchable
Returns the searchable state of the column (Boolean).
unsigned
Returns the unsigned flag of the column (Boolean).
precision
Returns the precision of the column (Integer).
scale
Returns the scale of the column (Integer).
type
Returns the SQL type of the column (Integer).
autoincrement
Returns true if the column automatically increments,
false, if not, and nil if that information cannot be
determined from the column.
The class to represent (read-only) information of a parameter of a
query.
Objects of this class are created as result of the
parameter
and
parameters
methods of
ODBC::Statement .
super class:
ODBC::Object
methods:
type
Returns the parameter's type, e.g. ODBC::SQL_CHAR.
precision
Returns the parameter's precision (Integer).
length
Returns the parameter's scale (Integer).
nullable
Returns the nullable state of the column (Boolean).
iotype
Returns the parameter's input/output type,
e.g. ODBC::SQL_PARAM_INPUT.
output_type
Returns the parameter's output type, only useful when the
parameter is an output parameter (ODBC::SQL_PARAM_OUTPUT or
ODBC::SQL_PARAM_INPUT_OUTPUT).
output_size
Returns the parameter's output buffer size, only useful when the
parameter is an output parameter (ODBC::SQL_PARAM_OUTPUT).
The class to represent a SQL_DATE
column in a table
or a SQL_DATE
query parameter.
super class:
ODBC::Object
mixins:
Comparable
methods:
<=>(adate )
Comparison, compares date with adate and returns
0, 1, or -1.
day[=num ]
Returns or sets the day component of the date object.
month[=num ]
Returns or sets the month component of the date object.
year[=num ]
Returns or sets the year component of the date object.
to_s
Returns a string representation of the object with format
YYYY-MM-DD
.
clone
Returns a fresh copy of the date object.
singleton methods:
new([year , month ,
day ])
new(date )
new(time )
new(string )
Creates a new date object from numeric values or from
a Date
, Time
, or String
object. Recognized string formats are e.g.
2001-01-01
2001-01-01 12:00:01
{ts '2001-01-01 12:00:01.1'}
{d '2001-01-01'}
The class to represent a SQL_TIME
column in a table
or a SQL_TIME
query parameter.
super class:
ODBC::Object
mixins:
Comparable
methods:
<=>(atime )
Comparison, compares time with atime and returns
0, 1, or -1.
second[=num ]
Returns or sets the second component of the time object.
minute[=num ]
Returns or sets the minute component of the time object.
hour[=num ]
Returns or sets the hour component of the time object.
to_s
Returns a string representation of the object with format
hh:mm:ss
.
clone
Returns a fresh copy of the time object.
singleton methods:
new([hour , minute ,
second ])
new(time )
new(string )
Creates a new time object from numeric values or from
a Time
or String
object.
Recognized string formats are e.g.
12:00:01
2001-01-01 12:00:01
{ts '2001-01-01 12:00:01.1'}
{t '12:00:01'}
The class to represent a SQL_TIMESTAMP
column in a table
or a SQL_TIMESTAMP
query parameter.
super class:
ODBC::Object
mixins:
Comparable
methods:
<=>(atimestamp )
Comparison, compares time stamp with atimestamp
and returns 0, 1, or -1.
fraction[=num ]
Returns or sets the fraction component of the time stamp object.
Note that this is expressed in nanoseconds.
second[=num ]
Returns or sets the second component of the time stamp object.
minute[=num ]
Returns or sets the minute component of the time stamp object.
hour[=num ]
Returns or sets the hour component of the time stamp object.
day[=num ]
Returns or sets the day component of the time stamp object.
month[=num ]
Returns or sets the month component of the time stamp object.
year[=num ]
Returns or sets the year component of the time stamp object.
to_s
Returns a string representation of the object with format
YYYY-MM-DD hh:mm:ss fraction
.
clone
Returns a fresh copy of the time stamp object.
singleton methods:
new([year , month ,
day , hour , minute ,
second , fraction ])
new(time )
new(string )
Creates a new time stamp object from numeric values or from
a Time
or String
object.
Recognized string formats are e.g.
12:00:01
2001-01-01
2001-01-01 12:00:01
{ts '2001-01-01 12:00:01.1'}
{d '2001-01-01'}
{t '12:00:01'}
The class to represent a data source name. Objects of this class are
created as result of a
ODBC::datasources
module function call.
super class:
ODBC::Object
methods:
name[=name ]
Queries or sets the name (String) of the data source.
descr[=descr ]
Queries or sets the descr (description, String)
of the data source.
singleton methods:
new
Returns an empty ODBC::DSN object.
The class to represent an ODBC driver with name and attributes.
Objects of this class are
created as result of a
ODBC::drivers
module function call.
super class:
ODBC::Object
methods:
name[=name ]
Queries or sets the name (String) of the ODBC driver.
attrs[[key ][=value ]]
Queries or sets attributes in the attrs Hash of the
ODBC driver object. The key s and value s
should be Strings.
singleton methods:
new
Returns an empty ODBC::Driver object.
The class to represent a procedure with ODBC database/statement
context.
Objects of this class are created as result of a
ODBC::Database.proc
method call.
super class:
Proc
methods:
call([args* ])
Executes the SQL statement with parameters set from args
and then invokes the procedure's block, setting the block's
single parameter to the
ODBC::Statement .
[[args* ]]
Synonym for call
.
The class to represent ODBC related exceptions. The descriptive
string is made up of the first ODBC driver or driver manager
message as concatenation of SQL state, native error, driver manager
name, database name/vendor, DSN, and error text, e.g.
S1000 (1146) [unixODBC][TCX][MySQL]Table 'test.foo' doesn't exist
For internally generated errors, e.g. method invocation on
a broken connection, the descriptive string starts with
'INTERN' and native error 0, e.g.
INTERN (0) [RubyODBC]No connection
For errors programmatically generated by the
raise
method,
the descriptive string starts with 'INTERN' and native error 1,
e.g.
INTERN (1) [RubyODBC]Programmer forgot to RTFM
super class:
StandardError
Undocumented
Use The Source, Luke!
ODBC::add_dsn(driver ,issys=false )
ODBC::add_dsn(name ,attrs ,issys=false )
ODBC::config_dsn(driver ,issys=false )
ODBC::config_dsn(name ,attrs ,issys=false )
ODBC::del_dsn(driver ,issys=false )
ODBC::del_dsn(name ,attrs ,issys=false )
ODBC::write_file_dsn(filename ,appname ,key [,value ])
ODBC::read_file_dsn(filename ,appname ,key )
ODBC::trace([mask ])
ODBC::Statement.fetch!
ODBC::Statement.fetch_first!
ODBC::Statement.fetch_first_hash(with_table_names=false ,use_sym=false )
ODBC::Statement.fetch_scroll!(direction ,offset=1 )
ODBC::Statement.fetch_hash!(with_table_names=false ,use_sym=false )
mailto:Christian Werner
./ruby-odbc-0.99998/ext/ 0040755 0000764 0000144 00000000000 13051023710 013250 5 ustar chw users ./ruby-odbc-0.99998/ext/utf8/ 0040755 0000764 0000144 00000000000 13051023710 014136 5 ustar chw users ./ruby-odbc-0.99998/ext/utf8/odbc.c 0100644 0000764 0000144 00000000562 11514252277 015227 0 ustar chw users /*
* ODBC-Ruby binding
* Copyright (c) 2001-2011 Christian Werner
*
* See the file "COPYING" for information on usage
* and redistribution of this file and for a
* DISCLAIMER OF ALL WARRANTIES.
*
* $Id: odbc.c,v 1.6 2011/01/15 08:02:55 chw Exp chw $
*/
#undef UNICODE
#undef _UNICODE
#define UNICODE
#define _UNICODE
#include "../odbc.c"
./ruby-odbc-0.99998/ext/utf8/init.c 0100644 0000764 0000144 00000000467 10605663303 015263 0 ustar chw users /*
* Part of ODBC-Ruby binding
* Copyright (c) 2006-2007 Christian Werner
*
* See the file "COPYING" for information on usage
* and redistribution of this file and for a
* DISCLAIMER OF ALL WARRANTIES.
*
* $Id: init.c,v 1.2 2007/04/07 09:39:08 chw Exp chw $
*/
#include "../init.c"
./ruby-odbc-0.99998/ext/utf8/extconf.rb 0100644 0000764 0000144 00000010774 11663106312 016146 0 ustar chw users require 'mkmf'
if ! defined? PLATFORM
PLATFORM = RUBY_PLATFORM
end
def have_library_ex(lib, func="main", headers=nil)
checking_for "#{func}() in -l#{lib}" do
libs = append_library($libs, lib)
if !func.nil? && !func.empty? && COMMON_LIBS.include?(lib)
true
elsif try_func(func, libs, headers)
$libs = libs
true
else
false
end
end
end
def try_func_nolink(func, libs, headers = nil, &b)
headers = cpp_include(headers)
try_compile(<<"SRC", libs, &b)
#{COMMON_HEADERS}
#{headers}
/*top*/
int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; }
SRC
end
def have_func_nolink(func, headers = nil, &b)
checking_for "#{func}()" do
if try_func_nolink(func, $libs, headers, &b)
$defs.push(format("-DHAVE_%s", func.upcase))
true
else
false
end
end
end
dir_config("odbc")
have_header("sql.h") || begin
puts "ERROR: sql.h not found"
exit 1
end
have_header("sqlext.h") || begin
puts "ERROR: sqlext.h not found"
exit 1
end
testdlopen = enable_config("dlopen", false)
begin
if PLATFORM !~ /(mingw|cygwin)/ then
header = "sqltypes.h"
else
header = ["windows.h", "sqltypes.h"]
end
if defined? have_type
have_type("SQLTCHAR", header)
else
throw
end
rescue
puts "WARNING: please check sqltypes.h for SQLTCHAR manually,"
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
puts "WARNING: the option -DHAVE_TYPE_SQLTCHAR"
end
begin
if PLATFORM !~ /(mingw|cygwin)/ then
header = "sqltypes.h"
else
header = ["windows.h", "sqltypes.h"]
end
if defined? have_type
have_type("SQLLEN", header)
else
throw
end
rescue
puts "WARNING: please check sqltypes.h for SQLLEN manually,"
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
puts "WARNING: the option -DHAVE_TYPE_SQLLEN"
end
begin
if PLATFORM !~ /(mingw|cygwin)/ then
header = "sqltypes.h"
else
header = ["windows.h", "sqltypes.h"]
end
if defined? have_type
have_type("SQLULEN", header)
else
throw
end
rescue
puts "WARNING: please check sqltypes.h for SQLULEN manually,"
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
puts "WARNING: the option -DHAVE_TYPE_SQLULEN"
end
$have_odbcinst_h = have_header("odbcinst.h")
if PLATFORM =~ /mswin32/ then
if !have_library_ex("odbc32", "SQLAllocConnect", "sql.h") ||
!have_library_ex("odbccp32", "SQLConfigDataSource", "odbcinst.h") ||
!have_library_ex("odbccp32", "SQLInstallerError", "odbcinst.h") ||
!have_library("user32", "CharUpper") then
puts "Can not locate odbc libraries"
exit 1
end
have_func("SQLConfigDataSourceW", "odbcinst.h")
have_func("SQLWriteFileDSNW", "odbcinst.h")
have_func("SQLReadFileDSNW", "odbcinst.h")
have_func("SQLInstallerError", "odbcinst.h")
have_func("SQLInstallerErrorW", "odbcinst.h")
elsif PLATFORM =~ /(mingw|cygwin)/ then
have_library("odbc32", "")
have_library("odbccp32", "")
have_library("user32", "")
header = ["windows.h", "odbcinst.h"]
have_func("SQLConfigDataSourceW", header)
have_func("SQLWriteFileDSNW", header)
have_func("SQLReadFileDSNW", header)
have_func("SQLInstallerError", header)
have_func("SQLInstallerErrorW", header)
elsif (testdlopen && PLATFORM !~ /(macos|darwin)/ && CONFIG["CC"] =~ /gcc/ && have_func("dlopen", "dlfcn.h") && have_library("dl", "dlopen")) then
$LDFLAGS+=" -Wl,-init -Wl,ruby_odbc_init -Wl,-fini -Wl,ruby_odbc_fini"
$CPPFLAGS+=" -DHAVE_SQLCONFIGDATASOURCE"
$CPPFLAGS+=" -DHAVE_SQLINSTALLERERROR"
$CPPFLAGS+=" -DUSE_DLOPEN_FOR_ODBC_LIBS"
# but test the UNICODE installer functions w/o linking
# in case we need to provide fwd declarations
have_func_nolink("SQLConfigDataSourceW", "odbcinst.h")
have_func_nolink("SQLWriteFileDSNW", "odbcinst.h")
have_func_nolink("SQLReadFileDSNW", "odbcinst.h")
have_func_nolink("SQLInstallerErrorW", "odbcinst.h")
else
$CPPFLAGS+=" -DUNICODE -D_UNICODE"
have_library("odbc", "SQLAllocConnect") ||
have_library("iodbc", "SQLAllocConnect")
($have_odbcinst_h &&
have_library("odbcinst", "SQLConfigDataSource")) ||
($have_odbcinst_h &&
have_library("iodbcinst", "SQLConfigDataSource"))
$have_odbcinst_h &&
have_func("SQLConfigDataSourceW", "odbcinst.h")
$have_odbcinst_h &&
have_func("SQLWriteFileDSNW", "odbcinst.h")
$have_odbcinst_h &&
have_func("SQLReadFileDSNW", "odbcinst.h")
$have_odbcinst_h &&
have_func("SQLInstallerError", "odbcinst.h")
$have_odbcinst_h &&
have_func("SQLInstallerErrorW", "odbcinst.h")
end
create_makefile("odbc_utf8")
./ruby-odbc-0.99998/ext/extconf.rb 0100644 0000764 0000144 00000010335 12504461473 015260 0 ustar chw users require 'mkmf'
if ! defined? PLATFORM
PLATFORM = RUBY_PLATFORM
end
def have_library_ex(lib, func="main", headers=nil)
checking_for "#{func}() in -l#{lib}" do
libs = append_library($libs, lib)
if !func.nil? && !func.empty? && COMMON_LIBS.include?(lib)
true
elsif try_func(func, libs, headers)
$libs = libs
true
else
false
end
end
end
dir_config("odbc")
have_header("version.h")
have_header("sql.h") || begin
puts "ERROR: sql.h not found"
exit 1
end
have_header("sqlext.h") || begin
puts "ERROR: sqlext.h not found"
exit 1
end
testdlopen = enable_config("dlopen", false)
begin
if PLATFORM !~ /(mingw|cygwin)/ then
header = "sqltypes.h"
else
header = ["windows.h", "sqltypes.h"]
end
if defined? have_type
have_type("SQLTCHAR", header)
else
throw
end
rescue
puts "WARNING: please check sqltypes.h for SQLTCHAR manually,"
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
puts "WARNING: the option -DHAVE_TYPE_SQLTCHAR"
end
begin
if PLATFORM !~ /(mingw|cygwin)/ then
header = "sqltypes.h"
else
header = ["windows.h", "sqltypes.h"]
end
if defined? have_type
have_type("SQLLEN", header)
else
throw
end
rescue
puts "WARNING: please check sqltypes.h for SQLLEN manually,"
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
puts "WARNING: the option -DHAVE_TYPE_SQLLEN"
end
begin
if PLATFORM !~ /(mingw|cygwin)/ then
header = "sqltypes.h"
else
header = ["windows.h", "sqltypes.h"]
end
if defined? have_type
have_type("SQLULEN", header)
else
throw
end
rescue
puts "WARNING: please check sqltypes.h for SQLULEN manually,"
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
puts "WARNING: the option -DHAVE_TYPE_SQLULEN"
end
$have_odbcinst_h = have_header("odbcinst.h")
begin
if PLATFORM !~ /(mingw|cygwin)/ then
header = "sqltypes.h"
else
header = ["windows.h", "sqltypes.h"]
end
if defined? have_type
have_type("SQLROWOFFSET", header)
else
throw
end
rescue
puts "WARNING: please check sqltypes.h for SQLROWOFFSET manually,"
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
puts "WARNING: the option -DHAVE_TYPE_SQLROWOFFSET"
end
$have_odbcinst_h = have_header("odbcinst.h")
begin
if PLATFORM !~ /(mingw|cygwin)/ then
header = "sqltypes.h"
else
header = ["windows.h", "sqltypes.h"]
end
if defined? have_type
have_type("SQLROWSETSIZE", header)
else
throw
end
rescue
puts "WARNING: please check sqltypes.h for SQLROWSETSIZE manually,"
puts "WARNING: if defined, modify CFLAGS in Makefile to contain"
puts "WARNING: the option -DHAVE_TYPE_SQLROWSETSIZE"
end
$have_odbcinst_h = have_header("odbcinst.h")
if PLATFORM =~ /mswin32/ then
if !have_library_ex("odbc32", "SQLAllocConnect", "sql.h") ||
!have_library_ex("odbccp32", "SQLConfigDataSource", "odbcinst.h") ||
!have_library_ex("odbccp32", "SQLInstallerError", "odbcinst.h") ||
!have_library("user32", "CharUpper") then
puts "Can not locate odbc libraries"
exit 1
end
have_func("SQLInstallerError", "odbcinst.h")
# mingw untested !!!
elsif PLATFORM =~ /(mingw|cygwin)/ then
have_library("odbc32", "")
have_library("odbccp32", "")
have_library("user32", "")
elsif (testdlopen && PLATFORM !~ /(macos|darwin)/ && CONFIG["CC"] =~ /gcc/ && have_func("dlopen", "dlfcn.h") && have_library("dl", "dlopen")) then
$LDFLAGS+=" -Wl,-init -Wl,ruby_odbc_init -Wl,-fini -Wl,ruby_odbc_fini"
$CPPFLAGS+=" -DHAVE_SQLCONFIGDATASOURCE"
$CPPFLAGS+=" -DHAVE_SQLINSTALLERERROR"
$CPPFLAGS+=" -DUSE_DLOPEN_FOR_ODBC_LIBS"
if defined? have_type then
if have_type("SQLBIGINT", "sqltypes.h", "-DHAVE_LONG_LONG") then
$CPPFLAGS+=" -DHAVE_LONG_LONG"
end
end
else
have_library("odbc", "SQLAllocConnect") ||
have_library("iodbc", "SQLAllocConnect")
($have_odbcinst_h &&
have_library("odbcinst", "SQLConfigDataSource")) ||
($have_odbcinst_h &&
have_library("iodbcinst", "SQLConfigDataSource"))
$have_odbcinst_h &&
have_func("SQLInstallerError", "odbcinst.h")
if defined? have_type then
if have_type("SQLBIGINT", "sqltypes.h", "-DHAVE_LONG_LONG") then
$CPPFLAGS+=" -DHAVE_LONG_LONG"
end
end
end
create_makefile("odbc")
./ruby-odbc-0.99998/ext/odbc.c 0100644 0000764 0000144 00000726111 13051023703 014332 0 ustar chw users /*
* ODBC-Ruby binding
* Copyright (c) 2001-2015 Christian Werner
* Portions copyright (c) 2004 Ryszard Niewisiewicz
* Portions copyright (c) 2006 Carl Blakeley
*
* See the file "COPYING" for information on usage
* and redistribution of this file and for a
* DISCLAIMER OF ALL WARRANTIES.
*
* $Id: odbc.c,v 1.78 2017/02/15 10:04:30 chw Exp chw $
*/
#undef ODBCVER
#if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__)
#include
#endif
#include
#include
#include "ruby.h"
#ifdef HAVE_VERSION_H
#include "version.h"
#endif
#ifdef HAVE_SQL_H
#include
#else
#error Missing include: sql.h
#endif
#ifdef HAVE_SQLEXT_H
#include
#else
#error Missing include: sqlext.h
#endif
#ifdef HAVE_ODBCINST_H
#include
#endif
#ifdef UNICODE
#include
#endif
#ifndef HAVE_TYPE_SQLTCHAR
#ifdef UNICODE
typedef SQLWCHAR SQLTCHAR;
#else
typedef SQLCHAR SQLTCHAR;
#endif
#endif
#ifndef HAVE_TYPE_SQLLEN
#define SQLLEN SQLINTEGER
#endif
#ifndef HAVE_TYPE_SQLULEN
#define SQLULEN SQLUINTEGER
#endif
#ifndef HAVE_TYPE_SQLROWOFFSET
#define SQLROWOFFSET SQLLEN
#endif
#ifndef HAVE_TYPE_SQLROWSETSIZE
#define SQLROWSETSIZE SQLULEN
#endif
#if (RUBY_VERSION_MAJOR <= 1) && (RUBY_VERSION_MINOR < 9)
#define TIME_USE_USEC 1
#endif
#ifdef HAVE_RUBY_THREAD_H
#include "ruby/thread.h"
#endif
/*
* Conditionally undefine aliases of ODBC installer UNICODE functions.
*/
#if defined(UNICODE) && defined(HAVE_SQLINSTALLERERRORW)
#undef SQLInstallerError
#endif
#if defined(UNICODE) && defined(HAVE_SQLCONFIGDATASOURCEW)
#undef SQLConfigDataSource
#endif
#if defined(UNICODE) && defined(HAVE_SQLREADFILEDSNW)
#undef SQLReadFileDSN
#endif
#if defined(UNICODE) && defined(HAVE_SQLWRITEFILEDSNW)
#undef SQLWriteFileDSN
#endif
#if defined(UNICODE) && defined(USE_DLOPEN_FOR_ODBC_LIBS)
extern int ruby_odbc_have_func(const char *name, void *addr);
#endif
#ifdef UNICODE
/*
* Declarations of required installer APIs in case
* header files don't provide them (unixODBC?).
*/
#ifndef HAVE_SQLINSTALLERERRORW
SQLRETURN INSTAPI SQLInstallerErrorW(WORD, DWORD *, LPWSTR, WORD, WORD *);
#endif
#ifndef HAVE_SQLCONFIGDATASOURCEW
BOOL INSTAPI SQLConfigDataSourceW(HWND, WORD, LPWSTR, LPWSTR);
#endif
#ifndef HAVE_SQLREADFILEDSNW
BOOL INSTAPI SQLReadFileDSNW(LPWSTR, LPWSTR, LPWSTR, LPWSTR, WORD, WORD *);
#endif
#ifndef HAVE_SQLWRITEFILEDSNW
BOOL INSTAPI SQLWriteFileDSNW(LPWSTR, LPWSTR, LPWSTR, LPWSTR);
#endif
#if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H
#define USE_RB_ENC 1
#include "ruby/encoding.h"
static rb_encoding *rb_enc = NULL;
static VALUE rb_encv = Qnil;
#endif
#endif /* UNICODE */
#ifndef HAVE_RB_DEFINE_ALLOC_FUNC
#define rb_define_alloc_func(cls, func) \
rb_define_singleton_method(cls, "new", func, -1)
#define rb_undefine_alloc_func(cls) \
rb_undef_method(CLASS_OF(cls), "new")
#endif
#ifdef RB_CVAR_SET_4ARGS
#define CVAR_SET(x, y, z) rb_cvar_set(x, y, z, 0)
#else
#define CVAR_SET(x, y, z) rb_cvar_set(x, y, z)
#endif
#ifndef STR2CSTR
#define STR2CSTR(x) StringValueCStr(x)
#define NO_RB_STR2CSTR 1
#endif
#ifdef TRACING
static int tracing = 0;
#define tracemsg(t, x) {if (tracing & t) { x }}
static SQLRETURN tracesql(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt,
SQLRETURN ret, const char *m);
#else
#define tracemsg(t, x)
#define tracesql(a, b, c, d, e) d
#endif
#ifndef SQL_SUCCEEDED
#define SQL_SUCCEEDED(x) \
(((x) == SQL_SUCCESS) || ((x) == SQL_SUCCESS_WITH_INFO))
#endif
#ifndef SQL_NO_DATA
#define SQL_NO_DATA SQL_NO_DATA_FOUND
#endif
typedef struct link {
struct link *succ;
struct link *pred;
struct link *head;
int offs;
} LINK;
typedef struct env {
VALUE self;
LINK dbcs;
SQLHENV henv;
} ENV;
typedef struct dbc {
LINK link;
VALUE self;
VALUE env;
struct env *envp;
LINK stmts;
SQLHDBC hdbc;
VALUE rbtime;
VALUE gmtime;
int upc;
VALUE use_sql_column_name;
} DBC;
typedef struct {
SQLSMALLINT type;
SQLULEN coldef;
SQLULEN coldef_max;
SQLSMALLINT scale;
SQLLEN rlen;
SQLSMALLINT nullable;
SQLSMALLINT iotype;
int override;
#ifdef UNICODE
SQLWCHAR *tofree;
#endif
char buffer[sizeof (double) * 4 + sizeof (TIMESTAMP_STRUCT)];
SQLSMALLINT ctype;
SQLSMALLINT outtype;
int outsize;
char *outbuf;
} PARAMINFO;
typedef struct {
int type;
int size;
} COLTYPE;
typedef struct stmt {
LINK link;
VALUE self;
VALUE dbc;
struct dbc *dbcp;
SQLHSTMT hstmt;
int nump;
PARAMINFO *paraminfo;
int ncols;
COLTYPE *coltypes;
char **colnames;
VALUE *colvals;
char **dbufs;
int fetchc;
int upc;
int usef;
} STMT;
static VALUE Modbc;
static VALUE Cobj;
static VALUE Cenv;
static VALUE Cdbc;
static VALUE Cstmt;
static VALUE Ccolumn;
static VALUE Cparam;
static VALUE Cerror;
static VALUE Cdsn;
static VALUE Cdrv;
static VALUE Cdate;
static VALUE Ctime;
static VALUE Ctimestamp;
static VALUE Cproc;
static VALUE rb_cDate;
static ID IDstart;
static ID IDatatinfo;
static ID IDataterror;
static ID IDkeys;
static ID IDatattrs;
static ID IDday;
static ID IDmonth;
static ID IDyear;
static ID IDmday;
static ID IDnsec;
static ID IDusec;
static ID IDsec;
static ID IDmin;
static ID IDhour;
static ID IDusec;
static ID IDkeyp;
static ID IDkey;
static ID IDSymbol;
static ID IDString;
static ID IDFixnum;
static ID IDtable_names;
static ID IDnew;
static ID IDnow;
static ID IDname;
static ID IDtable;
static ID IDtype;
static ID IDlength;
static ID IDnullable;
static ID IDscale;
static ID IDprecision;
static ID IDsearchable;
static ID IDunsigned;
static ID IDiotype;
static ID IDoutput_size;
static ID IDoutput_type;
static ID IDdescr;
static ID IDstatement;
static ID IDreturn_output_param;
static ID IDattrs;
static ID IDNULL;
static ID IDdefault;
#ifdef USE_RB_ENC
static ID IDencode;
#endif
static ID IDparse;
static ID IDutc;
static ID IDlocal;
static ID IDto_s;
/*
* Modes for dbc_info
*/
#define INFO_TABLES 0
#define INFO_COLUMNS 1
#define INFO_PRIMKEYS 2
#define INFO_INDEXES 3
#define INFO_TYPES 4
#define INFO_FORKEYS 5
#define INFO_TPRIV 6
#define INFO_PROCS 7
#define INFO_PROCCOLS 8
#define INFO_SPECCOLS 9
/*
* Modes for make_result/stmt_exec_int
*/
#define MAKERES_BLOCK 1
#define MAKERES_NOCLOSE 2
#define MAKERES_PREPARE 4
#define MAKERES_EXECD 8
#define EXEC_PARMXNULL(x) (16 | ((x) << 5))
#define EXEC_PARMXOUT(x) (((x) & 16) ? ((x) >> 5) : -1)
/*
* Modes for do_fetch
*/
#define DOFETCH_ARY 0
#define DOFETCH_HASH 1
#define DOFETCH_HASH2 2
#define DOFETCH_HASHK 3
#define DOFETCH_HASHK2 4
#define DOFETCH_HASHN 5
#define DOFETCH_MODES 7
#define DOFETCH_BANG 8
/*
* Size of segment when SQL_NO_TOTAL
*/
#define SEGSIZE 65536
/*
* Forward declarations.
*/
static SQLRETURN callsql(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt,
SQLRETURN ret, const char *m);
static VALUE stmt_exec(int argc, VALUE *argv, VALUE self);
static VALUE stmt_each(VALUE self);
static VALUE stmt_each_hash(int argc, VALUE *argv, VALUE self);
static VALUE stmt_close(VALUE self);
static VALUE stmt_drop(VALUE self);
/*
* Column name buffers on statement.
*/
static const char *colnamebuf[] = {
"@_c0", "@_c1", "@_c2", "@_c3"
};
/*
* Macro to align buffers.
*/
#define LEN_ALIGN(x) \
((x) + sizeof (double) - (((x) + sizeof (double)) % sizeof (double)))
/*
*----------------------------------------------------------------------
*
* Wrappers for long running SQL APIs with GVL released.
*
*----------------------------------------------------------------------
*/
#ifdef RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_
static void
empty_ubf(void *args)
{
}
struct S_SQLCONNECT {
SQLHDBC hdbc;
SQLTCHAR *dsn;
SQLSMALLINT dsn_len;
SQLTCHAR *usr;
SQLSMALLINT usr_len;
SQLTCHAR *pwd;
SQLSMALLINT pwd_len;
};
static void *
F_SQLCONNECT(void *args)
{
size_t ret;
struct S_SQLCONNECT *argp = (struct S_SQLCONNECT *) args;
ret = SQLConnect(argp->hdbc, argp->dsn, argp->dsn_len,
argp->usr, argp->usr_len, argp->pwd, argp->pwd_len);
return (void *) ret;
}
static inline SQLRETURN
SQLCONNECT(SQLHDBC hdbc, SQLTCHAR *dsn, SQLSMALLINT dsn_len, SQLTCHAR *usr,
SQLSMALLINT usr_len, SQLTCHAR *pwd, SQLSMALLINT pwd_len)
{
size_t ret;
struct S_SQLCONNECT arg;
arg.hdbc = hdbc;
arg.dsn = dsn;
arg.dsn_len = dsn_len;
arg.usr = usr;
arg.usr_len = usr_len;
arg.pwd = pwd;
arg.pwd_len = pwd_len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLCONNECT, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLDRIVERCONNECT {
SQLHDBC hdbc;
SQLHWND hwnd;
SQLTCHAR *connin;
SQLSMALLINT connin_len;
SQLTCHAR *connout;
SQLSMALLINT connout_max;
SQLSMALLINT *connout_len;
SQLUSMALLINT compl;
};
static void *
F_SQLDRIVERCONNECT(void *args)
{
size_t ret;
struct S_SQLDRIVERCONNECT *argp = (struct S_SQLDRIVERCONNECT *) args;
ret = SQLDriverConnect(argp->hdbc, argp->hwnd, argp->connin,
argp->connin_len, argp->connout, argp->connout_max,
argp->connout_len, argp->compl);
return (void *) ret;
}
static inline SQLRETURN
SQLDRIVERCONNECT(SQLHDBC hdbc, SQLHWND hwnd, SQLTCHAR *connin,
SQLSMALLINT connin_len, SQLTCHAR *connout,
SQLSMALLINT connout_max, SQLSMALLINT *connout_len,
SQLUSMALLINT compl)
{
size_t ret;
struct S_SQLDRIVERCONNECT arg;
arg.hdbc = hdbc;
arg.hwnd = hwnd;
arg.connin = connin;
arg.connin_len = connin_len;
arg.connout = connout;
arg.connout_max = connout_max;
arg.connout_len = connout_len;
arg.compl = compl;
ret = (size_t) rb_thread_call_without_gvl(F_SQLDRIVERCONNECT, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLDISCONNECT {
SQLHSTMT hstmt;
};
static void *
F_SQLDISCONNECT(void *args)
{
size_t ret;
struct S_SQLDISCONNECT *argp = (struct S_SQLDISCONNECT *) args;
ret = SQLDisconnect(argp->hstmt);
return (void *) ret;
}
static inline SQLRETURN
SQLDISCONNECT(SQLHSTMT hstmt)
{
size_t ret;
struct S_SQLDISCONNECT arg;
arg.hstmt = hstmt;
ret = (size_t) rb_thread_call_without_gvl(F_SQLDISCONNECT, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLTABLES {
SQLHSTMT hdbc;
SQLTCHAR *cat;
SQLSMALLINT cat_len;
SQLTCHAR *sch;
SQLSMALLINT sch_len;
SQLTCHAR *tbl;
SQLSMALLINT tbl_len;
SQLTCHAR *typ;
SQLSMALLINT typ_len;
};
static void *
F_SQLTABLES(void *args)
{
size_t ret;
struct S_SQLTABLES *argp = (struct S_SQLTABLES *) args;
ret = SQLTables(argp->hdbc, argp->cat, argp->cat_len,
argp->sch, argp->sch_len, argp->tbl,
argp->tbl_len, argp->typ, argp->typ_len);
return (void *) ret;
}
static inline SQLRETURN
SQLTABLES(SQLHDBC hdbc, SQLTCHAR *cat, SQLSMALLINT cat_len,
SQLTCHAR *sch, SQLSMALLINT sch_len, SQLTCHAR *tbl,
SQLSMALLINT tbl_len, SQLTCHAR *typ, SQLSMALLINT typ_len)
{
size_t ret;
struct S_SQLTABLES arg;
arg.hdbc = hdbc;
arg.cat = cat;
arg.cat_len = cat_len;
arg.sch = sch;
arg.sch_len = sch_len;
arg.tbl = tbl;
arg.tbl_len = tbl_len;
arg.typ = typ;
arg.typ_len = typ_len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLTABLES, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLCOLUMNS {
SQLHSTMT hdbc;
SQLTCHAR *cat;
SQLSMALLINT cat_len;
SQLTCHAR *sch;
SQLSMALLINT sch_len;
SQLTCHAR *tbl;
SQLSMALLINT tbl_len;
SQLTCHAR *col;
SQLSMALLINT col_len;
};
static void *
F_SQLCOLUMNS(void *args)
{
size_t ret;
struct S_SQLCOLUMNS *argp = (struct S_SQLCOLUMNS *) args;
ret = SQLColumns(argp->hdbc, argp->cat, argp->cat_len,
argp->sch, argp->sch_len, argp->tbl,
argp->tbl_len, argp->col, argp->col_len);
return (void *) ret;
}
static inline SQLRETURN
SQLCOLUMNS(SQLHDBC hdbc, SQLTCHAR *cat, SQLSMALLINT cat_len,
SQLTCHAR *sch, SQLSMALLINT sch_len, SQLTCHAR *tbl,
SQLSMALLINT tbl_len, SQLTCHAR *col, SQLSMALLINT col_len)
{
size_t ret;
struct S_SQLCOLUMNS arg;
arg.hdbc = hdbc;
arg.cat = cat;
arg.cat_len = cat_len;
arg.sch = sch;
arg.sch_len = sch_len;
arg.tbl = tbl;
arg.tbl_len = tbl_len;
arg.col = col;
arg.col_len = col_len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLCOLUMNS, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLPRIMARYKEYS {
SQLHSTMT hdbc;
SQLTCHAR *cat;
SQLSMALLINT cat_len;
SQLTCHAR *sch;
SQLSMALLINT sch_len;
SQLTCHAR *tbl;
SQLSMALLINT tbl_len;
};
static void *
F_SQLPRIMARYKEYS(void *args)
{
size_t ret;
struct S_SQLPRIMARYKEYS *argp = (struct S_SQLPRIMARYKEYS *) args;
ret = SQLPrimaryKeys(argp->hdbc, argp->cat, argp->cat_len,
argp->sch, argp->sch_len, argp->tbl, argp->tbl_len);
return (void *) ret;
}
static inline SQLRETURN
SQLPRIMARYKEYS(SQLHDBC hdbc, SQLTCHAR *cat, SQLSMALLINT cat_len,
SQLTCHAR *sch, SQLSMALLINT sch_len, SQLTCHAR *tbl,
SQLSMALLINT tbl_len)
{
size_t ret;
struct S_SQLPRIMARYKEYS arg;
arg.hdbc = hdbc;
arg.cat = cat;
arg.cat_len = cat_len;
arg.sch = sch;
arg.sch_len = sch_len;
arg.tbl = tbl;
arg.tbl_len = tbl_len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLPRIMARYKEYS, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLFOREIGNKEYS {
SQLHSTMT hdbc;
SQLTCHAR *pkcat;
SQLSMALLINT pkcat_len;
SQLTCHAR *pksch;
SQLSMALLINT pksch_len;
SQLTCHAR *pktbl;
SQLSMALLINT pktbl_len;
SQLTCHAR *fkcat;
SQLSMALLINT fkcat_len;
SQLTCHAR *fksch;
SQLSMALLINT fksch_len;
SQLTCHAR *fktbl;
SQLSMALLINT fktbl_len;
};
static void *
F_SQLFOREIGNKEYS(void *args)
{
size_t ret;
struct S_SQLFOREIGNKEYS *argp = (struct S_SQLFOREIGNKEYS *) args;
ret = SQLForeignKeys(argp->hdbc, argp->pkcat, argp->pkcat_len,
argp->pksch, argp->pksch_len,
argp->pktbl, argp->pktbl_len,
argp->fkcat, argp->fkcat_len,
argp->fksch, argp->fksch_len,
argp->fktbl, argp->fktbl_len);
return (void *) ret;
}
static inline SQLRETURN
SQLFOREIGNKEYS(SQLHDBC hdbc, SQLTCHAR *pkcat, SQLSMALLINT pkcat_len,
SQLTCHAR *pksch, SQLSMALLINT pksch_len, SQLTCHAR *pktbl,
SQLSMALLINT pktbl_len, SQLTCHAR *fkcat, SQLSMALLINT fkcat_len,
SQLTCHAR *fksch, SQLSMALLINT fksch_len, SQLTCHAR *fktbl,
SQLSMALLINT fktbl_len)
{
size_t ret;
struct S_SQLFOREIGNKEYS arg;
arg.hdbc = hdbc;
arg.pkcat = pkcat;
arg.pkcat_len = pkcat_len;
arg.pksch = pksch;
arg.pksch_len = pksch_len;
arg.pktbl = pktbl;
arg.pktbl_len = pktbl_len;
arg.fkcat = fkcat;
arg.fkcat_len = fkcat_len;
arg.fksch = fksch;
arg.fksch_len = fksch_len;
arg.fktbl = fktbl;
arg.fktbl_len = fktbl_len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLFOREIGNKEYS, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLPROCEDURES {
SQLHSTMT hdbc;
SQLTCHAR *cat;
SQLSMALLINT cat_len;
SQLTCHAR *sch;
SQLSMALLINT sch_len;
SQLTCHAR *prc;
SQLSMALLINT prc_len;
};
static void *
F_SQLPROCEDURES(void *args)
{
size_t ret;
struct S_SQLPROCEDURES *argp = (struct S_SQLPROCEDURES *) args;
ret = SQLProcedures(argp->hdbc, argp->cat, argp->cat_len,
argp->sch, argp->sch_len, argp->prc, argp->prc_len);
return (void *) ret;
}
static inline SQLRETURN
SQLPROCEDURES(SQLHDBC hdbc, SQLTCHAR *cat, SQLSMALLINT cat_len,
SQLTCHAR *sch, SQLSMALLINT sch_len, SQLTCHAR *prc,
SQLSMALLINT prc_len)
{
size_t ret;
struct S_SQLPROCEDURES arg;
arg.hdbc = hdbc;
arg.cat = cat;
arg.cat_len = cat_len;
arg.sch = sch;
arg.sch_len = sch_len;
arg.prc = prc;
arg.prc_len = prc_len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLPROCEDURES, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLPROCEDURECOLUMNS {
SQLHSTMT hdbc;
SQLTCHAR *cat;
SQLSMALLINT cat_len;
SQLTCHAR *sch;
SQLSMALLINT sch_len;
SQLTCHAR *prc;
SQLSMALLINT prc_len;
SQLTCHAR *col;
SQLSMALLINT col_len;
};
static void *
F_SQLPROCEDURECOLUMNS(void *args)
{
size_t ret;
struct S_SQLPROCEDURECOLUMNS *argp = (struct S_SQLPROCEDURECOLUMNS *) args;
ret = SQLProcedureColumns(argp->hdbc, argp->cat, argp->cat_len,
argp->sch, argp->sch_len, argp->prc,
argp->prc_len, argp->col, argp->col_len);
return (void *) ret;
}
static inline SQLRETURN
SQLPROCEDURECOLUMNS(SQLHDBC hdbc, SQLTCHAR *cat, SQLSMALLINT cat_len,
SQLTCHAR *sch, SQLSMALLINT sch_len, SQLTCHAR *prc,
SQLSMALLINT prc_len, SQLTCHAR *col, SQLSMALLINT col_len)
{
size_t ret;
struct S_SQLPROCEDURECOLUMNS arg;
arg.hdbc = hdbc;
arg.cat = cat;
arg.cat_len = cat_len;
arg.sch = sch;
arg.sch_len = sch_len;
arg.prc = prc;
arg.prc_len = prc_len;
arg.col = col;
arg.col_len = col_len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLPROCEDURECOLUMNS, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLTABLEPRIVILEGES {
SQLHSTMT hdbc;
SQLTCHAR *cat;
SQLSMALLINT cat_len;
SQLTCHAR *sch;
SQLSMALLINT sch_len;
SQLTCHAR *tbl;
SQLSMALLINT tbl_len;
};
static void *
F_SQLTABLEPRIVILEGES(void *args)
{
size_t ret;
struct S_SQLTABLEPRIVILEGES *argp = (struct S_SQLTABLEPRIVILEGES *) args;
ret = SQLTablePrivileges(argp->hdbc, argp->cat, argp->cat_len,
argp->sch, argp->sch_len, argp->tbl,
argp->tbl_len);
return (void *) ret;
}
static inline SQLRETURN
SQLTABLEPRIVILEGES(SQLHDBC hdbc, SQLTCHAR *cat, SQLSMALLINT cat_len,
SQLTCHAR *sch, SQLSMALLINT sch_len, SQLTCHAR *tbl,
SQLSMALLINT tbl_len)
{
size_t ret;
struct S_SQLTABLEPRIVILEGES arg;
arg.hdbc = hdbc;
arg.cat = cat;
arg.cat_len = cat_len;
arg.sch = sch;
arg.sch_len = sch_len;
arg.tbl = tbl;
arg.tbl_len = tbl_len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLTABLEPRIVILEGES, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLSTATISTICS {
SQLHSTMT hdbc;
SQLTCHAR *cat;
SQLSMALLINT cat_len;
SQLTCHAR *sch;
SQLSMALLINT sch_len;
SQLTCHAR *tbl;
SQLSMALLINT tbl_len;
SQLUSMALLINT uniq;
SQLUSMALLINT resv;
};
static void *
F_SQLSTATISTICS(void *args)
{
size_t ret;
struct S_SQLSTATISTICS *argp = (struct S_SQLSTATISTICS *) args;
ret = SQLStatistics(argp->hdbc, argp->cat, argp->cat_len,
argp->sch, argp->sch_len, argp->tbl,
argp->tbl_len, argp->uniq, argp->resv);
return (void *) ret;
}
static inline SQLRETURN
SQLSTATISTICS(SQLHDBC hdbc, SQLTCHAR *cat, SQLSMALLINT cat_len,
SQLTCHAR *sch, SQLSMALLINT sch_len, SQLTCHAR *tbl,
SQLSMALLINT tbl_len, SQLUSMALLINT uniq, SQLUSMALLINT resv)
{
size_t ret;
struct S_SQLSTATISTICS arg;
arg.hdbc = hdbc;
arg.cat = cat;
arg.cat_len = cat_len;
arg.sch = sch;
arg.sch_len = sch_len;
arg.tbl = tbl;
arg.tbl_len = tbl_len;
arg.uniq = uniq;
arg.resv = resv;
ret = (size_t) rb_thread_call_without_gvl(F_SQLSTATISTICS, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLSPECIALCOLUMNS {
SQLHSTMT hdbc;
SQLUSMALLINT idtyp;
SQLTCHAR *cat;
SQLSMALLINT cat_len;
SQLTCHAR *sch;
SQLSMALLINT sch_len;
SQLTCHAR *tbl;
SQLSMALLINT tbl_len;
SQLUSMALLINT scope;
SQLUSMALLINT nulbl;
};
static void *
F_SQLSPECIALCOLUMNS(void *args)
{
size_t ret;
struct S_SQLSPECIALCOLUMNS *argp = (struct S_SQLSPECIALCOLUMNS *) args;
ret = SQLSpecialColumns(argp->hdbc, argp->idtyp, argp->cat, argp->cat_len,
argp->sch, argp->sch_len, argp->tbl,
argp->tbl_len, argp->scope, argp->nulbl);
return (void *) ret;
}
static inline SQLRETURN
SQLSPECIALCOLUMNS(SQLHDBC hdbc, SQLUSMALLINT idtyp, SQLTCHAR *cat,
SQLSMALLINT cat_len, SQLTCHAR *sch, SQLSMALLINT sch_len,
SQLTCHAR *tbl, SQLSMALLINT tbl_len,
SQLUSMALLINT scope, SQLUSMALLINT nulbl)
{
size_t ret;
struct S_SQLSPECIALCOLUMNS arg;
arg.hdbc = hdbc;
arg.idtyp = idtyp;
arg.cat = cat;
arg.cat_len = cat_len;
arg.sch = sch;
arg.sch_len = sch_len;
arg.tbl = tbl;
arg.tbl_len = tbl_len;
arg.scope = scope;
arg.nulbl = nulbl;
ret = (size_t) rb_thread_call_without_gvl(F_SQLSPECIALCOLUMNS, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLGETTYPEINFO {
SQLHSTMT hdbc;
SQLSMALLINT type;
};
static void *
F_SQLGETTYPEINFO(void *args)
{
size_t ret;
struct S_SQLGETTYPEINFO *argp = (struct S_SQLGETTYPEINFO *) args;
ret = SQLGetTypeInfo(argp->hdbc, argp->type);
return (void *) ret;
}
static inline SQLRETURN
SQLGETTYPEINFO(SQLHDBC hdbc, SQLSMALLINT type)
{
size_t ret;
struct S_SQLGETTYPEINFO arg;
arg.hdbc = hdbc;
arg.type = type;
ret = (size_t) rb_thread_call_without_gvl(F_SQLGETTYPEINFO, &arg,
empty_ubf, &arg);
return ret;
}
#if (ODBCVER >= 0x0300)
struct S_SQLENDTRAN {
SQLSMALLINT htype;
SQLHANDLE handle;
SQLSMALLINT op;
};
static void *
F_SQLENDTRAN(void *args)
{
size_t ret;
struct S_SQLENDTRAN *argp = (struct S_SQLENDTRAN *) args;
ret = SQLEndTran(argp->htype, argp->handle, argp->op);
return (void *) ret;
}
static inline SQLRETURN
SQLENDTRAN(SQLUSMALLINT htype, SQLHANDLE handle, SQLUSMALLINT op)
{
size_t ret;
struct S_SQLENDTRAN arg;
arg.htype = htype;
arg.handle = handle;
arg.op = op;
ret = (size_t) rb_thread_call_without_gvl(F_SQLENDTRAN, &arg,
empty_ubf, &arg);
return ret;
}
#else
struct S_SQLTRANSACT {
SQLHENV henv;
SQLHDBC hdbc;
SQLSMALLINT op;
};
static void *
F_SQLTRANSACT(void *args)
{
size_t ret;
struct S_SQLTRANSACT *argp = (struct S_SQLTRANSACT *) args;
ret = SQLTransact(argp->henv, argp->hdbc, argp->op);
return (void *) ret;
}
static inline SQLRETURN
SQLTRANSACT(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT op)
{
size_t ret;
struct S_SQLTRANSACT arg;
arg.henv = henv;
arg.hdbc = hdbc;
arg.op = op;
ret = (size_t) rb_thread_call_without_gvl(F_SQLTRANCACT, &arg,
empty_ubf, &arg);
return ret;
}
#endif
struct S_SQLEXECDIRECT {
SQLHSTMT hstmt;
SQLTCHAR *sql;
SQLINTEGER len;
};
static void *
F_SQLEXECDIRECT(void *args)
{
size_t ret;
struct S_SQLEXECDIRECT *argp = (struct S_SQLEXECDIRECT *) args;
ret = SQLExecDirect(argp->hstmt, argp->sql, argp->len);
return (void *) ret;
}
static void
F_SQLEXECDIRECT_UBF(void *args)
{
struct S_SQLEXECDIRECT *argp = (struct S_SQLEXECDIRECT *) args;
SQLCancel(argp->hstmt);
}
static inline SQLRETURN
SQLEXECDIRECT(SQLHSTMT hstmt, SQLTCHAR *sql, SQLINTEGER len)
{
size_t ret;
struct S_SQLEXECDIRECT arg;
arg.hstmt = hstmt;
arg.sql = sql;
arg.len = len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLEXECDIRECT, &arg,
F_SQLEXECDIRECT_UBF, &arg);
return ret;
}
struct S_SQLEXECUTE {
SQLHSTMT hstmt;
};
static void *
F_SQLEXECUTE(void *args)
{
size_t ret;
struct S_SQLEXECUTE *argp = (struct S_SQLEXECUTE *) args;
ret = SQLExecute(argp->hstmt);
return (void *) ret;
}
static void
F_SQLEXECUTE_UBF(void *args)
{
struct S_SQLEXECUTE *argp = (struct S_SQLEXECUTE *) args;
SQLCancel(argp->hstmt);
}
static inline SQLRETURN
SQLEXECUTE(SQLHSTMT hstmt)
{
size_t ret;
struct S_SQLEXECUTE arg;
arg.hstmt = hstmt;
ret = (size_t) rb_thread_call_without_gvl(F_SQLEXECUTE, &arg,
F_SQLEXECUTE_UBF, &arg);
return ret;
}
struct S_SQLPREPARE {
SQLHSTMT hstmt;
SQLTCHAR *sql;
SQLINTEGER len;
};
static void *
F_SQLPREPARE(void *args)
{
size_t ret;
struct S_SQLPREPARE *argp = (struct S_SQLPREPARE *) args;
ret = SQLPrepare(argp->hstmt, argp->sql, argp->len);
return (void *) ret;
}
static void
F_SQLPREPARE_UBF(void *args)
{
struct S_SQLPREPARE *argp = (struct S_SQLPREPARE *) args;
SQLCancel(argp->hstmt);
}
static inline SQLRETURN
SQLPREPARE(SQLHSTMT hstmt, SQLTCHAR *sql, SQLINTEGER len)
{
size_t ret;
struct S_SQLPREPARE arg;
arg.hstmt = hstmt;
arg.sql = sql;
arg.len = len;
ret = (size_t) rb_thread_call_without_gvl(F_SQLPREPARE, &arg,
F_SQLPREPARE_UBF, &arg);
return ret;
}
struct S_SQLMORERESULTS {
SQLHSTMT hstmt;
};
static void *
F_SQLMORERESULTS(void *args)
{
size_t ret;
struct S_SQLMORERESULTS *argp = (struct S_SQLMORERESULTS *) args;
ret = SQLMoreResults(argp->hstmt);
return (void *) ret;
}
static inline SQLRETURN
SQLMORERESULTS(SQLHSTMT hstmt)
{
size_t ret;
struct S_SQLMORERESULTS arg;
arg.hstmt = hstmt;
ret = (size_t) rb_thread_call_without_gvl(F_SQLMORERESULTS, &arg,
empty_ubf, &arg);
return ret;
}
struct S_SQLFETCH {
SQLHSTMT hstmt;
};
static void *
F_SQLFETCH(void *args)
{
size_t ret;
struct S_SQLFETCH *argp = (struct S_SQLFETCH *) args;
ret = SQLFetch(argp->hstmt);
return (void *) ret;
}
static inline SQLRETURN
SQLFETCH(SQLHSTMT hstmt)
{
size_t ret;
struct S_SQLFETCH arg;
arg.hstmt = hstmt;
ret = (size_t) rb_thread_call_without_gvl(F_SQLFETCH, &arg,
empty_ubf, &arg);
return ret;
}
#if (ODBCVER >= 0x0300)
struct S_SQLFETCHSCROLL {
SQLHSTMT hstmt;
SQLSMALLINT dir;
SQLROWOFFSET offs;
};
static void *
F_SQLFETCHSCROLL(void *args)
{
size_t ret;
struct S_SQLFETCHSCROLL *argp = (struct S_SQLFETCHSCROLL *) args;
ret = SQLFetchScroll(argp->hstmt, argp->dir, argp->offs);
return (void *) ret;
}
static inline SQLRETURN
SQLFETCHSCROLL(SQLHSTMT hstmt, SQLSMALLINT dir, SQLROWOFFSET offs)
{
size_t ret;
struct S_SQLFETCHSCROLL arg;
arg.hstmt = hstmt;
arg.dir = dir;
arg.offs = offs;
ret = (size_t) rb_thread_call_without_gvl(F_SQLFETCHSCROLL, &arg,
empty_ubf, &arg);
return ret;
}
#else
struct S_SQLEXTENDEDFETCH {
SQLHSTMT hstmt;
SQLUSMALLINT type;
SQLROWOFFSET row;
SQLROWSETSIZE *rowp;
SQLUSMALLINT *status
};
static void *
F_SQLEXTENDEDFETCH(void *args)
{
size_t ret;
struct S_SQLEXTENDEDFETCH *argp = (struct S_SQLEXTENDEDFETCH *) args;
ret = SQLExtendedFetch(argp->hstmt, argp->type, argp->row, argp->rowp,
argp->status);
return (void *) ret;
}
static inline SQLRETURN
SQLEXTENDEDFETCH(SQLHSTMT hstmt, SQLUSMALLINT type, SQLROWOFFSET row,
SQLROWSETSIZE *rowp, SQLUSMALLINT *status)
{
size_t ret;
struct S_SQLEXTENDEDFETCH arg;
arg.hstmt = hstmt;
arg.type = type;
arg.row = row;
arg.rowp = rowp;
arg.status = status;
ret = (size_t) rb_thread_call_without_gvl(F_SQLEXTENDEDFETCH, &arg,
empty_ubf, &arg);
return ret;
}
#endif
#else
#define SQLCONNECT SQLConnect
#define SQLDRIVERCONNECT SQLDriverConnect
#define SQLDISCONNECT SQLDisconnect
#define SQLTABLES SQLTables
#define SQLCOLUMNS SQLColumns
#define SQLPRIMARYKEYS SQLPrimaryKeys
#define SQLFOREIGNKEYS SQLForeignKeys
#define SQLPROCEDURES SQLProcedures
#define SQLPROCEDURECOLUMNS SQLProcedureColumns
#define SQLTABLEPRIVILEGES SQLTablePrivileges
#define SQLSTATISTICS SQLStatistics
#define SQLSPECIALCOLUMNS SQLSpecialColumns
#define SQLGETTYPEINFO SQLGetTypeInfo
#if (ODBCVER >= 0x0300)
#define SQLENDTRAN SQLEndTran
#else
#define SQLTRANSACT SQLTransact
#endif
#define SQLEXECDIRECT SQLExecDirect
#define SQLEXECUTE SQLExecute
#define SQLPREPARE SQLPrepare
#define SQLMORERESULTS SQLMoreResults
#define SQLFETCH SQLFetch
#if (ODBCVER >= 0x0300)
#define SQLFETCHSCROLL SQLFetchScroll
#else
#define SQLEXTENDEDFETCH SQLExtendedFetch
#endif
#endif
/*
*----------------------------------------------------------------------
*
* UNICODE converters et.al.
*
*----------------------------------------------------------------------
*/
#ifdef UNICODE
static int
uc_strlen(SQLWCHAR *str)
{
int len = 0;
if (str != NULL) {
while (*str != '\0') {
++len;
++str;
}
}
return len;
}
static SQLWCHAR *
uc_strchr(SQLWCHAR *str, SQLWCHAR c)
{
if (str != NULL) {
while ((*str != '\0') && (*str != c)) {
++str;
}
str = (*str == c) ? str : NULL;
}
return str;
}
static int
mkutf(char *dest, SQLWCHAR *src, int len)
{
int i;
char *cp = dest;
for (i = 0; i < len; i++) {
unsigned long c = src[i];
if (sizeof (SQLWCHAR) == (2 * sizeof (char))) {
c &= 0xffff;
}
if (c < 0x80) {
*cp++ = c;
} else if (c < 0x800) {
*cp++ = 0xc0 | ((c >> 6) & 0x1f);
*cp++ = 0x80 | (c & 0x3f);
} else if (c < 0x10000) {
if ((sizeof (SQLWCHAR) == (2 * sizeof (char))) &&
(c >= 0xd800) && (c <= 0xdbff) && ((i + 1) < len)) {
unsigned long c2 = src[i + 1] & 0xffff;
if ((c2 >= 0xdc00) && (c <= 0xdfff)) {
c = ((c & 0x3ff) | ((c2 & 0x3ff) << 10)) + 0x10000;
*cp++ = 0xf0 | ((c >> 18) & 0x07);
*cp++ = 0x80 | ((c >> 12) & 0x3f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
++i;
continue;
}
}
*cp++ = 0xe0 | ((c >> 12) & 0x0f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
} else if (c < 0x200000) {
*cp++ = 0xf0 | ((c >> 18) & 0x07);
*cp++ = 0x80 | ((c >> 12) & 0x3f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
} else if (c < 0x4000000) {
*cp++ = 0xf8 | ((c >> 24) & 0x03);
*cp++ = 0x80 | ((c >> 18) & 0x3f);
*cp++ = 0x80 | ((c >> 12) & 0x3f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
} else if (c < 0x80000000) {
*cp++ = 0xfc | ((c >> 31) & 0x01);
*cp++ = 0x80 | ((c >> 24) & 0x3f);
*cp++ = 0x80 | ((c >> 18) & 0x3f);
*cp++ = 0x80 | ((c >> 12) & 0x3f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
}
}
*cp = '\0';
return cp - dest;
}
static VALUE
uc_tainted_str_new(SQLWCHAR *str, int len)
{
VALUE v;
char *cp = xmalloc(len * 6 + 1);
int ulen = 0;
if ((cp != NULL) && (str != NULL)) {
ulen = mkutf(cp, str, len);
}
v = rb_tainted_str_new((cp != NULL) ? cp : "", ulen);
#ifdef USE_RB_ENC
rb_enc_associate(v, rb_enc);
#endif
if (cp != NULL) {
xfree(cp);
}
return v;
}
static VALUE
uc_tainted_str_new2(SQLWCHAR *str)
{
return uc_tainted_str_new(str, uc_strlen(str));
}
static VALUE
uc_str_new(SQLWCHAR *str, int len)
{
VALUE v;
char *cp = xmalloc(len * 6 + 1);
int ulen = 0;
if ((cp != NULL) && (str != NULL)) {
ulen = mkutf(cp, str, len);
}
#ifdef USE_RB_ENC
v = rb_enc_str_new((cp != NULL) ? cp : "", ulen, rb_enc);
#else
v = rb_str_new((cp != NULL) ? cp : "", ulen);
#endif
if (cp != NULL) {
xfree(cp);
}
return v;
}
static VALUE
uc_str_new2(SQLWCHAR *str)
{
return uc_str_new(str, uc_strlen(str));
}
static VALUE
uc_str_cat(VALUE v, SQLWCHAR *str, int len)
{
VALUE vv = v;
char *cp = xmalloc(len * 6 + 1);
int ulen = 0;
if ((cp != NULL) && (str != NULL)) {
ulen = mkutf(cp, str, len);
}
if (cp != NULL) {
vv = rb_str_cat(v, cp, ulen);
xfree(cp);
}
return vv;
}
static SQLWCHAR *
uc_from_utf(unsigned char *str, int len)
{
SQLWCHAR *uc = NULL;
if (str != NULL) {
int i = 0;
unsigned char *strend;
if (len < 0) {
len = strlen((char *) str);
}
strend = str + len;
uc = ALLOC_N(SQLWCHAR, len + 1);
if (uc != NULL) {
while (str < strend) {
unsigned char c = str[0];
if (c < 0x80) {
uc[i++] = c;
++str;
} else if ((c <= 0xc1) || (c >= 0xf5)) {
/* illegal, ignored */
++str;
} else if (c < 0xe0) {
if ((str[1] & 0xc0) == 0x80) {
unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
uc[i++] = t;
str += 2;
} else {
uc[i++] = c;
++str;
}
} else if (c < 0xf0) {
if (((str[1] & 0xc0) == 0x80) &&
((str[2] & 0xc0) == 0x80)) {
unsigned long t = ((c & 0x0f) << 12) |
((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
uc[i++] = t;
str += 3;
} else {
uc[i++] = c;
++str;
}
} else if (c < 0xf8) {
if (((str[1] & 0xc0) == 0x80) &&
((str[2] & 0xc0) == 0x80) &&
((str[3] & 0xc0) == 0x80)) {
unsigned long t = ((c & 0x03) << 18) |
((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
(str[4] & 0x3f);
if ((sizeof (SQLWCHAR) == (2 * sizeof (char))) &&
(t >= 0x10000)) {
t -= 0x10000;
uc[i++] = 0xd800 | (t & 0x3ff);
t = 0xdc00 | ((t >> 10) & 0x3ff);
}
uc[i++] = t;
str += 4;
} else {
uc[i++] = c;
++str;
}
} else if (c < 0xfc) {
if (((str[1] & 0xc0) == 0x80) &&
((str[2] & 0xc0) == 0x80) &&
((str[3] & 0xc0) == 0x80) &&
((str[4] & 0xc0) == 0x80)) {
unsigned long t = ((c & 0x01) << 24) |
((str[1] & 0x3f) << 18) | ((str[2] & 0x3f) << 12) |
((str[4] & 0x3f) << 6) | (str[5] & 0x3f);
if ((sizeof (SQLWCHAR) == (2 * sizeof (char))) &&
(t >= 0x10000)) {
t -= 0x10000;
uc[i++] = 0xd800 | (t & 0x3ff);
t = 0xdc00 | ((t >> 10) & 0x3ff);
}
uc[i++] = t;
str += 5;
} else {
uc[i++] = c;
++str;
}
} else {
/* ignore */
++str;
}
}
uc[i] = 0;
}
}
return uc;
}
static void
uc_free(SQLWCHAR *str)
{
if (str != NULL) {
xfree(str);
}
}
#endif
/*
*----------------------------------------------------------------------
*
* Things for ODBC::DSN
*
*----------------------------------------------------------------------
*/
#ifndef HAVE_RB_DEFINE_ALLOC_FUNC
static VALUE
dsn_new(VALUE self)
{
VALUE obj = rb_obj_alloc(Cdsn);
rb_obj_call_init(obj, 0, NULL);
return obj;
}
#endif
static VALUE
dsn_init(VALUE self)
{
rb_iv_set(self, "@name", Qnil);
rb_iv_set(self, "@descr", Qnil);
return self;
}
/*
*----------------------------------------------------------------------
*
* Things for ODBC::Driver
*
*----------------------------------------------------------------------
*/
#ifndef HAVE_RB_DEFINE_ALLOC_FUNC
static VALUE
drv_new(VALUE self)
{
VALUE obj = rb_obj_alloc(Cdrv);
rb_obj_call_init(obj, 0, NULL);
return obj;
}
#endif
static VALUE
drv_init(VALUE self)
{
rb_iv_set(self, "@name", Qnil);
rb_iv_set(self, "@attrs", rb_hash_new());
return self;
}
/*
*----------------------------------------------------------------------
*
* Cleanup routines and GC mark/free callbacks.
*
*----------------------------------------------------------------------
*/
static void
list_init(LINK *link, int offs)
{
link->succ = link->pred = link->head = NULL;
link->offs = offs;
}
static void
list_add(LINK *link, LINK *head)
{
if (link->head != NULL) {
rb_fatal("RubyODBC: already in list");
}
if (head == NULL) {
rb_fatal("RubyODBC: invalid list head");
}
link->head = head;
link->pred = NULL;
link->succ = head->succ;
head->succ = link;
if (link->succ != NULL) {
link->succ->pred = link;
}
}
static void
list_del(LINK *link)
{
if (link == NULL) {
rb_fatal("RubyODBC: invalid list item");
}
if (link->head == NULL) {
rb_fatal("RubyODBC: item not in list");
}
if (link->succ != NULL) {
link->succ->pred = link->pred;
}
if (link->pred != NULL) {
link->pred->succ = link->succ;
} else {
link->head->succ = link->succ;
}
link->succ = link->pred = link->head = NULL;
}
static void *
list_first(LINK *head)
{
if (head->succ == NULL) {
return NULL;
}
return (void *) ((char *) head->succ - head->offs);
}
static int
list_empty(LINK *head)
{
return head->succ == NULL;
}
static void
free_env(ENV *e)
{
e->self = Qnil;
if (!list_empty(&e->dbcs)) {
return;
}
tracemsg(2, fprintf(stderr, "ObjFree: ENV %p\n", e););
if (e->henv != SQL_NULL_HENV) {
callsql(SQL_NULL_HENV, e->henv, SQL_NULL_HSTMT,
SQLFreeEnv(e->henv), "SQLFreeEnv");
e->henv = SQL_NULL_HENV;
}
xfree(e);
}
static void
link_dbc(DBC *p, ENV *e)
{
p->envp = e;
list_add(&p->link, &e->dbcs);
}
static void
unlink_dbc(DBC *p)
{
if (p == NULL) {
return;
}
p->env = Qnil;
if (p->envp != NULL) {
ENV *e = p->envp;
list_del(&p->link);
if (e->self == Qnil) {
free_env(e);
}
p->envp = NULL;
}
}
static void
free_dbc(DBC *p)
{
p->self = p->env = Qnil;
if (!list_empty(&p->stmts)) {
return;
}
tracemsg(2, fprintf(stderr, "ObjFree: DBC %p\n", p););
if (p->hdbc != SQL_NULL_HDBC) {
callsql(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLDISCONNECT(p->hdbc), "SQLDisconnect");
callsql(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLFreeConnect(p->hdbc), "SQLFreeConnect");
p->hdbc = SQL_NULL_HDBC;
}
unlink_dbc(p);
xfree(p);
}
static void
free_stmt_sub(STMT *q, int withp)
{
int i;
if (withp) {
if (q->paraminfo != NULL) {
for (i = 0; i < q->nump; i++) {
if (q->paraminfo[i].outbuf != NULL) {
xfree(q->paraminfo[i].outbuf);
}
}
xfree(q->paraminfo);
q->paraminfo = NULL;
}
q->nump = 0;
}
q->ncols = 0;
if (q->coltypes != NULL) {
xfree(q->coltypes);
q->coltypes = NULL;
}
if (q->colnames != NULL) {
xfree(q->colnames);
q->colnames = NULL;
}
if (q->colvals != NULL) {
xfree(q->colvals);
q->colvals = NULL;
}
if (q->dbufs != NULL) {
xfree(q->dbufs);
q->dbufs = NULL;
}
if (q->self != Qnil) {
VALUE v;
v = rb_iv_get(q->self, "@_a");
if (v != Qnil) {
rb_ary_clear(v);
}
v = rb_iv_get(q->self, "@_h");
if (v != Qnil) {
rb_iv_set(q->self, "@_h", rb_hash_new());
}
for (i = 0; i < 4; i++) {
v = rb_iv_get(q->self, colnamebuf[i]);
if (v != Qnil) {
rb_iv_set(q->self, colnamebuf[i], rb_hash_new());
}
}
}
}
static void
link_stmt(STMT *q, DBC *p)
{
q->dbcp = p;
list_add(&q->link, &p->stmts);
}
static void
unlink_stmt(STMT *q)
{
if (q == NULL) {
return;
}
q->dbc = Qnil;
if (q->dbcp != NULL) {
DBC *p = q->dbcp;
list_del(&q->link);
if (p->self == Qnil) {
free_dbc(p);
}
q->dbcp = NULL;
}
}
static void
free_stmt(STMT *q)
{
VALUE qself = q->self;
q->self = q->dbc = Qnil;
free_stmt_sub(q, 1);
tracemsg(2, fprintf(stderr, "ObjFree: STMT %p\n", q););
if (q->hstmt != SQL_NULL_HSTMT) {
/* Issue warning message. */
fprintf(stderr, "WARNING: # was not dropped"
" before garbage collection.\n", (long) qself);
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFreeStmt(q->hstmt, SQL_DROP), "SQLFreeStmt(SQL_DROP)");
q->hstmt = SQL_NULL_HSTMT;
}
unlink_stmt(q);
xfree(q);
}
static void
start_gc()
{
rb_funcall(rb_mGC, IDstart, 0, NULL);
}
static void
mark_dbc(DBC *p)
{
if (p->env != Qnil) {
rb_gc_mark(p->env);
}
}
static void
mark_stmt(STMT *q)
{
if (q->dbc != Qnil) {
rb_gc_mark(q->dbc);
}
}
/*
*----------------------------------------------------------------------
*
* Set internal error (or warning) message.
*
*----------------------------------------------------------------------
*/
static char *
set_err(const char *msg, int warn)
{
VALUE a, v = rb_str_new2("INTERN (0) [RubyODBC]");
v = rb_str_cat2(v, msg);
#ifdef USE_RB_ENC
rb_enc_associate(v, rb_enc);
#endif
a = rb_ary_new2(1);
rb_ary_push(a, rb_obj_taint(v));
CVAR_SET(Cobj, warn ? IDatatinfo : IDataterror, a);
return STR2CSTR(v);
}
/*
*----------------------------------------------------------------------
*
* Functions to retrieve last SQL error or warning.
*
*----------------------------------------------------------------------
*/
static char *
get_err_or_info(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, int isinfo)
{
#ifdef UNICODE
SQLWCHAR msg[SQL_MAX_MESSAGE_LENGTH], state[6 + 1];
#else
SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH], state[6 + 1];
#endif
char buf[32], tmp[SQL_MAX_MESSAGE_LENGTH];
SQLRETURN err;
SQLINTEGER nativeerr;
SQLSMALLINT len;
VALUE v0 = Qnil, a = Qnil, v;
int done = 0;
while (!done) {
v = Qnil;
err = tracesql(henv, hdbc, hstmt,
SQLError(henv, hdbc, hstmt, state, &nativeerr, msg,
SQL_MAX_MESSAGE_LENGTH - 1, &len),
"SQLError");
state[6] = '\0';
msg[SQL_MAX_MESSAGE_LENGTH - 1] = '\0';
switch (err) {
case SQL_SUCCESS:
#ifdef UNICODE
v = uc_str_new2(state);
#else
v = rb_str_new2((char *) state);
#endif
sprintf(buf, " (%d) ", (int) nativeerr);
v = rb_str_cat2(v, buf);
#ifdef UNICODE
v = uc_str_cat(v, msg, len);
#else
v = rb_str_cat(v, (char *) msg, len);
#endif
break;
case SQL_NO_DATA:
if ((v0 == Qnil) && (!isinfo)) {
v = rb_str_new2("INTERN (0) [RubyODBC]No data found");
} else {
v = Qnil;
}
done = 1;
break;
case SQL_INVALID_HANDLE:
v = rb_str_new2("INTERN (0) [RubyODBC]Invalid handle");
done = 1;
break;
case SQL_ERROR:
v = rb_str_new2("INTERN (0) [RubyODBC]Error reading error message");
done = 1;
break;
default:
sprintf(tmp, "INTERN (0) [RubyODBC]Unknown error %d", (int) err);
v = rb_str_new2(tmp);
done = 1;
break;
}
if (v != Qnil) {
if (v0 == Qnil) {
v0 = v;
a = rb_ary_new();
}
rb_ary_push(a, rb_obj_taint(v));
tracemsg(1, fprintf(stderr, " | %s\n", STR2CSTR(v)););
}
}
CVAR_SET(Cobj, isinfo ? IDatatinfo : IDataterror, a);
if (isinfo) {
return NULL;
}
return (v0 == Qnil) ? NULL : STR2CSTR(v0);
}
#if defined(HAVE_SQLINSTALLERERROR) || (defined(UNICODE) && defined(HAVE_SQLINSTALLERERRORW))
static char *
get_installer_err()
{
#ifdef UNICODE
#ifdef HAVE_SQLINSTALLERERRORW
int have_w = 1;
#else
int have_w = 0;
#endif
SQLWCHAR msg[SQL_MAX_MESSAGE_LENGTH];
#else
char msg[SQL_MAX_MESSAGE_LENGTH];
#endif
char buf[128];
SQLRETURN err;
VALUE v0 = Qnil, a = Qnil, v;
int done = 0;
WORD i, len;
DWORD insterrcode;
for (i = 1; (!done) && (i <= 8); i++) {
v = Qnil;
#ifdef UNICODE
#ifdef USE_DLOPEN_FOR_ODBC_LIBS
have_w = ruby_odbc_have_func("SQLInstallerErrorW", SQLInstallerErrorW);
#endif
if (have_w) {
err = tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLInstallerErrorW(i, &insterrcode, msg,
SQL_MAX_MESSAGE_LENGTH, &len),
"SQLInstallerErrorW");
msg[SQL_MAX_MESSAGE_LENGTH - 1] = 0;
} else {
err = tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLInstallerError(i, &insterrcode, (char *) msg,
SQL_MAX_MESSAGE_LENGTH, &len),
"SQLInstallerErrorW");
((char *) msg)[SQL_MAX_MESSAGE_LENGTH - 1] = '\0';
}
#else
err = tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLInstallerError(i, &insterrcode, msg,
SQL_MAX_MESSAGE_LENGTH, &len),
"SQLInstallerError");
msg[SQL_MAX_MESSAGE_LENGTH - 1] = '\0';
#endif
switch (err) {
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
sprintf(buf, "INSTALLER (%d) ", (int) insterrcode);
v = rb_str_new2(buf);
#ifdef UNICODE
if (have_w) {
#ifdef USE_RB_ENC
rb_enc_associate(v, rb_enc);
#endif
v = uc_str_cat(v, msg, len);
} else {
v = rb_str_cat(v, (char *) msg, len);
}
#else
v = rb_str_cat(v, msg, len);
#endif
break;
case SQL_NO_DATA:
done = 1;
break;
case SQL_ERROR:
v = rb_str_new2("INTERN (0) [RubyODBC]");
v = rb_str_cat2(v, "Error reading installer error message");
done = 1;
break;
default:
v = rb_str_new2("INTERN (0) [RubyODBC]");
sprintf(buf, "Unknown installer error %d", (int) err);
v = rb_str_cat2(v, buf);
done = 1;
break;
}
if (v != Qnil) {
if (v0 == Qnil) {
v0 = v;
a = rb_ary_new();
}
rb_ary_push(a, rb_obj_taint(v));
tracemsg(1, fprintf(stderr, " | %s\n", STR2CSTR(v)););
}
}
CVAR_SET(Cobj, IDataterror, a);
return (v0 == Qnil) ? NULL : STR2CSTR(v0);
}
#endif
static char *
get_err(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt)
{
return get_err_or_info(henv, hdbc, hstmt, 0);
}
#ifdef TRACING
static void
trace_sql_ret(SQLRETURN ret)
{
char msg[32];
const char *p;
switch (ret) {
case SQL_SUCCESS:
p = "SQL_SUCCESS";
break;
case SQL_SUCCESS_WITH_INFO:
p = "SQL_SUCCESS_WITH_INFO";
break;
case SQL_NO_DATA:
p = "SQL_NO_DATA";
break;
case SQL_ERROR:
p = "SQL_ERROR";
break;
case SQL_INVALID_HANDLE:
p = "SQL_INVALID_HANDLE";
break;
default:
sprintf(msg, "SQL_RETURN=%d", (int) ret);
p = msg;
break;
}
fprintf(stderr, " < %s\n", p);
}
static SQLRETURN
tracesql(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN ret,
const char *m)
{
if (tracing & 1) {
fprintf(stderr, "SQLCall: %s", m);
fprintf(stderr, "\n > HENV=0x%lx, HDBC=0x%lx, HSTMT=0x%lx\n",
(long) henv, (long) hdbc, (long) hstmt);
trace_sql_ret(ret);
}
return ret;
}
#endif
static SQLRETURN
callsql(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN ret,
const char *m)
{
SQLRETURN err;
err = tracesql(henv, hdbc, hstmt, ret, m);
if (err != SQL_SUCCESS) {
#ifdef UNICODE
SQLWCHAR msg[SQL_MAX_MESSAGE_LENGTH], state[6 + 1];
#else
SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH], state[6 + 1];
#endif
SQLINTEGER nativeerr;
SQLSMALLINT len;
int done = 0;
while (!done) {
err = tracesql(henv, hdbc, hstmt,
SQLError(henv, hdbc, hstmt, state, &nativeerr, msg,
SQL_MAX_MESSAGE_LENGTH - 1, &len),
"SQLError");
switch (err) {
case SQL_SUCCESS:
break;
case SQL_NO_DATA:
case SQL_INVALID_HANDLE:
case SQL_ERROR:
default:
done = 1;
break;
}
}
}
return ret;
}
static int
succeeded_common(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN ret,
char **msgp)
{
if (!SQL_SUCCEEDED(ret)) {
char *dummy;
if (msgp == NULL) {
msgp = &dummy;
}
*msgp = get_err_or_info(henv, hdbc, hstmt, 0);
return 0;
}
if (ret == SQL_SUCCESS_WITH_INFO) {
get_err_or_info(henv, hdbc, hstmt, 1);
} else {
CVAR_SET(Cobj, IDatatinfo, Qnil);
}
return 1;
}
static int
succeeded(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN ret,
char **msgp, const char *m, ...)
{
#ifdef TRACING
va_list args;
if (tracing & 1) {
va_start(args, m);
fprintf(stderr, "SQLCall: ");
vfprintf(stderr, m, args);
va_end(args);
fprintf(stderr, "\n > HENV=0x%lx, HDBC=0x%lx, HSTMT=0x%lx\n",
(long) henv, (long) hdbc, (long) hstmt);
trace_sql_ret(ret);
}
#endif
return succeeded_common(henv, hdbc, hstmt, ret, msgp);
}
static int
succeeded_nodata(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN ret,
char **msgp, const char *m, ...)
{
#ifdef TRACING
va_list args;
if (tracing & 1) {
va_start(args, m);
fprintf(stderr, "SQLCall: ");
vfprintf(stderr, m, args);
va_end(args);
fprintf(stderr, "\n > HENV=0x%lx, HDBC=0x%lx, HSTMT=0x%lx\n",
(long) henv, (long) hdbc, (long) hstmt);
trace_sql_ret(ret);
}
#endif
if (ret == SQL_NO_DATA) {
CVAR_SET(Cobj, IDatatinfo, Qnil);
return 1;
}
return succeeded_common(henv, hdbc, hstmt, ret, msgp);
}
/*
*----------------------------------------------------------------------
*
* Return ENV from VALUE.
*
*----------------------------------------------------------------------
*/
static VALUE
env_of(VALUE self)
{
if (rb_obj_is_kind_of(self, Cstmt) == Qtrue) {
STMT *q;
Data_Get_Struct(self, STMT, q);
self = q->dbc;
if (self == Qnil) {
rb_raise(Cerror, "%s", set_err("Stale ODBC::Statement", 0));
}
}
if (rb_obj_is_kind_of(self, Cdbc) == Qtrue) {
DBC *p;
Data_Get_Struct(self, DBC, p);
self = p->env;
if (self == Qnil) {
rb_raise(Cerror, "%s", set_err("Stale ODBC::Database", 0));
}
}
return self;
}
static ENV *
get_env(VALUE self)
{
ENV *e;
Data_Get_Struct(env_of(self), ENV, e);
return e;
}
/*
*----------------------------------------------------------------------
*
* Return DBC from VALUE.
*
*----------------------------------------------------------------------
*/
static DBC *
get_dbc(VALUE self)
{
DBC *p;
if (rb_obj_is_kind_of(self, Cstmt) == Qtrue) {
STMT *q;
Data_Get_Struct(self, STMT, q);
self = q->dbc;
if (self == Qnil) {
rb_raise(Cerror, "%s", set_err("Stale ODBC::Statement", 0));
}
}
Data_Get_Struct(self, DBC, p);
return p;
}
/*
*----------------------------------------------------------------------
*
* Raise ODBC error from Ruby.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_raise(VALUE self, VALUE msg)
{
VALUE a, v;
char buf[SQL_MAX_MESSAGE_LENGTH + 1], *p;
if (TYPE(msg) == T_STRING) {
v = msg;
} else {
v = rb_any_to_s(msg);
}
strcpy(buf, "INTERN (1) [RubyODBC]");
p = STR2CSTR(v);
strncat(buf, p, SQL_MAX_MESSAGE_LENGTH - strlen(buf));
buf[SQL_MAX_MESSAGE_LENGTH] = '\0';
v = rb_str_new2(buf);
a = rb_ary_new2(1);
rb_ary_push(a, rb_obj_taint(v));
CVAR_SET(Cobj, IDataterror, a);
rb_raise(Cerror, "%s", buf);
return Qnil;
}
/*
*----------------------------------------------------------------------
*
* Obtain an ENV.
*
*----------------------------------------------------------------------
*/
static VALUE
env_new(VALUE self)
{
ENV *e;
SQLHENV henv = SQL_NULL_HENV;
VALUE obj;
if (TYPE(self) == T_MODULE) {
self = Cobj;
}
if (self == Cobj) {
self = Cenv;
}
if ((!SQL_SUCCEEDED(SQLAllocEnv(&henv))) || (henv == SQL_NULL_HENV)) {
rb_raise(Cerror, "%s", set_err("Cannot allocate SQLHENV", 0));
}
obj = Data_Make_Struct(self, ENV, NULL, free_env, e);
tracemsg(2, fprintf(stderr, "ObjAlloc: ENV %p\n", e););
e->self = obj;
e->henv = henv;
list_init(&e->dbcs, offsetof(DBC, link));
#if defined(UNICODE) && defined(SQL_OV_ODBC3)
callsql(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3, 0),
"SQLSetEnvAttr(SQL_OV_ODBC3)");
#endif
return obj;
}
/*
*----------------------------------------------------------------------
*
* Obtain array of known DSNs.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_dsns(VALUE self)
{
#ifdef UNICODE
SQLWCHAR dsn[SQL_MAX_DSN_LENGTH], descr[SQL_MAX_MESSAGE_LENGTH * 2];
#else
char dsn[SQL_MAX_DSN_LENGTH], descr[SQL_MAX_MESSAGE_LENGTH * 2];
#endif
SQLSMALLINT dsnLen = 0, descrLen = 0;
int first = 1;
VALUE env, aret;
ENV *e;
env = env_new(Cenv);
Data_Get_Struct(env, ENV, e);
aret = rb_ary_new();
while (succeeded(e->henv, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLDataSources(e->henv, (SQLUSMALLINT) (first ?
SQL_FETCH_FIRST : SQL_FETCH_NEXT),
(SQLTCHAR *) dsn,
(SQLSMALLINT) sizeof (dsn), &dsnLen,
(SQLTCHAR *) descr,
(SQLSMALLINT) sizeof (descr),
&descrLen),
NULL, "SQLDataSources")) {
VALUE odsn = rb_obj_alloc(Cdsn);
#ifdef UNICODE
dsnLen = (dsnLen == 0) ? (SQLSMALLINT) uc_strlen(dsn) :
(SQLSMALLINT) (dsnLen / sizeof (SQLWCHAR));
descrLen = (descrLen == 0) ?
(SQLSMALLINT) uc_strlen(descr) :
(SQLSMALLINT) (descrLen / sizeof (SQLWCHAR));
rb_iv_set(odsn, "@name", uc_tainted_str_new(dsn, dsnLen));
rb_iv_set(odsn, "@descr", uc_tainted_str_new(descr, descrLen));
#else
dsnLen = (dsnLen == 0) ? (SQLSMALLINT) strlen(dsn) : dsnLen;
descrLen = (descrLen == 0) ? (SQLSMALLINT) strlen(descr) : descrLen;
rb_iv_set(odsn, "@name", rb_tainted_str_new(dsn, dsnLen));
rb_iv_set(odsn, "@descr", rb_tainted_str_new(descr, descrLen));
#endif
rb_ary_push(aret, odsn);
first = dsnLen = descrLen = 0;
}
return aret;
}
/*
*----------------------------------------------------------------------
*
* Obtain array of known drivers.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_drivers(VALUE self)
{
#ifdef UNICODE
SQLWCHAR driver[SQL_MAX_MESSAGE_LENGTH], attrs[SQL_MAX_MESSAGE_LENGTH * 2];
SQLWCHAR *attr;
#else
char driver[SQL_MAX_MESSAGE_LENGTH], attrs[SQL_MAX_MESSAGE_LENGTH * 2];
char *attr;
#endif
SQLSMALLINT driverLen = 0, attrsLen = 0;
int first = 1;
VALUE env, aret;
ENV *e;
env = env_new(Cenv);
Data_Get_Struct(env, ENV, e);
aret = rb_ary_new();
while (succeeded(e->henv, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLDrivers(e->henv, (SQLUSMALLINT) (first ?
SQL_FETCH_FIRST : SQL_FETCH_NEXT),
(SQLTCHAR *) driver,
(SQLSMALLINT) sizeof (driver), &driverLen,
(SQLTCHAR *) attrs,
(SQLSMALLINT) sizeof (attrs), &attrsLen),
NULL, "SQLDrivers")) {
VALUE odrv = rb_obj_alloc(Cdrv);
VALUE h = rb_hash_new();
int count = 0;
#ifdef UNICODE
driverLen = (driverLen == 0) ?
(SQLSMALLINT) uc_strlen(driver) :
(SQLSMALLINT) (driverLen / sizeof (SQLWCHAR));
rb_iv_set(odrv, "@name", uc_tainted_str_new(driver, driverLen));
for (attr = attrs; *attr; attr += uc_strlen(attr) + 1) {
SQLWCHAR *p = uc_strchr(attr, (SQLWCHAR) '=');
if ((p != NULL) && (p != attr)) {
rb_hash_aset(h,
uc_tainted_str_new(attr, (p - attr) /
sizeof (SQLWCHAR)),
uc_tainted_str_new2(p + 1));
count++;
}
}
#else
driverLen = (driverLen == 0) ? (SQLSMALLINT) strlen(driver) : driverLen;
rb_iv_set(odrv, "@name", rb_tainted_str_new(driver, driverLen));
for (attr = attrs; *attr; attr += strlen(attr) + 1) {
char *p = strchr(attr, '=');
if ((p != NULL) && (p != attr)) {
rb_hash_aset(h, rb_tainted_str_new(attr, p - attr),
rb_tainted_str_new2(p + 1));
count++;
}
}
#endif
if (count > 0) {
rb_iv_set(odrv, "@attrs", h);
}
rb_ary_push(aret, odrv);
first = driverLen = attrsLen = 0;
}
return aret;
}
/*
*----------------------------------------------------------------------
*
* Management methods.
*
*----------------------------------------------------------------------
*/
#ifdef HAVE_ODBCINST_H
static VALUE
conf_dsn(int argc, VALUE *argv, VALUE self, int op)
{
VALUE drv, attr, issys, astr;
#ifdef UNICODE
#ifdef HAVE_SQLCONFIGDATASOURCEW
int have_w = 1;
#else
int have_w = 0;
#endif
SQLWCHAR *sdrv, *sastr;
#else
char *sdrv, *sastr;
#endif
rb_scan_args(argc, argv, "12", &drv, &attr, &issys);
if (rb_obj_is_kind_of(drv, Cdrv) == Qtrue) {
VALUE a, x;
if (argc > 2) {
rb_raise(rb_eArgError, "wrong # of arguments");
}
x = rb_iv_get(drv, "@name");
a = rb_iv_get(drv, "@attrs");
issys = attr;
drv = x;
attr = a;
}
Check_Type(drv, T_STRING);
if (RTEST(issys)) {
switch (op) {
case ODBC_ADD_DSN: op = ODBC_ADD_SYS_DSN; break;
case ODBC_CONFIG_DSN: op = ODBC_CONFIG_SYS_DSN; break;
case ODBC_REMOVE_DSN: op = ODBC_REMOVE_SYS_DSN; break;
}
}
astr = rb_str_new2("");
if (rb_obj_is_kind_of(attr, rb_cHash) == Qtrue) {
VALUE a, x;
a = rb_funcall(attr, IDkeys, 0, NULL);
while ((x = rb_ary_shift(a)) != Qnil) {
VALUE v = rb_hash_aref(attr, x);
astr = rb_str_concat(astr, x);
astr = rb_str_cat2(astr, "=");
astr = rb_str_concat(astr, v);
astr = rb_str_cat(astr, "", 1);
}
}
astr = rb_str_cat(astr, "", 1);
#ifdef UNICODE
#ifdef USE_DLOPEN_FOR_ODBC_LIBS
have_w = ruby_odbc_have_func("SQLConfigDataSourceW", SQLConfigDataSourceW);
#endif
if (have_w) {
#ifdef USE_RB_ENC
drv = rb_funcall(drv, IDencode, 1, rb_encv);
astr = rb_funcall(astr, IDencode, 1, rb_encv);
#endif
sdrv = uc_from_utf((unsigned char *) STR2CSTR(drv), -1);
sastr = uc_from_utf((unsigned char *) STR2CSTR(astr), -1);
if ((sdrv == NULL) || (sastr == NULL)) {
uc_free(sdrv);
uc_free(sastr);
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
if (SQLConfigDataSourceW(NULL, (WORD) op,
(LPWSTR) sdrv, (LPWSTR) sastr)) {
uc_free(sdrv);
uc_free(sastr);
return Qnil;
}
uc_free(sdrv);
uc_free(sastr);
} else {
sdrv = (SQLWCHAR *) STR2CSTR(drv);
sastr = (SQLWCHAR *) STR2CSTR(astr);
if (SQLConfigDataSource(NULL, (WORD) op,
(LPCSTR) sdrv, (LPCSTR) sastr)) {
return Qnil;
}
}
#else
sdrv = STR2CSTR(drv);
sastr = STR2CSTR(astr);
if (SQLConfigDataSource(NULL, (WORD) op, sdrv, sastr)) {
return Qnil;
}
#endif
#if defined(HAVE_SQLINSTALLERERROR) || (defined(UNICODE) && defined(HAVE_SQLINSTALLERERRORW))
rb_raise(Cerror, "%s", set_err(get_installer_err(), 0));
#else
rb_raise(Cerror, "%s", set_err("DSN configuration error", 0));
#endif
return Qnil;
}
#endif
static VALUE
dbc_adddsn(int argc, VALUE *argv, VALUE self)
{
#ifdef HAVE_ODBCINST_H
return conf_dsn(argc, argv, self, ODBC_ADD_DSN);
#else
rb_raise(Cerror, "%s", set_err("ODBC::add_dsn not supported", 0));
return Qnil;
#endif
}
static VALUE
dbc_confdsn(int argc, VALUE *argv, VALUE self)
{
#ifdef HAVE_ODBCINST_H
return conf_dsn(argc, argv, self, ODBC_CONFIG_DSN);
#else
rb_raise(Cerror, "%s", set_err("ODBC::config_dsn not supported", 0));
return Qnil;
#endif
}
static VALUE
dbc_deldsn(int argc, VALUE *argv, VALUE self)
{
#ifdef HAVE_ODBCINST_H
return conf_dsn(argc, argv, self, ODBC_REMOVE_DSN);
#else
rb_raise(Cerror, "%s", set_err("ODBC::del_dsn not supported", 0));
return Qnil;
#endif
}
static VALUE
dbc_wfdsn(int argc, VALUE *argv, VALUE self)
{
#ifdef HAVE_ODBCINST_H
VALUE fname, aname, kname, val;
#ifdef UNICODE
#ifdef HAVE_SQLWRITEFILEDSNW
int have_w = 1;
#else
int have_w = 0;
#endif
SQLWCHAR *sfname, *saname, *skname, *sval = NULL;
#else
char *sfname, *saname, *skname, *sval = NULL;
#endif
rb_scan_args(argc, argv, "31", &fname, &aname, &kname, &val);
Check_Type(fname, T_STRING);
Check_Type(aname, T_STRING);
Check_Type(kname, T_STRING);
if (val != Qnil) {
Check_Type(val, T_STRING);
}
#ifdef UNICODE
#ifdef USE_DLOPEN_FOR_ODBC_LIBS
have_w = ruby_odbc_have_func("SQLWriteFileDSNW", SQLWriteFileDSNW);
#endif
if (have_w) {
BOOL rc;
#ifdef USE_RB_ENC
fname = rb_funcall(fname, IDencode, 1, rb_encv);
aname = rb_funcall(aname, IDencode, 1, rb_encv);
kname = rb_funcall(kname, IDencode, 1, rb_encv);
if (val != Qnil) {
val = rb_funcall(val, IDencode, 1, rb_encv);
}
#endif
sfname = uc_from_utf((unsigned char *) STR2CSTR(fname), -1);
saname = uc_from_utf((unsigned char *) STR2CSTR(aname), -1);
skname = uc_from_utf((unsigned char *) STR2CSTR(kname), -1);
if ((sfname == NULL) || (saname == NULL) || (skname == NULL)) {
nomem:
uc_free(sfname);
uc_free(saname);
uc_free(skname);
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
if (val != Qnil) {
sval = uc_from_utf((unsigned char *) STR2CSTR(val), -1);
if (sval == NULL) {
goto nomem;
}
}
rc = SQLWriteFileDSNW(sfname, saname, skname, sval);
uc_free(sfname);
uc_free(saname);
uc_free(skname);
uc_free(sval);
if (rc) {
return Qnil;
}
} else {
sfname = (SQLWCHAR *) STR2CSTR(fname);
saname = (SQLWCHAR *) STR2CSTR(aname);
skname = (SQLWCHAR *) STR2CSTR(kname);
if (val != Qnil) {
sval = (SQLWCHAR *) STR2CSTR(val);
}
if (SQLWriteFileDSN((LPCSTR) sfname, (LPCSTR) saname,
(LPCSTR) skname, (LPCSTR) sval)) {
return Qnil;
}
}
#else
sfname = STR2CSTR(fname);
saname = STR2CSTR(aname);
skname = STR2CSTR(kname);
if (val != Qnil) {
sval = STR2CSTR(val);
}
if (SQLWriteFileDSN(sfname, saname, skname, sval)) {
return Qnil;
}
#endif
#if defined(HAVE_SQLINSTALLERERROR) || (defined(UNICODE) && defined(HAVE_SQLINSTALLERERRORW))
rb_raise(Cerror, "%s", set_err(get_installer_err(), 0));
#else
rb_raise(Cerror, "%s", set_err("File DSN configuration error", 0));
#endif
#else
rb_raise(Cerror, "%s", set_err("ODBC::write_file_dsn not supported", 0));
#endif
return Qnil;
}
static VALUE
dbc_rfdsn(int argc, VALUE *argv, VALUE self)
{
#ifdef HAVE_ODBCINST_H
VALUE fname, aname, kname;
#ifdef UNICODE
#ifdef HAVE_SQLREADFILEDSNW
int have_w = 1;
#else
int have_w = 0;
#endif
SQLWCHAR *sfname, *saname, *skname, valbuf[SQL_MAX_MESSAGE_LENGTH];
#else
char *sfname, *saname, *skname, valbuf[SQL_MAX_MESSAGE_LENGTH];
#endif
rb_scan_args(argc, argv, "30", &fname, &aname, &kname);
Check_Type(fname, T_STRING);
Check_Type(aname, T_STRING);
Check_Type(kname, T_STRING);
#ifdef UNICODE
#ifdef USE_DLOPEN_FOR_ODBC_LIBS
have_w = ruby_odbc_have_func("SQLReadFileDSNW", SQLReadFileDSNW);
#endif
if (have_w) {
BOOL rc;
#ifdef USE_RB_ENC
fname = rb_funcall(fname, IDencode, 1, rb_encv);
aname = rb_funcall(aname, IDencode, 1, rb_encv);
kname = rb_funcall(kname, IDencode, 1, rb_encv);
#endif
sfname = uc_from_utf((unsigned char *) STR2CSTR(fname), -1);
saname = uc_from_utf((unsigned char *) STR2CSTR(aname), -1);
skname = uc_from_utf((unsigned char *) STR2CSTR(kname), -1);
valbuf[0] = 0;
if ((sfname == NULL) || (saname == NULL) || (skname == NULL)) {
uc_free(sfname);
uc_free(saname);
uc_free(skname);
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
rc = SQLReadFileDSNW(sfname, saname, skname, valbuf,
sizeof (valbuf), NULL);
uc_free(sfname);
uc_free(saname);
uc_free(skname);
if (rc) {
return uc_tainted_str_new2(valbuf);
}
} else {
sfname = (SQLWCHAR *) STR2CSTR(fname);
saname = (SQLWCHAR *) STR2CSTR(aname);
skname = (SQLWCHAR *) STR2CSTR(kname);
valbuf[0] = '\0';
if (SQLReadFileDSN((LPCSTR) sfname, (LPCSTR) saname,
(LPCSTR) skname, (LPSTR) valbuf,
sizeof (valbuf), NULL)) {
return rb_tainted_str_new2((char *) valbuf);
}
}
#else
sfname = STR2CSTR(fname);
saname = STR2CSTR(aname);
skname = STR2CSTR(kname);
valbuf[0] = '\0';
if (SQLReadFileDSN(sfname, saname, skname, valbuf,
sizeof (valbuf), NULL)) {
return rb_tainted_str_new2(valbuf);
}
#endif
#if defined(HAVE_SQLINSTALLERERROR) || (defined(UNICODE) && defined(HAVE_SQLINSTALLERERRORW))
rb_raise(Cerror, "%s", set_err(get_installer_err(), 0));
#else
rb_raise(Cerror, "%s", set_err("File DSN configuration error", 0));
#endif
#else
rb_raise(Cerror, "%s", set_err("ODBC::read_file_dsn not supported", 0));
return Qnil;
#endif
}
/*
*----------------------------------------------------------------------
*
* Return last ODBC error or warning.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_error(VALUE self)
{
return rb_cvar_get(Cobj, IDataterror);
}
static VALUE
dbc_warn(VALUE self)
{
return rb_cvar_get(Cobj, IDatatinfo);
}
static VALUE
dbc_clrerror(VALUE self)
{
CVAR_SET(Cobj, IDataterror, Qnil);
CVAR_SET(Cobj, IDatatinfo, Qnil);
return Qnil;
}
/*
*----------------------------------------------------------------------
*
* Connection instance initializer.
*
*----------------------------------------------------------------------
*/
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
static VALUE
dbc_alloc(VALUE self)
{
DBC *p;
VALUE obj = Data_Make_Struct(self, DBC, mark_dbc, free_dbc, p);
tracemsg(2, fprintf(stderr, "ObjAlloc: DBC %p\n", p););
list_init(&p->link, offsetof(DBC, link));
p->self = obj;
p->env = Qnil;
p->envp = NULL;
list_init(&p->stmts, offsetof(STMT, link));
p->hdbc = SQL_NULL_HDBC;
p->rbtime = Qfalse;
p->gmtime = Qfalse;
return obj;
}
#endif
static VALUE
dbc_new(int argc, VALUE *argv, VALUE self)
{
DBC *p;
VALUE obj, env = Qnil;
if (TYPE(self) == T_MODULE) {
self = Cobj;
}
if (self == Cobj) {
self = Cdbc;
}
if (rb_obj_is_kind_of(self, Cenv) == Qtrue) {
env = env_of(self);
self = Cdbc;
}
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
obj = rb_obj_alloc(Cdbc);
Data_Get_Struct(obj, DBC, p);
p->env = env;
#else
obj = Data_Make_Struct(self, DBC, mark_dbc, free_dbc, p);
tracemsg(2, fprintf(stderr, "ObjAlloc: DBC %p\n", p););
list_init(&p->link, offsetof(DBC, link));
p->self = obj;
p->env = env;
p->envp = NULL;
list_init(&p->stmts, offsetof(STMT, link));
p->hdbc = SQL_NULL_HDBC;
p->upc = 0;
p->use_sql_column_name = Qfalse;
#endif
if (env != Qnil) {
ENV *e;
Data_Get_Struct(env, ENV, e);
link_dbc(p, e);
}
if (argc > 0) {
rb_obj_call_init(obj, argc, argv);
}
return obj;
}
/*
*----------------------------------------------------------------------
*
* Connect to data source.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_connect(int argc, VALUE *argv, VALUE self)
{
ENV *e;
DBC *p;
VALUE dsn, user, passwd;
#ifdef UNICODE
SQLWCHAR *sdsn = NULL, *suser = NULL, *spasswd = NULL;
#else
char *sdsn, *suser = NULL, *spasswd = NULL;
#endif
char *msg;
SQLHDBC dbc;
rb_scan_args(argc, argv, "03", &dsn, &user, &passwd);
if (dsn != Qnil) {
if (rb_obj_is_kind_of(dsn, Cdsn) == Qtrue) {
dsn = rb_iv_get(dsn, "@name");
}
Check_Type(dsn, T_STRING);
}
if (user != Qnil) {
Check_Type(user, T_STRING);
}
if (passwd != Qnil) {
Check_Type(passwd, T_STRING);
}
p = get_dbc(self);
if (p->hdbc != SQL_NULL_HDBC) {
rb_raise(Cerror, "%s", set_err("Already connected", 0));
}
if (p->env == Qnil) {
p->env = env_new(Cenv);
e = get_env(p->env);
link_dbc(p, e);
} else {
e = get_env(p->env);
}
if (dsn == Qnil) {
return self;
}
#ifdef UNICODE
if (user != Qnil) {
#ifdef USE_RB_ENC
user = rb_funcall(user, IDencode, 1, rb_encv);
#endif
suser = uc_from_utf((unsigned char *) STR2CSTR(user), -1);
}
if (passwd != Qnil) {
#ifdef USE_RB_ENC
passwd = rb_funcall(passwd, IDencode, 1, rb_encv);
#endif
spasswd = uc_from_utf((unsigned char *) STR2CSTR(passwd), -1);
}
#ifdef USE_RB_ENC
dsn = rb_funcall(dsn, IDencode, 1, rb_encv);
#endif
sdsn = uc_from_utf((unsigned char *) STR2CSTR(dsn), -1);
if (((suser == NULL) && (user != Qnil)) ||
((spasswd == NULL) && (passwd != Qnil)) ||
(sdsn == NULL)) {
uc_free(sdsn);
uc_free(suser);
uc_free(spasswd);
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
#else
if (user != Qnil) {
suser = STR2CSTR(user);
}
if (passwd != Qnil) {
spasswd = STR2CSTR(passwd);
}
sdsn = STR2CSTR(dsn);
#endif
if (!succeeded(e->henv, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLAllocConnect(e->henv, &dbc), &msg, "SQLAllocConnect")) {
#ifdef UNICODE
uc_free(sdsn);
uc_free(suser);
uc_free(spasswd);
#endif
rb_raise(Cerror, "%s", msg);
}
if (!succeeded(SQL_NULL_HENV, dbc, SQL_NULL_HSTMT,
SQLCONNECT(dbc, (SQLTCHAR *) sdsn, SQL_NTS,
(SQLTCHAR *) suser,
(SQLSMALLINT) (suser ? SQL_NTS : 0),
(SQLTCHAR *) spasswd,
(SQLSMALLINT) (spasswd ? SQL_NTS : 0)),
&msg,
"SQLConnect('%s')", sdsn)) {
#ifdef UNICODE
uc_free(sdsn);
uc_free(suser);
uc_free(spasswd);
#endif
callsql(SQL_NULL_HENV, dbc, SQL_NULL_HSTMT,
SQLFreeConnect(dbc), "SQLFreeConnect");
rb_raise(Cerror, "%s", msg);
}
#ifdef UNICODE
uc_free(sdsn);
uc_free(suser);
uc_free(spasswd);
#endif
p->hdbc = dbc;
return self;
}
static VALUE
dbc_drvconnect(VALUE self, VALUE drv)
{
ENV *e;
DBC *p;
#ifdef UNICODE
SQLWCHAR *sdrv;
#else
char *sdrv;
#endif
char *msg;
SQLHDBC dbc;
if (rb_obj_is_kind_of(drv, Cdrv) == Qtrue) {
VALUE d, a, x;
d = rb_str_new2("");
a = rb_funcall(rb_iv_get(drv, "@attrs"), IDkeys, 0, NULL);
while ((x = rb_ary_shift(a)) != Qnil) {
VALUE v = rb_hash_aref(rb_iv_get(drv, "@attrs"), x);
d = rb_str_concat(d, x);
d = rb_str_cat2(d, "=");
d = rb_str_concat(d, v);
d = rb_str_cat2(d, ";");
}
drv = d;
}
Check_Type(drv, T_STRING);
p = get_dbc(self);
if (p->hdbc != SQL_NULL_HDBC) {
rb_raise(Cerror, "%s", set_err("Already connected", 0));
}
if (p->env == Qnil) {
p->env = env_new(Cenv);
e = get_env(p->env);
link_dbc(p, e);
} else {
e = get_env(p->env);
}
#ifdef UNICODE
#ifdef USE_RB_ENC
drv = rb_funcall(drv, IDencode, 1, rb_encv);
#endif
sdrv = uc_from_utf((unsigned char *) STR2CSTR(drv), -1);
if (sdrv == NULL) {
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
#else
sdrv = STR2CSTR(drv);
#endif
if (!succeeded(e->henv, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLAllocConnect(e->henv, &dbc), &msg, "SQLAllocConnect")) {
#ifdef UNICODE
uc_free(sdrv);
#endif
rb_raise(Cerror, "%s", msg);
}
if (!succeeded(e->henv, dbc, SQL_NULL_HSTMT,
SQLDRIVERCONNECT(dbc, NULL, (SQLTCHAR *) sdrv, SQL_NTS,
NULL, 0, NULL, SQL_DRIVER_NOPROMPT),
&msg, "SQLDriverConnect")) {
#ifdef UNICODE
uc_free(sdrv);
#endif
callsql(SQL_NULL_HENV, dbc, SQL_NULL_HSTMT,
SQLFreeConnect(dbc), "SQLFreeConnect");
rb_raise(Cerror, "%s", msg);
}
#ifdef UNICODE
uc_free(sdrv);
#endif
p->hdbc = dbc;
return self;
}
static VALUE
dbc_connected(VALUE self)
{
DBC *p = get_dbc(self);
return (p->hdbc == SQL_NULL_HDBC) ? Qfalse : Qtrue;
}
static VALUE
dbc_timefmt(int argc, VALUE *argv, VALUE self)
{
DBC *p = get_dbc(self);
VALUE val;
if (argc > 0) {
rb_scan_args(argc, argv, "1", &val);
p->rbtime = (val != Qnil && val != Qfalse) ? Qtrue : Qfalse;
}
return p->rbtime;
}
static VALUE
dbc_timeutc(int argc, VALUE *argv, VALUE self)
{
DBC *p = get_dbc(self);
VALUE val;
if (argc > 0) {
rb_scan_args(argc, argv, "1", &val);
p->gmtime = (val != Qnil && val != Qfalse) ? Qtrue : Qfalse;
}
return p->gmtime;
}
static VALUE
dbc_use_scn(int argc, VALUE *argv, VALUE self)
{
DBC *p = get_dbc(self);
VALUE val;
if (argc > 0) {
rb_scan_args(argc, argv, "1", &val);
p->use_sql_column_name =
(val != Qnil && val != Qfalse) ? Qtrue : Qfalse;
}
return p->use_sql_column_name;
}
/*
*----------------------------------------------------------------------
*
* Drop all active statements from data source.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_dropall(VALUE self)
{
DBC *p = get_dbc(self);
while (!list_empty(&p->stmts)) {
STMT *q = list_first(&p->stmts);
if (q->self == Qnil) {
rb_fatal("RubyODBC: invalid stmt in dropall");
}
stmt_drop(q->self);
}
return self;
}
/*
*----------------------------------------------------------------------
*
* Disconnect from data source.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_disconnect(int argc, VALUE *argv, VALUE self)
{
DBC *p = get_dbc(self);
VALUE nodrop = Qfalse;
char *msg;
rb_scan_args(argc, argv, "01", &nodrop);
if (!RTEST(nodrop)) {
dbc_dropall(self);
}
if (p->hdbc == SQL_NULL_HDBC) {
return Qtrue;
}
if (list_empty(&p->stmts)) {
callsql(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLDISCONNECT(p->hdbc), "SQLDisconnect");
if (!succeeded(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLFreeConnect(p->hdbc), &msg, "SQLFreeConnect")) {
rb_raise(Cerror, "%s", msg);
}
p->hdbc = SQL_NULL_HDBC;
unlink_dbc(p);
start_gc();
return Qtrue;
}
return Qfalse;
}
/*
*----------------------------------------------------------------------
*
* Database meta data via SQLGetInfo()
*
*----------------------------------------------------------------------
*/
#ifndef SQL_DTC_TRANSITION_COST
#define SQL_DTC_TRANSITION_COST 1750
#endif
#ifndef SQL_DTC_ENLIST_EXPENSIZE
#define SQL_DTC_ENLIST_EXPENDSIZE 1
#endif
#ifndef SQL_DTC_UNENLIST_EXPENSIZE
#define SQL_DTC_UNENLIST_EXPENDSIZE 2
#endif
#define GI_CONST_SINT(x) { #x, x, SQL_C_SHORT }
#define GI_CONST_INT(x) { #x, x, SQL_C_LONG }
#define GI_CONST_BITS(x) { #x, x, SQL_C_LONG }
#define GI_CONST_STR(x) { #x, x, SQL_C_CHAR }
#define GI_CONST_END { NULL, -1, -1 }
static struct {
const char *name;
int info;
int maptype;
} get_info_map[] = {
/* yielding ints */
GI_CONST_SINT(SQL_ACTIVE_ENVIRONMENTS),
GI_CONST_SINT(SQL_ACTIVE_CONNECTIONS),
GI_CONST_SINT(SQL_ACTIVE_STATEMENTS),
GI_CONST_INT(SQL_ASYNC_MODE),
GI_CONST_SINT(SQL_CATALOG_LOCATION),
GI_CONST_SINT(SQL_CONCAT_NULL_BEHAVIOR),
GI_CONST_SINT(SQL_CORRELATION_NAME),
GI_CONST_SINT(SQL_CURSOR_COMMIT_BEHAVIOR),
GI_CONST_SINT(SQL_CURSOR_ROLLBACK_BEHAVIOR),
GI_CONST_INT(SQL_CURSOR_SENSITIVITY),
GI_CONST_INT(SQL_DDL_INDEX),
GI_CONST_INT(SQL_DEFAULT_TXN_ISOLATION),
GI_CONST_INT(SQL_DRIVER_HDBC),
GI_CONST_INT(SQL_DRIVER_HENV),
GI_CONST_INT(SQL_DRIVER_HDESC),
GI_CONST_INT(SQL_DRIVER_HLIB),
GI_CONST_INT(SQL_DRIVER_HSTMT),
GI_CONST_SINT(SQL_FILE_USAGE),
GI_CONST_SINT(SQL_GROUP_BY),
GI_CONST_SINT(SQL_IDENTIFIER_CASE),
GI_CONST_INT(SQL_MAX_ASYNC_CONCURRENT_STATEMENTS),
GI_CONST_INT(SQL_MAX_BINARY_LITERAL_LEN),
GI_CONST_SINT(SQL_MAX_CATALOG_NAME_LEN),
GI_CONST_INT(SQL_MAX_CHAR_LITERAL_LEN),
GI_CONST_SINT(SQL_MAX_COLUMN_NAME_LEN),
GI_CONST_SINT(SQL_MAX_COLUMNS_IN_GROUP_BY),
GI_CONST_SINT(SQL_MAX_COLUMNS_IN_INDEX),
GI_CONST_SINT(SQL_MAX_COLUMNS_IN_ORDER_BY),
GI_CONST_SINT(SQL_MAX_COLUMNS_IN_SELECT),
GI_CONST_SINT(SQL_MAX_COLUMNS_IN_TABLE),
GI_CONST_SINT(SQL_MAX_CONCURRENT_ACTIVITIES),
GI_CONST_SINT(SQL_MAX_CURSOR_NAME_LEN),
GI_CONST_SINT(SQL_MAX_DRIVER_CONNECTIONS),
GI_CONST_SINT(SQL_MAX_IDENTIFIER_LEN),
GI_CONST_INT(SQL_MAX_INDEX_SIZE),
GI_CONST_SINT(SQL_MAX_OWNER_NAME_LEN),
GI_CONST_SINT(SQL_MAX_PROCEDURE_NAME_LEN),
GI_CONST_SINT(SQL_MAX_QUALIFIER_NAME_LEN),
GI_CONST_INT(SQL_MAX_ROW_SIZE),
GI_CONST_SINT(SQL_MAX_SCHEMA_NAME_LEN),
GI_CONST_INT(SQL_MAX_STATEMENT_LEN),
GI_CONST_SINT(SQL_MAX_TABLE_NAME_LEN),
GI_CONST_SINT(SQL_MAX_TABLES_IN_SELECT),
GI_CONST_SINT(SQL_MAX_USER_NAME_LEN),
GI_CONST_SINT(SQL_NON_NULLABLE_COLUMNS),
GI_CONST_SINT(SQL_NULL_COLLATION),
GI_CONST_SINT(SQL_ODBC_API_CONFORMANCE),
GI_CONST_INT(SQL_ODBC_INTERFACE_CONFORMANCE),
GI_CONST_SINT(SQL_ODBC_SAG_CLI_CONFORMANCE),
GI_CONST_SINT(SQL_ODBC_SQL_CONFORMANCE),
GI_CONST_INT(SQL_PARAM_ARRAY_ROW_COUNTS),
GI_CONST_INT(SQL_PARAM_ARRAY_SELECTS),
GI_CONST_SINT(SQL_QUALIFIER_LOCATION),
GI_CONST_SINT(SQL_QUOTED_IDENTIFIER_CASE),
GI_CONST_INT(SQL_SQL_CONFORMANCE),
GI_CONST_SINT(SQL_TXN_CAPABLE),
/* yielding ints (but bitmasks) */
GI_CONST_BITS(SQL_AGGREGATE_FUNCTIONS),
GI_CONST_BITS(SQL_ALTER_DOMAIN),
GI_CONST_BITS(SQL_ALTER_TABLE),
GI_CONST_BITS(SQL_BATCH_ROW_COUNT),
GI_CONST_BITS(SQL_BATCH_SUPPORT),
GI_CONST_BITS(SQL_BOOKMARK_PERSISTENCE),
GI_CONST_BITS(SQL_CATALOG_USAGE),
GI_CONST_BITS(SQL_CONVERT_BINARY),
GI_CONST_BITS(SQL_CONVERT_BIT),
GI_CONST_BITS(SQL_CONVERT_CHAR),
#ifdef SQL_CONVERT_GUID
GI_CONST_BITS(SQL_CONVERT_GUID),
#endif
GI_CONST_BITS(SQL_CONVERT_DATE),
GI_CONST_BITS(SQL_CONVERT_DECIMAL),
GI_CONST_BITS(SQL_CONVERT_DOUBLE),
GI_CONST_BITS(SQL_CONVERT_FLOAT),
GI_CONST_BITS(SQL_CONVERT_FUNCTIONS),
GI_CONST_BITS(SQL_CONVERT_INTEGER),
GI_CONST_BITS(SQL_CONVERT_INTERVAL_YEAR_MONTH),
GI_CONST_BITS(SQL_CONVERT_INTERVAL_DAY_TIME),
GI_CONST_BITS(SQL_CONVERT_LONGVARBINARY),
GI_CONST_BITS(SQL_CONVERT_LONGVARCHAR),
GI_CONST_BITS(SQL_CONVERT_NUMERIC),
GI_CONST_BITS(SQL_CONVERT_REAL),
GI_CONST_BITS(SQL_CONVERT_SMALLINT),
GI_CONST_BITS(SQL_CONVERT_TIME),
GI_CONST_BITS(SQL_CONVERT_TIMESTAMP),
GI_CONST_BITS(SQL_CONVERT_TINYINT),
GI_CONST_BITS(SQL_CONVERT_VARBINARY),
GI_CONST_BITS(SQL_CONVERT_VARCHAR),
GI_CONST_BITS(SQL_CONVERT_WCHAR),
GI_CONST_BITS(SQL_CONVERT_WLONGVARCHAR),
GI_CONST_BITS(SQL_CONVERT_WVARCHAR),
GI_CONST_BITS(SQL_CREATE_ASSERTION),
GI_CONST_BITS(SQL_CREATE_CHARACTER_SET),
GI_CONST_BITS(SQL_CREATE_COLLATION),
GI_CONST_BITS(SQL_CREATE_DOMAIN),
GI_CONST_BITS(SQL_CREATE_SCHEMA),
GI_CONST_BITS(SQL_CREATE_TABLE),
GI_CONST_BITS(SQL_CREATE_TRANSLATION),
GI_CONST_BITS(SQL_CREATE_VIEW),
GI_CONST_BITS(SQL_DATETIME_LITERALS),
GI_CONST_BITS(SQL_DROP_ASSERTION),
GI_CONST_BITS(SQL_DROP_CHARACTER_SET),
GI_CONST_BITS(SQL_DROP_COLLATION),
GI_CONST_BITS(SQL_DROP_DOMAIN),
GI_CONST_BITS(SQL_DROP_SCHEMA),
GI_CONST_BITS(SQL_DROP_TABLE),
GI_CONST_BITS(SQL_DROP_TRANSLATION),
GI_CONST_BITS(SQL_DROP_VIEW),
GI_CONST_BITS(SQL_DTC_TRANSITION_COST),
GI_CONST_BITS(SQL_DYNAMIC_CURSOR_ATTRIBUTES1),
GI_CONST_BITS(SQL_DYNAMIC_CURSOR_ATTRIBUTES2),
GI_CONST_BITS(SQL_FETCH_DIRECTION),
GI_CONST_BITS(SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1),
GI_CONST_BITS(SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2),
GI_CONST_BITS(SQL_GETDATA_EXTENSIONS),
GI_CONST_BITS(SQL_KEYSET_CURSOR_ATTRIBUTES1),
GI_CONST_BITS(SQL_KEYSET_CURSOR_ATTRIBUTES2),
GI_CONST_BITS(SQL_INDEX_KEYWORDS),
GI_CONST_BITS(SQL_INFO_SCHEMA_VIEWS),
GI_CONST_BITS(SQL_INSERT_STATEMENT),
GI_CONST_BITS(SQL_LOCK_TYPES),
GI_CONST_BITS(SQL_NUMERIC_FUNCTIONS),
GI_CONST_BITS(SQL_OJ_CAPABILITIES),
GI_CONST_BITS(SQL_OWNER_USAGE),
GI_CONST_BITS(SQL_POS_OPERATIONS),
GI_CONST_BITS(SQL_POSITIONED_STATEMENTS),
GI_CONST_BITS(SQL_QUALIFIER_USAGE),
GI_CONST_BITS(SQL_SCHEMA_USAGE),
GI_CONST_BITS(SQL_SCROLL_CONCURRENCY),
GI_CONST_BITS(SQL_SCROLL_OPTIONS),
GI_CONST_BITS(SQL_SQL92_DATETIME_FUNCTIONS),
GI_CONST_BITS(SQL_SQL92_FOREIGN_KEY_DELETE_RULE),
GI_CONST_BITS(SQL_SQL92_FOREIGN_KEY_UPDATE_RULE),
GI_CONST_BITS(SQL_SQL92_GRANT),
GI_CONST_BITS(SQL_SQL92_NUMERIC_VALUE_FUNCTIONS),
GI_CONST_BITS(SQL_SQL92_PREDICATES),
GI_CONST_BITS(SQL_SQL92_RELATIONAL_JOIN_OPERATORS),
GI_CONST_BITS(SQL_SQL92_REVOKE),
GI_CONST_BITS(SQL_SQL92_ROW_VALUE_CONSTRUCTOR),
GI_CONST_BITS(SQL_SQL92_STRING_FUNCTIONS),
GI_CONST_BITS(SQL_SQL92_VALUE_EXPRESSIONS),
GI_CONST_BITS(SQL_STANDARD_CLI_CONFORMANCE),
GI_CONST_BITS(SQL_STATIC_CURSOR_ATTRIBUTES1),
GI_CONST_BITS(SQL_STATIC_CURSOR_ATTRIBUTES2),
GI_CONST_BITS(SQL_STATIC_SENSITIVITY),
GI_CONST_BITS(SQL_STRING_FUNCTIONS),
GI_CONST_BITS(SQL_SUBQUERIES),
GI_CONST_BITS(SQL_SYSTEM_FUNCTIONS),
GI_CONST_BITS(SQL_TIMEDATE_ADD_INTERVALS),
GI_CONST_BITS(SQL_TIMEDATE_DIFF_INTERVALS),
GI_CONST_BITS(SQL_TIMEDATE_FUNCTIONS),
GI_CONST_BITS(SQL_TXN_ISOLATION_OPTION),
GI_CONST_BITS(SQL_UNION),
/* yielding strings */
GI_CONST_STR(SQL_ACCESSIBLE_PROCEDURES),
GI_CONST_STR(SQL_ACCESSIBLE_TABLES),
GI_CONST_STR(SQL_CATALOG_NAME),
GI_CONST_STR(SQL_CATALOG_NAME_SEPARATOR),
GI_CONST_STR(SQL_CATALOG_TERM),
GI_CONST_STR(SQL_COLLATION_SEQ),
GI_CONST_STR(SQL_COLUMN_ALIAS),
GI_CONST_STR(SQL_DATA_SOURCE_NAME),
GI_CONST_STR(SQL_DATA_SOURCE_READ_ONLY),
GI_CONST_STR(SQL_DATABASE_NAME),
GI_CONST_STR(SQL_DBMS_NAME),
GI_CONST_STR(SQL_DBMS_VER),
GI_CONST_STR(SQL_DESCRIBE_PARAMETER),
GI_CONST_STR(SQL_DM_VER),
GI_CONST_STR(SQL_DRIVER_NAME),
GI_CONST_STR(SQL_DRIVER_ODBC_VER),
GI_CONST_STR(SQL_DRIVER_VER),
GI_CONST_STR(SQL_EXPRESSIONS_IN_ORDERBY),
GI_CONST_STR(SQL_IDENTIFIER_QUOTE_CHAR),
GI_CONST_STR(SQL_INTEGRITY),
GI_CONST_STR(SQL_KEYWORDS),
GI_CONST_STR(SQL_LIKE_ESCAPE_CLAUSE),
GI_CONST_STR(SQL_MAX_ROW_SIZE_INCLUDES_LONG),
GI_CONST_STR(SQL_MULT_RESULT_SETS),
GI_CONST_STR(SQL_MULTIPLE_ACTIVE_TXN),
GI_CONST_STR(SQL_NEED_LONG_DATA_LEN),
GI_CONST_STR(SQL_ODBC_SQL_OPT_IEF),
GI_CONST_STR(SQL_ODBC_VER),
GI_CONST_STR(SQL_ORDER_BY_COLUMNS_IN_SELECT),
GI_CONST_STR(SQL_OUTER_JOINS),
GI_CONST_STR(SQL_OWNER_TERM),
GI_CONST_STR(SQL_PROCEDURE_TERM),
GI_CONST_STR(SQL_PROCEDURES),
GI_CONST_STR(SQL_QUALIFIER_NAME_SEPARATOR),
GI_CONST_STR(SQL_QUALIFIER_TERM),
GI_CONST_STR(SQL_ROW_UPDATES),
GI_CONST_STR(SQL_SCHEMA_TERM),
GI_CONST_STR(SQL_SEARCH_PATTERN_ESCAPE),
GI_CONST_STR(SQL_SERVER_NAME),
GI_CONST_STR(SQL_SPECIAL_CHARACTERS),
GI_CONST_STR(SQL_TABLE_TERM),
GI_CONST_STR(SQL_USER_NAME),
GI_CONST_STR(SQL_XOPEN_CLI_YEAR),
/* end of table */
GI_CONST_END
};
#define GI_CONST_BITMAP(x) { #x, x }
#define GI_CONST_BITMAP_END { NULL, 0 }
static struct {
const char *name;
int bits;
} get_info_bitmap[] = {
GI_CONST_BITMAP(SQL_AD_ADD_CONSTRAINT_DEFERRABLE),
GI_CONST_BITMAP(SQL_AD_ADD_CONSTRAINT_INITIALLY_DEFERRED),
GI_CONST_BITMAP(SQL_AD_ADD_CONSTRAINT_INITIALLY_IMMEDIATE),
GI_CONST_BITMAP(SQL_AD_ADD_CONSTRAINT_NON_DEFERRABLE),
GI_CONST_BITMAP(SQL_AD_ADD_DOMAIN_CONSTRAINT),
GI_CONST_BITMAP(SQL_AD_ADD_DOMAIN_DEFAULT),
GI_CONST_BITMAP(SQL_AD_CONSTRAINT_NAME_DEFINITION),
GI_CONST_BITMAP(SQL_AD_DROP_DOMAIN_CONSTRAINT),
GI_CONST_BITMAP(SQL_AD_DROP_DOMAIN_DEFAULT),
GI_CONST_BITMAP(SQL_AF_ALL),
GI_CONST_BITMAP(SQL_AF_AVG),
GI_CONST_BITMAP(SQL_AF_COUNT),
GI_CONST_BITMAP(SQL_AF_DISTINCT),
GI_CONST_BITMAP(SQL_AF_MAX),
GI_CONST_BITMAP(SQL_AF_MIN),
GI_CONST_BITMAP(SQL_AF_SUM),
GI_CONST_BITMAP(SQL_AM_CONNECTION),
GI_CONST_BITMAP(SQL_AM_NONE),
GI_CONST_BITMAP(SQL_AM_STATEMENT),
GI_CONST_BITMAP(SQL_AT_ADD_COLUMN),
GI_CONST_BITMAP(SQL_AT_ADD_COLUMN_COLLATION),
GI_CONST_BITMAP(SQL_AT_ADD_COLUMN_DEFAULT),
GI_CONST_BITMAP(SQL_AT_ADD_COLUMN_SINGLE),
GI_CONST_BITMAP(SQL_AT_ADD_CONSTRAINT),
GI_CONST_BITMAP(SQL_AT_ADD_TABLE_CONSTRAINT),
#ifdef SQL_AT_COLUMN_SINGLE
GI_CONST_BITMAP(SQL_AT_COLUMN_SINGLE),
#endif
GI_CONST_BITMAP(SQL_AT_CONSTRAINT_DEFERRABLE),
GI_CONST_BITMAP(SQL_AT_CONSTRAINT_INITIALLY_DEFERRED),
GI_CONST_BITMAP(SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE),
GI_CONST_BITMAP(SQL_AT_CONSTRAINT_NAME_DEFINITION),
GI_CONST_BITMAP(SQL_AT_CONSTRAINT_NON_DEFERRABLE),
GI_CONST_BITMAP(SQL_AT_DROP_COLUMN),
GI_CONST_BITMAP(SQL_AT_DROP_COLUMN_CASCADE),
GI_CONST_BITMAP(SQL_AT_DROP_COLUMN_DEFAULT),
GI_CONST_BITMAP(SQL_AT_DROP_COLUMN_RESTRICT),
GI_CONST_BITMAP(SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE),
GI_CONST_BITMAP(SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT),
GI_CONST_BITMAP(SQL_AT_SET_COLUMN_DEFAULT),
GI_CONST_BITMAP(SQL_BP_CLOSE),
GI_CONST_BITMAP(SQL_BP_DELETE),
GI_CONST_BITMAP(SQL_BP_DROP),
GI_CONST_BITMAP(SQL_BP_OTHER_HSTMT),
GI_CONST_BITMAP(SQL_BP_SCROLL),
GI_CONST_BITMAP(SQL_BP_TRANSACTION),
GI_CONST_BITMAP(SQL_BP_UPDATE),
GI_CONST_BITMAP(SQL_BRC_EXPLICIT),
GI_CONST_BITMAP(SQL_BRC_PROCEDURES),
GI_CONST_BITMAP(SQL_BRC_ROLLED_UP),
GI_CONST_BITMAP(SQL_BS_ROW_COUNT_EXPLICIT),
GI_CONST_BITMAP(SQL_BS_ROW_COUNT_PROC),
GI_CONST_BITMAP(SQL_BS_SELECT_EXPLICIT),
GI_CONST_BITMAP(SQL_BS_SELECT_PROC),
GI_CONST_BITMAP(SQL_CA1_ABSOLUTE),
GI_CONST_BITMAP(SQL_CA1_BOOKMARK),
GI_CONST_BITMAP(SQL_CA1_BULK_ADD),
GI_CONST_BITMAP(SQL_CA1_BULK_DELETE_BY_BOOKMARK),
GI_CONST_BITMAP(SQL_CA1_BULK_FETCH_BY_BOOKMARK),
GI_CONST_BITMAP(SQL_CA1_BULK_UPDATE_BY_BOOKMARK),
GI_CONST_BITMAP(SQL_CA1_LOCK_EXCLUSIVE),
GI_CONST_BITMAP(SQL_CA1_LOCK_NO_CHANGE),
GI_CONST_BITMAP(SQL_CA1_LOCK_UNLOCK),
GI_CONST_BITMAP(SQL_CA1_NEXT),
GI_CONST_BITMAP(SQL_CA1_POS_DELETE),
GI_CONST_BITMAP(SQL_CA1_POSITIONED_DELETE),
GI_CONST_BITMAP(SQL_CA1_POSITIONED_UPDATE),
GI_CONST_BITMAP(SQL_CA1_POS_POSITION),
GI_CONST_BITMAP(SQL_CA1_POS_REFRESH),
GI_CONST_BITMAP(SQL_CA1_POS_UPDATE),
GI_CONST_BITMAP(SQL_CA1_RELATIVE),
GI_CONST_BITMAP(SQL_CA1_SELECT_FOR_UPDATE),
GI_CONST_BITMAP(SQL_CA2_CRC_APPROXIMATE),
GI_CONST_BITMAP(SQL_CA2_CRC_EXACT),
GI_CONST_BITMAP(SQL_CA2_LOCK_CONCURRENCY),
GI_CONST_BITMAP(SQL_CA2_MAX_ROWS_AFFECTS_ALL),
GI_CONST_BITMAP(SQL_CA2_MAX_ROWS_CATALOG),
GI_CONST_BITMAP(SQL_CA2_MAX_ROWS_DELETE),
GI_CONST_BITMAP(SQL_CA2_MAX_ROWS_INSERT),
GI_CONST_BITMAP(SQL_CA2_MAX_ROWS_SELECT),
GI_CONST_BITMAP(SQL_CA2_MAX_ROWS_UPDATE),
GI_CONST_BITMAP(SQL_CA2_OPT_ROWVER_CONCURRENCY),
GI_CONST_BITMAP(SQL_CA2_OPT_VALUES_CONCURRENCY),
GI_CONST_BITMAP(SQL_CA2_READ_ONLY_CONCURRENCY),
GI_CONST_BITMAP(SQL_CA2_SENSITIVITY_ADDITIONS),
GI_CONST_BITMAP(SQL_CA2_SENSITIVITY_DELETIONS),
GI_CONST_BITMAP(SQL_CA2_SENSITIVITY_UPDATES),
GI_CONST_BITMAP(SQL_CA2_SIMULATE_NON_UNIQUE),
GI_CONST_BITMAP(SQL_CA2_SIMULATE_TRY_UNIQUE),
GI_CONST_BITMAP(SQL_CA2_SIMULATE_UNIQUE),
GI_CONST_BITMAP(SQL_CA_CONSTRAINT_DEFERRABLE),
GI_CONST_BITMAP(SQL_CA_CONSTRAINT_INITIALLY_DEFERRED),
GI_CONST_BITMAP(SQL_CA_CONSTRAINT_INITIALLY_IMMEDIATE),
GI_CONST_BITMAP(SQL_CA_CONSTRAINT_NON_DEFERRABLE),
GI_CONST_BITMAP(SQL_CA_CREATE_ASSERTION),
GI_CONST_BITMAP(SQL_CB_CLOSE),
GI_CONST_BITMAP(SQL_CB_DELETE),
GI_CONST_BITMAP(SQL_CB_NON_NULL),
GI_CONST_BITMAP(SQL_CB_NULL),
GI_CONST_BITMAP(SQL_CB_PRESERVE),
GI_CONST_BITMAP(SQL_CC_CLOSE),
GI_CONST_BITMAP(SQL_CC_DELETE),
GI_CONST_BITMAP(SQL_CCOL_CREATE_COLLATION),
GI_CONST_BITMAP(SQL_CC_PRESERVE),
GI_CONST_BITMAP(SQL_CCS_COLLATE_CLAUSE),
GI_CONST_BITMAP(SQL_CCS_CREATE_CHARACTER_SET),
GI_CONST_BITMAP(SQL_CCS_LIMITED_COLLATION),
GI_CONST_BITMAP(SQL_CDO_COLLATION),
GI_CONST_BITMAP(SQL_CDO_CONSTRAINT),
GI_CONST_BITMAP(SQL_CDO_CONSTRAINT_DEFERRABLE),
GI_CONST_BITMAP(SQL_CDO_CONSTRAINT_INITIALLY_DEFERRED),
GI_CONST_BITMAP(SQL_CDO_CONSTRAINT_INITIALLY_IMMEDIATE),
GI_CONST_BITMAP(SQL_CDO_CONSTRAINT_NAME_DEFINITION),
GI_CONST_BITMAP(SQL_CDO_CONSTRAINT_NON_DEFERRABLE),
GI_CONST_BITMAP(SQL_CDO_CREATE_DOMAIN),
GI_CONST_BITMAP(SQL_CDO_DEFAULT),
GI_CONST_BITMAP(SQL_CL_END),
GI_CONST_BITMAP(SQL_CL_START),
GI_CONST_BITMAP(SQL_CN_ANY),
GI_CONST_BITMAP(SQL_CN_DIFFERENT),
GI_CONST_BITMAP(SQL_CN_NONE),
GI_CONST_BITMAP(SQL_CONCUR_TIMESTAMP),
GI_CONST_BITMAP(SQL_CR_CLOSE),
GI_CONST_BITMAP(SQL_CR_DELETE),
GI_CONST_BITMAP(SQL_CR_PRESERVE),
GI_CONST_BITMAP(SQL_CS_AUTHORIZATION),
GI_CONST_BITMAP(SQL_CS_CREATE_SCHEMA),
GI_CONST_BITMAP(SQL_CS_DEFAULT_CHARACTER_SET),
GI_CONST_BITMAP(SQL_CT_COLUMN_COLLATION),
GI_CONST_BITMAP(SQL_CT_COLUMN_CONSTRAINT),
GI_CONST_BITMAP(SQL_CT_COLUMN_DEFAULT),
GI_CONST_BITMAP(SQL_CT_COMMIT_DELETE),
GI_CONST_BITMAP(SQL_CT_COMMIT_PRESERVE),
GI_CONST_BITMAP(SQL_CT_CONSTRAINT_DEFERRABLE),
GI_CONST_BITMAP(SQL_CT_CONSTRAINT_INITIALLY_DEFERRED),
GI_CONST_BITMAP(SQL_CT_CONSTRAINT_INITIALLY_IMMEDIATE),
GI_CONST_BITMAP(SQL_CT_CONSTRAINT_NAME_DEFINITION),
GI_CONST_BITMAP(SQL_CT_CONSTRAINT_NON_DEFERRABLE),
GI_CONST_BITMAP(SQL_CT_CREATE_TABLE),
GI_CONST_BITMAP(SQL_CT_GLOBAL_TEMPORARY),
GI_CONST_BITMAP(SQL_CT_LOCAL_TEMPORARY),
GI_CONST_BITMAP(SQL_CTR_CREATE_TRANSLATION),
GI_CONST_BITMAP(SQL_CT_TABLE_CONSTRAINT),
GI_CONST_BITMAP(SQL_CU_DML_STATEMENTS),
GI_CONST_BITMAP(SQL_CU_INDEX_DEFINITION),
GI_CONST_BITMAP(SQL_CU_PRIVILEGE_DEFINITION),
GI_CONST_BITMAP(SQL_CU_PROCEDURE_INVOCATION),
GI_CONST_BITMAP(SQL_CU_TABLE_DEFINITION),
GI_CONST_BITMAP(SQL_CV_CASCADED),
GI_CONST_BITMAP(SQL_CV_CHECK_OPTION),
GI_CONST_BITMAP(SQL_CV_CREATE_VIEW),
GI_CONST_BITMAP(SQL_CV_LOCAL),
GI_CONST_BITMAP(SQL_CVT_BIGINT),
GI_CONST_BITMAP(SQL_CVT_BINARY),
GI_CONST_BITMAP(SQL_CVT_BIT),
GI_CONST_BITMAP(SQL_CVT_CHAR),
GI_CONST_BITMAP(SQL_CVT_DATE),
GI_CONST_BITMAP(SQL_CVT_DECIMAL),
GI_CONST_BITMAP(SQL_CVT_DOUBLE),
GI_CONST_BITMAP(SQL_CVT_FLOAT),
GI_CONST_BITMAP(SQL_CVT_INTEGER),
GI_CONST_BITMAP(SQL_CVT_INTERVAL_DAY_TIME),
GI_CONST_BITMAP(SQL_CVT_INTERVAL_YEAR_MONTH),
GI_CONST_BITMAP(SQL_CVT_LONGVARBINARY),
GI_CONST_BITMAP(SQL_CVT_LONGVARCHAR),
GI_CONST_BITMAP(SQL_CVT_NUMERIC),
GI_CONST_BITMAP(SQL_CVT_REAL),
GI_CONST_BITMAP(SQL_CVT_SMALLINT),
GI_CONST_BITMAP(SQL_CVT_TIME),
GI_CONST_BITMAP(SQL_CVT_TIMESTAMP),
GI_CONST_BITMAP(SQL_CVT_TINYINT),
GI_CONST_BITMAP(SQL_CVT_VARBINARY),
GI_CONST_BITMAP(SQL_CVT_VARCHAR),
GI_CONST_BITMAP(SQL_CVT_WCHAR),
GI_CONST_BITMAP(SQL_CVT_WLONGVARCHAR),
GI_CONST_BITMAP(SQL_CVT_WVARCHAR),
GI_CONST_BITMAP(SQL_DA_DROP_ASSERTION),
GI_CONST_BITMAP(SQL_DC_DROP_COLLATION),
GI_CONST_BITMAP(SQL_DCS_DROP_CHARACTER_SET),
GI_CONST_BITMAP(SQL_DD_CASCADE),
GI_CONST_BITMAP(SQL_DD_DROP_DOMAIN),
GI_CONST_BITMAP(SQL_DD_RESTRICT),
GI_CONST_BITMAP(SQL_DI_CREATE_INDEX),
GI_CONST_BITMAP(SQL_DI_DROP_INDEX),
GI_CONST_BITMAP(SQL_DL_SQL92_DATE),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_DAY),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_DAY_TO_HOUR),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_DAY_TO_MINUTE),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_DAY_TO_SECOND),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_HOUR),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_HOUR_TO_MINUTE),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_HOUR_TO_SECOND),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_MINUTE),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_MINUTE_TO_SECOND),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_MONTH),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_SECOND),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_YEAR),
GI_CONST_BITMAP(SQL_DL_SQL92_INTERVAL_YEAR_TO_MONTH),
GI_CONST_BITMAP(SQL_DL_SQL92_TIME),
GI_CONST_BITMAP(SQL_DL_SQL92_TIMESTAMP),
GI_CONST_BITMAP(SQL_DS_CASCADE),
GI_CONST_BITMAP(SQL_DS_DROP_SCHEMA),
GI_CONST_BITMAP(SQL_DS_RESTRICT),
GI_CONST_BITMAP(SQL_DT_CASCADE),
GI_CONST_BITMAP(SQL_DTC_ENLIST_EXPENSIVE),
GI_CONST_BITMAP(SQL_DTC_UNENLIST_EXPENSIVE),
GI_CONST_BITMAP(SQL_DT_DROP_TABLE),
GI_CONST_BITMAP(SQL_DTR_DROP_TRANSLATION),
GI_CONST_BITMAP(SQL_DT_RESTRICT),
GI_CONST_BITMAP(SQL_DV_CASCADE),
GI_CONST_BITMAP(SQL_DV_DROP_VIEW),
GI_CONST_BITMAP(SQL_DV_RESTRICT),
GI_CONST_BITMAP(SQL_FD_FETCH_ABSOLUTE),
GI_CONST_BITMAP(SQL_FD_FETCH_BOOKMARK),
GI_CONST_BITMAP(SQL_FD_FETCH_FIRST),
GI_CONST_BITMAP(SQL_FD_FETCH_LAST),
GI_CONST_BITMAP(SQL_FD_FETCH_NEXT),
GI_CONST_BITMAP(SQL_FD_FETCH_PRIOR),
GI_CONST_BITMAP(SQL_FD_FETCH_RELATIVE),
#ifdef SQL_FD_FETCH_RESUME
GI_CONST_BITMAP(SQL_FD_FETCH_RESUME),
#endif
GI_CONST_BITMAP(SQL_FILE_CATALOG),
GI_CONST_BITMAP(SQL_FILE_NOT_SUPPORTED),
GI_CONST_BITMAP(SQL_FILE_QUALIFIER),
GI_CONST_BITMAP(SQL_FILE_TABLE),
GI_CONST_BITMAP(SQL_FN_CVT_CAST),
GI_CONST_BITMAP(SQL_FN_CVT_CONVERT),
GI_CONST_BITMAP(SQL_FN_NUM_ABS),
GI_CONST_BITMAP(SQL_FN_NUM_ACOS),
GI_CONST_BITMAP(SQL_FN_NUM_ASIN),
GI_CONST_BITMAP(SQL_FN_NUM_ATAN),
GI_CONST_BITMAP(SQL_FN_NUM_ATAN2),
GI_CONST_BITMAP(SQL_FN_NUM_CEILING),
GI_CONST_BITMAP(SQL_FN_NUM_COS),
GI_CONST_BITMAP(SQL_FN_NUM_COT),
GI_CONST_BITMAP(SQL_FN_NUM_DEGREES),
GI_CONST_BITMAP(SQL_FN_NUM_EXP),
GI_CONST_BITMAP(SQL_FN_NUM_FLOOR),
GI_CONST_BITMAP(SQL_FN_NUM_LOG),
GI_CONST_BITMAP(SQL_FN_NUM_LOG10),
GI_CONST_BITMAP(SQL_FN_NUM_MOD),
GI_CONST_BITMAP(SQL_FN_NUM_PI),
GI_CONST_BITMAP(SQL_FN_NUM_POWER),
GI_CONST_BITMAP(SQL_FN_NUM_RADIANS),
GI_CONST_BITMAP(SQL_FN_NUM_RAND),
GI_CONST_BITMAP(SQL_FN_NUM_ROUND),
GI_CONST_BITMAP(SQL_FN_NUM_SIGN),
GI_CONST_BITMAP(SQL_FN_NUM_SIN),
GI_CONST_BITMAP(SQL_FN_NUM_SQRT),
GI_CONST_BITMAP(SQL_FN_NUM_TAN),
GI_CONST_BITMAP(SQL_FN_NUM_TRUNCATE),
GI_CONST_BITMAP(SQL_FN_STR_ASCII),
GI_CONST_BITMAP(SQL_FN_STR_BIT_LENGTH),
GI_CONST_BITMAP(SQL_FN_STR_CHAR),
GI_CONST_BITMAP(SQL_FN_STR_CHARACTER_LENGTH),
GI_CONST_BITMAP(SQL_FN_STR_CHAR_LENGTH),
GI_CONST_BITMAP(SQL_FN_STR_CONCAT),
GI_CONST_BITMAP(SQL_FN_STR_DIFFERENCE),
GI_CONST_BITMAP(SQL_FN_STR_INSERT),
GI_CONST_BITMAP(SQL_FN_STR_LCASE),
GI_CONST_BITMAP(SQL_FN_STR_LEFT),
GI_CONST_BITMAP(SQL_FN_STR_LENGTH),
GI_CONST_BITMAP(SQL_FN_STR_LOCATE),
GI_CONST_BITMAP(SQL_FN_STR_LOCATE_2),
GI_CONST_BITMAP(SQL_FN_STR_LTRIM),
GI_CONST_BITMAP(SQL_FN_STR_OCTET_LENGTH),
GI_CONST_BITMAP(SQL_FN_STR_POSITION),
GI_CONST_BITMAP(SQL_FN_STR_REPEAT),
GI_CONST_BITMAP(SQL_FN_STR_REPLACE),
GI_CONST_BITMAP(SQL_FN_STR_RIGHT),
GI_CONST_BITMAP(SQL_FN_STR_RTRIM),
GI_CONST_BITMAP(SQL_FN_STR_SOUNDEX),
GI_CONST_BITMAP(SQL_FN_STR_SPACE),
GI_CONST_BITMAP(SQL_FN_STR_SUBSTRING),
GI_CONST_BITMAP(SQL_FN_STR_UCASE),
GI_CONST_BITMAP(SQL_FN_SYS_DBNAME),
GI_CONST_BITMAP(SQL_FN_SYS_IFNULL),
GI_CONST_BITMAP(SQL_FN_SYS_USERNAME),
GI_CONST_BITMAP(SQL_FN_TD_CURDATE),
GI_CONST_BITMAP(SQL_FN_TD_CURRENT_DATE),
GI_CONST_BITMAP(SQL_FN_TD_CURRENT_TIME),
GI_CONST_BITMAP(SQL_FN_TD_CURRENT_TIMESTAMP),
GI_CONST_BITMAP(SQL_FN_TD_CURTIME),
GI_CONST_BITMAP(SQL_FN_TD_DAYNAME),
GI_CONST_BITMAP(SQL_FN_TD_DAYOFMONTH),
GI_CONST_BITMAP(SQL_FN_TD_DAYOFWEEK),
GI_CONST_BITMAP(SQL_FN_TD_DAYOFYEAR),
GI_CONST_BITMAP(SQL_FN_TD_EXTRACT),
GI_CONST_BITMAP(SQL_FN_TD_HOUR),
GI_CONST_BITMAP(SQL_FN_TD_MINUTE),
GI_CONST_BITMAP(SQL_FN_TD_MONTH),
GI_CONST_BITMAP(SQL_FN_TD_MONTHNAME),
GI_CONST_BITMAP(SQL_FN_TD_NOW),
GI_CONST_BITMAP(SQL_FN_TD_QUARTER),
GI_CONST_BITMAP(SQL_FN_TD_SECOND),
GI_CONST_BITMAP(SQL_FN_TD_TIMESTAMPADD),
GI_CONST_BITMAP(SQL_FN_TD_TIMESTAMPDIFF),
GI_CONST_BITMAP(SQL_FN_TD_WEEK),
GI_CONST_BITMAP(SQL_FN_TD_YEAR),
GI_CONST_BITMAP(SQL_FN_TSI_DAY),
GI_CONST_BITMAP(SQL_FN_TSI_FRAC_SECOND),
GI_CONST_BITMAP(SQL_FN_TSI_HOUR),
GI_CONST_BITMAP(SQL_FN_TSI_MINUTE),
GI_CONST_BITMAP(SQL_FN_TSI_MONTH),
GI_CONST_BITMAP(SQL_FN_TSI_QUARTER),
GI_CONST_BITMAP(SQL_FN_TSI_SECOND),
GI_CONST_BITMAP(SQL_FN_TSI_WEEK),
GI_CONST_BITMAP(SQL_FN_TSI_YEAR),
GI_CONST_BITMAP(SQL_GB_COLLATE),
GI_CONST_BITMAP(SQL_GB_GROUP_BY_CONTAINS_SELECT),
GI_CONST_BITMAP(SQL_GB_GROUP_BY_EQUALS_SELECT),
GI_CONST_BITMAP(SQL_GB_NO_RELATION),
GI_CONST_BITMAP(SQL_GB_NOT_SUPPORTED),
GI_CONST_BITMAP(SQL_GD_ANY_COLUMN),
GI_CONST_BITMAP(SQL_GD_ANY_ORDER),
GI_CONST_BITMAP(SQL_GD_BLOCK),
GI_CONST_BITMAP(SQL_GD_BOUND),
GI_CONST_BITMAP(SQL_IC_LOWER),
GI_CONST_BITMAP(SQL_IC_MIXED),
GI_CONST_BITMAP(SQL_IC_SENSITIVE),
GI_CONST_BITMAP(SQL_IC_UPPER),
GI_CONST_BITMAP(SQL_IK_ALL),
GI_CONST_BITMAP(SQL_IK_ASC),
GI_CONST_BITMAP(SQL_IK_DESC),
GI_CONST_BITMAP(SQL_IK_NONE),
GI_CONST_BITMAP(SQL_IS_INSERT_LITERALS),
GI_CONST_BITMAP(SQL_IS_INSERT_SEARCHED),
GI_CONST_BITMAP(SQL_IS_SELECT_INTO),
GI_CONST_BITMAP(SQL_ISV_ASSERTIONS),
GI_CONST_BITMAP(SQL_ISV_CHARACTER_SETS),
GI_CONST_BITMAP(SQL_ISV_CHECK_CONSTRAINTS),
GI_CONST_BITMAP(SQL_ISV_COLLATIONS),
GI_CONST_BITMAP(SQL_ISV_COLUMN_DOMAIN_USAGE),
GI_CONST_BITMAP(SQL_ISV_COLUMN_PRIVILEGES),
GI_CONST_BITMAP(SQL_ISV_COLUMNS),
GI_CONST_BITMAP(SQL_ISV_CONSTRAINT_COLUMN_USAGE),
GI_CONST_BITMAP(SQL_ISV_CONSTRAINT_TABLE_USAGE),
GI_CONST_BITMAP(SQL_ISV_DOMAIN_CONSTRAINTS),
GI_CONST_BITMAP(SQL_ISV_DOMAINS),
GI_CONST_BITMAP(SQL_ISV_KEY_COLUMN_USAGE),
GI_CONST_BITMAP(SQL_ISV_REFERENTIAL_CONSTRAINTS),
GI_CONST_BITMAP(SQL_ISV_SCHEMATA),
GI_CONST_BITMAP(SQL_ISV_SQL_LANGUAGES),
GI_CONST_BITMAP(SQL_ISV_TABLE_CONSTRAINTS),
GI_CONST_BITMAP(SQL_ISV_TABLE_PRIVILEGES),
GI_CONST_BITMAP(SQL_ISV_TABLES),
GI_CONST_BITMAP(SQL_ISV_TRANSLATIONS),
GI_CONST_BITMAP(SQL_ISV_USAGE_PRIVILEGES),
GI_CONST_BITMAP(SQL_ISV_VIEW_COLUMN_USAGE),
GI_CONST_BITMAP(SQL_ISV_VIEWS),
GI_CONST_BITMAP(SQL_ISV_VIEW_TABLE_USAGE),
GI_CONST_BITMAP(SQL_LCK_EXCLUSIVE),
GI_CONST_BITMAP(SQL_LCK_NO_CHANGE),
GI_CONST_BITMAP(SQL_LCK_UNLOCK),
GI_CONST_BITMAP(SQL_NC_END),
GI_CONST_BITMAP(SQL_NC_HIGH),
GI_CONST_BITMAP(SQL_NC_LOW),
GI_CONST_BITMAP(SQL_NC_START),
GI_CONST_BITMAP(SQL_NNC_NON_NULL),
GI_CONST_BITMAP(SQL_NNC_NULL),
GI_CONST_BITMAP(SQL_OAC_LEVEL1),
GI_CONST_BITMAP(SQL_OAC_LEVEL2),
GI_CONST_BITMAP(SQL_OAC_NONE),
GI_CONST_BITMAP(SQL_OIC_CORE),
GI_CONST_BITMAP(SQL_OIC_LEVEL1),
GI_CONST_BITMAP(SQL_OIC_LEVEL2),
GI_CONST_BITMAP(SQL_OJ_ALL_COMPARISON_OPS),
GI_CONST_BITMAP(SQL_OJ_FULL),
GI_CONST_BITMAP(SQL_OJ_INNER),
GI_CONST_BITMAP(SQL_OJ_LEFT),
GI_CONST_BITMAP(SQL_OJ_NESTED),
GI_CONST_BITMAP(SQL_OJ_NOT_ORDERED),
GI_CONST_BITMAP(SQL_OJ_RIGHT),
GI_CONST_BITMAP(SQL_OSCC_COMPLIANT),
GI_CONST_BITMAP(SQL_OSCC_NOT_COMPLIANT),
GI_CONST_BITMAP(SQL_OSC_CORE),
GI_CONST_BITMAP(SQL_OSC_EXTENDED),
GI_CONST_BITMAP(SQL_OSC_MINIMUM),
GI_CONST_BITMAP(SQL_OU_DML_STATEMENTS),
GI_CONST_BITMAP(SQL_OU_INDEX_DEFINITION),
GI_CONST_BITMAP(SQL_OU_PRIVILEGE_DEFINITION),
GI_CONST_BITMAP(SQL_OU_PROCEDURE_INVOCATION),
GI_CONST_BITMAP(SQL_OU_TABLE_DEFINITION),
GI_CONST_BITMAP(SQL_PARC_BATCH),
GI_CONST_BITMAP(SQL_PARC_NO_BATCH),
GI_CONST_BITMAP(SQL_PAS_BATCH),
GI_CONST_BITMAP(SQL_PAS_NO_BATCH),
GI_CONST_BITMAP(SQL_PAS_NO_SELECT),
GI_CONST_BITMAP(SQL_POS_ADD),
GI_CONST_BITMAP(SQL_POS_DELETE),
GI_CONST_BITMAP(SQL_POS_POSITION),
GI_CONST_BITMAP(SQL_POS_REFRESH),
GI_CONST_BITMAP(SQL_POS_UPDATE),
GI_CONST_BITMAP(SQL_PS_POSITIONED_DELETE),
GI_CONST_BITMAP(SQL_PS_POSITIONED_UPDATE),
GI_CONST_BITMAP(SQL_PS_SELECT_FOR_UPDATE),
GI_CONST_BITMAP(SQL_QL_END),
GI_CONST_BITMAP(SQL_QL_START),
GI_CONST_BITMAP(SQL_QU_DML_STATEMENTS),
GI_CONST_BITMAP(SQL_QU_INDEX_DEFINITION),
GI_CONST_BITMAP(SQL_QU_PRIVILEGE_DEFINITION),
GI_CONST_BITMAP(SQL_QU_PROCEDURE_INVOCATION),
GI_CONST_BITMAP(SQL_QU_TABLE_DEFINITION),
GI_CONST_BITMAP(SQL_SCC_ISO92_CLI),
GI_CONST_BITMAP(SQL_SCCO_LOCK),
GI_CONST_BITMAP(SQL_SCCO_OPT_ROWVER),
GI_CONST_BITMAP(SQL_SCCO_OPT_TIMESTAMP),
GI_CONST_BITMAP(SQL_SCCO_OPT_VALUES),
GI_CONST_BITMAP(SQL_SCCO_READ_ONLY),
GI_CONST_BITMAP(SQL_SCC_XOPEN_CLI_VERSION1),
GI_CONST_BITMAP(SQL_SC_FIPS127_2_TRANSITIONAL),
GI_CONST_BITMAP(SQL_SC_NON_UNIQUE),
GI_CONST_BITMAP(SQL_SC_SQL92_ENTRY),
GI_CONST_BITMAP(SQL_SC_SQL92_FULL),
GI_CONST_BITMAP(SQL_SC_SQL92_INTERMEDIATE),
GI_CONST_BITMAP(SQL_SC_TRY_UNIQUE),
GI_CONST_BITMAP(SQL_SC_UNIQUE),
GI_CONST_BITMAP(SQL_SDF_CURRENT_DATE),
GI_CONST_BITMAP(SQL_SDF_CURRENT_TIME),
GI_CONST_BITMAP(SQL_SDF_CURRENT_TIMESTAMP),
GI_CONST_BITMAP(SQL_SFKD_CASCADE),
GI_CONST_BITMAP(SQL_SFKD_NO_ACTION),
GI_CONST_BITMAP(SQL_SFKD_SET_DEFAULT),
GI_CONST_BITMAP(SQL_SFKD_SET_NULL),
GI_CONST_BITMAP(SQL_SFKU_CASCADE),
GI_CONST_BITMAP(SQL_SFKU_NO_ACTION),
GI_CONST_BITMAP(SQL_SFKU_SET_DEFAULT),
GI_CONST_BITMAP(SQL_SFKU_SET_NULL),
GI_CONST_BITMAP(SQL_SG_DELETE_TABLE),
GI_CONST_BITMAP(SQL_SG_INSERT_COLUMN),
GI_CONST_BITMAP(SQL_SG_INSERT_TABLE),
GI_CONST_BITMAP(SQL_SG_REFERENCES_COLUMN),
GI_CONST_BITMAP(SQL_SG_REFERENCES_TABLE),
GI_CONST_BITMAP(SQL_SG_SELECT_TABLE),
GI_CONST_BITMAP(SQL_SG_UPDATE_COLUMN),
GI_CONST_BITMAP(SQL_SG_UPDATE_TABLE),
GI_CONST_BITMAP(SQL_SG_USAGE_ON_CHARACTER_SET),
GI_CONST_BITMAP(SQL_SG_USAGE_ON_COLLATION),
GI_CONST_BITMAP(SQL_SG_USAGE_ON_DOMAIN),
GI_CONST_BITMAP(SQL_SG_USAGE_ON_TRANSLATION),
GI_CONST_BITMAP(SQL_SG_WITH_GRANT_OPTION),
GI_CONST_BITMAP(SQL_SNVF_BIT_LENGTH),
GI_CONST_BITMAP(SQL_SNVF_CHARACTER_LENGTH),
GI_CONST_BITMAP(SQL_SNVF_CHAR_LENGTH),
GI_CONST_BITMAP(SQL_SNVF_EXTRACT),
GI_CONST_BITMAP(SQL_SNVF_OCTET_LENGTH),
GI_CONST_BITMAP(SQL_SNVF_POSITION),
GI_CONST_BITMAP(SQL_SO_DYNAMIC),
GI_CONST_BITMAP(SQL_SO_FORWARD_ONLY),
GI_CONST_BITMAP(SQL_SO_KEYSET_DRIVEN),
GI_CONST_BITMAP(SQL_SO_MIXED),
GI_CONST_BITMAP(SQL_SO_STATIC),
GI_CONST_BITMAP(SQL_SP_BETWEEN),
GI_CONST_BITMAP(SQL_SP_COMPARISON),
GI_CONST_BITMAP(SQL_SP_EXISTS),
GI_CONST_BITMAP(SQL_SP_IN),
GI_CONST_BITMAP(SQL_SP_ISNOTNULL),
GI_CONST_BITMAP(SQL_SP_ISNULL),
GI_CONST_BITMAP(SQL_SP_LIKE),
GI_CONST_BITMAP(SQL_SP_MATCH_FULL),
GI_CONST_BITMAP(SQL_SP_MATCH_PARTIAL),
GI_CONST_BITMAP(SQL_SP_MATCH_UNIQUE_FULL),
GI_CONST_BITMAP(SQL_SP_MATCH_UNIQUE_PARTIAL),
GI_CONST_BITMAP(SQL_SP_OVERLAPS),
GI_CONST_BITMAP(SQL_SP_QUANTIFIED_COMPARISON),
GI_CONST_BITMAP(SQL_SP_UNIQUE),
GI_CONST_BITMAP(SQL_SQ_COMPARISON),
GI_CONST_BITMAP(SQL_SQ_CORRELATED_SUBQUERIES),
GI_CONST_BITMAP(SQL_SQ_EXISTS),
GI_CONST_BITMAP(SQL_SQ_IN),
GI_CONST_BITMAP(SQL_SQ_QUANTIFIED),
GI_CONST_BITMAP(SQL_SR_CASCADE),
GI_CONST_BITMAP(SQL_SR_DELETE_TABLE),
GI_CONST_BITMAP(SQL_SR_GRANT_OPTION_FOR),
GI_CONST_BITMAP(SQL_SR_INSERT_COLUMN),
GI_CONST_BITMAP(SQL_SR_INSERT_TABLE),
GI_CONST_BITMAP(SQL_SRJO_CORRESPONDING_CLAUSE),
GI_CONST_BITMAP(SQL_SRJO_CROSS_JOIN),
GI_CONST_BITMAP(SQL_SRJO_EXCEPT_JOIN),
GI_CONST_BITMAP(SQL_SRJO_FULL_OUTER_JOIN),
GI_CONST_BITMAP(SQL_SRJO_INNER_JOIN),
GI_CONST_BITMAP(SQL_SRJO_INTERSECT_JOIN),
GI_CONST_BITMAP(SQL_SRJO_LEFT_OUTER_JOIN),
GI_CONST_BITMAP(SQL_SRJO_NATURAL_JOIN),
GI_CONST_BITMAP(SQL_SRJO_RIGHT_OUTER_JOIN),
GI_CONST_BITMAP(SQL_SRJO_UNION_JOIN),
GI_CONST_BITMAP(SQL_SR_REFERENCES_COLUMN),
GI_CONST_BITMAP(SQL_SR_REFERENCES_TABLE),
GI_CONST_BITMAP(SQL_SR_RESTRICT),
GI_CONST_BITMAP(SQL_SR_SELECT_TABLE),
GI_CONST_BITMAP(SQL_SR_UPDATE_COLUMN),
GI_CONST_BITMAP(SQL_SR_UPDATE_TABLE),
GI_CONST_BITMAP(SQL_SR_USAGE_ON_CHARACTER_SET),
GI_CONST_BITMAP(SQL_SR_USAGE_ON_COLLATION),
GI_CONST_BITMAP(SQL_SR_USAGE_ON_DOMAIN),
GI_CONST_BITMAP(SQL_SR_USAGE_ON_TRANSLATION),
GI_CONST_BITMAP(SQL_SRVC_DEFAULT),
GI_CONST_BITMAP(SQL_SRVC_NULL),
GI_CONST_BITMAP(SQL_SRVC_ROW_SUBQUERY),
GI_CONST_BITMAP(SQL_SRVC_VALUE_EXPRESSION),
GI_CONST_BITMAP(SQL_SS_ADDITIONS),
GI_CONST_BITMAP(SQL_SS_DELETIONS),
GI_CONST_BITMAP(SQL_SSF_CONVERT),
GI_CONST_BITMAP(SQL_SSF_LOWER),
GI_CONST_BITMAP(SQL_SSF_SUBSTRING),
GI_CONST_BITMAP(SQL_SSF_TRANSLATE),
GI_CONST_BITMAP(SQL_SSF_TRIM_BOTH),
GI_CONST_BITMAP(SQL_SSF_TRIM_LEADING),
GI_CONST_BITMAP(SQL_SSF_TRIM_TRAILING),
GI_CONST_BITMAP(SQL_SSF_UPPER),
GI_CONST_BITMAP(SQL_SS_UPDATES),
GI_CONST_BITMAP(SQL_SU_DML_STATEMENTS),
GI_CONST_BITMAP(SQL_SU_INDEX_DEFINITION),
GI_CONST_BITMAP(SQL_SU_PRIVILEGE_DEFINITION),
GI_CONST_BITMAP(SQL_SU_PROCEDURE_INVOCATION),
GI_CONST_BITMAP(SQL_SU_TABLE_DEFINITION),
GI_CONST_BITMAP(SQL_SVE_CASE),
GI_CONST_BITMAP(SQL_SVE_CAST),
GI_CONST_BITMAP(SQL_SVE_COALESCE),
GI_CONST_BITMAP(SQL_SVE_NULLIF),
GI_CONST_BITMAP(SQL_TC_ALL),
GI_CONST_BITMAP(SQL_TC_DDL_COMMIT),
GI_CONST_BITMAP(SQL_TC_DDL_IGNORE),
GI_CONST_BITMAP(SQL_TC_DML),
GI_CONST_BITMAP(SQL_TC_NONE),
GI_CONST_BITMAP(SQL_TRANSACTION_READ_COMMITTED),
GI_CONST_BITMAP(SQL_TRANSACTION_READ_UNCOMMITTED),
GI_CONST_BITMAP(SQL_TRANSACTION_REPEATABLE_READ),
GI_CONST_BITMAP(SQL_TRANSACTION_SERIALIZABLE),
GI_CONST_BITMAP(SQL_TXN_READ_COMMITTED),
GI_CONST_BITMAP(SQL_TXN_READ_UNCOMMITTED),
GI_CONST_BITMAP(SQL_TXN_REPEATABLE_READ),
GI_CONST_BITMAP(SQL_TXN_SERIALIZABLE),
#ifdef SQL_TXN_VERSIONING
GI_CONST_BITMAP(SQL_TXN_VERSIONING),
#endif
GI_CONST_BITMAP(SQL_US_UNION),
GI_CONST_BITMAP(SQL_US_UNION_ALL),
GI_CONST_BITMAP(SQL_U_UNION),
GI_CONST_BITMAP(SQL_U_UNION_ALL),
/* end of table */
GI_CONST_BITMAP_END
};
static VALUE
dbc_getinfo(int argc, VALUE *argv, VALUE self)
{
DBC *p = get_dbc(self);
VALUE which, vtype, vstr;
SQLRETURN ret;
int i, k, info = -1, maptype = -1, info_found = 0;
SQLUSMALLINT sbuffer;
SQLUINTEGER lbuffer;
SQLSMALLINT len_in, len_out;
char *string = NULL, buffer[513];
rb_scan_args(argc, argv, "11", &which, &vtype);
switch (TYPE(which)) {
default:
vstr = rb_any_to_s(which);
string = STR2CSTR(vstr);
goto doString;
case T_STRING:
string = STR2CSTR(which);
doString:
for (i = 0; get_info_map[i].name != NULL; i++) {
if (strcmp(string, get_info_map[i].name) == 0) {
info = get_info_map[i].info;
maptype = get_info_map[i].maptype;
info_found = 2;
break;
}
}
break;
case T_FLOAT:
case T_BIGNUM:
k = (int) NUM2DBL(which);
goto doInt;
case T_FIXNUM:
k = FIX2INT(which);
doInt:
info = k;
info_found = 1;
for (i = 0; get_info_map[i].name != NULL; i++) {
if (k == get_info_map[i].info) {
info = get_info_map[i].info;
maptype = get_info_map[i].maptype;
info_found = 3;
break;
}
}
break;
}
switch (info_found) {
case 0:
rb_raise(Cerror, "%s",
set_err("Invalid info type for ODBC::Connection.get_info",
0));
return Qnil;
case 1:
sprintf(buffer, "Unknown info type %d for ODBC::Connection.get_info",
info);
set_err(buffer, 1);
break;
}
if (vtype != Qnil) {
switch (TYPE(vtype)) {
case T_FIXNUM:
maptype = FIX2INT(vtype);
break;
case T_BIGNUM:
case T_FLOAT:
maptype = (int) NUM2DBL(vtype);
break;
default:
rb_raise(rb_eTypeError, "need number for sql_type");
return Qnil;
}
switch (maptype) {
case SQL_NUMERIC:
case SQL_DECIMAL:
case SQL_INTEGER:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DOUBLE:
case SQL_C_ULONG:
#ifdef SQL_BIGINT
case SQL_BIGINT:
#endif
#ifdef SQL_C_UBIGINT
case SQL_C_UBIGINT:
#endif
maptype = SQL_C_LONG;
break;
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_C_USHORT:
case SQL_C_UTINYINT:
maptype = SQL_C_SHORT;
break;
default:
maptype = SQL_C_CHAR;
break;
}
}
switch (maptype) {
case SQL_C_SHORT:
len_in = sizeof (sbuffer);
sbuffer = 0;
ret = SQLGetInfo(p->hdbc, (SQLUSMALLINT) info,
(SQLPOINTER) &sbuffer, len_in, &len_out);
break;
case SQL_C_LONG:
len_in = sizeof (lbuffer);
lbuffer = 0;
ret = SQLGetInfo(p->hdbc, (SQLUSMALLINT) info,
(SQLPOINTER) &lbuffer, len_in, &len_out);
break;
default:
case SQL_C_CHAR:
len_in = sizeof (buffer) - 1;
memset(buffer, 0, sizeof (buffer));
ret = SQLGetInfo(p->hdbc, (SQLUSMALLINT) info,
(SQLPOINTER) buffer, len_in, &len_out);
break;
}
if (!SQL_SUCCEEDED(ret)) {
rb_raise(Cerror, "%s",
get_err(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT));
}
switch (maptype) {
case SQL_C_SHORT:
return INT2NUM(sbuffer);
case SQL_C_LONG:
return INT2NUM(lbuffer);
default:
case SQL_C_CHAR:
return rb_str_new(buffer, len_out);
}
return Qnil;
}
/*
*----------------------------------------------------------------------
*
* Fill column type array for statement.
*
*----------------------------------------------------------------------
*/
static COLTYPE *
make_coltypes(SQLHSTMT hstmt, int ncols, char **msgp)
{
int i;
COLTYPE *ret = NULL;
for (i = 0; i < ncols; i++) {
SQLUSMALLINT ic = i + 1;
SQLLEN type = SQL_UNKNOWN_TYPE, size = 0;
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic,
SQL_COLUMN_TYPE, NULL, 0, NULL,
&type),
msgp, "SQLColAttributes(SQL_COLUMN_TYPE)")) {
return ret;
}
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic,
SQL_COLUMN_DISPLAY_SIZE,
NULL, 0, NULL, &size),
msgp, "SQLColAttributes(SQL_COLUMN_DISPLAY_SIZE)")) {
return ret;
}
}
ret = ALLOC_N(COLTYPE, ncols);
if (ret == NULL) {
if (msgp != NULL) {
*msgp = set_err("Out of memory", 0);
}
return NULL;
}
for (i = 0; i < ncols; i++) {
SQLUSMALLINT ic = i + 1;
SQLLEN type = SQL_UNKNOWN_TYPE, size = 0;
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic,
SQL_COLUMN_TYPE,
NULL, 0, NULL, &type),
"SQLColAttributes(SQL_COLUMN_TYPE)");
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic,
SQL_COLUMN_DISPLAY_SIZE,
NULL, 0, NULL, &size),
"SQLColAttributes(SQL_COLUMN_DISPLAY_SIZE)");
switch (type) {
#ifdef SQL_BIT
case SQL_BIT:
#endif
#ifdef SQL_TINYINT
case SQL_TINYINT:
#endif
case SQL_SMALLINT:
case SQL_INTEGER:
type = SQL_C_LONG;
size = sizeof (SQLINTEGER);
break;
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_REAL:
type = SQL_C_DOUBLE;
size = sizeof (double);
break;
case SQL_DATE:
#ifdef SQL_TYPE_DATE
case SQL_TYPE_DATE:
#endif
type = SQL_C_DATE;
size = sizeof (DATE_STRUCT);
break;
case SQL_TIME:
#ifdef SQL_TYPE_TIME
case SQL_TYPE_TIME:
#endif
type = SQL_C_TIME;
size = sizeof (TIME_STRUCT);
break;
case SQL_TIMESTAMP:
#ifdef SQL_TYPE_TIMESTAMP
case SQL_TYPE_TIMESTAMP:
#endif
type = SQL_C_TIMESTAMP;
size = sizeof (TIMESTAMP_STRUCT);
break;
case SQL_LONGVARBINARY:
type = SQL_C_BINARY;
size = SQL_NO_TOTAL;
break;
case SQL_LONGVARCHAR:
#ifdef UNICODE
case SQL_WLONGVARCHAR:
type = SQL_C_WCHAR;
#else
type = SQL_C_CHAR;
#endif
size = SQL_NO_TOTAL;
break;
#ifdef SQL_BIGINT
case SQL_BIGINT:
if (sizeof (SQLBIGINT) == sizeof (SQLINTEGER)) {
type = SQL_C_LONG;
size = sizeof (SQLINTEGER);
} else {
type = SQL_C_SBIGINT;
size = sizeof (SQLBIGINT);
}
break;
#endif
#ifdef SQL_UBIGINT
case SQL_UBIGINT:
if (sizeof (SQLBIGINT) == sizeof (SQLINTEGER)) {
type = SQL_C_LONG;
size = sizeof (SQLINTEGER);
} else {
type = SQL_C_UBIGINT;
size = sizeof (SQLBIGINT);
}
break;
#endif
default:
if ((size == 0) || (size > SEGSIZE)) {
size = SQL_NO_TOTAL;
}
#ifdef UNICODE
type = SQL_C_WCHAR;
if (size != SQL_NO_TOTAL) {
size *= sizeof (SQLWCHAR);
size += sizeof (SQLWCHAR);
}
#else
type = SQL_C_CHAR;
if (size != SQL_NO_TOTAL) {
size += 1;
}
#endif
break;
}
ret[i].type = type;
ret[i].size = size;
}
return ret;
}
/*
*----------------------------------------------------------------------
*
* Fill parameter info array for statement.
*
*----------------------------------------------------------------------
*/
static PARAMINFO *
make_paraminfo(SQLHSTMT hstmt, int nump, char **msgp)
{
int i;
PARAMINFO *paraminfo = NULL;
paraminfo = ALLOC_N(PARAMINFO, nump);
if (paraminfo == NULL) {
if (msgp != NULL) {
*msgp = set_err("Out of memory", 0);
}
return NULL;
}
for (i = 0; i < nump; i++) {
paraminfo[i].iotype = SQL_PARAM_INPUT;
paraminfo[i].outsize = 0;
paraminfo[i].outbuf = NULL;
paraminfo[i].rlen = SQL_NULL_DATA;
paraminfo[i].ctype = SQL_C_CHAR;
#ifdef UNICODE
paraminfo[i].outtype = SQL_WCHAR;
#else
paraminfo[i].outtype = SQL_CHAR;
#endif
paraminfo[i].coldef_max = 0;
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLDescribeParam(hstmt, (SQLUSMALLINT) (i + 1),
¶minfo[i].type,
¶minfo[i].coldef,
¶minfo[i].scale,
¶minfo[i].nullable),
NULL, "SQLDescribeParam")) {
#ifdef UNICODE
paraminfo[i].type = SQL_WVARCHAR;
#else
paraminfo[i].type = SQL_VARCHAR;
#endif
paraminfo[i].coldef = 0;
paraminfo[i].scale = 0;
paraminfo[i].nullable = SQL_NULLABLE_UNKNOWN;
paraminfo[i].override = 0;
}
}
return paraminfo;
}
static void
retain_paraminfo_override(STMT *q, int nump, PARAMINFO *paraminfo)
{
if ((q->paraminfo != NULL) && (q->nump == nump)) {
int i;
for (i = 0; i < nump; i++) {
paraminfo[i].iotype = q->paraminfo[i].iotype;
paraminfo[i].rlen = q->paraminfo[i].rlen;
paraminfo[i].ctype = q->paraminfo[i].ctype;
paraminfo[i].outtype = q->paraminfo[i].outtype;
paraminfo[i].outsize = q->paraminfo[i].outsize;
if (q->paraminfo[i].outbuf != NULL) {
paraminfo[i].outbuf = q->paraminfo[i].outbuf;
q->paraminfo[i].outbuf = NULL;
}
if (q->paraminfo[i].override) {
paraminfo[i].override = q->paraminfo[i].override;
paraminfo[i].type = q->paraminfo[i].type;
paraminfo[i].coldef = q->paraminfo[i].coldef;
paraminfo[i].scale = q->paraminfo[i].scale;
}
}
}
}
/*
*----------------------------------------------------------------------
*
* Wrap SQLHSTMT into struct/VALUE.
*
*----------------------------------------------------------------------
*/
static VALUE
wrap_stmt(VALUE dbc, DBC *p, SQLHSTMT hstmt, STMT **qp)
{
VALUE stmt = Qnil;
STMT *q;
int i;
stmt = Data_Make_Struct(Cstmt, STMT, mark_stmt, free_stmt, q);
tracemsg(2, fprintf(stderr, "ObjAlloc: STMT %p\n", q););
list_init(&q->link, offsetof(STMT, link));
q->self = stmt;
q->hstmt = hstmt;
q->dbc = dbc;
q->dbcp = NULL;
q->paraminfo = NULL;
q->coltypes = NULL;
q->colnames = q->dbufs = NULL;
q->colvals = NULL;
q->fetchc = 0;
q->upc = p->upc;
q->usef = 0;
rb_iv_set(q->self, "@_a", rb_ary_new());
rb_iv_set(q->self, "@_h", rb_hash_new());
for (i = 0; i < 4; i++) {
rb_iv_set(q->self, colnamebuf[i], rb_hash_new());
}
if (hstmt != SQL_NULL_HSTMT) {
link_stmt(q, p);
} else {
q->dbc = Qnil;
}
if (qp != NULL) {
*qp = q;
}
return stmt;
}
/*
*----------------------------------------------------------------------
*
* Create statement with result.
*
*----------------------------------------------------------------------
*/
static VALUE
make_result(VALUE dbc, SQLHSTMT hstmt, VALUE result, int mode)
{
DBC *p;
STMT *q;
SQLSMALLINT cols = 0, nump;
COLTYPE *coltypes = NULL;
PARAMINFO *paraminfo = NULL;
char *msg = NULL;
Data_Get_Struct(dbc, DBC, p);
if ((hstmt == SQL_NULL_HSTMT) ||
!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLNumParams(hstmt, &nump), NULL, "SQLNumParams")) {
nump = 0;
}
if (nump > 0) {
paraminfo = make_paraminfo(hstmt, nump, &msg);
if (paraminfo == NULL) {
goto error;
}
}
if ((mode & MAKERES_PREPARE) ||
(hstmt == SQL_NULL_HSTMT) ||
(!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLNumResultCols(hstmt, &cols), NULL,
"SQLNumResultCols"))) {
cols = 0;
}
if (cols > 0) {
coltypes = make_coltypes(hstmt, cols, &msg);
if (coltypes == NULL) {
goto error;
}
}
if (result == Qnil) {
result = wrap_stmt(dbc, p, hstmt, &q);
} else {
Data_Get_Struct(result, STMT, q);
retain_paraminfo_override(q, nump, paraminfo);
free_stmt_sub(q, 1);
if (q->dbc != dbc) {
unlink_stmt(q);
q->dbc = dbc;
if (hstmt != SQL_NULL_HSTMT) {
link_stmt(q, p);
}
}
q->hstmt = hstmt;
}
q->nump = nump;
q->paraminfo = paraminfo;
q->ncols = cols;
q->coltypes = coltypes;
if ((mode & MAKERES_BLOCK) && rb_block_given_p()) {
if (mode & MAKERES_NOCLOSE) {
return rb_yield(result);
}
return rb_ensure(rb_yield, result, stmt_close, result);
}
return result;
error:
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLFreeStmt(hstmt, SQL_DROP), "SQLFreeStmt(SQL_DROP)");
if (result != Qnil) {
Data_Get_Struct(result, STMT, q);
if (q->hstmt == hstmt) {
q->hstmt = SQL_NULL_HSTMT;
unlink_stmt(q);
}
}
if (paraminfo != NULL) {
xfree(paraminfo);
}
if (coltypes != NULL) {
xfree(coltypes);
}
rb_raise(Cerror, "%s", msg);
return Qnil;
}
static char *
upcase_if(char *string, int upc)
{
if (upc && (string != NULL)) {
unsigned char *p = (unsigned char *) string;
while (*p != '\0') {
#ifdef UNICODE
if ((*p < 0x80) && ISLOWER(*p))
#else
if (ISLOWER(*p))
#endif
{
*p = toupper(*p);
}
++p;
}
}
return string;
}
/*
*----------------------------------------------------------------------
*
* Constructor: make column from statement.
*
*----------------------------------------------------------------------
*/
static VALUE
make_column(SQLHSTMT hstmt, int i, int upc, int use_scn)
{
VALUE obj, v;
SQLUSMALLINT ic = i + 1;
SQLLEN iv;
#ifdef UNICODE
SQLWCHAR name[SQL_MAX_MESSAGE_LENGTH];
#else
char name[SQL_MAX_MESSAGE_LENGTH];
#endif
char *msg;
SQLSMALLINT name_len;
name[0] = 0;
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, use_scn ? SQL_COLUMN_NAME :
SQL_COLUMN_LABEL, name,
(SQLSMALLINT) sizeof (name),
&name_len, NULL),
&msg, use_scn ? "SQLColAttributes(SQL_COLUMN_NAME)" :
"SQLColAttributes(SQL_COLUMN_LABEL)")) {
rb_raise(Cerror, "%s", msg);
}
obj = rb_obj_alloc(Ccolumn);
if (name_len >= (SQLSMALLINT) sizeof (name)) {
name_len = sizeof (name) - 1;
}
if (name_len > 0) {
name[name_len / sizeof (name[0])] = 0;
}
#ifdef UNICODE
if (upc) {
int len = uc_strlen(name);
char tmpbuf[1];
char *tmp = xmalloc(len);
VALUE v;
if (tmp == NULL) {
tmp = tmpbuf;
len = 0;
}
mkutf(tmp, name, len);
v = rb_tainted_str_new2(upcase_if(tmp, 1));
#ifdef USE_RB_ENC
rb_enc_associate(v, rb_enc);
#endif
rb_iv_set(obj, "@name", v);
if ((tmp != NULL) && (tmp != tmpbuf)) {
xfree(tmp);
}
} else {
rb_iv_set(obj, "@name", uc_tainted_str_new2(name));
}
#else
rb_iv_set(obj, "@name", rb_tainted_str_new2(upcase_if(name, upc)));
#endif
v = Qnil;
name[0] = 0;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, SQL_COLUMN_TABLE_NAME, name,
(SQLSMALLINT) sizeof (name),
&name_len, NULL),
NULL, "SQLColAttributes(SQL_COLUMN_TABLE_NAME)")) {
if (name_len > (SQLSMALLINT) sizeof (name)) {
name_len = sizeof (name) - 1;
}
if (name_len > 0) {
name[name_len / sizeof (name[0])] = 0;
}
#ifdef UNICODE
v = uc_tainted_str_new2(name);
#else
v = rb_tainted_str_new2(name);
#endif
}
rb_iv_set(obj, "@table", v);
iv = SQL_UNKNOWN_TYPE;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, SQL_COLUMN_TYPE, NULL,
0, NULL, &iv),
NULL, "SQLColAttributes(SQL_COLUMN_TYPE)")) {
v = INT2NUM(iv);
} else {
v = INT2NUM(SQL_UNKNOWN_TYPE);
}
rb_iv_set(obj, "@type", v);
v = Qnil;
iv = 0;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic,
#if (ODBCVER >= 0x0300)
SQL_DESC_LENGTH,
#else
SQL_COLUMN_LENGTH,
#endif
NULL, 0, NULL, &iv),
NULL,
#if (ODBCVER >= 0x0300)
"SQLColAttributes(SQL_DESC_LENGTH)"
#else
"SQLColAttributes(SQL_COLUMN_LENGTH)"
#endif
)) {
v = INT2NUM(iv);
} else if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic,
SQL_COLUMN_DISPLAY_SIZE, NULL,
0, NULL, &iv),
NULL, "SQLColAttributes(SQL_COLUMN_DISPLAY_SIZE)")) {
v = INT2NUM(iv);
}
rb_iv_set(obj, "@length", v);
v = Qnil;
iv = SQL_NO_NULLS;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, SQL_COLUMN_NULLABLE, NULL,
0, NULL, &iv),
NULL, "SQLColAttributes(SQL_COLUMN_NULLABLE)")) {
v = (iv == SQL_NO_NULLS) ? Qfalse : Qtrue;
}
rb_iv_set(obj, "@nullable", v);
v = Qnil;
iv = 0;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, SQL_COLUMN_SCALE, NULL,
0, NULL, &iv),
NULL, "SQLColAttributes(SQL_COLUMN_SCALE)")) {
v = INT2NUM(iv);
}
rb_iv_set(obj, "@scale", v);
v = Qnil;
iv = 0;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, SQL_COLUMN_PRECISION, NULL,
0, NULL, &iv),
NULL, "SQLColAttributes(SQL_COLUMN_PRECISION)")) {
v = INT2NUM(iv);
}
rb_iv_set(obj, "@precision", v);
v = Qnil;
iv = SQL_UNSEARCHABLE;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, SQL_COLUMN_SEARCHABLE, NULL,
0, NULL, &iv),
NULL, "SQLColAttributes(SQL_COLUMN_SEARCHABLE)")) {
v = (iv == SQL_UNSEARCHABLE) ? Qfalse : Qtrue;
}
rb_iv_set(obj, "@searchable", v);
v = Qnil;
iv = SQL_FALSE;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, SQL_COLUMN_UNSIGNED, NULL,
0, NULL, &iv),
NULL, "SQLColAttributes(SQL_COLUMN_UNSIGNED)")) {
v = (iv == SQL_FALSE) ? Qfalse : Qtrue;
}
rb_iv_set(obj, "@unsigned", v);
v = Qnil;
#ifdef SQL_COLUMN_AUTO_INCREMENT
iv = SQL_FALSE;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLColAttributes(hstmt, ic, SQL_COLUMN_AUTO_INCREMENT, NULL,
0, NULL, &iv),
NULL, "SQLColAttributes(SQL_COLUMN_AUTO_INCREMENT)")) {
v = (iv == SQL_FALSE) ? Qfalse : Qtrue;
}
#endif
rb_iv_set(obj, "@autoincrement", v);
return obj;
}
/*
*----------------------------------------------------------------------
*
* Constructor: make parameter from statement.
*
*----------------------------------------------------------------------
*/
static VALUE
make_param(STMT *q, int i)
{
VALUE obj;
int v;
obj = rb_obj_alloc(Cparam);
#ifdef UNICODE
v = q->paraminfo ? q->paraminfo[i].type : SQL_WVARCHAR;
#else
v = q->paraminfo ? q->paraminfo[i].type : SQL_VARCHAR;
#endif
rb_iv_set(obj, "@type", INT2NUM(v));
v = q->paraminfo ? q->paraminfo[i].coldef : 0;
rb_iv_set(obj, "@precision", INT2NUM(v));
v = q->paraminfo ? q->paraminfo[i].scale : 0;
rb_iv_set(obj, "@scale", INT2NUM(v));
v = q->paraminfo ? q->paraminfo[i].nullable : SQL_NULLABLE_UNKNOWN;
rb_iv_set(obj, "@nullable", INT2NUM(v));
v = q->paraminfo ? q->paraminfo[i].iotype : SQL_PARAM_INPUT;
rb_iv_set(obj, "@iotype", INT2NUM(v));
v = q->paraminfo ? q->paraminfo[i].outsize : 0;
rb_iv_set(obj, "@output_size", INT2NUM(v));
#ifdef UNICODE
v = q->paraminfo ? q->paraminfo[i].outtype : SQL_WCHAR;
#else
v = q->paraminfo ? q->paraminfo[i].outtype : SQL_CHAR;
#endif
rb_iv_set(obj, "@output_type", INT2NUM(v));
return obj;
}
/*
*----------------------------------------------------------------------
*
* Query tables/columns/keys/indexes/types of data source.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_info(int argc, VALUE *argv, VALUE self, int mode)
{
DBC *p = get_dbc(self);
VALUE which = Qnil, which2 = Qnil, which3 = Qnil;
#ifdef UNICODE
SQLWCHAR *swhich = NULL, *swhich2 = NULL;
#else
SQLCHAR *swhich = NULL, *swhich2 = NULL;
#endif
char *msg;
const char *argspec = NULL;
SQLHSTMT hstmt;
int needstr = 1, itype = SQL_ALL_TYPES;
int iid = SQL_BEST_ROWID, iscope = SQL_SCOPE_CURROW;
if (p->hdbc == SQL_NULL_HDBC) {
rb_raise(Cerror, "%s", set_err("No connection", 0));
}
switch (mode) {
case INFO_TYPES:
needstr = 0;
/* FALL THRU */
case INFO_TABLES:
case INFO_PRIMKEYS:
case INFO_TPRIV:
case INFO_PROCS:
argspec = "01";
break;
case INFO_COLUMNS:
argspec = "02";
break;
case INFO_INDEXES:
case INFO_FORKEYS:
case INFO_PROCCOLS:
argspec = "11";
break;
case INFO_SPECCOLS:
argspec = "12";
break;
default:
rb_raise(Cerror, "%s", set_err("Invalid info mode", 0));
break;
}
rb_scan_args(argc, argv, argspec, &which, &which2, &which3);
if (which != Qnil) {
if (needstr) {
Check_Type(which, T_STRING);
#ifdef UNICODE
swhich = (SQLWCHAR *) which;
#else
swhich = (SQLCHAR *) STR2CSTR(which);
#endif
} else {
itype = NUM2INT(which);
}
}
if (which2 != Qnil) {
if (mode == INFO_SPECCOLS) {
iid = NUM2INT(which2);
} else if (mode != INFO_INDEXES) {
Check_Type(which2, T_STRING);
#ifdef UNICODE
swhich2 = (SQLWCHAR *) which2;
#else
swhich2 = (SQLCHAR *) STR2CSTR(which2);
#endif
}
}
#ifdef UNICODE
if (swhich != NULL) {
VALUE val = (VALUE) swhich;
#ifdef USE_RB_ENC
val = rb_funcall(val, IDencode, 1, rb_encv);
#endif
swhich = uc_from_utf((unsigned char *) STR2CSTR(val), -1);
if (swhich == NULL) {
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
}
if (swhich2 != NULL) {
VALUE val = (VALUE) swhich2;
#ifdef USE_RB_ENC
val = rb_funcall(val, IDencode, 1, rb_encv);
#endif
swhich2 = uc_from_utf((unsigned char *) STR2CSTR(val), -1);
if (swhich2 == NULL) {
uc_free(swhich);
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
}
#endif
if (which3 != Qnil) {
iscope = NUM2INT(which3);
}
if (!succeeded(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLAllocStmt(p->hdbc, &hstmt), &msg, "SQLAllocStmt")) {
#ifdef UNICODE
uc_free(swhich);
uc_free(swhich2);
#endif
rb_raise(Cerror, "%s", msg);
}
switch (mode) {
case INFO_TABLES:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLTABLES(hstmt, NULL, 0, NULL, 0,
swhich, (swhich == NULL) ? 0 : SQL_NTS,
NULL, 0),
&msg, "SQLTables")) {
goto error;
}
break;
case INFO_COLUMNS:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLCOLUMNS(hstmt, NULL, 0, NULL, 0,
swhich, (swhich == NULL) ? 0 : SQL_NTS,
swhich2, (swhich2 == NULL) ? 0 : SQL_NTS),
&msg, "SQLColumns")) {
goto error;
}
break;
case INFO_PRIMKEYS:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLPRIMARYKEYS(hstmt, NULL, 0, NULL, 0,
swhich, (swhich == NULL) ? 0 : SQL_NTS),
&msg, "SQLPrimaryKeys")) {
goto error;
}
break;
case INFO_INDEXES:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLSTATISTICS(hstmt, NULL, 0, NULL, 0,
swhich, (swhich == NULL) ? 0 : SQL_NTS,
(SQLUSMALLINT) (RTEST(which2) ?
SQL_INDEX_UNIQUE : SQL_INDEX_ALL),
SQL_ENSURE),
&msg, "SQLStatistics")) {
goto error;
}
break;
case INFO_TYPES:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLGETTYPEINFO(hstmt, (SQLSMALLINT) itype),
&msg, "SQLGetTypeInfo")) {
goto error;
}
break;
case INFO_FORKEYS:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLFOREIGNKEYS(hstmt, NULL, 0, NULL, 0,
swhich, (swhich == NULL) ? 0 : SQL_NTS,
NULL, 0, NULL, 0,
swhich2, (swhich2 == NULL) ? 0 : SQL_NTS),
&msg, "SQLForeignKeys")) {
goto error;
}
break;
case INFO_TPRIV:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLTABLEPRIVILEGES(hstmt, NULL, 0, NULL, 0, swhich,
(swhich == NULL) ? 0 : SQL_NTS),
&msg, "SQLTablePrivileges")) {
goto error;
}
break;
case INFO_PROCS:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLPROCEDURES(hstmt, NULL, 0, NULL, 0,
swhich, (swhich == NULL) ? 0 : SQL_NTS),
&msg, "SQLProcedures")) {
goto error;
}
break;
case INFO_PROCCOLS:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLPROCEDURECOLUMNS(hstmt, NULL, 0, NULL, 0,
swhich,
(swhich == NULL) ? 0 : SQL_NTS,
swhich2,
(swhich2 == NULL) ? 0 : SQL_NTS),
&msg, "SQLProcedureColumns")) {
goto error;
}
break;
case INFO_SPECCOLS:
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLSPECIALCOLUMNS(hstmt, (SQLUSMALLINT) iid,
NULL, 0, NULL, 0,
swhich,
(swhich == NULL) ? 0 : SQL_NTS,
(SQLUSMALLINT) iscope,
SQL_NULLABLE),
&msg, "SQLSpecialColumns")) {
goto error;
}
break;
}
#ifdef UNICODE
uc_free(swhich);
uc_free(swhich2);
#endif
return make_result(self, hstmt, Qnil, MAKERES_BLOCK);
error:
#ifdef UNICODE
uc_free(swhich);
uc_free(swhich2);
#endif
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLFreeStmt(hstmt, SQL_DROP), "SQLFreeStmt(SQL_DROP)");
rb_raise(Cerror, "%s", msg);
return Qnil;
}
static VALUE
dbc_tables(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_TABLES);
}
static VALUE
dbc_columns(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_COLUMNS);
}
static VALUE
dbc_primkeys(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_PRIMKEYS);
}
static VALUE
dbc_indexes(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_INDEXES);
}
static VALUE
dbc_types(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_TYPES);
}
static VALUE
dbc_forkeys(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_FORKEYS);
}
static VALUE
dbc_tpriv(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_TPRIV);
}
static VALUE
dbc_procs(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_PROCS);
}
static VALUE
dbc_proccols(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_PROCCOLS);
}
static VALUE
dbc_speccols(int argc, VALUE *argv, VALUE self)
{
return dbc_info(argc, argv, self, INFO_SPECCOLS);
}
/*
*----------------------------------------------------------------------
*
* Transaction stuff.
*
*----------------------------------------------------------------------
*/
static VALUE
dbc_trans(VALUE self, int what)
{
ENV *e;
SQLHDBC dbc = SQL_NULL_HDBC;
SQLRETURN ret;
char *msg;
e = get_env(self);
if (rb_obj_is_kind_of(self, Cdbc) == Qtrue) {
DBC *d;
d = get_dbc(self);
dbc = d->hdbc;
}
#if (ODBCVER >= 0x0300)
ret = SQLENDTRAN((SQLSMALLINT)
((dbc == SQL_NULL_HDBC) ? SQL_HANDLE_ENV : SQL_HANDLE_DBC),
(dbc == SQL_NULL_HDBC) ? e->henv : dbc,
(SQLSMALLINT) what);
#else
ret = SQLTRANSACT(e->henv, dbc, (SQLUSMALLINT) what);
#endif
if (!succeeded(e->henv, dbc, SQL_NULL_HSTMT, ret,
#if (ODBCVER >= 0x0300)
&msg, "SQLEndTran"
#else
&msg, "SQLTransact"
#endif
)) {
rb_raise(Cerror, "%s", msg);
}
return Qnil;
}
static VALUE
dbc_commit(VALUE self)
{
return dbc_trans(self, SQL_COMMIT);
}
static VALUE
dbc_rollback(VALUE self)
{
return dbc_trans(self, SQL_ROLLBACK);
}
static VALUE
dbc_nop(VALUE self)
{
return Qnil;
}
static VALUE
dbc_transbody(VALUE self)
{
return rb_yield(rb_ary_entry(self, 0));
}
static VALUE
dbc_transfail(VALUE self, VALUE err)
{
rb_ary_store(self, 1, err);
dbc_rollback(rb_ary_entry(self, 0));
return Qundef;
}
static VALUE
dbc_transaction(VALUE self)
{
VALUE a, ret;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "block required");
}
rb_ensure(dbc_commit, self, dbc_nop, self);
a = rb_ary_new2(2);
rb_ary_store(a, 0, self);
rb_ary_store(a, 1, Qnil);
if ((ret = rb_rescue2(dbc_transbody, a, dbc_transfail, a,
rb_eException, (VALUE) 0)) != Qundef) {
dbc_commit(self);
return ret;
}
ret = rb_ary_entry(a, 1);
rb_exc_raise(rb_exc_new3(rb_obj_class(ret),
rb_funcall(ret, IDto_s, 0, 0)));
return Qnil;
}
/*
*----------------------------------------------------------------------
*
* Environment attribute handling.
*
*----------------------------------------------------------------------
*/
#if (ODBCVER >= 0x0300)
static VALUE
do_attr(int argc, VALUE *argv, VALUE self, int op)
{
SQLHENV henv = SQL_NULL_HENV;
VALUE val;
SQLLEN v = 0;
SQLPOINTER vp;
SQLINTEGER l;
char *msg;
if (self != Modbc) {
henv = get_env(self)->henv;
}
rb_scan_args(argc, argv, "01", &val);
if (val == Qnil) {
if (!succeeded(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLGetEnvAttr(henv, (SQLINTEGER) op,
(SQLPOINTER) &v, sizeof (v), &l),
&msg, "SQLGetEnvAttr(%d)", op)) {
rb_raise(Cerror, "%s", msg);
}
return rb_int2inum(v);
}
v = NUM2INT(val);
vp = (SQLPOINTER) v;
if (!succeeded(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT,
SQLSetEnvAttr(henv, (SQLINTEGER) op, vp, SQL_IS_INTEGER),
&msg, "SQLSetEnvAttr(%d)", op)) {
rb_raise(Cerror, "%s", msg);
}
return Qnil;
}
#endif
static VALUE
env_cpooling(int argc, VALUE *argv, VALUE self)
{
#if (ODBCVER >= 0x0300)
return do_attr(argc, argv, self, SQL_ATTR_CONNECTION_POOLING);
#else
rb_raise(Cerror, "%s", set_err("Unsupported in ODBC < 3.0", 0));
return Qnil;
#endif
}
static VALUE
env_cpmatch(int argc, VALUE *argv, VALUE self)
{
#if (ODBCVER >= 0x0300)
return do_attr(argc, argv, self, SQL_ATTR_CP_MATCH);
#else
rb_raise(Cerror, "%s", set_err("Unsupported in ODBC < 3.0", 0));
return Qnil;
#endif
}
static VALUE
env_odbcver(int argc, VALUE *argv, VALUE self)
{
#if (ODBCVER >= 0x0300)
return do_attr(argc, argv, self, SQL_ATTR_ODBC_VERSION);
#else
VALUE val;
rb_scan_args(argc, argv, "01", &val);
if (val == Qnil) {
return rb_int2inum(ODBCVER >> 8);
}
rb_raise(Cerror, "%s", set_err("Unsupported in ODBC < 3.0", 0));
#endif
}
/*
*----------------------------------------------------------------------
*
* Connection/statement option handling.
*
* Note:
* ODBC 2 allows statement options to be set using SQLSetConnectOption,
* establishing the statement option as a default for any hstmts
* later allocated for that hdbc. This feature was deprecated in
* ODBC 3.x and may not work with ODBC 3.x drivers.
*
* Although the Database class includes attribute accessors for
* statement-level options, a safer alternative, if using an ODBC 3
* driver, is to set the option directly on the Statement instance.
*
*----------------------------------------------------------------------
*/
#define OPT_LEVEL_STMT 1
#define OPT_LEVEL_DBC 2
#define OPT_LEVEL_BOTH (OPT_LEVEL_STMT | OPT_LEVEL_DBC)
#define OPT_CONST_INT(x, level) { #x, x, level }
#define OPT_CONST_END { NULL, -1 }
static struct {
const char *name;
int option;
int level;
} option_map[] = {
/* yielding ints */
OPT_CONST_INT(SQL_AUTOCOMMIT, OPT_LEVEL_DBC),
OPT_CONST_INT(SQL_NOSCAN, OPT_LEVEL_BOTH),
OPT_CONST_INT(SQL_CONCURRENCY, OPT_LEVEL_BOTH),
OPT_CONST_INT(SQL_QUERY_TIMEOUT, OPT_LEVEL_BOTH),
OPT_CONST_INT(SQL_MAX_ROWS, OPT_LEVEL_BOTH),
OPT_CONST_INT(SQL_MAX_LENGTH, OPT_LEVEL_BOTH),
OPT_CONST_INT(SQL_ROWSET_SIZE, OPT_LEVEL_BOTH),
OPT_CONST_INT(SQL_CURSOR_TYPE, OPT_LEVEL_BOTH),
/* end of table */
OPT_CONST_END
};
static VALUE
do_option(int argc, VALUE *argv, VALUE self, int isstmt, int op)
{
DBC *p = NULL;
STMT *q = NULL;
VALUE val, val2 = Qnil;
SQLINTEGER v;
char *msg;
int level = isstmt ? OPT_LEVEL_STMT : OPT_LEVEL_DBC;
if (op == -1) {
rb_scan_args(argc, argv, "11", &val, &val2);
} else {
rb_scan_args(argc, argv, "01", &val);
}
if (isstmt) {
Data_Get_Struct(self, STMT, q);
if (q->dbc == Qnil) {
rb_raise(Cerror, "%s", set_err("Stale ODBC::Statement", 0));
}
if (q->hstmt == SQL_NULL_HSTMT) {
rb_raise(Cerror, "%s", set_err("No statement", 0));
}
} else {
p = get_dbc(self);
if (p->hdbc == SQL_NULL_HDBC) {
rb_raise(Cerror, "%s", set_err("No connection", 0));
}
}
if (op == -1) {
VALUE vstr;
char *string;
int i, op_found = 0;
switch (TYPE(val)) {
default:
vstr = rb_any_to_s(val);
string = STR2CSTR(vstr);
goto doString;
case T_STRING:
string = STR2CSTR(val);
doString:
for (i = 0; option_map[i].name != NULL; i++) {
if (strcmp(string, option_map[i].name) == 0) {
op = option_map[i].option;
level = option_map[i].level;
op_found = 3;
break;
}
}
break;
case T_FLOAT:
case T_BIGNUM:
op = (int) NUM2DBL(val);
goto doInt;
case T_FIXNUM:
op = FIX2INT(val);
doInt:
op_found = 1;
for (i = 0; option_map[i].name != NULL; i++) {
if (op == option_map[i].option) {
level = option_map[i].level;
op_found = 2;
break;
}
}
break;
}
if (!op_found) {
rb_raise(Cerror, "%s", set_err("Unknown option", 0));
return Qnil;
}
val = val2;
}
if ((isstmt && (!(level & OPT_LEVEL_STMT))) ||
(!isstmt && (!(level & OPT_LEVEL_DBC)))) {
rb_raise(Cerror, "%s",
set_err("Invalid option type for this level", 0));
return Qnil;
}
if (val == Qnil) {
if (p != NULL) {
if (!succeeded(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLGetConnectOption(p->hdbc, (SQLUSMALLINT) op,
(SQLPOINTER) &v),
&msg, "SQLGetConnectOption(%d)", op)) {
rb_raise(Cerror, "%s", msg);
}
} else {
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HSTMT, q->hstmt,
SQLGetStmtOption(q->hstmt, (SQLUSMALLINT) op,
(SQLPOINTER) &v),
&msg, "SQLGetStmtOption(%d)", op)) {
rb_raise(Cerror, "%s", msg);
}
}
}
switch (op) {
case SQL_AUTOCOMMIT:
if (val == Qnil) {
return v ? Qtrue : Qfalse;
}
v = (TYPE(val) == T_FIXNUM) ?
(FIX2INT(val) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF) :
(RTEST(val) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
break;
case SQL_NOSCAN:
if (val == Qnil) {
return v ? Qtrue : Qfalse;
}
v = (TYPE(val) == T_FIXNUM) ?
(FIX2INT(val) ? SQL_NOSCAN_ON : SQL_NOSCAN_OFF) :
(RTEST(val) ? SQL_NOSCAN_ON : SQL_NOSCAN_OFF);
break;
case SQL_CONCURRENCY:
case SQL_QUERY_TIMEOUT:
case SQL_MAX_ROWS:
case SQL_MAX_LENGTH:
case SQL_ROWSET_SIZE:
case SQL_CURSOR_TYPE:
default:
if (val == Qnil) {
return rb_int2inum(v);
}
Check_Type(val, T_FIXNUM);
v = FIX2INT(val);
if (op == SQL_ROWSET_SIZE) {
rb_raise(Cerror, "%s", set_err("Read only attribute", 0));
}
break;
}
if (p != NULL) {
if (!succeeded(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLSetConnectOption(p->hdbc, (SQLUSMALLINT) op,
(SQLUINTEGER) v),
&msg, "SQLSetConnectOption(%d)", op)) {
rb_raise(Cerror, "%s", msg);
}
} else {
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLSetStmtOption(q->hstmt, (SQLUSMALLINT) op,
(SQLUINTEGER) v),
&msg, "SQLSetStmtOption(%d)", op)) {
rb_raise(Cerror, "%s", msg);
}
}
return Qnil;
}
static VALUE
dbc_autocommit(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, SQL_AUTOCOMMIT);
}
static VALUE
dbc_concurrency(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, SQL_CONCURRENCY);
}
static VALUE
dbc_maxrows(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, SQL_MAX_ROWS);
}
static VALUE
dbc_timeout(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, SQL_QUERY_TIMEOUT);
}
static VALUE
dbc_maxlength(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, SQL_MAX_LENGTH);
}
static VALUE
dbc_rowsetsize(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, SQL_ROWSET_SIZE);
}
static VALUE
dbc_cursortype(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, SQL_CURSOR_TYPE);
}
static VALUE
dbc_noscan(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, SQL_NOSCAN);
}
static VALUE
dbc_getsetoption(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 0, -1);
}
static VALUE
stmt_concurrency(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 1, SQL_CONCURRENCY);
}
static VALUE
stmt_maxrows(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 1, SQL_MAX_ROWS);
}
static VALUE
stmt_timeout(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 1, SQL_QUERY_TIMEOUT);
}
static VALUE
stmt_maxlength(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 1, SQL_MAX_LENGTH);
}
static VALUE
stmt_rowsetsize(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 1, SQL_ROWSET_SIZE);
}
static VALUE
stmt_cursortype(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 1, SQL_CURSOR_TYPE);
}
static VALUE
stmt_noscan(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 1, SQL_NOSCAN);
}
static VALUE
stmt_getsetoption(int argc, VALUE *argv, VALUE self)
{
return do_option(argc, argv, self, 1, -1);
}
/*
*----------------------------------------------------------------------
*
* Scan literal date/time/timestamp to TIMESTAMP_STRUCT.
*
*----------------------------------------------------------------------
*/
static int
scan_dtts(VALUE str, int do_d, int do_t, TIMESTAMP_STRUCT *ts)
{
int yy = 0, mm = 0, dd = 0, hh = 0, mmm = 0, ss = 0, ff = 0, i;
char c, *cstr = STR2CSTR(str);
memset(ts, 0, sizeof (TIMESTAMP_STRUCT));
if (((sscanf(cstr, "{ts '%d-%d-%d %d:%d:%d.%d' %c",
&yy, &mm, &dd, &hh, &mmm, &ss, &ff, &c) == 8) ||
(sscanf(cstr, "{ts '%d-%d-%d %d:%d:%d' %c",
&yy, &mm, &dd, &hh, &mmm, &ss, &c) == 7)) &&
(c == '}')) {
ts->year = yy;
ts->month = mm;
ts->day = dd;
ts->hour = hh;
ts->minute = mmm;
ts->second = ss;
ts->fraction = ff;
return 1;
}
if (do_d &&
(sscanf(cstr, "{d '%d-%d-%d' %c", &yy, &mm, &dd, &c) == 4) &&
(c == '}')) {
ts->year = yy;
ts->month = mm;
ts->day = dd;
return 1;
}
if (do_t &&
(sscanf(cstr, "{t '%d:%d:%d' %c", &hh, &mmm, &ss, &c) == 4) &&
(c == '}')) {
ts->hour = yy;
ts->minute = mmm;
ts->second = ss;
return 1;
}
ff = ss = 0;
i = sscanf(cstr, "%d-%d-%d %d:%d:%d%c%d",
&yy, &mm, &dd, &hh, &mmm, &ss, &c, &ff);
if (i >= 5) {
if ((i > 6) && (c != 0) && (strchr(". \t", c) == NULL)) {
goto next;
}
ts->year = yy;
ts->month = mm;
ts->day = dd;
ts->hour = hh;
ts->minute = mmm;
ts->second = ss;
ts->fraction = ff;
return 1;
}
next:
ff = ss = 0;
if (do_d && (sscanf(cstr, "%d-%d-%d", &yy, &mm, &dd) == 3)) {
ts->year = yy;
ts->month = mm;
ts->day = dd;
return 1;
}
if (do_t && (sscanf(cstr, "%d:%d:%d", &hh, &mmm, &ss) == 3)) {
ts->hour = hh;
ts->minute = mmm;
ts->second = ss;
return 1;
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* Date methods.
*
*----------------------------------------------------------------------
*/
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
static VALUE
date_alloc(VALUE self)
{
DATE_STRUCT *date;
VALUE obj = Data_Make_Struct(self, DATE_STRUCT, 0, xfree, date);
memset(date, 0, sizeof (*date));
return obj;
}
#else
static VALUE
date_new(int argc, VALUE *argv, VALUE self)
{
DATE_STRUCT *date;
VALUE obj = Data_Make_Struct(self, DATE_STRUCT, 0, xfree, date);
rb_obj_call_init(obj, argc, argv);
return obj;
}
#endif
static VALUE
date_load1(VALUE self, VALUE str, int load)
{
TIMESTAMP_STRUCT tss;
if (scan_dtts(str, 1, 0, &tss)) {
DATE_STRUCT *date;
VALUE obj;
if (load) {
obj = Data_Make_Struct(self, DATE_STRUCT, 0, xfree, date);
} else {
obj = self;
Data_Get_Struct(self, DATE_STRUCT, date);
}
date->year = tss.year;
date->month = tss.month;
date->day = tss.day;
return obj;
}
if (load > 0) {
rb_raise(rb_eTypeError, "marshaled ODBC::Date format error");
}
return Qnil;
}
static VALUE
date_load(VALUE self, VALUE str)
{
return date_load1(self, str, 1);
}
static VALUE
date_init(int argc, VALUE *argv, VALUE self)
{
DATE_STRUCT *date;
VALUE d, m, y;
rb_scan_args(argc, argv, "03", &y, &m, &d);
if (rb_obj_is_kind_of(y, Cdate) == Qtrue) {
DATE_STRUCT *date2;
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
Data_Get_Struct(self, DATE_STRUCT, date);
Data_Get_Struct(y, DATE_STRUCT, date2);
*date = *date2;
return self;
}
if (rb_obj_is_kind_of(y, Ctimestamp) == Qtrue) {
TIMESTAMP_STRUCT *ts;
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
Data_Get_Struct(self, DATE_STRUCT, date);
Data_Get_Struct(y, TIMESTAMP_STRUCT, ts);
date->year = ts->year;
date->month = ts->month;
date->day = ts->day;
return self;
}
if (rb_obj_is_kind_of(y, rb_cTime) == Qtrue) {
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
d = rb_funcall(y, IDday, 0, NULL);
m = rb_funcall(y, IDmonth, 0, NULL);
y = rb_funcall(y, IDyear, 0, NULL);
} else if (rb_obj_is_kind_of(y, rb_cDate) == Qtrue) {
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
d = rb_funcall(y, IDmday, 0, NULL);
m = rb_funcall(y, IDmonth, 0, NULL);
y = rb_funcall(y, IDyear, 0, NULL);
} else if ((argc == 1) && (rb_obj_is_kind_of(y, rb_cString) == Qtrue)) {
if (date_load1(self, y, 0) != Qnil) {
return self;
}
}
Data_Get_Struct(self, DATE_STRUCT, date);
date->year = (y == Qnil) ? 0 : NUM2INT(y);
date->month = (m == Qnil) ? 0 : NUM2INT(m);
date->day = (d == Qnil) ? 0 : NUM2INT(d);
return self;
}
static VALUE
date_clone(VALUE self)
{
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
VALUE obj = rb_obj_alloc(CLASS_OF(self));
DATE_STRUCT *date1, *date2;
Data_Get_Struct(self, DATE_STRUCT, date1);
Data_Get_Struct(obj, DATE_STRUCT, date2);
*date2 = *date1;
return obj;
#else
return date_new(1, &self, CLASS_OF(self));
#endif
}
static VALUE
date_to_s(VALUE self)
{
DATE_STRUCT *date;
char buf[128];
Data_Get_Struct(self, DATE_STRUCT, date);
sprintf(buf, "%04d-%02d-%02d", date->year, date->month, date->day);
return rb_str_new2(buf);
}
static VALUE
date_dump(VALUE self, VALUE depth)
{
return date_to_s(self);
}
static VALUE
date_inspect(VALUE self)
{
VALUE s = rb_str_new2("#"));
}
static VALUE
date_year(int argc, VALUE *argv, VALUE self)
{
DATE_STRUCT *date;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, DATE_STRUCT, date);
if (v == Qnil) {
return INT2NUM(date->year);
}
date->year = NUM2INT(v);
return self;
}
static VALUE
date_month(int argc, VALUE *argv, VALUE self)
{
DATE_STRUCT *date;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, DATE_STRUCT, date);
if (v == Qnil) {
return INT2NUM(date->month);
}
date->month = NUM2INT(v);
return self;
}
static VALUE
date_day(int argc, VALUE *argv, VALUE self)
{
DATE_STRUCT *date;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, DATE_STRUCT, date);
if (v == Qnil) {
return INT2NUM(date->day);
}
date->day = NUM2INT(v);
return self;
}
static VALUE
date_cmp(VALUE self, VALUE date)
{
DATE_STRUCT *date1, *date2;
if (rb_obj_is_kind_of(date, Cdate) != Qtrue) {
rb_raise(rb_eTypeError, "need ODBC::Date as argument");
}
Data_Get_Struct(self, DATE_STRUCT, date1);
Data_Get_Struct(date, DATE_STRUCT, date2);
if (date1->year < date2->year) {
return INT2FIX(-1);
}
if (date1->year == date2->year) {
if (date1->month < date2->month) {
return INT2FIX(-1);
}
if (date1->month == date2->month) {
if (date1->day < date2->day) {
return INT2FIX(-1);
}
if (date1->day == date2->day) {
return INT2FIX(0);
}
}
}
return INT2FIX(1);
}
/*
*----------------------------------------------------------------------
*
* Time methods.
*
*----------------------------------------------------------------------
*/
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
static VALUE
time_alloc(VALUE self)
{
TIME_STRUCT *time;
VALUE obj = Data_Make_Struct(self, TIME_STRUCT, 0, xfree, time);
memset(time, 0, sizeof (*time));
return obj;
}
#else
static VALUE
time_new(int argc, VALUE *argv, VALUE self)
{
TIME_STRUCT *time;
VALUE obj = Data_Make_Struct(self, TIME_STRUCT, 0, xfree, time);
rb_obj_call_init(obj, argc, argv);
return obj;
}
#endif
static VALUE
time_load1(VALUE self, VALUE str, int load)
{
TIMESTAMP_STRUCT tss;
if (scan_dtts(str, 0, 1, &tss)) {
TIME_STRUCT *time;
VALUE obj;
if (load) {
obj = Data_Make_Struct(self, TIME_STRUCT, 0, xfree, time);
} else {
obj = self;
Data_Get_Struct(self, TIME_STRUCT, time);
}
time->hour = tss.hour;
time->minute = tss.minute;
time->second = tss.second;
return obj;
}
if (load > 0) {
rb_raise(rb_eTypeError, "marshaled ODBC::Time format error");
}
return Qnil;
}
static VALUE
time_load(VALUE self, VALUE str)
{
return time_load1(self, str, 1);
}
static VALUE
time_init(int argc, VALUE *argv, VALUE self)
{
TIME_STRUCT *time;
VALUE h, m, s;
rb_scan_args(argc, argv, "03", &h, &m, &s);
if (rb_obj_is_kind_of(h, Ctime) == Qtrue) {
TIME_STRUCT *time2;
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
Data_Get_Struct(self, TIME_STRUCT, time);
Data_Get_Struct(h, TIME_STRUCT, time2);
*time = *time2;
return self;
}
if (rb_obj_is_kind_of(h, Ctimestamp) == Qtrue) {
TIMESTAMP_STRUCT *ts;
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
Data_Get_Struct(self, TIME_STRUCT, time);
Data_Get_Struct(h, TIMESTAMP_STRUCT, ts);
time->hour = ts->hour;
time->minute = ts->minute;
time->second = ts->second;
return self;
}
if (rb_obj_is_kind_of(h, rb_cTime) == Qtrue) {
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
s = rb_funcall(h, IDsec, 0, NULL);
m = rb_funcall(h, IDmin, 0, NULL);
h = rb_funcall(h, IDhour, 0, NULL);
} else if ((argc == 1) && (rb_obj_is_kind_of(h, rb_cString) == Qtrue)) {
if (time_load1(self, h, 0) != Qnil) {
return self;
}
}
Data_Get_Struct(self, TIME_STRUCT, time);
time->hour = (h == Qnil) ? 0 : NUM2INT(h);
time->minute = (m == Qnil) ? 0 : NUM2INT(m);
time->second = (s == Qnil) ? 0 : NUM2INT(s);
return self;
}
static VALUE
time_clone(VALUE self)
{
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
VALUE obj = rb_obj_alloc(CLASS_OF(self));
TIME_STRUCT *time1, *time2;
Data_Get_Struct(self, TIME_STRUCT, time1);
Data_Get_Struct(obj, TIME_STRUCT, time2);
*time2 = *time1;
return obj;
#else
return time_new(1, &self, CLASS_OF(self));
#endif
}
static VALUE
time_to_s(VALUE self)
{
TIME_STRUCT *time;
char buf[128];
Data_Get_Struct(self, TIME_STRUCT, time);
sprintf(buf, "%02d:%02d:%02d", time->hour, time->minute, time->second);
return rb_str_new2(buf);
}
static VALUE
time_dump(VALUE self, VALUE depth)
{
return time_to_s(self);
}
static VALUE
time_inspect(VALUE self)
{
VALUE s = rb_str_new2("#"));
}
static VALUE
time_hour(int argc, VALUE *argv, VALUE self)
{
TIME_STRUCT *time;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIME_STRUCT, time);
if (v == Qnil) {
return INT2NUM(time->hour);
}
time->hour = NUM2INT(v);
return self;
}
static VALUE
time_min(int argc, VALUE *argv, VALUE self)
{
TIME_STRUCT *time;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIME_STRUCT, time);
if (v == Qnil) {
return INT2NUM(time->minute);
}
time->minute = NUM2INT(v);
return self;
}
static VALUE
time_sec(int argc, VALUE *argv, VALUE self)
{
TIME_STRUCT *time;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIME_STRUCT, time);
if (v == Qnil) {
return INT2NUM(time->second);
}
time->second = NUM2INT(v);
return self;
}
static VALUE
time_cmp(VALUE self, VALUE time)
{
TIME_STRUCT *time1, *time2;
if (rb_obj_is_kind_of(time, Ctime) != Qtrue) {
rb_raise(rb_eTypeError, "need ODBC::Time as argument");
}
Data_Get_Struct(self, TIME_STRUCT, time1);
Data_Get_Struct(time, TIME_STRUCT, time2);
if (time1->hour < time2->hour) {
return INT2FIX(-1);
}
if (time1->hour == time2->hour) {
if (time1->minute < time2->minute) {
return INT2FIX(-1);
}
if (time1->minute == time2->minute) {
if (time1->second < time2->second) {
return INT2FIX(-1);
}
if (time1->second == time2->second) {
return INT2FIX(0);
}
}
}
return INT2FIX(1);
}
/*
*----------------------------------------------------------------------
*
* TimeStamp methods.
*
*----------------------------------------------------------------------
*/
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
static VALUE
timestamp_alloc(VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE obj = Data_Make_Struct(self, TIMESTAMP_STRUCT, 0, xfree, ts);
memset(ts, 0, sizeof (*ts));
return obj;
}
#else
static VALUE
timestamp_new(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE obj = Data_Make_Struct(self, TIMESTAMP_STRUCT, 0, xfree, ts);
rb_obj_call_init(obj, argc, argv);
return obj;
}
#endif
static VALUE
timestamp_load1(VALUE self, VALUE str, int load)
{
TIMESTAMP_STRUCT tss;
if (scan_dtts(str, !load, !load, &tss)) {
TIMESTAMP_STRUCT *ts;
VALUE obj;
if (load) {
obj = Data_Make_Struct(self, TIMESTAMP_STRUCT, 0, xfree, ts);
} else {
obj = self;
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
}
*ts = tss;
return obj;
}
if (load > 0) {
rb_raise(rb_eTypeError, "marshaled ODBC::TimeStamp format error");
}
return Qnil;
}
static VALUE
timestamp_load(VALUE self, VALUE str)
{
return timestamp_load1(self, str, 1);
}
static VALUE
timestamp_init(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE d, m, y, hh, mm, ss, f;
rb_scan_args(argc, argv, "07", &y, &m, &d, &hh, &mm, &ss, &f);
if (rb_obj_is_kind_of(y, Ctimestamp) == Qtrue) {
TIMESTAMP_STRUCT *ts2;
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
Data_Get_Struct(y, TIMESTAMP_STRUCT, ts2);
*ts = *ts2;
return self;
}
if (rb_obj_is_kind_of(y, Cdate) == Qtrue) {
DATE_STRUCT *date;
if (argc > 1) {
if (argc > 2) {
rb_raise(rb_eArgError, "wrong # arguments");
}
if (rb_obj_is_kind_of(m, Ctime) == Qtrue) {
TIME_STRUCT *time;
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
Data_Get_Struct(m, TIME_STRUCT, time);
ts->hour = time->hour;
ts->minute = time->minute;
ts->second = time->second;
} else {
rb_raise(rb_eArgError, "need ODBC::Time argument");
}
}
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
Data_Get_Struct(y, DATE_STRUCT, date);
ts->year = date->year;
ts->year = date->year;
ts->year = date->year;
ts->fraction = 0;
return self;
}
if (rb_obj_is_kind_of(y, rb_cTime) == Qtrue) {
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
f = rb_funcall(y, IDusec, 0, NULL);
ss = rb_funcall(y, IDsec, 0, NULL);
mm = rb_funcall(y, IDmin, 0, NULL);
hh = rb_funcall(y, IDhour, 0, NULL);
d = rb_funcall(y, IDday, 0, NULL);
m = rb_funcall(y, IDmonth, 0, NULL);
y = rb_funcall(y, IDyear, 0, NULL);
f = INT2NUM(NUM2INT(f) * 1000);
} else if (rb_obj_is_kind_of(y, rb_cDate) == Qtrue) {
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments");
}
f = INT2FIX(0);
ss = INT2FIX(0);
mm = INT2FIX(0);
hh = INT2FIX(0);
d = rb_funcall(y, IDmday, 0, NULL);
m = rb_funcall(y, IDmonth, 0, NULL);
y = rb_funcall(y, IDyear, 0, NULL);
} else if ((argc == 1) && (rb_obj_is_kind_of(y, rb_cString) == Qtrue)) {
if (timestamp_load1(self, y, 0) != Qnil) {
return self;
}
}
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
ts->year = (y == Qnil) ? 0 : NUM2INT(y);
ts->month = (m == Qnil) ? 0 : NUM2INT(m);
ts->day = (d == Qnil) ? 0 : NUM2INT(d);
ts->hour = (hh == Qnil) ? 0 : NUM2INT(hh);
ts->minute = (mm == Qnil) ? 0 : NUM2INT(mm);
ts->second = (ss == Qnil) ? 0 : NUM2INT(ss);
ts->fraction = (f == Qnil) ? 0 : NUM2INT(f);
return self;
}
static VALUE
timestamp_clone(VALUE self)
{
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
VALUE obj = rb_obj_alloc(CLASS_OF(self));
TIMESTAMP_STRUCT *ts1, *ts2;
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts1);
Data_Get_Struct(obj, TIMESTAMP_STRUCT, ts2);
*ts2 = *ts1;
return obj;
#else
return timestamp_new(1, &self, CLASS_OF(self));
#endif
}
static VALUE
timestamp_to_s(VALUE self)
{
TIMESTAMP_STRUCT *ts;
char buf[256];
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d %u",
ts->year, ts->month, ts->day,
ts->hour, ts->minute, ts->second,
(unsigned int) ts->fraction);
return rb_str_new2(buf);
}
static VALUE
timestamp_dump(VALUE self, VALUE depth)
{
return timestamp_to_s(self);
}
static VALUE
timestamp_inspect(VALUE self)
{
VALUE s = rb_str_new2("#"));
}
static VALUE
timestamp_year(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
if (v == Qnil) {
return INT2NUM(ts->year);
}
ts->year = NUM2INT(v);
return self;
}
static VALUE
timestamp_month(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
if (v == Qnil) {
return INT2NUM(ts->month);
}
ts->month = NUM2INT(v);
return self;
}
static VALUE
timestamp_day(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
if (v == Qnil) {
return INT2NUM(ts->day);
}
ts->day = NUM2INT(v);
return self;
}
static VALUE
timestamp_hour(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
if (v == Qnil) {
return INT2NUM(ts->hour);
}
ts->hour = NUM2INT(v);
return self;
}
static VALUE
timestamp_min(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
if (v == Qnil) {
return INT2NUM(ts->minute);
}
ts->minute = NUM2INT(v);
return self;
}
static VALUE
timestamp_sec(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
if (v == Qnil) {
return INT2NUM(ts->second);
}
ts->second = NUM2INT(v);
return self;
}
static VALUE
timestamp_fraction(int argc, VALUE *argv, VALUE self)
{
TIMESTAMP_STRUCT *ts;
VALUE v;
rb_scan_args(argc, argv, "01", &v);
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts);
if (v == Qnil) {
return INT2NUM(ts->fraction);
}
ts->fraction = NUM2INT(v);
return self;
}
static VALUE
timestamp_cmp(VALUE self, VALUE timestamp)
{
TIMESTAMP_STRUCT *ts1, *ts2;
if (rb_obj_is_kind_of(timestamp, Ctimestamp) != Qtrue) {
rb_raise(rb_eTypeError, "need ODBC::TimeStamp as argument");
}
Data_Get_Struct(self, TIMESTAMP_STRUCT, ts1);
Data_Get_Struct(timestamp, TIMESTAMP_STRUCT, ts2);
if (ts1->year < ts2->year) {
return INT2FIX(-1);
}
if (ts1->year == ts2->year) {
if (ts1->month < ts2->month) {
return INT2FIX(-1);
}
if (ts1->month == ts2->month) {
if (ts1->day < ts2->day) {
return INT2FIX(-1);
}
if (ts1->day == ts2->day) {
if (ts1->hour < ts2->hour) {
return INT2FIX(-1);
}
if (ts1->hour == ts2->hour) {
if (ts1->minute < ts2->minute) {
return INT2FIX(-1);
}
if (ts1->minute == ts2->minute) {
if (ts1->second < ts2->second) {
return INT2FIX(-1);
}
if (ts1->second == ts2->second) {
if (ts1->fraction < ts2->fraction) {
return INT2FIX(-1);
}
if (ts1->fraction == ts2->fraction) {
return INT2FIX(0);
}
}
}
}
}
}
}
return INT2FIX(1);
}
/*
*----------------------------------------------------------------------
*
* Statement methods.
*
*----------------------------------------------------------------------
*/
static VALUE
stmt_drop(VALUE self)
{
STMT *q;
Data_Get_Struct(self, STMT, q);
if (q->hstmt != SQL_NULL_HSTMT) {
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFreeStmt(q->hstmt, SQL_DROP), "SQLFreeStmt(SQL_DROP)");
q->hstmt = SQL_NULL_HSTMT;
unlink_stmt(q);
}
free_stmt_sub(q, 1);
return self;
}
static VALUE
stmt_close(VALUE self)
{
STMT *q;
Data_Get_Struct(self, STMT, q);
if (q->hstmt != SQL_NULL_HSTMT) {
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFreeStmt(q->hstmt, SQL_CLOSE), "SQLFreeStmt(SQL_CLOSE)");
}
free_stmt_sub(q, 1);
return self;
}
static VALUE
stmt_cancel(VALUE self)
{
STMT *q;
char *msg;
Data_Get_Struct(self, STMT, q);
if (q->hstmt != SQL_NULL_HSTMT) {
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLCancel(q->hstmt), &msg, "SQLCancel")) {
rb_raise(Cerror, "%s", msg);
}
}
return self;
}
static void
check_ncols(STMT *q)
{
if ((q->hstmt != SQL_NULL_HSTMT) && (q->ncols <= 0) &&
(q->coltypes == NULL)) {
COLTYPE *coltypes = NULL;
SQLSMALLINT cols = 0;
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLNumResultCols(q->hstmt, &cols), NULL,
"SQLNumResultCols")
&& (cols > 0)) {
coltypes = make_coltypes(q->hstmt, cols, NULL);
if (coltypes != NULL) {
q->ncols = cols;
q->coltypes = coltypes;
}
}
}
}
static VALUE
stmt_ncols(VALUE self)
{
STMT *q;
Data_Get_Struct(self, STMT, q);
check_ncols(q);
return INT2FIX(q->ncols);
}
static VALUE
stmt_nrows(VALUE self)
{
STMT *q;
SQLLEN rows = -1;
char *msg;
Data_Get_Struct(self, STMT, q);
if ((q->hstmt != SQL_NULL_HSTMT) &&
(!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLRowCount(q->hstmt, &rows), &msg, "SQLRowCount"))) {
rb_raise(Cerror, "%s", msg);
}
return INT2NUM(rows);
}
static VALUE
stmt_nparams(VALUE self)
{
STMT *q;
Data_Get_Struct(self, STMT, q);
return INT2FIX(q->nump);
}
static int
param_num_check(STMT *q, VALUE pnum, int mkparaminfo, int needout)
{
int vnum;
Check_Type(pnum, T_FIXNUM);
vnum = NUM2INT(pnum);
if (mkparaminfo && (q->paraminfo == NULL)) {
char *msg = NULL;
SQLSMALLINT nump = 0;
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLNumParams(q->hstmt, &nump), NULL, "SQLNumParams")) {
nump = 0;
}
if (nump > 0) {
PARAMINFO *paraminfo = make_paraminfo(q->hstmt, nump, &msg);
if (paraminfo == NULL) {
rb_raise(Cerror, "%s", msg);
}
q->paraminfo = paraminfo;
if (q->paraminfo != NULL) {
q->nump = nump;
}
}
}
if ((q->paraminfo == NULL) || (vnum < 0) || (vnum >= q->nump)) {
rb_raise(rb_eArgError, "parameter number out of bounds");
}
if (needout) {
if ((q->paraminfo[vnum].iotype != SQL_PARAM_OUTPUT) &&
(q->paraminfo[vnum].iotype != SQL_PARAM_INPUT_OUTPUT)) {
rb_raise(Cerror, "not an output parameter");
}
}
return vnum;
}
static VALUE
stmt_param_type(int argc, VALUE *argv, VALUE self)
{
VALUE pnum, ptype, pcoldef, pscale;
int vnum;
STMT *q;
rb_scan_args(argc, argv, "13", &pnum, &ptype, &pcoldef, &pscale);
Data_Get_Struct(self, STMT, q);
vnum = param_num_check(q, pnum, 1, 0);
if (argc > 1) {
int vtype, vcoldef, vscale;
Check_Type(ptype, T_FIXNUM);
vtype = NUM2INT(ptype);
if (argc > 2) {
Check_Type(pcoldef, T_FIXNUM);
vcoldef = NUM2INT(pcoldef);
if (argc > 3) {
Check_Type(pscale, T_FIXNUM);
vscale = NUM2INT(pscale);
q->paraminfo[vnum].scale = vscale;
}
q->paraminfo[vnum].coldef = vcoldef;
}
q->paraminfo[vnum].type = vtype;
q->paraminfo[vnum].override = 1;
return Qnil;
}
return INT2NUM(q->paraminfo[vnum].type);
}
static VALUE
stmt_param_iotype(int argc, VALUE *argv, VALUE self)
{
VALUE pnum, piotype;
int vnum, viotype;
STMT *q;
rb_scan_args(argc, argv, "11", &pnum, &piotype);
Data_Get_Struct(self, STMT, q);
vnum = param_num_check(q, pnum, 1, 0);
if (argc > 1) {
Check_Type(piotype, T_FIXNUM);
viotype = NUM2INT(piotype);
switch (viotype) {
case SQL_PARAM_INPUT:
case SQL_PARAM_INPUT_OUTPUT:
case SQL_PARAM_OUTPUT:
q->paraminfo[vnum].iotype = viotype;
break;
}
}
return INT2NUM(q->paraminfo[vnum].iotype);
}
static VALUE
stmt_param_output_value(int argc, VALUE *argv, VALUE self)
{
VALUE pnum, v;
int vnum;
STMT *q;
rb_scan_args(argc, argv, "10", &pnum);
Data_Get_Struct(self, STMT, q);
vnum = param_num_check(q, pnum, 0, 1);
v = Qnil;
if (q->paraminfo[vnum].rlen == SQL_NULL_DATA) {
return v;
}
if (q->paraminfo[vnum].outbuf == NULL) {
rb_raise(Cerror, "no output value available");
}
switch (q->paraminfo[vnum].ctype) {
case SQL_C_LONG:
v = INT2NUM(*((SQLINTEGER *) q->paraminfo[vnum].outbuf));
break;
case SQL_C_DOUBLE:
v = rb_float_new(*((double *) q->paraminfo[vnum].outbuf));
break;
case SQL_C_DATE:
{
DATE_STRUCT *date;
if (q->dbcp != NULL && q->dbcp->rbtime == Qtrue) {
const char *p;
char buffer[128];
VALUE d;
date = (DATE_STRUCT *) q->paraminfo[vnum].outbuf;
p = (q->dbcp->gmtime == Qtrue) ? "+00:00" : "";
sprintf(buffer, "%d-%d-%dT00:00:00%s",
date->year, date->month, date->day, p);
d = rb_str_new2(buffer);
v = rb_funcall(rb_cDate, IDparse, 1, d);
} else {
v = Data_Make_Struct(Cdate, DATE_STRUCT, 0, xfree, date);
*date = *((DATE_STRUCT *) q->paraminfo[vnum].outbuf);
}
}
break;
case SQL_C_TIME:
{
TIME_STRUCT *time;
if (q->dbcp != NULL && q->dbcp->rbtime == Qtrue) {
VALUE now, frac;
time = (TIME_STRUCT *) q->paraminfo[vnum].outbuf;
frac = rb_float_new(0.0);
now = rb_funcall(rb_cTime, IDnow, 0, NULL);
v = rb_funcall(rb_cTime,
(q->dbcp->gmtime == Qtrue) ? IDutc : IDlocal,
7,
rb_funcall(now, IDyear, 0, NULL),
rb_funcall(now, IDmonth, 0, NULL),
rb_funcall(now, IDday, 0, NULL),
INT2NUM(time->hour),
INT2NUM(time->minute),
INT2NUM(time->second),
frac);
} else {
v = Data_Make_Struct(Ctime, TIME_STRUCT, 0, xfree, time);
*time = *((TIME_STRUCT *) q->paraminfo[vnum].outbuf);
}
}
break;
case SQL_C_TIMESTAMP:
{
TIMESTAMP_STRUCT *ts;
if (q->dbcp != NULL && q->dbcp->rbtime == Qtrue) {
VALUE frac;
ts = (TIMESTAMP_STRUCT *) q->paraminfo[vnum].outbuf;
frac = rb_float_new((double) 1.0e-3 * ts->fraction);
v = rb_funcall(rb_cTime,
(q->dbcp->gmtime == Qtrue) ? IDutc : IDlocal,
7,
INT2NUM(ts->year),
INT2NUM(ts->month),
INT2NUM(ts->day),
INT2NUM(ts->hour),
INT2NUM(ts->minute),
INT2NUM(ts->second),
frac);
} else {
v = Data_Make_Struct(Ctimestamp, TIMESTAMP_STRUCT,
0, xfree, ts);
*ts = *((TIMESTAMP_STRUCT *) q->paraminfo[vnum].outbuf);
}
}
break;
#ifdef UNICODE
case SQL_C_WCHAR:
v = uc_tainted_str_new((SQLWCHAR *) q->paraminfo[vnum].outbuf,
q->paraminfo[vnum].rlen / sizeof (SQLWCHAR));
break;
#endif
case SQL_C_CHAR:
v = rb_tainted_str_new(q->paraminfo[vnum].outbuf,
q->paraminfo[vnum].rlen);
break;
}
return v;
}
static VALUE
stmt_param_output_size(int argc, VALUE *argv, VALUE self)
{
VALUE pnum, psize;
int vnum, vsize;
STMT *q;
rb_scan_args(argc, argv, "11", &pnum, &psize);
Data_Get_Struct(self, STMT, q);
vnum = param_num_check(q, pnum, 0, 1);
if (argc > 1) {
Check_Type(psize, T_FIXNUM);
vsize = NUM2INT(psize);
if ((vsize > 0) && (vsize < (int) (4 * sizeof (double)))) {
vsize = 4 * sizeof (double);
}
q->paraminfo[vnum].outsize = (vsize > 0) ? vsize : 0;
}
return INT2NUM(q->paraminfo[vnum].outsize);
}
static VALUE
stmt_param_output_type(int argc, VALUE *argv, VALUE self)
{
VALUE pnum, ptype;
int vnum, vtype;
STMT *q;
rb_scan_args(argc, argv, "11", &pnum, &ptype);
Data_Get_Struct(self, STMT, q);
vnum = param_num_check(q, pnum, 0, 1);
if (argc > 1) {
Check_Type(ptype, T_FIXNUM);
vtype = NUM2INT(ptype);
q->paraminfo[vnum].outtype = vtype;
}
return INT2NUM(q->paraminfo[vnum].outtype);
}
static VALUE
stmt_cursorname(int argc, VALUE *argv, VALUE self)
{
VALUE cn = Qnil;
STMT *q;
#ifdef UNICODE
SQLWCHAR cname[SQL_MAX_MESSAGE_LENGTH];
SQLWCHAR *cp;
#else
SQLCHAR cname[SQL_MAX_MESSAGE_LENGTH];
SQLCHAR *cp;
#endif
char *msg;
SQLSMALLINT cnLen = 0;
rb_scan_args(argc, argv, "01", &cn);
Data_Get_Struct(self, STMT, q);
if (cn == Qnil) {
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLGetCursorName(q->hstmt, (SQLTCHAR *) cname,
(SQLSMALLINT) sizeof (cname), &cnLen),
&msg, "SQLGetCursorName")) {
rb_raise(Cerror, "%s", msg);
}
#ifdef UNICODE
cnLen = (cnLen == 0) ? (SQLSMALLINT) uc_strlen(cname) :
(SQLSMALLINT) (cnLen / sizeof (SQLWCHAR));
return uc_tainted_str_new(cname, cnLen);
#else
cnLen = (cnLen == 0) ? (SQLSMALLINT) strlen((char *) cname) : cnLen;
return rb_tainted_str_new((char *) cname, cnLen);
#endif
}
if (TYPE(cn) != T_STRING) {
cn = rb_any_to_s(cn);
}
#ifdef UNICODE
#ifdef USE_RB_ENC
cn = rb_funcall(cn, IDencode, 1, rb_encv);
#endif
cp = uc_from_utf((unsigned char *) STR2CSTR(cn), -1);
if (cp == NULL) {
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
#else
cp = (SQLCHAR *) STR2CSTR(cn);
#endif
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLSetCursorName(q->hstmt, cp, SQL_NTS),
&msg, "SQLSetCursorName")) {
#ifdef UNICODE
uc_free(cp);
#endif
rb_raise(Cerror, "%s", msg);
}
#ifdef UNICODE
uc_free(cp);
#endif
return cn;
}
static VALUE
stmt_column(int argc, VALUE *argv, VALUE self)
{
STMT *q;
VALUE col;
int use_scn = 0;
rb_scan_args(argc, argv, "1", &col);
Check_Type(col, T_FIXNUM);
Data_Get_Struct(self, STMT, q);
check_ncols(q);
if (q->dbcp != NULL && q->dbcp->use_sql_column_name == Qtrue) {
use_scn = 1;
}
return make_column(q->hstmt, FIX2INT(col), q->upc, use_scn);
}
static VALUE
stmt_columns(int argc, VALUE *argv, VALUE self)
{
STMT *q;
int i, use_scn = 0;
VALUE res, as_ary = Qfalse;
rb_scan_args(argc, argv, "01", &as_ary);
Data_Get_Struct(self, STMT, q);
check_ncols(q);
if (q->dbcp != NULL && q->dbcp->use_sql_column_name == Qtrue) {
use_scn = 1;
}
if (rb_block_given_p()) {
for (i = 0; i < q->ncols; i++) {
rb_yield(make_column(q->hstmt, i, q->upc, use_scn));
}
return self;
}
if (RTEST(as_ary)) {
res = rb_ary_new2(q->ncols);
} else {
res = rb_hash_new();
}
for (i = 0; i < q->ncols; i++) {
VALUE obj;
obj = make_column(q->hstmt, i, q->upc, use_scn);
if (RTEST(as_ary)) {
rb_ary_store(res, i, obj);
} else {
VALUE name = rb_iv_get(obj, "@name");
if (rb_funcall(res, IDkeyp, 1, name) == Qtrue) {
char buf[32];
sprintf(buf, "#%d", i);
name = rb_str_dup(name);
name = rb_obj_taint(rb_str_cat2(name, buf));
}
rb_hash_aset(res, name, obj);
}
}
return res;
}
static VALUE
stmt_param(int argc, VALUE *argv, VALUE self)
{
STMT *q;
VALUE par;
int i;
rb_scan_args(argc, argv, "1", &par);
Check_Type(par, T_FIXNUM);
Data_Get_Struct(self, STMT, q);
i = FIX2INT(par);
if ((i < 0) || (i >= q->nump)) {
rb_raise(Cerror, "%s", set_err("Parameter out of bounds", 0));
}
return make_param(q, i);
}
static VALUE
stmt_params(VALUE self)
{
STMT *q;
int i;
VALUE res;
Data_Get_Struct(self, STMT, q);
if (rb_block_given_p()) {
for (i = 0; i < q->nump; i++) {
rb_yield(make_param(q, i));
}
return self;
}
res = rb_ary_new2(q->nump);
for (i = 0; i < q->nump; i++) {
VALUE obj;
obj = make_param(q, i);
rb_ary_store(res, i, obj);
}
return res;
}
static VALUE
do_fetch(STMT *q, int mode)
{
int i, use_scn = 0, offc;
char **bufs, *msg;
VALUE res;
if (q->ncols <= 0) {
rb_raise(Cerror, "%s", set_err("No columns in result set", 0));
}
if (++q->fetchc >= 500) {
q->fetchc = 0;
start_gc();
}
bufs = q->dbufs;
if (bufs == NULL) {
int need = sizeof (char *) * q->ncols, needp;
char *p;
need = LEN_ALIGN(need);
needp = need;
for (i = 0; i < q->ncols; i++) {
if (q->coltypes[i].size != SQL_NO_TOTAL) {
need += LEN_ALIGN(q->coltypes[i].size);
}
}
p = ALLOC_N(char, need);
if (p == NULL) {
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
q->dbufs = bufs = (char **) p;
p += needp;
for (i = 0; i < q->ncols; i++) {
int len = q->coltypes[i].size;
if (len == SQL_NO_TOTAL) {
bufs[i] = NULL;
} else {
bufs[i] = p;
p += LEN_ALIGN(len);
}
}
}
if (q->dbcp != NULL && q->dbcp->use_sql_column_name == Qtrue) {
use_scn = 1;
}
switch (mode & DOFETCH_MODES) {
case DOFETCH_HASH:
case DOFETCH_HASH2:
case DOFETCH_HASHK:
case DOFETCH_HASHK2:
if (q->colnames == NULL) {
int need = sizeof (char *) * 4 * q->ncols + sizeof (char *);
int max_len[2] = { 0, 0 };
char **na, *p;
#ifdef UNICODE
SQLWCHAR name[SQL_MAX_MESSAGE_LENGTH];
#else
char name[SQL_MAX_MESSAGE_LENGTH];
#endif
SQLSMALLINT name_len;
for (i = 0; i < q->ncols; i++) {
int need_len;
name[0] = 0;
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLColAttributes(q->hstmt,
(SQLUSMALLINT) (i + 1),
SQL_COLUMN_TABLE_NAME,
name,
sizeof (name),
&name_len, NULL),
&msg,
"SQLColAttributes(SQL_COLUMN_TABLE_NAME)")) {
rb_raise(Cerror, "%s", msg);
}
if (name_len >= (SQLSMALLINT) sizeof (name)) {
name_len = sizeof (name) - 1;
}
if (name_len > 0) {
name[name_len / sizeof (name[0])] = 0;
}
#ifdef UNICODE
need_len = 6 * (uc_strlen(name) + 1);
#else
need_len = 2 * (strlen(name) + 1);
#endif
need += need_len;
if (max_len[0] < need_len) {
max_len[0] = need_len;
}
name[0] = 0;
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLColAttributes(q->hstmt,
(SQLUSMALLINT) (i + 1),
use_scn ? SQL_COLUMN_NAME :
SQL_COLUMN_LABEL, name,
sizeof (name),
&name_len, NULL),
&msg, use_scn ?
"SQLColAttributes(SQL_COLUMN_NAME)" :
"SQLColAttributes(SQL_COLUMN_LABEL)")) {
rb_raise(Cerror, "%s", msg);
}
if (name_len >= (SQLSMALLINT) sizeof (name)) {
name_len = sizeof (name) - 1;
}
if (name_len > 0) {
name[name_len / sizeof (name[0])] = 0;
}
#ifdef UNICODE
need_len = 6 * 2 * (uc_strlen(name) + 1);
#else
need_len = 2 * (strlen(name) + 1);
#endif
need += need_len;
if (max_len[1] < need_len) {
max_len[1] = need_len;
}
}
need += max_len[0] + max_len[1] + 32;
p = ALLOC_N(char, need);
if (p == NULL) {
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
na = (char **) p;
p += sizeof (char *) * 4 * q->ncols + sizeof (char *);
for (i = 0; i < q->ncols; i++) {
char *p0;
name[0] = 0;
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLColAttributes(q->hstmt, (SQLUSMALLINT) (i + 1),
SQL_COLUMN_TABLE_NAME, name,
sizeof (name), &name_len, NULL),
"SQLColAttributes(SQL_COLUMN_TABLE_NAME)");
if (name_len >= (SQLSMALLINT) sizeof (name)) {
name_len = sizeof (name) - 1;
}
if (name_len > 0) {
name[name_len / sizeof (name[0])] = 0;
}
na[i + q->ncols] = p;
#ifdef UNICODE
p += mkutf(p, name, uc_strlen(name));
#else
strcpy(p, name);
#endif
strcat(p, ".");
p += strlen(p);
p0 = p;
name[0] = 0;
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLColAttributes(q->hstmt, (SQLUSMALLINT) (i + 1),
use_scn ? SQL_COLUMN_NAME :
SQL_COLUMN_LABEL, name,
sizeof (name), &name_len, NULL),
use_scn ? "SQLColAttributes(SQL_COLUMN_NAME)" :
"SQLColAttributes(SQL_COLUMN_LABEL)");
if (name_len >= (SQLSMALLINT) sizeof (name)) {
name_len = sizeof (name) - 1;
}
if (name_len > 0) {
name[name_len / sizeof (name[0])] = 0;
}
na[i] = p;
#ifdef UNICODE
p += mkutf(p, name, uc_strlen(name)) + 1;
#else
strcpy(p, name);
p += strlen(p) + 1;
#endif
na[i + 3 * q->ncols] = p;
strcpy(p, na[i + q->ncols]);
p += p0 - na[i + q->ncols];
na[i + 2 * q->ncols] = upcase_if(p, 1);
p += strlen(p) + 1;
}
/* reserved space for later adjustments */
na[4 * q->ncols] = p;
q->colnames = na;
if (q->colvals == NULL) {
q->colvals = ALLOC_N(VALUE, 4 * q->ncols);
if (q->colvals != NULL) {
VALUE cname;
VALUE colbuf[4];
for (i = 0; i < 4 * q->ncols; i++) {
q->colvals[i] = Qnil;
}
for (i = 0; i < 4; i++) {
colbuf[i] = rb_iv_get(q->self, colnamebuf[i]);
if (colbuf[i] == Qnil) {
res = rb_hash_new();
rb_iv_set(q->self, colnamebuf[i], res);
}
}
for (i = 0; i < 4 * q->ncols; i++) {
res = colbuf[i / q->ncols];
cname = rb_tainted_str_new2(q->colnames[i]);
#ifdef USE_RB_ENC
rb_enc_associate(cname, rb_enc);
#endif
q->colvals[i] = cname;
if (rb_funcall(res, IDkeyp, 1, cname) == Qtrue) {
char *p;
cname = rb_tainted_str_new2(q->colnames[i]);
#ifdef USE_RB_ENC
rb_enc_associate(cname, rb_enc);
#endif
p = q->colnames[4 * q->ncols];
sprintf(p, "#%d", i);
cname = rb_str_cat2(cname, p);
q->colvals[i] = cname;
}
rb_obj_freeze(cname);
rb_hash_aset(res, cname, Qtrue);
}
}
}
}
/* FALL THRU */
case DOFETCH_HASHN:
if (mode & DOFETCH_BANG) {
res = rb_iv_get(q->self, "@_h");
if (res == Qnil) {
res = rb_hash_new();
rb_iv_set(q->self, "@_h", res);
}
} else {
res = rb_hash_new();
}
break;
default:
if (mode & DOFETCH_BANG) {
res = rb_iv_get(q->self, "@_a");
if (res == Qnil) {
res = rb_ary_new2(q->ncols);
rb_iv_set(q->self, "@_a", res);
} else {
rb_ary_clear(res);
}
} else {
res = rb_ary_new2(q->ncols);
}
}
offc = q->upc ? (2 * q->ncols) : 0;
switch (mode & DOFETCH_MODES) {
case DOFETCH_HASHK2:
case DOFETCH_HASH2:
offc += q->ncols;
break;
}
for (i = 0; i < q->ncols; i++) {
SQLLEN totlen;
SQLLEN curlen = q->coltypes[i].size;
SQLSMALLINT type = q->coltypes[i].type;
VALUE v, name;
char *valp, *freep = NULL;
if (curlen == SQL_NO_TOTAL) {
SQLLEN chunksize = SEGSIZE;
totlen = 0;
#ifdef UNICODE
valp = ALLOC_N(char, chunksize + sizeof (SQLWCHAR));
#else
valp = ALLOC_N(char, chunksize + 1);
#endif
freep = valp;
while ((curlen == SQL_NO_TOTAL) || (curlen > chunksize)) {
SQLRETURN rc;
int ret;
rc = SQLGetData(q->hstmt, (SQLUSMALLINT) (i + 1),
type, (SQLPOINTER) (valp + totlen),
#ifdef UNICODE
((type == SQL_C_CHAR) || (type == SQL_C_WCHAR)) ?
(chunksize + (int) sizeof (SQLWCHAR)) :
chunksize,
#else
(type == SQL_C_CHAR) ?
(chunksize + 1) : chunksize,
#endif
&curlen);
if (rc == SQL_NO_DATA) {
if (curlen == SQL_NO_TOTAL) {
curlen = totlen;
}
break;
}
ret = succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
rc, &msg, "SQLGetData");
if (!ret) {
xfree(valp);
rb_raise(Cerror, "%s", msg);
}
if (curlen == SQL_NULL_DATA) {
break;
}
if (curlen == SQL_NO_TOTAL) {
totlen += chunksize;
} else if (curlen > chunksize) {
totlen += chunksize;
chunksize = curlen - chunksize;
} else {
totlen += curlen;
break;
}
#ifdef UNICODE
REALLOC_N(valp, char, totlen + chunksize + sizeof (SQLWCHAR));
#else
REALLOC_N(valp, char, totlen + chunksize + 1);
#endif
if (valp == NULL) {
if (freep != NULL) {
xfree(freep);
}
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
freep = valp;
}
if (totlen > 0) {
curlen = totlen;
}
} else {
totlen = curlen;
valp = bufs[i];
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLGetData(q->hstmt, (SQLUSMALLINT) (i + 1), type,
(SQLPOINTER) valp, totlen, &curlen),
&msg, "SQLGetData")) {
rb_raise(Cerror, "%s", msg);
}
}
if (curlen == SQL_NULL_DATA) {
v = Qnil;
} else {
switch (type) {
case SQL_C_LONG:
v = INT2NUM(*((SQLINTEGER *) valp));
break;
case SQL_C_DOUBLE:
v = rb_float_new(*((double *) valp));
break;
#ifdef SQL_C_SBIGINT
case SQL_C_SBIGINT:
#ifdef LL2NUM
v = LL2NUM(*((SQLBIGINT *) valp));
#else
v = INT2NUM(*((SQLBIGINT *) valp));
#endif
break;
#endif
#ifdef SQL_C_UBIGINT
case SQL_C_UBIGINT:
#ifdef LL2NUM
v = ULL2NUM(*((SQLBIGINT *) valp));
#else
v = UINT2NUM(*((SQLBIGINT *) valp));
#endif
break;
#endif
case SQL_C_DATE:
{
DATE_STRUCT *date;
if (q->dbcp != NULL && q->dbcp->rbtime == Qtrue) {
const char *p;
char buffer[128];
VALUE d;
date = (DATE_STRUCT *) valp;
p = (q->dbcp->gmtime == Qtrue) ? "+00:00" : "";
sprintf(buffer, "%d-%d-%dT00:00:00%s",
date->year, date->month, date->day, p);
d = rb_str_new2(buffer);
v = rb_funcall(rb_cDate, IDparse, 1, d);
} else {
v = Data_Make_Struct(Cdate, DATE_STRUCT, 0, xfree,
date);
*date = *(DATE_STRUCT *) valp;
}
}
break;
case SQL_C_TIME:
{
TIME_STRUCT *time;
if (q->dbcp != NULL && q->dbcp->rbtime == Qtrue) {
VALUE now, frac;
time = (TIME_STRUCT *) valp;
frac = rb_float_new(0.0);
now = rb_funcall(rb_cTime, IDnow, 0, NULL);
v = rb_funcall(rb_cTime,
(q->dbcp->gmtime == Qtrue) ?
IDutc : IDlocal,
7,
rb_funcall(now, IDyear, 0, NULL),
rb_funcall(now, IDmonth, 0, NULL),
rb_funcall(now, IDday, 0, NULL),
INT2NUM(time->hour),
INT2NUM(time->minute),
INT2NUM(time->second),
frac);
} else {
v = Data_Make_Struct(Ctime, TIME_STRUCT, 0, xfree,
time);
*time = *(TIME_STRUCT *) valp;
}
}
break;
case SQL_C_TIMESTAMP:
{
TIMESTAMP_STRUCT *ts;
if (q->dbcp != NULL && q->dbcp->rbtime == Qtrue) {
VALUE frac;
ts = (TIMESTAMP_STRUCT *) valp;
frac = rb_float_new((double) 1.0e-3 * ts->fraction);
v = rb_funcall(rb_cTime,
(q->dbcp->gmtime == Qtrue) ?
IDutc : IDlocal,
7,
INT2NUM(ts->year),
INT2NUM(ts->month),
INT2NUM(ts->day),
INT2NUM(ts->hour),
INT2NUM(ts->minute),
INT2NUM(ts->second),
frac);
} else {
v = Data_Make_Struct(Ctimestamp, TIMESTAMP_STRUCT,
0, xfree, ts);
*ts = *(TIMESTAMP_STRUCT *) valp;
}
}
break;
#ifdef UNICODE
case SQL_C_WCHAR:
v = uc_tainted_str_new((SQLWCHAR *) valp,
curlen / sizeof (SQLWCHAR));
break;
#endif
default:
v = rb_tainted_str_new(valp, curlen);
break;
}
}
if (freep != NULL) {
xfree(freep);
}
switch (mode & DOFETCH_MODES) {
case DOFETCH_HASH:
case DOFETCH_HASH2:
valp = q->colnames[i + offc];
name = (q->colvals == NULL) ? Qnil : q->colvals[i + offc];
if (name == Qnil) {
name = rb_tainted_str_new2(valp);
#ifdef USE_RB_ENC
rb_enc_associate(name, rb_enc);
#endif
if (rb_funcall(res, IDkeyp, 1, name) == Qtrue) {
char *p;
name = rb_tainted_str_new2(valp);
#ifdef USE_RB_ENC
rb_enc_associate(name, rb_enc);
#endif
p = q->colnames[4 * q->ncols];
sprintf(p, "#%d", i);
name = rb_str_cat2(name, p);
}
}
rb_hash_aset(res, name, v);
break;
case DOFETCH_HASHK:
case DOFETCH_HASHK2:
valp = q->colnames[i + offc];
#ifdef USE_RB_ENC
name = ID2SYM(rb_intern3(valp, strlen(valp), rb_enc));
#else
name = ID2SYM(rb_intern(valp));
#endif
if (rb_funcall(res, IDkeyp, 1, name) == Qtrue) {
char *p;
p = q->colnames[4 * q->ncols];
sprintf(p, "%s#%d", valp, i);
#ifdef USE_RB_ENC
name = ID2SYM(rb_intern3(p, strlen(p), rb_enc));
#else
name = ID2SYM(rb_intern(p));
#endif
}
rb_hash_aset(res, name, v);
break;
case DOFETCH_HASHN:
name = INT2NUM(i);
rb_hash_aset(res, name, v);
break;
default:
rb_ary_push(res, v);
}
}
return res;
}
static VALUE
stmt_fetch1(VALUE self, int bang)
{
STMT *q;
SQLRETURN ret;
const char *msg;
char *err;
#if (ODBCVER < 0x0300)
SQLROWSETSIZE nRows;
SQLUSMALLINT rowStat[1];
#endif
Data_Get_Struct(self, STMT, q);
if (q->ncols <= 0) {
return Qnil;
}
if (q->usef) {
goto usef;
}
#if (ODBCVER < 0x0300)
msg = "SQLExtendedFetch(SQL_FETCH_NEXT)";
ret = SQLEXTENDEDFETCH(q->hstmt, SQL_FETCH_NEXT, 0, &nRows, rowStat);
#else
msg = "SQLFetchScroll(SQL_FETCH_NEXT)";
ret = SQLFETCHSCROLL(q->hstmt, SQL_FETCH_NEXT, 0);
#endif
if (ret == SQL_NO_DATA) {
(void) tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, msg);
return Qnil;
}
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, &err, msg)) {
return do_fetch(q, DOFETCH_ARY | (bang ? DOFETCH_BANG : 0));
}
if ((err != NULL) &&
((strncmp(err, "IM001", 5) == 0) ||
(strncmp(err, "HYC00", 5) == 0))) {
usef:
/* Fallback to SQLFetch() when others not implemented */
msg = "SQLFetch";
q->usef = 1;
ret = SQLFETCH(q->hstmt);
if (ret == SQL_NO_DATA) {
(void) tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, msg);
return Qnil;
}
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret,
&err, msg)) {
return do_fetch(q, DOFETCH_ARY | (bang ? DOFETCH_BANG : 0));
}
}
rb_raise(Cerror, "%s", err);
return Qnil;
}
static VALUE
stmt_fetch(VALUE self)
{
if (rb_block_given_p()) {
return stmt_each(self);
}
return stmt_fetch1(self, 0);
}
static VALUE
stmt_fetch_bang(VALUE self)
{
if (rb_block_given_p()) {
return stmt_each(self);
}
return stmt_fetch1(self, 1);
}
static VALUE
stmt_fetch_first1(VALUE self, int bang, int nopos)
{
STMT *q;
SQLRETURN ret;
const char *msg;
char *err;
#if (ODBCVER < 0x0300)
SQLROWSETSIZE nRows;
SQLUSMALLINT rowStat[1];
#endif
Data_Get_Struct(self, STMT, q);
if (q->ncols <= 0) {
return Qnil;
}
if (nopos) {
goto dofetch;
}
#if (ODBCVER < 0x0300)
msg = "SQLExtendedFetch(SQL_FETCH_FIRST)";
ret = SQLEXTENDEDFETCH(q->hstmt, SQL_FETCH_FIRST, 0, &nRows, rowStat);
#else
msg = "SQLFetchScroll(SQL_FETCH_FIRST)";
ret = SQLFETCHSCROLL(q->hstmt, SQL_FETCH_FIRST, 0);
#endif
if (ret == SQL_NO_DATA) {
(void) tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, msg);
return Qnil;
}
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, &err, msg)) {
dofetch:
return do_fetch(q, DOFETCH_ARY | (bang ? DOFETCH_BANG : 0));
}
rb_raise(Cerror, "%s", err);
return Qnil;
}
static VALUE
stmt_fetch_first(VALUE self)
{
return stmt_fetch_first1(self, 0, 0);
}
static VALUE
stmt_fetch_first_bang(VALUE self)
{
return stmt_fetch_first1(self, 1, 0);
}
static VALUE
stmt_fetch_scroll1(int argc, VALUE *argv, VALUE self, int bang)
{
STMT *q;
VALUE dir, offs;
SQLRETURN ret;
int idir, ioffs = 1;
char msg[128], *err;
#if (ODBCVER < 0x0300)
SQLROWSETSIZE nRows;
SQLUSMALLINT rowStat[1];
#endif
rb_scan_args(argc, argv, "11", &dir, &offs);
idir = NUM2INT(dir);
if (offs != Qnil) {
ioffs = NUM2INT(offs);
}
Data_Get_Struct(self, STMT, q);
if (q->ncols <= 0) {
return Qnil;
}
#if (ODBCVER < 0x0300)
sprintf(msg, "SQLExtendedFetch(%d)", idir);
ret = SQLEXTENDEDFETCH(q->hstmt, (SQLSMALLINT) idir, (SQLROWOFFSET) ioffs,
&nRows, rowStat);
#else
sprintf(msg, "SQLFetchScroll(%d)", idir);
ret = SQLFETCHSCROLL(q->hstmt, (SQLSMALLINT) idir, (SQLROWOFFSET) ioffs);
#endif
if (ret == SQL_NO_DATA) {
(void) tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, msg);
return Qnil;
}
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, &err, msg)) {
return do_fetch(q, DOFETCH_ARY | (bang ? DOFETCH_BANG : 0));
}
rb_raise(Cerror, "%s", err);
return Qnil;
}
static VALUE
stmt_fetch_scroll(int argc, VALUE *argv, VALUE self)
{
return stmt_fetch_scroll1(argc, argv, self, 0);
}
static VALUE
stmt_fetch_scroll_bang(int argc, VALUE *argv, VALUE self)
{
return stmt_fetch_scroll1(argc, argv, self, 1);
}
static VALUE
stmt_fetch_many(VALUE self, VALUE arg)
{
int i, max = 0, all = arg == Qnil;
VALUE res;
if (!all) {
max = NUM2INT(arg);
}
res = rb_ary_new();
for (i = 0; all || (i < max); i++) {
VALUE v = stmt_fetch1(self, 0);
if (v == Qnil) {
break;
}
rb_ary_push(res, v);
}
return (i == 0) ? Qnil : res;
}
static VALUE
stmt_fetch_all(VALUE self)
{
return stmt_fetch_many(self, Qnil);
}
static int
stmt_hash_mode(int argc, VALUE *argv, VALUE self)
{
VALUE withtab = Qnil, usesym = Qnil;
int mode = DOFETCH_HASH;
rb_scan_args(argc, argv, "02", &withtab, &usesym);
if ((withtab != Qtrue) && (withtab != Qfalse) && (withtab != Modbc) &&
(rb_obj_is_kind_of(withtab, rb_cHash) == Qtrue)) {
VALUE v;
v = rb_hash_aref(withtab, ID2SYM(IDkey));
if (v == ID2SYM(IDSymbol)) {
mode = DOFETCH_HASHK;
} else if (v == ID2SYM(IDString)) {
mode = DOFETCH_HASH;
} else if (v == ID2SYM(IDFixnum)) {
mode = DOFETCH_HASHN;
} else {
rb_raise(Cerror, "Unsupported key mode");
}
if (mode != DOFETCH_HASHN) {
v = rb_hash_aref(withtab, ID2SYM(IDtable_names));
if (RTEST(v)) {
mode = (mode == DOFETCH_HASHK)
? DOFETCH_HASHK2 : DOFETCH_HASH2;
}
}
return mode;
}
if (withtab == Modbc) {
return DOFETCH_HASHN;
}
mode = RTEST(withtab) ? DOFETCH_HASH2 : DOFETCH_HASH;
if (RTEST(usesym)) {
mode = (mode == DOFETCH_HASH2) ? DOFETCH_HASHK2 : DOFETCH_HASHK;
}
return mode;
}
static VALUE
stmt_fetch_hash1(int argc, VALUE *argv, VALUE self, int bang)
{
STMT *q;
SQLRETURN ret;
int mode = stmt_hash_mode(argc, argv, self);
const char *msg;
char *err;
#if (ODBCVER < 0x0300)
SQLROWSETSIZE nRows;
SQLUSMALLINT rowStat[1];
#endif
Data_Get_Struct(self, STMT, q);
if (q->ncols <= 0) {
return Qnil;
}
if (q->usef) {
goto usef;
}
#if (ODBCVER < 0x0300)
msg = "SQLExtendedFetch(SQL_FETCH_NEXT)";
ret = SQLEXTENDEDFETCH(q->hstmt, SQL_FETCH_NEXT, 0, &nRows, rowStat);
#else
msg = "SQLFetchScroll(SQL_FETCH_NEXT)";
ret = SQLFETCHSCROLL(q->hstmt, SQL_FETCH_NEXT, 0);
#endif
if (ret == SQL_NO_DATA) {
(void) tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, msg);
return Qnil;
}
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, &err, msg)) {
return do_fetch(q, mode | (bang ? DOFETCH_BANG : 0));
}
if ((err != NULL) &&
((strncmp(err, "IM001", 5) == 0) ||
(strncmp(err, "HYC00", 5) == 0))) {
usef:
/* Fallback to SQLFetch() when others not implemented */
msg = "SQLFetch";
q->usef = 1;
ret = SQLFETCH(q->hstmt);
if (ret == SQL_NO_DATA) {
(void) tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, msg);
return Qnil;
}
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret,
&err, msg)) {
return do_fetch(q, mode | (bang ? DOFETCH_BANG : 0));
}
}
rb_raise(Cerror, "%s", err);
return Qnil;
}
static VALUE
stmt_fetch_hash(int argc, VALUE *argv, VALUE self)
{
if (rb_block_given_p()) {
return stmt_each_hash(argc, argv, self);
}
return stmt_fetch_hash1(argc, argv, self, 0);
}
static VALUE
stmt_fetch_hash_bang(int argc, VALUE *argv, VALUE self)
{
if (rb_block_given_p()) {
return stmt_each_hash(argc, argv, self);
}
return stmt_fetch_hash1(argc, argv, self, 1);
}
static VALUE
stmt_fetch_first_hash1(int argc, VALUE *argv, VALUE self, int bang, int nopos)
{
STMT *q;
SQLRETURN ret;
int mode = stmt_hash_mode(argc, argv, self);
const char *msg;
char *err;
#if (ODBCVER < 0x0300)
SQLROWSETSIZE nRows;
SQLUSMALLINT rowStat[1];
#endif
Data_Get_Struct(self, STMT, q);
if (q->ncols <= 0) {
return Qnil;
}
if (nopos) {
goto dofetch;
}
#if (ODBCVER < 0x0300)
msg = "SQLExtendedFetch(SQL_FETCH_FIRST)";
ret = SQLEXTENDEDFETCH(q->hstmt, SQL_FETCH_FIRST, 0, &nRows, rowStat);
#else
msg = "SQLFetchScroll(SQL_FETCH_FIRST)";
ret = SQLFETCHSCROLL(q->hstmt, SQL_FETCH_FIRST, 0);
#endif
if (ret == SQL_NO_DATA) {
(void) tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, msg);
return Qnil;
}
if (succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, &err, msg)) {
dofetch:
return do_fetch(q, mode | (bang ? DOFETCH_BANG : 0));
}
rb_raise(Cerror, "%s", err);
return Qnil;
}
static VALUE
stmt_fetch_first_hash(int argc, VALUE *argv, VALUE self)
{
return stmt_fetch_first_hash1(argc, argv, self, 0, 0);
}
static VALUE
stmt_each(VALUE self)
{
VALUE row, res = Qnil;
STMT *q;
#if (ODBCVER < 0x0300)
SQLROWSETSIZE nRows;
SQLUSMALLINT rowStat[1];
#endif
Data_Get_Struct(self, STMT, q);
#if (ODBCVER < 0x0300)
switch (callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLEXTENDEDFETCH(q->hstmt, SQL_FETCH_FIRST, 0, &nRows,
rowStat),
"SQLExtendedFetch(SQL_FETCH_FIRST)"))
#else
switch (callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFETCHSCROLL(q->hstmt, SQL_FETCH_FIRST, 0),
"SQLFetchScroll(SQL_FETCH_FIRST)"))
#endif
{
case SQL_NO_DATA:
row = Qnil;
break;
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
row = stmt_fetch_first1(self, 0, 1);
break;
default:
row = stmt_fetch1(self, 0);
}
if (rb_block_given_p()) {
while (row != Qnil) {
rb_yield(row);
row = stmt_fetch1(self, 0);
}
return self;
}
if (row != Qnil) {
res = rb_ary_new();
while (row != Qnil) {
rb_ary_push(res, row);
row = stmt_fetch1(self, 0);
}
}
return res;
}
static VALUE
stmt_each_hash(int argc, VALUE *argv, VALUE self)
{
VALUE row, res = Qnil, withtab[2];
STMT *q;
int mode = stmt_hash_mode(argc, argv, self);
#if (ODBCVER < 0x0300)
SQLROWSETSIZE nRows;
SQLUSMALLINT rowStat[1];
#endif
if (mode == DOFETCH_HASHN) {
withtab[0] = Modbc;
withtab[1] = Qfalse;
} else {
withtab[0] = ((mode == DOFETCH_HASH2) || (mode == DOFETCH_HASHK2))
? Qtrue : Qfalse;
withtab[1] = ((mode == DOFETCH_HASHK) || (mode == DOFETCH_HASHK2))
? Qtrue : Qfalse;
}
Data_Get_Struct(self, STMT, q);
#if (ODBCVER < 0x0300)
switch (callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLEXTENDEDFETCH(q->hstmt, SQL_FETCH_FIRST, 0, &nRows,
rowStat),
"SQLExtendedFetch(SQL_FETCH_FIRST)"))
#else
switch (callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFETCHSCROLL(q->hstmt, SQL_FETCH_FIRST, 0),
"SQLFetchScroll(SQL_FETCH_FIRST)"))
#endif
{
case SQL_NO_DATA:
row = Qnil;
break;
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
row = stmt_fetch_first_hash1(2, withtab, self, 0, 1);
break;
default:
row = stmt_fetch_hash1(2, withtab, self, 0);
}
if (rb_block_given_p()) {
while (row != Qnil) {
rb_yield(row);
row = stmt_fetch_hash1(2, withtab, self, 0);
}
return self;
}
if (row != Qnil) {
res = rb_ary_new();
while (row != Qnil) {
rb_ary_push(res, row);
row = stmt_fetch_hash1(2, withtab, self, 0);
}
}
return res;
}
static VALUE
stmt_more_results(VALUE self)
{
STMT *q;
if (rb_block_given_p()) {
rb_raise(rb_eArgError, "block not allowed");
}
Data_Get_Struct(self, STMT, q);
if (q->hstmt == SQL_NULL_HSTMT) {
return Qfalse;
}
switch (tracesql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLMoreResults(q->hstmt), "SQLMoreResults")) {
case SQL_NO_DATA:
return Qfalse;
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
free_stmt_sub(q, 0);
make_result(q->dbc, q->hstmt, self, 0);
break;
default:
rb_raise(Cerror, "%s",
get_err(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt));
}
return Qtrue;
}
static VALUE
stmt_prep_int(int argc, VALUE *argv, VALUE self, int mode)
{
DBC *p = get_dbc(self);
STMT *q = NULL;
VALUE sql, dbc, stmt;
SQLHSTMT hstmt;
SQLRETURN ret;
#ifdef UNICODE
SQLWCHAR *ssql = NULL;
#else
SQLCHAR *ssql = NULL;
#endif
char *csql = NULL, *msg = NULL;
if (rb_obj_is_kind_of(self, Cstmt) == Qtrue) {
Data_Get_Struct(self, STMT, q);
free_stmt_sub(q, 0);
if (q->hstmt == SQL_NULL_HSTMT) {
if (!succeeded(SQL_NULL_HENV, p->hdbc, q->hstmt,
SQLAllocStmt(p->hdbc, &q->hstmt),
&msg, "SQLAllocStmt")) {
rb_raise(Cerror, "%s", msg);
}
} else if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFreeStmt(q->hstmt, SQL_CLOSE),
&msg, "SQLFreeStmt(SQL_CLOSE)")) {
rb_raise(Cerror, "%s", msg);
}
hstmt = q->hstmt;
stmt = self;
dbc = q->dbc;
} else {
if (!succeeded(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLAllocStmt(p->hdbc, &hstmt),
&msg, "SQLAllocStmt")) {
rb_raise(Cerror, "%s", msg);
}
stmt = Qnil;
dbc = self;
}
rb_scan_args(argc, argv, "1", &sql);
Check_Type(sql, T_STRING);
#ifdef UNICODE
#ifdef USE_RB_ENC
sql = rb_funcall(sql, IDencode, 1, rb_encv);
#endif
csql = STR2CSTR(sql);
ssql = uc_from_utf((unsigned char *) csql, -1);
if (ssql == NULL) {
rb_raise(Cerror, "%s", set_err("Out of memory", 0));
}
#else
csql = STR2CSTR(sql);
ssql = (SQLCHAR *) csql;
#endif
if ((mode & MAKERES_EXECD)) {
ret = SQLEXECDIRECT(hstmt, ssql, SQL_NTS);
if (!succeeded_nodata(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, ret,
&msg, "SQLExecDirect('%s')", csql)) {
goto sqlerr;
}
if (ret == SQL_NO_DATA) {
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLFreeStmt(hstmt, SQL_CLOSE), "SQLFreeStmt(SQL_DROP)");
if (q != NULL) {
q->hstmt = SQL_NULL_HSTMT;
unlink_stmt(q);
}
hstmt = SQL_NULL_HSTMT;
}
} else {
ret = SQLPREPARE(hstmt, ssql, SQL_NTS);
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, ret,
&msg, "SQLPrepare('%s')", csql)) {
sqlerr:
#ifdef UNICODE
uc_free(ssql);
#endif
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt,
SQLFreeStmt(hstmt, SQL_DROP), "SQLFreeStmt(SQL_DROP)");
if (q != NULL) {
q->hstmt = SQL_NULL_HSTMT;
unlink_stmt(q);
}
rb_raise(Cerror, "%s", msg);
} else {
mode |= MAKERES_PREPARE;
}
}
#ifdef UNICODE
uc_free(ssql);
#endif
return make_result(dbc, hstmt, stmt, mode);
}
static VALUE
stmt_prep(int argc, VALUE *argv, VALUE self)
{
return stmt_prep_int(argc, argv, self, MAKERES_BLOCK);
}
static int
bind_one_param(int pnum, VALUE arg, STMT *q, char **msgp, int *outpp)
{
SQLPOINTER valp = (SQLPOINTER) &q->paraminfo[pnum].buffer;
SQLSMALLINT ctype, stype;
SQLINTEGER vlen, rlen;
SQLUINTEGER coldef;
#ifdef NO_RB_STR2CSTR
VALUE val;
#endif
long llen;
int retry = 1;
#ifdef UNICODE
SQLWCHAR *up;
q->paraminfo[pnum].tofree = NULL;
#endif
switch (TYPE(arg)) {
case T_STRING:
#ifdef UNICODE
ctype = SQL_C_WCHAR;
#ifdef USE_RB_ENC
arg = rb_funcall(arg, IDencode, 1, rb_encv);
#endif
#ifndef NO_RB_STR2CSTR
up = (SQLWCHAR *) rb_str2cstr(arg, &llen);
if (llen != (long) strlen((char *) up)) {
ctype = SQL_C_BINARY;
valp = (SQLPOINTER) up;
rlen = llen;
vlen = rlen + 1;
break;
}
#else
val = rb_string_value(&arg);
up = (SQLWCHAR *) RSTRING_PTR(val);
llen = RSTRING_LEN(val);
if (up == NULL) {
goto oom;
}
if (memchr((char *) up, 0, llen)) {
ctype = SQL_C_BINARY;
valp = (SQLPOINTER) up;
rlen = llen;
vlen = rlen + 1;
break;
}
up = (SQLWCHAR *) rb_string_value_cstr(&arg);
#endif
up = uc_from_utf((unsigned char *) up, llen);
if (up == NULL) {
goto oom;
}
*(SQLWCHAR **) valp = up;
rlen = uc_strlen(up) * sizeof (SQLWCHAR);
vlen = rlen + sizeof (SQLWCHAR);
q->paraminfo[pnum].tofree = up;
#else
ctype = SQL_C_CHAR;
#ifndef NO_RB_STR2CSTR
valp = (SQLPOINTER) rb_str2cstr(arg, &llen);
rlen = llen;
if (rlen != (SQLINTEGER) strlen((char *) valp)) {
ctype = SQL_C_BINARY;
}
vlen = rlen + 1;
#else
val = rb_string_value(&arg);
valp = (SQLPOINTER) RSTRING_PTR(val);
llen = RSTRING_LEN(val);
if (valp == NULL) {
goto oom;
}
rlen = llen;
vlen = rlen + 1;
if (memchr((char *) valp, 0, llen)) {
ctype = SQL_C_BINARY;
break;
}
valp = (SQLPOINTER) rb_string_value_cstr(&arg);
#endif
#endif
break;
case T_FIXNUM:
ctype = SQL_C_LONG;
*(SQLINTEGER *) valp = FIX2INT(arg);
rlen = 1;
vlen = sizeof (SQLINTEGER);
break;
case T_FLOAT:
ctype = SQL_C_DOUBLE;
*(double *) valp = NUM2DBL(arg);
rlen = 1;
vlen = sizeof (double);
break;
case T_NIL:
ctype = SQL_C_CHAR;
valp = NULL;
rlen = SQL_NULL_DATA;
vlen = 0;
break;
case T_SYMBOL:
ctype = SQL_C_CHAR;
valp = NULL;
vlen = 0;
if (arg == ID2SYM(IDNULL)) {
rlen = SQL_NULL_DATA;
} else if (arg == ID2SYM(IDdefault)) {
rlen = SQL_DEFAULT_PARAM;
}
/* fall through */
default:
if (rb_obj_is_kind_of(arg, Cdate) == Qtrue) {
DATE_STRUCT *date;
ctype = SQL_C_DATE;
Data_Get_Struct(arg, DATE_STRUCT, date);
valp = (SQLPOINTER) date;
rlen = 1;
vlen = sizeof (DATE_STRUCT);
break;
}
if (rb_obj_is_kind_of(arg, Ctime) == Qtrue) {
TIME_STRUCT *time;
ctype = SQL_C_TIME;
Data_Get_Struct(arg, TIME_STRUCT, time);
valp = (SQLPOINTER) time;
rlen = 1;
vlen = sizeof (TIME_STRUCT);
break;
}
if (rb_obj_is_kind_of(arg, Ctimestamp) == Qtrue) {
TIMESTAMP_STRUCT *ts;
ctype = SQL_C_TIMESTAMP;
Data_Get_Struct(arg, TIMESTAMP_STRUCT, ts);
valp = (SQLPOINTER) ts;
rlen = 1;
vlen = sizeof (TIMESTAMP_STRUCT);
break;
}
if (rb_obj_is_kind_of(arg, rb_cTime) == Qtrue) {
if (q->paraminfo[pnum].type == SQL_TIME) {
TIME_STRUCT *time;
ctype = SQL_C_TIME;
time = (TIME_STRUCT *) valp;
memset(time, 0, sizeof (TIME_STRUCT));
time->hour = rb_funcall(arg, IDhour, 0, NULL);
time->minute = rb_funcall(arg, IDmin, 0, NULL);
time->second = rb_funcall(arg, IDsec, 0, NULL);
rlen = 1;
vlen = sizeof (TIME_STRUCT);
} else if (q->paraminfo[pnum].type == SQL_DATE) {
DATE_STRUCT *date;
ctype = SQL_C_DATE;
date = (DATE_STRUCT *) valp;
memset(date, 0, sizeof (DATE_STRUCT));
date->year = rb_funcall(arg, IDyear, 0, NULL);
date->month = rb_funcall(arg, IDmonth, 0, NULL);
date->day = rb_funcall(arg, IDday, 0, NULL);
rlen = 1;
vlen = sizeof (TIMESTAMP_STRUCT);
} else {
TIMESTAMP_STRUCT *ts;
ctype = SQL_C_TIMESTAMP;
ts = (TIMESTAMP_STRUCT *) valp;
memset(ts, 0, sizeof (TIMESTAMP_STRUCT));
ts->year = rb_funcall(arg, IDyear, 0, NULL);
ts->month = rb_funcall(arg, IDmonth, 0, NULL);
ts->day = rb_funcall(arg, IDday, 0, NULL);
ts->hour = rb_funcall(arg, IDhour, 0, NULL);
ts->minute = rb_funcall(arg, IDmin, 0, NULL);
ts->second = rb_funcall(arg, IDsec, 0, NULL);
#ifdef TIME_USE_USEC
ts->fraction = rb_funcall(arg, IDusec, 0, NULL) * 1000;
#else
ts->fraction = rb_funcall(arg, IDnsec, 0, NULL);
#endif
rlen = 1;
vlen = sizeof (TIMESTAMP_STRUCT);
}
break;
}
if (rb_obj_is_kind_of(arg, rb_cDate) == Qtrue) {
DATE_STRUCT *date;
ctype = SQL_C_DATE;
date = (DATE_STRUCT *) valp;
memset(date, 0, sizeof (DATE_STRUCT));
date->year = rb_funcall(arg, IDyear, 0, NULL);
date->month = rb_funcall(arg, IDmonth, 0, NULL);
date->day = rb_funcall(arg, IDmday, 0, NULL);
rlen = 1;
vlen = sizeof (DATE_STRUCT);
break;
}
ctype = SQL_C_CHAR;
#ifndef NO_RB_STR2CSTR
valp = (SQLPOINTER *) rb_str2cstr(rb_str_to_str(arg), &llen);
rlen = llen;
if (rlen != (SQLINTEGER) strlen((char *) valp)) {
ctype = SQL_C_BINARY;
}
vlen = rlen + 1;
#else
val = rb_string_value(&arg);
valp = (SQLPOINTER) RSTRING_PTR(val);
llen = RSTRING_LEN(val);
if (valp == NULL) {
goto oom;
}
rlen = llen;
vlen = rlen + 1;
if (memchr((char *) valp, 0, llen)) {
ctype = SQL_C_BINARY;
break;
}
valp = (SQLPOINTER) rb_string_value_cstr(&arg);
#endif
break;
}
stype = q->paraminfo[pnum].type;
coldef = q->paraminfo[pnum].coldef;
q->paraminfo[pnum].rlen = rlen;
q->paraminfo[pnum].ctype = ctype;
if (coldef == 0) {
switch (ctype) {
case SQL_C_LONG:
coldef = 10;
break;
case SQL_C_DOUBLE:
coldef = 15;
if (stype == SQL_VARCHAR) {
stype = SQL_DOUBLE;
}
break;
case SQL_C_DATE:
coldef = 10;
break;
case SQL_C_TIME:
coldef = 8;
break;
case SQL_C_TIMESTAMP:
coldef = 19;
break;
default:
/*
* Patch adopted from the Perl DBD::ODBC module ...
* per patch from Paul G. Weiss, who was experiencing re-preparing
* of queries when the size of the bound string's were increasing
* for example select * from tabtest where name = ?
* then executing with 'paul' and then 'thomas' would cause
* SQLServer to prepare the query twice, but if we ran 'thomas'
* then 'paul', it would not re-prepare the query. The key seems
* to be allocating enough space for the largest parameter.
* TBD: the default for this should be a tunable parameter.
*/
if ((stype == SQL_VARCHAR) &&
(q->paraminfo[pnum].iotype != SQL_PARAM_INPUT_OUTPUT) &&
(q->paraminfo[pnum].iotype != SQL_PARAM_OUTPUT)) {
if (q->paraminfo[pnum].coldef_max == 0) {
q->paraminfo[pnum].coldef_max = (vlen > 128) ? vlen : 128;
} else {
/* bump up max, if needed */
if (vlen > (SQLINTEGER) q->paraminfo[pnum].coldef_max) {
q->paraminfo[pnum].coldef_max = vlen;
}
}
coldef = q->paraminfo[pnum].coldef_max;
} else {
coldef = vlen;
}
break;
}
}
if ((q->paraminfo[pnum].iotype == SQL_PARAM_INPUT_OUTPUT) ||
(q->paraminfo[pnum].iotype == SQL_PARAM_OUTPUT)) {
if (valp == NULL) {
if (q->paraminfo[pnum].outsize > 0) {
if (q->paraminfo[pnum].outbuf != NULL) {
xfree(q->paraminfo[pnum].outbuf);
}
q->paraminfo[pnum].outbuf = xmalloc(q->paraminfo[pnum].outsize);
if (q->paraminfo[pnum].outbuf == NULL) {
goto oom;
}
ctype = q->paraminfo[pnum].ctype = q->paraminfo[pnum].outtype;
outpp[0]++;
valp = q->paraminfo[pnum].outbuf;
vlen = q->paraminfo[pnum].outsize;
}
} else {
if (q->paraminfo[pnum].outbuf != NULL) {
xfree(q->paraminfo[pnum].outbuf);
}
q->paraminfo[pnum].outbuf = xmalloc(vlen);
if (q->paraminfo[pnum].outbuf == NULL) {
oom:
#ifdef UNICODE
if (q->paraminfo[pnum].tofree != NULL) {
uc_free(q->paraminfo[pnum].tofree);
q->paraminfo[pnum].tofree = NULL;
}
#endif
*msgp = set_err("Out of memory", 0);
return -1;
}
#ifdef UNICODE
if (ctype == SQL_C_WCHAR) {
memcpy(q->paraminfo[pnum].outbuf, *(SQLWCHAR **) valp, vlen);
} else
#endif
memcpy(q->paraminfo[pnum].outbuf, valp, vlen);
#ifdef UNICODE
if (ctype == SQL_C_WCHAR) {
*(SQLWCHAR **) valp = (SQLWCHAR *) q->paraminfo[pnum].outbuf;
} else
#endif
valp = q->paraminfo[pnum].outbuf;
outpp[0]++;
}
}
retry:
#ifdef UNICODE
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLBindParameter(q->hstmt, (SQLUSMALLINT) (pnum + 1),
q->paraminfo[pnum].iotype,
ctype, stype, coldef,
q->paraminfo[pnum].scale,
(ctype == SQL_C_WCHAR) ?
*(SQLWCHAR **) valp : valp,
vlen, &q->paraminfo[pnum].rlen),
msgp, "SQLBindParameter(%d)", pnum + 1))
#else
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLBindParameter(q->hstmt, (SQLUSMALLINT) (pnum + 1),
q->paraminfo[pnum].iotype,
ctype, stype, coldef,
q->paraminfo[pnum].scale,
valp, vlen, &q->paraminfo[pnum].rlen),
msgp, "SQLBindParameter(%d)", pnum + 1))
#endif
{
if (retry) {
retry = 0;
if (stype == SQL_VARCHAR) {
/* maybe MS Jet memo field */
stype = SQL_LONGVARCHAR;
goto retry;
}
#ifdef UNICODE
if (stype == SQL_WVARCHAR) {
stype = SQL_WLONGVARCHAR;
goto retry;
}
#endif
}
return -1;
}
return 0;
}
static VALUE
stmt_exec_int(int argc, VALUE *argv, VALUE self, int mode)
{
STMT *q;
int i, argnum, has_out_parms = 0;
char *msg = NULL;
SQLRETURN ret;
Data_Get_Struct(self, STMT, q);
if (argc > q->nump - ((EXEC_PARMXOUT(mode) < 0) ? 0 : 1)) {
rb_raise(Cerror, "%s", set_err("Too much parameters", 0));
}
if (q->hstmt == SQL_NULL_HSTMT) {
rb_raise(Cerror, "%s", set_err("Stale ODBC::Statement", 0));
}
if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFreeStmt(q->hstmt, SQL_CLOSE),
&msg, "SQLFreeStmt(SQL_CLOSE)")) {
goto error;
}
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFreeStmt(q->hstmt, SQL_RESET_PARAMS),
"SQLFreeStmt(SQL_RESET_PARMS)");
for (i = argnum = 0; i < q->nump; i++) {
VALUE arg;
if (i == EXEC_PARMXOUT(mode)) {
if (bind_one_param(i, Qnil, q, &msg, &has_out_parms) < 0) {
goto error;
}
continue;
}
arg = (argnum < argc) ? argv[argnum++] : Qnil;
if (bind_one_param(i, arg, q, &msg, &has_out_parms) < 0) {
goto error;
}
}
ret = SQLEXECUTE(q->hstmt);
if (!succeeded_nodata(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret,
&msg, "SQLExecute")) {
error:
#ifdef UNICODE
for (i = 0; i < q->nump; i++) {
if (q->paraminfo[i].tofree != NULL) {
uc_free(q->paraminfo[i].tofree);
q->paraminfo[i].tofree = NULL;
}
}
#endif
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFreeStmt(q->hstmt, SQL_DROP), "SQLFreeStmt(SQL_DROP)");
q->hstmt = SQL_NULL_HSTMT;
unlink_stmt(q);
rb_raise(Cerror, "%s", msg);
}
#ifdef UNICODE
for (i = 0; i < q->nump; i++) {
if (q->paraminfo[i].tofree != NULL) {
uc_free(q->paraminfo[i].tofree);
q->paraminfo[i].tofree = NULL;
}
}
#endif
if (!has_out_parms) {
callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt,
SQLFreeStmt(q->hstmt, SQL_RESET_PARAMS),
"SQLFreeStmt(SQL_RESET_PARAMS)");
}
if (ret == SQL_NO_DATA) {
return Qnil;
}
return make_result(q->dbc, q->hstmt, self, mode);
}
static VALUE
stmt_exec(int argc, VALUE *argv, VALUE self)
{
return stmt_exec_int(argc, argv, self, MAKERES_BLOCK);
}
static VALUE
stmt_run(int argc, VALUE *argv, VALUE self)
{
if (argc < 1) {
rb_raise(rb_eArgError, "wrong # of arguments");
}
if (argc == 1) {
return stmt_prep_int(1, argv, self,
MAKERES_EXECD | MAKERES_BLOCK);
}
return stmt_exec(argc - 1, argv + 1, stmt_prep_int(1, argv, self, 0));
}
static VALUE
stmt_do(int argc, VALUE *argv, VALUE self)
{
VALUE stmt;
if (argc < 1) {
rb_raise(rb_eArgError, "wrong # of arguments");
}
if (argc == 1) {
stmt = stmt_prep_int(1, argv, self,
MAKERES_EXECD | MAKERES_BLOCK | MAKERES_NOCLOSE);
} else {
stmt = stmt_prep_int(1, argv, self, 0);
stmt_exec_int(argc - 1, argv + 1, stmt,
MAKERES_BLOCK | MAKERES_NOCLOSE);
}
return rb_ensure(stmt_nrows, stmt, stmt_drop, stmt);
}
static VALUE
stmt_ignorecase(int argc, VALUE *argv, VALUE self)
{
VALUE onoff = Qnil;
int *flag = NULL;
rb_scan_args(argc, argv, "01", &onoff);
if (rb_obj_is_kind_of(self, Cstmt) == Qtrue) {
STMT *q;
Data_Get_Struct(self, STMT, q);
flag = &q->upc;
} else if (rb_obj_is_kind_of(self, Cdbc) == Qtrue) {
DBC *p;
Data_Get_Struct(self, DBC, p);
flag = &p->upc;
} else {
rb_raise(rb_eTypeError, "ODBC::Statement or ODBC::Database expected");
return Qnil;
}
if (argc > 0) {
*flag = RTEST(onoff);
}
return *flag ? Qtrue : Qfalse;
}
/*
*----------------------------------------------------------------------
*
* Create statement without implicit SQL prepare or execute.
*
*----------------------------------------------------------------------
*/
static VALUE
stmt_new(VALUE self)
{
DBC *p;
SQLHSTMT hstmt;
char *msg = NULL;
Data_Get_Struct(self, DBC, p);
if (!succeeded(SQL_NULL_HENV, p->hdbc, SQL_NULL_HSTMT,
SQLAllocStmt(p->hdbc, &hstmt),
&msg, "SQLAllocStmt")) {
rb_raise(Cerror, "%s", msg);
}
return wrap_stmt(self, p, hstmt, NULL);
}
/*
*----------------------------------------------------------------------
*
* Procedures with statements.
*
*----------------------------------------------------------------------
*/
static VALUE
stmt_proc_init(int argc, VALUE *argv, VALUE self)
{
VALUE stmt = (argc > 0) ? argv[0] : Qnil;
if (rb_obj_is_kind_of(stmt, Cstmt) == Qtrue) {
rb_iv_set(self, "@statement", stmt);
rb_iv_set(self, "@return_output_param", (argc > 1) ? argv[1] : Qnil);
return self;
}
rb_raise(rb_eTypeError, "need ODBC::Statement as argument");
return Qnil;
}
static VALUE
stmt_proc_call(int argc, VALUE *argv, VALUE self)
{
VALUE stmt, val;
stmt = rb_iv_get(self, "@statement");
val = rb_iv_get(self, "@return_output_param");
if (RTEST(val)) {
int parnum = NUM2INT(val);
stmt_exec_int(argc, argv, stmt, EXEC_PARMXNULL(parnum));
rb_call_super(1, &stmt);
return stmt_param_output_value(1, &val, stmt);
}
stmt_exec_int(argc, argv, stmt, 0);
return rb_call_super(1, &stmt);
}
static VALUE
stmt_proc(int argc, VALUE *argv, VALUE self)
{
VALUE sql, ptype, psize, pnum = Qnil, stmt, args[2];
int parnum = 0;
rb_scan_args(argc, argv, "13", &sql, &ptype, &psize, &pnum);
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "block required");
}
stmt = stmt_prep_int(1, &sql, self, 0);
if (argc == 1) {
return rb_funcall(Cproc, IDnew, 1, stmt);
}
if ((argc < 4) || (pnum == Qnil)) {
pnum = INT2NUM(parnum);
} else {
parnum = NUM2INT(pnum);
}
args[0] = pnum;
args[1] = INT2NUM(SQL_PARAM_OUTPUT);
stmt_param_iotype(2, args, stmt);
args[1] = ptype;
stmt_param_output_type(2, args, stmt);
if (argc > 2) {
args[1] = psize;
} else {
args[1] = INT2NUM(256);
}
stmt_param_output_size(2, args, stmt);
return rb_funcall(Cproc, IDnew, 2, stmt, pnum);
}
static VALUE
stmt_procwrap(int argc, VALUE *argv, VALUE self)
{
VALUE arg0 = Qnil, arg1 = Qnil;
rb_scan_args(argc, argv, "02", &arg0, &arg1);
if (rb_obj_is_kind_of(self, Cstmt) == Qtrue) {
if (arg1 != Qnil) {
rb_raise(rb_eArgError, "wrong # arguments");
}
arg1 = arg0;
arg0 = self;
} else if (rb_obj_is_kind_of(arg0, Cstmt) != Qtrue) {
rb_raise(rb_eTypeError, "need ODBC::Statement as 1st argument");
}
return rb_funcall(Cproc, IDnew, 2, arg0, arg1);
}
/*
*----------------------------------------------------------------------
*
* Module functions.
*
*----------------------------------------------------------------------
*/
static VALUE
mod_dbcdisc(VALUE dbc)
{
return dbc_disconnect(0, NULL, dbc);
}
static VALUE
mod_connect(int argc, VALUE *argv, VALUE self)
{
VALUE dbc = dbc_new(argc, argv, self);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, dbc, mod_dbcdisc, dbc);
}
return dbc;
}
static VALUE
mod_2time(int argc, VALUE *argv, VALUE self)
{
VALUE a1, a2;
VALUE y, m, d, hh, mm, ss, us;
int once = 0;
rb_scan_args(argc, argv, "11", &a1, &a2);
again:
if (rb_obj_is_kind_of(a1, Ctimestamp) == Qtrue) {
TIMESTAMP_STRUCT *ts;
if (argc > 1) {
rb_raise(rb_eArgError, "wrong # arguments(2 for 1)");
}
Data_Get_Struct(a1, TIMESTAMP_STRUCT, ts);
y = INT2NUM(ts->year);
m = INT2NUM(ts->month);
d = INT2NUM(ts->day);
hh = INT2NUM(ts->hour);
mm = INT2NUM(ts->minute);
ss = INT2NUM(ts->second);
us = INT2NUM(ts->fraction / 1000);
goto mktime;
}
if (rb_obj_is_kind_of(a1, Cdate) == Qtrue) {
DATE_STRUCT *date;
if (a2 != Qnil) {
if (rb_obj_is_kind_of(a2, Ctime) == Qtrue) {
TIME_STRUCT *time;
Data_Get_Struct(a2, TIME_STRUCT, time);
hh = INT2NUM(time->hour);
mm = INT2NUM(time->minute);
ss = INT2NUM(time->second);
} else {
rb_raise(rb_eTypeError, "expecting ODBC::Time");
}
} else {
hh = INT2FIX(0);
mm = INT2FIX(0);
ss = INT2FIX(0);
}
Data_Get_Struct(a1, DATE_STRUCT, date);
y = INT2NUM(date->year);
m = INT2NUM(date->month);
d = INT2NUM(date->day);
us = INT2FIX(0);
}
if (rb_obj_is_kind_of(a1, Ctime) == Qtrue) {
TIME_STRUCT *time;
if (a2 != Qnil) {
if (rb_obj_is_kind_of(a2, Cdate) == Qtrue) {
DATE_STRUCT *date;
Data_Get_Struct(a2, DATE_STRUCT, date);
y = INT2NUM(date->year);
m = INT2NUM(date->month);
d = INT2NUM(date->day);
} else {
rb_raise(rb_eTypeError, "expecting ODBC::Date");
}
} else {
VALUE now = rb_funcall(rb_cTime, IDnow, 0, NULL);
y = rb_funcall(rb_cTime, IDyear, 1, now);
m = rb_funcall(rb_cTime, IDmonth, 1, now);
d = rb_funcall(rb_cTime, IDday, 1, now);
}
Data_Get_Struct(a1, TIME_STRUCT, time);
hh = INT2NUM(time->hour);
mm = INT2NUM(time->minute);
ss = INT2NUM(time->second);
us = INT2FIX(0);
mktime:
return rb_funcall(rb_cTime, IDlocal, 7, y, m, d, hh, mm, ss, us);
}
if ((!once) && ((m = timestamp_load1(Ctimestamp, a1, -1)) != Qnil)) {
a1 = m;
once++;
goto again;
}
if ((!once) && ((m = date_load1(Cdate, a1, -1)) != Qnil)) {
a1 = m;
if ((argc > 1) && ((m = time_load1(Ctime, a2, -1)) != Qnil)) {
a2 = m;
}
once++;
goto again;
}
if ((!once) && ((m = time_load1(Ctime, a1, -1)) != Qnil)) {
a1 = m;
if ((argc > 1) && ((m = date_load1(Cdate, a2, -1)) != Qnil)) {
a2 = m;
}
once++;
goto again;
}
rb_raise(rb_eTypeError,
"expecting ODBC::TimeStamp or ODBC::Date/Time or String");
return Qnil;
}
static VALUE
mod_2date(VALUE self, VALUE arg)
{
VALUE y, m, d;
int once = 0;
again:
if (rb_obj_is_kind_of(arg, Cdate) == Qtrue) {
DATE_STRUCT *date;
Data_Get_Struct(arg, DATE_STRUCT, date);
y = INT2NUM(date->year);
m = INT2NUM(date->month);
d = INT2NUM(date->day);
goto mkdate;
}
if (rb_obj_is_kind_of(arg, Ctimestamp) == Qtrue){
TIMESTAMP_STRUCT *ts;
Data_Get_Struct(arg, TIMESTAMP_STRUCT, ts);
y = INT2NUM(ts->year);
m = INT2NUM(ts->month);
d = INT2NUM(ts->day);
mkdate:
return rb_funcall(rb_cDate, IDnew, 3, y, m, d);
}
if ((!once) &&
(((m = date_load1(Cdate, arg, -1)) != Qnil) ||
((m = timestamp_load1(Ctimestamp, arg, -1)) != Qnil))) {
arg = m;
once++;
goto again;
}
rb_raise(rb_eTypeError, "expecting ODBC::Date/Timestamp or String");
return Qnil;
}
static VALUE
mod_trace(int argc, VALUE *argv, VALUE self)
{
VALUE v = Qnil;
rb_scan_args(argc, argv, "01", &v);
#ifdef TRACING
if (argc > 0) {
tracing = NUM2INT(v);
}
return INT2NUM(tracing);
#else
return INT2NUM(0);
#endif
}
/*
*----------------------------------------------------------------------
*
* Table of constants and intern'ed string mappings.
*
*----------------------------------------------------------------------
*/
#define O_CONST(x) { #x, x }
#define O_CONSTU(x) { #x, SQL_UNKNOWN_TYPE }
#define O_CONST2(x,y) { #x, y }
#define O_CONST_END { NULL, -1 }
static struct {
const char *name;
int value;
} o_const[] = {
O_CONST(SQL_CURSOR_FORWARD_ONLY),
O_CONST(SQL_CURSOR_KEYSET_DRIVEN),
O_CONST(SQL_CURSOR_DYNAMIC),
O_CONST(SQL_CURSOR_STATIC),
O_CONST(SQL_CONCUR_READ_ONLY),
O_CONST(SQL_CONCUR_LOCK),
O_CONST(SQL_CONCUR_ROWVER),
O_CONST(SQL_CONCUR_VALUES),
O_CONST(SQL_FETCH_NEXT),
O_CONST(SQL_FETCH_FIRST),
O_CONST(SQL_FETCH_LAST),
O_CONST(SQL_FETCH_PRIOR),
O_CONST(SQL_FETCH_ABSOLUTE),
O_CONST(SQL_FETCH_RELATIVE),
O_CONST(SQL_UNKNOWN_TYPE),
O_CONST(SQL_CHAR),
O_CONST(SQL_NUMERIC),
O_CONST(SQL_DECIMAL),
O_CONST(SQL_INTEGER),
O_CONST(SQL_SMALLINT),
O_CONST(SQL_FLOAT),
O_CONST(SQL_REAL),
O_CONST(SQL_DOUBLE),
O_CONST(SQL_VARCHAR),
#ifdef SQL_DATETIME
O_CONST(SQL_DATETIME),
#else
O_CONSTU(SQL_DATETIME),
#endif
#ifdef SQL_DATE
O_CONST(SQL_DATE),
#else
O_CONSTU(SQL_DATE),
#endif
#ifdef SQL_TYPE_DATE
O_CONST(SQL_TYPE_DATE),
#else
O_CONSTU(SQL_TYPE_DATE),
#endif
#ifdef SQL_TIME
O_CONST(SQL_TIME),
#else
O_CONSTU(SQL_TIME),
#endif
#ifdef SQL_TYPE_TIME
O_CONST(SQL_TYPE_TIME),
#else
O_CONSTU(SQL_TYPE_TIME),
#endif
#ifdef SQL_TIMESTAMP
O_CONST(SQL_TIMESTAMP),
#else
O_CONSTU(SQL_TIMESTAMP),
#endif
#ifdef SQL_TYPE_TIMESTAMP
O_CONST(SQL_TYPE_TIMESTAMP),
#else
O_CONSTU(SQL_TYPE_TIMESTAMP),
#endif
#ifdef SQL_LONGVARCHAR
O_CONST(SQL_LONGVARCHAR),
#else
O_CONSTU(SQL_LONGVARCHAR),
#endif
#ifdef SQL_BINARY
O_CONST(SQL_BINARY),
#else
O_CONSTU(SQL_BINARY),
#endif
#ifdef SQL_VARBINARY
O_CONST(SQL_VARBINARY),
#else
O_CONSTU(SQL_VARBINARY),
#endif
#ifdef SQL_LONGVARBINARY
O_CONST(SQL_LONGVARBINARY),
#else
O_CONSTU(SQL_LONGVARBINARY),
#endif
#ifdef SQL_BIGINT
O_CONST(SQL_BIGINT),
#else
O_CONSTU(SQL_BIGINT),
#endif
#ifdef SQL_TINYINT
O_CONST(SQL_TINYINT),
#else
O_CONSTU(SQL_TINYINT),
#endif
#ifdef SQL_BIT
O_CONST(SQL_BIT),
#else
O_CONSTU(SQL_BIT),
#endif
#ifdef SQL_GUID
O_CONST(SQL_GUID),
#else
O_CONSTU(SQL_GUID),
#endif
#ifdef SQL_WCHAR
O_CONST(SQL_WCHAR),
#else
O_CONSTU(SQL_WCHAR),
#endif
#ifdef SQL_WVARCHAR
O_CONST(SQL_WVARCHAR),
#else
O_CONSTU(SQL_WVARCHAR),
#endif
#ifdef SQL_WLONGVARCHAR
O_CONST(SQL_WLONGVARCHAR),
#else
O_CONSTU(SQL_WLONGVARCHAR),
#endif
#ifdef SQL_ATTR_ODBC_VERSION
O_CONST(SQL_OV_ODBC2),
O_CONST(SQL_OV_ODBC3),
#else
O_CONST2(SQL_OV_ODBC2, 2),
O_CONST2(SQL_OV_ODBC3, 3),
#endif
#ifdef SQL_ATTR_CONNECTION_POOLING
#ifdef SQL_CP_OFF
O_CONST(SQL_CP_OFF),
#else
O_CONST2(SQL_CP_OFF, 0),
#endif
#ifdef SQL_CP_ONE_PER_DRIVER
O_CONST(SQL_CP_ONE_PER_DRIVER),
#else
O_CONST2(SQL_CP_ONE_PER_DRIVER, 1),
#endif
#ifdef SQL_CP_ONE_PER_HENV
O_CONST(SQL_CP_ONE_PER_HENV),
#else
O_CONST2(SQL_CP_ONE_PER_HENV, 2),
#endif
#ifdef SQL_CP_DEFAULT
O_CONST(SQL_CP_DEFAULT),
#else
O_CONST2(SQL_CP_DEFAULT, 0),
#endif
#else
O_CONST2(SQL_CP_OFF, 0),
O_CONST2(SQL_CP_ONE_PER_DRIVER, 0),
O_CONST2(SQL_CP_ONE_PER_HENV, 0),
O_CONST2(SQL_CP_DEFAULT, 0),
#endif
#ifdef SQL_ATTR_CP_MATCH
O_CONST(SQL_CP_STRICT_MATCH),
O_CONST(SQL_CP_RELAXED_MATCH),
O_CONST(SQL_CP_MATCH_DEFAULT),
#else
O_CONST2(SQL_CP_STRICT_MATCH, 0),
O_CONST2(SQL_CP_RELAXED_MATCH, 0),
O_CONST2(SQL_CP_MATCH_DEFAULT, 0),
#endif
#ifdef SQL_SCOPE_CURROW
O_CONST(SQL_SCOPE_CURROW),
#else
O_CONST2(SQL_SCOPE_CURROW, 0),
#endif
#ifdef SQL_SCOPE_TRANSACTION
O_CONST(SQL_SCOPE_TRANSACTION),
#else
O_CONST2(SQL_SCOPE_TRANSACTION, 0),
#endif
#ifdef SQL_SCOPE_SESSION
O_CONST(SQL_SCOPE_SESSION),
#else
O_CONST2(SQL_SCOPE_SESSION, 0),
#endif
#ifdef SQL_BEST_ROWID
O_CONST(SQL_BEST_ROWID),
#else
O_CONST2(SQL_BEST_ROWID, 0),
#endif
#ifdef SQL_ROWVER
O_CONST(SQL_ROWVER),
#else
O_CONST2(SQL_ROWVER, 0),
#endif
O_CONST(SQL_PARAM_TYPE_UNKNOWN),
O_CONST(SQL_PARAM_INPUT),
O_CONST(SQL_PARAM_OUTPUT),
O_CONST(SQL_PARAM_INPUT_OUTPUT),
O_CONST(SQL_DEFAULT_PARAM),
O_CONST(SQL_RETURN_VALUE),
O_CONST(SQL_RESULT_COL),
O_CONST(SQL_PT_UNKNOWN),
O_CONST(SQL_PT_PROCEDURE),
O_CONST(SQL_PT_FUNCTION),
/* end of table */
O_CONST_END
};
static struct {
ID *idp;
const char *str;
} ids[] = {
{ &IDstart, "start" },
{ &IDatatinfo, "@@info" },
{ &IDataterror, "@@error" },
{ &IDkeys, "keys" },
{ &IDatattrs, "@attrs" },
{ &IDday, "day" },
{ &IDmonth, "month" },
{ &IDyear, "year" },
{ &IDmday, "mday" },
{ &IDnsec, "nsec" },
{ &IDusec, "usec" },
{ &IDsec, "sec" },
{ &IDmin, "min" },
{ &IDhour, "hour" },
{ &IDusec, "usec" },
{ &IDkeyp, "key?" },
{ &IDkey, "key" },
{ &IDSymbol, "Symbol" },
{ &IDString, "String" },
{ &IDFixnum, "Fixnum" },
{ &IDtable_names, "table_names" },
{ &IDnew, "new" },
{ &IDnow, "now" },
{ &IDlocal, "local" },
{ &IDname, "name" },
{ &IDtable, "table" },
{ &IDtype, "type" },
{ &IDlength, "length" },
{ &IDnullable, "nullable" },
{ &IDscale, "scale" },
{ &IDprecision, "precision" },
{ &IDsearchable, "searchable" },
{ &IDunsigned, "unsigned" },
{ &IDiotype, "iotype" },
{ &IDoutput_size, "output_size" },
{ &IDoutput_type, "output_type" },
{ &IDdescr, "descr" },
{ &IDstatement, "statement" },
{ &IDreturn_output_param, "return_output_param" },
{ &IDattrs, "attrs" },
{ &IDNULL, "NULL" },
{ &IDdefault, "default" },
#ifdef USE_RB_ENC
{ &IDencode, "encode" },
#endif
{ &IDparse, "parse" },
{ &IDutc, "utc" },
{ &IDlocal, "local" },
{ &IDto_s, "to_s" }
};
/*
*----------------------------------------------------------------------
*
* Module initializer.
*
*----------------------------------------------------------------------
*/
void
#ifdef UNICODE
Init_odbc_utf8()
#else
Init_odbc()
#endif
{
int i;
const char *modname = "ODBC";
ID modid = rb_intern(modname);
VALUE v = Qnil;
rb_require("date");
rb_cDate = rb_eval_string("Date");
if (rb_const_defined(rb_cObject, modid)) {
v = rb_const_get(rb_cObject, modid);
if (TYPE(v) != T_MODULE) {
rb_raise(rb_eTypeError, "%s already defined", modname);
}
}
if (v != Qnil) {
#ifdef UNICODE
modname = "ODBC_UTF8";
#else
modname = "ODBC_NONE";
#endif
}
for (i = 0; i < (int) (sizeof (ids) / sizeof (ids[0])); i++) {
*(ids[i].idp) = rb_intern(ids[i].str);
}
Modbc = rb_define_module(modname);
Cobj = rb_define_class_under(Modbc, "Object", rb_cObject);
rb_define_class_variable(Cobj, "@@error", Qnil);
rb_define_class_variable(Cobj, "@@info", Qnil);
Cenv = rb_define_class_under(Modbc, "Environment", Cobj);
Cdbc = rb_define_class_under(Modbc, "Database", Cenv);
Cstmt = rb_define_class_under(Modbc, "Statement", Cdbc);
rb_include_module(Cstmt, rb_mEnumerable);
Ccolumn = rb_define_class_under(Modbc, "Column", Cobj);
rb_attr(Ccolumn, IDname, 1, 0, Qfalse);
rb_attr(Ccolumn, IDtable, 1, 0, Qfalse);
rb_attr(Ccolumn, IDtype, 1, 0, Qfalse);
rb_attr(Ccolumn, IDlength, 1, 0, Qfalse);
rb_attr(Ccolumn, IDnullable, 1, 0, Qfalse);
rb_attr(Ccolumn, IDscale, 1, 0, Qfalse);
rb_attr(Ccolumn, IDprecision, 1, 0, Qfalse);
rb_attr(Ccolumn, IDsearchable, 1, 0, Qfalse);
rb_attr(Ccolumn, IDunsigned, 1, 0, Qfalse);
Cparam = rb_define_class_under(Modbc, "Parameter", Cobj);
rb_attr(Cparam, IDtype, 1, 0, Qfalse);
rb_attr(Cparam, IDprecision, 1, 0, Qfalse);
rb_attr(Cparam, IDscale, 1, 0, Qfalse);
rb_attr(Cparam, IDnullable, 1, 0, Qfalse);
rb_attr(Cparam, IDiotype, 1, 0, Qfalse);
rb_attr(Cparam, IDoutput_size, 1, 0, Qfalse);
rb_attr(Cparam, IDoutput_type, 1, 0, Qfalse);
Cdsn = rb_define_class_under(Modbc, "DSN", Cobj);
rb_attr(Cdsn, IDname, 1, 1, Qfalse);
rb_attr(Cdsn, IDdescr, 1, 1, Qfalse);
Cdrv = rb_define_class_under(Modbc, "Driver", Cobj);
rb_attr(Cdrv, IDname, 1, 1, Qfalse);
rb_attr(Cdrv, IDattrs, 1, 1, Qfalse);
Cerror = rb_define_class_under(Modbc, "Error", rb_eStandardError);
Cproc = rb_define_class("ODBCProc", rb_cProc);
Cdate = rb_define_class_under(Modbc, "Date", Cobj);
rb_include_module(Cdate, rb_mComparable);
Ctime = rb_define_class_under(Modbc, "Time", Cobj);
rb_include_module(Ctime, rb_mComparable);
Ctimestamp = rb_define_class_under(Modbc, "TimeStamp", Cobj);
rb_include_module(Ctimestamp, rb_mComparable);
/* module functions */
rb_define_module_function(Modbc, "trace", mod_trace, -1);
rb_define_module_function(Modbc, "trace=", mod_trace, -1);
rb_define_module_function(Modbc, "connect", mod_connect, -1);
rb_define_module_function(Modbc, "datasources", dbc_dsns, 0);
rb_define_module_function(Modbc, "drivers", dbc_drivers, 0);
rb_define_module_function(Modbc, "error", dbc_error, 0);
rb_define_module_function(Modbc, "info", dbc_warn, 0);
rb_define_module_function(Modbc, "clear_error", dbc_clrerror, 0);
rb_define_module_function(Modbc, "newenv", env_new, 0);
rb_define_module_function(Modbc, "to_time", mod_2time, -1);
rb_define_module_function(Modbc, "to_date", mod_2date, 1);
rb_define_module_function(Modbc, "connection_pooling", env_cpooling, -1);
rb_define_module_function(Modbc, "connection_pooling=", env_cpooling, -1);
rb_define_module_function(Modbc, "raise", dbc_raise, 1);
/* singleton methods and constructors */
rb_define_singleton_method(Cobj, "error", dbc_error, 0);
rb_define_singleton_method(Cobj, "info", dbc_warn, 0);
rb_define_singleton_method(Cobj, "clear_error", dbc_clrerror, 0);
rb_define_singleton_method(Cobj, "raise", dbc_raise, 1);
rb_define_alloc_func(Cenv, env_new);
rb_define_singleton_method(Cenv, "connect", dbc_new, -1);
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
rb_define_alloc_func(Cdbc, dbc_alloc);
#else
rb_define_alloc_func(Cdbc, dbc_new);
rb_define_alloc_func(Cdsn, dsn_new);
rb_define_alloc_func(Cdrv, drv_new);
#endif
rb_define_method(Cdsn, "initialize", dsn_init, 0);
rb_define_method(Cdrv, "initialize", drv_init, 0);
rb_define_method(Cdbc, "newstmt", stmt_new, 0);
/* common (Cobj) methods */
rb_define_method(Cobj, "error", dbc_error, 0);
rb_define_method(Cobj, "info", dbc_warn, 0);
rb_define_method(Cobj, "clear_error", dbc_clrerror, 0);
rb_define_method(Cobj, "raise", dbc_raise, 1);
/* common (Cenv) methods */
rb_define_method(Cenv, "connect", dbc_new, -1);
rb_define_method(Cenv, "environment", env_of, 0);
rb_define_method(Cenv, "transaction", dbc_transaction, 0);
rb_define_method(Cenv, "commit", dbc_commit, 0);
rb_define_method(Cenv, "rollback", dbc_rollback, 0);
rb_define_method(Cenv, "connection_pooling", env_cpooling, -1);
rb_define_method(Cenv, "connection_pooling=", env_cpooling, -1);
rb_define_method(Cenv, "cp_match", env_cpmatch, -1);
rb_define_method(Cenv, "cp_match=", env_cpmatch, -1);
rb_define_method(Cenv, "odbc_version", env_odbcver, -1);
rb_define_method(Cenv, "odbc_version=", env_odbcver, -1);
/* management things (odbcinst.h) */
rb_define_module_function(Modbc, "add_dsn", dbc_adddsn, -1);
rb_define_module_function(Modbc, "config_dsn", dbc_confdsn, -1);
rb_define_module_function(Modbc, "del_dsn", dbc_deldsn, -1);
rb_define_module_function(Modbc, "write_file_dsn", dbc_wfdsn, -1);
rb_define_module_function(Modbc, "read_file_dsn", dbc_rfdsn, -1);
/* connection (database) methods */
rb_define_method(Cdbc, "initialize", dbc_connect, -1);
rb_define_method(Cdbc, "connect", dbc_connect, -1);
rb_define_method(Cdbc, "connected?", dbc_connected, 0);
rb_define_method(Cdbc, "drvconnect", dbc_drvconnect, 1);
rb_define_method(Cdbc, "drop_all", dbc_dropall, 0);
rb_define_method(Cdbc, "disconnect", dbc_disconnect, -1);
rb_define_method(Cdbc, "tables", dbc_tables, -1);
rb_define_method(Cdbc, "columns", dbc_columns, -1);
rb_define_method(Cdbc, "primary_keys", dbc_primkeys, -1);
rb_define_method(Cdbc, "indexes", dbc_indexes, -1);
rb_define_method(Cdbc, "types", dbc_types, -1);
rb_define_method(Cdbc, "foreign_keys", dbc_forkeys, -1);
rb_define_method(Cdbc, "table_privileges", dbc_tpriv, -1);
rb_define_method(Cdbc, "procedures", dbc_procs, -1);
rb_define_method(Cdbc, "procedure_columns", dbc_proccols, -1);
rb_define_method(Cdbc, "special_columns", dbc_speccols, -1);
rb_define_method(Cdbc, "get_info", dbc_getinfo, -1);
rb_define_method(Cdbc, "prepare", stmt_prep, -1);
rb_define_method(Cdbc, "run", stmt_run, -1);
rb_define_method(Cdbc, "do", stmt_do, -1);
rb_define_method(Cdbc, "proc", stmt_proc, -1);
rb_define_method(Cdbc, "use_time", dbc_timefmt, -1);
rb_define_method(Cdbc, "use_time=", dbc_timefmt, -1);
rb_define_method(Cdbc, "use_utc", dbc_timeutc, -1);
rb_define_method(Cdbc, "use_utc=", dbc_timeutc, -1);
rb_define_method(Cdbc, "use_sql_column_name", dbc_use_scn, -1);
rb_define_method(Cdbc, "use_sql_column_name=", dbc_use_scn, -1);
/* connection options */
rb_define_method(Cdbc, "get_option", dbc_getsetoption, -1);
rb_define_method(Cdbc, "set_option", dbc_getsetoption, -1);
rb_define_method(Cdbc, "autocommit", dbc_autocommit, -1);
rb_define_method(Cdbc, "autocommit=", dbc_autocommit, -1);
rb_define_method(Cdbc, "concurrency", dbc_concurrency, -1);
rb_define_method(Cdbc, "concurrency=", dbc_concurrency, -1);
rb_define_method(Cdbc, "maxrows", dbc_maxrows, -1);
rb_define_method(Cdbc, "maxrows=", dbc_maxrows, -1);
rb_define_method(Cdbc, "timeout", dbc_timeout, -1);
rb_define_method(Cdbc, "timeout=", dbc_timeout, -1);
rb_define_method(Cdbc, "maxlength", dbc_maxlength, -1);
rb_define_method(Cdbc, "maxlength=", dbc_maxlength, -1);
rb_define_method(Cdbc, "rowsetsize", dbc_rowsetsize, -1);
rb_define_method(Cdbc, "cursortype", dbc_cursortype, -1);
rb_define_method(Cdbc, "cursortype=", dbc_cursortype, -1);
rb_define_method(Cdbc, "noscan", dbc_noscan, -1);
rb_define_method(Cdbc, "noscan=", dbc_noscan, -1);
rb_define_method(Cdbc, "ignorecase", stmt_ignorecase, -1);
rb_define_method(Cdbc, "ignorecase=", stmt_ignorecase, -1);
/* statement methods */
rb_define_method(Cstmt, "drop", stmt_drop, 0);
rb_define_method(Cstmt, "close", stmt_close, 0);
rb_define_method(Cstmt, "cancel", stmt_cancel, 0);
rb_define_method(Cstmt, "column", stmt_column, -1);
rb_define_method(Cstmt, "columns", stmt_columns, -1);
rb_define_method(Cstmt, "parameter", stmt_param, -1);
rb_define_method(Cstmt, "parameters", stmt_params, 0);
rb_define_method(Cstmt, "param_type", stmt_param_type, -1);
rb_define_method(Cstmt, "param_iotype", stmt_param_iotype, -1);
rb_define_method(Cstmt, "param_output_size", stmt_param_output_size, -1);
rb_define_method(Cstmt, "param_output_type", stmt_param_output_type, -1);
rb_define_method(Cstmt, "param_output_value", stmt_param_output_value, -1);
rb_define_method(Cstmt, "ncols", stmt_ncols, 0);
rb_define_method(Cstmt, "nrows", stmt_nrows, 0);
rb_define_method(Cstmt, "nparams", stmt_nparams, 0);
rb_define_method(Cstmt, "cursorname", stmt_cursorname, -1);
rb_define_method(Cstmt, "cursorname=", stmt_cursorname, -1);
rb_define_method(Cstmt, "fetch", stmt_fetch, 0);
rb_define_method(Cstmt, "fetch!", stmt_fetch_bang, 0);
rb_define_method(Cstmt, "fetch_first", stmt_fetch_first, 0);
rb_define_method(Cstmt, "fetch_first!", stmt_fetch_first_bang, 0);
rb_define_method(Cstmt, "fetch_scroll", stmt_fetch_scroll, -1);
rb_define_method(Cstmt, "fetch_scroll!", stmt_fetch_scroll_bang, -1);
rb_define_method(Cstmt, "fetch_hash", stmt_fetch_hash, -1);
rb_define_method(Cstmt, "fetch_hash!", stmt_fetch_hash_bang, -1);
rb_define_method(Cstmt, "fetch_first_hash", stmt_fetch_first_hash, 0);
rb_define_method(Cstmt, "fetch_many", stmt_fetch_many, 1);
rb_define_method(Cstmt, "fetch_all", stmt_fetch_all, 0);
rb_define_method(Cstmt, "each", stmt_each, 0);
rb_define_method(Cstmt, "each_hash", stmt_each_hash, -1);
rb_define_method(Cstmt, "execute", stmt_exec, -1);
rb_define_method(Cstmt, "make_proc", stmt_procwrap, -1);
rb_define_method(Cstmt, "more_results", stmt_more_results, 0);
rb_define_method(Cstmt, "prepare", stmt_prep, -1);
rb_define_method(Cstmt, "run", stmt_run, -1);
rb_define_singleton_method(Cstmt, "make_proc", stmt_procwrap, -1);
/* statement options */
rb_define_method(Cstmt, "get_option", stmt_getsetoption, -1);
rb_define_method(Cstmt, "set_option", stmt_getsetoption, -1);
rb_define_method(Cstmt, "concurrency", stmt_concurrency, -1);
rb_define_method(Cstmt, "concurrency=", stmt_concurrency, -1);
rb_define_method(Cstmt, "maxrows", stmt_maxrows, -1);
rb_define_method(Cstmt, "maxrows=", stmt_maxrows, -1);
rb_define_method(Cstmt, "timeout", stmt_timeout, -1);
rb_define_method(Cstmt, "timeout=", stmt_timeout, -1);
rb_define_method(Cstmt, "maxlength", stmt_maxlength, -1);
rb_define_method(Cstmt, "maxlength=", stmt_maxlength, -1);
rb_define_method(Cstmt, "cursortype", stmt_cursortype, -1);
rb_define_method(Cstmt, "cursortype=", stmt_cursortype, -1);
rb_define_method(Cstmt, "noscan", stmt_noscan, -1);
rb_define_method(Cstmt, "noscan=", stmt_noscan, -1);
rb_define_method(Cstmt, "rowsetsize", stmt_rowsetsize, -1);
/* data type methods */
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
rb_define_alloc_func(Cdate, date_alloc);
#else
rb_define_singleton_method(Cdate, "new", date_new, -1);
#endif
rb_define_singleton_method(Cdate, "_load", date_load, 1);
rb_define_method(Cdate, "initialize", date_init, -1);
rb_define_method(Cdate, "clone", date_clone, 0);
rb_define_method(Cdate, "to_s", date_to_s, 0);
rb_define_method(Cdate, "_dump", date_dump, 1);
rb_define_method(Cdate, "inspect", date_inspect, 0);
rb_define_method(Cdate, "year", date_year, -1);
rb_define_method(Cdate, "month", date_month, -1);
rb_define_method(Cdate, "day", date_day, -1);
rb_define_method(Cdate, "year=", date_year, -1);
rb_define_method(Cdate, "month=", date_month, -1);
rb_define_method(Cdate, "day=", date_day, -1);
rb_define_method(Cdate, "<=>", date_cmp, 1);
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
rb_define_alloc_func(Ctime, time_alloc);
#else
rb_define_singleton_method(Ctime, "new", time_new, -1);
#endif
rb_define_singleton_method(Ctime, "_load", time_load, 1);
rb_define_method(Ctime, "initialize", time_init, -1);
rb_define_method(Ctime, "clone", time_clone, 0);
rb_define_method(Ctime, "to_s", time_to_s, 0);
rb_define_method(Ctime, "_dump", time_dump, 1);
rb_define_method(Ctime, "inspect", time_inspect, 0);
rb_define_method(Ctime, "hour", time_hour, -1);
rb_define_method(Ctime, "minute", time_min, -1);
rb_define_method(Ctime, "second", time_sec, -1);
rb_define_method(Ctime, "hour=", time_hour, -1);
rb_define_method(Ctime, "minute=", time_min, -1);
rb_define_method(Ctime, "second=", time_sec, -1);
rb_define_method(Ctime, "<=>", time_cmp, 1);
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
rb_define_alloc_func(Ctimestamp, timestamp_alloc);
#else
rb_define_singleton_method(Ctimestamp, "new", timestamp_new, -1);
#endif
rb_define_singleton_method(Ctimestamp, "_load", timestamp_load, 1);
rb_define_method(Ctimestamp, "initialize", timestamp_init, -1);
rb_define_method(Ctimestamp, "clone", timestamp_clone, 0);
rb_define_method(Ctimestamp, "to_s", timestamp_to_s, 0);
rb_define_method(Ctimestamp, "_dump", timestamp_dump, 1);
rb_define_method(Ctimestamp, "inspect", timestamp_inspect, 0);
rb_define_method(Ctimestamp, "year", timestamp_year, -1);
rb_define_method(Ctimestamp, "month", timestamp_month, -1);
rb_define_method(Ctimestamp, "day", timestamp_day, -1);
rb_define_method(Ctimestamp, "hour", timestamp_hour, -1);
rb_define_method(Ctimestamp, "minute", timestamp_min, -1);
rb_define_method(Ctimestamp, "second", timestamp_sec, -1);
rb_define_method(Ctimestamp, "fraction", timestamp_fraction, -1);
rb_define_method(Ctimestamp, "year=", timestamp_year, -1);
rb_define_method(Ctimestamp, "month=", timestamp_month, -1);
rb_define_method(Ctimestamp, "day=", timestamp_day, -1);
rb_define_method(Ctimestamp, "hour=", timestamp_hour, -1);
rb_define_method(Ctimestamp, "minute=", timestamp_min, -1);
rb_define_method(Ctimestamp, "second=", timestamp_sec, -1);
rb_define_method(Ctimestamp, "fraction=", timestamp_fraction, -1);
rb_define_method(Ctimestamp, "<=>", timestamp_cmp, 1);
/* procedure methods */
rb_define_method(Cproc, "initialize", stmt_proc_init, -1);
rb_define_method(Cproc, "call", stmt_proc_call, -1);
rb_define_method(Cproc, "[]", stmt_proc_call, -1);
rb_attr(Cproc, IDstatement, 1, 0, Qfalse);
rb_attr(Cproc, IDreturn_output_param, 1, 0, Qfalse);
#ifndef HAVE_RB_DEFINE_ALLOC_FUNC
rb_enable_super(Cproc, "call");
rb_enable_super(Cproc, "[]");
#endif
/* constants */
for (i = 0; o_const[i].name != NULL; i++) {
rb_define_const(Modbc, o_const[i].name,
INT2NUM(o_const[i].value));
}
for (i = 0; get_info_map[i].name != NULL; i++) {
rb_define_const(Modbc, get_info_map[i].name,
INT2NUM(get_info_map[i].info));
}
for (i = 0; get_info_bitmap[i].name != NULL; i++) {
rb_define_const(Modbc, get_info_bitmap[i].name,
INT2NUM(get_info_bitmap[i].bits));
}
for (i = 0; option_map[i].name != NULL; i++) {
rb_define_const(Modbc, option_map[i].name,
INT2NUM(option_map[i].option));
}
#ifdef UNICODE
rb_define_const(Modbc, "UTF8", Qtrue);
#ifdef USE_RB_ENC
rb_enc = rb_utf8_encoding();
rb_encv = rb_enc_from_encoding(rb_enc);
#endif
#else
rb_define_const(Modbc, "UTF8", Qfalse);
#endif
#ifdef TRACING
if (ruby_verbose) {
tracing = -1;
}
#endif
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
* End:
*/
./ruby-odbc-0.99998/ext/init.c 0100644 0000764 0000144 00000011345 10605663302 014371 0 ustar chw users /*
* Part of ODBC-Ruby binding
* Copyright (c) 2006-2007 Christian Werner
*
* See the file "COPYING" for information on usage
* and redistribution of this file and for a
* DISCLAIMER OF ALL WARRANTIES.
*
* $Id: init.c,v 1.6 2007/04/07 09:39:08 chw Exp chw $
*/
#include "ruby.h"
#ifdef USE_DLOPEN_FOR_ODBC_LIBS
/*
* This module acts as a drop-in replacement for linking with
* "-lodbc -lodbcinst" or "-liodbc -liodbcinst" when dlopen()
* is supported.
*
* Setting the environment variable RUBY_ODBC_DM can be used
* to force loading a specific driver manager shared library.
* Same logic is used with RUBY_ODBC_INST for the ODBC installer
* shared library.
*/
#include
/* Create weak alias and function declarations. */
#define WEAKFUNC(name) \
int __attribute__((weak, alias("__"#name))) name (void); \
static int __attribute__((unused)) __ ## name (void) \
{ return -1; /* == SQL_ERROR */ }
#define WEAKFUNC_BOOL(name) \
int __attribute__((weak, alias("__"#name))) name (void); \
static int __attribute__((unused)) __ ## name (void) \
{ return 0; /* == BOOL/FALSE */ }
WEAKFUNC(SQLAllocConnect)
WEAKFUNC(SQLAllocEnv)
WEAKFUNC(SQLAllocStmt)
WEAKFUNC(SQLBindParameter)
WEAKFUNC(SQLCancel)
WEAKFUNC(SQLDescribeParam)
WEAKFUNC(SQLDisconnect)
WEAKFUNC(SQLExecute)
WEAKFUNC(SQLFetch)
WEAKFUNC(SQLFetchScroll)
WEAKFUNC(SQLFreeConnect)
WEAKFUNC(SQLFreeEnv)
WEAKFUNC(SQLFreeStmt)
WEAKFUNC(SQLGetData)
WEAKFUNC(SQLGetEnvAttr)
WEAKFUNC(SQLGetStmtOption)
WEAKFUNC(SQLMoreResults)
WEAKFUNC(SQLNumParams)
WEAKFUNC(SQLNumResultCols)
WEAKFUNC(SQLRowCount)
WEAKFUNC(SQLSetEnvAttr)
WEAKFUNC(SQLSetStmtOption)
WEAKFUNC(SQLTransact)
WEAKFUNC(SQLEndTran)
WEAKFUNC(SQLColAttributes)
WEAKFUNC(SQLColAttributesW)
WEAKFUNC(SQLColumns)
WEAKFUNC(SQLColumnsW)
WEAKFUNC(SQLConnect)
WEAKFUNC(SQLConnectW)
WEAKFUNC(SQLDataSources)
WEAKFUNC(SQLDataSourcesW)
WEAKFUNC(SQLDriverConnect)
WEAKFUNC(SQLDriverConnectW)
WEAKFUNC(SQLDrivers)
WEAKFUNC(SQLDriversW)
WEAKFUNC(SQLError)
WEAKFUNC(SQLErrorW)
WEAKFUNC(SQLExecDirect)
WEAKFUNC(SQLExecDirectW)
WEAKFUNC(SQLForeignKeys)
WEAKFUNC(SQLForeignKeysW)
WEAKFUNC(SQLGetConnectOption)
WEAKFUNC(SQLGetConnectOptionW)
WEAKFUNC(SQLGetCursorName)
WEAKFUNC(SQLGetCursorNameW)
WEAKFUNC(SQLGetInfo)
WEAKFUNC(SQLGetInfoW)
WEAKFUNC(SQLGetTypeInfo)
WEAKFUNC(SQLGetTypeInfoW)
WEAKFUNC(SQLPrepare)
WEAKFUNC(SQLPrepareW)
WEAKFUNC(SQLPrimaryKeys)
WEAKFUNC(SQLPrimaryKeysW)
WEAKFUNC(SQLProcedureColumns)
WEAKFUNC(SQLProcedureColumnsW)
WEAKFUNC(SQLProcedures)
WEAKFUNC(SQLProceduresW)
WEAKFUNC(SQLSetConnectOption)
WEAKFUNC(SQLSetConnectOptionW)
WEAKFUNC(SQLSetCursorName)
WEAKFUNC(SQLSetCursorNameW)
WEAKFUNC(SQLSpecialColumns)
WEAKFUNC(SQLSpecialColumnsW)
WEAKFUNC(SQLStatistics)
WEAKFUNC(SQLStatisticsW)
WEAKFUNC(SQLTablePrivileges)
WEAKFUNC(SQLTablePrivilegesW)
WEAKFUNC(SQLTables)
WEAKFUNC(SQLTablesW)
WEAKFUNC(SQLInstallerError)
WEAKFUNC(SQLInstallerErrorW)
WEAKFUNC_BOOL(SQLConfigDataSource)
WEAKFUNC_BOOL(SQLConfigDataSourceW)
WEAKFUNC_BOOL(SQLReadFileDSN)
WEAKFUNC_BOOL(SQLReadFileDSNW)
WEAKFUNC_BOOL(SQLWriteFileDSN)
WEAKFUNC_BOOL(SQLWriteFileDSNW)
/* Library initializer and finalizer. */
static void *lib_odbc = 0;
static void *lib_odbcinst = 0;
#define warn(msg) fputs(msg, stderr)
void
ruby_odbc_init()
{
int useiodbc = 0;
char *dm_name = getenv("RUBY_ODBC_DM");
char *inst_name = getenv("RUBY_ODBC_INST");
if (dm_name) {
lib_odbc = dlopen(dm_name, RTLD_NOW | RTLD_GLOBAL);
if (!lib_odbc) {
warn("WARNING: $RUBY_ODBC_DM not loaded.\n");
} else {
if (inst_name) {
lib_odbcinst = dlopen(inst_name, RTLD_NOW | RTLD_GLOBAL);
}
if (!lib_odbcinst) {
warn("WARNING: $RUBY_ODBC_INST not loaded.\n");
}
return;
}
}
lib_odbc = dlopen("libodbc" DLEXT ".1", RTLD_NOW | RTLD_GLOBAL);
if (!lib_odbc) {
lib_odbc = dlopen("libodbc" DLEXT, RTLD_NOW | RTLD_GLOBAL);
}
if (!lib_odbc) {
lib_odbc = dlopen("libiodbc" DLEXT ".2", RTLD_NOW | RTLD_GLOBAL);
if (!lib_odbc) {
lib_odbc = dlopen("libiodbc" DLEXT, RTLD_NOW | RTLD_GLOBAL);
}
if (!lib_odbc) {
warn("WARNING: no ODBC driver manager found.\n");
return;
}
useiodbc = 1;
}
lib_odbcinst = dlopen(useiodbc ?
"libiodbcinst" DLEXT ".2" : "libodbcinst" DLEXT ".1",
RTLD_NOW | RTLD_GLOBAL);
if (!lib_odbcinst) {
lib_odbcinst = dlopen(useiodbc ?
"libiodbcinst" DLEXT : "libodbcinst" DLEXT,
RTLD_NOW | RTLD_GLOBAL);
}
if (!lib_odbcinst) {
warn("WARNING: no ODBC installer library found.\n");
}
}
void
ruby_odbc_fini()
{
if (lib_odbcinst) {
dlclose(lib_odbcinst);
lib_odbcinst = 0;
}
if (lib_odbc) {
dlclose(lib_odbc);
lib_odbc = 0;
}
}
int
ruby_odbc_have_func(char *name, void *addr)
{
return name && addr && (dlsym(NULL, name) != addr);
}
#endif
./ruby-odbc-0.99998/lib/ 0040755 0000764 0000144 00000000000 13051023710 013216 5 ustar chw users ./ruby-odbc-0.99998/lib/cqgen.rb 0100644 0000764 0000144 00000040210 10434016545 014644 0 ustar chw users #!/usr/bin/env ruby
#
# cqgen.rb - Poor man's C code generator to automatically
# make access wrappers for ODBC datasources.
#
# -------------------------------------------------------------------
# This file is part of "ODBC-Ruby binding"
#
# Copyright (c) 2006 Christian Werner
#
# See the file "COPYING" for information on usage
# and redistribution of this file and for a
# DISCLAIMER OF ALL WARRANTIES.
# -------------------------------------------------------------------
#
# Pre-requisites:
#
# * Ruby 1.6 or 1.8
# * Ruby/ODBC >= 0.996
# * Acesss to a ODBC datasource with properly
# loaded schema for the wrappers to generate
#
# -------------------------------------------------------------------
#
# Functions in this module
#
# cqgen DSName, UID, PWD, CFName, SQL, [ParmTypes, ParmNames]
#
# DSName: name of datasource to connect
# UID: user name on datasource
# PWD: password on datasource
# CFName: name for C function
# SQL: SQL text of one query yielding
# one result set
# ParmTypes: (optional, array) types for
# query parameters
# ParmNames: (optional, array) names for
# query parameters
#
# use this function to make C code for
# SELECT/UPDATE/DELETE/INSERT SQL statements.
# The "ParmTypes" is useful since many ODBC drivers
# cannot return the proper types in SQLDescribeParam().
#
# cqgen_test
# append test functions and skeleton test main()
# to end of C file
#
#
# cqgen_output c_name, h_name
# write C source code, 'c_name' for functions,
# 'h_name' for optional header file
#
# -------------------------------------------------------------------
#
# Specification file sample
#
# ---BOF---
# require 'cqgen'
# # simple query
# cqgen 'bla', '', '', "GetResults", %q{
# select * from results
# }
# # query with parameters using last DSN
# cqgen nil, nil, nil, "GetResultsGt", %q{
# select * from results where funfactor > ?
# }
# # update with parameters using other DSN
# cqgen 'bla2', '', '', "IncrFunFactor", %q{
# update results set funfactor = ? where funfactor < ?
# }, [ ODBC::SQL_INTEGER, ODBC::SQL_INTEGER ],
# [ "newfunfactor", "maxfunfactor" ]
# cqgen_test
# cqgen_output 'bla_wrap.c'
# ---EOF---
#
# Run this file with a command line like
#
# $ ruby sample-file
# $ cc -c bla_wrap.c
# or
# $ cc -o bla_wrap_test bla_wrap.c -DTEST_cqgen_all -lodbc
#
# Depending on the SQL text, cqgen writes one or more
# C functions and zero or one structure typedefs.
# The structure typedefs are merged when possible,
# thus you should write the least specific queries
# on top of the specification file.
#
# In the sample:
#
# * function GetResults_init to initiate the query
# * function GetResults to retrieve one result row
# * function GetResults_deinit to release resources
# associated with the query
# * struct RESULT_GetResults for representation of
# one result row
#
# * function GetResultsGt_init with one parameter par1
# * macro GetResultsGt aliased to GetResults
# (function reused from 1st query)
# * macro GetResultsGt_deinit aliased to GetResults_deinit
# (function reused from 1st query)
# * struct RESULT_GetResults for representation of
# one result row (struct name reused from 1st query)
#
# * function IncrFunFactor with two parameters named
# "newfunfactor" and "maxfunfactor" and an SQLINTEGER
# reference for the number of affected rows
#
# -------------------------------------------------------------------
require 'odbc'
$cqgen_dsn=nil
$cqgen_uid=nil
$cqgen_pwd=nil
$cqgen_simple_fns=Hash.new
$cqgen_stypes=Hash.new
$cqgen_h1=''
$cqgen_h2=''
$cqgen_c=''
$cqgen_ct1=''
$cqgen_ct2=''
def cqgen(dsn, uid, pwd, name, sql, parmtypes=nil, parmnames=nil)
dsn=$cqgen_dsn if dsn.nil?
uid=$cqgen_uid if uid.nil?
pwd=$cqgen_pwd if pwd.nil?
begin
conn=ODBC::connect(dsn, uid, pwd)
$cqgen_dsn=dsn
$cqgen_uid=uid
$cqgen_pwd=pwd
rescue Exception => err
$stderr.puts("connect for #{name} failed:\n")
$stderr.puts("\t#{err}\n")
return
end
sql = sql.strip
sql = sql.gsub(/[\r\n]+/, " ")
if sql.downcase =~ /where/
sql0=sql + " and 1=0"
else
sql0=sql + " where 1=0"
end
begin
stmt=conn.prepare(sql0)
if stmt.ncols < 1
stmt.execute
end
rescue Exception => err
$stderr.puts("SQL error for #{name}:\n")
$stderr.puts("\t#{err}\n")
return
end
if stmt.ncols > 0
fhead="SQLRETURN\n" + name + "_init(SQLHDBC hdbc, SQLHSTMT *hstmtRet"
fhead2="SQLRETURN\n" + name + "(SQLHSTMT hstmt"
flvars2="{\n SQLRETURN ret;\n INTERNAL_STMT *istmt;\n"
fbody2="\n istmt = (INTERNAL_STMT *) hstmt;\n"
fhead3="SQLRETURN\n" + name + "_deinit(SQLHSTMT hstmt)\n"
flvars3="{\n INTERNAL_STMT *istmt;\n"
fbody3="\n istmt = (INTERNAL_STMT *) hstmt;\n"
fbody3+=" if (istmt != NULL) {\n"
fbody3+="\tSQLFreeStmt(istmt->hstmt, SQL_DROP);\n"
fbody3+="\tfree(istmt);\n"
fbody3+=" }\n return SQL_SUCCESS;\n}\n\n"
else
fhead="SQLRETURN\n" + name + "(SQLHDBC hdbc"
fhead2=""
flvars2=""
fbody2=""
fhead3=""
flvars3=""
fbody3=""
end
flvars="{\n SQLRETURN ret;\n"
if stmt.ncols < 1
flvars+=" SQLHSTMT hstmt;\n"
end
fbody=""
flvarst="{\n SQLRETURN ret;\n"
fheadt="SQLRETURN\n" + name + "_test(SQLHDBC hdbc"
fbodyt=""
if stmt.ncols > 0
flvars+=" INTERNAL_STMT *istmt;\n SQLHSTMT hstmt;\n"
fbody+=" *hstmtRet = hstmt = SQL_NULL_HSTMT;\n"
fbody+=" ret = SQLAllocStmt(hdbc, &hstmt);\n"
fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
fbody+=" istmt = malloc(sizeof (INTERNAL_STMT));\n"
fbody+=" if (istmt == NULL) {\n\tSQLFreeStmt(hstmt, SQL_DROP);\n"
fbody+="\treturn SQL_ERROR;\n }\n"
fbody+=" istmt->hstmt = hstmt;\n"
fbody+=" istmt->result = NULL;\n"
fbody+=" *hstmtRet = (SQLHSTMT) istmt;\n"
flvarst+=" SQLHSTMT hstmt;\n"
fbodyt+=" ret = #{name}_init(hdbc, &hstmt"
else
fbodyt+=" ret = #{name}(hdbc"
end
pnum=1
stmt.parameters.each do |par|
if !parmtypes.nil?
ptype=parmtypes[pnum-1]
end
if ptype.nil?
ptype = par.type
end
if !parmnames.nil?
pname=parmnames[pnum-1]
end
if pname.nil?
pname="par#{pnum}"
end
case ptype
when ODBC::SQL_INTEGER
pdef=", SQLINTEGER *#{pname}"
fbody+=" #{pname}_len = sizeof (SQLINTEGER);\n";
fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
fbody+=" SQL_C_LONG, SQL_INTEGER, #{par.precision}, #{par.scale},"
when ODBC::SQL_SMALLINT
pdef=", SQLSMALLINT *#{pname}"
fbody+=" #{pname}_len = sizeof (SQLSMALLINT);\n";
fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
fbody+=" SQL_C_SHORT, SQL_SMALLINT, #{par.precision}, #{par.scale},"
when ODBC::SQL_FLOAT
pdef=", SQLDOUBLE *#{pname}"
fbody+=" #{pname}_len = sizeof (SQLDOUBLE);\n";
fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
fbody+=" SQL_C_DOUBLE, SQL_FLOAT, #{par.precision}, #{par.scale},"
when ODBC::SQL_DOUBLE
pdef=", SQLDOUBLE *#{pname}"
fbody+=" #{pname}_len = sizeof (SQLDOUBLE);\n";
fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
fbody+=" SQL_C_DOUBLE, SQL_DOUBLE, #{par.precision}, #{par.scale},"
else
pdef=", SQLCHAR *#{pname}"
fbody+=" #{pname}_len = #{pname} ? strlen(#{pname}) : SQL_NULL_DATA;\n";
fbody+=" ret = SQLBindParameter(hstmt, #{pnum}, SQL_PARAM_INPUT,"
fbody+=" SQL_C_CHAR, SQL_CHAR, #{par.precision}, #{par.scale},"
end
fbody+=" #{pname}, #{pname}_len, {pname}_len);\n"
fhead+=pdef
fheadt+=pdef
fbodyt+=", #{pname}"
flvars+=" SQLINTEGER #{pname}_len;\n"
if stmt.ncols > 0
fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
else
fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\tgoto done;\n }\n"
end
pnum+=1
end
fheadt+=")\n"
if stmt.ncols < 1
fbodyt+= ", &rowCount"
end
fbodyt+=");\n"
if stmt.ncols > 0
fbodyt+=" if (!SQL_SUCCEEDED(ret)) {\n"
fbodyt+="\t#{name}_deinit(hstmt);\n\treturn ret;\n }\n"
end
struc=""
istruc=""
if stmt.ncols > 0
if pnum<=1
$cqgen_simple_fns["#{name}_test"]=1
end
fbody+=" ret = SQLPrepare(hstmt, \"#{sql}\", SQL_NTS);\n"
fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
fbody+=" ret = SQLExecute(hstmt);\n"
fbody+=" return ret;\n}\n\n"
struc+="typedef struct {\n"
fbody2+=" hstmt = istmt->hstmt;\n"
fbody2+=" if (result == istmt->result) {\n"
fbody2+="\tgoto doexec;\n }\n"
fbody2+=" istmt->result = NULL;\n"
fbodyt+=" do {\n"
fbodyt+="\tret = #{name}(hstmt, &result);\n"
fbodyt+="\tif (!SQL_SUCCEEDED(ret)) {\n\t break;\n\t}\n"
cols = stmt.columns(1)
coltable = Hash.new
cols.each do |col|
coltable[col.table => 1]
end
cnum=1
cols.each do |col|
if coltable.size > 1
cname=col.table+"_"+col.name
else
cname=col.name
end
case col.type
when ODBC::SQL_INTEGER
istruc+=" SQLLEN #{cname}_len;\n"
istruc+=" SQLINTEGER #{cname};\n"
fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_LONG,"
fbody2+=" &result->#{cname}, sizeof (SQL_C_LONG),"
fbody2+=" &result->#{cname}_len);\n"
when ODBC::SQL_SMALLINT
istruc+=" SQLLEN #{cname}_len;\n"
istruc+=" SQLSMALLINT #{cname};\n"
fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_SMALLINT,"
fbody2+=" &result->#{cname}, sizeof (SQL_C_SMALLINT),"
fbody2+=" &result->#{cname}_len);\n"
when ODBC::SQL_FLOAT
istruc+=" SQLLEN #{cname}_len;\n"
istruc+=" SQLDOUBLE #{cname};\n"
fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_DOUBLE,"
fbody2+=" &result->#{cname}, sizeof (SQLDOUBLE),"
fbody2+=" &result->#{cname}_len);\n"
when ODBC::SQL_DOUBLE
istruc+=" SQLLEN #{cname}_len;\n"
istruc+=" SQLDOUBLE #{cname};\n"
fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_DOUBLE,"
fbody2+=" &result->#{cname}, sizeof (SQL_C_DOUBLE),"
fbody2+=" &result->#{cname}_len);\n"
else
istruc+=" SQLLEN #{cname}_len;\n"
istruc+=" SQLCHAR #{cname}[#{col.length}];\n"
fbody2+=" ret = SQLBindCol(hstmt, #{cnum}, SQL_C_CHAR,"
fbody2+=" result->#{cname}, #{col.length},"
fbody2+=" &result->#{cname}_len);\n"
end
fbody2+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
cnum+=1;
end
sname=$cqgen_stypes[istruc]
if sname.nil?
sname="RESULT_#{name}"
$cqgen_stypes[istruc]=sname
addstruct=true
else
addstruct=false
end
struc+="#{istruc}} #{sname};\n\n"
flvarst+=" #{sname} result;\n\n"
if addstruct
fhead2+=", #{sname} *result"
else
fbody2=""
flvars2=""
fbody3=""
flvars3=""
fname=sname.gsub(/^RESULT_/, "")
fhead2="#define\t\t#{name}\t#{fname}\n"
fhead3="#define\t\t#{name}_deinit\t#{fname}_deinit\n"
end
cnum=1
cols.each do |col|
if coltable.size > 1
cname=col.table+"_"+col.name
else
cname=col.name
end
case col.type
when ODBC::SQL_INTEGER
fmt='%ld'
when ODBC::SQL_SMALLINT
fmt='%d'
when ODBC::SQL_FLOAT
fmt='%g'
when ODBC::SQL_DOUBLE
fmt='%g'
else
fmt='%s'
end
fbodyt+="\tif (result.#{cname}_len != SQL_NULL_DATA) {\n"
fbodyt+="\t printf(\"#{sname}.#{cname}=#{fmt}\\n\",\n"
fbodyt+="\t\t result.#{cname});\n"
fbodyt+="\t} else {\n"
fbodyt+="\t printf(\"#{sname}.#{cname}=NULL\\n\");\n"
fbodyt+="\t}\n"
cnum+=1;
end
fbodyt+=" } while (SQL_SUCCEEDED(ret));\n"
fbodyt+=" #{name}_deinit(hstmt);\n"
else
fhead+=", SQLINTEGER *rowCountRet"
fbody=" if (!SQL_SUCCEEDED(ret)) {\n\tgoto done;\n }\n" + fbody
fbody=" ret = SQLAllocStmt(hdbc, &hstmt);\n" + fbody
fbody=" *rowCountRet = 0;\n" + fbody
fbody+=" ret = SQLExecDirect(hstmt, "
fbody+='"'+sql+'"'
fbody+=", SQL_NTS);\n"
fbody+=" if (!SQL_SUCCEEDED(ret)) {\n\tgoto done;\n }\n"
fbody+=" ret = SQLRowCount(hstmt, rowCountRet);\ndone:\n"
fbody+=" SQLFreeStmt(hstmt, SQL_DROP);\n return ret;\n}\n\n"
flvarst+=" SQLINTEGER rowCount;\n\n"
fbodyt+=" printf(\"#{name}_test rowCount=%ld\\n\", rowCount);\n"
end
if fbodyt.length > 0
fbodyt+=" return ret;\n"
fbodyt+="}\n"
end
fhead+=")\n"
if fbody2.length > 0
fhead2+=")\n"
fbody2+="doexec:\n"
fbody2+=" ret = SQLFetch(hstmt);\n"
fbody2+=" if (!SQL_SUCCEEDED(ret)) {\n\treturn ret;\n }\n"
fbody2+=" istmt->result = result;\n"
fbody2+=" return ret;\n}\n\n"
end
flvars+="\n"
stmt.drop
conn.disconnect
sql = sql.gsub(/[ \t]+/, " ")
sql = sql.gsub(/\/\*/, "")
sql = sql.gsub(/\*\//, "")
$cqgen_h1+="/* #{sql} */\n" if addstruct
$cqgen_h1+=struc if addstruct
$cqgen_h2+="/* #{sql} */\n"
tmp=fhead.gsub(/SQLRETURN\n/, "SQLRETURN\t");
$cqgen_h2+=tmp.gsub(/\)\n/, ");\n")
if fhead2.length > 0
tmp=fhead2.gsub(/SQLRETURN\n/, "SQLRETURN\t");
$cqgen_h2+=tmp.gsub(/\)\n/, ");\n")
end
if fhead3.length > 0
tmp=fhead3.gsub(/SQLRETURN\n/, "SQLRETURN\t");
$cqgen_h2+=tmp.gsub(/\)\n/, ");\n")
end
$cqgen_h2+="\n"
$cqgen_c+=fhead
$cqgen_c+=flvars
$cqgen_c+=fbody
$cqgen_c+=fhead2 unless fhead2 =~ /^#define/
$cqgen_c+=flvars2
$cqgen_c+=fbody2
$cqgen_c+=fhead3 unless fhead3 =~ /^#define/
$cqgen_c+=flvars3
$cqgen_c+=fbody3
$cqgen_ct1+="#if defined(TEST_#{name}) || defined(TEST_cqgen_all)\n"
$cqgen_ct1+=fheadt
$cqgen_ct1+=flvarst
$cqgen_ct1+=fbodyt
$cqgen_ct1+="#endif\n\n"
end
def cqgen_test
$cggen_dsn="" if $cqgen_dsn.nil?
$cggen_uid="" if $cqgen_uid.nil?
$cggen_pwd="" if $cqgen_pwd.nil?
test_calls=""
$cqgen_simple_fns.each_key do |name|
test_calls+=" printf(\"=== #{name} ===\\n\");\n"
test_calls+=" #{name}(hdbc);\n"
end
$cqgen_ct2=$cqgen_ct1
$cqgen_ct2+=%Q{
#ifdef TEST_cqgen_all
int
main(int argc, char **argv)
{
SQLHENV henv;
SQLHDBC hdbc;
SQLRETURN ret;
ret = SQLAllocEnv(&henv);
if (!SQL_SUCCEEDED(ret)) {
exit(1);
}
ret = SQLAllocConnect(henv, &hdbc);
if (!SQL_SUCCEEDED(ret)) {
exit(2);
}
ret = SQLConnect(hdbc,
\"#{$cqgen_dsn}\", SQL_NTS,
\"#{$cqgen_uid}\", SQL_NTS,
\"#{$cqgen_pwd}\", SQL_NTS);
if (!SQL_SUCCEEDED(ret)) {
exit(3);
}
/* ADD YOUR TEST CALLS HERE */
#{test_calls}
SQLDisconnect(hdbc);
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
return 0;
}
#endif
}
end
def cqgen_output(c_name=nil, h_name=nil)
h=''
h+="#include \n"
h+="#include \n"
h+="#include \n"
h+="#include \n"
h+="#include \n"
h+="#include \n\n"
h+=$cqgen_h1
h+="\n"
h+=$cqgen_h2
if c_name.nil?
cf=$stdout
ctoclose=false
else
cf=File::open(c_name, 'w')
ctoclose=true
end
if h_name.nil?
hf=cf
htoclose=false
else
hf=File::open(h_name, 'w')
htoclose=true
hb=File::basename(h_name).gsub(/\W/, "_")
h="#ifndef _#{hb}\n#define _#{hb}\n\n#{h}\n#endif /* _#{hb} */\n"
end
hf.print(h)
c=''
if !h_name.nil? && (hf != cf)
c+="#include \n"
c+="#include \n"
c+="#include \n"
c+="#include \n"
c+="#include \n"
c+="#include \n\n"
c+="#include \"#{h_name}\"\n\n"
end
c+=%Q{
typedef struct {
SQLHSTMT hstmt;
void *result;
} INTERNAL_STMT;
}
c+=$cqgen_c
c+=$cqgen_ct2
cf.print(c)
hf.close if htoclose
cf.close if ctoclose
$cqgen_h1=''
$cqgen_h2=''
$cqgen_c=''
$cqgen_ct1=''
$cqgen_ct2=''
$cqgen_simple_fns.clear
$cqgen_stypes.clear
end
# Run this code only when the file is the main program
if $0 == __FILE__
files=ARGV.flatten
ARGV.clear
files.each do |f|
begin
load f
rescue Exception => err
$stderr.puts("in file #{f}:\n")
$stderr.puts("\t#{err}\n")
end
end
end
./ruby-odbc-0.99998/test/ 0040755 0000764 0000144 00000000000 13051023710 013427 5 ustar chw users ./ruby-odbc-0.99998/test/utf8/ 0040755 0000764 0000144 00000000000 13051023710 014315 5 ustar chw users ./ruby-odbc-0.99998/test/utf8/test.rb 0100644 0000764 0000144 00000001151 12504511740 015623 0 ustar chw users # $Id: test.rb,v 1.4 2015/03/25 10:54:18 chw Exp chw $
#
# Execute in ruby-odbc utf8 directory.
#
# ruby test.rb "mysql-DSN" "mysql-user" "mysql-password"
#
# Test creates and deletes table "test" in that DSN.
require 'odbc_utf8'
$dsn = ARGV.shift
$uid = ARGV.shift
$pwd = ARGV.shift
begin
Dir.glob("../[0-9]*.rb").sort.each do |f|
f =~ /^..\/\d+(.*)\.rb$/
print $1 + "."*(20-$1.length)
$stdout.flush
load f
print "ok\n"
end
ensure
begin
$c.drop_all unless $c.class != ODBC::Database
rescue
end
begin
ODBC.connect($dsn, $uid, $pwd).do("drop table test")
rescue
end
end
./ruby-odbc-0.99998/test/test.rb 0100644 0000764 0000144 00000001133 12504511725 014740 0 ustar chw users # $Id: test.rb,v 1.8 2015/03/25 10:53:59 chw Exp chw $
#
# Execute in ruby-odbc top directory.
#
# ruby test.rb "mysql-DSN" "mysql-user" "mysql-password"
#
# Test creates and deletes table "test" in that DSN.
require 'odbc'
$dsn = ARGV.shift
$uid = ARGV.shift
$pwd = ARGV.shift
begin
Dir.glob("[0-9]*.rb").sort.each do |f|
f =~ /\d+(.*)\.rb$/
print $1 + "."*(20-$1.length)
$stdout.flush
load f
print "ok\n"
end
ensure
begin
$c.drop_all unless $c.class != ODBC::Database
rescue
end
begin
ODBC.connect($dsn, $uid, $pwd).do("drop table test")
rescue
end
end
./ruby-odbc-0.99998/test/00connect.rb 0100644 0000764 0000144 00000000044 07467402434 015562 0 ustar chw users $c = ODBC.connect($dsn, $uid, $pwd)
./ruby-odbc-0.99998/test/10create_table.rb 0100644 0000764 0000144 00000000110 07303666376 016544 0 ustar chw users $c.run("create table test (id int not null, str varchar(32) not null)")
./ruby-odbc-0.99998/test/20insert.rb 0100644 0000764 0000144 00000000317 07303666476 015451 0 ustar chw users $q = $c.run("insert into test (id, str) values (1, 'foo')")
$q.run("insert into test (id, str) values (2, 'bar')")
$p = $c.proc("insert into test (id, str) values (?, ?)") {}
$p.call(3, "FOO")
$p[4, "BAR"]
./ruby-odbc-0.99998/test/30select.rb 0100644 0000764 0000144 00000003523 12720012733 015403 0 ustar chw users $q = $c.prepare("select id,str from test order by id")
if $q.column(0).name.upcase != "ID" then raise "fetch failed" end
if $q.column(1).name.upcase != "STR" then raise "fetch failed" end
$q.execute
if $q.fetch != [1, "foo"] then raise "fetch: failed" end
if $q.fetch != [2, "bar"] then raise "fetch: failed" end
if $q.fetch != [3, "FOO"] then raise "fetch: failed" end
if $q.fetch != [4, "BAR"] then raise "fetch: failed" end
if $q.fetch != nil then raise "fetch: failed" end
$q.close
if $q.execute.entries != [[1, "foo"], [2, "bar"], [3, "FOO"], [4, "BAR"]] then
raise "fetch: failed"
end
$q.close
if $q.execute.fetch_all != [[1, "foo"], [2, "bar"], [3, "FOO"], [4, "BAR"]] then
raise "fetch: failed"
end
$q.close
$q.execute
if $q.fetch_many(2) != [[1, "foo"], [2, "bar"]] then raise "fetch: failed" end
if $q.fetch_many(3) != [[3, "FOO"], [4, "BAR"]] then raise "fetch: failed" end
if $q.fetch_many(99) != nil then raise "fetch: failed" end
$q.close
a = []
$q.execute {|r| a=r.entries}
if a.size != 4 then raise "fetch: failed" end
$q.close
a = []
$q.execute.each {|r| a.push(r)}
if a.size != 4 then raise "fetch: failed" end
$q.close
a = []
$q.execute.each_hash {|r| a.push(r)}
if a.size != 4 then raise "fetch: failed" end
$q.close
a = []
$q.execute.each_hash(true) {|r| a.push(r)}
if a.size != 4 then raise "fetch: failed" end
$q.close
a = []
$q.execute.each_hash(:key=>:Symbol) {|r| a.push(r)}
if a.size != 4 then raise "fetch: failed" end
$q.close
a = []
$q.execute.each_hash(:key=>:Symbol,:table_names=>true) {|r| a.push(r)}
if a.size != 4 then raise "fetch: failed" end
$q.close
a = []
$q.execute.each_hash(:key=>:String,:table_names=>false) {|r| a.push(r)}
if a.size != 4 then raise "fetch: failed" end
$q.close
a = []
$q.execute.each_hash(:key=>:Fixnum,:table_names=>false) {|r| a.push(r)}
if a.size != 4 then raise "fetch: failed" end
$q.close
./ruby-odbc-0.99998/test/40update.rb 0100644 0000764 0000144 00000000217 07634621656 015426 0 ustar chw users $q = $c.run("update test set id=0, str='hoge'")
if $q.nrows != 4 then
$stderr.print "update row count: expected 4, got ", $q.nrows, "\n"
end
./ruby-odbc-0.99998/test/45delete.rb 0100644 0000764 0000144 00000000412 11423531352 015370 0 ustar chw users $count = $c.do("delete from test where 1 = 1")
if $count != 4
$stderr.print "delete row count: expected 4, got ", $count, "\n"
end
$count = $c.do("delete from test where 1 = 1")
if $count != 0
$stderr.print "delete row count: expected 0, got ", $count, "\n"
end
./ruby-odbc-0.99998/test/50drop_table.rb 0100644 0000764 0000144 00000000146 07303666077 016260 0 ustar chw users # drop all statements, otherwise table might be locked for drop.
$c.drop_all
$c.do("drop table test")
./ruby-odbc-0.99998/test/70close.rb 0100644 0000764 0000144 00000000016 07303547555 015247 0 ustar chw users $c.disconnect
./ruby-odbc-0.99998/COPYING 0100644 0000764 0000144 00000004371 07662676460 013540 0 ustar chw users Ruby/ODBC is copyrighted free software by Christian Werner
You can redistribute it and/or modify it under either the terms of the GPL
(see the file GPL), or the conditions below:
1. You may make and give away verbatim copies of the source form of the
software without restriction, provided that you duplicate all of the
original copyright notices and associated disclaimers.
2. You may modify your copy of the software in any way, provided that
you do at least ONE of the following:
a) place your modifications in the Public Domain or otherwise
make them Freely Available, such as by posting said
modifications to Usenet or an equivalent medium, or by allowing
the author to include your modifications in the software.
b) use the modified software only within your corporation or
organization.
c) give non-standard binaries non-standard names, with
instructions on where to get the original software distribution.
d) make other distribution arrangements with the author.
3. You may distribute the software in object code or binary form,
provided that you do at least ONE of the following:
a) distribute the binaries and library files of the software,
together with instructions (in the manual page or equivalent)
on where to get the original distribution.
b) accompany the distribution with the machine-readable source of
the software.
c) give non-standard binaries non-standard names, with
instructions on where to get the original software distribution.
d) make other distribution arrangements with the author.
4. You may modify and include the part of the software into any other
software (possibly commercial).
5. The scripts and library files supplied as input to or produced as
output from the software do not automatically fall under the
copyright of the software, but belong to whomever generated them,
and may be sold commercially, and may be aggregated with this
software.
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
./ruby-odbc-0.99998/ChangeLog 0100644 0000764 0000144 00000027153 13051021571 014232 0 ustar chw users ODBC binding for Ruby
---------------------
Wed Feb 15 2017 version 0.99998 released
* minor update to compile with Ruby 2.4, thangs to Kevin Deisz
* preset output vars before SQLColAttributes() call
Wed Apr 15 2015 version 0.99997 released
* fixed bug (typo) when compiling with Ruby < 2.0
Wed Mar 25 2015 version 0.99996 released
* when built for Ruby >= 2.0 release GVL for potentially
long running ODBC API functions, thanks Matt Conover
for initial implementation
Wed Mar 13 2013 version 0.99995 released
* added ODBC::Database.use_sql_column_name= flag to switch
usage of SQLColAttributes(SQL_COLUMN_LABEL) to
SQLColAttributes(SQL_COLUMN_NAME) on per connection basis
Sat Jan 15 2011 version 0.99994 released
* fixed column key caching, thanks Sean Noonan for bug report
Fri Dec 24 2010 version 0.99993 released
* fixed error reporting in Database.transaction method,
thanks Shane Emmons for bug report and testing
Thu Sep 16 2010 version 0.99992 released
* ODBC::Statement.each/each_hash now output arrays when
invoked without block
* column keys in result hashes now are cached/recycled Ruby strings
* added ODBC::Database methods use_time/use_utc to directly
output Ruby Time/Date objects
* added encoding support in the UTF8 variant for Ruby >= 1.9
* added module constant ODBC::UTF8 to indicate variant of module
* fixes for M$SQL server reporting zero column sizes
and unknown data types for varchar(strmax) columns
* eliminated compiler warnings
* use StringValueCStr instead of STR2CSTR (Ruby >= 1.9.1)
* small change for decision when to use SQLGetData() loop
Sun Apr 25 2010 version 0.99991 released
* detect HAVE_LONG_LONG for builds with unixODBC
* UTF-8 coding/decoding fix for range 0x80..0xBF
Thu Feb 18 2010 version 0.9999 released
* integrated Bosko Ivanisevic's fixes in ext/utf8/extconf.rb
and test/test.rb and test/utf8/test.rb
Fri Jan 15 2010 version 0.9998 released
* documentation update
* reorganized directory layout for making a gem
Wed May 20 2009 version 0.9997 released
* added Chad Johnson's FreeTDS/MSSQL patch to prevent from
re-prepare of queries with SQL_VARCHAR parameters
Mon Feb 02 2009 version 0.9996 released
* updates for Ruby > 1.8
* added Stephen Veit's SQL_NO_TOTAL handling to improve
retrieving large SQL_C_BINARY data
* fixes for SQLExecute/SQLExecDirect returning SQL_NO_DATA
Sat Apr 07 2007 version 0.9995 released
* init.c: prefer libiodbc.so.2 over libiodbc.so and
libodbc.so.1 over libodbc.so and same logic for
the installer shared library
* no exception thrown on stale HSTMT for ODBC::Statement.nrows
Mon Dec 25 2006 version 0.9994 released
* improved doc on ODBC::Statement.*param*, ODBC::Parameter,
and related ODBCProc
* added support for output/input-output parameters in queries,
methods ODBC::Statement.param_iotype/param_output_type/
param_output_size/param_output_value
Fri Sep 15 2006 version 0.9993 released
* more tweaks in extconf.rb for --enable-dlopen'ed utf8 version
thanks Daigo Moriwaki for testing
* eliminated warnings for installer functions
Mon Sep 11 2006 version 0.9992 released
* added parameter "column" in ODBC::Database::columns
* intern most strings on module load
* enhanced ODBC::Statement.fetch_hash et.al. to produce
intern'ed strings or fixnums as hash keys as requested
by Neville Burnell
* handle SQL_NO_DATA for chunk-wise SQLGetData()
* determine dynamically which API (UNICODE or ANSI) to
use for ODBC installer functions
* more 64 bit fixes
* added missing SQLEndTran() in init.c
Sat Aug 05 2006 version 0.9991 released
* fixed more SQLLEN vs SQLINTEGER issues and 64 bit warnings
* bail out during extconf.rb when sql.h/sqlext.h is not
available as requested by Curt Sampson
* fixed transaction logic ENV vs. DBC and use SQLEndTran()
for ODBCVER >= 0x0300, thanks Adam Harper for patch
* detect SQL parameter strings containing '\0's and use
SQL_C_BINARY when appropriate as parameter types to support
BLOB data, thanks Daigo Moriwaki for report and testing
* don't use dlopen()/GCC weak attributes on MacOSX
Wed Jun 28 2006 version 0.999 released
* added ODBC::Column@autoincrement information
* added init.c and extconf.rb logic for resolving iODBC/unixODBC
library dependencies at runtime using GCC weak attribute in
conjunction with dlopen(), this feature can be enabled/disabled
with "ruby extconf.rb --enable-dlopen"
Sun May 21 2006 version 0.998 released
* added undocumented module methods ODBC::write_file_dsn and
ODBC::read_file_dsn
* fixes in SQLConfigDataSource/SQLInstallerError detect/usage
* added statement level option handling (SQLSetStmtOption),
ODBC::Database.newstmt, ODBC::Statement.prepare|run as
contributed by Carl Blakeley of OpenLink Software
* eliminated most GCC 4.x warnings
Sun Dec 25 2005 version 0.997 released
* 32/64 bit issues as pointed out by Lars Kanis
* ODBC::Database.get_info implementation and constants, idea
and initial coding contributed by Tim Haynes of OpenLink Software
* ODBC::Statement.param_type implemented as work around for
Ingres ODBC driver. Thanks Jon Chambers for idea and testing
Sun Nov 21 2004 version 0.996 released
* use SQLInstallerError() for adddsn/confdsn/deldsn if available,
code contributed by Ryszard Niewisiewicz
* retry SQLBindParameter() for SQL_VARCHAR when SQLDescribeParam()
doesn't work (e.g. on MS Jet Engine)
* fixed crashes when SQLBindParameter failed in stmt_exec_int(),
as reported by Ryszard Niewisiewicz
Tue Sep 07 2004 version 0.995 released
* fixed another buffer alignment bug fetching doubles on sparc,
thanks Dan Debertin for testing.
Wed Jul 14 2004 version 0.994 released
* fixed ODBC::Database.new|connect so that
ODBC::Database.new.drvconnect(string) works
* fixed SQLTCHAR detect for Win32 in extconf.rb,
thanks to Pedro Luis Castedo Cepeda
Mon Jun 28 2004 version 0.993 released
* use HAVE_TYPE_SQLTCHAR from extconf.rb for old iODBC versions
* don't rb_define_alloc_func of dsn_new/drv_new for Ruby >= 1.8,
gives stack overflows, thanks to Pedro Luis Castedo Cepeda
for fixing
* fixes for iODBC driver manager concerning SQLFetchScroll
availability (SQL state codes IM001 vs HYC000)
* blob handling fix as suggested by Kaspar Schiess
Mon Mar 22 2004 version 0.992 released
* fixed buggy UTF8->Unicode conversion code
* fixed handling of uppercase column names in row hashes
Fri Dec 26 2003 version 0.991 released
* use SQLConfigDataSourceW() in utf8 version
* SQLError() is now always called after error/warning from
other ODBC API invokations in order to cleanup error
messages in driver manager/driver
* tweaks for SQLColAttributes() problems as suggested
by Nathaniel Talbott
* modified extconf.rb as suggestedb by
* eliminated use of alloca() in utf8 converters
* reworked to use Ruby 1.8 rb_define_alloc_func() API
Wed May 21 2003 version 0.99 released
* no functional changes with respect to 0.98
but starting with 0.99 released under Ruby style license.
Thu May 08 2003 version 0.98 released
* added utf8 version (-DUNICODE, -D_UNICODE for CFLAGS),
which generates odbc_utf.so, for build instructions
see README. Thanks Bosko Ivanisevic
for ideas and testing.
Fri Apr 25 2003 version 0.97 released
* align buffers for fetching scalar data (long, double et.al.)
to prevent alignment problems causing bus errors e.g. on sparc,
thanks sakazuki for testing.
Wed Mar 19 2003 version 0.96 released
* added fall back to SQLFetch() when SQLFetchScroll(SQL_FETCH_NEXT)
or SQLExtendedFetch(SQL_FETCH_NEXT) report IM001 error,
thanks Kiyonori Takeda for testing.
Mon May 13 2002 version 0.95 released
* doc updated
* minor code cleanups
* fixed ODBC::Database.run to properly accept blocks
as reported by Michael Neumann
* added ODBC::Statement.more_results method as
requested by Chris Morris
Thu Oct 11 2001 version 0.94 released
* doc updated
* fixed off-by-one bug in do_fetch function
* added some more SQL_* constants
* added ODBC::Database.special_columns method
* added unique flag to ODBC::Database.indexes
Fri Sep 07 2001 version 0.93 released
* doc updated
* removed default column name conversion to upper case
as introduced in version 0.91
* added ignorecase, ignorecase= methods for ODBC::Database
and ODBC::Statement as suggested by
Sean O'Halpin
Fri Aug 31 2001 version 0.92 released
* ODBC::Parameter class and ODBC::Statement.make_proc method added
* changes to support libiodbc-2.50 eg on Debian, thanks
Massimiliano Mirra for testing
* fixed typos in constant table (SQL_CP_* symbols, O_CONSTU macro)
* if odbcinst.h not available, make dummy DSN config methods
Sat Aug 25 2001 version 0.91 released
* handle non-unique keys in column name/result set hashes
by appending "#column-number" string
* convert column names to uppercase if ODBC driver is
identifier case insensitive as suggested by
Elmar Sonnenschein
* added cursorname method in Statement
* added assignment methods for Environment/Database/Statement
options
* taint strings
* use SQLExecDirect() in Statement.run/do when no parameters in query
Wed Aug 15 2001 version 0.9 released
* doc updated
* added alloc/free and ODBC API call tracing
(compile-time, -DTRACING)
* added array result for ODBC::Statement.columns
* statements are now by default dropped before SQLDisconnect
* rewrote resource tracking of environment, database connection
and statement objects due to crashes/hangs on Win32
* improved constructors for data/time/timestamp objects
* added clone methods for date/time/timestamp objects
Thu Jul 26 2001 version 0.8 released
* minor doc update
* added handling of block for ODBC::Statement.columns method
* revised error reporting and SQLRETURN handling with
respect to SQL_SUCCESS_WITH_INFO, introduced info method
to get warnings of last ODBC API call. Change was required
to support MS SQL Server, thanks to correspondence with
David Moore .
Wed Jun 20 2001 version 0.7 released
* minor doc update
* some more test cases in fetching data
* added some more fetch methods (fetch_many, fetch_all ...)
* added more tests for conditional include of
* again, fixes in parameter binding thanks to patches from
Steve Tuckner
Tue Jun 12 2001 version 0.6 released
* reviewed parameter and column information handling
* work around cases when SQLDescribeParam is not supported
by the selected ODBC driver
* bug fixes in parameter binding
Sun Jun 10 2001 version 0.5 released
* doc updated
* added environment attribute setting/getting methods
* eliminated alloca() in fetching data
* added missing SQL_CHAR constant
* fixed accessor methods for ODBC::(DSN|Driver|Column) as
suggested by Michael Neumann
Fri Jun 08 2001 version 0.4 released
* Cygwin fixes thanks to Michael Neumann
* minor optimizations
* cleanup GC related functions
Sun May 27 2001 version 0.3 released
* doc updated
* win32 port (mswin32 working, mingw untested)
* added types (ODBC::Date, ODBC::Time, ODBC::TimeStamp)
* reworked module/class organization
* major review
Thu May 17 2001 version 0.2 released
* updated and improved doc
* added fetch_hash, each_hash, column ODBCStmt methods
* added more constants in ODBC class
* added ODBCColumn class
* added accessor for ODBC::error
Sun May 13 2001 version 0.1 released
* initial release.
./ruby-odbc-0.99998/GPL 0100644 0000764 0000144 00000043131 07323124100 013014 0 ustar chw users GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
./ruby-odbc-0.99998/MANIFEST 0100644 0000764 0000144 00000000514 11324035121 013576 0 ustar chw users COPYING
ChangeLog
GPL
MANIFEST
README
ruby-odbc.gemspec
ext/extconf.rb
ext/odbc.c
ext/init.c
ext/utf8/extconf.rb
ext/utf8/odbc.c
ext/utf8/init.c
lib/cqgen.rb
doc/odbc.html
test/test.rb
test/00connect.rb
test/10create_table.rb
test/20insert.rb
test/30select.rb
test/40update.rb
test/50drop_table.rb
test/70close.rb
test/utf8/test.rb
./ruby-odbc-0.99998/README 0100644 0000764 0000144 00000005556 13051023575 013351 0 ustar chw users # $Id: README,v 1.45 2017/02/15 10:03:36 chw Exp chw $
ruby-odbc-0.99998
This is an ODBC binding for Ruby. So far it has been tested with
- Ruby 1.[6-9], MySQL 3.22/MyODBC (local), unixODBC 2.1.0
on Linux 2.2-x86 and 2.6-x86_64
- Ruby 1.6.4, MySQL 3.22/MyODBC (local), libiodbc 2.50
on Linux 2.2-x86
- Ruby 1.[6-8], MySQL 3.22/MyODBC (remote), MS Jet Engine, MSVC++ 6.0
on Windows NT4SP6
- Ruby 1.6.[3-5], MySQL 3.22/MyODBC (remote), MS Jet Engine, cygwin,
on Windows NT4SP6 and 2000
- Ruby 1.8.*, SQLite/ODBC >= 0.67, libiodbc 3.52.4 on Fedora Core 3 x86
- Ruby 2.0.0, SQLite/ODBC >= 0.93, unixODBC 2.2.14 on Ubuntu 12.04 x86
- Ruby 2.4
Michael Neumann and
Will Merrell reported successful compilation
with Cygwin on Win32.
Requirements:
- Ruby 1.6.[3-8] or Ruby >= 1.7
- unixODBC 2.x or libiodbc 3.52 on UN*X
Installation:
$ ruby -Cext extconf.rb [--enable-dlopen|--disable-dlopen]
$ make -C ext
# make -C ext install
--enable/disble-dlopen turns on/off special initialization
code to make ruby-odbc agnostic to unixODBC/iODBC driver
manager shared library names when GCC is used for compile.
In cases where unixODBC or iODBC is installed in non-standard
locations, use the option --with-odbc-dir=
when running extconf.rb
Installation of utf8 version:
$ ruby -Cext/utf8 extconf.rb [--enable-dlopen|--disable-dlopen]
$ make -C ext/utf8
# make -C ext/utf8 install
Installation MSVC:
C:..>ruby -Cext extconf.rb
C:..>cd ext
C:..>nmake
C:..>nmake install
C:..>ruby -Cutf8 extconf.rb
C:..>cd utf8
C:..>nmake
C:..>nmake install
Testing:
$ ruby -Ctest test.rb DSN [uid] [pwd]
or
$ ruby -KU -Ctest/utf8 test.rb DSN [uid] [pwd]
Usage:
Refer to doc/odbc.html
The difference between utf8 and non-utf8 versions are:
- non-utf8 version uses normal SQL.* ANSI functions
- utf8 version uses SQL.*W UNICODE functions and
requires/returns all strings in UTF8 format
Thus, depending on the -K option of ruby one could use
that code snippet:
...
if $KCODE == "UTF8" then
require 'odbc_utf8'
else
require 'odbc'
fi
It is also possible to load both non-utf8 and utf8 version
into ruby:
...
# non-utf8 version
require 'odbc'
# utf8 version
require 'odbc_utf8'
Whichever is loaded first, gets the module name 'ODBC'.
The second loaded module will be named 'ODBC_UTF8' (for
'odbc_utf8') or 'ODBC_NONE' (for 'odbc'). That should
allow to use both versions simultaneously in special
situations.
TODO:
- heavier testing
- improve documentation
Author:
Christian Werner
mailto:chw@ch-werner.de
http://www.ch-werner.de/rubyodbc
./ruby-odbc-0.99998/ruby-odbc.gemspec 0100644 0000764 0000144 00000001044 13051021766 015710 0 ustar chw users require 'date'
spec = Gem::Specification.new do |s|
s.name = "ruby-odbc"
s.version = "0.99998"
s.date = Date.today.to_s
s.author = "Christian Werner"
s.email = "chw @nospam@ ch-werner.de"
s.summary = "ODBC binding for Ruby"
s.homepage = "http://www.ch-werner.de/rubyodbc"
s.files = Dir.glob("**/*")
s.require_paths << 'lib'
s.test_files = Dir.glob('tests/*.rb')
s.has_rdoc = false
s.extra_rdoc_files = ["README", "COPYING", "ChangeLog", "GPL", "doc/odbc.html"]
s.extensions = ["ext/extconf.rb", "ext/utf8/extconf.rb"]
end