jpayne@68
|
1 # tdbcodbc.tcl --
|
jpayne@68
|
2 #
|
jpayne@68
|
3 # Class definitions and Tcl-level methods for the tdbc::odbc bridge.
|
jpayne@68
|
4 #
|
jpayne@68
|
5 # Copyright (c) 2008 by Kevin B. Kenny
|
jpayne@68
|
6 # See the file "license.terms" for information on usage and redistribution
|
jpayne@68
|
7 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
jpayne@68
|
8 #
|
jpayne@68
|
9 # RCS: @(#) $Id: tdbcodbc.tcl,v 1.47 2008/02/27 02:08:27 kennykb Exp $
|
jpayne@68
|
10 #
|
jpayne@68
|
11 #------------------------------------------------------------------------------
|
jpayne@68
|
12
|
jpayne@68
|
13 package require tdbc
|
jpayne@68
|
14
|
jpayne@68
|
15 ::namespace eval ::tdbc::odbc {
|
jpayne@68
|
16
|
jpayne@68
|
17 namespace export connection datasources drivers
|
jpayne@68
|
18
|
jpayne@68
|
19 # Data types that are predefined in ODBC
|
jpayne@68
|
20
|
jpayne@68
|
21 variable sqltypes [dict create \
|
jpayne@68
|
22 1 char \
|
jpayne@68
|
23 2 numeric \
|
jpayne@68
|
24 3 decimal \
|
jpayne@68
|
25 4 integer \
|
jpayne@68
|
26 5 smallint \
|
jpayne@68
|
27 6 float \
|
jpayne@68
|
28 7 real \
|
jpayne@68
|
29 8 double \
|
jpayne@68
|
30 9 datetime \
|
jpayne@68
|
31 12 varchar \
|
jpayne@68
|
32 91 date \
|
jpayne@68
|
33 92 time \
|
jpayne@68
|
34 93 timestamp \
|
jpayne@68
|
35 -1 longvarchar \
|
jpayne@68
|
36 -2 binary \
|
jpayne@68
|
37 -3 varbinary \
|
jpayne@68
|
38 -4 longvarbinary \
|
jpayne@68
|
39 -5 bigint \
|
jpayne@68
|
40 -6 tinyint \
|
jpayne@68
|
41 -7 bit \
|
jpayne@68
|
42 -8 wchar \
|
jpayne@68
|
43 -9 wvarchar \
|
jpayne@68
|
44 -10 wlongvarchar \
|
jpayne@68
|
45 -11 guid]
|
jpayne@68
|
46 }
|
jpayne@68
|
47
|
jpayne@68
|
48 #------------------------------------------------------------------------------
|
jpayne@68
|
49 #
|
jpayne@68
|
50 # tdbc::odbc::connection --
|
jpayne@68
|
51 #
|
jpayne@68
|
52 # Class representing a connection to a database through ODBC.
|
jpayne@68
|
53 #
|
jpayne@68
|
54 #-------------------------------------------------------------------------------
|
jpayne@68
|
55
|
jpayne@68
|
56 ::oo::class create ::tdbc::odbc::connection {
|
jpayne@68
|
57
|
jpayne@68
|
58 superclass ::tdbc::connection
|
jpayne@68
|
59
|
jpayne@68
|
60 variable statementSeq typemap
|
jpayne@68
|
61
|
jpayne@68
|
62 # The constructor is written in C. It takes the connection string
|
jpayne@68
|
63 # as its argument It sets up a namespace to hold the statements
|
jpayne@68
|
64 # associated with the connection, and then delegates to the 'init'
|
jpayne@68
|
65 # method (written in C) to do the actual work of attaching to the
|
jpayne@68
|
66 # database. When that comes back, it sets up a statement to query
|
jpayne@68
|
67 # the support types, makes a dictionary to enumerate them, and
|
jpayne@68
|
68 # calls back to set a flag if WVARCHAR is seen (If WVARCHAR is
|
jpayne@68
|
69 # seen, the database supports Unicode.)
|
jpayne@68
|
70
|
jpayne@68
|
71 # The 'statementCreate' method forwards to the constructor of the
|
jpayne@68
|
72 # statement class
|
jpayne@68
|
73
|
jpayne@68
|
74 forward statementCreate ::tdbc::odbc::statement create
|
jpayne@68
|
75
|
jpayne@68
|
76 # The 'tables' method returns a dictionary describing the tables
|
jpayne@68
|
77 # in the database
|
jpayne@68
|
78
|
jpayne@68
|
79 method tables {{pattern %}} {
|
jpayne@68
|
80 set stmt [::tdbc::odbc::tablesStatement create \
|
jpayne@68
|
81 Stmt::[incr statementSeq] [self] $pattern]
|
jpayne@68
|
82 set status [catch {
|
jpayne@68
|
83 set retval {}
|
jpayne@68
|
84 $stmt foreach -as dicts row {
|
jpayne@68
|
85 if {[dict exists $row TABLE_NAME]} {
|
jpayne@68
|
86 dict set retval [dict get $row TABLE_NAME] $row
|
jpayne@68
|
87 }
|
jpayne@68
|
88 }
|
jpayne@68
|
89 set retval
|
jpayne@68
|
90 } result options]
|
jpayne@68
|
91 catch {rename $stmt {}}
|
jpayne@68
|
92 return -level 0 -options $options $result
|
jpayne@68
|
93 }
|
jpayne@68
|
94
|
jpayne@68
|
95 # The 'columns' method returns a dictionary describing the tables
|
jpayne@68
|
96 # in the database
|
jpayne@68
|
97
|
jpayne@68
|
98 method columns {table {pattern %}} {
|
jpayne@68
|
99 # Make sure that the type map is initialized
|
jpayne@68
|
100 my typemap
|
jpayne@68
|
101
|
jpayne@68
|
102 # Query the columns from the database
|
jpayne@68
|
103
|
jpayne@68
|
104 set stmt [::tdbc::odbc::columnsStatement create \
|
jpayne@68
|
105 Stmt::[incr statementSeq] [self] $table $pattern]
|
jpayne@68
|
106 set status [catch {
|
jpayne@68
|
107 set retval {}
|
jpayne@68
|
108 $stmt foreach -as dicts origrow {
|
jpayne@68
|
109
|
jpayne@68
|
110 # Map the type, precision, scale and nullable indicators
|
jpayne@68
|
111 # to tdbc's notation
|
jpayne@68
|
112
|
jpayne@68
|
113 set row {}
|
jpayne@68
|
114 dict for {key value} $origrow {
|
jpayne@68
|
115 dict set row [string tolower $key] $value
|
jpayne@68
|
116 }
|
jpayne@68
|
117 if {[dict exists $row column_name]} {
|
jpayne@68
|
118 if {[dict exists $typemap \
|
jpayne@68
|
119 [dict get $row data_type]]} {
|
jpayne@68
|
120 dict set row type \
|
jpayne@68
|
121 [dict get $typemap \
|
jpayne@68
|
122 [dict get $row data_type]]
|
jpayne@68
|
123 } else {
|
jpayne@68
|
124 dict set row type [dict get $row type_name]
|
jpayne@68
|
125 }
|
jpayne@68
|
126 if {[dict exists $row column_size]} {
|
jpayne@68
|
127 dict set row precision \
|
jpayne@68
|
128 [dict get $row column_size]
|
jpayne@68
|
129 }
|
jpayne@68
|
130 if {[dict exists $row decimal_digits]} {
|
jpayne@68
|
131 dict set row scale \
|
jpayne@68
|
132 [dict get $row decimal_digits]
|
jpayne@68
|
133 }
|
jpayne@68
|
134 if {![dict exists $row nullable]} {
|
jpayne@68
|
135 dict set row nullable \
|
jpayne@68
|
136 [expr {!![string trim [dict get $row is_nullable]]}]
|
jpayne@68
|
137 }
|
jpayne@68
|
138 dict set retval [dict get $row column_name] $row
|
jpayne@68
|
139 }
|
jpayne@68
|
140 }
|
jpayne@68
|
141 set retval
|
jpayne@68
|
142 } result options]
|
jpayne@68
|
143 catch {rename $stmt {}}
|
jpayne@68
|
144 return -level 0 -options $options $result
|
jpayne@68
|
145 }
|
jpayne@68
|
146
|
jpayne@68
|
147 # The 'primarykeys' method returns a dictionary describing the primary
|
jpayne@68
|
148 # keys of a table
|
jpayne@68
|
149
|
jpayne@68
|
150 method primarykeys {tableName} {
|
jpayne@68
|
151 set stmt [::tdbc::odbc::primarykeysStatement create \
|
jpayne@68
|
152 Stmt::[incr statementSeq] [self] $tableName]
|
jpayne@68
|
153 set status [catch {
|
jpayne@68
|
154 set retval {}
|
jpayne@68
|
155 $stmt foreach -as dicts row {
|
jpayne@68
|
156 foreach {odbcKey tdbcKey} {
|
jpayne@68
|
157 TABLE_CAT tableCatalog
|
jpayne@68
|
158 TABLE_SCHEM tableSchema
|
jpayne@68
|
159 TABLE_NAME tableName
|
jpayne@68
|
160 COLUMN_NAME columnName
|
jpayne@68
|
161 KEY_SEQ ordinalPosition
|
jpayne@68
|
162 PK_NAME constraintName
|
jpayne@68
|
163 } {
|
jpayne@68
|
164 if {[dict exists $row $odbcKey]} {
|
jpayne@68
|
165 dict set row $tdbcKey [dict get $row $odbcKey]
|
jpayne@68
|
166 dict unset row $odbcKey
|
jpayne@68
|
167 }
|
jpayne@68
|
168 }
|
jpayne@68
|
169 lappend retval $row
|
jpayne@68
|
170 }
|
jpayne@68
|
171 set retval
|
jpayne@68
|
172 } result options]
|
jpayne@68
|
173 catch {rename $stmt {}}
|
jpayne@68
|
174 return -level 0 -options $options $result
|
jpayne@68
|
175 }
|
jpayne@68
|
176
|
jpayne@68
|
177 # The 'foreignkeys' method returns a dictionary describing the foreign
|
jpayne@68
|
178 # keys of a table
|
jpayne@68
|
179
|
jpayne@68
|
180 method foreignkeys {args} {
|
jpayne@68
|
181 set stmt [::tdbc::odbc::foreignkeysStatement create \
|
jpayne@68
|
182 Stmt::[incr statementSeq] [self] {*}$args]
|
jpayne@68
|
183 set status [catch {
|
jpayne@68
|
184 set fkseq 0
|
jpayne@68
|
185 set retval {}
|
jpayne@68
|
186 $stmt foreach -as dicts row {
|
jpayne@68
|
187 foreach {odbcKey tdbcKey} {
|
jpayne@68
|
188 PKTABLE_CAT primaryCatalog
|
jpayne@68
|
189 PKTABLE_SCHEM primarySchema
|
jpayne@68
|
190 PKTABLE_NAME primaryTable
|
jpayne@68
|
191 PKCOLUMN_NAME primaryColumn
|
jpayne@68
|
192 FKTABLE_CAT foreignCatalog
|
jpayne@68
|
193 FKTABLE_SCHEM foreignSchema
|
jpayne@68
|
194 FKTABLE_NAME foreignTable
|
jpayne@68
|
195 FKCOLUMN_NAME foreignColumn
|
jpayne@68
|
196 UPDATE_RULE updateRule
|
jpayne@68
|
197 DELETE_RULE deleteRule
|
jpayne@68
|
198 DEFERRABILITY deferrable
|
jpayne@68
|
199 KEY_SEQ ordinalPosition
|
jpayne@68
|
200 FK_NAME foreignConstraintName
|
jpayne@68
|
201 } {
|
jpayne@68
|
202 if {[dict exists $row $odbcKey]} {
|
jpayne@68
|
203 dict set row $tdbcKey [dict get $row $odbcKey]
|
jpayne@68
|
204 dict unset row $odbcKey
|
jpayne@68
|
205 }
|
jpayne@68
|
206 }
|
jpayne@68
|
207 # Horrible kludge: If the driver doesn't report FK_NAME,
|
jpayne@68
|
208 # make one up.
|
jpayne@68
|
209 if {![dict exists $row foreignConstraintName]} {
|
jpayne@68
|
210 if {![dict exists $row ordinalPosition]
|
jpayne@68
|
211 || [dict get $row ordinalPosition] == 1} {
|
jpayne@68
|
212 set fkname ?[dict get $row foreignTable]?[incr fkseq]
|
jpayne@68
|
213 }
|
jpayne@68
|
214 dict set row foreignConstraintName $fkname
|
jpayne@68
|
215 }
|
jpayne@68
|
216 lappend retval $row
|
jpayne@68
|
217 }
|
jpayne@68
|
218 set retval
|
jpayne@68
|
219 } result options]
|
jpayne@68
|
220 catch {rename $stmt {}}
|
jpayne@68
|
221 return -level 0 -options $options $result
|
jpayne@68
|
222 }
|
jpayne@68
|
223
|
jpayne@68
|
224 # The 'evaldirect' evaluates driver-native SQL code without preparing it,
|
jpayne@68
|
225 # and returns a list of dicts (similar to '$connection allrows -as dicts').
|
jpayne@68
|
226
|
jpayne@68
|
227 method evaldirect {sqlStatement} {
|
jpayne@68
|
228 set stmt [::tdbc::odbc::evaldirectStatement create \
|
jpayne@68
|
229 Stmt::[incr statementSeq] [self] $sqlStatement]
|
jpayne@68
|
230 set status [catch {
|
jpayne@68
|
231 $stmt allrows -as dicts
|
jpayne@68
|
232 } result options]
|
jpayne@68
|
233 catch {rename $stmt {}}
|
jpayne@68
|
234 return -level 0 -options $options $result
|
jpayne@68
|
235 }
|
jpayne@68
|
236
|
jpayne@68
|
237 # The 'prepareCall' method gives a portable interface to prepare
|
jpayne@68
|
238 # calls to stored procedures. It delegates to 'prepare' to do the
|
jpayne@68
|
239 # actual work.
|
jpayne@68
|
240
|
jpayne@68
|
241 method preparecall {call} {
|
jpayne@68
|
242
|
jpayne@68
|
243 regexp {^[[:space:]]*(?:([A-Za-z_][A-Za-z_0-9]*)[[:space:]]*=)?(.*)} \
|
jpayne@68
|
244 $call -> varName rest
|
jpayne@68
|
245 if {$varName eq {}} {
|
jpayne@68
|
246 my prepare \\{CALL $rest\\}
|
jpayne@68
|
247 } else {
|
jpayne@68
|
248 my prepare \\{:$varName=CALL $rest\\}
|
jpayne@68
|
249 }
|
jpayne@68
|
250
|
jpayne@68
|
251 if 0 {
|
jpayne@68
|
252 # Kevin thinks this is going to be
|
jpayne@68
|
253
|
jpayne@68
|
254 if {![regexp -expanded {
|
jpayne@68
|
255 ^\s* # leading whitespace
|
jpayne@68
|
256 (?::([[:alpha:]_][[:alnum:]_]*)\s*=\s*) # possible variable name
|
jpayne@68
|
257 (?:(?:([[:alpha:]_][[:alnum:]_]*)\s*[.]\s*)? # catalog
|
jpayne@68
|
258 ([[:alpha:]_][[:alnum:]_]*)\s*[.]\s*)? # schema
|
jpayne@68
|
259 ([[:alpha:]_][[:alnum:]_]*)\s* # procedure
|
jpayne@68
|
260 (.*)$ # argument list
|
jpayne@68
|
261 } $call -> varName catalog schema procedure arglist]} {
|
jpayne@68
|
262 return -code error \
|
jpayne@68
|
263 -errorCode [list TDBC \
|
jpayne@68
|
264 SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION \
|
jpayne@68
|
265 42000 ODBC -1] \
|
jpayne@68
|
266 "Syntax error in stored procedure call"
|
jpayne@68
|
267 } else {
|
jpayne@68
|
268 my PrepareCall $varName $catalog $schema $procedure $arglist
|
jpayne@68
|
269 }
|
jpayne@68
|
270
|
jpayne@68
|
271 # at least if making all parameters 'inout' doesn't work.
|
jpayne@68
|
272
|
jpayne@68
|
273 }
|
jpayne@68
|
274
|
jpayne@68
|
275 }
|
jpayne@68
|
276
|
jpayne@68
|
277 # The 'typemap' method returns the type map
|
jpayne@68
|
278
|
jpayne@68
|
279 method typemap {} {
|
jpayne@68
|
280 if {![info exists typemap]} {
|
jpayne@68
|
281 set typemap $::tdbc::odbc::sqltypes
|
jpayne@68
|
282 set typesStmt [tdbc::odbc::typesStatement new [self]]
|
jpayne@68
|
283 $typesStmt foreach row {
|
jpayne@68
|
284 set typeNum [dict get $row DATA_TYPE]
|
jpayne@68
|
285 if {![dict exists $typemap $typeNum]} {
|
jpayne@68
|
286 dict set typemap $typeNum [string tolower \
|
jpayne@68
|
287 [dict get $row TYPE_NAME]]
|
jpayne@68
|
288 }
|
jpayne@68
|
289 switch -exact -- $typeNum {
|
jpayne@68
|
290 -9 {
|
jpayne@68
|
291 [self] HasWvarchar 1
|
jpayne@68
|
292 }
|
jpayne@68
|
293 -5 {
|
jpayne@68
|
294 [self] HasBigint 1
|
jpayne@68
|
295 }
|
jpayne@68
|
296 }
|
jpayne@68
|
297 }
|
jpayne@68
|
298 rename $typesStmt {}
|
jpayne@68
|
299 }
|
jpayne@68
|
300 return $typemap
|
jpayne@68
|
301 }
|
jpayne@68
|
302
|
jpayne@68
|
303 # The 'begintransaction', 'commit' and 'rollback' methods are
|
jpayne@68
|
304 # implemented in C.
|
jpayne@68
|
305
|
jpayne@68
|
306 }
|
jpayne@68
|
307
|
jpayne@68
|
308 #-------------------------------------------------------------------------------
|
jpayne@68
|
309 #
|
jpayne@68
|
310 # tdbc::odbc::statement --
|
jpayne@68
|
311 #
|
jpayne@68
|
312 # The class 'tdbc::odbc::statement' models one statement against a
|
jpayne@68
|
313 # database accessed through an ODBC connection
|
jpayne@68
|
314 #
|
jpayne@68
|
315 #-------------------------------------------------------------------------------
|
jpayne@68
|
316
|
jpayne@68
|
317 ::oo::class create ::tdbc::odbc::statement {
|
jpayne@68
|
318
|
jpayne@68
|
319 superclass ::tdbc::statement
|
jpayne@68
|
320
|
jpayne@68
|
321 # The constructor is implemented in C. It accepts the handle to
|
jpayne@68
|
322 # the connection and the SQL code for the statement to prepare.
|
jpayne@68
|
323 # It creates a subordinate namespace to hold the statement's
|
jpayne@68
|
324 # active result sets, and then delegates to the 'init' method,
|
jpayne@68
|
325 # written in C, to do the actual work of preparing the statement.
|
jpayne@68
|
326
|
jpayne@68
|
327 # The 'resultSetCreate' method forwards to the result set constructor
|
jpayne@68
|
328
|
jpayne@68
|
329 forward resultSetCreate ::tdbc::odbc::resultset create
|
jpayne@68
|
330
|
jpayne@68
|
331 # The 'params' method describes the parameters to the statement
|
jpayne@68
|
332
|
jpayne@68
|
333 method params {} {
|
jpayne@68
|
334 set typemap [[my connection] typemap]
|
jpayne@68
|
335 set result {}
|
jpayne@68
|
336 foreach {name flags typeNum precision scale nullable} [my ParamList] {
|
jpayne@68
|
337 set lst [dict create \
|
jpayne@68
|
338 name $name \
|
jpayne@68
|
339 direction [lindex {unknown in out inout} \
|
jpayne@68
|
340 [expr {($flags & 0x06) >> 1}]] \
|
jpayne@68
|
341 type [dict get $typemap $typeNum] \
|
jpayne@68
|
342 precision $precision \
|
jpayne@68
|
343 scale $scale]
|
jpayne@68
|
344 if {$nullable in {0 1}} {
|
jpayne@68
|
345 dict set list nullable $nullable
|
jpayne@68
|
346 }
|
jpayne@68
|
347 dict set result $name $lst
|
jpayne@68
|
348 }
|
jpayne@68
|
349 return $result
|
jpayne@68
|
350 }
|
jpayne@68
|
351
|
jpayne@68
|
352 # Methods implemented in C:
|
jpayne@68
|
353 # init statement ?dictionary?
|
jpayne@68
|
354 # Does the heavy lifting for the constructor
|
jpayne@68
|
355 # connection
|
jpayne@68
|
356 # Returns the connection handle to which this statement belongs
|
jpayne@68
|
357 # paramtype paramname ?direction? type ?precision ?scale??
|
jpayne@68
|
358 # Declares the type of a parameter in the statement
|
jpayne@68
|
359
|
jpayne@68
|
360 }
|
jpayne@68
|
361
|
jpayne@68
|
362 #------------------------------------------------------------------------------
|
jpayne@68
|
363 #
|
jpayne@68
|
364 # tdbc::odbc::tablesStatement --
|
jpayne@68
|
365 #
|
jpayne@68
|
366 # The class 'tdbc::odbc::tablesStatement' represents the special
|
jpayne@68
|
367 # statement that queries the tables in a database through an ODBC
|
jpayne@68
|
368 # connection.
|
jpayne@68
|
369 #
|
jpayne@68
|
370 #------------------------------------------------------------------------------
|
jpayne@68
|
371
|
jpayne@68
|
372 oo::class create ::tdbc::odbc::tablesStatement {
|
jpayne@68
|
373
|
jpayne@68
|
374 superclass ::tdbc::statement
|
jpayne@68
|
375
|
jpayne@68
|
376 # The constructor is written in C. It accepts the handle to the
|
jpayne@68
|
377 # connection and a pattern to match table names. It works in all
|
jpayne@68
|
378 # ways like the constructor of the 'statement' class except that
|
jpayne@68
|
379 # its 'init' method sets up to enumerate tables and not run a SQL
|
jpayne@68
|
380 # query.
|
jpayne@68
|
381
|
jpayne@68
|
382 # The 'resultSetCreate' method forwards to the result set constructor
|
jpayne@68
|
383
|
jpayne@68
|
384 forward resultSetCreate ::tdbc::odbc::resultset create
|
jpayne@68
|
385
|
jpayne@68
|
386 }
|
jpayne@68
|
387
|
jpayne@68
|
388 #------------------------------------------------------------------------------
|
jpayne@68
|
389 #
|
jpayne@68
|
390 # tdbc::odbc::columnsStatement --
|
jpayne@68
|
391 #
|
jpayne@68
|
392 # The class 'tdbc::odbc::tablesStatement' represents the special
|
jpayne@68
|
393 # statement that queries the columns of a table or view
|
jpayne@68
|
394 # in a database through an ODBC connection.
|
jpayne@68
|
395 #
|
jpayne@68
|
396 #------------------------------------------------------------------------------
|
jpayne@68
|
397
|
jpayne@68
|
398 oo::class create ::tdbc::odbc::columnsStatement {
|
jpayne@68
|
399
|
jpayne@68
|
400 superclass ::tdbc::statement
|
jpayne@68
|
401
|
jpayne@68
|
402 # The constructor is written in C. It accepts the handle to the
|
jpayne@68
|
403 # connection, a table name, and a pattern to match column
|
jpayne@68
|
404 # names. It works in all ways like the constructor of the
|
jpayne@68
|
405 # 'statement' class except that its 'init' method sets up to
|
jpayne@68
|
406 # enumerate tables and not run a SQL query.
|
jpayne@68
|
407
|
jpayne@68
|
408 # The 'resultSetCreate' class forwards to the constructor of the
|
jpayne@68
|
409 # result set
|
jpayne@68
|
410
|
jpayne@68
|
411 forward resultSetCreate ::tdbc::odbc::resultset create
|
jpayne@68
|
412
|
jpayne@68
|
413 }
|
jpayne@68
|
414
|
jpayne@68
|
415 #------------------------------------------------------------------------------
|
jpayne@68
|
416 #
|
jpayne@68
|
417 # tdbc::odbc::primarykeysStatement --
|
jpayne@68
|
418 #
|
jpayne@68
|
419 # The class 'tdbc::odbc::primarykeysStatement' represents the special
|
jpayne@68
|
420 # statement that queries the primary keys on a table through an ODBC
|
jpayne@68
|
421 # connection.
|
jpayne@68
|
422 #
|
jpayne@68
|
423 #------------------------------------------------------------------------------
|
jpayne@68
|
424
|
jpayne@68
|
425 oo::class create ::tdbc::odbc::primarykeysStatement {
|
jpayne@68
|
426
|
jpayne@68
|
427 superclass ::tdbc::statement
|
jpayne@68
|
428
|
jpayne@68
|
429 # The constructor is written in C. It accepts the handle to the
|
jpayne@68
|
430 # connection and a table name. It works in all
|
jpayne@68
|
431 # ways like the constructor of the 'statement' class except that
|
jpayne@68
|
432 # its 'init' method sets up to enumerate primary keys and not run a SQL
|
jpayne@68
|
433 # query.
|
jpayne@68
|
434
|
jpayne@68
|
435 # The 'resultSetCreate' method forwards to the result set constructor
|
jpayne@68
|
436
|
jpayne@68
|
437 forward resultSetCreate ::tdbc::odbc::resultset create
|
jpayne@68
|
438
|
jpayne@68
|
439 }
|
jpayne@68
|
440
|
jpayne@68
|
441 #------------------------------------------------------------------------------
|
jpayne@68
|
442 #
|
jpayne@68
|
443 # tdbc::odbc::foreignkeysStatement --
|
jpayne@68
|
444 #
|
jpayne@68
|
445 # The class 'tdbc::odbc::foreignkeysStatement' represents the special
|
jpayne@68
|
446 # statement that queries the foreign keys on a table through an ODBC
|
jpayne@68
|
447 # connection.
|
jpayne@68
|
448 #
|
jpayne@68
|
449 #------------------------------------------------------------------------------
|
jpayne@68
|
450
|
jpayne@68
|
451 oo::class create ::tdbc::odbc::foreignkeysStatement {
|
jpayne@68
|
452
|
jpayne@68
|
453 superclass ::tdbc::statement
|
jpayne@68
|
454
|
jpayne@68
|
455 # The constructor is written in C. It accepts the handle to the
|
jpayne@68
|
456 # connection and the -primary and -foreign options. It works in all
|
jpayne@68
|
457 # ways like the constructor of the 'statement' class except that
|
jpayne@68
|
458 # its 'init' method sets up to enumerate foreign keys and not run a SQL
|
jpayne@68
|
459 # query.
|
jpayne@68
|
460
|
jpayne@68
|
461 # The 'resultSetCreate' method forwards to the result set constructor
|
jpayne@68
|
462
|
jpayne@68
|
463 forward resultSetCreate ::tdbc::odbc::resultset create
|
jpayne@68
|
464
|
jpayne@68
|
465 }
|
jpayne@68
|
466
|
jpayne@68
|
467 #------------------------------------------------------------------------------
|
jpayne@68
|
468 #
|
jpayne@68
|
469 # tdbc::odbc::evaldirectStatement --
|
jpayne@68
|
470 #
|
jpayne@68
|
471 # The class 'tdbc::odbc::evaldirectStatement' provides a mechanism to
|
jpayne@68
|
472 # execute driver-name SQL code through an ODBC connection. The SQL code
|
jpayne@68
|
473 # is not prepared and no tokenization or variable substitution is done.
|
jpayne@68
|
474 #
|
jpayne@68
|
475 #------------------------------------------------------------------------------
|
jpayne@68
|
476
|
jpayne@68
|
477 oo::class create ::tdbc::odbc::evaldirectStatement {
|
jpayne@68
|
478
|
jpayne@68
|
479 superclass ::tdbc::statement
|
jpayne@68
|
480
|
jpayne@68
|
481 # The constructor is written in C. It accepts the handle to the
|
jpayne@68
|
482 # connection and a SQL statement. It works in all
|
jpayne@68
|
483 # ways like the constructor of the 'statement' class except that
|
jpayne@68
|
484 # its 'init' method does not tokenize or prepare the SQL statement, and
|
jpayne@68
|
485 # sets up to run the SQL query without performing variable substitution.
|
jpayne@68
|
486
|
jpayne@68
|
487 # The 'resultSetCreate' method forwards to the result set constructor
|
jpayne@68
|
488
|
jpayne@68
|
489 forward resultSetCreate ::tdbc::odbc::resultset create
|
jpayne@68
|
490
|
jpayne@68
|
491 }
|
jpayne@68
|
492
|
jpayne@68
|
493 #------------------------------------------------------------------------------
|
jpayne@68
|
494 #
|
jpayne@68
|
495 # tdbc::odbc::typesStatement --
|
jpayne@68
|
496 #
|
jpayne@68
|
497 # The class 'tdbc::odbc::typesStatement' represents the special
|
jpayne@68
|
498 # statement that queries the types available in a database through
|
jpayne@68
|
499 # an ODBC connection.
|
jpayne@68
|
500 #
|
jpayne@68
|
501 #------------------------------------------------------------------------------
|
jpayne@68
|
502
|
jpayne@68
|
503
|
jpayne@68
|
504 oo::class create ::tdbc::odbc::typesStatement {
|
jpayne@68
|
505
|
jpayne@68
|
506 superclass ::tdbc::statement
|
jpayne@68
|
507
|
jpayne@68
|
508 # The constructor is written in C. It accepts the handle to the
|
jpayne@68
|
509 # connection, and (optionally) a data type number. It works in all
|
jpayne@68
|
510 # ways like the constructor of the 'statement' class except that
|
jpayne@68
|
511 # its 'init' method sets up to enumerate types and not run a SQL
|
jpayne@68
|
512 # query.
|
jpayne@68
|
513
|
jpayne@68
|
514 # The 'resultSetCreate' method forwards to the constructor of result sets
|
jpayne@68
|
515
|
jpayne@68
|
516 forward resultSetCreate ::tdbc::odbc::resultset create
|
jpayne@68
|
517
|
jpayne@68
|
518 # The C code contains a variant implementation of the 'init' method.
|
jpayne@68
|
519
|
jpayne@68
|
520 }
|
jpayne@68
|
521
|
jpayne@68
|
522 #------------------------------------------------------------------------------
|
jpayne@68
|
523 #
|
jpayne@68
|
524 # tdbc::odbc::resultset --
|
jpayne@68
|
525 #
|
jpayne@68
|
526 # The class 'tdbc::odbc::resultset' models the result set that is
|
jpayne@68
|
527 # produced by executing a statement against an ODBC database.
|
jpayne@68
|
528 #
|
jpayne@68
|
529 #------------------------------------------------------------------------------
|
jpayne@68
|
530
|
jpayne@68
|
531 ::oo::class create ::tdbc::odbc::resultset {
|
jpayne@68
|
532
|
jpayne@68
|
533 superclass ::tdbc::resultset
|
jpayne@68
|
534
|
jpayne@68
|
535 # Methods implemented in C include:
|
jpayne@68
|
536
|
jpayne@68
|
537 # constructor statement ?dictionary?
|
jpayne@68
|
538 # -- Executes the statement against the database, optionally providing
|
jpayne@68
|
539 # a dictionary of substituted parameters (default is to get params
|
jpayne@68
|
540 # from variables in the caller's scope).
|
jpayne@68
|
541 # columns
|
jpayne@68
|
542 # -- Returns a list of the names of the columns in the result.
|
jpayne@68
|
543 # nextdict
|
jpayne@68
|
544 # -- Stores the next row of the result set in the given variable in
|
jpayne@68
|
545 # the caller's scope as a dictionary whose keys are
|
jpayne@68
|
546 # column names and whose values are column values.
|
jpayne@68
|
547 # nextlist
|
jpayne@68
|
548 # -- Stores the next row of the result set in the given variable in
|
jpayne@68
|
549 # the caller's scope as a list of cells.
|
jpayne@68
|
550 # rowcount
|
jpayne@68
|
551 # -- Returns a count of rows affected by the statement, or -1
|
jpayne@68
|
552 # if the count of rows has not been determined.
|
jpayne@68
|
553
|
jpayne@68
|
554 }
|