wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 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  
7 namespace Community.CsharpSqlite
8 {
9 #if TCLSH
10 using tcl.lang;
11 using ClientData = System.Object;
12  
13 #if !SQLITE_OMIT_INCRBLOB
14 using sqlite3_blob = sqlite.Incrblob;
15 #endif
16 using sqlite3_stmt = Sqlite3.Vdbe;
17 using Tcl_DString = tcl.lang.TclString;
18 using Tcl_Interp = tcl.lang.Interp;
19 using Tcl_Obj = tcl.lang.TclObject;
20 using Tcl_WideInt = System.Int64;
21  
22 using sqlite3_value = Sqlite3.Mem;
23 using System.IO;
24 using System.Text;
25  
26 public partial class Sqlite3
27 {
28 /*
29 ** 2001 September 15
30 **
31 ** The author disclaims copyright to this source code. In place of
32 ** a legal notice, here is a blessing:
33 **
34 ** May you do good and not evil.
35 ** May you find forgiveness for yourself and forgive others.
36 ** May you share freely, never taking more than you give.
37 **
38 *************************************************************************
39 ** A TCL Interface to SQLite. Append this file to sqlite3.c and
40 ** compile the whole thing to build a TCL-enabled version of SQLite.
41 **
42 ** Compile-time options:
43 **
44 ** -DTCLSH=1 Add a "main()" routine that works as a tclsh.
45 **
46 ** -DSQLITE_TCLMD5 When used in conjuction with -DTCLSH=1, add
47 ** four new commands to the TCL interpreter for
48 ** generating MD5 checksums: md5, md5file,
49 ** md5-10x8, and md5file-10x8.
50 **
51 ** -DSQLITE_TEST When used in conjuction with -DTCLSH=1, add
52 ** hundreds of new commands used for testing
53 ** SQLite. This option implies -DSQLITE_TCLMD5.
54 *************************************************************************
55 ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
56 ** C#-SQLite is an independent reimplementation of the SQLite software library
57 **
58 ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
59 **
60 *************************************************************************
61 */
62 //#include "tcl.h"
63 //#include <errno.h>
64  
65 /*
66 ** Some additional include files are needed if this file is not
67 ** appended to the amalgamation.
68 */
69 #if !SQLITE_AMALGAMATION
70 //# include "sqlite3.h"
71 //# include <stdlib.h>
72 //# include <string.h>
73 //# include <Debug.Assert.h>
74 // typedef unsigned char u8;
75 #endif
76  
77 /*
78 * Windows needs to know which symbols to export. Unix does not.
79 * BUILD_sqlite should be undefined for Unix.
80 */
81 #if BUILD_sqlite
82 //#undef TCL.Tcl_STORAGE_CLASS
83 //#define TCL.Tcl_STORAGE_CLASS DLLEXPORT
84 #endif // * BUILD_sqlite */
85  
86 const int NUM_PREPARED_STMTS = 10;//#define NUM_PREPARED_STMTS 10
87 const int MAX_PREPARED_STMTS = 100;//#define MAX_PREPARED_STMTS 100
88  
89 /*
90 ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
91 ** have to do a translation when going between the two. Set the
92 ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do
93 ** this translation.
94 */
95 #if Tcl_UTF_MAX && !SQLITE_UTF8
96 //# define UTF_TRANSLATION_NEEDED 1
97 #endif
98  
99 /*
100 ** New SQL functions can be created as TCL scripts. Each such function
101 ** is described by an instance of the following structure.
102 */
103 //typedef struct SqlFunc SqlFunc;
104 public class SqlFunc
105 {
106 public Tcl_Interp interp; /* The TCL interpret to execute the function */
107 public Tcl_Obj pScript; /* The Tcl_Obj representation of the script */
108 public int useEvalObjv; /* True if it is safe to use TCL.Tcl_EvalObjv */
109 public string zName; /* Name of this function */
110 public SqlFunc pNext; /* Next function on the list of them all */
111 }
112  
113 /*
114 ** New collation sequences function can be created as TCL scripts. Each such
115 ** function is described by an instance of the following structure.
116 */
117 //typedef struct SqlCollate SqlCollate;
118 public class SqlCollate
119 {
120 public Tcl_Interp interp; /* The TCL interpret to execute the function */
121 public string zScript; /* The script to be run */
122 public SqlCollate pNext; /* Next function on the list of them all */
123 }
124  
125 /*
126 ** Prepared statements are cached for faster execution. Each prepared
127 ** statement is described by an instance of the following structure.
128 */
129 //typedef struct SqlPreparedStmt SqlPreparedStmt;
130 public class SqlPreparedStmt
131 {
132 public SqlPreparedStmt pNext; /* Next in linked list */
133 public SqlPreparedStmt pPrev; /* Previous on the list */
134 public sqlite3_stmt pStmt; /* The prepared statement */
135 public Mem[] aMem; /* Original Memory Values to be reused */
136 public int nSql; /* chars in zSql[] */
137 public string zSql; /* Text of the SQL statement */
138 public int nParm; /* Size of apParm array */
139 public Tcl_Obj[] apParm; /* Array of referenced object pointers */
140 }
141  
142 //typedef struct IncrblobChannel IncrblobChannel;
143  
144 /*
145 ** There is one instance of this structure for each SQLite database
146 ** that has been opened by the SQLite TCL interface.
147 */
148 //typedef struct SqliteDb SqliteDb;
149 public class SqliteDb : object
150 {
151 public sqlite3 db; /* The "real" database structure. MUST BE FIRST */
152 public Tcl_Interp interp; /* The interpreter used for this database */
153 public string zBusy; /* The busy callback routine */
154 public string zCommit; /* The commit hook callback routine */
155 public string zTrace; /* The trace callback routine */
156 public string zProfile; /* The profile callback routine */
157 public string zProgress; /* The progress callback routine */
158 public string zAuth; /* The authorization callback routine */
159 public int disableAuth; /* Disable the authorizer if it exists */
160 public string zNull = ""; /* Text to substitute for an SQL NULL value */
161 public SqlFunc pFunc; /* List of SQL functions */
162 public Tcl_Obj pUpdateHook; /* Update hook script (if any) */
163 public Tcl_Obj pRollbackHook; /* Rollback hook script (if any) */
164 public Tcl_Obj pWalHook; /* WAL hook script (if any) */
165 public Tcl_Obj pUnlockNotify; /* Unlock notify script (if any) */
166 public SqlCollate pCollate; /* List of SQL collation functions */
167 public int rc; /* Return code of most recent sqlite3_exec() */
168 public Tcl_Obj pCollateNeeded; /* Collation needed script */
169 public SqlPreparedStmt stmtList; /* List of prepared statements*/
170 public SqlPreparedStmt stmtLast; /* Last statement in the list */
171 public int maxStmt; /* The next maximum number of stmtList */
172 public int nStmt; /* Number of statements in stmtList */
173 #if !SQLITE_OMIT_INCRBLOB
174 public IncrblobChannel pIncrblob; /* Linked list of open incrblob channels */
175 #endif
176 public int nStep, nSort, nIndex; /* Statistics for most recent operation */
177 public int nTransaction; /* Number of nested [transaction] methods */
178 }
179  
180 #if !SQLITE_OMIT_INCRBLOB
181 class IncrblobChannel
182 {
183 public sqlite3_blob pBlob; /* sqlite3 blob handle */
184 public SqliteDb pDb; /* Associated database connection */
185 public int iSeek; /* Current seek offset */
186 public Tcl_Channel channel; /* Channel identifier */
187 public IncrblobChannel pNext; /* Linked list of all open incrblob channels */
188 public IncrblobChannel pPrev; /* Linked list of all open incrblob channels */
189 }
190 #endif
191  
192  
193 /*
194 ** Compute a string length that is limited to what can be stored in
195 ** lower 30 bits of a 32-bit signed integer.
196 */
197 static int strlen30( StringBuilder z )
198 {
199 //string z2 = z;
200 //while( *z2 ){ z2++; }
201 return 0x3fffffff & z.Length;
202 }
203  
204 static int strlen30( string z )
205 {
206 //string z2 = z;
207 //while( *z2 ){ z2++; }
208 return 0x3fffffff & z.Length;
209 }
210  
211  
212 #if !SQLITE_OMIT_INCRBLOB
213 /*
214 ** Close all incrblob channels opened using database connection pDb.
215 ** This is called when shutting down the database connection.
216 */
217 static void closeIncrblobChannels( SqliteDb pDb )
218 {
219 IncrblobChannel p;
220 IncrblobChannel pNext;
221  
222 for ( p = pDb.pIncrblob ; p != null ; p = pNext )
223 {
224 pNext = p.pNext;
225  
226 /* Note: Calling unregister here call TCL.Tcl_Close on the incrblob channel,
227 ** which deletes the IncrblobChannel structure at p. So do not
228 ** call TCL.Tcl_Free() here.
229 */
230 TCL.Tcl_UnregisterChannel( pDb.interp, p.channel );
231 }
232 }
233  
234 /*
235 ** Close an incremental blob channel.
236 */
237 //static int incrblobClose(object instanceData, Tcl_Interp interp){
238 // IncrblobChannel p = (IncrblobChannel )instanceData;
239 // int rc = sqlite3_blob_close(p.pBlob);
240 // sqlite3 db = p.pDb.db;
241  
242 // /* Remove the channel from the SqliteDb.pIncrblob list. */
243 // if( p.pNext ){
244 // p.pNext.pPrev = p.pPrev;
245 // }
246 // if( p.pPrev ){
247 // p.pPrev.pNext = p.pNext;
248 // }
249 // if( p.pDb.pIncrblob==p ){
250 // p.pDb.pIncrblob = p.pNext;
251 // }
252  
253 // /* Free the IncrblobChannel structure */
254 // TCL.Tcl_Free((char )p);
255  
256 // if( rc!=SQLITE_OK ){
257 // TCL.Tcl_SetResult(interp, (char )sqlite3_errmsg(db), TCL.Tcl_VOLATILE);
258 // return TCL.TCL_ERROR;
259 // }
260 // return TCL.TCL_OK;
261 //}
262  
263 /*
264 ** Read data from an incremental blob channel.
265 */
266 //static int incrblobInput(
267 // object instanceData,
268 // char *buf,
269 // int bufSize,
270 // int *errorCodePtr
271 //){
272 // IncrblobChannel p = (IncrblobChannel )instanceData;
273 // int nRead = bufSize; /* Number of bytes to read */
274 // int nBlob; /* Total size of the blob */
275 // int rc; /* sqlite error code */
276  
277 // nBlob = sqlite3_blob_bytes(p.pBlob);
278 // if( (p.iSeek+nRead)>nBlob ){
279 // nRead = nBlob-p.iSeek;
280 // }
281 // if( nRead<=0 ){
282 // return 0;
283 // }
284  
285 // rc = sqlite3_blob_read(p.pBlob, (void )buf, nRead, p.iSeek);
286 // if( rc!=SQLITE_OK ){
287 // *errorCodePtr = rc;
288 // return -1;
289 // }
290  
291 // p.iSeek += nRead;
292 // return nRead;
293 //}
294  
295 /*
296 ** Write data to an incremental blob channel.
297 */
298 //static int incrblobOutput(
299 // object instanceData,
300 // string buf,
301 // int toWrite,
302 // int *errorCodePtr
303 //){
304 // IncrblobChannel p = (IncrblobChannel )instanceData;
305 // int nWrite = toWrite; /* Number of bytes to write */
306 // int nBlob; /* Total size of the blob */
307 // int rc; /* sqlite error code */
308  
309 // nBlob = sqlite3_blob_bytes(p.pBlob);
310 // if( (p.iSeek+nWrite)>nBlob ){
311 // *errorCodePtr = EINVAL;
312 // return -1;
313 // }
314 // if( nWrite<=0 ){
315 // return 0;
316 // }
317  
318 // rc = sqlite3_blob_write(p.pBlob, (void )buf, nWrite, p.iSeek);
319 // if( rc!=SQLITE_OK ){
320 // *errorCodePtr = EIO;
321 // return -1;
322 // }
323  
324 // p.iSeek += nWrite;
325 // return nWrite;
326 //}
327  
328 /*
329 ** Seek an incremental blob channel.
330 */
331 //static int incrblobSeek(
332 // object instanceData,
333 // long offset,
334 // int seekMode,
335 // int *errorCodePtr
336 //){
337 // IncrblobChannel p = (IncrblobChannel )instanceData;
338  
339 // switch( seekMode ){
340 // case SEEK_SET:
341 // p.iSeek = offset;
342 // break;
343 // case SEEK_CUR:
344 // p.iSeek += offset;
345 // break;
346 // case SEEK_END:
347 // p.iSeek = sqlite3_blob_bytes(p.pBlob) + offset;
348 // break;
349  
350 // default: Debug.Assert(!"Bad seekMode");
351 // }
352  
353 // return p.iSeek;
354 //}
355  
356  
357 //static void incrblobWatch(object instanceData, int mode){
358 // /* NO-OP */
359 //}
360 //static int incrblobHandle(object instanceData, int dir, object *hPtr){
361 // return TCL.TCL_ERROR;
362 //}
363  
364 static TCL.Tcl_ChannelType IncrblobChannelType = {
365 "incrblob", /* typeName */
366 TCL.Tcl_CHANNEL_VERSION_2, /* version */
367 incrblobClose, /* closeProc */
368 incrblobInput, /* inputProc */
369 incrblobOutput, /* outputProc */
370 incrblobSeek, /* seekProc */
371 0, /* setOptionProc */
372 0, /* getOptionProc */
373 incrblobWatch, /* watchProc (this is a no-op) */
374 incrblobHandle, /* getHandleProc (always returns error) */
375 0, /* close2Proc */
376 0, /* blockModeProc */
377 0, /* flushProc */
378 0, /* handlerProc */
379 0, /* wideSeekProc */
380 };
381  
382 /*
383 ** Create a new incrblob channel.
384 */
385 static int count = 0;
386 static int createIncrblobChannel(
387 Tcl_Interp interp,
388 SqliteDb pDb,
389 string zDb,
390 string zTable,
391 string zColumn,
392 sqlite_int64 iRow,
393 int isReadonly
394 ){
395 IncrblobChannel p;
396 sqlite3 db = pDb.db;
397 sqlite3_blob pBlob;
398 int rc;
399 int flags = TCL.Tcl_READABLE|(isReadonly ? 0 : TCL.Tcl_WRITABLE);
400  
401 /* This variable is used to name the channels: "incrblob_[incr count]" */
402 //static int count = 0;
403 string zChannel = "";//string[64];
404  
405 rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, pBlob);
406 if( rc!=SQLITE_OK ){
407 TCL.Tcl_SetResult(interp, sqlite3_errmsg(pDb.db), TCL.Tcl_VOLATILE);
408 return TCL.TCL_ERROR;
409 }
410  
411 p = new IncrblobChannel();//(IncrblobChannel )Tcl_Alloc(sizeof(IncrblobChannel));
412 p.iSeek = 0;
413 p.pBlob = pBlob;
414  
415 sqlite3_snprintf(64, zChannel, "incrblob_%d", ++count);
416 p.channel = TCL.Tcl_CreateChannel(IncrblobChannelType, zChannel, p, flags);
417 TCL.Tcl_RegisterChannel(interp, p.channel);
418  
419 /* Link the new channel into the SqliteDb.pIncrblob list. */
420 p.pNext = pDb.pIncrblob;
421 p.pPrev = null;
422 if( p.pNext!=null ){
423 p.pNext.pPrev = p;
424 }
425 pDb.pIncrblob = p;
426 p.pDb = pDb;
427  
428 TCL.Tcl_SetResult(interp, Tcl_GetChannelName(p.channel), TCL.Tcl_VOLATILE);
429 return TCL.TCL_OK;
430 }
431 #else // * else clause for "#if !SQLITE_OMIT_INCRBLOB" */
432 //#define closeIncrblobChannels(pDb)
433 static void closeIncrblobChannels( SqliteDb pDb )
434 {
435 }
436 #endif
437  
438 /*
439 ** Look at the script prefix in pCmd. We will be executing this script
440 ** after first appending one or more arguments. This routine analyzes
441 ** the script to see if it is safe to use TCL.Tcl_EvalObjv() on the script
442 ** rather than the more general TCL.Tcl_EvalEx(). TCL.Tcl_EvalObjv() is much
443 ** faster.
444 **
445 ** Scripts that are safe to use with TCL.Tcl_EvalObjv() consists of a
446 ** command name followed by zero or more arguments with no [...] or $
447 ** or {...} or ; to be seen anywhere. Most callback scripts consist
448 ** of just a single procedure name and they meet this requirement.
449 */
450 static int safeToUseEvalObjv( Tcl_Interp interp, Tcl_Obj pCmd )
451 {
452 /* We could try to do something with TCL.Tcl_Parse(). But we will instead
453 ** just do a search for forbidden characters. If any of the forbidden
454 ** characters appear in pCmd, we will report the string as unsafe.
455 */
456 string z;
457 int n = 0;
458 z = TCL.Tcl_GetStringFromObj( pCmd, out n );
459 while ( n-- > 0 )
460 {
461 int c = z[n];// *( z++ );
462 if ( c == '$' || c == '[' || c == ';' )
463 return 0;
464 }
465 return 1;
466 }
467  
468 /*
469 ** Find an SqlFunc structure with the given name. Or create a new
470 ** one if an existing one cannot be found. Return a pointer to the
471 ** structure.
472 */
473 static SqlFunc findSqlFunc( SqliteDb pDb, string zName )
474 {
475 SqlFunc p, pNew;
476 int i;
477 pNew = new SqlFunc();//(SqlFunc)Tcl_Alloc( sizeof(*pNew) + strlen30(zName) + 1 );
478 //pNew.zName = (char)&pNew[1];
479 //for(i=0; zName[i]; i++){ pNew.zName[i] = tolower(zName[i]); }
480 //pNew.zName[i] = 0;
481 pNew.zName = zName.ToLower();
482 for ( p = pDb.pFunc; p != null; p = p.pNext )
483 {
484 if ( p.zName == pNew.zName )
485 {
486 //Tcl_Free((char)pNew);
487 return p;
488 }
489 }
490 pNew.interp = pDb.interp;
491 pNew.pScript = null;
492 pNew.pNext = pDb.pFunc;
493 pDb.pFunc = pNew;
494 return pNew;
495 }
496  
497 /*
498 ** Finalize and free a list of prepared statements
499 */
500 static void flushStmtCache( SqliteDb pDb )
501 {
502 SqlPreparedStmt pPreStmt;
503  
504 while ( pDb.stmtList != null )
505 {
506 sqlite3_finalize( pDb.stmtList.pStmt );
507 pPreStmt = pDb.stmtList;
508 pDb.stmtList = pDb.stmtList.pNext;
509 TCL.Tcl_Free( ref pPreStmt );
510 }
511 pDb.nStmt = 0;
512 pDb.stmtLast = null;
513 }
514  
515 /*
516 ** TCL calls this procedure when an sqlite3 database command is
517 ** deleted.
518 */
519 static void DbDeleteCmd( ref object db )
520 {
521 SqliteDb pDb = (SqliteDb)db;
522 flushStmtCache( pDb );
523 closeIncrblobChannels( pDb );
524 sqlite3_close( pDb.db );
525 while ( pDb.pFunc != null )
526 {
527 SqlFunc pFunc = pDb.pFunc;
528 pDb.pFunc = pFunc.pNext;
529 TCL.Tcl_DecrRefCount( ref pFunc.pScript );
530 TCL.Tcl_Free( ref pFunc );
531 }
532 while ( pDb.pCollate != null )
533 {
534 SqlCollate pCollate = pDb.pCollate;
535 pDb.pCollate = pCollate.pNext;
536 TCL.Tcl_Free( ref pCollate );
537 }
538 if ( pDb.zBusy != null )
539 {
540 TCL.Tcl_Free( ref pDb.zBusy );
541 }
542 if ( pDb.zTrace != null )
543 {
544 TCL.Tcl_Free( ref pDb.zTrace );
545 }
546 if ( pDb.zProfile != null )
547 {
548 TCL.Tcl_Free( ref pDb.zProfile );
549 }
550 if ( pDb.zAuth != null )
551 {
552 TCL.Tcl_Free( ref pDb.zAuth );
553 }
554 if ( pDb.zNull != null )
555 {
556 TCL.Tcl_Free( ref pDb.zNull );
557 }
558 if ( pDb.pUpdateHook != null )
559 {
560 TCL.Tcl_DecrRefCount( ref pDb.pUpdateHook );
561 }
562 if ( pDb.pRollbackHook != null )
563 {
564 TCL.Tcl_DecrRefCount( ref pDb.pRollbackHook );
565 }
566 if ( pDb.pWalHook != null )
567 {
568 TCL.Tcl_DecrRefCount( ref pDb.pWalHook );
569 }
570 if ( pDb.pCollateNeeded != null )
571 {
572 TCL.Tcl_DecrRefCount( ref pDb.pCollateNeeded );
573 }
574 TCL.Tcl_Free( ref pDb );
575 }
576  
577 /*
578 ** This routine is called when a database file is locked while trying
579 ** to execute SQL.
580 */
581 static int DbBusyHandler( object cd, int nTries )
582 {
583 SqliteDb pDb = (SqliteDb)cd;
584 int rc;
585 StringBuilder zVal = new StringBuilder( 30 );//char zVal[30];
586  
587 sqlite3_snprintf( 30, zVal, "%d", nTries );
588 rc = TCL.Tcl_VarEval( pDb.interp, pDb.zBusy, " ", zVal.ToString(), null );
589 if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
590 {
591 return 0;
592 }
593 return 1;
594 }
595  
596 #if !SQLITE_OMIT_PROGRESS_CALLBACK
597 /*
598 ** This routine is invoked as the 'progress callback' for the database.
599 */
600 static int DbProgressHandler( object cd )
601 {
602 SqliteDb pDb = (SqliteDb)cd;
603 int rc;
604  
605 Debug.Assert( pDb.zProgress != null );
606 rc = TCL.Tcl_Eval( pDb.interp, pDb.zProgress );
607 if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
608 {
609 return 1;
610 }
611 return 0;
612 }
613 #endif
614  
615 #if !SQLITE_OMIT_TRACE
616 /*
617 ** This routine is called by the SQLite trace handler whenever a new
618 ** block of SQL is executed. The TCL script in pDb.zTrace is executed.
619 */
620 static void DbTraceHandler( object cd, string zSql )
621 {
622 SqliteDb pDb = (SqliteDb)cd;
623 TclObject str = null;
624  
625 TCL.Tcl_DStringInit( out str );
626 TCL.Tcl_DStringAppendElement( str, pDb.zTrace );
627 TCL.Tcl_DStringAppendElement( str, " {" + zSql + "}" );
628 TCL.Tcl_EvalObjEx( pDb.interp, str, 0 );// TCL.Tcl_Eval( pDb.interp, TCL.Tcl_DStringValue( ref str ) );
629 TCL.Tcl_DStringFree( ref str );
630 TCL.Tcl_ResetResult( pDb.interp );
631 }
632 #endif
633  
634 #if !SQLITE_OMIT_TRACE
635 /*
636 ** This routine is called by the SQLite profile handler after a statement
637 ** SQL has executed. The TCL script in pDb.zProfile is evaluated.
638 */
639 static void DbProfileHandler( object cd, string zSql, sqlite_int64 tm )
640 {
641 SqliteDb pDb = (SqliteDb)cd;
642 TclObject str = null;
643 StringBuilder zTm = new StringBuilder( 100 );//char zTm[100];
644  
645 sqlite3_snprintf( 100, zTm, "%lld", tm );
646 TCL.Tcl_DStringInit( out str );
647 TCL.Tcl_DStringAppendElement( str, pDb.zProfile );
648 TCL.Tcl_DStringAppendElement( str, " {" + zSql + "}" );
649 TCL.Tcl_DStringAppendElement( str, " {" + zTm.ToString() + "}" );
650 TCL.Tcl_Eval( pDb.interp, str.ToString() );
651 TCL.Tcl_DStringFree( ref str );
652 TCL.Tcl_ResetResult( pDb.interp );
653 }
654 #endif
655  
656 /*
657 ** This routine is called when a transaction is committed. The
658 ** TCL script in pDb.zCommit is executed. If it returns non-zero or
659 ** if it throws an exception, the transaction is rolled back instead
660 ** of being committed.
661 */
662 static int DbCommitHandler( object cd )
663 {
664 SqliteDb pDb = (SqliteDb)cd;
665 int rc;
666  
667 rc = TCL.Tcl_Eval( pDb.interp, pDb.zCommit );
668 if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
669 {
670 return 1;
671 }
672 return 0;
673 }
674  
675 static void DbRollbackHandler( object _object )
676 {
677 SqliteDb pDb = (SqliteDb)_object;
678 Debug.Assert( pDb.pRollbackHook != null );
679 if ( TCL.TCL_OK != TCL.Tcl_EvalObjEx( pDb.interp, pDb.pRollbackHook, 0 ) )
680 {
681 TCL.Tcl_BackgroundError( pDb.interp );
682 }
683 }
684  
685 /*
686 ** This procedure handles wal_hook callbacks.
687 */
688 static int DbWalHandler(
689 object clientData,
690 sqlite3 db,
691 string zDb,
692 int nEntry
693 )
694 {
695 int ret = SQLITE_OK;
696 Tcl_Obj p;
697 SqliteDb pDb = (SqliteDb)clientData;
698 Tcl_Interp interp = pDb.interp;
699 Debug.Assert( pDb.pWalHook != null );
700  
701 p = TCL.Tcl_DuplicateObj( pDb.pWalHook );
702 TCL.Tcl_IncrRefCount( p );
703 TCL.Tcl_ListObjAppendElement( interp, p, TCL.Tcl_NewStringObj( zDb, -1 ) );
704 TCL.Tcl_ListObjAppendElement( interp, p, TCL.Tcl_NewIntObj( nEntry ) );
705 if ( TCL.TCL_OK != TCL.Tcl_EvalObjEx( interp, p, 0 )
706 || TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, TCL.Tcl_GetObjResult( interp ), out ret )
707 )
708 {
709 TCL.Tcl_BackgroundError( interp );
710 }
711 TCL.Tcl_DecrRefCount( ref p );
712  
713 return ret;
714 }
715  
716 #if (SQLITE_TEST) && (SQLITE_ENABLE_UNLOCK_NOTIFY)
717 static void setTestUnlockNotifyVars(Tcl_Interp interp, int iArg, int nArg){
718 char zBuf[64];
719 sprintf(zBuf, "%d", iArg);
720 Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY);
721 sprintf(zBuf, "%d", nArg);
722 Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY);
723 }
724 #else
725 //# define setTestUnlockNotifyVars(x,y,z)
726 #endif
727  
728 #if SQLITE_ENABLE_UNLOCK_NOTIFY
729 static void DbUnlockNotify(void **apArg, int nArg){
730 int i;
731 for(i=0; i<nArg; i++){
732 const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
733 SqliteDb *pDb = (SqliteDb )apArg[i];
734 setTestUnlockNotifyVars(pDb.interp, i, nArg);
735 Debug.Assert( pDb.pUnlockNotify);
736 Tcl_EvalObjEx(pDb.interp, pDb.pUnlockNotify, flags);
737 Tcl_DecrRefCount(pDb.pUnlockNotify);
738 pDb.pUnlockNotify = 0;
739 }
740 }
741 #endif
742  
743 static void DbUpdateHandler(
744 object p,
745 int op,
746 string zDb,
747 string zTbl,
748 sqlite_int64 rowid
749 )
750 {
751 SqliteDb pDb = (SqliteDb)p;
752 Tcl_Obj pCmd;
753  
754 Debug.Assert( pDb.pUpdateHook != null );
755 Debug.Assert( op == SQLITE_INSERT || op == SQLITE_UPDATE || op == SQLITE_DELETE );
756  
757 pCmd = TCL.Tcl_DuplicateObj( pDb.pUpdateHook );
758 TCL.Tcl_IncrRefCount( pCmd );
759 TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj(
760 ( ( op == SQLITE_INSERT ) ? "INSERT" : ( op == SQLITE_UPDATE ) ? "UPDATE" : "DELETE" ), -1 ) );
761 TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj( zDb, -1 ) );
762 TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj( zTbl, -1 ) );
763 TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewWideIntObj( rowid ) );
764 TCL.Tcl_EvalObjEx( pDb.interp, pCmd, TCL.TCL_EVAL_DIRECT );
765 TCL.Tcl_DecrRefCount( ref pCmd );
766 }
767  
768 static void tclCollateNeeded(
769 object pCtx,
770 sqlite3 db,
771 int enc,
772 string zName
773 )
774 {
775 SqliteDb pDb = (SqliteDb)pCtx;
776 Tcl_Obj pScript = TCL.Tcl_DuplicateObj( pDb.pCollateNeeded );
777 TCL.Tcl_IncrRefCount( pScript );
778 TCL.Tcl_ListObjAppendElement( null, pScript, TCL.Tcl_NewStringObj( zName, -1 ) );
779 TCL.Tcl_EvalObjEx( pDb.interp, pScript, 0 );
780 TCL.Tcl_DecrRefCount( ref pScript );
781 }
782  
783 /*
784 ** This routine is called to evaluate an SQL collation function implemented
785 ** using TCL script.
786 */
787 static int tclSqlCollate(
788 object pCtx,
789 int nA,
790 string zA,
791 int nB,
792 string zB
793 )
794 {
795 SqlCollate p = (SqlCollate)pCtx;
796 Tcl_Obj pCmd;
797  
798 pCmd = TCL.Tcl_NewStringObj( p.zScript, -1 );
799 TCL.Tcl_IncrRefCount( pCmd );
800 TCL.Tcl_ListObjAppendElement( p.interp, pCmd, TCL.Tcl_NewStringObj( zA, nA ) );
801 TCL.Tcl_ListObjAppendElement( p.interp, pCmd, TCL.Tcl_NewStringObj( zB, nB ) );
802 TCL.Tcl_EvalObjEx( p.interp, pCmd, TCL.TCL_EVAL_DIRECT );
803 TCL.Tcl_DecrRefCount( ref pCmd );
804 return ( atoi( TCL.Tcl_GetStringResult( p.interp ) ) );
805 }
806  
807 /*
808 ** This routine is called to evaluate an SQL function implemented
809 ** using TCL script.
810 */
811 static void tclSqlFunc( sqlite3_context context, int argc, sqlite3_value[] argv )
812 {
813 SqlFunc p = (SqlFunc)sqlite3_user_data( context );
814 Tcl_Obj pCmd = null;
815 int i;
816 int rc;
817  
818 if ( argc == 0 )
819 {
820 /* If there are no arguments to the function, call TCL.Tcl_EvalObjEx on the
821 ** script object directly. This allows the TCL compiler to generate
822 ** bytecode for the command on the first invocation and thus make
823 ** subsequent invocations much faster. */
824 pCmd = p.pScript;
825 TCL.Tcl_IncrRefCount( pCmd );
826 rc = TCL.Tcl_EvalObjEx( p.interp, pCmd, 0 );
827 TCL.Tcl_DecrRefCount( ref pCmd );
828 }
829 else
830 {
831 /* If there are arguments to the function, make a shallow copy of the
832 ** script object, lappend the arguments, then evaluate the copy.
833 **
834 ** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated.
835 ** The new Tcl_Obj contains pointers to the original list elements.
836 ** That way, when TCL.Tcl_EvalObjv() is run and shimmers the first element
837 ** of the list to tclCmdNameType, that alternate representation will
838 ** be preserved and reused on the next invocation.
839 */
840 Tcl_Obj[] aArg = null;
841 int nArg = 0;
842 if ( TCL.Tcl_ListObjGetElements( p.interp, p.pScript, out nArg, out aArg ) )
843 {
844 sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
845 return;
846 }
847 pCmd = TCL.Tcl_NewListObj( nArg, aArg );
848 TCL.Tcl_IncrRefCount( pCmd );
849 for ( i = 0; i < argc; i++ )
850 {
851 sqlite3_value pIn = argv[i];
852 Tcl_Obj pVal;
853  
854 /* Set pVal to contain the i'th column of this row. */
855 switch ( sqlite3_value_type( pIn ) )
856 {
857 case SQLITE_BLOB:
858 {
859 int bytes = sqlite3_value_bytes( pIn );
860 pVal = TCL.Tcl_NewByteArrayObj( sqlite3_value_blob( pIn ), bytes );
861 break;
862 }
863 case SQLITE_INTEGER:
864 {
865 sqlite_int64 v = sqlite3_value_int64( pIn );
866 if ( v >= -2147483647 && v <= 2147483647 )
867 {
868 pVal = TCL.Tcl_NewIntObj( (int)v );
869 }
870 else
871 {
872 pVal = TCL.Tcl_NewWideIntObj( v );
873 }
874 break;
875 }
876 case SQLITE_FLOAT:
877 {
878 double r = sqlite3_value_double( pIn );
879 pVal = TCL.Tcl_NewDoubleObj( r );
880 break;
881 }
882 case SQLITE_NULL:
883 {
884 pVal = TCL.Tcl_NewStringObj( "", 0 );
885 break;
886 }
887 default:
888 {
889 int bytes = sqlite3_value_bytes( pIn );
890 pVal = TCL.Tcl_NewStringObj( sqlite3_value_text( pIn ), bytes );
891 break;
892 }
893 }
894 rc = TCL.Tcl_ListObjAppendElement( p.interp, pCmd, pVal ) ? 1 : 0;
895 if ( rc != 0 )
896 {
897 TCL.Tcl_DecrRefCount( ref pCmd );
898 sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
899 return;
900 }
901 }
902 if ( p.useEvalObjv == 0 )
903 {
904 /* TCL.Tcl_EvalObjEx() will automatically call TCL.Tcl_EvalObjv() if pCmd
905 ** is a list without a string representation. To prevent this from
906 ** happening, make sure pCmd has a valid string representation */
907 TCL.Tcl_GetString( pCmd );
908 }
909 rc = TCL.Tcl_EvalObjEx( p.interp, pCmd, TCL.TCL_EVAL_DIRECT );
910 TCL.Tcl_DecrRefCount( ref pCmd );
911 }
912  
913 if ( rc != 0 && rc != TCL.TCL_RETURN )
914 {
915 sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
916 }
917 else
918 {
919 Tcl_Obj pVar = TCL.Tcl_GetObjResult( p.interp );
920 int n = 0;
921 string data = "";
922 Tcl_WideInt v = 0;
923 double r = 0;
924 string zType = pVar.typePtr;//string zType = (pVar.typePtr ? pVar.typePtr.name : "");
925 if ( zType == "bytearray" )
926 { //&& pVar.bytes==0 ){
927 /* Only return a BLOB type if the Tcl variable is a bytearray and
928 ** has no string representation. */
929 data = Encoding.UTF8.GetString( TCL.Tcl_GetByteArrayFromObj( pVar, out n ) );
930 sqlite3_result_blob( context, data, n, null );
931 }
932 else if ( zType == "boolean" )
933 {
934 TCL.Tcl_GetIntFromObj( null, pVar, out n );
935 sqlite3_result_int( context, n );
936 }
937 else if ( zType == "wideint" ||
938 zType == "int" || Int64.TryParse( pVar.ToString(), out v ) )
939 {
940 TCL.Tcl_GetWideIntFromObj( null, pVar, out v );
941 sqlite3_result_int64( context, v );
942 }
943 else if ( zType == "double" || Double.TryParse( pVar.ToString(), out r ) )
944 {
945 TCL.Tcl_GetDoubleFromObj( null, pVar, out r );
946 sqlite3_result_double( context, r );
947 }
948 else
949 {
950 data = TCL.Tcl_GetStringFromObj( pVar, n );
951 n = data.Length;
952 sqlite3_result_text( context, data, n, SQLITE_TRANSIENT );
953 }
954 }
955 }
956  
957 #if !SQLITE_OMIT_AUTHORIZATION
958 /*
959 ** This is the authentication function. It appends the authentication
960 ** type code and the two arguments to zCmd[] then invokes the result
961 ** on the interpreter. The reply is examined to determine if the
962 ** authentication fails or succeeds.
963 */
964 static int auth_callback(
965 object pArg,
966 int code,
967 const string zArg1,
968 const string zArg2,
969 const string zArg3,
970 const string zArg4
971 ){
972 string zCode;
973 TCL.Tcl_DString str;
974 int rc;
975 const string zReply;
976 SqliteDb pDb = (SqliteDb)pArg;
977 if( pdb.disableAuth ) return SQLITE_OK;
978  
979 switch( code ){
980 case SQLITE_COPY : zCode="SQLITE_COPY"; break;
981 case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break;
982 case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break;
983 case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
984 case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
985 case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
986 case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
987 case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break;
988 case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break;
989 case SQLITE_DELETE : zCode="SQLITE_DELETE"; break;
990 case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break;
991 case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break;
992 case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break;
993 case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break;
994 case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
995 case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break;
996 case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break;
997 case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break;
998 case SQLITE_INSERT : zCode="SQLITE_INSERT"; break;
999 case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break;
1000 case SQLITE_READ : zCode="SQLITE_READ"; break;
1001 case SQLITE_SELECT : zCode="SQLITE_SELECT"; break;
1002 case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break;
1003 case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break;
1004 case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break;
1005 case SQLITE_DETACH : zCode="SQLITE_DETACH"; break;
1006 case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
1007 case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
1008 case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
1009 case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break;
1010 case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break;
1011 case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break;
1012 case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break;
1013 default : zCode="????"; break;
1014 }
1015 TCL.Tcl_DStringInit(&str);
1016 TCL.Tcl_DStringAppend(&str, pDb.zAuth, -1);
1017 TCL.Tcl_DStringAppendElement(&str, zCode);
1018 TCL.Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
1019 TCL.Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
1020 TCL.Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
1021 TCL.Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
1022 rc = TCL.Tcl_GlobalEval(pDb.interp, TCL.Tcl_DStringValue(&str));
1023 TCL.Tcl_DStringFree(&str);
1024 zReply = TCL.Tcl_GetStringResult(pDb.interp);
1025 if( strcmp(zReply,"SQLITE_OK")==0 ){
1026 rc = SQLITE_OK;
1027 }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
1028 rc = SQLITE_DENY;
1029 }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
1030 rc = SQLITE_IGNORE;
1031 }else{
1032 rc = 999;
1033 }
1034 return rc;
1035 }
1036 #endif // * SQLITE_OMIT_AUTHORIZATION */
1037  
1038 /*
1039 ** zText is a pointer to text obtained via an sqlite3_result_text()
1040 ** or similar interface. This routine returns a Tcl string object,
1041 ** reference count set to 0, containing the text. If a translation
1042 ** between iso8859 and UTF-8 is required, it is preformed.
1043 */
1044 static Tcl_Obj dbTextToObj( string zText )
1045 {
1046 Tcl_Obj pVal;
1047 #if UTF_TRANSLATION_NEEDED
1048 //TCL.Tcl_DString dCol;
1049 //TCL.Tcl_DStringInit(&dCol);
1050 //TCL.Tcl_ExternalToUtfDString(NULL, zText, -1, dCol);
1051 //pVal = TCL.Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
1052 //TCL.Tcl_DStringFree(ref dCol);
1053 if (zText.Length == Encoding.UTF8.GetByteCount(zText)) pVal = TCL.Tcl_NewStringObj( zText, -1 );
1054 else pVal = TCL.Tcl_NewStringObj( zText, -1 );
1055 #else
1056 pVal = TCL.Tcl_NewStringObj( zText, -1 );
1057 #endif
1058 return pVal;
1059 }
1060  
1061 /*
1062 ** This routine reads a line of text from FILE in, stores
1063 ** the text in memory obtained from malloc() and returns a pointer
1064 ** to the text. NULL is returned at end of file, or if malloc()
1065 ** fails.
1066 **
1067 ** The interface is like "readline" but no command-line editing
1068 ** is done.
1069 **
1070 ** copied from shell.c from '.import' command
1071 */
1072 //static char *local_getline(string zPrompt, FILE *in){
1073 // string zLine;
1074 // int nLine;
1075 // int n;
1076 // int eol;
1077  
1078 // nLine = 100;
1079 // zLine = malloc( nLine );
1080 // if( zLine==0 ) return 0;
1081 // n = 0;
1082 // eol = 0;
1083 // while( !eol ){
1084 // if( n+100>nLine ){
1085 // nLine = nLine*2 + 100;
1086 // zLine = realloc(zLine, nLine);
1087 // if( zLine==0 ) return 0;
1088 // }
1089 // if( fgets(&zLine[n], nLine - n, in)==0 ){
1090 // if( n==0 ){
1091 // free(zLine);
1092 // return 0;
1093 // }
1094 // zLine[n] = 0;
1095 // eol = 1;
1096 // break;
1097 // }
1098 // while( zLine[n] ){ n++; }
1099 // if( n>0 && zLine[n-1]=='\n' ){
1100 // n--;
1101 // zLine[n] = 0;
1102 // eol = 1;
1103 // }
1104 // }
1105 // zLine = realloc( zLine, n+1 );
1106 // return zLine;
1107 //}
1108  
1109  
1110 /*
1111 ** This function is part of the implementation of the command:
1112 **
1113 ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT
1114 **
1115 ** It is invoked after evaluating the script SCRIPT to commit or rollback
1116 ** the transaction or savepoint opened by the [transaction] command.
1117 */
1118 static int DbTransPostCmd(
1119 object data, /* data[0] is the Sqlite3Db* for $db */
1120 Tcl_Interp interp, /* Tcl interpreter */
1121 int result /* Result of evaluating SCRIPT */
1122 )
1123 {
1124 string[] azEnd = {
1125 "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */
1126 "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */
1127 "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction",
1128 "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */
1129 };
1130 SqliteDb pDb = (SqliteDb)data;
1131 int rc = result;
1132 string zEnd;
1133  
1134 pDb.nTransaction--;
1135 zEnd = azEnd[( ( rc == TCL.TCL_ERROR ) ? 1 : 0 ) * 2 + ( ( pDb.nTransaction == 0 ) ? 1 : 0 )];
1136  
1137 pDb.disableAuth++;
1138 if ( sqlite3_exec( pDb.db, zEnd, 0, 0, 0 ) != 0 )
1139 {
1140 /* This is a tricky scenario to handle. The most likely cause of an
1141 ** error is that the exec() above was an attempt to commit the
1142 ** top-level transaction that returned SQLITE_BUSY. Or, less likely,
1143 ** that an IO-error has occured. In either case, throw a Tcl exception
1144 ** and try to rollback the transaction.
1145 **
1146 ** But it could also be that the user executed one or more BEGIN,
1147 ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
1148 ** this method's logic. Not clear how this would be best handled.
1149 */
1150 if ( rc != TCL.TCL_ERROR )
1151 {
1152 TCL.Tcl_AppendResult( interp, sqlite3_errmsg( pDb.db ), 0 );
1153 rc = TCL.TCL_ERROR;
1154 }
1155 sqlite3_exec( pDb.db, "ROLLBACK", 0, 0, 0 );
1156 }
1157 pDb.disableAuth--;
1158  
1159 return rc;
1160 }
1161  
1162 /*
1163 ** Search the cache for a prepared-statement object that implements the
1164 ** first SQL statement in the buffer pointed to by parameter zIn. If
1165 ** no such prepared-statement can be found, allocate and prepare a new
1166 ** one. In either case, bind the current values of the relevant Tcl
1167 ** variables to any $var, :var or @var variables in the statement. Before
1168 ** returning, set *ppPreStmt to point to the prepared-statement object.
1169 **
1170 ** Output parameter *pzOut is set to point to the next SQL statement in
1171 ** buffer zIn, or to the '\0' byte at the end of zIn if there is no
1172 ** next statement.
1173 **
1174 ** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned
1175 ** and an error message loaded into interpreter pDb.interp.
1176 */
1177 static int dbPrepareAndBind(
1178 SqliteDb pDb, /* Database object */
1179 string zIn, /* SQL to compile */
1180 ref string pzOut, /* OUT: Pointer to next SQL statement */
1181 ref SqlPreparedStmt ppPreStmt /* OUT: Object used to cache statement */
1182 )
1183 {
1184 string zSql = zIn; /* Pointer to first SQL statement in zIn */
1185 sqlite3_stmt pStmt = null; /* Prepared statement object */
1186 SqlPreparedStmt pPreStmt; /* Pointer to cached statement */
1187 int nSql; /* Length of zSql in bytes */
1188 int nVar = 0; /* Number of variables in statement */
1189 int iParm = 0; /* Next free entry in apParm */
1190 int i;
1191 Tcl_Interp interp = pDb.interp;
1192  
1193 pzOut = null;
1194 ppPreStmt = null;
1195  
1196 /* Trim spaces from the start of zSql and calculate the remaining length. */
1197 zSql = zSql.TrimStart(); //while ( isspace( zSql[0] ) ) { zSql++; }
1198 nSql = strlen30( zSql );
1199  
1200 for ( pPreStmt = pDb.stmtList; pPreStmt != null; pPreStmt = pPreStmt.pNext )
1201 {
1202 int n = pPreStmt.nSql;
1203 if ( nSql >= n
1204 && zSql.StartsWith(pPreStmt.zSql)
1205 && ( nSql == n /* zSql[n]==0 */|| zSql[n - 1] == ';' )
1206 )
1207 {
1208 pStmt = pPreStmt.pStmt;
1209 /* Restore aMem values */
1210 if ( pStmt.aMem.Length < pPreStmt.aMem.Length )
1211 Array.Resize( ref pStmt.aMem, pPreStmt.aMem.Length );
1212 for ( int ix = 0; ix < pPreStmt.aMem.Length; ix++ )
1213 {
1214 pPreStmt.aMem[ix].CopyTo( ref pStmt.aMem[ix] );
1215 }
1216  
1217 pzOut = zSql.Substring( pPreStmt.nSql );
1218  
1219 /* When a prepared statement is found, unlink it from the
1220 ** cache list. It will later be added back to the beginning
1221 ** of the cache list in order to implement LRU replacement.
1222 */
1223 if ( pPreStmt.pPrev != null )
1224 {
1225 pPreStmt.pPrev.pNext = pPreStmt.pNext;
1226 }
1227 else
1228 {
1229 pDb.stmtList = pPreStmt.pNext;
1230 }
1231 if ( pPreStmt.pNext != null )
1232 {
1233 pPreStmt.pNext.pPrev = pPreStmt.pPrev;
1234 }
1235 else
1236 {
1237 pDb.stmtLast = pPreStmt.pPrev;
1238 }
1239 pDb.nStmt--;
1240 nVar = sqlite3_bind_parameter_count( pStmt );
1241 break;
1242 }
1243 }
1244  
1245 /* If no prepared statement was found. Compile the SQL text. Also allocate
1246 ** a new SqlPreparedStmt structure. */
1247 if ( pPreStmt == null )
1248 {
1249 int nByte;
1250  
1251 if ( SQLITE_OK != sqlite3_prepare_v2( pDb.db, zSql, -1, ref pStmt, ref pzOut ) )
1252 {
1253 TCL.Tcl_SetObjResult( interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
1254 pPreStmt = new SqlPreparedStmt();// (SqlPreparedStmt)Tcl_Alloc( nByte );
1255 return TCL.TCL_ERROR;
1256 }
1257 if ( pStmt == null )
1258 {
1259 if ( SQLITE_OK != sqlite3_errcode( pDb.db ) )
1260 {
1261 /* A compile-time error in the statement. */
1262 TCL.Tcl_SetObjResult( interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
1263 return TCL.TCL_ERROR;
1264 }
1265 else
1266 {
1267 /* The statement was a no-op. Continue to the next statement
1268 ** in the SQL string.
1269 */
1270 return TCL.TCL_OK;
1271 }
1272 }
1273  
1274 Debug.Assert( pPreStmt == null );
1275 nVar = sqlite3_bind_parameter_count( pStmt );
1276 //nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj );
1277 pPreStmt = new SqlPreparedStmt();// (SqlPreparedStmt)Tcl_Alloc( nByte );
1278 //memset(pPreStmt, 0, nByte);
1279  
1280 pPreStmt.pStmt = pStmt;
1281 pPreStmt.nSql = ( zSql.Length - pzOut.Length );
1282 pPreStmt.zSql = sqlite3_sql( pStmt );
1283 pPreStmt.apParm = new TclObject[nVar];//pPreStmt[1];
1284 }
1285 Debug.Assert( pPreStmt != null );
1286 Debug.Assert( strlen30( pPreStmt.zSql ) == pPreStmt.nSql );
1287 Debug.Assert( zSql.StartsWith( pPreStmt.zSql ) );
1288  
1289 /* Bind values to parameters that begin with $ or : */
1290 for ( i = 1; i <= nVar; i++ )
1291 {
1292 string zVar = sqlite3_bind_parameter_name( pStmt, i );
1293 if ( !String.IsNullOrEmpty( zVar ) && ( zVar[0] == '$' || zVar[0] == ':' || zVar[0] == '@' ) )
1294 {
1295 Tcl_Obj pVar = TCL.Tcl_GetVar2Ex( interp, zVar.Substring( 1 ), null, 0 );
1296 if ( pVar != null && pVar.typePtr != "null" )
1297 {
1298 int n = 0;
1299 string data;
1300 string zType = pVar.typePtr;
1301 //char c = zType[0];
1302 if ( zVar[0] == '@' ||
1303 ( zType == "bytearray" ) )// TODO -- && pVar.bytes == 0 ) )
1304 {
1305 /* Load a BLOB type if the Tcl variable is a bytearray and
1306 ** it has no string representation or the host
1307 ** parameter name begins with "@". */
1308 if ( zVar[0] == '@' || pVar.stringRep == null )
1309 sqlite3_bind_blob( pStmt, i, TCL.Tcl_GetByteArrayFromObj( pVar, out n ), n, SQLITE_STATIC );
1310 else
1311 sqlite3_bind_text( pStmt, i, TCL.Tcl_GetStringFromObj( pVar, out n ), n, SQLITE_STATIC );
1312 TCL.Tcl_IncrRefCount( pVar );
1313 pPreStmt.apParm[iParm++] = pVar;
1314 }
1315 else if ( zType == "boolean" )
1316 {
1317 TCL.Tcl_GetIntFromObj( interp, pVar, out n );
1318 sqlite3_bind_int( pStmt, i, n );
1319 }
1320 else if ( zType == "double" )
1321 {
1322 double r = 0;
1323 TCL.Tcl_GetDoubleFromObj( interp, pVar, out r );
1324 sqlite3_bind_double( pStmt, i, r );
1325 }
1326 else if ( zType == "wideint" ||
1327 zType == "int" )
1328 {
1329 Tcl_WideInt v = 0;
1330 TCL.Tcl_GetWideIntFromObj( interp, pVar, out v );
1331 sqlite3_bind_int64( pStmt, i, v );
1332 }
1333 else
1334 {
1335 data = TCL.Tcl_GetStringFromObj( pVar, out n );
1336 sqlite3_bind_text( pStmt, i, data, n, SQLITE_STATIC );
1337 TCL.Tcl_IncrRefCount( pVar );
1338 pPreStmt.apParm[iParm++] = pVar;
1339 }
1340 }
1341 else
1342 {
1343 sqlite3_bind_null( pStmt, i );
1344 }
1345 }
1346 }
1347 pPreStmt.nParm = iParm;
1348 /* save aMem values for later reuse */
1349 pPreStmt.aMem = new Mem[pPreStmt.pStmt.aMem.Length];
1350 for ( int ix = 0; ix < pPreStmt.pStmt.aMem.Length; ix++ )
1351 {
1352 pPreStmt.pStmt.aMem[ix].CopyTo( ref pPreStmt.aMem[ix] );
1353 }
1354 ppPreStmt = pPreStmt;
1355  
1356 return TCL.TCL_OK;
1357 }
1358  
1359  
1360 /*
1361 ** Release a statement reference obtained by calling dbPrepareAndBind().
1362 ** There should be exactly one call to this function for each call to
1363 ** dbPrepareAndBind().
1364 **
1365 ** If the discard parameter is non-zero, then the statement is deleted
1366 ** immediately. Otherwise it is added to the LRU list and may be returned
1367 ** by a subsequent call to dbPrepareAndBind().
1368 */
1369 static void dbReleaseStmt(
1370 SqliteDb pDb, /* Database handle */
1371 SqlPreparedStmt pPreStmt, /* Prepared statement handle to release */
1372 int discard /* True to delete (not cache) the pPreStmt */
1373 )
1374 {
1375 int i;
1376  
1377 /* Free the bound string and blob parameters */
1378 for ( i = 0; i < pPreStmt.nParm; i++ )
1379 {
1380 TCL.Tcl_DecrRefCount( ref pPreStmt.apParm[i] );
1381 }
1382 pPreStmt.nParm = 0;
1383  
1384 if ( pDb.maxStmt <= 0 || discard != 0 )
1385 {
1386 /* If the cache is turned off, deallocated the statement */
1387 sqlite3_finalize( pPreStmt.pStmt );
1388 TCL.Tcl_Free( ref pPreStmt );
1389 }
1390 else
1391 {
1392 /* Add the prepared statement to the beginning of the cache list. */
1393 pPreStmt.pNext = pDb.stmtList;
1394 pPreStmt.pPrev = null;
1395 if ( pDb.stmtList != null )
1396 {
1397 pDb.stmtList.pPrev = pPreStmt;
1398 }
1399 pDb.stmtList = pPreStmt;
1400 if ( pDb.stmtLast == null )
1401 {
1402 Debug.Assert( pDb.nStmt == 0 );
1403 pDb.stmtLast = pPreStmt;
1404 }
1405 else
1406 {
1407 Debug.Assert( pDb.nStmt > 0 );
1408 }
1409 pDb.nStmt++;
1410  
1411 /* If we have too many statement in cache, remove the surplus from
1412 ** the end of the cache list. */
1413 while ( pDb.nStmt > pDb.maxStmt )
1414 {
1415 sqlite3_finalize( pDb.stmtLast.pStmt );
1416 pDb.stmtLast = pDb.stmtLast.pPrev;
1417 TCL.Tcl_Free( ref pDb.stmtLast.pNext );
1418 pDb.stmtLast.pNext = null;
1419 pDb.nStmt--;
1420 }
1421 }
1422 }
1423  
1424 /*
1425 ** Structure used with dbEvalXXX() functions:
1426 **
1427 ** dbEvalInit()
1428 ** dbEvalStep()
1429 ** dbEvalFinalize()
1430 ** dbEvalRowInfo()
1431 ** dbEvalColumnValue()
1432 */
1433 //typedef struct DbEvalContext DbEvalContext;
1434 public class DbEvalContext
1435 {
1436 public SqliteDb pDb; /* Database handle */
1437 public Tcl_Obj pSql; /* Object holding string zSql */
1438 public string zSql; /* Remaining SQL to execute */
1439 public SqlPreparedStmt pPreStmt; /* Current statement */
1440 public int nCol; /* Number of columns returned by pStmt */
1441 public Tcl_Obj pArray; /* Name of array variable */
1442 public Tcl_Obj[] apColName; /* Array of column names */
1443  
1444 public void Clear()
1445 {
1446 pDb = null;
1447 pSql = null;
1448 zSql = null;
1449 pPreStmt = null;
1450 pArray = null;
1451 apColName = null;
1452  
1453 }
1454 };
1455  
1456 /*
1457 ** Release any cache of column names currently held as part of
1458 ** the DbEvalContext structure passed as the first argument.
1459 */
1460 static void dbReleaseColumnNames( DbEvalContext p )
1461 {
1462 if ( p.apColName != null )
1463 {
1464 int i;
1465 for ( i = 0; i < p.nCol; i++ )
1466 {
1467 TCL.Tcl_DecrRefCount( ref p.apColName[i] );
1468 }
1469 TCL.Tcl_Free( ref p.apColName );
1470 p.apColName = null;
1471 }
1472 p.nCol = 0;
1473 }
1474  
1475 /*
1476 ** Initialize a DbEvalContext structure.
1477 **
1478 ** If pArray is not NULL, then it contains the name of a Tcl array
1479 ** variable. The "*" member of this array is set to a list containing
1480 ** the names of the columns returned by the statement as part of each
1481 ** call to dbEvalStep(), in order from left to right. e.g. if the names
1482 ** of the returned columns are a, b and c, it does the equivalent of the
1483 ** tcl command:
1484 **
1485 ** set ${pArray}() {a b c}
1486 */
1487 static void dbEvalInit(
1488 DbEvalContext p, /* Pointer to structure to initialize */
1489 SqliteDb pDb, /* Database handle */
1490 Tcl_Obj pSql, /* Object containing SQL script */
1491 Tcl_Obj pArray /* Name of Tcl array to set () element of */
1492 )
1493 {
1494 if ( p != null )
1495 p.Clear();// memset( p, 0, sizeof( DbEvalContext ) );
1496 p.pDb = pDb;
1497 p.zSql = TCL.Tcl_GetString( pSql );
1498 p.pSql = pSql;
1499 TCL.Tcl_IncrRefCount( pSql );
1500 if ( pArray != null )
1501 {
1502 p.pArray = pArray;
1503 TCL.Tcl_IncrRefCount( pArray );
1504 }
1505 }
1506  
1507 /*
1508 ** Obtain information about the row that the DbEvalContext passed as the
1509 ** first argument currently points to.
1510 */
1511 static void dbEvalRowInfo(
1512 DbEvalContext p, /* Evaluation context */
1513 out int pnCol, /* OUT: Number of column names */
1514 out Tcl_Obj[] papColName /* OUT: Array of column names */
1515 )
1516 {
1517 /* Compute column names */
1518 if ( null == p.apColName )
1519 {
1520 sqlite3_stmt pStmt = p.pPreStmt.pStmt;
1521 int i; /* Iterator variable */
1522 int nCol; /* Number of columns returned by pStmt */
1523 Tcl_Obj[] apColName = null; /* Array of column names */
1524  
1525 p.nCol = nCol = sqlite3_column_count( pStmt );
1526 if ( nCol > 0 )// && ( papColName != null || p.pArray != null ) )
1527 {
1528 apColName = new TclObject[nCol];// (Tcl_Obj*)Tcl_Alloc( sizeof( Tcl_Obj* ) * nCol );
1529 for ( i = 0; i < nCol; i++ )
1530 {
1531 apColName[i] = dbTextToObj( sqlite3_column_name( pStmt, i ) );
1532 TCL.Tcl_IncrRefCount( apColName[i] );
1533 }
1534 p.apColName = apColName;
1535 }
1536  
1537 /* If results are being stored in an array variable, then create
1538 ** the array() entry for that array
1539 */
1540 if ( p.pArray != null )
1541 {
1542 Tcl_Interp interp = p.pDb.interp;
1543 Tcl_Obj pColList = TCL.Tcl_NewObj();
1544 Tcl_Obj pStar = TCL.Tcl_NewStringObj( "*", -1 );
1545  
1546 for ( i = 0; i < nCol; i++ )
1547 {
1548 TCL.Tcl_ListObjAppendElement( interp, pColList, apColName[i] );
1549 }
1550 TCL.Tcl_IncrRefCount( pStar );
1551 TCL.Tcl_ObjSetVar2( interp, p.pArray, pStar, pColList, 0 );
1552 TCL.Tcl_DecrRefCount( ref pStar );
1553 }
1554 }
1555  
1556 //if ( papColName != null )
1557 {
1558 papColName = p.apColName;
1559 }
1560 //if ( pnCol !=0)
1561 {
1562 pnCol = p.nCol;
1563 }
1564 }
1565  
1566 /*
1567 ** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is
1568 ** returned, then an error message is stored in the interpreter before
1569 ** returning.
1570 **
1571 ** A return value of TCL_OK means there is a row of data available. The
1572 ** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This
1573 ** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK
1574 ** is returned, then the SQL script has finished executing and there are
1575 ** no further rows available. This is similar to SQLITE_DONE.
1576 */
1577 static int dbEvalStep( DbEvalContext p )
1578 {
1579 while ( !String.IsNullOrEmpty( p.zSql ) || p.pPreStmt != null )
1580 {
1581 int rc;
1582 if ( p.pPreStmt == null )
1583 {
1584 rc = dbPrepareAndBind( p.pDb, p.zSql, ref p.zSql, ref p.pPreStmt );
1585 if ( rc != TCL.TCL_OK )
1586 return rc;
1587 }
1588 else
1589 {
1590 int rcs;
1591 SqliteDb pDb = p.pDb;
1592 SqlPreparedStmt pPreStmt = p.pPreStmt;
1593 sqlite3_stmt pStmt = pPreStmt.pStmt;
1594  
1595 rcs = sqlite3_step( pStmt );
1596 if ( rcs == SQLITE_ROW )
1597 {
1598 return TCL.TCL_OK;
1599 }
1600 if ( p.pArray != null )
1601 {
1602 TclObject[] pDummy;
1603 int iDummy;
1604 dbEvalRowInfo( p, out iDummy, out pDummy );
1605 }
1606 rcs = sqlite3_reset( pStmt );
1607  
1608 pDb.nStep = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1 );
1609 pDb.nSort = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_SORT, 1 );
1610 pDb.nIndex = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_AUTOINDEX, 1 );
1611 dbReleaseColumnNames( p );
1612 p.pPreStmt = null;
1613  
1614 if ( rcs != SQLITE_OK )
1615 {
1616 /* If a run-time error occurs, report the error and stop reading
1617 ** the SQL. */
1618 TCL.Tcl_SetObjResult( pDb.interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
1619 dbReleaseStmt( pDb, pPreStmt, 1 );
1620 return TCL.TCL_ERROR;
1621 }
1622 else
1623 {
1624 dbReleaseStmt( pDb, pPreStmt, 0 );
1625 }
1626 }
1627 }
1628  
1629 /* Finished */
1630 return TCL.TCL_BREAK;
1631 }
1632  
1633 /*
1634 ** Free all resources currently held by the DbEvalContext structure passed
1635 ** as the first argument. There should be exactly one call to this function
1636 ** for each call to dbEvalInit().
1637 */
1638 static void dbEvalFinalize( DbEvalContext p )
1639 {
1640 if ( p.pPreStmt != null )
1641 {
1642 sqlite3_reset( p.pPreStmt.pStmt );
1643 dbReleaseStmt( p.pDb, p.pPreStmt, 1 );
1644 p.pPreStmt = null;
1645 }
1646 if ( p.pArray != null )
1647 {
1648 TCL.Tcl_DecrRefCount( ref p.pArray );
1649 p.pArray = null;
1650 }
1651 TCL.Tcl_DecrRefCount( ref p.pSql );
1652 dbReleaseColumnNames( p );
1653 }
1654  
1655 /*
1656 ** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains
1657 ** the value for the iCol'th column of the row currently pointed to by
1658 ** the DbEvalContext structure passed as the first argument.
1659 */
1660 static Tcl_Obj dbEvalColumnValue( DbEvalContext p, int iCol )
1661 {
1662 sqlite3_stmt pStmt = p.pPreStmt.pStmt;
1663 switch ( sqlite3_column_type( pStmt, iCol ) )
1664 {
1665 case SQLITE_BLOB:
1666 {
1667 int bytes = sqlite3_column_bytes( pStmt, iCol );
1668 byte[] zBlob = sqlite3_column_blob( pStmt, iCol );
1669 if ( null == zBlob )
1670 bytes = 0;
1671 return TCL.Tcl_NewByteArrayObj( zBlob, bytes );
1672 }
1673 case SQLITE_INTEGER:
1674 {
1675 sqlite_int64 v = sqlite3_column_int64( pStmt, iCol );
1676 if ( v >= -2147483647 && v <= 2147483647 )
1677 {
1678 return TCL.Tcl_NewIntObj( (int)v );
1679 }
1680 else
1681 {
1682 return TCL.Tcl_NewWideIntObj( v );
1683 }
1684 }
1685 case SQLITE_FLOAT:
1686 {
1687 return TCL.Tcl_NewDoubleObj( sqlite3_column_double( pStmt, iCol ) );
1688 }
1689 case SQLITE_NULL:
1690 {
1691 return dbTextToObj( p.pDb.zNull );
1692 }
1693 }
1694  
1695 return dbTextToObj( sqlite3_column_text( pStmt, iCol ) );
1696 }
1697  
1698 /*
1699 ** If using Tcl version 8.6 or greater, use the NR functions to avoid
1700 ** recursive evalution of scripts by the [db eval] and [db trans]
1701 ** commands. Even if the headers used while compiling the extension
1702 ** are 8.6 or newer, the code still tests the Tcl version at runtime.
1703 ** This allows stubs-enabled builds to be used with older Tcl libraries.
1704 */
1705 #if TCL_MAJOR_VERSION//>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6)
1706 //# define SQLITE_TCL_NRE 1
1707 static int DbUseNre(void){
1708 int major, minor;
1709 Tcl_GetVersion(&major, &minor, 0, 0);
1710 return( (major==8 && minor>=6) || major>8 );
1711 }
1712 #else
1713 /*
1714 ** Compiling using headers earlier than 8.6. In this case NR cannot be
1715 ** used, so DbUseNre() to always return zero. Add #defines for the other
1716 ** Tcl_NRxxx() functions to prevent them from causing compilation errors,
1717 ** even though the only invocations of them are within conditional blocks
1718 ** of the form:
1719 **
1720 ** if( DbUseNre() ) { ... }
1721 */
1722 const int SQLITE_TCL_NRE = 0; //# define SQLITE_TCL_NRE 0
1723 static bool DbUseNre()
1724 {
1725 return false;
1726 } //# define DbUseNre() 0
1727 //# define Tcl_NRAddCallback(a,b,c,d,e,f) 0
1728 //# define Tcl_NREvalObj(a,b,c) 0
1729 //# define Tcl_NRCreateCommand(a,b,c,d,e,f) 0
1730 #endif
1731  
1732 /*
1733 ** This function is part of the implementation of the command:
1734 **
1735 ** $db eval SQL ?ARRAYNAME? SCRIPT
1736 */
1737 static int DbEvalNextCmd(
1738 object[] data, /* data[0] is the (DbEvalContext) */
1739 Tcl_Interp interp, /* Tcl interpreter */
1740 int result /* Result so far */
1741 )
1742 {
1743 int rc = result; /* Return code */
1744  
1745 /* The first element of the data[] array is a pointer to a DbEvalContext
1746 ** structure allocated using TCL.Tcl_Alloc(). The second element of data[]
1747 ** is a pointer to a TCL.Tcl_Obj containing the script to run for each row
1748 ** returned by the queries encapsulated in data[0]. */
1749 DbEvalContext p = (DbEvalContext)data[0];
1750 Tcl_Obj pScript = (Tcl_Obj)data[1];
1751 Tcl_Obj pArray = p.pArray;
1752  
1753 while ( ( rc == TCL.TCL_OK || rc == TCL.TCL_CONTINUE ) && TCL.TCL_OK == ( rc = dbEvalStep( p ) ) )
1754 {
1755 int i;
1756 int nCol;
1757 Tcl_Obj[] apColName;
1758 dbEvalRowInfo( p, out nCol, out apColName );
1759 for ( i = 0; i < nCol; i++ )
1760 {
1761 Tcl_Obj pVal = dbEvalColumnValue( p, i );
1762 if ( pArray == null )
1763 {
1764 TCL.Tcl_ObjSetVar2( interp, apColName[i], null, pVal, 0 );
1765 }
1766 else
1767 {
1768 TCL.Tcl_ObjSetVar2( interp, pArray, apColName[i], pVal, 0 );
1769 }
1770 }
1771  
1772 /* The required interpreter variables are now populated with the data
1773 ** from the current row. If using NRE, schedule callbacks to evaluate
1774 ** script pScript, then to invoke this function again to fetch the next
1775 ** row (or clean up if there is no next row or the script throws an
1776 ** exception). After scheduling the callbacks, return control to the
1777 ** caller.
1778 **
1779 ** If not using NRE, evaluate pScript directly and continue with the
1780 ** next iteration of this while(...) loop. */
1781 if ( DbUseNre() )
1782 {
1783 Debugger.Break();
1784 //TCL.Tcl_NRAddCallback(interp, DbEvalNextCmd, (void)p, (void)pScript, 0, 0);
1785 //return TCL.Tcl_NREvalObj(interp, pScript, 0);
1786 }
1787 else
1788 {
1789 rc = TCL.Tcl_EvalObjEx( interp, pScript, 0 );
1790 }
1791 }
1792  
1793 TCL.Tcl_DecrRefCount( ref pScript );
1794 dbEvalFinalize( p );
1795 TCL.Tcl_Free( ref p );
1796  
1797 if ( rc == TCL.TCL_OK || rc == TCL.TCL_BREAK )
1798 {
1799 TCL.Tcl_ResetResult( interp );
1800 rc = TCL.TCL_OK;
1801 }
1802 return rc;
1803 }
1804  
1805 /*
1806 ** The "sqlite" command below creates a new Tcl command for each
1807 ** connection it opens to an SQLite database. This routine is invoked
1808 ** whenever one of those connection-specific commands is executed
1809 ** in Tcl. For example, if you run Tcl code like this:
1810 **
1811 ** sqlite3 db1 "my_database"
1812 ** db1 close
1813 **
1814 ** The first command opens a connection to the "my_database" database
1815 ** and calls that connection "db1". The second command causes this
1816 ** subroutine to be invoked.
1817 */
1818 enum DB_enum
1819 {
1820 DB_AUTHORIZER,
1821 DB_BACKUP,
1822 DB_BUSY,
1823 DB_CACHE,
1824 DB_CHANGES,
1825 DB_CLOSE,
1826 DB_COLLATE,
1827 DB_COLLATION_NEEDED,
1828 DB_COMMIT_HOOK,
1829 DB_COMPLETE,
1830 DB_COPY,
1831 DB_ENABLE_LOAD_EXTENSION,
1832 DB_ERRORCODE,
1833 DB_EVAL,
1834 DB_EXISTS,
1835 DB_FUNCTION,
1836 DB_INCRBLOB,
1837 DB_INTERRUPT,
1838 DB_LAST_INSERT_ROWID,
1839 DB_NULLVALUE,
1840 DB_ONECOLUMN,
1841 DB_PROFILE,
1842 DB_PROGRESS,
1843 DB_REKEY,
1844 DB_RESTORE,
1845 DB_ROLLBACK_HOOK,
1846 DB_STATUS,
1847 DB_TIMEOUT,
1848 DB_TOTAL_CHANGES,
1849 DB_TRACE,
1850 DB_TRANSACTION,
1851 DB_UNLOCK_NOTIFY,
1852 DB_UPDATE_HOOK,
1853 DB_VERSION,
1854 DB_WAL_HOOK
1855 };
1856  
1857 enum TTYPE_enum
1858 {
1859 TTYPE_DEFERRED,
1860 TTYPE_EXCLUSIVE,
1861 TTYPE_IMMEDIATE
1862 };
1863  
1864 static int DbObjCmd( object cd, Tcl_Interp interp, int objc, Tcl_Obj[] objv )
1865 {
1866 SqliteDb pDb = (SqliteDb)cd;
1867 int choice = 0;
1868 int rc = TCL.TCL_OK;
1869 string[] DB_strs = {
1870 "authorizer", "backup", "busy",
1871 "cache", "changes", "close",
1872 "collate", "collation_needed", "commit_hook",
1873 "complete", "copy", "enable_load_extension",
1874 "errorcode", "eval", "exists",
1875 "function", "incrblob", "interrupt",
1876 "last_insert_rowid", "nullvalue", "onecolumn",
1877 "profile", "progress", "rekey",
1878 "restore", "rollback_hook", "status",
1879 "timeout", "total_changes", "trace",
1880 "transaction", "unlock_notify", "update_hook",
1881 "version", "wal_hook"
1882 };
1883  
1884 /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
1885 if ( objc < 2 )
1886 {
1887 TCL.Tcl_WrongNumArgs( interp, 1, objv, "SUBCOMMAND ..." );
1888 return TCL.TCL_ERROR;
1889 }
1890 if ( TCL.Tcl_GetIndexFromObj( interp, objv[1], DB_strs, "option", 0, out choice ) )
1891 {
1892 return TCL.TCL_ERROR;
1893 }
1894  
1895 switch ( choice )
1896 {
1897  
1898 /* $db authorizer ?CALLBACK?
1899 **
1900 ** Invoke the given callback to authorize each SQL operation as it is
1901 ** compiled. 5 arguments are appended to the callback before it is
1902 ** invoked:
1903 **
1904 ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)
1905 ** (2) First descriptive name (depends on authorization type)
1906 ** (3) Second descriptive name
1907 ** (4) Name of the database (ex: "main", "temp")
1908 ** (5) Name of trigger that is doing the access
1909 **
1910 ** The callback should return on of the following strings: SQLITE_OK,
1911 ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error.
1912 **
1913 ** If this method is invoked with no arguments, the current authorization
1914 ** callback string is returned.
1915 */
1916 case (int)DB_enum.DB_AUTHORIZER:
1917 {
1918 #if SQLITE_OMIT_AUTHORIZATION
1919 TCL.Tcl_AppendResult( interp, "authorization not available in this build" );
1920 return TCL.TCL_RETURN;
1921 #else
1922 if( objc>3 ){
1923 TCL.Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
1924 return TCL.TCL_ERROR;
1925 }else if( objc==2 ){
1926 if( pDb.zAuth ){
1927 TCL.Tcl_AppendResult(interp, pDb.zAuth);
1928 }
1929 }else{
1930 string zAuth;
1931 int len;
1932 if( pDb.zAuth ){
1933 TCL.Tcl_Free(pDb.zAuth);
1934 }
1935 zAuth = TCL.Tcl_GetStringFromObj(objv[2], len);
1936 if( zAuth && len>0 ){
1937 pDb.zAuth = TCL.Tcl_Alloc( len + 1 );
1938 memcpy(pDb.zAuth, zAuth, len+1);
1939 }else{
1940 pDb.zAuth = 0;
1941 }
1942 if( pDb.zAuth ){
1943 pDb.interp = interp;
1944 sqlite3_set_authorizer(pDb.db, auth_callback, pDb);
1945 }else{
1946 sqlite3_set_authorizer(pDb.db, 0, 0);
1947 }
1948 }
1949 break;
1950 #endif
1951 }
1952  
1953 /* $db backup ?DATABASE? FILENAME
1954 **
1955 ** Open or create a database file named FILENAME. Transfer the
1956 ** content of local database DATABASE (default: "main") into the
1957 ** FILENAME database.
1958 */
1959 case (int)DB_enum.DB_BACKUP:
1960 {
1961 string zDestFile;
1962 string zSrcDb;
1963 sqlite3 pDest = null;
1964 sqlite3_backup pBackup;
1965  
1966 if ( objc == 3 )
1967 {
1968 zSrcDb = "main";
1969 zDestFile = TCL.Tcl_GetString( objv[2] );
1970 }
1971 else if ( objc == 4 )
1972 {
1973 zSrcDb = TCL.Tcl_GetString( objv[2] );
1974 zDestFile = TCL.Tcl_GetString( objv[3] );
1975 }
1976 else
1977 {
1978 TCL.Tcl_WrongNumArgs( interp, 2, objv, "?DATABASE? FILENAME" );
1979 return TCL.TCL_ERROR;
1980 }
1981 rc = sqlite3_open( zDestFile, out pDest );
1982 if ( rc != SQLITE_OK )
1983 {
1984 TCL.Tcl_AppendResult( interp, "cannot open target database: ",
1985 sqlite3_errmsg( pDest ) );
1986 sqlite3_close( pDest );
1987 return TCL.TCL_ERROR;
1988 }
1989 pBackup = sqlite3_backup_init( pDest, "main", pDb.db, zSrcDb );
1990 if ( pBackup == null )
1991 {
1992 TCL.Tcl_AppendResult( interp, "backup failed: ",
1993 sqlite3_errmsg( pDest ) );
1994 sqlite3_close( pDest );
1995 return TCL.TCL_ERROR;
1996 }
1997 #if SQLITE_HAS_CODEC
1998 if ( pBackup.pSrc.pBt.pPager.pCodec != null )
1999 {
2000 pBackup.pDest.pBt.pPager.xCodec = pBackup.pSrc.pBt.pPager.xCodec;
2001 pBackup.pDest.pBt.pPager.xCodecFree = pBackup.pSrc.pBt.pPager.xCodecFree;
2002 pBackup.pDest.pBt.pPager.xCodecSizeChng = pBackup.pSrc.pBt.pPager.xCodecSizeChng;
2003 pBackup.pDest.pBt.pPager.pCodec = pBackup.pSrc.pBt.pPager.pCodec.Copy();
2004 }
2005 #endif
2006 while ( ( rc = sqlite3_backup_step( pBackup, 100 ) ) == SQLITE_OK )
2007 {
2008 }
2009 sqlite3_backup_finish( pBackup );
2010 if ( rc == SQLITE_DONE )
2011 {
2012 rc = TCL.TCL_OK;
2013 }
2014 else
2015 {
2016 TCL.Tcl_AppendResult( interp, "backup failed: ",
2017 sqlite3_errmsg( pDest ) );
2018 rc = TCL.TCL_ERROR;
2019 }
2020 sqlite3_close( pDest );
2021 break;
2022 }
2023  
2024 // /* $db busy ?CALLBACK?
2025 // **
2026 // ** Invoke the given callback if an SQL statement attempts to open
2027 // ** a locked database file.
2028 // */
2029 case (int)DB_enum.DB_BUSY:
2030 {
2031 if ( objc > 3 )
2032 {
2033 TCL.Tcl_WrongNumArgs( interp, 2, objv, "CALLBACK" );
2034 return TCL.TCL_ERROR;
2035 }
2036 else if ( objc == 2 )
2037 {
2038 if ( pDb.zBusy != null )
2039 {
2040 TCL.Tcl_AppendResult( interp, pDb.zBusy );
2041 }
2042 }
2043 else
2044 {
2045 string zBusy;
2046 int len = 0;
2047 if ( pDb.zBusy != null )
2048 {
2049 TCL.Tcl_Free( ref pDb.zBusy );
2050 }
2051 zBusy = TCL.Tcl_GetStringFromObj( objv[2], out len );
2052 if ( zBusy != null && len > 0 )
2053 {
2054 //pDb.zBusy = TCL.Tcl_Alloc( len + 1 );
2055 pDb.zBusy = zBusy;// memcpy( pDb.zBusy, zBusy, len + 1 );
2056 }
2057 else
2058 {
2059 pDb.zBusy = null;
2060 }
2061 if ( pDb.zBusy != null )
2062 {
2063 pDb.interp = interp;
2064 sqlite3_busy_handler( pDb.db, (dxBusy)DbBusyHandler, pDb );
2065 }
2066 else
2067 {
2068 sqlite3_busy_handler( pDb.db, null, null );
2069 }
2070 }
2071 break;
2072 }
2073  
2074 // /* $db cache flush
2075 // ** $db cache size n
2076 // **
2077 // ** Flush the prepared statement cache, or set the maximum number of
2078 // ** cached statements.
2079 // */
2080 case (int)DB_enum.DB_CACHE:
2081 {
2082 string subCmd;
2083 int n = 0;
2084  
2085 if ( objc <= 2 )
2086 {
2087 TCL.Tcl_WrongNumArgs( interp, 1, objv, "cache option ?arg?" );
2088 return TCL.TCL_ERROR;
2089 }
2090 subCmd = TCL.Tcl_GetStringFromObj( objv[2], 0 );
2091 if ( subCmd == "flush" )
2092 {
2093 if ( objc != 3 )
2094 {
2095 TCL.Tcl_WrongNumArgs( interp, 2, objv, "flush" );
2096 return TCL.TCL_ERROR;
2097 }
2098 else
2099 {
2100 flushStmtCache( pDb );
2101 }
2102 }
2103 else if ( subCmd == "size" )
2104 {
2105 if ( objc != 4 )
2106 {
2107 TCL.Tcl_WrongNumArgs( interp, 2, objv, "size n" );
2108 return TCL.TCL_ERROR;
2109 }
2110 else
2111 {
2112 if ( TCL.TCL_ERROR == ( TCL.Tcl_GetIntFromObj( interp, objv[3], out n ) != TCL.TCL_OK ? TCL.TCL_ERROR : TCL.TCL_OK ) )
2113 {
2114 TCL.Tcl_AppendResult( interp, "cannot convert \"",
2115 TCL.Tcl_GetStringFromObj( objv[3], 0 ), "\" to integer", 0 );
2116 return TCL.TCL_ERROR;
2117 }
2118 else
2119 {
2120 if ( n < 0 )
2121 {
2122 flushStmtCache( pDb );
2123 n = 0;
2124 }
2125 else if ( n > MAX_PREPARED_STMTS )
2126 {
2127 n = MAX_PREPARED_STMTS;
2128 }
2129 pDb.maxStmt = n;
2130 }
2131 }
2132 }
2133 else
2134 {
2135 TCL.Tcl_AppendResult( interp, "bad option \"",
2136 TCL.Tcl_GetStringFromObj( objv[2], 0 ), "\": must be flush or size", null );
2137 return TCL.TCL_ERROR;
2138 }
2139 break;
2140 }
2141  
2142 /* $db changes
2143 **
2144 ** Return the number of rows that were modified, inserted, or deleted by
2145 ** the most recent INSERT, UPDATE or DELETE statement, not including
2146 ** any changes made by trigger programs.
2147 */
2148 case (int)DB_enum.DB_CHANGES:
2149 {
2150 Tcl_Obj pResult;
2151 if ( objc != 2 )
2152 {
2153 TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
2154 return TCL.TCL_ERROR;
2155 }
2156 pResult = TCL.Tcl_GetObjResult( interp );
2157 TCL.Tcl_SetResult( interp, sqlite3_changes( pDb.db ).ToString(), 0 );
2158 break;
2159 }
2160  
2161 /* $db close
2162 **
2163 ** Shutdown the database
2164 */
2165 case (int)DB_enum.DB_CLOSE:
2166 {
2167 TCL.Tcl_DeleteCommand( interp, TCL.Tcl_GetStringFromObj( objv[0], 0 ) );
2168 break;
2169 }
2170  
2171 /*
2172 ** $db collate NAME SCRIPT
2173 **
2174 ** Create a new SQL collation function called NAME. Whenever
2175 ** that function is called, invoke SCRIPT to evaluate the function.
2176 */
2177 case (int)DB_enum.DB_COLLATE:
2178 {
2179 SqlCollate pCollate;
2180 string zName;
2181 string zScript;
2182 int nScript = 0;
2183 if ( objc != 4 )
2184 {
2185 TCL.Tcl_WrongNumArgs( interp, 2, objv, "NAME SCRIPT" );
2186 return TCL.TCL_ERROR;
2187 }
2188 zName = TCL.Tcl_GetStringFromObj( objv[2], 0 );
2189 zScript = TCL.Tcl_GetStringFromObj( objv[3], nScript );
2190 pCollate = new SqlCollate();//(SqlCollate)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );
2191 //if ( pCollate == null ) return TCL.TCL_ERROR;
2192 pCollate.interp = interp;
2193 pCollate.pNext = pDb.pCollate;
2194 pCollate.zScript = zScript; // pCollate[1];
2195 pDb.pCollate = pCollate;
2196 //memcpy( pCollate.zScript, zScript, nScript + 1 );
2197 if ( sqlite3_create_collation( pDb.db, zName, SQLITE_UTF8,
2198 pCollate, (dxCompare)tclSqlCollate ) != 0 )
2199 {
2200 TCL.Tcl_SetResult( interp, sqlite3_errmsg( pDb.db ), TCL.TCL_VOLATILE );
2201 return TCL.TCL_ERROR;
2202 }
2203 break;
2204 }
2205  
2206 /*
2207 ** $db collation_needed SCRIPT
2208 **
2209 ** Create a new SQL collation function called NAME. Whenever
2210 ** that function is called, invoke SCRIPT to evaluate the function.
2211 */
2212 case (int)DB_enum.DB_COLLATION_NEEDED:
2213 {
2214 if ( objc != 3 )
2215 {
2216 TCL.Tcl_WrongNumArgs( interp, 2, objv, "SCRIPT" );
2217 return TCL.TCL_ERROR;
2218 }
2219 if ( pDb.pCollateNeeded != null )
2220 {
2221 TCL.Tcl_DecrRefCount( ref pDb.pCollateNeeded );
2222 }
2223 pDb.pCollateNeeded = TCL.Tcl_DuplicateObj( objv[2] );
2224 TCL.Tcl_IncrRefCount( pDb.pCollateNeeded );
2225 sqlite3_collation_needed( pDb.db, (object)pDb, (dxCollNeeded)tclCollateNeeded );
2226 break;
2227 }
2228  
2229 /* $db commit_hook ?CALLBACK?
2230 **
2231 ** Invoke the given callback just before committing every SQL transaction.
2232 ** If the callback throws an exception or returns non-zero, then the
2233 ** transaction is aborted. If CALLBACK is an empty string, the callback
2234 ** is disabled.
2235 */
2236 case (int)DB_enum.DB_COMMIT_HOOK:
2237 {
2238 if ( objc > 3 )
2239 {
2240 TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
2241 return TCL.TCL_ERROR;
2242 }
2243 else if ( objc == 2 )
2244 {
2245 if ( pDb.zCommit != null )
2246 {
2247 TCL.Tcl_AppendResult( interp, pDb.zCommit );
2248 }
2249 }
2250 else
2251 {
2252 string zCommit;
2253 int len = 0;
2254 if ( pDb.zCommit != null )
2255 {
2256 TCL.Tcl_Free( ref pDb.zCommit );
2257 }
2258 zCommit = TCL.Tcl_GetStringFromObj( objv[2], out len );
2259 if ( zCommit != null && len > 0 )
2260 {
2261 pDb.zCommit = zCommit;// TCL.Tcl_Alloc( len + 1 );
2262 //memcpy( pDb.zCommit, zCommit, len + 1 );
2263 }
2264 else
2265 {
2266 pDb.zCommit = null;
2267 }
2268 if ( pDb.zCommit != null )
2269 {
2270 pDb.interp = interp;
2271 sqlite3_commit_hook( pDb.db, DbCommitHandler, pDb );
2272 }
2273 else
2274 {
2275 sqlite3_commit_hook( pDb.db, null, null );
2276 }
2277 }
2278 break;
2279 }
2280  
2281 /* $db complete SQL
2282 **
2283 ** Return TRUE if SQL is a complete SQL statement. Return FALSE if
2284 ** additional lines of input are needed. This is similar to the
2285 ** built-in "info complete" command of Tcl.
2286 */
2287 case (int)DB_enum.DB_COMPLETE:
2288 {
2289 #if !SQLITE_OMIT_COMPLETE
2290 Tcl_Obj pResult;
2291 int isComplete;
2292 if ( objc != 3 )
2293 {
2294 TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL" );
2295 return TCL.TCL_ERROR;
2296 }
2297 isComplete = sqlite3_complete( TCL.Tcl_GetStringFromObj( objv[2], 0 ) );
2298 pResult = TCL.Tcl_GetObjResult( interp );
2299 TCL.Tcl_SetBooleanObj( pResult, isComplete );
2300 #endif
2301 break;
2302 }
2303  
2304 /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
2305 **
2306 ** Copy data into table from filename, optionally using SEPARATOR
2307 ** as column separators. If a column contains a null string, or the
2308 ** value of NULLINDICATOR, a NULL is inserted for the column.
2309 ** conflict-algorithm is one of the sqlite conflict algorithms:
2310 ** rollback, abort, fail, ignore, replace
2311 ** On success, return the number of lines processed, not necessarily same
2312 ** as 'db changes' due to conflict-algorithm selected.
2313 **
2314 ** This code is basically an implementation/enhancement of
2315 ** the sqlite3 shell.c ".import" command.
2316 **
2317 ** This command usage is equivalent to the sqlite2.x COPY statement,
2318 ** which imports file data into a table using the PostgreSQL COPY file format:
2319 ** $db copy $conflit_algo $table_name $filename \t \\N
2320 */
2321 case (int)DB_enum.DB_COPY:
2322 {
2323 string zTable; /* Insert data into this table */
2324 string zFile; /* The file from which to extract data */
2325 string zConflict; /* The conflict algorithm to use */
2326 sqlite3_stmt pStmt = null; /* A statement */
2327 int nCol; /* Number of columns in the table */
2328 int nByte; /* Number of bytes in an SQL string */
2329 int i, j; /* Loop counters */
2330 int nSep; /* Number of bytes in zSep[] */
2331 int nNull; /* Number of bytes in zNull[] */
2332 StringBuilder zSql = new StringBuilder( 200 ); /* An SQL statement */
2333 string zLine; /* A single line of input from the file */
2334 string[] azCol; /* zLine[] broken up into columns */
2335 string zCommit; /* How to commit changes */
2336 TextReader _in; /* The input file */
2337 int lineno = 0; /* Line number of input file */
2338 StringBuilder zLineNum = new StringBuilder( 80 ); /* Line number print buffer */
2339 Tcl_Obj pResult; /* interp result */
2340  
2341 string zSep;
2342 string zNull;
2343 if ( objc < 5 || objc > 7 )
2344 {
2345 TCL.Tcl_WrongNumArgs( interp, 2, objv,
2346 "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?" );
2347 return TCL.TCL_ERROR;
2348 }
2349 if ( objc >= 6 )
2350 {
2351 zSep = TCL.Tcl_GetStringFromObj( objv[5], 0 );
2352 }
2353 else
2354 {
2355 zSep = "\t";
2356 }
2357 if ( objc >= 7 )
2358 {
2359 zNull = TCL.Tcl_GetStringFromObj( objv[6], 0 );
2360 }
2361 else
2362 {
2363 zNull = "";
2364 }
2365 zConflict = TCL.Tcl_GetStringFromObj( objv[2], 0 );
2366 zTable = TCL.Tcl_GetStringFromObj( objv[3], 0 );
2367 zFile = TCL.Tcl_GetStringFromObj( objv[4], 0 );
2368 nSep = strlen30( zSep );
2369 nNull = strlen30( zNull );
2370 if ( nSep == 0 )
2371 {
2372 TCL.Tcl_AppendResult( interp, "Error: non-null separator required for copy" );
2373 return TCL.TCL_ERROR;
2374 }
2375 if ( zConflict != "rollback" &&
2376 zConflict != "abort" &&
2377 zConflict != "fail" &&
2378 zConflict != "ignore" &&
2379 zConflict != "replace" )
2380 {
2381 TCL.Tcl_AppendResult( interp, "Error: \"", zConflict,
2382 "\", conflict-algorithm must be one of: rollback, " +
2383 "abort, fail, ignore, or replace", 0 );
2384 return TCL.TCL_ERROR;
2385 }
2386 zSql.Append( sqlite3_mprintf( "SELECT * FROM '%q'", zTable ) );
2387 if ( zSql == null )
2388 {
2389 TCL.Tcl_AppendResult( interp, "Error: no such table: ", zTable );
2390 return TCL.TCL_ERROR;
2391 }
2392 nByte = strlen30( zSql );
2393 rc = sqlite3_prepare( pDb.db, zSql.ToString(), -1, ref pStmt, 0 );
2394 sqlite3DbFree( null, ref zSql );
2395 if ( rc != 0 )
2396 {
2397 TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
2398 nCol = 0;
2399 }
2400 else
2401 {
2402 nCol = sqlite3_column_count( pStmt );
2403 }
2404 sqlite3_finalize( pStmt );
2405 if ( nCol == 0 )
2406 {
2407 return TCL.TCL_ERROR;
2408 }
2409 //zSql.Append(malloc( nByte + 50 + nCol*2 );
2410 //if( zSql==0 ) {
2411 // TCL.Tcl_AppendResult(interp, "Error: can't malloc()");
2412 // return TCL.TCL_ERROR;
2413 //}
2414 sqlite3_snprintf( nByte + 50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
2415 zConflict, zTable );
2416 j = strlen30( zSql );
2417 for ( i = 1; i < nCol; i++ )
2418 {
2419 //zSql+=[j++] = ',';
2420 //zSql[j++] = '?';
2421 zSql.Append( ",?" );
2422 }
2423 //zSql[j++] = ')';
2424 //zSql[j] = "";
2425 zSql.Append( ")" );
2426 rc = sqlite3_prepare( pDb.db, zSql.ToString(), -1, ref pStmt, 0 );
2427 //free(zSql);
2428 if ( rc != 0 )
2429 {
2430 TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
2431 sqlite3_finalize( pStmt );
2432 return TCL.TCL_ERROR;
2433 }
2434 _in = new StreamReader( zFile );//fopen(zFile, "rb");
2435 if ( _in == null )
2436 {
2437 TCL.Tcl_AppendResult( interp, "Error: cannot open file: ", zFile );
2438 sqlite3_finalize( pStmt );
2439 return TCL.TCL_ERROR;
2440 }
2441 azCol = new string[nCol + 1];//malloc( sizeof(azCol[0])*(nCol+1) );
2442 if ( azCol == null )
2443 {
2444 TCL.Tcl_AppendResult( interp, "Error: can't malloc()" );
2445 _in.Close();//fclose(_in);
2446 return TCL.TCL_ERROR;
2447 }
2448 sqlite3_exec( pDb.db, "BEGIN", 0, 0, 0 );
2449 zCommit = "COMMIT";
2450 while ( ( zLine = _in.ReadLine() ) != null )//local_getline(0, _in))!=0 )
2451 {
2452 string z;
2453 i = 0;
2454 lineno++;
2455 azCol = zLine.Split( zSep[0] );
2456 //for(i=0, z=zLine; *z; z++){
2457 // if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
2458 // *z = 0;
2459 // i++;
2460 // if( i<nCol ){
2461 // azCol[i] = z[nSep];
2462 // z += nSep-1;
2463 // }
2464 // }
2465 //}
2466 if ( azCol.Length != nCol )
2467 {
2468 StringBuilder zErr = new StringBuilder( 200 );
2469 int nErr = strlen30( zFile ) + 200;
2470 //zErr = malloc(nErr);
2471 //if( zErr ){
2472 sqlite3_snprintf( nErr, zErr,
2473 "Error: %s line %d: expected %d columns of data but found %d",
2474 zFile, lineno, nCol, i + 1 );
2475 TCL.Tcl_AppendResult( interp, zErr );
2476 // free(zErr);
2477 //}
2478 zCommit = "ROLLBACK";
2479 break;
2480 }
2481 for ( i = 0; i < nCol; i++ )
2482 {
2483 /* check for null data, if so, bind as null */
2484 if ( ( nNull > 0 && azCol[i] == zNull )
2485 || strlen30( azCol[i] ) == 0
2486 )
2487 {
2488 sqlite3_bind_null( pStmt, i + 1 );
2489 }
2490 else
2491 {
2492 sqlite3_bind_text( pStmt, i + 1, azCol[i], -1, SQLITE_STATIC );
2493 }
2494 }
2495 sqlite3_step( pStmt );
2496 rc = sqlite3_reset( pStmt );
2497 //free(zLine);
2498 if ( rc != SQLITE_OK )
2499 {
2500 TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
2501 zCommit = "ROLLBACK";
2502 break;
2503 }
2504 }
2505 //free(azCol);
2506 _in.Close();// fclose( _in );
2507 sqlite3_finalize( pStmt );
2508 sqlite3_exec( pDb.db, zCommit, 0, 0, 0 );
2509  
2510 if ( zCommit[0] == 'C' )
2511 {
2512 /* success, set result as number of lines processed */
2513 pResult = TCL.Tcl_GetObjResult( interp );
2514 TCL.Tcl_SetIntObj( pResult, lineno );
2515 rc = TCL.TCL_OK;
2516 }
2517 else
2518 {
2519 /* failure, append lineno where failed */
2520 sqlite3_snprintf( 80, zLineNum, "%d", lineno );
2521 TCL.Tcl_AppendResult( interp, ", failed while processing line: ", zLineNum );
2522 rc = TCL.TCL_ERROR;
2523 }
2524 break;
2525 }
2526  
2527 /*
2528 ** $db enable_load_extension BOOLEAN
2529 **
2530 ** Turn the extension loading feature on or off. It if off by
2531 ** default.
2532 */
2533 case (int)DB_enum.DB_ENABLE_LOAD_EXTENSION:
2534 {
2535 #if !SQLITE_OMIT_LOAD_EXTENSION
2536 bool onoff = false;
2537 if ( objc != 3 )
2538 {
2539 TCL.Tcl_WrongNumArgs( interp, 2, objv, "BOOLEAN" );
2540 return TCL.TCL_ERROR;
2541 }
2542 if ( TCL.Tcl_GetBooleanFromObj( interp, objv[2], out onoff ) )
2543 {
2544 return TCL.TCL_ERROR;
2545 }
2546 sqlite3_enable_load_extension( pDb.db, onoff ? 1 : 0 );
2547 break;
2548 #else
2549 TCL.Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
2550 0);
2551 return TCL.TCL_ERROR;
2552 #endif
2553 }
2554  
2555 /*
2556 ** $db errorcode
2557 **
2558 ** Return the numeric error code that was returned by the most recent
2559 ** call to sqlite3_exec().
2560 */
2561 case (int)DB_enum.DB_ERRORCODE:
2562 {
2563 TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_errcode( pDb.db ) ) );
2564 break;
2565 }
2566  
2567 /*
2568 ** $db exists $sql
2569 ** $db onecolumn $sql
2570 **
2571 ** The onecolumn method is the equivalent of:
2572 ** lindex [$db eval $sql] 0
2573 */
2574 case (int)DB_enum.DB_EXISTS:
2575 case (int)DB_enum.DB_ONECOLUMN:
2576 {
2577 DbEvalContext sEval = new DbEvalContext();
2578 ;
2579 if ( objc != 3 )
2580 {
2581 TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL" );
2582 return TCL.TCL_ERROR;
2583 }
2584 dbEvalInit( sEval, pDb, objv[2], null );
2585 rc = dbEvalStep( sEval );
2586 if ( choice == (int)DB_enum.DB_ONECOLUMN )
2587 {
2588 if ( rc == TCL.TCL_OK )
2589 {
2590 TCL.Tcl_SetObjResult( interp, dbEvalColumnValue( sEval, 0 ) );
2591 }
2592 }
2593 else if ( rc == TCL.TCL_BREAK || rc == TCL.TCL_OK )
2594 {
2595 TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( ( rc == TCL.TCL_OK ? 1 : 0 ) ) );
2596 }
2597 dbEvalFinalize( sEval );
2598  
2599 if ( rc == TCL.TCL_BREAK )
2600 {
2601 rc = TCL.TCL_OK;
2602 }
2603 break;
2604 }
2605  
2606 /*
2607 ** $db eval $sql ?array? ?{ ...code... }?
2608 **
2609 ** The SQL statement in $sql is evaluated. For each row, the values are
2610 ** placed in elements of the array named "array" and ...code... is executed.
2611 ** If "array" and "code" are omitted, then no callback is every invoked.
2612 ** If "array" is an empty string, then the values are placed in variables
2613 ** that have the same name as the fields extracted by the query.
2614 */
2615 case (int)DB_enum.DB_EVAL:
2616 {
2617 if ( objc < 3 || objc > 5 )
2618 {
2619 TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?" );
2620 return TCL.TCL_ERROR;
2621 }
2622  
2623 if ( objc == 3 )
2624 {
2625 DbEvalContext sEval = new DbEvalContext();
2626 Tcl_Obj pRet = TCL.Tcl_NewObj();
2627 TCL.Tcl_IncrRefCount( pRet );
2628 dbEvalInit( sEval, pDb, objv[2], null );
2629 //Console.WriteLine( objv[2].ToString() );
2630 while ( TCL.TCL_OK == ( rc = dbEvalStep( sEval ) ) )
2631 {
2632 int i;
2633 int nCol;
2634 TclObject[] pDummy;
2635 dbEvalRowInfo( sEval, out nCol, out pDummy );
2636 for ( i = 0; i < nCol; i++ )
2637 {
2638 TCL.Tcl_ListObjAppendElement( interp, pRet, dbEvalColumnValue( sEval, i ) );
2639 }
2640 }
2641 dbEvalFinalize( sEval );
2642 if ( rc == TCL.TCL_BREAK )
2643 {
2644 TCL.Tcl_SetObjResult( interp, pRet );
2645 rc = TCL.TCL_OK;
2646 }
2647 TCL.Tcl_DecrRefCount( ref pRet );
2648 }
2649 else
2650 {
2651 cd = new object[2];
2652 DbEvalContext p;
2653 Tcl_Obj pArray = null;
2654 Tcl_Obj pScript;
2655  
2656 if ( objc == 5 && !String.IsNullOrEmpty( TCL.Tcl_GetString( objv[3] ) ) )
2657 {
2658 pArray = objv[3];
2659 }
2660 pScript = objv[objc - 1];
2661 TCL.Tcl_IncrRefCount( pScript );
2662  
2663 p = new DbEvalContext();// (DbEvalContext)Tcl_Alloc( sizeof( DbEvalContext ) );
2664 dbEvalInit( p, pDb, objv[2], pArray );
2665  
2666 ( (object[])cd )[0] = p;
2667 ( (object[])cd )[1] = pScript;
2668 rc = DbEvalNextCmd( (object[])cd, interp, TCL.TCL_OK );
2669 }
2670 break;
2671 }
2672  
2673 /*
2674 ** $db function NAME [-argcount N] SCRIPT
2675 **
2676 ** Create a new SQL function called NAME. Whenever that function is
2677 ** called, invoke SCRIPT to evaluate the function.
2678 */
2679 case (int)DB_enum.DB_FUNCTION:
2680 {
2681 SqlFunc pFunc;
2682 Tcl_Obj pScript;
2683 string zName;
2684 int nArg = -1;
2685 if ( objc == 6 )
2686 {
2687 string z = TCL.Tcl_GetString( objv[3] );
2688 int n = strlen30( z );
2689 if ( n > 2 && z.StartsWith( "-argcount" ) )//strncmp( z, "-argcount", n ) == 0 )
2690 {
2691 if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[4], out nArg ) )
2692 return TCL.TCL_ERROR;
2693 if ( nArg < 0 )
2694 {
2695 TCL.Tcl_AppendResult( interp, "number of arguments must be non-negative" );
2696 return TCL.TCL_ERROR;
2697 }
2698 }
2699 pScript = objv[5];
2700 }
2701 else if ( objc != 4 )
2702 {
2703 TCL.Tcl_WrongNumArgs( interp, 2, objv, "NAME [-argcount N] SCRIPT" );
2704 return TCL.TCL_ERROR;
2705 }
2706 else
2707 {
2708 pScript = objv[3];
2709 }
2710 zName = TCL.Tcl_GetStringFromObj( objv[2], 0 );
2711 pFunc = findSqlFunc( pDb, zName );
2712 if ( pFunc == null )
2713 return TCL.TCL_ERROR;
2714 if ( pFunc.pScript != null )
2715 {
2716 TCL.Tcl_DecrRefCount( ref pFunc.pScript );
2717 }
2718 pFunc.pScript = pScript;
2719 TCL.Tcl_IncrRefCount( pScript );
2720 pFunc.useEvalObjv = safeToUseEvalObjv( interp, pScript );
2721 rc = sqlite3_create_function( pDb.db, zName, nArg, SQLITE_UTF8,
2722 pFunc, tclSqlFunc, null, null );
2723 if ( rc != SQLITE_OK )
2724 {
2725 rc = TCL.TCL_ERROR;
2726 TCL.Tcl_SetResult( interp, sqlite3_errmsg( pDb.db ), TCL.TCL_VOLATILE );
2727 }
2728 break;
2729 }
2730  
2731 /*
2732 ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID
2733 */
2734 case (int)DB_enum.DB_INCRBLOB:
2735 {
2736 #if SQLITE_OMIT_INCRBLOB
2737 TCL.Tcl_AppendResult( interp, "incrblob not available in this build" );
2738 return TCL.TCL_ERROR;
2739 #else
2740 int isReadonly = 0;
2741 string zDb = "main" ;
2742 string zTable;
2743 string zColumn;
2744 long iRow = 0;
2745  
2746 /* Check for the -readonly option */
2747 if ( objc > 3 && TCL.Tcl_GetString( objv[2] ) == "-readonly" )
2748 {
2749 isReadonly = 1;
2750 }
2751  
2752 if ( objc != ( 5 + isReadonly ) && objc != ( 6 + isReadonly ) )
2753 {
2754 TCL.Tcl_WrongNumArgs( interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID" );
2755 return TCL.TCL_ERROR;
2756 }
2757  
2758 if ( objc == ( 6 + isReadonly ) )
2759 {
2760 zDb = TCL.Tcl_GetString( objv[2] ) ;
2761 }
2762 zTable = TCL.Tcl_GetString( objv[objc - 3] );
2763 zColumn = TCL.Tcl_GetString( objv[objc - 2] ) ;
2764 rc = TCL.Tcl_GetWideIntFromObj( interp, objv[objc - 1], out iRow ) ? 1 : 0;
2765  
2766 if ( rc == TCL.TCL_OK )
2767 {
2768 rc = createIncrblobChannel(
2769 interp, pDb, zDb, zTable, zColumn, iRow, isReadonly
2770 );
2771 }
2772 break;
2773 #endif
2774 }
2775 /*
2776 ** $db interrupt
2777 **
2778 ** Interrupt the execution of the inner-most SQL interpreter. This
2779 ** causes the SQL statement to return an error of SQLITE_INTERRUPT.
2780 */
2781 case (int)DB_enum.DB_INTERRUPT:
2782 {
2783 sqlite3_interrupt( pDb.db );
2784 break;
2785 }
2786  
2787 /*
2788 ** $db nullvalue ?STRING?
2789 **
2790 ** Change text used when a NULL comes back from the database. If ?STRING?
2791 ** is not present, then the current string used for NULL is returned.
2792 ** If STRING is present, then STRING is returned.
2793 **
2794 */
2795 case (int)DB_enum.DB_NULLVALUE:
2796 {
2797 if ( objc != 2 && objc != 3 )
2798 {
2799 TCL.Tcl_WrongNumArgs( interp, 2, objv, "NULLVALUE" );
2800 return TCL.TCL_ERROR;
2801 }
2802 if ( objc == 3 )
2803 {
2804 int len = 0;
2805 string zNull = TCL.Tcl_GetStringFromObj( objv[2], out len );
2806 if ( pDb.zNull != null )
2807 {
2808 TCL.Tcl_Free( ref pDb.zNull );
2809 }
2810 if ( zNull != null && len > 0 )
2811 {
2812 pDb.zNull = zNull;
2813 //pDb.zNull = TCL.Tcl_Alloc( len + 1 );
2814 //memcpy(pDb->zNull, zNull, len);
2815 //pDb.zNull[len] = '\0';
2816 }
2817 else
2818 {
2819 pDb.zNull = null;
2820 }
2821 }
2822 TCL.Tcl_SetObjResult( interp, dbTextToObj( pDb.zNull ) );
2823 break;
2824 }
2825  
2826 /*
2827 ** $db last_insert_rowid
2828 **
2829 ** Return an integer which is the ROWID for the most recent insert.
2830 */
2831 case (int)DB_enum.DB_LAST_INSERT_ROWID:
2832 {
2833 Tcl_Obj pResult;
2834 Tcl_WideInt rowid;
2835 if ( objc != 2 )
2836 {
2837 TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
2838 return TCL.TCL_ERROR;
2839 }
2840 rowid = sqlite3_last_insert_rowid( pDb.db );
2841 pResult = TCL.Tcl_GetObjResult( interp );
2842 TCL.Tcl_SetLongObj( pResult, rowid );
2843 break;
2844 }
2845  
2846 /*
2847 ** The DB_ONECOLUMN method is implemented together with DB_EXISTS.
2848 */
2849  
2850 /* $db progress ?N CALLBACK?
2851 **
2852 ** Invoke the given callback every N virtual machine opcodes while executing
2853 ** queries.
2854 */
2855 case (int)DB_enum.DB_PROGRESS:
2856 {
2857 if ( objc == 2 )
2858 {
2859 if ( !String.IsNullOrEmpty( pDb.zProgress ) )
2860 {
2861 TCL.Tcl_AppendResult( interp, pDb.zProgress );
2862 }
2863 }
2864 else if ( objc == 4 )
2865 {
2866 string zProgress;
2867 int len = 0;
2868 int N = 0;
2869 if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out N ) )
2870 {
2871 return TCL.TCL_ERROR;
2872 };
2873 if ( !String.IsNullOrEmpty( pDb.zProgress ) )
2874 {
2875 TCL.Tcl_Free( ref pDb.zProgress );
2876 }
2877 zProgress = TCL.Tcl_GetStringFromObj( objv[3], len );
2878 if ( !String.IsNullOrEmpty( zProgress ) )
2879 {
2880 //pDb.zProgress = TCL.Tcl_Alloc( len + 1 );
2881 //memcpy( pDb.zProgress, zProgress, len + 1 );
2882 pDb.zProgress = zProgress;
2883 }
2884 else
2885 {
2886 pDb.zProgress = null;
2887 }
2888 #if !SQLITE_OMIT_PROGRESS_CALLBACK
2889 if ( !String.IsNullOrEmpty( pDb.zProgress ) )
2890 {
2891 pDb.interp = interp;
2892 sqlite3_progress_handler( pDb.db, N, DbProgressHandler, pDb );
2893 }
2894 else
2895 {
2896 sqlite3_progress_handler( pDb.db, 0, null, 0 );
2897 }
2898 #endif
2899 }
2900 else
2901 {
2902 TCL.Tcl_WrongNumArgs( interp, 2, objv, "N CALLBACK" );
2903 return TCL.TCL_ERROR;
2904 }
2905 break;
2906 }
2907  
2908 /* $db profile ?CALLBACK?
2909 **
2910 ** Make arrangements to invoke the CALLBACK routine after each SQL statement
2911 ** that has run. The text of the SQL and the amount of elapse time are
2912 ** appended to CALLBACK before the script is run.
2913 */
2914 case (int)DB_enum.DB_PROFILE:
2915 {
2916 if ( objc > 3 )
2917 {
2918 TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
2919 return TCL.TCL_ERROR;
2920 }
2921 else if ( objc == 2 )
2922 {
2923 if ( !String.IsNullOrEmpty( pDb.zProfile ) )
2924 {
2925 TCL.Tcl_AppendResult( interp, pDb.zProfile );
2926 }
2927 }
2928 else
2929 {
2930 string zProfile;
2931 int len = 0;
2932 if ( !String.IsNullOrEmpty( pDb.zProfile ) )
2933 {
2934 TCL.Tcl_Free( ref pDb.zProfile );
2935 }
2936 zProfile = TCL.Tcl_GetStringFromObj( objv[2], out len );
2937 if ( !String.IsNullOrEmpty( zProfile ) && len > 0 )
2938 {
2939 //pDb.zProfile = TCL.Tcl_Alloc( len + 1 );
2940 //memcpy( pDb.zProfile, zProfile, len + 1 );
2941 pDb.zProfile = zProfile;
2942 }
2943 else
2944 {
2945 pDb.zProfile = null;
2946 }
2947 #if !SQLITE_OMIT_TRACE && !(SQLITE_OMIT_FLOATING_POINT)
2948 if ( !String.IsNullOrEmpty( pDb.zProfile ) )
2949 {
2950 pDb.interp = interp;
2951 sqlite3_profile( pDb.db, DbProfileHandler, pDb );
2952 }
2953 else
2954 {
2955 sqlite3_profile( pDb.db, null, null );
2956 }
2957 #endif
2958 }
2959 break;
2960 }
2961  
2962 /*
2963 ** $db rekey KEY
2964 **
2965 ** Change the encryption key on the currently open database.
2966 */
2967 case (int)DB_enum.DB_REKEY:
2968 {
2969 int nKey = 0;
2970 string pKey;
2971 if ( objc != 3 )
2972 {
2973 TCL.Tcl_WrongNumArgs( interp, 2, objv, "KEY" );
2974 return TCL.TCL_ERROR;
2975 }
2976 pKey = TCL.Tcl_GetStringFromObj( objv[2], out nKey );
2977 #if SQLITE_HAS_CODEC
2978 rc = sqlite3_rekey( pDb.db, pKey, nKey );
2979 if ( rc != 0 )
2980 {
2981 TCL.Tcl_AppendResult( interp, sqlite3ErrStr( rc ) );
2982 rc = TCL.TCL_ERROR;
2983 }
2984 #endif
2985 break;
2986 }
2987  
2988 /* $db restore ?DATABASE? FILENAME
2989 **
2990 ** Open a database file named FILENAME. Transfer the content
2991 ** of FILENAME into the local database DATABASE (default: "main").
2992 */
2993 case (int)DB_enum.DB_RESTORE:
2994 {
2995 string zSrcFile;
2996 string zDestDb;
2997 sqlite3 pSrc = null;
2998 sqlite3_backup pBackup;
2999 int nTimeout = 0;
3000  
3001 if ( objc == 3 )
3002 {
3003 zDestDb = "main";
3004 zSrcFile = TCL.Tcl_GetString( objv[2] );
3005 }
3006 else if ( objc == 4 )
3007 {
3008 zDestDb = TCL.Tcl_GetString( objv[2] );
3009 zSrcFile = TCL.Tcl_GetString( objv[3] );
3010 }
3011 else
3012 {
3013 TCL.Tcl_WrongNumArgs( interp, 2, objv, "?DATABASE? FILENAME" );
3014 return TCL.TCL_ERROR;
3015 }
3016 rc = sqlite3_open_v2( zSrcFile, out pSrc, SQLITE_OPEN_READONLY, null );
3017 if ( rc != SQLITE_OK )
3018 {
3019 TCL.Tcl_AppendResult( interp, "cannot open source database: ",
3020 sqlite3_errmsg( pSrc ) );
3021 sqlite3_close( pSrc );
3022 return TCL.TCL_ERROR;
3023 }
3024 pBackup = sqlite3_backup_init( pDb.db, zDestDb, pSrc, "main" );
3025 if ( pBackup == null )
3026 {
3027 TCL.Tcl_AppendResult( interp, "restore failed: ",
3028 sqlite3_errmsg( pDb.db ) );
3029 sqlite3_close( pSrc );
3030 return TCL.TCL_ERROR;
3031 }
3032  
3033 #if SQLITE_HAS_CODEC
3034 if ( pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec != null )
3035 {
3036 pBackup.pSrc.pBt.pPager.xCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodec;
3037 pBackup.pSrc.pBt.pPager.xCodecFree = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecFree;
3038 pBackup.pSrc.pBt.pPager.xCodecSizeChng = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecSizeChng;
3039 pBackup.pSrc.pBt.pPager.pCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec.Copy();
3040 if ( pBackup.pDest.GetHashCode() != pBackup.pDestDb.aDb[0].GetHashCode() ) // Not Main Database
3041 {
3042 pBackup.pDest.pBt.pPager.xCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodec;
3043 pBackup.pDest.pBt.pPager.xCodecFree = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecFree;
3044 pBackup.pDest.pBt.pPager.xCodecSizeChng = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecSizeChng;
3045 pBackup.pDest.pBt.pPager.pCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec.Copy();
3046 }
3047 }
3048 #endif
3049 while ( ( rc = sqlite3_backup_step( pBackup, 100 ) ) == SQLITE_OK
3050 || rc == SQLITE_BUSY )
3051 {
3052 if ( rc == SQLITE_BUSY )
3053 {
3054 if ( nTimeout++ >= 3 )
3055 break;
3056 sqlite3_sleep( 100 );
3057 }
3058 }
3059 sqlite3_backup_finish( pBackup );
3060 if ( rc == SQLITE_DONE )
3061 {
3062 rc = TCL.TCL_OK;
3063 }
3064 else if ( rc == SQLITE_BUSY || rc == SQLITE_LOCKED )
3065 {
3066 TCL.Tcl_AppendResult( interp, "restore failed: source database busy"
3067 );
3068 rc = TCL.TCL_ERROR;
3069 }
3070 else
3071 {
3072 TCL.Tcl_AppendResult( interp, "restore failed: ",
3073 sqlite3_errmsg( pDb.db ) );
3074 rc = TCL.TCL_ERROR;
3075 }
3076 sqlite3_close( pSrc );
3077 break;
3078 }
3079  
3080 /*
3081 ** $db status (step|sort|autoindex)
3082 **
3083 ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
3084 ** SQLITE_STMTSTATUS_SORT for the most recent eval.
3085 */
3086 case (int)DB_enum.DB_STATUS:
3087 {
3088 int v;
3089 string zOp;
3090 if ( objc != 3 )
3091 {
3092 TCL.Tcl_WrongNumArgs( interp, 2, objv, "(step|sort|autoindex)" );
3093 return TCL.TCL_ERROR;
3094 }
3095 zOp = TCL.Tcl_GetString( objv[2] );
3096 if ( zOp == "step" )
3097 {
3098 v = pDb.nStep;
3099 }
3100 else if ( zOp == "sort" )
3101 {
3102 v = pDb.nSort;
3103 }
3104 else if ( zOp == "autoindex" )
3105 {
3106 v = pDb.nIndex;
3107 }
3108 else
3109 {
3110 TCL.Tcl_AppendResult( interp, "bad argument: should be autoindex, step or sort" );
3111 return TCL.TCL_ERROR;
3112 }
3113 TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( v ) );
3114 break;
3115 }
3116  
3117 /*
3118 ** $db timeout MILLESECONDS
3119 **
3120 ** Delay for the number of milliseconds specified when a file is locked.
3121 */
3122 case (int)DB_enum.DB_TIMEOUT:
3123 {
3124 int ms = 0;
3125 if ( objc != 3 )
3126 {
3127 TCL.Tcl_WrongNumArgs( interp, 2, objv, "MILLISECONDS" );
3128 return TCL.TCL_ERROR;
3129 }
3130 if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out ms ) )
3131 return TCL.TCL_ERROR;
3132 sqlite3_busy_timeout( pDb.db, ms );
3133 break;
3134 }
3135  
3136 /*
3137 ** $db total_changes
3138 **
3139 ** Return the number of rows that were modified, inserted, or deleted
3140 ** since the database handle was created.
3141 */
3142 case (int)DB_enum.DB_TOTAL_CHANGES:
3143 {
3144 Tcl_Obj pResult;
3145 if ( objc != 2 )
3146 {
3147 TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
3148 return TCL.TCL_ERROR;
3149 }
3150 pResult = TCL.Tcl_GetObjResult( interp );
3151 TCL.Tcl_SetIntObj( pResult, sqlite3_total_changes( pDb.db ) );
3152 break;
3153 }
3154  
3155 /* $db trace ?CALLBACK?
3156 **
3157 ** Make arrangements to invoke the CALLBACK routine for each SQL statement
3158 ** that is executed. The text of the SQL is appended to CALLBACK before
3159 ** it is executed.
3160 */
3161 case (int)DB_enum.DB_TRACE:
3162 {
3163 if ( objc > 3 )
3164 {
3165 TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
3166 return TCL.TCL_ERROR;
3167 }
3168 else if ( objc == 2 )
3169 {
3170 if ( pDb.zTrace != null )
3171 {
3172 TCL.Tcl_AppendResult( interp, pDb.zTrace );
3173 }
3174 }
3175 else
3176 {
3177 string zTrace;
3178 int len = 0;
3179 if ( pDb.zTrace != null )
3180 {
3181 TCL.Tcl_Free( ref pDb.zTrace );
3182 }
3183 zTrace = TCL.Tcl_GetStringFromObj( objv[2], out len );
3184 if ( zTrace != null && len > 0 )
3185 {
3186 //pDb.zTrace = TCL.Tcl_Alloc( len + 1 );
3187 pDb.zTrace = zTrace;//memcpy( pDb.zTrace, zTrace, len + 1 );
3188 }
3189 else
3190 {
3191 pDb.zTrace = null;
3192 }
3193 #if !SQLITE_OMIT_TRACE && !(SQLITE_OMIT_FLOATING_POINT)
3194 if ( pDb.zTrace != null )
3195 {
3196 pDb.interp = interp;
3197 sqlite3_trace( pDb.db, (dxTrace)DbTraceHandler, pDb );
3198 }
3199 else
3200 {
3201 sqlite3_trace( pDb.db, null, null );
3202 }
3203 #endif
3204 }
3205 break;
3206 }
3207  
3208 // /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
3209 // **
3210 // ** Start a new transaction (if we are not already in the midst of a
3211 // ** transaction) and execute the TCL script SCRIPT. After SCRIPT
3212 // ** completes, either commit the transaction or roll it back if SCRIPT
3213 // ** throws an exception. Or if no new transation was started, do nothing.
3214 // ** pass the exception on up the stack.
3215 // **
3216 // ** This command was inspired by Dave Thomas's talk on Ruby at the
3217 // ** 2005 O'Reilly Open Source Convention (OSCON).
3218 // */
3219 case (int)DB_enum.DB_TRANSACTION:
3220 {
3221 Tcl_Obj pScript;
3222 string zBegin = "SAVEPOINT _tcl_transaction";
3223 if ( objc != 3 && objc != 4 )
3224 {
3225 TCL.Tcl_WrongNumArgs( interp, 2, objv, "[TYPE] SCRIPT" );
3226 return TCL.TCL_ERROR;
3227 }
3228 if ( pDb.nTransaction == 0 && objc == 4 )
3229 {
3230 string[] TTYPE_strs = { "deferred", "exclusive", "immediate", null };
3231  
3232 int ttype = 0;
3233 if ( TCL.Tcl_GetIndexFromObj( interp, objv[2], TTYPE_strs, "transaction type",
3234 0, out ttype ) )
3235 {
3236 return TCL.TCL_ERROR;
3237 }
3238 switch ( ttype )
3239 {
3240 case (int)TTYPE_enum.TTYPE_DEFERRED: /* no-op */
3241 ;
3242 break;
3243 case (int)TTYPE_enum.TTYPE_EXCLUSIVE:
3244 zBegin = "BEGIN EXCLUSIVE";
3245 break;
3246 case (int)TTYPE_enum.TTYPE_IMMEDIATE:
3247 zBegin = "BEGIN IMMEDIATE";
3248 break;
3249 }
3250 }
3251 pScript = objv[objc - 1];
3252  
3253 /* Run the SQLite BEGIN command to open a transaction or savepoint. */
3254 pDb.disableAuth++;
3255 rc = sqlite3_exec( pDb.db, zBegin, 0, 0, 0 );
3256 pDb.disableAuth--;
3257 if ( rc != SQLITE_OK )
3258 {
3259 TCL.Tcl_AppendResult( interp, sqlite3_errmsg( pDb.db ) );
3260 return TCL.TCL_ERROR;
3261 }
3262 pDb.nTransaction++;
3263 /* If using NRE, schedule a callback to invoke the script pScript, then
3264 ** a second callback to commit (or rollback) the transaction or savepoint
3265 ** opened above. If not using NRE, evaluate the script directly, then
3266 ** call function DbTransPostCmd() to commit (or rollback) the transaction
3267 ** or savepoint. */
3268 if ( DbUseNre() )
3269 {
3270 Debugger.Break();
3271 //Tcl_NRAddCallback( interp, DbTransPostCmd, cd, 0, 0, 0 );
3272 //Tcl_NREvalObj(interp, pScript, 0);
3273 }
3274 else
3275 {
3276 rc = DbTransPostCmd( cd, interp, TCL.Tcl_EvalObjEx( interp, pScript, 0 ) );
3277 }
3278 break;
3279 }
3280  
3281 /*
3282 ** $db unlock_notify ?script?
3283 */
3284 case (int)DB_enum.DB_UNLOCK_NOTIFY:
3285 {
3286 #if !SQLITE_ENABLE_UNLOCK_NOTIFY
3287 TCL.Tcl_AppendResult( interp, "unlock_notify not available in this build", 0 );
3288 rc = TCL.TCL_ERROR;
3289 #else
3290 if( objc!=2 && objc!=3 ){
3291 Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
3292 rc = TCL.Tcl_ERROR;
3293 }else{
3294 void (*xNotify)(void **, int) = 0;
3295 void *pNotifyArg = 0;
3296  
3297 if( pDb.pUnlockNotify ){
3298 Tcl_DecrRefCount(pDb.pUnlockNotify);
3299 pDb.pUnlockNotify = 0;
3300 }
3301  
3302 if( objc==3 ){
3303 xNotify = DbUnlockNotify;
3304 pNotifyArg = (void )pDb;
3305 pDb.pUnlockNotify = objv[2];
3306 Tcl_IncrRefCount(pDb.pUnlockNotify);
3307 }
3308  
3309 if( sqlite3_unlock_notify(pDb.db, xNotify, pNotifyArg) ){
3310 Tcl_AppendResult(interp, sqlite3_errmsg(pDb.db), 0);
3311 rc = TCL.Tcl_ERROR;
3312 }
3313 }
3314 #endif
3315 break;
3316 }
3317 /*
3318 ** $db wal_hook ?script?
3319 ** $db update_hook ?script?
3320 ** $db rollback_hook ?script?
3321 */
3322 case (int)DB_enum.DB_WAL_HOOK:
3323 case (int)DB_enum.DB_UPDATE_HOOK:
3324 case (int)DB_enum.DB_ROLLBACK_HOOK:
3325 {
3326  
3327 /* set ppHook to point at pUpdateHook or pRollbackHook, depending on
3328 ** whether [$db update_hook] or [$db rollback_hook] was invoked.
3329 */
3330 Tcl_Obj ppHook;
3331 if ( choice == (int)DB_enum.DB_UPDATE_HOOK )
3332 {
3333 ppHook = pDb.pUpdateHook;
3334 }
3335 else if ( choice == (int)DB_enum.DB_WAL_HOOK )
3336 {
3337 ppHook = pDb.pWalHook;
3338 }
3339 else
3340 {
3341 ppHook = pDb.pRollbackHook;
3342 }
3343  
3344 if ( objc != 2 && objc != 3 )
3345 {
3346 TCL.Tcl_WrongNumArgs( interp, 2, objv, "?SCRIPT?" );
3347 return TCL.TCL_ERROR;
3348 }
3349 if ( ppHook != null )
3350 {
3351 TCL.Tcl_SetObjResult( interp, ppHook );
3352 if ( objc == 3 )
3353 {
3354 TCL.Tcl_DecrRefCount( ref ppHook );
3355 ppHook = null;
3356 }
3357 }
3358 if ( objc == 3 )
3359 {
3360 Debug.Assert( null == ppHook );
3361 if ( objv[2] != null )//TCL.Tcl_GetCharLength( objv[2] ) > 0 )
3362 {
3363 ppHook = objv[2];
3364 TCL.Tcl_IncrRefCount( ppHook );
3365 }
3366 }
3367 if ( choice == (int)DB_enum.DB_UPDATE_HOOK )
3368 {
3369 pDb.pUpdateHook = ppHook;
3370 }
3371 else
3372 {
3373 pDb.pRollbackHook = ppHook;
3374 }
3375 sqlite3_update_hook( pDb.db, ( pDb.pUpdateHook != null ? (dxUpdateCallback)DbUpdateHandler : null ), pDb );
3376 sqlite3_rollback_hook( pDb.db, ( pDb.pRollbackHook != null ? (dxRollbackCallback)DbRollbackHandler : null ), pDb );
3377 sqlite3_wal_hook( pDb.db, ( pDb.pWalHook != null ? (dxWalCallback)DbWalHandler : null ), pDb );
3378  
3379 break;
3380 }
3381  
3382 /* $db version
3383 **
3384 ** Return the version string for this database.
3385 */
3386 case (int)DB_enum.DB_VERSION:
3387 {
3388 TCL.Tcl_SetResult( interp, sqlite3_libversion(), TCL.TCL_STATIC );
3389 break;
3390 }
3391  
3392 default:
3393 Debug.Assert( false, "Missing switch:" + objv[1].ToString() );
3394 break;
3395 } /* End of the SWITCH statement */
3396 return rc;
3397 }
3398  
3399 #if SQLITE_TCL_NRE
3400 /*
3401 ** Adaptor that provides an objCmd interface to the NRE-enabled
3402 ** interface implementation.
3403 */
3404 static int DbObjCmdAdaptor(
3405 void *cd,
3406 Tcl_Interp interp,
3407 int objc,
3408 Tcl_Obj *const*objv
3409 ){
3410 return TCL.TCL_NRCallObjProc(interp, DbObjCmd, cd, objc, objv);
3411 }
3412 #endif //* SQLITE_TCL_NRE */
3413 /*
3414 ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
3415 ** ?-create BOOLEAN? ?-nomutex BOOLEAN?
3416 **
3417 ** This is the main Tcl command. When the "sqlite" Tcl command is
3418 ** invoked, this routine runs to process that command.
3419 **
3420 ** The first argument, DBNAME, is an arbitrary name for a new
3421 ** database connection. This command creates a new command named
3422 ** DBNAME that is used to control that connection. The database
3423 ** connection is deleted when the DBNAME command is deleted.
3424 **
3425 ** The second argument is the name of the database file.
3426 **
3427 */
3428 static int DbMain( object cd, Tcl_Interp interp, int objc, Tcl_Obj[] objv )
3429 {
3430 SqliteDb p;
3431 string pKey = null;
3432 int nKey = 0;
3433 string zArg;
3434 string zErrMsg;
3435 int i;
3436 string zFile;
3437 string zVfs = null;
3438 int flags;
3439 Tcl_DString translatedFilename;
3440 /* In normal use, each TCL interpreter runs in a single thread. So
3441 ** by default, we can turn of mutexing on SQLite database connections.
3442 ** However, for testing purposes it is useful to have mutexes turned
3443 ** on. So, by default, mutexes default off. But if compiled with
3444 ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
3445 */
3446 #if SQLITE_TCL_DEFAULT_FULLMUTEX
3447 flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
3448 #else
3449 flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
3450 #endif
3451 if ( objc == 2 )
3452 {
3453 zArg = TCL.Tcl_GetStringFromObj( objv[1], 0 );
3454 if ( zArg == "-version" )
3455 {
3456 TCL.Tcl_AppendResult( interp, sqlite3_version, null );
3457 return TCL.TCL_OK;
3458 }
3459 if ( zArg == "-has-codec" )
3460 {
3461 #if SQLITE_HAS_CODEC
3462 TCL.Tcl_AppendResult( interp, "1" );
3463 #else
3464 TCL.Tcl_AppendResult( interp, "0", null );
3465 #endif
3466 return TCL.TCL_OK;
3467 }
3468 if ( zArg == "-tcl-uses-utf" )
3469 {
3470 TCL.Tcl_AppendResult( interp, "1", null );
3471 return TCL.TCL_OK;
3472 }
3473 }
3474 for ( i = 3; i + 1 < objc; i += 2 )
3475 {
3476 zArg = TCL.Tcl_GetString( objv[i] );
3477 if ( zArg == "-key" )
3478 {
3479 pKey = TCL.Tcl_GetStringFromObj( objv[i + 1], out nKey );
3480 }
3481 else if ( zArg == "-vfs" )
3482 {
3483 zVfs = TCL.Tcl_GetString( objv[i + 1] );
3484 }
3485 else if ( zArg == "-readonly" )
3486 {
3487 bool b = false;
3488 if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
3489 return TCL.TCL_ERROR;
3490 if ( b )
3491 {
3492 flags &= ~( SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE );
3493 flags |= SQLITE_OPEN_READONLY;
3494 }
3495 else
3496 {
3497 flags &= ~SQLITE_OPEN_READONLY;
3498 flags |= SQLITE_OPEN_READWRITE;
3499 }
3500 }
3501 else if ( zArg == "-create" )
3502 {
3503 bool b = false;
3504 if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
3505 return TCL.TCL_ERROR;
3506 if ( b && ( flags & SQLITE_OPEN_READONLY ) == 0 )
3507 {
3508 flags |= SQLITE_OPEN_CREATE;
3509 }
3510 else
3511 {
3512 flags &= ~SQLITE_OPEN_CREATE;
3513 }
3514 }
3515 else if ( zArg == "-nomutex" )
3516 {
3517 bool b = false;
3518 if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
3519 return TCL.TCL_ERROR;
3520 if ( b )
3521 {
3522 flags |= SQLITE_OPEN_NOMUTEX;
3523 flags &= ~SQLITE_OPEN_FULLMUTEX;
3524 }
3525 else
3526 {
3527 flags &= ~SQLITE_OPEN_NOMUTEX;
3528 }
3529 }
3530 else if ( zArg == "-fullmutex" )//strcmp( zArg, "-fullmutex" ) == 0 )
3531 {
3532 bool b = false;
3533 if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
3534 return TCL.TCL_ERROR;
3535 if ( b )
3536 {
3537 flags |= SQLITE_OPEN_FULLMUTEX;
3538 flags &= ~SQLITE_OPEN_NOMUTEX;
3539 }
3540 else
3541 {
3542 flags &= ~SQLITE_OPEN_FULLMUTEX;
3543 }
3544 }
3545 else
3546 {
3547 TCL.Tcl_AppendResult( interp, "unknown option: ", zArg, null );
3548 return TCL.TCL_ERROR;
3549 }
3550 }
3551 if ( objc < 3 || ( objc & 1 ) != 1 )
3552 {
3553 TCL.Tcl_WrongNumArgs( interp, 1, objv,
3554 "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN?"
3555 #if SQLITE_HAS_CODEC
3556 + " ?-key CODECKEY?"
3557 #endif
3558 );
3559 return TCL.TCL_ERROR;
3560 }
3561 zErrMsg = "";
3562 p = new SqliteDb();//(SqliteDb)Tcl_Alloc( sizeof(*p) );
3563 if ( p == null )
3564 {
3565 TCL.Tcl_SetResult( interp, "malloc failed", TCL.TCL_STATIC );
3566 return TCL.TCL_ERROR;
3567 }
3568 //memset(p, 0, sizeof(*p));
3569 zFile = TCL.Tcl_GetStringFromObj( objv[2], 0 );
3570 //zFile = TCL.Tcl_TranslateFileName( interp, zFile, ref translatedFilename );
3571 sqlite3_open_v2( zFile, out p.db, flags, zVfs );
3572 //Tcl_DStringFree( ref translatedFilename );
3573 if ( SQLITE_OK != sqlite3_errcode( p.db ) )
3574 {
3575 zErrMsg = sqlite3_errmsg( p.db );// sqlite3_mprintf( "%s", sqlite3_errmsg( p.db ) );
3576 sqlite3_close( p.db );
3577 p.db = null;
3578 }
3579 #if SQLITE_HAS_CODEC
3580 if ( p.db != null )
3581 {
3582 sqlite3_key( p.db, pKey, nKey );
3583 }
3584 #endif
3585 if ( p.db == null )
3586 {
3587 TCL.Tcl_SetResult( interp, zErrMsg, TCL.TCL_VOLATILE );
3588 TCL.Tcl_Free( ref p );
3589 zErrMsg = "";// sqlite3DbFree( db, ref zErrMsg );
3590 return TCL.TCL_ERROR;
3591 }
3592 p.maxStmt = NUM_PREPARED_STMTS;
3593 p.interp = interp;
3594 zArg = TCL.Tcl_GetStringFromObj( objv[1], 0 );
3595 if ( DbUseNre() )
3596 {
3597 Debugger.Break();
3598 //Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd,
3599 // p, DbDeleteCmd);
3600 }
3601 else
3602 {
3603 TCL.Tcl_CreateObjCommand( interp, zArg, (Interp.dxObjCmdProc)DbObjCmd, p, (Interp.dxCmdDeleteProc)DbDeleteCmd );
3604 }
3605 return TCL.TCL_OK;
3606 }
3607  
3608 /*
3609 ** Provide a dummy TCL.Tcl_InitStubs if we are using this as a static
3610 ** library.
3611 */
3612 #if !USE_TCL_STUBS
3613 //# undef TCL.Tcl_InitStubs
3614 static void Tcl_InitStubs( Tcl_Interp interp, string s, int i )
3615 {
3616 }
3617 #endif
3618  
3619 /*
3620 ** Make sure we have a PACKAGE_VERSION macro defined. This will be
3621 ** defined automatically by the TEA makefile. But other makefiles
3622 ** do not define it.
3623 */
3624 #if !PACKAGE_VERSION
3625 public static string PACKAGE_VERSION;//# define PACKAGE_VERSION SQLITE_VERSION
3626 #endif
3627  
3628  
3629 /*
3630 ** Initialize this module.
3631 **
3632 ** This Tcl module contains only a single new Tcl command named "sqlite".
3633 ** (Hence there is no namespace. There is no point in using a namespace
3634 ** if the extension only supplies one new name!) The "sqlite" command is
3635 ** used to open a new SQLite database. See the DbMain() routine above
3636 ** for additional information.
3637 **
3638 ** The EXTERN macros are required by TCL in order to work on windows.
3639 */
3640 //int Sqlite3_Init(Tcl_Interp interp){
3641 static public int Sqlite3_Init( Tcl_Interp interp )
3642 {
3643 PACKAGE_VERSION = SQLITE_VERSION;
3644 Tcl_InitStubs( interp, "tclsharp 8.4", 0 );
3645 TCL.Tcl_CreateObjCommand( interp, "sqlite3", (Interp.dxObjCmdProc)DbMain, null, null );
3646 TCL.Tcl_PkgProvide( interp, "sqlite3", PACKAGE_VERSION );
3647  
3648 #if !SQLITE_3_SUFFIX_ONLY
3649 /* The "sqlite" alias is undocumented. It is here only to support
3650 ** legacy scripts. All new scripts should use only the "sqlite3"
3651 ** command.
3652 */
3653 TCL.Tcl_CreateObjCommand( interp, "sqlite", (Interp.dxObjCmdProc)DbMain, null, null );
3654 #endif
3655 return TCL.TCL_OK;
3656 }
3657 //int Tclsqlite3_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
3658 //int Sqlite3_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
3659 //int Tclsqlite3_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
3660 //int Sqlite3_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
3661 //int Tclsqlite3_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
3662 //int Sqlite3_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
3663 //int Tclsqlite3_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK;}
3664  
3665  
3666 #if !SQLITE_3_SUFFIX_ONLY
3667 //int Sqlite_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
3668 //int Tclsqlite_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
3669 //int Sqlite_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
3670 //int Tclsqlite_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
3671 //int Sqlite_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
3672 //int Tclsqlite_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
3673 //int Sqlite_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
3674 //int Tclsqlite_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK;}
3675 #endif
3676  
3677 #if TCLSH
3678 /*****************************************************************************
3679 ** All of the code that follows is used to build standalone TCL interpreters
3680 ** that are statically linked with SQLite. Enable these by compiling
3681 ** with -DTCLSH=n where n can be 1 or 2. An n of 1 generates a standard
3682 ** tclsh but with SQLite built in. An n of 2 generates the SQLite space
3683 ** analysis program.
3684 */
3685  
3686 #if (SQLITE_TEST) || (SQLITE_TCLMD5)
3687 /*
3688 * This code implements the MD5 message-digest algorithm.
3689 * The algorithm is due to Ron Rivest. This code was
3690 * written by Colin Plumb in 1993, no copyright is claimed.
3691 * This code is in the public domain; do with it what you wish.
3692 *
3693 * Equivalent code is available from RSA Data Security, Inc.
3694 * This code has been tested against that, and is equivalent,
3695 * except that you don't need to include two pages of legalese
3696 * with every copy.
3697 *
3698 * To compute the message digest of a chunk of bytes, declare an
3699 * MD5Context structure, pass it to MD5Init, call MD5Update as
3700 * needed on buffers full of bytes, and then call MD5Final, which
3701 * will fill a supplied 16-byte array with the digest.
3702 */
3703  
3704 /*
3705 * If compiled on a machine that doesn't have a 32-bit integer,
3706 * you just set "uint32" to the appropriate datatype for an
3707 * unsigned 32-bit integer. For example:
3708 *
3709 * cc -Duint32='unsigned long' md5.c
3710 *
3711 */
3712 //#if !uint32
3713 //# define uint32 unsigned int
3714 //#endif
3715  
3716 //struct MD5Context {
3717 // int isInit;
3718 // uint32 buf[4];
3719 // uint32 bits[2];
3720 // unsigned char in[64];
3721 //};
3722 //typedef struct MD5Context MD5Context;
3723 class MD5Context
3724 {
3725 public bool isInit;
3726 public u32[] buf = new u32[4];
3727 public u32[] bits = new u32[2];
3728 public u32[] _in = new u32[64];
3729 public Mem _Mem;
3730 };
3731  
3732 /*
3733 * Note: this code is harmless on little-endian machines.
3734 */
3735 //static void byteReverse (unsigned char *buf, unsigned longs){
3736 // uint32 t;
3737 // do {
3738 // t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
3739 // ((unsigned)buf[1]<<8 | buf[0]);
3740 // *(uint32 )buf = t;
3741 // buf += 4;
3742 // } while (--longs);
3743 //}
3744  
3745 /* The four core functions - F1 is optimized somewhat */
3746  
3747 delegate u32 dxF1234( u32 x, u32 y, u32 z );
3748  
3749 //* #define F1(x, y, z) (x & y | ~x & z) */
3750 //#define F1(x, y, z) (z ^ (x & (y ^ z)))
3751 static u32 F1( u32 x, u32 y, u32 z )
3752 {
3753 return ( z ^ ( x & ( y ^ z ) ) );
3754 }
3755  
3756 //#define F2(x, y, z) F1(z, x, y)
3757 static u32 F2( u32 x, u32 y, u32 z )
3758 {
3759 return F1( z, x, y );
3760 }
3761  
3762 //#define F3(x, y, z) (x ^ y ^ z)
3763 static u32 F3( u32 x, u32 y, u32 z )
3764 {
3765 return ( x ^ y ^ z );
3766 }
3767  
3768 //#define F4(x, y, z) (y ^ (x | ~z))
3769 static u32 F4( u32 x, u32 y, u32 z )
3770 {
3771 return ( y ^ ( x | ~z ) );
3772 }
3773  
3774 ///* This is the central step in the MD5 algorithm. */
3775 //#define MD5STEP(f, w, x, y, z, data, s) \
3776 // ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
3777 static void MD5STEP( dxF1234 f, ref u32 w, u32 x, u32 y, u32 z, u32 data, byte s )
3778 {
3779 w += f( x, y, z ) + data;
3780 w = w << s | w >> ( 32 - s );
3781 w += x;
3782 }
3783  
3784 /*
3785 * The core of the MD5 algorithm, this alters an existing MD5 hash to
3786 * reflect the addition of 16 longwords of new data. MD5Update blocks
3787 * the data and converts bytes into longwords for this routine.
3788 */
3789 static void MD5Transform( u32[] buf, u32[] _in )
3790 {
3791 u32 a, b, c, d;
3792  
3793 a = buf[0];
3794 b = buf[1];
3795 c = buf[2];
3796 d = buf[3];
3797  
3798 MD5STEP( F1, ref a, b, c, d, _in[0] + 0xd76aa478, 7 );
3799 MD5STEP( F1, ref d, a, b, c, _in[1] + 0xe8c7b756, 12 );
3800 MD5STEP( F1, ref c, d, a, b, _in[2] + 0x242070db, 17 );
3801 MD5STEP( F1, ref b, c, d, a, _in[3] + 0xc1bdceee, 22 );
3802 MD5STEP( F1, ref a, b, c, d, _in[4] + 0xf57c0faf, 7 );
3803 MD5STEP( F1, ref d, a, b, c, _in[5] + 0x4787c62a, 12 );
3804 MD5STEP( F1, ref c, d, a, b, _in[6] + 0xa8304613, 17 );
3805 MD5STEP( F1, ref b, c, d, a, _in[7] + 0xfd469501, 22 );
3806 MD5STEP( F1, ref a, b, c, d, _in[8] + 0x698098d8, 7 );
3807 MD5STEP( F1, ref d, a, b, c, _in[9] + 0x8b44f7af, 12 );
3808 MD5STEP( F1, ref c, d, a, b, _in[10] + 0xffff5bb1, 17 );
3809 MD5STEP( F1, ref b, c, d, a, _in[11] + 0x895cd7be, 22 );
3810 MD5STEP( F1, ref a, b, c, d, _in[12] + 0x6b901122, 7 );
3811 MD5STEP( F1, ref d, a, b, c, _in[13] + 0xfd987193, 12 );
3812 MD5STEP( F1, ref c, d, a, b, _in[14] + 0xa679438e, 17 );
3813 MD5STEP( F1, ref b, c, d, a, _in[15] + 0x49b40821, 22 );
3814  
3815 MD5STEP( F2, ref a, b, c, d, _in[1] + 0xf61e2562, 5 );
3816 MD5STEP( F2, ref d, a, b, c, _in[6] + 0xc040b340, 9 );
3817 MD5STEP( F2, ref c, d, a, b, _in[11] + 0x265e5a51, 14 );
3818 MD5STEP( F2, ref b, c, d, a, _in[0] + 0xe9b6c7aa, 20 );
3819 MD5STEP( F2, ref a, b, c, d, _in[5] + 0xd62f105d, 5 );
3820 MD5STEP( F2, ref d, a, b, c, _in[10] + 0x02441453, 9 );
3821 MD5STEP( F2, ref c, d, a, b, _in[15] + 0xd8a1e681, 14 );
3822 MD5STEP( F2, ref b, c, d, a, _in[4] + 0xe7d3fbc8, 20 );
3823 MD5STEP( F2, ref a, b, c, d, _in[9] + 0x21e1cde6, 5 );
3824 MD5STEP( F2, ref d, a, b, c, _in[14] + 0xc33707d6, 9 );
3825 MD5STEP( F2, ref c, d, a, b, _in[3] + 0xf4d50d87, 14 );
3826 MD5STEP( F2, ref b, c, d, a, _in[8] + 0x455a14ed, 20 );
3827 MD5STEP( F2, ref a, b, c, d, _in[13] + 0xa9e3e905, 5 );
3828 MD5STEP( F2, ref d, a, b, c, _in[2] + 0xfcefa3f8, 9 );
3829 MD5STEP( F2, ref c, d, a, b, _in[7] + 0x676f02d9, 14 );
3830 MD5STEP( F2, ref b, c, d, a, _in[12] + 0x8d2a4c8a, 20 );
3831  
3832 MD5STEP( F3, ref a, b, c, d, _in[5] + 0xfffa3942, 4 );
3833 MD5STEP( F3, ref d, a, b, c, _in[8] + 0x8771f681, 11 );
3834 MD5STEP( F3, ref c, d, a, b, _in[11] + 0x6d9d6122, 16 );
3835 MD5STEP( F3, ref b, c, d, a, _in[14] + 0xfde5380c, 23 );
3836 MD5STEP( F3, ref a, b, c, d, _in[1] + 0xa4beea44, 4 );
3837 MD5STEP( F3, ref d, a, b, c, _in[4] + 0x4bdecfa9, 11 );
3838 MD5STEP( F3, ref c, d, a, b, _in[7] + 0xf6bb4b60, 16 );
3839 MD5STEP( F3, ref b, c, d, a, _in[10] + 0xbebfbc70, 23 );
3840 MD5STEP( F3, ref a, b, c, d, _in[13] + 0x289b7ec6, 4 );
3841 MD5STEP( F3, ref d, a, b, c, _in[0] + 0xeaa127fa, 11 );
3842 MD5STEP( F3, ref c, d, a, b, _in[3] + 0xd4ef3085, 16 );
3843 MD5STEP( F3, ref b, c, d, a, _in[6] + 0x04881d05, 23 );
3844 MD5STEP( F3, ref a, b, c, d, _in[9] + 0xd9d4d039, 4 );
3845 MD5STEP( F3, ref d, a, b, c, _in[12] + 0xe6db99e5, 11 );
3846 MD5STEP( F3, ref c, d, a, b, _in[15] + 0x1fa27cf8, 16 );
3847 MD5STEP( F3, ref b, c, d, a, _in[2] + 0xc4ac5665, 23 );
3848  
3849 MD5STEP( F4, ref a, b, c, d, _in[0] + 0xf4292244, 6 );
3850 MD5STEP( F4, ref d, a, b, c, _in[7] + 0x432aff97, 10 );
3851 MD5STEP( F4, ref c, d, a, b, _in[14] + 0xab9423a7, 15 );
3852 MD5STEP( F4, ref b, c, d, a, _in[5] + 0xfc93a039, 21 );
3853 MD5STEP( F4, ref a, b, c, d, _in[12] + 0x655b59c3, 6 );
3854 MD5STEP( F4, ref d, a, b, c, _in[3] + 0x8f0ccc92, 10 );
3855 MD5STEP( F4, ref c, d, a, b, _in[10] + 0xffeff47d, 15 );
3856 MD5STEP( F4, ref b, c, d, a, _in[1] + 0x85845dd1, 21 );
3857 MD5STEP( F4, ref a, b, c, d, _in[8] + 0x6fa87e4f, 6 );
3858 MD5STEP( F4, ref d, a, b, c, _in[15] + 0xfe2ce6e0, 10 );
3859 MD5STEP( F4, ref c, d, a, b, _in[6] + 0xa3014314, 15 );
3860 MD5STEP( F4, ref b, c, d, a, _in[13] + 0x4e0811a1, 21 );
3861 MD5STEP( F4, ref a, b, c, d, _in[4] + 0xf7537e82, 6 );
3862 MD5STEP( F4, ref d, a, b, c, _in[11] + 0xbd3af235, 10 );
3863 MD5STEP( F4, ref c, d, a, b, _in[2] + 0x2ad7d2bb, 15 );
3864 MD5STEP( F4, ref b, c, d, a, _in[9] + 0xeb86d391, 21 );
3865  
3866 buf[0] += a;
3867 buf[1] += b;
3868 buf[2] += c;
3869 buf[3] += d;
3870 }
3871  
3872 /*
3873 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
3874 * initialization constants.
3875 */
3876 static void MD5Init( MD5Context ctx )
3877 {
3878 ctx.isInit = true;
3879 ctx.buf[0] = 0x67452301;
3880 ctx.buf[1] = 0xefcdab89;
3881 ctx.buf[2] = 0x98badcfe;
3882 ctx.buf[3] = 0x10325476;
3883 ctx.bits[0] = 0;
3884 ctx.bits[1] = 0;
3885 }
3886  
3887 /*
3888 * Update context to reflect the concatenation of another buffer full
3889 * of bytes.
3890 */
3891 static void MD5Update( MD5Context pCtx, byte[] buf, int len )
3892 {
3893  
3894 MD5Context ctx = (MD5Context)pCtx;
3895 int t;
3896  
3897 /* Update bitcount */
3898  
3899 t = (int)ctx.bits[0];
3900 if ( ( ctx.bits[0] = (u32)( t + ( (u32)len << 3 ) ) ) < t )
3901 ctx.bits[1]++; /* Carry from low to high */
3902 ctx.bits[1] += (u32)( len >> 29 );
3903  
3904 t = ( t >> 3 ) & 0x3f; /* Bytes already in shsInfo.data */
3905  
3906 /* Handle any leading odd-sized chunks */
3907  
3908 int _buf = 0; // Offset into buffer
3909 int p = t; //Offset into ctx._in
3910 if ( t != 0 )
3911 {
3912 //byte p = (byte)ctx._in + t;
3913 t = 64 - t;
3914 if ( len < t )
3915 {
3916 Buffer.BlockCopy( buf, _buf, ctx._in, p, len );// memcpy( p, buf, len );
3917 return;
3918 }
3919 Buffer.BlockCopy( buf, _buf, ctx._in, p, t ); //memcpy( p, buf, t );
3920 //byteReverse(ctx._in, 16);
3921 MD5Transform( ctx.buf, ctx._in );
3922 _buf += t;// buf += t;
3923 len -= t;
3924 }
3925  
3926 /* Process data in 64-byte chunks */
3927  
3928 while ( len >= 64 )
3929 {
3930 Buffer.BlockCopy( buf, _buf, ctx._in, 0, 64 );//memcpy( ctx._in, buf, 64 );
3931 //byteReverse(ctx._in, 16);
3932 MD5Transform( ctx.buf, ctx._in );
3933 _buf += 64;// buf += 64;
3934 len -= 64;
3935 }
3936  
3937 /* Handle any remaining bytes of data. */
3938  
3939 Buffer.BlockCopy( buf, _buf, ctx._in, 0, len ); //memcpy( ctx._in, buf, len );
3940 }
3941  
3942 /*
3943 * Final wrapup - pad to 64-byte boundary with the bit pattern
3944 * 1 0* (64-bit count of bits processed, MSB-first)
3945 */
3946  
3947 static void MD5Final( byte[] digest, MD5Context pCtx )
3948 {
3949 MD5Context ctx = pCtx;
3950 int count;
3951 int p;
3952  
3953 /* Compute number of bytes mod 64 */
3954 count = (int)( ctx.bits[0] >> 3 ) & 0x3F;
3955  
3956 /* Set the first char of padding to 0x80. This is safe since there is
3957 always at least one byte free */
3958 p = count;
3959 ctx._in[p++] = 0x80;
3960  
3961 /* Bytes of padding needed to make 64 bytes */
3962 count = 64 - 1 - count;
3963  
3964 /* Pad out to 56 mod 64 */
3965 if ( count < 8 )
3966 {
3967 /* Two lots of padding: Pad the first block to 64 bytes */
3968 Array.Clear( ctx._in, p, count );//memset(p, 0, count);
3969 //byteReverse( ctx._in, 16 );
3970 MD5Transform( ctx.buf, ctx._in );
3971  
3972 /* Now fill the next block with 56 bytes */
3973 Array.Clear( ctx._in, 0, 56 );//memset(ctx._in, 0, 56);
3974 }
3975 else
3976 {
3977 /* Pad block to 56 bytes */
3978 Array.Clear( ctx._in, p, count - 8 );//memset(p, 0, count-8);
3979 }
3980 //byteReverse( ctx._in, 14 );
3981  
3982 /* Append length in bits and transform */
3983 ctx._in[14] = (byte)ctx.bits[0];
3984 ctx._in[15] = (byte)ctx.bits[1];
3985  
3986 MD5Transform( ctx.buf, ctx._in );
3987 //byteReverse( ctx.buf, 4 );
3988 Buffer.BlockCopy( ctx.buf, 0, digest, 0, 16 );//memcpy(digest, ctx.buf, 16);
3989 //memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */
3990 Array.Clear( ctx._in, 0, ctx._in.Length );
3991 Array.Clear( ctx.bits, 0, ctx.bits.Length );
3992 Array.Clear( ctx.buf, 0, ctx.buf.Length );
3993 ctx._Mem = null;
3994 }
3995  
3996 /*
3997 ** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
3998 */
3999 static void DigestToBase16( byte[] digest, byte[] zBuf )
4000 {
4001 string zEncode = "0123456789abcdef";
4002 int i, j;
4003  
4004 for ( j = i = 0; i < 16; i++ )
4005 {
4006 int a = digest[i];
4007 zBuf[j++] = (byte)zEncode[( a >> 4 ) & 0xf];
4008 zBuf[j++] = (byte)zEncode[a & 0xf];
4009 }
4010 if ( j < zBuf.Length )
4011 zBuf[j] = 0;
4012 }
4013  
4014  
4015 /*
4016 ** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
4017 ** each representing 16 bits of the digest and separated from each
4018 ** other by a "-" character.
4019 */
4020 //static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
4021 // int i, j;
4022 // unsigned int x;
4023 // for(i=j=0; i<16; i+=2){
4024 // x = digest[i]*256 + digest[i+1];
4025 // if( i>0 ) zDigest[j++] = '-';
4026 // sprintf(&zDigest[j], "%05u", x);
4027 // j += 5;
4028 // }
4029 // zDigest[j] = 0;
4030 //}
4031  
4032 /*
4033 ** A TCL command for md5. The argument is the text to be hashed. The
4034 ** Result is the hash in base64.
4035 */
4036 static int md5_cmd( object cd, Tcl_Interp interp, int argc, Tcl_Obj[] argv )
4037 {
4038 MD5Context ctx = new MD5Context();
4039 byte[] digest = new byte[16];
4040 byte[] zBuf = new byte[32];
4041  
4042  
4043 if ( argc != 2 )
4044 {
4045 TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
4046 " TEXT\"" );
4047 return TCL.TCL_ERROR;
4048 }
4049 MD5Init( ctx );
4050 MD5Update( ctx, Encoding.UTF8.GetBytes( argv[1].ToString() ), Encoding.UTF8.GetByteCount( argv[1].ToString() ) );
4051 MD5Final( digest, ctx );
4052 DigestToBase16( digest, zBuf );
4053 TCL.Tcl_AppendResult( interp, Encoding.UTF8.GetString( zBuf, 0, zBuf.Length ) );
4054 return TCL.TCL_OK;
4055 }
4056  
4057  
4058 /*
4059 ** A TCL command to take the md5 hash of a file. The argument is the
4060 ** name of the file.
4061 */
4062 static int md5file_cmd( object cd, Tcl_Interp interp, int argc, Tcl_Obj[] argv )
4063 {
4064 StreamReader _in = null;
4065 byte[] digest = new byte[16];
4066 StringBuilder zBuf = new StringBuilder( 10240 );
4067  
4068 if ( argc != 2 )
4069 {
4070 TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
4071 " FILENAME\"", 0 );
4072 return TCL.TCL_ERROR;
4073 }
4074 Debugger.Break(); // TODO -- _in = fopen( argv[1], "rb" );
4075 if ( _in == null )
4076 {
4077 TCL.Tcl_AppendResult( interp, "unable to open file \"", argv[1],
4078 "\" for reading", 0 );
4079 return TCL.TCL_ERROR;
4080 }
4081 Debugger.Break(); // TODO
4082 //MD5Init( ctx );
4083 //for(;;){
4084 // int n;
4085 // n = fread(zBuf, 1, zBuf.Capacity, _in);
4086 // if( n<=0 ) break;
4087 // MD5Update(ctx, zBuf.ToString(), (unsigned)n);
4088 //}
4089 //fclose(_in);
4090 //MD5Final(digest, ctx);
4091 // DigestToBase16(digest, zBuf);
4092 //Tcl_AppendResult( interp, zBuf );
4093 return TCL.TCL_OK;
4094 }
4095  
4096 /*
4097 ** Register the four new TCL commands for generating MD5 checksums
4098 ** with the TCL interpreter.
4099 */
4100 static public int Md5_Init( Tcl_Interp interp )
4101 {
4102 TCL.Tcl_CreateCommand( interp, "md5", md5_cmd, null, null );
4103 //Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc)md5_cmd,
4104 // MD5DigestToBase10x8, 0);
4105  
4106 TCL.Tcl_CreateCommand( interp, "md5file", md5file_cmd, null, null );
4107  
4108 //Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc)md5file_cmd,
4109 // MD5DigestToBase10x8, 0);
4110 return TCL.TCL_OK;
4111 }
4112 #endif //* defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) */
4113  
4114 #if (SQLITE_TEST)
4115 /*
4116 ** During testing, the special md5sum() aggregate function is available.
4117 ** inside SQLite. The following routines implement that function.
4118 */
4119 static void md5step( sqlite3_context context, int argc, sqlite3_value[] argv )
4120 {
4121 MD5Context p = null;
4122 int i;
4123 if ( argc < 1 )
4124 return;
4125 Mem pMem = sqlite3_aggregate_context( context, 1 );//sizeof(*p));
4126 if ( pMem._MD5Context == null )
4127 {
4128 pMem._MD5Context = new MD5Context();
4129 ( (MD5Context)pMem._MD5Context )._Mem = pMem;
4130 }
4131 p = (MD5Context)pMem._MD5Context;
4132 if ( p == null )
4133 return;
4134 if ( !p.isInit )
4135 {
4136 MD5Init( p );
4137 }
4138 for ( i = 0; i < argc; i++ )
4139 {
4140 byte[] zData = sqlite3_value_text( argv[i] ) == null ? null : Encoding.UTF8.GetBytes( sqlite3_value_text( argv[i] ) );
4141 if ( zData != null )
4142 {
4143 MD5Update( p, zData, zData.Length );
4144 }
4145 }
4146 }
4147  
4148 static void md5finalize( sqlite3_context context )
4149 {
4150 MD5Context p;
4151 byte[] digest = new byte[16];
4152 byte[] zBuf = new byte[33];
4153 Mem pMem = sqlite3_aggregate_context( context, 0 );
4154 if ( pMem != null )
4155 {
4156 p = (MD5Context)pMem._MD5Context;
4157 MD5Final( digest, p );
4158 }
4159 DigestToBase16( digest, zBuf );
4160 sqlite3_result_text( context, Encoding.UTF8.GetString( zBuf, 0, zBuf.Length ), -1, SQLITE_TRANSIENT );
4161 }
4162  
4163 static int Md5_Register( sqlite3 db, ref string dummy1, sqlite3_api_routines dummy2 )
4164 {
4165 int rc = sqlite3_create_function( db, "md5sum", -1, SQLITE_UTF8, 0, null,
4166 md5step, md5finalize );
4167 sqlite3_overload_function( db, "md5sum", -1 ); /* To exercise this API */
4168 return rc;
4169 }
4170  
4171 #endif //* defined(SQLITE_TEST) */
4172  
4173  
4174 /*
4175 ** If the macro TCLSH is one, then put in code this for the
4176 ** "main" routine that will initialize Tcl and take input from
4177 ** standard input, or if a file is named on the command line
4178 ** the TCL interpreter reads and evaluates that file.
4179 */
4180 #if TCLSH//==1
4181 //static char zMainloop[] =
4182 // "set line {}\n"
4183 // "while {![eof stdin]} {\n"
4184 // "if {$line!=\"\"} {\n"
4185 // "puts -nonewline \"> \"\n"
4186 // "} else {\n"
4187 // "puts -nonewline \"% \"\n"
4188 // "}\n"
4189 // "flush stdout\n"
4190 // "append line [gets stdin]\n"
4191 // "if {[info complete $line]} {\n"
4192 // "if {[catch {uplevel #0 $line} result]} {\n"
4193 // "puts stderr \"Error: $result\"\n"
4194 // "} elseif {$result!=\"\"} {\n"
4195 // "puts $result\n"
4196 // "}\n"
4197 // "set line {}\n"
4198 // "} else {\n"
4199 // "append line \\n\n"
4200 // "}\n"
4201 // "}\n"
4202 //;
4203 #endif
4204  
4205 //#if TCLSH==2
4206 //static char zMainloop[] =
4207 //#include "spaceanal_tcl.h"
4208 //;
4209 //#endif
4210 //#define TCLSH_MAIN main /* Needed to fake out mktclapp */
4211 #if SQLITE_TEST
4212 //static void init_all(Tcl_Interp );
4213 static int init_all_cmd(
4214 ClientData cd,
4215 Tcl_Interp interp,
4216 int objc,
4217 Tcl_Obj[] objv
4218 )
4219 {
4220  
4221 Tcl_Interp slave;
4222 if ( objc != 2 )
4223 {
4224 TCL.Tcl_WrongNumArgs( interp, 1, objv, "SLAVE" );
4225 return TCL.TCL_ERROR;
4226 }
4227  
4228 slave = null;// TCL.Tcl_GetSlave( interp, TCL.Tcl_GetString( objv[1] ) );
4229 if ( slave == null )
4230 {
4231 return TCL.TCL_ERROR;
4232 }
4233  
4234 init_all( slave );
4235 return TCL.TCL_OK;
4236 }
4237 #endif
4238  
4239 /*
4240 ** Configure the interpreter passed as the first argument to have access
4241 ** to the commands and linked variables that make up:
4242 **
4243 ** * the [sqlite3] extension itself,
4244 **
4245 ** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
4246 **
4247 ** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
4248 ** test suite.
4249 */
4250 static void init_all( Tcl_Interp interp )
4251 {
4252 Sqlite3_Init( interp );
4253 #if (SQLITE_TEST) || (SQLITE_TCLMD5)
4254 Md5_Init( interp );
4255 #endif
4256 #if SQLITE_TEST
4257 //{
4258 //extern int Sqliteconfig_Init(Tcl_Interp);
4259 //extern int Sqlitetest1_Init(Tcl_Interp);
4260 //extern int Sqlitetest2_Init(Tcl_Interp);
4261 //extern int Sqlitetest3_Init(Tcl_Interp);
4262 //extern int Sqlitetest4_Init(Tcl_Interp);
4263 //extern int Sqlitetest5_Init(Tcl_Interp);
4264 //extern int Sqlitetest6_Init(Tcl_Interp);
4265 //extern int Sqlitetest7_Init(Tcl_Interp);
4266 //extern int Sqlitetest8_Init(Tcl_Interp);
4267 //extern int Sqlitetest9_Init(Tcl_Interp);
4268 //extern int Sqlitetestasync_Init(Tcl_Interp);
4269 //extern int Sqlitetest_autoext_Init(Tcl_Interp);
4270 //extern int Sqlitetest_demovfs_Init(Tcl_Interp );
4271 //extern int Sqlitetest_func_Init(Tcl_Interp);
4272 //extern int Sqlitetest_hexio_Init(Tcl_Interp);
4273 //extern int Sqlitetest_malloc_Init(Tcl_Interp);
4274 //extern int Sqlitetest_mutex_Init(Tcl_Interp);
4275 //extern int Sqlitetestschema_Init(Tcl_Interp);
4276 //extern int Sqlitetestsse_Init(Tcl_Interp);
4277 //extern int Sqlitetesttclvar_Init(Tcl_Interp);
4278 //extern int SqlitetestThread_Init(Tcl_Interp);
4279 //extern int SqlitetestOnefile_Init();
4280 //extern int SqlitetestOsinst_Init(Tcl_Interp);
4281 //extern int Sqlitetestbackup_Init(Tcl_Interp);
4282 //extern int Sqlitetestintarray_Init(Tcl_Interp);
4283 //extern int Sqlitetestvfs_Init(Tcl_Interp );
4284 //extern int SqlitetestStat_Init(Tcl_Interp);
4285 //extern int Sqlitetestrtree_Init(Tcl_Interp);
4286 //extern int Sqlitequota_Init(Tcl_Interp);
4287 //extern int Sqlitemultiplex_Init(Tcl_Interp);
4288 //extern int SqliteSuperlock_Init(Tcl_Interp);
4289 //extern int SqlitetestSyscall_Init(Tcl_Interp);
4290 //extern int Sqlitetestfuzzer_Init(Tcl_Interp);
4291 //extern int Sqlitetestwholenumber_Init(Tcl_Interp);
4292  
4293 #if (SQLITE_ENABLE_FTS3) || (SQLITE_ENABLE_FTS4)
4294 //extern int Sqlitetestfts3_Init(Tcl_Interp interp);
4295 #endif
4296  
4297 #if SQLITE_ENABLE_ZIPVFS
4298 // extern int Zipvfs_Init(Tcl_Interp);
4299 // Zipvfs_Init(interp);
4300 #endif
4301  
4302 Sqliteconfig_Init( interp );
4303 Sqlitetest1_Init( interp );
4304 Sqlitetest2_Init( interp );
4305 Sqlitetest3_Init( interp );
4306  
4307 //Threads not implemented under C#
4308 //Sqlitetest4_Init(interp);
4309  
4310 //TODO implemented under C#
4311 //Sqlitetest5_Init(interp);
4312  
4313 //Simulated Crashtests not implemented under C#
4314 //Sqlitetest6_Init(interp);
4315  
4316 //client/server version (Unix Only) not implemented under C#
4317 //Sqlitetest7_Init(interp);
4318  
4319 //virtual table interface not implemented under C#
4320 //Sqlitetest8_Init(interp);
4321  
4322 Sqlitetest9_Init( interp );
4323  
4324 //asynchronous IO extension interface not implemented under C#
4325 //Sqlitetestasync_Init(interp);
4326  
4327 //sqlite3_auto_extension() function not implemented under C#
4328 //Sqlitetest_autoext_Init(interp);
4329  
4330 //VFS not implemented under C#
4331 //Sqlitetest_demovfs_Init(interp);
4332  
4333 Sqlitetest_func_Init( interp );
4334 Sqlitetest_hexio_Init( interp );
4335 Sqlitetest_malloc_Init( interp );
4336 Sqlitetest_mutex_Init( interp );
4337  
4338 //virtual table interfaces not implemented under C#
4339 //Sqlitetestschema_Init(interp);
4340  
4341 //virtual table interfaces not implemented under C#
4342 //Sqlitetesttclvar_Init(interp);
4343  
4344 //Threads not implemented under C#
4345 //SqlitetestThread_Init(interp);
4346  
4347 //VFS not implemented under C#
4348 //SqlitetestOnefile_Init(interp);
4349  
4350 //VFS not implemented under C#
4351 //SqlitetestOsinst_Init(interp);
4352  
4353 Sqlitetestbackup_Init( interp );
4354  
4355 //virtual table interfaces not implemented under C#
4356 //Sqlitetestintarray_Init(interp);
4357  
4358 //VFS not implemented under C#
4359 //Sqlitetestvfs_Init(interp);
4360  
4361 //virtual table interfaces not implemented under C#
4362 //SqlitetestStat_Init(interp);
4363 //Sqlitetestrtree_Init( interp );
4364 //Sqlitequota_Init( interp );
4365 //Sqlitemultiplex_Init( interp );
4366 //SqliteSuperlock_Init( interp );
4367 //SqlitetestSyscall_Init( interp );
4368 Sqlitetestfuzzer_Init( interp );
4369 //Sqlitetestwholenumber_Init( interp );
4370  
4371 #if (SQLITE_ENABLE_FTS3) || (SQLITE_ENABLE_FTS4)
4372 //Sqlitetestfts3_Init(interp);
4373 #endif
4374 TCL.Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, null );
4375  
4376 #if SQLITE_SSE
4377 Sqlitetestsse_Init(interp);
4378 #endif
4379 }
4380 #endif
4381 }
4382  
4383 #if FALSE
4384 //#define TCLSH_MAIN main /* Needed to fake out mktclapp */
4385 int TCLSH_MAIN(int argc, char **argv){
4386 Tcl_Interp interp;
4387  
4388 /* Call sqlite3_shutdown() once before doing anything else. This is to
4389 ** test that sqlite3_shutdown() can be safely called by a process before
4390 ** sqlite3_initialize() is. */
4391 sqlite3_shutdown();
4392  
4393 #if TCLSH//TCLSH==2
4394 sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
4395 #endif
4396 Tcl_FindExecutable(argv[0]);
4397  
4398 interp = TCL.Tcl_CreateInterp();
4399 init_all(interp);
4400 if( argc>=2 ){
4401 int i;
4402 char zArgc[32];
4403 sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
4404 Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
4405 Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
4406 Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
4407 for(i=3-TCLSH; i<argc; i++){
4408 Tcl_SetVar(interp, "argv", argv[i],
4409 TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
4410 }
4411 if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
4412 string zInfo = TCL.Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
4413 if( zInfo==0 ) zInfo = TCL.Tcl_GetStringResult(interp);
4414 fprintf(stderr,"%s: %s\n", *argv, zInfo);
4415 return 1;
4416 }
4417 }
4418 if( TCLSH==2 || argc<=1 ){
4419 Tcl_GlobalEval(interp, zMainloop);
4420 }
4421 return 0;
4422 }
4423 #endif
4424 #endif // * TCLSH */
4425 #endif // NO_TCL
4426 }
4427