]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add CLI .x command, make string redirection work
authorlarrybr <larrybr@noemail.net>
Mon, 24 Jan 2022 04:21:20 +0000 (04:21 +0000)
committerlarrybr <larrybr@noemail.net>
Mon, 24 Jan 2022 04:21:20 +0000 (04:21 +0000)
FossilOrigin-Name: 2f2f1aaed691ba31ba70577012f785aae1f4a53ac7582bf30d26fbbec1eb3f3c

manifest
manifest.uuid
src/shell.c.in

index ffc845b2cee600b336f0577ce67a7d9d72022329..5275464dffeff84c5a0a679eb60d92c631f1aea3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C CLI\sprepared\sfor\sreading\sstring\sinput
-D 2022-01-24T00:22:06.344
+C Add\sCLI\s.x\scommand,\smake\sstring\sredirection\swork
+D 2022-01-24T04:21:20.922
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -553,7 +553,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
 F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027
-F src/shell.c.in e457581785607722cd12c79cbfe9e75b8385c194cf2705727b15c00b8870eb5a
+F src/shell.c.in 3308232026d5b984fcbe6386915dae00d786de06013dfb398d25b1996eec2c0a
 F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
@@ -1941,8 +1941,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 4462ed896459ee0312f1989d9a813c65150347ebdd15b59b2aa86bbce3abec1c
-R 4304075de837dc32a0991c68c10dfb6b
+P 073ded4d185d0133b07b4548dd78f4ad5eb17ce1f5c457d89fee23281420bbff
+R f62f785dd4d4b36cb5a7d1dd62c6a2c1
 U larrybr
-Z 3d97e11411e5c32cab39ea8a9a85a826
+Z c190fc10a0d856e1e83e9ea407a32719
 # Remove this line to create a well-formed Fossil manifest.
index 97851dc5f1be1bbbeb435e2b29790aad6f0c6a98..3b9949a547e835eb428507475b1391c014b4dfed 100644 (file)
@@ -1 +1 @@
-073ded4d185d0133b07b4548dd78f4ad5eb17ce1f5c457d89fee23281420bbff
\ No newline at end of file
+2f2f1aaed691ba31ba70577012f785aae1f4a53ac7582bf30d26fbbec1eb3f3c
\ No newline at end of file
index fbfb3c6a9d06e27453672db418f304907450ef5b..96da26b6a36417b57dfd79c283a83eea0c573051 100644 (file)
@@ -681,27 +681,82 @@ static char *local_getline(char *zLine, FILE *in){
 ** Arrange for shell input from either a FILE or a string.
 ** See getline_from(...) for applicable invariants. It is
 ** the only modifier of data within this struct, except for
-** initialization which is either {0, zS, 0} or {pF, 0, 0},
-** left to whatever routine is switching input sources.
+** initialization which is either {0, zS} or {pF, 0}, (with
+** the iReadOffset always 0-initialized), left to whatever
+** routine is switching input sources.
 */
 typedef struct InSource {
-  FILE *inFile;    /* Will be 0 when input is to be taken from string. */
-  char *zStrIn;    /* Will be 0 when no input is available from string. */
-  int iReadOffset; /* Offset into ZStrIn where next "read" to be done. */
+  FILE *inFile;     /* Will be 0 when input is to be taken from string. */
+  char *zStrIn;     /* Will be 0 when no input is available from string. */
+  int iReadOffset;  /* Offset into ZStrIn where next "read" to be done. */
+  const char *zSourceSay; /* For complaints, keep a name for this source. */
 } InSource;
 
 /*
 ** Read single lines of input text from source selected by pInSource.
 ** This function presents an interface similar to local_getline(...),
 ** to which it defers for FILE input. (This function may be considered
-** to be an adapter except for the source parameter.)
+** to be an adapter except for the source parameter. With a rewrite,
+** it and local_getline can merge, saving most of 26 LOC. )
 */
-static char *getline_from( char *zPrior, InSource *pSource ){
-  char *zResult = 0;
+static char *getline_from( char *zLine, InSource *pSource ){
   if( pSource->inFile!=0 ){
-    zResult = local_getline(zPrior, pSource->inFile);
+    return local_getline(zLine, pSource->inFile);
+  }else if( pSource->zStrIn!=0
+            && pSource->zStrIn[pSource->iReadOffset]!=0 ){
+    /* This code mostly copied from local_getline(); It begs for refactor. */
+    int nLine = zLine==0 ? 0 : 100;
+    int n = 0;
+
+    while( 1 ){
+      if( n+100>nLine ){
+        nLine = nLine*2 + 100;
+        zLine = realloc(zLine, nLine);
+        shell_check_oom(zLine);
+      }
+      {
+        /* This block is where fgets() became "read string". */
+        char *zBegin = pSource->zStrIn + pSource->iReadOffset;
+        int iTake = 0;
+        char c = zBegin[iTake];
+        if( c==0 ){
+          if( n==0 ){
+            free(zLine);
+            return 0;
+          }
+          zLine[n] = 0;
+          break;
+        }else{
+          while( iTake<nLine-n-1 && c!=0 ){
+            zLine[n+iTake++] = c;
+            if( c=='\n' ) break;
+            c = zBegin[iTake];
+          }
+          zLine[n+iTake] = 0;
+          pSource->iReadOffset += iTake;
+        }
+      }
+      /* Above block replaced this commented code: */
+      /* if( fgets(&zLine[n], nLine - n, in)==0 ){ */
+      /*   if( n==0 ){ */
+      /*     free(zLine); */
+      /*     return 0; */
+      /*   } */
+      /*   zLine[n] = 0; */
+      /*   break; */
+      /* } */
+      while( zLine[n] ) n++;
+      if( n>0 && zLine[n-1]=='\n' ){
+        n--;
+        if( n>0 && zLine[n-1]=='\r' ) n--;
+        zLine[n] = 0;
+        break;
+      }
+    }
+    return zLine;
+  }else{
+    return 0;
   }
-  return zResult;
 }
 
 /*
@@ -722,7 +777,7 @@ static char *one_input_line(InSource *pInSrc, char *zPrior, int isContinuation){
   char *zPrompt;
   char *zResult;
   if( pInSrc!=0 ){
-    zResult = local_getline(zPrior, pInSrc->inFile);
+    zResult = getline_from(zPrior, pInSrc);
   }else{
     zPrompt = isContinuation ? continuePrompt : mainPrompt;
 #if SHELL_USE_LOCAL_GETLINE
@@ -4284,7 +4339,9 @@ static const char *(azHelp[]) = {
   ".vfslist                 List all available VFSes",
   ".vfsname ?AUX?           Print the name of the VFS stack",
   ".width NUM1 NUM2 ...     Set minimum column widths for columnar output",
-  "     Negative values right-justify",
+  "   Negative values right-justify",
+  ".x NAME ...              Excecute content of some .param set variable(s)",
+  "   Only variables whose name begins with a letter are eligible for this."
 };
 
 /* Like azHelp[], but for undocumented commands. */
@@ -7669,6 +7726,66 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
 }
 #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
 
+static int execute_variables(char *azArg[], int nArg, ShellState *p){
+  int ia, rc, nErrors = 0;
+  sqlite3_stmt *pStmt = 0;
+  open_db(p, 0);
+  if( p->db==0 ){
+    utf8_printf(stderr, ".x can only be done with a database open.\n");
+    return 1;
+  }
+  if( sqlite3_table_column_metadata(p->db, "TEMP", "sqlite_parameters",
+                                    "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){
+    utf8_printf(stderr, "No temp.sqlite_parameters table exists.\n");
+    return 1;
+  }
+  rc = sqlite3_prepare_v2
+    (p->db, "SELECT value FROM temp.sqlite_parameters WHERE key=$1",
+     -1, &pStmt, 0);
+  if( rc!=SQLITE_OK ){
+    utf8_printf(stderr, "temp.sqlite_parameters is wrongly created.\n");
+    return 1;
+  }
+  for( ia=1; ia < nArg; ++ia ){
+    if( isalpha(azArg[ia][0]) ){
+      rc = sqlite3_reset(pStmt);
+      rc = sqlite3_bind_text(pStmt, 1, azArg[ia], -1, 0);
+      rc = sqlite3_step(pStmt);
+      if( rc==SQLITE_ROW ){
+        const unsigned char *zValue = sqlite3_column_text(pStmt, 0);
+        int nb = sqlite3_column_bytes(pStmt, 0);
+        /* If it's empty, just silently pretend to execute it. */
+        if( nb==0 ) continue;
+        while( IsSpace(zValue[nb-1]) ) --nb;
+        if( nb>0 ){
+          char *zSubmit = sqlite3_mprintf( "%.*s\n", nb, zValue );
+          InSource inSourceDivert = {0, zSubmit, 0, azArg[ia]};
+          InSource *pInSrcSave = p->pInSource;
+          int savedLineno = p->lineno;
+          shell_check_oom(zSubmit);
+          p->pInSource = &inSourceDivert;
+          rc = process_input(p);
+          sqlite3_free(zSubmit);
+          p->pInSource = pInSrcSave;
+          p->lineno = savedLineno;
+        }else{
+          continue; /* All white, ignore. */
+        }
+      }else{
+        utf8_printf(stderr,
+                    "Skipping parameter '%s' (not set.)\n", azArg[ia]);
+        ++nErrors;
+      }
+    }else{
+      utf8_printf(stderr,
+                  "Skipping badly named %s. Run \".help x\"\n", azArg[ia]);
+      ++nErrors;
+    }
+  }
+  sqlite3_finalize(pStmt);
+  return nErrors>0;
+}
+
 /*
 ** If an input line begins with "." then invoke this routine to
 ** process that line.
@@ -9462,7 +9579,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     if( inUse!=0 ){
       InSource *pInSrcSave = p->pInSource;
       int savedLineno = p->lineno;
-      InSource inSourceDivert = {inUse, 0, 0};
+      InSource inSourceDivert = {inUse, 0, 0, azArg[1]};
       p->pInSource = &inSourceDivert;
       rc = process_input(p);
       assert(fCloser!=0);
@@ -10827,6 +10944,10 @@ static int do_meta_command(char *zLine, ShellState *p){
     }
   }else
 
+  if( c=='x' && n==1 ){ /* "x" */
+    rc = execute_variables(azArg, nArg, p);
+  }else
+
   {
     utf8_printf(stderr, "Error: unknown command or invalid arguments: "
       " \"%s\". Enter \".help\" for help\n", azArg[0]);
@@ -11220,7 +11341,7 @@ static void process_sqliterc(
   if( inUse!=0 ){
     InSource *pInSrcSave = p->pInSource;
     int savedLineno = p->lineno;
-    InSource inSourceDivert = {inUse, 0, 0};
+    InSource inSourceDivert = {inUse, 0, 0, sqliterc};
     int rc;
     p->pInSource = &inSourceDivert;
     if( stdin_is_interactive ){
@@ -11400,7 +11521,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
 #endif
   char *zErrMsg = 0;
   ShellState data;
-  InSource inputSource = { stdin, 0, 0};
+  InSource inputSource = { stdin, 0, 0, "stdin"};
   const char *zInitFile = 0;
   int i;
   int rc = 0;