Index: src/date.c ================================================================== --- src/date.c +++ src/date.c @@ -410,16 +410,58 @@ 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. +** 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){ +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 ){ @@ -438,11 +480,15 @@ computeJD(&x); t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); #ifdef HAVE_LOCALTIME_R { struct tm sLocal; - localtime_r(&t, &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; @@ -449,11 +495,15 @@ y.s = sLocal.tm_sec; } #elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S { struct tm sLocal; - localtime_s(&sLocal, &t); + 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; @@ -461,25 +511,33 @@ } #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; + 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 */ /* @@ -499,13 +557,16 @@ ** weekday N ** unixepoch ** localtime ** utc ** -** Return 0 on success and 1 if there is any kind of error. +** 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(const char *zMod, DateTime *p){ +static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ int rc = 1; int n; double r; char *z, zBuf[30]; z = zBuf; @@ -521,13 +582,12 @@ ** 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); + p->iJD += localtimeOffset(p, pCtx, &rc); clearYMD_HMS_TZ(p); - rc = 0; } break; } #endif case 'u': { @@ -544,15 +604,16 @@ } #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; + 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': { @@ -729,13 +790,12 @@ if( !z || parseDateOrTime(context, (char*)z, p) ){ return 1; } } for(i=1; i