Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Return an error if localtime_r() fails within one of the date/time functions. Fix for [bd484a090c]. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
76ae8257efc1df6e20ce5718d4824adb |
User & Date: | dan 2011-06-21 12:47:30.109 |
Context
2011-06-21
| ||
12:53 | Fix an error made in the previous commit. The parameters to localtime_s() were accidentally reversed. Ticket [bd484a090c807]. (check-in: 97e86ec6df user: dan tags: trunk) | |
12:47 | Return an error if localtime_r() fails within one of the date/time functions. Fix for [bd484a090c]. (check-in: 76ae8257ef user: dan tags: trunk) | |
03:36 | Add a new AWK script in the tool/ folder for converting text files into C string literals. Use it for building sqlite3_analyzer. (check-in: dcb46d3f68 user: drh tags: trunk) | |
Changes
Changes to src/date.c.
︙ | ︙ | |||
408 409 410 411 412 413 414 415 | static void clearYMD_HMS_TZ(DateTime *p){ p->validYMD = 0; p->validHMS = 0; p->validTZ = 0; } #ifndef SQLITE_OMIT_LOCALTIME /* | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | > > > > | > > > > | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | static void clearYMD_HMS_TZ(DateTime *p){ p->validYMD = 0; p->validHMS = 0; p->validTZ = 0; } #ifndef SQLITE_OMIT_LOCALTIME /* ** The following three functions - osLocaltime_r(), osLocaltime_s() and ** osLocaltime() - are wrappers around system functions localtime_r(), ** localtime_s() and localtime(), respectively. ** ** If the sqlite3GlobalConfig.bLocaltimeFault variable is true when one ** of the following wrappers is called, it returns an error. */ #ifndef SQLITE_OMIT_BUILTIN_TEST #ifdef HAVE_LOCALTIME_R static struct tm * osLocaltime_r(time_t *t, struct tm *pTm){ if( sqlite3GlobalConfig.bLocaltimeFault ) return 0; return localtime_r(t); } #elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S static int osLocaltime_s(time_t *t, struct tm *pTm){ if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; return (int)localtime_s(t, pTm); } #else static struct tm * osLocaltime(time_t *t){ if( sqlite3GlobalConfig.bLocaltimeFault ) return 0; return localtime(t); } #endif #else # define osLocaltime_r(x,y) localtime_r(x,y) # define osLocaltime_s(x,y) localtime_s(x,y) # define osLocaltime(x) localtime(x) #endif /* ** Compute the difference (in milliseconds) between localtime and UTC ** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs, ** return this value and set *pRc to SQLITE_OK. ** ** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value ** is undefined in this case. */ static sqlite3_int64 localtimeOffset( DateTime *p, /* Date at which to calculate offset */ sqlite3_context *pCtx, /* Write error here if one occurs */ int *pRc /* OUT: Error code. SQLITE_OK or ERROR */ ){ DateTime x, y; time_t t; x = *p; computeYMD_HMS(&x); if( x.Y<1971 || x.Y>=2038 ){ x.Y = 2000; x.M = 1; |
︙ | ︙ | |||
436 437 438 439 440 441 442 | x.tz = 0; x.validJD = 0; computeJD(&x); t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); #ifdef HAVE_LOCALTIME_R { struct tm sLocal; | | > > > > | > > > > | > | | | | | | > > > > > > > | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | x.tz = 0; x.validJD = 0; computeJD(&x); t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); #ifdef HAVE_LOCALTIME_R { struct tm sLocal; if( 0==osLocaltime_r(&t, &sLocal) ){ sqlite3_result_error(pCtx, "error in localtime_r()", -1); *pRc = SQLITE_ERROR; return 0; } y.Y = sLocal.tm_year + 1900; y.M = sLocal.tm_mon + 1; y.D = sLocal.tm_mday; y.h = sLocal.tm_hour; y.m = sLocal.tm_min; y.s = sLocal.tm_sec; } #elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S { struct tm sLocal; if( 0!=osLocaltime_s(&t, &sLocal) ){ sqlite3_result_error(pCtx, "error in localtime_s()", -1); *pRc = SQLITE_ERROR; return 0; } y.Y = sLocal.tm_year + 1900; y.M = sLocal.tm_mon + 1; y.D = sLocal.tm_mday; y.h = sLocal.tm_hour; y.m = sLocal.tm_min; y.s = sLocal.tm_sec; } #else { struct tm *pTm; sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); pTm = osLocaltime(&t); if( pTm ){ y.Y = pTm->tm_year + 1900; y.M = pTm->tm_mon + 1; y.D = pTm->tm_mday; y.h = pTm->tm_hour; y.m = pTm->tm_min; y.s = pTm->tm_sec; } sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); if( !pTm ){ sqlite3_result_error(pCtx, "error in localtime()", -1); *pRc = SQLITE_ERROR; return 0; } } #endif y.validYMD = 1; y.validHMS = 1; y.validJD = 0; y.validTZ = 0; computeJD(&y); *pRc = SQLITE_OK; return y.iJD - x.iJD; } #endif /* SQLITE_OMIT_LOCALTIME */ /* ** Process a modifier to a date-time stamp. The modifiers are ** as follows: |
︙ | ︙ | |||
497 498 499 500 501 502 503 | ** start of week ** start of day ** weekday N ** unixepoch ** localtime ** utc ** | | > > > | | < | > | | | < > | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | ** start of week ** start of day ** weekday N ** unixepoch ** localtime ** utc ** ** Return 0 on success and 1 if there is any kind of error. If the error ** is in a system call (i.e. localtime()), then an error message is written ** to context pCtx. If the error is an unrecognized modifier, no error is ** written to pCtx. */ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ int rc = 1; int n; double r; char *z, zBuf[30]; z = zBuf; for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){ z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]]; } z[n] = 0; switch( z[0] ){ #ifndef SQLITE_OMIT_LOCALTIME case 'l': { /* localtime ** ** Assuming the current time value is UTC (a.k.a. GMT), shift it to ** show local time. */ if( strcmp(z, "localtime")==0 ){ computeJD(p); p->iJD += localtimeOffset(p, pCtx, &rc); clearYMD_HMS_TZ(p); } break; } #endif case 'u': { /* ** unixepoch ** ** Treat the current value of p->iJD as the number of ** seconds since 1970. Convert to a real julian day number. */ if( strcmp(z, "unixepoch")==0 && p->validJD ){ p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000; clearYMD_HMS_TZ(p); rc = 0; } #ifndef SQLITE_OMIT_LOCALTIME else if( strcmp(z, "utc")==0 ){ sqlite3_int64 c1; computeJD(p); c1 = localtimeOffset(p, pCtx, &rc); if( rc==SQLITE_OK ){ p->iJD -= c1; clearYMD_HMS_TZ(p); p->iJD += c1 - localtimeOffset(p, pCtx, &rc); } } #endif break; } case 'w': { /* ** weekday N |
︙ | ︙ | |||
727 728 729 730 731 732 733 | }else{ z = sqlite3_value_text(argv[0]); if( !z || parseDateOrTime(context, (char*)z, p) ){ return 1; } } for(i=1; i<argc; i++){ | | | < | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 | }else{ z = sqlite3_value_text(argv[0]); if( !z || parseDateOrTime(context, (char*)z, p) ){ return 1; } } for(i=1; i<argc; i++){ z = sqlite3_value_text(argv[i]); if( z==0 || parseModifier(context, (char*)z, p) ) return 1; } return 0; } /* ** The following routines implement the various date and time functions |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 | sz = va_arg(ap, int); ppNew = va_arg(ap, void**); pFree = va_arg(ap, void*); if( sz ) *ppNew = sqlite3ScratchMalloc(sz); sqlite3ScratchFree(pFree); break; } } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ return rc; } | > > > > > > > > > > > | 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 | sz = va_arg(ap, int); ppNew = va_arg(ap, void**); pFree = va_arg(ap, void*); if( sz ) *ppNew = sqlite3ScratchMalloc(sz); sqlite3ScratchFree(pFree); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff); ** ** If parameter onoff is non-zero, configure the wrappers so that all ** subsequent calls to localtime() and variants fail. If onoff is zero, ** undo this setting. */ case SQLITE_TESTCTRL_LOCALTIME_FAULT: { sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int); break; } } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ return rc; } |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
5569 5570 5571 5572 5573 5574 5575 | #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_PGHDRSZ 17 #define SQLITE_TESTCTRL_SCRATCHMALLOC 18 | > | | 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 | #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_PGHDRSZ 17 #define SQLITE_TESTCTRL_SCRATCHMALLOC 18 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 19 #define SQLITE_TESTCTRL_LAST 19 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 | int isMutexInit; /* True after mutexes are initialized */ int isMallocInit; /* True after malloc is initialized */ int isPCacheInit; /* True after malloc is initialized */ sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ int nRefInitMutex; /* Number of users of pInitMutex */ void (*xLog)(void*,int,const char*); /* Function for logging */ void *pLogArg; /* First argument to xLog() */ }; /* ** Context pointer passed down through the tree-walk. */ struct Walker { int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ | > | 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 | int isMutexInit; /* True after mutexes are initialized */ int isMallocInit; /* True after malloc is initialized */ int isPCacheInit; /* True after malloc is initialized */ sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ int nRefInitMutex; /* Number of users of pInitMutex */ void (*xLog)(void*,int,const char*); /* Function for logging */ void *pLogArg; /* First argument to xLog() */ int bLocaltimeFault; /* True to fail localtime() calls */ }; /* ** Context pointer passed down through the tree-walk. */ struct Walker { int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 | } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = printExplainQueryPlan(pStmt); Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } #endif /* SQLITE_OMIT_EXPLAIN */ /* ** optimization_control DB OPT BOOLEAN ** ** Enable or disable query optimizations using the sqlite3_test_control() ** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. ** OPT is the name of the optimization to be disabled. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 | } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = printExplainQueryPlan(pStmt); Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } #endif /* SQLITE_OMIT_EXPLAIN */ /* ** sqlite3_test_control VERB ARGS... */ static int test_test_control( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct Verb { const char *zName; int i; } aVerb[] = { { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT }, }; int iVerb; int iFlag; int rc; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "VERB ARGS..."); return TCL_ERROR; } rc = Tcl_GetIndexFromObjStruct( interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb ); if( rc!=TCL_OK ) return rc; iFlag = aVerb[iVerb].i; switch( iFlag ){ case SQLITE_TESTCTRL_LOCALTIME_FAULT: { int val; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "ONOFF"); return TCL_ERROR; } if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val); break; } } Tcl_ResetResult(interp); return TCL_OK; } /* ** optimization_control DB OPT BOOLEAN ** ** Enable or disable query optimizations using the sqlite3_test_control() ** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. ** OPT is the name of the optimization to be disabled. |
︙ | ︙ | |||
5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 | #endif { "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 }, { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 }, { "test_sqlite3_log", test_sqlite3_log, 0 }, #ifndef SQLITE_OMIT_EXPLAIN { "print_explain_query_plan", test_print_eqp, 0 }, #endif }; static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; extern int sqlite3_xferopt_count; | > | 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 | #endif { "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 }, { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 }, { "test_sqlite3_log", test_sqlite3_log, 0 }, #ifndef SQLITE_OMIT_EXPLAIN { "print_explain_query_plan", test_print_eqp, 0 }, #endif { "sqlite3_test_control", test_test_control }, }; static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; extern int sqlite3_xferopt_count; |
︙ | ︙ |
Added test/tkt-bd484a090c.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # 2011 June 21 # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests for SQLite. Specifically, it tests that SQLite # does not crash and an error is returned if localhost() fails. This # is the problem reported by ticket bd484a090c. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-bd484a090c do_test 1.1 { lindex [catchsql { SELECT datetime('now', 'localtime') }] 0 } {0} do_test 1.2 { lindex [catchsql { SELECT datetime('now', 'utc') }] 0 } {0} sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 1 do_test 2.1 { foreach {rc msg} [catchsql { SELECT datetime('now', 'localtime') }] {} set res [string match {error in localtime*()} $msg] list $rc $res } {1 1} do_test 2.2 { foreach {rc msg} [catchsql { SELECT datetime('now', 'utc') }] {} set res [string match {error in localtime*()} $msg] list $rc $res } {1 1} sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0 finish_test |