Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | New method '$odbcConnection evaldirect' to support SQL code that cannot be prepared or is mangled by the tokenizer (see bug [751477d142]). odbc::connection method 'evaldirect' constructs a subclass 'evaldirectStatement' of odbc::statement that does not tokenize or prepare the SQL statement. The SQL is executed via ODBC API function SQLExecDirectW, and the result set is flattened into a list of dicts (as for '$resultset allrows -as dicts') that is returned by 'evaldirect'. Approach suggested by KBK. Prototype implementation and docs provided; tests to follow. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | bug-751477d142-td |
Files: | files | file ages | folders |
SHA1: |
3ec6cefd876818119e49e0323ddcb047 |
User & Date: | twylite 2013-01-15 16:50:43.954 |
Context
2022-06-16
| ||
14:52 | Rebase to trunk check-in: c7eef045bc user: jan.nijtmans tags: bug-751477d142-td | |
2013-01-15
| ||
16:50 | New method '$odbcConnection evaldirect' to support SQL code that cannot be prepared or is mangled by the tokenizer (see bug [751477d142]). odbc::connection method 'evaldirect' constructs a subclass 'evaldirectStatement' of odbc::statement that does not tokenize or prepare the SQL statement. The SQL is executed via ODBC API function SQLExecDirectW, and the result set is flattened into a list of dicts (as for '$resultset allrows -as dicts') that is returned by 'evaldirect'. Approach suggested by KBK. Prototype implementation and docs provided; tests to follow. check-in: 3ec6cefd87 user: twylite tags: bug-751477d142-td | |
2012-12-10
| ||
15:07 | Put win/* nmake support files in the distribution. check-in: 10638f86a3 user: dgp tags: trunk, tdbcodbc-1-0-0 | |
Changes
Changes to doc/tdbc_odbc.n.
︙ | ︙ | |||
203 204 205 206 207 208 209 210 211 212 213 214 215 216 | {Microsoft Access Driver (*.mdb)} \\ CREATE_DB=[file native [file normalize $fileName]] \\ General .CE Creates a new, empty Microsoft Access database in the file identified by "$fileName". No connection is made to the database until the program calls \fBtdbc::odbc::connection create\fR. .SH "SEE ALSO" tdbc(n), tdbc::connection(n), tdbc::resultset(n), tdbc::statement(n) .SH "KEYWORDS" TDBC, SQL, ODBC, database, connectivity, connection .SH "COPYRIGHT" Copyright (c) 2008 by Kevin B. Kenny. .\" Local Variables: | > > > > > > > > > > > > > > > > | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | {Microsoft Access Driver (*.mdb)} \\ CREATE_DB=[file native [file normalize $fileName]] \\ General .CE Creates a new, empty Microsoft Access database in the file identified by "$fileName". No connection is made to the database until the program calls \fBtdbc::odbc::connection create\fR. .SH "ADDITIONAL CONNECTION METHODS" In addition to the usual methods on the tdbc::connection(n) object, connections to an ODBC database support one additional method: .IP \fI$connection\fR \fBevaldirect\fR \fIsqlStatement\fR This method takes the given driver-native SQL code \fIsqlStatement\fR and evaluates it without preparing it. The statement is not tokenized and must not contain variable substitutions. Evaluating the \fIsqlStatement\fR produces a result set of zero or more rows. The result of the command is a list of dictionaries, with one list element per row in the result set (in a similar format to the list returned by \fI$connection allrows -as dicts\fI). \fIThis command is not recommended\fR for anything where the usual \fIprepare\fR or \fIpreparecall\fR methods work correctly. It is provided so that data management language statements that are not implemented by the driver's prepared statement API (such as \fBCREATE DATABASE\fR or \fBCREATE PROCEDURE\fR), or that contain characters that are reserved by the tokenizer, can be executed. .SH "SEE ALSO" tdbc(n), tdbc::connection(n), tdbc::resultset(n), tdbc::statement(n) .SH "KEYWORDS" TDBC, SQL, ODBC, database, connectivity, connection .SH "COPYRIGHT" Copyright (c) 2008 by Kevin B. Kenny. .\" Local Variables: |
︙ | ︙ |
Changes to generic/odbcStubDefs.txt.
︙ | ︙ | |||
41 42 43 44 45 46 47 | SQLRETURN SQLPrepareW(SQLHSTMT,SQLWCHAR*,SQLINTEGER); SQLRETURN SQLPrimaryKeysW(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT); SQLRETURN SQLRowCount(SQLHSTMT,SQLLEN*); SQLRETURN SQLSetConnectAttr(SQLHDBC,SQLINTEGER,SQLPOINTER,SQLINTEGER); SQLRETURN SQLSetConnectOption(SQLHDBC,SQLUSMALLINT,SQLULEN); /* deprecated */ SQLRETURN SQLSetEnvAttr(SQLHENV,SQLINTEGER,SQLPOINTER,SQLINTEGER); SQLRETURN SQLTablesW(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT); | > | 41 42 43 44 45 46 47 48 | SQLRETURN SQLPrepareW(SQLHSTMT,SQLWCHAR*,SQLINTEGER); SQLRETURN SQLPrimaryKeysW(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT); SQLRETURN SQLRowCount(SQLHSTMT,SQLLEN*); SQLRETURN SQLSetConnectAttr(SQLHDBC,SQLINTEGER,SQLPOINTER,SQLINTEGER); SQLRETURN SQLSetConnectOption(SQLHDBC,SQLUSMALLINT,SQLULEN); /* deprecated */ SQLRETURN SQLSetEnvAttr(SQLHENV,SQLINTEGER,SQLPOINTER,SQLINTEGER); SQLRETURN SQLTablesW(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT); SQLRETURN SQLExecDirectW(SQLHSTMT,SQLWCHAR*,SQLINTEGER); |
Changes to generic/odbcStubInit.c.
1 2 3 4 5 6 | /* * odbcStubInit.c -- * * Stubs tables for the foreign ODBC libraries so that * Tcl extensions can use them without the linker's knowing about them. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * odbcStubInit.c -- * * Stubs tables for the foreign ODBC libraries so that * Tcl extensions can use them without the linker's knowing about them. * * @CREATED@ 2013-01-15 10:22:09Z by genExtStubs.tcl from ./odbcStubDefs.txt * * Copyright (c) 2010 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. * *----------------------------------------------------------------------------- |
︙ | ︙ | |||
71 72 73 74 75 76 77 78 79 80 81 82 83 84 | "SQLPrepareW", "SQLPrimaryKeysW", "SQLRowCount", "SQLSetConnectAttr", "SQLSetConnectOption", "SQLSetEnvAttr", "SQLTablesW", NULL /* @END@ */ }; /* * Table containing pointers to the functions named above. */ | > | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | "SQLPrepareW", "SQLPrimaryKeysW", "SQLRowCount", "SQLSetConnectAttr", "SQLSetConnectOption", "SQLSetEnvAttr", "SQLTablesW", "SQLExecDirectW", NULL /* @END@ */ }; /* * Table containing pointers to the functions named above. */ |
︙ | ︙ |
Changes to generic/odbcStubs.h.
1 2 3 | /* *----------------------------------------------------------------------------- * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* *----------------------------------------------------------------------------- * * odbcStubs.h -- * * Stubs for procedures in odbcStubDefs.txt * * Generated by genExtStubs.tcl: DO NOT EDIT * 2013-01-15 10:22:09Z * *----------------------------------------------------------------------------- */ typedef struct odbcStubDefs { /* Functions from libraries: odbc32 odbc libodbc32 libodbc */ |
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 | SQLRETURN (SQL_API*SQLPrepareWPtr)(SQLHSTMT,SQLWCHAR*,SQLINTEGER); SQLRETURN (SQL_API*SQLPrimaryKeysWPtr)(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT); SQLRETURN (SQL_API*SQLRowCountPtr)(SQLHSTMT,SQLLEN*); SQLRETURN (SQL_API*SQLSetConnectAttrPtr)(SQLHDBC,SQLINTEGER,SQLPOINTER,SQLINTEGER); SQLRETURN (SQL_API*SQLSetConnectOptionPtr)(SQLHDBC,SQLUSMALLINT,SQLULEN); SQLRETURN (SQL_API*SQLSetEnvAttrPtr)(SQLHENV,SQLINTEGER,SQLPOINTER,SQLINTEGER); SQLRETURN (SQL_API*SQLTablesWPtr)(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT); } odbcStubDefs; #define SQLAllocHandle (odbcStubs->SQLAllocHandlePtr) #define SQLBindParameter (odbcStubs->SQLBindParameterPtr) #define SQLCloseCursor (odbcStubs->SQLCloseCursorPtr) #define SQLColumnsW (odbcStubs->SQLColumnsWPtr) #define SQLDataSourcesW (odbcStubs->SQLDataSourcesWPtr) #define SQLDescribeColW (odbcStubs->SQLDescribeColWPtr) | > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | SQLRETURN (SQL_API*SQLPrepareWPtr)(SQLHSTMT,SQLWCHAR*,SQLINTEGER); SQLRETURN (SQL_API*SQLPrimaryKeysWPtr)(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT); SQLRETURN (SQL_API*SQLRowCountPtr)(SQLHSTMT,SQLLEN*); SQLRETURN (SQL_API*SQLSetConnectAttrPtr)(SQLHDBC,SQLINTEGER,SQLPOINTER,SQLINTEGER); SQLRETURN (SQL_API*SQLSetConnectOptionPtr)(SQLHDBC,SQLUSMALLINT,SQLULEN); SQLRETURN (SQL_API*SQLSetEnvAttrPtr)(SQLHENV,SQLINTEGER,SQLPOINTER,SQLINTEGER); SQLRETURN (SQL_API*SQLTablesWPtr)(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT); SQLRETURN (SQL_API*SQLExecDirectWPtr)(SQLHSTMT,SQLWCHAR*,SQLINTEGER); } odbcStubDefs; #define SQLAllocHandle (odbcStubs->SQLAllocHandlePtr) #define SQLBindParameter (odbcStubs->SQLBindParameterPtr) #define SQLCloseCursor (odbcStubs->SQLCloseCursorPtr) #define SQLColumnsW (odbcStubs->SQLColumnsWPtr) #define SQLDataSourcesW (odbcStubs->SQLDataSourcesWPtr) #define SQLDescribeColW (odbcStubs->SQLDescribeColWPtr) |
︙ | ︙ | |||
72 73 74 75 76 77 78 79 | #define SQLPrepareW (odbcStubs->SQLPrepareWPtr) #define SQLPrimaryKeysW (odbcStubs->SQLPrimaryKeysWPtr) #define SQLRowCount (odbcStubs->SQLRowCountPtr) #define SQLSetConnectAttr (odbcStubs->SQLSetConnectAttrPtr) #define SQLSetConnectOption (odbcStubs->SQLSetConnectOptionPtr) #define SQLSetEnvAttr (odbcStubs->SQLSetEnvAttrPtr) #define SQLTablesW (odbcStubs->SQLTablesWPtr) MODULE_SCOPE odbcStubDefs *odbcStubs; | > | 73 74 75 76 77 78 79 80 81 | #define SQLPrepareW (odbcStubs->SQLPrepareWPtr) #define SQLPrimaryKeysW (odbcStubs->SQLPrimaryKeysWPtr) #define SQLRowCount (odbcStubs->SQLRowCountPtr) #define SQLSetConnectAttr (odbcStubs->SQLSetConnectAttrPtr) #define SQLSetConnectOption (odbcStubs->SQLSetConnectOptionPtr) #define SQLSetEnvAttr (odbcStubs->SQLSetEnvAttrPtr) #define SQLTablesW (odbcStubs->SQLTablesWPtr) #define SQLExecDirectW (odbcStubs->SQLExecDirectWPtr) MODULE_SCOPE odbcStubDefs *odbcStubs; |
Changes to generic/tdbcodbc.c.
︙ | ︙ | |||
223 224 225 226 227 228 229 230 231 232 233 234 235 236 | * asking for data type metadata */ #define STATEMENT_FLAG_PRIMARYKEYS 0x20 /* This flag is set if the statement is * asking for primary key metadata */ #define STATEMENT_FLAG_FOREIGNKEYS 0x40 /* This flag is set if the statement is * asking for primary key metadata */ /* * Structure describing the data types of substituted parameters in * a SQL statement. */ typedef struct ParamData { | > > > > | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | * asking for data type metadata */ #define STATEMENT_FLAG_PRIMARYKEYS 0x20 /* This flag is set if the statement is * asking for primary key metadata */ #define STATEMENT_FLAG_FOREIGNKEYS 0x40 /* This flag is set if the statement is * asking for primary key metadata */ #define STATEMENT_FLAG_EVALDIRECT 0x80 /* This flag is set if the statement is * asking for direct execution (no prepare * or variable substitution) */ /* * Structure describing the data types of substituted parameters in * a SQL statement. */ typedef struct ParamData { |
︙ | ︙ | |||
441 442 443 444 445 446 447 448 449 450 451 452 453 454 | int objc, Tcl_Obj *const objv[]); static int PrimarykeysStatementConstructor(ClientData clientData, Tcl_Interp* interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const objv[]); static int ForeignkeysStatementConstructor(ClientData clientData, Tcl_Interp* interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const objv[]); static int TypesStatementConstructor(ClientData clientData, Tcl_Interp* interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const objv[]); static void DeleteStatementMetadata(ClientData clientData); static void DeleteStatement(StatementData* sdata); | > > > > | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | int objc, Tcl_Obj *const objv[]); static int PrimarykeysStatementConstructor(ClientData clientData, Tcl_Interp* interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const objv[]); static int ForeignkeysStatementConstructor(ClientData clientData, Tcl_Interp* interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const objv[]); static int EvaldirectStatementConstructor(ClientData clientData, Tcl_Interp* interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const objv[]); static int TypesStatementConstructor(ClientData clientData, Tcl_Interp* interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const objv[]); static void DeleteStatementMetadata(ClientData clientData); static void DeleteStatement(StatementData* sdata); |
︙ | ︙ | |||
680 681 682 683 684 685 686 687 688 689 690 691 692 693 | const static Tcl_MethodType ForeignkeysStatementConstructorType = { TCL_OO_METHOD_VERSION_CURRENT, /* version */ "CONSTRUCTOR", /* name */ ForeignkeysStatementConstructor, /* callProc */ NULL, /* deleteProc */ NULL /* cloneProc */ }; /* * Constructor type for the class that implements the fake 'statement' * used to query the names and attributes of database types. | > > > > > > > > > > > > > > > > | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | const static Tcl_MethodType ForeignkeysStatementConstructorType = { TCL_OO_METHOD_VERSION_CURRENT, /* version */ "CONSTRUCTOR", /* name */ ForeignkeysStatementConstructor, /* callProc */ NULL, /* deleteProc */ NULL /* cloneProc */ }; /* * Method types for the class that implements the 'evaldirect' statement * used to execute driver-native SQL code without preparing it or performing * variable substitutions. */ const static Tcl_MethodType EvaldirectStatementConstructorType = { TCL_OO_METHOD_VERSION_CURRENT, /* version */ "CONSTRUCTOR", /* name */ EvaldirectStatementConstructor, /* callProc */ NULL, /* deleteProc */ NULL /* cloneProc */ }; /* * Constructor type for the class that implements the fake 'statement' * used to query the names and attributes of database types. |
︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 | SQLRETURN rc; SQLHSTMT hStmt; ConnectionData* cdata = sdata->cdata; if (sdata->flags & (STATEMENT_FLAG_TABLES | STATEMENT_FLAG_COLUMNS | STATEMENT_FLAG_PRIMARYKEYS | STATEMENT_FLAG_FOREIGNKEYS | STATEMENT_FLAG_TYPES)) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot have multiple result " "sets in this context", -1)); return SQL_NULL_HSTMT; } rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &hStmt); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { | > | 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 | SQLRETURN rc; SQLHSTMT hStmt; ConnectionData* cdata = sdata->cdata; if (sdata->flags & (STATEMENT_FLAG_TABLES | STATEMENT_FLAG_COLUMNS | STATEMENT_FLAG_PRIMARYKEYS | STATEMENT_FLAG_FOREIGNKEYS | STATEMENT_FLAG_EVALDIRECT | STATEMENT_FLAG_TYPES)) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot have multiple result " "sets in this context", -1)); return SQL_NULL_HSTMT; } rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &hStmt); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { |
︙ | ︙ | |||
3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 | DecrStatementRefCount(sdata); return TCL_ERROR; } /* *----------------------------------------------------------------------------- * * TypesStatementConstructor -- * * C-level initialization for the object representing an ODBC query * for data type metadata * * Parameters: * Accepts a 3- or 4-element 'objv': | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 | DecrStatementRefCount(sdata); return TCL_ERROR; } /* *----------------------------------------------------------------------------- * * EvaldirectStatementConstructor -- * * C-level initialization for the object representing a a driver-native * ODBC query that is not tokenized or prepared. * * Parameters: * Accepts a 4-element 'objv': * columnsStatement new $connection $sqlStatement, * where $connection is the ODBC connection object and $sqlStatement is * the driver-native SQL to be executed. * * Results: * Returns a standard Tcl result * * Side effects: * Creates an ODBC statement, and stores it (plus a copy of the * driver-native sqlStatement a reference to the connection) in * instance metadata. * *----------------------------------------------------------------------------- */ static int EvaldirectStatementConstructor( ClientData clientData, /* Not used */ Tcl_Interp* interp, /* Tcl interpreter */ Tcl_ObjectContext context, /* Object context */ int objc, /* Parameter count */ Tcl_Obj *const objv[] /* Parameter vector */ ) { Tcl_Object thisObject = Tcl_ObjectContextObject(context); /* The current statement object */ int skip = Tcl_ObjectContextSkippedArgs(context); /* The number of parameters to skip */ Tcl_Object connectionObject; /* The database connection as a Tcl_Object */ ConnectionData* cdata; /* The connection object's data */ StatementData* sdata; /* The statement's object data */ RETCODE rc; /* Return code from ODBC */ /* Check param count */ if (objc != skip+2) { Tcl_WrongNumArgs(interp, skip, objv, "connection sqlStatement"); return TCL_ERROR; } /* Do not initialize superclasses; this constructor overrides * StatementConstructor so that the SQL is not tokenizer or prepared. */ /* Find the connection object, and get its data. */ connectionObject = Tcl_GetObjectFromObj(interp, objv[skip]); if (connectionObject == NULL) { return TCL_ERROR; } cdata = (ConnectionData*) Tcl_ObjectGetMetadata(connectionObject, &connectionDataType); if (cdata == NULL) { Tcl_AppendResult(interp, Tcl_GetString(objv[skip]), " does not refer to an ODBC connection", NULL); return TCL_ERROR; } /* * Allocate an object to hold data about this statement */ sdata = NewStatement(cdata, connectionObject); /* Allocate an ODBC statement handle */ rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &(sdata->hStmt)); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(allocating statement handle)"); goto freeSData; } /* * Stash the sqlStatement and set a flag to indicate direct execution. */ sdata->nativeSqlW = GetWCharStringFromObj(objv[skip+1], &(sdata->nativeSqlLen)); sdata->flags = STATEMENT_FLAG_EVALDIRECT; /* Attach the current statement data as metadata to the current object */ Tcl_ObjectSetMetadata(thisObject, &statementDataType, (ClientData) sdata); /* Statement will be executed when the statement object's resultSetCreate * is called (e.g. via $statement allrows). In this statement * resultSetCreate forwards to ResultSetConstructor. */ return TCL_OK; /* On error, unwind all the resource allocations */ freeSData: DecrStatementRefCount(sdata); return TCL_ERROR; } /* *----------------------------------------------------------------------------- * * TypesStatementConstructor -- * * C-level initialization for the object representing an ODBC query * for data type metadata * * Parameters: * Accepts a 3- or 4-element 'objv': |
︙ | ︙ | |||
3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 | sdata->nativeSqlW, sdata->nativeSqlLen); } else if (sdata->flags & STATEMENT_FLAG_FOREIGNKEYS) { rc = SQLForeignKeysW(rdata->hStmt, NULL, 0, NULL, 0, sdata->nativeSqlW, sdata->nativeSqlLen, NULL, 0, NULL, 0, sdata->nativeMatchPatternW, sdata->nativeMatchPatLen); } else { rc = SQLExecute(rdata->hStmt); } if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA) { TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, "(executing the statement)"); | > > > | 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 | sdata->nativeSqlW, sdata->nativeSqlLen); } else if (sdata->flags & STATEMENT_FLAG_FOREIGNKEYS) { rc = SQLForeignKeysW(rdata->hStmt, NULL, 0, NULL, 0, sdata->nativeSqlW, sdata->nativeSqlLen, NULL, 0, NULL, 0, sdata->nativeMatchPatternW, sdata->nativeMatchPatLen); } else if (sdata->flags & STATEMENT_FLAG_EVALDIRECT) { rc = SQLExecDirectW(rdata->hStmt, sdata->nativeSqlW, sdata->nativeSqlLen); } else { rc = SQLExecute(rdata->hStmt); } if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA) { TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, "(executing the statement)"); |
︙ | ︙ | |||
5339 5340 5341 5342 5343 5344 5345 | /* Attach the constructor to the 'primarykeysStatement' class */ Tcl_ClassSetConstructor(interp, curClass, Tcl_NewMethod(interp, curClass, NULL, 1, &PrimarykeysStatementConstructorType, (ClientData) NULL)); | < < < < < < < < < < < > > > > > > > > > > > > > > > > > > | 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 | /* Attach the constructor to the 'primarykeysStatement' class */ Tcl_ClassSetConstructor(interp, curClass, Tcl_NewMethod(interp, curClass, NULL, 1, &PrimarykeysStatementConstructorType, (ClientData) NULL)); /* Look up the 'foreignkeysStatement' class */ nameObj = Tcl_NewStringObj("::tdbc::odbc::foreignkeysStatement", -1); Tcl_IncrRefCount(nameObj); if ((curClassObject = Tcl_GetObjectFromObj(interp, nameObj)) == NULL) { Tcl_DecrRefCount(nameObj); return TCL_ERROR; } Tcl_DecrRefCount(nameObj); curClass = Tcl_GetObjectAsClass(curClassObject); /* Attach the constructor to the 'foreignkeysStatement' class */ Tcl_ClassSetConstructor(interp, curClass, Tcl_NewMethod(interp, curClass, NULL, 1, &ForeignkeysStatementConstructorType, (ClientData) NULL)); /* Look up the 'evaldirectStatement' class */ nameObj = Tcl_NewStringObj("::tdbc::odbc::evaldirectStatement", -1); Tcl_IncrRefCount(nameObj); if ((curClassObject = Tcl_GetObjectFromObj(interp, nameObj)) == NULL) { Tcl_DecrRefCount(nameObj); return TCL_ERROR; } Tcl_DecrRefCount(nameObj); curClass = Tcl_GetObjectAsClass(curClassObject); /* Attach the constructor to the 'evaldirectStatement' class */ Tcl_ClassSetConstructor(interp, curClass, Tcl_NewMethod(interp, curClass, NULL, 1, &EvaldirectStatementConstructorType, (ClientData) NULL)); /* Look up the 'typesStatement' class */ nameObj = Tcl_NewStringObj("::tdbc::odbc::typesStatement", -1); Tcl_IncrRefCount(nameObj); if ((curClassObject = Tcl_GetObjectFromObj(interp, nameObj)) == NULL) { Tcl_DecrRefCount(nameObj); |
︙ | ︙ |
Changes to library/tdbcodbc.tcl.
︙ | ︙ | |||
216 217 218 219 220 221 222 223 224 225 226 227 228 229 | lappend retval $row } set retval } result options] catch {rename $stmt {}} return -level 0 -options $options $result } # 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} { | > > > > > > > > > > > > > | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | lappend retval $row } set retval } result options] catch {rename $stmt {}} return -level 0 -options $options $result } # The 'evaldirect' evaluates driver-native SQL code without preparing it, # and returns a list of dicts (similar to '$connection allrows -as dicts'). method evaldirect {sqlStatement} { set stmt [::tdbc::odbc::evaldirectStatement create \ Stmt::[incr statementSeq] [self] $sqlStatement] set status [catch { $stmt allrows -as dicts } result options] catch {rename $stmt {}} return -level 0 -options $options $result } # 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} { |
︙ | ︙ | |||
441 442 443 444 445 446 447 448 449 450 451 452 453 454 | # The constructor is written in C. It accepts the handle to the # connection and the -primary and -foreign options. It works in all # ways like the constructor of the 'statement' class except that # its 'init' method sets up to enumerate foreign keys and not run a SQL # query. # The 'resultSetCreate' method forwards to the result set constructor forward resultSetCreate ::tdbc::odbc::resultset create } #------------------------------------------------------------------------------ | > > > > > > > > > > > > > > > > > > > > > > > > > > | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | # The constructor is written in C. It accepts the handle to the # connection and the -primary and -foreign options. It works in all # ways like the constructor of the 'statement' class except that # its 'init' method sets up to enumerate foreign keys and not run a SQL # query. # The 'resultSetCreate' method forwards to the result set constructor forward resultSetCreate ::tdbc::odbc::resultset create } #------------------------------------------------------------------------------ # # tdbc::odbc::evaldirectStatement -- # # The class 'tdbc::odbc::evaldirectStatement' provides a mechanism to # execute driver-name SQL code through an ODBC connection. The SQL code # is not prepared and no tokenization or variable substitution is done. # #------------------------------------------------------------------------------ oo::class create ::tdbc::odbc::evaldirectStatement { superclass ::tdbc::statement # The constructor is written in C. It accepts the handle to the # connection and a SQL statement. It works in all # ways like the constructor of the 'statement' class except that # its 'init' method does not tokenize or prepare the SQL statement, and # sets up to run the SQL query without performing variable substitution. # The 'resultSetCreate' method forwards to the result set constructor forward resultSetCreate ::tdbc::odbc::resultset create } #------------------------------------------------------------------------------ |
︙ | ︙ |