/ Check-in [37d11b8e82]
Login

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

Overview
Comment:Improved error messages when an ALTER TABLE RENAME COLUMN fails due to a duplicate column name.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | alter-table-rename-column
Files: files | file ages | folders
SHA3-256: 37d11b8e8224a8b241ff57b9c4b9499db39dde4ddcb56ff8b03a3d08091a4c11
User & Date: drh 2018-08-14 19:27:51
Context
2018-08-14
20:40
Merge latest trunk and ALTER TABLE error message improvements into this branch. check-in: 7a45802daf user: dan tags: edit-trigger-wrapper
20:38
Do not allow ALTER TABLE RENAME COLUMN on a virtual table. check-in: f6d6b47271 user: drh tags: alter-table-rename-column
19:27
Improved error messages when an ALTER TABLE RENAME COLUMN fails due to a duplicate column name. check-in: 37d11b8e82 user: drh tags: alter-table-rename-column
18:12
Merge fixes and enhancements from trunk. check-in: dff0314b7e user: drh tags: alter-table-rename-column
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/alter.c.

  1122   1122         for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
  1123   1123           sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
  1124   1124         }
  1125   1125       }
  1126   1126   
  1127   1127       for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
  1128   1128         for(i=0; i<pFKey->nCol; i++){
  1129         -        RenameToken *pTok = 0;
  1130   1129           if( bFKOnly==0 && pFKey->aCol[i].iFrom==sCtx.iCol ){
  1131   1130             renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
  1132   1131           }
  1133   1132           if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
  1134   1133            && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
  1135   1134           ){
  1136   1135             renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);

Changes to src/prepare.c.

    21     21   */
    22     22   static void corruptSchema(
    23     23     InitData *pData,     /* Initialization context */
    24     24     const char *zObj,    /* Object being parsed at the point of error */
    25     25     const char *zExtra   /* Error information */
    26     26   ){
    27     27     sqlite3 *db = pData->db;
    28         -  if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){
           28  +  if( db->mallocFailed ){
           29  +    pData->rc = SQLITE_NOMEM_BKPT;
           30  +  }else if( pData->pzErrMsg[0]!=0 ){
           31  +    /* A error message has already been generated.  Do not overwrite it */
           32  +  }else if( pData->mInitFlags & INITFLAG_AlterTable ){
           33  +    *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
           34  +    pData->rc = SQLITE_ERROR;
           35  +  }else if( db->flags & SQLITE_WriteSchema ){
           36  +    pData->rc = SQLITE_CORRUPT_BKPT;
           37  +  }else{
    29     38       char *z;
    30     39       if( zObj==0 ) zObj = "?";
    31     40       z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
    32     41       if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
    33         -    sqlite3DbFree(db, *pData->pzErrMsg);
    34     42       *pData->pzErrMsg = z;
           43  +    pData->rc = SQLITE_CORRUPT_BKPT;
    35     44     }
    36         -  pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
    37     45   }
    38     46   
    39     47   /*
    40     48   ** This is the callback routine for the code that initializes the
    41     49   ** database.  See sqlite3Init() below for additional information.
    42     50   ** This routine is also called from the OP_ParseSchema opcode of the VDBE.
    43     51   **
................................................................................
   128    136   ** Attempt to read the database schema and initialize internal
   129    137   ** data structures for a single database file.  The index of the
   130    138   ** database file is given by iDb.  iDb==0 is used for the main
   131    139   ** database.  iDb==1 should never be used.  iDb>=2 is used for
   132    140   ** auxiliary databases.  Return one of the SQLITE_ error codes to
   133    141   ** indicate success or failure.
   134    142   */
   135         -int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
          143  +int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
   136    144     int rc;
   137    145     int i;
   138    146   #ifndef SQLITE_OMIT_DEPRECATED
   139    147     int size;
   140    148   #endif
   141    149     Db *pDb;
   142    150     char const *azArg[4];
................................................................................
   163    171     azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
   164    172                               "rootpage int,sql text)";
   165    173     azArg[3] = 0;
   166    174     initData.db = db;
   167    175     initData.iDb = iDb;
   168    176     initData.rc = SQLITE_OK;
   169    177     initData.pzErrMsg = pzErrMsg;
          178  +  initData.mInitFlags = mFlags;
   170    179     sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
   171    180     if( initData.rc ){
   172    181       rc = initData.rc;
   173    182       goto error_out;
   174    183     }
   175    184   
   176    185     /* Create a cursor to hold the database open
................................................................................
   369    378     assert( sqlite3_mutex_held(db->mutex) );
   370    379     assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
   371    380     assert( db->init.busy==0 );
   372    381     ENC(db) = SCHEMA_ENC(db);
   373    382     assert( db->nDb>0 );
   374    383     /* Do the main schema first */
   375    384     if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
   376         -    rc = sqlite3InitOne(db, 0, pzErrMsg);
          385  +    rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
   377    386       if( rc ) return rc;
   378    387     }
   379    388     /* All other schemas after the main schema. The "temp" schema must be last */
   380    389     for(i=db->nDb-1; i>0; i--){
   381    390       assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
   382    391       if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
   383         -      rc = sqlite3InitOne(db, i, pzErrMsg);
          392  +      rc = sqlite3InitOne(db, i, pzErrMsg, 0);
   384    393         if( rc ) return rc;
   385    394       }
   386    395     }
   387    396     if( commit_internal ){
   388    397       sqlite3CommitInternalChanges(db);
   389    398     }
   390    399     return SQLITE_OK;

Changes to src/sqliteInt.h.

  3325   3325   ** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
  3326   3326   */
  3327   3327   typedef struct {
  3328   3328     sqlite3 *db;        /* The database being initialized */
  3329   3329     char **pzErrMsg;    /* Error message stored here */
  3330   3330     int iDb;            /* 0 for main database.  1 for TEMP, 2.. for ATTACHed */
  3331   3331     int rc;             /* Result code stored here */
         3332  +  u32 mInitFlags;     /* Flags controlling error messages */
  3332   3333   } InitData;
  3333   3334   
         3335  +/*
         3336  +** Allowed values for mInitFlags
         3337  +*/
         3338  +#define INITFLAG_AlterTable   0x0001  /* This is a reparse after ALTER TABLE */
         3339  +
  3334   3340   /*
  3335   3341   ** Structure containing global configuration data for the SQLite library.
  3336   3342   **
  3337   3343   ** This structure also contains some state information.
  3338   3344   */
  3339   3345   struct Sqlite3Config {
  3340   3346     int bMemstat;                     /* True to enable memory status */
................................................................................
  3797   3803   void sqlite3ExprListSetSortOrder(ExprList*,int);
  3798   3804   void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
  3799   3805   void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
  3800   3806   void sqlite3ExprListDelete(sqlite3*, ExprList*);
  3801   3807   u32 sqlite3ExprListFlags(const ExprList*);
  3802   3808   int sqlite3Init(sqlite3*, char**);
  3803   3809   int sqlite3InitCallback(void*, int, char**, char**);
  3804         -int sqlite3InitOne(sqlite3*, int, char**);
         3810  +int sqlite3InitOne(sqlite3*, int, char**, u32);
  3805   3811   void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
  3806   3812   #ifndef SQLITE_OMIT_VIRTUALTABLE
  3807   3813   Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
  3808   3814   #endif
  3809   3815   void sqlite3ResetAllSchemasOfConnection(sqlite3*);
  3810   3816   void sqlite3ResetOneSchema(sqlite3*,int);
  3811   3817   void sqlite3CollapseDatabaseArray(sqlite3*);

Changes to src/vdbe.c.

  5718   5718     if( rc ) goto abort_due_to_error;
  5719   5719     break;
  5720   5720   }
  5721   5721   
  5722   5722   /* Opcode: ParseSchema P1 * * P4 *
  5723   5723   **
  5724   5724   ** Read and parse all entries from the SQLITE_MASTER table of database P1
  5725         -** that match the WHERE clause P4. 
         5725  +** that match the WHERE clause P4.  If P4 is a NULL pointer, then the
         5726  +** entire schema for P1 is reparsed.
  5726   5727   **
  5727   5728   ** This opcode invokes the parser to create a new virtual machine,
  5728   5729   ** then runs the new virtual machine.  It is thus a re-entrant opcode.
  5729   5730   */
  5730   5731   case OP_ParseSchema: {
  5731   5732     int iDb;
  5732   5733     const char *zMaster;
................................................................................
  5747   5748     assert( iDb>=0 && iDb<db->nDb );
  5748   5749     assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
  5749   5750   
  5750   5751   #ifndef SQLITE_OMIT_ALTERTABLE
  5751   5752     if( pOp->p4.z==0 ){
  5752   5753       sqlite3SchemaClear(db->aDb[iDb].pSchema);
  5753   5754       db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
  5754         -    rc = sqlite3InitOne(db, iDb, &p->zErrMsg);
         5755  +    rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
  5755   5756       db->mDbFlags |= DBFLAG_SchemaChange;
  5756   5757     }else
  5757   5758   #endif
  5758         -  /* Used to be a conditional */ {
         5759  +  {
  5759   5760       zMaster = MASTER_NAME;
  5760   5761       initData.db = db;
  5761   5762       initData.iDb = pOp->p1;
  5762   5763       initData.pzErrMsg = &p->zErrMsg;
  5763   5764       zSql = sqlite3MPrintf(db,
  5764   5765          "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
  5765   5766          db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);

Changes to test/trigger7.test.

   109    109     execsql {
   110    110       PRAGMA writable_schema=on;
   111    111       UPDATE sqlite_master SET sql='nonsense';
   112    112     }
   113    113     db close
   114    114     catch { sqlite3 db test.db }
   115    115     catchsql { DROP TRIGGER t2r5 }
   116         -} {1 {malformed database schema (t2r12)}}
          116  +} {/1 {malformed database schema .*}/}
   117    117   
   118    118   finish_test