-C Improvements\sto\sthe\sway\s\x\sworks\sso\sthat\sit\scan\sbe\sused\sto\schange\nthe\sprompt\scolor.\s\sThis\sreally\smesses\swith\slinenoise,\sthough.
-D 2026-04-10T00:55:40.521
+C Prototype\ssqlite3_incomplete()\s-\sa\svariant\sof\ssqlite3_complete()\sthat\sreturns\nadditional\sinformation\sabout\swhat\sis\sneeded\sto\scomplete\sthe\sstatement.
+D 2026-04-10T13:43:48.738
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/build.c 8581de0af3b6c448f5d64e2d18a91ac1e7057b3bcb8b8827e1240f80d87486a4
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
-F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
+F src/complete.c 9304071c5f2ddd040cd786ec5d157c6a5592561674816e4a9e74164a0ba40647
F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
F src/shell.c.in 2bbbb04153354fe3d11677d69ce7b6d5bfe8113e2d3693791915590eaa4f1bce
-F src/sqlite.h.in e2915e4a86d5e0783afb5cb72411df38d987c7f3c5aa2d5441b8e74d30b649d8
+F src/sqlite.h.in a5605faa9479bbaac16c4ab43eb09ff50632004a8e05084d3fde56063ef73766
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 9cf28959671920b4909521bb1db6f0cbbc85448fbf3594c43b4000505b4e055b
-R 1af695b623ae09a49f6867ddfb6fa639
+P bbee56f970ade40734c8a278f46d8a268b305fe349c3739c977fa9141d2c3b6a
+R 12cd07af606e611ea7f41e67ab10d130
U drh
-Z 856f286521a626031b862b8cbac557c5
+Z 547b407658ddec4e488d7004be7d0be4
# Remove this line to create a well-formed Fossil manifest.
-bbee56f970ade40734c8a278f46d8a268b305fe349c3739c977fa9141d2c3b6a
+a698fbfb8bb256ee0d9802c01562c11492ca2800a45360b268ac6cf397a7fad7
#endif
/*
-** Return TRUE if the given SQL string ends in a semicolon.
+** Return zero if the given SQL string is complete - if all comments,
+** string and blob literals, and quoted identifiers have been closed and
+** if the entire string ends with ";" and possible with ";END;" if the
+** string is a CREATE TRIGGER statement. A non-zero return indicates
+** that the string is incomplete. Bits of the return value indicate
+** what is missing and is needed to close out the statement.
**
** Special handling is require for CREATE TRIGGER statements.
** Whenever the CREATE TRIGGER keywords are seen, the statement
** must end with ";END;".
**
+** Let the return code be a value R. R is split up into various
+** subfields, at byte boundaries:
+**
+** R = 0xwwwwwwww00xxyyzz
+**
+** In other words, zz is the least significant byte, yy is the next
+** most significant byte, xx is the third byte, wwwwwwww is a 32-bit
+** value from the middle.
+**
+** zz == SQLITE_OK Input is complete
+** zz == SQLITE_ERROR Input is incomplete
+** zz == SQLITE_MISUSE Input is a NULL pointer
+** zz != 0 New values for zz may be added in the future
+**
+** yy == 0x01 Need a semicolon at the end
+** yy == 0x02 Need "END" and a semicolon
+** yy == 0x03 Need semicolon, "END", and semicolon
+** yy != 0 New values for yy may be added in the future
+**
+** xx == '\'' Incomplete string or blob literal
+** xx == '"' Incomplete quoted identifier
+** xx == '`' Incompelte MySQL-style quoted identifier
+** xx == ']' Incomplete SQLServer-style quoted identifer
+** xx == '-' Incomplete SQL-style comment
+** xx == '/' Incomplete C-style comment
+** xx != 0 New values of xx may be added in the future
+**
+** wwwwwwww Interpret as a signed integer, the number
+** of unmatched "(". Negative means there are
+** more ")" and "(".
+**
+** ((R>>24)&0xff)!=0 New uses for the 4th byte may be added
+** in the future
+**
** This implementation uses a state machine with 8 states:
**
** (0) INVALID We have not yet seen a non-whitespace character.
** to recognize the end of a trigger can be omitted. All we have to do
** is look for a semicolon that is not part of an string or comment.
*/
-int sqlite3_complete(const char *zSql){
+sqlite3_int64 sqlite3_incomplete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
+ u8 pending = 0; /* unmatched structure character */
+ int nParen = 0; /* Nested parentheses */
#ifndef SQLITE_OMIT_TRIGGER
/* A complex statement machine used to detect the end of a CREATE TRIGGER
/* 2 NORMAL: */ { 1, 2, 2, },
};
#endif /* SQLITE_OMIT_TRIGGER */
+ /* Mapping state number to yy value for the return */
+ static const u8 statemap[8] = {
+ /* 0 INVALID */ 1,
+ /* 1 START */ 0,
+ /* 2 NORMAL */ 1,
+ /* 3 EXPLAIN */ 1,
+ /* 4 CREATE */ 1,
+ /* 5 TRIGGER */ 3,
+ /* 6 SEMI */ 2,
+ /* 7 END */ 1,
+ };
#ifdef SQLITE_ENABLE_API_ARMOR
if( zSql==0 ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
+ return SQLITE_MISUSE_BKPT;
}
#endif
}
zSql += 2;
while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
- if( zSql[0]==0 ) return 0;
+ if( zSql[0]==0 ){
+ pending = '/';
+ goto incomplete_finish;
+ }
zSql++;
token = tkWS;
break;
break;
}
while( *zSql && *zSql!='\n' ){ zSql++; }
- if( *zSql==0 ) return state==1;
+ if( *zSql==0 ){
+ if( state!=1 ) pending = '-';
+ goto incomplete_finish;
+ }
token = tkWS;
break;
}
case '[': { /* Microsoft-style identifiers in [...] */
zSql++;
while( *zSql && *zSql!=']' ){ zSql++; }
- if( *zSql==0 ) return 0;
+ if( *zSql==0 ){
+ pending = ']';
+ goto incomplete_finish;
+ }
token = tkOTHER;
break;
}
int c = *zSql;
zSql++;
while( *zSql && *zSql!=c ){ zSql++; }
- if( *zSql==0 ) return 0;
+ if( *zSql==0 ){
+ pending = c;
+ goto incomplete_finish;
+ }
+ token = tkOTHER;
+ break;
+ }
+ case '(': {
+ nParen++;
+ token = tkOTHER;
+ break;
+ }
+ case ')': {
+ nParen--;
token = tkOTHER;
break;
}
state = trans[state][token];
zSql++;
}
- return state==1;
+incomplete_finish:
+ if( state==1 ) nParen = 0;
+ return (((i64)nParen)<<32) |
+ ((i64)pending<<16) |
+ ((i64)statemap[state]<<8) |
+ (state!=1);
+}
+int sqlite3_complete(const char *zSql){
+ return sqlite3_incomplete(zSql)==0;
}
#ifndef SQLITE_OMIT_UTF16
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zSql8 ){
- rc = sqlite3_complete(zSql8);
+ rc = sqlite3_incomplete(zSql8)==0;
}else{
rc = SQLITE_NOMEM_BKPT;
}
** These routines are useful during command-line input to determine if the
** currently entered text seems to form a complete SQL statement or
** if additional input is needed before sending the text into
-** SQLite for parsing. ^These routines return 1 if the input string
-** appears to be a complete SQL statement. ^A statement is judged to be
+** SQLite for parsing. ^The sqlite3_complete(X) and sqlite3_complete16(X)
+** routines return 1 if the input string X appears to be a complete SQL
+** statement. ^A statement is judged to be
** complete if it ends with a semicolon token and is not a prefix of a
** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within
** string literals or quoted identifier names or comments are not
** embedded) and thus do not count as a statement terminator. ^Whitespace
** and comments that follow the final semicolon are ignored.
**
-** ^These routines return 0 if the statement is incomplete. ^If a
-** memory allocation fails, then SQLITE_NOMEM is returned.
+** ^The sqlite3_complete(X) and sqlite3_complete16(X) routines return 0
+** if the statement is incomplete. ^If a memory allocation fails, then
+** SQLITE_NOMEM is returned.
**
-** ^These routines do not parse the SQL statements and thus
-** will not detect syntactically incorrect SQL.
+** The [sqlite3_incomplete(X)] routine is similar to [sqlite3_complete(X)]
+** except that sqlite3_incomplete(X) returns 0 if the input X is complete
+** and non-zero if X is incomplete. The non-zero return from
+** sqlite3_incomplete(X) contains additional information about what is
+** needed to complete the input X. The sqlite3_incomplete(X) interface
+** is only available for UTF-8 text.
+**
+** ^None of these routines do a full parse the SQL statements and thus
+** will not detect syntactically incorrect SQL. They only determine if
+** input text has properly terminated comments, string literals, and
+** quoted identifiers, and if the statement ends with a semicolon.
**
** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
** then the return value from sqlite3_complete16() will be non-zero
** regardless of whether or not the input SQL is complete.)^
**
-** The input to [sqlite3_complete()] must be a zero-terminated
-** UTF-8 string.
+** The X input to [sqlite3_complete(X)] and [sqlite3_incomplete(X)
+** must be a zero-terminated UTF-8 string.
**
** The input to [sqlite3_complete16()] must be a zero-terminated
** UTF-16 string in native byte order.
*/
int sqlite3_complete(const char *sql);
int sqlite3_complete16(const void *sql);
+sqlite3_int64 sqlite3_incomplete(const char *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors