PageRenderTime 70ms CodeModel.GetById 20ms RepoModel.GetById 1ms 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
  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 equivalent of the
  1373. ** tcl command:
  1374. **
  1375. ** set ${pArray}() {a b c}
  1376. */
  1377. static void dbEvalInit(
  1378. DbEvalContext p, /* Pointer to structure to initialize */
  1379. SqliteDb pDb, /* Database handle */
  1380. Tcl_Obj pSql, /* Object containing SQL script */
  1381. Tcl_Obj pArray /* Name of Tcl array to set () element of */
  1382. )
  1383. {
  1384. if ( p != null )
  1385. p.Clear();// memset( p, 0, sizeof( DbEvalContext ) );
  1386. p.pDb = pDb;
  1387. p.zSql = TCL.Tcl_GetString( pSql );
  1388. p.pSql = pSql;
  1389. TCL.Tcl_IncrRefCount( pSql );
  1390. if ( pArray != null )
  1391. {
  1392. p.pArray = pArray;
  1393. TCL.Tcl_IncrRefCount( pArray );
  1394. }
  1395. }
  1396. /*
  1397. ** Obtain information about the row that the DbEvalContext passed as the
  1398. ** first argument currently points to.
  1399. */
  1400. static void dbEvalRowInfo(
  1401. DbEvalContext p, /* Evaluation context */
  1402. out int pnCol, /* OUT: Number of column names */
  1403. out Tcl_Obj[] papColName /* OUT: Array of column names */
  1404. )
  1405. {
  1406. /* Compute column names */
  1407. if ( null == p.apColName )
  1408. {
  1409. sqlite3_stmt pStmt = p.pPreStmt.pStmt;
  1410. int i; /* Iterator variable */
  1411. int nCol; /* Number of columns returned by pStmt */
  1412. Tcl_Obj[] apColName = null; /* Array of column names */
  1413. p.nCol = nCol = sqlite3_column_count( pStmt );
  1414. if ( nCol > 0 )// && ( papColName != null || p.pArray != null ) )
  1415. {
  1416. apColName = new TclObject[nCol];// (Tcl_Obj*)Tcl_Alloc( sizeof( Tcl_Obj* ) * nCol );
  1417. for ( i = 0; i < nCol; i++ )
  1418. {
  1419. apColName[i] = dbTextToObj( sqlite3_column_name( pStmt, i ) );
  1420. TCL.Tcl_IncrRefCount( apColName[i] );
  1421. }
  1422. p.apColName = apColName;
  1423. }
  1424. /* If results are being stored in an array variable, then create
  1425. ** the array() entry for that array
  1426. */
  1427. if ( p.pArray != null )
  1428. {
  1429. Tcl_Interp interp = p.pDb.interp;
  1430. Tcl_Obj pColList = TCL.Tcl_NewObj();
  1431. Tcl_Obj pStar = TCL.Tcl_NewStringObj( "*", -1 );
  1432. for ( i = 0; i < nCol; i++ )
  1433. {
  1434. TCL.Tcl_ListObjAppendElement( interp, pColList, apColName[i] );
  1435. }
  1436. TCL.Tcl_IncrRefCount( pStar );
  1437. TCL.Tcl_ObjSetVar2( interp, p.pArray, pStar, pColList, 0 );
  1438. TCL.Tcl_DecrRefCount( ref pStar );
  1439. }
  1440. }
  1441. //if ( papColName != null )
  1442. {
  1443. papColName = p.apColName;
  1444. }
  1445. //if ( pnCol !=0)
  1446. {
  1447. pnCol = p.nCol;
  1448. }
  1449. }
  1450. /*
  1451. ** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is
  1452. ** returned, then an error message is stored in the interpreter before
  1453. ** returning.
  1454. **
  1455. ** A return value of TCL_OK means there is a row of data available. The
  1456. ** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This
  1457. ** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK
  1458. ** is returned, then the SQL script has finished executing and there are
  1459. ** no further rows available. This is similar to SQLITE_DONE.
  1460. */
  1461. static int dbEvalStep( DbEvalContext p )
  1462. {
  1463. while ( !String.IsNullOrEmpty( p.zSql ) || p.pPreStmt != null )
  1464. {
  1465. int rc;
  1466. if ( p.pPreStmt == null )
  1467. {
  1468. rc = dbPrepareAndBind( p.pDb, p.zSql, ref p.zSql, ref p.pPreStmt );
  1469. if ( rc != TCL.TCL_OK )
  1470. return rc;
  1471. }
  1472. else
  1473. {
  1474. int rcs;
  1475. SqliteDb pDb = p.pDb;
  1476. SqlPreparedStmt pPreStmt = p.pPreStmt;
  1477. sqlite3_stmt pStmt = pPreStmt.pStmt;
  1478. rcs = sqlite3_step( pStmt );
  1479. if ( rcs == SQLITE_ROW )
  1480. {
  1481. return TCL.TCL_OK;
  1482. }
  1483. if ( p.pArray != null )
  1484. {
  1485. TclObject[] pDummy;
  1486. int iDummy;
  1487. dbEvalRowInfo( p, out iDummy, out pDummy );
  1488. }
  1489. rcs = sqlite3_reset( pStmt );
  1490. pDb.nStep = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1 );
  1491. pDb.nSort = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_SORT, 1 );
  1492. pDb.nIndex = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_AUTOINDEX, 1 );
  1493. dbReleaseColumnNames( p );
  1494. p.pPreStmt = null;
  1495. if ( rcs != SQLITE_OK )
  1496. {
  1497. /* If a run-time error occurs, report the error and stop reading
  1498. ** the SQL. */
  1499. TCL.Tcl_SetObjResult( pDb.interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
  1500. dbReleaseStmt( pDb, pPreStmt, 1 );
  1501. return TCL.TCL_ERROR;
  1502. }
  1503. else
  1504. {
  1505. dbReleaseStmt( pDb, pPreStmt, 0 );
  1506. }
  1507. }
  1508. }
  1509. /* Finished */
  1510. return TCL.TCL_BREAK;
  1511. }
  1512. /*
  1513. ** Free all resources currently held by the DbEvalContext structure passed
  1514. ** as the first argument. There should be exactly one call to this function
  1515. ** for each call to dbEvalInit().
  1516. */
  1517. static void dbEvalFinalize( DbEvalContext p )
  1518. {
  1519. if ( p.pPreStmt != null )
  1520. {
  1521. sqlite3_reset( p.pPreStmt.pStmt );
  1522. dbReleaseStmt( p.pDb, p.pPreStmt, 1 );
  1523. p.pPreStmt = null;
  1524. }
  1525. if ( p.pArray != null )
  1526. {
  1527. TCL.Tcl_DecrRefCount( ref p.pArray );
  1528. p.pArray = null;
  1529. }
  1530. TCL.Tcl_DecrRefCount( ref p.pSql );
  1531. dbReleaseColumnNames( p );
  1532. }
  1533. /*
  1534. ** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains
  1535. ** the value for the iCol'th column of the row currently pointed to by
  1536. ** the DbEvalContext structure passed as the first argument.
  1537. */
  1538. static Tcl_Obj dbEvalColumnValue( DbEvalContext p, int iCol )
  1539. {
  1540. sqlite3_stmt pStmt = p.pPreStmt.pStmt;
  1541. switch ( sqlite3_column_type( pStmt, iCol ) )
  1542. {
  1543. case SQLITE_BLOB:
  1544. {
  1545. int bytes = sqlite3_column_bytes( pStmt, iCol );
  1546. byte[] zBlob = sqlite3_column_blob( pStmt, iCol );
  1547. if ( null == zBlob )
  1548. bytes = 0;
  1549. return TCL.Tcl_NewByteArrayObj( zBlob, bytes );
  1550. }
  1551. case SQLITE_INTEGER:
  1552. {
  1553. sqlite_int64 v = sqlite3_column_int64( pStmt, iCol );
  1554. if ( v >= -2147483647 && v <= 2147483647 )
  1555. {
  1556. return TCL.Tcl_NewIntObj( (int)v );
  1557. }
  1558. else
  1559. {
  1560. return TCL.Tcl_NewWideIntObj( v );
  1561. }
  1562. }
  1563. case SQLITE_FLOAT:
  1564. {
  1565. return TCL.Tcl_NewDoubleObj( sqlite3_column_double( pStmt, iCol ) );
  1566. }
  1567. case SQLITE_NULL:
  1568. {
  1569. return dbTextToObj( p.pDb.zNull );
  1570. }
  1571. }
  1572. return dbTextToObj( sqlite3_column_text( pStmt, iCol ) );
  1573. }
  1574. /*
  1575. ** If using Tcl version 8.6 or greater, use the NR functions to avoid
  1576. ** recursive evalution of scripts by the [db eval] and [db trans]
  1577. ** commands. Even if the headers used while compiling the extension
  1578. ** are 8.6 or newer, the code still tests the Tcl version at runtime.
  1579. ** This allows stubs-enabled builds to be used with older Tcl libraries.
  1580. */
  1581. #if TCL_MAJOR_VERSION//>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6)
  1582. //# define SQLITE_TCL_NRE 1
  1583. static int DbUseNre(void){
  1584. int major, minor;
  1585. Tcl_GetVersion(&major, &minor, 0, 0);
  1586. return( (major==8 && minor>=6) || major>8 );
  1587. }
  1588. #else
  1589. /*
  1590. ** Compiling using headers earlier than 8.6. In this case NR cannot be
  1591. ** used, so DbUseNre() to always return zero. Add #defines for the other
  1592. ** Tcl_NRxxx() functions to prevent them from causing compilation errors,
  1593. ** even though the only invocations of them are within conditional blocks
  1594. ** of the form:
  1595. **
  1596. ** if( DbUseNre() ) { ... }
  1597. */
  1598. const int SQLITE_TCL_NRE = 0; //# define SQLITE_TCL_NRE 0
  1599. static bool DbUseNre()
  1600. {
  1601. return false;
  1602. } //# define DbUseNre() 0
  1603. //# define Tcl_NRAddCallback(a,b,c,d,e,f) 0
  1604. //# define Tcl_NREvalObj(a,b,c) 0
  1605. //# define Tcl_NRCreateCommand(a,b,c,d,e,f) 0
  1606. #endif
  1607. /*
  1608. ** This function is part of the implementation of the command:
  1609. **
  1610. ** $db eval SQL ?ARRAYNAME? SCRIPT
  1611. */
  1612. static int DbEvalNextCmd(
  1613. object[] data, /* data[0] is the (DbEvalContext) */
  1614. Tcl_Interp interp, /* Tcl interpreter */
  1615. int result /* Result so far */
  1616. )
  1617. {
  1618. int rc = result; /* Return code */
  1619. /* The first element of the data[] array is a pointer to a DbEvalContext
  1620. ** structure allocated using TCL.Tcl_Alloc(). The second element of data[]
  1621. ** is a pointer to a TCL.Tcl_Obj containing the script to run for each row
  1622. ** returned by the queries encapsulated in data[0]. */
  1623. DbEvalContext p = (DbEvalContext)data[0];
  1624. Tcl_Obj pScript = (Tcl_Obj)data[1];
  1625. Tcl_Obj pArray = p.pArray;
  1626. while ( ( rc == TCL.TCL_OK || rc == TCL.TCL_CONTINUE ) && TCL.TCL_OK == ( rc = dbEvalStep( p ) ) )
  1627. {
  1628. int i;
  1629. int nCol;
  1630. Tcl_Obj[] apColName;
  1631. dbEvalRowInfo( p, out nCol, out apColName );
  1632. for ( i = 0; i < nCol; i++ )
  1633. {
  1634. Tcl_Obj pVal = dbEvalColumnValue( p, i );
  1635. if ( pArray == null )
  1636. {
  1637. TCL.Tcl_ObjSetVar2( interp, apColName[i], null, pVal, 0 );
  1638. }
  1639. else
  1640. {
  1641. TCL.Tcl_ObjSetVar2( interp, pArray, apColName[i], pVal, 0 );
  1642. }
  1643. }
  1644. /* The required interpreter variables are now populated with the data
  1645. ** from the current row. If using NRE, schedule callbacks to evaluate
  1646. ** script pScript, then to invoke this function again to fetch the next
  1647. ** row (or clean up if there is no next row or the script throws an
  1648. ** exception). After scheduling the callbacks, return control to the
  1649. ** caller.
  1650. **
  1651. ** If not using NRE, evaluate pScript directly and continue with the
  1652. ** next iteration of this while(...) loop. */
  1653. if ( DbUseNre() )
  1654. {
  1655. Debugger.Break();
  1656. //TCL.Tcl_NRAddCallback(interp, DbEvalNextCmd, (void)p, (void)pScript, 0, 0);
  1657. //return TCL.Tcl_NREvalObj(interp, pScript, 0);
  1658. }
  1659. else
  1660. {
  1661. rc = TCL.Tcl_EvalObjEx( interp, pScript, 0 );
  1662. }
  1663. }
  1664. TCL.Tcl_DecrRefCount( ref pScript );
  1665. dbEvalFinalize( p );
  1666. TCL.Tcl_Free( ref p );
  1667. if ( rc == TCL.TCL_OK || rc == TCL.TCL_BREAK )
  1668. {
  1669. TCL.Tcl_ResetResult( interp );
  1670. rc = TCL.TCL_OK;
  1671. }
  1672. return rc;
  1673. }
  1674. /*
  1675. ** The "sqlite" command below creates a new Tcl command for each
  1676. ** connection it opens to an SQLite database. This routine is invoked
  1677. ** whenever one of those connection-specific commands is executed
  1678. ** in Tcl. For example, if you run Tcl code like this:
  1679. **
  1680. ** sqlite3 db1 "my_database"
  1681. ** db1 close
  1682. **
  1683. ** The first command opens a connection to the "my_database" database
  1684. ** and calls that connection "db1". The second command causes this
  1685. ** subroutine to be invoked.
  1686. */
  1687. enum DB_enum
  1688. {
  1689. DB_AUTHORIZER,
  1690. DB_BACKUP,
  1691. DB_BUSY,
  1692. DB_CACHE,
  1693. DB_CHANGES,
  1694. DB_CLOSE,
  1695. DB_COLLATE,
  1696. DB_COLLATION_NEEDED,
  1697. DB_COMMIT_HOOK,
  1698. DB_COMPLETE,
  1699. DB_COPY,
  1700. DB_ENABLE_LOAD_EXTENSION,
  1701. DB_ERRORCODE,
  1702. DB_EVAL,
  1703. DB_EXISTS,
  1704. DB_FUNCTION,
  1705. DB_INCRBLOB,
  1706. DB_INTERRUPT,
  1707. DB_LAST_INSERT_ROWID,
  1708. DB_NULLVALUE,
  1709. DB_ONECOLUMN,
  1710. DB_PROFILE,
  1711. DB_PROGRESS,
  1712. DB_REKEY,
  1713. DB_RESTORE,
  1714. DB_ROLLBACK_HOOK,
  1715. DB_STATUS,
  1716. DB_TIMEOUT,
  1717. DB_TOTAL_CHANGES,
  1718. DB_TRACE,
  1719. DB_TRANSACTION,
  1720. DB_UNLOCK_NOTIFY,
  1721. DB_UPDATE_HOOK,
  1722. DB_VERSION,
  1723. DB_WAL_HOOK
  1724. };
  1725. enum TTYPE_enum
  1726. {
  1727. TTYPE_DEFERRED,
  1728. TTYPE_EXCLUSIVE,
  1729. TTYPE_IMMEDIATE
  1730. };
  1731. static int DbObjCmd( object cd, Tcl_Interp interp, int objc, Tcl_Obj[] objv )
  1732. {
  1733. SqliteDb pDb = (SqliteDb)cd;
  1734. int choice = 0;
  1735. int rc = TCL.TCL_OK;
  1736. string[] DB_strs = {
  1737. "authorizer", "backup", "busy",
  1738. "cache", "changes", "close",
  1739. "collate", "collation_needed", "commit_hook",
  1740. "complete", "copy", "enable_load_extension",
  1741. "errorcode", "eval", "exists",
  1742. "function", "incrblob", "interrupt",
  1743. "last_insert_rowid", "nullvalue", "onecolumn",
  1744. "profile", "progress", "rekey",
  1745. "restore", "rollback_hook", "status",
  1746. "timeout", "total_changes", "trace",
  1747. "transaction", "unlock_notify", "update_hook",
  1748. "version", "wal_hook"
  1749. };
  1750. /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
  1751. if ( objc < 2 )
  1752. {
  1753. TCL.Tcl_WrongNumArgs( interp, 1, objv, "SUBCOMMAND ..." );
  1754. return TCL.TCL_ERROR;
  1755. }
  1756. if ( TCL.Tcl_GetIndexFromObj( interp, objv[1], DB_strs, "option", 0, out choice ) )
  1757. {
  1758. return TCL.TCL_ERROR;
  1759. }
  1760. switch ( choice )
  1761. {
  1762. /* $db authorizer ?CALLBACK?
  1763. **
  1764. ** Invoke the given callback to authorize each SQL operation as it is
  1765. ** compiled. 5 arguments are appended to the callback before it is
  1766. ** invoked:
  1767. **
  1768. ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)
  1769. ** (2) First descriptive name (depends on authorization type)
  1770. ** (3) Second descriptive name
  1771. ** (4) Name of the database (ex: "main", "temp")
  1772. ** (5) Name of trigger that is doing the access
  1773. **
  1774. ** The callback should return on of the following strings: SQLITE_OK,
  1775. ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error.
  1776. **
  1777. ** If this method is invoked with no arguments, the current authorization
  1778. ** callback string is returned.
  1779. */
  1780. case (int)DB_enum.DB_AUTHORIZER:
  1781. {
  1782. #if SQLITE_OMIT_AUTHORIZATION
  1783. TCL.Tcl_AppendResult( interp, "authorization not available in this build" );
  1784. return TCL.TCL_RETURN;
  1785. #else
  1786. if( objc>3 ){
  1787. TCL.Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
  1788. return TCL.TCL_ERROR;
  1789. }else if( objc==2 ){
  1790. if( pDb.zAuth ){
  1791. TCL.Tcl_AppendResult(interp, pDb.zAuth);
  1792. }
  1793. }else{
  1794. string zAuth;
  1795. int len;
  1796. if( pDb.zAuth ){
  1797. TCL.Tcl_Free(pDb.zAuth);
  1798. }
  1799. zAuth = TCL.Tcl_GetStringFromObj(objv[2], len);
  1800. if( zAuth && len>0 ){
  1801. pDb.zAuth = TCL.Tcl_Alloc( len + 1 );
  1802. memcpy(pDb.zAuth, zAuth, len+1);
  1803. }else{
  1804. pDb.zAuth = 0;
  1805. }
  1806. if( pDb.zAuth ){
  1807. pDb.interp = interp;
  1808. sqlite3_set_authorizer(pDb.db, auth_callback, pDb);
  1809. }else{
  1810. sqlite3_set_authorizer(pDb.db, 0, 0);
  1811. }
  1812. }
  1813. break;
  1814. #endif
  1815. }
  1816. /* $db backup ?DATABASE? FILENAME
  1817. **
  1818. ** Open or create a database file named FILENAME. Transfer the
  1819. ** content of local database DATABASE (default: "main") into the
  1820. ** FILENAME database.
  1821. */
  1822. case (int)DB_enum.DB_BACKUP:
  1823. {
  1824. string zDestFile;
  1825. string zSrcDb;
  1826. sqlite3 pDest = null;
  1827. sqlite3_backup pBackup;
  1828. if ( objc == 3 )
  1829. {
  1830. zSrcDb = "main";
  1831. zDestFile = TCL.Tcl_GetString( objv[2] );
  1832. }
  1833. else if ( objc == 4 )
  1834. {
  1835. zSrcDb = TCL.Tcl_GetString( objv[2] );
  1836. zDestFile = TCL.Tcl_GetString( objv[3] );
  1837. }
  1838. else
  1839. {
  1840. TCL.Tcl_WrongNumArgs( interp, 2, objv, "?DATABASE? FILENAME" );
  1841. return TCL.TCL_ERROR;
  1842. }
  1843. rc = sqlite3_open( zDestFile, out pDest );
  1844. if ( rc != SQLITE_OK )
  1845. {
  1846. TCL.Tcl_AppendResult( interp, "cannot open target database: ",
  1847. sqlite3_errmsg( pDest ) );
  1848. sqlite3_close( pDest );
  1849. return TCL.TCL_ERROR;
  1850. }
  1851. pBackup = sqlite3_backup_init( pDest, "main", pDb.db, zSrcDb );
  1852. if ( pBackup == null )
  1853. {
  1854. TCL.Tcl_AppendResult( interp, "backup failed: ",
  1855. sqlite3_errmsg( pDest ) );
  1856. sqlite3_close( pDest );
  1857. return TCL.TCL_ERROR;
  1858. }
  1859. #if SQLITE_HAS_CODEC
  1860. if ( pBackup.pSrc.pBt.pPager.pCodec != null )
  1861. {
  1862. pBackup.pDest.pBt.pPager.xCodec = pBackup.pSrc.pBt.pPager.xCodec;
  1863. pBackup.pDest.pBt.pPager.xCodecFree = pBackup.pSrc.pBt.pPager.xCodecFree;
  1864. pBackup.pDest.pBt.pPager.xCodecSizeChng = pBackup.pSrc.pBt.pPager.xCodecSizeChng;
  1865. pBackup.pDest.pBt.pPager.pCodec = pBackup.pSrc.pBt.pPager.pCodec.Copy();
  1866. }
  1867. #endif
  1868. while ( ( rc = sqlite3_backup_step( pBackup, 100 ) ) == SQLITE_OK )
  1869. {
  1870. }
  1871. sqlite3_backup_finish( pBackup );
  1872. if ( rc == SQLITE_DONE )
  1873. {
  1874. rc = TCL.TCL_OK;
  1875. }
  1876. else
  1877. {
  1878. TCL.Tcl_AppendResult( interp, "backup failed: ",
  1879. sqlite3_errmsg( pDest ) );
  1880. rc = TCL.TCL_ERROR;
  1881. }
  1882. sqlite3_close( pDest );
  1883. break;
  1884. }
  1885. // /* $db busy ?CALLBACK?
  1886. // **
  1887. // ** Invoke the given callback if an SQL statement attempts to open
  1888. // ** a locked database file.
  1889. // */
  1890. case (int)DB_enum.DB_BUSY:
  1891. {
  1892. if ( objc > 3 )
  1893. {
  1894. TCL.Tcl_WrongNumArgs( interp, 2, objv, "CALLBACK" );
  1895. return TCL.TCL_ERROR;
  1896. }
  1897. else if ( objc == 2 )
  1898. {
  1899. if ( pDb.zBusy != null )
  1900. {
  1901. TCL.Tcl_AppendResult( interp, pDb.zBusy );
  1902. }
  1903. }
  1904. else
  1905. {
  1906. string zBusy;
  1907. int len = 0;
  1908. if ( pDb.zBusy != null )
  1909. {
  1910. TCL.Tcl_Free( ref pDb.zBusy );
  1911. }
  1912. zBusy = TCL.Tcl_GetStringFromObj( objv[2], out len );
  1913. if ( zBusy != null && len > 0 )
  1914. {
  1915. //pDb.zBusy = TCL.Tcl_Alloc( len + 1 );
  1916. pDb.zBusy = zBusy;// memcpy( pDb.zBusy, zBusy, len + 1 );
  1917. }
  1918. else
  1919. {
  1920. pDb.zBusy = null;
  1921. }
  1922. if ( pDb.zBusy != null )
  1923. {
  1924. pDb.interp = interp;
  1925. sqlite3_busy_handler( pDb.db, (dxBusy)DbBusyHandler, pDb );
  1926. }
  1927. else
  1928. {
  1929. sqlite3_busy_handler( pDb.db, null, null );
  1930. }
  1931. }
  1932. break;
  1933. }
  1934. // /* $db cache flush
  1935. // ** $db cache size n
  1936. // **
  1937. // ** Flush the prepared statement cache, or set the maximum number of
  1938. // ** cached statements.
  1939. // */
  1940. case (int)DB_enum.DB_CACHE:
  1941. {
  1942. string subCmd;
  1943. int n = 0;
  1944. if ( objc <= 2 )
  1945. {
  1946. TCL.Tcl_WrongNumArgs( interp, 1, objv, "cache option ?arg?" );
  1947. return TCL.TCL_ERROR;
  1948. }
  1949. subCmd = TCL.Tcl_GetStringFromObj( objv[2], 0 );
  1950. if ( subCmd == "flush" )
  1951. {
  1952. if ( objc != 3 )
  1953. {
  1954. TCL.Tcl_WrongNumArgs( interp, 2, objv, "flush" );
  1955. return TCL.TCL_ERROR;
  1956. }
  1957. else
  1958. {
  1959. flushStmtCache( pDb );
  1960. }
  1961. }
  1962. else if ( subCmd == "size" )
  1963. {
  1964. if ( objc != 4 )
  1965. {
  1966. TCL.Tcl_WrongNumArgs( interp, 2, objv, "size n" );
  1967. return TCL.TCL_ERROR;
  1968. }
  1969. else
  1970. {
  1971. if ( TCL.TCL_ERROR == ( TCL.Tcl_GetIntFromObj( interp, objv[3], out n ) != TCL.TCL_OK ? TCL.TCL_ERROR : TCL.TCL_OK ) )
  1972. {
  1973. TCL.Tcl_AppendResult( interp, "cannot convert \"",
  1974. TCL.Tcl_GetStringFromObj( objv[3], 0 ), "\" to integer", 0 );
  1975. return TCL.TCL_ERROR;
  1976. }
  1977. else
  1978. {
  1979. if ( n < 0 )
  1980. {
  1981. flushStmtCache( pDb );
  1982. n = 0;
  1983. }
  1984. else if ( n > MAX_PREPARED_STMTS )
  1985. {
  1986. n = MAX_PREPARED_STMTS;
  1987. }
  1988. pDb.maxStmt = n;
  1989. }
  1990. }
  1991. }
  1992. else
  1993. {
  1994. TCL.Tcl_AppendResult( interp, "bad option \"",
  1995. TCL.Tcl_GetStringFromObj( objv[2], 0 ), "\": must be flush or size", null );
  1996. return TCL.TCL_ERROR;
  1997. }
  1998. break;
  1999. }
  2000. /* $db changes
  2001. **
  2002. ** Return the number of rows that were modified, inserted, or deleted by
  2003. ** the most recent INSERT, UPDATE or DELETE statement, not including
  2004. ** any changes made by trigger programs.
  2005. */
  2006. case (int)DB_enum.DB_CHANGES:
  2007. {
  2008. Tcl_Obj pResult;
  2009. if ( objc != 2 )
  2010. {
  2011. TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
  2012. return TCL.TCL_ERROR;
  2013. }
  2014. pResult = TCL.Tcl_GetObjResult( interp );
  2015. TCL.Tcl_SetResult( interp, sqlite3_changes( pDb.db ).ToString(), 0 );
  2016. break;
  2017. }
  2018. /* $db close
  2019. **
  2020. ** Shutdown the database
  2021. */
  2022. case (int)DB_enum.DB_CLOSE:
  2023. {
  2024. TCL.Tcl_DeleteCommand( interp, TCL.Tcl_GetStringFromObj( objv[0], 0 ) );
  2025. break;
  2026. }
  2027. /*
  2028. ** $db collate NAME SCRIPT
  2029. **
  2030. ** Create a new SQL collation function called NAME. Whenever
  2031. ** that function is called, invoke SCRIPT to evaluate the function.
  2032. */
  2033. case (int)DB_enum.DB_COLLATE:
  2034. {
  2035. SqlCollate pCollate;
  2036. string zName;
  2037. string zScript;
  2038. int nScript = 0;
  2039. if ( objc != 4 )
  2040. {
  2041. TCL.Tcl_WrongNumArgs( interp, 2, objv, "NAME SCRIPT" );
  2042. return TCL.TCL_ERROR;
  2043. }
  2044. zName = TCL.Tcl_GetStringFromObj( objv[2], 0 );
  2045. zScript = TCL.Tcl_GetStringFromObj( objv[3], nScript );
  2046. pCollate = new SqlCollate();//(SqlCollate)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );
  2047. //if ( pCollate == null ) return TCL.TCL_ERROR;
  2048. pCollate.interp = interp;
  2049. pCollate.pNext = pDb.pCollate;
  2050. pCollate.zScript = zScript; // pCollate[1];
  2051. pDb.pCollate = pCollate;
  2052. //memcpy( pCollate.zScript, zScript, nScript + 1 );
  2053. if ( sqlite3_create_collation( pDb.db, zName, SQLITE_UTF8,
  2054. pCollate, (dxCompare)tclSqlCollate ) != 0 )
  2055. {
  2056. TCL.Tcl_SetResult( interp, sqlite3_errmsg( pDb.db ), TCL.TCL_VOLATILE );
  2057. return TCL.TCL_ERROR;
  2058. }
  2059. break;
  2060. }
  2061. /*
  2062. ** $db collation_needed SCRIPT
  2063. **
  2064. ** Create a new SQL collation function called NAME. Whenever
  2065. ** that function is called, invoke SCRIPT to evaluate the function.
  2066. */
  2067. case (int)DB_enum.DB_COLLATION_NEEDED:
  2068. {
  2069. if ( objc != 3 )
  2070. {
  2071. TCL.Tcl_WrongNumArgs( interp, 2, objv, "SCRIPT" );
  2072. return TCL.TCL_ERROR;
  2073. }
  2074. if ( pDb.pCollateNeeded != null )
  2075. {
  2076. TCL.Tcl_DecrRefCount( ref pDb.pCollateNeeded );
  2077. }
  2078. pDb.pCollateNeeded = TCL.Tcl_DuplicateObj( objv[2] );
  2079. TCL.Tcl_IncrRefCount( pDb.pCollateNeeded );
  2080. sqlite3_collation_needed( pDb.db, (object)pDb, (dxCollNeeded)tclCollateNeeded );
  2081. break;
  2082. }
  2083. /* $db commit_hook ?CALLBACK?
  2084. **
  2085. ** Invoke the given callback just before committing every SQL transaction.
  2086. ** If the callback throws an exception or returns non-zero, then the
  2087. ** transaction is aborted. If CALLBACK is an empty string, the callback
  2088. ** is disabled.
  2089. */
  2090. case (int)DB_enum.DB_COMMIT_HOOK:
  2091. {
  2092. if ( objc > 3 )
  2093. {
  2094. TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
  2095. return TCL.TCL_ERROR;
  2096. }
  2097. else if ( objc == 2 )
  2098. {
  2099. if ( pDb.zCommit != null )
  2100. {
  2101. TCL.Tcl_AppendResult( interp, pDb.zCommit );
  2102. }
  2103. }
  2104. else
  2105. {
  2106. string zCommit;
  2107. int len = 0;
  2108. if ( pDb.zCommit != null )
  2109. {
  2110. TCL.Tcl_Free( ref pDb.zCommit );
  2111. }
  2112. zCommit = TCL.Tcl_GetStringFromObj( objv[2], out len );
  2113. if ( zCommit != null && len > 0 )
  2114. {
  2115. pDb.zCommit = zCommit;// TCL.Tcl_Alloc( len + 1 );
  2116. //memcpy( pDb.zCommit, zCommit, len + 1 );
  2117. }
  2118. else
  2119. {
  2120. pDb.zCommit = null;
  2121. }
  2122. if ( pDb.zCommit != null )
  2123. {
  2124. pDb.interp = interp;
  2125. sqlite3_commit_hook( pDb.db, DbCommitHandler, pDb );
  2126. }
  2127. else
  2128. {
  2129. sqlite3_commit_hook( pDb.db, null, null );
  2130. }
  2131. }
  2132. break;
  2133. }
  2134. /* $db complete SQL
  2135. **
  2136. ** Return TRUE if SQL is a complete SQL statement. Return FALSE if
  2137. ** additional lines of input are needed. This is similar to the
  2138. ** built-in "info complete" command of Tcl.
  2139. */
  2140. case (int)DB_enum.DB_COMPLETE:
  2141. {
  2142. #if !SQLITE_OMIT_COMPLETE
  2143. Tcl_Obj pResult;
  2144. int isComplete;
  2145. if ( objc != 3 )
  2146. {
  2147. TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL" );
  2148. return TCL.TCL_ERROR;
  2149. }
  2150. isComplete = sqlite3_complete( TCL.Tcl_GetStringFromObj( objv[2], 0 ) );
  2151. pResult = TCL.Tcl_GetObjResult( interp );
  2152. TCL.Tcl_SetBooleanObj( pResult, isComplete );
  2153. #endif
  2154. break;
  2155. }
  2156. /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
  2157. **
  2158. ** Copy data into table from filename, optionally using SEPARATOR
  2159. ** as column separators. If a column contains a null string, or the
  2160. ** value of NULLINDICATOR, a NULL is inserted for the column.
  2161. ** conflict-algorithm is one of the sqlite conflict algorithms:
  2162. ** rollback, abort, fail, ignore, replace
  2163. ** On success, return the number of lines processed, not necessarily same
  2164. ** as 'db changes' due to conflict-algorithm selected.
  2165. **
  2166. ** This code is basically an implementation/enhancement of
  2167. ** the sqlite3 shell.c ".import" command.
  2168. **
  2169. ** This command usage is equivalent to the sqlite2.x COPY statement,
  2170. ** which imports file data into a table using the PostgreSQL COPY file format:
  2171. ** $db copy $conflit_algo $table_name $filename \t \\N
  2172. */
  2173. case (int)DB_enum.DB_COPY:
  2174. {
  2175. string zTable; /* Insert data into this table */
  2176. string zFile; /* The file from which to extract data */
  2177. string zConflict; /* The conflict algorithm to use */
  2178. sqlite3_stmt pStmt = null; /* A statement */
  2179. int nCol; /* Number of columns in the table */
  2180. int nByte; /* Number of bytes in an SQL string */
  2181. int i, j; /* Loop counters */
  2182. int nSep; /* Number of bytes in zSep[] */
  2183. int nNull; /* Number of bytes in zNull[] */
  2184. StringBuilder zSql = new StringBuilder( 200 ); /* An SQL statement */
  2185. string zLine; /* A single line of input from the file */
  2186. string[] azCol; /* zLine[] broken up into columns */
  2187. string zCommit; /* How to commit changes */
  2188. TextReader _in; /* The input file */
  2189. int lineno = 0; /* Line number of input file */
  2190. StringBuilder zLineNum = new StringBuilder( 80 ); /* Line number print buffer */
  2191. Tcl_Obj pResult; /* interp result */
  2192. string zSep;
  2193. string zNull;
  2194. if ( objc < 5 || objc > 7 )
  2195. {
  2196. TCL.Tcl_WrongNumArgs( interp, 2, objv,
  2197. "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?" );
  2198. return TCL.TCL_ERROR;
  2199. }
  2200. if ( objc >= 6 )
  2201. {
  2202. zSep = TCL.Tcl_GetStringFromObj( objv[5], 0 );
  2203. }
  2204. else
  2205. {
  2206. zSep = "\t";
  2207. }
  2208. if ( objc >= 7 )
  2209. {
  2210. zNull = TCL.Tcl_GetStringFromObj( objv[6], 0 );
  2211. }
  2212. else
  2213. {
  2214. zNull = "";
  2215. }
  2216. zConflict = TCL.Tcl_GetStringFromObj( objv[2], 0 );
  2217. zTable = TCL.Tcl_GetStringFromObj( objv[3], 0 );
  2218. zFile = TCL.Tcl_GetStringFromObj( objv[4], 0 );
  2219. nSep = strlen30( zSep );
  2220. nNull = strlen30( zNull );
  2221. if ( nSep == 0 )
  2222. {
  2223. TCL.Tcl_AppendResult( interp, "Error: non-null separator required for copy" );
  2224. return TCL.TCL_ERROR;
  2225. }
  2226. if ( zConflict != "rollback" &&
  2227. zConflict != "abort" &&
  2228. zConflict != "fail" &&
  2229. zConflict != "ignore" &&
  2230. zConflict != "replace" )
  2231. {
  2232. TCL.Tcl_AppendResult( interp, "Error: \"", zConflict,
  2233. "\", conflict-algorithm must be one of: rollback, " +
  2234. "abort, fail, ignore, or replace", 0 );
  2235. return TCL.TCL_ERROR;
  2236. }
  2237. zSql.Append( sqlite3_mprintf( "SELECT * FROM '%q'", zTable ) );
  2238. if ( zSql == null )
  2239. {
  2240. TCL.Tcl_AppendResult( interp, "Error: no such table: ", zTable );
  2241. return TCL.TCL_ERROR;
  2242. }
  2243. nByte = strlen30( zSql );
  2244. rc = sqlite3_prepare( pDb.db, zSql.ToString(), -1, ref pStmt, 0 );
  2245. sqlite3DbFree( null, ref zSql );
  2246. if ( rc != 0 )
  2247. {
  2248. TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
  2249. nCol = 0;
  2250. }
  2251. else
  2252. {
  2253. nCol = sqlite3_column_count( pStmt );
  2254. }
  2255. sqlite3_finalize( pStmt );
  2256. if ( nCol == 0 )
  2257. {
  2258. return TCL.TCL_ERROR;
  2259. }
  2260. //zSql.Append(malloc( nByte + 50 + nCol*2 );
  2261. //if( zSql==0 ) {
  2262. // TCL.Tcl_AppendResult(interp, "Error: can't malloc()");
  2263. // return TCL.TCL_ERROR;
  2264. //}
  2265. sqlite3_snprintf( nByte + 50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
  2266. zConflict, zTable );
  2267. j = strlen30( zSql );
  2268. for ( i = 1; i < nCol; i++ )
  2269. {
  2270. //zSql+=[j++] = ',';
  2271. //zSql[j++] = '?';
  2272. zSql.Append( ",?" );
  2273. }
  2274. //zSql[j++] = ')';
  2275. //zSql[j] = "";
  2276. zSql.Append( ")" );
  2277. rc = sqlite3_prepare( pDb.db, zSql.ToString(), -1, ref pStmt, 0 );
  2278. //free(zSql);
  2279. if ( rc != 0 )
  2280. {
  2281. TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
  2282. sqlite3_finalize( pStmt );
  2283. return TCL.TCL_ERROR;
  2284. }
  2285. _in = new StreamReader( zFile );//fopen(zFile, "rb");
  2286. if ( _in == null )
  2287. {
  2288. TCL.Tcl_AppendResult( interp, "Error: cannot open file: ", zFile );
  2289. sqlite3_finalize( pStmt );
  2290. return TCL.TCL_ERROR;
  2291. }
  2292. azCol = new string[nCol + 1];//malloc( sizeof(azCol[0])*(nCol+1) );
  2293. if ( azCol == null )
  2294. {
  2295. TCL.Tcl_AppendResult( interp, "Error: can't malloc()" );
  2296. _in.Close();//fclose(_in);
  2297. return TCL.TCL_ERROR;
  2298. }
  2299. sqlite3_exec( pDb.db, "BEGIN", 0, 0, 0 );
  2300. zCommit = "COMMIT";
  2301. while ( ( zLine = _in.ReadLine() ) != null )//local_getline(0, _in))!=0 )
  2302. {
  2303. string z;
  2304. i = 0;
  2305. lineno++;
  2306. azCol = zLine.Split( zSep[0] );
  2307. //for(i=0, z=zLine; *z; z++){
  2308. // if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
  2309. // *z = 0;
  2310. // i++;
  2311. // if( i<nCol ){
  2312. // azCol[i] = z[nSep];
  2313. // z += nSep-1;
  2314. // }
  2315. // }
  2316. //}
  2317. if ( azCol.Length != nCol )
  2318. {
  2319. StringBuilder zErr = new StringBuilder( 200 );
  2320. int nErr = strlen30( zFile ) + 200;
  2321. //zErr = malloc(nErr);
  2322. //if( zErr ){
  2323. sqlite3_snprintf( nErr, zErr,
  2324. "Error: %s line %d: expected %d columns of data but found %d",
  2325. zFile, lineno, nCol, i + 1 );
  2326. TCL.Tcl_AppendResult( interp, zErr );
  2327. // free(zErr);
  2328. //}
  2329. zCommit = "ROLLBACK";
  2330. break;
  2331. }
  2332. for ( i = 0; i < nCol; i++ )
  2333. {
  2334. /* check for null data, if so, bind as null */
  2335. if ( ( nNull > 0 && azCol[i] == zNull )
  2336. || strlen30( azCol[i] ) == 0
  2337. )
  2338. {
  2339. sqlite3_bind_null( pStmt, i + 1 );
  2340. }
  2341. else
  2342. {
  2343. sqlite3_bind_text( pStmt, i + 1, azCol[i], -1, SQLITE_STATIC );
  2344. }
  2345. }
  2346. sqlite3_step( pStmt );
  2347. rc = sqlite3_reset( pStmt );
  2348. //free(zLine);
  2349. if ( rc != SQLITE_OK )
  2350. {
  2351. TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
  2352. zCommit = "ROLLBACK";
  2353. break;
  2354. }
  2355. }
  2356. //free(azCol);
  2357. _in.Close();// fclose( _in );
  2358. sqlite3_finalize( pStmt );
  2359. sqlite3_exec( pDb.db, zCommit, 0, 0, 0 );
  2360. if ( zCommit[0] == 'C' )
  2361. {
  2362. /* success, set result as number of lines processed */
  2363. pResult = TCL.Tcl_GetObjResult( interp );
  2364. TCL.Tcl_SetIntObj( pResult, lineno );
  2365. rc = TCL.TCL_OK;
  2366. }
  2367. else
  2368. {
  2369. /* failure, append lineno where failed */
  2370. sqlite3_snprintf( 80, zLineNum, "%d", lineno );
  2371. TCL.Tcl_AppendResult( interp, ", failed while processing line: ", zLineNum );
  2372. rc = TCL.TCL_ERROR;
  2373. }
  2374. break;
  2375. }
  2376. /*
  2377. ** $db enable_load_extension BOOLEAN
  2378. **
  2379. ** Turn the extension loading feature on or off. It if off by
  2380. ** default.
  2381. */
  2382. case (int)DB_enum.DB_ENABLE_LOAD_EXTENSION:
  2383. {
  2384. #if !SQLITE_OMIT_LOAD_EXTENSION
  2385. bool onoff = false;
  2386. if ( objc != 3 )
  2387. {
  2388. TCL.Tcl_WrongNumArgs( interp, 2, objv, "BOOLEAN" );
  2389. return TCL.TCL_ERROR;
  2390. }
  2391. if ( TCL.Tcl_GetBooleanFromObj( interp, objv[2], out onoff ) )
  2392. {
  2393. return TCL.TCL_ERROR;
  2394. }
  2395. sqlite3_enable_load_extension( pDb.db, onoff ? 1 : 0 );
  2396. break;
  2397. #else
  2398. TCL.Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
  2399. 0);
  2400. return TCL.TCL_ERROR;
  2401. #endif
  2402. }
  2403. /*
  2404. ** $db errorcode
  2405. **
  2406. ** Return the numeric error code that was returned by the most recent
  2407. ** call to sqlite3_exec().
  2408. */
  2409. case (int)DB_enum.DB_ERRORCODE:
  2410. {
  2411. TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_errcode( pDb.db ) ) );
  2412. break;
  2413. }
  2414. /*
  2415. ** $db exists $sql
  2416. ** $db onecolumn $sql
  2417. **
  2418. ** The onecolumn method is the equivalent of:
  2419. ** lindex [$db eval $sql] 0
  2420. */
  2421. case (int)DB_enum.DB_EXISTS:
  2422. case (int)DB_enum.DB_ONECOLUMN:
  2423. {
  2424. DbEvalContext sEval = new DbEvalContext();
  2425. ;
  2426. if ( objc != 3 )
  2427. {
  2428. TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL" );
  2429. return TCL.TCL_ERROR;
  2430. }
  2431. dbEvalInit( sEval, pDb, objv[2], null );
  2432. rc = dbEvalStep( sEval );
  2433. if ( choice == (int)DB_enum.DB_ONECOLUMN )
  2434. {
  2435. if ( rc == TCL.TCL_OK )
  2436. {
  2437. TCL.Tcl_SetObjResult( interp, dbEvalColumnValue( sEval, 0 ) );
  2438. }
  2439. }
  2440. else if ( rc == TCL.TCL_BREAK || rc == TCL.TCL_OK )
  2441. {
  2442. TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( ( rc == TCL.TCL_OK ? 1 : 0 ) ) );
  2443. }
  2444. dbEvalFinalize( sEval );
  2445. if ( rc == TCL.TCL_BREAK )
  2446. {
  2447. rc = TCL.TCL_OK;
  2448. }
  2449. break;
  2450. }
  2451. /*
  2452. ** $db eval $sql ?array? ?{ ...code... }?
  2453. **
  2454. ** The SQL statement in $sql is evaluated. For each row, the values are
  2455. ** placed in elements of the array named "array" and ...code... is executed.
  2456. ** If "array" and "code" are omitted, then no callback is every invoked.
  2457. ** If "array" is an empty string, then the values are placed in variables
  2458. ** that have the same name as the fields extracted by the query.
  2459. */
  2460. case (int)DB_enum.DB_EVAL:
  2461. {
  2462. if ( objc < 3 || objc > 5 )
  2463. {
  2464. TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?" );
  2465. return TCL.TCL_ERROR;
  2466. }
  2467. if ( objc == 3 )
  2468. {
  2469. DbEvalContext sEval = new DbEvalContext();
  2470. Tcl_Obj pRet = TCL.Tcl_NewObj();
  2471. TCL.Tcl_IncrRefCount( pRet );
  2472. dbEvalInit( sEval, pDb, objv[2], null );
  2473. //Console.WriteLine( objv[2].ToString() );
  2474. while ( TCL.TCL_OK == ( rc = dbEvalStep( sEval ) ) )
  2475. {
  2476. int i;
  2477. int nCol;
  2478. TclObject[] pDummy;
  2479. dbEvalRowInfo( sEval, out nCol, out pDummy );
  2480. for ( i = 0; i < nCol; i++ )
  2481. {
  2482. TCL.Tcl_ListObjAppendElement( interp, pRet, dbEvalColumnValue( sEval, i ) );
  2483. }
  2484. }
  2485. dbEvalFinalize( sEval );
  2486. if ( rc == TCL.TCL_BREAK )
  2487. {
  2488. TCL.Tcl_SetObjResult( interp, pRet );
  2489. rc = TCL.TCL_OK;
  2490. }
  2491. TCL.Tcl_DecrRefCount( ref pRet );
  2492. }
  2493. else
  2494. {
  2495. cd = new object[2];
  2496. DbEvalContext p;
  2497. Tcl_Obj pArray = null;
  2498. Tcl_Obj pScript;
  2499. if ( objc == 5 && !String.IsNullOrEmpty( TCL.Tcl_GetString( objv[3] ) ) )
  2500. {
  2501. pArray = objv[3];
  2502. }
  2503. pScript = objv[objc - 1];
  2504. TCL.Tcl_IncrRefCount( pScript );
  2505. p = new DbEvalContext();// (DbEvalContext)Tcl_Alloc( sizeof( DbEvalContext ) );
  2506. dbEvalInit( p, pDb, objv[2], pArray );
  2507. ( (object[])cd )[0] = p;
  2508. ( (object[])cd )[1] = pScript;
  2509. rc = DbEvalNextCmd( (object[])cd, interp, TCL.TCL_OK );
  2510. }
  2511. break;
  2512. }
  2513. /*
  2514. ** $db function NAME [-argcount N] SCRIPT
  2515. **
  2516. ** Create a new SQL function called NAME. Whenever that function is
  2517. ** called, invoke SCRIPT to evaluate the function.
  2518. */
  2519. case (int)DB_enum.DB_FUNCTION:
  2520. {
  2521. SqlFunc pFunc;
  2522. Tcl_Obj pScript;
  2523. string zName;
  2524. int nArg = -1;
  2525. if ( objc == 6 )
  2526. {
  2527. string z = TCL.Tcl_GetString( objv[3] );
  2528. int n = strlen30( z );
  2529. if ( n > 2 && z.StartsWith( "-argcount" ) )//strncmp( z, "-argcount", n ) == 0 )
  2530. {
  2531. if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[4], out nArg ) )
  2532. return TCL.TCL_ERROR;
  2533. if ( nArg < 0 )
  2534. {
  2535. TCL.Tcl_AppendResult( interp, "number of arguments must be non-negative" );
  2536. return TCL.TCL_ERROR;
  2537. }
  2538. }
  2539. pScript = objv[5];
  2540. }
  2541. else if ( objc != 4 )
  2542. {
  2543. TCL.Tcl_WrongNumArgs( interp, 2, objv, "NAME [-argcount N] SCRIPT" );
  2544. return TCL.TCL_ERROR;
  2545. }
  2546. else
  2547. {
  2548. pScript = objv[3];
  2549. }
  2550. zName = TCL.Tcl_GetStringFromObj( objv[2], 0 );
  2551. pFunc = findSqlFunc( pDb, zName );
  2552. if ( pFunc == null )
  2553. return TCL.TCL_ERROR;
  2554. if ( pFunc.pScript != null )
  2555. {
  2556. TCL.Tcl_DecrRefCount( ref pFunc.pScript );
  2557. }
  2558. pFunc.pScript = pScript;
  2559. TCL.Tcl_IncrRefCount( pScript );
  2560. pFunc.useEvalObjv = safeToUseEvalObjv( interp, pScript );
  2561. rc = sqlite3_create_function( pDb.db, zName, nArg, SQLITE_UTF8,
  2562. pFunc, tclSqlFunc, null, null );
  2563. if ( rc != SQLITE_OK )
  2564. {
  2565. rc = TCL.TCL_ERROR;
  2566. TCL.Tcl_SetResult( interp, sqlite3_errmsg( pDb.db ), TCL.TCL_VOLATILE );
  2567. }
  2568. break;
  2569. }
  2570. /*
  2571. ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID
  2572. */
  2573. case (int)DB_enum.DB_INCRBLOB:
  2574. {
  2575. #if SQLITE_OMIT_INCRBLOB
  2576. TCL.Tcl_AppendResult( interp, "incrblob not available in this build" );
  2577. return TCL.TCL_ERROR;
  2578. #else
  2579. int isReadonly = 0;
  2580. string zDb = "main" ;
  2581. string zTable;
  2582. string zColumn;
  2583. long iRow = 0;
  2584. /* Check for the -readonly option */
  2585. if ( objc > 3 && TCL.Tcl_GetString( objv[2] ) == "-readonly" )
  2586. {
  2587. isReadonly = 1;
  2588. }
  2589. if ( objc != ( 5 + isReadonly ) && objc != ( 6 + isReadonly ) )
  2590. {
  2591. TCL.Tcl_WrongNumArgs( interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID" );
  2592. return TCL.TCL_ERROR;
  2593. }
  2594. if ( objc == ( 6 + isReadonly ) )
  2595. {
  2596. zDb = TCL.Tcl_GetString( objv[2] ) ;
  2597. }
  2598. zTable = TCL.Tcl_GetString( objv[objc - 3] );
  2599. zColumn = TCL.Tcl_GetString( objv[objc - 2] ) ;
  2600. rc = TCL.Tcl_GetWideIntFromObj( interp, objv[objc - 1], out iRow ) ? 1 : 0;
  2601. if ( rc == TCL.TCL_OK )
  2602. {
  2603. rc = createIncrblobChannel(
  2604. interp, pDb, zDb, zTable, zColumn, iRow, isReadonly
  2605. );
  2606. }
  2607. break;
  2608. #endif
  2609. }
  2610. /*
  2611. ** $db interrupt
  2612. **
  2613. ** Interrupt the execution of the inner-most SQL interpreter. This
  2614. ** causes the SQL statement to return an error of SQLITE_INTERRUPT.
  2615. */
  2616. case (int)DB_enum.DB_INTERRUPT:
  2617. {
  2618. sqlite3_interrupt( pDb.db );
  2619. break;
  2620. }
  2621. /*
  2622. ** $db nullvalue ?STRING?
  2623. **
  2624. ** Change text used when a NULL comes back from the database. If ?STRING?
  2625. ** is not present, then the current string used for NULL is returned.
  2626. ** If STRING is present, then STRING is returned.
  2627. **
  2628. */
  2629. case (int)DB_enum.DB_NULLVALUE:
  2630. {
  2631. if ( objc != 2 && objc != 3 )
  2632. {
  2633. TCL.Tcl_WrongNumArgs( interp, 2, objv, "NULLVALUE" );
  2634. return TCL.TCL_ERROR;
  2635. }
  2636. if ( objc == 3 )
  2637. {
  2638. int len = 0;
  2639. string zNull = TCL.Tcl_GetStringFromObj( objv[2], out len );
  2640. if ( pDb.zNull != null )
  2641. {
  2642. TCL.Tcl_Free( ref pDb.zNull );
  2643. }
  2644. if ( zNull != null && len > 0 )
  2645. {
  2646. pDb.zNull = zNull;
  2647. //pDb.zNull = TCL.Tcl_Alloc( len + 1 );
  2648. //memcpy(pDb->zNull, zNull, len);
  2649. //pDb.zNull[len] = '\0';
  2650. }
  2651. else
  2652. {
  2653. pDb.zNull = null;
  2654. }
  2655. }
  2656. TCL.Tcl_SetObjResult( interp, dbTextToObj( pDb.zNull ) );
  2657. break;
  2658. }
  2659. /*
  2660. ** $db last_insert_rowid
  2661. **
  2662. ** Return an integer which is the ROWID for the most recent insert.
  2663. */
  2664. case (int)DB_enum.DB_LAST_INSERT_ROWID:
  2665. {
  2666. Tcl_Obj pResult;
  2667. Tcl_WideInt rowid;
  2668. if ( objc != 2 )
  2669. {
  2670. TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
  2671. return TCL.TCL_ERROR;
  2672. }
  2673. rowid = sqlite3_last_insert_rowid( pDb.db );
  2674. pResult = TCL.Tcl_GetObjResult( interp );
  2675. TCL.Tcl_SetLongObj( pResult, rowid );
  2676. break;
  2677. }
  2678. /*
  2679. ** The DB_ONECOLUMN method is implemented together with DB_EXISTS.
  2680. */
  2681. /* $db progress ?N CALLBACK?
  2682. **
  2683. ** Invoke the given callback every N virtual machine opcodes while executing
  2684. ** queries.
  2685. */
  2686. case (int)DB_enum.DB_PROGRESS:
  2687. {
  2688. if ( objc == 2 )
  2689. {
  2690. if ( !String.IsNullOrEmpty( pDb.zProgress ) )
  2691. {
  2692. TCL.Tcl_AppendResult( interp, pDb.zProgress );
  2693. }
  2694. }
  2695. else if ( objc == 4 )
  2696. {
  2697. string zProgress;
  2698. int len = 0;
  2699. int N = 0;
  2700. if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out N ) )
  2701. {
  2702. return TCL.TCL_ERROR;
  2703. };
  2704. if ( !String.IsNullOrEmpty( pDb.zProgress ) )
  2705. {
  2706. TCL.Tcl_Free( ref pDb.zProgress );
  2707. }
  2708. zProgress = TCL.Tcl_GetStringFromObj( objv[3], len );
  2709. if ( !String.IsNullOrEmpty( zProgress ) )
  2710. {
  2711. //pDb.zProgress = TCL.Tcl_Alloc( len + 1 );
  2712. //memcpy( pDb.zProgress, zProgress, len + 1 );
  2713. pDb.zProgress = zProgress;
  2714. }
  2715. else
  2716. {
  2717. pDb.zProgress = null;
  2718. }
  2719. #if !SQLITE_OMIT_PROGRESS_CALLBACK
  2720. if ( !String.IsNullOrEmpty( pDb.zProgress ) )
  2721. {
  2722. pDb.interp = interp;
  2723. sqlite3_progress_handler( pDb.db, N, DbProgressHandler, pDb );
  2724. }
  2725. else
  2726. {
  2727. sqlite3_progress_handler( pDb.db, 0, null, 0 );
  2728. }
  2729. #endif
  2730. }
  2731. else
  2732. {
  2733. TCL.Tcl_WrongNumArgs( interp, 2, objv, "N CALLBACK" );
  2734. return TCL.TCL_ERROR;
  2735. }
  2736. break;
  2737. }
  2738. /* $db profile ?CALLBACK?
  2739. **
  2740. ** Make arrangements to invoke the CALLBACK routine after each SQL statement
  2741. ** that has run. The text of the SQL and the amount of elapse time are
  2742. ** appended to CALLBACK before the script is run.
  2743. */
  2744. case (int)DB_enum.DB_PROFILE:
  2745. {
  2746. if ( objc > 3 )
  2747. {
  2748. TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
  2749. return TCL.TCL_ERROR;
  2750. }
  2751. else if ( objc == 2 )
  2752. {
  2753. if ( !String.IsNullOrEmpty( pDb.zProfile ) )
  2754. {
  2755. TCL.Tcl_AppendResult( interp, pDb.zProfile );
  2756. }
  2757. }
  2758. else
  2759. {
  2760. string zProfile;
  2761. int len = 0;
  2762. if ( !String.IsNullOrEmpty( pDb.zProfile ) )
  2763. {
  2764. TCL.Tcl_Free( ref pDb.zProfile );
  2765. }
  2766. zProfile = TCL.Tcl_GetStringFromObj( objv[2], out len );
  2767. if ( !String.IsNullOrEmpty( zProfile ) && len > 0 )
  2768. {
  2769. //pDb.zProfile = TCL.Tcl_Alloc( len + 1 );
  2770. //memcpy( pDb.zProfile, zProfile, len + 1 );
  2771. pDb.zProfile = zProfile;
  2772. }
  2773. else
  2774. {
  2775. pDb.zProfile = null;
  2776. }
  2777. #if !SQLITE_OMIT_TRACE && !(SQLITE_OMIT_FLOATING_POINT)
  2778. if ( !String.IsNullOrEmpty( pDb.zProfile ) )
  2779. {
  2780. pDb.interp = interp;
  2781. sqlite3_profile( pDb.db, DbProfileHandler, pDb );
  2782. }
  2783. else
  2784. {
  2785. sqlite3_profile( pDb.db, null, null );
  2786. }
  2787. #endif
  2788. }
  2789. break;
  2790. }
  2791. /*
  2792. ** $db rekey KEY
  2793. **
  2794. ** Change the encryption key on the currently open database.
  2795. */
  2796. case (int)DB_enum.DB_REKEY:
  2797. {
  2798. int nKey = 0;
  2799. string pKey;
  2800. if ( objc != 3 )
  2801. {
  2802. TCL.Tcl_WrongNumArgs( interp, 2, objv, "KEY" );
  2803. return TCL.TCL_ERROR;
  2804. }
  2805. pKey = TCL.Tcl_GetStringFromObj( objv[2], out nKey );
  2806. #if SQLITE_HAS_CODEC
  2807. rc = sqlite3_rekey( pDb.db, pKey, nKey );
  2808. if ( rc != 0 )
  2809. {
  2810. TCL.Tcl_AppendResult( interp, sqlite3ErrStr( rc ) );
  2811. rc = TCL.TCL_ERROR;
  2812. }
  2813. #endif
  2814. break;
  2815. }
  2816. /* $db restore ?DATABASE? FILENAME
  2817. **
  2818. ** Open a database file named FILENAME. Transfer the content
  2819. ** of FILENAME into the local database DATABASE (default: "main").
  2820. */
  2821. case (int)DB_enum.DB_RESTORE:
  2822. {
  2823. string zSrcFile;
  2824. string zDestDb;
  2825. sqlite3 pSrc = null;
  2826. sqlite3_backup pBackup;
  2827. int nTimeout = 0;
  2828. if ( objc == 3 )
  2829. {
  2830. zDestDb = "main";
  2831. zSrcFile = TCL.Tcl_GetString( objv[2] );
  2832. }
  2833. else if ( objc == 4 )
  2834. {
  2835. zDestDb = TCL.Tcl_GetString( objv[2] );
  2836. zSrcFile = TCL.Tcl_GetString( objv[3] );
  2837. }
  2838. else
  2839. {
  2840. TCL.Tcl_WrongNumArgs( interp, 2, objv, "?DATABASE? FILENAME" );
  2841. return TCL.TCL_ERROR;
  2842. }
  2843. rc = sqlite3_open_v2( zSrcFile, out pSrc, SQLITE_OPEN_READONLY, null );
  2844. if ( rc != SQLITE_OK )
  2845. {
  2846. TCL.Tcl_AppendResult( interp, "cannot open source database: ",
  2847. sqlite3_errmsg( pSrc ) );
  2848. sqlite3_close( pSrc );
  2849. return TCL.TCL_ERROR;
  2850. }
  2851. pBackup = sqlite3_backup_init( pDb.db, zDestDb, pSrc, "main" );
  2852. if ( pBackup == null )
  2853. {
  2854. TCL.Tcl_AppendResult( interp, "restore failed: ",
  2855. sqlite3_errmsg( pDb.db ) );
  2856. sqlite3_close( pSrc );
  2857. return TCL.TCL_ERROR;
  2858. }
  2859. #if SQLITE_HAS_CODEC
  2860. if ( pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec != null )
  2861. {
  2862. pBackup.pSrc.pBt.pPager.xCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodec;
  2863. pBackup.pSrc.pBt.pPager.xCodecFree = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecFree;
  2864. pBackup.pSrc.pBt.pPager.xCodecSizeChng = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecSizeChng;
  2865. pBackup.pSrc.pBt.pPager.pCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec.Copy();
  2866. if ( pBackup.pDest.GetHashCode() != pBackup.pDestDb.aDb[0].GetHashCode() ) // Not Main Database
  2867. {
  2868. pBackup.pDest.pBt.pPager.xCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodec;
  2869. pBackup.pDest.pBt.pPager.xCodecFree = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecFree;
  2870. pBackup.pDest.pBt.pPager.xCodecSizeChng = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecSizeChng;
  2871. pBackup.pDest.pBt.pPager.pCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec.Copy();
  2872. }
  2873. }
  2874. #endif
  2875. while ( ( rc = sqlite3_backup_step( pBackup, 100 ) ) == SQLITE_OK
  2876. || rc == SQLITE_BUSY )
  2877. {
  2878. if ( rc == SQLITE_BUSY )
  2879. {
  2880. if ( nTimeout++ >= 3 )
  2881. break;
  2882. sqlite3_sleep( 100 );
  2883. }
  2884. }
  2885. sqlite3_backup_finish( pBackup );
  2886. if ( rc == SQLITE_DONE )
  2887. {
  2888. rc = TCL.TCL_OK;
  2889. }
  2890. else if ( rc == SQLITE_BUSY || rc == SQLITE_LOCKED )
  2891. {
  2892. TCL.Tcl_AppendResult( interp, "restore failed: source database busy"
  2893. );
  2894. rc = TCL.TCL_ERROR;
  2895. }
  2896. else
  2897. {
  2898. TCL.Tcl_AppendResult( interp, "restore failed: ",
  2899. sqlite3_errmsg( pDb.db ) );
  2900. rc = TCL.TCL_ERROR;
  2901. }
  2902. sqlite3_close( pSrc );
  2903. break;
  2904. }
  2905. /*
  2906. ** $db status (step|sort|autoindex)
  2907. **
  2908. ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
  2909. ** SQLITE_STMTSTATUS_SORT for the most recent eval.
  2910. */
  2911. case (int)DB_enum.DB_STATUS:
  2912. {
  2913. int v;
  2914. string zOp;
  2915. if ( objc != 3 )
  2916. {
  2917. TCL.Tcl_WrongNumArgs( interp, 2, objv, "(step|sort|autoindex)" );
  2918. return TCL.TCL_ERROR;
  2919. }
  2920. zOp = TCL.Tcl_GetString( objv[2] );
  2921. if ( zOp == "step" )
  2922. {
  2923. v = pDb.nStep;
  2924. }
  2925. else if ( zOp == "sort" )
  2926. {
  2927. v = pDb.nSort;
  2928. }
  2929. else if ( zOp == "autoindex" )
  2930. {
  2931. v = pDb.nIndex;
  2932. }
  2933. else
  2934. {
  2935. TCL.Tcl_AppendResult( interp, "bad argument: should be autoindex, step or sort" );
  2936. return TCL.TCL_ERROR;
  2937. }
  2938. TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( v ) );
  2939. break;
  2940. }
  2941. /*
  2942. ** $db timeout MILLESECONDS
  2943. **
  2944. ** Delay for the number of milliseconds specified when a file is locked.
  2945. */
  2946. case (int)DB_enum.DB_TIMEOUT:
  2947. {
  2948. int ms = 0;
  2949. if ( objc != 3 )
  2950. {
  2951. TCL.Tcl_WrongNumArgs( interp, 2, objv, "MILLISECONDS" );
  2952. return TCL.TCL_ERROR;
  2953. }
  2954. if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out ms ) )
  2955. return TCL.TCL_ERROR;
  2956. sqlite3_busy_timeout( pDb.db, ms );
  2957. break;
  2958. }
  2959. /*
  2960. ** $db total_changes
  2961. **
  2962. ** Return the number of rows that were modified, inserted, or deleted
  2963. ** since the database handle was created.
  2964. */
  2965. case (int)DB_enum.DB_TOTAL_CHANGES:
  2966. {
  2967. Tcl_Obj pResult;
  2968. if ( objc != 2 )
  2969. {
  2970. TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
  2971. return TCL.TCL_ERROR;
  2972. }
  2973. pResult = TCL.Tcl_GetObjResult( interp );
  2974. TCL.Tcl_SetIntObj( pResult, sqlite3_total_changes( pDb.db ) );
  2975. break;
  2976. }
  2977. /* $db trace ?CALLBACK?
  2978. **
  2979. ** Make arrangements to invoke the CALLBACK routine for each SQL statement
  2980. ** that is executed. The text of the SQL is appended to CALLBACK before
  2981. ** it is executed.
  2982. */
  2983. case (int)DB_enum.DB_TRACE:
  2984. {
  2985. if ( objc > 3 )
  2986. {
  2987. TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
  2988. return TCL.TCL_ERROR;
  2989. }
  2990. else if ( objc == 2 )
  2991. {
  2992. if ( pDb.zTrace != null )
  2993. {
  2994. TCL.Tcl_AppendResult( interp, pDb.zTrace );
  2995. }
  2996. }
  2997. else
  2998. {
  2999. string zTrace;
  3000. int len = 0;
  3001. if ( pDb.zTrace != null )
  3002. {
  3003. TCL.Tcl_Free( ref pDb.zTrace );
  3004. }
  3005. zTrace = TCL.Tcl_GetStringFromObj( objv[2], out len );
  3006. if ( zTrace != null && len > 0 )
  3007. {
  3008. //pDb.zTrace = TCL.Tcl_Alloc( len + 1 );
  3009. pDb.zTrace = zTrace;//memcpy( pDb.zTrace, zTrace, len + 1 );
  3010. }
  3011. else
  3012. {
  3013. pDb.zTrace = null;
  3014. }
  3015. #if !SQLITE_OMIT_TRACE && !(SQLITE_OMIT_FLOATING_POINT)
  3016. if ( pDb.zTrace != null )
  3017. {
  3018. pDb.interp = interp;
  3019. sqlite3_trace( pDb.db, (dxTrace)DbTraceHandler, pDb );
  3020. }
  3021. else
  3022. {
  3023. sqlite3_trace( pDb.db, null, null );
  3024. }
  3025. #endif
  3026. }
  3027. break;
  3028. }
  3029. // /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
  3030. // **
  3031. // ** Start a new transaction (if we are not already in the midst of a
  3032. // ** transaction) and execute the TCL script SCRIPT. After SCRIPT
  3033. // ** completes, either commit the transaction or roll it back if SCRIPT
  3034. // ** throws an exception. Or if no new transation was started, do nothing.
  3035. // ** pass the exception on up the stack.
  3036. // **
  3037. // ** This command was inspired by Dave Thomas's talk on Ruby at the
  3038. // ** 2005 O'Reilly Open Source Convention (OSCON).
  3039. // */
  3040. case (int)DB_enum.DB_TRANSACTION:
  3041. {
  3042. Tcl_Obj pScript;
  3043. string zBegin = "SAVEPOINT _tcl_transaction";
  3044. if ( objc != 3 && objc != 4 )
  3045. {
  3046. TCL.Tcl_WrongNumArgs( interp, 2, objv, "[TYPE] SCRIPT" );
  3047. return TCL.TCL_ERROR;
  3048. }
  3049. if ( pDb.nTransaction == 0 && objc == 4 )
  3050. {
  3051. string[] TTYPE_strs = { "deferred", "exclusive", "immediate", null };
  3052. int ttype = 0;
  3053. if ( TCL.Tcl_GetIndexFromObj( interp, objv[2], TTYPE_strs, "transaction type",
  3054. 0, out ttype ) )
  3055. {
  3056. return TCL.TCL_ERROR;
  3057. }
  3058. switch ( ttype )
  3059. {
  3060. case (int)TTYPE_enum.TTYPE_DEFERRED: /* no-op */
  3061. ;
  3062. break;
  3063. case (int)TTYPE_enum.TTYPE_EXCLUSIVE:
  3064. zBegin = "BEGIN EXCLUSIVE";
  3065. break;
  3066. case (int)TTYPE_enum.TTYPE_IMMEDIATE:
  3067. zBegin = "BEGIN IMMEDIATE";
  3068. break;
  3069. }
  3070. }
  3071. pScript = objv[objc - 1];
  3072. /* Run the SQLite BEGIN command to open a transaction or savepoint. */
  3073. pDb.disableAuth++;
  3074. rc = sqlite3_exec( pDb.db, zBegin, 0, 0, 0 );
  3075. pDb.disableAuth--;
  3076. if ( rc != SQLITE_OK )
  3077. {
  3078. TCL.Tcl_AppendResult( interp, sqlite3_errmsg( pDb.db ) );
  3079. return TCL.TCL_ERROR;
  3080. }
  3081. pDb.nTransaction++;
  3082. /* If using NRE, schedule a callback to invoke the script pScript, then
  3083. ** a second callback to commit (or rollback) the transaction or savepoint
  3084. ** opened above. If not using NRE, evaluate the script directly, then
  3085. ** call function DbTransPostCmd() to commit (or rollback) the transaction
  3086. ** or savepoint. */
  3087. if ( DbUseNre() )
  3088. {
  3089. Debugger.Break();
  3090. //Tcl_NRAddCallback( interp, DbTransPostCmd, cd, 0, 0, 0 );
  3091. //Tcl_NREvalObj(interp, pScript, 0);
  3092. }
  3093. else
  3094. {
  3095. rc = DbTransPostCmd( cd, interp, TCL.Tcl_EvalObjEx( interp, pScript, 0 ) );
  3096. }
  3097. break;
  3098. }
  3099. /*
  3100. ** $db unlock_notify ?script?
  3101. */
  3102. case (int)DB_enum.DB_UNLOCK_NOTIFY:
  3103. {
  3104. #if !SQLITE_ENABLE_UNLOCK_NOTIFY
  3105. TCL.Tcl_AppendResult( interp, "unlock_notify not available in this build", 0 );
  3106. rc = TCL.TCL_ERROR;
  3107. #else
  3108. if( objc!=2 && objc!=3 ){
  3109. Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
  3110. rc = TCL.Tcl_ERROR;
  3111. }else{
  3112. void (*xNotify)(void **, int) = 0;
  3113. void *pNotifyArg = 0;
  3114. if( pDb.pUnlockNotify ){
  3115. Tcl_DecrRefCount(pDb.pUnlockNotify);
  3116. pDb.pUnlockNotify = 0;
  3117. }
  3118. if( objc==3 ){
  3119. xNotify = DbUnlockNotify;
  3120. pNotifyArg = (void )pDb;
  3121. pDb.pUnlockNotify = objv[2];
  3122. Tcl_IncrRefCount(pDb.pUnlockNotify);
  3123. }
  3124. if( sqlite3_unlock_notify(pDb.db, xNotify, pNotifyArg) ){
  3125. Tcl_AppendResult(interp, sqlite3_errmsg(pDb.db), 0);
  3126. rc = TCL.Tcl_ERROR;
  3127. }
  3128. }
  3129. #endif
  3130. break;
  3131. }
  3132. /*
  3133. ** $db wal_hook ?script?
  3134. ** $db update_hook ?script?
  3135. ** $db rollback_hook ?script?
  3136. */
  3137. case (int)DB_enum.DB_WAL_HOOK:
  3138. case (int)DB_enum.DB_UPDATE_HOOK:
  3139. case (int)DB_enum.DB_ROLLBACK_HOOK:
  3140. {
  3141. /* set ppHook to point at pUpdateHook or pRollbackHook, depending on
  3142. ** whether [$db update_hook] or [$db rollback_hook] was invoked.
  3143. */
  3144. Tcl_Obj ppHook;
  3145. if ( choice == (int)DB_enum.DB_UPDATE_HOOK )
  3146. {
  3147. ppHook = pDb.pUpdateHook;
  3148. }
  3149. else if ( choice == (int)DB_enum.DB_WAL_HOOK )
  3150. {
  3151. ppHook = pDb.pWalHook;
  3152. }
  3153. else
  3154. {
  3155. ppHook = pDb.pRollbackHook;
  3156. }
  3157. if ( objc != 2 && objc != 3 )
  3158. {
  3159. TCL.Tcl_WrongNumArgs( interp, 2, objv, "?SCRIPT?" );
  3160. return TCL.TCL_ERROR;
  3161. }
  3162. if ( ppHook != null )
  3163. {
  3164. TCL.Tcl_SetObjResult( interp, ppHook );
  3165. if ( objc == 3 )
  3166. {
  3167. TCL.Tcl_DecrRefCount( ref ppHook );
  3168. ppHook = null;
  3169. }
  3170. }
  3171. if ( objc == 3 )
  3172. {
  3173. Debug.Assert( null == ppHook );
  3174. if ( objv[2] != null )//TCL.Tcl_GetCharLength( objv[2] ) > 0 )
  3175. {
  3176. ppHook = objv[2];
  3177. TCL.Tcl_IncrRefCount( ppHook );
  3178. }
  3179. }
  3180. if ( choice == (int)DB_enum.DB_UPDATE_HOOK )
  3181. {
  3182. pDb.pUpdateHook = ppHook;
  3183. }
  3184. else
  3185. {
  3186. pDb.pRollbackHook = ppHook;
  3187. }
  3188. sqlite3_update_hook( pDb.db, ( pDb.pUpdateHook != null ? (dxUpdateCallback)DbUpdateHandler : null ), pDb );
  3189. sqlite3_rollback_hook( pDb.db, ( pDb.pRollbackHook != null ? (dxRollbackCallback)DbRollbackHandler : null ), pDb );
  3190. sqlite3_wal_hook( pDb.db, ( pDb.pWalHook != null ? (dxWalCallback)DbWalHandler : null ), pDb );
  3191. break;
  3192. }
  3193. /* $db version
  3194. **
  3195. ** Return the version string for this database.
  3196. */
  3197. case (int)DB_enum.DB_VERSION:
  3198. {
  3199. TCL.Tcl_SetResult( interp, sqlite3_libversion(), TCL.TCL_STATIC );
  3200. break;
  3201. }
  3202. default:
  3203. Debug.Assert( false, "Missing switch:" + objv[1].ToString() );
  3204. break;
  3205. } /* End of the SWITCH statement */
  3206. return rc;
  3207. }
  3208. #if SQLITE_TCL_NRE
  3209. /*
  3210. ** Adaptor that provides an objCmd interface to the NRE-enabled
  3211. ** interface implementation.
  3212. */
  3213. static int DbObjCmdAdaptor(
  3214. void *cd,
  3215. Tcl_Interp interp,
  3216. int objc,
  3217. Tcl_Obj *const*objv
  3218. ){
  3219. return TCL.TCL_NRCallObjProc(interp, DbObjCmd, cd, objc, objv);
  3220. }
  3221. #endif //* SQLITE_TCL_NRE */
  3222. /*
  3223. ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
  3224. ** ?-create BOOLEAN? ?-nomutex BOOLEAN?
  3225. **
  3226. ** This is the main Tcl command. When the "sqlite" Tcl command is
  3227. ** invoked, this routine runs to process that command.
  3228. **
  3229. ** The first argument, DBNAME, is an arbitrary name for a new
  3230. ** database connection. This command creates a new command named
  3231. ** DBNAME that is used to control that connection. The database
  3232. ** connection is deleted when the DBNAME command is deleted.
  3233. **
  3234. ** The second argument is the name of the database file.
  3235. **
  3236. */
  3237. static int DbMain( object cd, Tcl_Interp interp, int objc, Tcl_Obj[] objv )
  3238. {
  3239. SqliteDb p;
  3240. string pKey = null;
  3241. int nKey = 0;
  3242. string zArg;
  3243. string zErrMsg;
  3244. int i;
  3245. string zFile;
  3246. string zVfs = null;
  3247. int flags;
  3248. Tcl_DString translatedFilename;
  3249. /* In normal use, each TCL interpreter runs in a single thread. So
  3250. ** by default, we can turn of mutexing on SQLite database connections.
  3251. ** However, for testing purposes it is useful to have mutexes turned
  3252. ** on. So, by default, mutexes default off. But if compiled with
  3253. ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
  3254. */
  3255. #if SQLITE_TCL_DEFAULT_FULLMUTEX
  3256. flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
  3257. #else
  3258. flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
  3259. #endif
  3260. if ( objc == 2 )
  3261. {
  3262. zArg = TCL.Tcl_GetStringFromObj( objv[1], 0 );
  3263. if ( zArg == "-version" )
  3264. {
  3265. TCL.Tcl_AppendResult( interp, sqlite3_version, null );
  3266. return TCL.TCL_OK;
  3267. }
  3268. if ( zArg == "-has-codec" )
  3269. {
  3270. #if SQLITE_HAS_CODEC
  3271. TCL.Tcl_AppendResult( interp, "1" );
  3272. #else
  3273. TCL.Tcl_AppendResult( interp, "0", null );
  3274. #endif
  3275. return TCL.TCL_OK;
  3276. }
  3277. if ( zArg == "-tcl-uses-utf" )
  3278. {
  3279. TCL.Tcl_AppendResult( interp, "1", null );
  3280. return TCL.TCL_OK;
  3281. }
  3282. }
  3283. for ( i = 3; i + 1 < objc; i += 2 )
  3284. {
  3285. zArg = TCL.Tcl_GetString( objv[i] );
  3286. if ( zArg == "-key" )
  3287. {
  3288. pKey = TCL.Tcl_GetStringFromObj( objv[i + 1], out nKey );
  3289. }
  3290. else if ( zArg == "-vfs" )
  3291. {
  3292. zVfs = TCL.Tcl_GetString( objv[i + 1] );
  3293. }
  3294. else if ( zArg == "-readonly" )
  3295. {
  3296. bool b = false;
  3297. if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
  3298. return TCL.TCL_ERROR;
  3299. if ( b )
  3300. {
  3301. flags &= ~( SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE );
  3302. flags |= SQLITE_OPEN_READONLY;
  3303. }
  3304. else
  3305. {
  3306. flags &= ~SQLITE_OPEN_READONLY;
  3307. flags |= SQLITE_OPEN_READWRITE;
  3308. }
  3309. }
  3310. else if ( zArg == "-create" )
  3311. {
  3312. bool b = false;
  3313. if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
  3314. return TCL.TCL_ERROR;
  3315. if ( b && ( flags & SQLITE_OPEN_READONLY ) == 0 )
  3316. {
  3317. flags |= SQLITE_OPEN_CREATE;
  3318. }
  3319. else
  3320. {
  3321. flags &= ~SQLITE_OPEN_CREATE;
  3322. }
  3323. }
  3324. else if ( zArg == "-nomutex" )
  3325. {
  3326. bool b = false;
  3327. if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
  3328. return TCL.TCL_ERROR;
  3329. if ( b )
  3330. {
  3331. flags |= SQLITE_OPEN_NOMUTEX;
  3332. flags &= ~SQLITE_OPEN_FULLMUTEX;
  3333. }
  3334. else
  3335. {
  3336. flags &= ~SQLITE_OPEN_NOMUTEX;
  3337. }
  3338. }
  3339. else if ( zArg == "-fullmutex" )//strcmp( zArg, "-fullmutex" ) == 0 )
  3340. {
  3341. bool b = false;
  3342. if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
  3343. return TCL.TCL_ERROR;
  3344. if ( b )
  3345. {
  3346. flags |= SQLITE_OPEN_FULLMUTEX;
  3347. flags &= ~SQLITE_OPEN_NOMUTEX;
  3348. }
  3349. else
  3350. {
  3351. flags &= ~SQLITE_OPEN_FULLMUTEX;
  3352. }
  3353. }
  3354. else
  3355. {
  3356. TCL.Tcl_AppendResult( interp, "unknown option: ", zArg, null );
  3357. return TCL.TCL_ERROR;
  3358. }
  3359. }
  3360. if ( objc < 3 || ( objc & 1 ) != 1 )
  3361. {
  3362. TCL.Tcl_WrongNumArgs( interp, 1, objv,
  3363. "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN?"
  3364. #if SQLITE_HAS_CODEC
  3365. + " ?-key CODECKEY?"
  3366. #endif
  3367. );
  3368. return TCL.TCL_ERROR;
  3369. }
  3370. zErrMsg = "";
  3371. p = new SqliteDb();//(SqliteDb)Tcl_Alloc( sizeof(*p) );
  3372. if ( p == null )
  3373. {
  3374. TCL.Tcl_SetResult( interp, "malloc failed", TCL.TCL_STATIC );
  3375. return TCL.TCL_ERROR;
  3376. }
  3377. //memset(p, 0, sizeof(*p));
  3378. zFile = TCL.Tcl_GetStringFromObj( objv[2], 0 );
  3379. //zFile = TCL.Tcl_TranslateFileName( interp, zFile, ref translatedFilename );
  3380. sqlite3_open_v2( zFile, out p.db, flags, zVfs );
  3381. //Tcl_DStringFree( ref translatedFilename );
  3382. if ( SQLITE_OK != sqlite3_errcode( p.db ) )
  3383. {
  3384. zErrMsg = sqlite3_errmsg( p.db );// sqlite3_mprintf( "%s", sqlite3_errmsg( p.db ) );
  3385. sqlite3_close( p.db );
  3386. p.db = null;
  3387. }
  3388. #if SQLITE_HAS_CODEC
  3389. if ( p.db != null )
  3390. {
  3391. sqlite3_key( p.db, pKey, nKey );
  3392. }
  3393. #endif
  3394. if ( p.db == null )
  3395. {
  3396. TCL.Tcl_SetResult( interp, zErrMsg, TCL.TCL_VOLATILE );
  3397. TCL.Tcl_Free( ref p );
  3398. zErrMsg = "";// sqlite3DbFree( db, ref zErrMsg );
  3399. return TCL.TCL_ERROR;
  3400. }
  3401. p.maxStmt = NUM_PREPARED_STMTS;
  3402. p.interp = interp;
  3403. zArg = TCL.Tcl_GetStringFromObj( objv[1], 0 );
  3404. if ( DbUseNre() )
  3405. {
  3406. Debugger.Break();
  3407. //Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd,
  3408. // p, DbDeleteCmd);
  3409. }
  3410. else
  3411. {
  3412. TCL.Tcl_CreateObjCommand( interp, zArg, (Interp.dxObjCmdProc)DbObjCmd, p, (Interp.dxCmdDeleteProc)DbDeleteCmd );
  3413. }
  3414. return TCL.TCL_OK;
  3415. }
  3416. /*
  3417. ** Provide a dummy TCL.Tcl_InitStubs if we are using this as a static
  3418. ** library.
  3419. */
  3420. #if !USE_TCL_STUBS
  3421. //# undef TCL.Tcl_InitStubs
  3422. static void Tcl_InitStubs( Tcl_Interp interp, string s, int i )
  3423. {
  3424. }
  3425. #endif
  3426. /*
  3427. ** Make sure we have a PACKAGE_VERSION macro defined. This will be
  3428. ** defined automatically by the TEA makefile. But other makefiles
  3429. ** do not define it.
  3430. */
  3431. #if !PACKAGE_VERSION
  3432. public static string PACKAGE_VERSION;//# define PACKAGE_VERSION SQLITE_VERSION
  3433. #endif
  3434. /*
  3435. ** Initialize this module.
  3436. **
  3437. ** This Tcl module contains only a single new Tcl command named "sqlite".
  3438. ** (Hence there is no namespace. There is no point in using a namespace
  3439. ** if the extension only supplies one new name!) The "sqlite" command is
  3440. ** used to open a new SQLite database. See the DbMain() routine above
  3441. ** for additional information.
  3442. **
  3443. ** The EXTERN macros are required by TCL in order to work on windows.
  3444. */
  3445. //int Sqlite3_Init(Tcl_Interp interp){
  3446. static public int Sqlite3_Init( Tcl_Interp interp )
  3447. {
  3448. PACKAGE_VERSION = SQLITE_VERSION;
  3449. Tcl_InitStubs( interp, "tclsharp 8.4", 0 );
  3450. TCL.Tcl_CreateObjCommand( interp, "sqlite3", (Interp.dxObjCmdProc)DbMain, null, null );
  3451. TCL.Tcl_PkgProvide( interp, "sqlite3", PACKAGE_VERSION );
  3452. #if !SQLITE_3_SUFFIX_ONLY
  3453. /* The "sqlite" alias is undocumented. It is here only to support
  3454. ** legacy scripts. All new scripts should use only the "sqlite3"
  3455. ** command.
  3456. */
  3457. TCL.Tcl_CreateObjCommand( interp, "sqlite", (Interp.dxObjCmdProc)DbMain, null, null );
  3458. #endif
  3459. return TCL.TCL_OK;
  3460. }
  3461. //int Tclsqlite3_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
  3462. //int Sqlite3_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
  3463. //int Tclsqlite3_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
  3464. //int Sqlite3_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
  3465. //int Tclsqlite3_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
  3466. //int Sqlite3_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
  3467. //int Tclsqlite3_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK;}
  3468. #if !SQLITE_3_SUFFIX_ONLY
  3469. //int Sqlite_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
  3470. //int Tclsqlite_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
  3471. //int Sqlite_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
  3472. //int Tclsqlite_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
  3473. //int Sqlite_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
  3474. //int Tclsqlite_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
  3475. //int Sqlite_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
  3476. //int Tclsqlite_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK;}
  3477. #endif
  3478. #if TCLSH
  3479. /*****************************************************************************
  3480. ** All of the code that follows is used to build standalone TCL interpreters
  3481. ** that are statically linked with SQLite. Enable these by compiling
  3482. ** with -DTCLSH=n where n can be 1 or 2. An n of 1 generates a standard
  3483. ** tclsh but with SQLite built in. An n of 2 generates the SQLite space
  3484. ** analysis program.
  3485. */
  3486. #if (SQLITE_TEST) || (SQLITE_TCLMD5)
  3487. /*
  3488. * This code implements the MD5 message-digest algorithm.
  3489. * The algorithm is due to Ron Rivest. This code was
  3490. * written by Colin Plumb in 1993, no copyright is claimed.
  3491. * This code is in the public domain; do with it what you wish.
  3492. *
  3493. * Equivalent code is available from RSA Data Security, Inc.
  3494. * This code has been tested against that, and is equivalent,
  3495. * except that you don't need to include two pages of legalese
  3496. * with every copy.
  3497. *
  3498. * To compute the message digest of a chunk of bytes, declare an
  3499. * MD5Context structure, pass it to MD5Init, call MD5Update as
  3500. * needed on buffers full of bytes, and then call MD5Final, which
  3501. * will fill a supplied 16-byte array with the digest.
  3502. */
  3503. /*
  3504. * If compiled on a machine that doesn't have a 32-bit integer,
  3505. * you just set "uint32" to the appropriate datatype for an
  3506. * unsigned 32-bit integer. For example:
  3507. *
  3508. * cc -Duint32='unsigned long' md5.c
  3509. *
  3510. */
  3511. //#if !uint32
  3512. //# define uint32 unsigned int
  3513. //#endif
  3514. //struct MD5Context {
  3515. // int isInit;
  3516. // uint32 buf[4];
  3517. // uint32 bits[2];
  3518. // unsigned char in[64];
  3519. //};
  3520. //typedef struct MD5Context MD5Context;
  3521. class MD5Context
  3522. {
  3523. public bool isInit;
  3524. public u32[] buf = new u32[4];
  3525. public u32[] bits = new u32[2];
  3526. public u32[] _in = new u32[64];
  3527. public Mem _Mem;
  3528. };
  3529. /*
  3530. * Note: this code is harmless on little-endian machines.
  3531. */
  3532. //static void byteReverse (unsigned char *buf, unsigned longs){
  3533. // uint32 t;
  3534. // do {
  3535. // t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
  3536. // ((unsigned)buf[1]<<8 | buf[0]);
  3537. // *(uint32 )buf = t;
  3538. // buf += 4;
  3539. // } while (--longs);
  3540. //}
  3541. /* The four core functions - F1 is optimized somewhat */
  3542. delegate u32 dxF1234( u32 x, u32 y, u32 z );
  3543. //* #define F1(x, y, z) (x & y | ~x & z) */
  3544. //#define F1(x, y, z) (z ^ (x & (y ^ z)))
  3545. static u32 F1( u32 x, u32 y, u32 z )
  3546. {
  3547. return ( z ^ ( x & ( y ^ z ) ) );
  3548. }
  3549. //#define F2(x, y, z) F1(z, x, y)
  3550. static u32 F2( u32 x, u32 y, u32 z )
  3551. {
  3552. return F1( z, x, y );
  3553. }
  3554. //#define F3(x, y, z) (x ^ y ^ z)
  3555. static u32 F3( u32 x, u32 y, u32 z )
  3556. {
  3557. return ( x ^ y ^ z );
  3558. }
  3559. //#define F4(x, y, z) (y ^ (x | ~z))
  3560. static u32 F4( u32 x, u32 y, u32 z )
  3561. {
  3562. return ( y ^ ( x | ~z ) );
  3563. }
  3564. ///* This is the central step in the MD5 algorithm. */
  3565. //#define MD5STEP(f, w, x, y, z, data, s) \
  3566. // ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
  3567. static void MD5STEP( dxF1234 f, ref u32 w, u32 x, u32 y, u32 z, u32 data, byte s )
  3568. {
  3569. w += f( x, y, z ) + data;
  3570. w = w << s | w >> ( 32 - s );
  3571. w += x;
  3572. }
  3573. /*
  3574. * The core of the MD5 algorithm, this alters an existing MD5 hash to
  3575. * reflect the addition of 16 longwords of new data. MD5Update blocks
  3576. * the data and converts bytes into longwords for this routine.
  3577. */
  3578. static void MD5Transform( u32[] buf, u32[] _in )
  3579. {
  3580. u32 a, b, c, d;
  3581. a = buf[0];
  3582. b = buf[1];
  3583. c = buf[2];
  3584. d = buf[3];
  3585. MD5STEP( F1, ref a, b, c, d, _in[0] + 0xd76aa478, 7 );
  3586. MD5STEP( F1, ref d, a, b, c, _in[1] + 0xe8c7b756, 12 );
  3587. MD5STEP( F1, ref c, d, a, b, _in[2] + 0x242070db, 17 );
  3588. MD5STEP( F1, ref b, c, d, a, _in[3] + 0xc1bdceee, 22 );
  3589. MD5STEP( F1, ref a, b, c, d, _in[4] + 0xf57c0faf, 7 );
  3590. MD5STEP( F1, ref d, a, b, c, _in[5] + 0x4787c62a, 12 );
  3591. MD5STEP( F1, ref c, d, a, b, _in[6] + 0xa8304613, 17 );
  3592. MD5STEP( F1, ref b, c, d, a, _in[7] + 0xfd469501, 22 );
  3593. MD5STEP( F1, ref a, b, c, d, _in[8] + 0x698098d8, 7 );
  3594. MD5STEP( F1, ref d, a, b, c, _in[9] + 0x8b44f7af, 12 );
  3595. MD5STEP( F1, ref c, d, a, b, _in[10] + 0xffff5bb1, 17 );
  3596. MD5STEP( F1, ref b, c, d, a, _in[11] + 0x895cd7be, 22 );
  3597. MD5STEP( F1, ref a, b, c, d, _in[12] + 0x6b901122, 7 );
  3598. MD5STEP( F1, ref d, a, b, c, _in[13] + 0xfd987193, 12 );
  3599. MD5STEP( F1, ref c, d, a, b, _in[14] + 0xa679438e, 17 );
  3600. MD5STEP( F1, ref b, c, d, a, _in[15] + 0x49b40821, 22 );
  3601. MD5STEP( F2, ref a, b, c, d, _in[1] + 0xf61e2562, 5 );
  3602. MD5STEP( F2, ref d, a, b, c, _in[6] + 0xc040b340, 9 );
  3603. MD5STEP( F2, ref c, d, a, b, _in[11] + 0x265e5a51, 14 );
  3604. MD5STEP( F2, ref b, c, d, a, _in[0] + 0xe9b6c7aa, 20 );
  3605. MD5STEP( F2, ref a, b, c, d, _in[5] + 0xd62f105d, 5 );
  3606. MD5STEP( F2, ref d, a, b, c, _in[10] + 0x02441453, 9 );
  3607. MD5STEP( F2, ref c, d, a, b, _in[15] + 0xd8a1e681, 14 );
  3608. MD5STEP( F2, ref b, c, d, a, _in[4] + 0xe7d3fbc8, 20 );
  3609. MD5STEP( F2, ref a, b, c, d, _in[9] + 0x21e1cde6, 5 );
  3610. MD5STEP( F2, ref d, a, b, c, _in[14] + 0xc33707d6, 9 );
  3611. MD5STEP( F2, ref c, d, a, b, _in[3] + 0xf4d50d87, 14 );
  3612. MD5STEP( F2, ref b, c, d, a, _in[8] + 0x455a14ed, 20 );
  3613. MD5STEP( F2, ref a, b, c, d, _in[13] + 0xa9e3e905, 5 );
  3614. MD5STEP( F2, ref d, a, b, c, _in[2] + 0xfcefa3f8, 9 );
  3615. MD5STEP( F2, ref c, d, a, b, _in[7] + 0x676f02d9, 14 );
  3616. MD5STEP( F2, ref b, c, d, a, _in[12] + 0x8d2a4c8a, 20 );
  3617. MD5STEP( F3, ref a, b, c, d, _in[5] + 0xfffa3942, 4 );
  3618. MD5STEP( F3, ref d, a, b, c, _in[8] + 0x8771f681, 11 );
  3619. MD5STEP( F3, ref c, d, a, b, _in[11] + 0x6d9d6122, 16 );
  3620. MD5STEP( F3, ref b, c, d, a, _in[14] + 0xfde5380c, 23 );
  3621. MD5STEP( F3, ref a, b, c, d, _in[1] + 0xa4beea44, 4 );
  3622. MD5STEP( F3, ref d, a, b, c, _in[4] + 0x4bdecfa9, 11 );
  3623. MD5STEP( F3, ref c, d, a, b, _in[7] + 0xf6bb4b60, 16 );
  3624. MD5STEP( F3, ref b, c, d, a, _in[10] + 0xbebfbc70, 23 );
  3625. MD5STEP( F3, ref a, b, c, d, _in[13] + 0x289b7ec6, 4 );
  3626. MD5STEP( F3, ref d, a, b, c, _in[0] + 0xeaa127fa, 11 );
  3627. MD5STEP( F3, ref c, d, a, b, _in[3] + 0xd4ef3085, 16 );
  3628. MD5STEP( F3, ref b, c, d, a, _in[6] + 0x04881d05, 23 );
  3629. MD5STEP( F3, ref a, b, c, d, _in[9] + 0xd9d4d039, 4 );
  3630. MD5STEP( F3, ref d, a, b, c, _in[12] + 0xe6db99e5, 11 );
  3631. MD5STEP( F3, ref c, d, a, b, _in[15] + 0x1fa27cf8, 16 );
  3632. MD5STEP( F3, ref b, c, d, a, _in[2] + 0xc4ac5665, 23 );
  3633. MD5STEP( F4, ref a, b, c, d, _in[0] + 0xf4292244, 6 );
  3634. MD5STEP( F4, ref d, a, b, c, _in[7] + 0x432aff97, 10 );
  3635. MD5STEP( F4, ref c, d, a, b, _in[14] + 0xab9423a7, 15 );
  3636. MD5STEP( F4, ref b, c, d, a, _in[5] + 0xfc93a039, 21 );
  3637. MD5STEP( F4, ref a, b, c, d, _in[12] + 0x655b59c3, 6 );
  3638. MD5STEP( F4, ref d, a, b, c, _in[3] + 0x8f0ccc92, 10 );
  3639. MD5STEP( F4, ref c, d, a, b, _in[10] + 0xffeff47d, 15 );
  3640. MD5STEP( F4, ref b, c, d, a, _in[1] + 0x85845dd1, 21 );
  3641. MD5STEP( F4, ref a, b, c, d, _in[8] + 0x6fa87e4f, 6 );
  3642. MD5STEP( F4, ref d, a, b, c, _in[15] + 0xfe2ce6e0, 10 );
  3643. MD5STEP( F4, ref c, d, a, b, _in[6] + 0xa3014314, 15 );
  3644. MD5STEP( F4, ref b, c, d, a, _in[13] + 0x4e0811a1, 21 );
  3645. MD5STEP( F4, ref a, b, c, d, _in[4] + 0xf7537e82, 6 );
  3646. MD5STEP( F4, ref d, a, b, c, _in[11] + 0xbd3af235, 10 );
  3647. MD5STEP( F4, ref c, d, a, b, _in[2] + 0x2ad7d2bb, 15 );
  3648. MD5STEP( F4, ref b, c, d, a, _in[9] + 0xeb86d391, 21 );
  3649. buf[0] += a;
  3650. buf[1] += b;
  3651. buf[2] += c;
  3652. buf[3] += d;
  3653. }
  3654. /*
  3655. * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
  3656. * initialization constants.
  3657. */
  3658. static void MD5Init( MD5Context ctx )
  3659. {
  3660. ctx.isInit = true;
  3661. ctx.buf[0] = 0x67452301;
  3662. ctx.buf[1] = 0xefcdab89;
  3663. ctx.buf[2] = 0x98badcfe;
  3664. ctx.buf[3] = 0x10325476;
  3665. ctx.bits[0] = 0;
  3666. ctx.bits[1] = 0;
  3667. }
  3668. /*
  3669. * Update context to reflect the concatenation of another buffer full
  3670. * of bytes.
  3671. */
  3672. static void MD5Update( MD5Context pCtx, byte[] buf, int len )
  3673. {
  3674. MD5Context ctx = (MD5Context)pCtx;
  3675. int t;
  3676. /* Update bitcount */
  3677. t = (int)ctx.bits[0];
  3678. if ( ( ctx.bits[0] = (u32)( t + ( (u32)len << 3 ) ) ) < t )
  3679. ctx.bits[1]++; /* Carry from low to high */
  3680. ctx.bits[1] += (u32)( len >> 29 );
  3681. t = ( t >> 3 ) & 0x3f; /* Bytes already in shsInfo.data */
  3682. /* Handle any leading odd-sized chunks */
  3683. int _buf = 0; // Offset into buffer
  3684. int p = t; //Offset into ctx._in
  3685. if ( t != 0 )
  3686. {
  3687. //byte p = (byte)ctx._in + t;
  3688. t = 64 - t;
  3689. if ( len < t )
  3690. {
  3691. Buffer.BlockCopy( buf, _buf, ctx._in, p, len );// memcpy( p, buf, len );
  3692. return;
  3693. }
  3694. Buffer.BlockCopy( buf, _buf, ctx._in, p, t ); //memcpy( p, buf, t );
  3695. //byteReverse(ctx._in, 16);
  3696. MD5Transform( ctx.buf, ctx._in );
  3697. _buf += t;// buf += t;
  3698. len -= t;
  3699. }
  3700. /* Process data in 64-byte chunks */
  3701. while ( len >= 64 )
  3702. {
  3703. Buffer.BlockCopy( buf, _buf, ctx._in, 0, 64 );//memcpy( ctx._in, buf, 64 );
  3704. //byteReverse(ctx._in, 16);
  3705. MD5Transform( ctx.buf, ctx._in );
  3706. _buf += 64;// buf += 64;
  3707. len -= 64;
  3708. }
  3709. /* Handle any remaining bytes of data. */
  3710. Buffer.BlockCopy( buf, _buf, ctx._in, 0, len ); //memcpy( ctx._in, buf, len );
  3711. }
  3712. /*
  3713. * Final wrapup - pad to 64-byte boundary with the bit pattern
  3714. * 1 0* (64-bit count of bits processed, MSB-first)
  3715. */
  3716. static void MD5Final( byte[] digest, MD5Context pCtx )
  3717. {
  3718. MD5Context ctx = pCtx;
  3719. int count;
  3720. int p;
  3721. /* Compute number of bytes mod 64 */
  3722. count = (int)( ctx.bits[0] >> 3 ) & 0x3F;
  3723. /* Set the first char of padding to 0x80. This is safe since there is
  3724. always at least one byte free */
  3725. p = count;
  3726. ctx._in[p++] = 0x80;
  3727. /* Bytes of padding needed to make 64 bytes */
  3728. count = 64 - 1 - count;
  3729. /* Pad out to 56 mod 64 */
  3730. if ( count < 8 )
  3731. {
  3732. /* Two lots of padding: Pad the first block to 64 bytes */
  3733. Array.Clear( ctx._in, p, count );//memset(p, 0, count);
  3734. //byteReverse( ctx._in, 16 );
  3735. MD5Transform( ctx.buf, ctx._in );
  3736. /* Now fill the next block with 56 bytes */
  3737. Array.Clear( ctx._in, 0, 56 );//memset(ctx._in, 0, 56);
  3738. }
  3739. else
  3740. {
  3741. /* Pad block to 56 bytes */
  3742. Array.Clear( ctx._in, p, count - 8 );//memset(p, 0, count-8);
  3743. }
  3744. //byteReverse( ctx._in, 14 );
  3745. /* Append length in bits and transform */
  3746. ctx._in[14] = (byte)ctx.bits[0];
  3747. ctx._in[15] = (byte)ctx.bits[1];
  3748. MD5Transform( ctx.buf, ctx._in );
  3749. //byteReverse( ctx.buf, 4 );
  3750. Buffer.BlockCopy( ctx.buf, 0, digest, 0, 16 );//memcpy(digest, ctx.buf, 16);
  3751. //memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */
  3752. Array.Clear( ctx._in, 0, ctx._in.Length );
  3753. Array.Clear( ctx.bits, 0, ctx.bits.Length );
  3754. Array.Clear( ctx.buf, 0, ctx.buf.Length );
  3755. ctx._Mem = null;
  3756. }
  3757. /*
  3758. ** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
  3759. */
  3760. static void DigestToBase16( byte[] digest, byte[] zBuf )
  3761. {
  3762. string zEncode = "0123456789abcdef";
  3763. int i, j;
  3764. for ( j = i = 0; i < 16; i++ )
  3765. {
  3766. int a = digest[i];
  3767. zBuf[j++] = (byte)zEncode[( a >> 4 ) & 0xf];
  3768. zBuf[j++] = (byte)zEncode[a & 0xf];
  3769. }
  3770. if ( j < zBuf.Length )
  3771. zBuf[j] = 0;
  3772. }
  3773. /*
  3774. ** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
  3775. ** each representing 16 bits of the digest and separated from each
  3776. ** other by a "-" character.
  3777. */
  3778. //static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
  3779. // int i, j;
  3780. // unsigned int x;
  3781. // for(i=j=0; i<16; i+=2){
  3782. // x = digest[i]*256 + digest[i+1];
  3783. // if( i>0 ) zDigest[j++] = '-';
  3784. // sprintf(&zDigest[j], "%05u", x);
  3785. // j += 5;
  3786. // }
  3787. // zDigest[j] = 0;
  3788. //}
  3789. /*
  3790. ** A TCL command for md5. The argument is the text to be hashed. The
  3791. ** Result is the hash in base64.
  3792. */
  3793. static int md5_cmd( object cd, Tcl_Interp interp, int argc, Tcl_Obj[] argv )
  3794. {
  3795. MD5Context ctx = new MD5Context();
  3796. byte[] digest = new byte[16];
  3797. byte[] zBuf = new byte[32];
  3798. if ( argc != 2 )
  3799. {
  3800. TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
  3801. " TEXT\"" );
  3802. return TCL.TCL_ERROR;
  3803. }
  3804. MD5Init( ctx );
  3805. MD5Update( ctx, Encoding.UTF8.GetBytes( argv[1].ToString() ), Encoding.UTF8.GetByteCount( argv[1].ToString() ) );
  3806. MD5Final( digest, ctx );
  3807. DigestToBase16( digest, zBuf );
  3808. TCL.Tcl_AppendResult( interp, Encoding.UTF8.GetString( zBuf, 0, zBuf.Length ) );
  3809. return TCL.TCL_OK;
  3810. }
  3811. /*
  3812. ** A TCL command to take the md5 hash of a file. The argument is the
  3813. ** name of the file.
  3814. */
  3815. static int md5file_cmd( object cd, Tcl_Interp interp, int argc, Tcl_Obj[] argv )
  3816. {
  3817. StreamReader _in = null;
  3818. byte[] digest = new byte[16];
  3819. StringBuilder zBuf = new StringBuilder( 10240 );
  3820. if ( argc != 2 )
  3821. {
  3822. TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
  3823. " FILENAME\"", 0 );
  3824. return TCL.TCL_ERROR;
  3825. }
  3826. Debugger.Break(); // TODO -- _in = fopen( argv[1], "rb" );
  3827. if ( _in == null )
  3828. {
  3829. TCL.Tcl_AppendResult( interp, "unable to open file \"", argv[1],
  3830. "\" for reading", 0 );
  3831. return TCL.TCL_ERROR;
  3832. }
  3833. Debugger.Break(); // TODO
  3834. //MD5Init( ctx );
  3835. //for(;;){
  3836. // int n;
  3837. // n = fread(zBuf, 1, zBuf.Capacity, _in);
  3838. // if( n<=0 ) break;
  3839. // MD5Update(ctx, zBuf.ToString(), (unsigned)n);
  3840. //}
  3841. //fclose(_in);
  3842. //MD5Final(digest, ctx);
  3843. // DigestToBase16(digest, zBuf);
  3844. //Tcl_AppendResult( interp, zBuf );
  3845. return TCL.TCL_OK;
  3846. }
  3847. /*
  3848. ** Register the four new TCL commands for generating MD5 checksums
  3849. ** with the TCL interpreter.
  3850. */
  3851. static public int Md5_Init( Tcl_Interp interp )
  3852. {
  3853. TCL.Tcl_CreateCommand( interp, "md5", md5_cmd, null, null );
  3854. //Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc)md5_cmd,
  3855. // MD5DigestToBase10x8, 0);
  3856. TCL.Tcl_CreateCommand( interp, "md5file", md5file_cmd, null, null );
  3857. //Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc)md5file_cmd,
  3858. // MD5DigestToBase10x8, 0);
  3859. return TCL.TCL_OK;
  3860. }
  3861. #endif //* defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) */
  3862. #if (SQLITE_TEST)
  3863. /*
  3864. ** During testing, the special md5sum() aggregate function is available.
  3865. ** inside SQLite. The following routines implement that function.
  3866. */
  3867. static void md5step( sqlite3_context context, int argc, sqlite3_value[] argv )
  3868. {
  3869. MD5Context p = null;
  3870. int i;
  3871. if ( argc < 1 )
  3872. return;
  3873. Mem pMem = sqlite3_aggregate_context( context, 1 );//sizeof(*p));
  3874. if ( pMem._MD5Context == null )
  3875. {
  3876. pMem._MD5Context = new MD5Context();
  3877. ( (MD5Context)pMem._MD5Context )._Mem = pMem;
  3878. }
  3879. p = (MD5Context)pMem._MD5Context;
  3880. if ( p == null )
  3881. return;
  3882. if ( !p.isInit )
  3883. {
  3884. MD5Init( p );
  3885. }
  3886. for ( i = 0; i < argc; i++ )
  3887. {
  3888. byte[] zData = sqlite3_value_text( argv[i] ) == null ? null : Encoding.UTF8.GetBytes( sqlite3_value_text( argv[i] ) );
  3889. if ( zData != null )
  3890. {
  3891. MD5Update( p, zData, zData.Length );
  3892. }
  3893. }
  3894. }
  3895. static void md5finalize( sqlite3_context context )
  3896. {
  3897. MD5Context p;
  3898. byte[] digest = new byte[16];
  3899. byte[] zBuf = new byte[33];
  3900. Mem pMem = sqlite3_aggregate_context( context, 0 );
  3901. if ( pMem != null )
  3902. {
  3903. p = (MD5Context)pMem._MD5Context;
  3904. MD5Final( digest, p );
  3905. }
  3906. DigestToBase16( digest, zBuf );
  3907. sqlite3_result_text( context, Encoding.UTF8.GetString( zBuf, 0, zBuf.Length ), -1, SQLITE_TRANSIENT );
  3908. }
  3909. static int Md5_Register( sqlite3 db, ref string dummy1, sqlite3_api_routines dummy2 )
  3910. {
  3911. int rc = sqlite3_create_function( db, "md5sum", -1, SQLITE_UTF8, 0, null,
  3912. md5step, md5finalize );
  3913. sqlite3_overload_function( db, "md5sum", -1 ); /* To exercise this API */
  3914. return rc;
  3915. }
  3916. #endif //* defined(SQLITE_TEST) */
  3917. /*
  3918. ** If the macro TCLSH is one, then put in code this for the
  3919. ** "main" routine that will initialize Tcl and take input from
  3920. ** standard input, or if a file is named on the command line
  3921. ** the TCL interpreter reads and evaluates that file.
  3922. */
  3923. #if TCLSH//==1
  3924. //static char zMainloop[] =
  3925. // "set line {}\n"
  3926. // "while {![eof stdin]} {\n"
  3927. // "if {$line!=\"\"} {\n"
  3928. // "puts -nonewline \"> \"\n"
  3929. // "} else {\n"
  3930. // "puts -nonewline \"% \"\n"
  3931. // "}\n"
  3932. // "flush stdout\n"
  3933. // "append line [gets stdin]\n"
  3934. // "if {[info complete $line]} {\n"
  3935. // "if {[catch {uplevel #0 $line} result]} {\n"
  3936. // "puts stderr \"Error: $result\"\n"
  3937. // "} elseif {$result!=\"\"} {\n"
  3938. // "puts $result\n"
  3939. // "}\n"
  3940. // "set line {}\n"
  3941. // "} else {\n"
  3942. // "append line \\n\n"
  3943. // "}\n"
  3944. // "}\n"
  3945. //;
  3946. #endif
  3947. //#if TCLSH==2
  3948. //static char zMainloop[] =
  3949. //#include "spaceanal_tcl.h"
  3950. //;
  3951. //#endif
  3952. //#define TCLSH_MAIN main /* Needed to fake out mktclapp */
  3953. #if SQLITE_TEST
  3954. //static void init_all(Tcl_Interp );
  3955. static int init_all_cmd(
  3956. ClientData cd,
  3957. Tcl_Interp interp,
  3958. int objc,
  3959. Tcl_Obj[] objv
  3960. )
  3961. {
  3962. Tcl_Interp slave;
  3963. if ( objc != 2 )
  3964. {
  3965. TCL.Tcl_WrongNumArgs( interp, 1, objv, "SLAVE" );
  3966. return TCL.TCL_ERROR;
  3967. }
  3968. slave = null;// TCL.Tcl_GetSlave( interp, TCL.Tcl_GetString( objv[1] ) );
  3969. if ( slave == null )
  3970. {
  3971. return TCL.TCL_ERROR;
  3972. }
  3973. init_all( slave );
  3974. return TCL.TCL_OK;
  3975. }
  3976. #endif
  3977. /*
  3978. ** Configure the interpreter passed as the first argument to have access
  3979. ** to the commands and linked variables that make up:
  3980. **
  3981. ** * the [sqlite3] extension itself,
  3982. **
  3983. ** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
  3984. **
  3985. ** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
  3986. ** test suite.
  3987. */
  3988. static void init_all( Tcl_Interp interp )
  3989. {
  3990. Sqlite3_Init( interp );
  3991. #if (SQLITE_TEST) || (SQLITE_TCLMD5)
  3992. Md5_Init( interp );
  3993. #endif
  3994. #if SQLITE_TEST
  3995. //{
  3996. //extern int Sqliteconfig_Init(Tcl_Interp);
  3997. //extern int Sqlitetest1_Init(Tcl_Interp);
  3998. //extern int Sqlitetest2_Init(Tcl_Interp);
  3999. //extern int Sqlitetest3_Init(Tcl_Interp);
  4000. //extern int Sqlitetest4_Init(Tcl_Interp);
  4001. //extern int Sqlitetest5_Init(Tcl_Interp);
  4002. //extern int Sqlitetest6_Init(Tcl_Interp);
  4003. //extern int Sqlitetest7_Init(Tcl_Interp);
  4004. //extern int Sqlitetest8_Init(Tcl_Interp);
  4005. //extern int Sqlitetest9_Init(Tcl_Interp);
  4006. //extern int Sqlitetestasync_Init(Tcl_Interp);
  4007. //extern int Sqlitetest_autoext_Init(Tcl_Interp);
  4008. //extern int Sqlitetest_demovfs_Init(Tcl_Interp );
  4009. //extern int Sqlitetest_func_Init(Tcl_Interp);
  4010. //extern int Sqlitetest_hexio_Init(Tcl_Interp);
  4011. //extern int Sqlitetest_malloc_Init(Tcl_Interp);
  4012. //extern int Sqlitetest_mutex_Init(Tcl_Interp);
  4013. //extern int Sqlitetestschema_Init(Tcl_Interp);
  4014. //extern int Sqlitetestsse_Init(Tcl_Interp);
  4015. //extern int Sqlitetesttclvar_Init(Tcl_Interp);
  4016. //extern int SqlitetestThread_Init(Tcl_Interp);
  4017. //extern int SqlitetestOnefile_Init();
  4018. //extern int SqlitetestOsinst_Init(Tcl_Interp);
  4019. //extern int Sqlitetestbackup_Init(Tcl_Interp);
  4020. //extern int Sqlitetestintarray_Init(Tcl_Interp);
  4021. //extern int Sqlitetestvfs_Init(Tcl_Interp );
  4022. //extern int SqlitetestStat_Init(Tcl_Interp);
  4023. //extern int Sqlitetestrtree_Init(Tcl_Interp);
  4024. //extern int Sqlitequota_Init(Tcl_Interp);
  4025. //extern int Sqlitemultiplex_Init(Tcl_Interp);
  4026. //extern int SqliteSuperlock_Init(Tcl_Interp);
  4027. //extern int SqlitetestSyscall_Init(Tcl_Interp);
  4028. //extern int Sqlitetestfuzzer_Init(Tcl_Interp);
  4029. //extern int Sqlitetestwholenumber_Init(Tcl_Interp);
  4030. #if (SQLITE_ENABLE_FTS3) || (SQLITE_ENABLE_FTS4)
  4031. //extern int Sqlitetestfts3_Init(Tcl_Interp interp);
  4032. #endif
  4033. #if SQLITE_ENABLE_ZIPVFS
  4034. // extern int Zipvfs_Init(Tcl_Interp);
  4035. // Zipvfs_Init(interp);
  4036. #endif
  4037. Sqliteconfig_Init( interp );
  4038. Sqlitetest1_Init( interp );
  4039. Sqlitetest2_Init( interp );
  4040. Sqlitetest3_Init( interp );
  4041. //Threads not implemented under C#
  4042. //Sqlitetest4_Init(interp);
  4043. //TODO implemented under C#
  4044. //Sqlitetest5_Init(interp);
  4045. //Simulated Crashtests not implemented under C#
  4046. //Sqlitetest6_Init(interp);
  4047. //client/server version (Unix Only) not implemented under C#
  4048. //Sqlitetest7_Init(interp);
  4049. //virtual table interface not implemented under C#
  4050. //Sqlitetest8_Init(interp);
  4051. Sqlitetest9_Init( interp );
  4052. //asynchronous IO extension interface not implemented under C#
  4053. //Sqlitetestasync_Init(interp);
  4054. //sqlite3_auto_extension() function not implemented under C#
  4055. //Sqlitetest_autoext_Init(interp);
  4056. //VFS not implemented under C#
  4057. //Sqlitetest_demovfs_Init(interp);
  4058. Sqlitetest_func_Init( interp );
  4059. Sqlitetest_hexio_Init( interp );
  4060. Sqlitetest_malloc_Init( interp );
  4061. Sqlitetest_mutex_Init( interp );
  4062. //virtual table interfaces not implemented under C#
  4063. //Sqlitetestschema_Init(interp);
  4064. //virtual table interfaces not implemented under C#
  4065. //Sqlitetesttclvar_Init(interp);
  4066. //Threads not implemented under C#
  4067. //SqlitetestThread_Init(interp);
  4068. //VFS not implemented under C#
  4069. //SqlitetestOnefile_Init(interp);
  4070. //VFS not implemented under C#
  4071. //SqlitetestOsinst_Init(interp);
  4072. Sqlitetestbackup_Init( interp );
  4073. //virtual table interfaces not implemented under C#
  4074. //Sqlitetestintarray_Init(interp);
  4075. //VFS not implemented under C#
  4076. //Sqlitetestvfs_Init(interp);
  4077. //virtual table interfaces not implemented under C#
  4078. //SqlitetestStat_Init(interp);
  4079. //Sqlitetestrtree_Init( interp );
  4080. //Sqlitequota_Init( interp );
  4081. //Sqlitemultiplex_Init( interp );
  4082. //SqliteSuperlock_Init( interp );
  4083. //SqlitetestSyscall_Init( interp );
  4084. Sqlitetestfuzzer_Init( interp );
  4085. //Sqlitetestwholenumber_Init( interp );
  4086. #if (SQLITE_ENABLE_FTS3) || (SQLITE_ENABLE_FTS4)
  4087. //Sqlitetestfts3_Init(interp);
  4088. #endif
  4089. TCL.Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, null );
  4090. #if SQLITE_SSE
  4091. Sqlitetestsse_Init(interp);
  4092. #endif
  4093. }
  4094. #endif
  4095. }
  4096. #if FALSE
  4097. //#define TCLSH_MAIN main /* Needed to fake out mktclapp */
  4098. int TCLSH_MAIN(int argc, char **argv){
  4099. Tcl_Interp interp;
  4100. /* Call sqlite3_shutdown() once before doing anything else. This is to
  4101. ** test that sqlite3_shutdown() can be safely called by a process before
  4102. ** sqlite3_initialize() is. */
  4103. sqlite3_shutdown();
  4104. #if TCLSH//TCLSH==2
  4105. sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
  4106. #endif
  4107. Tcl_FindExecutable(argv[0]);
  4108. interp = TCL.Tcl_CreateInterp();
  4109. init_all(interp);
  4110. if( argc>=2 ){
  4111. int i;
  4112. char zArgc[32];
  4113. sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
  4114. Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
  4115. Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
  4116. Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
  4117. for(i=3-TCLSH; i<argc; i++){
  4118. Tcl_SetVar(interp, "argv", argv[i],
  4119. TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
  4120. }
  4121. if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
  4122. string zInfo = TCL.Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
  4123. if( zInfo==0 ) zInfo = TCL.Tcl_GetStringResult(interp);
  4124. fprintf(stderr,"%s: %s\n", *argv, zInfo);
  4125. return 1;
  4126. }
  4127. }
  4128. if( TCLSH==2 || argc<=1 ){
  4129. Tcl_GlobalEval(interp, zMainloop);
  4130. }
  4131. return 0;
  4132. }
  4133. #endif
  4134. #endif // * TCLSH */
  4135. #endif // NO_TCL
  4136. }