diff --git a/embed/sqlite3.wasm b/embed/sqlite3.wasm index 13ac5a3..f62206b 100755 Binary files a/embed/sqlite3.wasm and b/embed/sqlite3.wasm differ diff --git a/sqlite3/date.patch b/sqlite3/date.patch new file mode 100644 index 0000000..7ed3c1b --- /dev/null +++ b/sqlite3/date.patch @@ -0,0 +1,556 @@ +# Backport from 3.46. +# https://sqlite.org/draft/releaselog/current.html +--- sqlite3.c.orig ++++ sqlite3.c +@@ -71,13 +71,14 @@ struct DateTime { + int tz; /* Timezone offset in minutes */ + double s; /* Seconds */ + char validJD; /* True (1) if iJD is valid */ +- char rawS; /* Raw numeric value stored in s */ + char validYMD; /* True (1) if Y,M,D are valid */ + char validHMS; /* True (1) if h,m,s are valid */ +- char validTZ; /* True (1) if tz is valid */ +- char tzSet; /* Timezone was set explicitly */ +- char isError; /* An overflow has occurred */ +- char useSubsec; /* Display subsecond precision */ ++ char nFloor; /* Days to implement "floor" */ ++ unsigned rawS : 1; /* Raw numeric value stored in s */ ++ unsigned isError : 1; /* An overflow has occurred */ ++ unsigned useSubsec : 1; /* Display subsecond precision */ ++ unsigned isUtc : 1; /* Time is known to be UTC */ ++ unsigned isLocal : 1; /* Time is known to be localtime */ + }; + + +@@ -175,6 +176,8 @@ static int parseTimezone(const char *zDate, DateTime *p){ + sgn = +1; + }else if( c=='Z' || c=='z' ){ + zDate++; ++ p->isLocal = 0; ++ p->isUtc = 1; + goto zulu_time; + }else{ + return c!=0; +@@ -187,7 +190,6 @@ static int parseTimezone(const char *zDate, DateTime *p){ + p->tz = sgn*(nMn + nHr*60); + zulu_time: + while( sqlite3Isspace(*zDate) ){ zDate++; } +- p->tzSet = 1; + return *zDate!=0; + } + +@@ -231,7 +233,6 @@ static int parseHhMmSs(const char *zDate, DateTime *p){ + p->m = m; + p->s = s + ms; + if( parseTimezone(zDate, p) ) return 1; +- p->validTZ = (p->tz!=0)?1:0; + return 0; + } + +@@ -278,15 +279,40 @@ static void computeJD(DateTime *p){ + p->validJD = 1; + if( p->validHMS ){ + p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5); +- if( p->validTZ ){ ++ if( p->tz ){ + p->iJD -= p->tz*60000; + p->validYMD = 0; + p->validHMS = 0; +- p->validTZ = 0; ++ p->tz = 0; ++ p->isUtc = 1; ++ p->isLocal = 0; + } + } + } + ++/* ++** Given the YYYY-MM-DD information current in p, determine if there ++** is day-of-month overflow and set nFloor to the number of days that ++** would need to be subtracted from the date in order to bring the ++** date back to the end of the month. ++*/ ++static void computeFloor(DateTime *p){ ++ assert( p->validYMD || p->isError ); ++ assert( p->D>=0 && p->D<=31 ); ++ assert( p->M>=0 && p->M<=12 ); ++ if( p->D<=28 ){ ++ p->nFloor = 0; ++ }else if( (1<M) & 0x15aa ){ ++ p->nFloor = 0; ++ }else if( p->M!=2 ){ ++ p->nFloor = (p->D==31); ++ }else if( p->Y%4!=0 || (p->Y%100==0 && p->Y%400!=0) ){ ++ p->nFloor = p->D - 28; ++ }else{ ++ p->nFloor = p->D - 29; ++ } ++} ++ + /* + ** Parse dates of the form + ** +@@ -325,12 +351,16 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){ + p->Y = neg ? -Y : Y; + p->M = M; + p->D = D; +- if( p->validTZ ){ ++ computeFloor(p); ++ if( p->tz ){ + computeJD(p); + } + return 0; + } + ++ ++static void clearYMD_HMS_TZ(DateTime *p); /* Forward declaration */ ++ + /* + ** Set the time to the current time reported by the VFS. + ** +@@ -340,6 +370,9 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ + p->iJD = sqlite3StmtCurrentTime(context); + if( p->iJD>0 ){ + p->validJD = 1; ++ p->isUtc = 1; ++ p->isLocal = 0; ++ clearYMD_HMS_TZ(p); + return 0; + }else{ + return 1; +@@ -478,7 +511,7 @@ static void computeYMD_HMS(DateTime *p){ + static void clearYMD_HMS_TZ(DateTime *p){ + p->validYMD = 0; + p->validHMS = 0; +- p->validTZ = 0; ++ p->tz = 0; + } + + #ifndef SQLITE_OMIT_LOCALTIME +@@ -610,7 +643,7 @@ static int toLocaltime( + p->validHMS = 1; + p->validJD = 0; + p->rawS = 0; +- p->validTZ = 0; ++ p->tz = 0; + p->isError = 0; + return SQLITE_OK; + } +@@ -630,12 +663,12 @@ static const struct { + float rLimit; /* Maximum NNN value for this transform */ + float rXform; /* Constant used for this transform */ + } aXformType[] = { +- { 6, "second", 4.6427e+14, 1.0 }, +- { 6, "minute", 7.7379e+12, 60.0 }, +- { 4, "hour", 1.2897e+11, 3600.0 }, +- { 3, "day", 5373485.0, 86400.0 }, +- { 5, "month", 176546.0, 2592000.0 }, +- { 4, "year", 14713.0, 31536000.0 }, ++ /* 0 */ { 6, "second", 4.6427e+14, 1.0 }, ++ /* 1 */ { 6, "minute", 7.7379e+12, 60.0 }, ++ /* 2 */ { 4, "hour", 1.2897e+11, 3600.0 }, ++ /* 3 */ { 3, "day", 5373485.0, 86400.0 }, ++ /* 4 */ { 5, "month", 176546.0, 30.0*86400.0 }, ++ /* 5 */ { 4, "year", 14713.0, 365.0*86400.0 }, + }; + + /* +@@ -667,14 +700,20 @@ static void autoAdjustDate(DateTime *p){ + ** NNN.NNNN seconds + ** NNN months + ** NNN years ++** +/-YYYY-MM-DD HH:MM:SS.SSS ++** ceiling ++** floor + ** start of month + ** start of year + ** start of week + ** start of day + ** weekday N + ** unixepoch ++** auto + ** localtime + ** utc ++** subsec ++** subsecond + ** + ** 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 +@@ -705,6 +744,37 @@ static int parseModifier( + } + break; + } ++ case 'c': { ++ /* ++ ** ceiling ++ ** ++ ** Resolve day-of-month overflow by rolling forward into the next ++ ** month. As this is the default action, this modifier is really ++ ** a no-op that is only included for symmetry. See "floor". ++ */ ++ if( sqlite3_stricmp(z, "ceiling")==0 ){ ++ computeJD(p); ++ clearYMD_HMS_TZ(p); ++ rc = 0; ++ p->nFloor = 0; ++ } ++ break; ++ } ++ case 'f': { ++ /* ++ ** floor ++ ** ++ ** Resolve day-of-month overflow by rolling back to the end of the ++ ** previous month. ++ */ ++ if( sqlite3_stricmp(z, "floor")==0 ){ ++ computeJD(p); ++ p->iJD -= p->nFloor*86400000; ++ clearYMD_HMS_TZ(p); ++ rc = 0; ++ } ++ break; ++ } + case 'j': { + /* + ** julianday +@@ -731,7 +801,9 @@ static int parseModifier( + ** show local time. + */ + if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ +- rc = toLocaltime(p, pCtx); ++ rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx); ++ p->isUtc = 0; ++ p->isLocal = 1; + } + break; + } +@@ -756,7 +828,7 @@ static int parseModifier( + } + #ifndef SQLITE_OMIT_LOCALTIME + else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ +- if( p->tzSet==0 ){ ++ if( p->isUtc==0 ){ + i64 iOrigJD; /* Original localtime */ + i64 iGuess; /* Guess at the corresponding utc time */ + int cnt = 0; /* Safety to prevent infinite loop */ +@@ -779,7 +851,8 @@ static int parseModifier( + memset(p, 0, sizeof(*p)); + p->iJD = iGuess; + p->validJD = 1; +- p->tzSet = 1; ++ p->isUtc = 1; ++ p->isLocal = 0; + } + rc = SQLITE_OK; + } +@@ -799,7 +872,7 @@ static int parseModifier( + && r>=0.0 && r<7.0 && (n=(int)r)==r ){ + sqlite3_int64 Z; + computeYMD_HMS(p); +- p->validTZ = 0; ++ p->tz = 0; + p->validJD = 0; + computeJD(p); + Z = ((p->iJD + 129600000)/86400000) % 7; +@@ -839,7 +912,7 @@ static int parseModifier( + p->h = p->m = 0; + p->s = 0.0; + p->rawS = 0; +- p->validTZ = 0; ++ p->tz = 0; + p->validJD = 0; + if( sqlite3_stricmp(z,"month")==0 ){ + p->D = 1; +@@ -910,6 +983,7 @@ static int parseModifier( + x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; + p->Y += x; + p->M -= x*12; ++ computeFloor(p); + computeJD(p); + p->validHMS = 0; + p->validYMD = 0; +@@ -956,11 +1030,12 @@ static int parseModifier( + z += n; + while( sqlite3Isspace(*z) ) z++; + n = sqlite3Strlen30(z); +- if( n>10 || n<3 ) break; ++ if( n<3 || n>10 ) break; + if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--; + computeJD(p); + assert( rc==1 ); + rRounder = r<0 ? -0.5 : +0.5; ++ p->nFloor = 0; + for(i=0; iM += (int)r; + x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; + p->Y += x; + p->M -= x*12; ++ computeFloor(p); + p->validJD = 0; + r -= (int)r; + break; + } + case 5: { /* Special processing to add years */ + int y = (int)r; +- assert( strcmp(aXformType[i].zName,"year")==0 ); ++ assert( strcmp(aXformType[5].zName,"year")==0 ); + computeYMD_HMS(p); ++ assert( p->M>=0 && p->M<=12 ); + p->Y += y; ++ computeFloor(p); + p->validJD = 0; + r -= (int)r; + break; +@@ -1236,22 +1314,83 @@ static void dateFunc( + } + } + ++/* ++** Compute the number of days after the most recent January 1. ++** ++** In other words, compute the zero-based day number for the ++** current year: ++** ++** Jan01 = 0, Jan02 = 1, ..., Jan31 = 30, Feb01 = 31, ... ++** Dec31 = 364 or 365. ++*/ ++static int daysAfterJan01(DateTime *pDate){ ++ DateTime jan01 = *pDate; ++ assert( jan01.validYMD ); ++ assert( jan01.validHMS ); ++ assert( pDate->validJD ); ++ jan01.validJD = 0; ++ jan01.M = 1; ++ jan01.D = 1; ++ computeJD(&jan01); ++ return (int)((pDate->iJD-jan01.iJD+43200000)/86400000); ++} ++ ++/* ++** Return the number of days after the most recent Monday. ++** ++** In other words, return the day of the week according ++** to this code: ++** ++** 0=Monday, 1=Tuesday, 2=Wednesday, ..., 6=Sunday. ++*/ ++static int daysAfterMonday(DateTime *pDate){ ++ assert( pDate->validJD ); ++ return (int)((pDate->iJD+43200000)/86400000) % 7; ++} ++ ++/* ++** Return the number of days after the most recent Sunday. ++** ++** In other words, return the day of the week according ++** to this code: ++** ++** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday ++*/ ++static int daysAfterSunday(DateTime *pDate){ ++ assert( pDate->validJD ); ++ return (int)((pDate->iJD+129600000)/86400000) % 7; ++} ++ + /* + ** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) + ** + ** Return a string described by FORMAT. Conversions as follows: + ** +-** %d day of month ++** %d day of month 01-31 ++** %e day of month 1-31 + ** %f ** fractional seconds SS.SSS ++** %F ISO date. YYYY-MM-DD ++** %G ISO year corresponding to %V 0000-9999. ++** %g 2-digit ISO year corresponding to %V 00-99 + ** %H hour 00-24 +-** %j day of year 000-366 ++** %k hour 0-24 (leading zero converted to space) ++** %I hour 01-12 ++** %j day of year 001-366 + ** %J ** julian day number ++** %l hour 1-12 (leading zero converted to space) + ** %m month 01-12 + ** %M minute 00-59 ++** %p "am" or "pm" ++** %P "AM" or "PM" ++** %R time as HH:MM + ** %s seconds since 1970-01-01 + ** %S seconds 00-59 +-** %w day of week 0-6 Sunday==0 +-** %W week of year 00-53 ++** %T time as HH:MM:SS ++** %u day of week 1-7 Monday==1, Sunday==7 ++** %w day of week 0-6 Sunday==0, Monday==1 ++** %U week of year 00-53 (First Sunday is start of week 01) ++** %V week of year 01-53 (First week containing Thursday is week 01) ++** %W week of year 00-53 (First Monday is start of week 01) + ** %Y year 0000-9999 + ** %% % + */ +@@ -1288,7 +1427,7 @@ static void strftimeFunc( + sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D); + break; + } +- case 'f': { ++ case 'f': { /* Fractional seconds. (Non-standard) */ + double s = x.s; + if( s>59.999 ) s = 59.999; + sqlite3_str_appendf(&sRes, "%06.3f", s); +@@ -1298,6 +1437,21 @@ static void strftimeFunc( + sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D); + break; + } ++ case 'G': /* Fall thru */ ++ case 'g': { ++ DateTime y = x; ++ assert( y.validJD ); ++ /* Move y so that it is the Thursday in the same week as x */ ++ y.iJD += (3 - daysAfterMonday(&x))*86400000; ++ y.validYMD = 0; ++ computeYMD(&y); ++ if( cf=='g' ){ ++ sqlite3_str_appendf(&sRes, "%02d", y.Y%100); ++ }else{ ++ sqlite3_str_appendf(&sRes, "%04d", y.Y); ++ } ++ break; ++ } + case 'H': + case 'k': { + sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h); +@@ -1311,25 +1465,11 @@ static void strftimeFunc( + sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h); + break; + } +- case 'W': /* Fall thru */ +- case 'j': { +- int nDay; /* Number of days since 1st day of year */ +- DateTime y = x; +- y.validJD = 0; +- y.M = 1; +- y.D = 1; +- computeJD(&y); +- nDay = (int)((x.iJD-y.iJD+43200000)/86400000); +- if( cf=='W' ){ +- int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ +- wd = (int)(((x.iJD+43200000)/86400000)%7); +- sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); +- }else{ +- sqlite3_str_appendf(&sRes,"%03d",nDay+1); +- } ++ case 'j': { /* Day of year. Jan01==1, Jan02==2, and so forth */ ++ sqlite3_str_appendf(&sRes,"%03d",daysAfterJan01(&x)+1); + break; + } +- case 'J': { ++ case 'J': { /* Julian day number. (Non-standard) */ + sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); + break; + } +@@ -1372,13 +1512,33 @@ static void strftimeFunc( + sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s); + break; + } +- case 'u': /* Fall thru */ +- case 'w': { +- char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; ++ case 'u': /* Day of week. 1 to 7. Monday==1, Sunday==7 */ ++ case 'w': { /* Day of week. 0 to 6. Sunday==0, Monday==1 */ ++ char c = (char)daysAfterSunday(&x) + '0'; + if( c=='0' && cf=='u' ) c = '7'; + sqlite3_str_appendchar(&sRes, 1, c); + break; + } ++ case 'U': { /* Week num. 00-53. First Sun of the year is week 01 */ ++ sqlite3_str_appendf(&sRes,"%02d", ++ (daysAfterJan01(&x)-daysAfterSunday(&x)+7)/7); ++ break; ++ } ++ case 'V': { /* Week num. 01-53. First week with a Thur is week 01 */ ++ DateTime y = x; ++ /* Adjust y so that is the Thursday in the same week as x */ ++ assert( y.validJD ); ++ y.iJD += (3 - daysAfterMonday(&x))*86400000; ++ y.validYMD = 0; ++ computeYMD(&y); ++ sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1); ++ break; ++ } ++ case 'W': { /* Week num. 00-53. First Mon of the year is week 01 */ ++ sqlite3_str_appendf(&sRes,"%02d", ++ (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7); ++ break; ++ } + case 'Y': { + sqlite3_str_appendf(&sRes,"%04d",x.Y); + break; +@@ -1525,9 +1685,7 @@ static void timediffFunc( + d1.iJD = d2.iJD - d1.iJD; + d1.iJD += (u64)1486995408 * (u64)100000; + } +- d1.validYMD = 0; +- d1.validHMS = 0; +- d1.validTZ = 0; ++ clearYMD_HMS_TZ(&d1); + computeYMD_HMS(&d1); + sqlite3StrAccumInit(&sRes, 0, 0, 0, 100); + sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f", +@@ -1596,6 +1754,36 @@ static void currentTimeFunc( + } + #endif + ++#if !defined(SQLITE_OMIT_DATETIME_FUNCS) && defined(SQLITE_DEBUG) ++/* ++** datedebug(...) ++** ++** This routine returns JSON that describes the internal DateTime object. ++** Used for debugging and testing only. Subject to change. ++*/ ++static void datedebugFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ DateTime x; ++ if( isDate(context, argc, argv, &x)==0 ){ ++ char *zJson; ++ zJson = sqlite3_mprintf( ++ "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d," ++ "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d," ++ "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d," ++ "isUtc:%d,isLocal:%d}", ++ x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz, ++ x.s, x.validJD, x.validYMD, x.validHMS, ++ x.nFloor, x.rawS, x.isError, x.useSubsec, ++ x.isUtc, x.isLocal); ++ sqlite3_result_text(context, zJson, -1, sqlite3_free); ++ } ++} ++#endif /* !SQLITE_OMIT_DATETIME_FUNCS && SQLITE_DEBUG */ ++ ++ + /* + ** This function registered all of the above C functions as SQL + ** functions. This should be the only routine in this file with +@@ -1611,6 +1799,9 @@ void sqlite3RegisterDateTimeFunctions(void){ + PURE_DATE(datetime, -1, 0, 0, datetimeFunc ), + PURE_DATE(strftime, -1, 0, 0, strftimeFunc ), + PURE_DATE(timediff, 2, 0, 0, timediffFunc ), ++#ifdef SQLITE_DEBUG ++ PURE_DATE(datedebug, -1, 0, 0, datedebugFunc ), ++#endif + DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), + DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), + DFUNCTION(current_date, 0, 0, 0, cdateFunc ), diff --git a/sqlite3/include.h b/sqlite3/include.h index a5e3eed..1471752 100644 --- a/sqlite3/include.h +++ b/sqlite3/include.h @@ -5,7 +5,7 @@ // https://github.com/JuliaLang/julia/blob/v1.9.4/src/julia.h#L67-L68 #define container_of(ptr, type, member) \ - ((type *)((char *)(ptr)-offsetof(type, member))) + ((type *)((char *)(ptr) - offsetof(type, member))) typedef void *go_handle; void go_destroy(go_handle); diff --git a/sqlite3/isoweek.patch b/sqlite3/isoweek.patch deleted file mode 100644 index 3b80d48..0000000 --- a/sqlite3/isoweek.patch +++ /dev/null @@ -1,185 +0,0 @@ -# ISO week date specifiers, backport from 3.46. ---- sqlite3.c.orig -+++ sqlite3.c -@@ -25340,21 +25340,82 @@ - } - - /* -+** Compute the number of days after the most recent January 1. -+** -+** In other words, compute the zero-based day number for the -+** current year: -+** -+** Jan01 = 0, Jan02 = 1, ..., Jan31 = 30, Feb01 = 31, ... -+** Dec31 = 364 or 365. -+*/ -+static int daysAfterJan01(DateTime *pDate){ -+ DateTime jan01 = *pDate; -+ assert( jan01.validYMD ); -+ assert( jan01.validHMS ); -+ assert( pDate->validJD ); -+ jan01.validJD = 0; -+ jan01.M = 1; -+ jan01.D = 1; -+ computeJD(&jan01); -+ return (int)((pDate->iJD-jan01.iJD+43200000)/86400000); -+} -+ -+/* -+** Return the number of days after the most recent Monday. -+** -+** In other words, return the day of the week according -+** to this code: -+** -+** 0=Monday, 1=Tuesday, 2=Wednesday, ..., 6=Sunday. -+*/ -+static int daysAfterMonday(DateTime *pDate){ -+ assert( pDate->validJD ); -+ return (int)((pDate->iJD+43200000)/86400000) % 7; -+} -+ -+/* -+** Return the number of days after the most recent Sunday. -+** -+** In other words, return the day of the week according -+** to this code: -+** -+** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday -+*/ -+static int daysAfterSunday(DateTime *pDate){ -+ assert( pDate->validJD ); -+ return (int)((pDate->iJD+129600000)/86400000) % 7; -+} -+ -+/* - ** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) - ** - ** Return a string described by FORMAT. Conversions as follows: - ** --** %d day of month -+** %d day of month 01-31 -+** %e day of month 1-31 - ** %f ** fractional seconds SS.SSS -+** %F ISO date. YYYY-MM-DD -+** %G ISO year corresponding to %V 0000-9999. -+** %g 2-digit ISO year corresponding to %V 00-99 - ** %H hour 00-24 --** %j day of year 000-366 -+** %k hour 0-24 (leading zero converted to space) -+** %I hour 01-12 -+** %j day of year 001-366 - ** %J ** julian day number -+** %l hour 1-12 (leading zero converted to space) - ** %m month 01-12 - ** %M minute 00-59 -+** %p "am" or "pm" -+** %P "AM" or "PM" -+** %R time as HH:MM - ** %s seconds since 1970-01-01 - ** %S seconds 00-59 --** %w day of week 0-6 Sunday==0 --** %W week of year 00-53 -+** %T time as HH:MM:SS -+** %u day of week 1-7 Monday==1, Sunday==7 -+** %w day of week 0-6 Sunday==0, Monday==1 -+** %U week of year 00-53 (First Sunday is start of week 01) -+** %V week of year 01-53 (First week containing Thursday is week 01) -+** %W week of year 00-53 (First Monday is start of week 01) - ** %Y year 0000-9999 - ** %% % - */ -@@ -25391,7 +25452,7 @@ - sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D); - break; - } -- case 'f': { -+ case 'f': { /* Fractional seconds. (Non-standard) */ - double s = x.s; - if( s>59.999 ) s = 59.999; - sqlite3_str_appendf(&sRes, "%06.3f", s); -@@ -25401,6 +25462,21 @@ - sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D); - break; - } -+ case 'G': /* Fall thru */ -+ case 'g': { -+ DateTime y = x; -+ assert( y.validJD ); -+ /* Move y so that it is the Thursday in the same week as x */ -+ y.iJD += (3 - daysAfterMonday(&x))*86400000; -+ y.validYMD = 0; -+ computeYMD(&y); -+ if( cf=='g' ){ -+ sqlite3_str_appendf(&sRes, "%02d", y.Y%100); -+ }else{ -+ sqlite3_str_appendf(&sRes, "%04d", y.Y); -+ } -+ break; -+ } - case 'H': - case 'k': { - sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h); -@@ -25414,25 +25490,11 @@ - sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h); - break; - } -- case 'W': /* Fall thru */ -- case 'j': { -- int nDay; /* Number of days since 1st day of year */ -- DateTime y = x; -- y.validJD = 0; -- y.M = 1; -- y.D = 1; -- computeJD(&y); -- nDay = (int)((x.iJD-y.iJD+43200000)/86400000); -- if( cf=='W' ){ -- int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ -- wd = (int)(((x.iJD+43200000)/86400000)%7); -- sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); -- }else{ -- sqlite3_str_appendf(&sRes,"%03d",nDay+1); -- } -+ case 'j': { /* Day of year. Jan01==1, Jan02==2, and so forth */ -+ sqlite3_str_appendf(&sRes,"%03d",daysAfterJan01(&x)+1); - break; - } -- case 'J': { -+ case 'J': { /* Julian day number. (Non-standard) */ - sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); - break; - } -@@ -25475,11 +25537,31 @@ - sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s); - break; - } -- case 'u': /* Fall thru */ -- case 'w': { -- char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; -+ case 'u': /* Day of week. 1 to 7. Monday==1, Sunday==7 */ -+ case 'w': { /* Day of week. 0 to 6. Sunday==0, Monday==1 */ -+ char c = (char)daysAfterSunday(&x) + '0'; - if( c=='0' && cf=='u' ) c = '7'; - sqlite3_str_appendchar(&sRes, 1, c); -+ break; -+ } -+ case 'U': { /* Week num. 00-53. First Sun of the year is week 01 */ -+ sqlite3_str_appendf(&sRes,"%02d", -+ (daysAfterJan01(&x)-daysAfterSunday(&x)+7)/7); -+ break; -+ } -+ case 'V': { /* Week num. 01-53. First week with a Thur is week 01 */ -+ DateTime y = x; -+ /* Adjust y so that is the Thursday in the same week as x */ -+ assert( y.validJD ); -+ y.iJD += (3 - daysAfterMonday(&x))*86400000; -+ y.validYMD = 0; -+ computeYMD(&y); -+ sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1); -+ break; -+ } -+ case 'W': { /* Week num. 00-53. First Mon of the year is week 01 */ -+ sqlite3_str_appendf(&sRes,"%02d", -+ (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7); - break; - } - case 'Y': { diff --git a/sqlite3/time.c b/sqlite3/time.c index 35af30f..7b3619a 100644 --- a/sqlite3/time.c +++ b/sqlite3/time.c @@ -27,63 +27,10 @@ static int time_collation(void *pArg, int nKey1, const void *pKey1, int nKey2, return rc; } -static void json_time_func(sqlite3_context *context, int argc, - sqlite3_value **argv) { - DateTime x; - if (isDate(context, argc, argv, &x)) return; - if (x.tzSet && x.tz) { - x.iJD += x.tz * 60000; - if (!validJulianDay(x.iJD)) return; - x.validYMD = 0; - x.validHMS = 0; - } - computeYMD_HMS(&x); - - sqlite3 *db = sqlite3_context_db_handle(context); - sqlite3_str *res = sqlite3_str_new(db); - - sqlite3_str_appendf(res, "%04d-%02d-%02dT%02d:%02d:%02d", // - x.Y, x.M, x.D, // - x.h, x.m, (int)(x.iJD / 1000 % 60)); - - if (x.useSubsec) { - int rem = x.iJD % 1000; - if (rem) { - sqlite3_str_appendchar(res, 1, '.'); - sqlite3_str_appendchar(res, 1, '0' + rem / 100); - if ((rem %= 100)) { - sqlite3_str_appendchar(res, 1, '0' + rem / 10); - if ((rem %= 10)) { - sqlite3_str_appendchar(res, 1, '0' + rem); - } - } - } - } - - if (x.tz) { - sqlite3_str_appendf(res, "%+03d:%02d", x.tz / 60, abs(x.tz) % 60); - } else { - sqlite3_str_appendchar(res, 1, 'Z'); - } - - int rc = sqlite3_str_errcode(res); - if (rc) { - sqlite3_result_error_code(context, rc); - return; - } - - int n = sqlite3_str_length(res); - sqlite3_result_text(context, sqlite3_str_finish(res), n, sqlite3_free); -} - int sqlite3_time_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { sqlite3_create_collation_v2(db, "time", SQLITE_UTF8, /*arg=*/NULL, time_collation, /*destroy=*/NULL); - sqlite3_create_function_v2( - db, "json_time", /*nArg=*/-1, - SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, /*arg=*/NULL, - json_time_func, /*step=*/NULL, /*final=*/NULL, /*destroy=*/NULL); return SQLITE_OK; } \ No newline at end of file diff --git a/sqlite3/timezone.patch b/sqlite3/timezone.patch deleted file mode 100644 index 9063c90..0000000 --- a/sqlite3/timezone.patch +++ /dev/null @@ -1,45 +0,0 @@ -# Set UTC timezone, compute local offset. ---- sqlite3.c.orig -+++ sqlite3.c -@@ -340,6 +340,7 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ - p->iJD = sqlite3StmtCurrentTime(context); - if( p->iJD>0 ){ - p->validJD = 1; -+ p->tzSet = 1; - return 0; - }else{ - return 1; -@@ -355,6 +356,7 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ - static void setRawDateNumber(DateTime *p, double r){ - p->s = r; - p->rawS = 1; -+ p->tzSet = 1; - if( r>=0.0 && r<5373484.5 ){ - p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); - p->validJD = 1; -@@ -731,7 +733,16 @@ static int parseModifier( - ** show local time. - */ - if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ -- rc = toLocaltime(p, pCtx); -+ if( p->tzSet!=0 || p->tz==0 ) { -+ rc = toLocaltime(p, pCtx); -+ i64 iOrigJD = p->iJD; -+ p->tzSet = 0; -+ computeJD(p); -+ p->tz = (p->iJD-iOrigJD)/60000; -+ if( abs(p->tz)>= 900 ) p->tz = 0; -+ } else { -+ rc = 0; -+ } - } - break; - } -@@ -781,6 +792,7 @@ static int parseModifier( - p->validJD = 1; - p->tzSet = 1; - } -+ p->tz = 0; - rc = SQLITE_OK; - } - #endif