Speed and (slightly) simplify shell's input line early processing.
FossilOrigin-Name: a1c7f7f8e1b46440234be96e813e4c2c28150413dd95dcab5d13b9c80a202edf
This commit is contained in:
commit
866c44704f
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sthe\s"PRAGMA\stable_list"\scommand\swith\sits\scorresponding\seponymous\ntable-valued\sfunction:\s"pragma_table_list".
|
||||
D 2021-09-21T17:26:23.956
|
||||
C Speed\sand\s(slightly)\ssimplify\sshell's\sinput\sline\searly\sprocessing.
|
||||
D 2021-09-21T19:19:28.756
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -548,7 +548,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
|
||||
F src/resolve.c 42b94d37a54200707a95566eff4f7e8a380e32d080016b699f23bd79a73a5028
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c 030c3d07326708343208418c84da607752aebc13c92df929b7c68c7c08e7df54
|
||||
F src/shell.c.in b6cf46c676e89a21dd70b2dfb1312116ae4411fc8140af56c794192c1c8270f2
|
||||
F src/shell.c.in 639c01f9a743ed73beb1d4b1e982b07b731c3801811d8344063f43b11008582a
|
||||
F src/sqlite.h.in 4e977a5e2ed1a9e8987ff65a2cab5f99a4298ebf040ea5ff636e1753339ff45a
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510
|
||||
@ -1375,8 +1375,8 @@ F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test 56a7358a2a05e850e9e4aa24629db9c8975e8038dbe8debd2d95be22a5f03612
|
||||
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
|
||||
F test/shell2.test a03b835a9e7dcc1f79b471e4d62e0c85bdc4cb954a00820702603f1409553caf
|
||||
F test/shell3.test 1586a163e7918775d3c25530bf84200453f30a77cc338490389114a67352f4d9
|
||||
F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be
|
||||
F test/shell5.test 84a30b55722a95a5b72989e691c469a999ca7591e7aa00b7fabc783ea5c9a6fe
|
||||
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
|
||||
@ -1925,7 +1925,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P af5dcc9c2a3a45d10b985f6b7ea18d39c75502ed10fa6496aad787dbe8c8c3fb
|
||||
R b7f36cbc91c6a24f15ccb096ef89f4e1
|
||||
U drh
|
||||
Z cb33f0f0128d5123d146e61157efe535
|
||||
P 2c0e7ae541e9ecb86aa58fa7e7057def8aac1b1af1af1aa80b8bf2d260f9a2f9 577544c5a2f193e00e5ca55b7feae96568198019573b9b0b37e2bf4300d6d524
|
||||
R 3f0f5d8f4d6753399cf7fbd70ddb9c72
|
||||
U larrybr
|
||||
Z da72ab7831c9560c80854036f35fcf46
|
||||
|
@ -1 +1 @@
|
||||
2c0e7ae541e9ecb86aa58fa7e7057def8aac1b1af1af1aa80b8bf2d260f9a2f9
|
||||
a1c7f7f8e1b46440234be96e813e4c2c28150413dd95dcab5d13b9c80a202edf
|
151
src/shell.c.in
151
src/shell.c.in
@ -10617,38 +10617,91 @@ meta_command_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if a semicolon occurs anywhere in the first N characters
|
||||
** of string z[].
|
||||
/* Line scan result and intermediate states (supporting scan resumption)
|
||||
*/
|
||||
static int line_contains_semicolon(const char *z, int N){
|
||||
int i;
|
||||
for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
|
||||
return 0;
|
||||
}
|
||||
typedef enum {
|
||||
QSS_HasDark = 1<<CHAR_BIT, QSS_EndingSemi = 2<<CHAR_BIT,
|
||||
QSS_CharMask = (1<<CHAR_BIT)-1, QSS_ScanMask = 3<<CHAR_BIT,
|
||||
QSS_Start = 0
|
||||
} QuickScanState;
|
||||
#define QSS_SETV(qss, newst) ((newst) | ((qss) & QSS_ScanMask))
|
||||
#define QSS_INPLAIN(qss) (((qss)&QSS_CharMask)==QSS_Start)
|
||||
#define QSS_PLAINWHITE(qss) (((qss)&~QSS_EndingSemi)==QSS_Start)
|
||||
#define QSS_PLAINDARK(qss) (((qss)&~QSS_EndingSemi)==QSS_HasDark)
|
||||
#define QSS_SEMITERM(qss) (((qss)&~QSS_HasDark)==QSS_EndingSemi)
|
||||
|
||||
/*
|
||||
** Test to see if a line consists entirely of whitespace.
|
||||
** Scan line for classification to guide shell's handling.
|
||||
** The scan is resumable for subsequent lines when prior
|
||||
** return values are passed as the 2nd argument.
|
||||
*/
|
||||
static int _all_whitespace(const char *z){
|
||||
for(; *z; z++){
|
||||
if( IsSpace(z[0]) ) continue;
|
||||
if( *z=='/' && z[1]=='*' ){
|
||||
z += 2;
|
||||
while( *z && (*z!='*' || z[1]!='/') ){ z++; }
|
||||
if( *z==0 ) return 0;
|
||||
z++;
|
||||
continue;
|
||||
static QuickScanState quickscan(char *zLine, QuickScanState qss){
|
||||
char cin;
|
||||
char cWait = (char)qss; /* intentional narrowing loss */
|
||||
if( cWait==0 ){
|
||||
PlainScan:
|
||||
while (cin = *zLine++){
|
||||
if( IsSpace(cin) )
|
||||
continue;
|
||||
switch (cin){
|
||||
case '-':
|
||||
if( *zLine!='-' )
|
||||
break;
|
||||
while((cin = *++zLine)!=0 )
|
||||
if( cin=='\n')
|
||||
goto PlainScan;
|
||||
return qss;
|
||||
case ';':
|
||||
qss |= QSS_EndingSemi;
|
||||
continue;
|
||||
case '/':
|
||||
if( *zLine=='*' ){
|
||||
++zLine;
|
||||
cWait = '*';
|
||||
qss = QSS_SETV(qss, cWait);
|
||||
goto TermScan;
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
cin = ']';
|
||||
/* fall thru */
|
||||
case '`': case '\'': case '"':
|
||||
cWait = cin;
|
||||
qss = QSS_HasDark | cWait;
|
||||
goto TermScan;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
qss = (qss & ~QSS_EndingSemi) | QSS_HasDark;
|
||||
}
|
||||
if( *z=='-' && z[1]=='-' ){
|
||||
z += 2;
|
||||
while( *z && *z!='\n' ){ z++; }
|
||||
if( *z==0 ) return 1;
|
||||
continue;
|
||||
}else{
|
||||
TermScan:
|
||||
while (cin = *zLine++){
|
||||
if( cin==cWait ){
|
||||
switch( cWait ){
|
||||
case '*':
|
||||
if( *zLine != '/' )
|
||||
continue;
|
||||
++zLine;
|
||||
cWait = 0;
|
||||
qss = QSS_SETV(qss, 0);
|
||||
goto PlainScan;
|
||||
case '`': case '\'': case '"':
|
||||
if(*zLine==cWait){
|
||||
++zLine;
|
||||
continue;
|
||||
}
|
||||
/* fall thru */
|
||||
case ']':
|
||||
cWait = 0;
|
||||
qss = QSS_SETV(qss, 0);
|
||||
goto PlainScan;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return qss;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -10656,16 +10709,15 @@ static int _all_whitespace(const char *z){
|
||||
** than a semi-colon. The SQL Server style "go" command is understood
|
||||
** as is the Oracle "/".
|
||||
*/
|
||||
static int line_is_command_terminator(const char *zLine){
|
||||
static int line_is_command_terminator(char *zLine){
|
||||
while( IsSpace(zLine[0]) ){ zLine++; };
|
||||
if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
|
||||
return 1; /* Oracle */
|
||||
}
|
||||
if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
|
||||
&& _all_whitespace(&zLine[2]) ){
|
||||
return 1; /* SQL Server */
|
||||
}
|
||||
return 0;
|
||||
if( zLine[0]=='/' )
|
||||
zLine += 1; /* Oracle */
|
||||
else if ( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' )
|
||||
zLine += 2; /* SQL Server */
|
||||
else
|
||||
return 0;
|
||||
return quickscan(zLine,QSS_Start)==QSS_Start;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -10748,7 +10800,7 @@ static int process_input(ShellState *p){
|
||||
int rc; /* Error code */
|
||||
int errCnt = 0; /* Number of errors seen */
|
||||
int startline = 0; /* Line number for start of current input */
|
||||
int bAllWhite = 1; /* Accumulated line empty or all whitespace */
|
||||
QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
|
||||
|
||||
p->lineno = 0;
|
||||
while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
|
||||
@ -10764,14 +10816,17 @@ static int process_input(ShellState *p){
|
||||
seenInterrupt = 0;
|
||||
}
|
||||
p->lineno++;
|
||||
if( _all_whitespace(zLine) ){
|
||||
if( nSql==0 ){
|
||||
if( ShellHasFlag(p, SHFLG_Echo) )
|
||||
printf("%s\n", zLine);
|
||||
continue;
|
||||
}
|
||||
}else{
|
||||
bAllWhite = 0;
|
||||
if( QSS_INPLAIN(qss)
|
||||
&& line_is_command_terminator(zLine)
|
||||
&& line_is_complete(zSql, nSql) ){
|
||||
memcpy(zLine,";",2);
|
||||
}
|
||||
qss = quickscan(zLine, qss);
|
||||
if( QSS_PLAINWHITE(qss) && nSql==0 ){
|
||||
if( ShellHasFlag(p, SHFLG_Echo) )
|
||||
printf("%s\n", zLine);
|
||||
/* Just swallow leading whitespace */
|
||||
continue;
|
||||
}
|
||||
if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
|
||||
if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
|
||||
@ -10785,9 +10840,6 @@ static int process_input(ShellState *p){
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
|
||||
memcpy(zLine,";",2);
|
||||
}
|
||||
nLine = strlen30(zLine);
|
||||
if( nSql+nLine+2>=nAlloc ){
|
||||
/* Grow buffer by half-again increments when big. */
|
||||
@ -10808,8 +10860,7 @@ static int process_input(ShellState *p){
|
||||
memcpy(zSql+nSql, zLine, nLine+1);
|
||||
nSql += nLine;
|
||||
}
|
||||
if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
|
||||
&& sqlite3_complete(zSql) ){
|
||||
if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
|
||||
errCnt += runOneSqlLine(p, zSql, p->in, startline);
|
||||
nSql = 0;
|
||||
if( p->outCount ){
|
||||
@ -10819,12 +10870,12 @@ static int process_input(ShellState *p){
|
||||
clearTempFile(p);
|
||||
}
|
||||
p->bSafeMode = p->bSafeModePersist;
|
||||
}else if( nSql && bAllWhite ){
|
||||
}else if( nSql && QSS_PLAINWHITE(qss) ){
|
||||
if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
|
||||
nSql = 0;
|
||||
}
|
||||
}
|
||||
if( nSql && !bAllWhite ){
|
||||
if( nSql && QSS_PLAINDARK(qss) ){
|
||||
errCnt += runOneSqlLine(p, zSql, p->in, startline);
|
||||
}
|
||||
free(zSql);
|
||||
|
@ -43,10 +43,10 @@ do_test shell2-1.1.1 {
|
||||
# Shell silently ignores extra parameters.
|
||||
# Ticket [f5cb008a65].
|
||||
do_test shell2-1.2.1 {
|
||||
set rc [catch { eval exec $CLI \":memory:\" \"select+3\" \"select+4\" } msg]
|
||||
list $rc $msg
|
||||
catchcmdex {:memory: "select+3" "select+4"}
|
||||
} {0 {3
|
||||
4}}
|
||||
4
|
||||
}}
|
||||
|
||||
# Test a problem reported on the mailing list. The shell was at one point
|
||||
# returning the generic SQLITE_ERROR message ("SQL error or missing database")
|
||||
@ -123,7 +123,7 @@ SELECT * FROM foo;}
|
||||
# NB. whitespace is important
|
||||
do_test shell2-1.4.5 {
|
||||
forcedelete foo.db
|
||||
catchcmd "foo.db" {.echo ON
|
||||
catchcmdex "foo.db" {.echo ON
|
||||
CREATE TABLE foo1(a);
|
||||
INSERT INTO foo1(a) VALUES(1);
|
||||
CREATE TABLE foo2(b);
|
||||
@ -155,7 +155,7 @@ SELECT * FROM foo2;
|
||||
# NB. whitespace is important
|
||||
do_test shell2-1.4.6 {
|
||||
forcedelete foo.db
|
||||
catchcmd "foo.db" {.echo ON
|
||||
catchcmdex "foo.db" {.echo ON
|
||||
.headers ON
|
||||
CREATE TABLE foo1(a);
|
||||
INSERT INTO foo1(a) VALUES(1);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#
|
||||
# shell3-1.*: Basic tests for running SQL statments from command line.
|
||||
# shell3-2.*: Basic tests for running SQL file from command line.
|
||||
# shell3-3.*: Basic tests for processing odd SQL constructs.
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -26,6 +27,7 @@ db close
|
||||
forcedelete test.db test.db-journal test.db-wal
|
||||
sqlite3 db test.db
|
||||
|
||||
|
||||
# There are inconsistencies in command-line argument quoting on Windows.
|
||||
# In particular, individual applications are responsible for command-line
|
||||
# parsing in Windows, not the shell. Depending on whether the sqlite3.exe
|
||||
@ -98,4 +100,39 @@ do_test shell3-2.7 {
|
||||
catchcmd "foo.db" "CREATE TABLE"
|
||||
} {1 {Error: near line 1: incomplete input}}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# shell3-3.*: Basic tests for processing odd SQL constructs.
|
||||
#
|
||||
|
||||
# Run combinations of odd identifiers, comments, semicolon placement
|
||||
do_test shell3-3.1 {
|
||||
forcedelete foo.db
|
||||
set rc [ catchcmd "foo.db" {CREATE TABLE t1("
|
||||
a--.
|
||||
" --x
|
||||
); CREATE TABLE t2("a[""b""]");
|
||||
.header on
|
||||
INSERT INTO t1 VALUES ('
|
||||
x''y');
|
||||
INSERT INTO t2 VALUES ('
|
||||
/*.
|
||||
.*/ x
|
||||
''y');
|
||||
SELECT * from t1 limit 1;
|
||||
SELECT * from t2 limit 1;
|
||||
} ]
|
||||
set fexist [file exist foo.db]
|
||||
list $rc $fexist
|
||||
} {{0 {
|
||||
a--.
|
||||
|
||||
|
||||
x'y
|
||||
a["b"]
|
||||
|
||||
/*.
|
||||
.*/ x
|
||||
'y}} 1}
|
||||
|
||||
finish_test
|
||||
|
Loading…
x
Reference in New Issue
Block a user