1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Simplify the date/time function logic for improved rebustness and also to

decrease the size of the binary.

FossilOrigin-Name: 6e144735ed0cd3d4461ae6a4d8034264563e3165
This commit is contained in:
drh
2016-12-02 19:07:03 +00:00
parent 861a56821b
commit 6d4e9c3d92
3 changed files with 85 additions and 64 deletions

View File

@@ -1,5 +1,5 @@
C Extend\sthe\svalid\srange\sof\s'unixepoch'\sdates\sfrom\sJulianDay\s0\sthrough\s9999-12-31. C Simplify\sthe\sdate/time\sfunction\slogic\sfor\simproved\srebustness\sand\salso\sto\ndecrease\sthe\ssize\sof\sthe\sbinary.
D 2016-12-02T17:08:27.447 D 2016-12-02T19:07:03.138
F Makefile.in 7639c6a09da11a9c7c6f2630fc981ee588d1072d F Makefile.in 7639c6a09da11a9c7c6f2630fc981ee588d1072d
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da
@@ -338,7 +338,7 @@ F src/build.c 178f16698cbcb43402c343a9413fe22c99ffee21
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730 F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c a2a52d6e353f459d8ab0f07321f60fafa47d5421 F src/ctime.c a2a52d6e353f459d8ab0f07321f60fafa47d5421
F src/date.c 58d4275a8778c2da80fcb515e2605c791a2b8884 F src/date.c 116097946bffdfe510b30affa15b36026f632ae6
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
F src/delete.c cac97d1117a3008934da3a6a587b3608e65e1495 F src/delete.c cac97d1117a3008934da3a6a587b3608e65e1495
F src/expr.c b22e09630f874c52db0770973b7ce55ee50c1dde F src/expr.c b22e09630f874c52db0770973b7ce55ee50c1dde
@@ -1536,7 +1536,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 0bdb7ae126d3909344640813489ee68ecad041c4 P 768c9859b21a3c88be084d6dd87acab4211b3a87
R de507b0b0d00b8f392dd9c1b935d5409 R 65ce4f7c2b4b3fd05ab801cab333052f
U drh U drh
Z 8b7f9d120e42b1682165e88e877e78a0 Z 0e9aea10c8c8bd36917285b40426a93d

View File

@@ -1 +1 @@
768c9859b21a3c88be084d6dd87acab4211b3a87 6e144735ed0cd3d4461ae6a4d8034264563e3165

View File

@@ -414,10 +414,8 @@ static void computeYMD(DateTime *p){
p->Y = 2000; p->Y = 2000;
p->M = 1; p->M = 1;
p->D = 1; p->D = 1;
}else if( !validJulianDay(p->iJD) ){
datetimeError(p);
return;
}else{ }else{
assert( validJulianDay(p->iJD) );
Z = (int)((p->iJD + 43200000)/86400000); Z = (int)((p->iJD + 43200000)/86400000);
A = (int)((Z - 1867216.25)/36524.25); A = (int)((Z - 1867216.25)/36524.25);
A = Z + 1 + A - (A/4); A = Z + 1 + A - (A/4);
@@ -597,6 +595,29 @@ static sqlite3_int64 localtimeOffset(
} }
#endif /* SQLITE_OMIT_LOCALTIME */ #endif /* SQLITE_OMIT_LOCALTIME */
/*
** The following table defines various date transformations of the form
**
** 'NNN days'
**
** Where NNN is an arbitrary floating-point number and "days" can be one
** of several units of time.
*/
static const struct {
u8 eType; /* Transformation type code */
u8 nName; /* Length of th name */
char *zName; /* Name of the transformation */
double rLimit; /* Maximum NNN value for this transform */
double rXform; /* Constant used for this transform */
} aXformType[] = {
{ 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
{ 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) },
{ 0, 4, "hour", 128963628.0, 86400000.0/24.0 },
{ 0, 3, "day", 5373485.0, 86400000.0 },
{ 1, 5, "month", 176546.0, 30.0*86400000.0 },
{ 2, 4, "year", 14713.0, 365.0*86400000.0 },
};
/* /*
** Process a modifier to a date-time stamp. The modifiers are ** Process a modifier to a date-time stamp. The modifiers are
** as follows: ** as follows:
@@ -621,17 +642,15 @@ static sqlite3_int64 localtimeOffset(
** to context pCtx. If the error is an unrecognized modifier, no error is ** to context pCtx. If the error is an unrecognized modifier, no error is
** written to pCtx. ** written to pCtx.
*/ */
static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ static int parseModifier(
sqlite3_context *pCtx, /* Function context */
const char *z, /* The text of the modifier */
int n, /* Length of zMod in bytes */
DateTime *p /* The date/time value to be modified */
){
int rc = 1; int rc = 1;
int n;
double r; double r;
char *z, zBuf[30]; switch(sqlite3UpperToLower[(u8)z[0]] ){
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 #ifndef SQLITE_OMIT_LOCALTIME
case 'l': { case 'l': {
/* localtime /* localtime
@@ -639,7 +658,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** Assuming the current time value is UTC (a.k.a. GMT), shift it to ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
** show local time. ** show local time.
*/ */
if( strcmp(z, "localtime")==0 ){ if( sqlite3_stricmp(z, "localtime")==0 ){
computeJD(p); computeJD(p);
p->iJD += localtimeOffset(p, pCtx, &rc); p->iJD += localtimeOffset(p, pCtx, &rc);
clearYMD_HMS_TZ(p); clearYMD_HMS_TZ(p);
@@ -654,7 +673,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** Treat the current value of p->s as the number of ** Treat the current value of p->s as the number of
** seconds since 1970. Convert to a real julian day number. ** seconds since 1970. Convert to a real julian day number.
*/ */
if( strcmp(z, "unixepoch")==0 && p->rawS ){ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
double r = p->s*1000.0 + 210866760000000.0; double r = p->s*1000.0 + 210866760000000.0;
if( r>=0.0 && r<464269060800000.0 ){ if( r>=0.0 && r<464269060800000.0 ){
clearYMD_HMS_TZ(p); clearYMD_HMS_TZ(p);
@@ -665,7 +684,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
} }
} }
#ifndef SQLITE_OMIT_LOCALTIME #ifndef SQLITE_OMIT_LOCALTIME
else if( strcmp(z, "utc")==0 ){ else if( sqlite3_stricmp(z, "utc")==0 ){
if( p->tzSet==0 ){ if( p->tzSet==0 ){
sqlite3_int64 c1; sqlite3_int64 c1;
computeJD(p); computeJD(p);
@@ -691,7 +710,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** weekday N where 0==Sunday, 1==Monday, and so forth. If the ** weekday N where 0==Sunday, 1==Monday, and so forth. If the
** date is already on the appropriate weekday, this is a no-op. ** date is already on the appropriate weekday, this is a no-op.
*/ */
if( strncmp(z, "weekday ", 8)==0 if( sqlite3_strnicmp(z, "weekday ", 8)==0
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
&& (n=(int)r)==r && n>=0 && r<7 ){ && (n=(int)r)==r && n>=0 && r<7 ){
sqlite3_int64 Z; sqlite3_int64 Z;
@@ -714,7 +733,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** Move the date backwards to the beginning of the current day, ** Move the date backwards to the beginning of the current day,
** or month or year. ** or month or year.
*/ */
if( strncmp(z, "start of ", 9)!=0 ) break; if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
z += 9; z += 9;
computeYMD(p); computeYMD(p);
p->validHMS = 1; p->validHMS = 1;
@@ -722,15 +741,15 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
p->s = 0.0; p->s = 0.0;
p->validTZ = 0; p->validTZ = 0;
p->validJD = 0; p->validJD = 0;
if( strcmp(z,"month")==0 ){ if( sqlite3_stricmp(z,"month")==0 ){
p->D = 1; p->D = 1;
rc = 0; rc = 0;
}else if( strcmp(z,"year")==0 ){ }else if( sqlite3_stricmp(z,"year")==0 ){
computeYMD(p); computeYMD(p);
p->M = 1; p->M = 1;
p->D = 1; p->D = 1;
rc = 0; rc = 0;
}else if( strcmp(z,"day")==0 ){ }else if( sqlite3_stricmp(z,"day")==0 ){
rc = 0; rc = 0;
} }
break; break;
@@ -748,7 +767,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
case '8': case '8':
case '9': { case '9': {
double rRounder; double rRounder;
double rAbs; int i;
for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
rc = 1; rc = 1;
@@ -777,47 +796,48 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
rc = 0; rc = 0;
break; break;
} }
/* If control reaches this point, it means the transformation is
** one of the forms like "+NNN days". */
z += n; z += n;
while( sqlite3Isspace(*z) ) z++; while( sqlite3Isspace(*z) ) z++;
n = sqlite3Strlen30(z); n = sqlite3Strlen30(z);
if( n>10 || n<3 ) break; if( n>10 || n<3 ) break;
if( z[n-1]=='s' ){ z[n-1] = 0; n--; } if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
computeJD(p); computeJD(p);
rc = 0; rc = 1;
rRounder = r<0 ? -0.5 : +0.5; rRounder = r<0 ? -0.5 : +0.5;
rAbs = r<0 ? -r : r; for(i=0; i<ArraySize(aXformType); i++){
if( n==3 && strcmp(z,"day")==0 && rAbs<5373485.0 ){ if( aXformType[i].nName==n
p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder); && sqlite3_strnicmp(aXformType[i].zName, z, n)==0
}else if( n==4 && strcmp(z,"hour")==0 && rAbs<128963628.0 ){ && r>-aXformType[i].rLimit && r<aXformType[i].rLimit
p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder); ){
}else if( n==6 && strcmp(z,"minute")==0 && rAbs<7737817680.0 ){ switch( aXformType[i].eType ){
p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder); case 1: { /* Special processing to add months */
}else if( n==6 && strcmp(z,"second")==0 && rAbs<464269060800.0 ){ int x;
p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder); computeYMD_HMS(p);
}else if( n==5 && strcmp(z,"month")==0 && rAbs<176546.0 ){ p->M += (int)r;
int x, y; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
computeYMD_HMS(p); p->Y += x;
p->M += (int)r; p->M -= x*12;
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; p->validJD = 0;
p->Y += x; r -= (int)r;
p->M -= x*12; break;
p->validJD = 0; }
computeJD(p); case 2: { /* Special processing to add years */
y = (int)r; int y = (int)r;
if( y!=r ){ computeYMD_HMS(p);
p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder); p->Y += y;
p->validJD = 0;
r -= (int)r;
break;
}
}
computeJD(p);
p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder);
rc = 0;
break;
} }
}else if( n==4 && strcmp(z,"year")==0 && rAbs<14713.0 ){
int y = (int)r;
computeYMD_HMS(p);
p->Y += y;
p->validJD = 0;
computeJD(p);
if( y!=r ){
p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder);
}
}else{
rc = 1;
} }
clearYMD_HMS_TZ(p); clearYMD_HMS_TZ(p);
break; break;
@@ -844,7 +864,7 @@ static int isDate(
sqlite3_value **argv, sqlite3_value **argv,
DateTime *p DateTime *p
){ ){
int i; int i, n;
const unsigned char *z; const unsigned char *z;
int eType; int eType;
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
@@ -862,7 +882,8 @@ static int isDate(
} }
for(i=1; i<argc; i++){ for(i=1; i<argc; i++){
z = sqlite3_value_text(argv[i]); z = sqlite3_value_text(argv[i]);
if( z==0 || parseModifier(context, (char*)z, p) ) return 1; n = sqlite3_value_bytes(argv[i]);
if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1;
} }
computeJD(p); computeJD(p);
if( p->isError || !validJulianDay(p->iJD) ) return 1; if( p->isError || !validJulianDay(p->iJD) ) return 1;