\documentclass[]{article}
\usepackage{amsmath,graphicx,supertabular,hyperref,tabularx,ifthen}
\title{TIP \#350: Tcl Database Connectivity --- Corrigenda}
\date{April 18, 2009}
\author{Kevin B. Kenny}
\urlstyle{sf}
\setlength{\parskip}{1ex}
\setlength{\parindent}{0pt}
\def\tipversion$#1${\texttt{\$#1\$}}
\def\tiplangle#1{\ensuremath{<}}
\def\tiprangle#1{\ensuremath{>}}
\def\tipbar#1{\ensuremath{|}}
\def\tipmail#1#2{\(\langle\){\small\expandafter\url{#1@#2}}\(\rangle\)}
\ifx\pdfoutput\undefined
\newcommand{\tipimage}[2]{\typeout{Make sure you download #1.eps}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.eps}}{\includegraphics[width=0.8\textwidth]{#1.eps}}}
\newcommand{\tipxref}[1]{}
\newcommand{\tipxrefend}{}
\else
\newcommand{\tipimage}[2]{\typeout{Make sure you create #1.pdf}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.pdf}}{\includegraphics[width=0.8\textwidth]{#1.pdf}}}
\pdfcatalog{/PageMode /UseOutlines}
\newcommand{\tipxref}[1]{\pdfannotlink attr {/C [0.5 0.5 1.0] /Border [0 0 1]} goto name {#1}}
\newcommand{\tipxrefend}{\pdfendlink}
\fi
\newenvironment{tipabstract}{\begin{abstract}}{\end{abstract}}
\begin{document}\maketitle
\begin{center}\begin{tabularx}{\linewidth}{|r@{: }X|}\hline
\textbf{TIP \#350}&\textbf{Tcl Database Connectivity --- Corrigenda}\\\hline
Author&

Kevin B. Kenny \tipmail{kennykb}{acm.org}
\\
Created&Saturday, \(\text{18}^{\text{th}}\) April 2009\\
Type&Informative\\
State&Draft\\
Vote&Pending\\
Version&\tipversion$Revision: 1.1 $\\
Obsoletes&308\\
Post History&\\
\hline\end{tabularx}\end{center}
\thispagestyle{empty}\pagestyle{empty}
\begin{tipabstract}

This TIP defines a common database access interface for Tcl scripts. It is an update to \cite{tip308} to take into account experience gained since that TIP was written. Note that this TIP does \textit{not} repeat the contents of that one, which is mostly correct apart from the changes described in this document.
\end{tipabstract}
\tableofcontents\setcounter{page}{0}\clearpage\pagestyle{plain}

\section{Summary of Changes}

Implementation experience on Tcl Database Connectivity \cite{tip308} has exposed several issues with its specification that require editorial corrections. In brief:
\begin{enumerate}
\item{}
The error codes returned from TDBC drivers are detailed in such a way as to make them more usable in the \textbf{try} command.
\item{}
The \textbf{starttransaction} method on a database connection is renamed, \textbf{begintransaction}
\item{}
The \textbf{execute} method on a statement, and all of the methods that invoke it (\textbf{allrows} and \textbf{foreach} 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.
\item{}
The order of arguments on the \textbf{foreach} methods on database connections, statements and result sets is changed.
\item{}
The \textit{statementClass} and \textit{resultSetClass} instance variables, and the \textit{init} method of connections, statements and result sets, are deprecated; a new initialization API is provided.
\item{}
A Tcl command, \textbf{tdbc::mapSqlState}, and a C function, \textbf{Tdbc\_MapSqlState} are provided for the convenience of driver writers.
\end{enumerate}

\section{Introduction}

The actual implementation of TDBC and three database drivers for it has revealed a handful of mistakes in the TDBC specification \cite{tip308}. The purpose of this TIP is to correct those errors and promulgate a specification that matches TDBC as implemented.

\section{Specification}

\subsection{Error Codes}

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 \textbf{TDBC}. The second should be an 'error class' chosen from the list below. The third should be the (usually five-character) SQL state that the database reported, or the constant string \textbf{HY000} if the SQL state cannot be determined. (In the latter case, the error class should be \textbf{GENERAL\_ERROR}.) 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.

The permissible values for the error class are as follows. Note that each one corresponds to the first two characters of a five-character 'SQL state' that is common to most SQL database API's; the SQL state corresponding to the class is also given.
\begingroup\small\begin{verbatim}
 SQL State
 Prefix     Error Class
 --------------------------------------------------------
    00      UNQUALIFIED_SUCCESSFUL_COMPLETION
    01      WARNING
    02      NO_DATA
    07      DYNAMIC_SQL_ERROR
    08      CONNECTION_EXCEPTION
    09      TRIGGERED_ACTION_EXCEPTION
    0A      FEATURE_NOT_SUPPORTED
    0B      INVALID_TRANSACTION_INITIATION
    0D      INVALID_TARGET_TYPE_SPECIFICATION
    0F      LOCATOR_EXCEPTION
    0K      INVALID_RESIGNAL_STATEMENT
    0L      INVALID_GRANTOR
    0P      INVALID_ROLE_SPECIFICATION
    0W      INVALID_STATEMENT_UN_TRIGGER
    20      CASE_NOT_FOUND_FOR_CASE_STATEMENT
    21      CARDINALITY_VIOLATION
    22      DATA_EXCEPTION
    23      CONSTRAINT_VIOLATION
    24      INVALID_CURSOR_STATE
    25      INVALID_TRANSACTION_STATE
    26      INVALID_SQL_STATEMENT_IDENTIFIER
    27      TRIGGERED_DATA_CHANGE_VIOLATION
    28      INVALID_AUTHORIZATION_SPECIFICATION
    2B      DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST
    2C      INVALID_CHARACTER_SET_NAME
    2D      INVALID_TRANSACTION_TERMINATION
    2E      INVALID_CONNECTION_NAME
    2F      SQL_ROUTINE_EXCEPTION
    33      INVALID_SQL_DESCRIPTOR_NAME
    34      INVALID_CURSOR_NAME
    35      INVALID_CONDITION_NUMBER
    36      CURSOR_SENSITIVITY_EXCEPTION
    37      SYNTAX_ERROR_OR_ACCESS_VIOLATION
    38      EXTERNAL_ROUTINE_EXCEPTION
    39      EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
    3B      SAVEPOINT_EXCEPTION
    3C      AMBIGUOUS_CURSOR_NAME
    3D      INVALID_CATALOG_NAME
    3F      INVALID_SCHEMA_NAME
    40      TRANSACTION_ROLLBACK
    42      SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION
    44      WITH_CHECK_OPTION_VIOLATION
    45      UNHANDLED_USER_DEFINED_EXCEPTION
    46      JAVA_DDL
    51      INVALID_APPLICATION_STATE
    53      INSUFFICIENT_RESOURCES
    54      PROGRAM_LIMIT_EXCEEDED
    55      OBJECT_NOT_IN_PREREQUISITE_STATE
    56      MISCELLANEOUS_SQL_OR_PRODUCT_ERROR
    57      RESOURCE_NOT_AVAILABLE_OR_OPERATOR_INTERVENTION
    58      SYSTEM_ERROR
    70      INTERRUPTED
    F0      CONFIGURATION_FILE_ERROR
    HY      GENERAL_ERROR
    HZ      REMOTE_DATABASE_ACCESS_ERROR
    IM      DRIVER_ERROR
    P0      PGSQL_PLSQL_ERROR
    S0      ODBC_2_0_DML_ERROR
    S1      ODBC_2_0_GENERAL_ERROR
    XA      TRANSACTION_ERROR
    XX      INTERNAL_ERROR
  anything
   else     UNKNOWN_SQLSTATE
\end{verbatim}
\endgroup

The reason for structuring the error codes in this way is to make errors more accessible to the \textbf{try} command \cite{tip329}. For instance, a Tcl script that wishes to detect and handle division by zero in a SQL statement might look like:
\begingroup\small\begin{verbatim}
  try {
      $statement foreach row {
          # ... process the row
      }
 } trap {TDBC DATA_EXCEPTION 22012} {
      puts "Division by zero!"
 }
\end{verbatim}
\endgroup

Since the previous specification \cite{tip308} left the error code unspecified, this change is not expected to impact any client code.

\subsection{Transaction Control}

The \textbf{begintransaction} method was inadvertently called, \textbf{starttransaction} in the TDBC specification. Therefore, the word \textbf{starttransaction} should be replaced with \textbf{begintransaction} wherever it appears.

This change will break no existing code; no \textbf{starttransaction} method has been defined for any TDBC driver.

\subsection{The '''execute''' Method of a Statement --- Variable Substitution}

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 \cite{tip308} fails to indicate what happens if a read trace on one of a statement's bound variables throws an error.

The sentence,

\begin{quote}
An array variable provided to a substituent MUST result in an error.
\end{quote}

is therefore to be replaced with:

\begin{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.
\end{quote}

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).

\subsection{The ''foreach'' Methods}

The syntax of the \textit{foreach} method of connections, statements, and result sets in the original specification contains editorial errors. The correct syntax is:

\begin{quote}
\textit{dbHandle} \textbf{foreach} ?\textbf{-as} \textbf{lists}\tipbar{}\textbf{dicts}? ?\textbf{-columnsvariable} \textit{varName}? ?-{}-? \textit{varName} \textit{sql} ?\textit{dictionary}? \textit{script}
\end{quote}

\begin{quote}
\textit{statement} \textbf{foreach} ?\textbf{-as} \textbf{lists}\tipbar{}\textbf{dicts}? ?\textbf{-columnsvariable} \textit{varName}? ?-{}-? \textit{varName} ?\textit{dictionary}? \textit{script}
\end{quote}

\begin{quote}
\textit{resultset} \textbf{foreach} ?\textbf{-as} \textbf{lists}\tipbar{}\textbf{dicts}? ?\textbf{-columnsvariable} \textit{varName}? ?-{}-? \textit{varName} \textit{script}
\end{quote}

This change represents an editorial correction; the reference implementation functioned in this way even prior to the acceptance of the original specification \cite{tip308}.

\subsection{The Constructor Patterns}

The \textit{statementClass} variable, and the \textbf{init} 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 \textbf{statementCreate} 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:
\begingroup\small\begin{verbatim}
  forward statementCreate ::driver::statement create
\end{verbatim}
\endgroup

If the \textbf{statementCreate} method is not present, the default one looks for a variable named \textit{statementClass} in the connection object, and invokes its \textbf{create} command.

In this way, drivers that are written to the original specification continue to operate.

Similarly, the \textit{resultSetClass} variable, and the \textbf{init} method, are no longer recommended for use in the constructors of statement classes. Instead, the statement class SHOULD implement a \textbf{resultSetCreate} method that accepts the fully qualified name of the command that will represent the result set, the statement handle, and the parameters to the \textbf{prepare} method. Once again, this method will usually simply be forwarded to the appropriate constructor:
\begingroup\small\begin{verbatim}
  forward resultSetCreate ::driver::resultSet create
\end{verbatim}
\endgroup

Once again, backward compatibility is provided by a \textbf{resultSetCreate} method in the base class. This method looks for a \textit{resultSetClass} variable in the statement instance, and interprets it as a class name, invoking the \textit{create} method in that class.

\textit{Rationale:} These changes eliminate several jumps among methods with \textbf{uplevel} calls, and yield both simpler code and improved performance.

\subsection{SQL State Mapping}

For the convenience of drivers that deal with database APIs that provide a standard SQL dtate in the event of errors, a Tcl command, \textbf{tdbc::mapSqlState} 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 \textbf{Error Codes} section above.

Similarly, A C function is provided:

\begin{quote}
const char * \textbf{Tdbc\_MapSqlState}(const char *\textit{sqlstate});
\end{quote}

This call looks up the given \textit{sqlstate} and returns its error class according to the table.

\section{License}

This file is explicitly released to the public domain and the author explicitly disclaims all rights under copyright law.

\section{Colophon}

\textit{TIP AutoGenerator --- written by Donal K. Fellows}
\begin{thebibliography}{TIP \#2}
\addcontentsline{toc}{section}{References}
\bibitem[TIP \#308]{tip308}
Kevin B. Kenny,
Artur Trzewik,
Andreas Leitgeb,
Donal K. Fellows,
\emph{Tcl Database Connectivity (TDBC)},
on-line at \url{http://purl.org/tcl/tip/308.html}
\bibitem[TIP \#329]{tip329}
Trevor Davel,
\emph{Try/Catch/Finally syntax},
on-line at \url{http://purl.org/tcl/tip/329.html}
\end{thebibliography}
\end{document}
