wasCSharpSQLite – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System; |
2 | using System.Diagnostics; |
||
3 | using System.Text; |
||
4 | |||
5 | using u8 = System.Byte; |
||
6 | using u16 = System.UInt16; |
||
7 | using u32 = System.UInt32; |
||
8 | using sqlite3_int64 = System.Int64; |
||
9 | |||
10 | namespace Community.CsharpSqlite |
||
11 | { |
||
12 | using sqlite3_stmt = Sqlite3.Vdbe; |
||
13 | |||
14 | public partial class Sqlite3 |
||
15 | { |
||
16 | /* |
||
17 | ** 2005 May 25 |
||
18 | ** |
||
19 | ** The author disclaims copyright to this source code. In place of |
||
20 | ** a legal notice, here is a blessing: |
||
21 | ** |
||
22 | ** May you do good and not evil. |
||
23 | ** May you find forgiveness for yourself and forgive others. |
||
24 | ** May you share freely, never taking more than you give. |
||
25 | ** |
||
26 | ************************************************************************* |
||
27 | ** This file contains the implementation of the sqlite3_prepare() |
||
28 | ** interface, and routines that contribute to loading the database schema |
||
29 | ** from disk. |
||
30 | ************************************************************************* |
||
31 | ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart |
||
32 | ** C#-SQLite is an independent reimplementation of the SQLite software library |
||
33 | ** |
||
34 | ** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e |
||
35 | ** |
||
36 | ************************************************************************* |
||
37 | */ |
||
38 | //#include "sqliteInt.h" |
||
39 | |||
40 | /* |
||
41 | ** Fill the InitData structure with an error message that indicates |
||
42 | ** that the database is corrupt. |
||
43 | */ |
||
44 | static void corruptSchema( |
||
45 | InitData pData, /* Initialization context */ |
||
46 | string zObj, /* Object being parsed at the point of error */ |
||
47 | string zExtra /* Error information */ |
||
48 | ) |
||
49 | { |
||
50 | sqlite3 db = pData.db; |
||
51 | if ( /* 0 == db.mallocFailed && */ ( db.flags & SQLITE_RecoveryMode ) == 0 ) |
||
52 | { |
||
53 | { |
||
54 | if ( zObj == null ) |
||
55 | { |
||
56 | zObj = "?"; |
||
57 | #if SQLITE_OMIT_UTF16 |
||
58 | if (ENC(db) != SQLITE_UTF8) |
||
59 | zObj =encnames[(ENC(db))].zName; |
||
60 | #endif |
||
61 | } |
||
62 | sqlite3SetString( ref pData.pzErrMsg, db, |
||
63 | "malformed database schema (%s)", zObj ); |
||
64 | if ( !string.IsNullOrEmpty( zExtra ) ) |
||
65 | { |
||
66 | pData.pzErrMsg = sqlite3MAppendf( db, pData.pzErrMsg |
||
67 | , "%s - %s", pData.pzErrMsg, zExtra ); |
||
68 | } |
||
69 | } |
||
70 | pData.rc = //db.mallocFailed != 0 ? SQLITE_NOMEM : |
||
71 | SQLITE_CORRUPT_BKPT(); |
||
72 | } |
||
73 | } |
||
74 | |||
75 | /* |
||
76 | ** This is the callback routine for the code that initializes the |
||
77 | ** database. See sqlite3Init() below for additional information. |
||
78 | ** This routine is also called from the OP_ParseSchema opcode of the VDBE. |
||
79 | ** |
||
80 | ** Each callback contains the following information: |
||
81 | ** |
||
82 | ** argv[0] = name of thing being created |
||
83 | ** argv[1] = root page number for table or index. 0 for trigger or view. |
||
84 | ** argv[2] = SQL text for the CREATE statement. |
||
85 | ** |
||
86 | */ |
||
87 | static int sqlite3InitCallback( object pInit, sqlite3_int64 argc, object p2, object NotUsed ) |
||
88 | { |
||
89 | string[] argv = (string[])p2; |
||
90 | InitData pData = (InitData)pInit; |
||
91 | sqlite3 db = pData.db; |
||
92 | int iDb = pData.iDb; |
||
93 | |||
94 | Debug.Assert( argc == 3 ); |
||
95 | UNUSED_PARAMETER2( NotUsed, argc ); |
||
96 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
97 | DbClearProperty( db, iDb, DB_Empty ); |
||
98 | //if ( db.mallocFailed != 0 ) |
||
99 | //{ |
||
100 | // corruptSchema( pData, argv[0], "" ); |
||
101 | // return 1; |
||
102 | //} |
||
103 | |||
104 | Debug.Assert( iDb >= 0 && iDb < db.nDb ); |
||
105 | if ( argv == null ) |
||
106 | return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ |
||
107 | if ( argv[1] == null ) |
||
108 | { |
||
109 | corruptSchema( pData, argv[0], string.Empty ); |
||
110 | } |
||
111 | else if ( !string.IsNullOrEmpty( argv[2] ) ) |
||
112 | { |
||
113 | /* Call the parser to process a CREATE TABLE, INDEX or VIEW. |
||
114 | ** But because db.init.busy is set to 1, no VDBE code is generated |
||
115 | ** or executed. All the parser does is build the internal data |
||
116 | ** structures that describe the table, index, or view. |
||
117 | */ |
||
118 | int rc; |
||
119 | sqlite3_stmt pStmt = null; |
||
120 | #if !NDEBUG || SQLITE_COVERAGE_TEST |
||
121 | //TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ |
||
122 | int rcp; |
||
123 | #endif |
||
124 | Debug.Assert( db.init.busy != 0 ); |
||
125 | db.init.iDb = iDb; |
||
126 | db.init.newTnum = sqlite3Atoi( argv[1] ); |
||
127 | db.init.orphanTrigger = 0; |
||
128 | //TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); |
||
129 | #if !NDEBUG || SQLITE_COVERAGE_TEST |
||
130 | rcp = sqlite3_prepare( db, argv[2], -1, ref pStmt, 0 ); |
||
131 | #else |
||
132 | sqlite3_prepare(db, argv[2], -1, ref pStmt, 0); |
||
133 | #endif |
||
134 | rc = db.errCode; |
||
135 | #if !NDEBUG || SQLITE_COVERAGE_TEST |
||
136 | Debug.Assert( ( rc & 0xFF ) == ( rcp & 0xFF ) ); |
||
137 | #endif |
||
138 | db.init.iDb = 0; |
||
139 | if ( SQLITE_OK != rc ) |
||
140 | { |
||
141 | if ( db.init.orphanTrigger != 0 ) |
||
142 | { |
||
143 | Debug.Assert( iDb == 1 ); |
||
144 | } |
||
145 | else |
||
146 | { |
||
147 | pData.rc = rc; |
||
148 | //if ( rc == SQLITE_NOMEM ) |
||
149 | //{ |
||
150 | // // db.mallocFailed = 1; |
||
151 | //} |
||
152 | //else |
||
153 | if ( rc != SQLITE_INTERRUPT && ( rc & 0xFF ) != SQLITE_LOCKED ) |
||
154 | { |
||
155 | corruptSchema( pData, argv[0], sqlite3_errmsg( db ) ); |
||
156 | } |
||
157 | } |
||
158 | } |
||
159 | sqlite3_finalize( pStmt ); |
||
160 | } |
||
161 | else if ( string.IsNullOrEmpty( argv[0] ) ) |
||
162 | { |
||
163 | corruptSchema( pData, null, null ); |
||
164 | } |
||
165 | else |
||
166 | { |
||
167 | /* If the SQL column is blank it means this is an index that |
||
168 | ** was created to be the PRIMARY KEY or to fulfill a UNIQUE |
||
169 | ** constraint for a CREATE TABLE. The index should have already |
||
170 | ** been created when we processed the CREATE TABLE. All we have |
||
171 | ** to do here is record the root page number for that index. |
||
172 | */ |
||
173 | Index pIndex; |
||
174 | pIndex = sqlite3FindIndex( db, argv[0], db.aDb[iDb].zName ); |
||
175 | if ( pIndex == null ) |
||
176 | { |
||
177 | /* This can occur if there exists an index on a TEMP table which |
||
178 | ** has the same name as another index on a permanent index. Since |
||
179 | ** the permanent table is hidden by the TEMP table, we can also |
||
180 | ** safely ignore the index on the permanent table. |
||
181 | */ |
||
182 | /* Do Nothing */ |
||
183 | ; |
||
184 | } |
||
185 | else if ( sqlite3GetInt32( argv[1], ref pIndex.tnum ) == false ) |
||
186 | { |
||
187 | corruptSchema( pData, argv[0], "invalid rootpage" ); |
||
188 | } |
||
189 | } |
||
190 | return 0; |
||
191 | } |
||
192 | |||
193 | /* |
||
194 | ** Attempt to read the database schema and initialize internal |
||
195 | ** data structures for a single database file. The index of the |
||
196 | ** database file is given by iDb. iDb==0 is used for the main |
||
197 | ** database. iDb==1 should never be used. iDb>=2 is used for |
||
198 | ** auxiliary databases. Return one of the SQLITE_ error codes to |
||
199 | ** indicate success or failure. |
||
200 | */ |
||
201 | static int sqlite3InitOne( sqlite3 db, int iDb, ref string pzErrMsg ) |
||
202 | { |
||
203 | int rc; |
||
204 | int i; |
||
205 | int size; |
||
206 | Table pTab; |
||
207 | Db pDb; |
||
208 | string[] azArg = new string[4]; |
||
209 | u32[] meta = new u32[5]; |
||
210 | InitData initData = new InitData(); |
||
211 | string zMasterSchema; |
||
212 | string zMasterName; |
||
213 | int openedTransaction = 0; |
||
214 | |||
215 | /* |
||
216 | ** The master database table has a structure like this |
||
217 | */ |
||
218 | string master_schema = |
||
219 | "CREATE TABLE sqlite_master(\n" + |
||
220 | " type text,\n" + |
||
221 | " name text,\n" + |
||
222 | " tbl_name text,\n" + |
||
223 | " rootpage integer,\n" + |
||
224 | " sql text\n" + |
||
225 | ")" |
||
226 | ; |
||
227 | #if !SQLITE_OMIT_TEMPDB |
||
228 | string temp_master_schema = |
||
229 | "CREATE TEMP TABLE sqlite_temp_master(\n" + |
||
230 | " type text,\n" + |
||
231 | " name text,\n" + |
||
232 | " tbl_name text,\n" + |
||
233 | " rootpage integer,\n" + |
||
234 | " sql text\n" + |
||
235 | ")" |
||
236 | ; |
||
237 | #else |
||
238 | //#define temp_master_schema 0 |
||
239 | #endif |
||
240 | |||
241 | Debug.Assert( iDb >= 0 && iDb < db.nDb ); |
||
242 | Debug.Assert( db.aDb[iDb].pSchema != null ); |
||
243 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
244 | Debug.Assert( iDb == 1 || sqlite3BtreeHoldsMutex( db.aDb[iDb].pBt ) ); |
||
245 | |||
246 | /* zMasterSchema and zInitScript are set to point at the master schema |
||
247 | ** and initialisation script appropriate for the database being |
||
248 | ** initialised. zMasterName is the name of the master table. |
||
249 | */ |
||
250 | if ( OMIT_TEMPDB == 0 && iDb == 1 ) |
||
251 | { |
||
252 | zMasterSchema = temp_master_schema; |
||
253 | } |
||
254 | else |
||
255 | { |
||
256 | zMasterSchema = master_schema; |
||
257 | } |
||
258 | zMasterName = SCHEMA_TABLE( iDb ); |
||
259 | |||
260 | /* Construct the schema tables. */ |
||
261 | azArg[0] = zMasterName; |
||
262 | azArg[1] = "1"; |
||
263 | azArg[2] = zMasterSchema; |
||
264 | azArg[3] = string.Empty; |
||
265 | initData.db = db; |
||
266 | initData.iDb = iDb; |
||
267 | initData.rc = SQLITE_OK; |
||
268 | initData.pzErrMsg = pzErrMsg; |
||
269 | sqlite3InitCallback( initData, 3, azArg, null ); |
||
270 | if ( initData.rc != 0 ) |
||
271 | { |
||
272 | rc = initData.rc; |
||
273 | goto error_out; |
||
274 | } |
||
275 | pTab = sqlite3FindTable( db, zMasterName, db.aDb[iDb].zName ); |
||
276 | if ( ALWAYS( pTab ) ) |
||
277 | { |
||
278 | pTab.tabFlags |= TF_Readonly; |
||
279 | } |
||
280 | |||
281 | /* Create a cursor to hold the database open |
||
282 | */ |
||
283 | pDb = db.aDb[iDb]; |
||
284 | if ( pDb.pBt == null ) |
||
285 | { |
||
286 | if ( OMIT_TEMPDB == 0 && ALWAYS( iDb == 1 ) ) |
||
287 | { |
||
288 | DbSetProperty( db, 1, DB_SchemaLoaded ); |
||
289 | } |
||
290 | return SQLITE_OK; |
||
291 | } |
||
292 | |||
293 | /* If there is not already a read-only (or read-write) transaction opened |
||
294 | ** on the b-tree database, open one now. If a transaction is opened, it |
||
295 | ** will be closed before this function returns. */ |
||
296 | sqlite3BtreeEnter( pDb.pBt ); |
||
297 | if ( !sqlite3BtreeIsInReadTrans( pDb.pBt ) ) |
||
298 | { |
||
299 | rc = sqlite3BtreeBeginTrans( pDb.pBt, 0 ); |
||
300 | if ( rc != SQLITE_OK ) |
||
301 | { |
||
302 | #if SQLITE_OMIT_WAL |
||
303 | if (pDb.pBt.pBt.pSchema.file_format == 2) |
||
304 | sqlite3SetString( ref pzErrMsg, db, "%s (wal format detected)", sqlite3ErrStr( rc ) ); |
||
305 | else |
||
306 | sqlite3SetString( ref pzErrMsg, db, "%s", sqlite3ErrStr( rc ) ); |
||
307 | #else |
||
308 | sqlite3SetString( ref pzErrMsg, db, "%s", sqlite3ErrStr( rc ) ); |
||
309 | #endif |
||
310 | goto initone_error_out; |
||
311 | } |
||
312 | openedTransaction = 1; |
||
313 | } |
||
314 | |||
315 | /* Get the database meta information. |
||
316 | ** |
||
317 | ** Meta values are as follows: |
||
318 | ** meta[0] Schema cookie. Changes with each schema change. |
||
319 | ** meta[1] File format of schema layer. |
||
320 | ** meta[2] Size of the page cache. |
||
321 | ** meta[3] Largest rootpage (auto/incr_vacuum mode) |
||
322 | ** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE |
||
323 | ** meta[5] User version |
||
324 | ** meta[6] Incremental vacuum mode |
||
325 | ** meta[7] unused |
||
326 | ** meta[8] unused |
||
327 | ** meta[9] unused |
||
328 | ** |
||
329 | ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to |
||
330 | ** the possible values of meta[BTREE_TEXT_ENCODING-1]. |
||
331 | */ |
||
332 | for ( i = 0; i < ArraySize( meta ); i++ ) |
||
333 | { |
||
334 | sqlite3BtreeGetMeta( pDb.pBt, i + 1, ref meta[i] ); |
||
335 | } |
||
336 | pDb.pSchema.schema_cookie = (int)meta[BTREE_SCHEMA_VERSION - 1]; |
||
337 | |||
338 | /* If opening a non-empty database, check the text encoding. For the |
||
339 | ** main database, set sqlite3.enc to the encoding of the main database. |
||
340 | ** For an attached db, it is an error if the encoding is not the same |
||
341 | ** as sqlite3.enc. |
||
342 | */ |
||
343 | if ( meta[BTREE_TEXT_ENCODING - 1] != 0 ) |
||
344 | { /* text encoding */ |
||
345 | if ( iDb == 0 ) |
||
346 | { |
||
347 | u8 encoding; |
||
348 | /* If opening the main database, set ENC(db). */ |
||
349 | encoding = (u8)( meta[BTREE_TEXT_ENCODING - 1] & 3 ); |
||
350 | if ( encoding == 0 ) |
||
351 | encoding = SQLITE_UTF8; |
||
352 | db.aDb[0].pSchema.enc = encoding; //ENC( db ) = encoding; |
||
353 | db.pDfltColl = sqlite3FindCollSeq( db, SQLITE_UTF8, "BINARY", 0 ); |
||
354 | } |
||
355 | else |
||
356 | { |
||
357 | /* If opening an attached database, the encoding much match ENC(db) */ |
||
358 | if ( meta[BTREE_TEXT_ENCODING - 1] != ENC( db ) ) |
||
359 | { |
||
360 | sqlite3SetString( ref pzErrMsg, db, "attached databases must use the same" + |
||
361 | " text encoding as main database" ); |
||
362 | rc = SQLITE_ERROR; |
||
363 | goto initone_error_out; |
||
364 | } |
||
365 | } |
||
366 | } |
||
367 | else |
||
368 | { |
||
369 | DbSetProperty( db, iDb, DB_Empty ); |
||
370 | } |
||
371 | pDb.pSchema.enc = ENC( db ); |
||
372 | |||
373 | if ( pDb.pSchema.cache_size == 0 ) |
||
374 | { |
||
375 | size = sqlite3AbsInt32((int)meta[BTREE_DEFAULT_CACHE_SIZE - 1]); |
||
376 | if ( size == 0 ) |
||
377 | { |
||
378 | size = SQLITE_DEFAULT_CACHE_SIZE; |
||
379 | } |
||
380 | pDb.pSchema.cache_size = size; |
||
381 | sqlite3BtreeSetCacheSize( pDb.pBt, pDb.pSchema.cache_size ); |
||
382 | } |
||
383 | |||
384 | /* |
||
385 | ** file_format==1 Version 3.0.0. |
||
386 | ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN |
||
387 | ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults |
||
388 | ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants |
||
389 | */ |
||
390 | pDb.pSchema.file_format = (u8)meta[BTREE_FILE_FORMAT - 1]; |
||
391 | if ( pDb.pSchema.file_format == 0 ) |
||
392 | { |
||
393 | pDb.pSchema.file_format = 1; |
||
394 | } |
||
395 | if ( pDb.pSchema.file_format > SQLITE_MAX_FILE_FORMAT ) |
||
396 | { |
||
397 | sqlite3SetString( ref pzErrMsg, db, "unsupported file format" ); |
||
398 | rc = SQLITE_ERROR; |
||
399 | goto initone_error_out; |
||
400 | } |
||
401 | |||
402 | /* Ticket #2804: When we open a database in the newer file format, |
||
403 | ** clear the legacy_file_format pragma flag so that a VACUUM will |
||
404 | ** not downgrade the database and thus invalidate any descending |
||
405 | ** indices that the user might have created. |
||
406 | */ |
||
407 | if ( iDb == 0 && meta[BTREE_FILE_FORMAT - 1] >= 4 ) |
||
408 | { |
||
409 | db.flags &= ~SQLITE_LegacyFileFmt; |
||
410 | } |
||
411 | |||
412 | /* Read the schema information out of the schema tables |
||
413 | */ |
||
414 | Debug.Assert( db.init.busy != 0 ); |
||
415 | { |
||
416 | string zSql; |
||
417 | zSql = sqlite3MPrintf( db, |
||
418 | "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid", |
||
419 | db.aDb[iDb].zName, zMasterName ); |
||
420 | #if !SQLITE_OMIT_AUTHORIZATION |
||
421 | { |
||
422 | int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); |
||
423 | xAuth = db.xAuth; |
||
424 | db.xAuth = 0; |
||
425 | #endif |
||
426 | rc = sqlite3_exec( db, zSql, (dxCallback)sqlite3InitCallback, initData, 0 ); |
||
427 | pzErrMsg = initData.pzErrMsg; |
||
428 | #if !SQLITE_OMIT_AUTHORIZATION |
||
429 | db.xAuth = xAuth; |
||
430 | } |
||
431 | #endif |
||
432 | if ( rc == SQLITE_OK ) |
||
433 | rc = initData.rc; |
||
434 | sqlite3DbFree( db, ref zSql ); |
||
435 | #if !SQLITE_OMIT_ANALYZE |
||
436 | if ( rc == SQLITE_OK ) |
||
437 | { |
||
438 | sqlite3AnalysisLoad( db, iDb ); |
||
439 | } |
||
440 | #endif |
||
441 | } |
||
442 | //if ( db.mallocFailed != 0 ) |
||
443 | //{ |
||
444 | // rc = SQLITE_NOMEM; |
||
445 | // sqlite3ResetInternalSchema( db, -1 ); |
||
446 | //} |
||
447 | if ( rc == SQLITE_OK || ( db.flags & SQLITE_RecoveryMode ) != 0 ) |
||
448 | { |
||
449 | /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider |
||
450 | ** the schema loaded, even if errors occurred. In this situation the |
||
451 | ** current sqlite3_prepare() operation will fail, but the following one |
||
452 | ** will attempt to compile the supplied statement against whatever subset |
||
453 | ** of the schema was loaded before the error occurred. The primary |
||
454 | ** purpose of this is to allow access to the sqlite_master table |
||
455 | ** even when its contents have been corrupted. |
||
456 | */ |
||
457 | DbSetProperty( db, iDb, DB_SchemaLoaded ); |
||
458 | rc = SQLITE_OK; |
||
459 | } |
||
460 | /* Jump here for an error that occurs after successfully allocating |
||
461 | ** curMain and calling sqlite3BtreeEnter(). For an error that occurs |
||
462 | ** before that point, jump to error_out. |
||
463 | */ |
||
464 | initone_error_out: |
||
465 | if ( openedTransaction != 0 ) |
||
466 | { |
||
467 | sqlite3BtreeCommit( pDb.pBt ); |
||
468 | } |
||
469 | sqlite3BtreeLeave( pDb.pBt ); |
||
470 | |||
471 | error_out: |
||
472 | if ( rc == SQLITE_NOMEM || rc == SQLITE_IOERR_NOMEM ) |
||
473 | { |
||
474 | // db.mallocFailed = 1; |
||
475 | } |
||
476 | return rc; |
||
477 | } |
||
478 | |||
479 | /* |
||
480 | ** Initialize all database files - the main database file, the file |
||
481 | ** used to store temporary tables, and any additional database files |
||
482 | ** created using ATTACH statements. Return a success code. If an |
||
483 | ** error occurs, write an error message into pzErrMsg. |
||
484 | ** |
||
485 | ** After a database is initialized, the DB_SchemaLoaded bit is set |
||
486 | ** bit is set in the flags field of the Db structure. If the database |
||
487 | ** file was of zero-length, then the DB_Empty flag is also set. |
||
488 | */ |
||
489 | static int sqlite3Init( sqlite3 db, ref string pzErrMsg ) |
||
490 | { |
||
491 | int i, rc; |
||
492 | bool commit_internal = !( ( db.flags & SQLITE_InternChanges ) != 0 ); |
||
493 | |||
494 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
495 | rc = SQLITE_OK; |
||
496 | db.init.busy = 1; |
||
497 | for ( i = 0; rc == SQLITE_OK && i < db.nDb; i++ ) |
||
498 | { |
||
499 | if ( DbHasProperty( db, i, DB_SchemaLoaded ) || i == 1 ) |
||
500 | continue; |
||
501 | rc = sqlite3InitOne( db, i, ref pzErrMsg ); |
||
502 | if ( rc != 0 ) |
||
503 | { |
||
504 | sqlite3ResetInternalSchema( db, i ); |
||
505 | } |
||
506 | } |
||
507 | |||
508 | /* Once all the other databases have been initialised, load the schema |
||
509 | ** for the TEMP database. This is loaded last, as the TEMP database |
||
510 | ** schema may contain references to objects in other databases. |
||
511 | */ |
||
512 | #if !SQLITE_OMIT_TEMPDB |
||
513 | if ( rc == SQLITE_OK && ALWAYS( db.nDb > 1 ) |
||
514 | && !DbHasProperty( db, 1, DB_SchemaLoaded ) ) |
||
515 | { |
||
516 | rc = sqlite3InitOne( db, 1, ref pzErrMsg ); |
||
517 | if ( rc != 0 ) |
||
518 | { |
||
519 | sqlite3ResetInternalSchema( db, 1 ); |
||
520 | } |
||
521 | } |
||
522 | #endif |
||
523 | |||
524 | db.init.busy = 0; |
||
525 | if ( rc == SQLITE_OK && commit_internal ) |
||
526 | { |
||
527 | sqlite3CommitInternalChanges( db ); |
||
528 | } |
||
529 | |||
530 | return rc; |
||
531 | } |
||
532 | |||
533 | /* |
||
534 | ** This routine is a no-op if the database schema is already initialised. |
||
535 | ** Otherwise, the schema is loaded. An error code is returned. |
||
536 | */ |
||
537 | static int sqlite3ReadSchema( Parse pParse ) |
||
538 | { |
||
539 | int rc = SQLITE_OK; |
||
540 | sqlite3 db = pParse.db; |
||
541 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
542 | if ( 0 == db.init.busy ) |
||
543 | { |
||
544 | rc = sqlite3Init( db, ref pParse.zErrMsg ); |
||
545 | } |
||
546 | if ( rc != SQLITE_OK ) |
||
547 | { |
||
548 | pParse.rc = rc; |
||
549 | pParse.nErr++; |
||
550 | } |
||
551 | return rc; |
||
552 | } |
||
553 | |||
554 | |||
555 | /* |
||
556 | ** Check schema cookies in all databases. If any cookie is out |
||
557 | ** of date set pParse->rc to SQLITE_SCHEMA. If all schema cookies |
||
558 | ** make no changes to pParse->rc. |
||
559 | */ |
||
560 | static void schemaIsValid( Parse pParse ) |
||
561 | { |
||
562 | sqlite3 db = pParse.db; |
||
563 | int iDb; |
||
564 | int rc; |
||
565 | u32 cookie = 0; |
||
566 | |||
567 | Debug.Assert( pParse.checkSchema != 0 ); |
||
568 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
569 | for ( iDb = 0; iDb < db.nDb; iDb++ ) |
||
570 | { |
||
571 | int openedTransaction = 0; /* True if a transaction is opened */ |
||
572 | Btree pBt = db.aDb[iDb].pBt; /* Btree database to read cookie from */ |
||
573 | if ( pBt == null ) |
||
574 | continue; |
||
575 | |||
576 | /* If there is not already a read-only (or read-write) transaction opened |
||
577 | ** on the b-tree database, open one now. If a transaction is opened, it |
||
578 | ** will be closed immediately after reading the meta-value. */ |
||
579 | if ( !sqlite3BtreeIsInReadTrans( pBt ) ) |
||
580 | { |
||
581 | rc = sqlite3BtreeBeginTrans( pBt, 0 ); |
||
582 | //if ( rc == SQLITE_NOMEM || rc == SQLITE_IOERR_NOMEM ) |
||
583 | //{ |
||
584 | // db.mallocFailed = 1; |
||
585 | //} |
||
586 | if ( rc != SQLITE_OK ) |
||
587 | return; |
||
588 | openedTransaction = 1; |
||
589 | } |
||
590 | |||
591 | /* Read the schema cookie from the database. If it does not match the |
||
592 | ** value stored as part of the in-memory schema representation, |
||
593 | ** set Parse.rc to SQLITE_SCHEMA. */ |
||
594 | sqlite3BtreeGetMeta( pBt, BTREE_SCHEMA_VERSION, ref cookie ); |
||
595 | Debug.Assert( sqlite3SchemaMutexHeld( db, iDb, null ) ); |
||
596 | if ( cookie != db.aDb[iDb].pSchema.schema_cookie ) |
||
597 | { |
||
598 | sqlite3ResetInternalSchema( db, iDb ); |
||
599 | pParse.rc = SQLITE_SCHEMA; |
||
600 | } |
||
601 | |||
602 | /* Close the transaction, if one was opened. */ |
||
603 | if ( openedTransaction != 0 ) |
||
604 | { |
||
605 | sqlite3BtreeCommit( pBt ); |
||
606 | } |
||
607 | } |
||
608 | } |
||
609 | |||
610 | /* |
||
611 | ** Convert a schema pointer into the iDb index that indicates |
||
612 | ** which database file in db.aDb[] the schema refers to. |
||
613 | ** |
||
614 | ** If the same database is attached more than once, the first |
||
615 | ** attached database is returned. |
||
616 | */ |
||
617 | static int sqlite3SchemaToIndex( sqlite3 db, Schema pSchema ) |
||
618 | { |
||
619 | int i = -1000000; |
||
620 | |||
621 | /* If pSchema is NULL, then return -1000000. This happens when code in |
||
622 | ** expr.c is trying to resolve a reference to a transient table (i.e. one |
||
623 | ** created by a sub-select). In this case the return value of this |
||
624 | ** function should never be used. |
||
625 | ** |
||
626 | ** We return -1000000 instead of the more usual -1 simply because using |
||
627 | ** -1000000 as the incorrect index into db->aDb[] is much |
||
628 | ** more likely to cause a segfault than -1 (of course there are assert() |
||
629 | ** statements too, but it never hurts to play the odds). |
||
630 | */ |
||
631 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
632 | if ( pSchema != null ) |
||
633 | { |
||
634 | for ( i = 0; ALWAYS( i < db.nDb ); i++ ) |
||
635 | { |
||
636 | if ( db.aDb[i].pSchema == pSchema ) |
||
637 | { |
||
638 | break; |
||
639 | } |
||
640 | } |
||
641 | Debug.Assert( i >= 0 && i < db.nDb ); |
||
642 | } |
||
643 | return i; |
||
644 | } |
||
645 | |||
646 | /* |
||
647 | ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. |
||
648 | */ |
||
649 | static int sqlite3Prepare( |
||
650 | sqlite3 db, /* Database handle. */ |
||
651 | string zSql, /* UTF-8 encoded SQL statement. */ |
||
652 | int nBytes, /* Length of zSql in bytes. */ |
||
653 | int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ |
||
654 | Vdbe pReprepare, /* VM being reprepared */ |
||
655 | ref sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
656 | ref string pzTail /* OUT: End of parsed string */ |
||
657 | ) |
||
658 | { |
||
659 | Parse pParse; /* Parsing context */ |
||
660 | string zErrMsg = string.Empty; /* Error message */ |
||
661 | int rc = SQLITE_OK; /* Result code */ |
||
662 | int i; /* Loop counter */ |
||
663 | |||
664 | ppStmt = null; |
||
665 | pzTail = null; |
||
666 | |||
667 | /* Allocate the parsing context */ |
||
668 | pParse = new Parse();//sqlite3StackAllocZero(db, sizeof(*pParse)); |
||
669 | //if ( pParse == null ) |
||
670 | //{ |
||
671 | // rc = SQLITE_NOMEM; |
||
672 | // goto end_prepare; |
||
673 | //} |
||
674 | pParse.pReprepare = pReprepare; |
||
675 | pParse.sLastToken.z = string.Empty; |
||
676 | |||
677 | // assert( ppStmt && *ppStmt==0 ); |
||
678 | //Debug.Assert( 0 == db.mallocFailed ); |
||
679 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
680 | |||
681 | /* Check to verify that it is possible to get a read lock on all |
||
682 | ** database schemas. The inability to get a read lock indicates that |
||
683 | ** some other database connection is holding a write-lock, which in |
||
684 | ** turn means that the other connection has made uncommitted changes |
||
685 | ** to the schema. |
||
686 | ** |
||
687 | ** Were we to proceed and prepare the statement against the uncommitted |
||
688 | ** schema changes and if those schema changes are subsequently rolled |
||
689 | ** back and different changes are made in their place, then when this |
||
690 | ** prepared statement goes to run the schema cookie would fail to detect |
||
691 | ** the schema change. Disaster would follow. |
||
692 | ** |
||
693 | ** This thread is currently holding mutexes on all Btrees (because |
||
694 | ** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it |
||
695 | ** is not possible for another thread to start a new schema change |
||
696 | ** while this routine is running. Hence, we do not need to hold |
||
697 | ** locks on the schema, we just need to make sure nobody else is |
||
698 | ** holding them. |
||
699 | ** |
||
700 | ** Note that setting READ_UNCOMMITTED overrides most lock detection, |
||
701 | ** but it does *not* override schema lock detection, so this all still |
||
702 | ** works even if READ_UNCOMMITTED is set. |
||
703 | */ |
||
704 | for ( i = 0; i < db.nDb; i++ ) |
||
705 | { |
||
706 | Btree pBt = db.aDb[i].pBt; |
||
707 | if ( pBt != null ) |
||
708 | { |
||
709 | Debug.Assert( sqlite3BtreeHoldsMutex( pBt ) ); |
||
710 | rc = sqlite3BtreeSchemaLocked( pBt ); |
||
711 | if ( rc != 0 ) |
||
712 | { |
||
713 | string zDb = db.aDb[i].zName; |
||
714 | sqlite3Error( db, rc, "database schema is locked: %s", zDb ); |
||
715 | testcase( db.flags & SQLITE_ReadUncommitted ); |
||
716 | goto end_prepare; |
||
717 | } |
||
718 | } |
||
719 | } |
||
720 | |||
721 | sqlite3VtabUnlockList( db ); |
||
722 | |||
723 | pParse.db = db; |
||
724 | pParse.nQueryLoop = (double)1; |
||
725 | if ( nBytes >= 0 && ( nBytes == 0 || zSql[nBytes - 1] != 0 ) ) |
||
726 | { |
||
727 | string zSqlCopy; |
||
728 | int mxLen = db.aLimit[SQLITE_LIMIT_SQL_LENGTH]; |
||
729 | testcase( nBytes == mxLen ); |
||
730 | testcase( nBytes == mxLen + 1 ); |
||
731 | if ( nBytes > mxLen ) |
||
732 | { |
||
733 | sqlite3Error( db, SQLITE_TOOBIG, "statement too long" ); |
||
734 | rc = sqlite3ApiExit( db, SQLITE_TOOBIG ); |
||
735 | goto end_prepare; |
||
736 | } |
||
737 | zSqlCopy = zSql.Substring( 0, nBytes );// sqlite3DbStrNDup(db, zSql, nBytes); |
||
738 | if ( zSqlCopy != null ) |
||
739 | { |
||
740 | sqlite3RunParser( pParse, zSqlCopy, ref zErrMsg ); |
||
741 | sqlite3DbFree( db, ref zSqlCopy ); |
||
742 | //pParse->zTail = &zSql[pParse->zTail-zSqlCopy]; |
||
743 | } |
||
744 | else |
||
745 | { |
||
746 | //pParse->zTail = &zSql[nBytes]; |
||
747 | } |
||
748 | } |
||
749 | else |
||
750 | { |
||
751 | sqlite3RunParser( pParse, zSql, ref zErrMsg ); |
||
752 | } |
||
753 | Debug.Assert( 1 == (int)pParse.nQueryLoop ); |
||
754 | |||
755 | //if ( db.mallocFailed != 0 ) |
||
756 | //{ |
||
757 | // pParse.rc = SQLITE_NOMEM; |
||
758 | //} |
||
759 | if ( pParse.rc == SQLITE_DONE ) |
||
760 | pParse.rc = SQLITE_OK; |
||
761 | if ( pParse.checkSchema != 0 ) |
||
762 | { |
||
763 | schemaIsValid( pParse ); |
||
764 | } |
||
765 | //if ( db.mallocFailed != 0 ) |
||
766 | //{ |
||
767 | // pParse.rc = SQLITE_NOMEM; |
||
768 | //} |
||
769 | //if (pzTail != null) |
||
770 | { |
||
771 | pzTail = pParse.zTail == null ? string.Empty : pParse.zTail.ToString(); |
||
772 | } |
||
773 | rc = pParse.rc; |
||
774 | #if !SQLITE_OMIT_EXPLAIN |
||
775 | if ( rc == SQLITE_OK && pParse.pVdbe != null && pParse.explain != 0 ) |
||
776 | { |
||
777 | string[] azColName = new string[] { |
||
778 | "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", |
||
779 | "selectid", "order", "from", "detail" |
||
780 | }; |
||
781 | int iFirst, mx; |
||
782 | if ( pParse.explain == 2 ) |
||
783 | { |
||
784 | sqlite3VdbeSetNumCols( pParse.pVdbe, 4 ); |
||
785 | iFirst = 8; |
||
786 | mx = 12; |
||
787 | } |
||
788 | else |
||
789 | { |
||
790 | sqlite3VdbeSetNumCols( pParse.pVdbe, 8 ); |
||
791 | iFirst = 0; |
||
792 | mx = 8; |
||
793 | } |
||
794 | for ( i = iFirst; i < mx; i++ ) |
||
795 | { |
||
796 | sqlite3VdbeSetColName( pParse.pVdbe, i - iFirst, COLNAME_NAME, |
||
797 | azColName[i], SQLITE_STATIC ); |
||
798 | } |
||
799 | } |
||
800 | #endif |
||
801 | |||
802 | Debug.Assert( db.init.busy == 0 || saveSqlFlag == 0 ); |
||
803 | if ( db.init.busy == 0 ) |
||
804 | { |
||
805 | Vdbe pVdbe = pParse.pVdbe; |
||
806 | sqlite3VdbeSetSql( pVdbe, zSql, (int)( zSql.Length - ( pParse.zTail == null ? 0 : pParse.zTail.Length ) ), saveSqlFlag ); |
||
807 | } |
||
808 | if ( pParse.pVdbe != null && ( rc != SQLITE_OK /*|| db.mallocFailed != 0 */ ) ) |
||
809 | { |
||
810 | sqlite3VdbeFinalize( ref pParse.pVdbe ); |
||
811 | //Debug.Assert( ppStmt == null ); |
||
812 | } |
||
813 | else |
||
814 | { |
||
815 | ppStmt = pParse.pVdbe; |
||
816 | } |
||
817 | |||
818 | if ( zErrMsg.Length > 0 ) |
||
819 | { |
||
820 | sqlite3Error( db, rc, "%s", zErrMsg ); |
||
821 | sqlite3DbFree( db, ref zErrMsg ); |
||
822 | } |
||
823 | else |
||
824 | { |
||
825 | sqlite3Error( db, rc, 0 ); |
||
826 | } |
||
827 | |||
828 | /* Delete any TriggerPrg structures allocated while parsing this statement. */ |
||
829 | while ( pParse.pTriggerPrg != null ) |
||
830 | { |
||
831 | TriggerPrg pT = pParse.pTriggerPrg; |
||
832 | pParse.pTriggerPrg = pT.pNext; |
||
833 | sqlite3DbFree( db, ref pT ); |
||
834 | } |
||
835 | |||
836 | end_prepare: |
||
837 | |||
838 | //sqlite3StackFree( db, pParse ); |
||
839 | rc = sqlite3ApiExit( db, rc ); |
||
840 | Debug.Assert( ( rc & db.errMask ) == rc ); |
||
841 | return rc; |
||
842 | } |
||
843 | |||
844 | //C# Version w/o End of Parsed String |
||
845 | static int sqlite3LockAndPrepare( |
||
846 | sqlite3 db, /* Database handle. */ |
||
847 | string zSql, /* UTF-8 encoded SQL statement. */ |
||
848 | int nBytes, /* Length of zSql in bytes. */ |
||
849 | int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ |
||
850 | Vdbe pOld, /* VM being reprepared */ |
||
851 | ref sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
852 | int dummy /* OUT: End of parsed string */ |
||
853 | ) |
||
854 | { |
||
855 | string sOut = null; |
||
856 | return sqlite3LockAndPrepare( db, zSql, nBytes, saveSqlFlag, pOld, ref ppStmt, ref sOut ); |
||
857 | } |
||
858 | |||
859 | static int sqlite3LockAndPrepare( |
||
860 | sqlite3 db, /* Database handle. */ |
||
861 | string zSql, /* UTF-8 encoded SQL statement. */ |
||
862 | int nBytes, /* Length of zSql in bytes. */ |
||
863 | int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ |
||
864 | Vdbe pOld, /* VM being reprepared */ |
||
865 | ref sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
866 | ref string pzTail /* OUT: End of parsed string */ |
||
867 | ) |
||
868 | { |
||
869 | int rc; |
||
870 | // assert( ppStmt!=0 ); |
||
871 | if ( !sqlite3SafetyCheckOk( db ) ) |
||
872 | { |
||
873 | ppStmt = null; |
||
874 | pzTail = null; |
||
875 | return SQLITE_MISUSE_BKPT(); |
||
876 | } |
||
877 | sqlite3_mutex_enter( db.mutex ); |
||
878 | sqlite3BtreeEnterAll( db ); |
||
879 | rc = sqlite3Prepare( db, zSql, nBytes, saveSqlFlag, pOld, ref ppStmt, ref pzTail ); |
||
880 | if ( rc == SQLITE_SCHEMA ) |
||
881 | { |
||
882 | sqlite3_finalize( ppStmt ); |
||
883 | rc = sqlite3Prepare( db, zSql, nBytes, saveSqlFlag, pOld, ref ppStmt, ref pzTail ); |
||
884 | } |
||
885 | sqlite3BtreeLeaveAll( db ); |
||
886 | sqlite3_mutex_leave( db.mutex ); |
||
887 | return rc; |
||
888 | } |
||
889 | |||
890 | /* |
||
891 | ** Rerun the compilation of a statement after a schema change. |
||
892 | ** |
||
893 | ** If the statement is successfully recompiled, return SQLITE_OK. Otherwise, |
||
894 | ** if the statement cannot be recompiled because another connection has |
||
895 | ** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error |
||
896 | ** occurs, return SQLITE_SCHEMA. |
||
897 | */ |
||
898 | static int sqlite3Reprepare( Vdbe p ) |
||
899 | { |
||
900 | int rc; |
||
901 | sqlite3_stmt pNew = new sqlite3_stmt(); |
||
902 | string zSql; |
||
903 | sqlite3 db; |
||
904 | |||
905 | Debug.Assert( sqlite3_mutex_held( sqlite3VdbeDb( p ).mutex ) ); |
||
906 | zSql = sqlite3_sql( (sqlite3_stmt)p ); |
||
907 | Debug.Assert( zSql != null ); /* Reprepare only called for prepare_v2() statements */ |
||
908 | db = sqlite3VdbeDb( p ); |
||
909 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
910 | rc = sqlite3LockAndPrepare( db, zSql, -1, 0, p, ref pNew, 0 ); |
||
911 | if ( rc != 0 ) |
||
912 | { |
||
913 | if ( rc == SQLITE_NOMEM ) |
||
914 | { |
||
915 | // db.mallocFailed = 1; |
||
916 | } |
||
917 | Debug.Assert( pNew == null ); |
||
918 | return rc; |
||
919 | } |
||
920 | else |
||
921 | { |
||
922 | Debug.Assert( pNew != null ); |
||
923 | } |
||
924 | sqlite3VdbeSwap( (Vdbe)pNew, p ); |
||
925 | sqlite3TransferBindings( pNew, (sqlite3_stmt)p ); |
||
926 | sqlite3VdbeResetStepResult( (Vdbe)pNew ); |
||
927 | sqlite3VdbeFinalize( ref pNew ); |
||
928 | return SQLITE_OK; |
||
929 | } |
||
930 | |||
931 | |||
932 | //C# Overload for ignore error out |
||
933 | static public int sqlite3_prepare( |
||
934 | sqlite3 db, /* Database handle. */ |
||
935 | string zSql, /* UTF-8 encoded SQL statement. */ |
||
936 | int nBytes, /* Length of zSql in bytes. */ |
||
937 | ref sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
938 | int dummy /* OUT: End of parsed string */ |
||
939 | ) |
||
940 | { |
||
941 | string sOut = null; |
||
942 | return sqlite3_prepare( db, zSql, nBytes, ref ppStmt, ref sOut ); |
||
943 | } |
||
944 | /* |
||
945 | ** Two versions of the official API. Legacy and new use. In the legacy |
||
946 | ** version, the original SQL text is not saved in the prepared statement |
||
947 | ** and so if a schema change occurs, SQLITE_SCHEMA is returned by |
||
948 | ** sqlite3_step(). In the new version, the original SQL text is retained |
||
949 | ** and the statement is automatically recompiled if an schema change |
||
950 | ** occurs. |
||
951 | */ |
||
952 | static public int sqlite3_prepare( |
||
953 | sqlite3 db, /* Database handle. */ |
||
954 | string zSql, /* UTF-8 encoded SQL statement. */ |
||
955 | int nBytes, /* Length of zSql in bytes. */ |
||
956 | ref sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
957 | ref string pzTail /* OUT: End of parsed string */ |
||
958 | ) |
||
959 | { |
||
960 | int rc; |
||
961 | rc = sqlite3LockAndPrepare( db, zSql, nBytes, 0, null, ref ppStmt, ref pzTail ); |
||
962 | Debug.Assert( rc == SQLITE_OK || ppStmt == null ); /* VERIFY: F13021 */ |
||
963 | return rc; |
||
964 | } |
||
965 | |||
966 | public static int sqlite3_prepare_v2( |
||
967 | sqlite3 db, /* Database handle. */ |
||
968 | string zSql, /* UTF-8 encoded SQL statement. */ |
||
969 | int nBytes, /* Length of zSql in bytes. */ |
||
970 | ref sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
971 | int dummy /* ( No string passed) */ |
||
972 | ) |
||
973 | { |
||
974 | string pzTail = null; |
||
975 | int rc; |
||
976 | rc = sqlite3LockAndPrepare( db, zSql, nBytes, 1, null, ref ppStmt, ref pzTail ); |
||
977 | Debug.Assert( rc == SQLITE_OK || ppStmt == null ); /* VERIFY: F13021 */ |
||
978 | return rc; |
||
979 | } |
||
980 | |||
981 | public static int sqlite3_prepare_v2( |
||
982 | sqlite3 db, /* Database handle. */ |
||
983 | string zSql, /* UTF-8 encoded SQL statement. */ |
||
984 | int nBytes, /* Length of zSql in bytes. */ |
||
985 | ref sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
986 | ref string pzTail /* OUT: End of parsed string */ |
||
987 | ) |
||
988 | { |
||
989 | int rc; |
||
990 | rc = sqlite3LockAndPrepare( db, zSql, nBytes, 1, null, ref ppStmt, ref pzTail ); |
||
991 | Debug.Assert( rc == SQLITE_OK || ppStmt == null ); /* VERIFY: F13021 */ |
||
992 | return rc; |
||
993 | } |
||
994 | |||
995 | |||
996 | #if !SQLITE_OMIT_UTF16 |
||
997 | |||
998 | /* |
||
999 | ** Compile the UTF-16 encoded SQL statement zSql into a statement handle. |
||
1000 | */ |
||
1001 | static int sqlite3Prepare16( |
||
1002 | sqlite3 db, /* Database handle. */ |
||
1003 | string zSql, /* UTF-15 encoded SQL statement. */ |
||
1004 | int nBytes, /* Length of zSql in bytes. */ |
||
1005 | bool saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */ |
||
1006 | out sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
1007 | out string pzTail /* OUT: End of parsed string */ |
||
1008 | ){ |
||
1009 | /* This function currently works by first transforming the UTF-16 |
||
1010 | ** encoded string to UTF-8, then invoking sqlite3_prepare(). The |
||
1011 | ** tricky bit is figuring out the pointer to return in pzTail. |
||
1012 | */ |
||
1013 | string zSql8; |
||
1014 | string zTail8 = string.Empty; |
||
1015 | int rc = SQLITE_OK; |
||
1016 | |||
1017 | assert( ppStmt ); |
||
1018 | *ppStmt = 0; |
||
1019 | if( !sqlite3SafetyCheckOk(db) ){ |
||
1020 | return SQLITE_MISUSE_BKPT; |
||
1021 | } |
||
1022 | sqlite3_mutex_enter(db.mutex); |
||
1023 | zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); |
||
1024 | if( zSql8 != string.Empty){ |
||
1025 | rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, null, ref ppStmt, ref zTail8); |
||
1026 | } |
||
1027 | |||
1028 | if( zTail8 != string.Empty && pzTail != string.Empty){ |
||
1029 | /* If sqlite3_prepare returns a tail pointer, we calculate the |
||
1030 | ** equivalent pointer into the UTF-16 string by counting the unicode |
||
1031 | ** characters between zSql8 and zTail8, and then returning a pointer |
||
1032 | ** the same number of characters into the UTF-16 string. |
||
1033 | */ |
||
1034 | Debugger.Break (); // TODO -- |
||
1035 | // int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8)); |
||
1036 | // pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); |
||
1037 | } |
||
1038 | sqlite3DbFree(db,ref zSql8); |
||
1039 | rc = sqlite3ApiExit(db, rc); |
||
1040 | sqlite3_mutex_leave(db.mutex); |
||
1041 | return rc; |
||
1042 | } |
||
1043 | |||
1044 | /* |
||
1045 | ** Two versions of the official API. Legacy and new use. In the legacy |
||
1046 | ** version, the original SQL text is not saved in the prepared statement |
||
1047 | ** and so if a schema change occurs, SQLITE_SCHEMA is returned by |
||
1048 | ** sqlite3_step(). In the new version, the original SQL text is retained |
||
1049 | ** and the statement is automatically recompiled if an schema change |
||
1050 | ** occurs. |
||
1051 | */ |
||
1052 | public static int sqlite3_prepare16( |
||
1053 | sqlite3 db, /* Database handle. */ |
||
1054 | string zSql, /* UTF-16 encoded SQL statement. */ |
||
1055 | int nBytes, /* Length of zSql in bytes. */ |
||
1056 | out sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
1057 | out string pzTail /* OUT: End of parsed string */ |
||
1058 | ){ |
||
1059 | int rc; |
||
1060 | rc = sqlite3Prepare16(db,zSql,nBytes,false,ref ppStmt,ref pzTail); |
||
1061 | Debug.Assert( rc==SQLITE_OK || ppStmt==null || ppStmt==null ); /* VERIFY: F13021 */ |
||
1062 | return rc; |
||
1063 | } |
||
1064 | public static int sqlite3_prepare16_v2( |
||
1065 | sqlite3 db, /* Database handle. */ |
||
1066 | string zSql, /* UTF-16 encoded SQL statement. */ |
||
1067 | int nBytes, /* Length of zSql in bytes. */ |
||
1068 | out sqlite3_stmt ppStmt, /* OUT: A pointer to the prepared statement */ |
||
1069 | out string pzTail /* OUT: End of parsed string */ |
||
1070 | ) |
||
1071 | { |
||
1072 | int rc; |
||
1073 | rc = sqlite3Prepare16(db,zSql,nBytes,true,ref ppStmt,ref pzTail); |
||
1074 | Debug.Assert( rc==SQLITE_OK || ppStmt==null || ppStmt==null ); /* VERIFY: F13021 */ |
||
1075 | return rc; |
||
1076 | } |
||
1077 | |||
1078 | #endif // * SQLITE_OMIT_UTF16 */ |
||
1079 | } |
||
1080 | } |