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 System.Text;
4  
5 using u8 = System.Byte;
6 using u32 = System.UInt32;
7  
8 namespace Community.CsharpSqlite
9 {
10 #if TCLSH
11 using tcl.lang;
12 using sqlite_int64 = System.Int64;
13 using sqlite3_int64 = System.Int64;
14 using sqlite3_stmt = Community.CsharpSqlite.Sqlite3.Vdbe;
15 using Tcl_Interp = tcl.lang.Interp;
16 using Tcl_Obj = tcl.lang.TclObject;
17 using ClientData = System.Object;
18  
19 public partial class Sqlite3
20 {
21 /*
22 ** 2010 May 05
23 **
24 ** The author disclaims copyright to this source code. In place of
25 ** a legal notice, here is a blessing:
26 **
27 ** May you do good and not evil.
28 ** May you find forgiveness for yourself and forgive others.
29 ** May you share freely, never taking more than you give.
30 **
31 ******************************************************************************
32 **
33 ** This file contains the implementation of the Tcl [testvfs] command,
34 ** used to create SQLite VFS implementations with various properties and
35 ** instrumentation to support testing SQLite.
36 **
37 ** testvfs VFSNAME ?OPTIONS?
38 **
39 ** Available options are:
40 **
41 ** -noshm BOOLEAN (True to omit shm methods. Default false)
42 ** -default BOOLEAN (True to make the vfs default. Default false)
43 ** -szosfile INTEGER (Value for sqlite3_vfs.szOsFile)
44 ** -mxpathname INTEGER (Value for sqlite3_vfs.mxPathname)
45 ** -iversion INTEGER (Value for sqlite3_vfs.iVersion)
46 */
47 #if SQLITE_TEST //* This file is used for testing only */
48  
49 //#include "sqlite3.h"
50 //#include "sqliteInt.h"
51  
52 //typedef struct Testvfs Testvfs;
53 //typedef struct TestvfsShm TestvfsShm;
54 //typedef struct TestvfsBuffer TestvfsBuffer;
55 //typedef struct TestvfsFile TestvfsFile;
56 //typedef struct TestvfsFd TestvfsFd;
57  
58 /*
59 ** An open file handle.
60 */
61 class TestvfsFile : sqlite3_file
62 {
63 //public sqlite3_file base; /* Base class. Must be first */
64 public TestvfsFd pFd; /* File data */
65 };
66 //#define tvfsGetFd(pFile) (((TestvfsFile )pFile)->pFd)
67 static TestvfsFd tvfsGetFd( sqlite3_file pFile )
68 {
69 return ((TestvfsFile)pFile).pFd;
70 }
71  
72 class TestvfsFd {
73 public sqlite3_vfs pVfs; /* The VFS */
74 public string zFilename; /* Filename as passed to xOpen() */
75 public sqlite3_file pReal; /* The real, underlying file descriptor */
76 public Tcl_Obj pShmId; /* Shared memory id for Tcl callbacks */
77  
78 public TestvfsBuffer pShm; /* Shared memory buffer */
79 public u32 excllock; /* Mask of exclusive locks */
80 public u32 sharedlock; /* Mask of shared locks */
81 public TestvfsFd pNext; /* Next handle opened on the same file */
82 };
83  
84  
85 //#define FAULT_INJECT_NONE 0
86 //#define FAULT_INJECT_TRANSIENT 1
87 //#define FAULT_INJECT_PERSISTENT 2
88 const int FAULT_INJECT_NONE = 0;
89 const int FAULT_INJECT_TRANSIENT = 1;
90 const int FAULT_INJECT_PERSISTENT = 2;
91  
92 //typedef struct TestFaultInject TestFaultInject;
93 class TestFaultInject {
94 public int iCnt; /* Remaining calls before fault injection */
95 public int eFault; /* A FAULT_INJECT_* value */
96 public int nFail; /* Number of faults injected */
97 };
98  
99 /*
100 ** An instance of this structure is allocated for each VFS created. The
101 ** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite
102 ** is set to point to it.
103 */
104 class Testvfs {
105 public string zName; /* Name of this VFS */
106 public sqlite3_vfs pParent; /* The VFS to use for file IO */
107 public sqlite3_vfs pVfs; /* The testvfs registered with SQLite */
108 public Tcl_Interp interp; /* Interpreter to run script in */
109 public Tcl_Obj pScript; /* Script to execute */
110 public TestvfsBuffer pBuffer; /* List of shared buffers */
111 public int isNoshm;
112  
113 public int mask; /* Mask controlling [script] and [ioerr] */
114  
115 public TestFaultInject ioerr_err;
116 public TestFaultInject full_err;
117 public TestFaultInject cantopen_err;
118  
119 #if FALSE
120 public int iIoerrCnt;
121 public int ioerr;
122 public int nIoerrFail;
123 public int iFullCnt;
124 public int fullerr;
125 public int nFullFail;
126 #endif
127  
128 public int iDevchar;
129 public int iSectorsize;
130 };
131  
132 /*
133 ** The Testvfs.mask variable is set to a combination of the following.
134 ** If a bit is clear in Testvfs.mask, then calls made by SQLite to the
135 ** corresponding VFS method is ignored for purposes of:
136 **
137 ** + Simulating IO errors, and
138 ** + Invoking the Tcl callback script.
139 */
140 //#define TESTVFS_SHMOPEN_MASK 0x00000001
141 //#define TESTVFS_SHMLOCK_MASK 0x00000010
142 //#define TESTVFS_SHMMAP_MASK 0x00000020
143 //#define TESTVFS_SHMBARRIER_MASK 0x00000040
144 //#define TESTVFS_SHMCLOSE_MASK 0x00000080
145 const int TESTVFS_SHMOPEN_MASK =0x00000001;
146 const int TESTVFS_SHMLOCK_MASK =0x00000010;
147 const int TESTVFS_SHMMAP_MASK =0x00000020;
148 const int TESTVFS_SHMBARRIER_MASK =0x00000040;
149 const int TESTVFS_SHMCLOSE_MASK =0x00000080;
150  
151 //#define TESTVFS_OPEN_MASK 0x00000100
152 //#define TESTVFS_SYNC_MASK 0x00000200
153 //#define TESTVFS_DELETE_MASK 0x00000400
154 //#define TESTVFS_CLOSE_MASK 0x00000800
155 //#define TESTVFS_WRITE_MASK 0x00001000
156 //#define TESTVFS_TRUNCATE_MASK 0x00002000
157 //#define TESTVFS_ACCESS_MASK 0x00004000
158 //#define TESTVFS_FULLPATHNAME_MASK 0x00008000
159 //#define TESTVFS_ALL_MASK 0x0001FFFF
160 const int TESTVFS_OPEN_MASK =0x00000100;
161 const int TESTVFS_SYNC_MASK =0x00000200;
162 const int TESTVFS_DELETE_MASK =0x00000400;
163 const int TESTVFS_CLOSE_MASK =0x00000800;
164 const int TESTVFS_WRITE_MASK =0x00001000;
165 const int TESTVFS_TRUNCATE_MASK =0x00002000;
166 const int TESTVFS_ACCESS_MASK =0x00004000;
167 const int TESTVFS_FULLPATHNAME_MASK =0x00008000;
168 const int TESTVFS_ALL_MASK =0x0001FFFF;
169  
170 //#define TESTVFS_MAX_PAGES 1024
171 const int TESTVFS_MAX_PAGES =1024;
172  
173 /*
174 ** A shared-memory buffer. There is one of these objects for each shared
175 ** memory region opened by clients. If two clients open the same file,
176 ** there are two TestvfsFile structures but only one TestvfsBuffer structure.
177 */
178 class TestvfsBuffer {
179 public string zFile; /* Associated file name */
180 public int pgsz; /* Page size */
181 public u8[] aPage = new u8[TESTVFS_MAX_PAGES]; /* Array of ckalloc'd pages */
182 public TestvfsFd pFile; /* List of open handles */
183 public TestvfsBuffer pNext; /* Next in linked list of all buffers */
184 };
185  
186  
187 //#define PARENTVFS(x) (((Testvfs )((x)->pAppData))->pParent)
188 static sqlite3_vfs PARENTVFS( sqlite3_vfs x )
189 {
190 return ( (Testvfs)x.pAppData ).pParent;
191 }
192  
193 //#define TESTVFS_MAX_ARGS 12
194 const int TESTVFS_MAX_ARGS =12;
195  
196  
197 /*
198 ** Method declarations for TestvfsFile.
199 */
200 //static int tvfsClose(sqlite3_file);
201 //static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
202 //static int tvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
203 //static int tvfsTruncate(sqlite3_file*, sqlite3_int64 size);
204 //static int tvfsSync(sqlite3_file*, int flags);
205 //static int tvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
206 //static int tvfsLock(sqlite3_file*, int);
207 //static int tvfsUnlock(sqlite3_file*, int);
208 //static int tvfsCheckReservedLock(sqlite3_file*, int );
209 //static int tvfsFileControl(sqlite3_file*, int op, object *pArg);
210 //static int tvfsSectorSize(sqlite3_file);
211 //static int tvfsDeviceCharacteristics(sqlite3_file);
212  
213 ///*
214 //** Method declarations for tvfs_vfs.
215 //*/
216 //static int tvfsOpen(sqlite3_vfs*, string , sqlite3_file*, int , int );
217 //static int tvfsDelete(sqlite3_vfs*, string zName, int syncDir);
218 //static int tvfsAccess(sqlite3_vfs*, string zName, int flags, int );
219 //static int tvfsFullPathname(sqlite3_vfs*, string zName, int, string zOut);
220 //#if !SQLITE_OMIT_LOAD_EXTENSION
221 //static void tvfsDlOpen(sqlite3_vfs*, string zFilename);
222 //static void tvfsDlError(sqlite3_vfs*, int nByte, string zErrMsg);
223 //static void (*tvfsDlSym(sqlite3_vfs*,void*, string zSymbol))(void);
224 //static void tvfsDlClose(sqlite3_vfs*, void);
225 //#endif //* SQLITE_OMIT_LOAD_EXTENSION */
226 //static int tvfsRandomness(sqlite3_vfs*, int nByte, string zOut);
227 //static int tvfsSleep(sqlite3_vfs*, int microseconds);
228 //static int tvfsCurrentTime(sqlite3_vfs*, double);
229  
230 //static int tvfsShmOpen(sqlite3_file);
231 //static int tvfsShmLock(sqlite3_file*, int , int, int);
232 //static int tvfsShmMap(sqlite3_file*,int,int,int, object volatile *);
233 //static void tvfsShmBarrier(sqlite3_file);
234 //static int tvfsShmUnmap(sqlite3_file*, int);
235  
236 static sqlite3_io_methods tvfs_io_methods = new sqlite3_io_methods(
237 2, /* iVersion */
238 tvfsClose, /* xClose */
239 tvfsRead, /* xRead */
240 tvfsWrite, /* xWrite */
241 tvfsTruncate, /* xTruncate */
242 tvfsSync, /* xSync */
243 tvfsFileSize, /* xFileSize */
244 tvfsLock, /* xLock */
245 tvfsUnlock, /* xUnlock */
246 tvfsCheckReservedLock, /* xCheckReservedLock */
247 tvfsFileControl, /* xFileControl */
248 tvfsSectorSize, /* xSectorSize */
249 tvfsDeviceCharacteristics, /* xDeviceCharacteristics */
250 tvfsShmMap, /* xShmMap */
251 tvfsShmLock, /* xShmLock */
252 tvfsShmBarrier, /* xShmBarrier */
253 tvfsShmUnmap /* xShmUnmap */
254 );
255  
256 class errcode {
257 public int eCode;
258 public string zCode;
259  
260 public errcode(int eCode, string zCode){
261 this.eCode=eCode;this.zCode=zCode;
262 }
263 }
264 static int tvfsResultCode(Testvfs p, ref int pRc){
265 errcode[] aCode = new errcode[] {
266 new errcode( SQLITE_OK, "SQLITE_OK" ),
267 new errcode( SQLITE_ERROR, "SQLITE_ERROR" ),
268 new errcode( SQLITE_IOERR, "SQLITE_IOERR" ),
269 new errcode( SQLITE_LOCKED, "SQLITE_LOCKED" ),
270 new errcode( SQLITE_BUSY, "SQLITE_BUSY" )
271 };
272  
273 string z;
274 int i;
275  
276 z = TCL.Tcl_GetStringResult(p.interp);
277 for(i=0; i<ArraySize(aCode); i++){
278 if ( 0 == z.CompareTo( aCode[i].zCode ) )
279 {
280 pRc = aCode[i].eCode;
281 return 1;
282 }
283 }
284  
285 return 0;
286 }
287  
288 static int tvfsInjectFault(TestFaultInject p){
289 int ret = 0;
290 if ( p.eFault != 0 )
291 {
292 p.iCnt--;
293 if( p.iCnt==0 || (p.iCnt<0 && p.eFault==FAULT_INJECT_PERSISTENT ) ){
294 ret = 1;
295 p.nFail++;
296 }
297 }
298 return ret;
299 }
300  
301  
302 static int tvfsInjectIoerr(Testvfs p){
303 return tvfsInjectFault(p.ioerr_err);
304 }
305  
306 static int tvfsInjectFullerr(Testvfs p){
307 return tvfsInjectFault(p.full_err);
308 }
309 static int tvfsInjectCantopenerr(Testvfs p){
310 return tvfsInjectFault(p.cantopen_err);
311 }
312  
313  
314 static void tvfsExecTcl(
315 Testvfs p,
316 string zMethod,
317 Tcl_Obj arg1,
318 Tcl_Obj arg2,
319 Tcl_Obj arg3
320 ){
321 int rc; /* Return code from Tcl_EvalObj() */
322 Tcl_Obj pEval;
323 Debug.Assert( p.pScript!=null );
324  
325 Debug.Assert( zMethod != null );
326 Debug.Assert( p != null );
327 Debug.Assert( arg2 == null || arg1 != null );
328 Debug.Assert( arg3 == null || arg2 != null );
329  
330 pEval = TCL.Tcl_DuplicateObj(p.pScript);
331 TCL.Tcl_IncrRefCount(p.pScript);
332 TCL.Tcl_ListObjAppendElement( p.interp, pEval, TCL.Tcl_NewStringObj( zMethod, -1 ) );
333 if ( arg1!=null )
334 TCL.Tcl_ListObjAppendElement( p.interp, pEval, arg1 );
335 if ( arg2 !=null )
336 TCL.Tcl_ListObjAppendElement( p.interp, pEval, arg2 );
337 if ( arg3 != null )
338 TCL.Tcl_ListObjAppendElement( p.interp, pEval, arg3 );
339  
340 rc = TCL.Tcl_EvalObjEx(p.interp, pEval, TCL.TCL_EVAL_GLOBAL);
341 if ( rc != TCL.TCL_OK )
342 {
343 TCL.Tcl_BackgroundError( p.interp );
344 TCL.Tcl_ResetResult( p.interp );
345 }
346 }
347  
348  
349 /*
350 ** Close an tvfs-file.
351 */
352 static int tvfsClose(sqlite3_file pFile){
353 int rc=0;
354 TestvfsFile pTestfile = (TestvfsFile )pFile;
355 TestvfsFd pFd = pTestfile.pFd;
356 Testvfs p = (Testvfs )pFd.pVfs.pAppData;
357  
358 Debugger.Break(); //TODO
359 //if( p.pScript != null && (p.mask&TESTVFS_CLOSE_MASK)!=0 ){
360 // tvfsExecTcl(p, "xClose",
361 // Tcl_NewStringObj(pFd.zFilename, -1), pFd.pShmId, 0
362 // );
363 //}
364  
365 //if( pFd.pShmId != null){
366 // Tcl_DecrRefCount(pFd.pShmId);
367 // pFd.pShmId = null;
368 //}
369 //if ( pFile.pMethods != null )
370 //{
371 // ckfree((char )pFile.pMethods);
372 //}
373 //rc = sqlite3OsClose(pFd.pReal);
374 //ckfree((char )pFd);
375 //pTestfile.pFd = null;
376 return rc;
377 }
378  
379 /*
380 ** Read data from an tvfs-file.
381 */
382 static int tvfsRead(
383 sqlite3_file pFile,
384 byte[] zBuf,
385 int iAmt,
386 sqlite_int64 iOfst
387 ){
388 TestvfsFd p = tvfsGetFd(pFile);
389 return sqlite3OsRead(p.pReal, zBuf, iAmt, iOfst);
390 }
391  
392 /*
393 ** Write data to an tvfs-file.
394 */
395 static int tvfsWrite(
396 sqlite3_file pFile,
397 byte[] zBuf,
398 int iAmt,
399 sqlite_int64 iOfst
400 ){
401 int rc = SQLITE_OK;
402 Debugger.Break();//TODO
403 //TestvfsFd pFd = tvfsGetFd(pFile);
404 //Testvfs p = (Testvfs )pFd.pVfs.pAppData;
405  
406 //if ( p.pScript != null && (p.mask & TESTVFS_WRITE_MASK) != 0 )
407 //{
408 // tvfsExecTcl(p, "xWrite",
409 // TCL.Tcl_NewStringObj(pFd.zFilename, -1), pFd.pShmId, null
410 // );
411 // tvfsResultCode(p, ref rc);
412 //}
413  
414 //if( rc==SQLITE_OK && tvfsInjectFullerr(p)!=0 ){
415 // rc = SQLITE_FULL;
416 //}
417 //if ( rc == SQLITE_OK && (p.mask & TESTVFS_WRITE_MASK) != 0 && tvfsInjectIoerr( p ) != 0 )
418 //{
419 // rc = SQLITE_IOERR;
420 //}
421  
422 //if( rc==SQLITE_OK ){
423 // rc = sqlite3OsWrite(pFd.pReal, zBuf, iAmt, iOfst);
424 //}
425 return rc;
426 }
427  
428 /*
429 ** Truncate an tvfs-file.
430 */
431 static int tvfsTruncate(sqlite3_file pFile, sqlite_int64 size){
432 int rc = SQLITE_OK;
433 TestvfsFd pFd = tvfsGetFd(pFile);
434 Testvfs p = (Testvfs )pFd.pVfs.pAppData;
435  
436 if ( p.pScript != null && ( p.mask & TESTVFS_TRUNCATE_MASK ) != 0 )
437 {
438 tvfsExecTcl(p, "xTruncate",
439 TCL.Tcl_NewStringObj(pFd.zFilename, -1), pFd.pShmId,null
440 );
441 tvfsResultCode(p, ref rc);
442 }
443  
444 if( rc==SQLITE_OK ){
445 rc = sqlite3OsTruncate(pFd.pReal, size);
446 }
447 return rc;
448 }
449  
450 /*
451 ** Sync an tvfs-file.
452 */
453 static int tvfsSync(sqlite3_file pFile, int flags){
454 int rc = SQLITE_OK;
455 TestvfsFd pFd = tvfsGetFd(pFile);
456 Testvfs p = (Testvfs )pFd.pVfs.pAppData;
457  
458 if ( p.pScript != null && ( p.mask & TESTVFS_SYNC_MASK ) != 0 )
459 {
460 string zFlags = "";
461  
462 switch( flags ){
463 case SQLITE_SYNC_NORMAL:
464 zFlags = "normal";
465 break;
466 case SQLITE_SYNC_FULL:
467 zFlags = "full";
468 break;
469 case SQLITE_SYNC_NORMAL|SQLITE_SYNC_DATAONLY:
470 zFlags = "normal|dataonly";
471 break;
472 case SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY:
473 zFlags = "full|dataonly";
474 break;
475 default:
476 Debug.Assert(false);
477 break;
478 }
479  
480 tvfsExecTcl(p, "xSync",
481 TCL.Tcl_NewStringObj(pFd.zFilename, -1), pFd.pShmId,
482 TCL.Tcl_NewStringObj( zFlags, -1 )
483 );
484 tvfsResultCode(p, ref rc);
485 }
486  
487 if( rc==SQLITE_OK && tvfsInjectFullerr(p)!=0 ) rc = SQLITE_FULL;
488  
489 if( rc==SQLITE_OK ){
490 rc = sqlite3OsSync(pFd.pReal, flags);
491 }
492  
493 return rc;
494 }
495  
496 /*
497 ** Return the current file-size of an tvfs-file.
498 */
499 static int tvfsFileSize(sqlite3_file pFile, ref sqlite_int64 pSize){
500 TestvfsFd p = tvfsGetFd(pFile);
501 return sqlite3OsFileSize(p.pReal, ref pSize);
502 }
503  
504 /*
505 ** Lock an tvfs-file.
506 */
507 static int tvfsLock(sqlite3_file pFile, int eLock){
508 TestvfsFd p = tvfsGetFd(pFile);
509 return sqlite3OsLock(p.pReal, eLock);
510 }
511  
512 /*
513 ** Unlock an tvfs-file.
514 */
515 static int tvfsUnlock(sqlite3_file pFile, int eLock){
516 TestvfsFd p = tvfsGetFd(pFile);
517 return sqlite3OsUnlock(p.pReal, eLock);
518 }
519  
520 /*
521 ** Check if another file-handle holds a RESERVED lock on an tvfs-file.
522 */
523 static int tvfsCheckReservedLock( sqlite3_file pFile, ref int pResOut )
524 {
525 TestvfsFd p = tvfsGetFd(pFile);
526 return sqlite3OsCheckReservedLock( p.pReal, ref pResOut );
527 }
528  
529 /*
530 ** File control method. For custom operations on an tvfs-file.
531 */
532 static int tvfsFileControl( sqlite3_file pFile, int op, ref sqlite3_int64 pArg )
533 {
534 TestvfsFd p = tvfsGetFd(pFile);
535 return sqlite3OsFileControl( p.pReal, (u32)op, ref pArg );
536 }
537  
538 /*
539 ** Return the sector-size in bytes for an tvfs-file.
540 */
541 static int tvfsSectorSize(sqlite3_file pFile){
542 TestvfsFd pFd = tvfsGetFd(pFile);
543 Testvfs p = (Testvfs )pFd.pVfs.pAppData;
544 if( p.iSectorsize>=0 ){
545 return p.iSectorsize;
546 }
547 return sqlite3OsSectorSize(pFd.pReal);
548 }
549  
550 /*
551 ** Return the device characteristic flags supported by an tvfs-file.
552 */
553 static int tvfsDeviceCharacteristics(sqlite3_file pFile){
554 TestvfsFd pFd = tvfsGetFd(pFile);
555 Testvfs p = (Testvfs )pFd.pVfs.pAppData;
556 if( p.iDevchar>=0 ){
557 return p.iDevchar;
558 }
559 return sqlite3OsDeviceCharacteristics(pFd.pReal);
560 }
561  
562 /*
563 ** Open an tvfs file handle.
564 */
565 static int tvfsOpen(
566 sqlite3_vfs pVfs,
567 string zName,
568 sqlite3_file pFile,
569 int flags,
570 ref int pOutFlags
571 ){
572 int rc=0;
573 Debugger.Break();//TODO
574 //TestvfsFile pTestfile = (TestvfsFile)pFile;
575 //TestvfsFd pFd;
576 //Tcl_Obj pId = null;
577 //Testvfs p = (Testvfs )pVfs.pAppData;
578  
579 //pFd = (TestvfsFd )ckalloc(sizeof(TestvfsFd) + PARENTVFS(pVfs).szOsFile);
580 //pFd = new TestvfsFd();// memset( pFd, 0, sizeof( TestvfsFd ) + PARENTVFS( pVfs ).szOsFile );
581 //pFd.pShm = null;
582 //pFd.pShmId = null;
583 //pFd.zFilename = zName;
584 //pFd.pVfs = pVfs;
585 //pFd.pReal = (sqlite3_file )pFd[1];
586 //pTestfile = new TestvfsFile();// memset( pTestfile, 0, sizeof( TestvfsFile ) );
587 //pTestfile.pFd = pFd;
588  
589 ///* Evaluate the Tcl script:
590 //**
591 //** SCRIPT xOpen FILENAME KEY-VALUE-ARGS
592 //**
593 //** If the script returns an SQLite error code other than SQLITE_OK, an
594 //** error is returned to the caller. If it returns SQLITE_OK, the new
595 //** connection is named "anon". Otherwise, the value returned by the
596 //** script is used as the connection name.
597 //*/
598 //TCL.Tcl_ResetResult(p.interp);
599 //if ( p.pScript != null && ( p.mask & TESTVFS_OPEN_MASK ) != 0 )
600 //{
601 // Tcl_Obj pArg = TCL.Tcl_NewObj();
602 // TCL.Tcl_IncrRefCount( pArg );
603 // if( (flags&SQLITE_OPEN_MAIN_DB )!=0){
604 // string z = zName[strlen(zName)+1];
605 // while( *z ){
606 // TCL.Tcl_ListObjAppendElement( 0, pArg, TCL.Tcl_NewStringObj( z, -1 ) );
607 // z += strlen(z) + 1;
608 // TCL.Tcl_ListObjAppendElement( 0, pArg, TCL.Tcl_NewStringObj( z, -1 ) );
609 // z += strlen(z) + 1;
610 // }
611 // }
612 // tvfsExecTcl(p, "xOpen", TCL.Tcl_NewStringObj(pFd.zFilename, -1), pArg, null);
613 // TCL.Tcl_DecrRefCount( pArg );
614 // if( tvfsResultCode(p, ref rc)!=0 ){
615 // if( rc!=SQLITE_OK ) return rc;
616 // }else{
617 // pId = TCL.Tcl_GetObjResult(p.interp);
618 // }
619 //}
620  
621 //if( (p.mask&TESTVFS_OPEN_MASK)!=0 && tvfsInjectIoerr(p) !=0) return SQLITE_IOERR;
622 //if( tvfsInjectCantopenerr(p)!=0 ) return SQLITE_CANTOPEN;
623 //if( tvfsInjectFullerr(p)!=0 ) return SQLITE_FULL;
624  
625 //if( null==pId ){
626 // pId = TCL.Tcl_NewStringObj("anon", -1);
627 //}
628 //TCL.Tcl_IncrRefCount( pId );
629 //pFd.pShmId = pId;
630 //TCL.Tcl_ResetResult( p.interp );
631  
632 //rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, pFd.pReal, flags, pOutFlags);
633 //if ( pFd.pReal.pMethods != null )
634 //{
635 // sqlite3_io_methods pMethods;
636 // int nByte;
637  
638 //if( pVfs.iVersion>1 ){
639 // nByte = sizeof(sqlite3_io_methods);
640 //}else{
641 // nByte = offsetof(sqlite3_io_methods, xShmMap);
642 //}
643  
644 //pMethods = (sqlite3_io_methods)ckalloc( nByte );
645 //memcpy(pMethods, &tvfs_io_methods, nByte);
646 //pMethods.iVersion = pVfs.iVersion;
647 //if( pVfs.iVersion>1 && ((Testvfs )pVfs.pAppData).isNoshm ){
648 // pMethods.xShmUnmap = 0;
649 // pMethods.xShmLock = 0;
650 // pMethods.xShmBarrier = 0;
651 // pMethods.xShmMap = 0;
652 //}
653 // pFile.pMethods = pMethods;
654 //}
655  
656 return rc;
657 }
658  
659 /*
660 ** Delete the file located at zPath. If the dirSync argument is true,
661 ** ensure the file-system modifications are synced to disk before
662 ** returning.
663 */
664 static int tvfsDelete(sqlite3_vfs pVfs, string zPath, int dirSync){
665 int rc = SQLITE_OK;
666 Testvfs p = (Testvfs )pVfs.pAppData;
667  
668 if( p.pScript !=null && (p.mask&TESTVFS_DELETE_MASK)!=0 ){
669 tvfsExecTcl(p, "xDelete",
670 TCL.Tcl_NewStringObj( zPath, -1 ), TCL.Tcl_NewIntObj( dirSync ), null
671 );
672 tvfsResultCode(p, ref rc);
673 }
674 if( rc==SQLITE_OK ){
675 rc = sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync);
676 }
677 return rc;
678 }
679  
680 /*
681 ** Test for access permissions. Return true if the requested permission
682 ** is available, or false otherwise.
683 */
684 static int tvfsAccess(
685 sqlite3_vfs pVfs,
686 string zPath,
687 int flags,
688 ref int pResOut
689 ){
690 Testvfs p = (Testvfs )pVfs.pAppData;
691 if ( p.pScript != null && ( p.mask & TESTVFS_ACCESS_MASK ) != 0 )
692 {
693 int rc=0;
694 string zArg = "";
695 if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS";
696 if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE";
697 if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ";
698 tvfsExecTcl(p, "xAccess",
699 TCL.Tcl_NewStringObj( zPath, -1 ), TCL.Tcl_NewStringObj( zArg, -1 ), null
700 );
701 if( tvfsResultCode(p, ref rc) !=0){
702 if( rc!=SQLITE_OK ) return rc;
703 }else{
704 Tcl_Interp interp = p.interp;
705 bool bTemp = false;
706 if ( !TCL.Tcl_GetBooleanFromObj( null, TCL.Tcl_GetObjResult( interp ), out bTemp ) )
707 {
708 pResOut = bTemp ? 1 : 0;
709 return SQLITE_OK;
710 }
711 }
712 }
713 return sqlite3OsAccess( PARENTVFS( pVfs ), zPath, flags, ref pResOut );
714 }
715  
716 /*
717 ** Populate buffer zOut with the full canonical pathname corresponding
718 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
719 ** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
720 */
721 static int tvfsFullPathname(
722 sqlite3_vfs pVfs,
723 string zPath,
724 int nOut,
725 StringBuilder zOut
726 ){
727 Testvfs p = (Testvfs )pVfs.pAppData;
728 if ( p.pScript != null && ( p.mask & TESTVFS_FULLPATHNAME_MASK ) != 0 )
729 {
730 int rc=0;
731 tvfsExecTcl(p, "xFullPathname", TCL.Tcl_NewStringObj(zPath, -1),null,null);
732 if( tvfsResultCode(p, ref rc) !=0){
733 if( rc!=SQLITE_OK ) return rc;
734 }
735 }
736 return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut);
737 }
738  
739 #if !SQLITE_OMIT_LOAD_EXTENSION
740 /*
741 ** Open the dynamic library located at zPath and return a handle.
742 */
743 static IntPtr tvfsDlOpen(sqlite3_vfs pVfs, string zPath){
744 return sqlite3OsDlOpen(PARENTVFS(pVfs), zPath);
745 }
746  
747 /*
748 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
749 ** utf-8 string describing the most recent error encountered associated
750 ** with dynamic libraries.
751 */
752 static void tvfsDlError(sqlite3_vfs pVfs, int nByte, string zErrMsg){
753 sqlite3OsDlError(PARENTVFS(pVfs), nByte, zErrMsg);
754 }
755  
756 /*
757 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
758 */
759 static void tvfsDlSym(sqlite3_vfs pVfs, IntPtr p, string zSym){
760 sqlite3OsDlSym(PARENTVFS(pVfs), p, ref zSym);
761 }
762  
763 /*
764 ** Close the dynamic library handle pHandle.
765 */
766 static void tvfsDlClose( sqlite3_vfs pVfs, IntPtr pHandle )
767 {
768 sqlite3OsDlClose(PARENTVFS(pVfs), pHandle);
769 }
770 #endif //* SQLITE_OMIT_LOAD_EXTENSION */
771  
772 /*
773 ** Populate the buffer pointed to by zBufOut with nByte bytes of
774 ** random data.
775 */
776 static int tvfsRandomness(sqlite3_vfs pVfs, int nByte, byte[] zBufOut){
777 return sqlite3OsRandomness(PARENTVFS(pVfs), nByte, zBufOut);
778 }
779  
780 /*
781 ** Sleep for nMicro microseconds. Return the number of microseconds
782 ** actually slept.
783 */
784 static int tvfsSleep(sqlite3_vfs pVfs, int nMicro){
785 return sqlite3OsSleep(PARENTVFS(pVfs), nMicro);
786 }
787  
788 /*
789 ** Return the current time as a Julian Day number in pTimeOut.
790 */
791 static int tvfsCurrentTime(sqlite3_vfs pVfs, double pTimeOut){
792 return PARENTVFS(pVfs).xCurrentTime(PARENTVFS(pVfs), ref pTimeOut);
793 }
794  
795 static int tvfsShmOpen(sqlite3_file pFile){
796 Testvfs p;
797 int rc = SQLITE_OK; /* Return code */
798 Debugger.Break();//TODO
799 //TestvfsBuffer pBuffer; /* Buffer to open connection to */
800 //TestvfsFd pFd; /* The testvfs file structure */
801  
802 //pFd = tvfsGetFd(pFile);
803 //p = (Testvfs )pFd.pVfs.pAppData;
804 //Debug.Assert( pFd.pShmId && pFd.pShm==null && pFd.pNext==null );
805  
806 ///* Evaluate the Tcl script:
807 //**
808 //** SCRIPT xShmOpen FILENAME
809 //*/
810 //TCL.Tcl_ResetResult(p.interp);
811 //if ( p.pScript != null && ( p.mask & TESTVFS_SHMOPEN_MASK ) != 0 )
812 //{
813 // tvfsExecTcl(p, "xShmOpen", TCL.Tcl_NewStringObj(pFd.zFilename, -1), 0, 0);
814 // if( tvfsResultCode(p, ref rc)!=0 ){
815 // if( rc!=SQLITE_OK ) return rc;
816 // }
817 //}
818  
819 //Debug.Assert( rc==SQLITE_OK );
820 //if ( ( p.mask & TESTVFS_SHMOPEN_MASK ) != 0 && tvfsInjectIoerr( p ) )
821 //{
822 // return SQLITE_IOERR;
823 //}
824  
825 ///* Search for a TestvfsBuffer. Create a new one if required. */
826 //for(pBuffer=p.pBuffer; pBuffer!=null; pBuffer=pBuffer.pNext){
827 // if( 0==strcmp(pFd.zFilename, pBuffer.zFile) ) break;
828 //}
829 //if( null==pBuffer ){
830 // int nByte = sizeof(TestvfsBuffer) + strlen(pFd.zFilename) + 1;
831 // pBuffer = (TestvfsBuffer )ckalloc(nByte);
832 // memset(pBuffer, 0, nByte);
833 // pBuffer.zFile = (char )&pBuffer[1];
834 // strcpy(pBuffer.zFile, pFd.zFilename);
835 // pBuffer.pNext = p.pBuffer;
836 // p.pBuffer = pBuffer;
837 //}
838  
839 ///* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */
840 //pFd.pNext = pBuffer.pFile;
841 //pBuffer.pFile = pFd;
842 //pFd.pShm = pBuffer;
843 return SQLITE_OK;
844 }
845  
846 static void tvfsAllocPage(TestvfsBuffer p, int iPage, int pgsz){
847 Debugger.Break();//TODO
848 //Debug.Assert( iPage < TESTVFS_MAX_PAGES );
849 //if( p.aPage[iPage]==0 ){
850 // p.aPage[iPage] = (u8 )ckalloc(pgsz);
851 // memset(p.aPage[iPage], 0, pgsz);
852 // p.pgsz = pgsz;
853 //}
854 }
855  
856 static int tvfsShmMap(
857 sqlite3_file pFile, /* Handle open on database file */
858 int iPage, /* Page to retrieve */
859 int pgsz, /* Size of pages */
860 int isWrite, /* True to extend file if necessary */
861 out object pp /* OUT: Mapped memory */
862 ){
863 int rc = SQLITE_OK;
864 Debugger.Break();//TODO
865 pp = null;
866 //TestvfsFd pFd = tvfsGetFd( pFile );
867 //Testvfs p = (Testvfs )(pFd.pVfs.pAppData);
868  
869 //if( 0==pFd.pShm ){
870 // rc = tvfsShmOpen(pFile);
871 // if( rc!=SQLITE_OK ){
872 // return rc;
873 // }
874 //}
875  
876 //if( p.pScript != null && (p.mask&TESTVFS_SHMMAP_MASK )!=0){
877 // Tcl_Obj pArg = TCL.Tcl_NewObj();
878 // Tcl_IncrRefCount(pArg);
879 // Tcl_ListObjAppendElement(p.interp, pArg, TCL.Tcl_NewIntObj(iPage));
880 // Tcl_ListObjAppendElement(p.interp, pArg, TCL.Tcl_NewIntObj(pgsz));
881 // Tcl_ListObjAppendElement(p.interp, pArg, TCL.Tcl_NewIntObj(isWrite));
882 // tvfsExecTcl(p, "xShmMap",
883 // Tcl_NewStringObj(pFd.pShm.zFile, -1), pFd.pShmId, pArg
884 // );
885 // tvfsResultCode(p, ref rc);
886 // Tcl_DecrRefCount(pArg);
887 //}
888 //if( rc==SQLITE_OK && (p.mask&TESTVFS_SHMMAP_MASK )!=0&& tvfsInjectIoerr(p) ){
889 // rc = SQLITE_IOERR;
890 //}
891  
892 //if( rc==SQLITE_OK && isWrite && !pFd.pShm.aPage[iPage] ){
893 // tvfsAllocPage(pFd.pShm, iPage, pgsz);
894 //}
895 //pp = pFd.pShm.aPage[iPage];
896  
897 return rc;
898 }
899  
900  
901 static int tvfsShmLock(
902 sqlite3_file pFile,
903 int ofst,
904 int n,
905 int flags
906 ){
907 int rc = SQLITE_OK;
908 Debugger.Break();//TODO
909 //TestvfsFd pFd = tvfsGetFd(pFile);
910 //Testvfs p = (Testvfs )(pFd.pVfs.pAppData);
911 //int nLock;
912 //StringBuilder zLock =new StringBuilder(80);//char zLock[80];
913  
914 //if( p.pScript !=null && (p.mask&TESTVFS_SHMLOCK_MASK)!=0 ){
915 // sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n);
916 // nLock = strlen(zLock);
917 // if( flags & SQLITE_SHM_LOCK ){
918 // strcpy(&zLock[nLock], " lock");
919 // }else{
920 // strcpy(&zLock[nLock], " unlock");
921 // }
922 // nLock += strlen(&zLock[nLock]);
923 // if( flags & SQLITE_SHM_SHARED ){
924 // strcpy(&zLock[nLock], " shared");
925 // }else{
926 // strcpy(&zLock[nLock], " exclusive");
927 // }
928 // tvfsExecTcl(p, "xShmLock",
929 // Tcl_NewStringObj(pFd.pShm.zFile, -1), pFd.pShmId,
930 // Tcl_NewStringObj(zLock, -1)
931 // );
932 // tvfsResultCode(p, ref rc);
933 //}
934  
935 //if( rc==SQLITE_OK && (p.mask&TESTVFS_SHMLOCK_MASK )!=0&& tvfsInjectIoerr(p) ){
936 // rc = SQLITE_IOERR;
937 //}
938  
939 //if( rc==SQLITE_OK ){
940 // int isLock = (flags & SQLITE_SHM_LOCK);
941 // int isExcl = (flags & SQLITE_SHM_EXCLUSIVE);
942 // u32 mask = (((1<<n)-1) << ofst);
943 // if( isLock ){
944 // TestvfsFd p2;
945 // for(p2=pFd.pShm.pFile; p2; p2=p2.pNext){
946 // if( p2==pFd ) continue;
947 // if( (p2.excllock&mask) || (isExcl && p2.sharedlock&mask) ){
948 // rc = SQLITE_BUSY;
949 // break;
950 // }
951 // }
952 // if( rc==SQLITE_OK ){
953 // if( isExcl ) pFd.excllock |= mask;
954 // if( null==isExcl ) pFd.sharedlock |= mask;
955 // }
956 // }else{
957 // if( isExcl ) pFd.excllock &= (~mask);
958 // if( null==isExcl ) pFd.sharedlock &= (~mask);
959 // }
960 //}
961  
962 return rc;
963 }
964  
965 static void tvfsShmBarrier(sqlite3_file pFile){
966 Debugger.Break();//TODO
967 //TestvfsFd pFd = tvfsGetFd(pFile);
968 //Testvfs p = (Testvfs )(pFd.pVfs.pAppData);
969  
970 //if ( p.pScript != null && ( p.mask & TESTVFS_SHMBARRIER_MASK ) != 0 )
971 //{
972 // tvfsExecTcl(p, "xShmBarrier",
973 // Tcl_NewStringObj(pFd.pShm.zFile, -1), pFd.pShmId, 0
974 // );
975 //}
976 }
977  
978 static int tvfsShmUnmap(
979 sqlite3_file pFile,
980 int deleteFlag
981 ){
982 int rc = SQLITE_OK;
983 Debugger.Break();//TODO
984 //TestvfsFd pFd = tvfsGetFd( pFile );
985 //Testvfs p = (Testvfs )(pFd.pVfs.pAppData);
986 //TestvfsBuffer pBuffer = pFd.pShm;
987 //TestvfsFd ppFd;
988  
989 //if( null==pBuffer ) return SQLITE_OK;
990 //Debug.Assert( pFd.pShmId && pFd.pShm );
991  
992 //if ( p.pScript != null && ( p.mask & TESTVFS_SHMCLOSE_MASK ) != 0 )
993 //{
994 // tvfsExecTcl(p, "xShmUnmap",
995 // Tcl_NewStringObj(pFd.pShm.zFile, -1), pFd.pShmId, 0
996 // );
997 // tvfsResultCode(p, ref rc);
998 //}
999  
1000 //for(ppFd=pBuffer.pFile; ppFd!=pFd; ppFd=&((ppFd).pNext));
1001 //Debug.Assert( (ppFd)==pFd );
1002 //ppFd = pFd.pNext;
1003 //pFd.pNext = 0;
1004  
1005 //if( pBuffer.pFile==null ){
1006 // int i;
1007 // TestvfsBuffer pp;
1008 // for(pp=p.pBuffer; pp!=pBuffer; pp=((pp).pNext));
1009 // pp = (pp).pNext;
1010 // Debugger.Break();//TODO
1011 // //for(i=0; pBuffer.aPage[i]!= null; i++){
1012 // // ckfree((char )pBuffer.aPage[i]);
1013 // //}
1014 // //ckfree((char )pBuffer);
1015 //}
1016 //pFd.pShm = null;
1017  
1018 return rc;
1019 }
1020  
1021 enum DB_enum_CMD {
1022 CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT,
1023 CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR, CMD_CANTOPENERR
1024 };
1025 class TestvfsSubcmd {
1026 public string zName;
1027 public DB_enum_CMD eCmd;
1028 public TestvfsSubcmd (string zName, DB_enum_CMD eCmd){this.zName=zName;this.eCmd=eCmd;}
1029 }
1030 class VfsMethod {
1031 public string zName;
1032 public int mask;
1033 public VfsMethod (string zName, int mask){this.zName=zName;this.mask=mask;}
1034 }
1035  
1036 class DeviceFlag {
1037 public string zName;
1038 public int iValue;
1039 public DeviceFlag (string zName, int iValue){this.zName=zName;this.iValue=iValue;}
1040 }
1041  
1042 class _aFlag
1043 {
1044 public string zName;
1045 public int iValue;
1046 public _aFlag( string zName, int iValue )
1047 {
1048 this.zName = zName;
1049 this.iValue = iValue;
1050 }
1051 }
1052  
1053  
1054 static int testvfs_obj_cmd(
1055 ClientData cd,
1056 Tcl_Interp interp,
1057 int objc,
1058 Tcl_Obj[] objv
1059 ){
1060 Debugger.Break();//TODO
1061 // Testvfs p = (Testvfs)cd;
1062  
1063 // TestvfsSubcmd[] aSubcmd = new TestvfsSubcmd[] {
1064 // new TestvfsSubcmd( "shm", DB_enum_CMD.CMD_SHM ),
1065 // new TestvfsSubcmd( "delete", DB_enum_CMD.CMD_DELETE ),
1066 // new TestvfsSubcmd( "filter", DB_enum_CMD.CMD_FILTER ),
1067 // new TestvfsSubcmd( "ioerr", DB_enum_CMD.CMD_IOERR ),
1068 // new TestvfsSubcmd( "fullerr", DB_enum_CMD.CMD_FULLERR ),
1069 // new TestvfsSubcmd( "cantopenerr", DB_enum_CMD.CMD_CANTOPENERR ),
1070 // new TestvfsSubcmd( "script", DB_enum_CMD.CMD_SCRIPT ),
1071 // new TestvfsSubcmd( "devchar", DB_enum_CMD.CMD_DEVCHAR ),
1072 // new TestvfsSubcmd( "sectorsize", DB_enum_CMD.CMD_SECTORSIZE ),
1073 // new TestvfsSubcmd( 0, 0 )
1074 // };
1075 // int i=0;
1076  
1077 // if( objc<2 ){
1078 // TCL.Tcl_WrongNumArgs( interp, 1, objv, "SUBCOMMAND ..." );
1079 // return TCL.TCL_ERROR;
1080 // }
1081 // if ( TCL.Tcl_GetIndexFromObjStruct(
1082 // interp, objv[1], aSubcmd, aSubcmd.Length, "subcommand", 0, ref i)
1083 // ){
1084 // return TCL.TCL_ERROR;
1085 // }
1086 // TCL.Tcl_ResetResult( interp );
1087  
1088 // switch( aSubcmd[i].eCmd ){
1089 // case DB_enum_CMD.CMD_SHM: {
1090 // Tcl_Obj pObj;
1091 // int i;
1092 // TestvfsBuffer pBuffer;
1093 // string zName;
1094 // if( objc!=3 && objc!=4 ){
1095 // TCL.Tcl_WrongNumArgs( interp, 2, objv, "FILE ?VALUE?" );
1096 // return TCL.TCL_ERROR;
1097 // }
1098 // zName = ckalloc(p.pParent.mxPathname);
1099 // p.pParent.xFullPathname(
1100 // p.pParent, TCL.Tcl_GetString(objv[2]),
1101 // p.pParent.mxPathname, zName
1102 // );
1103 // for(pBuffer=p.pBuffer; pBuffer; pBuffer=pBuffer.pNext){
1104 // if( 0==strcmp(pBuffer.zFile, zName) ) break;
1105 // }
1106 // ckfree(zName);
1107 // if( null==pBuffer ){
1108 // TCL.Tcl_AppendResult( interp, "no such file: ", TCL.Tcl_GetString( objv[2] ), 0 );
1109 // return TCL.TCL_ERROR;
1110 // }
1111 // if( objc==4 ){
1112 // int n;
1113 // u8 *a = TCL.Tcl_GetByteArrayFromObj(objv[3], &n);
1114 // int pgsz = pBuffer.pgsz;
1115 // if( pgsz==0 ) pgsz = 65536;
1116 // for(i=0; ipgsz<n; i++){
1117 // int nByte = pgsz;
1118 // tvfsAllocPage(pBuffer, i, pgsz);
1119 // if( n-ipgsz<pgsz ){
1120 // nByte = n;
1121 // }
1122 // memcpy(pBuffer.aPage[i], &a[ipgsz], nByte);
1123 // }
1124 // }
1125  
1126 // pObj = TCL.Tcl_NewObj();
1127 // for(i=0; pBuffer.aPage[i]!=null; i++){
1128 // int pgsz = pBuffer.pgsz;
1129 // if( pgsz==0 ) pgsz = 65536;
1130 // TCL.Tcl_AppendObjToObj(pObj, TCL.Tcl_NewByteArrayObj(pBuffer.aPage[i], pgsz));
1131 // }
1132 // TCL.Tcl_SetObjResult( interp, pObj );
1133 // break;
1134 // }
1135 // case DB_enum_CMD.CMD_FILTER: {
1136 //VfsMethod[] vfsmethod = new VfsMethod[] {
1137 // new VfsMethod( "xShmOpen", TESTVFS_SHMOPEN_MASK ),
1138 // new VfsMethod( "xShmLock", TESTVFS_SHMLOCK_MASK ),
1139 // new VfsMethod( "xShmBarrier", TESTVFS_SHMBARRIER_MASK ),
1140 // new VfsMethod( "xShmUnmap", TESTVFS_SHMCLOSE_MASK ),
1141 // new VfsMethod( "xShmMap", TESTVFS_SHMMAP_MASK ),
1142 // new VfsMethod( "xSync", TESTVFS_SYNC_MASK ),
1143 // new VfsMethod( "xDelete", TESTVFS_DELETE_MASK ),
1144 // new VfsMethod( "xWrite", TESTVFS_WRITE_MASK ),
1145 // new VfsMethod( "xTruncate", TESTVFS_TRUNCATE_MASK ),
1146 // new VfsMethod( "xOpen", TESTVFS_OPEN_MASK ),
1147 // new VfsMethod( "xClose", TESTVFS_CLOSE_MASK ),
1148 // new VfsMethod( "xAccess", TESTVFS_ACCESS_MASK ),
1149 // new VfsMethod( "xFullPathname", TESTVFS_FULLPATHNAME_MASK ),
1150 //};
1151 // Tcl_Obj[] apElem = null;
1152 // int nElem = 0;
1153 // int i;
1154 // int mask = 0;
1155 // if( objc!=3 ){
1156 // TCL.Tcl_WrongNumArgs( interp, 2, objv, "LIST" );
1157 // return TCL.TCL_ERROR;
1158 // }
1159 // if ( TCL.Tcl_ListObjGetElements( interp, objv[2], ref nElem, ref apElem ) )
1160 // {
1161 // return TCL.TCL_ERROR;
1162 // }
1163 // TCL.Tcl_ResetResult( interp );
1164 // for(i=0; i<nElem; i++){
1165 // int iMethod;
1166 // string zElem = TCL.Tcl_GetString(apElem[i]);
1167 // for(iMethod=0; iMethod<ArraySize(vfsmethod); iMethod++){
1168 // if( strcmp(zElem, vfsmethod[iMethod].zName)==0 ){
1169 // mask |= vfsmethod[iMethod].mask;
1170 // break;
1171 // }
1172 // }
1173 // if( iMethod==ArraySize(vfsmethod) ){
1174 // TCL.Tcl_AppendResult( interp, "unknown method: ", zElem, 0 );
1175 // return TCL.TCL_ERROR;
1176 // }
1177 // }
1178 // p.mask = mask;
1179 // break;
1180 // }
1181  
1182 // case DB_enum_CMD.CMD_SCRIPT: {
1183 // if( objc==3 ){
1184 // int nByte;
1185 // if( p.pScript !=null){
1186 // TCL.Tcl_DecrRefCount( p.pScript );
1187 // p.pScript = 0;
1188 // }
1189 // TCL.Tcl_GetStringFromObj( objv[2], &nByte );
1190 // if( nByte>0 ){
1191 // p.pScript = TCL.Tcl_DuplicateObj(objv[2]);
1192 // TCL.Tcl_IncrRefCount( p.pScript );
1193 // }
1194 // }else if( objc!=2 ){
1195 // TCL.Tcl_WrongNumArgs( interp, 2, objv, "?SCRIPT?" );
1196 // return TCL.TCL_ERROR;
1197 // }
1198  
1199 // TCL.Tcl_ResetResult( interp );
1200 // if( p.pScript !=null) if( p.pScript )TCL.Tcl_SetObjResult(interp, p.pScript);
1201  
1202 // break;
1203 // }
1204  
1205 // /*
1206 // ** TESTVFS ioerr ?IFAIL PERSIST?
1207 // **
1208 // ** Where IFAIL is an integer and PERSIST is boolean.
1209 // */
1210 // case DB_enum_CMD.CMD_CANTOPENERR:
1211 // case DB_enum_CMD.CMD_IOERR:
1212 // case DB_enum_CMD.CMD_FULLERR: {
1213 // TestFaultInject pTest;
1214 // int iRet;
1215  
1216 // switch( aSubcmd[i].eCmd ){
1217 // case DB_enum_CMD.CMD_IOERR: pTest = p.ioerr_err; break;
1218 // case DB_enum_CMD.CMD_FULLERR: pTest = p.full_err; break;
1219 // case DB_enum_CMD.CMD_CANTOPENERR: pTest = p.cantopen_err; break;
1220 // default: Debug.Assert(false);
1221 // }
1222 // iRet = pTest.nFail;
1223 // pTest.nFail = 0;
1224 // pTest.eFault = 0;
1225 // pTest.iCnt = 0;
1226  
1227 // if( objc==4 ){
1228 // int iCnt, iPersist;
1229 // if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], &iCnt )
1230 // || TCL.TCL_OK != TCL.Tcl_GetBooleanFromObj( interp, objv[3], &iPersist )
1231 // ){
1232 // return TCL.TCL_ERROR;
1233 // }
1234 // pTest.eFault = iPersist != 0 ? FAULT_INJECT_PERSISTENT : FAULT_INJECT_TRANSIENT;
1235 // pTest.iCnt = iCnt;
1236 // }else if( objc!=2 ){
1237 // TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CNT PERSIST?" );
1238 // return TCL.TCL_ERROR;
1239 // }
1240 // TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( iRet ) );
1241 // break;
1242 // }
1243  
1244 // case DB_enum_CMD.CMD_DELETE: {
1245 // TCL.Tcl_DeleteCommand( interp, TCL.Tcl_GetString( objv[0] ) );
1246 // break;
1247 // }
1248  
1249 // case DB_enum_CMD.CMD_DEVCHAR: {
1250 //_aFlag[] aFlag = new _aFlag[] {
1251 // new _aFlag( "default", -1 ),
1252 // new _aFlag( "atomic", SQLITE_IOCAP_ATOMIC ),
1253 // new _aFlag( "atomic512", SQLITE_IOCAP_ATOMIC512 ),
1254 // new _aFlag( "atomic1k", SQLITE_IOCAP_ATOMIC1K ),
1255 // new _aFlag( "atomic2k", SQLITE_IOCAP_ATOMIC2K ),
1256 // new _aFlag( "atomic4k", SQLITE_IOCAP_ATOMIC4K ),
1257 // new _aFlag( "atomic8k", SQLITE_IOCAP_ATOMIC8K ),
1258 // new _aFlag( "atomic16k", SQLITE_IOCAP_ATOMIC16K ),
1259 // new _aFlag( "atomic32k", SQLITE_IOCAP_ATOMIC32K ),
1260 // new _aFlag( "atomic64k", SQLITE_IOCAP_ATOMIC64K ),
1261 // new _aFlag( "sequential", SQLITE_IOCAP_SEQUENTIAL ),
1262 // new _aFlag( "safe_append", SQLITE_IOCAP_SAFE_APPEND ),
1263 // new _aFlag( "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN ),
1264 // new _aFlag( 0, 0 )
1265 // };
1266 // Tcl_Obj pRet;
1267 // int iFlag;
1268  
1269 // if( objc>3 ){
1270 // Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?");
1271 // return TCL.TCL_ERROR;
1272 // }
1273 // if( objc==3 ){
1274 // int j;
1275 // int iNew = 0;
1276 // Tcl_Obj[] flags = null;
1277 // int nFlags = 0;
1278  
1279 // if ( TCL.Tcl_ListObjGetElements( interp, objv[2], ref nFlags, ref flags ) )
1280 // {
1281 // return TCL.TCL_ERROR;
1282 // }
1283  
1284 // for(j=0; j<nFlags; j++){
1285 // int idx = 0;
1286 // if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag,
1287 // aFlag.Length, "flag", 0, ref idx)
1288 // ){
1289 // return TCL.TCL_ERROR;
1290 // }
1291 // if( aFlag[idx].iValue<0 && nFlags>1 ){
1292 // TCL.Tcl_AppendResult( interp, "bad flags: ", TCL.Tcl_GetString( objv[2] ), 0 );
1293 // return TCL.TCL_ERROR;
1294 // }
1295 // iNew |= aFlag[idx].iValue;
1296 // }
1297  
1298 // p.iDevchar = iNew;
1299 // }
1300  
1301 // pRet = TCL.Tcl_NewObj();
1302 // for(iFlag=0; iFlag<aFlag.Length ; iFlag++)//sizeof(aFlag)/sizeof(aFlag[0]); iFlag++)
1303 // {
1304 // if( p.iDevchar & aFlag[iFlag].iValue ){
1305 // TCL.Tcl_ListObjAppendElement(
1306 // interp, pRet, TCL.Tcl_NewStringObj(aFlag[iFlag].zName, -1)
1307 // );
1308 // }
1309 // }
1310 // TCL.Tcl_SetObjResult( interp, pRet );
1311  
1312 // break;
1313 // }
1314  
1315 // case DB_enum_CMD.CMD_SECTORSIZE: {
1316 // if( objc>3 ){
1317 // TCL.Tcl_WrongNumArgs( interp, 2, objv, "?VALUE?" );
1318 // return TCL.TCL_ERROR;
1319 // }
1320 // if( objc==3 ){
1321 // int iNew = 0;
1322 // if( Tcl_GetIntFromObj(interp, objv[2], ref iNew) ){
1323 // return TCL.TCL_ERROR;
1324 // }
1325 // p.iSectorsize = iNew;
1326 // }
1327 // TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( p.iSectorsize ) );
1328 // break;
1329 // }
1330 // }
1331 return TCL.TCL_OK;
1332 }
1333  
1334 static void testvfs_obj_del(ClientData cd){
1335 Testvfs p = (Testvfs)cd;
1336 if ( p.pScript !=null)
1337 TCL.Tcl_DecrRefCount( ref p.pScript );
1338 sqlite3_vfs_unregister(p.pVfs);
1339 Debugger.Break();//TODO
1340 //ckfree((char )p.pVfs);
1341 //ckfree((char )p);
1342 }
1343  
1344 /*
1345 ** Usage: testvfs VFSNAME ?SWITCHES?
1346 **
1347 ** Switches are:
1348 **
1349 ** -noshm BOOLEAN (True to omit shm methods. Default false)
1350 ** -default BOOLEAN (True to make the vfs default. Default false)
1351 **
1352 ** This command creates two things when it is invoked: an SQLite VFS, and
1353 ** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not
1354 ** installed as the default VFS.
1355 **
1356 ** The VFS passes all file I/O calls through to the underlying VFS.
1357 **
1358 ** Whenever the xShmMap method of the VFS
1359 ** is invoked, the SCRIPT is executed as follows:
1360 **
1361 ** SCRIPT xShmMap FILENAME ID
1362 **
1363 ** The value returned by the invocation of SCRIPT above is interpreted as
1364 ** an SQLite error code and returned to SQLite. Either a symbolic
1365 ** "SQLITE_OK" or numeric "0" value may be returned.
1366 **
1367 ** The contents of the shared-memory buffer associated with a given file
1368 ** may be read and set using the following command:
1369 **
1370 ** VFSNAME shm FILENAME ?NEWVALUE?
1371 **
1372 ** When the xShmLock method is invoked by SQLite, the following script is
1373 ** run:
1374 **
1375 ** SCRIPT xShmLock FILENAME ID LOCK
1376 **
1377 ** where LOCK is of the form "OFFSET NBYTE lock/unlock shared/exclusive"
1378 */
1379 static int testvfs_cmd(
1380 ClientData cd,
1381 Tcl_Interp interp,
1382 int objc,
1383 Tcl_Obj[] objv
1384 ){
1385 Debugger.Break();//TODO
1386 // sqlite3_vfs tvfs_vfs = new sqlite3_vfs(
1387 // 2, /* iVersion */
1388 // 0, /* szOsFile */
1389 // 0, /* mxPathname */
1390 // null, /* pNext */
1391 // null, /* zName */
1392 // 0, /* pAppData */
1393 // tvfsOpen, /* xOpen */
1394 // tvfsDelete, /* xDelete */
1395 // tvfsAccess, /* xAccess */
1396 // tvfsFullPathname, /* xFullPathname */
1397 //#if !SQLITE_OMIT_LOAD_EXTENSION
1398 // tvfsDlOpen, /* xDlOpen */
1399 // tvfsDlError, /* xDlError */
1400 // tvfsDlSym, /* xDlSym */
1401 // tvfsDlClose, /* xDlClose */
1402 //#else
1403 // null, /* xDlOpen */
1404 // null, /* xDlError */
1405 // null, /* xDlSym */
1406 // null, /* xDlClose */
1407 //#endif //* SQLITE_OMIT_LOAD_EXTENSION */
1408 // tvfsRandomness, /* xRandomness */
1409 // tvfsSleep, /* xSleep */
1410 // tvfsCurrentTime, /* xCurrentTime */
1411 // null, /* xGetLastError */
1412 // null, /* xCurrentTimeInt64 */
1413 // null, null, null
1414 // );
1415  
1416 // Testvfs p; /* New object */
1417 // sqlite3_vfs pVfs; /* New VFS */
1418 // string zVfs;
1419 // int nByte; /* Bytes of space to allocate at p */
1420  
1421 // int i;
1422 // int isNoshm = 0; /* True if -noshm is passed */
1423 // int isDefault = 0; /* True if -default is passed */
1424 // int szOsFile = 0; /* Value passed to -szosfile */
1425 // int mxPathname = -1; /* Value passed to -mxpathname */
1426 // int iVersion = 2; /* Value passed to -iversion */
1427  
1428 // if( objc<2 || 0!=(objc%2) ) goto bad_args;
1429 // for(i=2; i<objc; i += 2){
1430 // int nSwitch;
1431 // string zSwitch;
1432 // zSwitch = TCL.Tcl_GetStringFromObj(objv[i], &nSwitch);
1433  
1434 // if( nSwitch>2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){
1435 // if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], &isNoshm ) )
1436 // {
1437 // return TCL.TCL_ERROR;
1438 // }
1439 // }
1440 // else if( nSwitch>2 && 0==strncmp("-default", zSwitch, nSwitch) ){
1441 // if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], &isDefault ) )
1442 // {
1443 // return TCL.TCL_ERROR;
1444 // }
1445 // }
1446 // else if( nSwitch>2 && 0==strncmp("-szosfile", zSwitch, nSwitch) ){
1447 // if ( TCL.Tcl_GetIntFromObj( interp, objv[i + 1], &szOsFile ) )
1448 // {
1449 // return TCL.TCL_ERROR;
1450 // }
1451 // }
1452 // else if( nSwitch>2 && 0==strncmp("-mxpathname", zSwitch, nSwitch) ){
1453 // if ( TCL.Tcl_GetIntFromObj( interp, objv[i + 1], &mxPathname ) )
1454 // {
1455 // return TCL.TCL_ERROR;
1456 // }
1457 // }
1458 // else if( nSwitch>2 && 0==strncmp("-iversion", zSwitch, nSwitch) ){
1459 // if ( TCL.Tcl_GetIntFromObj( interp, objv[i + 1], &iVersion ) )
1460 // {
1461 // return TCL.TCL_ERROR;
1462 // }
1463 // }
1464 // else{
1465 // goto bad_args;
1466 // }
1467 // }
1468  
1469 // if( szOsFile<sizeof(TestvfsFile) ){
1470 // szOsFile = sizeof(TestvfsFile);
1471 // }
1472  
1473 // zVfs = TCL.Tcl_GetString(objv[1]);
1474 // nByte = sizeof(Testvfs) + strlen(zVfs)+1;
1475 // p = (Testvfs )ckalloc(nByte);
1476 // memset(p, 0, nByte);
1477 // p.iDevchar = -1;
1478 // p.iSectorsize = -1;
1479  
1480 // /* Create the new object command before querying SQLite for a default VFS
1481 // ** to use for 'real' IO operations. This is because creating the new VFS
1482 // ** may delete an existing [testvfs] VFS of the same name. If such a VFS
1483 // ** is currently the default, the new [testvfs] may end up calling the
1484 // ** methods of a deleted object.
1485 // */
1486 // TCL.Tcl_CreateObjCommand( interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del );
1487 // p.pParent = sqlite3_vfs_find("");
1488 // p.interp = interp;
1489  
1490 // p.zName = (char )&p[1];
1491 // memcpy(p.zName, zVfs, strlen(zVfs)+1);
1492  
1493 // pVfs = new sqlite3_vfs();//(sqlite3_vfs )ckalloc(sizeof(sqlite3_vfs));
1494 // tvfs_vfs.CopyTo(pVfs);//memcpy( pVfs, &tvfs_vfs, sizeof( sqlite3_vfs ) );
1495 // pVfs.pAppData = p;
1496 // pVfs.iVersion = iVersion;
1497 // pVfs.zName = p.zName;
1498 // pVfs.mxPathname = p.pParent.mxPathname;
1499 // if( mxPathname>=0 && mxPathname<pVfs.mxPathname ){
1500 // pVfs.mxPathname = mxPathname;
1501 // }
1502 // pVfs.szOsFile = szOsFile;
1503 // p.pVfs = pVfs;
1504 // p.isNoshm = isNoshm;
1505 // p.mask = TESTVFS_ALL_MASK;
1506  
1507 // sqlite3_vfs_register(pVfs, isDefault);
1508  
1509 // return TCL.TCL_OK;
1510  
1511 // bad_args:
1512 // TCL.Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?");
1513 return TCL.TCL_ERROR;
1514 }
1515  
1516 static int Sqlitetestvfs_Init(Tcl_Interp interp){
1517 TCL.Tcl_CreateObjCommand( interp, "testvfs", testvfs_cmd, null, null );
1518 return TCL.TCL_OK;
1519 }
1520 #endif
1521 }
1522 #endif
1523 }