tdbcmysql.tcl 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. # tdbcmysql.tcl --
  2. #
  3. # Class definitions and Tcl-level methods for the tdbc::mysql bridge.
  4. #
  5. # Copyright (c) 2008 by Kevin B. Kenny
  6. # See the file "license.terms" for information on usage and redistribution
  7. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  8. #
  9. # RCS: @(#) $Id: tdbcmysql.tcl,v 1.47 2008/02/27 02:08:27 kennykb Exp $
  10. #
  11. #------------------------------------------------------------------------------
  12. package require tdbc
  13. ::namespace eval ::tdbc::mysql {
  14. namespace export connection datasources drivers
  15. }
  16. #------------------------------------------------------------------------------
  17. #
  18. # tdbc::mysql::connection --
  19. #
  20. # Class representing a connection to a database through MYSQL.
  21. #
  22. #-------------------------------------------------------------------------------
  23. ::oo::class create ::tdbc::mysql::connection {
  24. superclass ::tdbc::connection
  25. # The constructor is written in C. It takes alternating keywords
  26. # and values pairs as its argumenta. (See the manual page for the
  27. # available options.)
  28. variable foreignKeysStatement
  29. # The 'statementCreate' method delegates to the constructor of the
  30. # statement class
  31. forward statementCreate ::tdbc::mysql::statement create
  32. # The 'columns' method returns a dictionary describing the tables
  33. # in the database
  34. method columns {table {pattern %}} {
  35. # To return correct lengths of CHARACTER and BINARY columns,
  36. # we need to know the maximum lengths of characters in each
  37. # collation. We cache this information only once, on the first
  38. # call to 'columns'.
  39. if {[my NeedCollationInfo]} {
  40. my SetCollationInfo {*}[my allrows -as lists {
  41. SELECT coll.id, cs.maxlen
  42. FROM INFORMATION_SCHEMA.COLLATIONS coll,
  43. INFORMATION_SCHEMA.CHARACTER_SETS cs
  44. WHERE cs.CHARACTER_SET_NAME = coll.CHARACTER_SET_NAME
  45. ORDER BY coll.id DESC
  46. }]
  47. }
  48. return [my Columns $table $pattern]
  49. }
  50. # The 'preparecall' method gives a portable interface to prepare
  51. # calls to stored procedures. It delegates to 'prepare' to do the
  52. # actual work.
  53. method preparecall {call} {
  54. regexp {^[[:space:]]*(?:([A-Za-z_][A-Za-z_0-9]*)[[:space:]]*=)?(.*)} \
  55. $call -> varName rest
  56. if {$varName eq {}} {
  57. my prepare "CALL $rest"
  58. } else {
  59. my prepare \\{:$varName=$rest\\}
  60. }
  61. }
  62. # The 'init', 'begintransaction', 'commit, 'rollback', 'tables'
  63. # 'NeedCollationInfo', 'SetCollationInfo', and 'Columns' methods
  64. # are implemented in C.
  65. # The 'BuildForeignKeysStatements' method builds a SQL statement to
  66. # retrieve the foreign keys from a database. (It executes once the
  67. # first time the 'foreignKeys' method is executed, and retains the
  68. # prepared statements for reuse.) It is slightly nonstandard because
  69. # MYSQL doesn't name the PRIMARY constraints uniquely.
  70. method BuildForeignKeysStatement {} {
  71. foreach {exists1 clause1} {
  72. 0 {}
  73. 1 { AND fkc.REFERENCED_TABLE_NAME = :primary}
  74. } {
  75. foreach {exists2 clause2} {
  76. 0 {}
  77. 1 { AND fkc.TABLE_NAME = :foreign}
  78. } {
  79. set stmt [my prepare "
  80. SELECT rc.CONSTRAINT_SCHEMA AS \"foreignConstraintSchema\",
  81. rc.CONSTRAINT_NAME AS \"foreignConstraintName\",
  82. rc.UPDATE_RULE AS \"updateAction\",
  83. rc.DELETE_RULE AS \"deleteAction\",
  84. fkc.REFERENCED_TABLE_SCHEMA AS \"primarySchema\",
  85. fkc.REFERENCED_TABLE_NAME AS \"primaryTable\",
  86. fkc.REFERENCED_COLUMN_NAME AS \"primaryColumn\",
  87. fkc.TABLE_SCHEMA AS \"foreignSchema\",
  88. fkc.TABLE_NAME AS \"foreignTable\",
  89. fkc.COLUMN_NAME AS \"foreignColumn\",
  90. fkc.ORDINAL_POSITION AS \"ordinalPosition\"
  91. FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
  92. INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE fkc
  93. ON fkc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
  94. AND fkc.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA
  95. WHERE 1=1
  96. $clause1
  97. $clause2
  98. "]
  99. dict set foreignKeysStatement $exists1 $exists2 $stmt
  100. }
  101. }
  102. }
  103. }
  104. #------------------------------------------------------------------------------
  105. #
  106. # tdbc::mysql::statement --
  107. #
  108. # The class 'tdbc::mysql::statement' models one statement against a
  109. # database accessed through an MYSQL connection
  110. #
  111. #------------------------------------------------------------------------------
  112. ::oo::class create ::tdbc::mysql::statement {
  113. superclass ::tdbc::statement
  114. # The 'resultSetCreate' method forwards to the constructor of the
  115. # result set.
  116. forward resultSetCreate ::tdbc::mysql::resultset create
  117. # Methods implemented in C:
  118. #
  119. # constructor connection SQLCode
  120. # The constructor accepts the handle to the connection and the SQL code
  121. # for the statement to prepare. It creates a subordinate namespace to
  122. # hold the statement's active result sets, and then delegates to the
  123. # 'init' method, written in C, to do the actual work of preparing the
  124. # statement.
  125. # params
  126. # Returns descriptions of the parameters of a statement.
  127. # paramtype paramname ?direction? type ?precision ?scale??
  128. # Declares the type of a parameter in the statement
  129. }
  130. #------------------------------------------------------------------------------
  131. #
  132. # tdbc::mysql::resultset --
  133. #
  134. # The class 'tdbc::mysql::resultset' models the result set that is
  135. # produced by executing a statement against an MYSQL database.
  136. #
  137. #------------------------------------------------------------------------------
  138. ::oo::class create ::tdbc::mysql::resultset {
  139. superclass ::tdbc::resultset
  140. # Methods implemented in C include:
  141. # constructor statement ?dictionary?
  142. # -- Executes the statement against the database, optionally providing
  143. # a dictionary of substituted parameters (default is to get params
  144. # from variables in the caller's scope).
  145. # columns
  146. # -- Returns a list of the names of the columns in the result.
  147. # nextdict
  148. # -- Stores the next row of the result set in the given variable in
  149. # the caller's scope as a dictionary whose keys are
  150. # column names and whose values are column values, or else
  151. # as a list of cells.
  152. # nextlist
  153. # -- Stores the next row of the result set in the given variable in
  154. # the caller's scope as a list of cells.
  155. # rowcount
  156. # -- Returns a count of rows affected by the statement, or -1
  157. # if the count of rows has not been determined.
  158. }