/trunk/Community.CsharpSqlite.shell/src/shell.cs |
@@ -0,0 +1,3876 @@ |
using System; |
using System.Diagnostics; |
using System.IO; |
using System.Runtime.InteropServices; |
using System.Text; |
|
using FILE = System.IO.TextWriter; |
using GETPROCTIMES = System.IntPtr; |
using HANDLE = System.IntPtr; |
using HINSTANCE = System.IntPtr; |
using sqlite3_int64 = System.Int64; |
using u32 = System.UInt32; |
using va_list = System.Object; |
|
namespace Community.CsharpSqlite |
{ |
using dxCallback = Sqlite3.dxCallback; |
using FILETIME = Sqlite3.FILETIME; |
using sqlite3 = Sqlite3.sqlite3; |
using sqlite3_stmt = Sqlite3.Vdbe; |
using sqlite3_value = Sqlite3.Mem; |
|
|
class Shell |
{ |
|
/* |
** 2001 September 15 |
** |
** The author disclaims copyright to this source code. In place of |
** a legal notice, here is a blessing: |
** |
** May you do good and not evil. |
** May you find forgiveness for yourself and forgive others. |
** May you share freely, never taking more than you give. |
** |
************************************************************************* |
** This file contains code to implement the "sqlite" command line |
** utility for accessing SQLite databases. |
************************************************************************* |
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart |
** C#-SQLite is an independent reimplementation of the SQLite software library |
** |
************************************************************************* |
*/ |
//#if defined(_WIN32) || defined(WIN32) |
///* This needs to come before any includes for MSVC compiler */ |
//#define _CRT_SECURE_NO_WARNINGS |
//#endif |
|
//#include <stdlib.h> |
//#include <string.h> |
//#include <stdio.h> |
//#include <Debug.Assert.h> |
//#include "sqlite3.h" |
//#include <ctype.h> |
//#include <stdarg.h> |
|
//#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) |
//# include <signal.h> |
//# if !defined(__RTP__) && !defined(_WRS_KERNEL) |
//# include <pwd.h> |
//# endif |
//# include <unistd.h> |
//# include <sys/types.h> |
//#endif |
|
//#if __OS2__ |
//# include <unistd.h> |
//#endif |
|
//#if HAVE_EDITLINE |
//# include <editline/editline.h> |
//#endif |
//#if defined(HAVE_READLINE) && HAVE_READLINE==1 |
//# include <readline/readline.h> |
//# include <readline/history.h> |
//#endif |
#if !(HAVE_EDITLINE) //&& (!(HAVE_READLINE) || HAVE_READLINE!=1) |
//# define readline(p) local_getline(p,stdin) |
static string readline(string p) |
{ |
return local_getline(p, stdin); |
} |
//# define add_history(X) |
static void add_history(object p) { } |
//# define read_history(X) |
static void read_history(object p) { } |
//# define write_history(X) |
static void write_history(object p) { } |
//# define stifle_history(X) |
static void stifle_history(object p) { } |
#endif |
|
#if (_WIN32) || (WIN32) |
//# include <io.h> |
//#define isatty(h) _isatty(h) |
static bool isatty(object h) { return stdin.Equals(Console.In); } |
//#define access(f,m) _access((f),(m)) |
#else |
/* Make sure isatty() has a prototype. |
*/ |
extern int isatty(); |
#endif |
|
//#if defined(_WIN32_WCE) |
///* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() |
// * thus we always assume that we have a console. That can be |
// * overridden with the -batch command line option. |
// */ |
//#define isatty(x) 1 |
//#endif |
|
/* True if the timer is enabled */ |
static bool enableTimer = false; |
|
#if FALSE//!defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL) |
//#include <sys/time.h> |
//#include <sys/resource.h> |
|
///* Saved resource information for the beginning of an operation */ |
//static struct rusage sBegin; |
|
///* |
//** Begin timing an operation |
//*/ |
//static void beginTimer(){ |
// if( enableTimer ){ |
// getrusage(RUSAGE_SELF, sBegin); |
// } |
//} |
|
///* Return the difference of two time_structs in seconds */ |
//static double timeDiff(timeval pStart, struct timeval pEnd){ |
// return (pEnd.tv_usec - pStart.tv_usec)*0.000001 + |
// (double)(pEnd.tv_sec - pStart.tv_sec); |
//} |
|
///* |
//** Print the timing results. |
//*/ |
//static void endTimer(){ |
// if( enableTimer ){ |
// struct rusage sEnd; |
// getrusage(RUSAGE_SELF, sEnd); |
// printf("CPU Time: user %f sys %f\n", |
// timeDiff(sBegin.ru_utime, sEnd.ru_utime), |
// timeDiff(sBegin.ru_stime, sEnd.ru_stime)); |
// } |
//} |
|
//#define BEGIN_TIMER beginTimer() |
//#define END_TIMER endTimer() |
//#define HAS_TIMER 1 |
|
#elif ((_WIN32) || (WIN32)) |
|
//#include <windows.h> |
|
/* Saved resource information for the beginning of an operation */ |
static Process hProcess; |
//static FILETIME ftKernelBegin; |
//static FILETIME ftUserBegin; |
static TimeSpan tsUserBegin; |
static TimeSpan tsKernelBegin; |
|
//typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); |
|
/* |
** Check to see if we have timer support. Return 1 if necessary |
** support found (or found previously). |
*/ |
//static bool has_timer() |
//{ |
// if (getProcessTimesAddr != IntPtr.Zero) |
// { |
// return true; |
// } |
// else |
// { |
// /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions. |
// ** See if the version we are running on has it, and if it does, save off |
// ** a pointer to it and the current process handle. |
// */ |
// hProcess = Process.GetCurrentProcess(); |
// if (hProcess != null) |
// { |
// HINSTANCE hinstLib = LoadLibrary("Kernel32.dll"); |
// if (null != hinstLib) |
// { |
// getProcessTimesAddr = (GETPROCTIMES)GetProcAddress(hinstLib, "GetProcessTimes"); |
// if (null != getProcessTimesAddr) |
// { |
// return true; |
// } |
// FreeLibrary(hinstLib); |
// } |
// } |
// } |
// return true; |
//} |
|
/* |
** Begin timing an operation |
*/ |
static void beginTimer() |
{ |
if (enableTimer)//&& getProcessTimesAddr != IntPtr.Zero) |
{ |
//FILETIME ftCreation, ftExit; |
//getProcessTimesAddr(hProcess, ftCreation, ftExit, ftKernelBegin, ftUserBegin); |
tsUserBegin = Process.GetCurrentProcess().UserProcessorTime; |
tsKernelBegin = Process.GetCurrentProcess().TotalProcessorTime - Process.GetCurrentProcess().UserProcessorTime; |
} |
} |
|
/* Return the difference of two TimeSpan structs in seconds */ |
static double timeDiff(TimeSpan pStart, TimeSpan pEnd) |
{ |
//sqlite3_int64 i64Start = ((sqlite3_int64)pStart.dwLowDateTime); |
//sqlite3_int64 i64End = ((sqlite3_int64)pEnd.dwLowDateTime); |
//return (double)((i64End - i64Start) / 10000000.0); |
return timeDiff(pStart, pEnd) / 10000000.0; |
} |
|
/* |
** Print the timing results. |
*/ |
static void endTimer() |
{ |
if (enableTimer)// && getProcessTimesAddr != IntPtr.Zero) |
{ |
//FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; |
//getProcessTimesAddr(hProcess, ftCreation, ftExit, ftKernelEnd, ftUserEnd); |
TimeSpan tsKernelEnd, tsUserEnd; |
tsUserEnd = Process.GetCurrentProcess().UserProcessorTime; |
tsKernelEnd = Process.GetCurrentProcess().TotalProcessorTime - Process.GetCurrentProcess().UserProcessorTime; |
|
printf("CPU Time: user %f sys %f\n", |
timeDiff(tsUserBegin, tsUserEnd), |
timeDiff(tsKernelBegin, tsKernelEnd)); |
} |
} |
|
//#define BEGIN_TIMER beginTimer() |
//#define END_TIMER endTimer() |
//#define HAS_TIMER HAS_TIMER |
static bool HAS_TIMER = true; |
#else |
//#define BEGIN_TIMER |
//#define END_TIMER |
//#define HAS_TIMER 0 |
#endif |
|
/* |
** Used to prevent warnings about unused parameters |
*/ |
//#define UNUSED_PARAMETER(x) ()(x) |
static void UNUSED_PARAMETER<T>(T x) { } |
|
/* |
** If the following flag is set, then command execution stops |
** at an error if we are not interactive. |
*/ |
static bool bail_on_error = false; |
|
/* |
** Threat stdin as an interactive input if the following variable |
** is true. Otherwise, assume stdin is connected to a file or pipe. |
*/ |
static bool stdin_is_interactive = true; |
|
/* |
** The following is the open SQLite database. We make a pointer |
** to this database a static variable so that it can be accessed |
** by the SIGINT handler to interrupt database processing. |
*/ |
static sqlite3 db = null; |
|
/* |
** True if an interrupt (Control-C) has been received. |
*/ |
static bool seenInterrupt = false; |
|
/* |
** This is the name of our program. It is set in main(), used |
** in a number of other places, mostly for error messages. |
*/ |
static string Argv0; |
|
/* |
** Prompt strings. Initialized in main. Settable with |
** .prompt main continue |
*/ |
static string mainPrompt; /* First line prompt. default: "sqlite> "*/ |
static string continuePrompt; /* Continuation prompt. default: " ...> " */ |
|
/* |
** Write I/O traces to the following stream. |
*/ |
#if SQLITE_ENABLE_IOTRACE |
static FILE iotrace = null; |
#endif |
|
/* |
** This routine works like printf in that its first argument is a |
** format string and subsequent arguments are values to be substituted |
** in place of % fields. The result of formatting this string |
** is written to iotrace. |
*/ |
#if SQLITE_ENABLE_IOTRACE |
static void iotracePrintf(string zFormat, ...){ |
va_list ap; |
string z; |
if( iotrace== null ) return; |
va_start(ap, zFormat); |
z = Sqlite3.SQLITE_vmprintf(zFormat, ap); |
va_end(ap); |
fprintf(iotrace, "%s", z); |
Sqlite3.sqlite3_free(z); |
} |
#endif |
|
|
/* |
** Determines if a string is a number of not. |
*/ |
//static int isNumber(string z, ref int realnum){ |
// if( *z=='-' || *z=='+' ) z++; |
// if( !isdigit(*z) ){ |
// return 0; |
// } |
// z++; |
// //if( realnum ) *realnum = 0; |
// realnum = 0; |
// while( isdigit(*z) ){ z++; } |
// if( *z=='.' ){ |
// z++; |
// if( !isdigit(*z) ) return 0; |
// while( isdigit(*z) ){ z++; } |
// //if( realnum ) *realnum = 1; |
// realnum = 1; |
// } |
// if( *z=='e' || *z=='E' ){ |
// z++; |
// if( *z=='+' || *z=='-' ) z++; |
// if( !isdigit(*z) ) return 0; |
// while( isdigit(*z) ){ z++; } |
// //if( realnum ) *realnum = 1; |
// realnum = 1; |
// } |
// return *z== null; |
//} |
static bool isNumber(string z) |
{ |
int i = 0; |
return isNumber(z, ref i); |
} |
static bool isNumber(string z, int i) |
{ |
return isNumber(z, ref i); |
} |
static bool isNumber(string z, ref int realnum) |
{ |
int zIdx = 0; |
if (z[zIdx] == '-' || z[zIdx] == '+') |
zIdx++; |
if (zIdx == z.Length || !isdigit(z[zIdx])) |
{ |
return false; |
} |
zIdx++; |
realnum = 0; |
while (zIdx < z.Length && isdigit(z[zIdx])) |
{ |
zIdx++; |
} |
if (z[zIdx] == '.') |
{ |
zIdx++; |
if (zIdx < z.Length && !isdigit(z[zIdx])) |
return false; |
while (zIdx < z.Length && isdigit(z[zIdx])) |
{ |
zIdx++; |
} |
realnum = 1; |
} |
if (z[zIdx] == 'e' || z[zIdx] == 'E') |
{ |
zIdx++; |
if (zIdx < z.Length && (z[zIdx] == '+' || z[zIdx] == '-')) |
zIdx++; |
if (zIdx == z.Length || !isdigit(z[zIdx])) |
return false; |
while (zIdx < z.Length && isdigit(z[zIdx])) |
{ |
zIdx++; |
} |
realnum = 1; |
} |
return zIdx == z.Length; |
} |
|
|
/* |
** A global char* and an SQL function to access its current value |
** from within an SQL statement. This program used to use the |
** Sqlite3.sqlite3_exec_printf() API to substitue a string into an SQL statement. |
** The correct way to do this with sqlite3 is to use the bind API, but |
** since the shell is built around the callback paradigm it would be a lot |
** of work. Instead just use this hack, which is quite harmless. |
*/ |
static string zShellStatic = ""; |
static void shellstaticFunc( |
Sqlite3.sqlite3_context context, |
int argc, |
sqlite3_value[] argv |
) |
{ |
Debug.Assert(0 == argc); |
Debug.Assert(String.IsNullOrEmpty(zShellStatic)); |
UNUSED_PARAMETER(argc); |
UNUSED_PARAMETER(argv); |
Sqlite3.sqlite3_result_text(context, zShellStatic, -1, Sqlite3.SQLITE_STATIC); |
} |
|
|
/* |
** This routine reads a line of text from FILE in, stores |
** the text in memory obtained from malloc() and returns a pointer |
** to the text. null is returned at end of file, or if malloc() |
** fails. |
** |
** The interface is like "readline" but no command-line editing |
** is done. |
*/ |
static string local_getline(string zPrompt, TextReader In) |
{ |
StringBuilder zIn = new StringBuilder(); |
StringBuilder zLine; |
int nLine; |
int n; |
bool eol; |
|
if (zPrompt != null) |
{ |
printf("%s", zPrompt); |
fflush(stdout); |
} |
nLine = 100; |
zLine = new StringBuilder(nLine);//malloc( nLine ); |
//if( zLine== null ) return 0; |
n = 0; |
eol = false; |
while (!eol) |
{ |
if (n + 100 > nLine) |
{ |
nLine = nLine * 2 + 100; |
zLine.Capacity = (nLine);//= realloc(zLine, nLine); |
//if (zLine == null) |
// return null; |
} |
if (fgets(zIn, nLine - n, In) == 0) |
{ |
if (zLine.Length == 0) |
{ |
zLine = null;//free(zLine); |
return null; |
} |
//zLine[n] = 0; |
eol = true; |
break; |
} |
n = 0; |
while (n < zLine.Length && zLine[n] != '\0') { n++; } |
n = zIn.Length - 1; |
if (zIn[n] == '\n') |
{ |
n--; |
if (n > 0 && zIn[n - 1] == '\r') |
n--; |
|
zIn.Length = n + 1; |
eol = true; |
} |
zLine.Append(zIn); |
} |
//zLine = realloc( zLine, n+1 ); |
return zLine.ToString(); |
} |
|
/* |
** Retrieve a single line of input text. |
** |
** zPrior is a string of prior text retrieved. If not the empty |
** string, then issue a continuation prompt. |
*/ |
static string one_input_line(string zPrior, TextReader In) |
{ |
string zPrompt; |
string zResult; |
if (In != null) |
{ |
return local_getline("", In).ToString(); |
} |
if (zPrior != null && zPrior.Length > 0) |
{ |
zPrompt = continuePrompt; |
} |
else |
{ |
zPrompt = mainPrompt; |
} |
zResult = readline(zPrompt); |
#if (HAVE_READLINE) //&& HAVE_READLINE==1 |
if( zResult && *zResult ) add_history(zResult); |
#endif |
return zResult; |
} |
|
class previous_mode_data |
{ |
public bool valid; /* Is there legit data in here? */ |
public int mode; |
public bool showHeader; |
public int[] colWidth = new int[200]; |
}; |
|
/* |
** An pointer to an instance of this structure is passed from |
** the main program to the callback. This is used to communicate |
** state and mode information. |
*/ |
class callback_data |
{ |
public sqlite3 db; /* The database */ |
public bool echoOn; /* True to echo input commands */ |
public bool statsOn; /* True to display memory stats before each finalize */ |
public int cnt; /* Number of records displayed so far */ |
public FILE Out; /* Write results here */ |
public int mode; /* An output mode setting */ |
public bool writableSchema; /* True if PRAGMA writable_schema=ON */ |
public bool showHeader; /* True to show column names in List or Column mode */ |
public string zDestTable; /* Name of destination table when MODE_Insert */ |
public string separator = ""; /* Separator character for MODE_List */ |
public int[] colWidth = new int[200]; /* Requested width of each column when in column mode*/ |
public int[] actualWidth = new int[200]; /* Actual width of each column */ |
public string nullvalue = "NULL"; /* The text to print when a null comes back from |
** the database */ |
public previous_mode_data explainPrev = new previous_mode_data(); |
/* Holds the mode information just before |
** .explain ON */ |
public StringBuilder outfile = new StringBuilder(260); /* Filename for Out */ |
public string zDbFilename; /* name of the database file */ |
public string zVfs; /* Name of VFS to use */ |
public sqlite3_stmt pStmt; /* Current statement if any. */ |
public FILE pLog; /* Write log output here */ |
|
internal callback_data Copy() |
{ |
return (callback_data)this.MemberwiseClone(); |
} |
}; |
// Store callback data variant |
class callback_data_extra |
{ |
public string[] azCols; //(string *)pData; /* Names of result columns */ |
public string[] azVals;//azCols[nCol]; /* Results */ |
public int[] aiTypes; //(int *)&azVals[nCol]; /* Result types */ |
} |
/* |
** These are the allowed modes. |
*/ |
//#define MODE_Line 0 /* One column per line. Blank line between records */ |
//#define MODE_Column 1 /* One record per line in neat columns */ |
//#define MODE_List 2 /* One record per line with a separator */ |
//#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */ |
//#define MODE_Html 4 /* Generate an XHTML table */ |
//#define MODE_Insert 5 /* Generate SQL "insert" statements */ |
//#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */ |
//#define MODE_Csv 7 /* Quote strings, numbers are plain */ |
//#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */ |
const int MODE_Line = 0; |
const int MODE_Column = 1; |
const int MODE_List = 2; |
const int MODE_Semi = 3; |
const int MODE_Html = 4; |
const int MODE_Insert = 5; |
const int MODE_Tcl = 6; |
const int MODE_Csv = 7; |
const int MODE_Explain = 8; |
|
static string[] modeDescr = new string[] { |
"line", |
"column", |
"list", |
"semi", |
"html", |
"insert", |
"tcl", |
"csv", |
"explain", |
}; |
|
/* |
** Number of elements in an array |
*/ |
//#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) |
static int ArraySize<T>(T[] X) { return X.Length; } |
|
/* |
** Compute a string length that is limited to what can be stored in |
** lower 30 bits of a 32-bit signed integer. |
*/ |
static int strlen30(StringBuilder z) |
{ |
//string z2 = z; |
//while( *z2 ){ z2++; } |
return 0x3fffffff & z.Length;//(int)(z2 - z); |
} |
static int strlen30(string z) |
{ |
//string z2 = z; |
//while( *z2 ){ z2++; } |
return 0x3fffffff & z.Length;//(int)(z2 - z); |
} |
|
|
/* |
** A callback for the Sqlite3.SQLITE_log() interface. |
*/ |
static void shellLog(object pArg, int iErrCode, string zMsg) |
{ |
callback_data p = (callback_data)pArg; |
if (p.pLog == null) |
return; |
fprintf(p.pLog, "(%d) %s\n", iErrCode, zMsg); |
fflush(p.pLog); |
} |
|
/* |
** Output the given string as a hex-encoded blob (eg. X'1234' ) |
*/ |
static void output_hex_blob(FILE Out, byte[] pBlob, int nBlob) |
{ |
int i; |
//string zBlob = (string )pBlob; |
fprintf(Out, "X'"); |
for (i = 0; i < nBlob; i++) { fprintf(Out, "%02x", pBlob[i]); } |
fprintf(Out, "'"); |
} |
|
/* |
** Output the given string as a quoted string using SQL quoting conventions. |
*/ |
static void output_quoted_string(TextWriter Out, string z) |
{ |
int i; |
int nSingle = 0; |
for (i = 0; z[i] != '\0'; i++) |
{ |
if (z[i] == '\'') |
nSingle++; |
} |
if (nSingle == 0) |
{ |
fprintf(Out, "'%s'", z); |
} |
else |
{ |
fprintf(Out, "'"); |
while (z != "") |
{ |
for (i = 0; i < z.Length && z[i] != '\''; i++) |
{ |
} |
if (i == 0) |
{ |
fprintf(Out, "''"); |
//z++; |
} |
else if (z[i] == '\'') |
{ |
fprintf(Out, "%.*s''", i, z); |
//z += i + 1; |
} |
else |
{ |
fprintf(Out, "%s", z); |
break; |
} |
} |
fprintf(Out, "'"); |
} |
} |
|
/* |
** Output the given string as a quoted according to C or TCL quoting rules. |
*/ |
static void output_c_string(TextWriter Out, string z) |
{ |
char c; |
fputc('"', Out); |
int zIdx = 0; |
while (zIdx < z.Length && (c = z[zIdx++]) != '\0') |
{ |
if (c == '\\') |
{ |
fputc(c, Out); |
fputc(c, Out); |
} |
else if (c == '\t') |
{ |
fputc('\\', Out); |
fputc('t', Out); |
} |
else if (c == '\n') |
{ |
fputc('\\', Out); |
fputc('n', Out); |
} |
else if (c == '\r') |
{ |
fputc('\\', Out); |
fputc('r', Out); |
} |
else if (!isprint(c)) |
{ |
fprintf(Out, "\\%03o", c & 0xff); |
} |
else |
{ |
fputc(c, Out); |
} |
} |
fputc('"', Out); |
} |
|
|
/* |
** Output the given string with characters that are special to |
** HTML escaped. |
*/ |
static void output_html_string(TextWriter Out, string z) |
{ |
int i; |
while (z != "") |
{ |
for (i = 0; i < z.Length && z[i] != '<' && z[i] != '&'; i++) |
{ |
} |
if (i > 0) |
{ |
fprintf(Out, "%.*s", i, z); |
} |
if (i < z.Length && z[i] == '<') |
{ |
fprintf(Out, "<"); |
} |
else if (i < z.Length && z[i] == '&') |
{ |
fprintf(Out, "&"); |
} |
else if (i < z.Length && z[i] == '\"') |
{ |
fprintf(Out, """); |
} |
else if (i < z.Length && z[i] == '\'') |
{ |
fprintf(Out, "'"); |
} |
else |
{ |
break; |
} |
z += i + 1; |
} |
} |
|
/* |
** If a field contains any character identified by a 1 in the following |
** array, then the string must be quoted for CSV. |
*/ |
static byte[] needCsvQuote = new byte[] { |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
}; |
|
/* |
** Output a single term of CSV. Actually, p.separator is used for |
** the separator, which may or may not be a comma. p.nullvalue is |
** the null value. Strings are quoted using ANSI-C rules. Numbers |
** appear outside of quotes. |
*/ |
static void output_csv(callback_data p, string z, bool bSep) |
{ |
TextWriter Out = p.Out; |
if (z == null) |
{ |
fprintf(Out, "%s", p.nullvalue); |
} |
else |
{ |
int i; |
int nSep = strlen30(p.separator); |
for (i = 0; i < z.Length; i++) |
{ |
if (needCsvQuote[z[i]] != 0 |
|| (z[i] == p.separator[0] && |
(nSep == 1 || z == p.separator))) |
{ |
i = 0; |
break; |
} |
} |
if (i == 0) |
{ |
putc('"', Out); |
for (i = 0; i < z.Length; i++) |
{ |
if (z[i] == '"') |
putc('"', Out); |
putc(z[i], Out); |
} |
putc('"', Out); |
} |
else |
{ |
fprintf(Out, "%s", z); |
} |
} |
if (bSep) |
{ |
fprintf(p.Out, "%s", p.separator); |
} |
} |
|
|
#if SIGINT |
/* |
** This routine runs when the user presses Ctrl-C |
*/ |
static void interrupt_handler(int NotUsed){ |
UNUSED_PARAMETER(NotUsed); |
seenInterrupt = 1; |
if( db ) Sqlite3.SQLITE_interrupt(db); |
} |
#endif |
|
/* |
** This is the callback routine that the shell |
** invokes for each row of a query result. |
*/ |
static int shell_callback(object pArg, sqlite3_int64 nArg, object p2, object p3) |
{ |
int i; |
callback_data p = (callback_data)pArg; |
|
//Unpack |
string[] azArg = ((callback_data_extra)p2).azVals; |
string[] azCol = ((callback_data_extra)p2).azCols; |
int[] aiType = ((callback_data_extra)p2).aiTypes; |
|
switch (p.mode) |
{ |
case MODE_Line: |
{ |
int w = 5; |
if (azArg == null) |
break; |
for (i = 0; i < nArg; i++) |
{ |
int len = strlen30(azCol[i] != null ? azCol[i] : ""); |
if (len > w) |
w = len; |
} |
if (p.cnt++ > 0) |
fprintf(p.Out, "\n"); |
for (i = 0; i < nArg; i++) |
{ |
fprintf(p.Out, "%*s = %s\n", w, azCol[i], |
azArg[i] != null ? azArg[i] : p.nullvalue); |
} |
break; |
} |
case MODE_Explain: |
case MODE_Column: |
{ |
if (p.cnt++ == 0) |
{ |
for (i = 0; i < nArg; i++) |
{ |
int w, n; |
if (i < ArraySize(p.colWidth)) |
{ |
w = p.colWidth[i]; |
} |
else |
{ |
w = 0; |
} |
if (w <= 0) |
{ |
w = strlen30(azCol[i] != null ? azCol[i] : ""); |
if (w < 10) |
w = 10; |
n = strlen30(azArg != null && azArg[i] != null ? azArg[i] : p.nullvalue); |
if (w < n) |
w = n; |
} |
if (i < ArraySize(p.actualWidth)) |
{ |
p.actualWidth[i] = w; |
} |
if (p.showHeader) |
{ |
fprintf(p.Out, "%-*.*s%s", w, w, azCol[i], i == nArg - 1 ? "\n" : " "); |
} |
} |
if (p.showHeader) |
{ |
for (i = 0; i < nArg; i++) |
{ |
int w; |
if (i < ArraySize(p.actualWidth)) |
{ |
w = p.actualWidth[i]; |
} |
else |
{ |
w = 10; |
} |
fprintf(p.Out, "%-*.*s%s", w, w, "-----------------------------------" + |
"----------------------------------------------------------", |
i == nArg - 1 ? "\n" : " "); |
} |
} |
} |
if (azArg == null) |
break; |
for (i = 0; i < nArg; i++) |
{ |
int w; |
if (i < ArraySize(p.actualWidth)) |
{ |
w = p.actualWidth[i]; |
} |
else |
{ |
w = 10; |
} |
if (p.mode == MODE_Explain && azArg[i] != null && |
strlen30(azArg[i]) > w) |
{ |
w = strlen30(azArg[i]); |
} |
fprintf(p.Out, "%-*.*s%s", w, w, |
azArg[i] != null ? azArg[i] : p.nullvalue, i == nArg - 1 ? "\n" : " "); |
} |
break; |
} |
case MODE_Semi: |
case MODE_List: |
{ |
if (p.cnt++ == null && p.showHeader) |
{ |
for (i = 0; i < nArg; i++) |
{ |
fprintf(p.Out, "%s%s", azCol[i], i == nArg - 1 ? "\n" : p.separator); |
} |
} |
if (azArg == null) |
break; |
for (i = 0; i < nArg; i++) |
{ |
string z = azArg[i]; |
if (z == null) |
z = p.nullvalue; |
fprintf(p.Out, "%s", z); |
if (i < nArg - 1) |
{ |
fprintf(p.Out, "%s", p.separator); |
} |
else if (p.mode == MODE_Semi) |
{ |
fprintf(p.Out, ";\n"); |
} |
else |
{ |
fprintf(p.Out, "\n"); |
} |
} |
break; |
} |
case MODE_Html: |
{ |
if (p.cnt++ == null && p.showHeader) |
{ |
fprintf(p.Out, "<TR>"); |
for (i = 0; i < nArg; i++) |
{ |
fprintf(p.Out, "<TH>"); |
output_html_string(p.Out, azCol[i]); |
fprintf(p.Out, "</TH>\n"); |
} |
fprintf(p.Out, "</TR>\n"); |
} |
if (azArg == null) |
break; |
fprintf(p.Out, "<TR>"); |
for (i = 0; i < nArg; i++) |
{ |
fprintf(p.Out, "<TD>"); |
output_html_string(p.Out, azArg[i] != null ? azArg[i] : p.nullvalue); |
fprintf(p.Out, "</TD>\n"); |
} |
fprintf(p.Out, "</TR>\n"); |
break; |
} |
case MODE_Tcl: |
{ |
if (p.cnt++ == null && p.showHeader) |
{ |
for (i = 0; i < nArg; i++) |
{ |
output_c_string(p.Out, azCol[i] != null ? azCol[i] : ""); |
fprintf(p.Out, "%s", p.separator); |
} |
fprintf(p.Out, "\n"); |
} |
if (azArg == null) |
break; |
for (i = 0; i < nArg; i++) |
{ |
output_c_string(p.Out, azArg[i] != null ? azArg[i] : p.nullvalue); |
fprintf(p.Out, "%s", p.separator); |
} |
fprintf(p.Out, "\n"); |
break; |
} |
case MODE_Csv: |
{ |
if (p.cnt++ == null && p.showHeader) |
{ |
for (i = 0; i < nArg; i++) |
{ |
output_csv(p, azCol[i] != null ? azCol[i] : "", i < nArg - 1); |
} |
fprintf(p.Out, "\n"); |
} |
if (azArg == null) |
break; |
for (i = 0; i < nArg; i++) |
{ |
output_csv(p, azArg[i], i < nArg - 1); |
} |
fprintf(p.Out, "\n"); |
break; |
} |
case MODE_Insert: |
{ |
p.cnt++; |
if (azArg == null) |
break; |
fprintf(p.Out, "INSERT INTO %s VALUES(", p.zDestTable); |
for (i = 0; i < nArg; i++) |
{ |
string zSep = i > 0 ? "," : ""; |
if ((azArg[i] == null) || (aiType != null && i < aiType.Length && aiType[i] == Sqlite3.SQLITE_NULL)) |
{ |
fprintf(p.Out, "%snull", zSep); |
} |
else if (aiType != null && aiType[i] == Sqlite3.SQLITE_TEXT) |
{ |
if (!String.IsNullOrEmpty(zSep)) |
fprintf(p.Out, "%s", zSep); |
output_quoted_string(p.Out, azArg[i]); |
} |
else if (aiType != null && (aiType[i] == Sqlite3.SQLITE_INTEGER || aiType[i] == Sqlite3.SQLITE_FLOAT)) |
{ |
fprintf(p.Out, "%s%s", zSep, azArg[i]); |
} |
else if (aiType != null && aiType[i] == Sqlite3.SQLITE_BLOB && p.pStmt != null) |
{ |
byte[] pBlob = Sqlite3.sqlite3_column_blob(p.pStmt, i); |
int nBlob = Sqlite3.sqlite3_column_bytes(p.pStmt, i); |
if (!String.IsNullOrEmpty(zSep)) |
fprintf(p.Out, "%s", zSep); |
output_hex_blob(p.Out, pBlob, nBlob); |
} |
else if (isNumber(azArg[i], 0)) |
{ |
fprintf(p.Out, "%s%s", zSep, azArg[i]); |
} |
else |
{ |
if (!String.IsNullOrEmpty(zSep)) |
fprintf(p.Out, "%s", zSep); |
output_quoted_string(p.Out, azArg[i]); |
} |
} |
fprintf(p.Out, ");\n"); |
break; |
} |
} |
return 0; |
} |
|
/* |
** This is the callback routine that the SQLite library |
** invokes for each row of a query result. |
*/ |
static int callback(object pArg, sqlite3_int64 nArg, object azArg, object azCol) |
{ |
/* since we don't have type info, call the shell_callback with a null value */ |
callback_data_extra cde = new callback_data_extra(); |
cde.azVals = (string[])azArg; |
cde.azCols = (string[])azCol; |
cde.aiTypes = null; |
return shell_callback(pArg, (int)nArg, cde, null); |
} |
|
/* |
** Set the destination table field of the callback_data structure to |
** the name of the table given. Escape any quote characters in the |
** table name. |
*/ |
static void set_table_name(callback_data p, string zName) |
{ |
int i, n; |
bool needQuote; |
string z = ""; |
|
if (p.zDestTable != null) |
{ |
//free(ref p.zDestTable); |
p.zDestTable = null; |
} |
if (zName == null) |
return; |
needQuote = !isalpha(zName[0]) && zName != "_"; |
for (i = n = 0; i < zName.Length; i++, n++) |
{ |
if (!isalnum(zName[i]) && zName[i] != '_') |
{ |
needQuote = true; |
if (zName[i] == '\'') |
n++; |
} |
} |
if (needQuote) |
n += 2; |
//z = p.zDestTable = malloc( n + 1 ); |
//if ( z == 0 ) |
//{ |
// fprintf( stderr, "Out of memory!\n" ); |
// exit( 1 ); |
//} |
//n = 0; |
if (needQuote) |
z += '\''; |
for (i = 0; i < zName.Length; i++) |
{ |
z += zName[i]; |
if (zName[i] == '\'') |
z += '\''; |
} |
if (needQuote) |
z += '\''; |
//z[n] = 0; |
p.zDestTable = z; |
} |
|
/* zIn is either a pointer to a null-terminated string in memory obtained |
** from malloc(), or a null pointer. The string pointed to by zAppend is |
** added to zIn, and the result returned in memory obtained from malloc(). |
** zIn, if it was not null, is freed. |
** |
** If the third argument, quote, is not '\0', then it is used as a |
** quote character for zAppend. |
*/ |
static void appendText(StringBuilder zIn, string zAppend, int noQuote) |
{ appendText(zIn, zAppend, '\0'); } |
|
static void appendText(StringBuilder zIn, string zAppend, char quote) |
{ |
int len; |
int i; |
int nAppend = strlen30(zAppend); |
int nIn = (zIn != null ? strlen30(zIn) : 0); |
|
len = nAppend + nIn; |
if (quote != '\0') |
{ |
len += 2; |
for (i = 0; i < nAppend; i++) |
{ |
if (zAppend[i] == quote) |
len++; |
} |
} |
|
//zIn = realloc( zIn, len ); |
//if ( !zIn ) |
//{ |
// return 0; |
//} |
|
if (quote != '\0') |
{ |
zIn.Append(quote); |
for (i = 0; i < nAppend; i++) |
{ |
zIn.Append(zAppend[i]); |
if (zAppend[i] == quote) |
zIn.Append(quote); |
} |
zIn.Append(quote); |
//zCsr++ = '\0'; |
Debug.Assert(zIn.Length == len); |
|
} |
else |
{ |
zIn.Append(zAppend);//memcpy( zIn[nIn], zAppend, nAppend ); |
//zIn[len - 1] = '\0'; |
} |
} |
|
|
|
/* |
** Execute a query statement that has a single result column. Print |
** that result column on a line by itself with a semicolon terminator. |
** |
** This is used, for example, to show the schema of the database by |
** querying the Sqlite3.SQLITE_MASTER table. |
*/ |
static int run_table_dump_query( |
FILE Out, /* Send output here */ |
sqlite3 db, /* Database to query */ |
StringBuilder zSelect, /* SELECT statement to extract content */ |
string zFirstRow /* Print before first row, if not null */ |
) |
{ return run_table_dump_query(Out, db, zSelect.ToString(), zFirstRow); } |
|
static int run_table_dump_query( |
FILE Out, /* Send output here */ |
sqlite3 db, /* Database to query */ |
string zSelect, /* SELECT statement to extract content */ |
string zFirstRow /* Print before first row, if not null */ |
) |
{ |
sqlite3_stmt pSelect = null; |
int rc; |
rc = Sqlite3.sqlite3_prepare(db, zSelect, -1, ref pSelect, 0); |
if (rc != Sqlite3.SQLITE_OK || null == pSelect) |
{ |
return rc; |
} |
rc = Sqlite3.sqlite3_step(pSelect); |
while (rc == Sqlite3.SQLITE_ROW) |
{ |
if (zFirstRow != null) |
{ |
fprintf(Out, "%s", zFirstRow); |
zFirstRow = null; |
} |
fprintf(Out, "%s;\n", Sqlite3.sqlite3_column_text(pSelect, 0)); |
rc = Sqlite3.sqlite3_step(pSelect); |
} |
return Sqlite3.sqlite3_finalize(pSelect); |
} |
|
/* |
** Allocate space and save off current error string. |
*/ |
static string save_err_msg( |
sqlite3 db /* Database to query */ |
) |
{ |
//int nErrMsg = 1 + strlen30(Sqlite3.sqlite3_errmsg(db)); |
//string zErrMsg = Sqlite3.sqlite3_malloc(nErrMsg); |
//if (zErrMsg != null) |
//{ |
// memcpy(zErrMsg, Sqlite3.sqlite3_errmsg(db), nErrMsg); |
//} |
return Sqlite3.sqlite3_errmsg(db); //zErrMsg; |
} |
|
/* |
** Display memory stats. |
*/ |
static int display_stats( |
sqlite3 db, /* Database to query */ |
callback_data pArg, /* Pointer to struct callback_data */ |
int bReset /* True to reset the stats */ |
) |
{ |
int iCur; |
int iHiwtr; |
|
if (pArg != null && pArg.Out != null) |
{ |
|
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_MEMORY_USED, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr); |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_MALLOC_COUNT, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr); |
/* |
** Not currently used by the CLI. |
** iHiwtr = iCur = -1; |
** Sqlite3.SQLITE_status(Sqlite3.SQLITE_STATUS_PAGECACHE_USED,ref iCur,ref iHiwtr, bReset); |
** fprintf(pArg.Out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); |
*/ |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_PAGECACHE_OVERFLOW, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); |
/* |
** Not currently used by the CLI. |
** iHiwtr = iCur = -1; |
** Sqlite3.SQLITE_status(Sqlite3.SQLITE_STATUS_SCRATCH_USED,ref iCur,ref iHiwtr, bReset); |
** fprintf(pArg.Out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); |
*/ |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_SCRATCH_OVERFLOW, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_MALLOC_SIZE, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Largest Allocation: %d bytes\n", iHiwtr); |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_PAGECACHE_SIZE, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Largest Pcache Allocation: %d bytes\n", iHiwtr); |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_status(Sqlite3.SQLITE_STATUS_SCRATCH_SIZE, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Largest Scratch Allocation: %d bytes\n", iHiwtr); |
#if YYTRACKMAXSTACKDEPTH |
iHiwtr = iCur = -1; |
Sqlite3.SQLITE_status(Sqlite3.SQLITE_STATUS_PARSER_STACK,ref iCur,ref iHiwtr, bReset); |
fprintf(pArg.Out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr); |
#endif |
} |
|
if (pArg != null && pArg.Out != null && db != null) |
{ |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_LOOKASIDE_USED, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); |
Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_LOOKASIDE_HIT, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Successful lookaside attempts: %d\n", iHiwtr); |
Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Lookaside failures due to size: %d\n", iHiwtr); |
Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Lookaside failures due to OOM: %d\n", iHiwtr); |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_CACHE_USED, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Pager Heap Usage: %d bytes\n", iCur); |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_SCHEMA_USED, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Schema Heap Usage: %d bytes\n", iCur); |
iHiwtr = iCur = -1; |
Sqlite3.sqlite3_db_status(db, Sqlite3.SQLITE_DBSTATUS_STMT_USED, ref iCur, ref iHiwtr, bReset); |
fprintf(pArg.Out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); |
} |
|
if (pArg != null && pArg.Out != null && db != null && pArg.pStmt != null) |
{ |
iCur = Sqlite3.sqlite3_stmt_status(pArg.pStmt, Sqlite3.SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); |
fprintf(pArg.Out, "Fullscan Steps: %d\n", iCur); |
iCur = Sqlite3.sqlite3_stmt_status(pArg.pStmt, Sqlite3.SQLITE_STMTSTATUS_SORT, bReset); |
fprintf(pArg.Out, "Sort Operations: %d\n", iCur); |
iCur = Sqlite3.sqlite3_stmt_status(pArg.pStmt, Sqlite3.SQLITE_STMTSTATUS_AUTOINDEX, bReset); |
fprintf(pArg.Out, "Autoindex Inserts: %d\n", iCur); |
} |
|
return 0; |
} |
|
/* |
** Execute a statement or set of statements. Print |
** any result rows/columns depending on the current mode |
** set via the supplied callback. |
** |
** This is very similar to SQLite's built-in Sqlite3.sqlite3_exec() |
** function except it takes a slightly different callback |
** and callback data argument. |
*/ |
static int shell_exec( |
sqlite3 db, /* An open database */ |
string zSql, /* SQL to be evaluated */ |
dxCallback xCallback, //int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */ |
/* (not the same as Sqlite3.sqlite3_exec) */ |
callback_data pArg, /* Pointer to struct callback_data */ |
ref string pzErrMsg /* Error msg written here */ |
) |
{ |
sqlite3_stmt pStmt = null; /* Statement to execute. */ |
int rc = Sqlite3.SQLITE_OK; /* Return Code */ |
string zLeftover = null; /* Tail of unprocessed SQL */ |
|
// if( pzErrMsg ) |
{ |
pzErrMsg = null; |
} |
|
while (!String.IsNullOrEmpty(zSql) && (Sqlite3.SQLITE_OK == rc)) |
{ |
rc = Sqlite3.sqlite3_prepare_v2(db, zSql, -1, ref pStmt, ref zLeftover); |
if (Sqlite3.SQLITE_OK != rc) |
{ |
//if (pzErrMsg != null) |
{ |
pzErrMsg = save_err_msg(db); |
} |
} |
else |
{ |
if (null == pStmt) |
{ |
/* this happens for a comment or white-space */ |
zSql = zLeftover.TrimStart(); |
//while (isspace(zSql[0])) |
// zSql++; |
continue; |
} |
|
/* save off the prepared statment handle and reset row count */ |
if (pArg != null) |
{ |
pArg.pStmt = pStmt; |
pArg.cnt = 0; |
} |
|
/* echo the sql statement if echo on */ |
if (pArg != null && pArg.echoOn) |
{ |
string zStmtSql = Sqlite3.sqlite3_sql(pStmt); |
fprintf(pArg.Out, "%s\n", zStmtSql != null ? zStmtSql : zSql); |
} |
|
/* perform the first step. this will tell us if we |
** have a result set or not and how wide it is. |
*/ |
rc = Sqlite3.sqlite3_step(pStmt); |
/* if we have a result set... */ |
if (Sqlite3.SQLITE_ROW == rc) |
{ |
/* if we have a callback... */ |
if (xCallback != null) |
{ |
/* allocate space for col name ptr, value ptr, and type */ |
int nCol = Sqlite3.sqlite3_column_count(pStmt); |
//void pData = Sqlite3.SQLITE_malloc(3*nCol*sizeof(const char*) + 1); |
//if( !pData ){ |
// rc = Sqlite3.SQLITE_NOMEM; |
//}else |
{ |
string[] azCols = new string[nCol];//(string *)pData; /* Names of result columns */ |
string[] azVals = new string[nCol];//azCols[nCol]; /* Results */ |
int[] aiTypes = new int[nCol];//(int *)&azVals[nCol]; /* Result types */ |
int i; |
//Debug.Assert(sizeof(int) <= sizeof(string )); |
/* save off ptrs to column names */ |
for (i = 0; i < nCol; i++) |
{ |
azCols[i] = (string)Sqlite3.sqlite3_column_name(pStmt, i); |
} |
do |
{ |
/* extract the data and data types */ |
for (i = 0; i < nCol; i++) |
{ |
azVals[i] = (string)Sqlite3.sqlite3_column_text(pStmt, i); |
aiTypes[i] = Sqlite3.sqlite3_column_type(pStmt, i); |
if (null == azVals[i] && (aiTypes[i] != Sqlite3.SQLITE_NULL)) |
{ |
rc = Sqlite3.SQLITE_NOMEM; |
break; /* from for */ |
} |
} /* end for */ |
|
/* if data and types extracted successfully... */ |
if (Sqlite3.SQLITE_ROW == rc) |
{ |
/* call the supplied callback with the result row data */ |
callback_data_extra cde = new callback_data_extra(); |
cde.azVals = azVals; |
cde.azCols = azCols; |
cde.aiTypes = aiTypes; |
|
if (xCallback(pArg, nCol, cde, null) != 0) |
{ |
rc = Sqlite3.SQLITE_ABORT; |
} |
else |
{ |
rc = Sqlite3.sqlite3_step(pStmt); |
} |
} |
} while (Sqlite3.SQLITE_ROW == rc); |
//Sqlite3.sqlite3_free(ref pData); |
} |
} |
else |
{ |
do |
{ |
rc = Sqlite3.sqlite3_step(pStmt); |
} while (rc == Sqlite3.SQLITE_ROW); |
} |
} |
|
/* print usage stats if stats on */ |
if (pArg != null && pArg.statsOn) |
{ |
display_stats(db, pArg, 0); |
} |
|
/* Finalize the statement just executed. If this fails, save a |
** copy of the error message. Otherwise, set zSql to point to the |
** next statement to execute. */ |
rc = Sqlite3.sqlite3_finalize(pStmt); |
if (rc == Sqlite3.SQLITE_OK) |
{ |
zSql = zLeftover.TrimStart(); |
//while (isspace(zSql[0])) |
// zSql++; |
} |
else //if (pzErrMsg) |
{ |
pzErrMsg = save_err_msg(db); |
} |
|
/* clear saved stmt handle */ |
if (pArg != null) |
{ |
pArg.pStmt = null; |
} |
} |
} /* end while */ |
|
return rc; |
} |
|
|
/* |
** This is a different callback routine used for dumping the database. |
** Each row received by this callback consists of a table name, |
** the table type ("index" or "table") and SQL to create the table. |
** This routine should print text sufficient to recreate the table. |
*/ |
static int dump_callback(object pArg, sqlite3_int64 nArg, object pazArg, object pazCol) |
{ |
int rc; |
string zTable; |
string zType; |
string zSql; |
string zPrepStmt = null; |
callback_data p = (callback_data)pArg; |
string[] azArg = (string[])pazArg; |
string[] azCol = (string[])pazCol; |
|
UNUSED_PARAMETER(azCol); |
if (nArg != 3) |
return 1; |
zTable = azArg[0]; |
zType = azArg[1]; |
zSql = azArg[2]; |
|
if (zTable.Equals("sqlite_sequence", StringComparison.InvariantCultureIgnoreCase)) |
{ |
zPrepStmt = "DELETE FROM sqlite_sequence;\n"; |
} |
else if (zTable.Equals("sqlite_stat1", StringComparison.InvariantCultureIgnoreCase)) |
{ |
fprintf(p.Out, "ANALYZE Sqlite3.SQLITE_master;\n"); |
} |
else if (zTable.StartsWith("SQLITE_", StringComparison.InvariantCultureIgnoreCase)) |
{ |
return 0; |
} |
else if (zSql.StartsWith("CREATE VIRTUAL TABLE", StringComparison.InvariantCultureIgnoreCase)) |
{ |
string zIns; |
if (!p.writableSchema) |
{ |
fprintf(p.Out, "PRAGMA writable_schema=ON;\n"); |
p.writableSchema = true; |
} |
zIns = Sqlite3.sqlite3_mprintf( |
"INSERT INTO Sqlite3.SQLITE_master(type,name,tbl_name,rootpage,sql)" + |
"VALUES('table','%q','%q',0,'%q');", |
zTable, zTable, zSql); |
fprintf(p.Out, "%s\n", zIns); |
zIns = null;//Sqlite3.sqlite3_free(zIns); |
return 0; |
} |
else |
{ |
fprintf(p.Out, "%s;\n", zSql); |
} |
|
if (zType.Equals("table", StringComparison.InvariantCultureIgnoreCase)) |
{ |
sqlite3_stmt pTableInfo = null; |
StringBuilder zSelect = new StringBuilder(); |
StringBuilder zTableInfo = new StringBuilder(); |
StringBuilder zTmp = new StringBuilder(); |
int nRow = 0; |
|
appendText(zTableInfo, "PRAGMA table_info(", 0); |
appendText(zTableInfo, zTable, '"'); |
appendText(zTableInfo, ");", 0); |
|
rc = Sqlite3.sqlite3_prepare(p.db, zTableInfo, -1, ref pTableInfo, 0); |
zTableInfo = null;//free(zTableInfo); |
if (rc != Sqlite3.SQLITE_OK || null == pTableInfo) |
{ |
return 1; |
} |
|
appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0); |
appendText(zTmp, zTable, '"'); |
//if (zTmp!=null) |
{ |
appendText(zSelect, zTmp.ToString(), '\''); |
} |
appendText(zSelect, " || ' VALUES(' || ", 0); |
rc = Sqlite3.sqlite3_step(pTableInfo); |
while (rc == Sqlite3.SQLITE_ROW) |
{ |
string zText = (string)Sqlite3.sqlite3_column_text(pTableInfo, 1); |
appendText(zSelect, "quote(", 0); |
appendText(zSelect, zText, '"'); |
rc = Sqlite3.sqlite3_step(pTableInfo); |
if (rc == Sqlite3.SQLITE_ROW) |
{ |
appendText(zSelect, ") || ',' || ", 0); |
} |
else |
{ |
appendText(zSelect, ") ", 0); |
} |
nRow++; |
} |
rc = Sqlite3.sqlite3_finalize(pTableInfo); |
if (rc != Sqlite3.SQLITE_OK || nRow == 0) |
{ |
zSelect = null;//free(zSelect); |
return 1; |
} |
appendText(zSelect, "|| ')' FROM ", 0); |
appendText(zSelect, zTable, '"'); |
|
rc = run_table_dump_query(p.Out, p.db, zSelect, zPrepStmt); |
if (rc == Sqlite3.SQLITE_CORRUPT) |
{ |
appendText(zSelect, " ORDER BY rowid DESC", 0); |
rc = run_table_dump_query(p.Out, p.db, zSelect, ""); |
} |
if (zSelect != null) |
zSelect = null;//free(zSelect); |
} |
return 0; |
} |
|
/* |
** Run zQuery. Use dump_callback() as the callback routine so that |
** the contents of the query are output as SQL statements. |
** |
** If we get a Sqlite3.SQLITE_CORRUPT error, rerun the query after appending |
** "ORDER BY rowid DESC" to the end. |
*/ |
static int run_schema_dump_query( |
callback_data p, |
string zQuery, |
string pzErrMsg |
) |
{ |
int rc; |
rc = Sqlite3.sqlite3_exec(p.db, zQuery, dump_callback, p, ref pzErrMsg); |
if (rc == Sqlite3.SQLITE_CORRUPT) |
{ |
StringBuilder zQ2; |
int len = strlen30(zQuery); |
if (pzErrMsg != null) |
pzErrMsg = null;//Sqlite3.sqlite3_free(pzErrMsg); |
zQ2 = new StringBuilder(len + 100);//zQ2 = malloc(len + 100); |
//if (zQ2 == null) |
// return rc; |
Sqlite3.sqlite3_snprintf(zQ2.Capacity, zQ2, "%s ORDER BY rowid DESC", zQuery); |
rc = Sqlite3.sqlite3_exec(p.db, zQ2.ToString(), dump_callback, p, ref pzErrMsg); |
zQ2 = null;//free(zQ2); |
} |
return rc; |
} |
|
/* |
** Text of a help message |
*/ |
static string zHelp = |
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" + |
".bail ON|OFF Stop after hitting an error. Default OFF\n" + |
".databases List names and files of attached databases\n" + |
".dump ?TABLE? ... Dump the database in an SQL text format\n" + |
" If TABLE specified, only dump tables matching\n" + |
" LIKE pattern TABLE.\n" + |
".echo ON|OFF Turn command echo on or off\n" + |
".exit Exit this program\n" + |
".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" + |
" With no args, it turns EXPLAIN on.\n" + |
".header(s) ON|OFF Turn display of headers on or off\n" + |
".help Show this message\n" + |
".import FILE TABLE Import data from FILE into TABLE\n" + |
".indices ?TABLE? Show names of all indices\n" + |
" If TABLE specified, only show indices for tables\n" + |
" matching LIKE pattern TABLE.\n" + |
#if SQLITE_ENABLE_IOTRACE |
".iotrace FILE Enable I/O diagnostic logging to FILE\n" + |
#endif |
#if !SQLITE_OMIT_LOAD_EXTENSION |
".load FILE ?ENTRY? Load an extension library\n" + |
#endif |
".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n" + |
".mode MODE ?TABLE? Set output mode where MODE is one of:\n" + |
" csv Comma-separated values\n" + |
" column Left-aligned columns. (See .width)\n" + |
" html HTML <table> code\n" + |
" insert SQL insert statements for TABLE\n" + |
" line One value per line\n" + |
" list Values delimited by .separator string\n" + |
" tabs Tab-separated values\n" + |
" tcl TCL list elements\n" + |
".nullvalue STRING Print STRING in place of null values\n" + |
".output FILENAME Send output to FILENAME\n" + |
".output stdout Send output to the screen\n" + |
".prompt MAIN CONTINUE Replace the standard prompts\n" + |
".quit Exit this program\n" + |
".read FILENAME Execute SQL in FILENAME\n" + |
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" + |
".schema ?TABLE? Show the CREATE statements\n" + |
" If TABLE specified, only show tables matching\n" + |
" LIKE pattern TABLE.\n" + |
".separator STRING Change separator used by output mode and .import\n" + |
".show Show the current values for various settings\n" + |
".stats ON|OFF Turn stats on or off\n" + |
".tables ?TABLE? List names of tables\n" + |
" If TABLE specified, only list tables matching\n" + |
" LIKE pattern TABLE.\n" + |
".timeout MS Try opening locked tables for MS milliseconds\n" + |
".width NUM1 NUM2 ... Set column widths for \"column\" mode\n" |
; |
|
static string zTimerHelp = |
".timer ON|OFF Turn the CPU timer measurement on or off\n" |
; |
|
/* Forward reference */ |
//static int process_input(callback_data p, FILE In); |
|
/* |
** Make sure the database is open. If it is not, then open it. If |
** the database fails to open, print an error message and exit. |
*/ |
static void open_db(callback_data p) |
{ |
if (p.db == null) |
{ |
Sqlite3.sqlite3_open(p.zDbFilename, out p.db); |
db = p.db; |
if (db != null && Sqlite3.sqlite3_errcode(db) == Sqlite3.SQLITE_OK) |
{ |
Sqlite3.sqlite3_create_function(db, "shellstatic", 0, Sqlite3.SQLITE_UTF8, 0, |
shellstaticFunc, null, null); |
} |
if (db == null || Sqlite3.SQLITE_OK != Sqlite3.sqlite3_errcode(db)) |
{ |
fprintf(stderr, "Error: unable to open database \"%s\": %s\n", |
p.zDbFilename, Sqlite3.sqlite3_errmsg(db)); |
exit(1); |
} |
#if !SQLITE_OMIT_LOAD_EXTENSION |
Sqlite3.sqlite3_enable_load_extension(p.db, 1); |
#endif |
} |
} |
|
/* |
** Do C-language style dequoting. |
** |
** \t . tab |
** \n . newline |
** \r . carriage return |
** \NNN . ascii character NNN in octal |
** \\ . backslash |
*/ |
static void resolve_backslashes(ref string z) |
{ |
StringBuilder sb = new StringBuilder(z); |
resolve_backslashes(sb); |
z = sb.ToString(); |
} |
static void resolve_backslashes(StringBuilder z) |
{ |
int i, j; |
char c; |
for (i = j = 0; i < z.Length && (c = z[i]) != 0; i++, j++) |
{ |
if (c == '\\') |
{ |
c = z[++i]; |
if (c == 'n') |
{ |
c = '\n'; |
} |
else if (c == 't') |
{ |
c = '\t'; |
} |
else if (c == 'r') |
{ |
c = '\r'; |
} |
else if (c >= '0' && c <= '7') |
{ |
c -= '0'; |
if (z[i + 1] >= '0' && z[i + 1] <= '7') |
{ |
i++; |
c = (char)((c << 3) + z[i] - '0'); |
if (z[i + 1] >= '0' && z[i + 1] <= '7') |
{ |
i++; |
c = (char)((c << 3) + z[i] - '0'); |
} |
} |
} |
} |
z[j] = c; |
} |
z.Length = j;//z[j] = '\0'; |
} |
|
|
/* |
** Interpret zArg as a boolean value. Return either 0 or 1. |
*/ |
static bool booleanValue(StringBuilder zArg) |
{ |
return booleanValue(zArg.ToString()); |
} |
|
static bool booleanValue(string zArg) |
{ |
if (String.IsNullOrEmpty(zArg)) |
return false; |
int val = Char.IsDigit(zArg[0]) ? Convert.ToInt32(zArg) : 0;// atoi( zArg ); |
int j; |
//for (j = 0; zArg[j]; j++) |
//{ |
// zArg[j] = (char)tolower(zArg[j]); |
//} |
if (zArg.Equals("on", StringComparison.InvariantCultureIgnoreCase)) |
{ |
val = 1; |
} |
else if (zArg.Equals("yes", StringComparison.InvariantCultureIgnoreCase)) |
{ |
val = 1; |
} |
return val != 0; |
} |
|
class _aCtrl |
{ |
public string zCtrlName; /* Name of a test-control option */ |
public int ctrlCode; /* Integer code for that option */ |
|
public _aCtrl(string zCtrlName, int ctrlCode) |
{ |
this.zCtrlName = zCtrlName; |
this.ctrlCode = ctrlCode; |
} |
} |
|
/* |
** If an input line begins with "." then invoke this routine to |
** process that line. |
** |
** Return 1 on error, 2 to exit, and 0 otherwise. |
*/ |
static int do_meta_command(StringBuilder zLine, callback_data p) |
{ |
int i = 1; |
int i0 = 0; |
int nArg = 0; |
int n, c; |
int rc = 0; |
string[] azArg = new string[50]; |
|
/* Parse the input line into tokens. |
*/ |
while (i < zLine.Length && nArg < ArraySize(azArg)) |
{ |
while (i < zLine.Length && Char.IsWhiteSpace(zLine[i])) { i++; } |
if (i == zLine.Length) |
break; |
if (zLine[i] == '\'' || zLine[i] == '"') |
{ |
int delim = zLine[i++]; |
i0 = i; |
azArg[nArg++] = zLine[i].ToString(); |
while (zLine[i] != '\0' && zLine[i] != delim) { i++; } |
if (zLine[i] == delim) |
{ |
zLine[i++] = '\0'; |
} |
if (delim == '"') |
resolve_backslashes(ref azArg[nArg - 1]); |
} |
else |
{ |
i0 = i; |
while (i < zLine.Length && !isspace(zLine[i])) { i++; } |
azArg[nArg++] = zLine.ToString().Substring(i0, i - i0); |
//if (i < zLine.Length - 1) |
// zLine[i++] = '\0'; |
resolve_backslashes(ref azArg[nArg - 1]); |
} |
} |
|
/* Process the input line. |
*/ |
if (nArg == 0) |
return 0; /* no tokens, no error */ |
n = strlen30(azArg[0]); |
c = azArg[0][0]; |
if (c == 'b' && n >= 3 && azArg[0].StartsWith("backup", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 4) |
{ |
string zDestFile; |
string zDb; |
sqlite3 pDest; |
Sqlite3.sqlite3_backup pBackup; |
if (nArg == 2) |
{ |
zDestFile = azArg[1]; |
zDb = "main"; |
} |
else |
{ |
zDestFile = azArg[2]; |
zDb = azArg[1]; |
} |
rc = Sqlite3.sqlite3_open(zDestFile, out pDest); |
if (rc != Sqlite3.SQLITE_OK) |
{ |
fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile); |
Sqlite3.sqlite3_close(pDest); |
return 1; |
} |
open_db(p); |
pBackup = Sqlite3.sqlite3_backup_init(pDest, "main", p.db, zDb); |
if (pBackup == null) |
{ |
fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(pDest)); |
Sqlite3.sqlite3_close(pDest); |
return 1; |
} |
while ((rc = Sqlite3.sqlite3_backup_step(pBackup, 100)) == Sqlite3.SQLITE_OK) { } |
Sqlite3.sqlite3_backup_finish(pBackup); |
if (rc == Sqlite3.SQLITE_DONE) |
{ |
rc = 0; |
} |
else |
{ |
fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(pDest)); |
rc = 1; |
} |
Sqlite3.sqlite3_close(pDest); |
} |
else |
|
if (c == 'b' && n >= 3 && azArg[0].StartsWith("bail", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 3) |
{ |
bail_on_error = booleanValue(azArg[1]); |
} |
else |
|
if (c == 'd' && n > 1 && azArg[0].StartsWith("databases", StringComparison.InvariantCultureIgnoreCase) && nArg == 1) |
{ |
callback_data data; |
string zErrMsg = null; |
open_db(p); |
data = p.Copy();// memcpy(data, p, sizeof(data)); |
data.showHeader = true; |
data.mode = MODE_Column; |
data.colWidth[0] = 3; |
data.colWidth[1] = 15; |
data.colWidth[2] = 58; |
data.cnt = 0; |
Sqlite3.sqlite3_exec(p.db, "PRAGMA database_list; ", callback, data, ref zErrMsg); |
if (!String.IsNullOrEmpty(zErrMsg)) |
{ |
fprintf(stderr, "Error: %s\n", zErrMsg); |
zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg); |
rc = 1; |
} |
} |
else |
|
if (c == 'd' && azArg[0].StartsWith("dump", StringComparison.InvariantCultureIgnoreCase) && nArg < 3) |
{ |
string zErrMsg = null; |
open_db(p); |
/* When playing back a "dump", the content might appear in an order |
** which causes immediate foreign key constraints to be violated. |
** So disable foreign-key constraint enforcement to prevent problems. */ |
fprintf(p.Out, "PRAGMA foreign_keys=OFF;\n"); |
fprintf(p.Out, "BEGIN TRANSACTION;\n"); |
p.writableSchema = false; |
Sqlite3.sqlite3_exec(p.db, "PRAGMA writable_schema=ON", 0, 0, 0); |
if (nArg == 1) |
{ |
run_schema_dump_query(p, |
"SELECT name, type, sql FROM sqlite_master " + |
"WHERE sql NOT null AND type=='table' AND name!='Sqlite3.SQLITE_sequence'", null |
); |
run_schema_dump_query(p, |
"SELECT name, type, sql FROM sqlite_master " + |
"WHERE name=='Sqlite3.SQLITE_sequence'", null |
); |
run_table_dump_query(p.Out, p.db, |
"SELECT sql FROM sqlite_master " + |
"WHERE sql NOT null AND type IN ('index','trigger','view')", null |
); |
} |
else |
{ |
int ii; |
for (ii = 1; ii < nArg; ii++) |
{ |
zShellStatic = azArg[ii]; |
run_schema_dump_query(p, |
"SELECT name, type, sql FROM sqlite_master " + |
"WHERE tbl_name LIKE shellstatic() AND type=='table'" + |
" AND sql NOT null", null); |
run_table_dump_query(p.Out, p.db, |
"SELECT sql FROM sqlite_master " + |
"WHERE sql NOT null" + |
" AND type IN ('index','trigger','view')" + |
" AND tbl_name LIKE shellstatic()", null |
); |
zShellStatic = null; |
} |
} |
if (p.writableSchema) |
{ |
fprintf(p.Out, "PRAGMA writable_schema=OFF;\n"); |
p.writableSchema = false; |
} |
Sqlite3.sqlite3_exec(p.db, "PRAGMA writable_schema=OFF", 0, 0, 0); |
if (!String.IsNullOrEmpty(zErrMsg)) |
{ |
fprintf(stderr, "Error: %s\n", zErrMsg); |
zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg); |
} |
else |
{ |
fprintf(p.Out, "COMMIT;\n"); |
} |
} |
else |
|
if (c == 'e' && azArg[0].StartsWith("echo", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 3) |
{ |
p.echoOn = booleanValue(azArg[1]); |
} |
else |
|
if (c == 'e' && azArg[0].StartsWith("exit", StringComparison.InvariantCultureIgnoreCase) && nArg == 1) |
{ |
rc = 2; |
} |
else |
|
if (c == 'e' && azArg[0].StartsWith("explain", StringComparison.InvariantCultureIgnoreCase) && nArg < 3) |
{ |
int val = nArg >= 2 ? booleanValue(azArg[1]) ? 1 : 0 : 1; |
if (val == 1) |
{ |
if (!p.explainPrev.valid) |
{ |
p.explainPrev.valid = true; |
p.explainPrev.mode = p.mode; |
p.explainPrev.showHeader = p.showHeader; |
p.explainPrev.colWidth = new int[p.colWidth.Length]; |
Array.Copy(p.colWidth, p.explainPrev.colWidth, p.colWidth.Length);//memcpy( p.explainPrev.colWidth, p.colWidth, sizeof( p.colWidth ) ); |
} |
/* We could put this code under the !p.explainValid |
** condition so that it does not execute if we are already in |
** explain mode. However, always executing it allows us an easy |
** was to reset to explain mode in case the user previously |
** did an .explain followed by a .width, .mode or .header |
** command. |
*/ |
p.mode = MODE_Explain; |
p.showHeader = true; |
Array.Clear(p.colWidth, 0, p.colWidth.Length);//memset(p.colWidth, 0, ArraySize(p.colWidth)); |
p.colWidth[0] = 4; /* addr */ |
p.colWidth[1] = 13; /* opcode */ |
p.colWidth[2] = 4; /* P1 */ |
p.colWidth[3] = 4; /* P2 */ |
p.colWidth[4] = 4; /* P3 */ |
p.colWidth[5] = 13; /* P4 */ |
p.colWidth[6] = 2; /* P5 */ |
p.colWidth[7] = 13; /* Comment */ |
} |
else if (p.explainPrev.valid) |
{ |
p.explainPrev.valid = false; |
p.mode = p.explainPrev.mode; |
p.showHeader = p.explainPrev.showHeader; |
Array.Copy(p.colWidth, p.explainPrev.colWidth, p.colWidth.Length);//memcpy(p.colWidth, p.explainPrev.colWidth, sizeof(p.colWidth)); |
} |
} |
else |
|
if (c == 'h' && (azArg[0].StartsWith("header", StringComparison.InvariantCultureIgnoreCase) || |
azArg[0].StartsWith("headers", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 3)) |
{ |
p.showHeader = booleanValue(azArg[1]); |
} |
else |
|
if (c == 'h' && azArg[0].StartsWith("help", StringComparison.InvariantCultureIgnoreCase)) |
{ |
fprintf(stderr, "%s", zHelp); |
if (HAS_TIMER) |
{ |
fprintf(stderr, "%s", zTimerHelp); |
} |
} |
else |
|
if (c == 'i' && azArg[0].StartsWith("import", StringComparison.InvariantCultureIgnoreCase) && nArg == 3) |
{ |
string zTable = azArg[2]; /* Insert data into this table */ |
string zFile = azArg[1]; /* The file from which to extract data */ |
sqlite3_stmt pStmt = null; /* A statement */ |
int nCol; /* Number of columns in the table */ |
int nByte; /* Number of bytes in an SQL string */ |
int ii, j; /* Loop counters */ |
int nSep; /* Number of bytes in p.separator[] */ |
StringBuilder zSql; /* An SQL statement */ |
//string zLine; /* A single line of input from the file */ |
string[] azCol; /* zLine[] broken up into columns */ |
string zCommit; /* How to commit changes */ |
TextReader In; /* The input file */ |
int lineno = 0; /* Line number of input file */ |
|
open_db(p); |
nSep = strlen30(p.separator); |
if (nSep == 0) |
{ |
fprintf(stderr, "Error: non-null separator required for import\n"); |
return 1; |
} |
zSql = new StringBuilder(Sqlite3.sqlite3_mprintf("SELECT * FROM '%q'", zTable)); |
//if (zSql == null) |
//{ |
// fprintf(stderr, "Error: out of memory\n"); |
// return 1; |
//} |
nByte = strlen30(zSql); |
rc = Sqlite3.sqlite3_prepare(p.db, zSql, -1, ref pStmt, 0); |
zSql = null;//Sqlite3.sqlite3_free(zSql); |
if (rc != 0) |
{ |
if (pStmt != null) |
Sqlite3.sqlite3_finalize(pStmt); |
fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(db)); |
return 1; |
} |
nCol = Sqlite3.sqlite3_column_count(pStmt); |
Sqlite3.sqlite3_finalize(pStmt); |
pStmt = null; |
if (nCol == 0) |
return 0; /* no columns, no error */ |
zSql = new StringBuilder(nByte + 20 + nCol * 2); |
//if (zSql == null) |
//{ |
// fprintf(stderr, "Error: out of memory\n"); |
// return 1; |
//} |
Sqlite3.sqlite3_snprintf(nByte + 20, zSql, "INSERT INTO '%q' VALUES(?", zTable); |
j = strlen30(zSql); |
for (ii = 1; ii < nCol; ii++) |
{ |
zSql[j++] = ','; |
zSql[j++] = '?'; |
} |
zSql[j++] = ')'; |
zSql[j] = '\0'; |
rc = Sqlite3.sqlite3_prepare(p.db, zSql, -1, ref pStmt, 0); |
zSql = null;//free(zSql); |
if (rc != 0) |
{ |
fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(db)); |
if (pStmt != null) |
Sqlite3.sqlite3_finalize(pStmt); |
return 1; |
} |
In = new StreamReader(zFile);// fopen(zFile, "rb"); |
if (In == null) |
{ |
fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); |
Sqlite3.sqlite3_finalize(pStmt); |
return 1; |
} |
azCol = new string[nCol + 1];//malloc( sizeof(azCol[0])*(nCol+1) ); |
//if( azCol== null ){ |
//fprintf(stderr, "Error: out of memory\n"); |
//fclose(In ); |
//Sqlite3.sqlite3_finalize(pStmt!=null); |
//return 1; |
//} |
Sqlite3.sqlite3_exec(p.db, "BEGIN", 0, 0, 0); |
zCommit = "COMMIT"; |
while ((zLine.Append(local_getline(null, In).ToString())).Length != 0) |
{ |
string z; |
//i = 0; |
lineno++; |
azCol = zLine.ToString().Split(p.separator.ToCharArray()); |
//azCol[0] = zLine; |
//for (i = 0, z = zLine; *z && *z != '\n' && *z != '\r'; z++) |
//{ |
// if (*z == p.separator[0] && z.StartsWith(p.separator)) |
// { |
// *z = 0; |
// i++; |
// if (i < nCol) |
// { |
// azCol[i] = z[nSep]; |
// z += nSep - 1; |
// } |
// } |
//} /* end for */ |
//*z = 0; |
if (azCol.Length != nCol) |
{ |
fprintf(stderr, |
"Error: %s line %d: expected %d columns of data but found %d\n", |
zFile, lineno, nCol, azCol.Length); |
zCommit = "ROLLBACK"; |
zLine = null;//free(zLine); |
rc = 1; |
break; /* from while */ |
} |
for (ii = 0; ii < nCol; ii++) |
{ |
Sqlite3.sqlite3_bind_text(pStmt, ii + 1, azCol[ii], -1, Sqlite3.SQLITE_STATIC); |
} |
Sqlite3.sqlite3_step(pStmt); |
rc = Sqlite3.sqlite3_reset(pStmt); |
zLine = null;//free(zLine); |
if (rc != Sqlite3.SQLITE_OK) |
{ |
fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(db)); |
zCommit = "ROLLBACK"; |
rc = 1; |
break; /* from while */ |
} |
} /* end while */ |
azCol = null;//free(azCol); |
In.Close();//fclose(in); |
Sqlite3.sqlite3_finalize(pStmt); |
Sqlite3.sqlite3_exec(p.db, zCommit, 0, 0, 0); |
} |
else |
|
if (c == 'i' && azArg[0].StartsWith("indices", StringComparison.InvariantCultureIgnoreCase) && nArg < 3) |
{ |
callback_data data; |
string zErrMsg = null; |
open_db(p); |
data = p.Copy();// memcpy(data, p, sizeof(data)); |
data.showHeader = false; |
data.mode = MODE_List; |
if (nArg == 1) |
{ |
rc = Sqlite3.sqlite3_exec(p.db, |
"SELECT name FROM sqlite_master " + |
"WHERE type='index' AND name NOT LIKE 'Sqlite3.SQLITE_%' " + |
"UNION ALL " + |
"SELECT name FROM sqlite_temp_master " + |
"WHERE type='index' " + |
"ORDER BY 1", |
callback, data, ref zErrMsg |
); |
} |
else |
{ |
zShellStatic = azArg[1]; |
rc = Sqlite3.sqlite3_exec(p.db, |
"SELECT name FROM sqlite_master " + |
"WHERE type='index' AND tbl_name LIKE shellstatic() " + |
"UNION ALL " + |
"SELECT name FROM sqlite_temp_master " + |
"WHERE type='index' AND tbl_name LIKE shellstatic() " + |
"ORDER BY 1", |
callback, data, ref zErrMsg |
); |
zShellStatic = null; |
} |
if (!String.IsNullOrEmpty(zErrMsg)) |
{ |
fprintf(stderr, "Error: %s\n", zErrMsg); |
zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg); |
rc = 1; |
} |
else if (rc != Sqlite3.SQLITE_OK) |
{ |
fprintf(stderr, "Error: querying Sqlite3.SQLITE_master and Sqlite3.SQLITE_temp_master\n"); |
rc = 1; |
} |
} |
else |
|
#if SQLITE_ENABLE_IOTRACE |
if( c=='i' && "iotrace", n)== null ){ |
extern void (*sqlite3IoTrace)(const char*, ...); |
if( iotrace && iotrace!=stdout ) iotrace.Close();//fclose(iotrace); |
iotrace = null; |
if( nArg<2 ){ |
sqlite3IoTrace = 0; |
}else if( azArg[1].Equals("-") ){ |
sqlite3IoTrace = iotracePrintf; |
iotrace = stdout; |
}else{ |
iotrace = new StreamWriter(azArg[1].ToString());// fopen(azArg[1], "w"); |
if( iotrace== null ){ |
fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); |
sqlite3IoTrace = 0; |
rc = 1; |
}else{ |
sqlite3IoTrace = iotracePrintf; |
} |
} |
}else |
#endif |
|
#if !SQLITE_OMIT_LOAD_EXTENSION |
if (c == 'l' && azArg[0].StartsWith("load", StringComparison.InvariantCultureIgnoreCase) && nArg >= 2) |
{ |
string zFile, zProc; |
string zErrMsg = null; |
zFile = azArg[1]; |
zProc = nArg >= 3 ? azArg[2] : null; |
open_db(p); |
rc = Sqlite3.sqlite3_load_extension(p.db, zFile, zProc, ref zErrMsg); |
if (rc != Sqlite3.SQLITE_OK) |
{ |
fprintf(stderr, "Error: %s\n", zErrMsg); |
zErrMsg = null;//Sqlite3.sqlite3_free( zErrMsg ); |
rc = 1; |
} |
} |
else |
#endif |
|
if (c == 'l' && azArg[0].StartsWith("log", StringComparison.InvariantCultureIgnoreCase) && nArg >= 2) |
{ |
string zFile = azArg[1]; |
if (p.pLog != null && p.pLog != stdout && p.pLog != stderr) |
{ |
p.pLog.Close();//fclose(p.pLog); |
p.pLog = null; |
} |
if (zFile.Equals("stdout", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.pLog = stdout; |
} |
else if (zFile.Equals("stderr", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.pLog = stderr; |
} |
else if (zFile.Equals("off", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.pLog = null; |
} |
else |
{ |
p.pLog = new StreamWriter(zFile);// fopen(zFile, "w"); |
if (p.pLog == null) |
{ |
fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); |
} |
} |
} |
else |
|
if (c == 'm' && azArg[0].StartsWith("mode", StringComparison.InvariantCultureIgnoreCase) && nArg == 2) |
{ |
int n2 = strlen30(azArg[1]); |
if ((n2 == 4 && azArg[1].StartsWith("line", StringComparison.InvariantCultureIgnoreCase)) |
|| |
(n2 == 5 && azArg[1].StartsWith("lines", StringComparison.InvariantCultureIgnoreCase))) |
{ |
p.mode = MODE_Line; |
} |
else if ((n2 == 6 && azArg[1].StartsWith("column", StringComparison.InvariantCultureIgnoreCase)) |
|| |
(n2 == 7 && azArg[1].StartsWith("columns", StringComparison.InvariantCultureIgnoreCase))) |
{ |
p.mode = MODE_Column; |
} |
else if (n2 == 4 && azArg[1].StartsWith("list", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.mode = MODE_List; |
} |
else if (n2 == 4 && azArg[1].StartsWith("html", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.mode = MODE_Html; |
} |
else if (n2 == 3 && azArg[1].StartsWith("tcl", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.mode = MODE_Tcl; |
} |
else if (n2 == 3 && azArg[1].StartsWith("csv", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.mode = MODE_Csv; |
snprintf(2, ref p.separator, ","); |
} |
else if (n2 == 4 && azArg[1].StartsWith("tabs", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.mode = MODE_List; |
snprintf(2, ref p.separator, "\t"); |
} |
else if (n2 == 6 && azArg[1].StartsWith("insert", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.mode = MODE_Insert; |
set_table_name(p, "table"); |
} |
else |
{ |
fprintf(stderr, "Error: mode should be one of: " + |
"column csv html insert line list tabs tcl\n"); |
rc = 1; |
} |
} |
else |
|
if (c == 'm' && azArg[0].StartsWith("mode", StringComparison.InvariantCultureIgnoreCase) && nArg == 3) |
{ |
int n2 = strlen30(azArg[1]); |
if (n2 == 6 && azArg[1].StartsWith("insert", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.mode = MODE_Insert; |
set_table_name(p, azArg[2]); |
} |
else |
{ |
fprintf(stderr, "Error: invalid arguments: " + |
" \"%s\". Enter \".help\" for help\n", azArg[2]); |
rc = 1; |
} |
} |
else |
|
if (c == 'n' && azArg[0].StartsWith("nullvalue", StringComparison.InvariantCultureIgnoreCase) && nArg == 2) |
{ |
snprintf(9, ref p.nullvalue, |
"%.*s", (int)p.nullvalue.Length - 1, azArg[1]); |
} |
else |
|
if (c == 'o' && azArg[0].StartsWith("output", StringComparison.InvariantCultureIgnoreCase) && nArg == 2) |
{ |
if (p.Out != stdout) |
{ |
p.Out.Close();//fclose(p.Out); |
} |
if (azArg[1].Equals("stdout", StringComparison.InvariantCultureIgnoreCase)) |
{ |
p.Out = stdout; |
Sqlite3.sqlite3_snprintf(p.outfile.Capacity, p.outfile, "stdout"); |
} |
else |
{ |
p.Out = new StreamWriter(azArg[1].ToString());// fopen(azArg[1], "wb"); |
if (p.Out == null) |
{ |
fprintf(stderr, "Error: cannot write to \"%s\"\n", azArg[1]); |
p.Out = stdout; |
rc = 1; |
} |
else |
{ |
Sqlite3.sqlite3_snprintf(p.outfile.Capacity, p.outfile, "%s", azArg[1]); |
} |
} |
} |
else |
|
if (c == 'p' && azArg[0].StartsWith("prompt", StringComparison.InvariantCultureIgnoreCase) && (nArg == 2 || nArg == 3)) |
{ |
if (nArg >= 2) |
{ |
mainPrompt = azArg[1].ToString();//strncpy(mainPrompt, azArg[1], (int)ArraySize(mainPrompt) - 1); |
} |
if (nArg >= 3) |
{ |
continuePrompt = azArg[1].ToString();//strncpy(continuePrompt, azArg[2], (int)ArraySize(continuePrompt) - 1); |
} |
} |
else |
|
if (c == 'q' && azArg[0].StartsWith("quit", StringComparison.InvariantCultureIgnoreCase) && nArg == 1) |
{ |
rc = 2; |
} |
else |
|
if (c == 'r' && n >= 3 && azArg[0].StartsWith("read", StringComparison.InvariantCultureIgnoreCase) && nArg == 2) |
{ |
StreamReader alt = new StreamReader(azArg[1].ToString());// fopen(azArg[1], "rb"); |
if (alt == null) |
{ |
fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); |
rc = 1; |
} |
else |
{ |
rc = process_input(p, alt); |
alt.Close();//fclose(alt); |
} |
} |
else |
|
if (c == 'r' && n >= 3 && azArg[0].StartsWith("restore", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 4) |
{ |
string zSrcFile; |
string zDb; |
sqlite3 pSrc; |
Sqlite3.sqlite3_backup pBackup; |
int nTimeout = 0; |
|
if (nArg == 2) |
{ |
zSrcFile = azArg[1]; |
zDb = "main"; |
} |
else |
{ |
zSrcFile = azArg[2]; |
zDb = azArg[1]; |
} |
rc = Sqlite3.sqlite3_open(zSrcFile, out pSrc); |
if (rc != Sqlite3.SQLITE_OK) |
{ |
fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); |
Sqlite3.sqlite3_close(pSrc); |
return 1; |
} |
open_db(p); |
pBackup = Sqlite3.sqlite3_backup_init(p.db, zDb, pSrc, "main"); |
if (pBackup == null) |
{ |
fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(p.db)); |
Sqlite3.sqlite3_close(pSrc); |
return 1; |
} |
while ((rc = Sqlite3.sqlite3_backup_step(pBackup, 100)) == Sqlite3.SQLITE_OK |
|| rc == Sqlite3.SQLITE_BUSY) |
{ |
if (rc == Sqlite3.SQLITE_BUSY) |
{ |
if (nTimeout++ >= 3) |
break; |
Sqlite3.sqlite3_sleep(100); |
} |
} |
Sqlite3.sqlite3_backup_finish(pBackup); |
if (rc == Sqlite3.SQLITE_DONE) |
{ |
rc = 0; |
} |
else if (rc == Sqlite3.SQLITE_BUSY || rc == Sqlite3.SQLITE_LOCKED) |
{ |
fprintf(stderr, "Error: source database is busy\n"); |
rc = 1; |
} |
else |
{ |
fprintf(stderr, "Error: %s\n", Sqlite3.sqlite3_errmsg(p.db)); |
rc = 1; |
} |
Sqlite3.sqlite3_close(pSrc); |
} |
else |
|
if (c == 's' && azArg[0].StartsWith("schema", StringComparison.InvariantCultureIgnoreCase) && nArg < 3) |
{ |
callback_data data; |
string zErrMsg = null; |
open_db(p); |
data = p.Copy();// memcpy(data, p, sizeof(data)); |
data.showHeader = false; |
data.mode = MODE_Semi; |
if (nArg > 1) |
{ |
//int i; |
//for (i = 0; azArg[1][i]; i++) |
// azArg[1][i] = (char)tolower(azArg[1][i]); |
azArg[1] = azArg[1].ToLower(); |
if (azArg[1].Equals("sqlite_master", StringComparison.InvariantCultureIgnoreCase)) |
{ |
string[] new_argv = new string[2]; |
string[] new_colv = new string[2]; |
new_argv[0] = "CREATE TABLE Sqlite3.SQLITE_master (\n" + |
" type text,\n" + |
" name text,\n" + |
" tbl_name text,\n" + |
" rootpage integer,\n" + |
" sql text\n" + |
")"; |
new_argv[1] = null; |
new_colv[0] = "sql"; |
new_colv[1] = null; |
callback(data, 1, new_argv, new_colv); |
rc = Sqlite3.SQLITE_OK; |
} |
else if (azArg[1].Equals("sqlite_temp_master", StringComparison.InvariantCultureIgnoreCase)) |
{ |
string[] new_argv = new string[2]; |
string[] new_colv = new string[2]; |
new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master(\n" + |
" type text,\n" + |
" name text,\n" + |
" tbl_name text,\n" + |
" rootpage integer,\n" + |
" sql text\n" + |
")"; |
new_argv[1] = null; |
new_colv[0] = "sql"; |
new_colv[1] = null; |
callback(data, 1, new_argv, new_colv); |
rc = Sqlite3.SQLITE_OK; |
} |
else |
{ |
zShellStatic = azArg[1]; |
rc = Sqlite3.sqlite3_exec(p.db, |
"SELECT sql FROM " + |
" (SELECT sql sql, type type, tbl_name tbl_name, name name" + |
" FROM sqlite_master UNION ALL" + |
" SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " + |
"WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTnull " + |
"ORDER BY substr(type,2,1), name", |
callback, data, ref zErrMsg); |
zShellStatic = null; |
} |
} |
else |
{ |
rc = Sqlite3.sqlite3_exec(p.db, |
"SELECT sql FROM " + |
" (SELECT sql sql, type type, tbl_name tbl_name, name name" + |
" FROM sqlite_master UNION ALL" + |
" SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " + |
"WHERE type!='meta' AND sql NOTnull AND name NOT LIKE 'Sqlite3.SQLITE_%'" + |
"ORDER BY substr(type,2,1), name", |
callback, data, ref zErrMsg |
); |
} |
if (!String.IsNullOrEmpty(zErrMsg)) |
{ |
fprintf(stderr, "Error: %s\n", zErrMsg); |
zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg); |
rc = 1; |
} |
else if (rc != Sqlite3.SQLITE_OK) |
{ |
fprintf(stderr, "Error: querying schema information\n"); |
rc = 1; |
} |
else |
{ |
rc = 0; |
} |
} |
else |
|
if (c == 's' && azArg[0].StartsWith("separator", StringComparison.InvariantCultureIgnoreCase) && nArg == 2) |
{ |
snprintf(2, ref p.separator, "%.*s", 2 - 1, azArg[1]); |
} |
else |
|
if (c == 's' && azArg[0].StartsWith("show", StringComparison.InvariantCultureIgnoreCase) && nArg == 1) |
{ |
int ii; |
fprintf(p.Out, "%9.9s: %s\n", "echo", p.echoOn ? "on" : "off"); |
fprintf(p.Out, "%9.9s: %s\n", "explain", p.explainPrev.valid ? "on" : "off"); |
fprintf(p.Out, "%9.9s: %s\n", "headers", p.showHeader ? "on" : "off"); |
fprintf(p.Out, "%9.9s: %s\n", "mode", modeDescr[p.mode]); |
fprintf(p.Out, "%9.9s: ", "nullvalue"); |
output_c_string(p.Out, p.nullvalue); |
fprintf(p.Out, "\n"); |
fprintf(p.Out, "%9.9s: %s\n", "output", |
strlen30(p.outfile) != 0 ? p.outfile.ToString() : "stdout"); |
fprintf(p.Out, "%9.9s: ", "separator"); |
output_c_string(p.Out, p.separator); |
fprintf(p.Out, "\n"); |
fprintf(p.Out, "%9.9s: %s\n", "stats", p.statsOn ? "on" : "off"); |
fprintf(p.Out, "%9.9s: ", "width"); |
for (ii = 0; ii < (int)ArraySize(p.colWidth) && p.colWidth[ii] != 0; ii++) |
{ |
fprintf(p.Out, "%d ", p.colWidth[ii]); |
} |
fprintf(p.Out, "\n"); |
} |
else |
|
if (c == 's' && azArg[0].StartsWith("stats", StringComparison.InvariantCultureIgnoreCase) && nArg > 1 && nArg < 3) |
{ |
p.statsOn = booleanValue(azArg[1]); |
} |
else |
|
if (c == 't' && n > 1 && azArg[0].StartsWith("tables", StringComparison.InvariantCultureIgnoreCase) && nArg < 3) |
{ |
string[] azResult = null; |
int nRow = 0; |
string zErrMsg = null; |
open_db(p); |
if (nArg == 1) |
{ |
rc = Sqlite3.sqlite3_get_table(p.db, |
"SELECT name FROM sqlite_master " + |
"WHERE type IN ('table','view') AND name NOT LIKE 'Sqlite3.SQLITE_%' " + |
"UNION ALL " + |
"SELECT name FROM sqlite_temp_master " + |
"WHERE type IN ('table','view') " + |
"ORDER BY 1", |
ref azResult, ref nRow, null, ref zErrMsg |
); |
} |
else |
{ |
zShellStatic = azArg[1]; |
rc = Sqlite3.sqlite3_get_table(p.db, |
"SELECT name FROM sqlite_master " + |
"WHERE type IN ('table','view') AND name LIKE shellstatic() " + |
"UNION ALL " + |
"SELECT name FROM sqlite_temp_master " + |
"WHERE type IN ('table','view') AND name LIKE shellstatic() " + |
"ORDER BY 1", |
ref azResult, ref nRow, null, ref zErrMsg |
); |
zShellStatic = null; |
} |
if (!String.IsNullOrEmpty(zErrMsg)) |
{ |
fprintf(stderr, "Error: %s\n", zErrMsg); |
zErrMsg = null;//Sqlite3.sqlite3_free(zErrMsg); |
rc = 1; |
} |
else if (rc != Sqlite3.SQLITE_OK) |
{ |
fprintf(stderr, "Error: querying Sqlite3.SQLITE_master and Sqlite3.SQLITE_temp_master\n"); |
rc = 1; |
} |
else |
{ |
int len, maxlen = 0; |
int ii, j; |
int nPrintCol, nPrintRow; |
for (ii = 1; ii <= nRow; ii++) |
{ |
if (azResult[ii] == null) |
continue; |
len = strlen30(azResult[ii]); |
if (len > maxlen) |
maxlen = len; |
} |
nPrintCol = 80 / (maxlen + 2); |
if (nPrintCol < 1) |
nPrintCol = 1; |
nPrintRow = (nRow + nPrintCol - 1) / nPrintCol; |
for (ii = 0; ii < nPrintRow; ii++) |
{ |
for (j = ii + 1; j <= nRow; j += nPrintRow) |
{ |
string zSp = j <= nPrintRow ? "" : " "; |
printf("%s%-*s", zSp, maxlen, !String.IsNullOrEmpty(azResult[j]) ? azResult[j] : ""); |
} |
printf("\n"); |
} |
} |
Sqlite3.sqlite3_free_table(ref azResult); |
} |
else |
|
if (c == 't' && n >= 8 && azArg[0].StartsWith("testctrl", StringComparison.InvariantCultureIgnoreCase) && nArg >= 2) |
{ |
//static const struct { |
// string zCtrlName; /* Name of a test-control option */ |
// int ctrlCode; /* Integer code for that option */ |
//} |
_aCtrl[] aCtrl = new _aCtrl[] { |
new _aCtrl( "prng_save", Sqlite3.SQLITE_TESTCTRL_PRNG_SAVE ), |
new _aCtrl( "prng_restore", Sqlite3.SQLITE_TESTCTRL_PRNG_RESTORE ), |
new _aCtrl( "prng_reset", Sqlite3.SQLITE_TESTCTRL_PRNG_RESET ), |
new _aCtrl( "bitvec_test", Sqlite3.SQLITE_TESTCTRL_BITVEC_TEST ), |
new _aCtrl( "fault_install", Sqlite3.SQLITE_TESTCTRL_FAULT_INSTALL ), |
new _aCtrl( "benign_malloc_hooks", Sqlite3.SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS ), |
new _aCtrl( "pending_byte", Sqlite3.SQLITE_TESTCTRL_PENDING_BYTE ), |
new _aCtrl( "Debug.Assert", Sqlite3.SQLITE_TESTCTRL_ASSERT ), |
new _aCtrl( "always", Sqlite3.SQLITE_TESTCTRL_ALWAYS ), |
new _aCtrl( "reserve", Sqlite3.SQLITE_TESTCTRL_RESERVE ), |
new _aCtrl( "optimizations", Sqlite3.SQLITE_TESTCTRL_OPTIMIZATIONS ), |
new _aCtrl( "iskeyword", Sqlite3.SQLITE_TESTCTRL_ISKEYWORD ), |
new _aCtrl( "pghdrsz", Sqlite3.SQLITE_TESTCTRL_PGHDRSZ ), |
new _aCtrl( "scratchmalloc", Sqlite3.SQLITE_TESTCTRL_SCRATCHMALLOC ), |
}; |
int testctrl = -1; |
//int rc = 0; |
int ii;//, n; |
open_db(p); |
|
/* convert testctrl text option to value. allow any unique prefix |
** of the option name, or a numerical value. */ |
//n = strlen30(azArg[1]); |
for (ii = 0; ii < aCtrl.Length; ii++)//(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++) |
{ |
if (aCtrl[ii].zCtrlName.StartsWith(azArg[1], StringComparison.InvariantCultureIgnoreCase)) |
{ |
if (testctrl < 0) |
{ |
testctrl = aCtrl[ii].ctrlCode; |
} |
else |
{ |
fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[ii]); |
testctrl = -1; |
break; |
} |
} |
} |
if (testctrl < 0) |
testctrl = Convert.ToInt32(azArg[1]);//atoi |
if ((testctrl < Sqlite3.SQLITE_TESTCTRL_FIRST) || (testctrl > Sqlite3.SQLITE_TESTCTRL_LAST)) |
{ |
fprintf(stderr, "Error: invalid testctrl option: %s\n", azArg[1]); |
} |
else |
{ |
switch (testctrl) |
{ |
|
/* Sqlite3.sqlite3_test_control(int, db, Int) */ |
case Sqlite3.SQLITE_TESTCTRL_OPTIMIZATIONS: |
case Sqlite3.SQLITE_TESTCTRL_RESERVE: |
if (nArg == 3) |
{ |
int opt = (int)System.Int64.Parse(azArg[2]); |
rc = Sqlite3.sqlite3_test_control(testctrl, p.db, opt); |
printf("%d (0x%08x)\n", rc, rc); |
} |
else |
{ |
fprintf(stderr, "Error: testctrl %s takes a single int option\n", |
azArg[1]); |
} |
break; |
|
/* Sqlite3.sqlite3_test_control(int) */ |
case Sqlite3.SQLITE_TESTCTRL_PRNG_SAVE: |
case Sqlite3.SQLITE_TESTCTRL_PRNG_RESTORE: |
case Sqlite3.SQLITE_TESTCTRL_PRNG_RESET: |
case Sqlite3.SQLITE_TESTCTRL_PGHDRSZ: |
if (nArg == 2) |
{ |
rc = Sqlite3.sqlite3_test_control(testctrl); |
printf("%d (0x%08x)\n", rc, rc); |
} |
else |
{ |
fprintf(stderr, "Error: testctrl %s takes no options\n", azArg[1]); |
} |
break; |
|
/* Sqlite3.sqlite3_test_control(int, uint) */ |
case Sqlite3.SQLITE_TESTCTRL_PENDING_BYTE: |
if (nArg == 3) |
{ |
u32 opt = (u32)Convert.ToInt32(azArg[2]);//atoi |
rc = Sqlite3.sqlite3_test_control(testctrl, opt); |
printf("%d (0x%08x)\n", rc, rc); |
} |
else |
{ |
fprintf(stderr, "Error: testctrl %s takes a single unsigned" + |
" int option\n", azArg[1]); |
} |
break; |
|
/* Sqlite3.sqlite3_test_control(int, Int) */ |
case Sqlite3.SQLITE_TESTCTRL_ASSERT: |
case Sqlite3.SQLITE_TESTCTRL_ALWAYS: |
if (nArg == 3) |
{ |
int opt = Convert.ToInt32(azArg[2]);//atoi |
rc = Sqlite3.sqlite3_test_control(testctrl, opt); |
printf("%d (0x%08x)\n", rc, rc); |
} |
else |
{ |
fprintf(stderr, "Error: testctrl %s takes a single int option\n", |
azArg[1]); |
} |
break; |
|
/* Sqlite3.sqlite3_test_control(int, string ) */ |
#if SQLITE_N_KEYWORD |
case Sqlite3.SQLITE_TESTCTRL_ISKEYWORD: |
if( nArg==3 ){ |
string opt = azArg[2]; |
rc = Sqlite3.sqlite3_test_control(testctrl, opt); |
printf("%d (0x%08x)\n", rc, rc); |
} else { |
fprintf(stderr,"Error: testctrl %s takes a single string option\n", |
azArg[1]); |
} |
break; |
#endif |
|
case Sqlite3.SQLITE_TESTCTRL_BITVEC_TEST: |
case Sqlite3.SQLITE_TESTCTRL_FAULT_INSTALL: |
case Sqlite3.SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: |
case Sqlite3.SQLITE_TESTCTRL_SCRATCHMALLOC: |
default: |
fprintf(stderr, "Error: CLI support for testctrl %s not implemented\n", |
azArg[1]); |
break; |
} |
} |
} |
else |
|
if (c == 't' && n > 4 && azArg[0].StartsWith("timeout", StringComparison.InvariantCultureIgnoreCase) && nArg == 2) |
{ |
open_db(p); |
Sqlite3.sqlite3_busy_timeout(p.db, Convert.ToInt32(azArg[1]));//atoi |
} |
else |
|
if (HAS_TIMER && c == 't' && n >= 5 && azArg[0].StartsWith("timer", StringComparison.InvariantCultureIgnoreCase) |
&& nArg == 2 |
) |
{ |
enableTimer = booleanValue(azArg[1]); |
} |
else |
|
if (c == 'v' && azArg[0].StartsWith("version", StringComparison.InvariantCultureIgnoreCase)) |
{ |
printf("SQLite %s %s\n", |
Sqlite3.sqlite3_libversion(), Sqlite3.sqlite3_sourceid()); |
} |
else |
|
if (c == 'w' && azArg[0].StartsWith("width", StringComparison.InvariantCultureIgnoreCase) && nArg > 1) |
{ |
int j; |
Debug.Assert(nArg <= ArraySize(azArg)); |
for (j = 1; j < nArg && j < ArraySize(p.colWidth); j++) |
{ |
p.colWidth[j - 1] = Convert.ToInt32(azArg[j]);//atoi |
} |
} |
else |
{ |
fprintf(stderr, "Error: unknown command or invalid arguments: " + |
" \"%s\". Enter \".help\" for help\n", azArg[0]); |
rc = 1; |
} |
|
return rc; |
} |
|
/* |
** Return TRUE if a semicolon occurs anywhere in the first N characters |
** of string z[]. |
*/ |
static bool _contains_semicolon(string z, int N) |
{ |
//int i; |
//for (i = 0; i < N; i++) { if (z[i] == ';') return 1; } |
//return 0; |
return z.Contains(";"); |
} |
|
/* |
** Test to see if a line consists entirely of whitespace. |
*/ |
static bool _all_whitespace(StringBuilder z) |
{ |
return String.IsNullOrEmpty(z.ToString().Trim()); |
} |
static bool _all_whitespace(string z) |
{ |
return String.IsNullOrEmpty(z.Trim()); |
} |
|
/* |
** Return TRUE if the line typed in is an SQL command terminator other |
** than a semi-colon. The SQL Server style "go" command is understood |
** as is the Oracle "/". |
*/ |
static bool _is_command_terminator(StringBuilder zLine) |
{ |
return _is_command_terminator(zLine.ToString()); |
} |
static bool _is_command_terminator(string zLine) |
{ |
zLine = zLine.Trim();// while ( isspace( zLine ) ) { zLine++; }; |
if (zLine.Length == 0) |
return false; |
if (zLine[0] == '/')//&& _all_whitespace(zLine[1]) ) |
{ |
return true; /* Oracle */ |
} |
if (Char.ToLower(zLine[0]) == 'g' && Char.ToLower(zLine[1]) == 'o') |
//&& _all_whitespace(&zLine[2]) ) |
{ |
return true; /* SQL Server */ |
} |
return false; |
} |
/* |
** Return true if zSql is a complete SQL statement. Return false if it |
** ends in the middle of a string literal or C-style comment. |
*/ |
static bool _is_complete(string zSql, int nSql) |
{ |
int rc; |
if (zSql == null) |
return true; |
//zSql[nSql] = ';'; |
//zSql[nSql + 1] = 0; |
rc = Sqlite3.sqlite3_complete(zSql + ";\0"); |
//zSql[nSql] = 0; |
return rc != 0; |
} |
|
/* |
** Read input from In and process it. If In== null then input |
** is interactive - the user is typing it it. Otherwise, Input |
** is coming from a file or device. A prompt is issued and history |
** is saved only if input is interactive. An interrupt signal will |
** cause this routine to exit immediately, unless input is interactive. |
** |
** Return the number of errors. |
*/ |
static int process_input(callback_data p, TextReader In) |
{ |
StringBuilder zLine = new StringBuilder(1024); |
string zSql = null; |
int nSql = 0; |
int nSqlPrior = 0; |
string zErrMsg = null; |
int rc; |
int errCnt = 0; |
int lineno = 0; |
int startline = 0; |
|
while (errCnt == null || !bail_on_error || (In == null && stdin_is_interactive)) |
{ |
fflush(p.Out); |
//free(zLine); |
zLine.Length = 0; |
zLine.Append(one_input_line(zSql, In)); |
if (In != null && ((System.IO.StreamReader)(In)).EndOfStream) |
{ |
break; /* We have reached EOF */ |
} |
//if (zLine == null) |
//{ |
// break; /* We have reached EOF */ |
//} |
if (seenInterrupt) |
{ |
if (In != null) |
break; |
seenInterrupt = false; |
} |
lineno++; |
if (String.IsNullOrEmpty(zSql) && _all_whitespace(zLine)) |
continue; |
if (zLine.Length > 0 && zLine[0] == '.' && nSql == 0) |
{ |
if (p.echoOn) |
printf("%s\n", zLine); |
rc = do_meta_command(zLine, p); |
if (rc == 2) |
{ /* exit requested */ |
break; |
} |
else if (rc != 0) |
{ |
errCnt++; |
} |
continue; |
} |
if (_is_command_terminator(zLine) && _is_complete(zSql, nSql)) |
{ |
zLine.Append(";");// memcpy(zLine, ";", 2); |
} |
nSqlPrior = nSql; |
if (zSql == null) |
{ |
int i; |
for (i = 0; i < zLine.Length && isspace(zLine[i]); i++) { } |
if (i < zLine.Length) |
{ |
nSql = strlen30(zLine); |
//zSql = malloc(nSql + 3); |
//if (zSql == null) |
//{ |
// fprintf(stderr, "Error: out of memory\n"); |
// exit(1); |
//} |
zSql += zLine.ToString(0, nSql);//memcpy(zSql, zLine, nSql + 1); |
startline = lineno; |
} |
} |
else |
{ |
int len = strlen30(zLine); |
//zSql = realloc(zSql, nSql + len + 4); |
//if (zSql == null) |
//{ |
// fprintf(stderr, "Error: out of memory\n"); |
// exit(1); |
//} |
zSql += '\n'; |
zSql += zLine;//memcpy(zSql[nSql], zLine, len + 1); |
nSql = zLine.Length; |
} |
if (!String.IsNullOrEmpty(zSql) && _contains_semicolon(zSql.Substring(nSqlPrior), nSql - nSqlPrior) |
&& Sqlite3.sqlite3_complete(zSql) != 0) |
{ |
p.cnt = 0; |
open_db(p); |
beginTimer(); |
rc = shell_exec(p.db, zSql, shell_callback, p, ref zErrMsg); |
endTimer(); |
if (rc != 0 || zErrMsg != null) |
{ |
string zPrefix = null; |
if (In != null || !stdin_is_interactive) |
{ |
snprintf(100, ref zPrefix, |
"Error: near line %d:", startline); |
} |
else |
{ |
snprintf(100, ref zPrefix, "Error:"); |
} |
if (zErrMsg != null) |
{ |
fprintf(stderr, "%s %s\n", zPrefix, zErrMsg); |
//Sqlite3.sqlite3_free(zErrMsg); |
zErrMsg = null; |
} |
else |
{ |
fprintf(stderr, "%s %s\n", zPrefix, Sqlite3.sqlite3_errmsg(p.db)); |
} |
errCnt++; |
} |
//free(zSql); |
zSql = null; |
nSql = 0; |
} |
} |
if (zSql != null) |
{ |
if (!_all_whitespace(zSql)) |
{ |
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); |
} |
zSql = null;//free(zSql); |
} |
zLine = null;//free(zLine); |
return errCnt; |
} |
|
/* |
** Return a pathname which is the user's home directory. A |
** 0 return indicates an error of some kind. Space to hold the |
** resulting string is obtained from malloc(). The calling |
** function should free the result. |
*/ |
static string find_home_dir() |
{ |
string home_dir = null; |
|
//#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL) |
// struct passwd pwent; |
// uid_t uid = getuid(); |
// if( (pwent=getpwuid(uid)) != null) { |
// home_dir = pwent.pw_dir; |
// } |
//#endif |
|
#if (_WIN32_WCE) |
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv() |
*/ |
home_dir = strdup("/"); |
#else |
|
#if (_WIN32) || (WIN32) || (__OS2__) |
//if (home_dir) |
{ |
home_dir = getenv("USERPROFILE"); |
} |
#endif |
|
if (!String.IsNullOrEmpty(home_dir)) |
{ |
home_dir = getenv("HOME"); |
} |
|
#if (_WIN32) || (WIN32) || (__OS2__) |
if (String.IsNullOrEmpty(home_dir)) |
{ |
string zDrive, zPath; |
int n; |
zDrive = getenv("HOMEDRIVE"); |
zPath = getenv("HOMEPATH"); |
if (!String.IsNullOrEmpty(zDrive) && !String.IsNullOrEmpty(zPath)) |
{ |
n = strlen30(zDrive) + strlen30(zPath) + 1; |
//home_dir = malloc(n); |
//if (home_dir == null) |
// return 0; |
snprintf(n, ref home_dir, "%s%s", zDrive, zPath); |
return home_dir; |
} |
home_dir = "c:\\"; |
} |
#endif |
|
#endif //* !_WIN32_WCE */ |
|
//if (home_dir) |
//{ |
// int n = strlen30(home_dir) + 1; |
// string z = malloc(n); |
// if (z) |
// memcpy(z, home_dir, n); |
// home_dir = z; |
//} |
|
return home_dir; |
} |
|
/* |
** Read input from the file given by sqliterc_override. Or if that |
** parameter is null, take input from ~/.sqliterc |
** |
** Returns the number of errors. |
*/ |
static int process_sqliterc( |
callback_data p, /* Configuration data */ |
string sqliterc_override /* Name of config file. null to use default */ |
) |
{ |
string home_dir = null; |
string sqliterc = sqliterc_override; |
StringBuilder zBuf = null; |
StreamReader In = null; |
int nBuf; |
int rc = 0; |
|
if (sqliterc == null) |
{ |
home_dir = find_home_dir(); |
if (home_dir == null) |
{ |
#if !(__RTP__) && !(_WRS_KERNEL) |
fprintf(stderr, "%s: Error: cannot locate your home directory\n", Argv0); |
#endif |
return 1; |
} |
nBuf = strlen30(home_dir) + 16; |
zBuf = new StringBuilder(nBuf); |
if (zBuf == null) |
{ |
fprintf(stderr, "%s: Error: out of memory\n", Argv0); |
return 1; |
} |
Sqlite3.sqlite3_snprintf(nBuf, zBuf, "%s/.sqliterc", home_dir); |
home_dir = null;//free(home_dir); |
sqliterc = zBuf.ToString(); |
} |
if (File.Exists(sqliterc)) |
{ |
try |
{ |
In = new StreamReader(sqliterc);// fopen(sqliterc, "rb"); |
if (In != null) |
{ |
if (stdin_is_interactive) |
{ |
fprintf(stderr, "-- Loading resources from %s\n", sqliterc); |
} |
rc = process_input(p, In); |
In.Close();//fclose(In); |
} |
} catch |
{ |
} |
} |
zBuf = null;//free(zBuf); |
return rc; |
} |
|
/* |
** Show available command line options |
*/ |
static string zOptions = |
" -help show this message\n" + |
" -init filename read/process named file\n" + |
" -echo print commands before execution\n" + |
" -[no]header turn headers on or off\n" + |
" -bail stop after hitting an error\n" + |
" -interactive force interactive I/O\n" + |
" -batch force batch I/O\n" + |
" -column set output mode to 'column'\n" + |
" -csv set output mode to 'csv'\n" + |
" -html set output mode to HTML\n" + |
" -line set output mode to 'line'\n" + |
" -list set output mode to 'list'\n" + |
" -separator 'x' set output field separator (|)\n" + |
" -stats print memory stats before each finalize\n" + |
" -nullvalue 'text' set text string for null values\n" + |
" -version show SQLite version\n" + |
" -vfs NAME use NAME as the default VFS\n" + |
#if SQLITE_ENABLE_VFSTRACE |
" -vfstrace enable tracing of all VFS calls\n" + |
#endif |
""; |
static void usage(bool showDetail) |
{ |
fprintf(stderr, |
"Usage: %s [OPTIONS] FILENAME [SQL]\n" + |
"FILENAME is the name of an SQLite database. A new database is created\n" + |
"if the file does not previously exist.\n", Argv0); |
if (showDetail) |
{ |
fprintf(stderr, "OPTIONS include:\n%s", zOptions); |
} |
else |
{ |
fprintf(stderr, "Use the -help option for additional information\n"); |
} |
exit(1); |
} |
|
/* |
** Initialize the state information in data |
*/ |
static void main_init(ref callback_data data) |
{ |
data = new callback_data();//memset(data, 0, sizeof(*data)); |
data.mode = MODE_List; |
data.separator = "|";//memcpy(data.separator, "|", 2); |
data.showHeader = false; |
Sqlite3.sqlite3_initialize(); |
Sqlite3.sqlite3_config(Sqlite3.SQLITE_CONFIG_URI, 1); |
Sqlite3.sqlite3_config(Sqlite3.SQLITE_CONFIG_LOG, new object[] { (Sqlite3.dxLog)shellLog, data, null }); |
snprintf(10, ref mainPrompt, "sqlite> "); |
snprintf(10, ref continuePrompt, " ...> "); |
Sqlite3.sqlite3_config(Sqlite3.SQLITE_CONFIG_SINGLETHREAD); |
} |
|
static int main(int argc, string[] argv) |
{ |
string zErrMsg = null; |
callback_data data = null; |
string zInitFile = null; |
StringBuilder zFirstCmd = null; |
int i; |
int rc = 0; |
|
if (!Sqlite3.sqlite3_sourceid().Equals(Sqlite3.SQLITE_SOURCE_ID, StringComparison.InvariantCultureIgnoreCase)) |
{ |
fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", |
Sqlite3.sqlite3_sourceid(), Sqlite3.SQLITE_SOURCE_ID); |
exit(1); |
} |
Argv0 = argv.Length == 0 ? null : argv[0]; |
main_init(ref data); |
stdin_is_interactive = isatty(0); |
|
/* Make sure we have a valid signal handler early, before anything |
** else is done. |
*/ |
#if SIGINT |
signal(SIGINT, Interrupt_handler); |
#endif |
|
/* Do an initial pass through the command-line argument to locate |
** the name of the database file, the name of the initialization file, |
** the size of the alternative malloc heap, |
** and the first command to execute. |
*/ |
for (i = 0; i < argc - 1; i++) |
{ |
string z; |
if (argv[i][0] != '-') |
break; |
z = argv[i]; |
if (z[0] == '-' && z[1] == '-') |
z = z.Remove(0, 1);//z++; |
if (argv[i].Equals("-separator", StringComparison.InvariantCultureIgnoreCase) || argv[i].Equals("-nullvalue", StringComparison.InvariantCultureIgnoreCase)) |
{ |
i++; |
} |
else if (argv[i].Equals("-init", StringComparison.InvariantCultureIgnoreCase)) |
{ |
i++; |
zInitFile = argv[i]; |
/* Need to check for batch mode here to so we can avoid printing |
** informational messages (like from process_sqliterc) before |
** we do the actual processing of arguments later in a second pass. |
*/ |
} |
else if (argv[i].Equals("-batch", StringComparison.InvariantCultureIgnoreCase)) |
{ |
stdin_is_interactive = false; |
} |
else if (argv[i].Equals("-heap", StringComparison.InvariantCultureIgnoreCase)) |
{ |
int j, c; |
string zSize; |
sqlite3_int64 szHeap; |
|
zSize = argv[++i]; |
szHeap = Convert.ToInt32(zSize);//atoi |
for (j = 0; (c = zSize[j]) != null; j++) |
{ |
if (c == 'M') { szHeap *= 1000000; break; } |
if (c == 'K') { szHeap *= 1000; break; } |
if (c == 'G') { szHeap *= 1000000000; break; } |
} |
if (szHeap > 0x7fff0000) |
szHeap = 0x7fff0000; |
#if (SQLITE_ENABLE_MEMSYS3) || (SQLITE_ENABLE_MEMSYS5) |
Sqlite3.SQLITE_config(Sqlite3.SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); |
#endif |
#if SQLITE_ENABLE_VFSTRACE |
}else if( argv[i].Equals("-vfstrace", StringComparison.InvariantCultureIgnoreCase) ){ |
extern int vfstrace_register( |
string zTraceName, |
string zOldVfsName, |
int (*xOut)(const char*,void*), |
void pOutArg, |
int makeDefault |
); |
vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); |
#endif |
} |
else if (argv[i].Equals("-vfs", StringComparison.InvariantCultureIgnoreCase)) |
{ |
Sqlite3.sqlite3_vfs pVfs = Sqlite3.sqlite3_vfs_find(argv[++i]); |
if (pVfs != null) |
{ |
Sqlite3.sqlite3_vfs_register(pVfs, 1); |
} |
else |
{ |
fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]); |
exit(1); |
} |
} |
} |
if (i < argc) |
{ |
#if (SQLITE_OS_OS2) && SQLITE_OS_OS2 |
data.zDbFilename = (string )convertCpPathToUtf8( argv[i++] ); |
#else |
data.zDbFilename = argv[i++]; |
#endif |
} |
else |
{ |
#if !SQLITE_OMIT_MEMORYDB |
data.zDbFilename = ":memory:"; |
#else |
data.zDbFilename = 0; |
#endif |
} |
if (i < argc) |
{ |
zFirstCmd.Append(argv[i++]); |
} |
if (i < argc) |
{ |
fprintf(stderr, "%s: Error: too many options: \"%s\"\n", Argv0, argv[i]); |
fprintf(stderr, "Use -help for a list of options.\n"); |
return 1; |
} |
data.Out = stdout; |
|
#if SQLITE_OMIT_MEMORYDB |
if( data.zDbFilename== null ){ |
fprintf(stderr,"%s: Error: no database filename specified\n", Argv0); |
return 1; |
} |
#endif |
|
/* Go ahead and open the database file if it already exists. If the |
** file does not exist, delay opening it. This prevents empty database |
** files from being created if a user mistypes the database name argument |
** to the sqlite command-line tool. |
*/ |
if (File.Exists(data.zDbFilename)) //(access(data.zDbFilename, 0) == 0) |
{ |
open_db(data); |
} |
|
/* Process the initialization file if there is one. If no -init option |
** is given on the command line, look for a file named ~/.sqliterc and |
** try to process it. |
*/ |
rc = process_sqliterc(data, zInitFile); |
if (rc > 0) |
{ |
return rc; |
} |
|
/* Make a second pass through the command-line argument and set |
** options. This second pass is delayed until after the initialization |
** file is processed so that the command-line arguments will override |
** settings in the initialization file. |
*/ |
for (i = 0; i < argc && argv[i][0] == '-'; i++) |
{ |
string z = argv[i]; |
if (z[1] == '-') { z = z.Remove(0, 1); } //z++; |
if (z.Equals("-init", StringComparison.InvariantCultureIgnoreCase)) |
{ |
i++; |
} |
else if (z.Equals("-html", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.mode = MODE_Html; |
} |
else if (z.Equals("-list", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.mode = MODE_List; |
} |
else if (z.Equals("-line", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.mode = MODE_Line; |
} |
else if (z.Equals("-column", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.mode = MODE_Column; |
} |
else if (z.Equals("-csv", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.mode = MODE_Csv; |
data.separator = ",";//memcpy(data.separator, ",", 2); |
} |
else if (z.Equals("-separator", StringComparison.InvariantCultureIgnoreCase)) |
{ |
i++; |
if (i >= argc) |
{ |
fprintf(stderr, "%s: Error: missing argument for option: %s\n", Argv0, z); |
fprintf(stderr, "Use -help for a list of options.\n"); |
return 1; |
} |
snprintf(data.separator.Length, ref data.separator, |
"%.*s", data.separator.Length - 1, argv[i]); |
} |
else if (z.Equals("-nullvalue", StringComparison.InvariantCultureIgnoreCase)) |
{ |
i++; |
if (i >= argc) |
{ |
fprintf(stderr, "%s: Error: missing argument for option: %s\n", Argv0, z); |
fprintf(stderr, "Use -help for a list of options.\n"); |
return 1; |
} |
snprintf(99, ref data.nullvalue, |
"%.*s", 99 - 1, argv[i]); |
} |
else if (z.Equals("-header", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.showHeader = true; |
} |
else if (z.Equals("-noheader", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.showHeader = false; |
} |
else if (z.Equals("-echo", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.echoOn = true; |
} |
else if (z.Equals("-stats", StringComparison.InvariantCultureIgnoreCase)) |
{ |
data.statsOn = true; |
} |
else if (z.Equals("-bail", StringComparison.InvariantCultureIgnoreCase)) |
{ |
bail_on_error = true; |
} |
else if (z.Equals("-version", StringComparison.InvariantCultureIgnoreCase)) |
{ |
printf("%s %s\n", Sqlite3.sqlite3_libversion(), Sqlite3.sqlite3_sourceid()); |
return 0; |
} |
else if (z.Equals("-interactive", StringComparison.InvariantCultureIgnoreCase)) |
{ |
stdin_is_interactive = true; |
} |
else if (z.Equals("-batch", StringComparison.InvariantCultureIgnoreCase)) |
{ |
stdin_is_interactive = false; |
} |
else if (z.Equals("-heap", StringComparison.InvariantCultureIgnoreCase)) |
{ |
i++; |
} |
else if (z.Equals("-vfs", StringComparison.InvariantCultureIgnoreCase)) |
{ |
i++; |
} |
else if (z.Equals("-vfstrace", StringComparison.InvariantCultureIgnoreCase)) |
{ |
i++; |
} |
else if (z.Equals("-help", StringComparison.InvariantCultureIgnoreCase) || z.Equals("--help", StringComparison.InvariantCultureIgnoreCase)) |
{ |
usage(true); |
} |
else |
{ |
fprintf(stderr, "%s: Error: unknown option: %s\n", Argv0, z); |
fprintf(stderr, "Use -help for a list of options.\n"); |
return 1; |
} |
} |
|
if (zFirstCmd != null && zFirstCmd.Length > 0) |
{ |
/* Run just the command that follows the database name |
*/ |
if (zFirstCmd[0] == '.') |
{ |
rc = do_meta_command(zFirstCmd, data); |
} |
else |
{ |
open_db(data); |
rc = shell_exec(data.db, zFirstCmd.ToString(), shell_callback, data, ref zErrMsg); |
if (zErrMsg != null) |
{ |
fprintf(stderr, "Error: %s\n", zErrMsg); |
return rc != 0 ? rc : 1; |
} |
else if (rc != 0) |
{ |
fprintf(stderr, "Error: unable to process SQL \"%s\"\n", zFirstCmd); |
return rc; |
} |
} |
} |
else |
{ |
/* Run commands received from standard input |
*/ |
if (stdin_is_interactive) |
{ |
string zHome; |
string zHistory = null; |
int nHistory; |
printf( |
#if (SQLITE_HAS_CODEC) && (SQLITE_ENABLE_CEROD) |
"SQLite version %s with the CEROD Extension\n" + |
"Copyright 2006 Hipp, Wyrick & Company, Inc.\n" + |
#else |
"SQLite version %s\n" + |
#endif |
"(source %.19s)\n" + |
"Enter \".help\" for instructions\n" + |
"Enter SQL statements terminated with a \";\"\n", |
Sqlite3.sqlite3_libversion(), Sqlite3.sqlite3_sourceid() |
); |
zHome = find_home_dir(); |
if (zHome != null) |
{ |
nHistory = strlen30(zHome) + 20; |
//if ((zHistory = malloc(nHistory)) != null) |
{ |
snprintf(nHistory, ref zHistory, "%s/.Sqlite3.SQLITE_history", zHome); |
} |
} |
#if (HAVE_READLINE)// && HAVE_READLINE==1 |
if( zHistory ) read_history(zHistory); |
#endif |
rc = process_input(data, null); |
if (zHistory != null) |
{ |
stifle_history(100); |
write_history(zHistory); |
zHistory = null;//free(zHistory); |
} |
zHome = null;//free(zHome); |
} |
else |
{ |
rc = process_input(data, stdin); |
} |
} |
set_table_name(data, null); |
if (data.db != null) |
{ |
Sqlite3.sqlite3_close(data.db); |
} |
return rc; |
} |
// C# DllImports |
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] |
internal static extern void FreeLibrary(IntPtr hModule); |
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] |
internal static extern IntPtr LoadLibrary(string lpFileName); |
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] |
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName); |
|
// Helper Variables for C# |
static TextReader stdin = Console.In; |
static TextWriter stdout = Console.Out; |
static TextWriter stderr = Console.Error; |
|
// Helper Functions for C# |
private static void exit(int p) |
{ |
if (p == 0) |
{ |
Console.WriteLine("Enter to CONTINUE:"); |
} |
else |
{ |
Console.WriteLine(String.Format("Error: {0}", p)); |
} |
Console.ReadKey(); |
} |
private static void fflush(TextWriter tw) |
{ |
tw.Flush(); |
} |
private static int fgets(StringBuilder p, int p_2, TextReader In) |
{ |
try |
{ |
p.Length = 0; |
p.Append(In.ReadLine()); |
if (p.Length > 0) |
p.Append('\n'); |
return p.Length; |
} catch |
{ |
return 0; |
} |
} |
private static void fputc(char c, TextWriter Out) |
{ |
Out.Write(c); |
} |
private static string getenv(string p) |
{ |
switch (p) |
{ |
case "USERPROFILE": |
return Environment.GetEnvironmentVariable("UserProfile"); |
case "HOME": |
{ |
return Environment.GetEnvironmentVariable("Home"); |
} |
case "HOMEDRIVE": |
{ |
return Environment.GetEnvironmentVariable("HomeDrive"); |
} |
case "HOMEPATH": |
{ |
return Environment.GetEnvironmentVariable("HomePath"); |
} |
default: |
throw new Exception("The method or operation is not implemented."); |
} |
} |
static bool isalnum(char c) |
{ |
return char.IsLetterOrDigit(c); |
} |
static bool isalpha(char c) |
{ |
return char.IsLetter(c); |
} |
static bool isdigit(char c) |
{ |
return char.IsDigit(c); |
} |
static bool isprint(char c) |
{ |
return !char.IsControl(c); |
} |
private static bool isspace(char c) |
{ |
return char.IsWhiteSpace(c); |
} |
static void fprintf(TextWriter tw, string zFormat, params va_list[] ap) |
{ |
tw.Write(Sqlite3.sqlite3_mprintf(zFormat, ap)); |
} |
public static void Main(string[] args) |
{ |
main(args.Length, args); |
} |
|
static void printf(string zFormat, params va_list[] ap) |
{ |
stdout.Write(Sqlite3.sqlite3_mprintf(zFormat, ap)); |
} |
private static void putc(char c, TextWriter _out) |
{ |
_out.Write(c); |
} |
private static void snprintf(int n, ref string zBuf, string zFormat, params va_list[] ap) |
{ |
StringBuilder sbBuf = new StringBuilder(100); |
Sqlite3.sqlite3_snprintf(n, sbBuf, zFormat, ap); |
zBuf = sbBuf.ToString(); |
} |
} |
} |