PageRenderTime 41ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/SQL/Community.CsharpSqlite.shell/src/shell.cs

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