diff --git a/embed/README.md b/embed/README.md index 87281a8..400fe87 100644 --- a/embed/README.md +++ b/embed/README.md @@ -1,6 +1,6 @@ # Embeddable Wasm build of SQLite -This folder includes an embeddable Wasm build of SQLite 3.45.3 for use with +This folder includes an embeddable Wasm build of SQLite 3.46.0 for use with [`github.com/ncruces/go-sqlite3`](https://pkg.go.dev/github.com/ncruces/go-sqlite3). The following optional features are compiled in: @@ -10,6 +10,7 @@ The following optional features are compiled in: - [R*Tree](https://sqlite.org/rtree.html) - [GeoPoly](https://sqlite.org/geopoly.html) - [soundex](https://sqlite.org/lang_corefunc.html#soundex) +- [stat4](https://sqlite.org/compile.html#enable_stat4) - [base64](https://github.com/sqlite/sqlite/blob/master/ext/misc/base64.c) - [decimal](https://github.com/sqlite/sqlite/blob/master/ext/misc/decimal.c) - [ieee754](https://github.com/sqlite/sqlite/blob/master/ext/misc/ieee754.c) diff --git a/embed/exports.txt b/embed/exports.txt index da16316..b3cb158 100644 --- a/embed/exports.txt +++ b/embed/exports.txt @@ -36,10 +36,13 @@ sqlite3_collation_needed_go sqlite3_column_blob sqlite3_column_bytes sqlite3_column_count +sqlite3_column_database_name sqlite3_column_decltype sqlite3_column_double sqlite3_column_int64 sqlite3_column_name +sqlite3_column_origin_name +sqlite3_column_table_name sqlite3_column_text sqlite3_column_type sqlite3_column_value diff --git a/embed/sqlite3.wasm b/embed/sqlite3.wasm index 519eb61..2689f77 100755 Binary files a/embed/sqlite3.wasm and b/embed/sqlite3.wasm differ diff --git a/sqlite3/busy_timeout.patch b/sqlite3/busy_timeout.patch index e9bbf63..1d954e8 100644 --- a/sqlite3/busy_timeout.patch +++ b/sqlite3/busy_timeout.patch @@ -2,7 +2,7 @@ # This patch allows Go to handle (and interrupt) sqlite3_busy_timeout. --- sqlite3.c.orig +++ sqlite3.c -@@ -181581,7 +181581,7 @@ +@@ -181614,7 +181614,7 @@ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif if( ms>0 ){ diff --git a/sqlite3/date.patch b/sqlite3/date.patch deleted file mode 100644 index 7ed3c1b..0000000 --- a/sqlite3/date.patch +++ /dev/null @@ -1,556 +0,0 @@ -# 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/download.sh b/sqlite3/download.sh index 5db422c..9d360bc 100755 --- a/sqlite3/download.sh +++ b/sqlite3/download.sh @@ -3,7 +3,7 @@ set -euo pipefail cd -P -- "$(dirname -- "$0")" -curl -#OL "https://sqlite.org/2024/sqlite-amalgamation-3450300.zip" +curl -#OL "https://sqlite.org/2024/sqlite-amalgamation-3460000.zip" unzip -d . sqlite-amalgamation-*.zip mv sqlite-amalgamation-*/sqlite3* . rm -rf sqlite-amalgamation-* @@ -12,25 +12,25 @@ cat *.patch | patch --no-backup-if-mismatch mkdir -p ext/ cd ext/ -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/ext/misc/anycollseq.c" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/ext/misc/base64.c" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/ext/misc/decimal.c" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/ext/misc/ieee754.c" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/ext/misc/regexp.c" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/ext/misc/series.c" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/ext/misc/uint.c" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/ext/misc/uuid.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/ext/misc/anycollseq.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/ext/misc/base64.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/ext/misc/decimal.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/ext/misc/ieee754.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/ext/misc/regexp.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/ext/misc/series.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/ext/misc/uint.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/ext/misc/uuid.c" cd ~- cd ../vfs/tests/mptest/testdata/ -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/mptest/mptest.c" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/mptest/config01.test" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/mptest/config02.test" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/mptest/crash01.test" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/mptest/crash02.subtest" -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/mptest/multiwrite01.test" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/mptest/mptest.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/mptest/config01.test" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/mptest/config02.test" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/mptest/crash01.test" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/mptest/crash02.subtest" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/mptest/multiwrite01.test" cd ~- cd ../vfs/tests/speedtest1/testdata/ -curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.3/test/speedtest1.c" +curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.46.0/test/speedtest1.c" cd ~- \ No newline at end of file diff --git a/sqlite3/sqlite_opt.h b/sqlite3/sqlite_opt.h index b578239..bf47bf8 100644 --- a/sqlite3/sqlite_opt.h +++ b/sqlite3/sqlite_opt.h @@ -23,6 +23,7 @@ #define SQLITE_DEFAULT_FOREIGN_KEYS 1 #define SQLITE_ENABLE_ATOMIC_WRITE #define SQLITE_ENABLE_BATCH_ATOMIC_WRITE +#define SQLITE_ENABLE_COLUMN_METADATA #define SQLITE_ENABLE_STAT4 1 // We have our own memdb VFS. diff --git a/sqlite3/time.c b/sqlite3/time.c index 7b3619a..784d43e 100644 --- a/sqlite3/time.c +++ b/sqlite3/time.c @@ -5,6 +5,8 @@ static int time_collation(void *pArg, int nKey1, const void *pKey1, int nKey2, const void *pKey2) { + UNUSED_PARAMETER(pArg); + // Remove a Z suffix if one key is no longer than the other. // A Z suffix collates before any character but after the empty string. // This avoids making different keys equal. @@ -29,8 +31,8 @@ static int time_collation(void *pArg, int nKey1, const void *pKey1, int nKey2, int sqlite3_time_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { + UNUSED_PARAMETER2(pzErrMsg, pApi); sqlite3_create_collation_v2(db, "time", SQLITE_UTF8, /*arg=*/NULL, - time_collation, - /*destroy=*/NULL); + time_collation, /*destroy=*/NULL); return SQLITE_OK; } \ No newline at end of file diff --git a/sqlite3/vfs_find.patch b/sqlite3/vfs_find.patch index 861c049..5e4b999 100644 --- a/sqlite3/vfs_find.patch +++ b/sqlite3/vfs_find.patch @@ -2,7 +2,7 @@ # This patch allows Go VFSes to be (un)registered. --- sqlite3.c.orig +++ sqlite3.c -@@ -26372,7 +26372,7 @@ +@@ -26396,7 +26396,7 @@ ** Locate a VFS by name. If no name is given, simply return the ** first VFS on the list. */ diff --git a/sqlite3/vtab.c b/sqlite3/vtab.c index a30fb1b..a9af043 100644 --- a/sqlite3/vtab.c +++ b/sqlite3/vtab.c @@ -72,6 +72,8 @@ static void go_mod_destroy(void *pAux) { static int go_vtab_create_wrapper(sqlite3 *db, void *pAux, int argc, const char *const *argv, sqlite3_vtab **ppVTab, char **pzErr) { + UNUSED_PARAMETER(db); + struct go_vtab *vtab = calloc(1, sizeof(struct go_vtab)); if (vtab == NULL) return SQLITE_NOMEM; *ppVTab = &vtab->base; @@ -88,6 +90,8 @@ static int go_vtab_create_wrapper(sqlite3 *db, void *pAux, int argc, static int go_vtab_connect_wrapper(sqlite3 *db, void *pAux, int argc, const char *const *argv, sqlite3_vtab **ppVTab, char **pzErr) { + UNUSED_PARAMETER(db); + struct go_vtab *vtab = calloc(1, sizeof(struct go_vtab)); if (vtab == NULL) return SQLITE_NOMEM; *ppVTab = &vtab->base; diff --git a/stmt.go b/stmt.go index fc26b1e..63c2085 100644 --- a/stmt.go +++ b/stmt.go @@ -367,12 +367,10 @@ func (s *Stmt) ColumnCount() int { func (s *Stmt) ColumnName(col int) string { r := s.c.call("sqlite3_column_name", uint64(s.handle), uint64(col)) - - ptr := uint32(r) - if ptr == 0 { + if r == 0 { panic(util.OOMErr) } - return util.ReadString(s.c.mod, ptr, _MAX_NAME) + return util.ReadString(s.c.mod, uint32(r), _MAX_NAME) } // ColumnType returns the initial [Datatype] of the result column. @@ -398,6 +396,48 @@ func (s *Stmt) ColumnDeclType(col int) string { return util.ReadString(s.c.mod, uint32(r), _MAX_NAME) } +// ColumnDatabaseName returns the name of the database +// that is the origin of a particular result column. +// The leftmost column of the result set has the index 0. +// +// https://sqlite.org/c3ref/column_database_name.html +func (s *Stmt) ColumnDatabaseName(col int) string { + r := s.c.call("sqlite3_column_database_name", + uint64(s.handle), uint64(col)) + if r == 0 { + return "" + } + return util.ReadString(s.c.mod, uint32(r), _MAX_NAME) +} + +// ColumnTableName returns the name of the table +// that is the origin of a particular result column. +// The leftmost column of the result set has the index 0. +// +// https://sqlite.org/c3ref/column_database_name.html +func (s *Stmt) ColumnTableName(col int) string { + r := s.c.call("sqlite3_column_table_name", + uint64(s.handle), uint64(col)) + if r == 0 { + return "" + } + return util.ReadString(s.c.mod, uint32(r), _MAX_NAME) +} + +// ColumnOriginName returns the name of the table column +// that is the origin of a particular result column. +// The leftmost column of the result set has the index 0. +// +// https://sqlite.org/c3ref/column_database_name.html +func (s *Stmt) ColumnOriginName(col int) string { + r := s.c.call("sqlite3_column_origin_name", + uint64(s.handle), uint64(col)) + if r == 0 { + return "" + } + return util.ReadString(s.c.mod, uint32(r), _MAX_NAME) +} + // ColumnBool returns the value of the result column as a bool. // The leftmost column of the result set has the index 0. // SQLite does not have a separate boolean storage class. diff --git a/tests/stmt_test.go b/tests/stmt_test.go index 42a3d59..215de74 100644 --- a/tests/stmt_test.go +++ b/tests/stmt_test.go @@ -20,7 +20,7 @@ func TestStmt(t *testing.T) { } defer db.Close() - err = db.Exec(`CREATE TABLE test (col)`) + err = db.Exec(`CREATE TABLE test (col ANY) STRICT`) if err != nil { t.Fatal(err) } @@ -136,7 +136,7 @@ func TestStmt(t *testing.T) { } // The table should have: 0, 1, 2, π, NULL, "", "text", "", "blob", NULL, "\0\0\0\0", "true", NULL - stmt, _, err = db.Prepare(`SELECT col FROM test`) + stmt, _, err = db.Prepare(`SELECT col AS c FROM test`) if err != nil { t.Fatal(err) } @@ -145,6 +145,21 @@ func TestStmt(t *testing.T) { if got := stmt.ReadOnly(); got != true { t.Error("got false, want true") } + if got := stmt.ColumnName(0); got != "c" { + t.Errorf(`got %q, want "c"`, got) + } + if got := stmt.ColumnDeclType(0); got != "ANY" { + t.Errorf(`got %q, want "ANY"`, got) + } + if got := stmt.ColumnOriginName(0); got != "col" { + t.Errorf(`got %q, want "col"`, got) + } + if got := stmt.ColumnTableName(0); got != "test" { + t.Errorf(`got %q, want "test"`, got) + } + if got := stmt.ColumnDatabaseName(0); got != "main" { + t.Errorf(`got %q, want "main"`, got) + } if stmt.Step() { if got := stmt.ColumnType(0); got != sqlite3.INTEGER { diff --git a/time.go b/time.go index cd72f35..0164a30 100644 --- a/time.go +++ b/time.go @@ -101,7 +101,7 @@ func (f TimeFormat) Encode(t time.Time) any { return t.UnixMicro() case TimeFormatUnixNano: return t.UnixNano() - // Special formats + // Special formats. case TimeFormatDefault, TimeFormatAuto: f = time.RFC3339Nano // SQLite assumes UTC if unspecified. @@ -139,7 +139,7 @@ func (f TimeFormat) Encode(t time.Time) any { // https://sqlite.org/lang_datefunc.html func (f TimeFormat) Decode(v any) (time.Time, error) { switch f { - // Numeric formats + // Numeric formats. case TimeFormatJulianDay: switch v := v.(type) { case string: @@ -222,7 +222,7 @@ func (f TimeFormat) Decode(v any) (time.Time, error) { return time.Time{}, util.TimeErr } - // Special formats + // Special formats. case TimeFormatAuto: switch s := v.(type) { case string: diff --git a/vfs/tests/mptest/testdata/mptest.wasm.bz2 b/vfs/tests/mptest/testdata/mptest.wasm.bz2 index c6e2766..5c80f2e 100644 --- a/vfs/tests/mptest/testdata/mptest.wasm.bz2 +++ b/vfs/tests/mptest/testdata/mptest.wasm.bz2 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db2dc210ff152cf9c03a4100064e9dd55eafbe61ac7ccf1cd0962c8ba3307300 -size 470743 +oid sha256:2bca04dc69100a3ea9492f20ce8cdb796cc0a6bd3c95da6abd40c94c599c7509 +size 479477 diff --git a/vfs/tests/speedtest1/testdata/speedtest1.wasm.bz2 b/vfs/tests/speedtest1/testdata/speedtest1.wasm.bz2 index bd54127..d0d2088 100644 --- a/vfs/tests/speedtest1/testdata/speedtest1.wasm.bz2 +++ b/vfs/tests/speedtest1/testdata/speedtest1.wasm.bz2 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f994bcf2ae8eed9333e9b4d3929a52f3b2c4cf0a780311efa243986c4be6f1c1 -size 484371 +oid sha256:9fc72178e4e89a735d90a0f297f22750718bc7110e9f4cd8618c2d67d9b3c6c4 +size 491944