SQLite

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
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.931
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
Side-by-Side Diff Ignore Whitespace Patch
Changes to src/alter.c.
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1122
1123
1124
1125
1126
1127
1128

1129
1130
1131
1132
1133
1134
1135







-







      for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
        sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
      }
    }

    for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
      for(i=0; i<pFKey->nCol; i++){
        RenameToken *pTok = 0;
        if( bFKOnly==0 && pFKey->aCol[i].iFrom==sCtx.iCol ){
          renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
        }
        if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
         && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
        ){
          renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);
Changes to src/prepare.c.
21
22
23
24
25
26
27







28



29
30
31
32
33
34

35
36
37
38
39
40
41
42
43
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41

42
43
44

45
46
47
48
49
50
51







+
+
+
+
+
+
+
-
+
+
+




-

+

-







*/
static void corruptSchema(
  InitData *pData,     /* Initialization context */
  const char *zObj,    /* Object being parsed at the point of error */
  const char *zExtra   /* Error information */
){
  sqlite3 *db = pData->db;
  if( db->mallocFailed ){
    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);
    pData->rc = SQLITE_ERROR;
  if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){
  }else if( db->flags & SQLITE_WriteSchema ){
    pData->rc = SQLITE_CORRUPT_BKPT;
  }else{
    char *z;
    if( zObj==0 ) zObj = "?";
    z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
    if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
    sqlite3DbFree(db, *pData->pzErrMsg);
    *pData->pzErrMsg = z;
    pData->rc = SQLITE_CORRUPT_BKPT;
  }
  pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
}

/*
** This is the callback routine for the code that initializes the
** database.  See sqlite3Init() below for additional information.
** This routine is also called from the OP_ParseSchema opcode of the VDBE.
**
128
129
130
131
132
133
134
135

136
137
138
139
140
141
142
136
137
138
139
140
141
142

143
144
145
146
147
148
149
150







-
+







** Attempt to read the database schema and initialize internal
** data structures for a single database file.  The index of the
** database file is given by iDb.  iDb==0 is used for the main
** database.  iDb==1 should never be used.  iDb>=2 is used for
** auxiliary databases.  Return one of the SQLITE_ error codes to
** indicate success or failure.
*/
int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
  int rc;
  int i;
#ifndef SQLITE_OMIT_DEPRECATED
  int size;
#endif
  Db *pDb;
  char const *azArg[4];
163
164
165
166
167
168
169

170
171
172
173
174
175
176
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185







+







  azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
                            "rootpage int,sql text)";
  azArg[3] = 0;
  initData.db = db;
  initData.iDb = iDb;
  initData.rc = SQLITE_OK;
  initData.pzErrMsg = pzErrMsg;
  initData.mInitFlags = mFlags;
  sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
  if( initData.rc ){
    rc = initData.rc;
    goto error_out;
  }

  /* Create a cursor to hold the database open
369
370
371
372
373
374
375
376

377
378
379
380
381
382
383

384
385
386
387
388
389
390
378
379
380
381
382
383
384

385
386
387
388
389
390
391

392
393
394
395
396
397
398
399







-
+






-
+







  assert( sqlite3_mutex_held(db->mutex) );
  assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
  assert( db->init.busy==0 );
  ENC(db) = SCHEMA_ENC(db);
  assert( db->nDb>0 );
  /* Do the main schema first */
  if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
    rc = sqlite3InitOne(db, 0, pzErrMsg);
    rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
    if( rc ) return rc;
  }
  /* All other schemas after the main schema. The "temp" schema must be last */
  for(i=db->nDb-1; i>0; i--){
    assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
    if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
      rc = sqlite3InitOne(db, i, pzErrMsg);
      rc = sqlite3InitOne(db, i, pzErrMsg, 0);
      if( rc ) return rc;
    }
  }
  if( commit_internal ){
    sqlite3CommitInternalChanges(db);
  }
  return SQLITE_OK;
Changes to src/sqliteInt.h.
3325
3326
3327
3328
3329
3330
3331

3332
3333





3334
3335
3336
3337
3338
3339
3340
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346







+


+
+
+
+
+







** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
*/
typedef struct {
  sqlite3 *db;        /* The database being initialized */
  char **pzErrMsg;    /* Error message stored here */
  int iDb;            /* 0 for main database.  1 for TEMP, 2.. for ATTACHed */
  int rc;             /* Result code stored here */
  u32 mInitFlags;     /* Flags controlling error messages */
} InitData;

/*
** Allowed values for mInitFlags
*/
#define INITFLAG_AlterTable   0x0001  /* This is a reparse after ALTER TABLE */

/*
** Structure containing global configuration data for the SQLite library.
**
** This structure also contains some state information.
*/
struct Sqlite3Config {
  int bMemstat;                     /* True to enable memory status */
3797
3798
3799
3800
3801
3802
3803
3804

3805
3806
3807
3808
3809
3810
3811
3803
3804
3805
3806
3807
3808
3809

3810
3811
3812
3813
3814
3815
3816
3817







-
+







void sqlite3ExprListSetSortOrder(ExprList*,int);
void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
void sqlite3ExprListDelete(sqlite3*, ExprList*);
u32 sqlite3ExprListFlags(const ExprList*);
int sqlite3Init(sqlite3*, char**);
int sqlite3InitCallback(void*, int, char**, char**);
int sqlite3InitOne(sqlite3*, int, char**);
int sqlite3InitOne(sqlite3*, int, char**, u32);
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
#ifndef SQLITE_OMIT_VIRTUALTABLE
Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
#endif
void sqlite3ResetAllSchemasOfConnection(sqlite3*);
void sqlite3ResetOneSchema(sqlite3*,int);
void sqlite3CollapseDatabaseArray(sqlite3*);
Changes to src/vdbe.c.
5718
5719
5720
5721
5722
5723
5724
5725


5726
5727
5728
5729
5730
5731
5732
5718
5719
5720
5721
5722
5723
5724

5725
5726
5727
5728
5729
5730
5731
5732
5733







-
+
+







  if( rc ) goto abort_due_to_error;
  break;
}

/* Opcode: ParseSchema P1 * * P4 *
**
** Read and parse all entries from the SQLITE_MASTER table of database P1
** that match the WHERE clause P4. 
** that match the WHERE clause P4.  If P4 is a NULL pointer, then the
** entire schema for P1 is reparsed.
**
** This opcode invokes the parser to create a new virtual machine,
** then runs the new virtual machine.  It is thus a re-entrant opcode.
*/
case OP_ParseSchema: {
  int iDb;
  const char *zMaster;
5747
5748
5749
5750
5751
5752
5753
5754

5755
5756
5757
5758

5759
5760
5761
5762
5763
5764
5765
5748
5749
5750
5751
5752
5753
5754

5755
5756
5757
5758

5759
5760
5761
5762
5763
5764
5765
5766







-
+



-
+







  assert( iDb>=0 && iDb<db->nDb );
  assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );

#ifndef SQLITE_OMIT_ALTERTABLE
  if( pOp->p4.z==0 ){
    sqlite3SchemaClear(db->aDb[iDb].pSchema);
    db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
    rc = sqlite3InitOne(db, iDb, &p->zErrMsg);
    rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
    db->mDbFlags |= DBFLAG_SchemaChange;
  }else
#endif
  /* Used to be a conditional */ {
  {
    zMaster = MASTER_NAME;
    initData.db = db;
    initData.iDb = pOp->p1;
    initData.pzErrMsg = &p->zErrMsg;
    zSql = sqlite3MPrintf(db,
       "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
       db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
Changes to test/trigger7.test.
109
110
111
112
113
114
115
116

117
118
109
110
111
112
113
114
115

116
117
118







-
+


  execsql {
    PRAGMA writable_schema=on;
    UPDATE sqlite_master SET sql='nonsense';
  }
  db close
  catch { sqlite3 db test.db }
  catchsql { DROP TRIGGER t2r5 }
} {1 {malformed database schema (t2r12)}}
} {/1 {malformed database schema .*}/}

finish_test