wasCSharpSQLite – Blame information for rev

Subversion Repositories:
Rev:
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  
7 namespace Community.CsharpSqlite
8 {
9 public partial class Sqlite3
10 {
11 /*
12 ** 2006 June 10
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 code used to help implement virtual tables.
23 *************************************************************************
24 ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
25 ** C#-SQLite is an independent reimplementation of the SQLite software library
26 **
27 ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
28 **
29 *************************************************************************
30 */
31 #if !SQLITE_OMIT_VIRTUALTABLE
32 //#include "sqliteInt.h"
33  
34 /*
35 ** Before a virtual table xCreate() or xConnect() method is invoked, the
36 ** sqlite3.pVtabCtx member variable is set to point to an instance of
37 ** this struct allocated on the stack. It is used by the implementation of
38 ** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which
39 ** are invoked only from within xCreate and xConnect methods.
40 */
41 public class VtabCtx
42 {
43 public Table pTab;
44 public VTable pVTable;
45 };
46  
47 /*
48 ** The actual function that does the work of creating a new module.
49 ** This function implements the sqlite3_create_module() and
50 ** sqlite3_create_module_v2() interfaces.
51 */
52 static int createModule(
53 sqlite3 db, /* Database in which module is registered */
54 string zName, /* Name assigned to this module */
55 sqlite3_module pModule, /* The definition of the module */
56 object pAux, /* Context pointer for xCreate/xConnect */
57 smdxDestroy xDestroy /* Module destructor function */
58 )
59 {
60 int rc, nName;
61 Module pMod;
62  
63 sqlite3_mutex_enter( db.mutex );
64 nName = sqlite3Strlen30( zName );
65 pMod = new Module();// (Module)sqlite3DbMallocRaw( db, sizeof( Module ) + nName + 1 );
66 if ( pMod != null )
67 {
68 Module pDel;
69 string zCopy;// = (char )(&pMod[1]);
70 zCopy = zName;//memcpy(zCopy, zName, nName+1);
71 pMod.zName = zCopy;
72 pMod.pModule = pModule;
73 pMod.pAux = pAux;
74 pMod.xDestroy = xDestroy;
75 pDel = (Module)sqlite3HashInsert( ref db.aModule, zCopy, nName, pMod );
76 if ( pDel != null && pDel.xDestroy != null )
77 {
78 sqlite3ResetInternalSchema( db, -1 );
79 pDel.xDestroy( ref pDel.pAux );
80 }
81 sqlite3DbFree( db, ref pDel );
82 //if( pDel==pMod ){
83 // db.mallocFailed = 1;
84 //}
85 }
86 else if ( xDestroy != null )
87 {
88 xDestroy( ref pAux );
89 }
90 rc = sqlite3ApiExit( db, SQLITE_OK );
91 sqlite3_mutex_leave( db.mutex );
92 return rc;
93 }
94  
95  
96 /*
97 ** External API function used to create a new virtual-table module.
98 */
99 static int sqlite3_create_module(
100 sqlite3 db, /* Database in which module is registered */
101 string zName, /* Name assigned to this module */
102 sqlite3_module pModule, /* The definition of the module */
103 object pAux /* Context pointer for xCreate/xConnect */
104 )
105 {
106 return createModule( db, zName, pModule, pAux, null );
107 }
108  
109 /*
110 ** External API function used to create a new virtual-table module.
111 */
112 static int sqlite3_create_module_v2(
113 sqlite3 db, /* Database in which module is registered */
114 string zName, /* Name assigned to this module */
115 sqlite3_module pModule, /* The definition of the module */
116 sqlite3_vtab pAux, /* Context pointer for xCreate/xConnect */
117 smdxDestroy xDestroy /* Module destructor function */
118 )
119 {
120 return createModule( db, zName, pModule, pAux, xDestroy );
121 }
122  
123 /*
124 ** Lock the virtual table so that it cannot be disconnected.
125 ** Locks nest. Every lock should have a corresponding unlock.
126 ** If an unlock is omitted, resources leaks will occur.
127 **
128 ** If a disconnect is attempted while a virtual table is locked,
129 ** the disconnect is deferred until all locks have been removed.
130 */
131 static void sqlite3VtabLock( VTable pVTab )
132 {
133 pVTab.nRef++;
134 }
135  
136  
137 /*
138 ** pTab is a pointer to a Table structure representing a virtual-table.
139 ** Return a pointer to the VTable object used by connection db to access
140 ** this virtual-table, if one has been created, or NULL otherwise.
141 */
142 static VTable sqlite3GetVTable( sqlite3 db, Table pTab )
143 {
144 VTable pVtab;
145 Debug.Assert( IsVirtual( pTab ) );
146 for ( pVtab = pTab.pVTable; pVtab != null && pVtab.db != db; pVtab = pVtab.pNext )
147 ;
148 return pVtab;
149 }
150  
151 /*
152 ** Decrement the ref-count on a virtual table object. When the ref-count
153 ** reaches zero, call the xDisconnect() method to delete the object.
154 */
155 static void sqlite3VtabUnlock( VTable pVTab )
156 {
157 sqlite3 db = pVTab.db;
158  
159 Debug.Assert( db != null);
160 Debug.Assert( pVTab.nRef > 0 );
161 Debug.Assert( sqlite3SafetyCheckOk( db ) );
162  
163 pVTab.nRef--;
164 if ( pVTab.nRef == 0 )
165 {
166 object p = pVTab.pVtab;
167 if ( p != null )
168 {
169 ((sqlite3_vtab)p).pModule.xDisconnect( ref p );
170 }
171 sqlite3DbFree( db, ref pVTab );
172 }
173 }
174  
175 /*
176 ** Table p is a virtual table. This function moves all elements in the
177 ** p.pVTable list to the sqlite3.pDisconnect lists of their associated
178 ** database connections to be disconnected at the next opportunity.
179 ** Except, if argument db is not NULL, then the entry associated with
180 ** connection db is left in the p.pVTable list.
181 */
182 static VTable vtabDisconnectAll( sqlite3 db, Table p )
183 {
184 VTable pRet = null;
185 VTable pVTable = p.pVTable;
186 p.pVTable = null;
187  
188 /* Assert that the mutex (if any) associated with the BtShared database
189 ** that contains table p is held by the caller. See header comments
190 ** above function sqlite3VtabUnlockList() for an explanation of why
191 ** this makes it safe to access the sqlite3.pDisconnect list of any
192 ** database connection that may have an entry in the p.pVTable list.
193 */
194 Debug.Assert( db == null || sqlite3SchemaMutexHeld( db, 0, p.pSchema ) );
195  
196 while ( pVTable != null )
197 {
198 sqlite3 db2 = pVTable.db;
199 VTable pNext = pVTable.pNext;
200 Debug.Assert( db2 != null );
201 if ( db2 == db )
202 {
203 pRet = pVTable;
204 p.pVTable = pRet;
205 pRet.pNext = null;
206 }
207 else
208 {
209 pVTable.pNext = db2.pDisconnect;
210 db2.pDisconnect = pVTable;
211 }
212 pVTable = pNext;
213 }
214  
215 Debug.Assert( null == db || pRet != null );
216 return pRet;
217 }
218  
219  
220 /*
221 ** Disconnect all the virtual table objects in the sqlite3.pDisconnect list.
222 **
223 ** This function may only be called when the mutexes associated with all
224 ** shared b-tree databases opened using connection db are held by the
225 ** caller. This is done to protect the sqlite3.pDisconnect list. The
226 ** sqlite3.pDisconnect list is accessed only as follows:
227 **
228 ** 1) By this function. In this case, all BtShared mutexes and the mutex
229 ** associated with the database handle itself must be held.
230 **
231 ** 2) By function vtabDisconnectAll(), when it adds a VTable entry to
232 ** the sqlite3.pDisconnect list. In this case either the BtShared mutex
233 ** associated with the database the virtual table is stored in is held
234 ** or, if the virtual table is stored in a non-sharable database, then
235 ** the database handle mutex is held.
236 **
237 ** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously
238 ** by multiple threads. It is thread-safe.
239 */
240 static void sqlite3VtabUnlockList( sqlite3 db )
241 {
242 VTable p = db.pDisconnect;
243 db.pDisconnect = null;
244  
245 Debug.Assert( sqlite3BtreeHoldsAllMutexes( db ) );
246 Debug.Assert( sqlite3_mutex_held( db.mutex ) );
247  
248 if ( p != null )
249 {
250 sqlite3ExpirePreparedStatements( db );
251 do
252 {
253 VTable pNext = p.pNext;
254 sqlite3VtabUnlock( p );
255 p = pNext;
256 } while ( p != null );
257 }
258 }
259  
260 /*
261 ** Clear any and all virtual-table information from the Table record.
262 ** This routine is called, for example, just before deleting the Table
263 ** record.
264 **
265 ** Since it is a virtual-table, the Table structure contains a pointer
266 ** to the head of a linked list of VTable structures. Each VTable
267 ** structure is associated with a single sqlite3* user of the schema.
268 ** The reference count of the VTable structure associated with database
269 ** connection db is decremented immediately (which may lead to the
270 ** structure being xDisconnected and free). Any other VTable structures
271 ** in the list are moved to the sqlite3.pDisconnect list of the associated
272 ** database connection.
273 */
274 static void sqlite3VtabClear( sqlite3 db, Table p )
275 {
276 if ( null == db || db.pnBytesFreed == 0 )
277 vtabDisconnectAll( null, p );
278 if ( p.azModuleArg != null )
279 {
280 int i;
281 for ( i = 0; i < p.nModuleArg; i++ )
282 {
283 sqlite3DbFree( db, ref p.azModuleArg[i] );
284 }
285 sqlite3DbFree( db, ref p.azModuleArg );
286 }
287 }
288  
289 /*
290 ** Add a new module argument to pTable.azModuleArg[].
291 ** The string is not copied - the pointer is stored. The
292 ** string will be freed automatically when the table is
293 ** deleted.
294 */
295 static void addModuleArgument( sqlite3 db, Table pTable, string zArg )
296 {
297 int i = pTable.nModuleArg++;
298 //int nBytes = sizeof(char )*(1+pTable.nModuleArg);
299 //string[] azModuleArg;
300 //sqlite3DbRealloc( db, pTable.azModuleArg, nBytes );
301 if ( pTable.azModuleArg == null || pTable.azModuleArg.Length < pTable.nModuleArg )
302 Array.Resize( ref pTable.azModuleArg, 3 + pTable.nModuleArg );
303 //if ( azModuleArg == null )
304 //{
305 // int j;
306 // for ( j = 0; j < i; j++ )
307 // {
308 // sqlite3DbFree( db, ref pTable.azModuleArg[j] );
309 // }
310 // sqlite3DbFree( db, ref zArg );
311 // sqlite3DbFree( db, ref pTable.azModuleArg );
312 // pTable.nModuleArg = 0;
313 //}
314 //else
315 {
316 pTable.azModuleArg[i] = zArg;
317 //pTable.azModuleArg[i + 1] = null;
318 //azModuleArg[i+1] = 0;
319 }
320 //pTable.azModuleArg = azModuleArg;
321 }
322  
323 /*
324 ** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE
325 ** statement. The module name has been parsed, but the optional list
326 ** of parameters that follow the module name are still pending.
327 */
328 static void sqlite3VtabBeginParse(
329 Parse pParse, /* Parsing context */
330 Token pName1, /* Name of new table, or database name */
331 Token pName2, /* Name of new table or NULL */
332 Token pModuleName /* Name of the module for the virtual table */
333 )
334 {
335 int iDb; /* The database the table is being created in */
336 Table pTable; /* The new virtual table */
337 sqlite3 db; /* Database connection */
338  
339 sqlite3StartTable( pParse, pName1, pName2, 0, 0, 1, 0 );
340 pTable = pParse.pNewTable;
341 if ( pTable == null )
342 return;
343 Debug.Assert( null == pTable.pIndex );
344  
345 db = pParse.db;
346 iDb = sqlite3SchemaToIndex( db, pTable.pSchema );
347 Debug.Assert( iDb >= 0 );
348  
349 pTable.tabFlags |= TF_Virtual;
350 pTable.nModuleArg = 0;
351 addModuleArgument( db, pTable, sqlite3NameFromToken( db, pModuleName ) );
352 addModuleArgument( db, pTable, db.aDb[iDb].zName);//sqlite3DbStrDup( db, db.aDb[iDb].zName ) );
353 addModuleArgument( db, pTable, pTable.zName );//sqlite3DbStrDup( db, pTable.zName ) );
354 pParse.sNameToken.n = pParse.sNameToken.z.Length;// (int)[pModuleName.n] - pName1.z );
355  
356 #if !SQLITE_OMIT_AUTHORIZATION
357 /* Creating a virtual table invokes the authorization callback twice.
358 ** The first invocation, to obtain permission to INSERT a row into the
359 ** sqlite_master table, has already been made by sqlite3StartTable().
360 ** The second call, to obtain permission to create the table, is made now.
361 */
362 if( pTable->azModuleArg ){
363 sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
364 pTable->azModuleArg[0], pParse->db->aDb[iDb].zName);
365 }
366 #endif
367 }
368  
369 /*
370 ** This routine takes the module argument that has been accumulating
371 ** in pParse.zArg[] and appends it to the list of arguments on the
372 ** virtual table currently under construction in pParse.pTable.
373 */
374 static void addArgumentToVtab( Parse pParse )
375 {
376 if ( pParse.sArg.z != null && ALWAYS( pParse.pNewTable ) )
377 {
378 string z = pParse.sArg.z.Substring( 0, pParse.sArg.n );
379 ////int n = pParse.sArg.n;
380 sqlite3 db = pParse.db;
381 addModuleArgument( db, pParse.pNewTable, z );////sqlite3DbStrNDup( db, z, n ) );
382 }
383 }
384  
385 /*
386 ** The parser calls this routine after the CREATE VIRTUAL TABLE statement
387 ** has been completely parsed.
388 */
389 static void sqlite3VtabFinishParse( Parse pParse, Token pEnd )
390 {
391 Table pTab = pParse.pNewTable; /* The table being constructed */
392 sqlite3 db = pParse.db; /* The database connection */
393  
394 if ( pTab == null )
395 return;
396 addArgumentToVtab( pParse );
397 pParse.sArg.z = string.Empty;
398 if ( pTab.nModuleArg < 1 )
399 return;
400  
401 /* If the CREATE VIRTUAL TABLE statement is being entered for the
402 ** first time (in other words if the virtual table is actually being
403 ** created now instead of just being read out of sqlite_master) then
404 ** do additional initialization work and store the statement text
405 ** in the sqlite_master table.
406 */
407 if ( 0 == db.init.busy )
408 {
409 string zStmt;
410 string zWhere;
411 int iDb;
412 Vdbe v;
413  
414 /* Compute the complete text of the CREATE VIRTUAL TABLE statement */
415 if ( pEnd != null )
416 {
417 pParse.sNameToken.n = pParse.sNameToken.z.Length;//(int)( pEnd.z - pParse.sNameToken.z ) + pEnd.n;
418 }
419 zStmt = sqlite3MPrintf( db, "CREATE VIRTUAL TABLE %T", pParse.sNameToken.z.Substring(0,pParse.sNameToken.n) );
420  
421 /* A slot for the record has already been allocated in the
422 ** SQLITE_MASTER table. We just need to update that slot with all
423 ** the information we've collected.
424 **
425 ** The VM register number pParse.regRowid holds the rowid of an
426 ** entry in the sqlite_master table tht was created for this vtab
427 ** by sqlite3StartTable().
428 */
429 iDb = sqlite3SchemaToIndex( db, pTab.pSchema );
430 sqlite3NestedParse( pParse,
431 "UPDATE %Q.%s " +
432 "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " +
433 "WHERE rowid=#%d",
434 db.aDb[iDb].zName, SCHEMA_TABLE( iDb ),
435 pTab.zName,
436 pTab.zName,
437 zStmt,
438 pParse.regRowid
439 );
440 sqlite3DbFree( db, ref zStmt );
441 v = sqlite3GetVdbe( pParse );
442 sqlite3ChangeCookie( pParse, iDb );
443  
444 sqlite3VdbeAddOp2( v, OP_Expire, 0, 0 );
445 zWhere = sqlite3MPrintf( db, "name='%q' AND type='table'", pTab.zName );
446 sqlite3VdbeAddParseSchemaOp( v, iDb, zWhere );
447 sqlite3VdbeAddOp4( v, OP_VCreate, iDb, 0, 0,
448 pTab.zName, sqlite3Strlen30( pTab.zName ) + 1 );
449 }
450  
451 /* If we are rereading the sqlite_master table create the in-memory
452 ** record of the table. The xConnect() method is not called until
453 ** the first time the virtual table is used in an SQL statement. This
454 ** allows a schema that contains virtual tables to be loaded before
455 ** the required virtual table implementations are registered. */
456 else
457 {
458 Table pOld;
459 Schema pSchema = pTab.pSchema;
460 string zName = pTab.zName;
461 int nName = sqlite3Strlen30( zName );
462 Debug.Assert( sqlite3SchemaMutexHeld( db, 0, pSchema ) );
463 pOld = sqlite3HashInsert( ref pSchema.tblHash, zName, nName, pTab );
464 if ( pOld != null )
465 {
466 //db.mallocFailed = 1;
467 Debug.Assert( pTab == pOld ); /* Malloc must have failed inside HashInsert() */
468 return;
469 }
470 pParse.pNewTable = null;
471 }
472 }
473  
474 /*
475 ** The parser calls this routine when it sees the first token
476 ** of an argument to the module name in a CREATE VIRTUAL TABLE statement.
477 */
478 static void sqlite3VtabArgInit( Parse pParse )
479 {
480 addArgumentToVtab( pParse );
481 pParse.sArg.z = null;
482 pParse.sArg.n = 0;
483 }
484  
485 /*
486 ** The parser calls this routine for each token after the first token
487 ** in an argument to the module name in a CREATE VIRTUAL TABLE statement.
488 */
489 static void sqlite3VtabArgExtend( Parse pParse, Token p )
490 {
491 Token pArg = pParse.sArg;
492 if ( pArg.z == null )
493 {
494 pArg.z = p.z;
495 pArg.n = p.n;
496 }
497 else
498 {
499 //Debug.Assert( pArg.z< p.z );
500 pArg.n += p.n+1;//(int)( p.z[p.n] - pArg.z );
501 }
502 }
503  
504 /*
505 ** Invoke a virtual table constructor (either xCreate or xConnect). The
506 ** pointer to the function to invoke is passed as the fourth parameter
507 ** to this procedure.
508 */
509 static int vtabCallConstructor(
510 sqlite3 db,
511 Table pTab,
512 Module pMod,
513 smdxCreateConnect xConstruct,
514 ref string pzErr
515 )
516 {
517 VtabCtx sCtx = new VtabCtx();
518 VTable pVTable;
519 int rc;
520 string[] azArg = pTab.azModuleArg;
521 int nArg = pTab.nModuleArg;
522 string zErr = null;
523 string zModuleName = sqlite3MPrintf( db, "%s", pTab.zName );
524  
525 //if ( string.IsNullOrEmpty( zModuleName ) )
526 //{
527 // return SQLITE_NOMEM;
528 //}
529  
530 pVTable = new VTable();//sqlite3DbMallocZero( db, sizeof( VTable ) );
531 //if ( null == pVTable )
532 //{
533 // sqlite3DbFree( db, ref zModuleName );
534 // return SQLITE_NOMEM;
535 //}
536 pVTable.db = db;
537 pVTable.pMod = pMod;
538  
539 /* Invoke the virtual table constructor */
540 //assert( &db->pVtabCtx );
541 Debug.Assert( xConstruct != null );
542 sCtx.pTab = pTab;
543 sCtx.pVTable = pVTable;
544 db.pVtabCtx = sCtx;
545 rc = xConstruct( db, pMod.pAux, nArg, azArg, out pVTable.pVtab, out zErr );
546 db.pVtabCtx = null;
547 //if ( rc == SQLITE_NOMEM )
548 // db.mallocFailed = 1;
549  
550 if ( SQLITE_OK != rc )
551 {
552 if ( zErr.Length == 0 )
553 {
554 pzErr = sqlite3MPrintf( db, "vtable constructor failed: %s", zModuleName );
555 }
556 else
557 {
558 pzErr = sqlite3MPrintf( db, "%s", zErr );
559 zErr = null;//sqlite3_free( zErr );
560 }
561 sqlite3DbFree( db, ref pVTable );
562 }
563 else if ( ALWAYS( pVTable.pVtab ) )
564 {
565 /* Justification of ALWAYS(): A correct vtab constructor must allocate
566 ** the sqlite3_vtab object if successful. */
567 pVTable.pVtab.pModule = pMod.pModule;
568 pVTable.nRef = 1;
569 if ( sCtx.pTab != null )
570 {
571 string zFormat = "vtable constructor did not declare schema: %s";
572 pzErr = sqlite3MPrintf( db, zFormat, pTab.zName );
573 sqlite3VtabUnlock( pVTable );
574 rc = SQLITE_ERROR;
575 }
576 else
577 {
578 int iCol;
579 /* If everything went according to plan, link the new VTable structure
580 ** into the linked list headed by pTab->pVTable. Then loop through the
581 ** columns of the table to see if any of them contain the token "hidden".
582 ** If so, set the Column.isHidden flag and remove the token from
583 ** the type string. */
584 pVTable.pNext = pTab.pVTable;
585 pTab.pVTable = pVTable;
586  
587 for ( iCol = 0; iCol < pTab.nCol; iCol++ )
588 {
589 if ( string.IsNullOrEmpty( pTab.aCol[iCol].zType ) )
590 continue;
591 StringBuilder zType = new StringBuilder( pTab.aCol[iCol].zType);
592 int nType;
593 int i = 0;
594 //if ( zType )
595 // continue;
596 nType = sqlite3Strlen30( zType );
597 if ( sqlite3StrNICmp( "hidden", 0, zType.ToString(), 6 ) != 0 || ( zType.Length > 6 && zType[6] != ' ' ) )
598 {
599 for ( i = 0; i < nType; i++ )
600 {
601 if ( ( 0 == sqlite3StrNICmp( " hidden", zType.ToString().Substring( i ), 7 ) )
602 && ( i+7 == zType.Length || (zType[i + 7] == '\0' || zType[i + 7] == ' ' ))
603 )
604 {
605 i++;
606 break;
607 }
608 }
609 }
610 if ( i < nType )
611 {
612 int j;
613 int nDel = 6 + ( zType.Length > i + 6 ? 1 : 0 );
614 for ( j = i; ( j + nDel ) < nType; j++ )
615 {
616 zType[j] = zType[j + nDel];
617 }
618 if ( zType[i] == '\0' && i > 0 )
619 {
620 Debug.Assert( zType[i - 1] == ' ' );
621 zType.Length = i;//[i - 1] = '\0';
622 }
623 pTab.aCol[iCol].isHidden = 1;
624 pTab.aCol[iCol].zType = zType.ToString().Substring(0,j);
625 }
626 }
627 }
628 }
629  
630 sqlite3DbFree( db, ref zModuleName );
631 return rc;
632 }
633  
634 /*
635 ** This function is invoked by the parser to call the xConnect() method
636 ** of the virtual table pTab. If an error occurs, an error code is returned
637 ** and an error left in pParse.
638 **
639 ** This call is a no-op if table pTab is not a virtual table.
640 */
641 static int sqlite3VtabCallConnect( Parse pParse, Table pTab )
642 {
643 sqlite3 db = pParse.db;
644 string zMod;
645 Module pMod;
646 int rc;
647  
648 Debug.Assert( pTab != null);
649 if ( ( pTab.tabFlags & TF_Virtual ) == 0 || sqlite3GetVTable( db, pTab )!= null )
650 {
651 return SQLITE_OK;
652 }
653  
654 /* Locate the required virtual table module */
655 zMod = pTab.azModuleArg[0];
656 pMod = (Module)sqlite3HashFind( db.aModule, zMod, sqlite3Strlen30( zMod ), (Module)null );
657  
658 if ( null == pMod )
659 {
660 string zModule = pTab.azModuleArg[0];
661 sqlite3ErrorMsg( pParse, "no such module: %s", zModule );
662 rc = SQLITE_ERROR;
663 }
664 else
665 {
666 string zErr = null;
667 rc = vtabCallConstructor( db, pTab, pMod, pMod.pModule.xConnect, ref zErr );
668 if ( rc != SQLITE_OK )
669 {
670 sqlite3ErrorMsg( pParse, "%s", zErr );
671 }
672 zErr = null;//sqlite3DbFree( db, zErr );
673 }
674  
675 return rc;
676 }
677 /*
678 ** Grow the db.aVTrans[] array so that there is room for at least one
679 ** more v-table. Return SQLITE_NOMEM if a malloc fails, or SQLITE_OK otherwise.
680 */
681 static int growVTrans( sqlite3 db )
682 {
683 const int ARRAY_INCR = 5;
684  
685 /* Grow the sqlite3.aVTrans array if required */
686 if ( ( db.nVTrans % ARRAY_INCR ) == 0 )
687 {
688 //VTable** aVTrans;
689 //int nBytes = sizeof( sqlite3_vtab* ) * ( db.nVTrans + ARRAY_INCR );
690 //aVTrans = sqlite3DbRealloc( db, (void)db.aVTrans, nBytes );
691 //if ( !aVTrans )
692 //{
693 // return SQLITE_NOMEM;
694 //}
695 //memset( &aVTrans[db.nVTrans], 0, sizeof( sqlite3_vtab* ) * ARRAY_INCR );
696 Array.Resize( ref db.aVTrans, db.nVTrans + ARRAY_INCR );
697 }
698  
699 return SQLITE_OK;
700 }
701  
702 /*
703 ** Add the virtual table pVTab to the array sqlite3.aVTrans[]. Space should
704 ** have already been reserved using growVTrans().
705 */
706 static void addToVTrans( sqlite3 db, VTable pVTab )
707 {
708 /* Add pVtab to the end of sqlite3.aVTrans */
709 db.aVTrans[db.nVTrans++] = pVTab;
710 sqlite3VtabLock( pVTab );
711 }
712  
713 /*
714 ** This function is invoked by the vdbe to call the xCreate method
715 ** of the virtual table named zTab in database iDb.
716 **
717 ** If an error occurs, *pzErr is set to point an an English language
718 ** description of the error and an SQLITE_XXX error code is returned.
719 ** In this case the caller must call sqlite3DbFree(db, ) on *pzErr.
720 */
721 static int sqlite3VtabCallCreate( sqlite3 db, int iDb, string zTab, ref string pzErr )
722 {
723 int rc = SQLITE_OK;
724 Table pTab;
725 Module pMod;
726 string zMod;
727  
728 pTab = sqlite3FindTable( db, zTab, db.aDb[iDb].zName );
729 Debug.Assert( pTab != null && ( pTab.tabFlags & TF_Virtual ) != 0 && null == pTab.pVTable );
730  
731 /* Locate the required virtual table module */
732 zMod = pTab.azModuleArg[0];
733 pMod = (Module)sqlite3HashFind( db.aModule, zMod, sqlite3Strlen30( zMod ), (Module)null );
734  
735 /* If the module has been registered and includes a Create method,
736 ** invoke it now. If the module has not been registered, return an
737 ** error. Otherwise, do nothing.
738 */
739 if ( null == pMod )
740 {
741 pzErr = sqlite3MPrintf( db, "no such module: %s", zMod );
742 rc = SQLITE_ERROR;
743 }
744 else
745 {
746 rc = vtabCallConstructor( db, pTab, pMod, pMod.pModule.xCreate, ref pzErr );
747 }
748  
749 /* Justification of ALWAYS(): The xConstructor method is required to
750 ** create a valid sqlite3_vtab if it returns SQLITE_OK. */
751 if ( rc == SQLITE_OK && ALWAYS( sqlite3GetVTable( db, pTab ) ) )
752 {
753 rc = growVTrans( db );
754 if ( rc == SQLITE_OK )
755 {
756 addToVTrans( db, sqlite3GetVTable( db, pTab ) );
757 }
758 }
759  
760 return rc;
761 }
762  
763 /*
764 ** This function is used to set the schema of a virtual table. It is only
765 ** valid to call this function from within the xCreate() or xConnect() of a
766 ** virtual table module.
767 */
768 static int sqlite3_declare_vtab( sqlite3 db, string zCreateTable )
769 {
770 Parse pParse;
771  
772 int rc = SQLITE_OK;
773 Table pTab;
774 string zErr = string.Empty;
775  
776 sqlite3_mutex_enter( db.mutex );
777 if ( null == db.pVtabCtx || null == ( pTab = db.pVtabCtx.pTab ) )
778 {
779 sqlite3Error( db, SQLITE_MISUSE, 0 );
780 sqlite3_mutex_leave( db.mutex );
781 return SQLITE_MISUSE_BKPT();
782 }
783 Debug.Assert( ( pTab.tabFlags & TF_Virtual ) != 0 );
784  
785 pParse = new Parse();//sqlite3StackAllocZero(db, sizeof(*pParse));
786 //if ( pParse == null )
787 //{
788 // rc = SQLITE_NOMEM;
789 //}
790 //else
791 {
792 pParse.declareVtab = 1;
793 pParse.db = db;
794 pParse.nQueryLoop = 1;
795  
796 if ( SQLITE_OK == sqlite3RunParser( pParse, zCreateTable, ref zErr )
797 && pParse.pNewTable != null
798 //&& !db.mallocFailed
799 && null==pParse.pNewTable.pSelect
800 && ( pParse.pNewTable.tabFlags & TF_Virtual ) == 0
801 )
802 {
803 if ( null==pTab.aCol )
804 {
805 pTab.aCol = pParse.pNewTable.aCol;
806 pTab.nCol = pParse.pNewTable.nCol;
807 pParse.pNewTable.nCol = 0;
808 pParse.pNewTable.aCol = null;
809 }
810 db.pVtabCtx.pTab = null;
811 }
812 else
813 {
814 sqlite3Error( db, SQLITE_ERROR, ( zErr != null ? "%s" : null ), zErr );
815 zErr = null;//sqlite3DbFree( db, zErr );
816 rc = SQLITE_ERROR;
817 }
818 pParse.declareVtab = 0;
819  
820 if ( pParse.pVdbe !=null)
821 {
822 sqlite3VdbeFinalize( ref pParse.pVdbe );
823 }
824 sqlite3DeleteTable( db, ref pParse.pNewTable );
825 //sqlite3StackFree( db, pParse );
826 }
827  
828 Debug.Assert( ( rc & 0xff ) == rc );
829 rc = sqlite3ApiExit( db, rc );
830 sqlite3_mutex_leave( db.mutex );
831 return rc;
832 }
833  
834 /*
835 ** This function is invoked by the vdbe to call the xDestroy method
836 ** of the virtual table named zTab in database iDb. This occurs
837 ** when a DROP TABLE is mentioned.
838 **
839 ** This call is a no-op if zTab is not a virtual table.
840 */
841 static int sqlite3VtabCallDestroy( sqlite3 db, int iDb, string zTab )
842 {
843 int rc = SQLITE_OK;
844 Table pTab;
845  
846 pTab = sqlite3FindTable( db, zTab, db.aDb[iDb].zName );
847 if ( ALWAYS( pTab != null && pTab.pVTable != null ) )
848 {
849 VTable p = vtabDisconnectAll( db, pTab );
850  
851 Debug.Assert( rc == SQLITE_OK );
852 object obj = p.pVtab;
853 rc = p.pMod.pModule.xDestroy( ref obj );
854 p.pVtab = null;
855  
856 /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
857 if ( rc == SQLITE_OK )
858 {
859 Debug.Assert( pTab.pVTable == p && p.pNext == null );
860 p.pVtab = null;
861 pTab.pVTable = null;
862 sqlite3VtabUnlock( p );
863 }
864 }
865  
866 return rc;
867 }
868  
869 /*
870 ** This function invokes either the xRollback or xCommit method
871 ** of each of the virtual tables in the sqlite3.aVTrans array. The method
872 ** called is identified by the second argument, "offset", which is
873 ** the offset of the method to call in the sqlite3_module structure.
874 **
875 ** The array is cleared after invoking the callbacks.
876 */
877 static void callFinaliser( sqlite3 db, int offset )
878 {
879 int i;
880 if ( db.aVTrans != null )
881 {
882 for ( i = 0; i < db.nVTrans; i++ )
883 {
884 VTable pVTab = db.aVTrans[i];
885 sqlite3_vtab p = pVTab.pVtab;
886 if ( p != null )
887 {
888 //int (*x)(sqlite3_vtab );
889 //x = *(int (*)(sqlite3_vtab ))((char )p.pModule + offset);
890 //if( x ) x(p);
891 if ( offset == 0 )
892 {
893 if ( p.pModule.xCommit != null )
894 p.pModule.xCommit( p );
895 }
896 else
897 {
898 if ( p.pModule.xRollback != null )
899 p.pModule.xRollback( p );
900 }
901 }
902 pVTab.iSavepoint = 0;
903 sqlite3VtabUnlock( pVTab );
904 }
905 sqlite3DbFree( db, ref db.aVTrans );
906 db.nVTrans = 0;
907 db.aVTrans = null;
908 }
909 }
910  
911 /*
912 ** Invoke the xSync method of all virtual tables in the sqlite3.aVTrans
913 ** array. Return the error code for the first error that occurs, or
914 ** SQLITE_OK if all xSync operations are successful.
915 **
916 ** Set *pzErrmsg to point to a buffer that should be released using
917 ** sqlite3DbFree() containing an error message, if one is available.
918 */
919 static int sqlite3VtabSync( sqlite3 db, ref string pzErrmsg )
920 {
921 int i;
922 int rc = SQLITE_OK;
923 VTable[] aVTrans = db.aVTrans;
924  
925 db.aVTrans = null;
926 for ( i = 0; rc == SQLITE_OK && i < db.nVTrans; i++ )
927 {
928 smdxFunction x;//int (*x)(sqlite3_vtab );
929 sqlite3_vtab pVtab = aVTrans[i].pVtab;
930 if ( pVtab != null && ( x = pVtab.pModule.xSync ) != null )
931 {
932 rc = x( pVtab );
933 //sqlite3DbFree(db, ref pzErrmsg);
934 pzErrmsg = pVtab.zErrMsg;// sqlite3DbStrDup( db, pVtab.zErrMsg );
935 pVtab.zErrMsg = null;//sqlite3_free( ref pVtab.zErrMsg );
936 }
937 }
938 db.aVTrans = aVTrans;
939 return rc;
940 }
941  
942 /*
943 ** Invoke the xRollback method of all virtual tables in the
944 ** sqlite3.aVTrans array. Then clear the array itself.
945 */
946 static int sqlite3VtabRollback( sqlite3 db )
947 {
948 callFinaliser( db, 1 );//offsetof( sqlite3_module, xRollback ) );
949 return SQLITE_OK;
950 }
951  
952 /*
953 ** Invoke the xCommit method of all virtual tables in the
954 ** sqlite3.aVTrans array. Then clear the array itself.
955 */
956 static int sqlite3VtabCommit( sqlite3 db )
957 {
958 callFinaliser( db, 0 );//offsetof( sqlite3_module, xCommit ) );
959 return SQLITE_OK;
960 }
961  
962 /*
963 ** If the virtual table pVtab supports the transaction interface
964 ** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is
965 ** not currently open, invoke the xBegin method now.
966 **
967 ** If the xBegin call is successful, place the sqlite3_vtab pointer
968 ** in the sqlite3.aVTrans array.
969 */
970 static int sqlite3VtabBegin( sqlite3 db, VTable pVTab )
971 {
972 int rc = SQLITE_OK;
973 sqlite3_module pModule;
974  
975 /* Special case: If db.aVTrans is NULL and db.nVTrans is greater
976 ** than zero, then this function is being called from within a
977 ** virtual module xSync() callback. It is illegal to write to
978 ** virtual module tables in this case, so return SQLITE_LOCKED.
979 */
980 if ( sqlite3VtabInSync( db ) )
981 {
982 return SQLITE_LOCKED;
983 }
984 if ( null == pVTab )
985 {
986 return SQLITE_OK;
987 }
988 pModule = pVTab.pVtab.pModule;
989  
990 if ( pModule.xBegin != null )
991 {
992 int i;
993  
994 /* If pVtab is already in the aVTrans array, return early */
995 for ( i = 0; i < db.nVTrans; i++ )
996 {
997 if ( db.aVTrans[i] == pVTab )
998 {
999 return SQLITE_OK;
1000 }
1001 }
1002  
1003 /* Invoke the xBegin method. If successful, add the vtab to the
1004 ** sqlite3.aVTrans[] array. */
1005 rc = growVTrans( db );
1006 if ( rc == SQLITE_OK )
1007 {
1008 rc = pModule.xBegin( pVTab.pVtab );
1009 if ( rc == SQLITE_OK )
1010 {
1011 addToVTrans( db, pVTab );
1012 }
1013 }
1014 }
1015 return rc;
1016 }
1017  
1018 /*
1019 ** Invoke either the xSavepoint, xRollbackTo or xRelease method of all
1020 ** virtual tables that currently have an open transaction. Pass iSavepoint
1021 ** as the second argument to the virtual table method invoked.
1022 **
1023 ** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is
1024 ** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is
1025 ** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with
1026 ** an open transaction is invoked.
1027 **
1028 ** If any virtual table method returns an error code other than SQLITE_OK,
1029 ** processing is abandoned and the error returned to the caller of this
1030 ** function immediately. If all calls to virtual table methods are successful,
1031 ** SQLITE_OK is returned.
1032 */
1033 static int sqlite3VtabSavepoint( sqlite3 db, int op, int iSavepoint )
1034 {
1035 int rc = SQLITE_OK;
1036  
1037 Debug.Assert( op == SAVEPOINT_RELEASE || op == SAVEPOINT_ROLLBACK || op == SAVEPOINT_BEGIN );
1038 Debug.Assert( iSavepoint >= 0 );
1039 if ( db.aVTrans != null )
1040 {
1041 int i;
1042 for ( i = 0; rc == SQLITE_OK && i < db.nVTrans; i++ )
1043 {
1044 VTable pVTab = db.aVTrans[i];
1045 sqlite3_module pMod = pVTab.pMod.pModule;
1046 if ( pMod.iVersion >= 2 )
1047 {
1048 smdxFunctionArg xMethod = null; //int (*xMethod)(sqlite3_vtab *, int);
1049 switch ( op )
1050 {
1051 case SAVEPOINT_BEGIN:
1052 xMethod = pMod.xSavepoint;
1053 pVTab.iSavepoint = iSavepoint + 1;
1054 break;
1055 case SAVEPOINT_ROLLBACK:
1056 xMethod = pMod.xRollbackTo;
1057 break;
1058 default:
1059 xMethod = pMod.xRelease;
1060 break;
1061 }
1062 if ( xMethod != null && pVTab.iSavepoint > iSavepoint )
1063 {
1064 rc = xMethod( db.aVTrans[i].pVtab, iSavepoint );
1065 }
1066 }
1067 }
1068 }
1069 return rc;
1070 }
1071  
1072 /*
1073 ** The first parameter (pDef) is a function implementation. The
1074 ** second parameter (pExpr) is the first argument to this function.
1075 ** If pExpr is a column in a virtual table, then let the virtual
1076 ** table implementation have an opportunity to overload the function.
1077 **
1078 ** This routine is used to allow virtual table implementations to
1079 ** overload MATCH, LIKE, GLOB, and REGEXP operators.
1080 **
1081 ** Return either the pDef argument (indicating no change) or a
1082 ** new FuncDef structure that is marked as ephemeral using the
1083 ** SQLITE_FUNC_EPHEM flag.
1084 */
1085 static FuncDef sqlite3VtabOverloadFunction(
1086 sqlite3 db, /* Database connection for reporting malloc problems */
1087 FuncDef pDef, /* Function to possibly overload */
1088 int nArg, /* Number of arguments to the function */
1089 Expr pExpr /* First argument to the function */
1090 )
1091 {
1092 Table pTab;
1093 sqlite3_vtab pVtab;
1094 sqlite3_module pMod;
1095 dxFunc xFunc = null;//void (*xFunc)(sqlite3_context*,int,sqlite3_value*) = 0;
1096 object pArg = null;
1097 FuncDef pNew;
1098 int rc = 0;
1099 string zLowerName;
1100 string z;
1101  
1102 /* Check to see the left operand is a column in a virtual table */
1103 if ( NEVER( pExpr == null ) )
1104 return pDef;
1105 if ( pExpr.op != TK_COLUMN )
1106 return pDef;
1107 pTab = pExpr.pTab;
1108 if ( NEVER( pTab == null ) )
1109 return pDef;
1110 if ( ( pTab.tabFlags & TF_Virtual ) == 0 )
1111 return pDef;
1112 pVtab = sqlite3GetVTable( db, pTab ).pVtab;
1113 Debug.Assert( pVtab != null );
1114 Debug.Assert( pVtab.pModule != null );
1115 pMod = (sqlite3_module)pVtab.pModule;
1116 if ( pMod.xFindFunction == null )
1117 return pDef;
1118  
1119 /* Call the xFindFunction method on the virtual table implementation
1120 ** to see if the implementation wants to overload this function
1121 */
1122 zLowerName = pDef.zName;//sqlite3DbStrDup(db, pDef.zName);
1123 if ( zLowerName != null )
1124 {
1125 //for(z=(unsigned char)zLowerName; *z; z++){
1126 // *z = sqlite3UpperToLower[*z];
1127 //}
1128 rc = pMod.xFindFunction( pVtab, nArg, zLowerName.ToLowerInvariant(), ref xFunc, ref pArg );
1129 sqlite3DbFree( db, ref zLowerName );
1130 }
1131 if ( rc == 0 )
1132 {
1133 return pDef;
1134 }
1135  
1136 /* Create a new ephemeral function definition for the overloaded
1137 ** function */
1138 //sqlite3DbMallocZero(db, sizeof(*pNew)
1139 // + sqlite3Strlen30(pDef.zName) + 1);
1140 //if ( pNew == null )
1141 //{
1142 // return pDef;
1143 //}
1144 pNew = pDef.Copy();
1145 pNew.zName = pDef.zName;
1146 //pNew.zName = (char )&pNew[1];
1147 //memcpy(pNew.zName, pDef.zName, sqlite3Strlen30(pDef.zName)+1);
1148 pNew.xFunc = xFunc;
1149 pNew.pUserData = pArg;
1150 pNew.flags |= SQLITE_FUNC_EPHEM;
1151 return pNew;
1152 }
1153  
1154 /*
1155 ** Make sure virtual table pTab is contained in the pParse.apVirtualLock[]
1156 ** array so that an OP_VBegin will get generated for it. Add pTab to the
1157 ** array if it is missing. If pTab is already in the array, this routine
1158 ** is a no-op.
1159 */
1160 static void sqlite3VtabMakeWritable( Parse pParse, Table pTab )
1161 {
1162 Parse pToplevel = sqlite3ParseToplevel( pParse );
1163 int i, n;
1164 //Table[] apVtabLock = null;
1165  
1166 Debug.Assert( IsVirtual( pTab ) );
1167 for ( i = 0; i < pToplevel.nVtabLock; i++ )
1168 {
1169 if ( pTab == pToplevel.apVtabLock[i] )
1170 return;
1171 }
1172 n = pToplevel.apVtabLock == null ? 1 : pToplevel.apVtabLock.Length + 1;//(pToplevel.nVtabLock+1)*sizeof(pToplevel.apVtabLock[0]);
1173 //sqlite3_realloc( pToplevel.apVtabLock, n );
1174 //if ( apVtabLock != null )
1175 {
1176 Array.Resize( ref pToplevel.apVtabLock, n );// pToplevel.apVtabLock= apVtabLock;
1177 pToplevel.apVtabLock[pToplevel.nVtabLock++] = pTab;
1178 }
1179 //else
1180 //{
1181 // pToplevel.db.mallocFailed = 1;
1182 //}
1183 }
1184  
1185 static int[] aMap = new int[] {
1186 SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
1187 };
1188 /*
1189 ** Return the ON CONFLICT resolution mode in effect for the virtual
1190 ** table update operation currently in progress.
1191 **
1192 ** The results of this routine are undefined unless it is called from
1193 ** within an xUpdate method.
1194 */
1195 static int sqlite3_vtab_on_conflict( sqlite3 db ){
1196 //static const unsigned char aMap[] = {
1197 // SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
1198 //};
1199 Debug.Assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 );
1200 Debug.Assert( OE_Ignore==4 && OE_Replace==5 );
1201 Debug.Assert( db.vtabOnConflict>=1 && db.vtabOnConflict<=5 );
1202 return (int)aMap[db.vtabOnConflict-1];
1203 }
1204  
1205 /*
1206 ** Call from within the xCreate() or xConnect() methods to provide
1207 ** the SQLite core with additional information about the behavior
1208 ** of the virtual table being implemented.
1209 */
1210 static int sqlite3_vtab_config( sqlite3 db, int op, params object[] ap ){ // TODO ...){
1211 //va_list ap;
1212 int rc = SQLITE_OK;
1213  
1214 sqlite3_mutex_enter(db.mutex);
1215  
1216 va_start(ap, "op");
1217 switch( op ){
1218 case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
1219 VtabCtx p = db.pVtabCtx;
1220 if( null == p ){
1221 rc = SQLITE_MISUSE_BKPT();
1222 }else{
1223 Debug.Assert( p.pTab == null || ( p.pTab.tabFlags & TF_Virtual ) != 0 );
1224 p.pVTable.bConstraint = (Byte)va_arg(ap, (Int32)0);
1225 }
1226 break;
1227 }
1228 default:
1229 rc = SQLITE_MISUSE_BKPT();
1230 break;
1231 }
1232 va_end(ref ap);
1233  
1234 if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0);
1235 sqlite3_mutex_leave(db.mutex);
1236 return rc;
1237 }
1238  
1239 #endif //* SQLITE_OMIT_VIRTUALTABLE */
1240 }
1241 }