PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/testfixture/src/tclsqlite_c.cs

https://bitbucket.org/eumario/csharp-sqlite
C# | 4427 lines | 2980 code | 291 blank | 1156 comment | 628 complexity | 25533ef33e9a5de69148b1e48b9509b1 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. using System;
  2. using System.Diagnostics;
  3. using sqlite_int64 = System.Int64;
  4. using sqlite_u3264 = System.UInt64;
  5. using u32 = System.UInt32;
  6. namespace Community.CsharpSqlite
  7. {
  8. #if TCLSH
  9. using tcl.lang;
  10. using ClientData = System.Object;
  11. #if !SQLITE_OMIT_INCRBLOB
  12. using sqlite3_blob = sqlite.Incrblob;
  13. #endif
  14. using sqlite3_stmt = Sqlite3.Vdbe;
  15. using Tcl_DString = tcl.lang.TclString;
  16. using Tcl_Interp = tcl.lang.Interp;
  17. using Tcl_Obj = tcl.lang.TclObject;
  18. using Tcl_WideInt = System.Int64;
  19. using sqlite3_value = Sqlite3.Mem;
  20. using System.IO;
  21. using System.Text;
  22. public partial class Sqlite3
  23. {
  24. /*
  25. ** 2001 September 15
  26. **
  27. ** The author disclaims copyright to this source code. In place of
  28. ** a legal notice, here is a blessing:
  29. **
  30. ** May you do good and not evil.
  31. ** May you find forgiveness for yourself and forgive others.
  32. ** May you share freely, never taking more than you give.
  33. **
  34. *************************************************************************
  35. ** A TCL Interface to SQLite. Append this file to sqlite3.c and
  36. ** compile the whole thing to build a TCL-enabled version of SQLite.
  37. **
  38. ** Compile-time options:
  39. **
  40. ** -DTCLSH=1 Add a "main()" routine that works as a tclsh.
  41. **
  42. ** -DSQLITE_TCLMD5 When used in conjuction with -DTCLSH=1, add
  43. ** four new commands to the TCL interpreter for
  44. ** generating MD5 checksums: md5, md5file,
  45. ** md5-10x8, and md5file-10x8.
  46. **
  47. ** -DSQLITE_TEST When used in conjuction with -DTCLSH=1, add
  48. ** hundreds of new commands used for testing
  49. ** SQLite. This option implies -DSQLITE_TCLMD5.
  50. *************************************************************************
  51. ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
  52. ** C#-SQLite is an independent reimplementation of the SQLite software library
  53. **
  54. ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
  55. **
  56. *************************************************************************
  57. */
  58. //#include "tcl.h"
  59. //#include <errno.h>
  60. /*
  61. ** Some additional include files are needed if this file is not
  62. ** appended to the amalgamation.
  63. */
  64. #if !SQLITE_AMALGAMATION
  65. //# include "sqlite3.h"
  66. //# include <stdlib.h>
  67. //# include <string.h>
  68. //# include <Debug.Assert.h>
  69. // typedef unsigned char u8;
  70. #endif
  71. /*
  72. * Windows needs to know which symbols to export. Unix does not.
  73. * BUILD_sqlite should be undefined for Unix.
  74. */
  75. #if BUILD_sqlite
  76. //#undef TCL.Tcl_STORAGE_CLASS
  77. //#define TCL.Tcl_STORAGE_CLASS DLLEXPORT
  78. #endif // * BUILD_sqlite */
  79. const int NUM_PREPARED_STMTS = 10;//#define NUM_PREPARED_STMTS 10
  80. const int MAX_PREPARED_STMTS = 100;//#define MAX_PREPARED_STMTS 100
  81. /*
  82. ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
  83. ** have to do a translation when going between the two. Set the
  84. ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do
  85. ** this translation.
  86. */
  87. #if Tcl_UTF_MAX && !SQLITE_UTF8
  88. //# define UTF_TRANSLATION_NEEDED 1
  89. #endif
  90. /*
  91. ** New SQL functions can be created as TCL scripts. Each such function
  92. ** is described by an instance of the following structure.
  93. */
  94. //typedef struct SqlFunc SqlFunc;
  95. public class SqlFunc
  96. {
  97. public Tcl_Interp interp; /* The TCL interpret to execute the function */
  98. public Tcl_Obj pScript; /* The Tcl_Obj representation of the script */
  99. public int useEvalObjv; /* True if it is safe to use TCL.Tcl_EvalObjv */
  100. public string zName; /* Name of this function */
  101. public SqlFunc pNext; /* Next function on the list of them all */
  102. }
  103. /*
  104. ** New collation sequences function can be created as TCL scripts. Each such
  105. ** function is described by an instance of the following structure.
  106. */
  107. //typedef struct SqlCollate SqlCollate;
  108. public class SqlCollate
  109. {
  110. public Tcl_Interp interp; /* The TCL interpret to execute the function */
  111. public string zScript; /* The script to be run */
  112. public SqlCollate pNext; /* Next function on the list of them all */
  113. }
  114. /*
  115. ** Prepared statements are cached for faster execution. Each prepared
  116. ** statement is described by an instance of the following structure.
  117. */
  118. //typedef struct SqlPreparedStmt SqlPreparedStmt;
  119. public class SqlPreparedStmt
  120. {
  121. public SqlPreparedStmt pNext; /* Next in linked list */
  122. public SqlPreparedStmt pPrev; /* Previous on the list */
  123. public sqlite3_stmt pStmt; /* The prepared statement */
  124. public Mem[] aMem; /* Original Memory Values to be reused */
  125. public int nSql; /* chars in zSql[] */
  126. public string zSql; /* Text of the SQL statement */
  127. public int nParm; /* Size of apParm array */
  128. public Tcl_Obj[] apParm; /* Array of referenced object pointers */
  129. }
  130. //typedef struct IncrblobChannel IncrblobChannel;
  131. /*
  132. ** There is one instance of this structure for each SQLite database
  133. ** that has been opened by the SQLite TCL interface.
  134. */
  135. //typedef struct SqliteDb SqliteDb;
  136. public class SqliteDb : object
  137. {
  138. public sqlite3 db; /* The "real" database structure. MUST BE FIRST */
  139. public Tcl_Interp interp; /* The interpreter used for this database */
  140. public string zBusy; /* The busy callback routine */
  141. public string zCommit; /* The commit hook callback routine */
  142. public string zTrace; /* The trace callback routine */
  143. public string zProfile; /* The profile callback routine */
  144. public string zProgress; /* The progress callback routine */
  145. public string zAuth; /* The authorization callback routine */
  146. public int disableAuth; /* Disable the authorizer if it exists */
  147. public string zNull = ""; /* Text to substitute for an SQL NULL value */
  148. public SqlFunc pFunc; /* List of SQL functions */
  149. public Tcl_Obj pUpdateHook; /* Update hook script (if any) */
  150. public Tcl_Obj pRollbackHook; /* Rollback hook script (if any) */
  151. public Tcl_Obj pWalHook; /* WAL hook script (if any) */
  152. public Tcl_Obj pUnlockNotify; /* Unlock notify script (if any) */
  153. public SqlCollate pCollate; /* List of SQL collation functions */
  154. public int rc; /* Return code of most recent sqlite3_exec() */
  155. public Tcl_Obj pCollateNeeded; /* Collation needed script */
  156. public SqlPreparedStmt stmtList; /* List of prepared statements*/
  157. public SqlPreparedStmt stmtLast; /* Last statement in the list */
  158. public int maxStmt; /* The next maximum number of stmtList */
  159. public int nStmt; /* Number of statements in stmtList */
  160. #if !SQLITE_OMIT_INCRBLOB
  161. public IncrblobChannel pIncrblob; /* Linked list of open incrblob channels */
  162. #endif
  163. public int nStep, nSort, nIndex; /* Statistics for most recent operation */
  164. public int nTransaction; /* Number of nested [transaction] methods */
  165. }
  166. #if !SQLITE_OMIT_INCRBLOB
  167. class IncrblobChannel
  168. {
  169. public sqlite3_blob pBlob; /* sqlite3 blob handle */
  170. public SqliteDb pDb; /* Associated database connection */
  171. public int iSeek; /* Current seek offset */
  172. public Tcl_Channel channel; /* Channel identifier */
  173. public IncrblobChannel pNext; /* Linked list of all open incrblob channels */
  174. public IncrblobChannel pPrev; /* Linked list of all open incrblob channels */
  175. }
  176. #endif
  177. /*
  178. ** Compute a string length that is limited to what can be stored in
  179. ** lower 30 bits of a 32-bit signed integer.
  180. */
  181. static int strlen30( StringBuilder z )
  182. {
  183. //string z2 = z;
  184. //while( *z2 ){ z2++; }
  185. return 0x3fffffff & z.Length;
  186. }
  187. static int strlen30( string z )
  188. {
  189. //string z2 = z;
  190. //while( *z2 ){ z2++; }
  191. return 0x3fffffff & z.Length;
  192. }
  193. #if !SQLITE_OMIT_INCRBLOB
  194. /*
  195. ** Close all incrblob channels opened using database connection pDb.
  196. ** This is called when shutting down the database connection.
  197. */
  198. static void closeIncrblobChannels( SqliteDb pDb )
  199. {
  200. IncrblobChannel p;
  201. IncrblobChannel pNext;
  202. for ( p = pDb.pIncrblob ; p != null ; p = pNext )
  203. {
  204. pNext = p.pNext;
  205. /* Note: Calling unregister here call TCL.Tcl_Close on the incrblob channel,
  206. ** which deletes the IncrblobChannel structure at p. So do not
  207. ** call TCL.Tcl_Free() here.
  208. */
  209. TCL.Tcl_UnregisterChannel( pDb.interp, p.channel );
  210. }
  211. }
  212. /*
  213. ** Close an incremental blob channel.
  214. */
  215. //static int incrblobClose(object instanceData, Tcl_Interp interp){
  216. // IncrblobChannel p = (IncrblobChannel )instanceData;
  217. // int rc = sqlite3_blob_close(p.pBlob);
  218. // sqlite3 db = p.pDb.db;
  219. // /* Remove the channel from the SqliteDb.pIncrblob list. */
  220. // if( p.pNext ){
  221. // p.pNext.pPrev = p.pPrev;
  222. // }
  223. // if( p.pPrev ){
  224. // p.pPrev.pNext = p.pNext;
  225. // }
  226. // if( p.pDb.pIncrblob==p ){
  227. // p.pDb.pIncrblob = p.pNext;
  228. // }
  229. // /* Free the IncrblobChannel structure */
  230. // TCL.Tcl_Free((char )p);
  231. // if( rc!=SQLITE_OK ){
  232. // TCL.Tcl_SetResult(interp, (char )sqlite3_errmsg(db), TCL.Tcl_VOLATILE);
  233. // return TCL.TCL_ERROR;
  234. // }
  235. // return TCL.TCL_OK;
  236. //}
  237. /*
  238. ** Read data from an incremental blob channel.
  239. */
  240. //static int incrblobInput(
  241. // object instanceData,
  242. // char *buf,
  243. // int bufSize,
  244. // int *errorCodePtr
  245. //){
  246. // IncrblobChannel p = (IncrblobChannel )instanceData;
  247. // int nRead = bufSize; /* Number of bytes to read */
  248. // int nBlob; /* Total size of the blob */
  249. // int rc; /* sqlite error code */
  250. // nBlob = sqlite3_blob_bytes(p.pBlob);
  251. // if( (p.iSeek+nRead)>nBlob ){
  252. // nRead = nBlob-p.iSeek;
  253. // }
  254. // if( nRead<=0 ){
  255. // return 0;
  256. // }
  257. // rc = sqlite3_blob_read(p.pBlob, (void )buf, nRead, p.iSeek);
  258. // if( rc!=SQLITE_OK ){
  259. // *errorCodePtr = rc;
  260. // return -1;
  261. // }
  262. // p.iSeek += nRead;
  263. // return nRead;
  264. //}
  265. /*
  266. ** Write data to an incremental blob channel.
  267. */
  268. //static int incrblobOutput(
  269. // object instanceData,
  270. // string buf,
  271. // int toWrite,
  272. // int *errorCodePtr
  273. //){
  274. // IncrblobChannel p = (IncrblobChannel )instanceData;
  275. // int nWrite = toWrite; /* Number of bytes to write */
  276. // int nBlob; /* Total size of the blob */
  277. // int rc; /* sqlite error code */
  278. // nBlob = sqlite3_blob_bytes(p.pBlob);
  279. // if( (p.iSeek+nWrite)>nBlob ){
  280. // *errorCodePtr = EINVAL;
  281. // return -1;
  282. // }
  283. // if( nWrite<=0 ){
  284. // return 0;
  285. // }
  286. // rc = sqlite3_blob_write(p.pBlob, (void )buf, nWrite, p.iSeek);
  287. // if( rc!=SQLITE_OK ){
  288. // *errorCodePtr = EIO;
  289. // return -1;
  290. // }
  291. // p.iSeek += nWrite;
  292. // return nWrite;
  293. //}
  294. /*
  295. ** Seek an incremental blob channel.
  296. */
  297. //static int incrblobSeek(
  298. // object instanceData,
  299. // long offset,
  300. // int seekMode,
  301. // int *errorCodePtr
  302. //){
  303. // IncrblobChannel p = (IncrblobChannel )instanceData;
  304. // switch( seekMode ){
  305. // case SEEK_SET:
  306. // p.iSeek = offset;
  307. // break;
  308. // case SEEK_CUR:
  309. // p.iSeek += offset;
  310. // break;
  311. // case SEEK_END:
  312. // p.iSeek = sqlite3_blob_bytes(p.pBlob) + offset;
  313. // break;
  314. // default: Debug.Assert(!"Bad seekMode");
  315. // }
  316. // return p.iSeek;
  317. //}
  318. //static void incrblobWatch(object instanceData, int mode){
  319. // /* NO-OP */
  320. //}
  321. //static int incrblobHandle(object instanceData, int dir, object *hPtr){
  322. // return TCL.TCL_ERROR;
  323. //}
  324. static TCL.Tcl_ChannelType IncrblobChannelType = {
  325. "incrblob", /* typeName */
  326. TCL.Tcl_CHANNEL_VERSION_2, /* version */
  327. incrblobClose, /* closeProc */
  328. incrblobInput, /* inputProc */
  329. incrblobOutput, /* outputProc */
  330. incrblobSeek, /* seekProc */
  331. 0, /* setOptionProc */
  332. 0, /* getOptionProc */
  333. incrblobWatch, /* watchProc (this is a no-op) */
  334. incrblobHandle, /* getHandleProc (always returns error) */
  335. 0, /* close2Proc */
  336. 0, /* blockModeProc */
  337. 0, /* flushProc */
  338. 0, /* handlerProc */
  339. 0, /* wideSeekProc */
  340. };
  341. /*
  342. ** Create a new incrblob channel.
  343. */
  344. static int count = 0;
  345. static int createIncrblobChannel(
  346. Tcl_Interp interp,
  347. SqliteDb pDb,
  348. string zDb,
  349. string zTable,
  350. string zColumn,
  351. sqlite_int64 iRow,
  352. int isReadonly
  353. ){
  354. IncrblobChannel p;
  355. sqlite3 db = pDb.db;
  356. sqlite3_blob pBlob;
  357. int rc;
  358. int flags = TCL.Tcl_READABLE|(isReadonly ? 0 : TCL.Tcl_WRITABLE);
  359. /* This variable is used to name the channels: "incrblob_[incr count]" */
  360. //static int count = 0;
  361. string zChannel = "";//string[64];
  362. rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, pBlob);
  363. if( rc!=SQLITE_OK ){
  364. TCL.Tcl_SetResult(interp, sqlite3_errmsg(pDb.db), TCL.Tcl_VOLATILE);
  365. return TCL.TCL_ERROR;
  366. }
  367. p = new IncrblobChannel();//(IncrblobChannel )Tcl_Alloc(sizeof(IncrblobChannel));
  368. p.iSeek = 0;
  369. p.pBlob = pBlob;
  370. sqlite3_snprintf(64, zChannel, "incrblob_%d", ++count);
  371. p.channel = TCL.Tcl_CreateChannel(IncrblobChannelType, zChannel, p, flags);
  372. TCL.Tcl_RegisterChannel(interp, p.channel);
  373. /* Link the new channel into the SqliteDb.pIncrblob list. */
  374. p.pNext = pDb.pIncrblob;
  375. p.pPrev = null;
  376. if( p.pNext!=null ){
  377. p.pNext.pPrev = p;
  378. }
  379. pDb.pIncrblob = p;
  380. p.pDb = pDb;
  381. TCL.Tcl_SetResult(interp, Tcl_GetChannelName(p.channel), TCL.Tcl_VOLATILE);
  382. return TCL.TCL_OK;
  383. }
  384. #else // * else clause for "#if !SQLITE_OMIT_INCRBLOB" */
  385. //#define closeIncrblobChannels(pDb)
  386. static void closeIncrblobChannels( SqliteDb pDb )
  387. {
  388. }
  389. #endif
  390. /*
  391. ** Look at the script prefix in pCmd. We will be executing this script
  392. ** after first appending one or more arguments. This routine analyzes
  393. ** the script to see if it is safe to use TCL.Tcl_EvalObjv() on the script
  394. ** rather than the more general TCL.Tcl_EvalEx(). TCL.Tcl_EvalObjv() is much
  395. ** faster.
  396. **
  397. ** Scripts that are safe to use with TCL.Tcl_EvalObjv() consists of a
  398. ** command name followed by zero or more arguments with no [...] or $
  399. ** or {...} or ; to be seen anywhere. Most callback scripts consist
  400. ** of just a single procedure name and they meet this requirement.
  401. */
  402. static int safeToUseEvalObjv( Tcl_Interp interp, Tcl_Obj pCmd )
  403. {
  404. /* We could try to do something with TCL.Tcl_Parse(). But we will instead
  405. ** just do a search for forbidden characters. If any of the forbidden
  406. ** characters appear in pCmd, we will report the string as unsafe.
  407. */
  408. string z;
  409. int n = 0;
  410. z = TCL.Tcl_GetStringFromObj( pCmd, out n );
  411. while ( n-- > 0 )
  412. {
  413. int c = z[n];// *( z++ );
  414. if ( c == '$' || c == '[' || c == ';' )
  415. return 0;
  416. }
  417. return 1;
  418. }
  419. /*
  420. ** Find an SqlFunc structure with the given name. Or create a new
  421. ** one if an existing one cannot be found. Return a pointer to the
  422. ** structure.
  423. */
  424. static SqlFunc findSqlFunc( SqliteDb pDb, string zName )
  425. {
  426. SqlFunc p, pNew;
  427. int i;
  428. pNew = new SqlFunc();//(SqlFunc)Tcl_Alloc( sizeof(*pNew) + strlen30(zName) + 1 );
  429. //pNew.zName = (char)&pNew[1];
  430. //for(i=0; zName[i]; i++){ pNew.zName[i] = tolower(zName[i]); }
  431. //pNew.zName[i] = 0;
  432. pNew.zName = zName.ToLower();
  433. for ( p = pDb.pFunc; p != null; p = p.pNext )
  434. {
  435. if ( p.zName == pNew.zName )
  436. {
  437. //Tcl_Free((char)pNew);
  438. return p;
  439. }
  440. }
  441. pNew.interp = pDb.interp;
  442. pNew.pScript = null;
  443. pNew.pNext = pDb.pFunc;
  444. pDb.pFunc = pNew;
  445. return pNew;
  446. }
  447. /*
  448. ** Finalize and free a list of prepared statements
  449. */
  450. static void flushStmtCache( SqliteDb pDb )
  451. {
  452. SqlPreparedStmt pPreStmt;
  453. while ( pDb.stmtList != null )
  454. {
  455. sqlite3_finalize( pDb.stmtList.pStmt );
  456. pPreStmt = pDb.stmtList;
  457. pDb.stmtList = pDb.stmtList.pNext;
  458. TCL.Tcl_Free( ref pPreStmt );
  459. }
  460. pDb.nStmt = 0;
  461. pDb.stmtLast = null;
  462. }
  463. /*
  464. ** TCL calls this procedure when an sqlite3 database command is
  465. ** deleted.
  466. */
  467. static void DbDeleteCmd( ref object db )
  468. {
  469. SqliteDb pDb = (SqliteDb)db;
  470. flushStmtCache( pDb );
  471. closeIncrblobChannels( pDb );
  472. sqlite3_close( pDb.db );
  473. while ( pDb.pFunc != null )
  474. {
  475. SqlFunc pFunc = pDb.pFunc;
  476. pDb.pFunc = pFunc.pNext;
  477. TCL.Tcl_DecrRefCount( ref pFunc.pScript );
  478. TCL.Tcl_Free( ref pFunc );
  479. }
  480. while ( pDb.pCollate != null )
  481. {
  482. SqlCollate pCollate = pDb.pCollate;
  483. pDb.pCollate = pCollate.pNext;
  484. TCL.Tcl_Free( ref pCollate );
  485. }
  486. if ( pDb.zBusy != null )
  487. {
  488. TCL.Tcl_Free( ref pDb.zBusy );
  489. }
  490. if ( pDb.zTrace != null )
  491. {
  492. TCL.Tcl_Free( ref pDb.zTrace );
  493. }
  494. if ( pDb.zProfile != null )
  495. {
  496. TCL.Tcl_Free( ref pDb.zProfile );
  497. }
  498. if ( pDb.zAuth != null )
  499. {
  500. TCL.Tcl_Free( ref pDb.zAuth );
  501. }
  502. if ( pDb.zNull != null )
  503. {
  504. TCL.Tcl_Free( ref pDb.zNull );
  505. }
  506. if ( pDb.pUpdateHook != null )
  507. {
  508. TCL.Tcl_DecrRefCount( ref pDb.pUpdateHook );
  509. }
  510. if ( pDb.pRollbackHook != null )
  511. {
  512. TCL.Tcl_DecrRefCount( ref pDb.pRollbackHook );
  513. }
  514. if ( pDb.pWalHook != null )
  515. {
  516. TCL.Tcl_DecrRefCount( ref pDb.pWalHook );
  517. }
  518. if ( pDb.pCollateNeeded != null )
  519. {
  520. TCL.Tcl_DecrRefCount( ref pDb.pCollateNeeded );
  521. }
  522. TCL.Tcl_Free( ref pDb );
  523. }
  524. /*
  525. ** This routine is called when a database file is locked while trying
  526. ** to execute SQL.
  527. */
  528. static int DbBusyHandler( object cd, int nTries )
  529. {
  530. SqliteDb pDb = (SqliteDb)cd;
  531. int rc;
  532. StringBuilder zVal = new StringBuilder( 30 );//char zVal[30];
  533. sqlite3_snprintf( 30, zVal, "%d", nTries );
  534. rc = TCL.Tcl_VarEval( pDb.interp, pDb.zBusy, " ", zVal.ToString(), null );
  535. if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
  536. {
  537. return 0;
  538. }
  539. return 1;
  540. }
  541. #if !SQLITE_OMIT_PROGRESS_CALLBACK
  542. /*
  543. ** This routine is invoked as the 'progress callback' for the database.
  544. */
  545. static int DbProgressHandler( object cd )
  546. {
  547. SqliteDb pDb = (SqliteDb)cd;
  548. int rc;
  549. Debug.Assert( pDb.zProgress != null );
  550. rc = TCL.Tcl_Eval( pDb.interp, pDb.zProgress );
  551. if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
  552. {
  553. return 1;
  554. }
  555. return 0;
  556. }
  557. #endif
  558. #if !SQLITE_OMIT_TRACE
  559. /*
  560. ** This routine is called by the SQLite trace handler whenever a new
  561. ** block of SQL is executed. The TCL script in pDb.zTrace is executed.
  562. */
  563. static void DbTraceHandler( object cd, string zSql )
  564. {
  565. SqliteDb pDb = (SqliteDb)cd;
  566. TclObject str = null;
  567. TCL.Tcl_DStringInit( out str );
  568. TCL.Tcl_DStringAppendElement( str, pDb.zTrace );
  569. TCL.Tcl_DStringAppendElement( str, " {" + zSql + "}" );
  570. TCL.Tcl_EvalObjEx( pDb.interp, str, 0 );// TCL.Tcl_Eval( pDb.interp, TCL.Tcl_DStringValue( ref str ) );
  571. TCL.Tcl_DStringFree( ref str );
  572. TCL.Tcl_ResetResult( pDb.interp );
  573. }
  574. #endif
  575. #if !SQLITE_OMIT_TRACE
  576. /*
  577. ** This routine is called by the SQLite profile handler after a statement
  578. ** SQL has executed. The TCL script in pDb.zProfile is evaluated.
  579. */
  580. static void DbProfileHandler( object cd, string zSql, sqlite_int64 tm )
  581. {
  582. SqliteDb pDb = (SqliteDb)cd;
  583. TclObject str = null;
  584. StringBuilder zTm = new StringBuilder( 100 );//char zTm[100];
  585. sqlite3_snprintf( 100, zTm, "%lld", tm );
  586. TCL.Tcl_DStringInit( out str );
  587. TCL.Tcl_DStringAppendElement( str, pDb.zProfile );
  588. TCL.Tcl_DStringAppendElement( str, " {" + zSql + "}" );
  589. TCL.Tcl_DStringAppendElement( str, " {" + zTm.ToString() + "}" );
  590. TCL.Tcl_Eval( pDb.interp, str.ToString() );
  591. TCL.Tcl_DStringFree( ref str );
  592. TCL.Tcl_ResetResult( pDb.interp );
  593. }
  594. #endif
  595. /*
  596. ** This routine is called when a transaction is committed. The
  597. ** TCL script in pDb.zCommit is executed. If it returns non-zero or
  598. ** if it throws an exception, the transaction is rolled back instead
  599. ** of being committed.
  600. */
  601. static int DbCommitHandler( object cd )
  602. {
  603. SqliteDb pDb = (SqliteDb)cd;
  604. int rc;
  605. rc = TCL.Tcl_Eval( pDb.interp, pDb.zCommit );
  606. if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
  607. {
  608. return 1;
  609. }
  610. return 0;
  611. }
  612. static void DbRollbackHandler( object _object )
  613. {
  614. SqliteDb pDb = (SqliteDb)_object;
  615. Debug.Assert( pDb.pRollbackHook != null );
  616. if ( TCL.TCL_OK != TCL.Tcl_EvalObjEx( pDb.interp, pDb.pRollbackHook, 0 ) )
  617. {
  618. TCL.Tcl_BackgroundError( pDb.interp );
  619. }
  620. }
  621. /*
  622. ** This procedure handles wal_hook callbacks.
  623. */
  624. static int DbWalHandler(
  625. object clientData,
  626. sqlite3 db,
  627. string zDb,
  628. int nEntry
  629. )
  630. {
  631. int ret = SQLITE_OK;
  632. Tcl_Obj p;
  633. SqliteDb pDb = (SqliteDb)clientData;
  634. Tcl_Interp interp = pDb.interp;
  635. Debug.Assert( pDb.pWalHook != null );
  636. p = TCL.Tcl_DuplicateObj( pDb.pWalHook );
  637. TCL.Tcl_IncrRefCount( p );
  638. TCL.Tcl_ListObjAppendElement( interp, p, TCL.Tcl_NewStringObj( zDb, -1 ) );
  639. TCL.Tcl_ListObjAppendElement( interp, p, TCL.Tcl_NewIntObj( nEntry ) );
  640. if ( TCL.TCL_OK != TCL.Tcl_EvalObjEx( interp, p, 0 )
  641. || TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, TCL.Tcl_GetObjResult( interp ), out ret )
  642. )
  643. {
  644. TCL.Tcl_BackgroundError( interp );
  645. }
  646. TCL.Tcl_DecrRefCount( ref p );
  647. return ret;
  648. }
  649. #if (SQLITE_TEST) && (SQLITE_ENABLE_UNLOCK_NOTIFY)
  650. static void setTestUnlockNotifyVars(Tcl_Interp interp, int iArg, int nArg){
  651. char zBuf[64];
  652. sprintf(zBuf, "%d", iArg);
  653. Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY);
  654. sprintf(zBuf, "%d", nArg);
  655. Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY);
  656. }
  657. #else
  658. //# define setTestUnlockNotifyVars(x,y,z)
  659. #endif
  660. #if SQLITE_ENABLE_UNLOCK_NOTIFY
  661. static void DbUnlockNotify(void **apArg, int nArg){
  662. int i;
  663. for(i=0; i<nArg; i++){
  664. const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
  665. SqliteDb *pDb = (SqliteDb )apArg[i];
  666. setTestUnlockNotifyVars(pDb.interp, i, nArg);
  667. Debug.Assert( pDb.pUnlockNotify);
  668. Tcl_EvalObjEx(pDb.interp, pDb.pUnlockNotify, flags);
  669. Tcl_DecrRefCount(pDb.pUnlockNotify);
  670. pDb.pUnlockNotify = 0;
  671. }
  672. }
  673. #endif
  674. static void DbUpdateHandler(
  675. object p,
  676. int op,
  677. string zDb,
  678. string zTbl,
  679. sqlite_int64 rowid
  680. )
  681. {
  682. SqliteDb pDb = (SqliteDb)p;
  683. Tcl_Obj pCmd;
  684. Debug.Assert( pDb.pUpdateHook != null );
  685. Debug.Assert( op == SQLITE_INSERT || op == SQLITE_UPDATE || op == SQLITE_DELETE );
  686. pCmd = TCL.Tcl_DuplicateObj( pDb.pUpdateHook );
  687. TCL.Tcl_IncrRefCount( pCmd );
  688. TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj(
  689. ( ( op == SQLITE_INSERT ) ? "INSERT" : ( op == SQLITE_UPDATE ) ? "UPDATE" : "DELETE" ), -1 ) );
  690. TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj( zDb, -1 ) );
  691. TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj( zTbl, -1 ) );
  692. TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewWideIntObj( rowid ) );
  693. TCL.Tcl_EvalObjEx( pDb.interp, pCmd, TCL.TCL_EVAL_DIRECT );
  694. TCL.Tcl_DecrRefCount( ref pCmd );
  695. }
  696. static void tclCollateNeeded(
  697. object pCtx,
  698. sqlite3 db,
  699. int enc,
  700. string zName
  701. )
  702. {
  703. SqliteDb pDb = (SqliteDb)pCtx;
  704. Tcl_Obj pScript = TCL.Tcl_DuplicateObj( pDb.pCollateNeeded );
  705. TCL.Tcl_IncrRefCount( pScript );
  706. TCL.Tcl_ListObjAppendElement( null, pScript, TCL.Tcl_NewStringObj( zName, -1 ) );
  707. TCL.Tcl_EvalObjEx( pDb.interp, pScript, 0 );
  708. TCL.Tcl_DecrRefCount( ref pScript );
  709. }
  710. /*
  711. ** This routine is called to evaluate an SQL collation function implemented
  712. ** using TCL script.
  713. */
  714. static int tclSqlCollate(
  715. object pCtx,
  716. int nA,
  717. string zA,
  718. int nB,
  719. string zB
  720. )
  721. {
  722. SqlCollate p = (SqlCollate)pCtx;
  723. Tcl_Obj pCmd;
  724. pCmd = TCL.Tcl_NewStringObj( p.zScript, -1 );
  725. TCL.Tcl_IncrRefCount( pCmd );
  726. TCL.Tcl_ListObjAppendElement( p.interp, pCmd, TCL.Tcl_NewStringObj( zA, nA ) );
  727. TCL.Tcl_ListObjAppendElement( p.interp, pCmd, TCL.Tcl_NewStringObj( zB, nB ) );
  728. TCL.Tcl_EvalObjEx( p.interp, pCmd, TCL.TCL_EVAL_DIRECT );
  729. TCL.Tcl_DecrRefCount( ref pCmd );
  730. return ( atoi( TCL.Tcl_GetStringResult( p.interp ) ) );
  731. }
  732. /*
  733. ** This routine is called to evaluate an SQL function implemented
  734. ** using TCL script.
  735. */
  736. static void tclSqlFunc( sqlite3_context context, int argc, sqlite3_value[] argv )
  737. {
  738. SqlFunc p = (SqlFunc)sqlite3_user_data( context );
  739. Tcl_Obj pCmd = null;
  740. int i;
  741. int rc;
  742. if ( argc == 0 )
  743. {
  744. /* If there are no arguments to the function, call TCL.Tcl_EvalObjEx on the
  745. ** script object directly. This allows the TCL compiler to generate
  746. ** bytecode for the command on the first invocation and thus make
  747. ** subsequent invocations much faster. */
  748. pCmd = p.pScript;
  749. TCL.Tcl_IncrRefCount( pCmd );
  750. rc = TCL.Tcl_EvalObjEx( p.interp, pCmd, 0 );
  751. TCL.Tcl_DecrRefCount( ref pCmd );
  752. }
  753. else
  754. {
  755. /* If there are arguments to the function, make a shallow copy of the
  756. ** script object, lappend the arguments, then evaluate the copy.
  757. **
  758. ** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated.
  759. ** The new Tcl_Obj contains pointers to the original list elements.
  760. ** That way, when TCL.Tcl_EvalObjv() is run and shimmers the first element
  761. ** of the list to tclCmdNameType, that alternate representation will
  762. ** be preserved and reused on the next invocation.
  763. */
  764. Tcl_Obj[] aArg = null;
  765. int nArg = 0;
  766. if ( TCL.Tcl_ListObjGetElements( p.interp, p.pScript, out nArg, out aArg ) )
  767. {
  768. sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
  769. return;
  770. }
  771. pCmd = TCL.Tcl_NewListObj( nArg, aArg );
  772. TCL.Tcl_IncrRefCount( pCmd );
  773. for ( i = 0; i < argc; i++ )
  774. {
  775. sqlite3_value pIn = argv[i];
  776. Tcl_Obj pVal;
  777. /* Set pVal to contain the i'th column of this row. */
  778. switch ( sqlite3_value_type( pIn ) )
  779. {
  780. case SQLITE_BLOB:
  781. {
  782. int bytes = sqlite3_value_bytes( pIn );
  783. pVal = TCL.Tcl_NewByteArrayObj( sqlite3_value_blob( pIn ), bytes );
  784. break;
  785. }
  786. case SQLITE_INTEGER:
  787. {
  788. sqlite_int64 v = sqlite3_value_int64( pIn );
  789. if ( v >= -2147483647 && v <= 2147483647 )
  790. {
  791. pVal = TCL.Tcl_NewIntObj( (int)v );
  792. }
  793. else
  794. {
  795. pVal = TCL.Tcl_NewWideIntObj( v );
  796. }
  797. break;
  798. }
  799. case SQLITE_FLOAT:
  800. {
  801. double r = sqlite3_value_double( pIn );
  802. pVal = TCL.Tcl_NewDoubleObj( r );
  803. break;
  804. }
  805. case SQLITE_NULL:
  806. {
  807. pVal = TCL.Tcl_NewStringObj( "", 0 );
  808. break;
  809. }
  810. default:
  811. {
  812. int bytes = sqlite3_value_bytes( pIn );
  813. pVal = TCL.Tcl_NewStringObj( sqlite3_value_text( pIn ), bytes );
  814. break;
  815. }
  816. }
  817. rc = TCL.Tcl_ListObjAppendElement( p.interp, pCmd, pVal ) ? 1 : 0;
  818. if ( rc != 0 )
  819. {
  820. TCL.Tcl_DecrRefCount( ref pCmd );
  821. sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
  822. return;
  823. }
  824. }
  825. if ( p.useEvalObjv == 0 )
  826. {
  827. /* TCL.Tcl_EvalObjEx() will automatically call TCL.Tcl_EvalObjv() if pCmd
  828. ** is a list without a string representation. To prevent this from
  829. ** happening, make sure pCmd has a valid string representation */
  830. TCL.Tcl_GetString( pCmd );
  831. }
  832. rc = TCL.Tcl_EvalObjEx( p.interp, pCmd, TCL.TCL_EVAL_DIRECT );
  833. TCL.Tcl_DecrRefCount( ref pCmd );
  834. }
  835. if ( rc != 0 && rc != TCL.TCL_RETURN )
  836. {
  837. sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
  838. }
  839. else
  840. {
  841. Tcl_Obj pVar = TCL.Tcl_GetObjResult( p.interp );
  842. int n = 0;
  843. string data = "";
  844. Tcl_WideInt v = 0;
  845. double r = 0;
  846. string zType = pVar.typePtr;//string zType = (pVar.typePtr ? pVar.typePtr.name : "");
  847. if ( zType == "bytearray" )
  848. { //&& pVar.bytes==0 ){
  849. /* Only return a BLOB type if the Tcl variable is a bytearray and
  850. ** has no string representation. */
  851. data = Encoding.UTF8.GetString( TCL.Tcl_GetByteArrayFromObj( pVar, out n ) );
  852. sqlite3_result_blob( context, data, n, null );
  853. }
  854. else if ( zType == "boolean" )
  855. {
  856. TCL.Tcl_GetIntFromObj( null, pVar, out n );
  857. sqlite3_result_int( context, n );
  858. }
  859. else if ( zType == "wideint" ||
  860. zType == "int" || Int64.TryParse( pVar.ToString(), out v ) )
  861. {
  862. TCL.Tcl_GetWideIntFromObj( null, pVar, out v );
  863. sqlite3_result_int64( context, v );
  864. }
  865. else if ( zType == "double" || Double.TryParse( pVar.ToString(), out r ) )
  866. {
  867. TCL.Tcl_GetDoubleFromObj( null, pVar, out r );
  868. sqlite3_result_double( context, r );
  869. }
  870. else
  871. {
  872. data = TCL.Tcl_GetStringFromObj( pVar, n );
  873. n = data.Length;
  874. sqlite3_result_text( context, data, n, SQLITE_TRANSIENT );
  875. }
  876. }
  877. }
  878. #if !SQLITE_OMIT_AUTHORIZATION
  879. /*
  880. ** This is the authentication function. It appends the authentication
  881. ** type code and the two arguments to zCmd[] then invokes the result
  882. ** on the interpreter. The reply is examined to determine if the
  883. ** authentication fails or succeeds.
  884. */
  885. static int auth_callback(
  886. object pArg,
  887. int code,
  888. const string zArg1,
  889. const string zArg2,
  890. const string zArg3,
  891. const string zArg4
  892. ){
  893. string zCode;
  894. TCL.Tcl_DString str;
  895. int rc;
  896. const string zReply;
  897. SqliteDb pDb = (SqliteDb)pArg;
  898. if( pdb.disableAuth ) return SQLITE_OK;
  899. switch( code ){
  900. case SQLITE_COPY : zCode="SQLITE_COPY"; break;
  901. case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break;
  902. case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break;
  903. case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
  904. case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
  905. case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
  906. case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
  907. case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break;
  908. case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break;
  909. case SQLITE_DELETE : zCode="SQLITE_DELETE"; break;
  910. case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break;
  911. case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break;
  912. case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break;
  913. case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break;
  914. case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
  915. case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break;
  916. case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break;
  917. case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break;
  918. case SQLITE_INSERT : zCode="SQLITE_INSERT"; break;
  919. case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break;
  920. case SQLITE_READ : zCode="SQLITE_READ"; break;
  921. case SQLITE_SELECT : zCode="SQLITE_SELECT"; break;
  922. case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break;
  923. case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break;
  924. case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break;
  925. case SQLITE_DETACH : zCode="SQLITE_DETACH"; break;
  926. case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
  927. case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
  928. case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
  929. case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break;
  930. case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break;
  931. case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break;
  932. case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break;
  933. default : zCode="????"; break;
  934. }
  935. TCL.Tcl_DStringInit(&str);
  936. TCL.Tcl_DStringAppend(&str, pDb.zAuth, -1);
  937. TCL.Tcl_DStringAppendElement(&str, zCode);
  938. TCL.Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
  939. TCL.Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
  940. TCL.Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
  941. TCL.Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
  942. rc = TCL.Tcl_GlobalEval(pDb.interp, TCL.Tcl_DStringValue(&str));
  943. TCL.Tcl_DStringFree(&str);
  944. zReply = TCL.Tcl_GetStringResult(pDb.interp);
  945. if( strcmp(zReply,"SQLITE_OK")==0 ){
  946. rc = SQLITE_OK;
  947. }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
  948. rc = SQLITE_DENY;
  949. }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
  950. rc = SQLITE_IGNORE;
  951. }else{
  952. rc = 999;
  953. }
  954. return rc;
  955. }
  956. #endif // * SQLITE_OMIT_AUTHORIZATION */
  957. /*
  958. ** zText is a pointer to text obtained via an sqlite3_result_text()
  959. ** or similar interface. This routine returns a Tcl string object,
  960. ** reference count set to 0, containing the text. If a translation
  961. ** between iso8859 and UTF-8 is required, it is preformed.
  962. */
  963. static Tcl_Obj dbTextToObj( string zText )
  964. {
  965. Tcl_Obj pVal;
  966. #if UTF_TRANSLATION_NEEDED
  967. //TCL.Tcl_DString dCol;
  968. //TCL.Tcl_DStringInit(&dCol);
  969. //TCL.Tcl_ExternalToUtfDString(NULL, zText, -1, dCol);
  970. //pVal = TCL.Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
  971. //TCL.Tcl_DStringFree(ref dCol);
  972. if (zText.Length == Encoding.UTF8.GetByteCount(zText)) pVal = TCL.Tcl_NewStringObj( zText, -1 );
  973. else pVal = TCL.Tcl_NewStringObj( zText, -1 );
  974. #else
  975. pVal = TCL.Tcl_NewStringObj( zText, -1 );
  976. #endif
  977. return pVal;
  978. }
  979. /*
  980. ** This routine reads a line of text from FILE in, stores
  981. ** the text in memory obtained from malloc() and returns a pointer
  982. ** to the text. NULL is returned at end of file, or if malloc()
  983. ** fails.
  984. **
  985. ** The interface is like "readline" but no command-line editing
  986. ** is done.
  987. **
  988. ** copied from shell.c from '.import' command
  989. */
  990. //static char *local_getline(string zPrompt, FILE *in){
  991. // string zLine;
  992. // int nLine;
  993. // int n;
  994. // int eol;
  995. // nLine = 100;
  996. // zLine = malloc( nLine );
  997. // if( zLine==0 ) return 0;
  998. // n = 0;
  999. // eol = 0;
  1000. // while( !eol ){
  1001. // if( n+100>nLine ){
  1002. // nLine = nLine*2 + 100;
  1003. // zLine = realloc(zLine, nLine);
  1004. // if( zLine==0 ) return 0;
  1005. // }
  1006. // if( fgets(&zLine[n], nLine - n, in)==0 ){
  1007. // if( n==0 ){
  1008. // free(zLine);
  1009. // return 0;
  1010. // }
  1011. // zLine[n] = 0;
  1012. // eol = 1;
  1013. // break;
  1014. // }
  1015. // while( zLine[n] ){ n++; }
  1016. // if( n>0 && zLine[n-1]=='\n' ){
  1017. // n--;
  1018. // zLine[n] = 0;
  1019. // eol = 1;
  1020. // }
  1021. // }
  1022. // zLine = realloc( zLine, n+1 );
  1023. // return zLine;
  1024. //}
  1025. /*
  1026. ** This function is part of the implementation of the command:
  1027. **
  1028. ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT
  1029. **
  1030. ** It is invoked after evaluating the script SCRIPT to commit or rollback
  1031. ** the transaction or savepoint opened by the [transaction] command.
  1032. */
  1033. static int DbTransPostCmd(
  1034. object data, /* data[0] is the Sqlite3Db* for $db */
  1035. Tcl_Interp interp, /* Tcl interpreter */
  1036. int result /* Result of evaluating SCRIPT */
  1037. )
  1038. {
  1039. string[] azEnd = {
  1040. "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */
  1041. "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */
  1042. "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction",
  1043. "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */
  1044. };
  1045. SqliteDb pDb = (SqliteDb)data;
  1046. int rc = result;
  1047. string zEnd;
  1048. pDb.nTransaction--;
  1049. zEnd = azEnd[( ( rc == TCL.TCL_ERROR ) ? 1 : 0 ) * 2 + ( ( pDb.nTransaction == 0 ) ? 1 : 0 )];
  1050. pDb.disableAuth++;
  1051. if ( sqlite3_exec( pDb.db, zEnd, 0, 0, 0 ) != 0 )
  1052. {
  1053. /* This is a tricky scenario to handle. The most likely cause of an
  1054. ** error is that the exec() above was an attempt to commit the
  1055. ** top-level transaction that returned SQLITE_BUSY. Or, less likely,
  1056. ** that an IO-error has occured. In either case, throw a Tcl exception
  1057. ** and try to rollback the transaction.
  1058. **
  1059. ** But it could also be that the user executed one or more BEGIN,
  1060. ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
  1061. ** this method's logic. Not clear how this would be best handled.
  1062. */
  1063. if ( rc != TCL.TCL_ERROR )
  1064. {
  1065. TCL.Tcl_AppendResult( interp, sqlite3_errmsg( pDb.db ), 0 );
  1066. rc = TCL.TCL_ERROR;
  1067. }
  1068. sqlite3_exec( pDb.db, "ROLLBACK", 0, 0, 0 );
  1069. }
  1070. pDb.disableAuth--;
  1071. return rc;
  1072. }
  1073. /*
  1074. ** Search the cache for a prepared-statement object that implements the
  1075. ** first SQL statement in the buffer pointed to by parameter zIn. If
  1076. ** no such prepared-statement can be found, allocate and prepare a new
  1077. ** one. In either case, bind the current values of the relevant Tcl
  1078. ** variables to any $var, :var or @var variables in the statement. Before
  1079. ** returning, set *ppPreStmt to point to the prepared-statement object.
  1080. **
  1081. ** Output parameter *pzOut is set to point to the next SQL statement in
  1082. ** buffer zIn, or to the '\0' byte at the end of zIn if there is no
  1083. ** next statement.
  1084. **
  1085. ** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned
  1086. ** and an error message loaded into interpreter pDb.interp.
  1087. */
  1088. static int dbPrepareAndBind(
  1089. SqliteDb pDb, /* Database object */
  1090. string zIn, /* SQL to compile */
  1091. ref string pzOut, /* OUT: Pointer to next SQL statement */
  1092. ref SqlPreparedStmt ppPreStmt /* OUT: Object used to cache statement */
  1093. )
  1094. {
  1095. string zSql = zIn; /* Pointer to first SQL statement in zIn */
  1096. sqlite3_stmt pStmt = null; /* Prepared statement object */
  1097. SqlPreparedStmt pPreStmt; /* Pointer to cached statement */
  1098. int nSql; /* Length of zSql in bytes */
  1099. int nVar = 0; /* Number of variables in statement */
  1100. int iParm = 0; /* Next free entry in apParm */
  1101. int i;
  1102. Tcl_Interp interp = pDb.interp;
  1103. pzOut = null;
  1104. ppPreStmt = null;
  1105. /* Trim spaces from the start of zSql and calculate the remaining length. */
  1106. zSql = zSql.TrimStart(); //while ( isspace( zSql[0] ) ) { zSql++; }
  1107. nSql = strlen30( zSql );
  1108. for ( pPreStmt = pDb.stmtList; pPreStmt != null; pPreStmt = pPreStmt.pNext )
  1109. {
  1110. int n = pPreStmt.nSql;
  1111. if ( nSql >= n
  1112. && zSql.StartsWith(pPreStmt.zSql)
  1113. && ( nSql == n /* zSql[n]==0 */|| zSql[n - 1] == ';' )
  1114. )
  1115. {
  1116. pStmt = pPreStmt.pStmt;
  1117. /* Restore aMem values */
  1118. if ( pStmt.aMem.Length < pPreStmt.aMem.Length )
  1119. Array.Resize( ref pStmt.aMem, pPreStmt.aMem.Length );
  1120. for ( int ix = 0; ix < pPreStmt.aMem.Length; ix++ )
  1121. {
  1122. pPreStmt.aMem[ix].CopyTo( ref pStmt.aMem[ix] );
  1123. }
  1124. pzOut = zSql.Substring( pPreStmt.nSql );
  1125. /* When a prepared statement is found, unlink it from the
  1126. ** cache list. It will later be added back to the beginning
  1127. ** of the cache list in order to implement LRU replacement.
  1128. */
  1129. if ( pPreStmt.pPrev != null )
  1130. {
  1131. pPreStmt.pPrev.pNext = pPreStmt.pNext;
  1132. }
  1133. else
  1134. {
  1135. pDb.stmtList = pPreStmt.pNext;
  1136. }
  1137. if ( pPreStmt.pNext != null )
  1138. {
  1139. pPreStmt.pNext.pPrev = pPreStmt.pPrev;
  1140. }
  1141. else
  1142. {
  1143. pDb.stmtLast = pPreStmt.pPrev;
  1144. }
  1145. pDb.nStmt--;
  1146. nVar = sqlite3_bind_parameter_count( pStmt );
  1147. break;
  1148. }
  1149. }
  1150. /* If no prepared statement was found. Compile the SQL text. Also allocate
  1151. ** a new SqlPreparedStmt structure. */
  1152. if ( pPreStmt == null )
  1153. {
  1154. int nByte;
  1155. if ( SQLITE_OK != sqlite3_prepare_v2( pDb.db, zSql, -1, ref pStmt, ref pzOut ) )
  1156. {
  1157. TCL.Tcl_SetObjResult( interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
  1158. pPreStmt = new SqlPreparedStmt();// (SqlPreparedStmt)Tcl_Alloc( nByte );
  1159. return TCL.TCL_ERROR;
  1160. }
  1161. if ( pStmt == null )
  1162. {
  1163. if ( SQLITE_OK != sqlite3_errcode( pDb.db ) )
  1164. {
  1165. /* A compile-time error in the statement. */
  1166. TCL.Tcl_SetObjResult( interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
  1167. return TCL.TCL_ERROR;
  1168. }
  1169. else
  1170. {
  1171. /* The statement was a no-op. Continue to the next statement
  1172. ** in the SQL string.
  1173. */
  1174. return TCL.TCL_OK;
  1175. }
  1176. }
  1177. Debug.Assert( pPreStmt == null );
  1178. nVar = sqlite3_bind_parameter_count( pStmt );
  1179. //nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj );
  1180. pPreStmt = new SqlPreparedStmt();// (SqlPreparedStmt)Tcl_Alloc( nByte );
  1181. //memset(pPreStmt, 0, nByte);
  1182. pPreStmt.pStmt = pStmt;
  1183. pPreStmt.nSql = ( zSql.Length - pzOut.Length );
  1184. pPreStmt.zSql = sqlite3_sql( pStmt );
  1185. pPreStmt.apParm = new TclObject[nVar];//pPreStmt[1];
  1186. }
  1187. Debug.Assert( pPreStmt != null );
  1188. Debug.Assert( strlen30( pPreStmt.zSql ) == pPreStmt.nSql );
  1189. Debug.Assert( zSql.StartsWith( pPreStmt.zSql ) );
  1190. /* Bind values to parameters that begin with $ or : */
  1191. for ( i = 1; i <= nVar; i++ )
  1192. {
  1193. string zVar = sqlite3_bind_parameter_name( pStmt, i );
  1194. if ( !String.IsNullOrEmpty( zVar ) && ( zVar[0] == '$' || zVar[0] == ':' || zVar[0] == '@' ) )
  1195. {
  1196. Tcl_Obj pVar = TCL.Tcl_GetVar2Ex( interp, zVar.Substring( 1 ), null, 0 );
  1197. if ( pVar != null && pVar.typePtr != "null" )
  1198. {
  1199. int n = 0;
  1200. string data;
  1201. string zType = pVar.typePtr;
  1202. //char c = zType[0];
  1203. if ( zVar[0] == '@' ||
  1204. ( zType == "bytearray" ) )// TODO -- && pVar.bytes == 0 ) )
  1205. {
  1206. /* Load a BLOB type if the Tcl variable is a bytearray and
  1207. ** it has no string representation or the host
  1208. ** parameter name begins with "@". */
  1209. if ( zVar[0] == '@' || pVar.stringRep == null )
  1210. sqlite3_bind_blob( pStmt, i, TCL.Tcl_GetByteArrayFromObj( pVar, out n ), n, SQLITE_STATIC );
  1211. else
  1212. sqlite3_bind_text( pStmt, i, TCL.Tcl_GetStringFromObj( pVar, out n ), n, SQLITE_STATIC );
  1213. TCL.Tcl_IncrRefCount( pVar );
  1214. pPreStmt.apParm[iParm++] = pVar;
  1215. }
  1216. else if ( zType == "boolean" )
  1217. {
  1218. TCL.Tcl_GetIntFromObj( interp, pVar, out n );
  1219. sqlite3_bind_int( pStmt, i, n );
  1220. }
  1221. else if ( zType == "double" )
  1222. {
  1223. double r = 0;
  1224. TCL.Tcl_GetDoubleFromObj( interp, pVar, out r );
  1225. sqlite3_bind_double( pStmt, i, r );
  1226. }
  1227. else if ( zType == "wideint" ||
  1228. zType == "int" )
  1229. {
  1230. Tcl_WideInt v = 0;
  1231. TCL.Tcl_GetWideIntFromObj( interp, pVar, out v );
  1232. sqlite3_bind_int64( pStmt, i, v );
  1233. }
  1234. else
  1235. {
  1236. data = TCL.Tcl_GetStringFromObj( pVar, out n );
  1237. sqlite3_bind_text( pStmt, i, data, n, SQLITE_STATIC );
  1238. TCL.Tcl_IncrRefCount( pVar );
  1239. pPreStmt.apParm[iParm++] = pVar;
  1240. }
  1241. }
  1242. else
  1243. {
  1244. sqlite3_bind_null( pStmt, i );
  1245. }
  1246. }
  1247. }
  1248. pPreStmt.nParm = iParm;
  1249. /* save aMem values for later reuse */
  1250. pPreStmt.aMem = new Mem[pPreStmt.pStmt.aMem.Length];
  1251. for ( int ix = 0; ix < pPreStmt.pStmt.aMem.Length; ix++ )
  1252. {
  1253. pPreStmt.pStmt.aMem[ix].CopyTo( ref pPreStmt.aMem[ix] );
  1254. }
  1255. ppPreStmt = pPreStmt;
  1256. return TCL.TCL_OK;
  1257. }
  1258. /*
  1259. ** Release a statement reference obtained by calling dbPrepareAndBind().
  1260. ** There should be exactly one call to this function for each call to
  1261. ** dbPrepareAndBind().
  1262. **
  1263. ** If the discard parameter is non-zero, then the statement is deleted
  1264. ** immediately. Otherwise it is added to the LRU list and may be returned
  1265. ** by a subsequent call to dbPrepareAndBind().
  1266. */
  1267. static void dbReleaseStmt(
  1268. SqliteDb pDb, /* Database handle */
  1269. SqlPreparedStmt pPreStmt, /* Prepared statement handle to release */
  1270. int discard /* True to delete (not cache) the pPreStmt */
  1271. )
  1272. {
  1273. int i;
  1274. /* Free the bound string and blob parameters */
  1275. for ( i = 0; i < pPreStmt.nParm; i++ )
  1276. {
  1277. TCL.Tcl_DecrRefCount( ref pPreStmt.apParm[i] );
  1278. }
  1279. pPreStmt.nParm = 0;
  1280. if ( pDb.maxStmt <= 0 || discard != 0 )
  1281. {
  1282. /* If the cache is turned off, deallocated the statement */
  1283. sqlite3_finalize( pPreStmt.pStmt );
  1284. TCL.Tcl_Free( ref pPreStmt );
  1285. }
  1286. else
  1287. {
  1288. /* Add the prepared statement to the beginning of the cache list. */
  1289. pPreStmt.pNext = pDb.stmtList;
  1290. pPreStmt.pPrev = null;
  1291. if ( pDb.stmtList != null )
  1292. {
  1293. pDb.stmtList.pPrev = pPreStmt;
  1294. }
  1295. pDb.stmtList = pPreStmt;
  1296. if ( pDb.stmtLast == null )
  1297. {
  1298. Debug.Assert( pDb.nStmt == 0 );
  1299. pDb.stmtLast = pPreStmt;
  1300. }
  1301. else
  1302. {
  1303. Debug.Assert( pDb.nStmt > 0 );
  1304. }
  1305. pDb.nStmt++;
  1306. /* If we have too many statement in cache, remove the surplus from
  1307. ** the end of the cache list. */
  1308. while ( pDb.nStmt > pDb.maxStmt )
  1309. {
  1310. sqlite3_finalize( pDb.stmtLast.pStmt );
  1311. pDb.stmtLast = pDb.stmtLast.pPrev;
  1312. TCL.Tcl_Free( ref pDb.stmtLast.pNext );
  1313. pDb.stmtLast.pNext = null;
  1314. pDb.nStmt--;
  1315. }
  1316. }
  1317. }
  1318. /*
  1319. ** Structure used with dbEvalXXX() functions:
  1320. **
  1321. ** dbEvalInit()
  1322. ** dbEvalStep()
  1323. ** dbEvalFinalize()
  1324. ** dbEvalRowInfo()
  1325. ** dbEvalColumnValue()
  1326. */
  1327. //typedef struct DbEvalContext DbEvalContext;
  1328. public class DbEvalContext
  1329. {
  1330. public SqliteDb pDb; /* Database handle */
  1331. public Tcl_Obj pSql; /* Object holding string zSql */
  1332. public string zSql; /* Remaining SQL to execute */
  1333. public SqlPreparedStmt pPreStmt; /* Current statement */
  1334. public int nCol; /* Number of columns returned by pStmt */
  1335. public Tcl_Obj pArray; /* Name of array variable */
  1336. public Tcl_Obj[] apColName; /* Array of column names */
  1337. public void Clear()
  1338. {
  1339. pDb = null;
  1340. pSql = null;
  1341. zSql = null;
  1342. pPreStmt = null;
  1343. pArray = null;
  1344. apColName = null;
  1345. }
  1346. };
  1347. /*
  1348. ** Release any cache of column names currently held as part of
  1349. ** the DbEvalContext structure passed as the first argument.
  1350. */
  1351. static void dbReleaseColumnNames( DbEvalContext p )
  1352. {
  1353. if ( p.apColName != null )
  1354. {
  1355. int i;
  1356. for ( i = 0; i < p.nCol; i++ )
  1357. {
  1358. TCL.Tcl_DecrRefCount( ref p.apColName[i] );
  1359. }
  1360. TCL.Tcl_Free( ref p.apColName );
  1361. p.apColName = null;
  1362. }
  1363. p.nCol = 0;
  1364. }
  1365. /*
  1366. ** Initialize a DbEvalContext structure.
  1367. **
  1368. ** If pArray is not NULL, then it contains the name of a Tcl array
  1369. ** variable. The "*" member of this array is set to a list containing
  1370. ** the names of the columns returned by the statement as part of each
  1371. ** call to dbEvalStep(), in order from left to right. e.g. if the names
  1372. ** of the returned columns are a, b and c, it does the equival…

Large files files are truncated, but you can click here to view the full file