]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix various issues with the changes on this branch. Add test cases for the same.
authordan <Dan Kennedy>
Wed, 17 Feb 2021 20:08:22 +0000 (20:08 +0000)
committerdan <Dan Kennedy>
Wed, 17 Feb 2021 20:08:22 +0000 (20:08 +0000)
FossilOrigin-Name: 10538ec6fc1642dfc2ca6cef06ce6cb9e124847b421ccf01f5842064fad379ab

13 files changed:
manifest
manifest.uuid
src/alter.c
src/build.c
src/prepare.c
src/sqliteInt.h
src/trigger.c
src/vdbe.c
src/vdbe.h
src/vdbeaux.c
src/vtab.c
test/alterdropcol.test
test/alterlegacy.test

index 2350dad5e231be991562ad936fe96af84fb2fccf..586bf12bbfb60f6c907decf6828193e640344615 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sexperimental\simplementation\sof\sALTER\sTABLE\sDROP\sCOLUMN.\sOnly\ssome\scases\swork\sso\sfar.
-D 2021-02-16T20:43:36.239
+C Fix\svarious\sissues\swith\sthe\schanges\son\sthis\sbranch.\sAdd\stest\scases\sfor\sthe\ssame.
+D 2021-02-17T20:08:22.323
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -475,7 +475,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
 F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
-F src/alter.c e912280eed81e2df936cc03af00a59abfcbfc24a27c3e5db8e8bd96022e2bf79
+F src/alter.c e4bb151562fb0de03dc89964c55d89ef06da4f1cbd6521ed166bd4ec7eaa66f8
 F src/analyze.c 01c6c6765cb4d40b473b71d85535093730770bb186f2f473abac25f07fcdee5c
 F src/attach.c e80162a47411f296bea550ed8fafd730481f4aa71e89ece23ba9c957eed15d4a
 F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853
@@ -485,7 +485,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
 F src/btree.c 694020ad8a3af3d79b09f74c8f1421272a419cdea42a13401e3b0f7dea6e9c3e
 F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
 F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
-F src/build.c 1bae5588bfdf21bdf41e634f0a053d633fb1ae3a2896117b4eea76412b76c2e0
+F src/build.c 50c70715bd4e958f8354410e78a676b30f9e2eaba107eaff8a54c465733628df
 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
@@ -536,7 +536,7 @@ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
 F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
 F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193
 F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf
-F src/prepare.c f288cbc35f79eb32e162de7e80a63ebe00d80e639dcfac071bee11570cbdb16f
+F src/prepare.c 77c7410c0c5c95278f6eb5e0d4cb82fdff3cb3e51434a7ab9f2b64b501a86974
 F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed
 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
 F src/resolve.c 89e4faf6171e179edf279905e8e45c4f9dd108777dc60716396729fbd7cb045e
@@ -546,7 +546,7 @@ F src/shell.c.in 9ebc74e4f05cfbd0f4a36060fdaeff1da4e9af4458358722bc08c5a1ab9a087
 F src/sqlite.h.in 8855a19f37ade8dad189a9e48233a2ebe1b46faf469c7eb0906a654e252dcc57
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
-F src/sqliteInt.h 514b41619e2c6b49188571df50249db2600ec33e4bfd1a6efb21f7e1c352f400
+F src/sqliteInt.h d701e738731988caef0c6d12c531a2df6a34cb10528ba8dfe442138b977e2045
 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -607,23 +607,23 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
 F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9
 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
-F src/trigger.c 983c7c8464c46840dac1ffe0461a6c447ac12c965746975c108eb5f4283e8801
+F src/trigger.c 861c3ec2c5b0fc830bdf82470454a9324fad70cbaa96d2e208fb54577c9e8d28
 F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723
 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048
 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
-F src/vdbe.c b3c9a3f9d546d4848a2a8c88a3c40875cd6ba3d248d9b99d01b1eeb38b29c171
-F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1
+F src/vdbe.c 9766281c0febf25f30a043d98b2417011acc7b04f287d3c671c3e59f656fc208
+F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
 F src/vdbeInt.h 3df118924e1711f1bbc8e30c46260d0ab6c3b029b32dd411f789111f76434f3c
 F src/vdbeapi.c 4a43e303ec3354c785f453e881521969378e85628278ab74ba4a9df790c0d93b
-F src/vdbeaux.c c8e96fb57ee6f7150845325ffb8d7fd4e340ff4f73aa527a6f26a485db8b9955
+F src/vdbeaux.c fb51483c2bcaf45c5de63c26cce8649ef37f1332e8e035867033d21ef5e7fc2c
 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
 F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f
 F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a
 F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724
 F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
-F src/vtab.c 81e1a336ba47eccc5cadb80de15f03afabd83c55ff9648e3a98d8988d4c264aa
+F src/vtab.c 88bd6d3f0207d5d71842faf984bebff7f7ed96746234bfd6c917d8f4ff93c654
 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c 69e770e96fd56cc21608992bf2c6f1f3dc5cf2572d0495c6a643b06c3a679f14
 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
@@ -647,8 +647,8 @@ F test/alter4.test dfd6086faf461b27ca2d2999848dcd207edf23352fc1592d0005c0844f3f0
 F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
 F test/alterauth2.test c0a1ddf5b93d93cb0d15ba7acaf0c5c6fb515bbe861ede75b2d3fabad33b6499
 F test/altercol.test 1d6a6fe698b81e626baea4881f5717f9bc53d7d07f1cd23ee7ad1b931f117ddf
-F test/alterdropcol.test 77539861deb0f1a04fb938f33984d7ccac8618337492611ac41dffea4b316863
-F test/alterlegacy.test 82022721ce0de29cedc9a7af63bc9fcc078b0ee000f8283b4b6ea9c3eab2f44b
+F test/alterdropcol.test 1d9577320aa1b501ebc44de02b7c101789bca9fb6fbbb393c99d24351f15d11e
+F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e228c15811
 F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
 F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b
 F test/altertab.test 6d7bbac2c4a6ef71b775094a3298fa3a92274d95034ee23157ffba92768e47e6
@@ -1901,10 +1901,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 27d4117980d125975b5e70eeea58a6ab07bcf066e71b5fcb81b822e05afdbab0
-R af9ecd1afb3809621548f4fa239dc0d6
-T *branch * alter-table-drop-column
-T *sym-alter-table-drop-column *
-T -sym-trunk *
+P f0217937d7306fb595727e61e871e8b03d8c881d339a0865bfd0117d90d42e4e
+R 35acba48cd575f61e2691128781d8577
 U dan
-Z e426edd9d98bb43cdac675b225a7f76a
+Z 437b0700aa4a252237abb9f1d982595f
index 031aa0ca61c735422f865ad082d3c3b96e8129ce..f8588015c35ff6263ca5f03a92434786b0222d8a 100644 (file)
@@ -1 +1 @@
-f0217937d7306fb595727e61e871e8b03d8c881d339a0865bfd0117d90d42e4e
\ No newline at end of file
+10538ec6fc1642dfc2ca6cef06ce6cb9e124847b421ccf01f5842064fad379ab
\ No newline at end of file
index 4b00d4c38631cc1dbd4418f907f4e1f31b8cb6e8..4fc2d1f7f38f141c213a199dc8a9d6a783f8e4ae 100644 (file)
@@ -77,12 +77,12 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
 ** Generate code to reload the schema for database iDb. And, if iDb!=1, for
 ** the temp database as well.
 */
-static void renameReloadSchema(Parse *pParse, int iDb){
+static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){
   Vdbe *v = pParse->pVdbe;
   if( v ){
     sqlite3ChangeCookie(pParse, iDb);
-    sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
-    if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
+    sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5);
+    if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5);
   }
 }
 
@@ -250,7 +250,7 @@ void sqlite3AlterRenameTable(
   }
 #endif
 
-  renameReloadSchema(pParse, iDb);
+  renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
   renameTestSchema(pParse, zDb, iDb==1);
 
 exit_rename_table:
@@ -413,7 +413,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
   }
 
   /* Reload the table definition */
-  renameReloadSchema(pParse, iDb);
+  renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
 }
 
 /*
@@ -513,7 +513,7 @@ exit_begin_add_column:
 ** Or, if pTab is not a view or virtual table, zero is returned.
 */
 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
-static int isRealTable(Parse *pParse, Table *pTab){
+static int isRealTable(Parse *pParse, Table *pTab, int bDrop){
   const char *zType = 0;
 #ifndef SQLITE_OMIT_VIEW
   if( pTab->pSelect ){
@@ -526,15 +526,16 @@ static int isRealTable(Parse *pParse, Table *pTab){
   }
 #endif
   if( zType ){
-    sqlite3ErrorMsg(
-        pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName
+    sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"", 
+        (bDrop ? "drop column from" : "rename columns of"),
+        zType, pTab->zName
     );
     return 1;
   }
   return 0;
 }
 #else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
-# define isRealTable(x,y) (0)
+# define isRealTable(x,y,z) (0)
 #endif
 
 /*
@@ -563,7 +564,7 @@ void sqlite3AlterRenameColumn(
 
   /* Cannot alter a system table */
   if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
-  if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
+  if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_rename_column;
 
   /* Which schema holds the table to be altered */  
   iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -617,7 +618,7 @@ void sqlite3AlterRenameColumn(
   );
 
   /* Drop and reload the database schema. */
-  renameReloadSchema(pParse, iSchema);
+  renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename);
   renameTestSchema(pParse, zDb, iSchema==1);
 
  exit_rename_column:
@@ -1762,12 +1763,17 @@ static void renameTableTest(
 }
 
 /*
+** The implementation of internal UDF sqlite_drop_column().
+** 
 ** Arguments:
 **
 **  argv[0]: An integer - the index of the schema containing the table
 **  argv[1]: CREATE TABLE statement to modify.
 **  argv[2]: An integer - the index of the column to remove.
 **  argv[3]: Byte offset of first byte after last column definition in argv[1]
+**
+** The value returned is a string containing the CREATE TABLE statement
+** with column argv[2] removed.
 */
 static void dropColumnFunc(
   sqlite3_context *context,
@@ -1809,21 +1815,21 @@ drop_column_done:
   renameParseCleanup(&sParse);
 }
 
+/*
+** This function is called by the parser upon parsing an 
+**
+**     ALTER TABLE pSrc DROP COLUMN pName
+**
+** statement. Argument pSrc contains the possibly qualified name of the
+** table being edited, and token pName the name of the column to drop.
+*/
 void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
-  Table *pTab;
-  int i;
-  int iSchema = 0;
-  const char *zDb = 0;
-  sqlite3 *db = pParse->db;
-  char *zCol = 0;
-  int iCol = 0;
-  Vdbe *v;
-  int iCur;
-  int addr;
-  int reg;
-  int regRec;
-  Index *pIdx;
-  Index *pPk = 0;
+  sqlite3 *db = pParse->db;       /* Database handle */
+  Table *pTab;                    /* Table to modify */
+  int iDb;                        /* Index of db containing pTab in aDb[] */
+  const char *zDb;                /* Database containing pTab ("main" etc.) */
+  char *zCol = 0;                 /* Name of column to drop */
+  int iCol;                       /* Index of column zCol in pTab->aCol[] */
 
   /* Look up the table being altered. */
   assert( pParse->pNewTable==0 );
@@ -1832,26 +1838,10 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
   pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
   if( !pTab ) goto exit_drop_column;
 
-  /* Which schema holds the table to be altered */  
-  iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
-  assert( iSchema>=0 );
-  zDb = db->aDb[iSchema].zDbSName;
-
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-  if( IsVirtual(pTab) ){
-    sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
-    goto exit_drop_column;
-  }
-#endif
-
-  /* Make sure this is not an attempt to ALTER a view. */
-  if( pTab->pSelect ){
-    sqlite3ErrorMsg(pParse, "cannot drop a column from a view");
-    goto exit_drop_column;
-  }
-  if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
-    goto exit_drop_column;
-  }
+  /* Make sure this is not an attempt to ALTER a view, virtual table or 
+  ** system table. */
+  if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_column;
+  if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_column;
 
   /* Find the index of the column being dropped. */
   zCol = sqlite3NameFromToken(db, pName);
@@ -1867,65 +1857,74 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
 
   /* Do not allow the user to drop a PRIMARY KEY column or a column 
   ** constrained by a UNIQUE constraint.  */
-  if( pTab->iPKey==iCol ){
-    sqlite3ErrorMsg(pParse, "cannot drop PRIMARY KEY column: \"%s\"", zCol);
+  if( pTab->aCol[iCol].colFlags & (COLFLAG_PRIMKEY|COLFLAG_UNIQUE) ){
+    sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"", 
+        (pTab->aCol[iCol].colFlags&COLFLAG_PRIMKEY) ? "PRIMARY KEY" : "UNIQUE",
+        zCol
+    );
     goto exit_drop_column;
   }
-  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
-    int ii;
-    for(ii=0; ii<pIdx->nKeyCol; ii++){
-      if( iCol==pIdx->aiColumn[ii] 
-       && sqlite3_strnicmp("sqlite_", pIdx->zName, 7)==0
-      ){
-        sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"", 
-          pIdx->idxType==2 ? "PRIMARY KEY" : "UNIQUE", zCol
-        );
-        goto exit_drop_column;
-      }
-    }
-  }
 
+  /* Edit the sqlite_schema table */
+  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+  assert( iDb>=0 );
+  zDb = db->aDb[iDb].zDbSName;
   sqlite3NestedParse(pParse, 
       "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
       "sql = sqlite_drop_column(%d, sql, %d, %d) "
       "WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)"
-      , zDb, iSchema, iCol, pTab->addColOffset, pTab->zName
+      , zDb, iDb, iCol, pTab->addColOffset, pTab->zName
   );
 
   /* Drop and reload the database schema. */
-  renameReloadSchema(pParse, iSchema);
-  renameTestSchema(pParse, zDb, iSchema==1);
+  renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop);
+  renameTestSchema(pParse, zDb, iDb==1);
 
   /* Edit rows of table on disk */
-  v = sqlite3GetVdbe(pParse);
-  iCur = pParse->nTab++;
-  sqlite3OpenTable(pParse, iCur, iSchema, pTab, OP_OpenWrite);
-  addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur);
-  reg = ++pParse->nMem;
-  pParse->nMem += pTab->nCol;
-  if( HasRowid(pTab) ){
-    sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg);
-  }else{
-    pPk = sqlite3PrimaryKeyIndex(pTab);
-  }
-  for(i=0; i<pTab->nCol; i++){
-    if( i!=iCol ){
-      int iPos = (pPk ? sqlite3TableColumnToIndex(pPk, i) : i);
-      int iColPos = (pPk ? sqlite3TableColumnToIndex(pPk, iCol) : iCol);
-      int regOut = reg+1+iPos-(iPos>iColPos);
-      sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
+  if( (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){
+    int i;
+    int addr;
+    int reg;
+    int regRec;
+    Index *pPk = 0;
+    int nField = 0;               /* Number of non-virtual columns after drop */
+    int iCur;
+    Vdbe *v = sqlite3GetVdbe(pParse);
+    iCur = pParse->nTab++;
+    sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
+    addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur);
+    reg = ++pParse->nMem;
+    pParse->nMem += pTab->nCol;
+    if( HasRowid(pTab) ){
+      sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg);
+    }else{
+      pPk = sqlite3PrimaryKeyIndex(pTab);
+    }
+    for(i=0; i<pTab->nCol; i++){
+      if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
+        int regOut;
+        if( pPk ){
+          int iPos = sqlite3TableColumnToIndex(pPk, i);
+          int iColPos = sqlite3TableColumnToIndex(pPk, iCol);
+          regOut = reg+1+iPos-(iPos>iColPos);
+        }else{
+          regOut = reg+1+nField;
+        }
+        sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
+        nField++;
+      }
+    }
+    regRec = reg + pTab->nCol;
+    sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec);
+    if( pPk ){
+      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol);
+    }else{
+      sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg);
     }
-  }
-  regRec = reg + pTab->nCol;
-  sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, pTab->nCol-1, regRec);
-  if( HasRowid(pTab) ){
-    sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg);
-  }else{
-    sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol);
-  }
 
-  sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1);
-  sqlite3VdbeJumpHere(v, addr);
+    sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1);
+    sqlite3VdbeJumpHere(v, addr);
+  }
 
 exit_drop_column:
   sqlite3DbFree(db, zCol);
index f5c796fac356f7590173b9f4c47e583df377dc6a..065b50c082b10adae38065d2d49c6ee1185a5a6a 100644 (file)
@@ -2638,7 +2638,7 @@ void sqlite3EndTable(
 
     /* Reparse everything to update our internal data structures */
     sqlite3VdbeAddParseSchemaOp(v, iDb,
-           sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
+           sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
   }
 
   /* Add the table to the in-memory representation of the database.
@@ -4126,7 +4126,7 @@ void sqlite3CreateIndex(
         sqlite3RefillIndex(pParse, pIndex, iMem);
         sqlite3ChangeCookie(pParse, iDb);
         sqlite3VdbeAddParseSchemaOp(v, iDb,
-            sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
+            sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0);
         sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
       }
 
index 87c1ab9368e0fc31b095f5b6363668c557154e2a..4888744a89cf7ef194a9893cbb79b1c527721967 100644 (file)
@@ -21,7 +21,7 @@
 */
 static void corruptSchema(
   InitData *pData,     /* Initialization context */
-  const char *zObj,    /* Object being parsed at the point of error */
+  char **azObj,        /* Type and name of object being parsed */
   const char *zExtra   /* Error information */
 ){
   sqlite3 *db = pData->db;
@@ -29,14 +29,18 @@ static void corruptSchema(
     pData->rc = SQLITE_NOMEM_BKPT;
   }else if( pData->pzErrMsg[0]!=0 ){
     /* A error message has already been generated.  Do not overwrite it */
-  }else if( pData->mInitFlags & INITFLAG_AlterTable ){
-    *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
+  }else if( pData->mInitFlags & (INITFLAG_AlterRename|INITFLAG_AlterDrop) ){
+    *pData->pzErrMsg = sqlite3MPrintf(db, 
+        "error in %s %s after %s: %s", azObj[0], azObj[1], 
+        (pData->mInitFlags & INITFLAG_AlterRename) ? "rename" : "drop column",
+        zExtra
+    );
     pData->rc = SQLITE_ERROR;
   }else if( db->flags & SQLITE_WriteSchema ){
     pData->rc = SQLITE_CORRUPT_BKPT;
   }else{
     char *z;
-    if( zObj==0 ) zObj = "?";
+    const char *zObj = azObj[1] ? azObj[1] : "?";
     z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
     if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
     *pData->pzErrMsg = z;
@@ -94,14 +98,14 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
   db->mDbFlags |= DBFLAG_EncodingFixed;
   pData->nInitRow++;
   if( db->mallocFailed ){
-    corruptSchema(pData, argv[1], 0);
+    corruptSchema(pData, argv, 0);
     return 1;
   }
 
   assert( iDb>=0 && iDb<db->nDb );
   if( argv==0 ) return 0;   /* Might happen if EMPTY_RESULT_CALLBACKS are on */
   if( argv[3]==0 ){
-    corruptSchema(pData, argv[1], 0);
+    corruptSchema(pData, argv, 0);
   }else if( argv[4]
          && 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]]
          && 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){
@@ -126,7 +130,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
      || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
     ){
       if( sqlite3Config.bExtraSchemaChecks ){
-        corruptSchema(pData, argv[1], "invalid rootpage");
+        corruptSchema(pData, argv, "invalid rootpage");
       }
     }
     db->init.orphanTrigger = 0;
@@ -145,13 +149,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
         if( rc==SQLITE_NOMEM ){
           sqlite3OomFault(db);
         }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
-          corruptSchema(pData, argv[1], sqlite3_errmsg(db));
+          corruptSchema(pData, argv, sqlite3_errmsg(db));
         }
       }
     }
     sqlite3_finalize(pStmt);
   }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
-    corruptSchema(pData, argv[1], 0);
+    corruptSchema(pData, argv, 0);
   }else{
     /* If the SQL column is blank it means this is an index that
     ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@@ -162,7 +166,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
     Index *pIndex;
     pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
     if( pIndex==0 ){
-      corruptSchema(pData, argv[1], "orphan index");
+      corruptSchema(pData, argv, "orphan index");
     }else
     if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
      || pIndex->tnum<2
@@ -170,7 +174,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
      || sqlite3IndexHasDuplicateRootPage(pIndex)
     ){
       if( sqlite3Config.bExtraSchemaChecks ){
-        corruptSchema(pData, argv[1], "invalid rootpage");
+        corruptSchema(pData, argv, "invalid rootpage");
       }
     }
   }
index 9c09b24acafa0df5d6f35899ffd3646c427b8005..850396ced3adf0bae18397cb3fbf83c79c6df119 100644 (file)
@@ -3711,7 +3711,8 @@ typedef struct {
 /*
 ** Allowed values for mInitFlags
 */
-#define INITFLAG_AlterTable   0x0001  /* This is a reparse after ALTER TABLE */
+#define INITFLAG_AlterRename   0x0001  /* Reparse after a RENAME */
+#define INITFLAG_AlterDrop     0x0002  /* Reparse after a DROP COLUMN */
 
 /*
 ** Structure containing global configuration data for the SQLite library.
index 1d4c2790c35d641d10c3d9dce41cbd2075344985..689c7c741eeba429736329232a813b0a97124d86 100644 (file)
@@ -356,7 +356,7 @@ void sqlite3FinishTrigger(
     sqlite3DbFree(db, z);
     sqlite3ChangeCookie(pParse, iDb);
     sqlite3VdbeAddParseSchemaOp(v, iDb,
-        sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
+        sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0);
   }
 
   if( db->init.busy ){
index 97cd696de318d4c27b67ec37d1070965ec935615..153ed40b75f278f0f95b26fa4e345dac292456ae 100644 (file)
@@ -6330,7 +6330,7 @@ case OP_ParseSchema: {
   if( pOp->p4.z==0 ){
     sqlite3SchemaClear(db->aDb[iDb].pSchema);
     db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
-    rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
+    rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5);
     db->mDbFlags |= DBFLAG_SchemaChange;
     p->expired = 0;
   }else
index 17f11fdd7734604216b66415895164b2888378e6..3257ff68a174d8dbd675368e21e4daccd5a782ae 100644 (file)
@@ -223,7 +223,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
 #else
 # define sqlite3ExplainBreakpoint(A,B) /*no-op*/
 #endif
-void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
+void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16);
 void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
 void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
 void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
index 7ee4f629e0edc4da2efb38273b538167a56e6d1f..ede652dfac67ae9c9f122efd22bc039a6bdfd4e5 100644 (file)
@@ -471,9 +471,10 @@ void sqlite3VdbeExplainPop(Parse *pParse){
 ** The zWhere string must have been obtained from sqlite3_malloc().
 ** This routine will take ownership of the allocated memory.
 */
-void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
+void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){
   int j;
   sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
+  sqlite3VdbeChangeP5(p, p5);
   for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
   sqlite3MayAbort(p->pParse);
 }
index 400ae40968eb642a8cd1a2bb851f1d139f63db54..0da5518b152196aff42797084c6ff1ea1a10d942 100644 (file)
@@ -489,7 +489,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
 
     sqlite3VdbeAddOp0(v, OP_Expire);
     zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
-    sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
+    sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0);
     sqlite3DbFree(db, zStmt);
 
     iReg = ++pParse->nMem;
index 7bb597705473b578ff931ba55e0116d7bf38a07d..ef3e97dea767e9a530336829ba51b1909b550ec2 100644 (file)
@@ -26,6 +26,9 @@ do_execsql_test 1.0 {
 
   CREATE TABLE t2(x INTEGER PRIMARY KEY, y, z UNIQUE);
   CREATE INDEX t2y ON t2(y);
+
+  CREATE TABLE t3(q, r, s);
+  CREATE INDEX t3rs ON t3(r+s);
 }
 
 do_catchsql_test 1.1 {
@@ -34,7 +37,7 @@ do_catchsql_test 1.1 {
 
 do_catchsql_test 1.2 {
   ALTER TABLE v1 DROP COLUMN c;
-} {1 {cannot drop a column from a view}}
+} {1 {cannot drop column from view "v1"}}
 
 ifcapable fts5 {
   do_execsql_test 1.3.1 {
@@ -42,7 +45,7 @@ ifcapable fts5 {
   }
   do_catchsql_test 1.3.2 {
     ALTER TABLE ft1 DROP COLUMN two;
-  } {1 {virtual tables may not be altered}}
+  } {1 {cannot drop column from virtual table "ft1"}}
 }
 
 do_catchsql_test 1.4 {
@@ -67,6 +70,10 @@ do_execsql_test 1.7.2 {
   SELECT sql FROM sqlite_schema WHERE name = 't1'
 } {{CREATE TABLE t1(a)}}
 
+do_catchsql_test 1.7.3 {
+  ALTER TABLE t1 DROP COLUMN a;
+} {1 {error in table t1 after drop column: near ")": syntax error}}
+
 
 do_catchsql_test 1.8 {
   ALTER TABLE t2 DROP COLUMN z
@@ -78,7 +85,11 @@ do_catchsql_test 1.9 {
 
 do_catchsql_test 1.10 {
   ALTER TABLE t2 DROP COLUMN y
-} {1 {cannot drop indexed column: "y"}}
+} {1 {error in index t2y after drop column: no such column: y}}
+
+do_catchsql_test 1.11 {
+  ALTER TABLE t3 DROP COLUMN s
+} {1 {error in index t3rs after drop column: no such column: s}}
 
 #-------------------------------------------------------------------------
 
@@ -109,5 +120,95 @@ foreach {tn wo} {
   }
 }]}
 
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 3.0 {
+  CREATE TABLE t12(a, b, c, CHECK(c>10));
+  CREATE TABLE t13(a, b, c CHECK(c>10));
+}
+do_catchsql_test 3.1 {
+  ALTER TABLE t12 DROP COLUMN c;
+} {1 {error in table t12 after drop column: no such column: c}}
+
+do_catchsql_test 3.2 {
+  ALTER TABLE t13 DROP COLUMN c;
+} {0 {}}
+
+#-------------------------------------------------------------------------
+# Test that generated columns can be dropped. And that other columns from
+# tables that contain generated columns can be dropped.
+#
+foreach {tn wo vs} {
+  1 ""              ""
+  2 ""              VIRTUAL
+  3 ""              STORED
+  4 "WITHOUT ROWID" STORED
+  5 "WITHOUT ROWID" VIRTUAL
+} {
+  reset_db
+
+  do_execsql_test 4.$tn.0 "
+    CREATE TABLE 'my table'(a, b PRIMARY KEY, c AS (a+b) $vs, d) $wo
+  "
+  do_execsql_test 4.$tn.1 {
+    INSERT INTO "my table"(a, b, d) VALUES(1, 2, 'hello');
+    INSERT INTO "my table"(a, b, d) VALUES(3, 4, 'world');
+
+    SELECT * FROM "my table"
+  } {
+    1 2 3 hello
+    3 4 7 world
+  }
+
+  do_execsql_test 4.$tn.2 {
+    ALTER TABLE "my table" DROP COLUMN c;
+  }
+  do_execsql_test 4.$tn.3 {
+    SELECT * FROM "my table"
+  } {
+    1 2 hello
+    3 4 world
+  }
+  
+  do_execsql_test 4.$tn.4 "
+    CREATE TABLE x1(a, b, c PRIMARY KEY, d AS (b+c) $vs, e) $wo
+  "
+  do_execsql_test 4.$tn.5 {
+    INSERT INTO x1(a, b, c, e) VALUES(1, 2, 3, 4);
+    INSERT INTO x1(a, b, c, e) VALUES(5, 6, 7, 8);
+    INSERT INTO x1(a, b, c, e) VALUES(9, 10, 11, 12);
+    SELECT * FROM x1;
+  } {
+    1 2 3 5 4
+    5 6 7 13 8
+    9 10 11 21 12
+  }
+
+  do_execsql_test 4.$tn.6 {
+    ALTER TABLE x1 DROP COLUMN a
+  }
+  do_execsql_test 4.$tn.7 {
+    SELECT * FROM x1
+  } {
+    2 3 5 4
+    6 7 13 8
+    10 11 21 12
+  }
+  do_execsql_test 4.$tn.8 {
+    ALTER TABLE x1 DROP COLUMN e
+  }
+  do_execsql_test 4.$tn.9 {
+    SELECT * FROM x1
+  } {
+    2 3 5
+    6 7 13
+    10 11 21
+  }
+}
+
+
+
 finish_test
 
+
index 47d8bcfba986e32d1f4be47ffff790c48014ceb0..dfa171646718b636b33b68a50157d365e97cc848 100644 (file)
@@ -40,7 +40,7 @@ do_execsql_test 1.1 {
 # slightly different - it rejects the change and rolls back the transaction.
 do_catchsql_test 1.2 {
   ALTER TABLE t1 RENAME TO t1new;
-} {1 {no such column: t1.a}}
+} {1 {error in table t1new after rename: no such column: t1.a}}
 
 do_execsql_test 1.3 {
   CREATE TABLE t3(c, d);
@@ -59,7 +59,7 @@ do_execsql_test 1.4 {
 
 do_catchsql_test 1.3 {
   ALTER TABLE t2 RENAME TO t2new;
-} {1 {no such column: t2.b}}
+} {1 {error in index t2expr after rename: no such column: t2.b}}
 do_execsql_test 1.4 {
   SELECT sql FROM sqlite_master
 } {