From f62641e91cc0aee1a24ea4a3c81289e4e821c4e5 Mon Sep 17 00:00:00 2001
From: drh <>
Date: Fri, 24 Dec 2021 20:22:13 +0000
Subject: [PATCH 1/5] Add the sqlite3_error_offset() interface. Use it in the
CLI to provide better context for error messages.
FossilOrigin-Name: b518ce77439852759bc0901071f36d622b1314c9bf3d29c279dfcc405188b975
---
manifest | 31 +++++++++++++-----------
manifest.uuid | 2 +-
src/loadext.c | 2 ++
src/main.c | 13 +++++++++++
src/printf.c | 25 ++++++++++++++++++++
src/shell.c.in | 61 ++++++++++++++++++++++++++++++++++++++++++------
src/sqlite.h.in | 11 ++++++++-
src/sqlite3ext.h | 4 ++++
src/sqliteInt.h | 2 ++
src/test1.c | 29 +++++++++++++++++++++++
src/util.c | 29 ++++++++---------------
11 files changed, 167 insertions(+), 42 deletions(-)
diff --git a/manifest b/manifest
index a6c925887d..086b4676d3 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\sminor\sproblem\sin\sthe\sCLI\sintroduced\sby\s[d156123885abe6bf],\sapparently.
-D 2021-12-24T19:44:11.241
+C Add\sthe\ssqlite3_error_offset()\sinterface.\s\sUse\sit\sin\sthe\sCLI\sto\sprovide\nbetter\scontext\sfor\serror\smessages.
+D 2021-12-24T20:22:13.535
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -513,8 +513,8 @@ F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c e0293a6f686e18cb2c9dd0619a731518e0109d7e1f1db1932974659e7843cfd1
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
-F src/loadext.c e1dcff1c916bf6834e150b492eddda5d9792453182d2ad64294d2266b6e93c4c
-F src/main.c 674a0fdfc2808e1d5a78b2eefe2ec3f93428cf82f0f6c013d577df1a1caa5940
+F src/loadext.c 95db1fe62c5973f1c5d9c53f6083e21a73ece14cdd47eeca0639691332e85c4d
+F src/main.c d7719ea81cc8ea81253cb2af0603d089407ea70dd5742f53a81ee3c168186344
F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -546,21 +546,21 @@ F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
F src/pragma.c c536665ce8431c8b1efbf7e0a5c01852f49f7bf28f1954f8118b2d28e4a3797f
F src/pragma.h 87330ed2fbfa2a1274de93ca0ab850fba336189228cb256089202c3b52766fad
F src/prepare.c 40961a1170a4c4151a90dae29dd00fc6c155f1af8246abeeeb8f0a10b3fb9719
-F src/printf.c 9565aeb5af5376fd23c993b8da1ac37008fad65435a703316eef9f41229f702d
+F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
F src/resolve.c 6144db65157ff96fe27e3e6f784ab331b3de35db233cd0a6e93278a5d23fcf06
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c a7a3d9f54eb24821ec5f67f2e5589b68a5d42d46fc5849d7376886777d93a85a
-F src/shell.c.in 1b567fc5463470fb22f3e45a5dbf05ee2ce9dd9066b2973c4a2bdd7daa74bb5f
-F src/sqlite.h.in 5124aa99d3eb9b6a4e5030cb035076ed060d2dac020cd8fc8fba3022725d54af
+F src/shell.c.in c2f60a11f4a0720cd952d14ec20331543fb185a982e10a2385c5715e129369fd
+F src/sqlite.h.in a5e0d6bd47e67aabf1475986d36bdcc7bfa9e06566790ebf8e3aa7fa551c9f99
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
-F src/sqlite3ext.h 8ff2fd2c166150b2e48639f5e506fb44e29f1a3f65031710b9e89d1c126ac839
-F src/sqliteInt.h e7dd69a85c53461c937d50c97f8efd9761b14f9bcfb63450809e85c100c08538
+F src/sqlite3ext.h 01eb85e4f2759a5ee79c183f4b2877889d4ffdc49d27ae74529c9579e3c8c0ef
+F src/sqliteInt.h 418dd1a178abcc40b86b39cee972083822b17e84888fe56ed7a3b00b473d8bb5
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 48f291e1a7e672a7204884d4c164a8ed3a522ff087c361ada2991f5d54e987f6
-F src/test1.c 37b323d74aef3156394478bd09dff855332077e537b37c9a7e455c03cb04da09
+F src/test1.c c24fe3a13ff78f5cbc29ac7049123e03ee1f33c6601646a45766c5f8d5db7f92
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
@@ -620,7 +620,7 @@ F src/trigger.c 2ef56f0b7b75349a5557d0604b475126329c2e1a02432e7d49c4c710613e8254
F src/update.c d6f5c7b9e072660757ac7d58175aca11c07cb95ebbb297ae7f38853700f52328
F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
-F src/util.c 569349b0bddcbfbc661856f446adb92e1b0a47b3cbef548da9fc5aa639d7964c
+F src/util.c 89e51820bcb468ff3877a8d942f5cc807208087f021227e0927693e928a195bc
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
F src/vdbe.c b63594839cbf770a29e2b3b81570971a3d2c1c995c0586aade09bb548142113a
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
@@ -1934,8 +1934,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 8af8c153f8c3fe16db1c2280571e005838c4ea3c48929ad7660a1686e49ed255
-R b3820a24a997ecbc0d96c676f9253e0d
+P 37e6e10f4364f556c7503c80408fc62895cdccdd0372fb2b63aaca02c3a1ee30
+R dc8a0d1713a6a184c2032656b8115b23
+T *branch * improved-error-context
+T *sym-improved-error-context *
+T -sym-trunk *
U drh
-Z 32815daf40ab0d51da0a9e14b1eae912
+Z 3c3faf346f54edef0799304c35a23ad2
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index b59febd5a3..4479c72102 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-37e6e10f4364f556c7503c80408fc62895cdccdd0372fb2b63aaca02c3a1ee30
\ No newline at end of file
+b518ce77439852759bc0901071f36d622b1314c9bf3d29c279dfcc405188b975
\ No newline at end of file
diff --git a/src/loadext.c b/src/loadext.c
index 4edefec0c9..681e12c4e7 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -485,6 +485,8 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_total_changes64,
/* Version 3.37.0 and later */
sqlite3_autovacuum_pages,
+ /* Version 3.38.0 and later */
+ sqlite3_error_offset,
};
/* True if x is the directory separator character
diff --git a/src/main.c b/src/main.c
index 1b7853f609..07c67d33d7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2597,6 +2597,19 @@ const char *sqlite3_errmsg(sqlite3 *db){
return z;
}
+/*
+** Return the byte offset of the most recent error
+*/
+int sqlite3_error_offset(sqlite3 *db){
+ int iOffset = -1;
+ if( db && sqlite3SafetyCheckSickOrOk(db) ){
+ sqlite3_mutex_enter(db->mutex);
+ iOffset = db->errByteOffset;
+ sqlite3_mutex_leave(db->mutex);
+ }
+ return iOffset;
+}
+
#ifndef SQLITE_OMIT_UTF16
/*
** Return UTF-16 encoded English language explanation of the most recent
diff --git a/src/printf.c b/src/printf.c
index 6128e5cb4c..9fea2d6ef0 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -855,6 +855,7 @@ void sqlite3_str_vappendf(
assert( bArgList==0 );
if( pToken && pToken->n ){
sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n);
+ sqlite3RecordErrorByteOffset(pAccum->db, pToken->z);
}
length = width = 0;
break;
@@ -909,6 +910,30 @@ void sqlite3_str_vappendf(
}/* End for loop over the format string */
} /* End of function */
+
+/*
+** The z string points to the first character of a token that is
+** associated with an error. If db does not already have an error
+** byte offset recorded, try to compute the error byte offset for
+** z and set the error byte offset in db.
+*/
+void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){
+ const Parse *pParse;
+ const char *zText;
+ const char *zEnd;
+ assert( z!=0 );
+ if( NEVER(db==0) ) return;
+ if( db->errByteOffset!=(-2) ) return;
+ pParse = db->pParse;
+ if( NEVER(pParse==0) ) return;
+ zText =pParse->zTail;
+ if( NEVER(zText==0) ) return;
+ zEnd = &zText[strlen(zText)];
+ if( SQLITE_WITHIN(z,zText,zEnd) ){
+ db->errByteOffset = (int)(z-zText);
+ }
+}
+
/*
** Enlarge the memory allocation on a StrAccum object so that it is
** able to accept at least N more bytes of text.
diff --git a/src/shell.c.in b/src/shell.c.in
index c6f623f5b7..c8d7692560 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -2519,6 +2519,47 @@ static void set_table_name(ShellState *p, const char *zName){
z[n] = 0;
}
+/*
+** Maybe construct two lines of text that point out the position of a
+** syntax error. Return a pointer to the text, in memory obtained from
+** sqlite3_malloc(). Or, if the most recent error does not involve a
+** specific token that we can point to, return an empty string.
+**
+** In all cases, the memory returned is obtained from sqlite3_malloc64()
+** and should be released by the caller invoking sqlite3_free().
+*/
+static char *shell_error_context(const char *zSql, sqlite3 *db){
+ int iOffset;
+ size_t len;
+ char *zCode;
+ char *zMsg;
+ int i;
+ if( db==0
+ || zSql==0
+ || (iOffset = sqlite3_error_offset(db))<0
+ ){
+ return sqlite3_mprintf("");
+ }
+ while( iOffset>50 ){
+ iOffset--;
+ zSql++;
+ while( (zSql[0]&0xc0)==0x80 ){ zSql++; iOffset--; }
+ }
+ len = strlen(zSql);
+ if( len>78 ){
+ len = 78;
+ while( (zSql[len]&0xc0)==0x80 ) len--;
+ }
+ zCode = sqlite3_mprintf("%.*s", len, zSql);
+ for(i=0; zCode[i]; i++){ if( IsSpace(zSql[i]) ) zCode[i] = ' '; }
+ if( iOffset<25 ){
+ zMsg = sqlite3_mprintf("\n %z\n %*s^--- error here", zCode, iOffset, "");
+ }else{
+ zMsg = sqlite3_mprintf("\n %z\n %*serror here ---^", zCode, iOffset-14, "");
+ }
+ return zMsg;
+}
+
/*
** Execute a query statement that will generate SQL output. Print
@@ -2541,8 +2582,10 @@ static int run_table_dump_query(
const char *z;
rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
- utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
- sqlite3_errmsg(p->db));
+ char *zContext = shell_error_context(zSelect, p->db);
+ utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n%s", rc,
+ sqlite3_errmsg(p->db), zContext);
+ sqlite3_free(zContext);
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
return rc;
}
@@ -2578,12 +2621,16 @@ static int run_table_dump_query(
static char *save_err_msg(
sqlite3 *db, /* Database to query */
const char *zWhen, /* Qualifier (format) wrapper */
- int rc /* Error code returned from API */
+ int rc, /* Error code returned from API */
+ const char *zSql /* SQL string, or NULL */
){
char *zErr;
- if( zWhen==0 ) zWhen = "%s (%d)";
- zErr = sqlite3_mprintf(zWhen, sqlite3_errmsg(db), rc);
+ char *zContext;
+ if( zWhen==0 ) zWhen = "%s (%d)%s";
+ zContext = shell_error_context(zSql, db);
+ zErr = sqlite3_mprintf(zWhen, sqlite3_errmsg(db), rc, zContext);
shell_check_oom(zErr);
+ sqlite3_free(zContext);
return zErr;
}
@@ -3518,7 +3565,7 @@ static int shell_exec(
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
if( SQLITE_OK != rc ){
if( pzErrMsg ){
- *pzErrMsg = save_err_msg(db, "in prepare, %s (%d)", rc);
+ *pzErrMsg = save_err_msg(db, "in prepare, %s (%d)%s", rc, zSql);
}
}else{
if( !pStmt ){
@@ -3634,7 +3681,7 @@ static int shell_exec(
zSql = zLeftover;
while( IsSpace(zSql[0]) ) zSql++;
}else if( pzErrMsg ){
- *pzErrMsg = save_err_msg(db, "stepping, %s (%d)", rc);
+ *pzErrMsg = save_err_msg(db, "stepping, %s (%d)", rc, 0);
}
/* clear saved stmt handle */
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 3c92503a11..3aad3690a2 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -3824,13 +3824,14 @@ void sqlite3_free_filename(char*);
** sqlite3_extended_errcode() might change with each API call.
** Except, there are some interfaces that are guaranteed to never
** change the value of the error code. The error-code preserving
-** interfaces are:
+** interfaces include the following:
**
**
** - sqlite3_errcode()
**
- sqlite3_extended_errcode()
**
- sqlite3_errmsg()
**
- sqlite3_errmsg16()
+**
- sqlite3_error_offset()
**
**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
@@ -3845,6 +3846,13 @@ void sqlite3_free_filename(char*);
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
+** ^If the most recent error references a specific token in the input
+** SQL, the sqlite3_error_offset() interface returns the byte offset
+** of the start of that token. ^The byte offset returned by
+** sqlite3_error_offset() assumes that the input SQL is UTF8.
+** ^If the most error does not reference a specific token in the input
+** SQL, then the sqlite3_error_offset() function returns -1.
+**
** When the serialized [threading mode] is in use, it might be the
** case that a second error occurs on a separate thread in between
** the time of the first error and the call to these interfaces.
@@ -3864,6 +3872,7 @@ int sqlite3_extended_errcode(sqlite3 *db);
const char *sqlite3_errmsg(sqlite3*);
const void *sqlite3_errmsg16(sqlite3*);
const char *sqlite3_errstr(int);
+int sqlite3_error_offset(sqlite3 *db);
/*
** CAPI3REF: Prepared Statement Object
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index 9767daa01d..5b82346227 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -344,6 +344,8 @@ struct sqlite3_api_routines {
int (*autovacuum_pages)(sqlite3*,
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
void*, void(*)(void*));
+ /* Version 3.38.0 and later */
+ int (*error_offset)(sqlite3*);
};
/*
@@ -655,6 +657,8 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_total_changes64 sqlite3_api->total_changes64
/* Version 3.37.0 and later */
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
+/* Version 3.38.0 and later */
+#define sqlite3_error_offset sqlite3_api->error_offset
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 48a94a7b33..092bbccdc6 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1527,6 +1527,7 @@ struct sqlite3 {
u32 nSchemaLock; /* Do not reset the schema when non-zero */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
+ int errByteOffset; /* Byte offset of error in SQL statement */
int errMask; /* & result codes with this before returning */
int iSysErrno; /* Errno value from last system error */
u32 dbOptFlags; /* Flags to enable/disable optimizations */
@@ -4977,6 +4978,7 @@ void sqlite3StrAccumSetError(StrAccum*, u8);
void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
void sqlite3SelectDestInit(SelectDest*,int,int);
Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
+void sqlite3RecordErrorByteOffset(sqlite3*,const char*);
void sqlite3BackupRestart(sqlite3_backup *);
void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
diff --git a/src/test1.c b/src/test1.c
index 8cdb7b285e..84d888ff37 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -4366,6 +4366,34 @@ static int SQLITE_TCLAPI test_errmsg(
return TCL_OK;
}
+
+/*
+** Usage: sqlite3_error_offset DB
+**
+** Return the byte offset into the input UTF8 SQL for the most recent
+** error, or -1 of the error does not refer to a specific token.
+*/
+static int SQLITE_TCLAPI test_error_offset(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+ int iByteOffset;
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+
+ iByteOffset = sqlite3_error_offset(db);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(zErr, -1));
+ return TCL_OK;
+}
+
/*
** Usage: test_errmsg16 DB
**
@@ -8422,6 +8450,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_errcode", test_errcode ,0 },
{ "sqlite3_extended_errcode", test_ex_errcode ,0 },
{ "sqlite3_errmsg", test_errmsg ,0 },
+ { "sqlite3_error_offset", test_error_offset ,0 },
{ "sqlite3_errmsg16", test_errmsg16 ,0 },
{ "sqlite3_open", test_open ,0 },
{ "sqlite3_open16", test_open16 ,0 },
diff --git a/src/util.c b/src/util.c
index 8ea951fa16..dec205df43 100644
--- a/src/util.c
+++ b/src/util.c
@@ -117,7 +117,11 @@ static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){
void sqlite3Error(sqlite3 *db, int err_code){
assert( db!=0 );
db->errCode = err_code;
- if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
+ if( err_code || db->pErr ){
+ sqlite3ErrorFinish(db, err_code);
+ }else{
+ db->errByteOffset = -1;
+ }
}
/*
@@ -127,6 +131,7 @@ void sqlite3Error(sqlite3 *db, int err_code){
void sqlite3ErrorClear(sqlite3 *db){
assert( db!=0 );
db->errCode = SQLITE_OK;
+ db->errByteOffset = -1;
if( db->pErr ) sqlite3ValueSetNull(db->pErr);
}
@@ -147,17 +152,8 @@ void sqlite3SystemError(sqlite3 *db, int rc){
** handle "db". The error code is set to "err_code".
**
** If it is not NULL, string zFormat specifies the format of the
-** error string in the style of the printf functions: The following
-** format characters are allowed:
-**
-** %s Insert a string
-** %z A string that should be freed after use
-** %d Insert an integer
-** %T Insert a token
-** %S Insert the first element of a SrcList
-**
-** zFormat and any string tokens that follow it are assumed to be
-** encoded in UTF-8.
+** error string. zFormat and any string tokens that follow it are
+** assumed to be encoded in UTF-8.
**
** To clear the most recent error for sqlite handle "db", sqlite3Error
** should be called with err_code set to SQLITE_OK and zFormat set
@@ -181,13 +177,6 @@ void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
/*
** Add an error message to pParse->zErrMsg and increment pParse->nErr.
-** The following formatting characters are allowed:
-**
-** %s Insert a string
-** %z A string that should be freed after use
-** %d Insert an integer
-** %T Insert a token
-** %S Insert the first element of a SrcList
**
** This function should be used to report any error that occurs while
** compiling an SQL statement (i.e. within sqlite3_prepare()). The
@@ -200,9 +189,11 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
char *zMsg;
va_list ap;
sqlite3 *db = pParse->db;
+ db->errByteOffset = -2;
va_start(ap, zFormat);
zMsg = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
+ if( db->errByteOffset<-1 ) db->errByteOffset = -1;
if( db->suppressErr ){
sqlite3DbFree(db, zMsg);
}else{
From 5cec7e1a5fdde96c2386a6c40e488e58ebc2b78a Mon Sep 17 00:00:00 2001
From: drh <>
Date: Sat, 25 Dec 2021 00:19:46 +0000
Subject: [PATCH 2/5] One minor change for an exceptional case in
sqlite3_error_offset().
FossilOrigin-Name: c93609a8b9dc2e656bb4360138606e269fd323469f7666dbc3bbc699e431313e
---
manifest | 15 ++++++---------
manifest.uuid | 2 +-
src/main.c | 2 +-
3 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/manifest b/manifest
index 086b4676d3..6cd01d0137 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\ssqlite3_error_offset()\sinterface.\s\sUse\sit\sin\sthe\sCLI\sto\sprovide\nbetter\scontext\sfor\serror\smessages.
-D 2021-12-24T20:22:13.535
+C One\sminor\schange\sfor\san\sexceptional\scase\sin\ssqlite3_error_offset().
+D 2021-12-25T00:19:46.998
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -514,7 +514,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c e0293a6f686e18cb2c9dd0619a731518e0109d7e1f1db1932974659e7843cfd1
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 95db1fe62c5973f1c5d9c53f6083e21a73ece14cdd47eeca0639691332e85c4d
-F src/main.c d7719ea81cc8ea81253cb2af0603d089407ea70dd5742f53a81ee3c168186344
+F src/main.c aa24539f6c26460543d51027ea14b79cad35e34bc9d4907bc349b52b71066644
F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -1934,11 +1934,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 37e6e10f4364f556c7503c80408fc62895cdccdd0372fb2b63aaca02c3a1ee30
-R dc8a0d1713a6a184c2032656b8115b23
-T *branch * improved-error-context
-T *sym-improved-error-context *
-T -sym-trunk *
+P b518ce77439852759bc0901071f36d622b1314c9bf3d29c279dfcc405188b975
+R 8f03bf9f6f19504237d0970665f639d4
U drh
-Z 3c3faf346f54edef0799304c35a23ad2
+Z 4eae18cf6b28cc5b2fc2672ed68ce869
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 4479c72102..45b61f562d 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-b518ce77439852759bc0901071f36d622b1314c9bf3d29c279dfcc405188b975
\ No newline at end of file
+c93609a8b9dc2e656bb4360138606e269fd323469f7666dbc3bbc699e431313e
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 07c67d33d7..be73f6df65 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2602,7 +2602,7 @@ const char *sqlite3_errmsg(sqlite3 *db){
*/
int sqlite3_error_offset(sqlite3 *db){
int iOffset = -1;
- if( db && sqlite3SafetyCheckSickOrOk(db) ){
+ if( db && sqlite3SafetyCheckSickOrOk(db) && db->errCode ){
sqlite3_mutex_enter(db->mutex);
iOffset = db->errByteOffset;
sqlite3_mutex_leave(db->mutex);
From d66d5c2d353d031d4125ac80f840741a264d91c2 Mon Sep 17 00:00:00 2001
From: drh <>
Date: Sat, 25 Dec 2021 23:59:54 +0000
Subject: [PATCH 3/5] Change an assert() in FTS3 into assert_fts3_nc(), since
it is a harmless condition that can occur when processing a corrupt database
file.
FossilOrigin-Name: c03205aee9015fd886b8db02c8190899cee699255ca370f939e547deaf5ba9e8
---
ext/fts3/fts3.c | 2 +-
manifest | 13 ++++++-------
manifest.uuid | 2 +-
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index 9a341a89a0..097338f547 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -4486,7 +4486,7 @@ void sqlite3Fts3DoclistPrev(
assert( nDoclist>0 );
assert( *pbEof==0 );
- assert( p || *piDocid==0 );
+ assert_fts3_nc( p || *piDocid==0 );
assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) );
if( p==0 ){
diff --git a/manifest b/manifest
index 1e06248283..0a9e781a33 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\ssqlite3_error_offset()\sinterface.\s\sUse\sit\sto\senhance\serror\sreporting\nin\sthe\sCLI.
-D 2021-12-25T00:26:51.340
+C Change\san\sassert()\sin\sFTS3\sinto\sassert_fts3_nc(),\ssince\sit\sis\sa\sharmless\ncondition\sthat\scan\soccur\swhen\sprocessing\sa\scorrupt\sdatabase\sfile.
+D 2021-12-25T23:59:54.620
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -84,7 +84,7 @@ F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c f27e890395640be4938b9b554cad46fdf1e42e6bd7d64154bbac27d079d00f9e
+F ext/fts3/fts3.c 6634a3854e70afa8710ee5e3a7253cd0f0c89d4cce207fcbfe2ead3bad1db7d5
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h dafdc371f9fbab175744b06cfe019d5f040cdfdbd11fea752f5dc28d45b04c05
F ext/fts3/fts3_aux.c f0dc9bd98582615b7750218899bd0c729879b6bbf94d1be57ca1833ff49afc6f
@@ -1934,9 +1934,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 37e6e10f4364f556c7503c80408fc62895cdccdd0372fb2b63aaca02c3a1ee30 c93609a8b9dc2e656bb4360138606e269fd323469f7666dbc3bbc699e431313e
-R 8f03bf9f6f19504237d0970665f639d4
-T +closed c93609a8b9dc2e656bb4360138606e269fd323469f7666dbc3bbc699e431313e
+P 7fa20ca4c09ab0249de0363691541fa836120ec277e72feb0e1516b9bfbdd97a
+R 2b2719b5920685e35cd64747f22d50b0
U drh
-Z 6c4e7daae6067f5d0876bbf1b0ae2412
+Z 595d1de7ae7f6fab7b1ff88e1ba1b7f2
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index f50d0ac9ba..8a9e02a19f 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-7fa20ca4c09ab0249de0363691541fa836120ec277e72feb0e1516b9bfbdd97a
\ No newline at end of file
+c03205aee9015fd886b8db02c8190899cee699255ca370f939e547deaf5ba9e8
\ No newline at end of file
From a2ba25b508d0442e2b1fd7b9eb8f184e61957f83 Mon Sep 17 00:00:00 2001
From: larrybr
Date: Tue, 28 Dec 2021 05:08:38 +0000
Subject: [PATCH 4/5] Make .read's help tell of piped input
FossilOrigin-Name: e4ddcd8aa582c1130c34e9f05cd3e5f96ebf03c97a36c09ca442e3612fee4a20
---
manifest | 14 +++++++-------
manifest.uuid | 2 +-
src/shell.c.in | 3 ++-
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/manifest b/manifest
index 0a9e781a33..8e741d300c 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Change\san\sassert()\sin\sFTS3\sinto\sassert_fts3_nc(),\ssince\sit\sis\sa\sharmless\ncondition\sthat\scan\soccur\swhen\sprocessing\sa\scorrupt\sdatabase\sfile.
-D 2021-12-25T23:59:54.620
+C Make\s.read's\shelp\stell\sof\spiped\sinput
+D 2021-12-28T05:08:38.128
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -551,7 +551,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
F src/resolve.c 6144db65157ff96fe27e3e6f784ab331b3de35db233cd0a6e93278a5d23fcf06
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c a7a3d9f54eb24821ec5f67f2e5589b68a5d42d46fc5849d7376886777d93a85a
-F src/shell.c.in c2f60a11f4a0720cd952d14ec20331543fb185a982e10a2385c5715e129369fd
+F src/shell.c.in 41b0e1f3a0c2443cb0a8d25e5d40529c911c574b5fe5a91dc54e19f90947a359
F src/sqlite.h.in a5e0d6bd47e67aabf1475986d36bdcc7bfa9e06566790ebf8e3aa7fa551c9f99
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 01eb85e4f2759a5ee79c183f4b2877889d4ffdc49d27ae74529c9579e3c8c0ef
@@ -1934,8 +1934,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 7fa20ca4c09ab0249de0363691541fa836120ec277e72feb0e1516b9bfbdd97a
-R 2b2719b5920685e35cd64747f22d50b0
-U drh
-Z 595d1de7ae7f6fab7b1ff88e1ba1b7f2
+P c03205aee9015fd886b8db02c8190899cee699255ca370f939e547deaf5ba9e8
+R 035fc7ecc447249d615762da61b11d6c
+U larrybr
+Z a3c99601a959abd1cb8e7bea62bdef11
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 8a9e02a19f..7aef9d428e 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-c03205aee9015fd886b8db02c8190899cee699255ca370f939e547deaf5ba9e8
\ No newline at end of file
+e4ddcd8aa582c1130c34e9f05cd3e5f96ebf03c97a36c09ca442e3612fee4a20
\ No newline at end of file
diff --git a/src/shell.c.in b/src/shell.c.in
index c8d7692560..1bc57873da 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -4147,7 +4147,8 @@ static const char *(azHelp[]) = {
#endif
".prompt MAIN CONTINUE Replace the standard prompts",
".quit Exit this program",
- ".read FILE Read input from FILE",
+ ".read FILE Read input from FILE or command output",
+ " If FILE begins with \"|\", it is a command that generates the input.",
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
".recover Recover as much data as possible from corrupt db.",
" --freelist-corrupt Assume the freelist is corrupt",
From 9169d0cb0f8dcf3f5594f5520e5c9607fa90cbae Mon Sep 17 00:00:00 2001
From: drh <>
Date: Wed, 29 Dec 2021 04:08:11 +0000
Subject: [PATCH 5/5] Fix the build-breaker bug in test1.c introduced by
check-in [7fa20ca4c09ab024].
FossilOrigin-Name: 5f804da1820c98e7ff5c377e57e30b5154844b92ce622ed2ff888fe2c887e1ca
---
manifest | 14 +++++++-------
manifest.uuid | 2 +-
src/test1.c | 2 +-
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/manifest b/manifest
index 8e741d300c..7b690ae778 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\s.read's\shelp\stell\sof\spiped\sinput
-D 2021-12-28T05:08:38.128
+C Fix\sthe\sbuild-breaker\sbug\sin\stest1.c\sintroduced\sby\scheck-in\s[7fa20ca4c09ab024].
+D 2021-12-29T04:08:11.285
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -560,7 +560,7 @@ F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a3
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 48f291e1a7e672a7204884d4c164a8ed3a522ff087c361ada2991f5d54e987f6
-F src/test1.c c24fe3a13ff78f5cbc29ac7049123e03ee1f33c6601646a45766c5f8d5db7f92
+F src/test1.c a02b46f382baadfdfb1a541caf55a26aae44619ad0cff4f6d27eeca84594636a
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
@@ -1934,8 +1934,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P c03205aee9015fd886b8db02c8190899cee699255ca370f939e547deaf5ba9e8
-R 035fc7ecc447249d615762da61b11d6c
-U larrybr
-Z a3c99601a959abd1cb8e7bea62bdef11
+P e4ddcd8aa582c1130c34e9f05cd3e5f96ebf03c97a36c09ca442e3612fee4a20
+R 258b3a6c81183d6fd1aebc821d3d480b
+U drh
+Z c81e1f18d29297bc5455db4d8770f644
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 7aef9d428e..9adea975c1 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-e4ddcd8aa582c1130c34e9f05cd3e5f96ebf03c97a36c09ca442e3612fee4a20
\ No newline at end of file
+5f804da1820c98e7ff5c377e57e30b5154844b92ce622ed2ff888fe2c887e1ca
\ No newline at end of file
diff --git a/src/test1.c b/src/test1.c
index 84d888ff37..520f4145ef 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -4390,7 +4390,7 @@ static int SQLITE_TCLAPI test_error_offset(
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
iByteOffset = sqlite3_error_offset(db);
- Tcl_SetObjResult(interp, Tcl_NewIntObj(zErr, -1));
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(iByteOffset));
return TCL_OK;
}