/ Check-in [76ae8257]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:76ae8257efc1df6e20ce5718d4824adbbde423ec
User & Date: dan 2011-06-21 12:47:30
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: 97e86ec6 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: 76ae8257 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: dcb46d3f user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/date.c.

408
409
410
411
412
413
414

415


































416
417
418




419
420




421
422
423
424
425
426
427
...
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
...
497
498
499
500
501
502
503
504



505
506
507
508
509
510
511
512
513
...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
...
542
543
544
545
546
547
548
549

550
551
552
553

554
555
556
557
558
559
560
...
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
static void clearYMD_HMS_TZ(DateTime *p){
  p->validYMD = 0;
  p->validHMS = 0;
  p->validTZ = 0;
}

#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.




*/
static sqlite3_int64 localtimeOffset(DateTime *p){




  DateTime x, y;
  time_t t;
  x = *p;
  computeYMD_HMS(&x);
  if( x.Y<1971 || x.Y>=2038 ){
    x.Y = 2000;
    x.M = 1;
................................................................................
  x.tz = 0;
  x.validJD = 0;
  computeJD(&x);
  t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
#ifdef HAVE_LOCALTIME_R
  {
    struct tm sLocal;
    localtime_r(&t, &sLocal);




    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;
    localtime_s(&sLocal, &t);




    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 = localtime(&t);

    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));





  }
#endif
  y.validYMD = 1;
  y.validHMS = 1;
  y.validJD = 0;
  y.validTZ = 0;
  computeJD(&y);

  return y.iJD - x.iJD;
}
#endif /* SQLITE_OMIT_LOCALTIME */

/*
** Process a modifier to a date-time stamp.  The modifiers are
** as follows:
................................................................................
**     start of week
**     start of day
**     weekday N
**     unixepoch
**     localtime
**     utc
**
** Return 0 on success and 1 if there is any kind of error.



*/
static int parseModifier(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]];
................................................................................
      /*    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);
        clearYMD_HMS_TZ(p);
        rc = 0;
      }
      break;
    }
#endif
    case 'u': {
      /*
      **    unixepoch
................................................................................
        clearYMD_HMS_TZ(p);
        rc = 0;
      }
#ifndef SQLITE_OMIT_LOCALTIME
      else if( strcmp(z, "utc")==0 ){
        sqlite3_int64 c1;
        computeJD(p);
        c1 = localtimeOffset(p);

        p->iJD -= c1;
        clearYMD_HMS_TZ(p);
        p->iJD += c1 - localtimeOffset(p);
        rc = 0;

      }
#endif
      break;
    }
    case 'w': {
      /*
      **    weekday N
................................................................................
  }else{
    z = sqlite3_value_text(argv[0]);
    if( !z || parseDateOrTime(context, (char*)z, p) ){
      return 1;
    }
  }
  for(i=1; i<argc; i++){
    if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){
      return 1;
    }
  }
  return 0;
}


/*
** The following routines implement the various date and time functions







>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
|
>
>
>
>

|
>
>
>
>







 







|
>
>
>
>










|
>
>
>
>











|
>
|
|
|
|
|
|
>

>
>
>
>
>







>







 







|
>
>
>

|







 







|

<







 







|
>
|
|
|
<
>







 







|
|
<







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
...
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
...
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
...
580
581
582
583
584
585
586
587
588

589
590
591
592
593
594
595
...
602
603
604
605
606
607
608
609
610
611
612
613

614
615
616
617
618
619
620
621
...
788
789
790
791
792
793
794
795
796

797
798
799
800
801
802
803
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;
................................................................................
  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:
................................................................................
**     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]];
................................................................................
      /*    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
................................................................................
        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
................................................................................
  }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

5576
5577
5578
5579
5580
5581
5582
5583
#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_LAST                    18

/*
** 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







>
|







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
....
5781
5782
5783
5784
5785
5786
5787

5788
5789
5790
5791
5792
5793
5794
  }
  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.
................................................................................
#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;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







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
....
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
  }
  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.
................................................................................
#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