Spaces:
Runtime error
Runtime error
| # tdbcmysql.tcl -- | |
| # | |
| # Class definitions and Tcl-level methods for the tdbc::mysql bridge. | |
| # | |
| # Copyright (c) 2008 by Kevin B. Kenny | |
| # See the file "license.terms" for information on usage and redistribution | |
| # of this file, and for a DISCLAIMER OF ALL WARRANTIES. | |
| # | |
| # RCS: @(#) $Id: tdbcmysql.tcl,v 1.47 2008/02/27 02:08:27 kennykb Exp $ | |
| # | |
| #------------------------------------------------------------------------------ | |
| package require tdbc | |
| ::namespace eval ::tdbc::mysql { | |
| namespace export connection datasources drivers | |
| } | |
| #------------------------------------------------------------------------------ | |
| # | |
| # tdbc::mysql::connection -- | |
| # | |
| # Class representing a connection to a database through MYSQL. | |
| # | |
| #------------------------------------------------------------------------------- | |
| ::oo::class create ::tdbc::mysql::connection { | |
| superclass ::tdbc::connection | |
| # The constructor is written in C. It takes alternating keywords | |
| # and values pairs as its argumenta. (See the manual page for the | |
| # available options.) | |
| variable foreignKeysStatement | |
| # The 'statementCreate' method delegates to the constructor of the | |
| # statement class | |
| forward statementCreate ::tdbc::mysql::statement create | |
| # The 'columns' method returns a dictionary describing the tables | |
| # in the database | |
| method columns {table {pattern %}} { | |
| # To return correct lengths of CHARACTER and BINARY columns, | |
| # we need to know the maximum lengths of characters in each | |
| # collation. We cache this information only once, on the first | |
| # call to 'columns'. | |
| if {[my NeedCollationInfo]} { | |
| my SetCollationInfo {*}[my allrows -as lists { | |
| SELECT coll.id, cs.maxlen | |
| FROM INFORMATION_SCHEMA.COLLATIONS coll, | |
| INFORMATION_SCHEMA.CHARACTER_SETS cs | |
| WHERE cs.CHARACTER_SET_NAME = coll.CHARACTER_SET_NAME | |
| ORDER BY coll.id DESC | |
| }] | |
| } | |
| return [my Columns $table $pattern] | |
| } | |
| # The 'preparecall' method gives a portable interface to prepare | |
| # calls to stored procedures. It delegates to 'prepare' to do the | |
| # actual work. | |
| method preparecall {call} { | |
| regexp {^[[:space:]]*(?:([A-Za-z_][A-Za-z_0-9]*)[[:space:]]*=)?(.*)} \ | |
| $call -> varName rest | |
| if {$varName eq {}} { | |
| my prepare "CALL $rest" | |
| } else { | |
| my prepare \\{:$varName=$rest\\} | |
| } | |
| } | |
| # The 'init', 'begintransaction', 'commit, 'rollback', 'tables' | |
| # 'NeedCollationInfo', 'SetCollationInfo', and 'Columns' methods | |
| # are implemented in C. | |
| # The 'BuildForeignKeysStatements' method builds a SQL statement to | |
| # retrieve the foreign keys from a database. (It executes once the | |
| # first time the 'foreignKeys' method is executed, and retains the | |
| # prepared statements for reuse.) It is slightly nonstandard because | |
| # MYSQL doesn't name the PRIMARY constraints uniquely. | |
| method BuildForeignKeysStatement {} { | |
| foreach {exists1 clause1} { | |
| 0 {} | |
| 1 { AND fkc.REFERENCED_TABLE_NAME = :primary} | |
| } { | |
| foreach {exists2 clause2} { | |
| 0 {} | |
| 1 { AND fkc.TABLE_NAME = :foreign} | |
| } { | |
| set stmt [my prepare " | |
| SELECT rc.CONSTRAINT_SCHEMA AS \"foreignConstraintSchema\", | |
| rc.CONSTRAINT_NAME AS \"foreignConstraintName\", | |
| rc.UPDATE_RULE AS \"updateAction\", | |
| rc.DELETE_RULE AS \"deleteAction\", | |
| fkc.REFERENCED_TABLE_SCHEMA AS \"primarySchema\", | |
| fkc.REFERENCED_TABLE_NAME AS \"primaryTable\", | |
| fkc.REFERENCED_COLUMN_NAME AS \"primaryColumn\", | |
| fkc.TABLE_SCHEMA AS \"foreignSchema\", | |
| fkc.TABLE_NAME AS \"foreignTable\", | |
| fkc.COLUMN_NAME AS \"foreignColumn\", | |
| fkc.ORDINAL_POSITION AS \"ordinalPosition\" | |
| FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc | |
| INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE fkc | |
| ON fkc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME | |
| AND fkc.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA | |
| WHERE 1=1 | |
| $clause1 | |
| $clause2 | |
| "] | |
| dict set foreignKeysStatement $exists1 $exists2 $stmt | |
| } | |
| } | |
| } | |
| } | |
| #------------------------------------------------------------------------------ | |
| # | |
| # tdbc::mysql::statement -- | |
| # | |
| # The class 'tdbc::mysql::statement' models one statement against a | |
| # database accessed through an MYSQL connection | |
| # | |
| #------------------------------------------------------------------------------ | |
| ::oo::class create ::tdbc::mysql::statement { | |
| superclass ::tdbc::statement | |
| # The 'resultSetCreate' method forwards to the constructor of the | |
| # result set. | |
| forward resultSetCreate ::tdbc::mysql::resultset create | |
| # Methods implemented in C: | |
| # | |
| # constructor connection SQLCode | |
| # The constructor accepts the handle to the connection and the SQL code | |
| # for the statement to prepare. It creates a subordinate namespace to | |
| # hold the statement's active result sets, and then delegates to the | |
| # 'init' method, written in C, to do the actual work of preparing the | |
| # statement. | |
| # params | |
| # Returns descriptions of the parameters of a statement. | |
| # paramtype paramname ?direction? type ?precision ?scale?? | |
| # Declares the type of a parameter in the statement | |
| } | |
| #------------------------------------------------------------------------------ | |
| # | |
| # tdbc::mysql::resultset -- | |
| # | |
| # The class 'tdbc::mysql::resultset' models the result set that is | |
| # produced by executing a statement against an MYSQL database. | |
| # | |
| #------------------------------------------------------------------------------ | |
| ::oo::class create ::tdbc::mysql::resultset { | |
| superclass ::tdbc::resultset | |
| # Methods implemented in C include: | |
| # constructor statement ?dictionary? | |
| # -- Executes the statement against the database, optionally providing | |
| # a dictionary of substituted parameters (default is to get params | |
| # from variables in the caller's scope). | |
| # columns | |
| # -- Returns a list of the names of the columns in the result. | |
| # nextdict | |
| # -- Stores the next row of the result set in the given variable in | |
| # the caller's scope as a dictionary whose keys are | |
| # column names and whose values are column values, or else | |
| # as a list of cells. | |
| # nextlist | |
| # -- Stores the next row of the result set in the given variable in | |
| # the caller's scope as a list of cells. | |
| # rowcount | |
| # -- Returns a count of rows affected by the statement, or -1 | |
| # if the count of rows has not been determined. | |
| } | |