SQLite

Check-in [9dc0d34586]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enhance the ".imposter" command in the CLI so that the first argument can be an existing WITHOUT ROWID table instead of an index. The resulting imposter is the same table, but with columns in storage order and with all constraints removed.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 9dc0d34586eebf6705d9bd81494c417ac76707b8625d1ff99eda18b4ca2d8a50
User & Date: drh 2019-10-18 15:58:50.284
Context
2019-10-20
08:26
Fix a resource leak in fts5 that could occur if an auxiliary function is called from within a query that does not use the full-text index. (check-in: b528bdcd45 user: dan tags: trunk)
2019-10-18
17:47
Merge trunk enhancements into the generated-columns branch. (check-in: 85bc4524d7 user: drh tags: generated-columns)
15:58
Enhance the ".imposter" command in the CLI so that the first argument can be an existing WITHOUT ROWID table instead of an index. The resulting imposter is the same table, but with columns in storage order and with all constraints removed. (check-in: 9dc0d34586 user: drh tags: trunk)
2019-10-17
15:41
Avoid an infinite loop in fts3/4 incremental-merge in the case where the lowest level in the database contains segments but no data (because there is a delete-marker for each valid entry). Fix for [bf1aab89]. (check-in: 35beaee059 user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/shell.c.in.
7754
7755
7756
7757
7758
7759
7760


7761
7762
7763
7764







7765
7766
7767
7768
7769
7770
7771
7772
7773

7774






7775
7776
7777
7778

7779
7780
7781
7782
7783
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801



7802
7803
7804
7805
7806
7807
7808







7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822

7823
7824
7825
7826
7827
7828
7829

#ifndef SQLITE_UNTESTABLE
  if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
    char *zSql;
    char *zCollist = 0;
    sqlite3_stmt *pStmt;
    int tnum = 0;


    int i;
    if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
      utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n"
                          "       .imposter off\n");







      rc = 1;
      goto meta_command_exit;
    }
    open_db(p, 0);
    if( nArg==2 ){
      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1);
      goto meta_command_exit;
    }
    zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master"

                           " WHERE name='%q' AND type='index'", azArg[1]);






    sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    if( sqlite3_step(pStmt)==SQLITE_ROW ){
      tnum = sqlite3_column_int(pStmt, 0);

    }
    sqlite3_finalize(pStmt);
    if( tnum==0 ){
      utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
      rc = 1;
      goto meta_command_exit;
    }
    zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    i = 0;
    while( sqlite3_step(pStmt)==SQLITE_ROW ){
      char zLabel[20];
      const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
      i++;
      if( zCol==0 ){
        if( sqlite3_column_int(pStmt,1)==-1 ){
          zCol = "_ROWID_";
        }else{
          sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
          zCol = zLabel;
        }
      }



      if( zCollist==0 ){
        zCollist = sqlite3_mprintf("\"%w\"", zCol);
      }else{
        zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
      }
    }
    sqlite3_finalize(pStmt);







    zSql = sqlite3_mprintf(
          "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%s))WITHOUT ROWID",
          azArg[2], zCollist, zCollist);
    sqlite3_free(zCollist);
    rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
    if( rc==SQLITE_OK ){
      rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
      if( rc ){
        utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
      }else{
        utf8_printf(stdout, "%s;\n", zSql);
        raw_printf(stdout,
           "WARNING: writing to an imposter table will corrupt the index!\n"

        );
      }
    }else{
      raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
      rc = 1;
    }
    sqlite3_free(zSql);







>
>




>
>
>
>
>
>
>








|
>
|
>
>
>
>
>
>




>


<
<
<
<
<
















>
>
>







>
>
>
>
>
>
>

|
|










|
>







7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776
7777
7778
7779
7780
7781
7782
7783
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797





7798
7799
7800
7801
7802
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
7851
7852

#ifndef SQLITE_UNTESTABLE
  if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
    char *zSql;
    char *zCollist = 0;
    sqlite3_stmt *pStmt;
    int tnum = 0;
    int isWO = 0;  /* True if making an imposter of a WITHOUT ROWID table */
    int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
    int i;
    if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
      utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n"
                          "       .imposter off\n");
      /* Also allowed, but not documented:
      **
      **    .imposter TABLE IMPOSTER
      **
      ** where TABLE is a WITHOUT ROWID table.  In that case, the
      ** imposter is another WITHOUT ROWID table with the columns in
      ** storage order. */
      rc = 1;
      goto meta_command_exit;
    }
    open_db(p, 0);
    if( nArg==2 ){
      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1);
      goto meta_command_exit;
    }
    zSql = sqlite3_mprintf(
      "SELECT rootpage, 0 FROM sqlite_master"
      " WHERE name='%q' AND type='index'"
      "UNION ALL "
      "SELECT rootpage, 1 FROM sqlite_master"
      " WHERE name='%q' AND type='table'"
      "   AND sql LIKE '%%without%%rowid%%'",
      azArg[1], azArg[1]
    );
    sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    if( sqlite3_step(pStmt)==SQLITE_ROW ){
      tnum = sqlite3_column_int(pStmt, 0);
      isWO = sqlite3_column_int(pStmt, 1);
    }
    sqlite3_finalize(pStmt);





    zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    i = 0;
    while( sqlite3_step(pStmt)==SQLITE_ROW ){
      char zLabel[20];
      const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
      i++;
      if( zCol==0 ){
        if( sqlite3_column_int(pStmt,1)==-1 ){
          zCol = "_ROWID_";
        }else{
          sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
          zCol = zLabel;
        }
      }
      if( isWO && lenPK==0 && sqlite3_column_int(pStmt,5)==0 && zCollist ){
        lenPK = (int)strlen(zCollist);
      }
      if( zCollist==0 ){
        zCollist = sqlite3_mprintf("\"%w\"", zCol);
      }else{
        zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
      }
    }
    sqlite3_finalize(pStmt);
    if( i==0 || tnum==0 ){
      utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
      rc = 1;
      sqlite3_free(zCollist);
      goto meta_command_exit;
    }
    if( lenPK==0 ) lenPK = 100000;
    zSql = sqlite3_mprintf(
          "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID",
          azArg[2], zCollist, lenPK, zCollist);
    sqlite3_free(zCollist);
    rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
    if( rc==SQLITE_OK ){
      rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
      if( rc ){
        utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
      }else{
        utf8_printf(stdout, "%s;\n", zSql);
        raw_printf(stdout,
          "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n",
          azArg[1], isWO ? "table" : "index"
        );
      }
    }else{
      raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
      rc = 1;
    }
    sqlite3_free(zSql);