wasCSharpSQLite – Blame information for rev 3

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Diagnostics;
3 using System.Text;
4  
5 namespace Community.CsharpSqlite
6 {
7 using sqlite3_value = Sqlite3.Mem;
8  
9 public partial class Sqlite3
10 {
11 /*
12 ** 2005 February 15
13 **
14 ** The author disclaims copyright to this source code. In place of
15 ** a legal notice, here is a blessing:
16 **
17 ** May you do good and not evil.
18 ** May you find forgiveness for yourself and forgive others.
19 ** May you share freely, never taking more than you give.
20 **
21 *************************************************************************
22 ** This file contains C code routines that used to generate VDBE code
23 ** that implements the ALTER TABLE command.
24 *************************************************************************
25 ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
26 ** C#-SQLite is an independent reimplementation of the SQLite software library
27 **
28 ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
29 **
30 *************************************************************************
31 */
32 //#include "sqliteInt.h"
33  
34 /*
35 ** The code in this file only exists if we are not omitting the
36 ** ALTER TABLE logic from the build.
37 */
38 #if !SQLITE_OMIT_ALTERTABLE
39  
40  
41 /*
42 ** This function is used by SQL generated to implement the
43 ** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
44 ** CREATE INDEX command. The second is a table name. The table name in
45 ** the CREATE TABLE or CREATE INDEX statement is replaced with the third
46 ** argument and the result returned. Examples:
47 **
48 ** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
49 ** . 'CREATE TABLE def(a, b, c)'
50 **
51 ** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def')
52 ** . 'CREATE INDEX i ON def(a, b, c)'
53 */
54 static void renameTableFunc(
55 sqlite3_context context,
56 int NotUsed,
57 sqlite3_value[] argv
58 )
59 {
60 string bResult = sqlite3_value_text( argv[0] );
61 string zSql = bResult ?? string.Empty;
62 string zTableName = sqlite3_value_text( argv[1] );
63  
64 int token = 0;
65 Token tname = new Token();
66 int zCsr = 0;
67 int zLoc = 0;
68 int len = 0;
69 string zRet;
70  
71 sqlite3 db = sqlite3_context_db_handle( context );
72  
73 UNUSED_PARAMETER( NotUsed );
74  
75 /* The principle used to locate the table name in the CREATE TABLE
76 ** statement is that the table name is the first non-space token that
77 ** is immediately followed by a TK_LP or TK_USING token.
78 */
79 if ( zSql.Length > 0 )
80 {
81 do
82 {
83 if ( zCsr == zSql.Length )
84 {
85 /* Ran out of input before finding an opening bracket. Return NULL. */
86 return;
87 }
88  
89 /* Store the token that zCsr points to in tname. */
90 zLoc = zCsr;
91 tname.z = zSql.Substring( zCsr );//(char*)zCsr;
92 tname.n = len;
93  
94 /* Advance zCsr to the next token. Store that token type in 'token',
95 ** and its length in 'len' (to be used next iteration of this loop).
96 */
97 do
98 {
99 zCsr += len;
100 len = ( zCsr == zSql.Length ) ? 1 : sqlite3GetToken( zSql, zCsr, ref token );
101 } while ( token == TK_SPACE );
102 Debug.Assert( len > 0 );
103 } while ( token != TK_LP && token != TK_USING );
104  
105 zRet = sqlite3MPrintf( db, "%.*s\"%w\"%s", zLoc, zSql.Substring( 0, zLoc ),
106 zTableName, zSql.Substring( zLoc + tname.n ) );
107  
108 sqlite3_result_text( context, zRet, -1, SQLITE_DYNAMIC );
109 }
110 }
111  
112 /*
113 ** This C function implements an SQL user function that is used by SQL code
114 ** generated by the ALTER TABLE ... RENAME command to modify the definition
115 ** of any foreign key constraints that use the table being renamed as the
116 ** parent table. It is passed three arguments:
117 **
118 ** 1) The complete text of the CREATE TABLE statement being modified,
119 ** 2) The old name of the table being renamed, and
120 ** 3) The new name of the table being renamed.
121 **
122 ** It returns the new CREATE TABLE statement. For example:
123 **
124 ** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3')
125 ** -> 'CREATE TABLE t1(a REFERENCES t3)'
126 */
127 #if !SQLITE_OMIT_FOREIGN_KEY
128 static void renameParentFunc(
129 sqlite3_context context,
130 int NotUsed,
131 sqlite3_value[] argv
132 )
133 {
134 sqlite3 db = sqlite3_context_db_handle( context );
135 string zOutput = string.Empty;
136 string zResult;
137 string zInput = sqlite3_value_text( argv[0] );
138 string zOld = sqlite3_value_text( argv[1] );
139 string zNew = sqlite3_value_text( argv[2] );
140  
141 int zIdx; /* Pointer to token */
142 int zLeft = 0; /* Pointer to remainder of String */
143 int n = 0; /* Length of token z */
144 int token = 0; /* Type of token */
145  
146 UNUSED_PARAMETER( NotUsed );
147 for ( zIdx = 0; zIdx < zInput.Length; zIdx += n )//z=zInput; *z; z=z+n)
148 {
149 n = sqlite3GetToken( zInput, zIdx, ref token );
150 if ( token == TK_REFERENCES )
151 {
152 string zParent;
153 do
154 {
155 zIdx += n;
156 n = sqlite3GetToken( zInput, zIdx, ref token );
157 } while ( token == TK_SPACE );
158  
159 zParent = zIdx + n < zInput.Length ? zInput.Substring( zIdx, n ) : string.Empty;//sqlite3DbStrNDup(db, zIdx, n);
160 if ( string.IsNullOrEmpty( zParent ) )
161 break;
162 sqlite3Dequote( ref zParent );
163 if ( zOld.Equals( zParent, StringComparison.OrdinalIgnoreCase ) )
164 {
165 string zOut = sqlite3MPrintf( db, "%s%.*s\"%w\"",
166 zOutput, zIdx - zLeft, zInput.Substring( zLeft ), zNew
167 );
168 sqlite3DbFree( db, ref zOutput );
169 zOutput = zOut;
170 zIdx += n;// zInput = &z[n];
171 zLeft = zIdx;
172 }
173 sqlite3DbFree( db, ref zParent );
174 }
175 }
176  
177 zResult = sqlite3MPrintf( db, "%s%s", zOutput, zInput.Substring( zLeft ) );
178 sqlite3_result_text( context, zResult, -1, SQLITE_DYNAMIC );
179 sqlite3DbFree( db, ref zOutput );
180 }
181 #endif
182  
183 #if !SQLITE_OMIT_TRIGGER
184 /* This function is used by SQL generated to implement the
185 ** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
186 ** statement. The second is a table name. The table name in the CREATE
187 ** TRIGGER statement is replaced with the third argument and the result
188 ** returned. This is analagous to renameTableFunc() above, except for CREATE
189 ** TRIGGER, not CREATE INDEX and CREATE TABLE.
190 */
191 static void renameTriggerFunc(
192 sqlite3_context context,
193 int NotUsed,
194 sqlite3_value[] argv
195 )
196 {
197 string zSql = sqlite3_value_text( argv[0] );
198 string zTableName = sqlite3_value_text( argv[1] );
199  
200 int token = 0;
201 Token tname = new Token();
202 int dist = 3;
203 int zCsr = 0;
204 int zLoc = 0;
205 int len = 1;
206 string zRet;
207  
208 sqlite3 db = sqlite3_context_db_handle( context );
209  
210 UNUSED_PARAMETER( NotUsed );
211  
212 /* The principle used to locate the table name in the CREATE TRIGGER
213 ** statement is that the table name is the first token that is immediatedly
214 ** preceded by either TK_ON or TK_DOT and immediatedly followed by one
215 ** of TK_WHEN, TK_BEGIN or TK_FOR.
216 */
217 if ( zSql != null )
218 {
219 do
220 {
221  
222 if ( zCsr == zSql.Length )
223 {
224 /* Ran out of input before finding the table name. Return NULL. */
225 return;
226 }
227  
228 /* Store the token that zCsr points to in tname. */
229 zLoc = zCsr;
230 tname.z = zSql.Substring( zCsr, len );//(char*)zCsr;
231 tname.n = len;
232  
233 /* Advance zCsr to the next token. Store that token type in 'token',
234 ** and its length in 'len' (to be used next iteration of this loop).
235 */
236 do
237 {
238 zCsr += len;
239 len = ( zCsr == zSql.Length ) ? 1 : sqlite3GetToken( zSql, zCsr, ref token );
240 } while ( token == TK_SPACE );
241 Debug.Assert( len > 0 );
242  
243 /* Variable 'dist' stores the number of tokens read since the most
244 ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN
245 ** token is read and 'dist' equals 2, the condition stated above
246 ** to be met.
247 **
248 ** Note that ON cannot be a database, table or column name, so
249 ** there is no need to worry about syntax like
250 ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc.
251 */
252 dist++;
253 if ( token == TK_DOT || token == TK_ON )
254 {
255 dist = 0;
256 }
257 } while ( dist != 2 || ( token != TK_WHEN && token != TK_FOR && token != TK_BEGIN ) );
258  
259 /* Variable tname now contains the token that is the old table-name
260 ** in the CREATE TRIGGER statement.
261 */
262 zRet = sqlite3MPrintf( db, "%.*s\"%w\"%s", zLoc, zSql.Substring( 0, zLoc ),
263 zTableName, zSql.Substring( zLoc + tname.n ) );
264 sqlite3_result_text( context, zRet, -1, SQLITE_DYNAMIC );
265 }
266 }
267 #endif // * !SQLITE_OMIT_TRIGGER */
268  
269 /*
270 ** Register built-in functions used to help implement ALTER TABLE
271 */
272 static FuncDef[] aAlterTableFuncs;
273 static void sqlite3AlterFunctions()
274 {
275 aAlterTableFuncs = new FuncDef[] {
276 FUNCTION("sqlite_rename_table", 2, 0, 0, renameTableFunc),
277 #if !SQLITE_OMIT_TRIGGER
278 FUNCTION("sqlite_rename_trigger", 2, 0, 0, renameTriggerFunc),
279 #endif
280 #if !SQLITE_OMIT_FOREIGN_KEY
281 FUNCTION("sqlite_rename_parent", 3, 0, 0, renameParentFunc),
282 #endif
283 };
284 #if SQLITE_OMIT_WSD
285 FuncDefHash pHash = GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
286 FuncDef[] aFunc = GLOBAL(FuncDef, aAlterTableFuncs);
287 #else
288 FuncDefHash pHash = sqlite3GlobalFunctions;
289 FuncDef[] aFunc = aAlterTableFuncs;
290 #endif
291  
292 for (int i = 0; i < ArraySize( aAlterTableFuncs ); i++ )
293 {
294 sqlite3FuncDefInsert( pHash, aFunc[i] );
295 }
296 }
297  
298 /*
299 ** This function is used to create the text of expressions of the form:
300 **
301 ** name=<constant1> OR name=<constant2> OR ...
302 **
303 ** If argument zWhere is NULL, then a pointer string containing the text
304 ** "name=<constant>" is returned, where <constant> is the quoted version
305 ** of the string passed as argument zConstant. The returned buffer is
306 ** allocated using sqlite3DbMalloc(). It is the responsibility of the
307 ** caller to ensure that it is eventually freed.
308 **
309 ** If argument zWhere is not NULL, then the string returned is
310 ** "<where> OR name=<constant>", where <where> is the contents of zWhere.
311 ** In this case zWhere is passed to sqlite3DbFree() before returning.
312 **
313 */
314 static string whereOrName( sqlite3 db, string zWhere, string zConstant )
315 {
316 string zNew;
317 if ( string.IsNullOrEmpty( zWhere ) )
318 {
319 zNew = sqlite3MPrintf( db, "name=%Q", zConstant );
320 }
321 else
322 {
323 zNew = sqlite3MPrintf( db, "%s OR name=%Q", zWhere, zConstant );
324 sqlite3DbFree( db, ref zWhere );
325 }
326 return zNew;
327 }
328  
329 #if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
330 /*
331 ** Generate the text of a WHERE expression which can be used to select all
332 ** tables that have foreign key constraints that refer to table pTab (i.e.
333 ** constraints for which pTab is the parent table) from the sqlite_master
334 ** table.
335 */
336 static string whereForeignKeys( Parse pParse, Table pTab )
337 {
338 FKey p;
339 string zWhere = string.Empty;
340 for ( p = sqlite3FkReferences( pTab ); p != null; p = p.pNextTo )
341 {
342 zWhere = whereOrName( pParse.db, zWhere, p.pFrom.zName );
343 }
344 return zWhere;
345 }
346 #endif
347  
348 /*
349 ** Generate the text of a WHERE expression which can be used to select all
350 ** temporary triggers on table pTab from the sqlite_temp_master table. If
351 ** table pTab has no temporary triggers, or is itself stored in the
352 ** temporary database, NULL is returned.
353 */
354 static string whereTempTriggers( Parse pParse, Table pTab )
355 {
356 Trigger pTrig;
357 string zWhere = string.Empty;
358 Schema pTempSchema = pParse.db.aDb[1].pSchema; /* Temp db schema */
359  
360 /* If the table is not located in the temp.db (in which case NULL is
361 ** returned, loop through the tables list of triggers. For each trigger
362 ** that is not part of the temp.db schema, add a clause to the WHERE
363 ** expression being built up in zWhere.
364 */
365 if ( pTab.pSchema != pTempSchema )
366 {
367 sqlite3 db = pParse.db;
368 for ( pTrig = sqlite3TriggerList( pParse, pTab ); pTrig != null; pTrig = pTrig.pNext )
369 {
370 if ( pTrig.pSchema == pTempSchema )
371 {
372 zWhere = whereOrName( db, zWhere, pTrig.zName );
373 }
374 }
375 }
376 if ( !string.IsNullOrEmpty( zWhere ) )
377 {
378 zWhere = sqlite3MPrintf( pParse.db, "type='trigger' AND (%s)", zWhere );
379 //sqlite3DbFree( pParse.db, ref zWhere );
380 //zWhere = zNew;
381 }
382 return zWhere;
383 }
384  
385 /*
386 ** Generate code to drop and reload the internal representation of table
387 ** pTab from the database, including triggers and temporary triggers.
388 ** Argument zName is the name of the table in the database schema at
389 ** the time the generated code is executed. This can be different from
390 ** pTab.zName if this function is being called to code part of an
391 ** "ALTER TABLE RENAME TO" statement.
392 */
393 static void reloadTableSchema( Parse pParse, Table pTab, string zName )
394 {
395 Vdbe v;
396 string zWhere;
397 int iDb; /* Index of database containing pTab */
398 #if !SQLITE_OMIT_TRIGGER
399 Trigger pTrig;
400 #endif
401  
402 v = sqlite3GetVdbe( pParse );
403 if ( NEVER( v == null ) )
404 return;
405 Debug.Assert( sqlite3BtreeHoldsAllMutexes( pParse.db ) );
406 iDb = sqlite3SchemaToIndex( pParse.db, pTab.pSchema );
407 Debug.Assert( iDb >= 0 );
408  
409 #if !SQLITE_OMIT_TRIGGER
410 /* Drop any table triggers from the internal schema. */
411 for ( pTrig = sqlite3TriggerList( pParse, pTab ); pTrig != null; pTrig = pTrig.pNext )
412 {
413 int iTrigDb = sqlite3SchemaToIndex( pParse.db, pTrig.pSchema );
414 Debug.Assert( iTrigDb == iDb || iTrigDb == 1 );
415 sqlite3VdbeAddOp4( v, OP_DropTrigger, iTrigDb, 0, 0, pTrig.zName, 0 );
416 }
417 #endif
418  
419 /* Drop the table and index from the internal schema. */
420 sqlite3VdbeAddOp4( v, OP_DropTable, iDb, 0, 0, pTab.zName, 0 );
421  
422 /* Reload the table, index and permanent trigger schemas. */
423 zWhere = sqlite3MPrintf( pParse.db, "tbl_name=%Q", zName );
424 if ( zWhere == null )
425 return;
426 sqlite3VdbeAddParseSchemaOp( v, iDb, zWhere );
427  
428 #if !SQLITE_OMIT_TRIGGER
429 /* Now, if the table is not stored in the temp database, reload any temp
430 ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined.
431 */
432 if ( ( zWhere = whereTempTriggers( pParse, pTab ) ).Length > 0 )
433 {
434 sqlite3VdbeAddParseSchemaOp( v, 1, zWhere );
435 }
436 #endif
437 }
438  
439 /*
440 ** Parameter zName is the name of a table that is about to be altered
441 ** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN).
442 ** If the table is a system table, this function leaves an error message
443 ** in pParse->zErr (system tables may not be altered) and returns non-zero.
444 **
445 ** Or, if zName is not a system table, zero is returned.
446 */
447 static int isSystemTable( Parse pParse, string zName )
448 {
449 if ( zName.StartsWith( "sqlite_", System.StringComparison.OrdinalIgnoreCase ) )
450 {
451 sqlite3ErrorMsg( pParse, "table %s may not be altered", zName );
452 return 1;
453 }
454 return 0;
455 }
456  
457 /*
458 ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
459 ** command.
460 */
461 static void sqlite3AlterRenameTable(
462 Parse pParse, /* Parser context. */
463 SrcList pSrc, /* The table to rename. */
464 Token pName /* The new table name. */
465 )
466 {
467 int iDb; /* Database that contains the table */
468 string zDb; /* Name of database iDb */
469 Table pTab; /* Table being renamed */
470 string zName = null; /* NULL-terminated version of pName */
471 sqlite3 db = pParse.db; /* Database connection */
472 int nTabName; /* Number of UTF-8 characters in zTabName */
473 string zTabName; /* Original name of the table */
474 Vdbe v;
475 #if !SQLITE_OMIT_TRIGGER
476 string zWhere = string.Empty; /* Where clause to locate temp triggers */
477 #endif
478 VTable pVTab = null; /* Non-zero if this is a v-tab with an xRename() */
479 int savedDbFlags; /* Saved value of db->flags */
480  
481 savedDbFlags = db.flags;
482  
483 //if ( NEVER( db.mallocFailed != 0 ) ) goto exit_rename_table;
484 Debug.Assert( pSrc.nSrc == 1 );
485 Debug.Assert( sqlite3BtreeHoldsAllMutexes( pParse.db ) );
486 pTab = sqlite3LocateTable( pParse, 0, pSrc.a[0].zName, pSrc.a[0].zDatabase );
487 if ( pTab == null )
488 goto exit_rename_table;
489 iDb = sqlite3SchemaToIndex( pParse.db, pTab.pSchema );
490 zDb = db.aDb[iDb].zName;
491 db.flags |= SQLITE_PreferBuiltin;
492  
493 /* Get a NULL terminated version of the new table name. */
494 zName = sqlite3NameFromToken( db, pName );
495 if ( zName == null )
496 goto exit_rename_table;
497  
498 /* Check that a table or index named 'zName' does not already exist
499 ** in database iDb. If so, this is an error.
500 */
501 if ( sqlite3FindTable( db, zName, zDb ) != null || sqlite3FindIndex( db, zName, zDb ) != null )
502 {
503 sqlite3ErrorMsg( pParse,
504 "there is already another table or index with this name: %s", zName );
505 goto exit_rename_table;
506 }
507  
508 /* Make sure it is not a system table being altered, or a reserved name
509 ** that the table is being renamed to.
510 */
511 if ( SQLITE_OK!=isSystemTable(pParse, pTab.zName) )
512 {
513 goto exit_rename_table;
514 }
515 if ( SQLITE_OK != sqlite3CheckObjectName( pParse, zName ) )
516 {
517 goto exit_rename_table;
518 }
519  
520 #if !SQLITE_OMIT_VIEW
521 if ( pTab.pSelect != null )
522 {
523 sqlite3ErrorMsg( pParse, "view %s may not be altered", pTab.zName );
524 goto exit_rename_table;
525 }
526 #endif
527  
528 #if !SQLITE_OMIT_AUTHORIZATION
529 /* Invoke the authorization callback. */
530 if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab.zName, 0) ){
531 goto exit_rename_table;
532 }
533 #endif
534  
535 if ( sqlite3ViewGetColumnNames( pParse, pTab ) != 0 )
536 {
537 goto exit_rename_table;
538 }
539 #if !SQLITE_OMIT_VIRTUALTABLE
540 if ( IsVirtual( pTab ) )
541 {
542 pVTab = sqlite3GetVTable( db, pTab );
543 if ( pVTab.pVtab.pModule.xRename == null )
544 {
545 pVTab = null;
546 }
547 }
548 #endif
549 /* Begin a transaction and code the VerifyCookie for database iDb.
550 ** Then modify the schema cookie (since the ALTER TABLE modifies the
551 ** schema). Open a statement transaction if the table is a virtual
552 ** table.
553 */
554 v = sqlite3GetVdbe( pParse );
555 if ( v == null )
556 {
557 goto exit_rename_table;
558 }
559 sqlite3BeginWriteOperation( pParse, pVTab != null ? 1 : 0, iDb );
560 sqlite3ChangeCookie( pParse, iDb );
561  
562 /* If this is a virtual table, invoke the xRename() function if
563 ** one is defined. The xRename() callback will modify the names
564 ** of any resources used by the v-table implementation (including other
565 ** SQLite tables) that are identified by the name of the virtual table.
566 */
567 #if !SQLITE_OMIT_VIRTUALTABLE
568 if ( pVTab !=null)
569 {
570 int i = ++pParse.nMem;
571 sqlite3VdbeAddOp4( v, OP_String8, 0, i, 0, zName, 0 );
572 sqlite3VdbeAddOp4( v, OP_VRename, i, 0, 0, pVTab, P4_VTAB );
573 sqlite3MayAbort(pParse);
574 }
575 #endif
576  
577 /* figure out how many UTF-8 characters are in zName */
578 zTabName = pTab.zName;
579 nTabName = sqlite3Utf8CharLen( zTabName, -1 );
580  
581 #if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
582 if ( ( db.flags & SQLITE_ForeignKeys ) != 0 )
583 {
584 /* If foreign-key support is enabled, rewrite the CREATE TABLE
585 ** statements corresponding to all child tables of foreign key constraints
586 ** for which the renamed table is the parent table. */
587 if ( ( zWhere = whereForeignKeys( pParse, pTab ) ) != null )
588 {
589 sqlite3NestedParse( pParse,
590 "UPDATE \"%w\".%s SET " +
591 "sql = sqlite_rename_parent(sql, %Q, %Q) " +
592 "WHERE %s;", zDb, SCHEMA_TABLE( iDb ), zTabName, zName, zWhere );
593 sqlite3DbFree( db, ref zWhere );
594 }
595 }
596 #endif
597  
598 /* Modify the sqlite_master table to use the new table name. */
599 sqlite3NestedParse( pParse,
600 "UPDATE %Q.%s SET " +
601 #if SQLITE_OMIT_TRIGGER
602 "sql = sqlite_rename_table(sql, %Q), " +
603 #else
604 "sql = CASE " +
605 "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" +
606 "ELSE sqlite_rename_table(sql, %Q) END, " +
607 #endif
608 "tbl_name = %Q, " +
609 "name = CASE " +
610 "WHEN type='table' THEN %Q " +
611 "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " +
612 "'sqlite_autoindex_' || %Q || substr(name,%d+18) " +
613 "ELSE name END " +
614 "WHERE tbl_name=%Q AND " +
615 "(type='table' OR type='index' OR type='trigger');",
616 zDb, SCHEMA_TABLE( iDb ), zName, zName, zName,
617 #if !SQLITE_OMIT_TRIGGER
618 zName,
619 #endif
620 zName, nTabName, zTabName
621 );
622  
623 #if !SQLITE_OMIT_AUTOINCREMENT
624 /* If the sqlite_sequence table exists in this database, then update
625 ** it with the new table name.
626 */
627 if ( sqlite3FindTable( db, "sqlite_sequence", zDb ) != null )
628 {
629 sqlite3NestedParse( pParse,
630 "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q",
631 zDb, zName, pTab.zName
632 );
633 }
634 #endif
635  
636 #if !SQLITE_OMIT_TRIGGER
637 /* If there are TEMP triggers on this table, modify the sqlite_temp_master
638 ** table. Don't do this if the table being ALTERed is itself located in
639 ** the temp database.
640 */
641 if ( ( zWhere = whereTempTriggers( pParse, pTab ) ).Length > 0 )
642 {
643 sqlite3NestedParse( pParse,
644 "UPDATE sqlite_temp_master SET " +
645 "sql = sqlite_rename_trigger(sql, %Q), " +
646 "tbl_name = %Q " +
647 "WHERE %s;", zName, zName, zWhere );
648 sqlite3DbFree( db, ref zWhere );
649 }
650 #endif
651  
652 #if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
653 if ( ( db.flags & SQLITE_ForeignKeys ) != 0 )
654 {
655 FKey p;
656 for ( p = sqlite3FkReferences( pTab ); p != null; p = p.pNextTo )
657 {
658 Table pFrom = p.pFrom;
659 if ( pFrom != pTab )
660 {
661 reloadTableSchema( pParse, p.pFrom, pFrom.zName );
662 }
663 }
664 }
665 #endif
666  
667 /* Drop and reload the internal table schema. */
668 reloadTableSchema( pParse, pTab, zName );
669  
670 exit_rename_table:
671 sqlite3SrcListDelete( db, ref pSrc );
672 sqlite3DbFree( db, ref zName );
673 db.flags = savedDbFlags;
674 }
675  
676 /*
677 ** Generate code to make sure the file format number is at least minFormat.
678 ** The generated code will increase the file format number if necessary.
679 */
680 static void sqlite3MinimumFileFormat( Parse pParse, int iDb, int minFormat )
681 {
682 Vdbe v;
683 v = sqlite3GetVdbe( pParse );
684 /* The VDBE should have been allocated before this routine is called.
685 ** If that allocation failed, we would have quit before reaching this
686 ** point */
687 if ( ALWAYS( v ) )
688 {
689 int r1 = sqlite3GetTempReg( pParse );
690 int r2 = sqlite3GetTempReg( pParse );
691 int j1;
692 sqlite3VdbeAddOp3( v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT );
693 sqlite3VdbeUsesBtree( v, iDb );
694 sqlite3VdbeAddOp2( v, OP_Integer, minFormat, r2 );
695 j1 = sqlite3VdbeAddOp3( v, OP_Ge, r2, 0, r1 );
696 sqlite3VdbeAddOp3( v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2 );
697 sqlite3VdbeJumpHere( v, j1 );
698 sqlite3ReleaseTempReg( pParse, r1 );
699 sqlite3ReleaseTempReg( pParse, r2 );
700 }
701 }
702  
703 /*
704 ** This function is called after an "ALTER TABLE ... ADD" statement
705 ** has been parsed. Argument pColDef contains the text of the new
706 ** column definition.
707 **
708 ** The Table structure pParse.pNewTable was extended to include
709 ** the new column during parsing.
710 */
711 static void sqlite3AlterFinishAddColumn( Parse pParse, Token pColDef )
712 {
713 Table pNew; /* Copy of pParse.pNewTable */
714 Table pTab; /* Table being altered */
715 int iDb; /* Database number */
716 string zDb; /* Database name */
717 string zTab; /* Table name */
718 string zCol; /* Null-terminated column definition */
719 Column pCol; /* The new column */
720 Expr pDflt; /* Default value for the new column */
721 sqlite3 db; /* The database connection; */
722  
723 db = pParse.db;
724 if ( pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
725 return;
726 pNew = pParse.pNewTable;
727 Debug.Assert( pNew != null );
728 Debug.Assert( sqlite3BtreeHoldsAllMutexes( db ) );
729 iDb = sqlite3SchemaToIndex( db, pNew.pSchema );
730 zDb = db.aDb[iDb].zName;
731 zTab = pNew.zName.Substring( 16 );// zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */
732 pCol = pNew.aCol[pNew.nCol - 1];
733 pDflt = pCol.pDflt;
734 pTab = sqlite3FindTable( db, zTab, zDb );
735 Debug.Assert( pTab != null );
736  
737 #if !SQLITE_OMIT_AUTHORIZATION
738 /* Invoke the authorization callback. */
739 if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab.zName, 0) ){
740 return;
741 }
742 #endif
743  
744 /* If the default value for the new column was specified with a
745 ** literal NULL, then set pDflt to 0. This simplifies checking
746 ** for an SQL NULL default below.
747 */
748 if ( pDflt != null && pDflt.op == TK_NULL )
749 {
750 pDflt = null;
751 }
752  
753 /* Check that the new column is not specified as PRIMARY KEY or UNIQUE.
754 ** If there is a NOT NULL constraint, then the default value for the
755 ** column must not be NULL.
756 */
757 if ( pCol.isPrimKey != 0 )
758 {
759 sqlite3ErrorMsg( pParse, "Cannot add a PRIMARY KEY column" );
760 return;
761 }
762 if ( pNew.pIndex != null )
763 {
764 sqlite3ErrorMsg( pParse, "Cannot add a UNIQUE column" );
765 return;
766 }
767 if ( ( db.flags & SQLITE_ForeignKeys ) != 0 && pNew.pFKey != null && pDflt != null )
768 {
769 sqlite3ErrorMsg( pParse,
770 "Cannot add a REFERENCES column with non-NULL default value" );
771 return;
772 }
773 if ( pCol.notNull != 0 && pDflt == null )
774 {
775 sqlite3ErrorMsg( pParse,
776 "Cannot add a NOT NULL column with default value NULL" );
777 return;
778 }
779  
780 /* Ensure the default expression is something that sqlite3ValueFromExpr()
781 ** can handle (i.e. not CURRENT_TIME etc.)
782 */
783 if ( pDflt != null )
784 {
785 sqlite3_value pVal = null;
786 if ( sqlite3ValueFromExpr( db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, ref pVal ) != 0 )
787 {
788 // db.mallocFailed = 1;
789 return;
790 }
791 if ( pVal == null )
792 {
793 sqlite3ErrorMsg( pParse, "Cannot add a column with non-constant default" );
794 return;
795 }
796 sqlite3ValueFree( ref pVal );
797 }
798  
799 /* Modify the CREATE TABLE statement. */
800 zCol = pColDef.z.Substring( 0, pColDef.n ).Replace( ";", " " ).Trim();//sqlite3DbStrNDup(db, (char*)pColDef.z, pColDef.n);
801 if ( zCol != null )
802 {
803 // char zEnd = zCol[pColDef.n-1];
804 int savedDbFlags = db.flags;
805 // while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
806 // zEnd-- = '\0';
807 // }
808 db.flags |= SQLITE_PreferBuiltin;
809 sqlite3NestedParse( pParse,
810 "UPDATE \"%w\".%s SET " +
811 "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " +
812 "WHERE type = 'table' AND name = %Q",
813 zDb, SCHEMA_TABLE( iDb ), pNew.addColOffset, zCol, pNew.addColOffset + 1,
814 zTab
815 );
816 sqlite3DbFree( db, ref zCol );
817 db.flags = savedDbFlags;
818 }
819  
820 /* If the default value of the new column is NULL, then set the file
821 ** format to 2. If the default value of the new column is not NULL,
822 ** the file format becomes 3.
823 */
824 sqlite3MinimumFileFormat( pParse, iDb, pDflt != null ? 3 : 2 );
825  
826 /* Reload the schema of the modified table. */
827 reloadTableSchema( pParse, pTab, pTab.zName );
828 }
829  
830 /*
831 ** This function is called by the parser after the table-name in
832 ** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
833 ** pSrc is the full-name of the table being altered.
834 **
835 ** This routine makes a (partial) copy of the Table structure
836 ** for the table being altered and sets Parse.pNewTable to point
837 ** to it. Routines called by the parser as the column definition
838 ** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
839 ** the copy. The copy of the Table structure is deleted by tokenize.c
840 ** after parsing is finished.
841 **
842 ** Routine sqlite3AlterFinishAddColumn() will be called to complete
843 ** coding the "ALTER TABLE ... ADD" statement.
844 */
845 static void sqlite3AlterBeginAddColumn( Parse pParse, SrcList pSrc )
846 {
847 Table pNew;
848 Table pTab;
849 Vdbe v;
850 int iDb;
851 int i;
852 int nAlloc;
853 sqlite3 db = pParse.db;
854  
855 /* Look up the table being altered. */
856 Debug.Assert( pParse.pNewTable == null );
857 Debug.Assert( sqlite3BtreeHoldsAllMutexes( db ) );
858 // if ( db.mallocFailed != 0 ) goto exit_begin_add_column;
859 pTab = sqlite3LocateTable( pParse, 0, pSrc.a[0].zName, pSrc.a[0].zDatabase );
860 if ( pTab == null )
861 goto exit_begin_add_column;
862  
863 if ( IsVirtual( pTab ) )
864 {
865 sqlite3ErrorMsg( pParse, "virtual tables may not be altered" );
866 goto exit_begin_add_column;
867 }
868  
869 /* Make sure this is not an attempt to ALTER a view. */
870 if ( pTab.pSelect != null )
871 {
872 sqlite3ErrorMsg( pParse, "Cannot add a column to a view" );
873 goto exit_begin_add_column;
874 }
875 if ( SQLITE_OK != isSystemTable( pParse, pTab.zName ) )
876 {
877 goto exit_begin_add_column;
878 }
879  
880 Debug.Assert( pTab.addColOffset > 0 );
881 iDb = sqlite3SchemaToIndex( db, pTab.pSchema );
882  
883 /* Put a copy of the Table struct in Parse.pNewTable for the
884 ** sqlite3AddColumn() function and friends to modify. But modify
885 ** the name by adding an "sqlite_altertab_" prefix. By adding this
886 ** prefix, we insure that the name will not collide with an existing
887 ** table because user table are not allowed to have the "sqlite_"
888 ** prefix on their name.
889 */
890 pNew = new Table();// (Table*)sqlite3DbMallocZero( db, sizeof(Table))
891 if ( pNew == null )
892 goto exit_begin_add_column;
893 pParse.pNewTable = pNew;
894 pNew.nRef = 1;
895 pNew.nCol = pTab.nCol;
896 Debug.Assert( pNew.nCol > 0 );
897 nAlloc = ( ( ( pNew.nCol - 1 ) / 8 ) * 8 ) + 8;
898 Debug.Assert( nAlloc >= pNew.nCol && nAlloc % 8 == 0 && nAlloc - pNew.nCol < 8 );
899 pNew.aCol = new Column[nAlloc];// (Column*)sqlite3DbMallocZero( db, sizeof(Column) * nAlloc );
900 pNew.zName = sqlite3MPrintf( db, "sqlite_altertab_%s", pTab.zName );
901 if ( pNew.aCol == null || pNew.zName == null )
902 {
903 // db.mallocFailed = 1;
904 goto exit_begin_add_column;
905 }
906 // memcpy( pNew.aCol, pTab.aCol, sizeof(Column) * pNew.nCol );
907 for ( i = 0; i < pNew.nCol; i++ )
908 {
909 Column pCol = pTab.aCol[i].Copy();
910 // sqlite3DbStrDup( db, pCol.zName );
911 pCol.zColl = null;
912 pCol.zType = null;
913 pCol.pDflt = null;
914 pCol.zDflt = null;
915 pNew.aCol[i] = pCol;
916 }
917 pNew.pSchema = db.aDb[iDb].pSchema;
918 pNew.addColOffset = pTab.addColOffset;
919 pNew.nRef = 1;
920  
921 /* Begin a transaction and increment the schema cookie. */
922 sqlite3BeginWriteOperation( pParse, 0, iDb );
923 v = sqlite3GetVdbe( pParse );
924 if ( v == null )
925 goto exit_begin_add_column;
926 sqlite3ChangeCookie( pParse, iDb );
927  
928 exit_begin_add_column:
929 sqlite3SrcListDelete( db, ref pSrc );
930 return;
931 }
932 #endif // * SQLITE_ALTER_TABLE */
933 }
934 }