Bug Summary

File:db/dbinit.c
Warning:line 1572, column 9
Using a fixed address is not portable because that address will probably not be valid in all environments or platforms

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name dbinit.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/isvv/naviserver/nsdb -resource-dir /usr/local/lib/clang/15.0.0 -D _FORTIFY_SOURCE=2 -D NDEBUG -D SYSTEM_MALLOC -I ../include -I /usr/include/tcl8.6 -D HAVE_CONFIG_H -internal-isystem /usr/local/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/isvv/naviserver/nsdb -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker alpha -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-07-23-130959-11103-1 -x c dbinit.c
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 * dbinit.c --
33 *
34 * This file contains routines for creating and accessing
35 * pools of database handles.
36 */
37
38#include "db.h"
39
40Ns_LogSeverity Ns_LogSqlDebug;
41
42/*
43 * The following structure defines a database pool.
44 */
45
46struct Handle;
47
48typedef struct Pool {
49 const char *name;
50 const char *desc;
51 const char *source;
52 const char *user;
53 const char *pass;
54 Ns_Mutex lock;
55 Ns_Cond waitCond;
56 Ns_Cond getCond;
57 const char *driver;
58 struct DbDriver *driverPtr;
59 int waiting;
60 int nhandles;
61 struct Handle *firstPtr;
62 struct Handle *lastPtr;
63 Ns_Time maxidle;
64 Ns_Time maxopen;
65 Tcl_WideInt statementCount;
66 Tcl_WideInt getHandleCount;
67 Ns_Time waitTime;
68 Ns_Time sqlTime;
69 Ns_Time minDuration;
70 int stale_on_close;
71 bool_Bool fVerboseError;
72} Pool;
73
74/*
75 * The following structure defines the internal
76 * state of a database handle.
77 */
78
79typedef struct Handle {
80 const char *driver;
81 const char *datasource;
82 const char *user;
83 const char *password;
84 void *connection;
85 const char *poolname;
86 bool_Bool connected;
87 bool_Bool verbose;
88 Ns_Set *row;
89 char cExceptionCode[6];
90 Ns_DStringTcl_DString dsExceptionMsg;
91 void *context;
92 void *statement;
93 bool_Bool fetchingRows;
94 /* Members above must match Ns_DbHandle */
95 struct Handle *nextPtr;
96 struct Pool *poolPtr;
97 time_t otime; /* open time */
98 time_t atime; /* last access time */
99 uintptr_t sessionId;
100 Ns_Time sqlTime;
101 Tcl_WideInt statementCount;
102 int stale_on_close;
103 bool_Bool stale;
104 bool_Bool used;
105 bool_Bool active;
106} Handle;
107
108/*
109 * The following structure maintains per-server data.
110 */
111
112typedef struct ServData {
113 const char *defpool;
114 const char *allowed;
115} ServData;
116
117const char *NS_EMPTY_STRING = "";
118
119/*
120 * Local functions defined in this file
121 */
122
123static Pool *GetPool(const char *pool)
124 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1)));
125static void ReturnHandle(Handle *handlePtr)
126 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1)));
127static bool_Bool IsStale(const Handle *handlePtr, time_t now)
128 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1)));
129static Ns_ReturnCode Connect(Handle *handlePtr)
130 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1)));
131static Pool *CreatePool(const char *pool, const char *path, const char *driver)
132 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2)));
133static int IncrCount(const char *context, const Pool *poolPtr, int incr)
134 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2)));
135static ServData *GetServer(const char *server)
136 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1)));
137static void TransferHandleStats(Handle *handlePtr)
138 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1)));
139
140/*
141 * Static variables defined in this file
142 */
143
144static Ns_TlsCleanup FreeTable;
145static Ns_SchedProc CheckPool;
146static Ns_ArgProc CheckArgProc;
147
148static Tcl_HashTable poolsTable;
149static Tcl_HashTable serversTable;
150static Ns_Tls tls;
151static Ns_Mutex sessionMutex = NULL((void*)0);
152
153/*
154 *----------------------------------------------------------------------
155 *
156 * Ns_DbPoolDescription --
157 *
158 * Return the pool's description string.
159 *
160 * Results:
161 * Configured description string or NULL.
162 *
163 * Side effects:
164 * None.
165 *
166 *----------------------------------------------------------------------
167 */
168
169const char *
170Ns_DbPoolDescription(const char *pool)
171{
172 const Pool *poolPtr;
173 const char *result;
174
175 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
176
177 poolPtr = GetPool(pool);
178 if (poolPtr == NULL((void*)0)) {
179 result = NULL((void*)0);
180 } else {
181 result = poolPtr->desc;
182 }
183
184 return result;
185}
186
187
188/*
189 *----------------------------------------------------------------------
190 *
191 * Ns_DbPoolDefault --
192 *
193 * Return the default pool.
194 *
195 * Results:
196 * String name of default pool or NULL if no default is defined.
197 *
198 * Side effects:
199 * None.
200 *
201 *----------------------------------------------------------------------
202 */
203
204const char *
205Ns_DbPoolDefault(const char *server)
206{
207 const ServData *sdataPtr;
208
209 NS_NONNULL_ASSERT(server != NULL)((void) (0));
210
211 sdataPtr = GetServer(server);
212 return ((sdataPtr != NULL((void*)0)) ? sdataPtr->defpool : NULL((void*)0));
213}
214
215
216/*
217 *----------------------------------------------------------------------
218 *
219 * Ns_DbPoolList --
220 *
221 * Return the list of all pools.
222 *
223 * Results:
224 * Double-null terminated list of pool names.
225 *
226 * Side effects:
227 * None.
228 *
229 *----------------------------------------------------------------------
230 */
231
232const char *
233Ns_DbPoolList(const char *server)
234{
235 const ServData *sdataPtr;
236
237 NS_NONNULL_ASSERT(server != NULL)((void) (0));
238
239 sdataPtr = GetServer(server);
240 return ((sdataPtr != NULL((void*)0)) ? sdataPtr->allowed : NULL((void*)0));
241}
242
243
244/*
245 *----------------------------------------------------------------------
246 *
247 * Ns_DbPoolAllowable --
248 *
249 * Check that access is allowed to a pool.
250 *
251 * Results:
252 * NS_TRUE if allowed, NS_FALSE otherwise.
253 *
254 * Side effects:
255 * None.
256 *
257 *----------------------------------------------------------------------
258 */
259
260bool_Bool
261Ns_DbPoolAllowable(const char *server, const char *pool)
262{
263 register const char *p;
264 bool_Bool result = NS_FALSE0;
265
266 NS_NONNULL_ASSERT(server != NULL)((void) (0));
267 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
268
269 p = Ns_DbPoolList(server);
270 if (p != NULL((void*)0)) {
271 while (*p != '\0') {
272 if (STREQ(pool, p)(((*(pool)) == (*(p))) && (strcmp((pool),(p)) == 0))) {
273 result = NS_TRUE1;
274 break;
275 }
276 p = p + strlen(p) + 1;
277 }
278 }
279 return result;
280}
281
282
283/*
284 *----------------------------------------------------------------------
285 *
286 * Ns_DbPoolPutHandle --
287 *
288 * Cleanup and then return a handle to its pool.
289 *
290 * Results:
291 * None.
292 *
293 * Side effects:
294 * Handle is flushed, reset, and possibly closed as required.
295 *
296 *----------------------------------------------------------------------
297 */
298
299void
300Ns_DbPoolPutHandle(Ns_DbHandle *handle)
301{
302 Handle *handlePtr;
303 Pool *poolPtr;
304 time_t now;
305
306 NS_NONNULL_ASSERT(handle != NULL)((void) (0));
307
308 handlePtr = (Handle *) handle;
309 poolPtr = handlePtr->poolPtr;
310
311 /*
312 * Cleanup the handle.
313 */
314
315 (void) Ns_DbFlush(handle);
316 (void) Ns_DbResetHandle(handle);
317
318 Ns_DStringFreeTcl_DStringFree(&handle->dsExceptionMsg);
319 handle->cExceptionCode[0] = '\0';
320 handlePtr->active = NS_FALSE0;
321
322 /*
323 * Close the handle if it is stale, otherwise update
324 * the last access time.
325 */
326
327 time(&now);
328 if (IsStale(handlePtr, now) == NS_TRUE1) {
1
Assuming the condition is false
2
Taking false branch
329 NsDbDisconnect(handle);
330 } else {
331 handlePtr->atime = now;
332 }
333 (void) IncrCount("Ns_DbPoolPutHandle", poolPtr, -1);
3
Calling 'IncrCount'
334
335 Ns_MutexLock(&poolPtr->lock);
336 TransferHandleStats(handlePtr);
337 ReturnHandle(handlePtr);
338 if (poolPtr->waiting != 0) {
339 Ns_CondSignal(&poolPtr->getCond);
340 }
341 Ns_MutexUnlock(&poolPtr->lock);
342}
343
344
345/*
346 *----------------------------------------------------------------------
347 *
348 * Ns_DbPoolTimedGetHandle --
349 *
350 * Return a single handle from a pool within the given number of
351 * seconds.
352 *
353 * Results:
354 * Pointer to Ns_DbHandle or NULL on error or timeout.
355 *
356 * Side effects:
357 * Database may be opened if needed.
358 *
359 *----------------------------------------------------------------------
360 */
361
362Ns_DbHandle *
363Ns_DbPoolTimedGetHandle(const char *pool, const Ns_Time *wait)
364{
365 Ns_DbHandle *handle;
366
367 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
368
369 if (Ns_DbPoolTimedGetMultipleHandles(&handle, pool, 1, wait) != NS_OK) {
370 handle = NULL((void*)0);
371 }
372 return handle;
373}
374
375
376/*
377 *----------------------------------------------------------------------
378 *
379 * Ns_DbPoolGetHandle --
380 *
381 * Return a single handle from a pool.
382 *
383 * Results:
384 * Pointer to Ns_DbHandle or NULL on error.
385 *
386 * Side effects:
387 * Database may be opened if needed.
388 *
389 *----------------------------------------------------------------------
390 */
391
392Ns_DbHandle *
393Ns_DbPoolGetHandle(const char *pool)
394{
395 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
396
397 return Ns_DbPoolTimedGetHandle(pool, NULL((void*)0));
398}
399
400
401/*
402 *----------------------------------------------------------------------
403 *
404 * Ns_DbPoolGetMultipleHandles --
405 *
406 * Return 1 or more handles from a pool.
407 *
408 * Results:
409 * NS_OK if the handlers where allocated, NS_ERROR
410 * otherwise.
411 *
412 * Side effects:
413 * Given array of handles is updated with pointers to allocated
414 * handles. Also, database may be opened if needed.
415 *
416 *----------------------------------------------------------------------
417 */
418
419Ns_ReturnCode
420Ns_DbPoolGetMultipleHandles(Ns_DbHandle **handles, const char *pool, int nwant)
421{
422 NS_NONNULL_ASSERT(handles != NULL)((void) (0));
423 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
424
425 return Ns_DbPoolTimedGetMultipleHandles(handles, pool, nwant, NULL((void*)0));
426}
427
428
429/*
430 *----------------------------------------------------------------------
431 *
432 * Ns_DbPoolTimedGetMultipleHandles --
433 *
434 * Return 1 or more handles from a pool within the given number
435 * of seconds.
436 *
437 * Results:
438 * NS_OK if the handlers where allocated, NS_TIMEOUT if the
439 * thread could not wait long enough for the handles, NS_ERROR
440 * otherwise.
441 *
442 * Side effects:
443 * Given array of handles is updated with pointers to allocated
444 * handles. Also, database may be opened if needed.
445 *
446 *----------------------------------------------------------------------
447 */
448
449Ns_ReturnCode
450Ns_DbPoolTimedGetMultipleHandles(Ns_DbHandle **handles, const char *pool,
451 int nwant, const Ns_Time *wait)
452{
453 Handle *handlePtr;
454 Handle **handlesPtrPtr = (Handle **) handles;
455 Pool *poolPtr;
456 Ns_Time timeout, startTime, endTime, diffTime;
457 const Ns_Time *timePtr;
458 int i, ngot;
459 Ns_ReturnCode status;
460
461 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
462 NS_NONNULL_ASSERT(handles != NULL)((void) (0));
463
464 /*
465 * Verify the pool, the number of available handles in the pool,
466 * and that the calling thread does not already own handles from
467 * this pool.
468 */
469
470 poolPtr = GetPool(pool);
471 if (poolPtr == NULL((void*)0)) {
472 Ns_Log(Error, "dbinit: no such pool '%s'", pool);
473 return NS_ERROR;
474 }
475 if (poolPtr->nhandles < nwant) {
476 Ns_Log(Error, "dbinit: "
477 "failed to get %d handles from a db pool of only %d handles: '%s'",
478 nwant, poolPtr->nhandles, pool);
479 return NS_ERROR;
480 }
481 ngot = IncrCount("Ns_DbPoolTimedGetMultipleHandles try", poolPtr, nwant);
482 if (ngot > 0) {
483 Ns_Log(Error, "dbinit: db handle limit exceeded: "
484 "thread already owns %d handle%s from pool '%s'",
485 ngot, ngot == 1 ? NS_EMPTY_STRING : "s", pool);
486 (void) IncrCount("Ns_DbPoolTimedGetMultipleHandles fail", poolPtr, -nwant);
487 return NS_ERROR;
488 }
489
490 /*
491 * Wait until this thread can be the exclusive thread acquiring
492 * handles and then wait until all requested handles are available,
493 * watching for timeout in either of these waits.
494 */
495 Ns_GetTime(&startTime);
496 if (wait == NULL((void*)0)) {
497 timePtr = NULL((void*)0);
498 } else {
499 Ns_GetTime(&timeout);
500 Ns_IncrTime(&timeout, wait->sec, wait->usec);
501 timePtr = &timeout;
502 }
503 status = NS_OK;
504
505 Ns_MutexLock(&poolPtr->lock);
506 while (status == NS_OK && poolPtr->waiting != 0) {
507 status = Ns_CondTimedWait(&poolPtr->waitCond, &poolPtr->lock, timePtr);
508 }
509 if (status == NS_OK) {
510 poolPtr->waiting = 1;
511 while (status == NS_OK && ngot < nwant) {
512 while (status == NS_OK && poolPtr->firstPtr == NULL((void*)0)) {
513 status = Ns_CondTimedWait(&poolPtr->getCond, &poolPtr->lock,
514 timePtr);
515 }
516 if (poolPtr->firstPtr != NULL((void*)0)) {
517 handlePtr = poolPtr->firstPtr;
518 poolPtr->firstPtr = handlePtr->nextPtr;
519 handlePtr->nextPtr = NULL((void*)0);
520 if (poolPtr->lastPtr == handlePtr) {
521 poolPtr->lastPtr = NULL((void*)0);
522 }
523 handlePtr->used = NS_TRUE1;
524 handlesPtrPtr[ngot++] = handlePtr;
525 }
526 }
527 poolPtr->waiting = 0;
528 Ns_CondSignal(&poolPtr->waitCond);
529 }
530 Ns_MutexUnlock(&poolPtr->lock);
531
532 /*
533 * Handle special race condition where the final requested handle
534 * arrived just as the condition wait was timing out.
535 */
536
537 if (status == NS_TIMEOUT && ngot == nwant) {
538 status = NS_OK;
539 }
540
541 /*
542 * If status is still ok, connect any handles not already connected,
543 * otherwise return any allocated handles back to the pool, then
544 * update the final number of handles owned by this thread.
545 */
546
547 for (i = 0; status == NS_OK && i < ngot; ++i) {
548 handlePtr = handlesPtrPtr[i];
549 if (!handlePtr->connected) {
550 status = Connect(handlePtr);
551 }
552 }
553
554 Ns_GetTime(&endTime);
555 (void)Ns_DiffTime(&endTime, &startTime, &diffTime);
556
557 Ns_MutexLock(&poolPtr->lock);
558 if (status != NS_OK) {
559 while (ngot > 0) {
560 ReturnHandle(handlesPtrPtr[--ngot]);
561 }
562 if (poolPtr->waiting != 0) {
563 Ns_CondSignal(&poolPtr->getCond);
564 }
565 (void) IncrCount("Ns_DbPoolTimedGetMultipleHandles fail2", poolPtr, -nwant);
566 }
567
568 Ns_IncrTime(&poolPtr->waitTime, diffTime.sec, diffTime.usec);
569 poolPtr->getHandleCount++;
570 Ns_MutexUnlock(&poolPtr->lock);
571
572 return status;
573}
574
575
576/*
577 *----------------------------------------------------------------------
578 *
579 * Ns_DbBouncePool --
580 *
581 * Close all handles in the pool.
582 * Marks handles as stale and close these via CheckPool().
583 *
584 * Results:
585 * NS_OK if pool was in use, NS_ERROR otherwise.
586 *
587 * Side effects:
588 * Closing handles.
589 *
590 *----------------------------------------------------------------------
591 */
592
593Ns_ReturnCode
594Ns_DbBouncePool(const char *pool)
595{
596 Pool *poolPtr;
597 Handle *handlePtr;
598 Ns_ReturnCode status = NS_OK;
599
600 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
601
602 poolPtr = GetPool(pool);
603 if (poolPtr == NULL((void*)0)) {
604 status = NS_ERROR;
605
606 } else {
607 Ns_MutexLock(&poolPtr->lock);
608 poolPtr->stale_on_close++;
609 handlePtr = poolPtr->firstPtr;
610 while (handlePtr != NULL((void*)0)) {
611 if (handlePtr->connected) {
612 handlePtr->stale = NS_TRUE1;
613 }
614 handlePtr->stale_on_close = poolPtr->stale_on_close;
615 handlePtr = handlePtr->nextPtr;
616 }
617 Ns_MutexUnlock(&poolPtr->lock);
618 CheckPool(poolPtr, 0);
619 }
620 return status;
621}
622
623
624/*
625 *----------------------------------------------------------------------
626 *
627 * NsDbInitPools --
628 *
629 * Initialize the database pools at startup.
630 *
631 * Results:
632 * None.
633 *
634 * Side effects:
635 * Pools may be created as configured.
636 *
637 *----------------------------------------------------------------------
638 */
639
640void
641NsDbInitPools(void)
642{
643 const Pool *poolPtr;
644 const Ns_Set *pools;
645 const char *path, *driver;
646 int isNew;
647 size_t i;
648
649 Ns_TlsAlloc(&tls, FreeTable);
650
651 /*
652 * Provide a name for the lock when it is not yet initialized.
653 */
654 if (sessionMutex == NULL((void*)0)) {
655 Ns_MutexInit(&sessionMutex);
656 Ns_MutexSetName(&sessionMutex, "nsdb:session");
657 }
658
659 /*
660 * Attempt to create each database pool.
661 */
662
663 Tcl_InitHashTable(&serversTable, TCL_STRING_KEYS(0));
664 Tcl_InitHashTable(&poolsTable, TCL_STRING_KEYS(0));
665 pools = Ns_ConfigGetSection("ns/db/pools");
666
667 for (i = 0u; (pools != NULL((void*)0)) && (i < Ns_SetSize(pools)((pools)->size)); ++i) {
668 const char *pool = Ns_SetKey(pools, i)((pools)->fields[(i)].name);
669 Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&poolsTable, pool, &isNew)(*((&poolsTable)->createProc))(&poolsTable, (const
char *)(pool), &isNew)
;
670
671 Ns_Log(Ns_LogSqlDebug, "nsdb: Add DB pool: %s", pool);
672 if (isNew == 0) {
673 Ns_Log(Error, "dbinit: duplicate pool: %s", pool);
674 continue;
675 }
676 path = Ns_ConfigSectionPath(NULL((void*)0), NULL((void*)0), NULL((void*)0), "db", "pool", pool, (char *)0L);
677 driver = Ns_ConfigGetValue(path, "driver");
678 poolPtr = CreatePool(pool, path, driver);
679 if (poolPtr == NULL((void*)0)) {
680 Tcl_DeleteHashEntry(hPtr);
681 } else {
682 Tcl_SetHashValue(hPtr, poolPtr)((hPtr)->clientData = (ClientData) (poolPtr));
683 }
684 }
685 Ns_RegisterProcInfo((ns_funcptr_t)CheckPool, "nsdb:check", CheckArgProc);
686}
687
688
689/*
690 *----------------------------------------------------------------------
691 *
692 * Ns_DbPoolStats --
693 *
694 * return usage statistics from pools
695 *
696 * Results:
697 * Tcl result code.
698 *
699 * Side effects:
700 * None.
701 *
702 *----------------------------------------------------------------------
703 */
704int
705Ns_DbPoolStats(Tcl_Interp *interp)
706{
707 const Ns_Set *pools;
708 size_t i;
709 Tcl_Obj *resultObj;
710 int result = TCL_OK0;
711
712 NS_NONNULL_ASSERT(interp != NULL)((void) (0));
713
714 resultObj = Tcl_NewListObj(0, NULL((void*)0));
715 pools = Ns_ConfigGetSection("ns/db/pools");
716
717 for (i = 0u; (pools != NULL((void*)0)) && (i < Ns_SetSize(pools)((pools)->size)); ++i) {
718 const char *pool = Ns_SetKey(pools, i)((pools)->fields[(i)].name);
719 Pool *poolPtr;
720
721 poolPtr = GetPool(pool);
722 if (poolPtr == NULL((void*)0)) {
723 Ns_Log(Warning, "Ignore invalid pool: %s", pool);
724 } else {
725 Handle *handlePtr;
726 Tcl_Obj *valuesObj;
727 int unused = 0, connected = 0, len;
728 char buf[100];
729 Tcl_WideInt statementCount, getHandleCount;
730 Ns_Time sqlTime, waitTime;
731
732 /*
733 * Iterate over the handles of this pool. Some of the
734 * currently unused handles might have been never used. By
735 * subtracting the never used handles from the total
736 * handles, we determine the used handles.
737 */
738 Ns_MutexLock(&poolPtr->lock);
739 for (handlePtr = poolPtr->firstPtr; handlePtr != NULL((void*)0); handlePtr = handlePtr->nextPtr) {
740 if (!handlePtr->used) {
741 unused ++;
742 }
743 if (handlePtr->connected) {
744 connected ++;
745 }
746 TransferHandleStats(handlePtr);
747 }
748 statementCount = poolPtr->statementCount;
749 getHandleCount = poolPtr->getHandleCount;
750 sqlTime = poolPtr->sqlTime;
751 waitTime = poolPtr->waitTime;
752 Ns_MutexUnlock(&poolPtr->lock);
753
754 valuesObj = Tcl_NewListObj(0, NULL((void*)0));
755 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("statements", 10));
756 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
757 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewWideIntObj(statementCount));
758 }
759 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
760 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("gethandles", 10));
761 }
762 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
763 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewWideIntObj(getHandleCount));
764 }
765 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
766 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("handles", 7));
767 }
768 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
769 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewIntObj(poolPtr->nhandles));
770 }
771 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
772 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("connected", 9));
773 }
774 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
775 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewIntObj(connected));
776 }
777 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
778 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("used", 4));
779 }
780 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
781 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewIntObj(poolPtr->nhandles - unused));
782 }
783 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
784 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("waittime", 8));
785 }
786 /*
787 * We could use Ns_TclNewTimeObj here (2x), when the default representation
788 * of the obj would be floating point format, but we have still sec:usec.
789 *
790 * Tcl_ListObjAppendElement(interp, valuesObj, Ns_TclNewTimeObj(&poolPtr->waitTime));
791 */
792 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
793 len = snprintf(buf, sizeof(buf), NS_TIME_FMT, (int64_t)waitTime.sec, waitTime.usec)__builtin___snprintf_chk (buf, sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), "%" "l" "d" ".%06ld", (int64_t)waitTime.sec
, waitTime.usec)
;
794 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj(buf, len));
795 }
796 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
797 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("sqltime", 7));
798 }
799 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
800 len = snprintf(buf, sizeof(buf), NS_TIME_FMT, (int64_t)sqlTime.sec, sqlTime.usec)__builtin___snprintf_chk (buf, sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), "%" "l" "d" ".%06ld", (int64_t)sqlTime.sec,
sqlTime.usec)
;
801 result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj(buf, len));
802 }
803 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
804 result = Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(pool, -1));
805 }
806 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
807 result = Tcl_ListObjAppendElement(interp, resultObj, valuesObj);
808 }
809 if (unlikely(result != TCL_OK)(__builtin_expect((result != 0), 0))) {
810 break;
811 }
812 }
813 }
814 if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) {
815 Tcl_SetObjResult(interp, resultObj);
816 }
817
818 return result;
819}
820
821
822
823/*
824 *----------------------------------------------------------------------
825 *
826 * NsDbInitServer --
827 *
828 * Initialize a virtual server allowed and default options.
829 *
830 * Results:
831 * None.
832 *
833 * Side effects:
834 * None.
835 *
836 *----------------------------------------------------------------------
837 */
838
839void
840NsDbInitServer(const char *server)
841{
842 ServData *sdataPtr;
843 Tcl_HashEntry *hPtr;
844 Tcl_HashSearch search;
845 const char *path, *pool;
846 Ns_DStringTcl_DString ds;
847 int isNew;
848
849 path = Ns_ConfigSectionPath(NULL((void*)0), server, NULL((void*)0), "db", (char *)0L);
850
851 /*
852 * Verify the default pool exists, if any.
853 */
854
855 sdataPtr = ns_malloc(sizeof(ServData));
856 hPtr = Tcl_CreateHashEntry(&serversTable, server, &isNew)(*((&serversTable)->createProc))(&serversTable, (const
char *)(server), &isNew)
;
857 Tcl_SetHashValue(hPtr, sdataPtr)((hPtr)->clientData = (ClientData) (sdataPtr));
858 sdataPtr->defpool = Ns_ConfigGetValue(path, "defaultpool");
859 if (sdataPtr->defpool != NULL((void*)0) &&
860 (Tcl_FindHashEntry(&poolsTable, sdataPtr->defpool)(*((&poolsTable)->findProc))(&poolsTable, (const char
*)(sdataPtr->defpool))
== NULL((void*)0))) {
861 Ns_Log(Error, "dbinit: no such default pool '%s'", sdataPtr->defpool);
862 sdataPtr->defpool = NULL((void*)0);
863 }
864
865 /*
866 * Construct the allowed list and call the server-specific init.
867 */
868
869 sdataPtr->allowed = NS_EMPTY_STRING;
870 pool = Ns_ConfigGetValue(path, "pools");
871 if (pool != NULL((void*)0) && poolsTable.numEntries > 0) {
872 const Pool *poolPtr;
873 char *allowed;
874
875 Ns_DStringInitTcl_DStringInit(&ds);
876 if (STREQ(pool, "*")(((*(pool)) == (*("*"))) && (strcmp((pool),("*")) == 0
))
) {
877 hPtr = Tcl_FirstHashEntry(&poolsTable, &search);
878 while (hPtr != NULL((void*)0)) {
879 poolPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
880 NsDbDriverInit(server, poolPtr->driverPtr);
881 Ns_DStringAppendArg(&ds, poolPtr->name);
882 hPtr = Tcl_NextHashEntry(&search);
883 }
884 } else {
885 char *p, *toDelete, *pool2;
886
887 toDelete = p = pool2 = ns_strdup(pool);
888 while (p != NULL((void*)0) && *p != '\0') {
889 p = strchr(pool2, INTCHAR(',')((int)((unsigned char)((',')))));
890 if (p != NULL((void*)0)) {
891 *p = '\0';
892 }
893 hPtr = Tcl_FindHashEntry(&poolsTable, pool2)(*((&poolsTable)->findProc))(&poolsTable, (const char
*)(pool2))
;
894 if (hPtr != NULL((void*)0)) {
895 poolPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
896 NsDbDriverInit(server, poolPtr->driverPtr);
897 Ns_DStringAppendArg(&ds, poolPtr->name);
898 }
899 if (p != NULL((void*)0)) {
900 *p++ = ',';
901 }
902 pool2 = p;
903 }
904 ns_free(toDelete);
905 }
906 allowed = ns_malloc((size_t)ds.length + 1u);
907 memcpy(allowed, ds.string, (size_t)ds.length + 1u);
908 sdataPtr->allowed = allowed;
909 Ns_DStringFreeTcl_DStringFree(&ds);
910 }
911}
912
913
914/*
915 *----------------------------------------------------------------------
916 *
917 * NsDbDisconnect --
918 *
919 * Disconnect a handle by closing the database if needed.
920 *
921 * Results:
922 * None.
923 *
924 * Side effects:
925 * None.
926 *
927 *----------------------------------------------------------------------
928 */
929
930void
931NsDbDisconnect(Ns_DbHandle *handle)
932{
933 Handle *handlePtr;
934
935 NS_NONNULL_ASSERT(handle != NULL)((void) (0));
936
937 handlePtr = (Handle *) handle;
938 (void)NsDbClose(handle);
939
940 handlePtr->connected = NS_FALSE0;
941 handlePtr->atime = handlePtr->otime = 0;
942 handlePtr->active = NS_FALSE0;
943 handlePtr->stale = NS_FALSE0;
944}
945
946
947/*
948 *----------------------------------------------------------------------
949 *
950 * NsDbGetActive, NsDbSetActive --
951 *
952 * Query or modify the "active" state of a handle. A handle is
953 * active between a "ns_db select" and the last "ns_db getrow"
954 * statement.
955 *
956 * Results:
957 * Boolean activity state
958 *
959 * Side effects:
960 * None.
961 *
962 *----------------------------------------------------------------------
963 */
964bool_Bool
965NsDbGetActive(Ns_DbHandle *handle)
966{
967 Handle *handlePtr = (Handle *) handle;
968
969 NS_NONNULL_ASSERT(handle != NULL)((void) (0));
970
971 return handlePtr->active;
972}
973
974void
975NsDbSetActive(const char *UNUSED(context)UNUSED_context __attribute__((__unused__)), Ns_DbHandle *handle, bool_Bool active)
976{
977 Handle *handlePtr = (Handle *) handle;
978
979 /*NS_NONNULL_ASSERT(context != NULL);*/
980 NS_NONNULL_ASSERT(handle != NULL)((void) (0));
981
982 handlePtr->active = active;
983}
984
985
986
987/*
988 *----------------------------------------------------------------------
989 *
990 * NsDbLogSql --
991 *
992 * Log a SQL statement depending on the verbose state of the
993 * handle.
994 *
995 * Results:
996 * None.
997 *
998 * Side effects:
999 * None.
1000 *
1001 *----------------------------------------------------------------------
1002 */
1003
1004void
1005NsDbLogSql(const Ns_Time *startTime, Ns_DbHandle *handle, const char *sql)
1006{
1007 Pool *poolPtr;
1008 Handle *handlePtr;
1009
1010 NS_NONNULL_ASSERT(startTime != NULL)((void) (0));
1011 NS_NONNULL_ASSERT(handle != NULL)((void) (0));
1012 NS_NONNULL_ASSERT(sql != NULL)((void) (0));
1013
1014 handlePtr = (Handle *)handle;
1015 poolPtr = handlePtr->poolPtr;
1016 handlePtr->statementCount++;
1017
1018 if (handle->dsExceptionMsg.length > 0) {
1019 /*
1020 * An exception occurred.
1021 */
1022 if (poolPtr->fVerboseError) {
1023 Ns_Log(Error, "dbinit: source %s msg '%s' SQL:\n%s",
1024 handle->datasource, handle->dsExceptionMsg.string, sql);
1025 }
1026 } else {
1027 /*
1028 * No exception occurred.
1029 */
1030 Ns_Time endTime, diffTime;
1031 long delta;
1032
1033 /*
1034 * Update SQL statistics.
1035 */
1036 Ns_GetTime(&endTime);
1037 delta = Ns_DiffTime(&endTime, startTime, &diffTime);
1038 if (likely(delta >= 0)(__builtin_expect((delta >= 0), 1))) {
1039 Ns_IncrTime(&handlePtr->sqlTime, diffTime.sec, diffTime.usec);
1040 } else {
1041 Ns_Log(Warning, "negative runtime pool %s duration " NS_TIME_FMT"%" "l" "d" ".%06ld" " secs: '%s'",
1042 handle->poolname, (int64_t)diffTime.sec, diffTime.usec, sql);
1043 }
1044
1045 /*
1046 * Log entry, when SQL debug is enabled and SQL time is above
1047 * logging threshold.
1048 */
1049 if (Ns_LogSeverityEnabled(Ns_LogSqlDebug) == NS_TRUE1) {
1050 delta = Ns_DiffTime(&poolPtr->minDuration, &diffTime, NULL((void*)0));
1051
1052 if (delta < 1) {
1053 Ns_Log(Ns_LogSqlDebug, "pool %s duration " NS_TIME_FMT"%" "l" "d" ".%06ld" " secs: '%s'",
1054 handle->poolname, (int64_t)diffTime.sec, diffTime.usec, sql);
1055 }
1056 }
1057 }
1058
1059}
1060
1061
1062/*
1063 *----------------------------------------------------------------------
1064 *
1065 * NsDbGetDriver --
1066 *
1067 * Return a pointer to the driver structure for a handle.
1068 *
1069 * Results:
1070 * Pointer to driver or NULL on error.
1071 *
1072 * Side effects:
1073 * None.
1074 *
1075 *----------------------------------------------------------------------
1076 */
1077
1078struct DbDriver *
1079NsDbGetDriver(const Ns_DbHandle *handle)
1080{
1081 struct DbDriver *result;
1082 const Handle *handlePtr = (const Handle *) handle;
1083
1084 if (handlePtr != NULL((void*)0) && handlePtr->poolPtr != NULL((void*)0)) {
1085 result = handlePtr->poolPtr->driverPtr;
1086 } else {
1087 result = NULL((void*)0);
1088 }
1089
1090 return result;
1091}
1092
1093
1094/*
1095 *----------------------------------------------------------------------
1096 *
1097 * GetPool --
1098 *
1099 * Return the Pool structure for the given pool name.
1100 *
1101 * Results:
1102 * Pointer to Pool structure or NULL if pool does not exist.
1103 *
1104 * Side effects:
1105 * None.
1106 *
1107 *----------------------------------------------------------------------
1108 */
1109
1110static Pool *
1111GetPool(const char *pool)
1112{
1113 Pool * result;
1114 const Tcl_HashEntry *hPtr;
1115
1116 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
1117
1118 hPtr = Tcl_FindHashEntry(&poolsTable, pool)(*((&poolsTable)->findProc))(&poolsTable, (const char
*)(pool))
;
1119 if (hPtr == NULL((void*)0)) {
1120 result = NULL((void*)0);
1121 } else {
1122 result = (Pool *) Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1123 }
1124
1125 return result;
1126}
1127
1128
1129/*
1130 *----------------------------------------------------------------------
1131 *
1132 * ReturnHandle --
1133 *
1134 * Return a handle to its pool. Connected handles are pushed on
1135 * the front of the list, disconnected handles are appended to the
1136 * end.
1137 *
1138 * Results:
1139 * None.
1140 *
1141 * Side effects:
1142 * Handle is returned to the pool. Note: The pool lock must be
1143 * held by the caller and this function does not signal a thread
1144 * waiting for handles.
1145 *
1146 *----------------------------------------------------------------------
1147 */
1148
1149static void
1150ReturnHandle(Handle *handlePtr)
1151{
1152 Pool *poolPtr;
1153
1154 NS_NONNULL_ASSERT(handlePtr != NULL)((void) (0));
1155
1156 poolPtr = handlePtr->poolPtr;
1157 if (poolPtr->firstPtr == NULL((void*)0)) {
1158 poolPtr->firstPtr = poolPtr->lastPtr = handlePtr;
1159 handlePtr->nextPtr = NULL((void*)0);
1160 } else if (handlePtr->connected) {
1161 handlePtr->nextPtr = poolPtr->firstPtr;
1162 poolPtr->firstPtr = handlePtr;
1163 } else {
1164 poolPtr->lastPtr->nextPtr = handlePtr;
1165 poolPtr->lastPtr = handlePtr;
1166 handlePtr->nextPtr = NULL((void*)0);
1167 }
1168}
1169
1170
1171/*
1172 *----------------------------------------------------------------------
1173 *
1174 * IsStale --
1175 *
1176 * Check to see if a handle is stale.
1177 *
1178 * Results:
1179 * NS_TRUE if handle stale, NS_FALSE otherwise.
1180 *
1181 * Side effects:
1182 * None.
1183 *
1184 *----------------------------------------------------------------------
1185 */
1186
1187static bool_Bool
1188IsStale(const Handle *handlePtr, time_t now)
1189{
1190 bool_Bool result = NS_FALSE0;
1191
1192 NS_NONNULL_ASSERT(handlePtr != NULL)((void) (0));
1193
1194 if (handlePtr->connected) {
1195 time_t minAccess, minOpen;
1196
1197 minAccess = now - handlePtr->poolPtr->maxidle.sec;
1198 minOpen = now - handlePtr->poolPtr->maxopen.sec;
1199 if ((handlePtr->poolPtr->maxidle.sec > 0 && handlePtr->atime < minAccess) ||
1200 (handlePtr->poolPtr->maxopen.sec > 0 && (handlePtr->otime < minOpen)) ||
1201 (handlePtr->stale) ||
1202 (handlePtr->poolPtr->stale_on_close > handlePtr->stale_on_close)) {
1203
1204 Ns_Log(Notice, "nsdb: closing %s handle in pool '%s'",
1205 (handlePtr->poolPtr->maxidle.sec > 0 && handlePtr->atime < minAccess) ? "idle"
1206 : (handlePtr->poolPtr->maxopen.sec > 0 && (handlePtr->otime < minOpen) ? "old"
1207 : "stale"),
1208 handlePtr->poolname);
1209
1210 result = NS_TRUE1;
1211 }
1212 }
1213
1214 return result;
1215}
1216
1217
1218/*
1219 *----------------------------------------------------------------------
1220 *
1221 * CheckArgProc --
1222 *
1223 * Ns_ArgProc callback for the pool checker.
1224 *
1225 * Results:
1226 * None.
1227 *
1228 * Side effects:
1229 * Copies name of pool to given dstring.
1230 *
1231 *----------------------------------------------------------------------
1232 */
1233
1234static void
1235CheckArgProc(Tcl_DString *dsPtr, const void *arg)
1236{
1237 const Pool *poolPtr = arg;
1238
1239 Tcl_DStringAppendElement(dsPtr, poolPtr->name);
1240}
1241
1242
1243/*
1244 *----------------------------------------------------------------------
1245 *
1246 * TransferHandleStats --
1247 *
1248 * Transfer the cached statistics values kept per handle into the
1249 * pool statistics (sqlTime and statementCount). The purpose of per
1250 * handle caching is to avoid frequent locking on the pool mutex.
1251 *
1252 * It is assumed that the pool data is mutex protected by the caller.
1253 *
1254 * Results:
1255 * None.
1256 *
1257 * Side effects:
1258 * Updates poolPtr->statementCount and poolPtr->sqlTime.
1259 *
1260 *----------------------------------------------------------------------
1261 */
1262static void
1263TransferHandleStats(Handle *handlePtr)
1264{
1265 NS_NONNULL_ASSERT(handlePtr != NULL)((void) (0));
1266
1267 if (handlePtr->statementCount > 0) {
1268 if (handlePtr->sqlTime.sec != 0 || handlePtr->sqlTime.usec != 0) {
1269 Ns_IncrTime(&handlePtr->poolPtr->sqlTime, handlePtr->sqlTime.sec, handlePtr->sqlTime.usec);
1270 handlePtr->sqlTime.sec = 0;
1271 handlePtr->sqlTime.usec = 0;
1272 }
1273 handlePtr->poolPtr->statementCount += handlePtr->statementCount;
1274 handlePtr->statementCount = 0;
1275 }
1276}
1277
1278/*
1279 *----------------------------------------------------------------------
1280 *
1281 * CheckPool --
1282 *
1283 * Verify all handles in a pool are not stale.
1284 *
1285 * Results:
1286 * None.
1287 *
1288 * Side effects:
1289 * Stale handles, if any, are closed.
1290 *
1291 *----------------------------------------------------------------------
1292 */
1293static void
1294CheckPool(void *arg, int UNUSED(id)UNUSED_id __attribute__((__unused__)))
1295{
1296 Pool *poolPtr = arg;
1297 Handle *handlePtr;
1298
1299 /*
1300 * Grab the entire list of handles from the pool.
1301 */
1302 Ns_MutexLock(&poolPtr->lock);
1303 handlePtr = poolPtr->firstPtr;
1304 poolPtr->firstPtr = poolPtr->lastPtr = NULL((void*)0);
1305 Ns_MutexUnlock(&poolPtr->lock);
1306
1307 /*
1308 * Run through the list of handles, closing any
1309 * which have gone stale, and then return them
1310 * all to the pool.
1311 */
1312
1313 if (handlePtr != NULL((void*)0)) {
1314 Handle *checkedPtr = NULL((void*)0);
1315 time_t now;
1316
1317 time(&now);
1318
1319 while (handlePtr != NULL((void*)0)) {
1320 Handle *nextPtr = handlePtr->nextPtr;
1321
1322 if (IsStale(handlePtr, now) == NS_TRUE1) {
1323 NsDbDisconnect((Ns_DbHandle *) handlePtr);
1324 }
1325 handlePtr->nextPtr = checkedPtr;
1326 checkedPtr = handlePtr;
1327 handlePtr = nextPtr;
1328 }
1329
1330 Ns_MutexLock(&poolPtr->lock);
1331 handlePtr = checkedPtr;
1332 while (handlePtr != NULL((void*)0)) {
1333 Handle *nextPtr = handlePtr->nextPtr;
1334
1335 TransferHandleStats(handlePtr);
1336 ReturnHandle(handlePtr);
1337 handlePtr = nextPtr;
1338 }
1339 if (poolPtr->waiting != 0) {
1340 Ns_CondSignal(&poolPtr->getCond);
1341 }
1342 Ns_MutexUnlock(&poolPtr->lock);
1343 }
1344}
1345
1346
1347/*
1348 *----------------------------------------------------------------------
1349 *
1350 * CreatePool --
1351 *
1352 * Create a new pool using the given driver.
1353 *
1354 * Results:
1355 * Pointer to newly allocated Pool structure.
1356 *
1357 * Side effects:
1358 * None.
1359 *
1360 *----------------------------------------------------------------------
1361 */
1362
1363static Pool *
1364CreatePool(const char *pool, const char *path, const char *driver)
1365{
1366 Pool *poolPtr;
1367 struct DbDriver *driverPtr;
1368 Ns_Time checkinterval;
1369
1370 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
1371 NS_NONNULL_ASSERT(path != NULL)((void) (0));
1372
1373 if (driver == NULL((void*)0)) {
1374 Ns_Log(Error, "dbinit: no driver for pool '%s'", pool);
1375 driverPtr = NULL((void*)0);
1376 } else {
1377 driverPtr = NsDbLoadDriver(driver);
1378 }
1379
1380 if (driverPtr == NULL((void*)0)) {
1381 poolPtr = NULL((void*)0);
1382
1383 } else {
1384 int i;
1385 const char *source;
1386
1387 /*
1388 * Load the configured values.
1389 */
1390 source = Ns_ConfigGetValue(path, "datasource");
1391 if (source == NULL((void*)0)) {
1392 Ns_Log(Error, "dbinit: missing datasource for pool '%s'", pool);
1393 return NULL((void*)0);
1394 }
1395 /*
1396 * Allocate Pool structure and initialize its members
1397 */
1398 poolPtr = ns_calloc(1u, sizeof(Pool));
1399 poolPtr->driver = driver;
1400 poolPtr->driverPtr = driverPtr;
1401 Ns_MutexInit(&poolPtr->lock);
1402 Ns_MutexSetName2(&poolPtr->lock, "nsdb", pool);
1403 Ns_CondInit(&poolPtr->waitCond);
1404 Ns_CondInit(&poolPtr->getCond);
1405 poolPtr->source = source;
1406 poolPtr->name = pool;
1407 poolPtr->user = Ns_ConfigGetValue(path, "user");
1408 poolPtr->pass = Ns_ConfigGetValue(path, "password");
1409 poolPtr->desc = Ns_ConfigGetValue("ns/db/pools", pool);
1410 poolPtr->stale_on_close = 0;
1411 poolPtr->fVerboseError = Ns_ConfigBool(path, "logsqlerrors", NS_FALSE0);
1412 poolPtr->nhandles = Ns_ConfigIntRange(path, "connections", 2, 0, INT_MAX2147483647);
1413
1414 Ns_ConfigTimeUnitRange(path, "maxidle",
1415 "5m", 0, 0, INT_MAX2147483647, 0, &poolPtr->maxidle);
1416 Ns_ConfigTimeUnitRange(path, "maxopen",
1417 "60m", 0, 0, INT_MAX2147483647, 0, &poolPtr->maxopen);
1418 if (poolPtr->maxidle.usec != 0) {
1419 Ns_Log(Warning, "maxidle is implemented based on seconds granularity. "
1420 "Fractions of seconds are ignored");
1421 }
1422 if (poolPtr->maxopen.usec != 0) {
1423 Ns_Log(Warning, "maxopen is implemented based on seconds granularity. "
1424 "Fractions of seconds are ignored");
1425 }
1426
1427 Ns_ConfigTimeUnitRange(path, "logminduration",
1428 "0ms", 0, 0, INT_MAX2147483647, 0, &poolPtr->minDuration);
1429 if (poolPtr->minDuration.sec != 0 || poolPtr->minDuration.usec != 0) {
1430 Ns_Log(Notice, "dbinit: set LogMinDuration for pool %s to " NS_TIME_FMT"%" "l" "d" ".%06ld",
1431 pool, (int64_t)poolPtr->minDuration.sec,
1432 poolPtr->minDuration.usec);
1433 }
1434
1435 /*
1436 * Allocate the handles in the pool
1437 */
1438 poolPtr->firstPtr = poolPtr->lastPtr = NULL((void*)0);
1439 for (i = 0; i < poolPtr->nhandles; ++i) {
1440 Handle *handlePtr = ns_malloc(sizeof(Handle));
1441
1442 Ns_DStringInitTcl_DStringInit(&handlePtr->dsExceptionMsg);
1443 handlePtr->poolPtr = poolPtr;
1444 handlePtr->connection = NULL((void*)0);
1445 handlePtr->connected = NS_FALSE0;
1446 handlePtr->fetchingRows = NS_FALSE0;
1447 handlePtr->row = Ns_SetCreate(NS_SET_NAME_DB"db");
1448#ifdef NS_SET_DEBUG
1449 Ns_Log(Notice, "Ns_DbInit CreatePool %s %i: %p", pool, i, (void*)handlePtr->row);
1450#endif
1451 handlePtr->cExceptionCode[0] = '\0';
1452 handlePtr->otime = handlePtr->atime = 0;
1453 handlePtr->stale = NS_FALSE0;
1454 handlePtr->stale_on_close = 0;
1455 handlePtr->statementCount = 0;
1456 handlePtr->sqlTime.sec = 0;
1457 handlePtr->sqlTime.usec = 0;
1458
1459 /*
1460 * The following elements of the Handle structure could be
1461 * obtained by dereferencing the poolPtr. They're only needed
1462 * to maintain the original Ns_DbHandle structure definition
1463 * which was designed to allow handles outside of pools, a
1464 * feature no longer supported.
1465 */
1466
1467 handlePtr->driver = driver;
1468 handlePtr->datasource = poolPtr->source;
1469 handlePtr->user = poolPtr->user;
1470 handlePtr->password = poolPtr->pass;
1471 handlePtr->verbose = poolPtr->fVerboseError;
1472 handlePtr->poolname = pool;
1473 ReturnHandle(handlePtr);
1474 }
1475
1476 Ns_ConfigTimeUnitRange(path, "checkinterval",
1477 "5m", 1, 0, INT_MAX2147483647, 0, &checkinterval);
1478
1479 (void) Ns_ScheduleProcEx(CheckPool, poolPtr, 0, &checkinterval, NULL((void*)0));
1480 }
1481 return poolPtr;
1482}
1483
1484
1485/*
1486 *----------------------------------------------------------------------
1487 *
1488 * Connect --
1489 *
1490 * Connect a handle by opening the database.
1491 *
1492 * Results:
1493 * NS_OK if connect ok, NS_ERROR otherwise.
1494 *
1495 * Side effects:
1496 * None.
1497 *
1498 *----------------------------------------------------------------------
1499 */
1500
1501static Ns_ReturnCode
1502Connect(Handle *handlePtr)
1503{
1504 Ns_ReturnCode status;
1505
1506 NS_NONNULL_ASSERT(handlePtr != NULL)((void) (0));
1507
1508 status = NsDbOpen((Ns_DbHandle *) handlePtr);
1509 if (status != NS_OK) {
1510 handlePtr->connected = NS_FALSE0;
1511 handlePtr->atime = handlePtr->otime = 0;
1512 handlePtr->stale = NS_FALSE0;
1513 } else {
1514 static uintptr_t sessionId = 0u;
1515
1516 Ns_MutexLock(&sessionMutex);
1517 sessionId++;
1518 Ns_MutexUnlock(&sessionMutex);
1519
1520 handlePtr->connected = NS_TRUE1;
1521 handlePtr->atime = handlePtr->otime = time(NULL((void*)0));
1522 handlePtr->sessionId = sessionId;
1523 }
1524
1525 return status;
1526}
1527
1528
1529/*
1530 *----------------------------------------------------------------------
1531 *
1532 * IncrCount --
1533 *
1534 * Update per-thread count of allocated handles. If count == 0,
1535 * return the current number of allocated handles for this pool.
1536 *
1537 * Results:
1538 * Previous count of allocated handles.
1539 *
1540 * Side effects:
1541 * None.
1542 *
1543 *----------------------------------------------------------------------
1544 */
1545
1546static int
1547IncrCount(const char *UNUSED(context)UNUSED_context __attribute__((__unused__)), const Pool *poolPtr, int incr)
1548{
1549 Tcl_HashTable *tablePtr;
1550 Tcl_HashEntry *hPtr;
1551 int prev, count, isNew;
1552
1553 /*NS_NONNULL_ASSERT(context != NULL);*/
1554 NS_NONNULL_ASSERT(poolPtr != NULL)((void) (0));
1555
1556 tablePtr = Ns_TlsGet(&tls);
1557 if (tablePtr == NULL((void*)0)) {
4
Assuming 'tablePtr' is not equal to NULL
5
Taking false branch
1558 tablePtr = ns_malloc(sizeof(Tcl_HashTable));
1559 Tcl_InitHashTable(tablePtr, TCL_ONE_WORD_KEYS(1));
1560 Ns_TlsSet(&tls, tablePtr);
1561 }
1562 hPtr = Tcl_CreateHashEntry(tablePtr, (const char *) poolPtr, &isNew)(*((tablePtr)->createProc))(tablePtr, (const char *)((const
char *) poolPtr), &isNew)
;
1563 if (isNew != 0) {
6
Assuming 'isNew' is not equal to 0
7
Taking true branch
1564 prev = 0;
1565 } else {
1566 prev = PTR2INT(Tcl_GetHashValue(hPtr))((int)(intptr_t)(((hPtr)->clientData)));
1567 }
1568 count = prev + incr;
1569 if (count
7.1
'count' is not equal to 0
== 0) {
8
Taking false branch
1570 Tcl_DeleteHashEntry(hPtr);
1571 } else if (count
8.1
'count' is not equal to 'prev'
!= prev) {
9
Taking true branch
1572 Tcl_SetHashValue(hPtr, INT2PTR(count))((hPtr)->clientData = (ClientData) (((void *)(intptr_t)(count
))))
;
10
Using a fixed address is not portable because that address will probably not be valid in all environments or platforms
1573 }
1574
1575 return prev;
1576}
1577
1578
1579
1580/*
1581 *----------------------------------------------------------------------
1582 *
1583 * GetServer --
1584 *
1585 * Get per-server data.
1586 *
1587 * Results:
1588 * Pointer to per-server data.
1589 *
1590 * Side effects:
1591 * None.
1592 *
1593 *----------------------------------------------------------------------
1594 */
1595
1596static ServData *
1597GetServer(const char *server)
1598{
1599 ServData *result = NULL((void*)0);
1600 const Tcl_HashEntry *hPtr;
1601
1602 NS_NONNULL_ASSERT(server != NULL)((void) (0));
1603
1604 hPtr = Tcl_FindHashEntry(&serversTable, server)(*((&serversTable)->findProc))(&serversTable, (const
char *)(server))
;
1605 if (hPtr != NULL((void*)0)) {
1606 result = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1607 }
1608 return result;
1609}
1610
1611
1612/*
1613 *----------------------------------------------------------------------
1614 *
1615 * FreeTable --
1616 *
1617 * Free the per-thread count of allocated handles table.
1618 *
1619 * Results:
1620 * None.
1621 *
1622 * Side effects:
1623 * None.
1624 *
1625 *----------------------------------------------------------------------
1626 */
1627
1628static void
1629FreeTable(void *arg)
1630{
1631 Tcl_HashTable *tablePtr = arg;
1632
1633 Tcl_DeleteHashTable(tablePtr);
1634 ns_free(tablePtr);
1635}
1636
1637
1638/*
1639 *----------------------------------------------------------------------
1640 *
1641 * NsDbGetSessionId --
1642 *
1643 * Return the current sessionId
1644 *
1645 * Results:
1646 * sessionId
1647 *
1648 * Side effects:
1649 * None.
1650 *
1651 *----------------------------------------------------------------------
1652 */
1653uintptr_t
1654NsDbGetSessionId(const Ns_DbHandle *handle)
1655{
1656 NS_NONNULL_ASSERT(handle != NULL)((void) (0));
1657
1658 return ((const Handle *)handle)->sessionId;
1659}
1660
1661
1662/*
1663 *----------------------------------------------------------------------
1664 *
1665 * Ns_DbListMinDurations --
1666 *
1667 * Introspection function to list min duration for every available
1668 * pool.
1669 *
1670 * Results:
1671 * Tcl_ListObj containing pairs of pool names and minDurations.
1672 *
1673 * Side effects:
1674 * None.
1675 *
1676 *----------------------------------------------------------------------
1677 */
1678
1679Tcl_Obj *
1680Ns_DbListMinDurations(Tcl_Interp *interp, const char *server)
1681{
1682 Tcl_Obj *resultObj;
1683 const char *pool;
1684
1685 NS_NONNULL_ASSERT(interp != NULL)((void) (0));
1686 NS_NONNULL_ASSERT(server != NULL)((void) (0));
1687
1688 resultObj = Tcl_NewListObj(0, NULL((void*)0));
1689 pool = Ns_DbPoolList(server);
1690 if (pool != NULL((void*)0)) {
1691 for ( ; *pool != '\0'; pool += strlen(pool) + 1u) {
1692 char buffer[100];
1693 const Pool *poolPtr;
1694 int len;
1695
1696 poolPtr = GetPool(pool);
1697 (void) Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(pool, -1));
1698 len = snprintf(buffer, sizeof(buffer), NS_TIME_FMT,__builtin___snprintf_chk (buffer, sizeof(buffer), 2 - 1, __builtin_object_size
(buffer, 2 > 1), "%" "l" "d" ".%06ld", (int64_t)poolPtr->
minDuration.sec, poolPtr->minDuration.usec)
1699 (int64_t)poolPtr->minDuration.sec, poolPtr->minDuration.usec)__builtin___snprintf_chk (buffer, sizeof(buffer), 2 - 1, __builtin_object_size
(buffer, 2 > 1), "%" "l" "d" ".%06ld", (int64_t)poolPtr->
minDuration.sec, poolPtr->minDuration.usec)
;
1700 (void) Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(buffer, len));
1701 }
1702 }
1703 return resultObj;
1704}
1705
1706
1707/*
1708 *----------------------------------------------------------------------
1709 *
1710 * Ns_DbGetMinDuration --
1711 *
1712 * Return the minDuration of the specified pool in the third
1713 * argument.
1714 *
1715 * Results:
1716 * Tcl result code
1717 *
1718 * Side effects:
1719 * None.
1720 *
1721 *----------------------------------------------------------------------
1722 */
1723
1724int
1725Ns_DbGetMinDuration(Tcl_Interp *interp, const char *pool, Ns_Time **minDuration)
1726{
1727 Pool *poolPtr;
1728 int result;
1729
1730 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
1731 NS_NONNULL_ASSERT(minDuration != NULL)((void) (0));
1732
1733 /*
1734 * Get the poolPtr
1735 */
1736 poolPtr = GetPool(pool);
1737 if (poolPtr == NULL((void*)0) && interp != NULL((void*)0)) {
1738 Ns_TclPrintfResult(interp, "Invalid pool '%s'", pool);
1739 result = TCL_ERROR1;
1740 } else {
1741 /*
1742 * Return the duration.
1743 */
1744 *minDuration = &(poolPtr->minDuration);
1745 result = TCL_OK0;
1746 }
1747 return result;
1748}
1749
1750
1751/*
1752 *----------------------------------------------------------------------
1753 *
1754 * Ns_DbSetMinDuration --
1755 *
1756 * Set the minDuration of the specified pool
1757 *
1758 * Results:
1759 * Tcl result code
1760 *
1761 * Side effects:
1762 * None.
1763 *
1764 *----------------------------------------------------------------------
1765 */
1766
1767int
1768Ns_DbSetMinDuration(Tcl_Interp *interp, const char *pool, const Ns_Time *minDuration)
1769{
1770 Pool *poolPtr;
1771 int result;
1772
1773 NS_NONNULL_ASSERT(interp != NULL)((void) (0));
1774 NS_NONNULL_ASSERT(pool != NULL)((void) (0));
1775 NS_NONNULL_ASSERT(minDuration != NULL)((void) (0));
1776
1777 /*
1778 * Get the poolPtr
1779 */
1780 poolPtr = GetPool(pool);
1781 if (poolPtr == NULL((void*)0)) {
1782 Ns_TclPrintfResult(interp, "Invalid pool '%s'", pool);
1783 result = TCL_ERROR1;
1784 } else {
1785 /*
1786 * Set the duration.
1787 */
1788 poolPtr->minDuration = *minDuration;
1789 result = TCL_OK0;
1790 }
1791 return result;
1792}
1793
1794/*
1795 * Local Variables:
1796 * mode: c
1797 * c-basic-offset: 4
1798 * fill-column: 72
1799 * indent-tabs-mode: nil
1800 * End:
1801 */