<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE TIP SYSTEM "http://tcl.activestate.com/cgi-bin/tct/tip/tipxml.dtd">
<!-- Converted at Wed May 16 20:12:54 GMT 2012 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='350'>
<header><title>Tcl Database Connectivity - Corrigenda</title><author address="mailto:kennykb@acm.org">Kevin B. Kenny</author><status type='informative' state='draft' vote='prior'>$Revision: 1.1 $</status><history></history><created day='18' month='apr' year='2009' /><obsoletes tip='308'/></header>
<abstract>This TIP defines a common database access interface for Tcl scripts. It is an update to <tipref type="text" tip="308"/> to take into account experience gained since that TIP was written. Note that this TIP does <emph style="italic">not</emph> repeat the contents of that one, which is mostly correct apart from the changes described in this document.</abstract>
<body><section title="Summary of Changes">
<para>Implementation experience on Tcl Database Connectivity <tipref type="text" tip="308"/> has exposed several issues with its specification that require editorial corrections. In brief:</para>
<enumerate><item.e index='1'><para>The error codes returned from TDBC drivers are detailed in such a way as to make them more usable in the <emph style="bold">try</emph> command.</para></item.e><item.e index='2'><para>The <emph style="bold">starttransaction</emph> method on a database connection is renamed, <emph style="bold">begintransaction</emph></para></item.e><item.e index='3'><para>The <emph style="bold">execute</emph> method on a statement, and all of the methods that invoke it (<emph style="bold">allrows</emph> and <emph style="bold">foreach</emph> on database connections) changes its behaviour in the case where a bound variable in its SQL code refers to a Tcl variable that is an array, or a read trace on the associated variable fails.</para></item.e><item.e index='4'><para>The order of arguments on the <emph style="bold">foreach</emph> methods on database connections, statements and result sets is changed.</para></item.e><item.e index='5'><para>The <emph style="italic">statementClass</emph> and <emph style="italic">resultSetClass</emph> instance variables, and the <emph style="italic">init</emph> method of connections, statements and result sets, are deprecated; a new initialization API is provided.</para></item.e><item.e index='6'><para>A Tcl command, <emph style="bold">tdbc::mapSqlState</emph>, and a C function, <emph style="bold">Tdbc_MapSqlState</emph> are provided for the convenience of driver writers.</para></item.e></enumerate>
</section>
<section title="Introduction">
<para>The actual implementation of TDBC and three database drivers for it has revealed a handful of mistakes in the TDBC specification <tipref type="text" tip="308"/>. The purpose of this TIP is to correct those errors and promulgate a specification that matches TDBC as implemented.</para>
</section>
<section title="Specification">

<subsection title="Error Codes">
<para>Whenever a TDBC driver reports an error in interacting with an underlying database, it SHOULD set the interpreter error code to a list of at least four elements. The first element should be the constant string <emph style="bold">TDBC</emph>. The second should be an &apos;error class&apos; chosen from the list below. The third should be the (usually five-character) SQL state that the database reported, or the constant string <emph style="bold">HY000</emph> if the SQL state cannot be determined. (In the latter case, the error class should be <emph style="bold">GENERAL_ERROR</emph>.) The fourth element should be the name of the TDBC driver that reported the error. Any elements beyond the fourth SHOULD give further details (for example an error code returned by a native API), and are driver dependent.</para>
<para>The permissible values for the error class are as follows. Note that each one corresponds to the first two characters of a five-character &apos;SQL state&apos; that is common to most SQL database API&apos;s; the SQL state corresponding to the class is also given.</para>
<verbatim><vline encoding='base64'>IFNRTCBTdGF0ZQ==</vline><vline encoding='base64'>IFByZWZpeCAgICAgRXJyb3IgQ2xhc3M=</vline><vline encoding='base64'>IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t</vline><vline encoding='base64'>ICAgIDAwICAgICAgVU5RVUFMSUZJRURfU1VDQ0VTU0ZVTF9DT01QTEVUSU9O</vline><vline encoding='base64'>ICAgIDAxICAgICAgV0FSTklORw==</vline><vline encoding='base64'>ICAgIDAyICAgICAgTk9fREFUQQ==</vline><vline encoding='base64'>ICAgIDA3ICAgICAgRFlOQU1JQ19TUUxfRVJST1I=</vline><vline encoding='base64'>ICAgIDA4ICAgICAgQ09OTkVDVElPTl9FWENFUFRJT04=</vline><vline encoding='base64'>ICAgIDA5ICAgICAgVFJJR0dFUkVEX0FDVElPTl9FWENFUFRJT04=</vline><vline encoding='base64'>ICAgIDBBICAgICAgRkVBVFVSRV9OT1RfU1VQUE9SVEVE</vline><vline encoding='base64'>ICAgIDBCICAgICAgSU5WQUxJRF9UUkFOU0FDVElPTl9JTklUSUFUSU9O</vline><vline encoding='base64'>ICAgIDBEICAgICAgSU5WQUxJRF9UQVJHRVRfVFlQRV9TUEVDSUZJQ0FUSU9O</vline><vline encoding='base64'>ICAgIDBGICAgICAgTE9DQVRPUl9FWENFUFRJT04=</vline><vline encoding='base64'>ICAgIDBLICAgICAgSU5WQUxJRF9SRVNJR05BTF9TVEFURU1FTlQ=</vline><vline encoding='base64'>ICAgIDBMICAgICAgSU5WQUxJRF9HUkFOVE9S</vline><vline encoding='base64'>ICAgIDBQICAgICAgSU5WQUxJRF9ST0xFX1NQRUNJRklDQVRJT04=</vline><vline encoding='base64'>ICAgIDBXICAgICAgSU5WQUxJRF9TVEFURU1FTlRfVU5fVFJJR0dFUg==</vline><vline encoding='base64'>ICAgIDIwICAgICAgQ0FTRV9OT1RfRk9VTkRfRk9SX0NBU0VfU1RBVEVNRU5U</vline><vline encoding='base64'>ICAgIDIxICAgICAgQ0FSRElOQUxJVFlfVklPTEFUSU9O</vline><vline encoding='base64'>ICAgIDIyICAgICAgREFUQV9FWENFUFRJT04=</vline><vline encoding='base64'>ICAgIDIzICAgICAgQ09OU1RSQUlOVF9WSU9MQVRJT04=</vline><vline encoding='base64'>ICAgIDI0ICAgICAgSU5WQUxJRF9DVVJTT1JfU1RBVEU=</vline><vline encoding='base64'>ICAgIDI1ICAgICAgSU5WQUxJRF9UUkFOU0FDVElPTl9TVEFURQ==</vline><vline encoding='base64'>ICAgIDI2ICAgICAgSU5WQUxJRF9TUUxfU1RBVEVNRU5UX0lERU5USUZJRVI=</vline><vline encoding='base64'>ICAgIDI3ICAgICAgVFJJR0dFUkVEX0RBVEFfQ0hBTkdFX1ZJT0xBVElPTg==</vline><vline encoding='base64'>ICAgIDI4ICAgICAgSU5WQUxJRF9BVVRIT1JJWkFUSU9OX1NQRUNJRklDQVRJT04=</vline><vline encoding='base64'>ICAgIDJCICAgICAgREVQRU5ERU5UX1BSSVZJTEVHRV9ERVNDUklQVE9SU19TVElMTF9FWElTVA==</vline><vline encoding='base64'>ICAgIDJDICAgICAgSU5WQUxJRF9DSEFSQUNURVJfU0VUX05BTUU=</vline><vline encoding='base64'>ICAgIDJEICAgICAgSU5WQUxJRF9UUkFOU0FDVElPTl9URVJNSU5BVElPTg==</vline><vline encoding='base64'>ICAgIDJFICAgICAgSU5WQUxJRF9DT05ORUNUSU9OX05BTUU=</vline><vline encoding='base64'>ICAgIDJGICAgICAgU1FMX1JPVVRJTkVfRVhDRVBUSU9O</vline><vline encoding='base64'>ICAgIDMzICAgICAgSU5WQUxJRF9TUUxfREVTQ1JJUFRPUl9OQU1F</vline><vline encoding='base64'>ICAgIDM0ICAgICAgSU5WQUxJRF9DVVJTT1JfTkFNRQ==</vline><vline encoding='base64'>ICAgIDM1ICAgICAgSU5WQUxJRF9DT05ESVRJT05fTlVNQkVS</vline><vline encoding='base64'>ICAgIDM2ICAgICAgQ1VSU09SX1NFTlNJVElWSVRZX0VYQ0VQVElPTg==</vline><vline encoding='base64'>ICAgIDM3ICAgICAgU1lOVEFYX0VSUk9SX09SX0FDQ0VTU19WSU9MQVRJT04=</vline><vline encoding='base64'>ICAgIDM4ICAgICAgRVhURVJOQUxfUk9VVElORV9FWENFUFRJT04=</vline><vline encoding='base64'>ICAgIDM5ICAgICAgRVhURVJOQUxfUk9VVElORV9JTlZPQ0FUSU9OX0VYQ0VQVElPTg==</vline><vline encoding='base64'>ICAgIDNCICAgICAgU0FWRVBPSU5UX0VYQ0VQVElPTg==</vline><vline encoding='base64'>ICAgIDNDICAgICAgQU1CSUdVT1VTX0NVUlNPUl9OQU1F</vline><vline encoding='base64'>ICAgIDNEICAgICAgSU5WQUxJRF9DQVRBTE9HX05BTUU=</vline><vline encoding='base64'>ICAgIDNGICAgICAgSU5WQUxJRF9TQ0hFTUFfTkFNRQ==</vline><vline encoding='base64'>ICAgIDQwICAgICAgVFJBTlNBQ1RJT05fUk9MTEJBQ0s=</vline><vline encoding='base64'>ICAgIDQyICAgICAgU1lOVEFYX0VSUk9SX09SX0FDQ0VTU19SVUxFX1ZJT0xBVElPTg==</vline><vline encoding='base64'>ICAgIDQ0ICAgICAgV0lUSF9DSEVDS19PUFRJT05fVklPTEFUSU9O</vline><vline encoding='base64'>ICAgIDQ1ICAgICAgVU5IQU5ETEVEX1VTRVJfREVGSU5FRF9FWENFUFRJT04=</vline><vline encoding='base64'>ICAgIDQ2ICAgICAgSkFWQV9EREw=</vline><vline encoding='base64'>ICAgIDUxICAgICAgSU5WQUxJRF9BUFBMSUNBVElPTl9TVEFURQ==</vline><vline encoding='base64'>ICAgIDUzICAgICAgSU5TVUZGSUNJRU5UX1JFU09VUkNFUw==</vline><vline encoding='base64'>ICAgIDU0ICAgICAgUFJPR1JBTV9MSU1JVF9FWENFRURFRA==</vline><vline encoding='base64'>ICAgIDU1ICAgICAgT0JKRUNUX05PVF9JTl9QUkVSRVFVSVNJVEVfU1RBVEU=</vline><vline encoding='base64'>ICAgIDU2ICAgICAgTUlTQ0VMTEFORU9VU19TUUxfT1JfUFJPRFVDVF9FUlJPUg==</vline><vline encoding='base64'>ICAgIDU3ICAgICAgUkVTT1VSQ0VfTk9UX0FWQUlMQUJMRV9PUl9PUEVSQVRPUl9JTlRFUlZFTlRJT04=</vline><vline encoding='base64'>ICAgIDU4ICAgICAgU1lTVEVNX0VSUk9S</vline><vline encoding='base64'>ICAgIDcwICAgICAgSU5URVJSVVBURUQ=</vline><vline encoding='base64'>ICAgIEYwICAgICAgQ09ORklHVVJBVElPTl9GSUxFX0VSUk9S</vline><vline encoding='base64'>ICAgIEhZICAgICAgR0VORVJBTF9FUlJPUg==</vline><vline encoding='base64'>ICAgIEhaICAgICAgUkVNT1RFX0RBVEFCQVNFX0FDQ0VTU19FUlJPUg==</vline><vline encoding='base64'>ICAgIElNICAgICAgRFJJVkVSX0VSUk9S</vline><vline encoding='base64'>ICAgIFAwICAgICAgUEdTUUxfUExTUUxfRVJST1I=</vline><vline encoding='base64'>ICAgIFMwICAgICAgT0RCQ18yXzBfRE1MX0VSUk9S</vline><vline encoding='base64'>ICAgIFMxICAgICAgT0RCQ18yXzBfR0VORVJBTF9FUlJPUg==</vline><vline encoding='base64'>ICAgIFhBICAgICAgVFJBTlNBQ1RJT05fRVJST1I=</vline><vline encoding='base64'>ICAgIFhYICAgICAgSU5URVJOQUxfRVJST1I=</vline><vline encoding='base64'>ICBhbnl0aGluZw==</vline><vline encoding='base64'>ICAgZWxzZSAgICAgVU5LTk9XTl9TUUxTVEFURQ==</vline></verbatim>
<para>The reason for structuring the error codes in this way is to make errors more accessible to the <emph style="bold">try</emph> command <tipref type="text" tip="329"/>. For instance, a Tcl script that wishes to detect and handle division by zero in a SQL statement might look like:</para>
<verbatim><vline encoding='base64'>ICB0cnkgew==</vline><vline encoding='base64'>ICAgICAgJHN0YXRlbWVudCBmb3JlYWNoIHJvdyB7</vline><vline encoding='base64'>ICAgICAgICAgICMgLi4uIHByb2Nlc3MgdGhlIHJvdw==</vline><vline encoding='base64'>ICAgICAgfQ==</vline><vline encoding='base64'>IH0gdHJhcCB7VERCQyBEQVRBX0VYQ0VQVElPTiAyMjAxMn0gew==</vline><vline encoding='base64'>ICAgICAgcHV0cyAiRGl2aXNpb24gYnkgemVybyEi</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>Since the previous specification <tipref type="text" tip="308"/> left the error code unspecified, this change is not expected to impact any client code.</para>
</subsection>
<subsection title="Transaction Control">
<para>The <emph style="bold">begintransaction</emph> method was inadvertently called, <emph style="bold">starttransaction</emph> in the TDBC specification. Therefore, the word <emph style="bold">starttransaction</emph> should be replaced with <emph style="bold">begintransaction</emph> wherever it appears.</para>
<para>This change will break no existing code; no <emph style="bold">starttransaction</emph> method has been defined for any TDBC driver.</para>
</subsection>
<subsection title="The &apos;&apos;&apos;execute&apos;&apos;&apos; Method of a Statement - Variable Substitution">
<para>The rule that an array variable provided as a bound value to a substituent in a SQL statement MUST result in an error has proven to be awkward to implement in practice. Moreover, the original specification <tipref type="text" tip="308"/> fails to indicate what happens if a read trace on one of a statement&apos;s bound variables throws an error.</para>
<para>The sentence,</para>
<quote>An array variable provided to a substituent MUST result in an error.</quote>
<para>is therefore to be replaced with:</para>
<quote>An array variable provided to a substituent, or a variable in which substitution results in an error being reported by a read trace, MUST result in a NULL value being provided.</quote>
<para>This change is expected to have minimal impact on existing code; the behaviour being described is simply providing a NULL value for a case that was an error before (an array where a scalar is expected) and a case that was unspecified before (an error within a variable trace).</para>
</subsection>
<subsection title="The &apos;&apos;foreach&apos;&apos; Methods">
<para>The syntax of the <emph style="italic">foreach</emph> method of connections, statements, and result sets in the original specification contains editorial errors. The correct syntax is:</para>
<quote><emph style="italic">dbHandle</emph> <emph style="bold">foreach</emph> ?<emph style="bold">-as</emph> <emph style="bold">lists</emph>|<emph style="bold">dicts</emph>? ?<emph style="bold">-columnsvariable</emph> <emph style="italic">varName</emph>? ?--? <emph style="italic">varName</emph> <emph style="italic">sql</emph> ?<emph style="italic">dictionary</emph>? <emph style="italic">script</emph></quote>
<quote><emph style="italic">statement</emph> <emph style="bold">foreach</emph> ?<emph style="bold">-as</emph> <emph style="bold">lists</emph>|<emph style="bold">dicts</emph>? ?<emph style="bold">-columnsvariable</emph> <emph style="italic">varName</emph>? ?--? <emph style="italic">varName</emph> ?<emph style="italic">dictionary</emph>? <emph style="italic">script</emph></quote>
<quote><emph style="italic">resultset</emph> <emph style="bold">foreach</emph> ?<emph style="bold">-as</emph> <emph style="bold">lists</emph>|<emph style="bold">dicts</emph>? ?<emph style="bold">-columnsvariable</emph> <emph style="italic">varName</emph>? ?--? <emph style="italic">varName</emph> <emph style="italic">script</emph></quote>
<para>This change represents an editorial correction; the reference implementation functioned in this way even prior to the acceptance of the original specification <tipref type="text" tip="308"/>.</para>
</subsection>
<subsection title="The Constructor Patterns">
<para>The <emph style="italic">statementClass</emph> variable, and the <emph style="bold">init</emph> method, are no longer recommended for use in the constructors of connection classes. Instead, the recommended pattern is that a connection class SHOULD implement a <emph style="bold">statementCreate</emph> method that accepts the fully qualified name of the command that is to represent the statement, the connection handle and the SQL statement, and returns a handle to the statement object. The usual way to do so is with a forwarded method:</para>
<verbatim><vline encoding='base64'>ICBmb3J3YXJkIHN0YXRlbWVudENyZWF0ZSA6OmRyaXZlcjo6c3RhdGVtZW50IGNyZWF0ZQ==</vline></verbatim>
<para>If the <emph style="bold">statementCreate</emph> method is not present, the default one looks for a variable named <emph style="italic">statementClass</emph> in the connection object, and invokes its <emph style="bold">create</emph> command.</para>
<para>In this way, drivers that are written to the original specification continue to operate.</para>
<para>Similarly, the <emph style="italic">resultSetClass</emph> variable, and the <emph style="bold">init</emph> method, are no longer recommended for use in the constructors of statement classes. Instead, the statement class SHOULD implement a <emph style="bold">resultSetCreate</emph> method that accepts the fully qualified name of the command that will represent the result set, the statement handle, and the parameters to the <emph style="bold">prepare</emph> method. Once again, this method will usually simply be forwarded to the appropriate constructor:</para>
<verbatim><vline encoding='base64'>ICBmb3J3YXJkIHJlc3VsdFNldENyZWF0ZSA6OmRyaXZlcjo6cmVzdWx0U2V0IGNyZWF0ZQ==</vline></verbatim>
<para>Once again, backward compatibility is provided by a <emph style="bold">resultSetCreate</emph> method in the base class. This method looks for a <emph style="italic">resultSetClass</emph> variable in the statement instance, and interprets it as a class name, invoking the <emph style="italic">create</emph> method in that class.</para>
<para><emph style="italic">Rationale:</emph> These changes eliminate several jumps among methods with <emph style="bold">uplevel</emph> calls, and yield both simpler code and improved performance.</para>
</subsection>
<subsection title="SQL State Mapping">
<para>For the convenience of drivers that deal with database APIs that provide a standard SQL dtate in the event of errors, a Tcl command, <emph style="bold">tdbc::mapSqlState</emph> is provided. This command accepts a (usually five character) SQL state, and returns the error class that should go in the second element of the error code. The mapping is described in the table in the <emph style="bold">Error Codes</emph> section above.</para>
<para>Similarly, A C function is provided:</para>
<quote>const char * <emph style="bold">Tdbc_MapSqlState</emph>(const char *<emph style="italic">sqlstate</emph>);</quote>
<para>This call looks up the given <emph style="italic">sqlstate</emph> and returns its error class according to the table.</para>
</subsection>
</section>
<section title="License">
<para>This file is explicitly released to the public domain and the author explicitly disclaims all rights under copyright law.</para>
</section>
</body></TIP>

