Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b92691f85 | |||
| 7509c6351e | |||
| 57e46429fe | |||
| a9c2e08087 | |||
| 7f1f4c803d | |||
| bd13573a96 | |||
| 0cadeecf6f | |||
| ad52288e0d | |||
| d5f0e01593 | |||
| 3e663bd8c7 | |||
| 97901bbd69 | |||
| c549e28c67 | |||
| 90dae0d01d | |||
| 0a0a52ae93 | |||
| e1d4680fdd | |||
| 532e506d18 | |||
| c9bed48c3c | |||
| 6b4eb6725f | |||
| 6176034151 | |||
| 7471b5d6c0 | |||
| 1fc7341ad2 | |||
| 6af10b0efd | |||
| 70d1e3e75e | |||
| 74006fdcdb | |||
| 4b9f9d6794 | |||
| 39b2fe7e5b | |||
| 01ec60bb87 | |||
| e2dbd0a578 | |||
| df7b22790e | |||
| 50811f74e0 | |||
| d7bf8233ff | |||
| 455486bbc4 | |||
| ba9092e228 | |||
| 67d4e0226f | |||
| 323b3fc121 | |||
| 78279e2550 | |||
| 4e4962f6b3 | |||
| ed95a9d103 | |||
| e791e7c7a0 | |||
| 2545d9c201 | |||
| 2a07c6de2c | |||
| 68b07ddd41 | |||
| 4b69e7704b | |||
| e17ab401f0 | |||
| 57ee077c5e | |||
| c7edd22456 | |||
| 8606a52934 | |||
| 5c6404aa77 | |||
| 429369f4aa | |||
| 9529894a29 | |||
| c4c47a49a8 | |||
| ee7f6f29fc | |||
| c3b52dff53 |
+24
-23
@@ -419,7 +419,7 @@ static void analyzeFunc(
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int n;
|
||||
sqlite3_int64 i64;
|
||||
sqlite3_int64 ii;
|
||||
sqlite3_int64 pgsz;
|
||||
sqlite3_int64 nPage;
|
||||
sqlite3_int64 nPageInUse;
|
||||
@@ -429,6 +429,7 @@ static void analyzeFunc(
|
||||
Analysis s;
|
||||
sqlite3_uint64 r[2];
|
||||
|
||||
(void)argc;
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.db = sqlite3_context_db_handle(context);
|
||||
s.context = context;
|
||||
@@ -445,10 +446,10 @@ static void analyzeFunc(
|
||||
sqlite3_result_text(context, "cannot analyze \"temp\"",-1,SQLITE_STATIC);
|
||||
return;
|
||||
}
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s,&i64,"SELECT 1 FROM pragma_database_list"
|
||||
ii = 0;
|
||||
rc = analysisSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list"
|
||||
" WHERE name=%Q COLLATE nocase",s.zSchema);
|
||||
if( rc || i64==0 ){
|
||||
if( rc || ii==0 ){
|
||||
analysisReset(&s);
|
||||
sqlite3_result_text(context,"no such database",-1,SQLITE_STATIC);
|
||||
return;
|
||||
@@ -570,25 +571,25 @@ static void analyzeFunc(
|
||||
analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList);
|
||||
analysisPercent(&s, (nFreeList*100.0)/(double)nPage);
|
||||
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64, "PRAGMA \"%w\".auto_vacuum", s.zSchema);
|
||||
ii = 0;
|
||||
rc = analysisSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema);
|
||||
if( rc ) return;
|
||||
if( i64==0 || nPage<=1 ){
|
||||
i64 = 0;
|
||||
if( ii==0 || nPage<=1 ){
|
||||
ii = 0;
|
||||
}else{
|
||||
double rPtrsPerPage = pgsz/5;
|
||||
double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0);
|
||||
i64 = (sqlite3_int64)ceil(rAvPage);
|
||||
ii = (sqlite3_int64)ceil(rAvPage);
|
||||
}
|
||||
analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", i64);
|
||||
analysisPercent(&s, (i64*100.0)/(double)nPage);
|
||||
analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii);
|
||||
analysisPercent(&s, (ii*100.0)/(double)nPage);
|
||||
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
ii = 0;
|
||||
rc = analysisSqlInt(&s, &ii,
|
||||
"SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of tables", "%lld\n", i64);
|
||||
analysisLine(&s, "Number of tables", "%lld\n", ii);
|
||||
nWORowid = 0;
|
||||
rc = analysisSqlInt(&s, &nWORowid,
|
||||
"SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr",
|
||||
@@ -596,7 +597,7 @@ static void analyzeFunc(
|
||||
if( rc ) return;
|
||||
if( nWORowid>0 ){
|
||||
analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid);
|
||||
analysisLine(&s, "Number of rowid tables", "%lld\n", i64 - nWORowid);
|
||||
analysisLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid);
|
||||
}
|
||||
nIndex = 0;
|
||||
rc = analysisSqlInt(&s, &nIndex,
|
||||
@@ -604,23 +605,23 @@ static void analyzeFunc(
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of indexes", "%lld\n", nIndex);
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
ii = 0;
|
||||
rc = analysisSqlInt(&s, &ii,
|
||||
"SELECT count(*) FROM \"%w\".sqlite_schema"
|
||||
" WHERE name GLOB 'sqlite_autoindex_*' AND type='index'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - i64);
|
||||
analysisLine(&s, "Number of implied indexes", "%lld\n", i64);
|
||||
analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii);
|
||||
analysisLine(&s, "Number of implied indexes", "%lld\n", ii);
|
||||
analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage);
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
ii = 0;
|
||||
rc = analysisSqlInt(&s, &ii,
|
||||
"SELECT sum(payload) FROM temp.%s"
|
||||
" WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'",
|
||||
s.zSU);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Bytes of payload", "%-11lld ", i64);
|
||||
analysisPercent(&s, i64*100.0/(double)(pgsz*nPage));
|
||||
analysisLine(&s, "Bytes of payload", "%-11lld ", ii);
|
||||
analysisPercent(&s, ii*100.0/(double)(pgsz*nPage));
|
||||
|
||||
analysisTitle(&s, "Page counts for all tables with their indexes");
|
||||
pStmt = analysisPrepare(&s,
|
||||
|
||||
+31
-19
@@ -428,7 +428,6 @@ static void qrfEqpStats(Qrf *p){
|
||||
if( nRow>=0 ){
|
||||
if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' ');
|
||||
qrfApproxInt64(pStats, nRow);
|
||||
nSp = 2;
|
||||
if( p->spec.eStyle==QRF_STYLE_StatsEst ){
|
||||
sqlite3_str_appendf(pStats, " ");
|
||||
qrfApproxInt64(pStats, (i64)rEstCum);
|
||||
@@ -718,19 +717,16 @@ static int qrfDisplayWidth(const char *zIn, sqlite3_int64 nByte, int *pnNL){
|
||||
}
|
||||
|
||||
/*
|
||||
** Escape the input string if it is needed and in accordance with
|
||||
** eEsc, which is either QRF_ESC_Ascii or QRF_ESC_Symbol.
|
||||
** Escape the text starting at byte iStart of pStr, if needed, using the
|
||||
** escape encoding of eEsc, which is either QRF_ESC_Ascii or QRF_ESC_Symbol.
|
||||
** The pStr string is modified appropriately.
|
||||
**
|
||||
** Escaping is needed if the string contains any control characters
|
||||
** other than \t, \n, and \r\n
|
||||
**
|
||||
** If no escaping is needed (the common case) then set *ppOut to NULL
|
||||
** and return 0. If escaping is needed, write the escaped string into
|
||||
** memory obtained from sqlite3_malloc64() and make *ppOut point to that
|
||||
** memory and return 0. If an error occurs, return non-zero.
|
||||
**
|
||||
** The caller is responsible for freeing *ppFree if it is non-NULL in order
|
||||
** to reclaim memory.
|
||||
** If no escaping is needed (the common case) then pStr is unchanged.
|
||||
** If escaping is required, then pStr is expanded and modified to hold
|
||||
** an escaped representation of the text.
|
||||
*/
|
||||
static void qrfEscape(
|
||||
int eEsc, /* QRF_ESC_Ascii or QRF_ESC_Symbol */
|
||||
@@ -738,20 +734,22 @@ static void qrfEscape(
|
||||
int iStart /* Begin escapding on this byte of pStr */
|
||||
){
|
||||
sqlite3_int64 i, j; /* Loop counters */
|
||||
sqlite3_int64 sz; /* Size of the string prior to escaping */
|
||||
sqlite3_int64 nCtrl = 0;/* Number of control characters to escape */
|
||||
unsigned char *zIn; /* Text to be escaped */
|
||||
unsigned int nIn; /* Bytes of text to be escaped */
|
||||
unsigned char c; /* A single character of the text */
|
||||
unsigned char *zOut; /* Where to write the results */
|
||||
|
||||
/* Find the text to be escaped */
|
||||
zIn = (unsigned char*)sqlite3_str_value(pStr);
|
||||
nIn = sqlite3_str_length(pStr);
|
||||
if( zIn==0 ) return;
|
||||
zIn += iStart;
|
||||
nIn -= iStart;
|
||||
|
||||
/* Count the control characters */
|
||||
for(i=0; (c = zIn[i])!=0; i++){
|
||||
if( c<=0x1f
|
||||
for(i=0; i<nIn; i++){
|
||||
if( (c = zIn[i])<=0x1f
|
||||
&& c!='\t'
|
||||
&& c!='\n'
|
||||
&& (c!='\r' || zIn[i+1]!='\n')
|
||||
@@ -763,18 +761,17 @@ static void qrfEscape(
|
||||
|
||||
/* Make space to hold the escapes. Copy the original text to the end
|
||||
** of the available space. */
|
||||
sz = sqlite3_str_length(pStr) - iStart;
|
||||
if( eEsc==QRF_ESC_Symbol ) nCtrl *= 2;
|
||||
sqlite3_str_appendchar(pStr, nCtrl, ' ');
|
||||
zOut = (unsigned char*)sqlite3_str_value(pStr);
|
||||
if( zOut==0 ) return;
|
||||
zOut += iStart;
|
||||
zIn = zOut + nCtrl;
|
||||
memmove(zIn,zOut,sz);
|
||||
memmove(zIn,zOut,nIn);
|
||||
|
||||
/* Convert the control characters */
|
||||
for(i=j=0; (c = zIn[i])!=0; i++){
|
||||
if( c>0x1f
|
||||
for(i=j=0; i<nIn; i++){
|
||||
if( (c = zIn[i])>0x1f
|
||||
|| c=='\t'
|
||||
|| c=='\n'
|
||||
|| (c=='\r' && zIn[i+1]=='\n')
|
||||
@@ -786,6 +783,7 @@ static void qrfEscape(
|
||||
j += i;
|
||||
}
|
||||
zIn += i+1;
|
||||
nIn -= i+1;
|
||||
i = -1;
|
||||
if( eEsc==QRF_ESC_Symbol ){
|
||||
zOut[j++] = 0xe2;
|
||||
@@ -1188,8 +1186,22 @@ static void qrfRenderValue(Qrf *p, sqlite3_str *pOut, int iCol){
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
|
||||
qrfEncodeText(p, pOut, zTxt);
|
||||
const void *pBlob = sqlite3_column_blob(p->pStmt,iCol);
|
||||
int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
|
||||
int rc;
|
||||
qrfWrite(p);
|
||||
if( nBlob==0 ){
|
||||
/* no-op */
|
||||
}else if( p->spec.eEsc==QRF_ESC_Off ){
|
||||
rc = p->spec.xWrite(p->spec.pWriteArg,pBlob,nBlob);
|
||||
if( rc ){
|
||||
qrfError(p, rc, "Failed to write %d bytes of BLOB output", nBlob);
|
||||
}
|
||||
}else{
|
||||
sqlite3_str_append(pOut, pBlob, nBlob);
|
||||
qrfEscape(p->spec.eEsc, pOut, 0);
|
||||
qrfWrite(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -532,18 +532,39 @@ static void recoverFinalize(sqlite3_recover *p, sqlite3_stmt *pStmt){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run a single SQL statement in zSql. If zSql contains two or more
|
||||
** SQL statements separated by ';', only the first is run.
|
||||
**
|
||||
** Return the sqlite3_finalizer() or sqlite3_prepare() result code
|
||||
** from running the zSql statement.
|
||||
*/
|
||||
static int recoverOneStmt(sqlite3 *db, const char *zSql){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
if( zSql==0 ) return SQLITE_OK;
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){}
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is a no-op if recover handle p already contains an error
|
||||
** (if p->errCode!=SQLITE_OK). A copy of p->errCode is returned in this
|
||||
** case.
|
||||
**
|
||||
** Otherwise, execute SQL script zSql. If successful, return SQLITE_OK.
|
||||
** Or, if an error occurs, leave an error code and message in the recover
|
||||
** handle and return a copy of the error code.
|
||||
** Otherwise, execute a single SQL statment in zSql. Even if zSql contains
|
||||
** two or more SQL statements separated by ';', only execute the first one.
|
||||
** If successful, return SQLITE_OK. Or, if an error occurs, leave an error
|
||||
** code and message in the recover handle and return a copy of the error code.
|
||||
*/
|
||||
static int recoverExec(sqlite3_recover *p, sqlite3 *db, const char *zSql){
|
||||
if( p->errCode==SQLITE_OK ){
|
||||
int rc = sqlite3_exec(db, zSql, 0, 0, 0);
|
||||
int rc = recoverOneStmt(db, zSql);
|
||||
if( rc ){
|
||||
recoverDbError(p, db);
|
||||
}
|
||||
@@ -943,7 +964,8 @@ static void recoverTransferSettings(sqlite3_recover *p){
|
||||
}
|
||||
recoverFinalize(p, p1);
|
||||
}
|
||||
recoverExec(p, db2, "CREATE TABLE t1(a); DROP TABLE t1;");
|
||||
recoverExec(p, db2, "CREATE TABLE t1(a)");
|
||||
recoverExec(p, db2, "DROP TABLE t1");
|
||||
|
||||
if( p->errCode==SQLITE_OK ){
|
||||
sqlite3 *db = p->dbOut;
|
||||
@@ -1025,12 +1047,12 @@ static int recoverOpenOutput(sqlite3_recover *p){
|
||||
static void recoverOpenRecovery(sqlite3_recover *p){
|
||||
char *zSql = recoverMPrintf(p, "ATTACH %Q AS recovery;", p->zStateDb);
|
||||
recoverExec(p, p->dbOut, zSql);
|
||||
recoverExec(p, p->dbOut,
|
||||
"PRAGMA writable_schema = 1;"
|
||||
"CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT);"
|
||||
"CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);"
|
||||
);
|
||||
sqlite3_free(zSql);
|
||||
recoverExec(p, p->dbOut, "PRAGMA writable_schema = 1");
|
||||
recoverExec(p, p->dbOut,
|
||||
"CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT)");
|
||||
recoverExec(p, p->dbOut,
|
||||
"CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql)");
|
||||
}
|
||||
|
||||
|
||||
@@ -1170,7 +1192,7 @@ static int recoverWriteSchema1(sqlite3_recover *p){
|
||||
")"
|
||||
"SELECT rootpage, tbl, isVirtual, name, sql"
|
||||
" FROM dbschema "
|
||||
" WHERE tbl OR isIndex"
|
||||
" WHERE (tbl OR isIndex) AND sql GLOB 'CREATE *'"
|
||||
" ORDER BY tbl DESC, name=='sqlite_sequence' DESC"
|
||||
);
|
||||
|
||||
@@ -1196,7 +1218,7 @@ static int recoverWriteSchema1(sqlite3_recover *p){
|
||||
zName, zName, zSql
|
||||
));
|
||||
}
|
||||
rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0);
|
||||
rc = recoverOneStmt(p->dbOut, zSql);
|
||||
if( rc==SQLITE_OK ){
|
||||
recoverSqlCallback(p, zSql);
|
||||
if( bTable && !bVirtual ){
|
||||
@@ -1238,15 +1260,17 @@ static int recoverWriteSchema2(sqlite3_recover *p){
|
||||
p->bSlowIndexes ?
|
||||
"SELECT rootpage, sql FROM recovery.schema "
|
||||
" WHERE type!='table' AND type!='index'"
|
||||
" AND sql GLOB 'CREATE *'"
|
||||
:
|
||||
"SELECT rootpage, sql FROM recovery.schema "
|
||||
" WHERE type!='table' AND (type!='index' OR sql NOT LIKE '%unique%')"
|
||||
" AND sql GLOB 'CREATE *'"
|
||||
);
|
||||
|
||||
if( pSelect ){
|
||||
while( sqlite3_step(pSelect)==SQLITE_ROW ){
|
||||
const char *zSql = (const char*)sqlite3_column_text(pSelect, 1);
|
||||
int rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0);
|
||||
int rc = recoverOneStmt(p->dbOut, zSql);
|
||||
if( rc==SQLITE_OK ){
|
||||
recoverSqlCallback(p, zSql);
|
||||
}else if( rc!=SQLITE_ERROR ){
|
||||
@@ -2624,7 +2648,7 @@ static void recoverStep(sqlite3_recover *p){
|
||||
if( bUseWrapper ) recoverUninstallWrapper(p);
|
||||
}while( p->errCode==SQLITE_NOTADB
|
||||
&& (bUseWrapper--)
|
||||
&& SQLITE_OK==sqlite3_exec(p->dbIn, "ROLLBACK", 0, 0, 0)
|
||||
&& SQLITE_OK==recoverOneStmt(p->dbIn, "ROLLBACK")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2689,7 +2713,7 @@ static void recoverStep(sqlite3_recover *p){
|
||||
** database. Regardless of whether or not an error has occurred, make
|
||||
** an attempt to end the read transaction on the input database. */
|
||||
recoverExec(p, p->dbOut, "COMMIT");
|
||||
rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0);
|
||||
rc = recoverOneStmt(p->dbIn, "END");
|
||||
if( p->errCode==SQLITE_OK ) p->errCode = rc;
|
||||
|
||||
recoverSqlCallback(p, "PRAGMA writable_schema = off");
|
||||
@@ -2885,7 +2909,7 @@ int sqlite3_recover_finish(sqlite3_recover *p){
|
||||
}else{
|
||||
recoverFinalCleanup(p);
|
||||
if( p->bCloseTransaction && sqlite3_get_autocommit(p->dbIn)==0 ){
|
||||
rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0);
|
||||
rc = recoverOneStmt(p->dbIn, "END");
|
||||
if( p->errCode==SQLITE_OK ) p->errCode = rc;
|
||||
}
|
||||
rc = p->errCode;
|
||||
|
||||
@@ -665,17 +665,17 @@ static unsigned int sessionChangeHash(
|
||||
u8 *a = aRecord; /* Used to iterate through change record */
|
||||
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
int eType = *a;
|
||||
int isPK = pTab->abPK[i];
|
||||
if( bPkOnly && isPK==0 ) continue;
|
||||
|
||||
assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
|
||||
|| eType==SQLITE_TEXT || eType==SQLITE_BLOB
|
||||
|| eType==SQLITE_NULL || eType==0
|
||||
);
|
||||
|
||||
if( isPK ){
|
||||
a++;
|
||||
int eType = *a++;
|
||||
|
||||
assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
|
||||
|| eType==SQLITE_TEXT || eType==SQLITE_BLOB
|
||||
|| eType==SQLITE_NULL || eType==0
|
||||
);
|
||||
|
||||
h = sessionHashAppendType(h, eType);
|
||||
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
|
||||
h = sessionHashAppendI64(h, sessionGetI64(a));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Disable\soptimization\sof\snested\sEXIST\sloops.\sPossible\sfix\sfor\s[forum:/forumpost/077c02e8ed\s|\sforum\spost\s77c02e8ed].
|
||||
D 2026-04-21T16:40:08.614
|
||||
C This\sis\san\sidea\sfor\snew\sAPIs\sto\simprove\supon\ssqlite3_set_authorizer().\nAfter\simplementing\sit,\showever,\sI'm\shaving\ssecond\sthroughts.\s\sSaved\shere\nin\scase\sI\schanged\smy\smind.
|
||||
D 2026-05-01T23:56:16.497
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -358,7 +358,7 @@ F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b6
|
||||
F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0
|
||||
F ext/misc/README.md 6243cdc4d7eb791c41ef0716f3980b8b5f6aa8c61ff76a3958cbf0031c6ebfa7
|
||||
F ext/misc/amatch.c 8d237cc014b3736922c26a76a451050d244aa4980c47c531f368f817b1e77b49
|
||||
F ext/misc/analyze.c 13caf932d591d7c0ce3f0470023a5c835aa24caddec673c41d296ac89de98220
|
||||
F ext/misc/analyze.c 77e0f45a44c13d66f30922db553072305521c0fb3a448b920e641fccd2498527
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
|
||||
F ext/misc/base64.c 1445761667c16356e827fc6418294c869468be934429aaa8315035e76dd58acf
|
||||
@@ -422,7 +422,7 @@ F ext/misc/zipfile.c 5a583b5e72b4d777dc9f845529e6bd185d58024b633aafc93588679c787
|
||||
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
|
||||
F ext/qrf/README.md 9e644615d7d7b77ef7e9db798765679e50c5ed12eda48bce21c9ef9eb4715e9d
|
||||
F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
|
||||
F ext/qrf/qrf.c 64203184d9fc6ee75439fb6da70fd51dc7aaf3243600e52aa87d18ea1e4d6e73
|
||||
F ext/qrf/qrf.c 9bd4ad396e75a7905b1eb956ac53fd93f77942963c5ffac176ae39880368553b
|
||||
F ext/qrf/qrf.h fbb223ff5789b324b3e9c22e787e4c1f53e217cff7cc5a243164d4b2e8410f4b
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
|
||||
@@ -487,7 +487,7 @@ F ext/recover/recoverpgsz.test 88766fcb810e52ee05335c456d4e5fb06d02b73d3ccb48c52
|
||||
F ext/recover/recoverrowid.test f948bf4024a5f41b0e21b8af80c60564c5b5d78c05a8d64fc00787715ff9f45f
|
||||
F ext/recover/recoverslowidx.test c90d59c46bb8924a973ac6fbc38f3163cee38cc240256addcab1cf1a322c37dc
|
||||
F ext/recover/recoversql.test e66d01f95302a223bcd3fd42b5ee58dc2b53d70afa90b0d00e41e4b8eab20486
|
||||
F ext/recover/sqlite3recover.c 56c216332ea91233d6d820d429f3384adbec9ecedda67aa98186b691d427cc57
|
||||
F ext/recover/sqlite3recover.c dfbfca5a8e4909333e5aa3749bcffb5dd7e396de9541c338f8cc843b2e20217e
|
||||
F ext/recover/sqlite3recover.h 011c799f02deb70ab685916f6f538e6bb32c4e0025e79bfd0e24ff9c74820959
|
||||
F ext/recover/test_recover.c 3d0fb1df7823f5bc22a0b93955034d16a2dfa2eb1e443e9a0123a77f120599a3
|
||||
F ext/rtree/README 734aa36238bcd2dee91db5dba107d5fcbdb02396612811377a8ad50f1272b1c1
|
||||
@@ -572,7 +572,7 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a
|
||||
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
|
||||
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
|
||||
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
||||
F ext/session/sqlite3session.c 871d8a4574bfc682ca0816efb55c85c5fea048e0becf9367a4b271d6a4474b2f
|
||||
F ext/session/sqlite3session.c 48b5585ea444c9646294d86f16ad3efa28dd19632dd3e295557c1ab40c447a4c
|
||||
F ext/session/sqlite3session.h 063e7bf7be2fff874456f452a224b5b3013b25682d108933b0351c93a1279b9c
|
||||
F ext/session/test_session.c 2a02a68b522e2f3d4a64b2a4733af54b0f3e500769aeccd5bcbdd440103db069
|
||||
F ext/wasm/GNUmakefile 68c750f173106d9d63f12c1edf1256c6f4bad9894b155da5db64322f4912de4b
|
||||
@@ -668,11 +668,11 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
|
||||
F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398
|
||||
F src/alter.c e257c51ac9301b3d72be4e1ac39c3c78528aad83194d963a075351344fbc14c7
|
||||
F src/alter.c 7d7ddbdc189f0e0c686e32ee170abdddc95c11f2089e40df4ffcee88f5334826
|
||||
F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d
|
||||
F src/attach.c 7cf07d4fa42b9fc8662237c60c40b730326c30aa90ae5fffc0b18b2d726ebf61
|
||||
F src/auth.c ebec42df26b34a62b6750d30d9c2c03554a1c522020182476f7729a439fef04f
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/attach.c c58278c7d2d954785591c4fde81669ec3e4d52f348c453b028a19ae8adf4f338
|
||||
F src/auth.c ca42996e133f1b7b50447b54291db6a5e2b7c8fbca015235c101dcc97e719917
|
||||
F src/backup.c 6ebe22ccbedfcb92423833992130e8d65824be4e6599c3a03f540ab38fc7d13c
|
||||
F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399
|
||||
F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c 216ffbe197e330118a2999adc7d3f09b0e2eeb163df8746ba9a2b27fed3d4335
|
||||
@@ -685,7 +685,7 @@ F src/complete.c f216b970ce99c5a657556cf1f17e7ddd494515d3beb63df426bf59ff43bd3d9
|
||||
F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
|
||||
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
|
||||
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
|
||||
F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
|
||||
F src/delete.c 59eeca3fb88c29329afc41bb803ee568b120d9dd7470b5f38ab55cc38390b451
|
||||
F src/expr.c 68400681c5f6e41231d2c85abf6bb432aeeb2e36c4abdf90eb7b78551a5ce0f3
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08
|
||||
@@ -695,25 +695,25 @@ F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca
|
||||
F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
|
||||
F src/hwtime.h 21c2cf1f736e7b97502c3674d0c386db3f06870d6f10d0cf8174e2a4b8cb726e
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
|
||||
F src/insert.c 77aa90e7ddbebf131c5de504854b5a61c25b11d53580649fb375b23752793651
|
||||
F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 78d5b06f18996ffa1203129b28fea043f63a87a4117539678f1d761c30b4ff65
|
||||
F src/main.c 6180079f53ccdd784df2eddc3751f49ea7153c5959bee792b19ad9f4bdbcf437
|
||||
F src/main.c 022f66a3adb94db148c4ad9ff4357a4d4586fea0c0546f8b91f745bd54a3529c
|
||||
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
|
||||
F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
|
||||
F src/mem5.c b7da5c10a726aacacc9ad7cdcb0667deec643e117591cc69cf9b4b9e7f3e96ff
|
||||
F src/memdb.c a3feb427cdd4036ea2db0ba56d152f14c8212ca760ccb05fb7aa49ff6b897df3
|
||||
F src/memdb.c 0a0e827311cec57fdea2ed3142d6684704a1b90e7995b286f74fd7d1a6c5a62c
|
||||
F src/memjournal.c c283c6c95d940eb9dc70f1863eef3ee40382dbd35e5a1108026e7817c206e8a0
|
||||
F src/msvc.h 80b35f95d93bf996ccb3e498535255f2ef1118c78764719a7cd15ab4106ccac9
|
||||
F src/mutex.c 00b8cee206a67fd764d001f3a148494331d8d0b3b9c3974ecd69ff29bb444462
|
||||
F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
|
||||
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
||||
F src/mutex_unix.c f7ee5a2061a4c11815a2bf4fc0e2bfa6fb8d9dc89390eb613ca0cec32fc9a3d1
|
||||
F src/mutex_w32.c e1d317d29cb623667d43de94714264d1e1871cc4bb39fa67dd17048e8138c739
|
||||
F src/mutex_unix.c caec9862aeebad01f6c8997cf709a239abeb0715fcce1895720b87fe7e2ef42f
|
||||
F src/mutex_w32.c d44e94c064f8ab39e0318fb6fa00171cf7e5645bd4241129b07d655a8ddbd44b
|
||||
F src/notify.c 57c2d1a2805d6dee32acd5d250d928ab94e02d76369ae057dee7d445fd64e878
|
||||
F src/os.c 509452169d5ea739723e213b8e2481cf0e587f0e88579a912d200db5269f5f6d
|
||||
F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||
@@ -721,11 +721,11 @@ F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e
|
||||
F src/os_kv.c e7d96727db5b67e39d590a68cc61c86daf4c093c36c011a09ebfb521182ec28d
|
||||
F src/os_setup.h 8efc64eda6a6c2f221387eefc2e7e45fd5a3d5c8337a7a83519ba4fbd2957ae2
|
||||
F src/os_unix.c a07dce662f6c4e18098f6faa9f7ec7cf311f56ee9151bed2aad4dcd55852c9e2
|
||||
F src/os_win.c 0d553b6e8b92c8eb85e7f1b4a8036fe8638c8b32c9ad8d9d72a861c10f81b4c5
|
||||
F src/os_win.h 5e168adf482484327195d10f9c3bce3520f598e04e07ffe62c9c5a8067c1037b
|
||||
F src/os_win.c 4786b1123beea22a9cd8f8e9d781cc1b4bf4679c56103edbf60a519ce23a2781
|
||||
F src/os_win.h c06ccc3a090cf54202ea58981c298817f3309d4c9e4d52ad0a02927346493721
|
||||
F src/pager.c fbec9063ea139dfa5d94ce540671752b89f8e8dc38f8a1f614bab1aa04a2dd40
|
||||
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
|
||||
F src/parse.y 3b784d6083380a950e3b1b32ce5ddd303e8c7c209d8ab788df2c62aaf9ee8eb3
|
||||
F src/parse.y 8c8003a932f6f98ac612fd239d3cdc7ca64480f61ca5f4f680c4fe69b1bc68c9
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
|
||||
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
|
||||
@@ -736,11 +736,11 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c 4c05cde130f26991b7411d8c6809e0630625e18078742c963a047b4b9cc01d49
|
||||
F src/shell.c.in 4e68371fec5a8ab31038d51e7179d9ef3539d693e05a5fdabcd59483e445b27d
|
||||
F src/sqlite.h.in 39d2e09114d2bdb7afd998f4a469c8f8cd065f8093835a7d0422f260fc78fb4f
|
||||
F src/shell.c.in 3ed0902de2a82c92ee535c1bc627fb7cfd64cc3b81762f1c10b59c634597da10
|
||||
F src/sqlite.h.in fa079952ae30eb0921e3b5eb11e4c73741d7dee86d202b2fa7e4c688d6f9b0cf
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 9788c301f95370fa30e808861f1d2e6f022a816ddbe2a4f67486784c1b31db2e
|
||||
F src/sqliteInt.h 1e9df4f7f0a754cebbc5e1494ff74b54bf510046b800db1d5382393972f53499
|
||||
F src/sqliteInt.h 5071d64ad787d9922e524d834c3fe7b7a11989d29dc6ea25f7944892a43266f4
|
||||
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -800,9 +800,9 @@ F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20
|
||||
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
|
||||
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
|
||||
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
|
||||
F src/util.c 377af5da226519a0f374dc3c6d408c9d303a92943e3ae5986432c7d52e6679a2
|
||||
F src/util.c 7c85ba0cdf97f91b57ec9d45f9852aaa4f61e3b7e7cc36d197ee354ad44cdba2
|
||||
F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
|
||||
F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
|
||||
F src/vdbe.c 1cd55e8171e4e87054de196c3c4747d44b69041b5ec910cf547ae82a85beb3e4
|
||||
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
|
||||
F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
|
||||
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
|
||||
@@ -839,7 +839,7 @@ F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256b
|
||||
F test/alterauth2.test 4b74fa8f184f4736497317feb587b65759eb87d87acfe3a8ef433d4d18bb002b
|
||||
F test/altercol.test 3661c432aacb42bc2198dd4611bbb9c3b09fc73251b59edda046109103b8ac00
|
||||
F test/altercons.test ea18def4a0f26b9066da56095c9c480df705df4d02e4ae151708fae76f7e3884
|
||||
F test/altercons2.test ade124ce5c733d7d939a5b602946eaf4a1825c7e355319a2b00bcc0b34aafe3f
|
||||
F test/altercons2.test 4933eadb035fc0ccfc34ed879f69a09051c53907f9dae9c3d36d25f93519ccc7
|
||||
F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12
|
||||
F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e
|
||||
F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
|
||||
@@ -1105,9 +1105,10 @@ F test/existsexpr2.test dc23e76389eff3d29f6488ff733012a3560cd67ec8cfaecbecd52cce
|
||||
F test/existsfault.test ff41c11f3052c1bbd4f8dd557802310026253d67d7c4e3a180c16d2f0862973e
|
||||
F test/expr.test db981f8a85520e99ae20aab7ad2e9b5b0437ed09159b57ced434c672075d2e61
|
||||
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
|
||||
F test/exprfault.test da33606d799718e2f8e34efd0e5858884a1ad87f608774c552a7f5517cc27181
|
||||
F test/exprfault.test 7475e363c7221847855722e9dd2459cf60088f6b172c0c808dba75f89e1704b8
|
||||
F test/exprfault2.test c49e84273898969af5dbc4fe6a3f4335f14639799f343590336c9ddf84425965
|
||||
F test/expridx1.test b464520126e1d781a7800f8540621c82e8bbc526f089ff8b0b57ffc51feea6b7
|
||||
F test/expridx2.test 13348ed208a5d18d9cef7d0a70f8e17948d3c0b5b46508c0573b7e983456165f
|
||||
F test/extension01.test 5de412c66276105901c370770175003381fdcb0c4da7054fa43cf4a31e0bfa3a
|
||||
F test/external_reader.test 6fdec43eeca23eb32faad1e95a4d1abc402bc8b3db70df12d6fc08a637f4a2b5
|
||||
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
|
||||
@@ -1423,7 +1424,7 @@ F test/malloctraceviewer.tcl 3e3ddf11e30d2b20f53aa16aa6615082fb24a100bea61cca721
|
||||
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7
|
||||
F test/memdb1.test c737ac9aa5895092332b1dde24fae7ae494b7fcbcd346d22d600891096a3836d
|
||||
F test/memdb1.test 413f845c0c2d20dc9808d4084de9e57d55759070eed2a4cf23cd30335a96c295
|
||||
F test/memdb2.test 4ba1fc09e2f51df80d148a540e4a3fa66d0462e91167b27497084de4d1f6b5b4
|
||||
F test/memjournal.test 70f3a00c7f84ee2978ad14e831231caa1e7f23915a2c54b4f775a021d5740c6c
|
||||
F test/memjournal2.test dbc2c5cb5f7b38950f4f6dc3e73fcecf0fcbed3fc32c7ce913bba164d288da1e
|
||||
@@ -1623,7 +1624,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
|
||||
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell-prompt.sql 43ed98433bfde83171b5d06c300525154f4cab9230570a326ca606aaef351db6
|
||||
F test/shell-prompt.sql 868ca1711677ada45720532fe23dbbbe881f3612dc29692dac45b19129648b3f
|
||||
F test/shell1.test c84eff209f93ad17ccdf7e1634969fc8231684254edeb21d9b13d67c3179cdb5
|
||||
F test/shell2.test dc541d2681503e55466a24d35a4cbf8ca5b90b8fcdef37fc4db07373a67d31d3
|
||||
F test/shell3.test 91efdd545097a61a1f72cf79c9ad5b49da080f3f10282eaf4c3c272cd1012db2
|
||||
@@ -1719,7 +1720,7 @@ F test/temptrigfault.tes fc5918e64f3867156fefe7cfca9d8e1f495134a5229b2b511b0dc11
|
||||
F test/temptrigger.test a00f258ed8d21a0e8fd4f322f15e8cfb5cef2e43655670e07a753e3fb4769d61
|
||||
F test/tester.tcl 2d943f60200e0a36bcd3f1f0baf181a751cd3604ef6b6bd4c8dc39b4e8a53116
|
||||
F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27
|
||||
F test/testrunner.tcl 1ad787b744277532521a2a9898ac66ee6a8363fbcc1211027db0dadad4ee3214 x
|
||||
F test/testrunner.tcl 6d13732185c13aef87540ebf9daafb8d9657e66f0ac00eb082d93f4749311d4e x
|
||||
F test/testrunner_data.tcl dfcf192d274e965845189cc014ac89fff91dde92b6e2ac9e1262897fc21ee2e0
|
||||
F test/testrunner_estwork.tcl 81e2ae10238f50540f42fbf2d94913052a99bfb494b69e546506323f195dcff9
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
@@ -1927,7 +1928,7 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
|
||||
F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
|
||||
F test/unixexcl.test d2366ef2d3d95249314307861d748924d9ab4f24305541159a08be61ccd4a9ee
|
||||
F test/unordered.test 0edaf3411d300693bca595897c5201421c6c5ec787990a1dfe2f7f60ae93f1e2
|
||||
F test/update.test 258dcf26d401177d3cb7fdf0beab14d671dbe72e8ff6e0435fd85a08fcd57bd9
|
||||
F test/update.test 93fba5f7505f7a7b25d66135d98d9b055b7f1bd627a7e514dbba1ea6213f0c41
|
||||
F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3
|
||||
F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9041
|
||||
F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1
|
||||
@@ -2181,7 +2182,7 @@ F tool/soak1.tcl a3892082ed1079671565c044e93b55c3c7f38829aedf53cc597c65d23ffdadd
|
||||
F tool/spaceanal.tcl 1f83962090a6b60e1d7bf92495d643e622bef9fe82ea3f2d22350dcbce9a12d0
|
||||
F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d40618 x
|
||||
F tool/split-sqlite3c.tcl 4969fd642dad0ea483e4e104163021d92baf98f6a8eac981fe48525f9b873430
|
||||
F tool/sqldiff.c 847edc1e0d1e1feb652d3d6128e504456deaf254ab9ad3e7cebd4317d2037182
|
||||
F tool/sqldiff.c de59a4eecbc802db8ad053889c10e6f8b8427b6f349199ee79938c92c20860dd
|
||||
F tool/sqlite3_analyzer.c.in 14f02cb5ec3c264cd6107d1f1dad77092b1cf440fc196c30b69ae87b56a1a43b
|
||||
F tool/sqlite3_rsync.c f510a8b230e1c5b0f62842acd0e94ff15d2f77a00ae782f7d20f9e39919fa19b
|
||||
F tool/sqltclsh.c.in c103c6fc7d42bce611f9d4596774d60b7ef3d0b291a1f58c9e6184e458b89296
|
||||
@@ -2202,11 +2203,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
|
||||
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P 24df42104d5fd1cf974f2bf539fa7515808e21e68d64899c39f5fcf3bee49a48
|
||||
R 9a3da3dbb0fb1d6e93abd196b6a44c9b
|
||||
T *branch * disable-nested-exist-opt
|
||||
T *sym-disable-nested-exist-opt *
|
||||
P fc64113e8f9aee0161e682db7c244a7849f2db86551a557b276deb1785941476
|
||||
R 5c538d610a39b9c009307badcddf6e4d
|
||||
T *branch * push-pop-authorizer
|
||||
T *sym-push-pop-authorizer *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 5d80e9245f4b6dbd6635f95d676dfd7d
|
||||
U drh
|
||||
Z a0686f1cab4b032dd5f99fc3c9d92233
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
branch disable-nested-exist-opt
|
||||
tag disable-nested-exist-opt
|
||||
branch push-pop-authorizer
|
||||
tag push-pop-authorizer
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
64f0d9eb63a351de12bb9643f1f6390a89f6d95dc81c07f1dc409ee31bae6f83
|
||||
c3c3d9731535650ba1bcac8709ead27ce037736b31b7efef37422b502e10d332
|
||||
|
||||
+3
-2
@@ -2798,8 +2798,9 @@ void sqlite3AlterDropConstraint(
|
||||
if( !pTab ) return;
|
||||
|
||||
if( pCons ){
|
||||
sqlite3DequoteToken(pCons);
|
||||
zArg = sqlite3MPrintf(db, "%.*Q", pCons->n, pCons->z);
|
||||
char *z = sqlite3NameFromToken(db, pCons);
|
||||
zArg = sqlite3MPrintf(db, "%Q", z);
|
||||
sqlite3DbFree(db, z);
|
||||
}else{
|
||||
int iCol;
|
||||
if( alterFindCol(pParse, pTab, pCol, &iCol) ) return;
|
||||
|
||||
+11
-2
@@ -106,6 +106,16 @@ static void attachFunc(
|
||||
** from sqlite3_deserialize() to close database db->init.iDb and
|
||||
** reopen it as a MemDB */
|
||||
Btree *pNewBt = 0;
|
||||
|
||||
pNew = &db->aDb[db->init.iDb];
|
||||
assert( pNew->pBt!=0 );
|
||||
if( sqlite3BtreeTxnState(pNew->pBt)!=SQLITE_TXN_NONE
|
||||
|| sqlite3BtreeIsInBackup(pNew->pBt)
|
||||
){
|
||||
rc = SQLITE_BUSY;
|
||||
goto attach_error;
|
||||
}
|
||||
|
||||
pVfs = sqlite3_vfs_find("memdb");
|
||||
if( pVfs==0 ) return;
|
||||
rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB);
|
||||
@@ -115,8 +125,7 @@ static void attachFunc(
|
||||
/* Both the Btree and the new Schema were allocated successfully.
|
||||
** Close the old db and update the aDb[] slot with the new memdb
|
||||
** values. */
|
||||
pNew = &db->aDb[db->init.iDb];
|
||||
if( ALWAYS(pNew->pBt) ) sqlite3BtreeClose(pNew->pBt);
|
||||
sqlite3BtreeClose(pNew->pBt);
|
||||
pNew->pBt = pNewBt;
|
||||
pNew->pSchema = pNewSchema;
|
||||
}else{
|
||||
|
||||
+88
@@ -257,4 +257,92 @@ void sqlite3AuthContextPop(AuthContext *pContext){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** There is a single instance of this object for each nested
|
||||
** authorizer.
|
||||
*/
|
||||
typedef struct NestedAuth {
|
||||
int (*xPriorAuth)(void*,int,const char*,const char*,const char*,const char*);
|
||||
void *pPriorArg;
|
||||
int (*xThisAuth)(void*,int,const char*,const char*,const char*,const char*);
|
||||
void *pThisArg;
|
||||
int bOvrd;
|
||||
} NestedAuth;
|
||||
|
||||
/*
|
||||
** This is an authorizer implementation that invokes two separate
|
||||
** authorizers and returns the most restrictive answer.
|
||||
**
|
||||
** The pArg value is a pointer to an sqlite3_auth object that contains
|
||||
** the function pointer and augument for two other (real) authorizers.
|
||||
** This routine runs both of the nested authorizers. If either returns
|
||||
** SQLITE_DENY, this routine returns SQLITE_DENY. If neither returns
|
||||
** SQLITE_DENY but either of them return SQLITE_IGNORE, then this
|
||||
** routine returns SQLITE_IGNORE. Only if both authorizers return
|
||||
** SQLITE_OK does this routine return SQLITE_OK.
|
||||
*/
|
||||
static int sqlite3NestedAuthorizer(
|
||||
void *pArg, /* Must be an sqlite3_auth object */
|
||||
int eOp, /* Operation to be authorized */
|
||||
const char *z1, /* First argument */
|
||||
const char *z2, /* Second argument */
|
||||
const char *z3, /* Third argument */
|
||||
const char *z4 /* Fourth argument */
|
||||
){
|
||||
NestedAuth *p = (NestedAuth*)pArg;
|
||||
int rc1, rc2;
|
||||
if( p->xThisAuth==0 ){
|
||||
rc1 = SQLITE_OK;
|
||||
/* If the top-most authorizer is a NULL, then do no perform
|
||||
** any other authorizations. */
|
||||
}else{
|
||||
rc1 = p->xThisAuth(p->pThisArg,eOp,z1,z2,z3,z4);
|
||||
if( rc1==SQLITE_DENY || p->bOvrd ) return rc1;
|
||||
}
|
||||
assert( p->xPriorAuth!=0 );
|
||||
rc2 = p->xPriorAuth(p->pPriorArg,eOp,z1,z2,z3,z4);
|
||||
if( rc2 ) return rc2;
|
||||
return rc1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Push a new authorizer function xAuth with pArg. This new authorizer
|
||||
** runs first before any prior authorizer.
|
||||
*/
|
||||
int sqlite3_push_authorizer(
|
||||
sqlite3 *db,
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
|
||||
void *pArg,
|
||||
int bOvrd
|
||||
){
|
||||
NestedAuth *p;
|
||||
if( db==0 ) return SQLITE_MISUSE;
|
||||
if( db->xAuth==0 ){
|
||||
return sqlite3_set_authorizer(db, xAuth, pArg);
|
||||
}
|
||||
p = sqlite3DbMallocZero(db, sizeof(NestedAuth));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
p->xPriorAuth = db->xAuth;
|
||||
p->pPriorArg = db->pAuthArg;
|
||||
p->xThisAuth = xAuth;
|
||||
p->pThisArg = pArg;
|
||||
p->bOvrd = bOvrd;
|
||||
return sqlite3_set_authorizer(db, sqlite3NestedAuthorizer, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Pop the top-most authorizer off of the authorizer stack.
|
||||
*/
|
||||
int sqlite3_pop_authorizer(sqlite3 *db){
|
||||
if( db==0 ) return SQLITE_MISUSE;
|
||||
if( db->xAuth==sqlite3NestedAuthorizer ){
|
||||
NestedAuth *p = (NestedAuth*)db->pAuthArg;
|
||||
(void)sqlite3_set_authorizer(db, p->xPriorAuth, p->pPriorArg);
|
||||
sqlite3DbFree(db, p);
|
||||
}else{
|
||||
(void)sqlite3_set_authorizer(db, 0, 0);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
+66
-54
@@ -20,13 +20,13 @@
|
||||
*/
|
||||
struct sqlite3_backup {
|
||||
sqlite3* pDestDb; /* Destination database handle */
|
||||
Btree *pDest; /* Destination b-tree file */
|
||||
Db *pDest; /* Destination db file */
|
||||
u32 iDestSchema; /* Original schema cookie in destination */
|
||||
int bDestLocked; /* True once a write-transaction is open on pDest */
|
||||
|
||||
Pgno iNext; /* Page number of the next source page to copy */
|
||||
sqlite3* pSrcDb; /* Source database handle */
|
||||
Btree *pSrc; /* Source b-tree file */
|
||||
Db *pSrc; /* Source db file */
|
||||
|
||||
int rc; /* Backup process error code */
|
||||
|
||||
@@ -79,7 +79,7 @@ struct sqlite3_backup {
|
||||
** function. If an error occurs while doing so, return 0 and write an
|
||||
** error message to pErrorDb.
|
||||
*/
|
||||
static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
static Db *findDatabase(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
int i = sqlite3FindDbName(pDb, zDb);
|
||||
|
||||
if( i==1 ){
|
||||
@@ -102,7 +102,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pDb->aDb[i].pBt;
|
||||
return &pDb->aDb[i];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -110,9 +110,9 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
** of the source.
|
||||
*/
|
||||
static int setDestPgsz(sqlite3_backup *p){
|
||||
int rc;
|
||||
rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
|
||||
return rc;
|
||||
return sqlite3BtreeSetPageSize(p->pDest->pBt,
|
||||
sqlite3BtreeGetPageSize(p->pSrc->pBt), 0, 0
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -181,15 +181,15 @@ sqlite3_backup *sqlite3_backup_init(
|
||||
|
||||
/* If the allocation succeeded, populate the new object. */
|
||||
if( p ){
|
||||
p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb);
|
||||
p->pDest = findBtree(pDestDb, pDestDb, zDestDb);
|
||||
p->pSrc = findDatabase(pDestDb, pSrcDb, zSrcDb);
|
||||
p->pDest = findDatabase(pDestDb, pDestDb, zDestDb);
|
||||
p->pDestDb = pDestDb;
|
||||
p->pSrcDb = pSrcDb;
|
||||
p->iNext = 1;
|
||||
p->isAttached = 0;
|
||||
|
||||
if( 0==p->pSrc || 0==p->pDest
|
||||
|| checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
|
||||
|| checkReadTransaction(pDestDb, p->pDest->pBt)!=SQLITE_OK
|
||||
){
|
||||
/* One (or both) of the named databases did not exist or an OOM
|
||||
** error was hit. Or there is a transaction open on the destination
|
||||
@@ -201,7 +201,7 @@ sqlite3_backup *sqlite3_backup_init(
|
||||
}
|
||||
}
|
||||
if( p ){
|
||||
p->pSrc->nBackup++;
|
||||
p->pSrc->pBt->nBackup++;
|
||||
}
|
||||
|
||||
sqlite3_mutex_leave(pDestDb->mutex);
|
||||
@@ -229,18 +229,18 @@ static int backupOnePage(
|
||||
const u8 *zSrcData, /* Source database page data */
|
||||
int bUpdate /* True for an update, false otherwise */
|
||||
){
|
||||
Pager * const pDestPager = sqlite3BtreePager(p->pDest);
|
||||
const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc);
|
||||
int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
|
||||
Pager * const pDestPager = sqlite3BtreePager(p->pDest->pBt);
|
||||
const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc->pBt);
|
||||
int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest->pBt);
|
||||
const int nCopy = MIN(nSrcPgsz, nDestPgsz);
|
||||
const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
|
||||
int rc = SQLITE_OK;
|
||||
i64 iOff;
|
||||
|
||||
assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 );
|
||||
assert( sqlite3BtreeGetReserveNoMutex(p->pSrc->pBt)>=0 );
|
||||
assert( p->bDestLocked );
|
||||
assert( !isFatalError(p->rc) );
|
||||
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
|
||||
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt->pBt) );
|
||||
assert( zSrcData );
|
||||
assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 );
|
||||
|
||||
@@ -251,7 +251,7 @@ static int backupOnePage(
|
||||
for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){
|
||||
DbPage *pDestPg = 0;
|
||||
Pgno iDest = (Pgno)(iOff/nDestPgsz)+1;
|
||||
if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt) ) continue;
|
||||
if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt->pBt) ) continue;
|
||||
if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0))
|
||||
&& SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg))
|
||||
){
|
||||
@@ -269,7 +269,7 @@ static int backupOnePage(
|
||||
memcpy(zOut, zIn, nCopy);
|
||||
((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0;
|
||||
if( iOff==0 && bUpdate==0 ){
|
||||
sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc));
|
||||
sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc->pBt));
|
||||
}
|
||||
}
|
||||
sqlite3PagerUnref(pDestPg);
|
||||
@@ -301,8 +301,8 @@ static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){
|
||||
*/
|
||||
static void attachBackupObject(sqlite3_backup *p){
|
||||
sqlite3_backup **pp;
|
||||
assert( sqlite3BtreeHoldsMutex(p->pSrc) );
|
||||
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
|
||||
assert( sqlite3BtreeHoldsMutex(p->pSrc->pBt) );
|
||||
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc->pBt));
|
||||
p->pNext = *pp;
|
||||
*pp = p;
|
||||
p->isAttached = 1;
|
||||
@@ -316,20 +316,26 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
int destMode; /* Destination journal mode */
|
||||
int pgszSrc = 0; /* Source page size */
|
||||
int pgszDest = 0; /* Destination page size */
|
||||
Btree *pDest;
|
||||
Btree *pSrc;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( p==0 ) return SQLITE_MISUSE_BKPT;
|
||||
#endif
|
||||
assert( p->pDest );
|
||||
assert( p->pSrc );
|
||||
pDest = p->pDest->pBt;
|
||||
pSrc = p->pSrc->pBt;
|
||||
sqlite3_mutex_enter(p->pSrcDb->mutex);
|
||||
sqlite3BtreeEnter(p->pSrc);
|
||||
sqlite3BtreeEnter(pSrc);
|
||||
if( p->pDestDb ){
|
||||
sqlite3_mutex_enter(p->pDestDb->mutex);
|
||||
}
|
||||
|
||||
rc = p->rc;
|
||||
if( !isFatalError(rc) ){
|
||||
Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */
|
||||
Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */
|
||||
Pager * const pSrcPager = sqlite3BtreePager(pSrc); /* Source pager */
|
||||
Pager * const pDestPager = sqlite3BtreePager(pDest); /* Dest pager */
|
||||
int ii; /* Iterator variable */
|
||||
int nSrcPage = -1; /* Size of source db in pages */
|
||||
int bCloseTrans = 0; /* True if src db requires unlocking */
|
||||
@@ -337,7 +343,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
/* If the source pager is currently in a write-transaction, return
|
||||
** SQLITE_BUSY immediately.
|
||||
*/
|
||||
if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){
|
||||
if( p->pDestDb && pSrc->pBt->inTransaction==TRANS_WRITE ){
|
||||
rc = SQLITE_BUSY;
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
@@ -347,8 +353,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
** one now. If a transaction is opened here, then it will be closed
|
||||
** before this function exits.
|
||||
*/
|
||||
if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){
|
||||
rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0);
|
||||
if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(pSrc) ){
|
||||
rc = sqlite3BtreeBeginTrans(pSrc, 0, 0);
|
||||
bCloseTrans = 1;
|
||||
}
|
||||
|
||||
@@ -364,7 +370,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
|
||||
/* Lock the destination database, if it is not locked already. */
|
||||
if( SQLITE_OK==rc && p->bDestLocked==0
|
||||
&& SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2,
|
||||
&& SQLITE_OK==(rc = sqlite3BtreeBeginTrans(pDest, 2,
|
||||
(int*)&p->iDestSchema))
|
||||
){
|
||||
p->bDestLocked = 1;
|
||||
@@ -372,9 +378,9 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
|
||||
/* Do not allow backup if the destination database is in WAL mode
|
||||
** and the page sizes are different between source and destination */
|
||||
pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
|
||||
pgszDest = sqlite3BtreeGetPageSize(p->pDest);
|
||||
destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
|
||||
pgszSrc = sqlite3BtreeGetPageSize(pSrc);
|
||||
pgszDest = sqlite3BtreeGetPageSize(pDest);
|
||||
destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(pDest));
|
||||
if( SQLITE_OK==rc
|
||||
&& (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
|
||||
&& pgszSrc!=pgszDest
|
||||
@@ -385,11 +391,11 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
/* Now that there is a read-lock on the source database, query the
|
||||
** source pager for the number of pages in the database.
|
||||
*/
|
||||
nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc);
|
||||
nSrcPage = (int)sqlite3BtreeLastPage(pSrc);
|
||||
assert( nSrcPage>=0 );
|
||||
for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){
|
||||
const Pgno iSrcPg = p->iNext; /* Source page number */
|
||||
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
|
||||
if( iSrcPg!=PENDING_BYTE_PAGE(pSrc->pBt) ){
|
||||
DbPage *pSrcPg; /* Source page object */
|
||||
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg,PAGER_GET_READONLY);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -416,18 +422,18 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
*/
|
||||
if( rc==SQLITE_DONE ){
|
||||
if( nSrcPage==0 ){
|
||||
rc = sqlite3BtreeNewDb(p->pDest);
|
||||
rc = sqlite3BtreeNewDb(pDest);
|
||||
nSrcPage = 1;
|
||||
}
|
||||
if( rc==SQLITE_OK || rc==SQLITE_DONE ){
|
||||
rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
|
||||
rc = sqlite3BtreeUpdateMeta(pDest,1,p->iDestSchema+1);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
if( p->pDestDb ){
|
||||
sqlite3ResetAllSchemasOfConnection(p->pDestDb);
|
||||
}
|
||||
if( destMode==PAGER_JOURNALMODE_WAL ){
|
||||
rc = sqlite3BtreeSetVersion(p->pDest, 2);
|
||||
rc = sqlite3BtreeSetVersion(pDest, 2);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -444,12 +450,12 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
** journalled by PagerCommitPhaseOne() before they are destroyed
|
||||
** by the file truncation.
|
||||
*/
|
||||
assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
|
||||
assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
|
||||
assert( pgszSrc==sqlite3BtreeGetPageSize(pSrc) );
|
||||
assert( pgszDest==sqlite3BtreeGetPageSize(pDest) );
|
||||
if( pgszSrc<pgszDest ){
|
||||
int ratio = pgszDest/pgszSrc;
|
||||
nDestTruncate = (nSrcPage+ratio-1)/ratio;
|
||||
if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
|
||||
if( nDestTruncate==(int)PENDING_BYTE_PAGE(pDest->pBt) ){
|
||||
nDestTruncate--;
|
||||
}
|
||||
}else{
|
||||
@@ -477,7 +483,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
assert( pFile );
|
||||
assert( nDestTruncate==0
|
||||
|| (i64)nDestTruncate*(i64)pgszDest >= iSize || (
|
||||
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
|
||||
nDestTruncate==(int)(PENDING_BYTE_PAGE(pDest->pBt)-1)
|
||||
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
|
||||
));
|
||||
|
||||
@@ -489,7 +495,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
** journal file. */
|
||||
sqlite3PagerPagecount(pDestPager, &nDstPage);
|
||||
for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
|
||||
if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
|
||||
if( iPg!=PENDING_BYTE_PAGE(pDest->pBt) ){
|
||||
DbPage *pPg;
|
||||
rc = sqlite3PagerGet(pDestPager, iPg, &pPg, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -533,7 +539,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
|
||||
/* Finish committing the transaction to the destination database. */
|
||||
if( SQLITE_OK==rc
|
||||
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
|
||||
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(pDest, 0))
|
||||
){
|
||||
rc = SQLITE_DONE;
|
||||
}
|
||||
@@ -547,8 +553,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
*/
|
||||
if( bCloseTrans ){
|
||||
TESTONLY( int rc2 );
|
||||
TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0);
|
||||
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
|
||||
TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(pSrc, 0);
|
||||
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(pSrc, 0);
|
||||
assert( rc2==SQLITE_OK );
|
||||
}
|
||||
|
||||
@@ -560,7 +566,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
if( p->pDestDb ){
|
||||
sqlite3_mutex_leave(p->pDestDb->mutex);
|
||||
}
|
||||
sqlite3BtreeLeave(p->pSrc);
|
||||
sqlite3BtreeLeave(pSrc);
|
||||
sqlite3_mutex_leave(p->pSrcDb->mutex);
|
||||
return rc;
|
||||
}
|
||||
@@ -577,17 +583,17 @@ int sqlite3_backup_finish(sqlite3_backup *p){
|
||||
if( p==0 ) return SQLITE_OK;
|
||||
pSrcDb = p->pSrcDb;
|
||||
sqlite3_mutex_enter(pSrcDb->mutex);
|
||||
sqlite3BtreeEnter(p->pSrc);
|
||||
sqlite3BtreeEnter(p->pSrc->pBt);
|
||||
if( p->pDestDb ){
|
||||
sqlite3_mutex_enter(p->pDestDb->mutex);
|
||||
}
|
||||
|
||||
/* Detach this backup from the source pager. */
|
||||
if( p->pDestDb ){
|
||||
p->pSrc->nBackup--;
|
||||
p->pSrc->pBt->nBackup--;
|
||||
}
|
||||
if( p->isAttached ){
|
||||
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
|
||||
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc->pBt));
|
||||
assert( pp!=0 );
|
||||
while( *pp!=p ){
|
||||
pp = &(*pp)->pNext;
|
||||
@@ -597,7 +603,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){
|
||||
}
|
||||
|
||||
/* If a transaction is still open on the Btree, roll it back. */
|
||||
sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0);
|
||||
sqlite3BtreeRollback(p->pDest->pBt, SQLITE_OK, 0);
|
||||
|
||||
/* Set the error code of the destination database handle. */
|
||||
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
|
||||
@@ -607,7 +613,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){
|
||||
/* Exit the mutexes and free the backup context structure. */
|
||||
sqlite3LeaveMutexAndCloseZombie(p->pDestDb);
|
||||
}
|
||||
sqlite3BtreeLeave(p->pSrc);
|
||||
sqlite3BtreeLeave(p->pSrc->pBt);
|
||||
if( p->pDestDb ){
|
||||
/* EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
|
||||
** call to sqlite3_backup_init() and is destroyed by a call to
|
||||
@@ -665,7 +671,7 @@ static SQLITE_NOINLINE void backupUpdate(
|
||||
){
|
||||
assert( p!=0 );
|
||||
do{
|
||||
assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) );
|
||||
assert( sqlite3_mutex_held(p->pSrc->pBt->pBt->mutex) );
|
||||
if( !isFatalError(p->rc) && iPage<p->iNext ){
|
||||
/* The backup process p has already copied page iPage. But now it
|
||||
** has been modified by a transaction on the source pager. Copy
|
||||
@@ -701,7 +707,7 @@ void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){
|
||||
void sqlite3BackupRestart(sqlite3_backup *pBackup){
|
||||
sqlite3_backup *p; /* Iterator variable */
|
||||
for(p=pBackup; p; p=p->pNext){
|
||||
assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) );
|
||||
assert( sqlite3_mutex_held(p->pSrc->pBt->pBt->mutex) );
|
||||
p->iNext = 1;
|
||||
}
|
||||
}
|
||||
@@ -719,6 +725,8 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
||||
int rc;
|
||||
sqlite3_file *pFd; /* File descriptor for database pTo */
|
||||
sqlite3_backup b;
|
||||
Db dbDest;
|
||||
Db dbSrc;
|
||||
sqlite3BtreeEnter(pTo);
|
||||
sqlite3BtreeEnter(pFrom);
|
||||
|
||||
@@ -737,9 +745,13 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
||||
** from this function, not directly by the user.
|
||||
*/
|
||||
memset(&b, 0, sizeof(b));
|
||||
memset(&dbDest, 0, sizeof(dbDest));
|
||||
memset(&dbSrc, 0, sizeof(dbSrc));
|
||||
dbDest.pBt = pTo;
|
||||
dbSrc.pBt = pFrom;
|
||||
b.pSrcDb = pFrom->db;
|
||||
b.pSrc = pFrom;
|
||||
b.pDest = pTo;
|
||||
b.pSrc = &dbSrc;
|
||||
b.pDest = &dbDest;
|
||||
b.iNext = 1;
|
||||
|
||||
/* 0x7FFFFFFF is the hard limit for the number of pages in a database
|
||||
@@ -755,7 +767,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
||||
if( rc==SQLITE_OK ){
|
||||
pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
|
||||
}else{
|
||||
sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
|
||||
sqlite3PagerClearCache(sqlite3BtreePager(pTo));
|
||||
}
|
||||
|
||||
assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE );
|
||||
|
||||
+6
-3
@@ -915,6 +915,7 @@ void sqlite3GenerateRowIndexDelete(
|
||||
v = pParse->pVdbe;
|
||||
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
int p3 = 0;
|
||||
assert( iIdxCur+i!=iDataCur || pPk==pIdx );
|
||||
if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
|
||||
if( pIdx==pPk ) continue;
|
||||
@@ -922,10 +923,12 @@ void sqlite3GenerateRowIndexDelete(
|
||||
VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
|
||||
&iPartIdxLabel, pPrior, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn
|
||||
);
|
||||
if( pIdx->bHasExpr && aRegIdx ){
|
||||
p3 = aRegIdx[i];
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, p3);
|
||||
sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX);
|
||||
sqlite3VdbeChangeP5(v, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
||||
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
||||
pPrior = pIdx;
|
||||
}
|
||||
|
||||
+4
-1
@@ -2809,7 +2809,10 @@ void sqlite3CompleteInsertion(
|
||||
|| pIdx->pNext==0
|
||||
|| pIdx->pNext->onError==OE_Replace );
|
||||
if( aRegIdx[i]==0 ) continue;
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
if( pIdx->pPartIdxWhere || (update_flags && pIdx->bHasExpr) ){
|
||||
/* If this is a partial index, or an UPDATE of an index on an
|
||||
** expression, then the record register may be set to NULL to indicate
|
||||
** that no record should be inserted into this index. */
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
@@ -1302,6 +1302,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
|
||||
if( p->xDestructor ) p->xDestructor(p->pData);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
while( db->xAuth ){
|
||||
sqlite3_pop_authorizer(db);
|
||||
}
|
||||
|
||||
/* Convert the connection into a zombie and then close it.
|
||||
*/
|
||||
|
||||
+3
-4
@@ -876,10 +876,10 @@ int sqlite3_deserialize(
|
||||
if( rc ) goto end_deserialize;
|
||||
db->init.iDb = (u8)iDb;
|
||||
db->init.reopenMemdb = 1;
|
||||
rc = sqlite3_step(pStmt);
|
||||
sqlite3_step(pStmt);
|
||||
db->init.reopenMemdb = 0;
|
||||
if( rc!=SQLITE_DONE ){
|
||||
rc = SQLITE_ERROR;
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto end_deserialize;
|
||||
}
|
||||
p = memdbFromDbSchema(db, zSchema);
|
||||
@@ -900,7 +900,6 @@ int sqlite3_deserialize(
|
||||
}
|
||||
|
||||
end_deserialize:
|
||||
sqlite3_finalize(pStmt);
|
||||
if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){
|
||||
sqlite3_free(pData);
|
||||
}
|
||||
|
||||
+35
-16
@@ -35,8 +35,15 @@
|
||||
# define SQLITE_MUTEX_NREF 0
|
||||
#endif
|
||||
|
||||
#if GCC_VERSION>0
|
||||
# define ALIGN128 __attribute__((aligned(128)))
|
||||
#else
|
||||
# define ALIGN128
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Each recursive mutex is an instance of the following structure.
|
||||
** Each SQLite mutex is an instance of the following structure.
|
||||
**
|
||||
*/
|
||||
struct sqlite3_mutex {
|
||||
pthread_mutex_t mutex; /* Mutex controlling the lock */
|
||||
@@ -151,19 +158,31 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
|
||||
** the same type number.
|
||||
*/
|
||||
static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
static sqlite3_mutex staticMutexes[] = {
|
||||
SQLITE3_MUTEX_INITIALIZER(2),
|
||||
SQLITE3_MUTEX_INITIALIZER(3),
|
||||
SQLITE3_MUTEX_INITIALIZER(4),
|
||||
SQLITE3_MUTEX_INITIALIZER(5),
|
||||
SQLITE3_MUTEX_INITIALIZER(6),
|
||||
SQLITE3_MUTEX_INITIALIZER(7),
|
||||
SQLITE3_MUTEX_INITIALIZER(8),
|
||||
SQLITE3_MUTEX_INITIALIZER(9),
|
||||
SQLITE3_MUTEX_INITIALIZER(10),
|
||||
SQLITE3_MUTEX_INITIALIZER(11),
|
||||
SQLITE3_MUTEX_INITIALIZER(12),
|
||||
SQLITE3_MUTEX_INITIALIZER(13)
|
||||
/* Static mutexes - those with IDs of 2 or more...
|
||||
**
|
||||
** The ALIGN128 macro attempts to force 128-byte alignment on mutexes,
|
||||
** so that adjacent mutex objects are always on different cache lines
|
||||
** in the CPU. This is CPU-dependent, of course, but 128-byte alignment
|
||||
** seems to work well for all contemporary processors. Experiments show
|
||||
** that 64 works just as well most of the time, but the internet says
|
||||
** that 128-byte alignment works better.
|
||||
*/
|
||||
static ALIGN128 union staticMutex {
|
||||
sqlite3_mutex m;
|
||||
char aSpacer[128];
|
||||
} aMutex[] = {
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(2) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(3) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(4) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(5) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(6) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(7) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(8) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(9) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(10) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(11) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(12) },
|
||||
{ .m = SQLITE3_MUTEX_INITIALIZER(13) },
|
||||
};
|
||||
sqlite3_mutex *p;
|
||||
switch( iType ){
|
||||
@@ -200,12 +219,12 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
}
|
||||
default: {
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){
|
||||
if( iType-2<0 || iType-2>=ArraySize(aMutex) ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
p = &staticMutexes[iType-2];
|
||||
p = &aMutex[iType-2].m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+87
-94
@@ -31,11 +31,29 @@
|
||||
*/
|
||||
#ifdef SQLITE_MUTEX_W32
|
||||
|
||||
#if MSVC_VERSION>0
|
||||
# define ALIGN128 __declspec(align(128))
|
||||
#else
|
||||
# define ALIGN128
|
||||
#endif
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4324)
|
||||
/*
|
||||
** Each recursive mutex is an instance of the following structure.
|
||||
** Each SQLite mutex is an instance of the following structure.
|
||||
**
|
||||
** The ALIGN128 macro attempts to force 128-byte alignment on mutexes,
|
||||
** so that adjacent mutex objects are always on different cache lines
|
||||
** in the CPU. This is CPU-dependent, of course, but 128-byte alignment
|
||||
** seems to work well for all contemporary processors. Experiments show
|
||||
** that 64 works just as well most of the time, but the internet says
|
||||
** that 128-byte alignment works better.
|
||||
*/
|
||||
struct sqlite3_mutex {
|
||||
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
|
||||
struct sqlite3_mutex {
|
||||
union {
|
||||
CRITICAL_SECTION cs; /* The CRITICAL_SECTION mutex. id==1 */
|
||||
SRWLOCK srwl; /* The Slim reader/writer lock. id!=1 */
|
||||
} u;
|
||||
int id; /* Mutex type */
|
||||
#ifdef SQLITE_DEBUG
|
||||
volatile int nRef; /* Number of entrances */
|
||||
@@ -43,20 +61,7 @@ struct sqlite3_mutex {
|
||||
volatile LONG trace; /* True to trace changes */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** These are the initializer values used when declaring a "static" mutex
|
||||
** on Win32. It should be noted that all mutexes require initialization
|
||||
** on the Win32 platform.
|
||||
*/
|
||||
#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \
|
||||
0L, (DWORD)0, 0 }
|
||||
#else
|
||||
#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id }
|
||||
#endif
|
||||
#pragma warning(pop)
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
@@ -67,13 +72,8 @@ static int winMutexHeld(sqlite3_mutex *p){
|
||||
return p->nRef!=0 && p->owner==GetCurrentThreadId();
|
||||
}
|
||||
|
||||
static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
|
||||
return p->nRef==0 || p->owner!=tid;
|
||||
}
|
||||
|
||||
static int winMutexNotheld(sqlite3_mutex *p){
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
return winMutexNotheld2(p, tid);
|
||||
return p->nRef==0 || p->owner!=GetCurrentThreadId();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -95,41 +95,42 @@ void sqlite3MemoryBarrier(void){
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
** Static mutexes.
|
||||
**
|
||||
** The ALIGN128 macro on the static mutex array forces 128-byte alignment
|
||||
** on the mutexes so that adjacent mutex objects are always on different
|
||||
** cache lines in the CPU. This is CPU-dependent, of course, but 128-byte
|
||||
** alignment seems to work well for all contemporary processors.
|
||||
** Experiments show that 64 works just as well most of the time, but
|
||||
** the internet says that 128-byte alignment works better.
|
||||
*/
|
||||
static sqlite3_mutex winMutex_staticMutexes[] = {
|
||||
SQLITE3_MUTEX_INITIALIZER(2),
|
||||
SQLITE3_MUTEX_INITIALIZER(3),
|
||||
SQLITE3_MUTEX_INITIALIZER(4),
|
||||
SQLITE3_MUTEX_INITIALIZER(5),
|
||||
SQLITE3_MUTEX_INITIALIZER(6),
|
||||
SQLITE3_MUTEX_INITIALIZER(7),
|
||||
SQLITE3_MUTEX_INITIALIZER(8),
|
||||
SQLITE3_MUTEX_INITIALIZER(9),
|
||||
SQLITE3_MUTEX_INITIALIZER(10),
|
||||
SQLITE3_MUTEX_INITIALIZER(11),
|
||||
SQLITE3_MUTEX_INITIALIZER(12),
|
||||
SQLITE3_MUTEX_INITIALIZER(13)
|
||||
};
|
||||
|
||||
static ALIGN128 union staticMutexes {
|
||||
sqlite3_mutex m;
|
||||
char spacer[128];
|
||||
} aWindowsMutex[12];
|
||||
static int winMutex_isInit = 0;
|
||||
static int winMutex_isNt = -1; /* <0 means "need to query" */
|
||||
|
||||
/* As the winMutexInit() and winMutexEnd() functions are called as part
|
||||
** of the sqlite3_initialize() and sqlite3_shutdown() processing, the
|
||||
** "interlocked" magic used here is probably not strictly necessary.
|
||||
*/
|
||||
static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;
|
||||
static LONG volatile winMutex_lock = 0;
|
||||
|
||||
int sqlite3_win32_is_nt(void); /* os_win.c */
|
||||
void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
|
||||
|
||||
static int winMutexInit(void){
|
||||
/* The first to increment to 1 does actual initialization */
|
||||
if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
|
||||
int i;
|
||||
for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
|
||||
InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);
|
||||
for(i=0; i<ArraySize(aWindowsMutex); i++){
|
||||
sqlite3_mutex *p = &aWindowsMutex[i].m;
|
||||
p->id = i+2;
|
||||
InitializeSRWLock(&p->u.srwl);
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->nRef = 0;
|
||||
p->owner = 0;
|
||||
p->trace = 0;
|
||||
#endif
|
||||
}
|
||||
winMutex_isInit = 1;
|
||||
}else{
|
||||
@@ -147,10 +148,6 @@ static int winMutexEnd(void){
|
||||
** (which should be the last to shutdown.) */
|
||||
if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){
|
||||
if( winMutex_isInit==1 ){
|
||||
int i;
|
||||
for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
|
||||
DeleteCriticalSection(&winMutex_staticMutexes[i].mutex);
|
||||
}
|
||||
winMutex_isInit = 0;
|
||||
}
|
||||
}
|
||||
@@ -219,18 +216,22 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
p->trace = 1;
|
||||
#endif
|
||||
#endif
|
||||
InitializeCriticalSection(&p->mutex);
|
||||
if( iType==SQLITE_MUTEX_RECURSIVE ){
|
||||
InitializeCriticalSection(&p->u.cs);
|
||||
}else{
|
||||
InitializeSRWLock(&p->u.srwl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){
|
||||
if( iType-2<0 || iType-2>=ArraySize(aWindowsMutex) ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
p = &winMutex_staticMutexes[iType-2];
|
||||
p = &aWindowsMutex[iType-2].m;
|
||||
#ifdef SQLITE_DEBUG
|
||||
#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
|
||||
InterlockedCompareExchange(&p->trace, 1, 0);
|
||||
@@ -252,8 +253,10 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
static void winMutexFree(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->nRef==0 && p->owner==0 );
|
||||
if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){
|
||||
DeleteCriticalSection(&p->mutex);
|
||||
if( p->id==SQLITE_MUTEX_FAST ){
|
||||
sqlite3_free(p);
|
||||
}else if( p->id==SQLITE_MUTEX_RECURSIVE ){
|
||||
DeleteCriticalSection(&p->u.cs);
|
||||
sqlite3_free(p);
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
@@ -274,67 +277,56 @@ static void winMutexFree(sqlite3_mutex *p){
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
static void winMutexEnter(sqlite3_mutex *p){
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
#endif
|
||||
assert( p );
|
||||
#ifdef SQLITE_DEBUG
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
|
||||
#else
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
|
||||
#endif
|
||||
assert( winMutex_isInit==1 );
|
||||
EnterCriticalSection(&p->mutex);
|
||||
if( p->id==SQLITE_MUTEX_RECURSIVE ){
|
||||
EnterCriticalSection(&p->u.cs);
|
||||
}else{
|
||||
AcquireSRWLockExclusive(&p->u.srwl);
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
assert( p->nRef>0 || p->owner==0 );
|
||||
p->owner = tid;
|
||||
p->owner = GetCurrentThreadId();
|
||||
p->nRef++;
|
||||
if( p->trace ){
|
||||
OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
|
||||
tid, p->id, p, p->trace, p->nRef));
|
||||
GetCurrentThreadId(), p->id, p, p->trace, p->nRef));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int winMutexTry(sqlite3_mutex *p){
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
#endif
|
||||
int rc = SQLITE_BUSY;
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
|
||||
/*
|
||||
** The sqlite3_mutex_try() routine is very rarely used, and when it
|
||||
** is used it is merely an optimization. So it is OK for it to always
|
||||
** The sqlite3_mutex_try() routine is seldom used, and when it is
|
||||
** used it is merely an optimization. So it is OK for it to always
|
||||
** fail.
|
||||
**
|
||||
** The TryEnterCriticalSection() interface is only available on WinNT.
|
||||
** And some windows compilers complain if you try to use it without
|
||||
** first doing some #defines that prevent SQLite from building on Win98.
|
||||
** For that reason, we will omit this optimization for now. See
|
||||
** ticket #2685.
|
||||
*/
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400
|
||||
assert( winMutex_isInit==1 );
|
||||
assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );
|
||||
if( winMutex_isNt<0 ){
|
||||
winMutex_isNt = sqlite3_win32_is_nt();
|
||||
if( p->id==SQLITE_MUTEX_RECURSIVE ){
|
||||
rc = TryEnterCriticalSection(&p->u.cs);
|
||||
}else{
|
||||
rc = TryAcquireSRWLockExclusive(&p->u.srwl);
|
||||
}
|
||||
assert( winMutex_isNt==0 || winMutex_isNt==1 );
|
||||
if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){
|
||||
if( rc ){
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->owner = tid;
|
||||
p->owner = GetCurrentThreadId();
|
||||
p->nRef++;
|
||||
#endif
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(p);
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
|
||||
tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
|
||||
OSTRACE((
|
||||
"TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
|
||||
GetCurrentThreadId(), p->id, p, p->trace, p->owner, p->nRef,
|
||||
sqlite3ErrName(rc)));
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
@@ -347,23 +339,24 @@ static int winMutexTry(sqlite3_mutex *p){
|
||||
** is not currently allocated. SQLite will never do either.
|
||||
*/
|
||||
static void winMutexLeave(sqlite3_mutex *p){
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
#endif
|
||||
assert( p );
|
||||
#ifdef SQLITE_DEBUG
|
||||
assert( p->nRef>0 );
|
||||
assert( p->owner==tid );
|
||||
assert( p->owner==GetCurrentThreadId() );
|
||||
p->nRef--;
|
||||
if( p->nRef==0 ) p->owner = 0;
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
#endif
|
||||
assert( winMutex_isInit==1 );
|
||||
LeaveCriticalSection(&p->mutex);
|
||||
if( p->id==SQLITE_MUTEX_RECURSIVE ){
|
||||
LeaveCriticalSection(&p->u.cs);
|
||||
}else{
|
||||
ReleaseSRWLockExclusive(&p->u.srwl);
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
|
||||
tid, p->id, p, p->trace, p->nRef));
|
||||
GetCurrentThreadId(), p->id, p, p->trace, p->nRef));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+317
-1553
File diff suppressed because it is too large
Load Diff
+1
-43
@@ -27,53 +27,11 @@
|
||||
# include <errno.h> /* amalgamator: dontcache */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with Windows NT.
|
||||
**
|
||||
** We ought to be able to determine if we are compiling for Windows 9x or
|
||||
** Windows NT using the _WIN32_WINNT macro as follows:
|
||||
**
|
||||
** #if defined(_WIN32_WINNT)
|
||||
** # define SQLITE_OS_WINNT 1
|
||||
** #else
|
||||
** # define SQLITE_OS_WINNT 0
|
||||
** #endif
|
||||
**
|
||||
** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as
|
||||
** it ought to, so the above test does not work. We'll just assume that
|
||||
** everything is Windows NT unless the programmer explicitly says otherwise
|
||||
** by setting SQLITE_OS_WINNT to 0.
|
||||
*/
|
||||
#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT)
|
||||
# define SQLITE_OS_WINNT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with Windows CE - which has a much reduced
|
||||
** API.
|
||||
*/
|
||||
#if defined(_WIN32_WCE)
|
||||
# define SQLITE_OS_WINCE 1
|
||||
#else
|
||||
# define SQLITE_OS_WINCE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For WinCE, some API function parameters do not appear to be declared as
|
||||
** volatile.
|
||||
*/
|
||||
#if SQLITE_OS_WINCE
|
||||
# define SQLITE_WIN32_VOLATILE
|
||||
#else
|
||||
# define SQLITE_WIN32_VOLATILE volatile
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For some Windows sub-platforms, the _beginthreadex() / _endthreadex()
|
||||
** functions are not available (e.g. those not using MSVC, Cygwin, etc).
|
||||
*/
|
||||
#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && \
|
||||
SQLITE_THREADSAFE>0 && !defined(__CYGWIN__)
|
||||
#if SQLITE_OS_WIN && SQLITE_THREADSAFE>0 && !defined(__CYGWIN__)
|
||||
# define SQLITE_OS_WIN_THREADS 1
|
||||
#else
|
||||
# define SQLITE_OS_WIN_THREADS 0
|
||||
|
||||
@@ -1476,6 +1476,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
A = sqlite3PExpr(pParse, TK_BETWEEN, A, 0);
|
||||
if( A ){
|
||||
A->x.pList = pList;
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A);
|
||||
}else{
|
||||
sqlite3ExprListDelete(pParse->db, pList);
|
||||
}
|
||||
|
||||
+423
-96
@@ -356,6 +356,13 @@ typedef struct Mode {
|
||||
#define MFLG_CRLF 0x02 /* Use CR/LF output line endings */
|
||||
#define MFLG_HDR 0x04 /* .header used to change headers on/off */
|
||||
|
||||
/* A file that needs to be deleted, but only after a delay.
|
||||
*/
|
||||
typedef struct Unlink {
|
||||
sqlite3_int64 tm; /* Unlink after this time */
|
||||
char *zFN; /* Name of file. Space from sqlite3_malloc() */
|
||||
} Unlink;
|
||||
|
||||
/*
|
||||
** State information about the database connection is contained in an
|
||||
** instance of the following structure.
|
||||
@@ -401,7 +408,10 @@ struct ShellState {
|
||||
FILE *pLog; /* Write log output here */
|
||||
char *azPrompt[2]; /* Main and continuation prompt strings */
|
||||
Mode mode; /* Current display mode */
|
||||
Mode modePrior; /* Backup */
|
||||
Mode *aModeStack; /* Backups */
|
||||
unsigned nModeStack; /* Number of entries in aModeStack[] */
|
||||
unsigned nUnlink; /* Number of entries in aDelayUnlink[] */
|
||||
Unlink *aUnlink; /* Temp files to unlink after a delay */
|
||||
struct SavedMode { /* Ability to define custom mode configurations */
|
||||
char *zTag; /* Name of this saved mode */
|
||||
Mode mode; /* The saved mode */
|
||||
@@ -596,7 +606,7 @@ static const ModeInfo aModeInfo[] = {
|
||||
** text encoding |/ | show | \
|
||||
** v-------------------' | hdrs? | The QRF style
|
||||
** 0: n/a blob | v-----'
|
||||
** 1: plain v_---------' 0: n/a
|
||||
** 1: plain v----------' 0: n/a
|
||||
** 2: sql 0: auto 1: no
|
||||
** 3: csv 1: as-text 2: yes
|
||||
** 4: html 2: sql
|
||||
@@ -605,18 +615,6 @@ static const ModeInfo aModeInfo[] = {
|
||||
** 5: json
|
||||
** 6: size
|
||||
******************************************************************/
|
||||
/*
|
||||
** These are the column/row/line separators used by the various
|
||||
** import/export modes.
|
||||
*/
|
||||
#define SEP_Column "|"
|
||||
#define SEP_Row "\n"
|
||||
#define SEP_Tab "\t"
|
||||
#define SEP_Space " "
|
||||
#define SEP_Comma ","
|
||||
#define SEP_CrLf "\r\n"
|
||||
#define SEP_Unit "\x1F"
|
||||
#define SEP_Record "\x1E"
|
||||
|
||||
/*
|
||||
** Default values for the various QRF limits
|
||||
@@ -665,6 +663,13 @@ static int stdout_tty_width = -1;
|
||||
*/
|
||||
static sqlite3 *globalDb = 0;
|
||||
|
||||
/*
|
||||
** This is a global pointer to the main ShellState variable. This
|
||||
** exists so that the atexit() callback can access the ShellState
|
||||
** object to do some cleanup.
|
||||
*/
|
||||
static struct ShellState *globalShellState = 0;
|
||||
|
||||
/*
|
||||
** True if an interrupt (Control-C) has been received.
|
||||
*/
|
||||
@@ -689,6 +694,7 @@ static FILE *iotrace = 0;
|
||||
** Works like.
|
||||
** --------------
|
||||
** cli_printf(FILE*, const char*, ...); fprintf()
|
||||
** cli_write(FILE*, const char*, int); write()
|
||||
** cli_puts(const char*, FILE*); fputs()
|
||||
** cli_vprintf(FILE*, const char*, va_list); vfprintf()
|
||||
**
|
||||
@@ -715,6 +721,18 @@ static int cli_printf(FILE *out, const char *zFormat, ...){
|
||||
va_end(ap);
|
||||
return rc;
|
||||
}
|
||||
static int cli_write(FILE *out, const char *zData, int nData){
|
||||
if( cli_output_capture && (out==stdout || out==stderr) ){
|
||||
sqlite3_str_append(cli_output_capture, zData, nData);
|
||||
#ifdef _WIN32
|
||||
}else if( out==stdout || out==stderr ){
|
||||
nData = sqlite3_fprintf(out, "%.*s", nData, zData);
|
||||
#endif
|
||||
}else{
|
||||
nData = (int)fwrite(zData, 1, nData, out);
|
||||
}
|
||||
return nData;
|
||||
}
|
||||
static int cli_puts(const char *zText, FILE *out){
|
||||
if( cli_output_capture && (out==stdout || out==stderr) ){
|
||||
sqlite3_str_appendall(cli_output_capture, zText);
|
||||
@@ -909,15 +927,77 @@ static char *local_getline(char *zLine, FILE *in){
|
||||
}
|
||||
|
||||
/*
|
||||
** The default prompts.
|
||||
** The SQLITE_PS_APPDEF macro should be set to the name of a function
|
||||
** that accepts a single "int" argument and returns a "const char *"
|
||||
** that is guaranteed to be non-NULL. The value returned depends on the
|
||||
** argument:
|
||||
**
|
||||
** 1 Default main prompt.
|
||||
** 2 Default continuation prompt.
|
||||
** 3 Environment variable to override main prompt ("SQLITE_PS1")
|
||||
** 4 Environment variable to override continuatio ("SQLITE_PS2")
|
||||
** 'A' The name of the application. (Nominally "SQLite")
|
||||
** 'V' Version number including patch. (ex: "3.54.1")
|
||||
** 'v' Version number without patch. (ex: "3.54")
|
||||
**
|
||||
*/
|
||||
#ifndef SQLITE_PS1
|
||||
# define SQLITE_PS1 "SQLite /f> "
|
||||
#ifdef SQLITE_PS_APPDEF
|
||||
extern const char *SQLITE_PS_APPDEF(int);
|
||||
#else
|
||||
# define SQLITE_PS_APPDEF shellPromptAppDef
|
||||
static const char *shellPromptAppDef(int c){
|
||||
switch( c ){
|
||||
/* The default main prompt string */
|
||||
case 1:
|
||||
#if defined(SQLITE_PS1)
|
||||
return SQLITE_PS1;
|
||||
#elif defined(SQLITE_PS_NOANSI)
|
||||
return "/A-/v /~> ";
|
||||
#else
|
||||
return "/e[1;32m/A-/v /e[1;/x33/:36/;m/m/e[3m/;/f/;/e[0m-> ";
|
||||
#endif
|
||||
#ifndef SQLITE_PS2
|
||||
# define SQLITE_PS2 "/B.../H> "
|
||||
|
||||
/* The default continuation prompt string */
|
||||
case 2:
|
||||
#if defined(SQLITE_PS2)
|
||||
return SQLITE_PS2;
|
||||
#elif defined(SQLITE_PS_NOANSI)
|
||||
return "/B/C> ";
|
||||
#else
|
||||
return "/B/e[1;/x33/:36/;m/C/e[0m-> ";
|
||||
#endif
|
||||
|
||||
/* Name of environment variables that override the prompt strings
|
||||
** of cases 1 and 2 */
|
||||
case 3: return "SQLITE_PS1";
|
||||
case 4: return "SQLITE_PS2";
|
||||
|
||||
/* Name of the application */
|
||||
case 'A': return "SQLite";
|
||||
|
||||
/* Full version number of the application, including patch level */
|
||||
case 'V': return sqlite3_libversion();
|
||||
|
||||
/* Version number without the patch level */
|
||||
case 'v': {
|
||||
static char zRel[16];
|
||||
const char *zF = sqlite3_libversion();
|
||||
const char *zD = strrchr(zF,'.');
|
||||
if( zD && (size_t)(zD-zF)<sizeof(zRel)-1 ){
|
||||
memcpy(zRel,zF,(size_t)(zD-zF));
|
||||
zRel[(size_t)(zD-zF)] = 0;
|
||||
return zRel;
|
||||
}else{
|
||||
return zF;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
#endif /* !defined(SQLITE_PS_APPDEF) */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Return the raw (unexpanded) prompt string. This will be the
|
||||
** first of the following that exist:
|
||||
@@ -936,21 +1016,17 @@ static const char *prompt_string(ShellState *p, int bContinue){
|
||||
return p->azPrompt[bContinue];
|
||||
}
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
zPS = getenv(bContinue ? "SQLITE_PS2" : "SQLITE_PS1");
|
||||
zPS = getenv(SQLITE_PS_APPDEF(3+bContinue));
|
||||
if( zPS ) return zPS;
|
||||
#endif
|
||||
if( bContinue ){
|
||||
return SQLITE_PS2;
|
||||
}else{
|
||||
return SQLITE_PS1;
|
||||
}
|
||||
return SQLITE_PS_APPDEF(1+bContinue);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the name of the open database file, to be used for prompt
|
||||
** expansion purposes.
|
||||
*/
|
||||
static const char *prompt_filename(ShellState *p){
|
||||
static const char *prompt_filename(ShellState *p, const char *zMemoryName){
|
||||
sqlite3_filename pFN;
|
||||
const char *zFN = 0;
|
||||
if( p->pAuxDb->mFlgs & 0x01 ){
|
||||
@@ -961,12 +1037,51 @@ static const char *prompt_filename(ShellState *p){
|
||||
if( zFN==0 || zFN[0]==0 ){
|
||||
zFN = p->pAuxDb->zDbFilename;
|
||||
if( zFN==0 || zFN[0]==0 || cli_strcmp(zFN,":memory:")==0 ){
|
||||
zFN = "in-memory";
|
||||
zFN = zMemoryName;
|
||||
}
|
||||
}
|
||||
return zFN;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the name of the computer on which we are running.
|
||||
*/
|
||||
static const char *prompt_hostname(int bFull){
|
||||
#ifdef _WIN32
|
||||
const char *z = getenv("COMPUTERNAME");
|
||||
if( z==0 || z[0]==0 ) z = "?";
|
||||
return z;
|
||||
#else
|
||||
static char zHost[256];
|
||||
if( gethostname(zHost, sizeof(zHost)) ){
|
||||
zHost[0] = '?';
|
||||
zHost[1] = 0;
|
||||
}
|
||||
if( !bFull ){
|
||||
char *p = strchr(zHost,'.');
|
||||
if( p ) p[0] = 0;
|
||||
}
|
||||
return zHost;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the username. This is taken from an environment variable
|
||||
** and can thus be forged. Do not depend on it.
|
||||
*/
|
||||
static const char *prompt_user(void){
|
||||
const char *z;
|
||||
#ifdef _WIN32
|
||||
z = getenv("USERNAME");
|
||||
if( z==0 || z[0]==0 ) z = "?";
|
||||
#else
|
||||
z = getenv("USER");
|
||||
if( z==0 || z[0]==0 ) z = getenv("LOGNAME");
|
||||
if( z==0 || z[0]==0 ) z = "?";
|
||||
#endif
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Expand escapes in the given input prompt string. Return the
|
||||
** expanded prompt in memory obtained from sqlite3_malloc(). The
|
||||
@@ -988,12 +1103,13 @@ static char *expand_prompt(
|
||||
sqlite3_str *pOut = sqlite3_str_new(0);
|
||||
int i;
|
||||
char c;
|
||||
int onoff = 1;
|
||||
unsigned int mOff = 0; /* Bitmask of FALSE for if/then/else */
|
||||
int idxSpace = -1;
|
||||
int iDate = -1;
|
||||
for(i=0; zPrompt[i]; i++){
|
||||
if( zPrompt[i]!='/' ) continue;
|
||||
if( i>0 ){
|
||||
if( onoff ) sqlite3_str_append(pOut, zPrompt, i);
|
||||
if( !mOff ) sqlite3_str_append(pOut, zPrompt, i);
|
||||
zPrompt += i;
|
||||
i = 0;
|
||||
}
|
||||
@@ -1016,14 +1132,23 @@ static char *expand_prompt(
|
||||
while( i<=2 && zPrompt[i+1]>='0' && zPrompt[i+1]<='7' ){
|
||||
v = v*8 + zPrompt[++i] - '0';
|
||||
}
|
||||
if( onoff ) sqlite3_str_appendchar(pOut, 1, v);
|
||||
if( !mOff ) sqlite3_str_appendchar(pOut, 1, v);
|
||||
zPrompt += i+1;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
if( c=='e' ){
|
||||
/* /e is shorthand for /033 which is U+001B "Escape" */
|
||||
if( onoff ) sqlite3_str_append(pOut, "\033", 1);
|
||||
if( !mOff ) sqlite3_str_append(pOut, "\033", 1);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
if( c=='A' || c=='V' || c=='v' ){
|
||||
/* /A expands to the application name */
|
||||
/* /V expands to the version number with patch level */
|
||||
/* /v expands to the version number without the patch level */
|
||||
if( !mOff ) sqlite3_str_appendall(pOut, SQLITE_PS_APPDEF(c));
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
@@ -1043,33 +1168,47 @@ static char *expand_prompt(
|
||||
** .prompt '/e[1;/x31/:34/;m~f>/e[0m '
|
||||
*/
|
||||
if( c==':' ){
|
||||
/* toggle display on/off */
|
||||
onoff = !onoff;
|
||||
/* ELSE: toggle display on/off */
|
||||
mOff ^= 1;
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
if( c==';' ){
|
||||
/* Turn display on */
|
||||
onoff = 1;
|
||||
/* ENDIF: Turn display on */
|
||||
mOff >>= 1;
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
if( c=='x' ){
|
||||
/* /x turns display off not in a transaction, on if in txn */
|
||||
onoff = p->db && !sqlite3_get_autocommit(p->db);
|
||||
mOff = (mOff<<1) | (p->db==0 || sqlite3_get_autocommit(p->db)!=0);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
if( c=='r' ){
|
||||
/* /r turns display off if database is read/write, on if read-only */
|
||||
mOff = (mOff<<1) | (p->db==0 || sqlite3_db_readonly(p->db,0)==0);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
if( c=='m' ){
|
||||
/* /m turns display on for an in-memory database and off for persistent */
|
||||
mOff = (mOff<<1) | (p->db && prompt_filename(p,0)!=0);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( c=='f' || c=='F' || c=='~' ){
|
||||
/* /f becomes the tail of the database filename */
|
||||
/* /F becomes the full pathname */
|
||||
/* /~ becomes the full pathname relative to $HOME */
|
||||
if( onoff ){
|
||||
const char *zFN = prompt_filename(p);
|
||||
if( !mOff ){
|
||||
const char *zFN = prompt_filename(p,"memory");
|
||||
if( c=='f' ){
|
||||
#ifdef _WIN32
|
||||
const char *zTail = strrchr(zFN,'\\');
|
||||
@@ -1095,9 +1234,29 @@ static char *expand_prompt(
|
||||
continue;
|
||||
}
|
||||
|
||||
if( c=='H' ){
|
||||
/* /H becomes text needed to terminate current input */
|
||||
if( onoff ){
|
||||
if( c=='h' || c=='H' ){
|
||||
/* /h becomes hostname up to the first '.' */
|
||||
/* /H is the full hostname */
|
||||
if( !mOff ){
|
||||
sqlite3_str_appendall(pOut, prompt_hostname(c=='H'));
|
||||
}
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
if( c=='u' ){
|
||||
/* /u becomes the username (taken from environment variables) */
|
||||
if( !mOff ){
|
||||
sqlite3_str_appendall(pOut, prompt_user());
|
||||
}
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( c=='C' ){
|
||||
/* /C becomes text needed to terminate current input */
|
||||
if( !mOff ){
|
||||
sqlite3_int64 R = zPrior ? sqlite3_incomplete(zPrior) : 0;
|
||||
int cc = (R>>16)&0xff;
|
||||
int nParen = R>>32;
|
||||
@@ -1131,18 +1290,44 @@ static char *expand_prompt(
|
||||
/* /B is a no-op for the main prompt. For the continuation prompt,
|
||||
** /B expands to zero or more spaces to make the continuation prompt
|
||||
** at least as wide as the main prompt. */
|
||||
if( onoff ) idxSpace = sqlite3_str_length(pOut);
|
||||
if( !mOff ) idxSpace = sqlite3_str_length(pOut);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No match to a known escape. Generate an error. */
|
||||
if( onoff ) sqlite3_str_appendf(pOut,"UNKNOWN(\"/%c\")",c);
|
||||
if( c=='D' ){
|
||||
/* /D.../D replaces all of the text between the two /D escapes with
|
||||
** the result from strftime(). */
|
||||
if( iDate<0 ){
|
||||
iDate = sqlite3_str_length(pOut);
|
||||
}else{
|
||||
if( !mOff ){
|
||||
time_t now;
|
||||
char zBuf[200];
|
||||
zBuf[0] = 0;
|
||||
time(&now);
|
||||
strftime(zBuf, sizeof(zBuf)-1, sqlite3_str_value(pOut)+iDate,
|
||||
localtime(&now));
|
||||
zBuf[199] = 0;
|
||||
sqlite3_str_truncate(pOut, iDate);
|
||||
sqlite3_str_appendall(pOut, zBuf);
|
||||
}
|
||||
iDate = -1;
|
||||
}
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No match to a known escape. Generate an error. The mOff flag
|
||||
** is ignored for this output, so that errors appear even if they
|
||||
** are in an unused branch. */
|
||||
sqlite3_str_appendf(pOut,"UNKNOWN(\"/%c\")",c);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
}
|
||||
if( i>0 && onoff ){
|
||||
if( i>0 && !mOff ){
|
||||
sqlite3_str_append(pOut, zPrompt, i);
|
||||
}
|
||||
|
||||
@@ -1166,7 +1351,11 @@ static char *expand_prompt(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( 0==sqlite3_str_length(pOut) ){
|
||||
/* Avoid a bogus OOM */
|
||||
sqlite3_str_appendchar(pOut, 1, '\0');
|
||||
}
|
||||
return sqlite3_str_finish(pOut);
|
||||
}
|
||||
|
||||
@@ -1589,6 +1778,7 @@ static void shellExpandPrompt(
|
||||
sqlite3_free(zRes);
|
||||
}
|
||||
|
||||
|
||||
/************************* BEGIN PERFORMANCE TIMER *****************************/
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
|
||||
#include <sys/time.h>
|
||||
@@ -1932,20 +2122,20 @@ static int modeFind(ShellState *p, const char *zName){
|
||||
** Save or restore the current output mode
|
||||
*/
|
||||
static void modePush(ShellState *p){
|
||||
if( p->nPopMode==0 ){
|
||||
modeFree(&p->modePrior);
|
||||
modeDup(&p->modePrior,&p->mode);
|
||||
}
|
||||
p->aModeStack = realloc(p->aModeStack, sizeof(Mode)*(1+p->nModeStack));
|
||||
shell_check_oom(p->aModeStack);
|
||||
modeDup(&p->aModeStack[p->nModeStack], &p->mode);
|
||||
p->nModeStack++;
|
||||
}
|
||||
static void modePop(ShellState *p){
|
||||
if( p->modePrior.spec.iVersion>0 ){
|
||||
if( p->nModeStack ){
|
||||
modeFree(&p->mode);
|
||||
p->mode = p->modePrior;
|
||||
memset(&p->modePrior, 0, sizeof(p->modePrior));
|
||||
p->nModeStack--;
|
||||
memcpy(&p->mode, &p->aModeStack[p->nModeStack], sizeof(Mode));
|
||||
memset(&p->aModeStack[p->nModeStack], 0, sizeof(Mode));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** A callback for the sqlite3_log() interface.
|
||||
*/
|
||||
@@ -2355,6 +2545,11 @@ static void interrupt_handler(int NotUsed){
|
||||
if( ++seenInterrupt>1 ) cli_exit(1);
|
||||
if( globalDb ) sqlite3_interrupt(globalDb);
|
||||
}
|
||||
/* No-masking interrupts (SIGTERM or SIGHUP) */
|
||||
static void sigterm_handler(int NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
cli_exit(1);
|
||||
}
|
||||
|
||||
/* Try to determine the screen width. Use the default if unable.
|
||||
*/
|
||||
@@ -3414,7 +3609,7 @@ static int expertDotCommand(
|
||||
*/
|
||||
static int shellWriteQR(void *pX, const char *z, sqlite3_int64 n){
|
||||
ShellState *pArg = (ShellState*)pX;
|
||||
cli_printf(pArg->out, "%.*s", (int)n, z);
|
||||
cli_write(pArg->out, z, (int)n);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -4675,6 +4870,9 @@ static void shellModuleSchema(
|
||||
#define OPEN_DB_KEEPALIVE 0x001 /* Return after error if true */
|
||||
#define OPEN_DB_ZIPFILE 0x002 /* Open as ZIP if name matches *.zip */
|
||||
|
||||
/* Forward reference */
|
||||
static void shellTempFilenameFunc(sqlite3_context*,int,sqlite3_value**);
|
||||
|
||||
/*
|
||||
** Make sure the database is open. If it is not, then open it. If
|
||||
** the database fails to open, print an error message and exit.
|
||||
@@ -4847,6 +5045,8 @@ static void open_db(ShellState *p, int openFlags){
|
||||
p, shellExpandPrompt, 0, 0);
|
||||
sqlite3_create_function(p->db, "shell_prompt_test", 3, SQLITE_UTF8,
|
||||
p, shellExpandPrompt, 0, 0);
|
||||
sqlite3_create_function(p->db, "shell_temp_filename", 1, SQLITE_UTF8,
|
||||
p, shellTempFilenameFunc, 0, 0);
|
||||
|
||||
|
||||
if( p->openMode==SHELL_OPEN_ZIPFILE ){
|
||||
@@ -5662,7 +5862,12 @@ static void output_reset(ShellState *p){
|
||||
/* Give the start/open/xdg-open command some time to get
|
||||
** going before we continue and potentially delete the
|
||||
** p->zTempFile data file out from under it */
|
||||
sqlite3_sleep(2000);
|
||||
p->aUnlink = realloc(p->aUnlink, sizeof(Unlink)*(1+p->nUnlink));
|
||||
shell_check_oom(p->aUnlink);
|
||||
p->aUnlink[p->nUnlink].tm = timeOfDay()+10000;
|
||||
p->aUnlink[p->nUnlink].zFN = p->zTempFile;
|
||||
p->nUnlink++;
|
||||
p->zTempFile = 0;
|
||||
}
|
||||
sqlite3_free(zCmd);
|
||||
modePop(p);
|
||||
@@ -6075,29 +6280,111 @@ static char *shellFilenameFromUri(const char *zFN){
|
||||
|
||||
/*
|
||||
** Delete a file.
|
||||
**
|
||||
** If unsuccessful on the first attempt and if pRetry!=NULL and pRetry[0]
|
||||
** is positive, then delay for pRetry[0] milliseconds and try again. On
|
||||
** a retry, pRetry[0] is set to zero. Unsuccessful unlinks usually only
|
||||
** happen on Windows. It is possible (in theory) for unlink() to fail
|
||||
** on Unix, but it rarely happens.
|
||||
**
|
||||
** Return 0 on success and non-zero if unable.
|
||||
*/
|
||||
int shellDeleteFile(const char *zFilename){
|
||||
int shellDeleteFile(const char *zFilename, int *pRetry){
|
||||
int rc;
|
||||
for(;;){
|
||||
#ifdef _WIN32
|
||||
wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename);
|
||||
rc = _wunlink(z);
|
||||
sqlite3_free(z);
|
||||
wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename);
|
||||
rc = _wunlink(z);
|
||||
if( rc && _waccess(z,0)!=0 ) rc = 0;
|
||||
sqlite3_free(z);
|
||||
#else
|
||||
rc = unlink(zFilename);
|
||||
rc = unlink(zFilename);
|
||||
if( rc && access(zFilename, 0)!=0 ) rc = 0;
|
||||
#endif
|
||||
if( rc && pRetry && pRetry[0] ){
|
||||
sqlite3_sleep(pRetry[0]);
|
||||
pRetry[0] = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to delete the temporary file (if there is one) and free the
|
||||
** memory used to hold the name of the temp file.
|
||||
** This routine does two things:
|
||||
**
|
||||
** (1) Delete (unlink) temporary files that are no longer needed.
|
||||
** (2) Free memory used to hold the names of those temporary files.
|
||||
**
|
||||
** Temp filenames are stored in p->zTempName and in the p->aUnlink[]
|
||||
** array. The p->zTempFile is always subject to immediate deletion. The
|
||||
** temp files named in p->aUnlink[] are usually not deleted until after
|
||||
** the timestamp stored in the p->aUnlink[].tm field, except if
|
||||
** bForce is true, the p->aUnlink[] files will be deleted even if they
|
||||
** have not reached their expiration, as long as a delay of at least
|
||||
** nDelay milliseconds occurs first.
|
||||
**
|
||||
** If nDelay is non-zero and a deletion attempt is not successful,
|
||||
** wait for nDelay milliseconds and try again before giving up. Only
|
||||
** a single wait occurs, even if problems are encountered with multiple
|
||||
** temp files. Only the first problem seen takes the delay. Thus
|
||||
** the total delay never exceeds nDelay milliseconds. When nDelay
|
||||
** is non-zero, memory used to hold the filename is reclaimed regardless
|
||||
** of whether or not the temporary files were successfully deleted.
|
||||
**
|
||||
** If bForce is true, deletion is attempted on p->aUnlink[] files
|
||||
** even if their time has not expired. However, there is a pause
|
||||
** of up to nDelay milliseconds before doing the deletion.
|
||||
**
|
||||
** When nDelay is zero and the deletion attempt fails, memory used to
|
||||
** store temporary filesnames is not reclaimed.
|
||||
**
|
||||
** The bForce flag is used only when the process is about to exit. When
|
||||
** bForce is set, that indicates that this is our last opportunity to
|
||||
** clean up temporary files.
|
||||
*/
|
||||
static void clearTempFile(ShellState *p){
|
||||
if( p->zTempFile==0 ) return;
|
||||
if( p->doXdgOpen ) return;
|
||||
if( shellDeleteFile(p->zTempFile) ) return;
|
||||
sqlite3_free(p->zTempFile);
|
||||
p->zTempFile = 0;
|
||||
static void clearTempFile(ShellState *p, int nDelay, int bForce){
|
||||
int alwaysFree = (nDelay>0) || bForce;
|
||||
int rc = 0;
|
||||
if( p->zTempFile && (!p->doXdgOpen || bForce) ){
|
||||
rc = shellDeleteFile(p->zTempFile, &nDelay);
|
||||
if( rc==0 || alwaysFree ){
|
||||
sqlite3_free(p->zTempFile);
|
||||
p->zTempFile = 0;
|
||||
}
|
||||
}
|
||||
if( p->nUnlink ){
|
||||
unsigned int i;
|
||||
for(i=0; i<p->nUnlink; i++){
|
||||
sqlite3_int64 tmToGo = p->aUnlink[i].tm - timeOfDay();
|
||||
int doDelete = tmToGo<=0;
|
||||
if( !doDelete && alwaysFree ){
|
||||
int tmSleep = nDelay;
|
||||
if( tmSleep > tmToGo ) tmSleep = (int)tmToGo;
|
||||
sqlite3_sleep(tmSleep);
|
||||
nDelay -= tmSleep;
|
||||
doDelete = 1;
|
||||
}
|
||||
if( doDelete ){
|
||||
char *zFN = p->aUnlink[i].zFN;
|
||||
rc = shellDeleteFile(zFN, &nDelay);
|
||||
if( rc==0 || alwaysFree ){
|
||||
sqlite3_free(p->aUnlink[i].zFN);
|
||||
p->nUnlink--;
|
||||
if( i<p->nUnlink ){
|
||||
p->aUnlink[i] = p->aUnlink[p->nUnlink];
|
||||
memset(&p->aUnlink[p->nUnlink], 0, sizeof(Unlink));
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( p->nUnlink==0 ){
|
||||
free(p->aUnlink);
|
||||
p->aUnlink = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Forward reference */
|
||||
@@ -6127,7 +6414,7 @@ static void newTempFile(ShellState *p, const char *zSuffix){
|
||||
r /= 36;
|
||||
}
|
||||
zRand[i] = 0;
|
||||
clearTempFile(p);
|
||||
clearTempFile(p,10,0);
|
||||
sqlite3_free(p->zTempFile);
|
||||
p->zTempFile = 0;
|
||||
zHome = find_home_dir(0);
|
||||
@@ -6136,6 +6423,26 @@ static void newTempFile(ShellState *p, const char *zSuffix){
|
||||
shell_check_oom(p->zTempFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: shell_temp_filename(SUFFIX)
|
||||
**
|
||||
** Return a randomly generated temporary filename.
|
||||
*/
|
||||
static void shellTempFilenameFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
|
||||
const char *zSuffix = (const char*)sqlite3_value_text(apVal[0]);
|
||||
(void)nVal;
|
||||
if( zSuffix==0 ) zSuffix = "";
|
||||
newTempFile(p, zSuffix);
|
||||
sqlite3_result_text(pCtx, p->zTempFile, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_free(p->zTempFile);
|
||||
p->zTempFile = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The implementation of SQL scalar function fkey_collate_clause(), used
|
||||
** by the ".lint fkey-indexes" command. This scalar function is always
|
||||
@@ -7765,8 +8072,8 @@ static int dotCmdImport(ShellState *p){
|
||||
}else if( cli_strcmp(z,"-skip")==0 && i<nArg-1 ){
|
||||
nSkip = integerValue(azArg[++i]);
|
||||
}else if( cli_strcmp(z,"-ascii")==0 ){
|
||||
if( sCtx.cColSep==0 ) sCtx.cColSep = SEP_Unit[0];
|
||||
if( sCtx.cRowSep==0 ) sCtx.cRowSep = SEP_Record[0];
|
||||
if( sCtx.cColSep==0 ) sCtx.cColSep = '\037';
|
||||
if( sCtx.cRowSep==0 ) sCtx.cRowSep = '\036';
|
||||
xRead = ascii_read_one_field;
|
||||
}else if( cli_strcmp(z,"-csv")==0 ){
|
||||
if( sCtx.cColSep==0 ) sCtx.cColSep = ',';
|
||||
@@ -8373,7 +8680,6 @@ static int dotCmdMode(ShellState *p){
|
||||
chng = 1; /* Not really a change, but we still want to suppress the
|
||||
** "current mode" output */
|
||||
}else if( optionMatch(z,"once") ){
|
||||
p->nPopMode = 0;
|
||||
modePush(p);
|
||||
p->nPopMode = 1;
|
||||
}else if( optionMatch(z,"noquote") ){
|
||||
@@ -8882,8 +9188,8 @@ static int dotCmdOutput(ShellState *p){
|
||||
newTempFile(p, "csv");
|
||||
p->mode.mFlags &= ~MFLG_ECHO;
|
||||
p->mode.eMode = MODE_Csv;
|
||||
modeSetStr(&p->mode.spec.zColumnSep, SEP_Comma);
|
||||
modeSetStr(&p->mode.spec.zRowSep, SEP_CrLf);
|
||||
modeSetStr(&p->mode.spec.zColumnSep, ",");
|
||||
modeSetStr(&p->mode.spec.zRowSep, "\r\n");
|
||||
#ifdef _WIN32
|
||||
zBom = zBomUtf8; /* Always include the BOM on Windows, as Excel does
|
||||
** not work without it. */
|
||||
@@ -9240,7 +9546,7 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
if( nArg==0 ) return 0; /* no tokens, no error */
|
||||
n = strlen30(azArg[0]);
|
||||
c = azArg[0][0];
|
||||
clearTempFile(p);
|
||||
clearTempFile(p,0,0);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
|
||||
@@ -10476,10 +10782,10 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
if( cli_strncmp(zFN,"file:",5)==0 ){
|
||||
char *zDel = shellFilenameFromUri(zFN);
|
||||
shell_check_oom(zDel);
|
||||
shellDeleteFile(zDel);
|
||||
shellDeleteFile(zDel, 0);
|
||||
sqlite3_free(zDel);
|
||||
}else{
|
||||
shellDeleteFile(zFN);
|
||||
shellDeleteFile(zFN, 0);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
@@ -12553,7 +12859,7 @@ static int runOneSqlLine(
|
||||
rc = shell_exec(p, zSql, &zErrMsg);
|
||||
END_TIMER(p);
|
||||
if( rc || zErrMsg ){
|
||||
char zPrefix[100];
|
||||
sqlite3_str *pPrefix = sqlite3_str_new(p->db);
|
||||
const char *zErrorTail;
|
||||
const char *zErrorType;
|
||||
if( zErrMsg==0 ){
|
||||
@@ -12571,28 +12877,27 @@ static int runOneSqlLine(
|
||||
}
|
||||
if( zFilename || !stdin_is_interactive ){
|
||||
if( cli_strcmp(zFilename,"cmdline")==0 ){
|
||||
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
|
||||
sqlite3_str_appendf(pPrefix,
|
||||
"%s in %r command line argument:", zErrorType, startline);
|
||||
}else if( cli_strcmp(zFilename,"<stdin>")==0 ){
|
||||
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
|
||||
sqlite3_str_appendf(pPrefix,
|
||||
"%s near line %d:", zErrorType, startline);
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
|
||||
sqlite3_str_appendf(pPrefix,
|
||||
"%s near line %d of %s:", zErrorType, startline, zFilename);
|
||||
}
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
|
||||
sqlite3_str_appendf(pPrefix, "%s:", zErrorType);
|
||||
}
|
||||
cli_printf(stderr,"%s %s\n", zPrefix, zErrorTail);
|
||||
cli_printf(stderr,"%s %s\n", sqlite3_str_value(pPrefix), zErrorTail);
|
||||
sqlite3_str_free(pPrefix);
|
||||
sqlite3_free(zErrMsg);
|
||||
zErrMsg = 0;
|
||||
return 1;
|
||||
}else if( ShellHasFlag(p, SHFLG_CountChanges) ){
|
||||
char zLineBuf[2000];
|
||||
sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
|
||||
"changes: %lld total_changes: %lld",
|
||||
cli_printf(p->out,
|
||||
"changes: %lld total_changes: %lld\n",
|
||||
sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
|
||||
cli_printf(p->out, "%s\n", zLineBuf);
|
||||
}
|
||||
|
||||
if( doAutoDetectRestore(p, zSql) ) return 1;
|
||||
@@ -12748,7 +13053,7 @@ static int process_input(ShellState *p, const char *zSrc){
|
||||
output_reset(p);
|
||||
p->nPopOutput = 0;
|
||||
}else{
|
||||
clearTempFile(p);
|
||||
clearTempFile(p,0,0);
|
||||
}
|
||||
if( p->nPopMode ){
|
||||
modePop(p);
|
||||
@@ -13051,12 +13356,13 @@ static void main_init(ShellState *p) {
|
||||
#endif
|
||||
sqlite3_config(SQLITE_CONFIG_URI, 1);
|
||||
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
|
||||
globalShellState = p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Output text to the console in a font that attracts extra attention.
|
||||
*/
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
#if 0 /* Windows now handles ANSI escape codes */
|
||||
static void printBold(const char *zText){
|
||||
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
|
||||
@@ -13069,7 +13375,7 @@ static void printBold(const char *zText){
|
||||
}
|
||||
#else
|
||||
static void printBold(const char *zText){
|
||||
cli_printf(stdout, "\033[1m%s\033[0m", zText);
|
||||
cli_printf(stdout, "\033[1;36m\033[3m%s\033[0m", zText);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -13086,8 +13392,14 @@ static char *cmdline_option_value(int argc, char **argv, int i){
|
||||
return argv[i];
|
||||
}
|
||||
|
||||
static void sayAbnormalExit(void){
|
||||
/*
|
||||
** The callback from atexit().
|
||||
*/
|
||||
static void abnormalExit(void){
|
||||
if( seenInterrupt ) eputz("Program interrupted.\n");
|
||||
if( globalShellState ){
|
||||
clearTempFile(globalShellState, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Routine to output from vfstrace
|
||||
@@ -13129,6 +13441,8 @@ static int auto_ext_leak_tester(
|
||||
int SQLITE_CDECL utf8_main(int,char**); /* Forward declaration */
|
||||
int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
int rc, i;
|
||||
DWORD mode;
|
||||
HANDLE hOut;
|
||||
char **argv = malloc( sizeof(char*) * (argc+1) );
|
||||
char **orig = argv;
|
||||
if( argv==0 ){
|
||||
@@ -13153,6 +13467,9 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
}
|
||||
}
|
||||
argv[argc] = 0;
|
||||
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
GetConsoleMode(hOut, &mode);
|
||||
SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
rc = utf8_main(argc, argv);
|
||||
for(i=0; i<argc; i++) free(orig[i]);
|
||||
free(argv);
|
||||
@@ -13200,7 +13517,7 @@ int SQLITE_CDECL main(int argc, char **argv){
|
||||
stdin_is_interactive = isatty(0);
|
||||
stdout_is_console = isatty(1);
|
||||
#endif
|
||||
atexit(sayAbnormalExit);
|
||||
atexit(abnormalExit);
|
||||
#ifdef SQLITE_DEBUG
|
||||
mem_main_enter = sqlite3_memory_used();
|
||||
#endif
|
||||
@@ -13233,6 +13550,13 @@ int SQLITE_CDECL main(int argc, char **argv){
|
||||
eputz("No ^C handler.\n");
|
||||
}
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
signal(SIGTERM, sigterm_handler);
|
||||
#endif
|
||||
#ifdef SIGHUP
|
||||
signal(SIGHUP, sigterm_handler);
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_SYSTEM_SQLITE+0!=1
|
||||
if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
|
||||
@@ -13518,7 +13842,7 @@ int SQLITE_CDECL main(int argc, char **argv){
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
sqlite3_appendvfs_init(0,0,0);
|
||||
#ifdef SQLITE_DEBUG
|
||||
sqlite3_auto_extension( (void (*)())auto_ext_leak_tester );
|
||||
sqlite3_auto_extension( (void(*)(void))auto_ext_leak_tester );
|
||||
#endif
|
||||
#endif
|
||||
modeDefault(&data);
|
||||
@@ -13793,7 +14117,7 @@ int SQLITE_CDECL main(int argc, char **argv){
|
||||
output_reset(&data);
|
||||
data.nPopOutput = 0;
|
||||
}else{
|
||||
clearTempFile(&data);
|
||||
clearTempFile(&data,0,0);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -13872,7 +14196,10 @@ int SQLITE_CDECL main(int argc, char **argv){
|
||||
find_home_dir(1);
|
||||
output_reset(&data);
|
||||
data.doXdgOpen = 0;
|
||||
clearTempFile(&data);
|
||||
clearTempFile(&data,2500,1);
|
||||
globalShellState = 0;
|
||||
while( data.nModeStack ) modePop(&data);
|
||||
free(data.aModeStack);
|
||||
modeFree(&data.mode);
|
||||
if( data.nSavedModes ){
|
||||
int ii;
|
||||
|
||||
+64
-35
@@ -3388,58 +3388,57 @@ void sqlite3_randomness(int N, void *P);
|
||||
** METHOD: sqlite3
|
||||
** KEYWORDS: {authorizer callback}
|
||||
**
|
||||
** ^This routine registers an authorizer callback with a particular
|
||||
** [database connection], supplied in the first argument.
|
||||
** ^The authorizer callback is invoked as SQL statements are being compiled
|
||||
** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
|
||||
** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()],
|
||||
** and [sqlite3_prepare16_v3()]. ^At various
|
||||
** The sqlite3_set_authorizer(D,X,P) and sqlite3_push_authorizer(D,X,P,F)
|
||||
** routines registers an authorizer callback X with a particular
|
||||
** [database connection] D. The sqlite3_push_authorizer() interface
|
||||
** is preferred.
|
||||
**
|
||||
** The authorizer callback is invoked multiple times as SQL statements
|
||||
** are being compiled by [sqlite3_prepare()] or its variants
|
||||
** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16()],
|
||||
** [sqlite3_prepare16_v2()], and [sqlite3_prepare16_v3()]. At various
|
||||
** points during the compilation process, as logic is being created
|
||||
** to perform various actions, the authorizer callback is invoked to
|
||||
** see if those actions are allowed. ^The authorizer callback should
|
||||
** see if those actions are allowed. The authorizer callback should
|
||||
** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the
|
||||
** specific action but allow the SQL statement to continue to be
|
||||
** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be
|
||||
** rejected with an error. ^If the authorizer callback returns
|
||||
** rejected with an error. If the authorizer callback returns
|
||||
** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY]
|
||||
** then the [sqlite3_prepare_v2()] or equivalent call that triggered
|
||||
** the authorizer will fail with an error message.
|
||||
**
|
||||
** When the callback returns [SQLITE_OK], that means the operation
|
||||
** requested is ok. ^When the callback returns [SQLITE_DENY], the
|
||||
** [sqlite3_prepare_v2()] or equivalent call that triggered the
|
||||
** authorizer will fail with an error message explaining that
|
||||
** access is denied.
|
||||
**
|
||||
** ^The first parameter to the authorizer callback is a copy of the third
|
||||
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
|
||||
** The first parameter to the authorizer callback is a copy of the third
|
||||
** parameter (P) to the sqlite3_set_authorizer(D,X,P) or
|
||||
** sqlite3_push_authorizer(D,X,P,F) interface that created the
|
||||
** authorizer. The second parameter
|
||||
** to the callback is an integer [SQLITE_COPY | action code] that specifies
|
||||
** the particular action to be authorized. ^The third through sixth parameters
|
||||
** the particular action to be authorized. The third through sixth parameters
|
||||
** to the callback are either NULL pointers or zero-terminated strings
|
||||
** that contain additional details about the action to be authorized.
|
||||
** Applications must always be prepared to encounter a NULL pointer in any
|
||||
** of the third through the sixth parameters of the authorization callback.
|
||||
**
|
||||
** ^If the action code is [SQLITE_READ]
|
||||
** If the action code is [SQLITE_READ]
|
||||
** and the callback returns [SQLITE_IGNORE] then the
|
||||
** [prepared statement] statement is constructed to substitute
|
||||
** a NULL value in place of the table column that would have
|
||||
** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
|
||||
** return can be used to deny an untrusted user access to individual
|
||||
** columns of a table.
|
||||
** ^When a table is referenced by a [SELECT] but no column values are
|
||||
** When a table is referenced by a [SELECT] but no column values are
|
||||
** extracted from that table (for example in a query like
|
||||
** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
|
||||
** is invoked once for that table with a column name that is an empty string.
|
||||
** ^If the action code is [SQLITE_DELETE] and the callback returns
|
||||
** If the action code is [SQLITE_DELETE] and the callback returns
|
||||
** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
|
||||
** [truncate optimization] is disabled and all rows are deleted individually.
|
||||
**
|
||||
** An authorizer is used when [sqlite3_prepare | preparing]
|
||||
** SQL statements from an untrusted source, to ensure that the SQL statements
|
||||
** do not try to access data they are not allowed to see, or that they do not
|
||||
** try to execute malicious statements that damage the database. For
|
||||
** example, an application may allow a user to enter arbitrary
|
||||
** The authorizer mechanism is designed for use when
|
||||
** [sqlite3_prepare | preparing] SQL statements from an untrusted source,
|
||||
** to ensure that the SQL statements do not access data they are
|
||||
** not allowed to see, or change data that they are not allowed to
|
||||
** modify. For example, an application may allow a user to enter arbitrary
|
||||
** SQL queries for evaluation by a database. But the application does
|
||||
** not want the user to be able to make arbitrary changes to the
|
||||
** database. An authorizer could then be put in place while the
|
||||
@@ -3451,22 +3450,45 @@ void sqlite3_randomness(int N, void *P);
|
||||
** and limiting database size using the [max_page_count] [PRAGMA]
|
||||
** in addition to using an authorizer.
|
||||
**
|
||||
** ^(Only a single authorizer can be in place on a database connection
|
||||
** at a time. Each call to sqlite3_set_authorizer overrides the
|
||||
** previous call.)^ ^Disable the authorizer by installing a NULL callback.
|
||||
** The authorizer is disabled by default.
|
||||
** The sqlite3_set_authorizer(D,X,P) interface causes X to be the only
|
||||
** authorizer that runs. Any previously registered authorizers are
|
||||
** discarded. Older versions of SQLite (prior to version 3.54.0)
|
||||
** only support sqlite3_set_authorizer().
|
||||
**
|
||||
** The authorizer callback must not do anything that will modify
|
||||
** the database connection that invoked the authorizer callback.
|
||||
** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
|
||||
** database connections for the meaning of "modify" in this paragraph.
|
||||
** The sqlite3_push_authorizer(D,X,P,F) interface pushes a new authorizer
|
||||
** onto a stack of authorizers. The sqlite3_pop_authorizer(D) pops that
|
||||
** authorizer back off the stack. If the F flag is 1, then the pushed
|
||||
** authorizer callback is the only one that is considered - previous
|
||||
** authorizers are retained so that they can be restored after the
|
||||
** next sqlite3_pop_authorizer(), but they are not used while the new
|
||||
** authorizer is still on the stack. If the F flag to
|
||||
** sqlite3_push_authorizer(D,X,P,F) is zero, that means that
|
||||
** the new authorizer runs first, but preexisting authorizers are also
|
||||
** run and the result is the most restrictive result returned by
|
||||
** any authorizer. SQLITE_DENY is more restrictive than SQLITE_IGNORE,
|
||||
** and SQLITE_IGNORE is more restrictive than SQLITE_OK.
|
||||
**
|
||||
** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the
|
||||
** A call to sqlite3_push_authorizer() will return SQLITE_NOMEM if it
|
||||
** is unable to allocate memory to hold prior authorizers.
|
||||
**
|
||||
** Use sqlite3_push_authorizer(D,0,0,1) to disable all authorizers on
|
||||
** database connection D temporarily, but remember prior authorizers
|
||||
** so that they are restored at the next sqlite3_pop_authorizer(D).
|
||||
**
|
||||
** It is illegal to invoke sqlite3_set_authorizer() if there are pending
|
||||
** (unpopped) calls to sqlite3_push_authorizer(). Doing so can lead
|
||||
** to memory leaks. The use of sqlite3_set_authorizer() is discouraged.
|
||||
** New applications should use only sqlite3_push_authorizer() and
|
||||
** sqlite3_pop_authorizer().
|
||||
**
|
||||
** <h2>Important Details</h2>
|
||||
**
|
||||
** When [sqlite3_prepare_v2()] is used to prepare a statement, the
|
||||
** statement might be re-prepared during [sqlite3_step()] due to a
|
||||
** schema change. Hence, the application should ensure that the
|
||||
** correct authorizer callback remains in place during the [sqlite3_step()].
|
||||
**
|
||||
** ^Note that the authorizer callback is invoked only during
|
||||
** Note that the authorizer callback is invoked only during
|
||||
** [sqlite3_prepare()] or its variants. Authorization is not
|
||||
** performed during statement evaluation in [sqlite3_step()], unless
|
||||
** as stated in the previous paragraph, sqlite3_step() invokes
|
||||
@@ -3477,6 +3499,13 @@ int sqlite3_set_authorizer(
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
|
||||
void *pUserData
|
||||
);
|
||||
int sqlite3_push_authorizer(
|
||||
sqlite3*,
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
|
||||
void *pUserData,
|
||||
int bOvrd
|
||||
);
|
||||
int sqlite3_pop_authorizer(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Authorizer Return Codes
|
||||
|
||||
+1
-1
@@ -202,7 +202,7 @@
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** Reuse the STATIC_LRU for mutex access to sqlite3_temp_directory.
|
||||
** Reuse the STATIC_VFS1 for mutex access to sqlite3_temp_directory.
|
||||
*/
|
||||
#define SQLITE_MUTEX_STATIC_TEMPDIR SQLITE_MUTEX_STATIC_VFS1
|
||||
|
||||
|
||||
+11
-6
@@ -465,15 +465,20 @@ u8 sqlite3StrIHash(const char *z){
|
||||
return h;
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_DISABLE_INTRINSIC) \
|
||||
&& (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || \
|
||||
(defined(__riscv) && defined(__riscv_xlen) && (__riscv_xlen>32)))
|
||||
#define SQLITE_USE_UINT128
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Two inputs are multiplied to get a 128-bit result. Write the
|
||||
** lower 64-bits of the result into *pLo, and return the high-order
|
||||
** 64 bits.
|
||||
*/
|
||||
static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
|
||||
&& !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
#if defined(SQLITE_USE_UINT128)
|
||||
__uint128_t r = (__uint128_t)a * b;
|
||||
*pLo = (u64)r;
|
||||
return (u64)(r>>64);
|
||||
@@ -507,9 +512,7 @@ static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
|
||||
** The lower 64 bits of A*B are discarded.
|
||||
*/
|
||||
static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
|
||||
&& !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
#if defined(SQLITE_USE_UINT128)
|
||||
__uint128_t r = (__uint128_t)a * b;
|
||||
r += ((__uint128_t)aLo * b) >> 32;
|
||||
*pLo = (r>>32)&0xffffffff;
|
||||
@@ -547,6 +550,8 @@ static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef SQLITE_USE_UINT128
|
||||
|
||||
/*
|
||||
** Return a u64 with the N-th bit set.
|
||||
*/
|
||||
|
||||
+52
-7
@@ -708,7 +708,6 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** For OP_Column, factor out the case where content is loaded from
|
||||
** overflow pages, so that the code to implement this case is separate
|
||||
@@ -794,6 +793,40 @@ static SQLITE_NOINLINE int vdbeColumnFromOverflow(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Memory cell pMem may contain a blob or a NULL value. Cursor pCsr is
|
||||
** open on an index. If the current index entry matches the blob value in
|
||||
** pMem byte-for-byte, set pMem to NULL and return 1. Otherwise, return 0.
|
||||
**
|
||||
** If an error occurs, set (*pRc) to an SQLite error code. Return 1 in this
|
||||
** case as well.
|
||||
*/
|
||||
static SQLITE_NOINLINE int vdbeIndexKeyCompare(
|
||||
BtCursor *pCsr, /* Cursor to compare key to */
|
||||
Mem *pMem,
|
||||
int *pRc
|
||||
){
|
||||
int ret = 0;
|
||||
u32 nKey = 0;
|
||||
|
||||
assert( pMem->flags & (MEM_Blob|MEM_Null) );
|
||||
nKey = sqlite3BtreePayloadSize(pCsr);
|
||||
if( nKey==(u32)pMem->n && ALWAYS((pMem->flags & MEM_Blob)!=0) ){
|
||||
/* This code could just use sqlite3BtreePayloadFetch(). But calling that
|
||||
** function here apparently prevents compilers from inlining it in other,
|
||||
** more performance critical, places. So this code uses
|
||||
** MemFromBtreeZeroOffset(), which is just as fast in most cases, but also
|
||||
** handles the case where the index record uses overflow pages. */
|
||||
Mem m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
*pRc = sqlite3VdbeMemFromBtreeZeroOffset(pCsr, nKey, &m);
|
||||
ret = (*pRc!=SQLITE_OK || 0==memcmp(pMem->z, m.z, nKey));
|
||||
sqlite3VdbeMemReleaseMalloc(&m);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** Send a "statement aborts" message to the error log.
|
||||
*/
|
||||
@@ -6622,15 +6655,20 @@ case OP_SorterInsert: { /* in2 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IdxDelete P1 P2 P3 P4 *
|
||||
** Synopsis: key=r[P2@P3]
|
||||
/* Opcode: IdxDelete P1 P2 P3 P4 P5
|
||||
** Synopsis: key=r[P2@P5]
|
||||
**
|
||||
** The content of P3 registers starting at register P2 form
|
||||
** The content of P5 registers starting at register P2 form
|
||||
** an unpacked index key. This opcode removes that entry from the
|
||||
** index opened by cursor P1.
|
||||
**
|
||||
** P4 is a pointer to an Index structure.
|
||||
**
|
||||
** If P3 is non-zero, it is the register number of a register holding
|
||||
** a record that will be inserted into this index. If that record is
|
||||
** identical to the one that would be deleted by this instruction,
|
||||
** skip the delete and set register P3 to NULL.
|
||||
**
|
||||
** Raise an SQLITE_CORRUPT_INDEX error if no matching index entry is found
|
||||
** and not in writable_schema mode.
|
||||
*/
|
||||
@@ -6640,8 +6678,8 @@ case OP_IdxDelete: {
|
||||
int res;
|
||||
UnpackedRecord r;
|
||||
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 );
|
||||
assert( pOp->p5>0 );
|
||||
assert( pOp->p2>0 && pOp->p2+pOp->p5<=(p->nMem+1 - p->nCursor)+1 );
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
@@ -6650,7 +6688,7 @@ case OP_IdxDelete: {
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr!=0 );
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
r.nField = (u16)pOp->p3;
|
||||
r.nField = pOp->p5;
|
||||
r.default_rc = 0;
|
||||
r.aMem = &aMem[pOp->p2];
|
||||
rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res);
|
||||
@@ -6669,6 +6707,13 @@ case OP_IdxDelete: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( pOp->p3 && vdbeIndexKeyCompare(pCrsr, &aMem[pOp->p3], &rc) ){
|
||||
if( rc ) goto abort_due_to_error;
|
||||
sqlite3VdbeMemSetNull(&aMem[pOp->p3]);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
assert( pC->deferredMoveto==0 );
|
||||
|
||||
@@ -283,5 +283,13 @@ do_execsql_test 12.5 {
|
||||
"IsActive" INTEGER)}
|
||||
}
|
||||
|
||||
do_execsql_test 12.6 {
|
||||
CREATE TABLE t1(a, b CONSTRAINT "a""b" CHECK (b IS NOT NULL));
|
||||
}
|
||||
|
||||
do_execsql_test 12.7 {
|
||||
ALTER TABLE t1 DROP CONSTRAINT "a""b"
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -41,5 +41,26 @@ do_faultsim_test 2 -faults oom* -prep {
|
||||
faultsim_test_result {0 ABCDEF}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
PRAGMA page_size=1024;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE INDEX i1 ON t1( hex(b) );
|
||||
INSERT INTO t1 VALUES(10, randomblob(500));
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 3 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
UPDATE t1 SET b=randomblob(500);
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# 2026-04-23
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests for omitting the update of an index when the new value is the
|
||||
# same as the old.
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix expridx2
|
||||
|
||||
# This test requires wal mode, but the journaltest permutation installs
|
||||
# a custom VFS that does not support wal mode.
|
||||
if {[permutation]=="journaltest"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA journal_mode = wal;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO t1 VALUES(1, '{a: 10, b: 20, c: 30}');
|
||||
INSERT INTO t1 VALUES(2, '{a: 11, b: 21, c: 31}');
|
||||
INSERT INTO t1 VALUES(3, '{a: 12, b: 22, c: 32}');
|
||||
INSERT INTO t1 VALUES(4, '{a: 13, b: 23, c: 33}');
|
||||
|
||||
CREATE INDEX t1a ON t1( (b->>'a') );
|
||||
CREATE INDEX t1b ON t1( (b->>'b') );
|
||||
CREATE INDEX t1c ON t1( (b->>'c') );
|
||||
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX t2b ON t2( b );
|
||||
INSERT INTO t2 VALUES(1, 1, 1);
|
||||
INSERT INTO t2 VALUES(2, 2, 2);
|
||||
INSERT INTO t2 VALUES(3, 3, 3);
|
||||
INSERT INTO t2 VALUES(4, 4, 4);
|
||||
} {wal}
|
||||
|
||||
proc nWrite {sql} {
|
||||
sqlite3_db_status db CACHE_WRITE 1
|
||||
execsql $sql
|
||||
lindex [sqlite3_db_status db CACHE_WRITE 0] 1
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
nWrite { UPDATE t1 SET b = json_set(b, '$.a', b->>'a' + 1) }
|
||||
} {2}
|
||||
|
||||
do_test 1.2 {
|
||||
nWrite {
|
||||
UPDATE t1 SET b = json_set(
|
||||
json_set(b, '$.a', b->>'a' + 1),
|
||||
'$.b', b->>'b' + 1
|
||||
);
|
||||
}
|
||||
} {3}
|
||||
|
||||
do_test 1.3 {
|
||||
nWrite {
|
||||
UPDATE t1 SET b = '{a:1, b:2, c:3}' WHERE rowid=1;
|
||||
}
|
||||
} {4}
|
||||
|
||||
integrity_check 1.4
|
||||
|
||||
do_test 1.5 {
|
||||
nWrite { UPDATE t2 SET b = b+1, c=c+1 }
|
||||
} {2}
|
||||
|
||||
do_test 1.6 {
|
||||
nWrite { UPDATE t2 SET b = b, c=c+1 }
|
||||
} {2}
|
||||
|
||||
do_test 1.7 {
|
||||
nWrite { UPDATE t2 SET c=c+1 }
|
||||
} {1}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -280,4 +280,65 @@ do_test 900 {
|
||||
} 1
|
||||
dbempty close
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Make sure a database cannot be overwritten by deserialize() if
|
||||
# there is an open transaction on it.
|
||||
#
|
||||
do_execsql_test 1000 {
|
||||
CREATE TABLE t(x);
|
||||
INSERT INTO t VALUES(1),(2);
|
||||
}
|
||||
|
||||
set blob [db serialize main]
|
||||
|
||||
do_test 1010 {
|
||||
set seen 0
|
||||
list [catch {
|
||||
db eval {SELECT x FROM t} {
|
||||
incr seen
|
||||
if {$seen == 1} {
|
||||
db deserialize main $blob
|
||||
}
|
||||
}
|
||||
} msg] $msg
|
||||
} {1 {unable to set MEMDB content}}
|
||||
|
||||
forcedelete test.db2
|
||||
sqlite3 db2 test.db2
|
||||
do_test 1020 {
|
||||
set seen 0
|
||||
sqlite3_backup B db2 main db main
|
||||
B step 2
|
||||
set res [list [catch {
|
||||
db deserialize main $blob
|
||||
} msg] $msg]
|
||||
B finish
|
||||
set res
|
||||
} {1 {unable to set MEMDB content}}
|
||||
db2 close
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that things work if the destination database of a backup is
|
||||
# overwritten using sqlite3_deserialize() between sqlite3_backup_init()
|
||||
# and the first call to sqlite3_backup_step(). Forum post 15d82885e2.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 1100 {
|
||||
CREATE TABLE t(x);
|
||||
INSERT INTO t VALUES(1),(2);
|
||||
}
|
||||
|
||||
set blob [db serialize main]
|
||||
|
||||
forcedelete test.db2
|
||||
sqlite3 db2 test.db2
|
||||
do_test 1110 {
|
||||
set seen 0
|
||||
sqlite3_backup B db2 main db main
|
||||
db2 deserialize main $blob
|
||||
B step 2
|
||||
B finish
|
||||
} {SQLITE_OK}
|
||||
|
||||
finish_test
|
||||
|
||||
+27
-19
@@ -28,9 +28,9 @@
|
||||
|
||||
.testcase 110
|
||||
.prompt --show
|
||||
.check <<END
|
||||
Main prompt: 'SQLite /f> '
|
||||
Continuation: '/B.../H> '
|
||||
.check --glob <<END
|
||||
Main prompt: '*/A*/f*-> '
|
||||
Continuation: '/B*/C*-> '
|
||||
END
|
||||
.testcase 111
|
||||
.prompt 'abc> ' '123> ' -show
|
||||
@@ -47,9 +47,9 @@ Continuation: '--second'
|
||||
END
|
||||
.testcase 113
|
||||
.prompt --reset --show
|
||||
.check <<END
|
||||
Main prompt: 'SQLite /f> '
|
||||
Continuation: '/B.../H> '
|
||||
.check --glob <<END
|
||||
Main prompt: '*/A*/f*> '
|
||||
Continuation: '/B*/C*> '
|
||||
END
|
||||
|
||||
.testcase 120 --error-prefix ERROR:
|
||||
@@ -64,9 +64,9 @@ END
|
||||
.check ''
|
||||
.testcase 122
|
||||
.prompt --show
|
||||
.check <<END
|
||||
.check --glob <<END
|
||||
Main prompt: 'show'
|
||||
Continuation: '/B.../H> '
|
||||
Continuation: '/B*/C*> '
|
||||
END
|
||||
|
||||
.testcase 130
|
||||
@@ -90,31 +90,31 @@ END
|
||||
|
||||
.testcase 1000
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check 'SQLite test.db> ';
|
||||
.check --glob '*SQLite-3*test.db*-> ';
|
||||
.testcase 1001
|
||||
SELECT shell_prompt_test(NULL,'SELECT');
|
||||
.check ' ...;> ';
|
||||
.check --glob ' *;*-> ';
|
||||
.testcase 1002
|
||||
SELECT shell_prompt_test(NULL,'SELECT ((("');
|
||||
.check ' ...")));> ';
|
||||
.check --glob ' *[ m]")));*-> ';
|
||||
.testcase 1003
|
||||
SELECT shell_prompt_test(NULL,'SELECT ((()[');
|
||||
.check ' ...]));> ';
|
||||
.check --glob ' *[ m]]));*-> ';
|
||||
.testcase 1004
|
||||
SELECT shell_prompt_test(NULL,'SELECT ''');
|
||||
.check " ...';> ";
|
||||
.check --glob " *[ m]';*-> ";
|
||||
.testcase 1005
|
||||
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN');
|
||||
.check " ...;END;> ";
|
||||
.check --glob " *[ m];END;*-> ";
|
||||
.testcase 1006
|
||||
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT ((([');
|
||||
.check " ...])));END;> ";
|
||||
.check --glob " *[ m]])));END;*-> ";
|
||||
.testcase 1007
|
||||
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT ((/*a(((''bc');
|
||||
.check " ...*/));END;> ";
|
||||
.check --glob " *[ m][*]/));END;*-> ";
|
||||
.testcase 1008
|
||||
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT 1;');
|
||||
.check " ...END;> ";
|
||||
.check --glob " *[ m]END;*-> ";
|
||||
|
||||
.testcase 2000
|
||||
.prompt 'SQLite/x-txn$/:>/; '
|
||||
@@ -135,6 +135,14 @@ SELECT shell_prompt_test(NULL);
|
||||
.testcase 2004
|
||||
.prompt --reset
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check 'SQLite test.db> ';
|
||||
.check --glob '*SQLite-3.# *test.db*-> ';
|
||||
|
||||
.testcase
|
||||
.testcase 3000
|
||||
SELECT shell_prompt_test('(/A-/V)');
|
||||
.check --glob '(SQLite-3.#.#)'
|
||||
.testcase 3001
|
||||
SELECT shell_prompt_test('(/A-/v)');
|
||||
.check --glob '(SQLite-3.#)'
|
||||
.testcase 3002
|
||||
SELECT shell_prompt_test('(/A-/D%Y-%m-%dT%H:%M:%S/D)');
|
||||
.check --glob '(SQLite-20#-#-#T#:#:#)'
|
||||
|
||||
+7
-1
@@ -1969,6 +1969,7 @@ proc run_testset {} {
|
||||
SELECT DISTINCT substr(svers,1,79) as v1 FROM jobs WHERE svers IS NOT NULL
|
||||
} {puts $v1}
|
||||
|
||||
return [expr {$nErr>0}]
|
||||
}
|
||||
|
||||
# If the argument is "retest", simply rerun all tests from the previous
|
||||
@@ -2028,6 +2029,7 @@ proc explain_tests {} {
|
||||
explain_layer "" ""
|
||||
}
|
||||
|
||||
set exit_status 0
|
||||
sqlite3 trdb $TRG(dbname)
|
||||
trdb timeout $TRG(timeout)
|
||||
if {[llength $TRG(patternlist)]==1 && $TRG(patternlist) eq "retest"} {
|
||||
@@ -2046,6 +2048,10 @@ if {$TRG(explain)} {
|
||||
puts "built testset in [expr $tm/1000]ms.."
|
||||
}
|
||||
handle_buildonly
|
||||
run_testset
|
||||
set exit_status [run_testset]
|
||||
}
|
||||
trdb close
|
||||
exit $exit_status
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -787,4 +787,14 @@ do_eqp_test update-21.12 {
|
||||
`--SEARCH t3 USING AUTOMATIC COVERING INDEX (x=?)
|
||||
}
|
||||
|
||||
# /forumpost/2026-04-21T19:10:55Z
|
||||
do_execsql_test update-22.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(x INT, y INT);
|
||||
INSERT INTO t1(x) VALUES(1),(2),(3),(4),(5);
|
||||
UPDATE t1 SET x=x+100, y=x<=(SELECT min(x) FROM t1)
|
||||
WHERE x<3 OR (1 BETWEEN 0 AND x<=(SELECT min(x)+2 FROM t1));
|
||||
SELECT x FROM t1 WHERE x<100 ORDER BY x;
|
||||
} {4 5}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-1
@@ -1900,7 +1900,7 @@ static void showHelp(void){
|
||||
}
|
||||
|
||||
/* work-around the Microsoft "WorstFit" bug */
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(main)
|
||||
#define main utf8_main
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user