]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Have ".recover" handle "\r" and "\n" in the same way as ".dump".
authordan <dan@noemail.net>
Tue, 23 Apr 2019 20:48:32 +0000 (20:48 +0000)
committerdan <dan@noemail.net>
Tue, 23 Apr 2019 20:48:32 +0000 (20:48 +0000)
FossilOrigin-Name: f95f0f02ab6c6cf45f25b613c7ab57f68249689d0a9eddf4c9518ddf0edad365

manifest
manifest.uuid
src/shell.c.in

index 509212bede28b2c41786c67f52904155d42499a7..e3ab13575f784bbe7bc2b7a7ac0741ecac17df98 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fixes\sfor\sthe\s".recover"\sshell\scommand.
-D 2019-04-23T18:03:02.318
+C Have\s".recover"\shandle\s"\\r"\sand\s"\\n"\sin\sthe\ssame\sway\sas\s".dump".
+D 2019-04-23T20:48:32.366
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -520,7 +520,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
 F src/resolve.c 567888ee3faec14dae06519b4306201771058364a37560186a3e0e755ebc4cb8
 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
 F src/select.c 9263f5c30dd44c7ac2eb29f40a7ec64322a96885b71c00de6bc30b756c2e1c49
-F src/shell.c.in 6c02cbd1de3b878abc04b08f2f74cc4d65d0a8e52dd3e78194db2a79d686b841
+F src/shell.c.in 6e56c60640410885a8c3c264971619407ae5c7f46165e2bfe5fb1ca1a6a58ad0
 F src/sqlite.h.in 38390767acc1914d58930e03149595ee4710afa4e3c43ab6c3a8aea3f1a6b8cd
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5
@@ -1821,7 +1821,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 f193ca587f9e4f925f4f2343b0b07053bd6f93dd87fc6f8f41cf4479e90cf562
-R 73bcd5cc8a48367ff5a018a5ccb0a79d
+P 8dcc1d89d955bf58c80a8c30a37960f0cf95719953951a92626cc332cc75ec60
+R b9c18dd1095e3f7b028bdaea88f9fcb0
 U dan
-Z e408dc486ac689ec1d61c890dc79708f
+Z edabfc3afbc2656b0ce1a8fb6b1e492b
index 680d92aac8bf5ca337b0e22f47817eb8d97373d5..fdcc68f9a95e32e9c2b6e3e6ac5cbc33f50b6daf 100644 (file)
@@ -1 +1 @@
-8dcc1d89d955bf58c80a8c30a37960f0cf95719953951a92626cc332cc75ec60
\ No newline at end of file
+f95f0f02ab6c6cf45f25b613c7ab57f68249689d0a9eddf4c9518ddf0edad365
\ No newline at end of file
index 8ac87fbfa2b56949133149cdac34e492c380b2a9..7989c9dfdef0c060b786e0ac217611bd375cb800 100644 (file)
@@ -3934,6 +3934,96 @@ readHexDb_error:
 }
 #endif /* SQLITE_ENABLE_DESERIALIZE */
 
+/*
+** Scalar function "shell_escape_crnl" used by the .recover command.
+** The argument passed to this function is the output of built-in
+** function quote(). If the first character of the input is "'", 
+** indicating that the value passed to quote() was a text value,
+** then this function searches the input for "\n" and "\r" characters
+** and adds a wrapper similar to the following:
+**
+**   replace(replace(<input>, '\n', char(10), '\r', char(13));
+**
+** Or, if the first character of the input is not "'", then a copy
+** of the input is returned.
+*/
+static void shellEscapeCrnl(
+  sqlite3_context *context, 
+  int argc, 
+  sqlite3_value **argv
+){
+  const char *zText = (const char*)sqlite3_value_text(argv[0]);
+  if( zText[0]=='\'' ){
+    int nText = sqlite3_value_bytes(argv[0]);
+    int i;
+    char zBuf1[20];
+    char zBuf2[20];
+    const char *zNL = 0;
+    const char *zCR = 0;
+    int nCR = 0;
+    int nNL = 0;
+
+    for(i=0; zText[i]; i++){
+      if( zNL==0 && zText[i]=='\n' ){
+        zNL = unused_string(zText, "\\n", "\\012", zBuf1);
+        nNL = (int)strlen(zNL);
+      }
+      if( zCR==0 && zText[i]=='\r' ){
+        zCR = unused_string(zText, "\\r", "\\015", zBuf2);
+        nCR = (int)strlen(zCR);
+      }
+    }
+
+    if( zNL || zCR ){
+      int iOut = 0;
+      i64 nMax = (nNL > nCR) ? nNL : nCR;
+      i64 nAlloc = nMax * nText + (nMax+12)*2;
+      char *zOut = (char*)sqlite3_malloc64(nAlloc);
+      if( zOut==0 ){
+        sqlite3_result_error_nomem(context);
+        return;
+      }
+
+      if( zNL && zCR ){
+        memcpy(&zOut[iOut], "replace(replace(", 16);
+        iOut += 16;
+      }else{
+        memcpy(&zOut[iOut], "replace(", 8);
+        iOut += 8;
+      }
+      for(i=0; zText[i]; i++){
+        if( zText[i]=='\n' ){
+          memcpy(&zOut[iOut], zNL, nNL);
+          iOut += nNL;
+        }else if( zText[i]=='\r' ){
+          memcpy(&zOut[iOut], zCR, nCR);
+          iOut += nCR;
+        }else{
+          zOut[iOut] = zText[i];
+          iOut++;
+        }
+      }
+
+      if( zNL ){
+        memcpy(&zOut[iOut], ",'", 2); iOut += 2;
+        memcpy(&zOut[iOut], zNL, nNL); iOut += nNL;
+        memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12;
+      }
+      if( zCR ){
+        memcpy(&zOut[iOut], ",'", 2); iOut += 2;
+        memcpy(&zOut[iOut], zCR, nCR); iOut += nCR;
+        memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12;
+      }
+
+      sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT);
+      sqlite3_free(zOut);
+      return;
+    }
+  }
+
+  sqlite3_result_value(context, argv[0]);
+}
+
 /* Flags for open_db().
 **
 ** The default behavior of open_db() is to exit(1) if the database fails to
@@ -4013,6 +4103,8 @@ static void open_db(ShellState *p, int openFlags){
                             shellModuleSchema, 0, 0);
     sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
                             shellPutsFunc, 0, 0);
+    sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0,
+                            shellEscapeCrnl, 0, 0);
 #ifndef SQLITE_NOHAVE_SYSTEM
     sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
                             editFunc, 0, 0);
@@ -6349,16 +6441,6 @@ static int recoverDatabaseCmd(ShellState *pState){
     "GROUP BY pgno, cell;"
   );
 
-#if 0
-  zSql = "SELECT type ||','|| name ||','|| tbl_name ||','|| rootpage ||','|| sql FROM recovery.schema;";
-  shellPrepare(pState->db, &rc, zSql, &pLoop);
-  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
-    raw_printf(pState->out, "%s\n", (const char*)sqlite3_column_text(pLoop, 0));
-  }
-  shellFinalize(&rc, pLoop);
-  return rc;
-#endif
-
   /* Open a transaction, then print out all non-virtual, non-"sqlite_%" 
   ** CREATE TABLE statements that extracted from the existing schema.  */
   if( rc==SQLITE_OK ){
@@ -6398,7 +6480,7 @@ static int recoverDatabaseCmd(ShellState *pState){
         raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n");
       }
       shellPreparePrintf(pState->db, &rc, &pData, 
-        "SELECT max(field), group_concat(quote(value), ', ') "
+        "SELECT max(field), group_concat(shell_escape_crnl(quote(value)),', ')"
         "FROM sqlite_dbdata WHERE pgno IN ("
         "  SELECT pgno FROM recovery.map WHERE root=%d"
         ")"
@@ -6423,7 +6505,7 @@ static int recoverDatabaseCmd(ShellState *pState){
     sqlite3_stmt *pStmt = 0;
     shellPrepare(pState->db, &rc, 
         "SELECT sql, name FROM recovery.schema "
-        "WHERE (type='table' AND sql LIKE 'create table%') IS NOT TRUE", &pStmt
+        "WHERE sql NOT LIKE 'create table%'", &pStmt
     );
     while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
       const char *zSql = (const char*)sqlite3_column_text(pStmt, 0);