]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Take CLI input redirect recursion limit from trunk
authorlarrybr <larrybr@noemail.net>
Mon, 24 Jan 2022 07:11:25 +0000 (07:11 +0000)
committerlarrybr <larrybr@noemail.net>
Mon, 24 Jan 2022 07:11:25 +0000 (07:11 +0000)
FossilOrigin-Name: 5e7020441514d1febdd6d97d6c5be4429f65310e9bcde2eb50c071aa9459a333

1  2 
manifest
manifest.uuid
src/shell.c.in
test/shell4.test

diff --cc manifest
index 5275464dffeff84c5a0a679eb60d92c631f1aea3,4e48b7001b0b2eff86696e049f8ca08e406e7c5e..9d76dc6f892d61917295d1ba0b35c24c7584f0d0
+++ b/manifest
@@@ -1,5 -1,5 +1,5 @@@
- C Add\sCLI\s.x\scommand,\smake\sstring\sredirection\swork
- D 2022-01-24T04:21:20.922
 -C Limit\sCLI\sinput\sredirect\snesting
 -D 2022-01-24T06:36:16.156
++C Take\sCLI\sinput\sredirect\srecursion\slimit\sfrom\strunk
++D 2022-01-24T07:11:25.201
  F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
  F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
  F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@@ -553,7 -553,7 +553,7 @@@ F src/random.c 097dc8b31b8fba5a9aca1697
  F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9
  F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
  F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027
- F src/shell.c.in 3308232026d5b984fcbe6386915dae00d786de06013dfb398d25b1996eec2c0a
 -F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2
++F src/shell.c.in a97789adf08a352a98e8de2e225253e02b06535301c7e8c0d430fee15828ceaa
  F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863
  F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
  F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
@@@ -1388,7 -1388,7 +1388,7 @@@ F test/sharedlock.test 5ede3c37439067c4
  F test/shell1.test 70f46b5d07776a107335c3c2c9cbd0431d44637bfeae1f6b9ded5e33b4c7c0bf
  F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c
  F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566
- F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be
 -F test/shell4.test 8427e08751d4b16100fadb29f109cc1b8cce5c3858bdf34837c6e3b35fbbfee7
++F test/shell4.test d817597bb7f11f97ea86e4ccad0480c21183bcdc2083cd9de05a11303d9ee577
  F test/shell5.test b85069bfcf3159b225228629ab2c3e69aa923d098fea8ea074b5dcd743522e2c
  F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
  F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
@@@ -1941,8 -1941,8 +1941,8 @@@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a9
  F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
  F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
  F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P 073ded4d185d0133b07b4548dd78f4ad5eb17ce1f5c457d89fee23281420bbff
- R f62f785dd4d4b36cb5a7d1dd62c6a2c1
 -P e4caf1e3932b1bd0dea072df7fc9458aed98c84ea397b6948b89292603949c41
 -R 3ff059f17b79f35a7110343334a8c695
++P 2f2f1aaed691ba31ba70577012f785aae1f4a53ac7582bf30d26fbbec1eb3f3c 7a073931752d16ba71f1a606091461e427ca5ccf4d135d3c5141bfdd4e67e2d5
++R 2171c849337bd842c8b5ea7647d1f610
  U larrybr
- Z c190fc10a0d856e1e83e9ea407a32719
 -Z 22bca9d238f29be7cbeeb6418fbc3f83
++Z 86bfffa52bc0d70bd85c5a9f759d466b
  # Remove this line to create a well-formed Fossil manifest.
diff --cc manifest.uuid
index 3b9949a547e835eb428507475b1391c014b4dfed,b9b364e4c198b9757ab015688da51aaf275ed854..5dfa7fb4c41dea0c5d2285a18048f45fdb7f2b74
@@@ -1,1 -1,1 +1,1 @@@
- 2f2f1aaed691ba31ba70577012f785aae1f4a53ac7582bf30d26fbbec1eb3f3c
 -7a073931752d16ba71f1a606091461e427ca5ccf4d135d3c5141bfdd4e67e2d5
++5e7020441514d1febdd6d97d6c5be4429f65310e9bcde2eb50c071aa9459a333
diff --cc src/shell.c.in
index 96da26b6a36417b57dfd79c283a83eea0c573051,0a903672cc32f7ecbc54a63a2ec3cabadb1167ec..74154decabc542f809f7cf3ffbf0efb0c13ceb3c
@@@ -677,88 -677,6 +677,89 @@@ static char *local_getline(char *zLine
    return zLine;
  }
  
-   const char *zSourceSay; /* For complaints, keep a name for this source. */
 +/*
 +** 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} 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. */
++  const char *zSourceSay; /* For complaints, keep a name for this source */
++  struct InSource *pFrom; /* and redirect tracking to aid unraveling. */
 +} 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. With a rewrite,
 +** it and local_getline can merge, saving most of 26 LOC. )
 +*/
 +static char *getline_from( char *zLine, InSource *pSource ){
 +  if( pSource->inFile!=0 ){
 +    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;
 +  }
 +}
 +
  /*
  ** Retrieve a single line of input text.
  **
@@@ -7726,66 -7604,6 +7734,67 @@@ static int recoverDatabaseCmd(ShellStat
  }
  #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
  
-           InSource inSourceDivert = {0, zSubmit, 0, azArg[ia]};
 +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], p->pInSource };
 +          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.
@@@ -9574,19 -9385,11 +9583,20 @@@ static int do_meta_command(char *zLine
        utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
        rc = 1;
      }else{
-       InSource inSourceDivert = {inUse, 0, 0, azArg[1]};
 +      fCloser = fclose;
 +    }
 +    if( inUse!=0 ){
 +      InSource *pInSrcSave = p->pInSource;
 +      int savedLineno = p->lineno;
++      InSource inSourceDivert =
++        {inUse, 0, 0, azArg[1], p->pInSource};
 +      p->pInSource = &inSourceDivert;
        rc = process_input(p);
 -      fclose(p->in);
 +      assert(fCloser!=0);
 +      fCloser(inUse);
 +      p->pInSource = pInSrcSave;
 +      p->lineno = savedLineno;
      }
 -    p->in = inSaved;
 -    p->lineno = savedLineno;
    }else
  
    if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
@@@ -11155,15 -10947,20 +11165,27 @@@ static int process_input(ShellState *p)
    int startline = 0;        /* Line number for start of current input */
    QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
  
 -    /* This will be more informative in a later version. */
 -    utf8_printf(stderr,"Input nesting limit (%d) reached at line %d."
 -                " Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
+   if( p->inputNesting==MAX_INPUT_NESTING ){
++    InSource *pInSrc = p->pInSource;
++    utf8_printf
++      (stderr,
++       "Input nesting limit (%d) reached, from line %d of \"%s\",\n",
++       MAX_INPUT_NESTING, p->lineno-1, pInSrc->zSourceSay);
++    for( rc=0; rc<3 && (pInSrc=pInSrc->pFrom)!=0; ++rc )
++      utf8_printf(stderr, " from \"%s\"", pInSrc->zSourceSay);
++    utf8_printf(stderr, " ...\nCheck recursion.\n");
+     return 1;
+   }
+   ++p->inputNesting;
    p->lineno = 0;
 -  while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
 +  while( errCnt==0
 +         || !bail_on_error
 +         || (p->pInSource==0 && stdin_is_interactive) ){
      fflush(p->out);
 -    zLine = one_input_line(p->in, zLine, nSql>0);
 +    zLine = one_input_line(p->pInSource, zLine, nSql>0);
      if( zLine==0 ){
        /* End of input */
 -      if( p->in==0 && stdin_is_interactive ) printf("\n");
 +      if( p->pInSource==0 && stdin_is_interactive ) printf("\n");
        break;
      }
      if( seenInterrupt ){
@@@ -11337,13 -11136,8 +11360,13 @@@ static void process_sqliterc
      shell_check_oom(zBuf);
      sqliterc = zBuf;
    }
 -  p->in = fopen(sqliterc,"rb");
 -  if( p->in ){
 +  inUse = fopen(sqliterc,"rb");
 +  if( inUse!=0 ){
 +    InSource *pInSrcSave = p->pInSource;
 +    int savedLineno = p->lineno;
-     InSource inSourceDivert = {inUse, 0, 0, sqliterc};
++    InSource inSourceDivert = {inUse, 0, 0, sqliterc, p->pInSource};
 +    int rc;
 +    p->pInSource = &inSourceDivert;
      if( stdin_is_interactive ){
        utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
      }
index 9e3c58fbec6d25539409dfa4c7ca66cc26aa1d1e,1be2c1d9accf859ea12e3e0a2b0859a9474c256d..107125ed6ff3562e95e472dbf90d0d825753c30c
@@@ -138,4 -139,11 +139,13 @@@ do_test shell4-3.2 
    exec $::CLI :memory: --interactive ".read t1.txt"
  } {pound: £}
  
 -} {1 {Input nesting limit (25) reached at line 1. Watch recursion.}}
+ do_test shell4-4.1 {
+   set fd [open t1.txt wb]
+   puts $fd ".read t1.txt"
+   close $fd
+   catchcmd ":memory:" ".read t1.txt"
++} {1 {Input nesting limit (25) reached, from line 0 of "t1.txt",
++ from "t1.txt" from "t1.txt" from "t1.txt" ...
++Check recursion.}}
  finish_test