233 lines
6.6 KiB
C
233 lines
6.6 KiB
C
|
/*
|
|||
|
* tdbc.c --
|
|||
|
*
|
|||
|
* Basic services for TDBC (Tcl DataBase Connectivity)
|
|||
|
*
|
|||
|
* Copyright (c) 2008 by Kevin B. Kenny.
|
|||
|
*
|
|||
|
* Please refer to the file, 'license.terms' for the conditions on
|
|||
|
* redistribution of this file and for a DISCLAIMER OF ALL WARRANTIES.
|
|||
|
*
|
|||
|
* RCS: @(#) $Id$
|
|||
|
*
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
#include <tcl.h>
|
|||
|
#include <string.h>
|
|||
|
#include "tdbcInt.h"
|
|||
|
|
|||
|
/* Static procedures declared in this file */
|
|||
|
|
|||
|
static int TdbcMapSqlStateObjCmd(ClientData unused, Tcl_Interp* interp,
|
|||
|
int objc, Tcl_Obj *const objv[]);
|
|||
|
|
|||
|
MODULE_SCOPE const TdbcStubs tdbcStubs;
|
|||
|
|
|||
|
/* Table of commands to create for TDBC */
|
|||
|
|
|||
|
static const struct TdbcCommand {
|
|||
|
const char* name; /* Name of the command */
|
|||
|
Tcl_ObjCmdProc* proc; /* Command procedure */
|
|||
|
} commandTable[] = {
|
|||
|
{ "::tdbc::mapSqlState", TdbcMapSqlStateObjCmd },
|
|||
|
{ "::tdbc::tokenize", TdbcTokenizeObjCmd },
|
|||
|
{ NULL, NULL },
|
|||
|
};
|
|||
|
|
|||
|
/* Table mapping SQLSTATE to error code */
|
|||
|
|
|||
|
static const struct SqlStateLookup {
|
|||
|
const char* stateclass;
|
|||
|
const char* message;
|
|||
|
} StateLookup [] = {
|
|||
|
{ "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" },
|
|||
|
{ NULL, NULL }
|
|||
|
};
|
|||
|
|
|||
|
/*
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
*
|
|||
|
* Tdbc_MapSqlState --
|
|||
|
*
|
|||
|
* Maps the 'sqlstate' return from a database error to a key
|
|||
|
* to place in the '::errorCode' variable.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Returns the key.
|
|||
|
*
|
|||
|
* This procedure examines only the first two characters of 'sqlstate',
|
|||
|
* which are fairly portable among databases. The remaining three characters
|
|||
|
* are ignored. The result is that state '22012' (Division by zero)
|
|||
|
* is returned as 'data exception', while state '23505' (Unique key
|
|||
|
* constraint violation) is returned as 'constraint violation'.
|
|||
|
*
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
*/
|
|||
|
TDBCAPI const char*
|
|||
|
Tdbc_MapSqlState(const char* sqlstate)
|
|||
|
{
|
|||
|
int i;
|
|||
|
for (i = 0; StateLookup[i].stateclass != NULL; ++i) {
|
|||
|
if (!strncmp(sqlstate, StateLookup[i].stateclass, 2)) {
|
|||
|
return StateLookup[i].message;
|
|||
|
}
|
|||
|
}
|
|||
|
return "UNKNOWN_SQLSTATE";
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TdbcMapSqlStateObjCmd --
|
|||
|
*
|
|||
|
* Command to call from a Tcl script to get a string that describes
|
|||
|
* a SQLSTATE
|
|||
|
*
|
|||
|
* Usage:
|
|||
|
* tdbc::mapSqlState state
|
|||
|
*
|
|||
|
* Parameters:
|
|||
|
* state -- A five-character SQLSTATE
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* Returns a one-word token suitable for interpolating into
|
|||
|
* errorInfo
|
|||
|
*
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
static int
|
|||
|
TdbcMapSqlStateObjCmd(
|
|||
|
ClientData dummy, /* No client data */
|
|||
|
Tcl_Interp* interp, /* Tcl interpreter */
|
|||
|
int objc, /* Parameter count */
|
|||
|
Tcl_Obj *const objv[] /* Parameter vector */
|
|||
|
) {
|
|||
|
(void)dummy;
|
|||
|
|
|||
|
if (objc != 2) {
|
|||
|
Tcl_WrongNumArgs(interp, 1, objv, "sqlstate");
|
|||
|
return TCL_ERROR;
|
|||
|
} else {
|
|||
|
const char* sqlstate = Tcl_GetString(objv[1]);
|
|||
|
Tcl_SetObjResult(interp, Tcl_NewStringObj(Tdbc_MapSqlState(sqlstate),
|
|||
|
-1));
|
|||
|
return TCL_OK;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
*
|
|||
|
* Tdbc_Init --
|
|||
|
*
|
|||
|
* Initializes the TDBC framework when this library is loaded.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
*
|
|||
|
* Creates a ::tdbc namespace and a ::tdbc::Connection class
|
|||
|
* from which the connection objects created by a TDBC driver
|
|||
|
* may inherit.
|
|||
|
*
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef __cplusplus
|
|||
|
extern "C" {
|
|||
|
#endif /* __cplusplus */
|
|||
|
DLLEXPORT int
|
|||
|
Tdbc_Init(
|
|||
|
Tcl_Interp* interp /* Tcl interpreter */
|
|||
|
) {
|
|||
|
|
|||
|
int i;
|
|||
|
|
|||
|
/* Require Tcl */
|
|||
|
|
|||
|
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
|
|||
|
return TCL_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
/* Create the provided commands */
|
|||
|
|
|||
|
for (i = 0; commandTable[i].name != NULL; ++i) {
|
|||
|
Tcl_CreateObjCommand(interp, commandTable[i].name, commandTable[i].proc,
|
|||
|
(ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
|
|||
|
}
|
|||
|
|
|||
|
/* Provide the TDBC package */
|
|||
|
|
|||
|
if (Tcl_PkgProvideEx(interp, PACKAGE_NAME, PACKAGE_VERSION,
|
|||
|
(ClientData) &tdbcStubs) == TCL_ERROR) {
|
|||
|
return TCL_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
return TCL_OK;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#ifdef __cplusplus
|
|||
|
}
|
|||
|
#endif /* __cplusplus */
|