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.IO;
4 using System.Runtime.InteropServices;
5 using System.Text;
6  
7 using FILE = System.IO.TextWriter;
8 using GETPROCTIMES = System.IntPtr;
9 using HANDLE = System.IntPtr;
10 using HINSTANCE = System.IntPtr;
11 using sqlite3_int64 = System.Int64;
12 using u32 = System.UInt32;
13 using va_list = System.Object;
14  
15 namespace Community.CsharpSqlite
16 {
17 using dxCallback = Sqlite3.dxCallback;
18 using FILETIME = Sqlite3.FILETIME;
19 using sqlite3 = Sqlite3.sqlite3;
20 using sqlite3_stmt = Sqlite3.Vdbe;
21 using sqlite3_value = Sqlite3.Mem;
22  
23  
24 class Shell
25 {
26  
27 /*
28 ** 2001 September 15
29 **
30 ** The author disclaims copyright to this source code. In place of
31 ** a legal notice, here is a blessing:
32 **
33 ** May you do good and not evil.
34 ** May you find forgiveness for yourself and forgive others.
35 ** May you share freely, never taking more than you give.
36 **
37 *************************************************************************
38 ** This file contains code to implement the "sqlite" command line
39 ** utility for accessing SQLite databases.
40 *************************************************************************
41 ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
42 ** C#-SQLite is an independent reimplementation of the SQLite software library
43 **
44 *************************************************************************
45 */
46 //#if defined(_WIN32) || defined(WIN32)
47 ///* This needs to come before any includes for MSVC compiler */
48 //#define _CRT_SECURE_NO_WARNINGS
49 //#endif
50  
51 //#include <stdlib.h>
52 //#include <string.h>
53 //#include <stdio.h>
54 //#include <Debug.Assert.h>
55 //#include "sqlite3.h"
56 //#include <ctype.h>
57 //#include <stdarg.h>
58  
59 //#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
60 //# include <signal.h>
61 //# if !defined(__RTP__) && !defined(_WRS_KERNEL)
62 //# include <pwd.h>
63 //# endif
64 //# include <unistd.h>
65 //# include <sys/types.h>
66 //#endif
67  
68 //#if __OS2__
69 //# include <unistd.h>
70 //#endif
71  
72 //#if HAVE_EDITLINE
73 //# include <editline/editline.h>
74 //#endif
75 //#if defined(HAVE_READLINE) && HAVE_READLINE==1
76 //# include <readline/readline.h>
77 //# include <readline/history.h>
78 //#endif
79 #if !(HAVE_EDITLINE) //&& (!(HAVE_READLINE) || HAVE_READLINE!=1)
80 //# define readline(p) local_getline(p,stdin)
81 static string readline(string p)
82 {
83 return local_getline(p, stdin);
84 }
85 //# define add_history(X)
86 static void add_history(object p) { }
87 //# define read_history(X)
88 static void read_history(object p) { }
89 //# define write_history(X)
90 static void write_history(object p) { }
91 //# define stifle_history(X)
92 static void stifle_history(object p) { }
93 #endif
94  
95 #if (_WIN32) || (WIN32)
96 //# include <io.h>
97 //#define isatty(h) _isatty(h)
98 static bool isatty(object h) { return stdin.Equals(Console.In); }
99 //#define access(f,m) _access((f),(m))
100 #else
101 /* Make sure isatty() has a prototype.
102 */
103 extern int isatty();
104 #endif
105  
106 //#if defined(_WIN32_WCE)
107 ///* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
108 // * thus we always assume that we have a console. That can be
109 // * overridden with the -batch command line option.
110 // */
111 //#define isatty(x) 1
112 //#endif
113  
114 /* True if the timer is enabled */
115 static bool enableTimer = false;
116  
117 #if FALSE//!defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
118 //#include <sys/time.h>
119 //#include <sys/resource.h>
120  
121 ///* Saved resource information for the beginning of an operation */
122 //static struct rusage sBegin;
123  
124 ///*
125 //** Begin timing an operation
126 //*/
127 //static void beginTimer(){
128 // if( enableTimer ){
129 // getrusage(RUSAGE_SELF, sBegin);
130 // }
131 //}
132  
133 ///* Return the difference of two time_structs in seconds */
134 //static double timeDiff(timeval pStart, struct timeval pEnd){
135 // return (pEnd.tv_usec - pStart.tv_usec)*0.000001 +
136 // (double)(pEnd.tv_sec - pStart.tv_sec);
137 //}
138  
139 ///*
140 //** Print the timing results.
141 //*/
142 //static void endTimer(){
143 // if( enableTimer ){
144 // struct rusage sEnd;
145 // getrusage(RUSAGE_SELF, sEnd);
146 // printf("CPU Time: user %f sys %f\n",
147 // timeDiff(sBegin.ru_utime, sEnd.ru_utime),
148 // timeDiff(sBegin.ru_stime, sEnd.ru_stime));
149 // }
150 //}
151  
152 //#define BEGIN_TIMER beginTimer()
153 //#define END_TIMER endTimer()
154 //#define HAS_TIMER 1
155  
156 #elif ((_WIN32) || (WIN32))
157  
158 //#include <windows.h>
159  
160 /* Saved resource information for the beginning of an operation */
161 static Process hProcess;
162 //static FILETIME ftKernelBegin;
163 //static FILETIME ftUserBegin;
164 static TimeSpan tsUserBegin;
165 static TimeSpan tsKernelBegin;
166  
167 //typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
168  
169 /*
170 ** Check to see if we have timer support. Return 1 if necessary
171 ** support found (or found previously).
172 */
173 //static bool has_timer()
174 //{
175 // if (getProcessTimesAddr != IntPtr.Zero)
176 // {
177 // return true;
178 // }
179 // else
180 // {
181 // /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions.
182 // ** See if the version we are running on has it, and if it does, save off
183 // ** a pointer to it and the current process handle.
184 // */
185 // hProcess = Process.GetCurrentProcess();
186 // if (hProcess != null)
187 // {
188 // HINSTANCE hinstLib = LoadLibrary("Kernel32.dll");
189 // if (null != hinstLib)
190 // {
191 // getProcessTimesAddr = (GETPROCTIMES)GetProcAddress(hinstLib, "GetProcessTimes");
192 // if (null != getProcessTimesAddr)
193 // {
194 // return true;
195 // }
196 // FreeLibrary(hinstLib);
197 // }
198 // }
199 // }
200 // return true;
201 //}
202  
203 /*
204 ** Begin timing an operation
205 */
206 static void beginTimer()
207 {
208 if (enableTimer)//&& getProcessTimesAddr != IntPtr.Zero)
209 {
210 //FILETIME ftCreation, ftExit;
211 //getProcessTimesAddr(hProcess, ftCreation, ftExit, ftKernelBegin, ftUserBegin);
212 tsUserBegin = Process.GetCurrentProcess().UserProcessorTime;
213 tsKernelBegin = Process.GetCurrentProcess().TotalProcessorTime - Process.GetCurrentProcess().UserProcessorTime;
214 }
215 }
216  
217 /* Return the difference of two TimeSpan structs in seconds */
218 static double timeDiff(TimeSpan pStart, TimeSpan pEnd)
219 {
220 //sqlite3_int64 i64Start = ((sqlite3_int64)pStart.dwLowDateTime);
221 //sqlite3_int64 i64End = ((sqlite3_int64)pEnd.dwLowDateTime);
222 //return (double)((i64End - i64Start) / 10000000.0);
223 return timeDiff(pStart, pEnd) / 10000000.0;
224 }
225  
226 /*
227 ** Print the timing results.
228 */
229 static void endTimer()
230 {
231 if (enableTimer)// && getProcessTimesAddr != IntPtr.Zero)
232 {
233 //FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
234 //getProcessTimesAddr(hProcess, ftCreation, ftExit, ftKernelEnd, ftUserEnd);
235 TimeSpan tsKernelEnd, tsUserEnd;
236 tsUserEnd = Process.GetCurrentProcess().UserProcessorTime;
237 tsKernelEnd = Process.GetCurrentProcess().TotalProcessorTime - Process.GetCurrentProcess().UserProcessorTime;
238  
239 printf("CPU Time: user %f sys %f\n",
240 timeDiff(tsUserBegin, tsUserEnd),
241 timeDiff(tsKernelBegin, tsKernelEnd));
242 }
243 }
244  
245 //#define BEGIN_TIMER beginTimer()
246 //#define END_TIMER endTimer()
247 //#define HAS_TIMER HAS_TIMER
248 static bool HAS_TIMER = true;
249 #else
250 //#define BEGIN_TIMER
251 //#define END_TIMER
252 //#define HAS_TIMER 0
253 #endif
254  
255 /*
256 ** Used to prevent warnings about unused parameters
257 */
258 //#define UNUSED_PARAMETER(x) ()(x)
259 static void UNUSED_PARAMETER<T>(T x) { }
260  
261 /*
262 ** If the following flag is set, then command execution stops
263 ** at an error if we are not interactive.
264 */
265 static bool bail_on_error = false;
266  
267 /*
268 ** Threat stdin as an interactive input if the following variable
269 ** is true. Otherwise, assume stdin is connected to a file or pipe.
270 */
271 static bool stdin_is_interactive = true;
272  
273 /*
274 ** The following is the open SQLite database. We make a pointer
275 ** to this database a static variable so that it can be accessed
276 ** by the SIGINT handler to interrupt database processing.
277 */
278 static sqlite3 db = null;
279  
280 /*
281 ** True if an interrupt (Control-C) has been received.
282 */
283 static bool seenInterrupt = false;
284  
285 /*
286 ** This is the name of our program. It is set in main(), used
287 ** in a number of other places, mostly for error messages.
288 */
289 static string Argv0;
290  
291 /*
292 ** Prompt strings. Initialized in main. Settable with
293 ** .prompt main continue
294 */
295 static string mainPrompt; /* First line prompt. default: "sqlite> "*/
296 static string continuePrompt; /* Continuation prompt. default: " ...> " */
297  
298 /*
299 ** Write I/O traces to the following stream.
300 */
301 #if SQLITE_ENABLE_IOTRACE
302 static FILE iotrace = null;
303 #endif
304  
305 /*
306 ** This routine works like printf in that its first argument is a
307 ** format string and subsequent arguments are values to be substituted
308 ** in place of % fields. The result of formatting this string
309 ** is written to iotrace.
310 */
311 #if SQLITE_ENABLE_IOTRACE
312 static void iotracePrintf(string zFormat, ...){
313 va_list ap;
314 string z;
315 if( iotrace== null ) return;
316 va_start(ap, zFormat);
317 z = Sqlite3.SQLITE_vmprintf(zFormat, ap);
318 va_end(ap);
319 fprintf(iotrace, "%s", z);
320 Sqlite3.sqlite3_free(z);
321 }
322 #endif
323  
324  
325 /*
326 ** Determines if a string is a number of not.
327 */
328 //static int isNumber(string z, ref int realnum){
329 // if( *z=='-' || *z=='+' ) z++;
330 // if( !isdigit(*z) ){
331 // return 0;
332 // }
333 // z++;
334 // //if( realnum ) *realnum = 0;
335 // realnum = 0;
336 // while( isdigit(*z) ){ z++; }
337 // if( *z=='.' ){
338 // z++;
339 // if( !isdigit(*z) ) return 0;
340 // while( isdigit(*z) ){ z++; }
341 // //if( realnum ) *realnum = 1;
342 // realnum = 1;
343 // }
344 // if( *z=='e' || *z=='E' ){
345 // z++;
346 // if( *z=='+' || *z=='-' ) z++;
347 // if( !isdigit(*z) ) return 0;
348 // while( isdigit(*z) ){ z++; }
349 // //if( realnum ) *realnum = 1;
350 // realnum = 1;
351 // }
352 // return *z== null;
353 //}
354 static bool isNumber(string z)
355 {
356 int i = 0;
357 return isNumber(z, ref i);
358 }
359 static bool isNumber(string z, int i)
360 {
361 return isNumber(z, ref i);
362 }
363 static bool isNumber(string z, ref int realnum)
364 {
365 int zIdx = 0;
366 if (z[zIdx] == '-' || z[zIdx] == '+')
367 zIdx++;
368 if (zIdx == z.Length || !isdigit(z[zIdx]))
369 {
370 return false;
371 }
372 zIdx++;
373 realnum = 0;
374 while (zIdx < z.Length && isdigit(z[zIdx]))
375 {
376 zIdx++;
377 }
378 if (z[zIdx] == '.')
379 {
380 zIdx++;
381 if (zIdx < z.Length && !isdigit(z[zIdx]))
382 return false;
383 while (zIdx < z.Length && isdigit(z[zIdx]))
384 {
385 zIdx++;
386 }
387 realnum = 1;
388 }
389 if (z[zIdx] == 'e' || z[zIdx] == 'E')
390 {
391 zIdx++;
392 if (zIdx < z.Length && (z[zIdx] == '+' || z[zIdx] == '-'))
393 zIdx++;
394 if (zIdx == z.Length || !isdigit(z[zIdx]))
395 return false;
396 while (zIdx < z.Length && isdigit(z[zIdx]))
397 {
398 zIdx++;
399 }
400 realnum = 1;
401 }
402 return zIdx == z.Length;
403 }
404  
405  
406 /*
407 ** A global char* and an SQL function to access its current value
408 ** from within an SQL statement. This program used to use the
409 ** Sqlite3.sqlite3_exec_printf() API to substitue a string into an SQL statement.
410 ** The correct way to do this with sqlite3 is to use the bind API, but
411 ** since the shell is built around the callback paradigm it would be a lot
412 ** of work. Instead just use this hack, which is quite harmless.
413 */
414 static string zShellStatic = "";
415 static void shellstaticFunc(
416 Sqlite3.sqlite3_context context,
417 int argc,
418 sqlite3_value[] argv
419 )
420 {
421 Debug.Assert(0 == argc);
422 Debug.Assert(String.IsNullOrEmpty(zShellStatic));
423 UNUSED_PARAMETER(argc);
424 UNUSED_PARAMETER(argv);
425 Sqlite3.sqlite3_result_text(context, zShellStatic, -1, Sqlite3.SQLITE_STATIC);
426 }
427  
428  
429 /*
430 ** This routine reads a line of text from FILE in, stores
431 ** the text in memory obtained from malloc() and returns a pointer
432 ** to the text. null is returned at end of file, or if malloc()
433 ** fails.
434 **
435 ** The interface is like "readline" but no command-line editing
436 ** is done.
437 */
438 static string local_getline(string zPrompt, TextReader In)
439 {
440 StringBuilder zIn = new StringBuilder();
441 StringBuilder zLine;
442 int nLine;
443 int n;
444 bool eol;
445  
446 if (zPrompt != null)
447 {
448 printf("%s", zPrompt);
449 fflush(stdout);
450 }
451 nLine = 100;
452 zLine = new StringBuilder(nLine);//malloc( nLine );
453 //if( zLine== null ) return 0;
454 n = 0;
455 eol = false;
456 while (!eol)
457 {
458 if (n + 100 > nLine)
459 {
460 nLine = nLine * 2 + 100;
461 zLine.Capacity = (nLine);//= realloc(zLine, nLine);
462 //if (zLine == null)
463 // return null;
464 }
465 if (fgets(zIn, nLine - n, In) == 0)
466 {
467 if (zLine.Length == 0)
468 {
469 zLine = null;//free(zLine);
470 return null;
471 }
472 //zLine[n] = 0;
473 eol = true;
474 break;
475 }
476 n = 0;
477 while (n < zLine.Length && zLine[n] != '\0') { n++; }
478 n = zIn.Length - 1;
479 if (zIn[n] == '\n')
480 {
481 n--;
482 if (n > 0 && zIn[n - 1] == '\r')
483 n--;
484  
485 zIn.Length = n + 1;
486 eol = true;
487 }
488 zLine.Append(zIn);
489 }
490 //zLine = realloc( zLine, n+1 );
491 return zLine.ToString();
492 }
493  
494 /*
495 ** Retrieve a single line of input text.
496 **
497 ** zPrior is a string of prior text retrieved. If not the empty
498 ** string, then issue a continuation prompt.
499 */
500 static string one_input_line(string zPrior, TextReader In)
501 {
502 string zPrompt;
503 string zResult;
504 if (In != null)
505 {
506 return local_getline("", In).ToString();
507 }
508 if (zPrior != null && zPrior.Length > 0)
509 {
510 zPrompt = continuePrompt;
511 }
512 else
513 {
514 zPrompt = mainPrompt;
515 }
516 zResult = readline(zPrompt);
517 #if (HAVE_READLINE) //&& HAVE_READLINE==1
518 if( zResult && *zResult ) add_history(zResult);
519 #endif
520 return zResult;
521 }
522  
523 class previous_mode_data
524 {
525 public bool valid; /* Is there legit data in here? */
526 public int mode;
527 public bool showHeader;
528 public int[] colWidth = new int[200];
529 };
530  
531 /*
532 ** An pointer to an instance of this structure is passed from
533 ** the main program to the callback. This is used to communicate
534 ** state and mode information.
535 */
536 class callback_data
537 {
538 public sqlite3 db; /* The database */
539 public bool echoOn; /* True to echo input commands */
540 public bool statsOn; /* True to display memory stats before each finalize */
541 public int cnt; /* Number of records displayed so far */
542 public FILE Out; /* Write results here */
543 public int mode; /* An output mode setting */
544 public bool writableSchema; /* True if PRAGMA writable_schema=ON */
545 public bool showHeader; /* True to show column names in List or Column mode */
546 public string zDestTable; /* Name of destination table when MODE_Insert */
547 public string separator = ""; /* Separator character for MODE_List */
548 public int[] colWidth = new int[200]; /* Requested width of each column when in column mode*/
549 public int[] actualWidth = new int[200]; /* Actual width of each column */
550 public string nullvalue = "NULL"; /* The text to print when a null comes back from
551 ** the database */
552 public previous_mode_data explainPrev = new previous_mode_data();
553 /* Holds the mode information just before
554 ** .explain ON */
555 public StringBuilder outfile = new StringBuilder(260); /* Filename for Out */
556 public string zDbFilename; /* name of the database file */
557 public string zVfs; /* Name of VFS to use */
558 public sqlite3_stmt pStmt; /* Current statement if any. */
559 public FILE pLog; /* Write log output here */
560  
561 internal callback_data Copy()
562 {
563 return (callback_data)this.MemberwiseClone();
564 }
565 };
566 // Store callback data variant
567 class callback_data_extra
568 {
569 public string[] azCols; //(string *)pData; /* Names of result columns */
570 public string[] azVals;//azCols[nCol]; /* Results */
571 public int[] aiTypes; //(int *)&azVals[nCol]; /* Result types */
572 }
573 /*
574 ** These are the allowed modes.
575 */
576 //#define MODE_Line 0 /* One column per line. Blank line between records */
577 //#define MODE_Column 1 /* One record per line in neat columns */
578 //#define MODE_List 2 /* One record per line with a separator */
579 //#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
580 //#define MODE_Html 4 /* Generate an XHTML table */
581 //#define MODE_Insert 5 /* Generate SQL "insert" statements */
582 //#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
583 //#define MODE_Csv 7 /* Quote strings, numbers are plain */
584 //#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
585 const int MODE_Line = 0;
586 const int MODE_Column = 1;
587 const int MODE_List = 2;
588 const int MODE_Semi = 3;
589 const int MODE_Html = 4;
590 const int MODE_Insert = 5;
591 const int MODE_Tcl = 6;
592 const int MODE_Csv = 7;
593 const int MODE_Explain = 8;
594  
595 static string[] modeDescr = new string[] {
596 "line",
597 "column",
598 "list",
599 "semi",
600 "html",
601 "insert",
602 "tcl",
603 "csv",
604 "explain",
605 };
606  
607 /*
608 ** Number of elements in an array
609 */
610 //#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
611 static int ArraySize<T>(T[] X) { return X.Length; }
612  
613 /*
614 ** Compute a string length that is limited to what can be stored in
615 ** lower 30 bits of a 32-bit signed integer.
616 */
617 static int strlen30(StringBuilder z)
618 {
619 //string z2 = z;
620 //while( *z2 ){ z2++; }
621 return 0x3fffffff & z.Length;//(int)(z2 - z);
622 }
623 static int strlen30(string z)
624 {
625 //string z2 = z;
626 //while( *z2 ){ z2++; }
627 return 0x3fffffff & z.Length;//(int)(z2 - z);
628 }
629  
630  
631 /*
632 ** A callback for the Sqlite3.SQLITE_log() interface.
633 */
634 static void shellLog(object pArg, int iErrCode, string zMsg)
635 {
636 callback_data p = (callback_data)pArg;
637 if (p.pLog == null)
638 return;
639 fprintf(p.pLog, "(%d) %s\n", iErrCode, zMsg);
640 fflush(p.pLog);
641 }
642  
643 /*
644 ** Output the given string as a hex-encoded blob (eg. X'1234' )
645 */
646 static void output_hex_blob(FILE Out, byte[] pBlob, int nBlob)
647 {
648 int i;
649 //string zBlob = (string )pBlob;
650 fprintf(Out, "X'");
651 for (i = 0; i < nBlob; i++) { fprintf(Out, "%02x", pBlob[i]); }
652 fprintf(Out, "'");
653 }
654  
655 /*
656 ** Output the given string as a quoted string using SQL quoting conventions.
657 */
658 static void output_quoted_string(TextWriter Out, string z)
659 {
660 int i;
661 int nSingle = 0;
662 for (i = 0; z[i] != '\0'; i++)
663 {
664 if (z[i] == '\'')
665 nSingle++;
666 }
667 if (nSingle == 0)
668 {
669 fprintf(Out, "'%s'", z);
670 }
671 else
672 {
673 fprintf(Out, "'");
674 while (z != "")
675 {
676 for (i = 0; i < z.Length && z[i] != '\''; i++)
677 {
678 }
679 if (i == 0)
680 {
681 fprintf(Out, "''");
682 //z++;
683 }
684 else if (z[i] == '\'')
685 {
686 fprintf(Out, "%.*s''", i, z);
687 //z += i + 1;
688 }
689 else
690 {
691 fprintf(Out, "%s", z);
692 break;
693 }
694 }
695 fprintf(Out, "'");
696 }
697 }
698  
699 /*
700 ** Output the given string as a quoted according to C or TCL quoting rules.
701 */
702 static void output_c_string(TextWriter Out, string z)
703 {
704 char c;
705 fputc('"', Out);
706 int zIdx = 0;
707 while (zIdx < z.Length && (c = z[zIdx++]) != '\0')
708 {
709 if (c == '\\')
710 {
711 fputc(c, Out);
712 fputc(c, Out);
713 }
714 else if (c == '\t')
715 {
716 fputc('\\', Out);
717 fputc('t', Out);
718 }
719 else if (c == '\n')
720 {
721 fputc('\\', Out);
722 fputc('n', Out);
723 }
724 else if (c == '\r')
725 {
726 fputc('\\', Out);
727 fputc('r', Out);
728 }
729 else if (!isprint(c))
730 {
731 fprintf(Out, "\\%03o", c & 0xff);
732 }
733 else
734 {
735 fputc(c, Out);
736 }
737 }
738 fputc('"', Out);
739 }
740  
741  
742 /*
743 ** Output the given string with characters that are special to
744 ** HTML escaped.
745 */
746 static void output_html_string(TextWriter Out, string z)
747 {
748 int i;
749 while (z != "")
750 {
751 for (i = 0; i < z.Length && z[i] != '<' && z[i] != '&'; i++)
752 {
753 }
754 if (i > 0)
755 {
756 fprintf(Out, "%.*s", i, z);
757 }
758 if (i < z.Length && z[i] == '<')
759 {
760 fprintf(Out, "&lt;");
761 }
762 else if (i < z.Length && z[i] == '&')
763 {
764 fprintf(Out, "&amp;");
765 }
766 else if (i < z.Length && z[i] == '\"')
767 {
768 fprintf(Out, "&quot;");
769 }
770 else if (i < z.Length && z[i] == '\'')
771 {
772 fprintf(Out, "&#39;");
773 }
774 else
775 {
776 break;
777 }
778 z += i + 1;
779 }
780 }
781  
782 /*
783 ** If a field contains any character identified by a 1 in the following
784 ** array, then the string must be quoted for CSV.
785 */
786 static byte[] needCsvQuote = new byte[] {
787 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
788 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
789 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
790 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
793 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
794 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
795 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
796 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
797 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
798 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
799 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
800 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
801 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
802 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
803 };
804  
805 /*
806 ** Output a single term of CSV. Actually, p.separator is used for
807 ** the separator, which may or may not be a comma. p.nullvalue is
808 ** the null value. Strings are quoted using ANSI-C rules. Numbers
809 ** appear outside of quotes.
810 */
811 static void output_csv(callback_data p, string z, bool bSep)
812 {
813 TextWriter Out = p.Out;
814 if (z == null)
815 {
816 fprintf(Out, "%s", p.nullvalue);
817 }
818 else
819 {
820 int i;
821 int nSep = strlen30(p.separator);
822 for (i = 0; i < z.Length; i++)
823 {
824 if (needCsvQuote[z[i]] != 0
825 || (z[i] == p.separator[0] &&
826 (nSep == 1 || z == p.separator)))
827 {
828 i = 0;
829 break;
830 }
831 }
832 if (i == 0)
833 {
834 putc('"', Out);
835 for (i = 0; i < z.Length; i++)
836 {
837 if (z[i] == '"')
838 putc('"', Out);
839 putc(z[i], Out);
840 }
841 putc('"', Out);
842 }
843 else
844 {
845 fprintf(Out, "%s", z);
846 }
847 }
848 if (bSep)
849 {
850 fprintf(p.Out, "%s", p.separator);
851 }
852 }
853  
854  
855 #if SIGINT
856 /*
857 ** This routine runs when the user presses Ctrl-C
858 */
859 static void interrupt_handler(int NotUsed){
860 UNUSED_PARAMETER(NotUsed);
861 seenInterrupt = 1;
862 if( db ) Sqlite3.SQLITE_interrupt(db);
863 }
864 #endif
865  
866 /*
867 ** This is the callback routine that the shell
868 ** invokes for each row of a query result.
869 */
870 static int shell_callback(object pArg, sqlite3_int64 nArg, object p2, object p3)
871 {
872 int i;
873 callback_data p = (callback_data)pArg;
874  
875 //Unpack
876 string[] azArg = ((callback_data_extra)p2).azVals;
877 string[] azCol = ((callback_data_extra)p2).azCols;
878 int[] aiType = ((callback_data_extra)p2).aiTypes;
879  
880 switch (p.mode)
881 {
882 case MODE_Line:
883 {
884 int w = 5;
885 if (azArg == null)
886 break;
887 for (i = 0; i < nArg; i++)
888 {
889 int len = strlen30(azCol[i] != null ? azCol[i] : "");
890 if (len > w)
891 w = len;
892 }
893 if (p.cnt++ > 0)
894 fprintf(p.Out, "\n");
895 for (i = 0; i < nArg; i++)
896 {
897 fprintf(p.Out, "%*s = %s\n", w, azCol[i],
898 azArg[i] != null ? azArg[i] : p.nullvalue);
899 }
900 break;
901 }
902 case MODE_Explain:
903 case MODE_Column:
904 {
905 if (p.cnt++ == 0)
906 {
907 for (i = 0; i < nArg; i++)
908 {
909 int w, n;
910 if (i < ArraySize(p.colWidth))
911 {
912 w = p.colWidth[i];
913 }
914 else
915 {
916 w = 0;
917 }
918 if (w <= 0)
919 {
920 w = strlen30(azCol[i] != null ? azCol[i] : "");
921 if (w < 10)
922 w = 10;
923 n = strlen30(azArg != null && azArg[i] != null ? azArg[i] : p.nullvalue);
924 if (w < n)
925 w = n;
926 }
927 if (i < ArraySize(p.actualWidth))
928 {
929 p.actualWidth[i] = w;
930 }
931 if (p.showHeader)
932 {
933 fprintf(p.Out, "%-*.*s%s", w, w, azCol[i], i == nArg - 1 ? "\n" : " ");
934 }
935 }
936 if (p.showHeader)
937 {
938 for (i = 0; i < nArg; i++)
939 {
940 int w;
941 if (i < ArraySize(p.actualWidth))
942 {
943 w = p.actualWidth[i];
944 }
945 else
946 {
947 w = 10;
948 }
949 fprintf(p.Out, "%-*.*s%s", w, w, "-----------------------------------" +
950 "----------------------------------------------------------",
951 i == nArg - 1 ? "\n" : " ");
952 }
953 }
954 }
955 if (azArg == null)
956 break;
957 for (i = 0; i < nArg; i++)
958 {
959 int w;
960 if (i < ArraySize(p.actualWidth))
961 {
962 w = p.actualWidth[i];
963 }
964 else
965 {
966 w = 10;
967 }
968 if (p.mode == MODE_Explain && azArg[i] != null &&
969 strlen30(azArg[i]) > w)
970 {
971 w = strlen30(azArg[i]);
972 }
973 fprintf(p.Out, "%-*.*s%s", w, w,
974 azArg[i] != null ? azArg[i] : p.nullvalue, i == nArg - 1 ? "\n" : " ");
975 }
976 break;
977 }
978 case MODE_Semi:
979 case MODE_List:
980 {
981 if (p.cnt++ == null && p.showHeader)
982 {
983 for (i = 0; i < nArg; i++)
984 {
985 fprintf(p.Out, "%s%s", azCol[i], i == nArg - 1 ? "\n" : p.separator);
986 }
987 }
988 if (azArg == null)
989 break;
990 for (i = 0; i < nArg; i++)
991 {
992 string z = azArg[i];
993 if (z == null)
994 z = p.nullvalue;
995 fprintf(p.Out, "%s", z);
996 if (i < nArg - 1)
997 {
998 fprintf(p.Out, "%s", p.separator);
999 }
1000 else if (p.mode == MODE_Semi)
1001 {
1002 fprintf(p.Out, ";\n");
1003 }
1004 else
1005 {
1006 fprintf(p.Out, "\n");
1007 }
1008 }
1009 break;
1010 }
1011 case MODE_Html:
1012 {
1013 if (p.cnt++ == null && p.showHeader)
1014 {
1015 fprintf(p.Out, "<TR>");
1016 for (i = 0; i < nArg; i++)
1017 {
1018 fprintf(p.Out, "<TH>");
1019 output_html_string(p.Out, azCol[i]);
1020 fprintf(p.Out, "</TH>\n");
1021 }
1022 fprintf(p.Out, "</TR>\n");
1023 }
1024 if (azArg == null)
1025 break;
1026 fprintf(p.Out, "<TR>");
1027 for (i = 0; i < nArg; i++)
1028 {
1029 fprintf(p.Out, "<TD>");
1030 output_html_string(p.Out, azArg[i] != null ? azArg[i] : p.nullvalue);
1031 fprintf(p.Out, "</TD>\n");
1032 }
1033 fprintf(p.Out, "</TR>\n");
1034 break;
1035 }
1036 case MODE_Tcl:
1037 {
1038 if (p.cnt++ == null && p.showHeader)
1039 {
1040 for (i = 0; i < nArg; i++)
1041 {
1042 output_c_string(p.Out, azCol[i] != null ? azCol[i] : "");
1043 fprintf(p.Out, "%s", p.separator);
1044 }
1045 fprintf(p.Out, "\n");
1046 }
1047 if (azArg == null)
1048 break;
1049 for (i = 0; i < nArg; i++)
1050 {
1051 output_c_string(p.Out, azArg[i] != null ? azArg[i] : p.nullvalue);
1052 fprintf(p.Out, "%s", p.separator);
1053 }
1054 fprintf(p.Out, "\n");
1055 break;
1056 }
1057 case MODE_Csv:
1058 {
1059 if (p.cnt++ == null && p.showHeader)
1060 {
1061 for (i = 0; i < nArg; i++)
1062 {
1063 output_csv(p, azCol[i] != null ? azCol[i] : "", i < nArg - 1);
1064 }
1065 fprintf(p.Out, "\n");
1066 }
1067 if (azArg == null)
1068 break;
1069 for (i = 0; i < nArg; i++)
1070 {
1071 output_csv(p, azArg[i], i < nArg - 1);
1072 }
1073 fprintf(p.Out, "\n");
1074 break;
1075 }
1076 case MODE_Insert:
1077 {
1078 p.cnt++;
1079 if (azArg == null)
1080 break;
1081 fprintf(p.Out, "INSERT INTO %s VALUES(", p.zDestTable);
1082 for (i = 0; i < nArg; i++)
1083 {
1084 string zSep = i > 0 ? "," : "";
1085 if ((azArg[i] == null) || (aiType != null && i < aiType.Length && aiType[i] == Sqlite3.SQLITE_NULL))
1086 {
1087 fprintf(p.Out, "%snull", zSep);
1088 }
1089 else if (aiType != null && aiType[i] == Sqlite3.SQLITE_TEXT)
1090 {
1091 if (!String.IsNullOrEmpty(zSep))
1092 fprintf(p.Out, "%s", zSep);
1093 output_quoted_string(p.Out, azArg[i]);
1094 }
1095 else if (aiType != null && (aiType[i] == Sqlite3.SQLITE_INTEGER || aiType[i] == Sqlite3.SQLITE_FLOAT))
1096 {
1097 fprintf(p.Out, "%s%s", zSep, azArg[i]);
1098 }
1099 else if (aiType != null && aiType[i] == Sqlite3.SQLITE_BLOB && p.pStmt != null)
1100 {
1101 byte[] pBlob = Sqlite3.sqlite3_column_blob(p.pStmt, i);
1102 int nBlob = Sqlite3.sqlite3_column_bytes(p.pStmt, i);
1103 if (!String.IsNullOrEmpty(zSep))
1104 fprintf(p.Out, "%s", zSep);
1105 output_hex_blob(p.Out, pBlob, nBlob);
1106 }
1107 else if (isNumber(azArg[i], 0))
1108 {
1109 fprintf(p.Out, "%s%s", zSep, azArg[i]);
1110 }
1111 else
1112 {
1113 if (!String.IsNullOrEmpty(zSep))
1114 fprintf(p.Out, "%s", zSep);
1115 output_quoted_string(p.Out, azArg[i]);
1116 }
1117 }
1118 fprintf(p.Out, ");\n");
1119 break;
1120 }
1121 }
1122 return 0;
1123 }
1124  
1125 /*
1126 ** This is the callback routine that the SQLite library
1127 ** invokes for each row of a query result.
1128 */
1129 static int callback(object pArg, sqlite3_int64 nArg, object azArg, object azCol)
1130 {
1131 /* since we don't have type info, call the shell_callback with a null value */
1132 callback_data_extra cde = new callback_data_extra();
1133 cde.azVals = (string[])azArg;
1134 cde.azCols = (string[])azCol;
1135 cde.aiTypes = null;
1136 return shell_callback(pArg, (int)nArg, cde, null);
1137 }
1138  
1139 /*
1140 ** Set the destination table field of the callback_data structure to
1141 ** the name of the table given. Escape any quote characters in the
1142 ** table name.
1143 */
1144 static void set_table_name(callback_data p, string zName)
1145 {
1146 int i, n;
1147 bool needQuote;
1148 string z = "";
1149  
1150 if (p.zDestTable != null)
1151 {
1152 //free(ref p.zDestTable);
1153 p.zDestTable = null;
1154 }
1155 if (zName == null)
1156 return;
1157 needQuote = !isalpha(zName[0]) && zName != "_";
1158 for (i = n = 0; i < zName.Length; i++, n++)
1159 {
1160 if (!isalnum(zName[i]) && zName[i] != '_')
1161 {
1162 needQuote = true;
1163 if (zName[i] == '\'')
1164 n++;
1165 }
1166 }
1167 if (needQuote)
1168 n += 2;
1169 //z = p.zDestTable = malloc( n + 1 );
1170 //if ( z == 0 )
1171 //{
1172 // fprintf( stderr, "Out of memory!\n" );
1173 // exit( 1 );
1174 //}
1175 //n = 0;
1176 if (needQuote)
1177 z += '\'';
1178 for (i = 0; i < zName.Length; i++)
1179 {
1180 z += zName[i];
1181 if (zName[i] == '\'')
1182 z += '\'';
1183 }
1184 if (needQuote)
1185 z += '\'';
1186 //z[n] = 0;
1187 p.zDestTable = z;
1188 }
1189  
1190 /* zIn is either a pointer to a null-terminated string in memory obtained
1191 ** from malloc(), or a null pointer. The string pointed to by zAppend is
1192 ** added to zIn, and the result returned in memory obtained from malloc().
1193 ** zIn, if it was not null, is freed.
1194 **
1195 ** If the third argument, quote, is not '\0', then it is used as a
1196 ** quote character for zAppend.
1197 */
1198 static void appendText(StringBuilder zIn, string zAppend, int noQuote)
1199 { appendText(zIn, zAppend, '\0'); }
1200  
1201 static void appendText(StringBuilder zIn, string zAppend, char quote)
1202 {
1203 int len;
1204 int i;
1205 int nAppend = strlen30(zAppend);
1206 int nIn = (zIn != null ? strlen30(zIn) : 0);
1207  
1208 len = nAppend + nIn;
1209 if (quote != '\0')
1210 {
1211 len += 2;
1212 for (i = 0; i < nAppend; i++)
1213 {
1214 if (zAppend[i] == quote)
1215 len++;
1216 }
1217 }
1218  
1219 //zIn = realloc( zIn, len );
1220 //if ( !zIn )
1221 //{
1222 // return 0;
1223 //}
1224  
1225 if (quote != '\0')
1226 {
1227 zIn.Append(quote);
1228 for (i = 0; i < nAppend; i++)
1229 {
1230 zIn.Append(zAppend[i]);
1231 if (zAppend[i] == quote)
1232 zIn.Append(quote);
1233 }
1234 zIn.Append(quote);
1235 //zCsr++ = '\0';
1236 Debug.Assert(zIn.Length == len);
1237  
1238 }
1239 else
1240 {
1241 zIn.Append(zAppend);//memcpy( zIn[nIn], zAppend, nAppend );
1242 //zIn[len - 1] = '\0';
1243 }
1244 }
1245  
1246  
1247  
1248 /*
1249 ** Execute a query statement that has a single result column. Print
1250 ** that result column on a line by itself with a semicolon terminator.
1251 **
1252 ** This is used, for example, to show the schema of the database by
1253 ** querying the Sqlite3.SQLITE_MASTER table.
1254 */
1255 static int run_table_dump_query(
1256 FILE Out, /* Send output here */
1257 sqlite3 db, /* Database to query */
1258 StringBuilder zSelect, /* SELECT statement to extract content */
1259 string zFirstRow /* Print before first row, if not null */
1260 )
1261 { return run_table_dump_query(Out, db, zSelect.ToString(), zFirstRow); }
1262  
1263 static int run_table_dump_query(
1264 FILE Out, /* Send output here */
1265 sqlite3 db, /* Database to query */
1266 string zSelect, /* SELECT statement to extract content */
1267 string zFirstRow /* Print before first row, if not null */
1268 )
1269 {
1270 sqlite3_stmt pSelect = null;
1271 int rc;
1272 rc = Sqlite3.sqlite3_prepare(db, zSelect, -1, ref pSelect, 0);
1273 if (rc != Sqlite3.SQLITE_OK || null == pSelect)
1274 {
1275 return rc;
1276 }
1277 rc = Sqlite3.sqlite3_step(pSelect);
1278 while (rc == Sqlite3.SQLITE_ROW)
1279 {
1280 if (zFirstRow != null)
1281 {
1282 fprintf(Out, "%s", zFirstRow);
1283 zFirstRow = null;
1284 }
1285 fprintf(Out, "%s;\n", Sqlite3.sqlite3_column_text(pSelect, 0));
1286 rc = Sqlite3.sqlite3_step(pSelect);
1287 }
1288 return Sqlite3.sqlite3_finalize(pSelect);
1289 }
1290  
1291 /*
1292 ** Allocate space and save off current error string.
1293 */
1294 static string save_err_msg(
1295 sqlite3 db /* Database to query */
1296 )
1297 {
1298 //int nErrMsg = 1 + strlen30(Sqlite3.sqlite3_errmsg(db));
1299 //string zErrMsg = Sqlite3.sqlite3_malloc(nErrMsg);
1300 //if (zErrMsg != null)
1301 //{
1302 // memcpy(zErrMsg, Sqlite3.sqlite3_errmsg(db), nErrMsg);
1303 //}
1304 return Sqlite3.sqlite3_errmsg(db); //zErrMsg;
1305 }
1306  
1307 /*
1308 ** Display memory stats.
1309 */
1310 static int display_stats(
1311 sqlite3 db, /* Database to query */
1312 callback_data pArg, /* Pointer to struct callback_data */
1313 int bReset /* True to reset the stats */
1314 )
1315 {
1316 int iCur;
1317 int iHiwtr;
1318  
1319 if (pArg != null && pArg.Out != null)
1320 {
1321  
1322 iHiwtr = iCur = -1;
1323 Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_MEMORY_USED, ref iCur, ref iHiwtr, bReset);
1324 fprintf(pArg.Out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr);
1325 iHiwtr = iCur = -1;
1326 Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_MALLOC_COUNT, ref iCur, ref iHiwtr, bReset);
1327 fprintf(pArg.Out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr);
1328 /*
1329 ** Not currently used by the CLI.
1330 ** iHiwtr = iCur = -1;
1331 ** Sqlite3.SQLITE_status(Sqlite3.SQLITE_STATUS_PAGECACHE_USED,ref iCur,ref iHiwtr, bReset);
1332 ** fprintf(pArg.Out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr);
1333 */
1334 iHiwtr = iCur = -1;
1335 Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_PAGECACHE_OVERFLOW, ref iCur, ref iHiwtr, bReset);
1336 fprintf(pArg.Out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr);
1337 /*
1338 ** Not currently used by the CLI.
1339 ** iHiwtr = iCur = -1;
1340 ** Sqlite3.SQLITE_status(Sqlite3.SQLITE_STATUS_SCRATCH_USED,ref iCur,ref iHiwtr, bReset);
1341 ** fprintf(pArg.Out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr);
1342 */
1343 iHiwtr = iCur = -1;
1344 Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_SCRATCH_OVERFLOW, ref iCur, ref iHiwtr, bReset);
1345 fprintf(pArg.Out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr);
1346 iHiwtr = iCur = -1;
1347 Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_MALLOC_SIZE, ref iCur, ref iHiwtr, bReset);
1348 fprintf(pArg.Out, "Largest Allocation: %d bytes\n", iHiwtr);
1349 iHiwtr = iCur = -1;
1350 Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_PAGECACHE_SIZE, ref iCur, ref iHiwtr, bReset);
1351 fprintf(pArg.Out, "Largest Pcache Allocation: %d bytes\n", iHiwtr);
1352 iHiwtr = iCur = -1;
1353 Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_SCRATCH_SIZE, ref iCur, ref iHiwtr, bReset);
1354 fprintf(pArg.Out, "Largest Scratch Allocation: %d bytes\n", iHiwtr);
1355 #if YYTRACKMAXSTACKDEPTH
1356 iHiwtr = iCur = -1;
1357 Sqlite3.SQLITE_status(Sqlite3.SQLITE_STATUS_PARSER_STACK,ref iCur,ref iHiwtr, bReset);
1358 fprintf(pArg.Out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr);
1359 #endif
1360 }
1361  
1362 if (pArg != null && pArg.Out != null && db != null)
1363 {
1364 iHiwtr = iCur = -1;
1365 Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_LOOKASIDE_USED, ref iCur, ref iHiwtr, bReset);
1366 fprintf(pArg.Out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
1367 Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_LOOKASIDE_HIT, ref iCur, ref iHiwtr, bReset);
1368 fprintf(pArg.Out, "Successful lookaside attempts: %d\n", iHiwtr);
1369 Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, ref iCur, ref iHiwtr, bReset);
1370 fprintf(pArg.Out, "Lookaside failures due to size: %d\n", iHiwtr);
1371 Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, ref iCur, ref iHiwtr, bReset);
1372 fprintf(pArg.Out, "Lookaside failures due to OOM: %d\n", iHiwtr);
1373 iHiwtr = iCur = -1;
1374 Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_CACHE_USED, ref iCur, ref iHiwtr, bReset);
1375 fprintf(pArg.Out, "Pager Heap Usage: %d bytes\n", iCur);
1376 iHiwtr = iCur = -1;
1377 Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_SCHEMA_USED, ref iCur, ref iHiwtr, bReset);
1378 fprintf(pArg.Out, "Schema Heap Usage: %d bytes\n", iCur);
1379 iHiwtr = iCur = -1;
1380 Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_STMT_USED, ref iCur, ref iHiwtr, bReset);
1381 fprintf(pArg.Out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
1382 }
1383  
1384 if (pArg != null && pArg.Out != null && db != null && pArg.pStmt != null)
1385 {
1386 iCur = Sqlite3.sqlite3_stmt_status(pArg.pStmt, Sqlite3.SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
1387 fprintf(pArg.Out, "Fullscan Steps: %d\n", iCur);
1388 iCur = Sqlite3.sqlite3_stmt_status(pArg.pStmt, Sqlite3.SQLITE_STMTSTATUS_SORT, bReset);
1389 fprintf(pArg.Out, "Sort Operations: %d\n", iCur);
1390 iCur = Sqlite3.sqlite3_stmt_status(pArg.pStmt, Sqlite3.SQLITE_STMTSTATUS_AUTOINDEX, bReset);
1391 fprintf(pArg.Out, "Autoindex Inserts: %d\n", iCur);
1392 }
1393  
1394 return 0;
1395 }
1396  
1397 /*
1398 ** Execute a statement or set of statements. Print
1399 ** any result rows/columns depending on the current mode
1400 ** set via the supplied callback.
1401 **
1402 ** This is very similar to SQLite's built-in Sqlite3.sqlite3_exec()
1403 ** function except it takes a slightly different callback
1404 ** and callback data argument.
1405 */
1406 static int shell_exec(
1407 sqlite3 db, /* An open database */
1408 string zSql, /* SQL to be evaluated */
1409 dxCallback xCallback, //int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */
1410 /* (not the same as Sqlite3.sqlite3_exec) */
1411 callback_data pArg, /* Pointer to struct callback_data */
1412 ref string pzErrMsg /* Error msg written here */
1413 )
1414 {
1415 sqlite3_stmt pStmt = null; /* Statement to execute. */
1416 int rc = Sqlite3.SQLITE_OK; /* Return Code */
1417 string zLeftover = null; /* Tail of unprocessed SQL */
1418  
1419 // if( pzErrMsg )
1420 {
1421 pzErrMsg = null;
1422 }
1423  
1424 while (!String.IsNullOrEmpty(zSql) && (Sqlite3.SQLITE_OK == rc))
1425 {
1426 rc = Sqlite3.sqlite3_prepare_v2(db, zSql, -1, ref pStmt, ref zLeftover);
1427 if (Sqlite3.SQLITE_OK != rc)
1428 {
1429 //if (pzErrMsg != null)
1430 {
1431 pzErrMsg = save_err_msg(db);
1432 }
1433 }
1434 else
1435 {
1436 if (null == pStmt)
1437 {
1438 /* this happens for a comment or white-space */
1439 zSql = zLeftover.TrimStart();
1440 //while (isspace(zSql[0]))
1441 // zSql++;
1442 continue;
1443 }
1444  
1445 /* save off the prepared statment handle and reset row count */
1446 if (pArg != null)
1447 {
1448 pArg.pStmt = pStmt;
1449 pArg.cnt = 0;
1450 }
1451  
1452 /* echo the sql statement if echo on */
1453 if (pArg != null && pArg.echoOn)
1454 {
1455 string zStmtSql = Sqlite3.sqlite3_sql(pStmt);
1456 fprintf(pArg.Out, "%s\n", zStmtSql != null ? zStmtSql : zSql);
1457 }
1458  
1459 /* perform the first step. this will tell us if we
1460 ** have a result set or not and how wide it is.
1461 */
1462 rc = Sqlite3.sqlite3_step(pStmt);
1463 /* if we have a result set... */
1464 if (Sqlite3.SQLITE_ROW == rc)
1465 {
1466 /* if we have a callback... */
1467 if (xCallback != null)
1468 {
1469 /* allocate space for col name ptr, value ptr, and type */
1470 int nCol = Sqlite3.sqlite3_column_count(pStmt);
1471 //void pData = Sqlite3.SQLITE_malloc(3*nCol*sizeof(const char*) + 1);
1472 //if( !pData ){
1473 // rc = Sqlite3.SQLITE_NOMEM;
1474 //}else
1475 {
1476 string[] azCols = new string[nCol];//(string *)pData; /* Names of result columns */
1477 string[] azVals = new string[nCol];//azCols[nCol]; /* Results */
1478 int[] aiTypes = new int[nCol];//(int *)&azVals[nCol]; /* Result types */
1479 int i;
1480 //Debug.Assert(sizeof(int) <= sizeof(string ));
1481 /* save off ptrs to column names */
1482 for (i = 0; i < nCol; i++)
1483 {
1484 azCols[i] = (string)Sqlite3.sqlite3_column_name(pStmt, i);
1485 }
1486 do
1487 {
1488 /* extract the data and data types */
1489 for (i = 0; i < nCol; i++)
1490 {
1491 azVals[i] = (string)Sqlite3.sqlite3_column_text(pStmt, i);
1492 aiTypes[i] = Sqlite3.sqlite3_column_type(pStmt, i);
1493 if (null == azVals[i] && (aiTypes[i] != Sqlite3.SQLITE_NULL))
1494 {
1495 rc = Sqlite3.SQLITE_NOMEM;
1496 break; /* from for */
1497 }
1498 } /* end for */
1499  
1500 /* if data and types extracted successfully... */
1501 if (Sqlite3.SQLITE_ROW == rc)
1502 {
1503 /* call the supplied callback with the result row data */
1504 callback_data_extra cde = new callback_data_extra();
1505 cde.azVals = azVals;
1506 cde.azCols = azCols;
1507 cde.aiTypes = aiTypes;
1508  
1509 if (xCallback(pArg, nCol, cde, null) != 0)
1510 {
1511 rc = Sqlite3.SQLITE_ABORT;
1512 }
1513 else
1514 {
1515 rc = Sqlite3.sqlite3_step(pStmt);
1516 }
1517 }
1518 } while (Sqlite3.SQLITE_ROW == rc);
1519 //Sqlite3.sqlite3_free(ref pData);
1520 }
1521 }
1522 else
1523 {
1524 do
1525 {
1526 rc = Sqlite3.sqlite3_step(pStmt);
1527 } while (rc == Sqlite3.SQLITE_ROW);
1528 }
1529 }
1530  
1531 /* print usage stats if stats on */
1532 if (pArg != null && pArg.statsOn)
1533 {
1534 display_stats(db, pArg, 0);
1535 }
1536  
1537 /* Finalize the statement just executed. If this fails, save a
1538 ** copy of the error message. Otherwise, set zSql to point to the
1539 ** next statement to execute. */
1540 rc = Sqlite3.sqlite3_finalize(pStmt);
1541 if (rc == Sqlite3.SQLITE_OK)
1542 {
1543 zSql = zLeftover.TrimStart();
1544 //while (isspace(zSql[0]))
1545 // zSql++;
1546 }
1547 else //if (pzErrMsg)
1548 {
1549 pzErrMsg = save_err_msg(db);
1550 }
1551  
1552 /* clear saved stmt handle */
1553 if (pArg != null)
1554 {
1555 pArg.pStmt = null;
1556 }
1557 }
1558 } /* end while */
1559  
1560 return rc;
1561 }
1562  
1563  
1564 /*
1565 ** This is a different callback routine used for dumping the database.
1566 ** Each row received by this callback consists of a table name,
1567 ** the table type ("index" or "table") and SQL to create the table.
1568 ** This routine should print text sufficient to recreate the table.
1569 */
1570 static int dump_callback(object pArg, sqlite3_int64 nArg, object pazArg, object pazCol)
1571 {
1572 int rc;
1573 string zTable;
1574 string zType;
1575 string zSql;
1576 string zPrepStmt = null;
1577 callback_data p = (callback_data)pArg;
1578 string[] azArg = (string[])pazArg;
1579 string[] azCol = (string[])pazCol;
1580  
1581 UNUSED_PARAMETER(azCol);
1582 if (nArg != 3)
1583 return 1;
1584 zTable = azArg[0];
1585 zType = azArg[1];
1586 zSql = azArg[2];
1587  
1588 if (zTable.Equals("sqlite_sequence", StringComparison.InvariantCultureIgnoreCase))
1589 {
1590 zPrepStmt = "DELETE FROM sqlite_sequence;\n";
1591 }
1592 else if (zTable.Equals("sqlite_stat1", StringComparison.InvariantCultureIgnoreCase))
1593 {
1594 fprintf(p.Out, "ANALYZE Sqlite3.SQLITE_master;\n");
1595 }
1596 else if (zTable.StartsWith("SQLITE_", StringComparison.InvariantCultureIgnoreCase))
1597 {
1598 return 0;
1599 }
1600 else if (zSql.StartsWith("CREATE VIRTUAL TABLE", StringComparison.InvariantCultureIgnoreCase))
1601 {
1602 string zIns;
1603 if (!p.writableSchema)
1604 {
1605 fprintf(p.Out, "PRAGMA writable_schema=ON;\n");
1606 p.writableSchema = true;
1607 }
1608 zIns = Sqlite3.sqlite3_mprintf(
1609 "INSERT INTO Sqlite3.SQLITE_master(type,name,tbl_name,rootpage,sql)" +
1610 "VALUES('table','%q','%q',0,'%q');",
1611 zTable, zTable, zSql);
1612 fprintf(p.Out, "%s\n", zIns);
1613 zIns = null;//Sqlite3.sqlite3_free(zIns);
1614 return 0;
1615 }
1616 else
1617 {
1618 fprintf(p.Out, "%s;\n", zSql);
1619 }
1620  
1621 if (zType.Equals("table", StringComparison.InvariantCultureIgnoreCase))
1622 {
1623 sqlite3_stmt pTableInfo = null;
1624 StringBuilder zSelect = new StringBuilder();
1625 StringBuilder zTableInfo = new StringBuilder();
1626 StringBuilder zTmp = new StringBuilder();
1627 int nRow = 0;
1628  
1629 appendText(zTableInfo, "PRAGMA table_info(", 0);
1630 appendText(zTableInfo, zTable, '"');
1631 appendText(zTableInfo, ");", 0);
1632  
1633 rc = Sqlite3.sqlite3_prepare(p.db, zTableInfo, -1, ref pTableInfo, 0);
1634 zTableInfo = null;//free(zTableInfo);
1635 if (rc != Sqlite3.SQLITE_OK || null == pTableInfo)
1636 {
1637 return 1;
1638 }
1639  
1640 appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
1641 appendText(zTmp, zTable, '"');
1642 //if (zTmp!=null)
1643 {
1644 appendText(zSelect, zTmp.ToString(), '\'');
1645 }
1646 appendText(zSelect, " || ' VALUES(' || ", 0);
1647 rc = Sqlite3.sqlite3_step(pTableInfo);
1648 while (rc == Sqlite3.SQLITE_ROW)
1649 {
1650 string zText = (string)Sqlite3.sqlite3_column_text(pTableInfo, 1);
1651 appendText(zSelect, "quote(", 0);
1652 appendText(zSelect, zText, '"');
1653 rc = Sqlite3.sqlite3_step(pTableInfo);
1654 if (rc == Sqlite3.SQLITE_ROW)
1655 {
1656 appendText(zSelect, ") || ',' || ", 0);
1657 }
1658 else
1659 {
1660 appendText(zSelect, ") ", 0);
1661 }
1662 nRow++;
1663 }
1664 rc = Sqlite3.sqlite3_finalize(pTableInfo);
1665 if (rc != Sqlite3.SQLITE_OK || nRow == 0)
1666 {
1667 zSelect = null;//free(zSelect);
1668 return 1;
1669 }
1670 appendText(zSelect, "|| ')' FROM ", 0);
1671 appendText(zSelect, zTable, '"');
1672  
1673 rc = run_table_dump_query(p.Out, p.db, zSelect, zPrepStmt);
1674 if (rc == Sqlite3.SQLITE_CORRUPT)
1675 {
1676 appendText(zSelect, " ORDER BY rowid DESC", 0);
1677 rc = run_table_dump_query(p.Out, p.db, zSelect, "");
1678 }
1679 if (zSelect != null)
1680 zSelect = null;//free(zSelect);
1681 }
1682 return 0;
1683 }
1684  
1685 /*
1686 ** Run zQuery. Use dump_callback() as the callback routine so that
1687 ** the contents of the query are output as SQL statements.
1688 **
1689 ** If we get a Sqlite3.SQLITE_CORRUPT error, rerun the query after appending
1690 ** "ORDER BY rowid DESC" to the end.
1691 */
1692 static int run_schema_dump_query(
1693 callback_data p,
1694 string zQuery,
1695 string pzErrMsg
1696 )
1697 {
1698 int rc;
1699 rc = Sqlite3.sqlite3_exec(p.db, zQuery, dump_callback, p, ref pzErrMsg);
1700 if (rc == Sqlite3.SQLITE_CORRUPT)
1701 {
1702 StringBuilder zQ2;
1703 int len = strlen30(zQuery);
1704 if (pzErrMsg != null)
1705 pzErrMsg = null;//Sqlite3.sqlite3_free(pzErrMsg);
1706 zQ2 = new StringBuilder(len + 100);//zQ2 = malloc(len + 100);
1707 //if (zQ2 == null)
1708 // return rc;
1709 Sqlite3.sqlite3_snprintf(zQ2.Capacity, zQ2, "%s ORDER BY rowid DESC", zQuery);
1710 rc = Sqlite3.sqlite3_exec(p.db, zQ2.ToString(), dump_callback, p, ref pzErrMsg);
1711 zQ2 = null;//free(zQ2);
1712 }
1713 return rc;
1714 }
1715  
1716 /*
1717 ** Text of a help message
1718 */
1719 static string zHelp =
1720 ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" +
1721 ".bail ON|OFF Stop after hitting an error. Default OFF\n" +
1722 ".databases List names and files of attached databases\n" +
1723 ".dump ?TABLE? ... Dump the database in an SQL text format\n" +
1724 " If TABLE specified, only dump tables matching\n" +
1725 " LIKE pattern TABLE.\n" +
1726 ".echo ON|OFF Turn command echo on or off\n" +
1727 ".exit Exit this program\n" +
1728 ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" +
1729 " With no args, it turns EXPLAIN on.\n" +
1730 ".header(s) ON|OFF Turn display of headers on or off\n" +
1731 ".help Show this message\n" +
1732 ".import FILE TABLE Import data from FILE into TABLE\n" +
1733 ".indices ?TABLE? Show names of all indices\n" +
1734 " If TABLE specified, only show indices for tables\n" +
1735 " matching LIKE pattern TABLE.\n" +
1736 #if SQLITE_ENABLE_IOTRACE
1737 ".iotrace FILE Enable I/O diagnostic logging to FILE\n" +
1738 #endif
1739 #if !SQLITE_OMIT_LOAD_EXTENSION
1740 ".load FILE ?ENTRY? Load an extension library\n" +
1741 #endif
1742 ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n" +
1743 ".mode MODE ?TABLE? Set output mode where MODE is one of:\n" +
1744 " csv Comma-separated values\n" +
1745 " column Left-aligned columns. (See .width)\n" +
1746 " html HTML <table> code\n" +
1747 " insert SQL insert statements for TABLE\n" +
1748 " line One value per line\n" +
1749 " list Values delimited by .separator string\n" +
1750 " tabs Tab-separated values\n" +
1751 " tcl TCL list elements\n" +
1752 ".nullvalue STRING Print STRING in place of null values\n" +
1753 ".output FILENAME Send output to FILENAME\n" +
1754 ".output stdout Send output to the screen\n" +
1755 ".prompt MAIN CONTINUE Replace the standard prompts\n" +
1756 ".quit Exit this program\n" +
1757 ".read FILENAME Execute SQL in FILENAME\n" +
1758 ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" +
1759 ".schema ?TABLE? Show the CREATE statements\n" +
1760 " If TABLE specified, only show tables matching\n" +
1761 " LIKE pattern TABLE.\n" +
1762 ".separator STRING Change separator used by output mode and .import\n" +
1763 ".show Show the current values for various settings\n" +
1764 ".stats ON|OFF Turn stats on or off\n" +
1765 ".tables ?TABLE? List names of tables\n" +
1766 " If TABLE specified, only list tables matching\n" +
1767 " LIKE pattern TABLE.\n" +
1768 ".timeout MS Try opening locked tables for MS milliseconds\n" +
1769 ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
1770 ;
1771  
1772 static string zTimerHelp =
1773 ".timer ON|OFF Turn the CPU timer measurement on or off\n"
1774 ;
1775  
1776 /* Forward reference */
1777 //static int process_input(callback_data p, FILE In);
1778  
1779 /*
1780 ** Make sure the database is open. If it is not, then open it. If
1781 ** the database fails to open, print an error message and exit.
1782 */
1783 static void open_db(callback_data p)
1784 {
1785 if (p.db == null)
1786 {
1787 Sqlite3.sqlite3_open(p.zDbFilename, out p.db);
1788 db = p.db;
1789 if (db != null && Sqlite3.sqlite3_errcode(db) == Sqlite3.SQLITE_OK)
1790 {
1791 Sqlite3.sqlite3_create_function(db, "shellstatic", 0, Sqlite3.SQLITE_UTF8, 0,
1792 shellstaticFunc, null, null);
1793 }
1794 if (db == null || Sqlite3.SQLITE_OK != Sqlite3.sqlite3_errcode(db))
1795 {
1796 fprintf(stderr, "Error: unable to open database \"%s\": %s\n",
1797 p.zDbFilename, Sqlite3.sqlite3_errmsg(db));
1798 exit(1);
1799 }
1800 #if !SQLITE_OMIT_LOAD_EXTENSION
1801 Sqlite3.sqlite3_enable_load_extension(p.db, 1);
1802 #endif
1803 }
1804 }
1805  
1806 /*
1807 ** Do C-language style dequoting.
1808 **
1809 ** \t . tab
1810 ** \n . newline
1811 ** \r . carriage return
1812 ** \NNN . ascii character NNN in octal
1813 ** \\ . backslash
1814 */
1815 static void resolve_backslashes(ref string z)
1816 {
1817 StringBuilder sb = new StringBuilder(z);
1818 resolve_backslashes(sb);
1819 z = sb.ToString();
1820 }
1821 static void resolve_backslashes(StringBuilder z)
1822 {
1823 int i, j;
1824 char c;
1825 for (i = j = 0; i < z.Length && (c = z[i]) != 0; i++, j++)
1826 {
1827 if (c == '\\')
1828 {
1829 c = z[++i];
1830 if (c == 'n')
1831 {
1832 c = '\n';
1833 }
1834 else if (c == 't')
1835 {
1836 c = '\t';
1837 }
1838 else if (c == 'r')
1839 {
1840 c = '\r';
1841 }
1842 else if (c >= '0' && c <= '7')
1843 {
1844 c -= '0';
1845 if (z[i + 1] >= '0' && z[i + 1] <= '7')
1846 {
1847 i++;
1848 c = (char)((c << 3) + z[i] - '0');
1849 if (z[i + 1] >= '0' && z[i + 1] <= '7')
1850 {
1851 i++;
1852 c = (char)((c << 3) + z[i] - '0');
1853 }
1854 }
1855 }
1856 }
1857 z[j] = c;
1858 }
1859 z.Length = j;//z[j] = '\0';
1860 }
1861  
1862  
1863 /*
1864 ** Interpret zArg as a boolean value. Return either 0 or 1.
1865 */
1866 static bool booleanValue(StringBuilder zArg)
1867 {
1868 return booleanValue(zArg.ToString());
1869 }
1870  
1871 static bool booleanValue(string zArg)
1872 {
1873 if (String.IsNullOrEmpty(zArg))
1874 return false;
1875 int val = Char.IsDigit(zArg[0]) ? Convert.ToInt32(zArg) : 0;// atoi( zArg );
1876 int j;
1877 //for (j = 0; zArg[j]; j++)
1878 //{
1879 // zArg[j] = (char)tolower(zArg[j]);
1880 //}
1881 if (zArg.Equals("on", StringComparison.InvariantCultureIgnoreCase))
1882 {
1883 val = 1;
1884 }
1885 else if (zArg.Equals("yes", StringComparison.InvariantCultureIgnoreCase))
1886 {
1887 val = 1;
1888 }
1889 return val != 0;
1890 }
1891  
1892 class _aCtrl
1893 {
1894 public string zCtrlName; /* Name of a test-control option */
1895 public int ctrlCode; /* Integer code for that option */
1896  
1897 public _aCtrl(string zCtrlName, int ctrlCode)
1898 {
1899 this.zCtrlName = zCtrlName;
1900 this.ctrlCode = ctrlCode;
1901 }
1902 }
1903  
1904 /*
1905 ** If an input line begins with "." then invoke this routine to
1906 ** process that line.
1907 **
1908 ** Return 1 on error, 2 to exit, and 0 otherwise.
1909 */
1910 static int do_meta_command(StringBuilder zLine, callback_data p)
1911 {
1912 int i = 1;
1913 int i0 = 0;
1914 int nArg = 0;
1915 int n, c;
1916 int rc = 0;
1917 string[] azArg = new string[50];
1918  
1919 /* Parse the input line into tokens.
1920 */
1921 while (i < zLine.Length && nArg < ArraySize(azArg))
1922 {
1923 while (i < zLine.Length && Char.IsWhiteSpace(zLine[i])) { i++; }
1924 if (i == zLine.Length)
1925 break;
1926 if (zLine[i] == '\'' || zLine[i] == '"')
1927 {
1928 int delim = zLine[i++];
1929 i0 = i;
1930 azArg[nArg++] = zLine[i].ToString();
1931 while (zLine[i] != '\0' && zLine[i] != delim) { i++; }
1932 if (zLine[i] == delim)
1933 {
1934 zLine[i++] = '\0';
1935 }
1936 if (delim == '"')
1937 resolve_backslashes(ref azArg[nArg - 1]);
1938 }
1939 else
1940 {
1941 i0 = i;
1942 while (i < zLine.Length && !isspace(zLine[i])) { i++; }
1943 azArg[nArg++] = zLine.ToString().Substring(i0, i - i0);
1944 //if (i < zLine.Length - 1)
1945 // zLine[i++] = '\0';
1946 resolve_backslashes(ref azArg[nArg - 1]);
1947 }
1948 }
1949  
1950 /* Process the input line.
1951 */
1952 if (nArg == 0)
1953 return 0; /* no tokens, no error */
1954 n = strlen30(azArg[0]);
1955 c = azArg[0][0];
1956 if (c == 'b' && n >= 3 && azArg[0].StartsWith("backup", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 4)
1957 {
1958 string zDestFile;
1959 string zDb;
1960 sqlite3 pDest;
1961 Sqlite3.sqlite3_backup pBackup;
1962 if (nArg == 2)
1963 {
1964 zDestFile = azArg[1];
1965 zDb = "main";
1966 }
1967 else
1968 {
1969 zDestFile = azArg[2];
1970 zDb = azArg[1];
1971 }
1972 rc = Sqlite3.sqlite3_open(zDestFile, out pDest);
1973 if (rc != Sqlite3.SQLITE_OK)
1974 {
1975 fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
1976 Sqlite3.sqlite3_close(pDest);
1977 return 1;
1978 }
1979 open_db(p);
1980 pBackup = Sqlite3.sqlite3_backup_init(pDest, "main", p.db, zDb);
1981 if (pBackup == null)
1982 {
1983 fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(pDest));
1984 Sqlite3.sqlite3_close(pDest);
1985 return 1;
1986 }
1987 while ((rc = Sqlite3.sqlite3_backup_step(pBackup, 100)) == Sqlite3.SQLITE_OK) { }
1988 Sqlite3.sqlite3_backup_finish(pBackup);
1989 if (rc == Sqlite3.SQLITE_DONE)
1990 {
1991 rc = 0;
1992 }
1993 else
1994 {
1995 fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(pDest));
1996 rc = 1;
1997 }
1998 Sqlite3.sqlite3_close(pDest);
1999 }
2000 else
2001  
2002 if (c == 'b' && n >= 3 && azArg[0].StartsWith("bail", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 3)
2003 {
2004 bail_on_error = booleanValue(azArg[1]);
2005 }
2006 else
2007  
2008 if (c == 'd' && n > 1 && azArg[0].StartsWith("databases", StringComparison.InvariantCultureIgnoreCase) && nArg == 1)
2009 {
2010 callback_data data;
2011 string zErrMsg = null;
2012 open_db(p);
2013 data = p.Copy();// memcpy(data, p, sizeof(data));
2014 data.showHeader = true;
2015 data.mode = MODE_Column;
2016 data.colWidth[0] = 3;
2017 data.colWidth[1] = 15;
2018 data.colWidth[2] = 58;
2019 data.cnt = 0;
2020 Sqlite3.sqlite3_exec(p.db, "PRAGMA database_list; ", callback, data, ref zErrMsg);
2021 if (!String.IsNullOrEmpty(zErrMsg))
2022 {
2023 fprintf(stderr, "Error: %s\n", zErrMsg);
2024 zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg);
2025 rc = 1;
2026 }
2027 }
2028 else
2029  
2030 if (c == 'd' && azArg[0].StartsWith("dump", StringComparison.InvariantCultureIgnoreCase) && nArg < 3)
2031 {
2032 string zErrMsg = null;
2033 open_db(p);
2034 /* When playing back a "dump", the content might appear in an order
2035 ** which causes immediate foreign key constraints to be violated.
2036 ** So disable foreign-key constraint enforcement to prevent problems. */
2037 fprintf(p.Out, "PRAGMA foreign_keys=OFF;\n");
2038 fprintf(p.Out, "BEGIN TRANSACTION;\n");
2039 p.writableSchema = false;
2040 Sqlite3.sqlite3_exec(p.db, "PRAGMA writable_schema=ON", 0, 0, 0);
2041 if (nArg == 1)
2042 {
2043 run_schema_dump_query(p,
2044 "SELECT name, type, sql FROM sqlite_master " +
2045 "WHERE sql NOT null AND type=='table' AND name!='Sqlite3.SQLITE_sequence'", null
2046 );
2047 run_schema_dump_query(p,
2048 "SELECT name, type, sql FROM sqlite_master " +
2049 "WHERE name=='Sqlite3.SQLITE_sequence'", null
2050 );
2051 run_table_dump_query(p.Out, p.db,
2052 "SELECT sql FROM sqlite_master " +
2053 "WHERE sql NOT null AND type IN ('index','trigger','view')", null
2054 );
2055 }
2056 else
2057 {
2058 int ii;
2059 for (ii = 1; ii < nArg; ii++)
2060 {
2061 zShellStatic = azArg[ii];
2062 run_schema_dump_query(p,
2063 "SELECT name, type, sql FROM sqlite_master " +
2064 "WHERE tbl_name LIKE shellstatic() AND type=='table'" +
2065 " AND sql NOT null", null);
2066 run_table_dump_query(p.Out, p.db,
2067 "SELECT sql FROM sqlite_master " +
2068 "WHERE sql NOT null" +
2069 " AND type IN ('index','trigger','view')" +
2070 " AND tbl_name LIKE shellstatic()", null
2071 );
2072 zShellStatic = null;
2073 }
2074 }
2075 if (p.writableSchema)
2076 {
2077 fprintf(p.Out, "PRAGMA writable_schema=OFF;\n");
2078 p.writableSchema = false;
2079 }
2080 Sqlite3.sqlite3_exec(p.db, "PRAGMA writable_schema=OFF", 0, 0, 0);
2081 if (!String.IsNullOrEmpty(zErrMsg))
2082 {
2083 fprintf(stderr, "Error: %s\n", zErrMsg);
2084 zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg);
2085 }
2086 else
2087 {
2088 fprintf(p.Out, "COMMIT;\n");
2089 }
2090 }
2091 else
2092  
2093 if (c == 'e' && azArg[0].StartsWith("echo", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 3)
2094 {
2095 p.echoOn = booleanValue(azArg[1]);
2096 }
2097 else
2098  
2099 if (c == 'e' && azArg[0].StartsWith("exit", StringComparison.InvariantCultureIgnoreCase) && nArg == 1)
2100 {
2101 rc = 2;
2102 }
2103 else
2104  
2105 if (c == 'e' && azArg[0].StartsWith("explain", StringComparison.InvariantCultureIgnoreCase) && nArg < 3)
2106 {
2107 int val = nArg >= 2 ? booleanValue(azArg[1]) ? 1 : 0 : 1;
2108 if (val == 1)
2109 {
2110 if (!p.explainPrev.valid)
2111 {
2112 p.explainPrev.valid = true;
2113 p.explainPrev.mode = p.mode;
2114 p.explainPrev.showHeader = p.showHeader;
2115 p.explainPrev.colWidth = new int[p.colWidth.Length];
2116 Array.Copy(p.colWidth, p.explainPrev.colWidth, p.colWidth.Length);//memcpy( p.explainPrev.colWidth, p.colWidth, sizeof( p.colWidth ) );
2117 }
2118 /* We could put this code under the !p.explainValid
2119 ** condition so that it does not execute if we are already in
2120 ** explain mode. However, always executing it allows us an easy
2121 ** was to reset to explain mode in case the user previously
2122 ** did an .explain followed by a .width, .mode or .header
2123 ** command.
2124 */
2125 p.mode = MODE_Explain;
2126 p.showHeader = true;
2127 Array.Clear(p.colWidth, 0, p.colWidth.Length);//memset(p.colWidth, 0, ArraySize(p.colWidth));
2128 p.colWidth[0] = 4; /* addr */
2129 p.colWidth[1] = 13; /* opcode */
2130 p.colWidth[2] = 4; /* P1 */
2131 p.colWidth[3] = 4; /* P2 */
2132 p.colWidth[4] = 4; /* P3 */
2133 p.colWidth[5] = 13; /* P4 */
2134 p.colWidth[6] = 2; /* P5 */
2135 p.colWidth[7] = 13; /* Comment */
2136 }
2137 else if (p.explainPrev.valid)
2138 {
2139 p.explainPrev.valid = false;
2140 p.mode = p.explainPrev.mode;
2141 p.showHeader = p.explainPrev.showHeader;
2142 Array.Copy(p.colWidth, p.explainPrev.colWidth, p.colWidth.Length);//memcpy(p.colWidth, p.explainPrev.colWidth, sizeof(p.colWidth));
2143 }
2144 }
2145 else
2146  
2147 if (c == 'h' && (azArg[0].StartsWith("header", StringComparison.InvariantCultureIgnoreCase) ||
2148 azArg[0].StartsWith("headers", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 3))
2149 {
2150 p.showHeader = booleanValue(azArg[1]);
2151 }
2152 else
2153  
2154 if (c == 'h' && azArg[0].StartsWith("help", StringComparison.InvariantCultureIgnoreCase))
2155 {
2156 fprintf(stderr, "%s", zHelp);
2157 if (HAS_TIMER)
2158 {
2159 fprintf(stderr, "%s", zTimerHelp);
2160 }
2161 }
2162 else
2163  
2164 if (c == 'i' && azArg[0].StartsWith("import", StringComparison.InvariantCultureIgnoreCase) && nArg == 3)
2165 {
2166 string zTable = azArg[2]; /* Insert data into this table */
2167 string zFile = azArg[1]; /* The file from which to extract data */
2168 sqlite3_stmt pStmt = null; /* A statement */
2169 int nCol; /* Number of columns in the table */
2170 int nByte; /* Number of bytes in an SQL string */
2171 int ii, j; /* Loop counters */
2172 int nSep; /* Number of bytes in p.separator[] */
2173 StringBuilder zSql; /* An SQL statement */
2174 //string zLine; /* A single line of input from the file */
2175 string[] azCol; /* zLine[] broken up into columns */
2176 string zCommit; /* How to commit changes */
2177 TextReader In; /* The input file */
2178 int lineno = 0; /* Line number of input file */
2179  
2180 open_db(p);
2181 nSep = strlen30(p.separator);
2182 if (nSep == 0)
2183 {
2184 fprintf(stderr, "Error: non-null separator required for import\n");
2185 return 1;
2186 }
2187 zSql = new StringBuilder(Sqlite3.sqlite3_mprintf("SELECT * FROM '%q'", zTable));
2188 //if (zSql == null)
2189 //{
2190 // fprintf(stderr, "Error: out of memory\n");
2191 // return 1;
2192 //}
2193 nByte = strlen30(zSql);
2194 rc = Sqlite3.sqlite3_prepare(p.db, zSql, -1, ref pStmt, 0);
2195 zSql = null;//Sqlite3.sqlite3_free(zSql);
2196 if (rc != 0)
2197 {
2198 if (pStmt != null)
2199 Sqlite3.sqlite3_finalize(pStmt);
2200 fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(db));
2201 return 1;
2202 }
2203 nCol = Sqlite3.sqlite3_column_count(pStmt);
2204 Sqlite3.sqlite3_finalize(pStmt);
2205 pStmt = null;
2206 if (nCol == 0)
2207 return 0; /* no columns, no error */
2208 zSql = new StringBuilder(nByte + 20 + nCol * 2);
2209 //if (zSql == null)
2210 //{
2211 // fprintf(stderr, "Error: out of memory\n");
2212 // return 1;
2213 //}
2214 Sqlite3.sqlite3_snprintf(nByte + 20, zSql, "INSERT INTO '%q' VALUES(?", zTable);
2215 j = strlen30(zSql);
2216 for (ii = 1; ii < nCol; ii++)
2217 {
2218 zSql[j++] = ',';
2219 zSql[j++] = '?';
2220 }
2221 zSql[j++] = ')';
2222 zSql[j] = '\0';
2223 rc = Sqlite3.sqlite3_prepare(p.db, zSql, -1, ref pStmt, 0);
2224 zSql = null;//free(zSql);
2225 if (rc != 0)
2226 {
2227 fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(db));
2228 if (pStmt != null)
2229 Sqlite3.sqlite3_finalize(pStmt);
2230 return 1;
2231 }
2232 In = new StreamReader(zFile);// fopen(zFile, "rb");
2233 if (In == null)
2234 {
2235 fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
2236 Sqlite3.sqlite3_finalize(pStmt);
2237 return 1;
2238 }
2239 azCol = new string[nCol + 1];//malloc( sizeof(azCol[0])*(nCol+1) );
2240 //if( azCol== null ){
2241 //fprintf(stderr, "Error: out of memory\n");
2242 //fclose(In );
2243 //Sqlite3.sqlite3_finalize(pStmt!=null);
2244 //return 1;
2245 //}
2246 Sqlite3.sqlite3_exec(p.db, "BEGIN", 0, 0, 0);
2247 zCommit = "COMMIT";
2248 while ((zLine.Append(local_getline(null, In).ToString())).Length != 0)
2249 {
2250 string z;
2251 //i = 0;
2252 lineno++;
2253 azCol = zLine.ToString().Split(p.separator.ToCharArray());
2254 //azCol[0] = zLine;
2255 //for (i = 0, z = zLine; *z && *z != '\n' && *z != '\r'; z++)
2256 //{
2257 // if (*z == p.separator[0] && z.StartsWith(p.separator))
2258 // {
2259 // *z = 0;
2260 // i++;
2261 // if (i < nCol)
2262 // {
2263 // azCol[i] = z[nSep];
2264 // z += nSep - 1;
2265 // }
2266 // }
2267 //} /* end for */
2268 //*z = 0;
2269 if (azCol.Length != nCol)
2270 {
2271 fprintf(stderr,
2272 "Error: %s line %d: expected %d columns of data but found %d\n",
2273 zFile, lineno, nCol, azCol.Length);
2274 zCommit = "ROLLBACK";
2275 zLine = null;//free(zLine);
2276 rc = 1;
2277 break; /* from while */
2278 }
2279 for (ii = 0; ii < nCol; ii++)
2280 {
2281 Sqlite3.sqlite3_bind_text(pStmt, ii + 1, azCol[ii], -1, Sqlite3.SQLITE_STATIC);
2282 }
2283 Sqlite3.sqlite3_step(pStmt);
2284 rc = Sqlite3.sqlite3_reset(pStmt);
2285 zLine = null;//free(zLine);
2286 if (rc != Sqlite3.SQLITE_OK)
2287 {
2288 fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(db));
2289 zCommit = "ROLLBACK";
2290 rc = 1;
2291 break; /* from while */
2292 }
2293 } /* end while */
2294 azCol = null;//free(azCol);
2295 In.Close();//fclose(in);
2296 Sqlite3.sqlite3_finalize(pStmt);
2297 Sqlite3.sqlite3_exec(p.db, zCommit, 0, 0, 0);
2298 }
2299 else
2300  
2301 if (c == 'i' && azArg[0].StartsWith("indices", StringComparison.InvariantCultureIgnoreCase) && nArg < 3)
2302 {
2303 callback_data data;
2304 string zErrMsg = null;
2305 open_db(p);
2306 data = p.Copy();// memcpy(data, p, sizeof(data));
2307 data.showHeader = false;
2308 data.mode = MODE_List;
2309 if (nArg == 1)
2310 {
2311 rc = Sqlite3.sqlite3_exec(p.db,
2312 "SELECT name FROM sqlite_master " +
2313 "WHERE type='index' AND name NOT LIKE 'Sqlite3.SQLITE_%' " +
2314 "UNION ALL " +
2315 "SELECT name FROM sqlite_temp_master " +
2316 "WHERE type='index' " +
2317 "ORDER BY 1",
2318 callback, data, ref zErrMsg
2319 );
2320 }
2321 else
2322 {
2323 zShellStatic = azArg[1];
2324 rc = Sqlite3.sqlite3_exec(p.db,
2325 "SELECT name FROM sqlite_master " +
2326 "WHERE type='index' AND tbl_name LIKE shellstatic() " +
2327 "UNION ALL " +
2328 "SELECT name FROM sqlite_temp_master " +
2329 "WHERE type='index' AND tbl_name LIKE shellstatic() " +
2330 "ORDER BY 1",
2331 callback, data, ref zErrMsg
2332 );
2333 zShellStatic = null;
2334 }
2335 if (!String.IsNullOrEmpty(zErrMsg))
2336 {
2337 fprintf(stderr, "Error: %s\n", zErrMsg);
2338 zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg);
2339 rc = 1;
2340 }
2341 else if (rc != Sqlite3.SQLITE_OK)
2342 {
2343 fprintf(stderr, "Error: querying Sqlite3.SQLITE_master and Sqlite3.SQLITE_temp_master\n");
2344 rc = 1;
2345 }
2346 }
2347 else
2348  
2349 #if SQLITE_ENABLE_IOTRACE
2350 if( c=='i' && "iotrace", n)== null ){
2351 extern void (*sqlite3IoTrace)(const char*, ...);
2352 if( iotrace && iotrace!=stdout ) iotrace.Close();//fclose(iotrace);
2353 iotrace = null;
2354 if( nArg<2 ){
2355 sqlite3IoTrace = 0;
2356 }else if( azArg[1].Equals("-") ){
2357 sqlite3IoTrace = iotracePrintf;
2358 iotrace = stdout;
2359 }else{
2360 iotrace = new StreamWriter(azArg[1].ToString());// fopen(azArg[1], "w");
2361 if( iotrace== null ){
2362 fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
2363 sqlite3IoTrace = 0;
2364 rc = 1;
2365 }else{
2366 sqlite3IoTrace = iotracePrintf;
2367 }
2368 }
2369 }else
2370 #endif
2371  
2372 #if !SQLITE_OMIT_LOAD_EXTENSION
2373 if (c == 'l' && azArg[0].StartsWith("load", StringComparison.InvariantCultureIgnoreCase) && nArg >= 2)
2374 {
2375 string zFile, zProc;
2376 string zErrMsg = null;
2377 zFile = azArg[1];
2378 zProc = nArg >= 3 ? azArg[2] : null;
2379 open_db(p);
2380 rc = Sqlite3.sqlite3_load_extension(p.db, zFile, zProc, ref zErrMsg);
2381 if (rc != Sqlite3.SQLITE_OK)
2382 {
2383 fprintf(stderr, "Error: %s\n", zErrMsg);
2384 zErrMsg = null;//Sqlite3.sqlite3_free( zErrMsg );
2385 rc = 1;
2386 }
2387 }
2388 else
2389 #endif
2390  
2391 if (c == 'l' && azArg[0].StartsWith("log", StringComparison.InvariantCultureIgnoreCase) && nArg >= 2)
2392 {
2393 string zFile = azArg[1];
2394 if (p.pLog != null && p.pLog != stdout && p.pLog != stderr)
2395 {
2396 p.pLog.Close();//fclose(p.pLog);
2397 p.pLog = null;
2398 }
2399 if (zFile.Equals("stdout", StringComparison.InvariantCultureIgnoreCase))
2400 {
2401 p.pLog = stdout;
2402 }
2403 else if (zFile.Equals("stderr", StringComparison.InvariantCultureIgnoreCase))
2404 {
2405 p.pLog = stderr;
2406 }
2407 else if (zFile.Equals("off", StringComparison.InvariantCultureIgnoreCase))
2408 {
2409 p.pLog = null;
2410 }
2411 else
2412 {
2413 p.pLog = new StreamWriter(zFile);// fopen(zFile, "w");
2414 if (p.pLog == null)
2415 {
2416 fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
2417 }
2418 }
2419 }
2420 else
2421  
2422 if (c == 'm' && azArg[0].StartsWith("mode", StringComparison.InvariantCultureIgnoreCase) && nArg == 2)
2423 {
2424 int n2 = strlen30(azArg[1]);
2425 if ((n2 == 4 && azArg[1].StartsWith("line", StringComparison.InvariantCultureIgnoreCase))
2426 ||
2427 (n2 == 5 && azArg[1].StartsWith("lines", StringComparison.InvariantCultureIgnoreCase)))
2428 {
2429 p.mode = MODE_Line;
2430 }
2431 else if ((n2 == 6 && azArg[1].StartsWith("column", StringComparison.InvariantCultureIgnoreCase))
2432 ||
2433 (n2 == 7 && azArg[1].StartsWith("columns", StringComparison.InvariantCultureIgnoreCase)))
2434 {
2435 p.mode = MODE_Column;
2436 }
2437 else if (n2 == 4 && azArg[1].StartsWith("list", StringComparison.InvariantCultureIgnoreCase))
2438 {
2439 p.mode = MODE_List;
2440 }
2441 else if (n2 == 4 && azArg[1].StartsWith("html", StringComparison.InvariantCultureIgnoreCase))
2442 {
2443 p.mode = MODE_Html;
2444 }
2445 else if (n2 == 3 && azArg[1].StartsWith("tcl", StringComparison.InvariantCultureIgnoreCase))
2446 {
2447 p.mode = MODE_Tcl;
2448 }
2449 else if (n2 == 3 && azArg[1].StartsWith("csv", StringComparison.InvariantCultureIgnoreCase))
2450 {
2451 p.mode = MODE_Csv;
2452 snprintf(2, ref p.separator, ",");
2453 }
2454 else if (n2 == 4 && azArg[1].StartsWith("tabs", StringComparison.InvariantCultureIgnoreCase))
2455 {
2456 p.mode = MODE_List;
2457 snprintf(2, ref p.separator, "\t");
2458 }
2459 else if (n2 == 6 && azArg[1].StartsWith("insert", StringComparison.InvariantCultureIgnoreCase))
2460 {
2461 p.mode = MODE_Insert;
2462 set_table_name(p, "table");
2463 }
2464 else
2465 {
2466 fprintf(stderr, "Error: mode should be one of: " +
2467 "column csv html insert line list tabs tcl\n");
2468 rc = 1;
2469 }
2470 }
2471 else
2472  
2473 if (c == 'm' && azArg[0].StartsWith("mode", StringComparison.InvariantCultureIgnoreCase) && nArg == 3)
2474 {
2475 int n2 = strlen30(azArg[1]);
2476 if (n2 == 6 && azArg[1].StartsWith("insert", StringComparison.InvariantCultureIgnoreCase))
2477 {
2478 p.mode = MODE_Insert;
2479 set_table_name(p, azArg[2]);
2480 }
2481 else
2482 {
2483 fprintf(stderr, "Error: invalid arguments: " +
2484 " \"%s\". Enter \".help\" for help\n", azArg[2]);
2485 rc = 1;
2486 }
2487 }
2488 else
2489  
2490 if (c == 'n' && azArg[0].StartsWith("nullvalue", StringComparison.InvariantCultureIgnoreCase) && nArg == 2)
2491 {
2492 snprintf(9, ref p.nullvalue,
2493 "%.*s", (int)p.nullvalue.Length - 1, azArg[1]);
2494 }
2495 else
2496  
2497 if (c == 'o' && azArg[0].StartsWith("output", StringComparison.InvariantCultureIgnoreCase) && nArg == 2)
2498 {
2499 if (p.Out != stdout)
2500 {
2501 p.Out.Close();//fclose(p.Out);
2502 }
2503 if (azArg[1].Equals("stdout", StringComparison.InvariantCultureIgnoreCase))
2504 {
2505 p.Out = stdout;
2506 Sqlite3.sqlite3_snprintf(p.outfile.Capacity, p.outfile, "stdout");
2507 }
2508 else
2509 {
2510 p.Out = new StreamWriter(azArg[1].ToString());// fopen(azArg[1], "wb");
2511 if (p.Out == null)
2512 {
2513 fprintf(stderr, "Error: cannot write to \"%s\"\n", azArg[1]);
2514 p.Out = stdout;
2515 rc = 1;
2516 }
2517 else
2518 {
2519 Sqlite3.sqlite3_snprintf(p.outfile.Capacity, p.outfile, "%s", azArg[1]);
2520 }
2521 }
2522 }
2523 else
2524  
2525 if (c == 'p' && azArg[0].StartsWith("prompt", StringComparison.InvariantCultureIgnoreCase) && (nArg == 2 || nArg == 3))
2526 {
2527 if (nArg >= 2)
2528 {
2529 mainPrompt = azArg[1].ToString();//strncpy(mainPrompt, azArg[1], (int)ArraySize(mainPrompt) - 1);
2530 }
2531 if (nArg >= 3)
2532 {
2533 continuePrompt = azArg[1].ToString();//strncpy(continuePrompt, azArg[2], (int)ArraySize(continuePrompt) - 1);
2534 }
2535 }
2536 else
2537  
2538 if (c == 'q' && azArg[0].StartsWith("quit", StringComparison.InvariantCultureIgnoreCase) && nArg == 1)
2539 {
2540 rc = 2;
2541 }
2542 else
2543  
2544 if (c == 'r' && n >= 3 && azArg[0].StartsWith("read", StringComparison.InvariantCultureIgnoreCase) && nArg == 2)
2545 {
2546 StreamReader alt = new StreamReader(azArg[1].ToString());// fopen(azArg[1], "rb");
2547 if (alt == null)
2548 {
2549 fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
2550 rc = 1;
2551 }
2552 else
2553 {
2554 rc = process_input(p, alt);
2555 alt.Close();//fclose(alt);
2556 }
2557 }
2558 else
2559  
2560 if (c == 'r' && n >= 3 && azArg[0].StartsWith("restore", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 4)
2561 {
2562 string zSrcFile;
2563 string zDb;
2564 sqlite3 pSrc;
2565 Sqlite3.sqlite3_backup pBackup;
2566 int nTimeout = 0;
2567  
2568 if (nArg == 2)
2569 {
2570 zSrcFile = azArg[1];
2571 zDb = "main";
2572 }
2573 else
2574 {
2575 zSrcFile = azArg[2];
2576 zDb = azArg[1];
2577 }
2578 rc = Sqlite3.sqlite3_open(zSrcFile, out pSrc);
2579 if (rc != Sqlite3.SQLITE_OK)
2580 {
2581 fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
2582 Sqlite3.sqlite3_close(pSrc);
2583 return 1;
2584 }
2585 open_db(p);
2586 pBackup = Sqlite3.sqlite3_backup_init(p.db, zDb, pSrc, "main");
2587 if (pBackup == null)
2588 {
2589 fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(p.db));
2590 Sqlite3.sqlite3_close(pSrc);
2591 return 1;
2592 }
2593 while ((rc = Sqlite3.sqlite3_backup_step(pBackup, 100)) == Sqlite3.SQLITE_OK
2594 || rc == Sqlite3.SQLITE_BUSY)
2595 {
2596 if (rc == Sqlite3.SQLITE_BUSY)
2597 {
2598 if (nTimeout++ >= 3)
2599 break;
2600 Sqlite3.sqlite3_sleep(100);
2601 }
2602 }
2603 Sqlite3.sqlite3_backup_finish(pBackup);
2604 if (rc == Sqlite3.SQLITE_DONE)
2605 {
2606 rc = 0;
2607 }
2608 else if (rc == Sqlite3.SQLITE_BUSY || rc == Sqlite3.SQLITE_LOCKED)
2609 {
2610 fprintf(stderr, "Error: source database is busy\n");
2611 rc = 1;
2612 }
2613 else
2614 {
2615 fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(p.db));
2616 rc = 1;
2617 }
2618 Sqlite3.sqlite3_close(pSrc);
2619 }
2620 else
2621  
2622 if (c == 's' && azArg[0].StartsWith("schema", StringComparison.InvariantCultureIgnoreCase) && nArg < 3)
2623 {
2624 callback_data data;
2625 string zErrMsg = null;
2626 open_db(p);
2627 data = p.Copy();// memcpy(data, p, sizeof(data));
2628 data.showHeader = false;
2629 data.mode = MODE_Semi;
2630 if (nArg > 1)
2631 {
2632 //int i;
2633 //for (i = 0; azArg[1][i]; i++)
2634 // azArg[1][i] = (char)tolower(azArg[1][i]);
2635 azArg[1] = azArg[1].ToLower();
2636 if (azArg[1].Equals("sqlite_master", StringComparison.InvariantCultureIgnoreCase))
2637 {
2638 string[] new_argv = new string[2];
2639 string[] new_colv = new string[2];
2640 new_argv[0] = "CREATE TABLE Sqlite3.SQLITE_master (\n" +
2641 " type text,\n" +
2642 " name text,\n" +
2643 " tbl_name text,\n" +
2644 " rootpage integer,\n" +
2645 " sql text\n" +
2646 ")";
2647 new_argv[1] = null;
2648 new_colv[0] = "sql";
2649 new_colv[1] = null;
2650 callback(data, 1, new_argv, new_colv);
2651 rc = Sqlite3.SQLITE_OK;
2652 }
2653 else if (azArg[1].Equals("sqlite_temp_master", StringComparison.InvariantCultureIgnoreCase))
2654 {
2655 string[] new_argv = new string[2];
2656 string[] new_colv = new string[2];
2657 new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master(\n" +
2658 " type text,\n" +
2659 " name text,\n" +
2660 " tbl_name text,\n" +
2661 " rootpage integer,\n" +
2662 " sql text\n" +
2663 ")";
2664 new_argv[1] = null;
2665 new_colv[0] = "sql";
2666 new_colv[1] = null;
2667 callback(data, 1, new_argv, new_colv);
2668 rc = Sqlite3.SQLITE_OK;
2669 }
2670 else
2671 {
2672 zShellStatic = azArg[1];
2673 rc = Sqlite3.sqlite3_exec(p.db,
2674 "SELECT sql FROM " +
2675 " (SELECT sql sql, type type, tbl_name tbl_name, name name" +
2676 " FROM sqlite_master UNION ALL" +
2677 " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " +
2678 "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTnull " +
2679 "ORDER BY substr(type,2,1), name",
2680 callback, data, ref zErrMsg);
2681 zShellStatic = null;
2682 }
2683 }
2684 else
2685 {
2686 rc = Sqlite3.sqlite3_exec(p.db,
2687 "SELECT sql FROM " +
2688 " (SELECT sql sql, type type, tbl_name tbl_name, name name" +
2689 " FROM sqlite_master UNION ALL" +
2690 " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " +
2691 "WHERE type!='meta' AND sql NOTnull AND name NOT LIKE 'Sqlite3.SQLITE_%'" +
2692 "ORDER BY substr(type,2,1), name",
2693 callback, data, ref zErrMsg
2694 );
2695 }
2696 if (!String.IsNullOrEmpty(zErrMsg))
2697 {
2698 fprintf(stderr, "Error: %s\n", zErrMsg);
2699 zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg);
2700 rc = 1;
2701 }
2702 else if (rc != Sqlite3.SQLITE_OK)
2703 {
2704 fprintf(stderr, "Error: querying schema information\n");
2705 rc = 1;
2706 }
2707 else
2708 {
2709 rc = 0;
2710 }
2711 }
2712 else
2713  
2714 if (c == 's' && azArg[0].StartsWith("separator", StringComparison.InvariantCultureIgnoreCase) && nArg == 2)
2715 {
2716 snprintf(2, ref p.separator, "%.*s", 2 - 1, azArg[1]);
2717 }
2718 else
2719  
2720 if (c == 's' && azArg[0].StartsWith("show", StringComparison.InvariantCultureIgnoreCase) && nArg == 1)
2721 {
2722 int ii;
2723 fprintf(p.Out, "%9.9s: %s\n", "echo", p.echoOn ? "on" : "off");
2724 fprintf(p.Out, "%9.9s: %s\n", "explain", p.explainPrev.valid ? "on" : "off");
2725 fprintf(p.Out, "%9.9s: %s\n", "headers", p.showHeader ? "on" : "off");
2726 fprintf(p.Out, "%9.9s: %s\n", "mode", modeDescr[p.mode]);
2727 fprintf(p.Out, "%9.9s: ", "nullvalue");
2728 output_c_string(p.Out, p.nullvalue);
2729 fprintf(p.Out, "\n");
2730 fprintf(p.Out, "%9.9s: %s\n", "output",
2731 strlen30(p.outfile) != 0 ? p.outfile.ToString() : "stdout");
2732 fprintf(p.Out, "%9.9s: ", "separator");
2733 output_c_string(p.Out, p.separator);
2734 fprintf(p.Out, "\n");
2735 fprintf(p.Out, "%9.9s: %s\n", "stats", p.statsOn ? "on" : "off");
2736 fprintf(p.Out, "%9.9s: ", "width");
2737 for (ii = 0; ii < (int)ArraySize(p.colWidth) && p.colWidth[ii] != 0; ii++)
2738 {
2739 fprintf(p.Out, "%d ", p.colWidth[ii]);
2740 }
2741 fprintf(p.Out, "\n");
2742 }
2743 else
2744  
2745 if (c == 's' && azArg[0].StartsWith("stats", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 3)
2746 {
2747 p.statsOn = booleanValue(azArg[1]);
2748 }
2749 else
2750  
2751 if (c == 't' && n > 1 && azArg[0].StartsWith("tables", StringComparison.InvariantCultureIgnoreCase) && nArg < 3)
2752 {
2753 string[] azResult = null;
2754 int nRow = 0;
2755 string zErrMsg = null;
2756 open_db(p);
2757 if (nArg == 1)
2758 {
2759 rc = Sqlite3.sqlite3_get_table(p.db,
2760 "SELECT name FROM sqlite_master " +
2761 "WHERE type IN ('table','view') AND name NOT LIKE 'Sqlite3.SQLITE_%' " +
2762 "UNION ALL " +
2763 "SELECT name FROM sqlite_temp_master " +
2764 "WHERE type IN ('table','view') " +
2765 "ORDER BY 1",
2766 ref azResult, ref nRow, null, ref zErrMsg
2767 );
2768 }
2769 else
2770 {
2771 zShellStatic = azArg[1];
2772 rc = Sqlite3.sqlite3_get_table(p.db,
2773 "SELECT name FROM sqlite_master " +
2774 "WHERE type IN ('table','view') AND name LIKE shellstatic() " +
2775 "UNION ALL " +
2776 "SELECT name FROM sqlite_temp_master " +
2777 "WHERE type IN ('table','view') AND name LIKE shellstatic() " +
2778 "ORDER BY 1",
2779 ref azResult, ref nRow, null, ref zErrMsg
2780 );
2781 zShellStatic = null;
2782 }
2783 if (!String.IsNullOrEmpty(zErrMsg))
2784 {
2785 fprintf(stderr, "Error: %s\n", zErrMsg);
2786 zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg);
2787 rc = 1;
2788 }
2789 else if (rc != Sqlite3.SQLITE_OK)
2790 {
2791 fprintf(stderr, "Error: querying Sqlite3.SQLITE_master and Sqlite3.SQLITE_temp_master\n");
2792 rc = 1;
2793 }
2794 else
2795 {
2796 int len, maxlen = 0;
2797 int ii, j;
2798 int nPrintCol, nPrintRow;
2799 for (ii = 1; ii <= nRow; ii++)
2800 {
2801 if (azResult[ii] == null)
2802 continue;
2803 len = strlen30(azResult[ii]);
2804 if (len > maxlen)
2805 maxlen = len;
2806 }
2807 nPrintCol = 80 / (maxlen + 2);
2808 if (nPrintCol < 1)
2809 nPrintCol = 1;
2810 nPrintRow = (nRow + nPrintCol - 1) / nPrintCol;
2811 for (ii = 0; ii < nPrintRow; ii++)
2812 {
2813 for (j = ii + 1; j <= nRow; j += nPrintRow)
2814 {
2815 string zSp = j <= nPrintRow ? "" : " ";
2816 printf("%s%-*s", zSp, maxlen, !String.IsNullOrEmpty(azResult[j]) ? azResult[j] : "");
2817 }
2818 printf("\n");
2819 }
2820 }
2821 Sqlite3.sqlite3_free_table(ref azResult);
2822 }
2823 else
2824  
2825 if (c == 't' && n >= 8 && azArg[0].StartsWith("testctrl", StringComparison.InvariantCultureIgnoreCase) && nArg >= 2)
2826 {
2827 //static const struct {
2828 // string zCtrlName; /* Name of a test-control option */
2829 // int ctrlCode; /* Integer code for that option */
2830 //}
2831 _aCtrl[] aCtrl = new _aCtrl[] {
2832 new _aCtrl( "prng_save", Sqlite3.SQLITE_TESTCTRL_PRNG_SAVE ),
2833 new _aCtrl( "prng_restore", Sqlite3.SQLITE_TESTCTRL_PRNG_RESTORE ),
2834 new _aCtrl( "prng_reset", Sqlite3.SQLITE_TESTCTRL_PRNG_RESET ),
2835 new _aCtrl( "bitvec_test", Sqlite3.SQLITE_TESTCTRL_BITVEC_TEST ),
2836 new _aCtrl( "fault_install", Sqlite3.SQLITE_TESTCTRL_FAULT_INSTALL ),
2837 new _aCtrl( "benign_malloc_hooks", Sqlite3.SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS ),
2838 new _aCtrl( "pending_byte", Sqlite3.SQLITE_TESTCTRL_PENDING_BYTE ),
2839 new _aCtrl( "Debug.Assert", Sqlite3.SQLITE_TESTCTRL_ASSERT ),
2840 new _aCtrl( "always", Sqlite3.SQLITE_TESTCTRL_ALWAYS ),
2841 new _aCtrl( "reserve", Sqlite3.SQLITE_TESTCTRL_RESERVE ),
2842 new _aCtrl( "optimizations", Sqlite3.SQLITE_TESTCTRL_OPTIMIZATIONS ),
2843 new _aCtrl( "iskeyword", Sqlite3.SQLITE_TESTCTRL_ISKEYWORD ),
2844 new _aCtrl( "pghdrsz", Sqlite3.SQLITE_TESTCTRL_PGHDRSZ ),
2845 new _aCtrl( "scratchmalloc", Sqlite3.SQLITE_TESTCTRL_SCRATCHMALLOC ),
2846 };
2847 int testctrl = -1;
2848 //int rc = 0;
2849 int ii;//, n;
2850 open_db(p);
2851  
2852 /* convert testctrl text option to value. allow any unique prefix
2853 ** of the option name, or a numerical value. */
2854 //n = strlen30(azArg[1]);
2855 for (ii = 0; ii < aCtrl.Length; ii++)//(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++)
2856 {
2857 if (aCtrl[ii].zCtrlName.StartsWith(azArg[1], StringComparison.InvariantCultureIgnoreCase))
2858 {
2859 if (testctrl < 0)
2860 {
2861 testctrl = aCtrl[ii].ctrlCode;
2862 }
2863 else
2864 {
2865 fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[ii]);
2866 testctrl = -1;
2867 break;
2868 }
2869 }
2870 }
2871 if (testctrl < 0)
2872 testctrl = Convert.ToInt32(azArg[1]);//atoi
2873 if ((testctrl < Sqlite3.SQLITE_TESTCTRL_FIRST) || (testctrl > Sqlite3.SQLITE_TESTCTRL_LAST))
2874 {
2875 fprintf(stderr, "Error: invalid testctrl option: %s\n", azArg[1]);
2876 }
2877 else
2878 {
2879 switch (testctrl)
2880 {
2881  
2882 /* Sqlite3.sqlite3_test_control(int, db, Int) */
2883 case Sqlite3.SQLITE_TESTCTRL_OPTIMIZATIONS:
2884 case Sqlite3.SQLITE_TESTCTRL_RESERVE:
2885 if (nArg == 3)
2886 {
2887 int opt = (int)System.Int64.Parse(azArg[2]);
2888 rc = Sqlite3.sqlite3_test_control(testctrl, p.db, opt);
2889 printf("%d (0x%08x)\n", rc, rc);
2890 }
2891 else
2892 {
2893 fprintf(stderr, "Error: testctrl %s takes a single int option\n",
2894 azArg[1]);
2895 }
2896 break;
2897  
2898 /* Sqlite3.sqlite3_test_control(int) */
2899 case Sqlite3.SQLITE_TESTCTRL_PRNG_SAVE:
2900 case Sqlite3.SQLITE_TESTCTRL_PRNG_RESTORE:
2901 case Sqlite3.SQLITE_TESTCTRL_PRNG_RESET:
2902 case Sqlite3.SQLITE_TESTCTRL_PGHDRSZ:
2903 if (nArg == 2)
2904 {
2905 rc = Sqlite3.sqlite3_test_control(testctrl);
2906 printf("%d (0x%08x)\n", rc, rc);
2907 }
2908 else
2909 {
2910 fprintf(stderr, "Error: testctrl %s takes no options\n", azArg[1]);
2911 }
2912 break;
2913  
2914 /* Sqlite3.sqlite3_test_control(int, uint) */
2915 case Sqlite3.SQLITE_TESTCTRL_PENDING_BYTE:
2916 if (nArg == 3)
2917 {
2918 u32 opt = (u32)Convert.ToInt32(azArg[2]);//atoi
2919 rc = Sqlite3.sqlite3_test_control(testctrl, opt);
2920 printf("%d (0x%08x)\n", rc, rc);
2921 }
2922 else
2923 {
2924 fprintf(stderr, "Error: testctrl %s takes a single unsigned" +
2925 " int option\n", azArg[1]);
2926 }
2927 break;
2928  
2929 /* Sqlite3.sqlite3_test_control(int, Int) */
2930 case Sqlite3.SQLITE_TESTCTRL_ASSERT:
2931 case Sqlite3.SQLITE_TESTCTRL_ALWAYS:
2932 if (nArg == 3)
2933 {
2934 int opt = Convert.ToInt32(azArg[2]);//atoi
2935 rc = Sqlite3.sqlite3_test_control(testctrl, opt);
2936 printf("%d (0x%08x)\n", rc, rc);
2937 }
2938 else
2939 {
2940 fprintf(stderr, "Error: testctrl %s takes a single int option\n",
2941 azArg[1]);
2942 }
2943 break;
2944  
2945 /* Sqlite3.sqlite3_test_control(int, string ) */
2946 #if SQLITE_N_KEYWORD
2947 case Sqlite3.SQLITE_TESTCTRL_ISKEYWORD:
2948 if( nArg==3 ){
2949 string opt = azArg[2];
2950 rc = Sqlite3.sqlite3_test_control(testctrl, opt);
2951 printf("%d (0x%08x)\n", rc, rc);
2952 } else {
2953 fprintf(stderr,"Error: testctrl %s takes a single string option\n",
2954 azArg[1]);
2955 }
2956 break;
2957 #endif
2958  
2959 case Sqlite3.SQLITE_TESTCTRL_BITVEC_TEST:
2960 case Sqlite3.SQLITE_TESTCTRL_FAULT_INSTALL:
2961 case Sqlite3.SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
2962 case Sqlite3.SQLITE_TESTCTRL_SCRATCHMALLOC:
2963 default:
2964 fprintf(stderr, "Error: CLI support for testctrl %s not implemented\n",
2965 azArg[1]);
2966 break;
2967 }
2968 }
2969 }
2970 else
2971  
2972 if (c == 't' && n > 4 && azArg[0].StartsWith("timeout", StringComparison.InvariantCultureIgnoreCase) && nArg == 2)
2973 {
2974 open_db(p);
2975 Sqlite3.sqlite3_busy_timeout(p.db, Convert.ToInt32(azArg[1]));//atoi
2976 }
2977 else
2978  
2979 if (HAS_TIMER && c == 't' && n >= 5 && azArg[0].StartsWith("timer", StringComparison.InvariantCultureIgnoreCase)
2980 && nArg == 2
2981 )
2982 {
2983 enableTimer = booleanValue(azArg[1]);
2984 }
2985 else
2986  
2987 if (c == 'v' && azArg[0].StartsWith("version", StringComparison.InvariantCultureIgnoreCase))
2988 {
2989 printf("SQLite %s %s\n",
2990 Sqlite3.sqlite3_libversion(), Sqlite3.sqlite3_sourceid());
2991 }
2992 else
2993  
2994 if (c == 'w' && azArg[0].StartsWith("width", StringComparison.InvariantCultureIgnoreCase) && nArg > 1)
2995 {
2996 int j;
2997 Debug.Assert(nArg <= ArraySize(azArg));
2998 for (j = 1; j < nArg && j < ArraySize(p.colWidth); j++)
2999 {
3000 p.colWidth[j - 1] = Convert.ToInt32(azArg[j]);//atoi
3001 }
3002 }
3003 else
3004 {
3005 fprintf(stderr, "Error: unknown command or invalid arguments: " +
3006 " \"%s\". Enter \".help\" for help\n", azArg[0]);
3007 rc = 1;
3008 }
3009  
3010 return rc;
3011 }
3012  
3013 /*
3014 ** Return TRUE if a semicolon occurs anywhere in the first N characters
3015 ** of string z[].
3016 */
3017 static bool _contains_semicolon(string z, int N)
3018 {
3019 //int i;
3020 //for (i = 0; i < N; i++) { if (z[i] == ';') return 1; }
3021 //return 0;
3022 return z.Contains(";");
3023 }
3024  
3025 /*
3026 ** Test to see if a line consists entirely of whitespace.
3027 */
3028 static bool _all_whitespace(StringBuilder z)
3029 {
3030 return String.IsNullOrEmpty(z.ToString().Trim());
3031 }
3032 static bool _all_whitespace(string z)
3033 {
3034 return String.IsNullOrEmpty(z.Trim());
3035 }
3036  
3037 /*
3038 ** Return TRUE if the line typed in is an SQL command terminator other
3039 ** than a semi-colon. The SQL Server style "go" command is understood
3040 ** as is the Oracle "/".
3041 */
3042 static bool _is_command_terminator(StringBuilder zLine)
3043 {
3044 return _is_command_terminator(zLine.ToString());
3045 }
3046 static bool _is_command_terminator(string zLine)
3047 {
3048 zLine = zLine.Trim();// while ( isspace( zLine ) ) { zLine++; };
3049 if (zLine.Length == 0)
3050 return false;
3051 if (zLine[0] == '/')//&& _all_whitespace(zLine[1]) )
3052 {
3053 return true; /* Oracle */
3054 }
3055 if (Char.ToLower(zLine[0]) == 'g' && Char.ToLower(zLine[1]) == 'o')
3056 //&& _all_whitespace(&zLine[2]) )
3057 {
3058 return true; /* SQL Server */
3059 }
3060 return false;
3061 }
3062 /*
3063 ** Return true if zSql is a complete SQL statement. Return false if it
3064 ** ends in the middle of a string literal or C-style comment.
3065 */
3066 static bool _is_complete(string zSql, int nSql)
3067 {
3068 int rc;
3069 if (zSql == null)
3070 return true;
3071 //zSql[nSql] = ';';
3072 //zSql[nSql + 1] = 0;
3073 rc = Sqlite3.sqlite3_complete(zSql + ";\0");
3074 //zSql[nSql] = 0;
3075 return rc != 0;
3076 }
3077  
3078 /*
3079 ** Read input from In and process it. If In== null then input
3080 ** is interactive - the user is typing it it. Otherwise, Input
3081 ** is coming from a file or device. A prompt is issued and history
3082 ** is saved only if input is interactive. An interrupt signal will
3083 ** cause this routine to exit immediately, unless input is interactive.
3084 **
3085 ** Return the number of errors.
3086 */
3087 static int process_input(callback_data p, TextReader In)
3088 {
3089 StringBuilder zLine = new StringBuilder(1024);
3090 string zSql = null;
3091 int nSql = 0;
3092 int nSqlPrior = 0;
3093 string zErrMsg = null;
3094 int rc;
3095 int errCnt = 0;
3096 int lineno = 0;
3097 int startline = 0;
3098  
3099 while (errCnt == null || !bail_on_error || (In == null && stdin_is_interactive))
3100 {
3101 fflush(p.Out);
3102 //free(zLine);
3103 zLine.Length = 0;
3104 zLine.Append(one_input_line(zSql, In));
3105 if (In != null && ((System.IO.StreamReader)(In)).EndOfStream)
3106 {
3107 break; /* We have reached EOF */
3108 }
3109 //if (zLine == null)
3110 //{
3111 // break; /* We have reached EOF */
3112 //}
3113 if (seenInterrupt)
3114 {
3115 if (In != null)
3116 break;
3117 seenInterrupt = false;
3118 }
3119 lineno++;
3120 if (String.IsNullOrEmpty(zSql) && _all_whitespace(zLine))
3121 continue;
3122 if (zLine.Length > 0 && zLine[0] == '.' && nSql == 0)
3123 {
3124 if (p.echoOn)
3125 printf("%s\n", zLine);
3126 rc = do_meta_command(zLine, p);
3127 if (rc == 2)
3128 { /* exit requested */
3129 break;
3130 }
3131 else if (rc != 0)
3132 {
3133 errCnt++;
3134 }
3135 continue;
3136 }
3137 if (_is_command_terminator(zLine) && _is_complete(zSql, nSql))
3138 {
3139 zLine.Append(";");// memcpy(zLine, ";", 2);
3140 }
3141 nSqlPrior = nSql;
3142 if (zSql == null)
3143 {
3144 int i;
3145 for (i = 0; i < zLine.Length && isspace(zLine[i]); i++) { }
3146 if (i < zLine.Length)
3147 {
3148 nSql = strlen30(zLine);
3149 //zSql = malloc(nSql + 3);
3150 //if (zSql == null)
3151 //{
3152 // fprintf(stderr, "Error: out of memory\n");
3153 // exit(1);
3154 //}
3155 zSql += zLine.ToString(0, nSql);//memcpy(zSql, zLine, nSql + 1);
3156 startline = lineno;
3157 }
3158 }
3159 else
3160 {
3161 int len = strlen30(zLine);
3162 //zSql = realloc(zSql, nSql + len + 4);
3163 //if (zSql == null)
3164 //{
3165 // fprintf(stderr, "Error: out of memory\n");
3166 // exit(1);
3167 //}
3168 zSql += '\n';
3169 zSql += zLine;//memcpy(zSql[nSql], zLine, len + 1);
3170 nSql = zLine.Length;
3171 }
3172 if (!String.IsNullOrEmpty(zSql) && _contains_semicolon(zSql.Substring(nSqlPrior), nSql - nSqlPrior)
3173 && Sqlite3.sqlite3_complete(zSql) != 0)
3174 {
3175 p.cnt = 0;
3176 open_db(p);
3177 beginTimer();
3178 rc = shell_exec(p.db, zSql, shell_callback, p, ref zErrMsg);
3179 endTimer();
3180 if (rc != 0 || zErrMsg != null)
3181 {
3182 string zPrefix = null;
3183 if (In != null || !stdin_is_interactive)
3184 {
3185 snprintf(100, ref zPrefix,
3186 "Error: near line %d:", startline);
3187 }
3188 else
3189 {
3190 snprintf(100, ref zPrefix, "Error:");
3191 }
3192 if (zErrMsg != null)
3193 {
3194 fprintf(stderr, "%s %s\n", zPrefix, zErrMsg);
3195 //Sqlite3.sqlite3_free(zErrMsg);
3196 zErrMsg = null;
3197 }
3198 else
3199 {
3200 fprintf(stderr, "%s %s\n", zPrefix, Sqlite3.sqlite3_errmsg(p.db));
3201 }
3202 errCnt++;
3203 }
3204 //free(zSql);
3205 zSql = null;
3206 nSql = 0;
3207 }
3208 }
3209 if (zSql != null)
3210 {
3211 if (!_all_whitespace(zSql))
3212 {
3213 fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
3214 }
3215 zSql = null;//free(zSql);
3216 }
3217 zLine = null;//free(zLine);
3218 return errCnt;
3219 }
3220  
3221 /*
3222 ** Return a pathname which is the user's home directory. A
3223 ** 0 return indicates an error of some kind. Space to hold the
3224 ** resulting string is obtained from malloc(). The calling
3225 ** function should free the result.
3226 */
3227 static string find_home_dir()
3228 {
3229 string home_dir = null;
3230  
3231 //#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
3232 // struct passwd pwent;
3233 // uid_t uid = getuid();
3234 // if( (pwent=getpwuid(uid)) != null) {
3235 // home_dir = pwent.pw_dir;
3236 // }
3237 //#endif
3238  
3239 #if (_WIN32_WCE)
3240 /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
3241 */
3242 home_dir = strdup("/");
3243 #else
3244  
3245 #if (_WIN32) || (WIN32) || (__OS2__)
3246 //if (home_dir)
3247 {
3248 home_dir = getenv("USERPROFILE");
3249 }
3250 #endif
3251  
3252 if (!String.IsNullOrEmpty(home_dir))
3253 {
3254 home_dir = getenv("HOME");
3255 }
3256  
3257 #if (_WIN32) || (WIN32) || (__OS2__)
3258 if (String.IsNullOrEmpty(home_dir))
3259 {
3260 string zDrive, zPath;
3261 int n;
3262 zDrive = getenv("HOMEDRIVE");
3263 zPath = getenv("HOMEPATH");
3264 if (!String.IsNullOrEmpty(zDrive) && !String.IsNullOrEmpty(zPath))
3265 {
3266 n = strlen30(zDrive) + strlen30(zPath) + 1;
3267 //home_dir = malloc(n);
3268 //if (home_dir == null)
3269 // return 0;
3270 snprintf(n, ref home_dir, "%s%s", zDrive, zPath);
3271 return home_dir;
3272 }
3273 home_dir = "c:\\";
3274 }
3275 #endif
3276  
3277 #endif //* !_WIN32_WCE */
3278  
3279 //if (home_dir)
3280 //{
3281 // int n = strlen30(home_dir) + 1;
3282 // string z = malloc(n);
3283 // if (z)
3284 // memcpy(z, home_dir, n);
3285 // home_dir = z;
3286 //}
3287  
3288 return home_dir;
3289 }
3290  
3291 /*
3292 ** Read input from the file given by sqliterc_override. Or if that
3293 ** parameter is null, take input from ~/.sqliterc
3294 **
3295 ** Returns the number of errors.
3296 */
3297 static int process_sqliterc(
3298 callback_data p, /* Configuration data */
3299 string sqliterc_override /* Name of config file. null to use default */
3300 )
3301 {
3302 string home_dir = null;
3303 string sqliterc = sqliterc_override;
3304 StringBuilder zBuf = null;
3305 StreamReader In = null;
3306 int nBuf;
3307 int rc = 0;
3308  
3309 if (sqliterc == null)
3310 {
3311 home_dir = find_home_dir();
3312 if (home_dir == null)
3313 {
3314 #if !(__RTP__) && !(_WRS_KERNEL)
3315 fprintf(stderr, "%s: Error: cannot locate your home directory\n", Argv0);
3316 #endif
3317 return 1;
3318 }
3319 nBuf = strlen30(home_dir) + 16;
3320 zBuf = new StringBuilder(nBuf);
3321 if (zBuf == null)
3322 {
3323 fprintf(stderr, "%s: Error: out of memory\n", Argv0);
3324 return 1;
3325 }
3326 Sqlite3.sqlite3_snprintf(nBuf, zBuf, "%s/.sqliterc", home_dir);
3327 home_dir = null;//free(home_dir);
3328 sqliterc = zBuf.ToString();
3329 }
3330 if (File.Exists(sqliterc))
3331 {
3332 try
3333 {
3334 In = new StreamReader(sqliterc);// fopen(sqliterc, "rb");
3335 if (In != null)
3336 {
3337 if (stdin_is_interactive)
3338 {
3339 fprintf(stderr, "-- Loading resources from %s\n", sqliterc);
3340 }
3341 rc = process_input(p, In);
3342 In.Close();//fclose(In);
3343 }
3344 } catch
3345 {
3346 }
3347 }
3348 zBuf = null;//free(zBuf);
3349 return rc;
3350 }
3351  
3352 /*
3353 ** Show available command line options
3354 */
3355 static string zOptions =
3356 " -help show this message\n" +
3357 " -init filename read/process named file\n" +
3358 " -echo print commands before execution\n" +
3359 " -[no]header turn headers on or off\n" +
3360 " -bail stop after hitting an error\n" +
3361 " -interactive force interactive I/O\n" +
3362 " -batch force batch I/O\n" +
3363 " -column set output mode to 'column'\n" +
3364 " -csv set output mode to 'csv'\n" +
3365 " -html set output mode to HTML\n" +
3366 " -line set output mode to 'line'\n" +
3367 " -list set output mode to 'list'\n" +
3368 " -separator 'x' set output field separator (|)\n" +
3369 " -stats print memory stats before each finalize\n" +
3370 " -nullvalue 'text' set text string for null values\n" +
3371 " -version show SQLite version\n" +
3372 " -vfs NAME use NAME as the default VFS\n" +
3373 #if SQLITE_ENABLE_VFSTRACE
3374 " -vfstrace enable tracing of all VFS calls\n" +
3375 #endif
3376 "";
3377 static void usage(bool showDetail)
3378 {
3379 fprintf(stderr,
3380 "Usage: %s [OPTIONS] FILENAME [SQL]\n" +
3381 "FILENAME is the name of an SQLite database. A new database is created\n" +
3382 "if the file does not previously exist.\n", Argv0);
3383 if (showDetail)
3384 {
3385 fprintf(stderr, "OPTIONS include:\n%s", zOptions);
3386 }
3387 else
3388 {
3389 fprintf(stderr, "Use the -help option for additional information\n");
3390 }
3391 exit(1);
3392 }
3393  
3394 /*
3395 ** Initialize the state information in data
3396 */
3397 static void main_init(ref callback_data data)
3398 {
3399 data = new callback_data();//memset(data, 0, sizeof(*data));
3400 data.mode = MODE_List;
3401 data.separator = "|";//memcpy(data.separator, "|", 2);
3402 data.showHeader = false;
3403 Sqlite3.sqlite3_initialize();
3404 Sqlite3.sqlite3_config(Sqlite3.SQLITE_CONFIG_URI, 1);
3405 Sqlite3.sqlite3_config(Sqlite3.SQLITE_CONFIG_LOG, new object[] { (Sqlite3.dxLog)shellLog, data, null });
3406 snprintf(10, ref mainPrompt, "sqlite> ");
3407 snprintf(10, ref continuePrompt, " ...> ");
3408 Sqlite3.sqlite3_config(Sqlite3.SQLITE_CONFIG_SINGLETHREAD);
3409 }
3410  
3411 static int main(int argc, string[] argv)
3412 {
3413 string zErrMsg = null;
3414 callback_data data = null;
3415 string zInitFile = null;
3416 StringBuilder zFirstCmd = null;
3417 int i;
3418 int rc = 0;
3419  
3420 if (!Sqlite3.sqlite3_sourceid().Equals(Sqlite3.SQLITE_SOURCE_ID, StringComparison.InvariantCultureIgnoreCase))
3421 {
3422 fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
3423 Sqlite3.sqlite3_sourceid(), Sqlite3.SQLITE_SOURCE_ID);
3424 exit(1);
3425 }
3426 Argv0 = argv.Length == 0 ? null : argv[0];
3427 main_init(ref data);
3428 stdin_is_interactive = isatty(0);
3429  
3430 /* Make sure we have a valid signal handler early, before anything
3431 ** else is done.
3432 */
3433 #if SIGINT
3434 signal(SIGINT, Interrupt_handler);
3435 #endif
3436  
3437 /* Do an initial pass through the command-line argument to locate
3438 ** the name of the database file, the name of the initialization file,
3439 ** the size of the alternative malloc heap,
3440 ** and the first command to execute.
3441 */
3442 for (i = 0; i < argc - 1; i++)
3443 {
3444 string z;
3445 if (argv[i][0] != '-')
3446 break;
3447 z = argv[i];
3448 if (z[0] == '-' && z[1] == '-')
3449 z = z.Remove(0, 1);//z++;
3450 if (argv[i].Equals("-separator", StringComparison.InvariantCultureIgnoreCase) || argv[i].Equals("-nullvalue", StringComparison.InvariantCultureIgnoreCase))
3451 {
3452 i++;
3453 }
3454 else if (argv[i].Equals("-init", StringComparison.InvariantCultureIgnoreCase))
3455 {
3456 i++;
3457 zInitFile = argv[i];
3458 /* Need to check for batch mode here to so we can avoid printing
3459 ** informational messages (like from process_sqliterc) before
3460 ** we do the actual processing of arguments later in a second pass.
3461 */
3462 }
3463 else if (argv[i].Equals("-batch", StringComparison.InvariantCultureIgnoreCase))
3464 {
3465 stdin_is_interactive = false;
3466 }
3467 else if (argv[i].Equals("-heap", StringComparison.InvariantCultureIgnoreCase))
3468 {
3469 int j, c;
3470 string zSize;
3471 sqlite3_int64 szHeap;
3472  
3473 zSize = argv[++i];
3474 szHeap = Convert.ToInt32(zSize);//atoi
3475 for (j = 0; (c = zSize[j]) != null; j++)
3476 {
3477 if (c == 'M') { szHeap *= 1000000; break; }
3478 if (c == 'K') { szHeap *= 1000; break; }
3479 if (c == 'G') { szHeap *= 1000000000; break; }
3480 }
3481 if (szHeap > 0x7fff0000)
3482 szHeap = 0x7fff0000;
3483 #if (SQLITE_ENABLE_MEMSYS3) || (SQLITE_ENABLE_MEMSYS5)
3484 Sqlite3.SQLITE_config(Sqlite3.SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
3485 #endif
3486 #if SQLITE_ENABLE_VFSTRACE
3487 }else if( argv[i].Equals("-vfstrace", StringComparison.InvariantCultureIgnoreCase) ){
3488 extern int vfstrace_register(
3489 string zTraceName,
3490 string zOldVfsName,
3491 int (*xOut)(const char*,void*),
3492 void pOutArg,
3493 int makeDefault
3494 );
3495 vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
3496 #endif
3497 }
3498 else if (argv[i].Equals("-vfs", StringComparison.InvariantCultureIgnoreCase))
3499 {
3500 Sqlite3.sqlite3_vfs pVfs = Sqlite3.sqlite3_vfs_find(argv[++i]);
3501 if (pVfs != null)
3502 {
3503 Sqlite3.sqlite3_vfs_register(pVfs, 1);
3504 }
3505 else
3506 {
3507 fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
3508 exit(1);
3509 }
3510 }
3511 }
3512 if (i < argc)
3513 {
3514 #if (SQLITE_OS_OS2) && SQLITE_OS_OS2
3515 data.zDbFilename = (string )convertCpPathToUtf8( argv[i++] );
3516 #else
3517 data.zDbFilename = argv[i++];
3518 #endif
3519 }
3520 else
3521 {
3522 #if !SQLITE_OMIT_MEMORYDB
3523 data.zDbFilename = ":memory:";
3524 #else
3525 data.zDbFilename = 0;
3526 #endif
3527 }
3528 if (i < argc)
3529 {
3530 zFirstCmd.Append(argv[i++]);
3531 }
3532 if (i < argc)
3533 {
3534 fprintf(stderr, "%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
3535 fprintf(stderr, "Use -help for a list of options.\n");
3536 return 1;
3537 }
3538 data.Out = stdout;
3539  
3540 #if SQLITE_OMIT_MEMORYDB
3541 if( data.zDbFilename== null ){
3542 fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
3543 return 1;
3544 }
3545 #endif
3546  
3547 /* Go ahead and open the database file if it already exists. If the
3548 ** file does not exist, delay opening it. This prevents empty database
3549 ** files from being created if a user mistypes the database name argument
3550 ** to the sqlite command-line tool.
3551 */
3552 if (File.Exists(data.zDbFilename)) //(access(data.zDbFilename, 0) == 0)
3553 {
3554 open_db(data);
3555 }
3556  
3557 /* Process the initialization file if there is one. If no -init option
3558 ** is given on the command line, look for a file named ~/.sqliterc and
3559 ** try to process it.
3560 */
3561 rc = process_sqliterc(data, zInitFile);
3562 if (rc > 0)
3563 {
3564 return rc;
3565 }
3566  
3567 /* Make a second pass through the command-line argument and set
3568 ** options. This second pass is delayed until after the initialization
3569 ** file is processed so that the command-line arguments will override
3570 ** settings in the initialization file.
3571 */
3572 for (i = 0; i < argc && argv[i][0] == '-'; i++)
3573 {
3574 string z = argv[i];
3575 if (z[1] == '-') { z = z.Remove(0, 1); } //z++;
3576 if (z.Equals("-init", StringComparison.InvariantCultureIgnoreCase))
3577 {
3578 i++;
3579 }
3580 else if (z.Equals("-html", StringComparison.InvariantCultureIgnoreCase))
3581 {
3582 data.mode = MODE_Html;
3583 }
3584 else if (z.Equals("-list", StringComparison.InvariantCultureIgnoreCase))
3585 {
3586 data.mode = MODE_List;
3587 }
3588 else if (z.Equals("-line", StringComparison.InvariantCultureIgnoreCase))
3589 {
3590 data.mode = MODE_Line;
3591 }
3592 else if (z.Equals("-column", StringComparison.InvariantCultureIgnoreCase))
3593 {
3594 data.mode = MODE_Column;
3595 }
3596 else if (z.Equals("-csv", StringComparison.InvariantCultureIgnoreCase))
3597 {
3598 data.mode = MODE_Csv;
3599 data.separator = ",";//memcpy(data.separator, ",", 2);
3600 }
3601 else if (z.Equals("-separator", StringComparison.InvariantCultureIgnoreCase))
3602 {
3603 i++;
3604 if (i >= argc)
3605 {
3606 fprintf(stderr, "%s: Error: missing argument for option: %s\n", Argv0, z);
3607 fprintf(stderr, "Use -help for a list of options.\n");
3608 return 1;
3609 }
3610 snprintf(data.separator.Length, ref data.separator,
3611 "%.*s", data.separator.Length - 1, argv[i]);
3612 }
3613 else if (z.Equals("-nullvalue", StringComparison.InvariantCultureIgnoreCase))
3614 {
3615 i++;
3616 if (i >= argc)
3617 {
3618 fprintf(stderr, "%s: Error: missing argument for option: %s\n", Argv0, z);
3619 fprintf(stderr, "Use -help for a list of options.\n");
3620 return 1;
3621 }
3622 snprintf(99, ref data.nullvalue,
3623 "%.*s", 99 - 1, argv[i]);
3624 }
3625 else if (z.Equals("-header", StringComparison.InvariantCultureIgnoreCase))
3626 {
3627 data.showHeader = true;
3628 }
3629 else if (z.Equals("-noheader", StringComparison.InvariantCultureIgnoreCase))
3630 {
3631 data.showHeader = false;
3632 }
3633 else if (z.Equals("-echo", StringComparison.InvariantCultureIgnoreCase))
3634 {
3635 data.echoOn = true;
3636 }
3637 else if (z.Equals("-stats", StringComparison.InvariantCultureIgnoreCase))
3638 {
3639 data.statsOn = true;
3640 }
3641 else if (z.Equals("-bail", StringComparison.InvariantCultureIgnoreCase))
3642 {
3643 bail_on_error = true;
3644 }
3645 else if (z.Equals("-version", StringComparison.InvariantCultureIgnoreCase))
3646 {
3647 printf("%s %s\n", Sqlite3.sqlite3_libversion(), Sqlite3.sqlite3_sourceid());
3648 return 0;
3649 }
3650 else if (z.Equals("-interactive", StringComparison.InvariantCultureIgnoreCase))
3651 {
3652 stdin_is_interactive = true;
3653 }
3654 else if (z.Equals("-batch", StringComparison.InvariantCultureIgnoreCase))
3655 {
3656 stdin_is_interactive = false;
3657 }
3658 else if (z.Equals("-heap", StringComparison.InvariantCultureIgnoreCase))
3659 {
3660 i++;
3661 }
3662 else if (z.Equals("-vfs", StringComparison.InvariantCultureIgnoreCase))
3663 {
3664 i++;
3665 }
3666 else if (z.Equals("-vfstrace", StringComparison.InvariantCultureIgnoreCase))
3667 {
3668 i++;
3669 }
3670 else if (z.Equals("-help", StringComparison.InvariantCultureIgnoreCase) || z.Equals("--help", StringComparison.InvariantCultureIgnoreCase))
3671 {
3672 usage(true);
3673 }
3674 else
3675 {
3676 fprintf(stderr, "%s: Error: unknown option: %s\n", Argv0, z);
3677 fprintf(stderr, "Use -help for a list of options.\n");
3678 return 1;
3679 }
3680 }
3681  
3682 if (zFirstCmd != null && zFirstCmd.Length > 0)
3683 {
3684 /* Run just the command that follows the database name
3685 */
3686 if (zFirstCmd[0] == '.')
3687 {
3688 rc = do_meta_command(zFirstCmd, data);
3689 }
3690 else
3691 {
3692 open_db(data);
3693 rc = shell_exec(data.db, zFirstCmd.ToString(), shell_callback, data, ref zErrMsg);
3694 if (zErrMsg != null)
3695 {
3696 fprintf(stderr, "Error: %s\n", zErrMsg);
3697 return rc != 0 ? rc : 1;
3698 }
3699 else if (rc != 0)
3700 {
3701 fprintf(stderr, "Error: unable to process SQL \"%s\"\n", zFirstCmd);
3702 return rc;
3703 }
3704 }
3705 }
3706 else
3707 {
3708 /* Run commands received from standard input
3709 */
3710 if (stdin_is_interactive)
3711 {
3712 string zHome;
3713 string zHistory = null;
3714 int nHistory;
3715 printf(
3716 #if (SQLITE_HAS_CODEC) && (SQLITE_ENABLE_CEROD)
3717 "SQLite version %s with the CEROD Extension\n" +
3718 "Copyright 2006 Hipp, Wyrick & Company, Inc.\n" +
3719 #else
3720 "SQLite version %s\n" +
3721 #endif
3722 "(source %.19s)\n" +
3723 "Enter \".help\" for instructions\n" +
3724 "Enter SQL statements terminated with a \";\"\n",
3725 Sqlite3.sqlite3_libversion(), Sqlite3.sqlite3_sourceid()
3726 );
3727 zHome = find_home_dir();
3728 if (zHome != null)
3729 {
3730 nHistory = strlen30(zHome) + 20;
3731 //if ((zHistory = malloc(nHistory)) != null)
3732 {
3733 snprintf(nHistory, ref zHistory, "%s/.Sqlite3.SQLITE_history", zHome);
3734 }
3735 }
3736 #if (HAVE_READLINE)// && HAVE_READLINE==1
3737 if( zHistory ) read_history(zHistory);
3738 #endif
3739 rc = process_input(data, null);
3740 if (zHistory != null)
3741 {
3742 stifle_history(100);
3743 write_history(zHistory);
3744 zHistory = null;//free(zHistory);
3745 }
3746 zHome = null;//free(zHome);
3747 }
3748 else
3749 {
3750 rc = process_input(data, stdin);
3751 }
3752 }
3753 set_table_name(data, null);
3754 if (data.db != null)
3755 {
3756 Sqlite3.sqlite3_close(data.db);
3757 }
3758 return rc;
3759 }
3760 // C# DllImports
3761 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
3762 internal static extern void FreeLibrary(IntPtr hModule);
3763  
3764 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
3765 internal static extern IntPtr LoadLibrary(string lpFileName);
3766  
3767 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
3768 internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
3769  
3770 // Helper Variables for C#
3771 static TextReader stdin = Console.In;
3772 static TextWriter stdout = Console.Out;
3773 static TextWriter stderr = Console.Error;
3774  
3775 // Helper Functions for C#
3776 private static void exit(int p)
3777 {
3778 if (p == 0)
3779 {
3780 Console.WriteLine("Enter to CONTINUE:");
3781 }
3782 else
3783 {
3784 Console.WriteLine(String.Format("Error: {0}", p));
3785 }
3786 Console.ReadKey();
3787 }
3788 private static void fflush(TextWriter tw)
3789 {
3790 tw.Flush();
3791 }
3792 private static int fgets(StringBuilder p, int p_2, TextReader In)
3793 {
3794 try
3795 {
3796 p.Length = 0;
3797 p.Append(In.ReadLine());
3798 if (p.Length > 0)
3799 p.Append('\n');
3800 return p.Length;
3801 } catch
3802 {
3803 return 0;
3804 }
3805 }
3806 private static void fputc(char c, TextWriter Out)
3807 {
3808 Out.Write(c);
3809 }
3810 private static string getenv(string p)
3811 {
3812 switch (p)
3813 {
3814 case "USERPROFILE":
3815 return Environment.GetEnvironmentVariable("UserProfile");
3816 case "HOME":
3817 {
3818 return Environment.GetEnvironmentVariable("Home");
3819 }
3820 case "HOMEDRIVE":
3821 {
3822 return Environment.GetEnvironmentVariable("HomeDrive");
3823 }
3824 case "HOMEPATH":
3825 {
3826 return Environment.GetEnvironmentVariable("HomePath");
3827 }
3828 default:
3829 throw new Exception("The method or operation is not implemented.");
3830 }
3831 }
3832 static bool isalnum(char c)
3833 {
3834 return char.IsLetterOrDigit(c);
3835 }
3836 static bool isalpha(char c)
3837 {
3838 return char.IsLetter(c);
3839 }
3840 static bool isdigit(char c)
3841 {
3842 return char.IsDigit(c);
3843 }
3844 static bool isprint(char c)
3845 {
3846 return !char.IsControl(c);
3847 }
3848 private static bool isspace(char c)
3849 {
3850 return char.IsWhiteSpace(c);
3851 }
3852 static void fprintf(TextWriter tw, string zFormat, params va_list[] ap)
3853 {
3854 tw.Write(Sqlite3.sqlite3_mprintf(zFormat, ap));
3855 }
3856 public static void Main(string[] args)
3857 {
3858 main(args.Length, args);
3859 }
3860  
3861 static void printf(string zFormat, params va_list[] ap)
3862 {
3863 stdout.Write(Sqlite3.sqlite3_mprintf(zFormat, ap));
3864 }
3865 private static void putc(char c, TextWriter _out)
3866 {
3867 _out.Write(c);
3868 }
3869 private static void snprintf(int n, ref string zBuf, string zFormat, params va_list[] ap)
3870 {
3871 StringBuilder sbBuf = new StringBuilder(100);
3872 Sqlite3.sqlite3_snprintf(n, sbBuf, zFormat, ap);
3873 zBuf = sbBuf.ToString();
3874 }
3875 }
3876 }