File: | db/dbtcl.c |
Warning: | line 637, column 9 Duplicate code detected |
Note: | line 641, column 9 Similar code here |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * The contents of this file are subject to the Mozilla Public License |
3 | * Version 1.1 (the "License"); you may not use this file except in |
4 | * compliance with the License. You may obtain a copy of the License at |
5 | * http://mozilla.org/. |
6 | * |
7 | * Software distributed under the License is distributed on an "AS IS" |
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
9 | * the License for the specific language governing rights and limitations |
10 | * under the License. |
11 | * |
12 | * The Original Code is AOLserver Code and related documentation |
13 | * distributed by AOL. |
14 | * |
15 | * The Initial Developer of the Original Code is America Online, |
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, |
17 | * Inc. All Rights Reserved. |
18 | * |
19 | * Alternatively, the contents of this file may be used under the terms |
20 | * of the GNU General Public License (the "GPL"), in which case the |
21 | * provisions of GPL are applicable instead of those above. If you wish |
22 | * to allow use of your version of this file only under the terms of the |
23 | * GPL and not to allow others to use your version of this file under the |
24 | * License, indicate your decision by deleting the provisions above and |
25 | * replace them with the notice and other provisions required by the GPL. |
26 | * If you do not delete the provisions above, a recipient may use your |
27 | * version of this file under either the License or the GPL. |
28 | */ |
29 | |
30 | |
31 | /* |
32 | * dbtcl.c -- |
33 | * |
34 | * Tcl database access routines. |
35 | */ |
36 | |
37 | #include "db.h" |
38 | |
39 | /* |
40 | * The following structure maintains per-interp data. |
41 | */ |
42 | |
43 | typedef struct InterpData { |
44 | const char *server; |
45 | Tcl_HashTable dbs; |
46 | } InterpData; |
47 | |
48 | /* |
49 | * Local functions defined in this file |
50 | */ |
51 | |
52 | static int DbFail(Tcl_Interp *interp, Ns_DbHandle *handle, const char *cmd) |
53 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))); |
54 | |
55 | static void EnterDbHandle(InterpData *idataPtr, Tcl_Interp *interp, Ns_DbHandle *handle, Tcl_Obj *listObj) |
56 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))) NS_GNUC_NONNULL(4)__attribute__((__nonnull__(4))); |
57 | |
58 | static int DbGetHandle(InterpData *idataPtr, Tcl_Interp *interp, const char *handleId, |
59 | Ns_DbHandle **handle, Tcl_HashEntry **hPtrPtr); |
60 | |
61 | static Ns_ReturnCode QuoteSqlValue(Tcl_DString *dsPtr, Tcl_Obj *valueObj, int valueType) |
62 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))); |
63 | |
64 | static void |
65 | FinishElement(Tcl_DString *elemPtr, Tcl_DString *colsPtr, bool_Bool quoted) |
66 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))); |
67 | |
68 | #if !defined(NS_TCL_PRE85) |
69 | static Ns_ReturnCode CurrentHandles( Tcl_Interp *interp, Tcl_HashTable *tablePtr, Tcl_Obj *dictObj) |
70 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))); |
71 | #endif |
72 | |
73 | static Tcl_InterpDeleteProc FreeData; |
74 | static Tcl_ObjCmdProc |
75 | DbConfigPathObjCmd, |
76 | DbErrorCodeObjCmd, |
77 | DbErrorMsgObjCmd, |
78 | DbObjCmd, |
79 | GetCsvObjCmd, |
80 | PoolDescriptionObjCmd, |
81 | QuoteListObjCmd, |
82 | QuoteListToListObjCmd, |
83 | QuoteValueObjCmd; |
84 | |
85 | static int ErrorObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv, char cmd); |
86 | |
87 | |
88 | /* |
89 | * Local variables defined in this file. |
90 | */ |
91 | |
92 | static const Tcl_ObjType *intTypePtr = NULL((void*)0); |
93 | static const char *const datakey = "nsdb:data"; |
94 | |
95 | static const Ns_ObjvTable valueTypes[] = { |
96 | {"decimal", UCHAR('n')((unsigned char)('n'))}, |
97 | {"double", UCHAR('n')((unsigned char)('n'))}, |
98 | {"integer", UCHAR('n')((unsigned char)('n'))}, |
99 | {"int", UCHAR('n')((unsigned char)('n'))}, |
100 | {"real", UCHAR('n')((unsigned char)('n'))}, |
101 | {"smallint", UCHAR('n')((unsigned char)('n'))}, |
102 | {"bigint", UCHAR('n')((unsigned char)('n'))}, |
103 | {"bit", UCHAR('n')((unsigned char)('n'))}, |
104 | {"float", UCHAR('n')((unsigned char)('n'))}, |
105 | {"numeric", UCHAR('n')((unsigned char)('n'))}, |
106 | {"tinyint", UCHAR('n')((unsigned char)('n'))}, |
107 | {"text", UCHAR('q')((unsigned char)('q'))}, |
108 | {NULL((void*)0), 0u} |
109 | }; |
110 | |
111 | |
112 | /* |
113 | *---------------------------------------------------------------------- |
114 | * Ns_TclDbGetHandle -- |
115 | * |
116 | * Get database handle from its handle id. |
117 | * |
118 | * Results: |
119 | * Tcl result code. |
120 | * |
121 | * Side effects: |
122 | * None. |
123 | * |
124 | *---------------------------------------------------------------------- |
125 | */ |
126 | |
127 | int |
128 | Ns_TclDbGetHandle(Tcl_Interp *interp, const char *handleId, Ns_DbHandle **handlePtr) |
129 | { |
130 | int result; |
131 | InterpData *idataPtr; |
132 | |
133 | idataPtr = Tcl_GetAssocData(interp, datakey, NULL((void*)0)); |
134 | if (idataPtr == NULL((void*)0)) { |
135 | result = TCL_ERROR1; |
136 | } else { |
137 | result = DbGetHandle(idataPtr, interp, handleId, handlePtr, NULL((void*)0)); |
138 | } |
139 | return result; |
140 | } |
141 | |
142 | |
143 | /* |
144 | *---------------------------------------------------------------------- |
145 | * |
146 | * NsDbAddCmds -- |
147 | * |
148 | * Add the nsdb commands. |
149 | * |
150 | * Results: |
151 | * None. |
152 | * |
153 | * Side effects: |
154 | * None. |
155 | * |
156 | *---------------------------------------------------------------------- |
157 | */ |
158 | |
159 | int |
160 | NsDbAddCmds(Tcl_Interp *interp, const void *arg) |
161 | { |
162 | const char *server = arg; |
163 | InterpData *idataPtr; |
164 | |
165 | /* |
166 | * Initialize the per-interp data. |
167 | */ |
168 | |
169 | idataPtr = ns_malloc(sizeof(InterpData)); |
170 | idataPtr->server = server; |
171 | Tcl_InitHashTable(&idataPtr->dbs, TCL_STRING_KEYS(0)); |
172 | Tcl_SetAssocData(interp, datakey, FreeData, idataPtr); |
173 | |
174 | intTypePtr = Tcl_GetObjType("int"); |
175 | if (intTypePtr == NULL((void*)0)) { |
176 | Tcl_Panic("NsTclInitObjs: no int type"); |
177 | } |
178 | |
179 | (void)Tcl_CreateObjCommand(interp, "ns_db", DbObjCmd, idataPtr, NULL((void*)0)); |
180 | (void)Tcl_CreateObjCommand(interp, "ns_dbconfigpath", DbConfigPathObjCmd, idataPtr, NULL((void*)0)); |
181 | (void)Tcl_CreateObjCommand(interp, "ns_dberrorcode", DbErrorCodeObjCmd, idataPtr, NULL((void*)0)); |
182 | (void)Tcl_CreateObjCommand(interp, "ns_dberrormsg", DbErrorMsgObjCmd, idataPtr, NULL((void*)0)); |
183 | (void)Tcl_CreateObjCommand(interp, "ns_dbquotevalue", QuoteValueObjCmd, idataPtr, NULL((void*)0)); |
184 | (void)Tcl_CreateObjCommand(interp, "ns_dbquotelist", QuoteListObjCmd, idataPtr, NULL((void*)0)); |
185 | (void)Tcl_CreateObjCommand(interp, "ns_getcsv", GetCsvObjCmd, idataPtr, NULL((void*)0)); |
186 | (void)Tcl_CreateObjCommand(interp, "ns_pooldescription", PoolDescriptionObjCmd, idataPtr, NULL((void*)0)); |
187 | (void)Tcl_CreateObjCommand(interp, "ns_quotelisttolist", QuoteListToListObjCmd, idataPtr, NULL((void*)0)); |
188 | |
189 | return TCL_OK0; |
190 | } |
191 | |
192 | |
193 | /* |
194 | *---------------------------------------------------------------------- |
195 | * NsDbReleaseHandles -- |
196 | * |
197 | * Release any database handles still held when an interp is |
198 | * deallocated. |
199 | * |
200 | * Results: |
201 | * None. |
202 | * |
203 | * Side effects: |
204 | * None. |
205 | * |
206 | *---------------------------------------------------------------------- |
207 | */ |
208 | |
209 | int |
210 | NsDbReleaseHandles(Tcl_Interp *interp, const void *UNUSED(arg)UNUSED_arg __attribute__((__unused__))) |
211 | { |
212 | InterpData *idataPtr; |
213 | |
214 | idataPtr = Tcl_GetAssocData(interp, datakey, NULL((void*)0)); |
215 | if (idataPtr != NULL((void*)0)) { |
216 | Tcl_HashSearch search; |
217 | const Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&idataPtr->dbs, &search); |
218 | |
219 | while (hPtr != NULL((void*)0)) { |
220 | Ns_DbHandle *handlePtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData); |
221 | |
222 | Ns_DbPoolPutHandle(handlePtr); |
223 | hPtr = Tcl_NextHashEntry(&search); |
224 | } |
225 | Tcl_DeleteHashTable(&idataPtr->dbs); |
226 | Tcl_InitHashTable(&idataPtr->dbs, TCL_STRING_KEYS(0)); |
227 | } |
228 | |
229 | return TCL_OK0; |
230 | } |
231 | |
232 | #if !defined(NS_TCL_PRE85) |
233 | |
234 | /* |
235 | *---------------------------------------------------------------------- |
236 | * |
237 | * CurrentHandles -- |
238 | * |
239 | * Return a Tcl dict with information about the current allocated |
240 | * handles in the current interp/thread. |
241 | * |
242 | * Results: |
243 | * NS_OK if everything went well, NS_ERROR otherwise. |
244 | * |
245 | * Side effects: |
246 | * None. |
247 | * |
248 | *---------------------------------------------------------------------- |
249 | */ |
250 | |
251 | static Ns_ReturnCode |
252 | CurrentHandles( Tcl_Interp *interp, Tcl_HashTable *tablePtr, Tcl_Obj *dictObj) |
253 | { |
254 | Tcl_HashSearch search; |
255 | const Tcl_HashEntry *hPtr; |
256 | |
257 | NS_NONNULL_ASSERT(interp != NULL)((void) (0)); |
258 | NS_NONNULL_ASSERT(tablePtr != NULL)((void) (0)); |
259 | NS_NONNULL_ASSERT(dictObj != NULL)((void) (0)); |
260 | |
261 | hPtr = Tcl_FirstHashEntry(tablePtr, &search); |
262 | while (hPtr != NULL((void*)0)) { |
263 | Ns_DbHandle *handlePtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData); |
264 | Tcl_Obj *keyv[2]; |
265 | |
266 | keyv[0] = Tcl_NewStringObj(handlePtr->poolname, -1); |
267 | keyv[1] = Tcl_NewStringObj(Tcl_GetHashKey(tablePtr, hPtr)((void *) (((tablePtr)->keyType == (1) || (tablePtr)->keyType == (-1)) ? (hPtr)->key.oneWordValue : (hPtr)->key.string )), -1); |
268 | Tcl_DictObjPutKeyList(interp, dictObj, 2, keyv, Tcl_NewIntObj(NsDbGetActive(handlePtr))); |
269 | hPtr = Tcl_NextHashEntry(&search); |
270 | } |
271 | |
272 | return NS_OK; |
273 | } |
274 | #endif |
275 | |
276 | |
277 | /* |
278 | *---------------------------------------------------------------------- |
279 | * |
280 | * DbObjCmd -- |
281 | * |
282 | * Implements "ns_db". |
283 | * |
284 | * Results: |
285 | * Return TCL_OK upon success and TCL_ERROR otherwise. |
286 | * |
287 | * Side effects: |
288 | * Depends on the command. |
289 | * |
290 | *---------------------------------------------------------------------- |
291 | */ |
292 | |
293 | static int |
294 | DbObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
295 | { |
296 | InterpData *idataPtr = clientData; |
297 | char tmpbuf[32] = ""; |
298 | const char *pool = NULL((void*)0); |
299 | int cmd, nrows; |
300 | Ns_DbHandle *handlePtr = NULL((void*)0); |
301 | Ns_Set *rowPtr; |
302 | Tcl_HashEntry *hPtr; |
303 | int result = TCL_OK0; |
304 | |
305 | enum { |
306 | ZERO_OR_ONE_ROW, |
307 | ONE_ROW, |
308 | BINDROW, |
309 | BOUNCEPOOL, |
310 | CANCEL, |
311 | CONNECTED, |
312 | #if !defined(NS_TCL_PRE85) |
313 | CURRENTHANDLES, |
314 | #endif |
315 | DATASOURCE, |
316 | DBTYPE, |
317 | DISCONNECT, |
318 | DML, |
319 | DRIVER, |
320 | EXCEPTION, |
321 | EXEC, |
322 | FLUSH, |
323 | GETHANDLE, |
324 | GETROW, |
325 | INTERPRETSQLFILE, |
326 | LOGMINDURATION, |
327 | PASSWORD, |
328 | POOLNAME, |
329 | POOLS, |
330 | RELEASEHANDLE, |
331 | RESETHANDLE, |
332 | ROWCOUNT, |
333 | SELECT, |
334 | SESSIONID, |
335 | SETEXCEPTION, |
336 | SP_EXEC, |
337 | SP_GETPARAMS, |
338 | SP_RETURNCODE, |
339 | SP_SETPARAM, |
340 | SP_START, |
341 | STATS, |
342 | USER, |
343 | VERBOSE |
344 | }; |
345 | |
346 | static const char *const subcmd[] = { |
347 | "0or1row", |
348 | "1row", |
349 | "bindrow", |
350 | "bouncepool", |
351 | "cancel", |
352 | "connected", |
353 | #if !defined(NS_TCL_PRE85) |
354 | "currenthandles", |
355 | #endif |
356 | "datasource", |
357 | "dbtype", |
358 | "disconnect", |
359 | "dml", |
360 | "driver", |
361 | "exception", |
362 | "exec", |
363 | "flush", |
364 | "gethandle", |
365 | "getrow", |
366 | "interpretsqlfile", |
367 | "logminduration", |
368 | "password", |
369 | "poolname", |
370 | "pools", |
371 | "releasehandle", |
372 | "resethandle", |
373 | "rowcount", |
374 | "select", |
375 | "session_id", |
376 | "setexception", |
377 | "sp_exec", |
378 | "sp_getparams", |
379 | "sp_returncode", |
380 | "sp_setparam", |
381 | "sp_start", |
382 | "stats", |
383 | "user", |
384 | "verbose", |
385 | NULL((void*)0) |
386 | }; |
387 | |
388 | if (objc < 2) { |
389 | Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); |
390 | return TCL_ERROR1; |
391 | } |
392 | if (Tcl_GetIndexFromObj(interp, objv[1], subcmd, "option", 0, &cmd)Tcl_GetIndexFromObjStruct(interp, objv[1], subcmd, sizeof(char *), "option", 0, &cmd) != TCL_OK0) { |
393 | return TCL_ERROR1; |
394 | } |
395 | |
396 | switch (cmd) { |
397 | case POOLS: |
398 | if (objc != 2) { |
399 | Tcl_WrongNumArgs(interp, 2, objv, NULL((void*)0)); |
400 | result = TCL_ERROR1; |
401 | } else { |
402 | pool = Ns_DbPoolList(idataPtr->server); |
403 | if (pool != NULL((void*)0)) { |
404 | Tcl_Obj *listObj = Tcl_NewListObj(0, NULL((void*)0)); |
405 | |
406 | while (*pool != '\0') { |
407 | Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(pool, -1)); |
408 | pool = pool + strlen(pool) + 1; |
409 | } |
410 | Tcl_SetObjResult(interp, listObj); |
411 | } |
412 | } |
413 | break; |
414 | |
415 | case BOUNCEPOOL: |
416 | if (objc != 3) { |
417 | Tcl_WrongNumArgs(interp, 2, objv, "pool"); |
418 | result = TCL_ERROR1; |
419 | |
420 | } else if (Ns_DbBouncePool(Tcl_GetString(objv[2])) == NS_ERROR) { |
421 | Ns_TclPrintfResult(interp, "could not bounce: %s", Tcl_GetString(objv[2])); |
422 | result = TCL_ERROR1; |
423 | } |
424 | break; |
425 | |
426 | case GETHANDLE: { |
427 | int nhandles = 1; |
428 | Ns_Time *timeoutPtr = NULL((void*)0); |
429 | Ns_DbHandle **handlesPtrPtr; |
430 | Ns_ReturnCode status; |
431 | char *poolString = NULL((void*)0); |
432 | Ns_ObjvValueRange handlesRange = {1, INT_MAX2147483647}; |
433 | Ns_ObjvSpec opts[] = { |
434 | {"-timeout", Ns_ObjvTime, &timeoutPtr, NULL((void*)0)}, |
435 | {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)}, |
436 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
437 | }; |
438 | Ns_ObjvSpec args[] = { |
439 | {"?pool", Ns_ObjvString, &poolString, NULL((void*)0)}, |
440 | {"?nhandles", Ns_ObjvInt, &nhandles, &handlesRange}, |
441 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
442 | }; |
443 | |
444 | if (Ns_ParseObjv(opts, args, interp, 2, objc, objv) != NS_OK) { |
445 | return TCL_ERROR1; |
446 | } |
447 | |
448 | /* |
449 | * Determine the pool and requested number of handles |
450 | * from the remaining args. |
451 | */ |
452 | |
453 | if (poolString == NULL((void*)0)) { |
454 | pool = Ns_DbPoolDefault(idataPtr->server); |
455 | if (pool == NULL((void*)0)) { |
456 | Ns_TclPrintfResult(interp, "no defaultpool configured"); |
457 | return TCL_ERROR1; |
458 | } |
459 | } else { |
460 | pool = (const char *)poolString; |
461 | } |
462 | |
463 | if (Ns_DbPoolAllowable(idataPtr->server, pool) == NS_FALSE0) { |
464 | Ns_TclPrintfResult(interp, "no access to pool: \"%s\"", pool); |
465 | return TCL_ERROR1; |
466 | } |
467 | |
468 | /* |
469 | * When timeout is specified as 0 (or 0:0) then treat is as |
470 | * non-specified (blocking). |
471 | */ |
472 | if (timeoutPtr != NULL((void*)0) && timeoutPtr->sec == 0 && timeoutPtr->usec == 0) { |
473 | timeoutPtr = NULL((void*)0); |
474 | } |
475 | |
476 | /* |
477 | * Allocate handles and enter them into Tcl. |
478 | */ |
479 | |
480 | if (nhandles == 1) { |
481 | handlesPtrPtr = &handlePtr; |
482 | } else { |
483 | handlesPtrPtr = ns_malloc((size_t)nhandles * sizeof(Ns_DbHandle *)); |
484 | } |
485 | status = Ns_DbPoolTimedGetMultipleHandles(handlesPtrPtr, pool, |
486 | nhandles, timeoutPtr); |
487 | if (status == NS_OK) { |
488 | int i; |
489 | Tcl_Obj *listObj = Tcl_NewListObj(0, NULL((void*)0)); |
490 | |
491 | for (i = 0; i < nhandles; ++i) { |
492 | EnterDbHandle(idataPtr, interp, *(handlesPtrPtr + i), listObj); |
493 | } |
494 | Tcl_SetObjResult(interp, listObj); |
495 | } |
496 | if (handlesPtrPtr != &handlePtr) { |
497 | ns_free(handlesPtrPtr); |
498 | } |
499 | if (status != NS_TIMEOUT && status != NS_OK) { |
500 | Ns_TclPrintfResult(interp, |
501 | "could not allocate %d handle%s from pool \"%s\"", |
502 | nhandles, |
503 | nhandles > 1 ? "s" : NS_EMPTY_STRING, |
504 | pool); |
505 | result = TCL_ERROR1; |
506 | } |
507 | break; |
508 | } |
509 | |
510 | case CURRENTHANDLES: { |
511 | if (Ns_ParseObjv(NULL((void*)0), NULL((void*)0), interp, 2, objc, objv) != NS_OK) { |
512 | result = TCL_ERROR1; |
513 | |
514 | } else { |
515 | Ns_ReturnCode status; |
516 | Tcl_Obj *dictObj = Tcl_NewDictObj(); |
517 | |
518 | assert(idataPtr != NULL)((void) (0)); |
519 | |
520 | status = CurrentHandles(interp, &idataPtr->dbs, dictObj); |
521 | if (status != NS_OK) { |
522 | Tcl_DecrRefCount(dictObj)do { Tcl_Obj *_objPtr = (dictObj); if (_objPtr->refCount-- <= 1) { TclFreeObj(_objPtr); } } while(0); |
523 | result = TCL_ERROR1; |
524 | } else { |
525 | Tcl_SetObjResult(interp, dictObj); |
526 | } |
527 | } |
528 | break; |
529 | } |
530 | |
531 | |
532 | case LOGMINDURATION: { |
533 | Ns_Time *minDurationPtr = NULL((void*)0); |
534 | char *poolString = NULL((void*)0); |
535 | Ns_ObjvSpec args[] = { |
536 | {"?pool", Ns_ObjvString, &poolString, NULL((void*)0)}, |
537 | {"?minduration", Ns_ObjvTime, &minDurationPtr, NULL((void*)0)}, |
538 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
539 | }; |
540 | |
541 | if (Ns_ParseObjv(NULL((void*)0), args, interp, 2, objc, objv) != NS_OK) { |
542 | result = TCL_ERROR1; |
543 | |
544 | } else if (poolString == NULL((void*)0)) { |
545 | /* |
546 | * No argument, list min duration for every pool. |
547 | */ |
548 | Tcl_SetObjResult(interp, Ns_DbListMinDurations(interp, idataPtr->server)); |
549 | |
550 | } else if (minDurationPtr == NULL((void*)0)) { |
551 | pool = (const char *)poolString; |
552 | /* |
553 | * In this case, minduration was not given, return the |
554 | * actual minduration of this pool. |
555 | */ |
556 | |
557 | if (Ns_DbGetMinDuration(interp, pool, &minDurationPtr) != TCL_OK0) { |
558 | result = TCL_ERROR1; |
559 | } else { |
560 | Tcl_SetObjResult(interp, Ns_TclNewTimeObj(minDurationPtr)); |
561 | } |
562 | |
563 | } else { |
564 | pool = (const char *)poolString; |
565 | /* |
566 | * Set the minduration the specified value. |
567 | */ |
568 | if (Ns_DbSetMinDuration(interp, pool, minDurationPtr) != TCL_OK0) { |
569 | result = TCL_ERROR1; |
570 | } else { |
571 | Tcl_SetObjResult(interp, Ns_TclNewTimeObj(minDurationPtr)); |
572 | } |
573 | } |
574 | |
575 | break; |
576 | } |
577 | |
578 | case EXCEPTION: |
579 | if (objc != 3) { |
580 | Tcl_WrongNumArgs(interp, 2, objv, "dbId"); |
581 | result = TCL_ERROR1; |
582 | |
583 | } else if (DbGetHandle(idataPtr, interp, Tcl_GetString(objv[2]), &handlePtr, NULL((void*)0)) != TCL_OK0) { |
584 | result = TCL_ERROR1; |
585 | |
586 | } else { |
587 | Tcl_Obj *listObj = Tcl_NewListObj(0, NULL((void*)0)); |
588 | |
589 | Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(handlePtr->cExceptionCode, -1)); |
590 | Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(handlePtr->dsExceptionMsg.string, -1)); |
591 | Tcl_SetObjResult(interp, listObj); |
592 | } |
593 | break; |
594 | |
595 | case STATS: |
596 | if (objc != 2) { |
597 | Tcl_WrongNumArgs(interp, 2, objv, NULL((void*)0)); |
598 | result = TCL_ERROR1; |
599 | } else if (Ns_DbPoolStats(interp) != TCL_OK0) { |
600 | result = TCL_ERROR1; |
601 | } |
602 | break; |
603 | |
604 | case POOLNAME: NS_FALL_THROUGH((void)0); /* fall through */ |
605 | case PASSWORD: NS_FALL_THROUGH((void)0); /* fall through */ |
606 | case USER: NS_FALL_THROUGH((void)0); /* fall through */ |
607 | case DATASOURCE: NS_FALL_THROUGH((void)0); /* fall through */ |
608 | case DISCONNECT: NS_FALL_THROUGH((void)0); /* fall through */ |
609 | case DBTYPE: NS_FALL_THROUGH((void)0); /* fall through */ |
610 | case DRIVER: NS_FALL_THROUGH((void)0); /* fall through */ |
611 | case CANCEL: NS_FALL_THROUGH((void)0); /* fall through */ |
612 | case BINDROW: NS_FALL_THROUGH((void)0); /* fall through */ |
613 | case FLUSH: NS_FALL_THROUGH((void)0); /* fall through */ |
614 | case RELEASEHANDLE: NS_FALL_THROUGH((void)0); /* fall through */ |
615 | case RESETHANDLE: NS_FALL_THROUGH((void)0); /* fall through */ |
616 | case CONNECTED: NS_FALL_THROUGH((void)0); /* fall through */ |
617 | case SP_EXEC: NS_FALL_THROUGH((void)0); /* fall through */ |
618 | case SP_GETPARAMS: NS_FALL_THROUGH((void)0); /* fall through */ |
619 | case SP_RETURNCODE: NS_FALL_THROUGH((void)0); /* fall through */ |
620 | case SESSIONID: |
621 | |
622 | if (objc < 3) { |
623 | Tcl_WrongNumArgs(interp, 2, objv, "dbId"); |
624 | return TCL_ERROR1; |
625 | } |
626 | if (DbGetHandle(idataPtr, interp, Tcl_GetString(objv[2]), &handlePtr, &hPtr) != TCL_OK0) { |
627 | return TCL_ERROR1; |
628 | } |
629 | Ns_DStringFreeTcl_DStringFree(&handlePtr->dsExceptionMsg); |
630 | handlePtr->cExceptionCode[0] = '\0'; |
631 | |
632 | /* |
633 | * The following commands require just the handle. |
634 | */ |
635 | |
636 | switch (cmd) { |
637 | case POOLNAME: |
Duplicate code detected | |
638 | Tcl_SetObjResult(interp, Tcl_NewStringObj(handlePtr->poolname, -1)); |
639 | break; |
640 | |
641 | case PASSWORD: |
Similar code here | |
642 | Tcl_SetObjResult(interp, Tcl_NewStringObj(handlePtr->password, -1)); |
643 | break; |
644 | |
645 | case USER: |
646 | Tcl_SetObjResult(interp, Tcl_NewStringObj(handlePtr->user, -1)); |
647 | break; |
648 | |
649 | case DATASOURCE: |
650 | Tcl_SetObjResult(interp, Tcl_NewStringObj(handlePtr->datasource, -1)); |
651 | break; |
652 | |
653 | case DISCONNECT: |
654 | NsDbDisconnect(handlePtr); |
655 | break; |
656 | |
657 | case DBTYPE: |
658 | Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_DbDriverDbType(handlePtr), -1)); |
659 | break; |
660 | |
661 | case DRIVER: |
662 | Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_DbDriverName(handlePtr), -1)); |
663 | break; |
664 | |
665 | case CANCEL: |
666 | if (Ns_DbCancel(handlePtr) != NS_OK) { |
667 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
668 | } |
669 | break; |
670 | |
671 | case BINDROW: |
672 | rowPtr = Ns_DbBindRow(handlePtr); |
673 | if (rowPtr == NULL((void*)0)) { |
674 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
675 | |
676 | } else if (unlikely(Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_STATIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_STATIC ) != 0), 0))) { |
677 | result = TCL_ERROR1; |
678 | } |
679 | break; |
680 | |
681 | case ROWCOUNT: |
682 | Tcl_SetObjResult(interp, Tcl_NewIntObj(Ns_DbGetRowCount(handlePtr))); |
683 | break; |
684 | |
685 | case FLUSH: |
686 | if (Ns_DbFlush(handlePtr) != NS_OK) { |
687 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
688 | } |
689 | break; |
690 | |
691 | case RELEASEHANDLE: |
692 | Tcl_DeleteHashEntry(hPtr); |
693 | Ns_DbPoolPutHandle(handlePtr); |
694 | break; |
695 | |
696 | case RESETHANDLE: |
697 | if (Ns_DbResetHandle(handlePtr) != NS_OK) { |
698 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
699 | } else { |
700 | Tcl_SetObjResult(interp, Tcl_NewIntObj(NS_OK)); |
701 | } |
702 | break; |
703 | |
704 | case CONNECTED: |
705 | Tcl_SetObjResult(interp, Tcl_NewBooleanObj(handlePtr->connected)Tcl_NewIntObj((handlePtr->connected)!=0)); |
706 | break; |
707 | |
708 | case SESSIONID: |
709 | { |
710 | char idstr[TCL_INTEGER_SPACE24 + 4]; |
711 | int length; |
712 | |
713 | memcpy(idstr, "sid", 3u); |
714 | length = ns_uint64toa(&idstr[3], (uint64_t)NsDbGetSessionId(handlePtr)); |
715 | Tcl_SetObjResult(interp, Tcl_NewStringObj(idstr, length + 3)); |
716 | } |
717 | break; |
718 | |
719 | case SP_EXEC: |
720 | switch (Ns_DbSpExec(handlePtr)) { |
721 | case NS_DML: |
722 | Tcl_SetObjResult(interp, Tcl_NewStringObj("NS_DML", 6)); |
723 | break; |
724 | case NS_ROWS: |
725 | Tcl_SetObjResult(interp, Tcl_NewStringObj("NS_ROWS", 7)); |
726 | break; |
727 | default: |
728 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
729 | } |
730 | break; |
731 | |
732 | case SP_GETPARAMS: |
733 | rowPtr = Ns_DbSpGetParams(handlePtr); |
734 | if (rowPtr == NULL((void*)0)) { |
735 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
736 | |
737 | } else if (unlikely(Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_DYNAMIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_DYNAMIC ) != 0), 0))) { |
738 | result = TCL_ERROR1; |
739 | } |
740 | break; |
741 | |
742 | case SP_RETURNCODE: |
743 | if (Ns_DbSpReturnCode(handlePtr, tmpbuf, 32) != NS_OK) { |
744 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
745 | } else { |
746 | Tcl_SetObjResult(interp, Tcl_NewStringObj(tmpbuf, -1)); |
747 | } |
748 | break; |
749 | |
750 | default: |
751 | /* should not happen */ |
752 | assert(cmd && 0)((void) (0)); |
753 | } |
754 | break; |
755 | |
756 | case DML: NS_FALL_THROUGH((void)0); /* fall through */ |
757 | case GETROW: NS_FALL_THROUGH((void)0); /* fall through */ |
758 | case ONE_ROW: NS_FALL_THROUGH((void)0); /* fall through */ |
759 | case ZERO_OR_ONE_ROW: NS_FALL_THROUGH((void)0); /* fall through */ |
760 | case EXEC: NS_FALL_THROUGH((void)0); /* fall through */ |
761 | case SELECT: NS_FALL_THROUGH((void)0); /* fall through */ |
762 | case SP_START: NS_FALL_THROUGH((void)0); /* fall through */ |
763 | case INTERPRETSQLFILE: |
764 | { |
765 | const char *value; |
766 | int valueLength = 0; |
767 | Tcl_DString ds; |
768 | |
769 | /* |
770 | * The following commands require a 3rd argument. |
771 | */ |
772 | |
773 | if (objc != 4) { |
774 | if (cmd == INTERPRETSQLFILE) { |
775 | Tcl_WrongNumArgs(interp, 2, objv, "dbId sqlfile"); |
776 | |
777 | } else if (cmd == GETROW) { |
778 | Tcl_WrongNumArgs(interp, 2, objv, "dbId row"); |
779 | |
780 | } else { |
781 | Tcl_WrongNumArgs(interp, 2, objv, "dbId sql"); |
782 | } |
783 | return TCL_ERROR1; |
784 | } |
785 | |
786 | if (DbGetHandle(idataPtr, interp, Tcl_GetString(objv[2]), &handlePtr, &hPtr) != TCL_OK0) { |
787 | return TCL_ERROR1; |
788 | } |
789 | Ns_DStringFreeTcl_DStringFree(&handlePtr->dsExceptionMsg); |
790 | handlePtr->cExceptionCode[0] = '\0'; |
791 | value = Tcl_GetStringFromObj(objv[3], &valueLength); |
792 | |
793 | /* |
794 | * Convert data to external UTF-8... and lets hope, the |
795 | * driver can handle UTF-8. In case it does not, we might |
796 | * have to tailor this functionality for certain drivers |
797 | * (would need additional configuration options). |
798 | */ |
799 | Tcl_UtfToExternalDString(NULL((void*)0), value, valueLength, &ds); |
800 | value = ds.string; |
801 | |
802 | /*if (cmd != GETROW) { |
803 | fprintf(stderr, "CMD %s: <%s> (%s)\n", Tcl_GetString(objv[1]), value, |
804 | objv[3]->typePtr ? objv[3]->typePtr->name : "none"); |
805 | }*/ |
806 | |
807 | switch (cmd) { |
808 | case DML: |
809 | if (Ns_DbDML(handlePtr, value) != NS_OK) { |
810 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
811 | } |
812 | break; |
813 | |
814 | case ONE_ROW: |
815 | rowPtr = Ns_Db1Row(handlePtr, value); |
816 | if (rowPtr == NULL((void*)0)) { |
817 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
818 | |
819 | } else if (unlikely(Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_DYNAMIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_DYNAMIC ) != 0), 0))) { |
820 | result = TCL_ERROR1; |
821 | } |
822 | break; |
823 | |
824 | case ZERO_OR_ONE_ROW: |
825 | rowPtr = Ns_Db0or1Row(handlePtr, value, &nrows); |
826 | if (rowPtr == NULL((void*)0)) { |
827 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
828 | |
829 | } else if (nrows == 0) { |
830 | Ns_SetFree(rowPtr); |
831 | |
832 | } else if (unlikely(Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_DYNAMIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_DYNAMIC ) != 0), 0))) { |
833 | result = TCL_ERROR1; |
834 | } |
835 | break; |
836 | |
837 | case EXEC: |
838 | switch (Ns_DbExec(handlePtr, value)) { |
839 | case NS_DML: |
840 | Tcl_SetObjResult(interp, Tcl_NewStringObj("NS_DML", 6)); |
841 | break; |
842 | case NS_ROWS: |
843 | Tcl_SetObjResult(interp, Tcl_NewStringObj("NS_ROWS", 7)); |
844 | break; |
845 | default: |
846 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
847 | } |
848 | break; |
849 | |
850 | case SELECT: |
851 | rowPtr = Ns_DbSelect(handlePtr, value); |
852 | if (rowPtr == NULL((void*)0)) { |
853 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
854 | |
855 | } else if (unlikely(Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_STATIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, rowPtr, NS_TCL_SET_STATIC ) != 0), 0))) { |
856 | result = TCL_ERROR1; |
857 | } |
858 | break; |
859 | |
860 | case SP_START: |
861 | if (Ns_DbSpStart(handlePtr, value) != NS_OK) { |
862 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
863 | } else { |
864 | Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); |
865 | } |
866 | break; |
867 | |
868 | case INTERPRETSQLFILE: |
869 | if (Ns_DbInterpretSqlFile(handlePtr, value) != NS_OK) { |
870 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
871 | } |
872 | break; |
873 | |
874 | |
875 | case GETROW: |
876 | if (Ns_TclGetSet2(interp, value, &rowPtr) != TCL_OK0) { |
877 | result = TCL_ERROR1; |
878 | } else { |
879 | switch (Ns_DbGetRow(handlePtr, rowPtr)) { |
880 | case NS_OK: |
881 | Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); |
882 | break; |
883 | case NS_END_DATA: |
884 | Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); |
885 | break; |
886 | default: |
887 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
888 | } |
889 | } |
890 | break; |
891 | |
892 | default: |
893 | /* should not happen */ |
894 | assert(cmd && 0)((void) (0)); |
895 | } |
896 | |
897 | Tcl_DStringFree(&ds); |
898 | } |
899 | break; |
900 | |
901 | case VERBOSE: |
902 | { |
903 | int verbose = 0; |
904 | char *idString; |
905 | Ns_ObjvSpec args[] = { |
906 | {"dbID", Ns_ObjvString, &idString, NULL((void*)0)}, |
907 | {"?verbose", Ns_ObjvBool, &verbose, NULL((void*)0)}, |
908 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
909 | }; |
910 | |
911 | if (Ns_ParseObjv(NULL((void*)0), args, interp, 2, objc, objv) != NS_OK) { |
912 | result = TCL_ERROR1; |
913 | |
914 | } else if (DbGetHandle(idataPtr, interp, idString, &handlePtr, NULL((void*)0)) != TCL_OK0) { |
915 | result = TCL_ERROR1; |
916 | |
917 | } else { |
918 | assert(handlePtr != NULL)((void) (0)); |
919 | Ns_LogDeprecated(objv, 2, "ns_logctl debug(sql) ...", NULL((void*)0)); |
920 | |
921 | if (objc == 4) { |
922 | handlePtr->verbose = verbose; |
923 | (void) Ns_LogSeveritySetEnabled(Ns_LogSqlDebug, (bool_Bool)verbose); |
924 | } |
925 | |
926 | Tcl_SetObjResult(interp, Tcl_NewBooleanObj(handlePtr->verbose)Tcl_NewIntObj((handlePtr->verbose)!=0)); |
927 | } |
928 | } |
929 | break; |
930 | |
931 | case SETEXCEPTION: |
932 | if (objc != 5) { |
933 | Tcl_WrongNumArgs(interp, 2, objv, "dbId code message"); |
934 | result = TCL_ERROR1; |
935 | |
936 | } else if (DbGetHandle(idataPtr, interp, Tcl_GetString(objv[2]), &handlePtr, NULL((void*)0)) != TCL_OK0) { |
937 | result = TCL_ERROR1; |
938 | |
939 | } else { |
940 | const char *code; |
941 | int codeLen; |
942 | |
943 | assert(handlePtr != NULL)((void) (0)); |
944 | |
945 | code = Tcl_GetStringFromObj(objv[3], &codeLen); |
946 | if (codeLen > 5) { |
947 | Ns_TclPrintfResult(interp, "code \"%s"" more than 5 characters", code); |
948 | result = TCL_ERROR1; |
949 | } else { |
950 | Ns_DbSetException(handlePtr, code, Tcl_GetString(objv[4])); |
951 | } |
952 | } |
953 | break; |
954 | |
955 | case SP_SETPARAM: |
956 | if (objc != 7) { |
957 | Tcl_WrongNumArgs(interp, 2, objv, "dbId paramname type in|out value"); |
958 | result = TCL_ERROR1; |
959 | } else { |
960 | const char *arg5 = Tcl_GetString(objv[5]); |
961 | |
962 | if (!STREQ(arg5, "in")(((*(arg5)) == (*("in"))) && (strcmp((arg5),("in")) == 0)) && !STREQ(arg5, "out")(((*(arg5)) == (*("out"))) && (strcmp((arg5),("out")) == 0))) { |
963 | Ns_TclPrintfResult(interp, "inout parameter of setparam must " |
964 | "be \"in\" or \"out\""); |
965 | result = TCL_ERROR1; |
966 | |
967 | } else if (DbGetHandle(idataPtr, interp, Tcl_GetString(objv[2]), &handlePtr, NULL((void*)0)) != TCL_OK0) { |
968 | result = TCL_ERROR1; |
969 | |
970 | } else { |
971 | assert(handlePtr != NULL)((void) (0)); |
972 | |
973 | if (Ns_DbSpSetParam(handlePtr, |
974 | Tcl_GetString(objv[3]), |
975 | Tcl_GetString(objv[4]), |
976 | arg5, |
977 | Tcl_GetString(objv[6])) != NS_OK) { |
978 | result = DbFail(interp, handlePtr, Tcl_GetString(objv[1])); |
979 | } else { |
980 | Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); |
981 | } |
982 | } |
983 | } |
984 | break; |
985 | |
986 | default: |
987 | /* should not happen */ |
988 | assert(cmd && 0)((void) (0)); |
989 | } |
990 | |
991 | return result; |
992 | } |
993 | |
994 | |
995 | /* |
996 | *---------------------------------------------------------------------- |
997 | * DbErrorCodeObjCmd -- |
998 | * |
999 | * Implements "ns_dberrorcode". |
1000 | * Returns database exception code for the database handle. |
1001 | * |
1002 | * Results: |
1003 | * Returns TCL_OK and database exception code is set as Tcl result |
1004 | * or TCL_ERROR if failure. |
1005 | * |
1006 | * Side effects: |
1007 | * None. |
1008 | * |
1009 | *---------------------------------------------------------------------- |
1010 | */ |
1011 | |
1012 | static int |
1013 | ErrorObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv, char cmd) |
1014 | { |
1015 | InterpData *idataPtr = clientData; |
1016 | Ns_DbHandle *handle; |
1017 | int result = TCL_OK0; |
1018 | |
1019 | if (objc != 2) { |
1020 | Tcl_WrongNumArgs(interp, 1, objv, "dbId"); |
1021 | result = TCL_ERROR1; |
1022 | |
1023 | } else if (DbGetHandle(idataPtr, interp, Tcl_GetString(objv[1]), &handle, NULL((void*)0)) != TCL_OK0) { |
1024 | result = TCL_ERROR1; |
1025 | |
1026 | } else { |
1027 | if (cmd == 'c') { |
1028 | Tcl_SetObjResult(interp, Tcl_NewStringObj(handle->cExceptionCode, -1)); |
1029 | } else { |
1030 | Tcl_DStringResult(interp, &handle->dsExceptionMsg); |
1031 | } |
1032 | } |
1033 | return result; |
1034 | } |
1035 | |
1036 | static int |
1037 | DbErrorCodeObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
1038 | { |
1039 | return ErrorObjCmd(clientData, interp, objc, objv, 'c'); |
1040 | } |
1041 | |
1042 | static int |
1043 | DbErrorMsgObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
1044 | { |
1045 | return ErrorObjCmd(clientData, interp, objc, objv, 'm'); |
1046 | } |
1047 | |
1048 | |
1049 | /* |
1050 | *---------------------------------------------------------------------- |
1051 | * DbConfigPathObjCmd -- |
1052 | * |
1053 | * Implements "ns_dbconfigpath". Get the database section name |
1054 | * from the configuration file. |
1055 | * |
1056 | * Results: |
1057 | * TCL_OK and the database section name is set as the Tcl result |
1058 | * or TCL_ERROR if failure. |
1059 | * |
1060 | * Side effects: |
1061 | * None. |
1062 | * |
1063 | *---------------------------------------------------------------------- |
1064 | */ |
1065 | |
1066 | static int |
1067 | DbConfigPathObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
1068 | { |
1069 | int result = TCL_OK0; |
1070 | |
1071 | if (objc != 1) { |
1072 | Tcl_WrongNumArgs(interp, 0, objv, NULL((void*)0)); |
1073 | result = TCL_ERROR1; |
1074 | } else { |
1075 | const InterpData *idataPtr = clientData; |
1076 | const char *section = Ns_ConfigSectionPath(NULL((void*)0), idataPtr->server, NULL((void*)0), "db", (char *)0L); |
1077 | |
1078 | Tcl_SetObjResult(interp, Tcl_NewStringObj(section, -1)); |
1079 | } |
1080 | return result; |
1081 | } |
1082 | |
1083 | |
1084 | /* |
1085 | *---------------------------------------------------------------------- |
1086 | * PoolDescriptionObjCmd -- |
1087 | * |
1088 | * Implements "ns_pooldescription". Returns the pool's |
1089 | * description string. |
1090 | * |
1091 | * Results: |
1092 | * Return TCL_OK and the pool's description string is set as the |
1093 | * Tcl result string or TCL_ERROR if failure. |
1094 | * |
1095 | * Side effects: |
1096 | * None. |
1097 | * |
1098 | *---------------------------------------------------------------------- |
1099 | */ |
1100 | |
1101 | static int |
1102 | PoolDescriptionObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
1103 | { |
1104 | int result = TCL_OK0; |
1105 | |
1106 | if (objc != 2) { |
1107 | Tcl_WrongNumArgs(interp, 1, objv, "poolname"); |
1108 | result = TCL_ERROR1; |
1109 | } else { |
1110 | Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_DbPoolDescription(Tcl_GetString(objv[1])), -1)); |
1111 | } |
1112 | |
1113 | return result; |
1114 | } |
1115 | |
1116 | |
1117 | /* |
1118 | *---------------------------------------------------------------------- |
1119 | * QuoteListToListObjCmd -- |
1120 | * |
1121 | * Implements "ns_quotelisttolist". Removes space, \ and ' |
1122 | * characters in a string. |
1123 | * |
1124 | * Results: |
1125 | * TCL_OK and set the stripped string as the Tcl result or TCL_ERROR |
1126 | * if failure. |
1127 | * |
1128 | * Side effects: |
1129 | * None. |
1130 | * |
1131 | *---------------------------------------------------------------------- |
1132 | */ |
1133 | |
1134 | static int |
1135 | QuoteListToListObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
1136 | { |
1137 | int result = TCL_OK0; |
1138 | |
1139 | if (objc != 2) { |
1140 | Tcl_WrongNumArgs(interp, 1, objv, "quotelist"); |
1141 | result = TCL_ERROR1; |
1142 | } else { |
1143 | const char *quotelist; |
1144 | bool_Bool inquotes; |
1145 | Ns_DStringTcl_DString ds; |
1146 | Tcl_Obj *listObj = Tcl_NewListObj(0, NULL((void*)0)); |
1147 | |
1148 | Ns_DStringInitTcl_DStringInit(&ds); |
1149 | quotelist = Tcl_GetString(objv[1]); |
1150 | inquotes = NS_FALSE0; |
1151 | |
1152 | while (*quotelist != '\0') { |
1153 | if (CHARTYPE(space, *quotelist)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*quotelist ))))] & (unsigned short int) _ISspace)) != 0 && !inquotes) { |
1154 | if (ds.length != 0) { |
1155 | Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(ds.string, ds.length)); |
1156 | Ns_DStringSetLengthTcl_DStringSetLength(&ds, 0); |
1157 | } |
1158 | while (CHARTYPE(space, *quotelist)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*quotelist ))))] & (unsigned short int) _ISspace)) != 0) { |
1159 | quotelist++; |
1160 | } |
1161 | } else if (*quotelist == '\\' && (*(quotelist + 1) != '\0')) { |
1162 | Ns_DStringNAppendTcl_DStringAppend(&ds, quotelist + 1, 1); |
1163 | quotelist += 2; |
1164 | } else if (*quotelist == '\'') { |
1165 | if (inquotes) { |
1166 | /* Finish element */ |
1167 | Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(ds.string, ds.length)); |
1168 | Ns_DStringSetLengthTcl_DStringSetLength(&ds, 0); |
1169 | inquotes = NS_FALSE0; |
1170 | } else { |
1171 | /* Start element */ |
1172 | inquotes = NS_TRUE1; |
1173 | } |
1174 | quotelist++; |
1175 | } else { |
1176 | Ns_DStringNAppendTcl_DStringAppend(&ds, quotelist, 1); |
1177 | quotelist++; |
1178 | } |
1179 | } |
1180 | if (ds.length != 0) { |
1181 | Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(ds.string, ds.length)); |
1182 | } |
1183 | Ns_DStringFreeTcl_DStringFree(&ds); |
1184 | Tcl_SetObjResult(interp, listObj); |
1185 | } |
1186 | return result; |
1187 | } |
1188 | |
1189 | |
1190 | /* |
1191 | *---------------------------------------------------------------------- |
1192 | * QuoteSqlValue -- |
1193 | * |
1194 | * Helper function for QuoteValueObjCmd() and QuoteListObjCmd() |
1195 | * doing the actual quoting work. |
1196 | * |
1197 | * Results: |
1198 | * Ns_ReturnCode to indicate success (NS_OK or NS_ERROR). |
1199 | * |
1200 | * Side effects: |
1201 | * Updates dsPtr by appending the value. |
1202 | * |
1203 | *---------------------------------------------------------------------- |
1204 | */ |
1205 | static Ns_ReturnCode |
1206 | QuoteSqlValue(Tcl_DString *dsPtr, Tcl_Obj *valueObj, int valueType) |
1207 | { |
1208 | int valueLength; |
1209 | const char *valueString; |
1210 | Ns_ReturnCode result = NS_OK; |
1211 | |
1212 | NS_NONNULL_ASSERT(dsPtr != NULL)((void) (0)); |
1213 | NS_NONNULL_ASSERT(valueObj != NULL)((void) (0)); |
1214 | |
1215 | valueString = Tcl_GetStringFromObj(valueObj, &valueLength); |
1216 | |
1217 | if (valueObj->typePtr == intTypePtr) { |
1218 | /* |
1219 | * Since we can trust the byterep, we can bypass the expensive |
1220 | * Tcl_UtfToExternalDString check. |
1221 | */ |
1222 | if (valueType == INTCHAR('n')((int)((unsigned char)(('n'))))) { |
1223 | Tcl_DStringAppend(dsPtr, valueString, valueLength); |
1224 | } else { |
1225 | Tcl_DStringAppend(dsPtr, "'", 1); |
1226 | Tcl_DStringAppend(dsPtr, valueString, valueLength); |
1227 | Tcl_DStringAppend(dsPtr, "'", 1); |
1228 | } |
1229 | } else { |
1230 | Tcl_DString ds; |
1231 | /* |
1232 | * Protect against potential attacks, e.g. embedded nulls |
1233 | * appearing after conversion to the external value. |
1234 | */ |
1235 | Tcl_DStringInit(&ds); |
1236 | Tcl_UtfToExternalDString(NULL((void*)0), valueString, valueLength, &ds); |
1237 | |
1238 | if (strlen(ds.string) < (size_t)ds.length) { |
1239 | result = NS_ERROR; |
1240 | |
1241 | } else if (valueType == INTCHAR('n')((int)((unsigned char)(('n'))))) { |
1242 | Tcl_DStringAppend(dsPtr, valueString, valueLength); |
1243 | |
1244 | } else { |
1245 | Tcl_DStringAppend(dsPtr, "'", 1); |
1246 | |
1247 | for (;;) { |
1248 | const char *p = strchr(valueString, INTCHAR('\'')((int)((unsigned char)(('\''))))); |
1249 | if (p == NULL((void*)0)) { |
1250 | Tcl_DStringAppend(dsPtr, valueString, valueLength); |
1251 | break; |
1252 | } else { |
1253 | int length = (int)((p - valueString) + 1); |
1254 | |
1255 | Tcl_DStringAppend(dsPtr, valueString, length); |
1256 | Tcl_DStringAppend(dsPtr, "'", 1); |
1257 | valueString = p+1; |
1258 | valueLength -= length; |
1259 | } |
1260 | } |
1261 | Tcl_DStringAppend(dsPtr, "'", 1); |
1262 | } |
1263 | Tcl_DStringFree(&ds); |
1264 | } |
1265 | |
1266 | return result; |
1267 | } |
1268 | |
1269 | /* |
1270 | *---------------------------------------------------------------------- |
1271 | * QuoteValueObjCmd -- |
1272 | * |
1273 | * Implements "ns_dbquotevalue". |
1274 | * Prepare a value string for inclusion in an SQL statement: |
1275 | * - "" is translated into NULL. |
1276 | * - All values of any numeric type are left alone. |
1277 | * - All other values are surrounded by single quotes and any |
1278 | * single quotes included in the value are escaped (i.e. translated |
1279 | * into 2 single quotes). |
1280 | * |
1281 | * Results: |
1282 | * Tcl standard result codes. |
1283 | * |
1284 | * Side effects: |
1285 | * Modifying interp result. |
1286 | * |
1287 | *---------------------------------------------------------------------- |
1288 | */ |
1289 | static int |
1290 | QuoteValueObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
1291 | { |
1292 | int result, valueType = INTCHAR('q')((int)((unsigned char)(('q')))); |
1293 | Tcl_Obj *valueObj; |
1294 | Ns_ObjvSpec args[] = { |
1295 | {"value", Ns_ObjvObj, &valueObj, NULL((void*)0)}, |
1296 | {"?type", Ns_ObjvIndex, &valueType, (void*)valueTypes}, |
1297 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
1298 | }; |
1299 | |
1300 | if (Ns_ParseObjv(NULL((void*)0), args, interp, 1, objc, objv) != NS_OK) { |
1301 | result = TCL_ERROR1; |
1302 | |
1303 | } else if (*Tcl_GetString(valueObj) == '\0') { |
1304 | Tcl_SetObjResult(interp, Tcl_NewStringObj("NULL", 4)); |
1305 | result = TCL_OK0; |
1306 | |
1307 | } else { |
1308 | Tcl_DString ds; |
1309 | |
1310 | Tcl_DStringInit(&ds); |
1311 | if (unlikely(QuoteSqlValue(&ds, valueObj, valueType) == NS_ERROR)(__builtin_expect((QuoteSqlValue(&ds, valueObj, valueType ) == NS_ERROR), 0))) { |
1312 | Ns_TclPrintfResult(interp, "input string '%s' contains invalid characters", |
1313 | Tcl_GetString(valueObj)); |
1314 | Tcl_DStringFree(&ds); |
1315 | result = TCL_ERROR1; |
1316 | |
1317 | } else { |
1318 | Tcl_DStringResult(interp, &ds); |
1319 | result = TCL_OK0; |
1320 | } |
1321 | |
1322 | } |
1323 | return result; |
1324 | } |
1325 | |
1326 | |
1327 | /* |
1328 | *---------------------------------------------------------------------- |
1329 | * QuoteListObjCmd -- |
1330 | * |
1331 | * Implements "ns_dbquotelist". |
1332 | * Prepare a value string for inclusion in an SQL statement: |
1333 | * - "" is translated into NULL. |
1334 | * - All values of any numeric type are left alone. |
1335 | * - All other values are surrounded by single quotes and any |
1336 | * single quotes included in the value are escaped (i.e. translated |
1337 | * into 2 single quotes). |
1338 | * |
1339 | * Results: |
1340 | * Tcl standard result codes. |
1341 | * |
1342 | * Side effects: |
1343 | * Modifying interp result. |
1344 | * |
1345 | *---------------------------------------------------------------------- |
1346 | */ |
1347 | |
1348 | static int |
1349 | QuoteListObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
1350 | { |
1351 | int result = TCL_OK0, valueType = INTCHAR('q')((int)((unsigned char)(('q')))); |
1352 | Tcl_Obj *listObj; |
1353 | Ns_ObjvSpec args[] = { |
1354 | {"list", Ns_ObjvObj, &listObj, NULL((void*)0)}, |
1355 | {"?type", Ns_ObjvIndex, &valueType, (void*)valueTypes}, |
1356 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
1357 | }; |
1358 | |
1359 | if (Ns_ParseObjv(NULL((void*)0), args, interp, 1, objc, objv) != NS_OK) { |
1360 | result = TCL_ERROR1; |
1361 | |
1362 | } else { |
1363 | Tcl_DString ds; |
1364 | int oc; |
1365 | Tcl_Obj **ov; |
1366 | |
1367 | Tcl_DStringInit(&ds); |
1368 | if (Tcl_ListObjGetElements(interp, listObj, &oc, &ov) == TCL_OK0) { |
1369 | int i; |
1370 | |
1371 | for (i = 0; i < oc; i++) { |
1372 | |
1373 | if (QuoteSqlValue(&ds, ov[i], valueType) != NS_OK) { |
1374 | Ns_TclPrintfResult(interp, "input string '%s' contains invalid characters", |
1375 | Tcl_GetString(ov[i])); |
1376 | result = TCL_ERROR1; |
1377 | break; |
1378 | |
1379 | } else { |
1380 | if (i < oc-1) { |
1381 | Tcl_DStringAppend(&ds, ",", 1); |
1382 | } |
1383 | } |
1384 | } |
1385 | if (result == TCL_OK0) { |
1386 | Tcl_DStringResult(interp, &ds); |
1387 | } else { |
1388 | Tcl_DStringFree(&ds); |
1389 | } |
1390 | |
1391 | } else { |
1392 | result = TCL_ERROR1; |
1393 | } |
1394 | } |
1395 | return result; |
1396 | } |
1397 | |
1398 | /* |
1399 | *---------------------------------------------------------------------- |
1400 | * |
1401 | * GetCsvObjCmd -- |
1402 | * |
1403 | * Implements "ns_getcsv". The command reads a single line from a |
1404 | * CSV file and parses the results into a Tcl list variable. |
1405 | * |
1406 | * Results: |
1407 | * A standard Tcl result. |
1408 | * |
1409 | * Side effects: |
1410 | * One line is read for given open channel. |
1411 | * |
1412 | *---------------------------------------------------------------------- |
1413 | */ |
1414 | static void |
1415 | FinishElement(Tcl_DString *elemPtr, Tcl_DString *colsPtr, bool_Bool quoted) |
1416 | { |
1417 | if (!quoted) { |
1418 | Tcl_DStringAppendElement(colsPtr, Ns_StrTrim(elemPtr->string)); |
1419 | } else { |
1420 | Tcl_DStringAppendElement(colsPtr, elemPtr->string); |
1421 | } |
1422 | Tcl_DStringSetLength(elemPtr, 0); |
1423 | } |
1424 | |
1425 | |
1426 | static int |
1427 | GetCsvObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
1428 | { |
1429 | int trimUnquoted = 0, result = TCL_OK0; |
1430 | char *delimiter = (char *)",", *quoteString = (char *)"\"", *fileId, *varName; |
1431 | Tcl_Channel chan; |
1432 | Ns_ObjvSpec opts[] = { |
1433 | {"-delimiter", Ns_ObjvString, &delimiter, NULL((void*)0)}, |
1434 | {"-trim", Ns_ObjvBool, &trimUnquoted, INT2PTR(NS_TRUE)((void *)(intptr_t)(1))}, |
1435 | {"-quotechar", Ns_ObjvString, "eString, NULL((void*)0)}, |
1436 | {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)}, |
1437 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
1438 | }; |
1439 | Ns_ObjvSpec args[] = { |
1440 | {"fileId", Ns_ObjvString, &fileId, NULL((void*)0)}, |
1441 | {"varName", Ns_ObjvString, &varName, NULL((void*)0)}, |
1442 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
1443 | }; |
1444 | |
1445 | if (Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK) { |
1446 | result = TCL_ERROR1; |
1447 | |
1448 | } else if (Ns_TclGetOpenChannel(interp, fileId, 0, NS_FALSE0, &chan) == TCL_ERROR1) { |
1449 | result = TCL_ERROR1; |
1450 | |
1451 | } else { |
1452 | int ncols; |
1453 | bool_Bool inquote, quoted, emptyElement; |
1454 | const char *p, *value; |
1455 | Tcl_DString line, cols, elem; |
1456 | char c, quote = *quoteString; |
1457 | |
1458 | Tcl_DStringInit(&line); |
1459 | Tcl_DStringInit(&cols); |
1460 | Tcl_DStringInit(&elem); |
1461 | |
1462 | ncols = 0; |
1463 | inquote = NS_FALSE0; |
1464 | quoted = NS_FALSE0; |
1465 | emptyElement = NS_TRUE1; |
1466 | |
1467 | for (;;) { |
1468 | if (Tcl_Gets(chan, &line) < 0) { |
1469 | Tcl_DStringFree(&line); |
1470 | Tcl_DStringFree(&cols); |
1471 | Tcl_DStringFree(&elem); |
1472 | |
1473 | if (Tcl_Eof(chan) == 0) { |
1474 | Ns_TclPrintfResult(interp, "could not read from %s: %s", |
1475 | fileId, Tcl_PosixError(interp)); |
1476 | return TCL_ERROR1; |
1477 | } |
1478 | Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); |
1479 | return TCL_OK0; |
1480 | } |
1481 | |
1482 | p = line.string; |
1483 | while (*p != '\0') { |
1484 | c = *p++; |
1485 | loopstart: |
1486 | if (inquote) { |
1487 | if (c == quote) { |
1488 | c = *p++; |
1489 | if (c == '\0') { |
1490 | /* |
1491 | * Line ends after quote |
1492 | */ |
1493 | inquote = NS_FALSE0; |
1494 | break; |
1495 | } |
1496 | if (c == quote) { |
1497 | /* |
1498 | * We have a quote in the quote. |
1499 | */ |
1500 | Tcl_DStringAppend(&elem, &c, 1); |
1501 | } else { |
1502 | inquote = NS_FALSE0; |
1503 | goto loopstart; |
1504 | } |
1505 | } else { |
1506 | Tcl_DStringAppend(&elem, &c, 1); |
1507 | } |
1508 | } else { |
1509 | if (c == quote && emptyElement) { |
1510 | inquote = NS_TRUE1; |
1511 | quoted = NS_TRUE1; |
1512 | emptyElement = NS_FALSE0; |
1513 | } else if (strchr(delimiter, INTCHAR(c)((int)((unsigned char)((c))))) != NULL((void*)0)) { |
1514 | FinishElement(&elem, &cols, (trimUnquoted ? quoted : 1)); |
1515 | ncols++; |
1516 | quoted = NS_FALSE0; |
1517 | emptyElement = NS_TRUE1; |
1518 | } else { |
1519 | emptyElement = NS_FALSE0; |
1520 | if (!quoted) { |
1521 | Tcl_DStringAppend(&elem, &c, 1); |
1522 | } |
1523 | } |
1524 | } |
1525 | } |
1526 | if (inquote) { |
1527 | Tcl_DStringAppend(&elem, "\n", 1); |
1528 | Tcl_DStringSetLength(&line, 0); |
1529 | continue; |
1530 | } |
1531 | break; |
1532 | } |
1533 | |
1534 | if (!(ncols == 0 && emptyElement)) { |
1535 | FinishElement(&elem, &cols, (trimUnquoted ? quoted : 1)); |
1536 | ncols++; |
1537 | } |
1538 | value = Tcl_SetVar(interp, varName, cols.string, TCL_LEAVE_ERR_MSG)Tcl_SetVar2(interp, varName, ((void*)0), cols.string, 0x200); |
1539 | Tcl_DStringFree(&line); |
1540 | Tcl_DStringFree(&cols); |
1541 | Tcl_DStringFree(&elem); |
1542 | |
1543 | if (value == NULL((void*)0)) { |
1544 | result = TCL_ERROR1; |
1545 | } else { |
1546 | Tcl_SetObjResult(interp, Tcl_NewIntObj(ncols)); |
1547 | } |
1548 | } |
1549 | return result; |
1550 | } |
1551 | |
1552 | |
1553 | /* |
1554 | *---------------------------------------------------------------------- |
1555 | * DbGetHandle -- |
1556 | * |
1557 | * Get database handle from its handle id. |
1558 | * |
1559 | * Results: |
1560 | * Return TCL_OK if handle is found or TCL_ERROR otherwise. |
1561 | * |
1562 | * Side effects: |
1563 | * None. |
1564 | * |
1565 | *---------------------------------------------------------------------- |
1566 | */ |
1567 | |
1568 | static int |
1569 | DbGetHandle(InterpData *idataPtr, Tcl_Interp *interp, const char *handleId, Ns_DbHandle **handle, |
1570 | Tcl_HashEntry **hPtrPtr) |
1571 | { |
1572 | Tcl_HashEntry *hPtr; |
1573 | int result = TCL_OK0; |
1574 | |
1575 | hPtr = Tcl_FindHashEntry(&idataPtr->dbs, handleId)(*((&idataPtr->dbs)->findProc))(&idataPtr->dbs , (const char *)(handleId)); |
1576 | if (hPtr == NULL((void*)0)) { |
1577 | Ns_TclPrintfResult(interp, "invalid database id: \"%s\"", handleId); |
1578 | result = TCL_ERROR1; |
1579 | |
1580 | } else { |
1581 | *handle = (Ns_DbHandle *) Tcl_GetHashValue(hPtr)((hPtr)->clientData); |
1582 | if (hPtrPtr != NULL((void*)0)) { |
1583 | *hPtrPtr = hPtr; |
1584 | } |
1585 | } |
1586 | return result; |
1587 | } |
1588 | |
1589 | |
1590 | /* |
1591 | *---------------------------------------------------------------------- |
1592 | * EnterDbHandle -- |
1593 | * |
1594 | * Enter a database handle and create its handle id. |
1595 | * |
1596 | * Results: |
1597 | * The database handle id is returned as a Tcl result. |
1598 | * |
1599 | * Side effects: |
1600 | * None. |
1601 | * |
1602 | *---------------------------------------------------------------------- |
1603 | */ |
1604 | |
1605 | static void |
1606 | EnterDbHandle(InterpData *idataPtr, Tcl_Interp *interp, Ns_DbHandle *handle, Tcl_Obj *listObj) |
1607 | { |
1608 | Tcl_HashEntry *hPtr; |
1609 | int isNew, next, len; |
1610 | char buf[100]; |
1611 | |
1612 | NS_NONNULL_ASSERT(idataPtr != NULL)((void) (0)); |
1613 | NS_NONNULL_ASSERT(interp != NULL)((void) (0)); |
1614 | NS_NONNULL_ASSERT(handle != NULL)((void) (0)); |
1615 | NS_NONNULL_ASSERT(listObj != NULL)((void) (0)); |
1616 | |
1617 | next = idataPtr->dbs.numEntries; |
1618 | do { |
1619 | len = snprintf(buf, sizeof(buf), "nsdb%x", next++)__builtin___snprintf_chk (buf, sizeof(buf), 2 - 1, __builtin_object_size (buf, 2 > 1), "nsdb%x", next++); |
1620 | hPtr = Tcl_CreateHashEntry(&idataPtr->dbs, buf, &isNew)(*((&idataPtr->dbs)->createProc))(&idataPtr-> dbs, (const char *)(buf), &isNew); |
1621 | } while (isNew == 0); |
1622 | |
1623 | Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(buf, len)); |
1624 | Tcl_SetHashValue(hPtr, handle)((hPtr)->clientData = (ClientData) (handle)); |
1625 | } |
1626 | |
1627 | |
1628 | /* |
1629 | *---------------------------------------------------------------------- |
1630 | * DbFail -- |
1631 | * |
1632 | * Common routine that creates database failure message. |
1633 | * |
1634 | * Results: |
1635 | * Return TCL_ERROR and set database failure message as Tcl result. |
1636 | * |
1637 | * Side effects: |
1638 | * None. |
1639 | * |
1640 | *---------------------------------------------------------------------- |
1641 | */ |
1642 | |
1643 | static int |
1644 | DbFail(Tcl_Interp *interp, Ns_DbHandle *handle, const char *cmd) |
1645 | { |
1646 | Tcl_DString ds; |
1647 | NS_NONNULL_ASSERT(handle != NULL)((void) (0)); |
1648 | |
1649 | Tcl_DStringInit(&ds); |
1650 | Ns_DStringPrintf(&ds, "Database operation \"%s\" failed", cmd); |
1651 | if (handle->cExceptionCode[0] != '\0') { |
1652 | Ns_DStringPrintf(&ds, " (exception %s", handle->cExceptionCode); |
1653 | if (handle->dsExceptionMsg.length > 0) { |
1654 | Ns_DStringPrintf(&ds, ", \"%s\"", handle->dsExceptionMsg.string); |
1655 | } |
1656 | Ns_DStringPrintf(&ds, ")"); |
1657 | } |
1658 | Tcl_DStringResult(interp, &ds); |
1659 | NsDbSetActive("dbfail", handle, NS_FALSE0); |
1660 | |
1661 | return TCL_ERROR1; |
1662 | } |
1663 | |
1664 | |
1665 | /* |
1666 | *---------------------------------------------------------------------- |
1667 | * FreeData -- |
1668 | * |
1669 | * Free per-interp data at interp delete time. |
1670 | * |
1671 | * Results: |
1672 | * None. |
1673 | * |
1674 | * Side effects: |
1675 | * None. |
1676 | * |
1677 | *---------------------------------------------------------------------- |
1678 | */ |
1679 | |
1680 | static void |
1681 | FreeData(ClientData clientData, Tcl_Interp *UNUSED(interp)UNUSED_interp __attribute__((__unused__))) |
1682 | { |
1683 | InterpData *idataPtr = clientData; |
1684 | |
1685 | Tcl_DeleteHashTable(&idataPtr->dbs); |
1686 | ns_free(idataPtr); |
1687 | } |
1688 | |
1689 | /* |
1690 | * Local Variables: |
1691 | * mode: c |
1692 | * c-basic-offset: 4 |
1693 | * fill-column: 70 |
1694 | * indent-tabs-mode: nil |
1695 | * End: |
1696 | */ |