Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Backport the localtime() failure fix of ticket [bd484a090c8077] to the 3.7.6 branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | branch-3.7.6 |
Files: | files | file ages | folders |
SHA1: |
5d4b0c5bfc5be1b16b05d43f943cd8f7 |
User & Date: | drh 2011-06-21 15:15:16.412 |
Context
2011-06-21
| ||
15:58 | Give the osLocaltime() function file scope in date.c. (check-in: 1abce55a1e user: dan tags: branch-3.7.6) | |
15:15 | Backport the localtime() failure fix of ticket [bd484a090c8077] to the 3.7.6 branch. (check-in: 5d4b0c5bfc user: drh tags: branch-3.7.6) | |
2011-05-19
| ||
13:26 | Version 3.7.6.3. (check-in: ed1da510a2 user: drh tags: release, branch-3.7.6, version-3.7.6.3) | |
Changes
Changes to src/date.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 | #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> #include <time.h> #ifndef SQLITE_OMIT_DATETIME_FUNCS | < < < < < < < < < < < < < < < < | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> #include <time.h> #ifndef SQLITE_OMIT_DATETIME_FUNCS /* ** A structure for holding a single date and time. */ typedef struct DateTime DateTime; struct DateTime { sqlite3_int64 iJD; /* The julian day number times 86400000 */ |
︙ | ︙ | |||
406 407 408 409 410 411 412 413 414 415 | ** Clear the YMD and HMS and the TZ */ static void clearYMD_HMS_TZ(DateTime *p){ p->validYMD = 0; p->validHMS = 0; p->validTZ = 0; } #ifndef SQLITE_OMIT_LOCALTIME /* | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | > > > > | > > > > > > < < < | | < | | < < < < < < | | | | | | < < < < < < < < < < < < < < < > | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 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 470 471 472 473 474 475 476 477 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 | ** Clear the YMD and HMS and the TZ */ static void clearYMD_HMS_TZ(DateTime *p){ p->validYMD = 0; p->validHMS = 0; p->validTZ = 0; } /* ** On recent Windows platforms, the localtime_s() function is available ** as part of the "Secure CRT". It is essentially equivalent to ** localtime_r() available under most POSIX platforms, except that the ** order of the parameters is reversed. ** ** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx. ** ** If the user has not indicated to use localtime_r() or localtime_s() ** already, check for an MSVC build environment that provides ** localtime_s(). */ #if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \ defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE) #define HAVE_LOCALTIME_S 1 #endif #ifndef SQLITE_OMIT_LOCALTIME /* ** The following routine implements the rough equivalent of localtime_r() ** using whatever operating-system specific localtime facility that ** is available. This routine returns 0 on success and ** non-zero on any kind of error. ** ** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this ** routine will always fail. */ int osLocaltime(time_t *t, struct tm *pTm){ int rc; #if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \ && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S) struct tm *pX; sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); sqlite3_mutex_enter(mutex); pX = localtime(t); #ifndef SQLITE_OMIT_BUILTIN_TEST if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; #endif if( pX ) *pTm = *pX; sqlite3_mutex_leave(mutex); rc = pX==0; #else #ifndef SQLITE_OMIT_BUILTIN_TEST if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; #endif #if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R rc = localtime_r(t, pTm)==0; #else rc = localtime_s(pTm, t); #endif /* HAVE_LOCALTIME_R */ #endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */ return rc; } #endif /* SQLITE_OMIT_LOCALTIME */ #ifndef SQLITE_OMIT_LOCALTIME /* ** 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; struct tm sLocal; x = *p; computeYMD_HMS(&x); if( x.Y<1971 || x.Y>=2038 ){ x.Y = 2000; x.M = 1; x.D = 1; x.h = 0; x.m = 0; x.s = 0.0; } else { int s = (int)(x.s + 0.5); x.s = s; } x.tz = 0; x.validJD = 0; computeJD(&x); t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); if( osLocaltime(&t, &sLocal) ){ sqlite3_result_error(pCtx, "local time unavailable", -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; 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 ** | | > > > | | < | > | | | < > | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 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 | ** 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++){ | | | < | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | }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.
︙ | ︙ | |||
2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 | 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; } | > > > > > > > > > > > | 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 | 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.
︙ | ︙ | |||
5406 5407 5408 5409 5410 5411 5412 | #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 | > | | 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 | #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.
︙ | ︙ | |||
2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 | 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 */ | > | 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 | 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.
︙ | ︙ | |||
5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 | } 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. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 | } 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. |
︙ | ︙ | |||
5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 | #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; | > | 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 | #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 {local time unavailable} $msg] list $rc $res } {1 1} do_test 2.2 { foreach {rc msg} [catchsql { SELECT datetime('now', 'utc') }] {} set res [string match {local time unavailable} $msg] list $rc $res } {1 1} sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0 finish_test |