1251883Speter/* 2251883Speter** 2001 September 15 3251883Speter** 4251883Speter** The author disclaims copyright to this source code. In place of 5251883Speter** a legal notice, here is a blessing: 6251883Speter** 7251883Speter** May you do good and not evil. 8251883Speter** May you find forgiveness for yourself and forgive others. 9251883Speter** May you share freely, never taking more than you give. 10251883Speter** 11251883Speter************************************************************************* 12251883Speter** This file contains code to implement the "sqlite" command line 13251883Speter** utility for accessing SQLite databases. 14251883Speter*/ 15251883Speter#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS) 16251883Speter/* This needs to come before any includes for MSVC compiler */ 17251883Speter#define _CRT_SECURE_NO_WARNINGS 18251883Speter#endif 19251883Speter 20251883Speter/* 21251883Speter** Enable large-file support for fopen() and friends on unix. 22251883Speter*/ 23251883Speter#ifndef SQLITE_DISABLE_LFS 24251883Speter# define _LARGE_FILE 1 25251883Speter# ifndef _FILE_OFFSET_BITS 26251883Speter# define _FILE_OFFSET_BITS 64 27251883Speter# endif 28251883Speter# define _LARGEFILE_SOURCE 1 29251883Speter#endif 30251883Speter 31251883Speter#include <stdlib.h> 32251883Speter#include <string.h> 33251883Speter#include <stdio.h> 34251883Speter#include <assert.h> 35251883Speter#include "sqlite3.h" 36251883Speter#include <ctype.h> 37251883Speter#include <stdarg.h> 38251883Speter 39251883Speter#if !defined(_WIN32) && !defined(WIN32) 40251883Speter# include <signal.h> 41251883Speter# if !defined(__RTP__) && !defined(_WRS_KERNEL) 42251883Speter# include <pwd.h> 43251883Speter# endif 44251883Speter# include <unistd.h> 45251883Speter# include <sys/types.h> 46251883Speter#endif 47251883Speter 48251883Speter#ifdef HAVE_EDITLINE 49251883Speter# include <editline/editline.h> 50251883Speter#endif 51251883Speter#if defined(HAVE_READLINE) && HAVE_READLINE==1 52251883Speter# include <readline/readline.h> 53251883Speter# include <readline/history.h> 54251883Speter#endif 55251883Speter#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1) 56251883Speter# define readline(p) local_getline(p,stdin,0) 57251883Speter# define add_history(X) 58251883Speter# define read_history(X) 59251883Speter# define write_history(X) 60251883Speter# define stifle_history(X) 61251883Speter#endif 62251883Speter 63251883Speter#if defined(_WIN32) || defined(WIN32) 64251883Speter# include <io.h> 65251883Speter#define isatty(h) _isatty(h) 66251883Speter#define access(f,m) _access((f),(m)) 67251883Speter#undef popen 68251883Speter#define popen(a,b) _popen((a),(b)) 69251883Speter#undef pclose 70251883Speter#define pclose(x) _pclose(x) 71251883Speter#else 72251883Speter/* Make sure isatty() has a prototype. 73251883Speter*/ 74251883Speterextern int isatty(int); 75251883Speter#endif 76251883Speter 77251883Speter#if defined(_WIN32_WCE) 78251883Speter/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() 79251883Speter * thus we always assume that we have a console. That can be 80251883Speter * overridden with the -batch command line option. 81251883Speter */ 82251883Speter#define isatty(x) 1 83251883Speter#endif 84251883Speter 85251883Speter/* True if the timer is enabled */ 86251883Speterstatic int enableTimer = 0; 87251883Speter 88251883Speter/* ctype macros that work with signed characters */ 89251883Speter#define IsSpace(X) isspace((unsigned char)X) 90251883Speter#define IsDigit(X) isdigit((unsigned char)X) 91251883Speter#define ToLower(X) (char)tolower((unsigned char)X) 92251883Speter 93251883Speter#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \ 94251883Speter && !defined(__minux) 95251883Speter#include <sys/time.h> 96251883Speter#include <sys/resource.h> 97251883Speter 98251883Speter/* Saved resource information for the beginning of an operation */ 99251883Speterstatic struct rusage sBegin; 100251883Speter 101251883Speter/* 102251883Speter** Begin timing an operation 103251883Speter*/ 104251883Speterstatic void beginTimer(void){ 105251883Speter if( enableTimer ){ 106251883Speter getrusage(RUSAGE_SELF, &sBegin); 107251883Speter } 108251883Speter} 109251883Speter 110251883Speter/* Return the difference of two time_structs in seconds */ 111251883Speterstatic double timeDiff(struct timeval *pStart, struct timeval *pEnd){ 112251883Speter return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + 113251883Speter (double)(pEnd->tv_sec - pStart->tv_sec); 114251883Speter} 115251883Speter 116251883Speter/* 117251883Speter** Print the timing results. 118251883Speter*/ 119251883Speterstatic void endTimer(void){ 120251883Speter if( enableTimer ){ 121251883Speter struct rusage sEnd; 122251883Speter getrusage(RUSAGE_SELF, &sEnd); 123251883Speter printf("CPU Time: user %f sys %f\n", 124251883Speter timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), 125251883Speter timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); 126251883Speter } 127251883Speter} 128251883Speter 129251883Speter#define BEGIN_TIMER beginTimer() 130251883Speter#define END_TIMER endTimer() 131251883Speter#define HAS_TIMER 1 132251883Speter 133251883Speter#elif (defined(_WIN32) || defined(WIN32)) 134251883Speter 135251883Speter#include <windows.h> 136251883Speter 137251883Speter/* Saved resource information for the beginning of an operation */ 138251883Speterstatic HANDLE hProcess; 139251883Speterstatic FILETIME ftKernelBegin; 140251883Speterstatic FILETIME ftUserBegin; 141251883Spetertypedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); 142251883Speterstatic GETPROCTIMES getProcessTimesAddr = NULL; 143251883Speter 144251883Speter/* 145251883Speter** Check to see if we have timer support. Return 1 if necessary 146251883Speter** support found (or found previously). 147251883Speter*/ 148251883Speterstatic int hasTimer(void){ 149251883Speter if( getProcessTimesAddr ){ 150251883Speter return 1; 151251883Speter } else { 152251883Speter /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions. 153251883Speter ** See if the version we are running on has it, and if it does, save off 154251883Speter ** a pointer to it and the current process handle. 155251883Speter */ 156251883Speter hProcess = GetCurrentProcess(); 157251883Speter if( hProcess ){ 158251883Speter HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); 159251883Speter if( NULL != hinstLib ){ 160251883Speter getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); 161251883Speter if( NULL != getProcessTimesAddr ){ 162251883Speter return 1; 163251883Speter } 164251883Speter FreeLibrary(hinstLib); 165251883Speter } 166251883Speter } 167251883Speter } 168251883Speter return 0; 169251883Speter} 170251883Speter 171251883Speter/* 172251883Speter** Begin timing an operation 173251883Speter*/ 174251883Speterstatic void beginTimer(void){ 175251883Speter if( enableTimer && getProcessTimesAddr ){ 176251883Speter FILETIME ftCreation, ftExit; 177251883Speter getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin); 178251883Speter } 179251883Speter} 180251883Speter 181251883Speter/* Return the difference of two FILETIME structs in seconds */ 182251883Speterstatic double timeDiff(FILETIME *pStart, FILETIME *pEnd){ 183251883Speter sqlite_int64 i64Start = *((sqlite_int64 *) pStart); 184251883Speter sqlite_int64 i64End = *((sqlite_int64 *) pEnd); 185251883Speter return (double) ((i64End - i64Start) / 10000000.0); 186251883Speter} 187251883Speter 188251883Speter/* 189251883Speter** Print the timing results. 190251883Speter*/ 191251883Speterstatic void endTimer(void){ 192251883Speter if( enableTimer && getProcessTimesAddr){ 193251883Speter FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; 194251883Speter getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd); 195251883Speter printf("CPU Time: user %f sys %f\n", 196251883Speter timeDiff(&ftUserBegin, &ftUserEnd), 197251883Speter timeDiff(&ftKernelBegin, &ftKernelEnd)); 198251883Speter } 199251883Speter} 200251883Speter 201251883Speter#define BEGIN_TIMER beginTimer() 202251883Speter#define END_TIMER endTimer() 203251883Speter#define HAS_TIMER hasTimer() 204251883Speter 205251883Speter#else 206251883Speter#define BEGIN_TIMER 207251883Speter#define END_TIMER 208251883Speter#define HAS_TIMER 0 209251883Speter#endif 210251883Speter 211251883Speter/* 212251883Speter** Used to prevent warnings about unused parameters 213251883Speter*/ 214251883Speter#define UNUSED_PARAMETER(x) (void)(x) 215251883Speter 216251883Speter/* 217251883Speter** If the following flag is set, then command execution stops 218251883Speter** at an error if we are not interactive. 219251883Speter*/ 220251883Speterstatic int bail_on_error = 0; 221251883Speter 222251883Speter/* 223251883Speter** Threat stdin as an interactive input if the following variable 224251883Speter** is true. Otherwise, assume stdin is connected to a file or pipe. 225251883Speter*/ 226251883Speterstatic int stdin_is_interactive = 1; 227251883Speter 228251883Speter/* 229251883Speter** The following is the open SQLite database. We make a pointer 230251883Speter** to this database a static variable so that it can be accessed 231251883Speter** by the SIGINT handler to interrupt database processing. 232251883Speter*/ 233251883Speterstatic sqlite3 *db = 0; 234251883Speter 235251883Speter/* 236251883Speter** True if an interrupt (Control-C) has been received. 237251883Speter*/ 238251883Speterstatic volatile int seenInterrupt = 0; 239251883Speter 240251883Speter/* 241251883Speter** This is the name of our program. It is set in main(), used 242251883Speter** in a number of other places, mostly for error messages. 243251883Speter*/ 244251883Speterstatic char *Argv0; 245251883Speter 246251883Speter/* 247251883Speter** Prompt strings. Initialized in main. Settable with 248251883Speter** .prompt main continue 249251883Speter*/ 250251883Speterstatic char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/ 251251883Speterstatic char continuePrompt[20]; /* Continuation prompt. default: " ...> " */ 252251883Speter 253251883Speter/* 254251883Speter** Write I/O traces to the following stream. 255251883Speter*/ 256251883Speter#ifdef SQLITE_ENABLE_IOTRACE 257251883Speterstatic FILE *iotrace = 0; 258251883Speter#endif 259251883Speter 260251883Speter/* 261251883Speter** This routine works like printf in that its first argument is a 262251883Speter** format string and subsequent arguments are values to be substituted 263251883Speter** in place of % fields. The result of formatting this string 264251883Speter** is written to iotrace. 265251883Speter*/ 266251883Speter#ifdef SQLITE_ENABLE_IOTRACE 267251883Speterstatic void iotracePrintf(const char *zFormat, ...){ 268251883Speter va_list ap; 269251883Speter char *z; 270251883Speter if( iotrace==0 ) return; 271251883Speter va_start(ap, zFormat); 272251883Speter z = sqlite3_vmprintf(zFormat, ap); 273251883Speter va_end(ap); 274251883Speter fprintf(iotrace, "%s", z); 275251883Speter sqlite3_free(z); 276251883Speter} 277251883Speter#endif 278251883Speter 279251883Speter 280251883Speter/* 281251883Speter** Determines if a string is a number of not. 282251883Speter*/ 283251883Speterstatic int isNumber(const char *z, int *realnum){ 284251883Speter if( *z=='-' || *z=='+' ) z++; 285251883Speter if( !IsDigit(*z) ){ 286251883Speter return 0; 287251883Speter } 288251883Speter z++; 289251883Speter if( realnum ) *realnum = 0; 290251883Speter while( IsDigit(*z) ){ z++; } 291251883Speter if( *z=='.' ){ 292251883Speter z++; 293251883Speter if( !IsDigit(*z) ) return 0; 294251883Speter while( IsDigit(*z) ){ z++; } 295251883Speter if( realnum ) *realnum = 1; 296251883Speter } 297251883Speter if( *z=='e' || *z=='E' ){ 298251883Speter z++; 299251883Speter if( *z=='+' || *z=='-' ) z++; 300251883Speter if( !IsDigit(*z) ) return 0; 301251883Speter while( IsDigit(*z) ){ z++; } 302251883Speter if( realnum ) *realnum = 1; 303251883Speter } 304251883Speter return *z==0; 305251883Speter} 306251883Speter 307251883Speter/* 308251883Speter** A global char* and an SQL function to access its current value 309251883Speter** from within an SQL statement. This program used to use the 310251883Speter** sqlite_exec_printf() API to substitue a string into an SQL statement. 311251883Speter** The correct way to do this with sqlite3 is to use the bind API, but 312251883Speter** since the shell is built around the callback paradigm it would be a lot 313251883Speter** of work. Instead just use this hack, which is quite harmless. 314251883Speter*/ 315251883Speterstatic const char *zShellStatic = 0; 316251883Speterstatic void shellstaticFunc( 317251883Speter sqlite3_context *context, 318251883Speter int argc, 319251883Speter sqlite3_value **argv 320251883Speter){ 321251883Speter assert( 0==argc ); 322251883Speter assert( zShellStatic ); 323251883Speter UNUSED_PARAMETER(argc); 324251883Speter UNUSED_PARAMETER(argv); 325251883Speter sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC); 326251883Speter} 327251883Speter 328251883Speter 329251883Speter/* 330251883Speter** This routine reads a line of text from FILE in, stores 331251883Speter** the text in memory obtained from malloc() and returns a pointer 332251883Speter** to the text. NULL is returned at end of file, or if malloc() 333251883Speter** fails. 334251883Speter** 335251883Speter** The interface is like "readline" but no command-line editing 336251883Speter** is done. 337251883Speter*/ 338251883Speterstatic char *local_getline(char *zPrompt, FILE *in, int csvFlag){ 339251883Speter char *zLine; 340251883Speter int nLine; 341251883Speter int n; 342251883Speter int inQuote = 0; 343251883Speter 344251883Speter if( zPrompt && *zPrompt ){ 345251883Speter printf("%s",zPrompt); 346251883Speter fflush(stdout); 347251883Speter } 348251883Speter nLine = 100; 349251883Speter zLine = malloc( nLine ); 350251883Speter if( zLine==0 ) return 0; 351251883Speter n = 0; 352251883Speter while( 1 ){ 353251883Speter if( n+100>nLine ){ 354251883Speter nLine = nLine*2 + 100; 355251883Speter zLine = realloc(zLine, nLine); 356251883Speter if( zLine==0 ) return 0; 357251883Speter } 358251883Speter if( fgets(&zLine[n], nLine - n, in)==0 ){ 359251883Speter if( n==0 ){ 360251883Speter free(zLine); 361251883Speter return 0; 362251883Speter } 363251883Speter zLine[n] = 0; 364251883Speter break; 365251883Speter } 366251883Speter while( zLine[n] ){ 367251883Speter if( zLine[n]=='"' ) inQuote = !inQuote; 368251883Speter n++; 369251883Speter } 370251883Speter if( n>0 && zLine[n-1]=='\n' && (!inQuote || !csvFlag) ){ 371251883Speter n--; 372251883Speter if( n>0 && zLine[n-1]=='\r' ) n--; 373251883Speter zLine[n] = 0; 374251883Speter break; 375251883Speter } 376251883Speter } 377251883Speter zLine = realloc( zLine, n+1 ); 378251883Speter return zLine; 379251883Speter} 380251883Speter 381251883Speter/* 382251883Speter** Retrieve a single line of input text. 383251883Speter** 384251883Speter** zPrior is a string of prior text retrieved. If not the empty 385251883Speter** string, then issue a continuation prompt. 386251883Speter*/ 387251883Speterstatic char *one_input_line(const char *zPrior, FILE *in){ 388251883Speter char *zPrompt; 389251883Speter char *zResult; 390251883Speter if( in!=0 ){ 391251883Speter return local_getline(0, in, 0); 392251883Speter } 393251883Speter if( zPrior && zPrior[0] ){ 394251883Speter zPrompt = continuePrompt; 395251883Speter }else{ 396251883Speter zPrompt = mainPrompt; 397251883Speter } 398251883Speter zResult = readline(zPrompt); 399251883Speter#if defined(HAVE_READLINE) && HAVE_READLINE==1 400251883Speter if( zResult && *zResult ) add_history(zResult); 401251883Speter#endif 402251883Speter return zResult; 403251883Speter} 404251883Speter 405251883Speterstruct previous_mode_data { 406251883Speter int valid; /* Is there legit data in here? */ 407251883Speter int mode; 408251883Speter int showHeader; 409251883Speter int colWidth[100]; 410251883Speter}; 411251883Speter 412251883Speter/* 413251883Speter** An pointer to an instance of this structure is passed from 414251883Speter** the main program to the callback. This is used to communicate 415251883Speter** state and mode information. 416251883Speter*/ 417251883Speterstruct callback_data { 418251883Speter sqlite3 *db; /* The database */ 419251883Speter int echoOn; /* True to echo input commands */ 420251883Speter int statsOn; /* True to display memory stats before each finalize */ 421251883Speter int cnt; /* Number of records displayed so far */ 422251883Speter FILE *out; /* Write results here */ 423251883Speter FILE *traceOut; /* Output for sqlite3_trace() */ 424251883Speter int nErr; /* Number of errors seen */ 425251883Speter int mode; /* An output mode setting */ 426251883Speter int writableSchema; /* True if PRAGMA writable_schema=ON */ 427251883Speter int showHeader; /* True to show column names in List or Column mode */ 428251883Speter char *zDestTable; /* Name of destination table when MODE_Insert */ 429251883Speter char separator[20]; /* Separator character for MODE_List */ 430251883Speter int colWidth[100]; /* Requested width of each column when in column mode*/ 431251883Speter int actualWidth[100]; /* Actual width of each column */ 432251883Speter char nullvalue[20]; /* The text to print when a NULL comes back from 433251883Speter ** the database */ 434251883Speter struct previous_mode_data explainPrev; 435251883Speter /* Holds the mode information just before 436251883Speter ** .explain ON */ 437251883Speter char outfile[FILENAME_MAX]; /* Filename for *out */ 438251883Speter const char *zDbFilename; /* name of the database file */ 439251883Speter const char *zVfs; /* Name of VFS to use */ 440251883Speter sqlite3_stmt *pStmt; /* Current statement if any. */ 441251883Speter FILE *pLog; /* Write log output here */ 442251883Speter}; 443251883Speter 444251883Speter/* 445251883Speter** These are the allowed modes. 446251883Speter*/ 447251883Speter#define MODE_Line 0 /* One column per line. Blank line between records */ 448251883Speter#define MODE_Column 1 /* One record per line in neat columns */ 449251883Speter#define MODE_List 2 /* One record per line with a separator */ 450251883Speter#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */ 451251883Speter#define MODE_Html 4 /* Generate an XHTML table */ 452251883Speter#define MODE_Insert 5 /* Generate SQL "insert" statements */ 453251883Speter#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */ 454251883Speter#define MODE_Csv 7 /* Quote strings, numbers are plain */ 455251883Speter#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */ 456251883Speter 457251883Speterstatic const char *modeDescr[] = { 458251883Speter "line", 459251883Speter "column", 460251883Speter "list", 461251883Speter "semi", 462251883Speter "html", 463251883Speter "insert", 464251883Speter "tcl", 465251883Speter "csv", 466251883Speter "explain", 467251883Speter}; 468251883Speter 469251883Speter/* 470251883Speter** Number of elements in an array 471251883Speter*/ 472251883Speter#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) 473251883Speter 474251883Speter/* 475251883Speter** Compute a string length that is limited to what can be stored in 476251883Speter** lower 30 bits of a 32-bit signed integer. 477251883Speter*/ 478251883Speterstatic int strlen30(const char *z){ 479251883Speter const char *z2 = z; 480251883Speter while( *z2 ){ z2++; } 481251883Speter return 0x3fffffff & (int)(z2 - z); 482251883Speter} 483251883Speter 484251883Speter/* 485251883Speter** A callback for the sqlite3_log() interface. 486251883Speter*/ 487251883Speterstatic void shellLog(void *pArg, int iErrCode, const char *zMsg){ 488251883Speter struct callback_data *p = (struct callback_data*)pArg; 489251883Speter if( p->pLog==0 ) return; 490251883Speter fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg); 491251883Speter fflush(p->pLog); 492251883Speter} 493251883Speter 494251883Speter/* 495251883Speter** Output the given string as a hex-encoded blob (eg. X'1234' ) 496251883Speter*/ 497251883Speterstatic void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ 498251883Speter int i; 499251883Speter char *zBlob = (char *)pBlob; 500251883Speter fprintf(out,"X'"); 501251883Speter for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]&0xff); } 502251883Speter fprintf(out,"'"); 503251883Speter} 504251883Speter 505251883Speter/* 506251883Speter** Output the given string as a quoted string using SQL quoting conventions. 507251883Speter*/ 508251883Speterstatic void output_quoted_string(FILE *out, const char *z){ 509251883Speter int i; 510251883Speter int nSingle = 0; 511251883Speter for(i=0; z[i]; i++){ 512251883Speter if( z[i]=='\'' ) nSingle++; 513251883Speter } 514251883Speter if( nSingle==0 ){ 515251883Speter fprintf(out,"'%s'",z); 516251883Speter }else{ 517251883Speter fprintf(out,"'"); 518251883Speter while( *z ){ 519251883Speter for(i=0; z[i] && z[i]!='\''; i++){} 520251883Speter if( i==0 ){ 521251883Speter fprintf(out,"''"); 522251883Speter z++; 523251883Speter }else if( z[i]=='\'' ){ 524251883Speter fprintf(out,"%.*s''",i,z); 525251883Speter z += i+1; 526251883Speter }else{ 527251883Speter fprintf(out,"%s",z); 528251883Speter break; 529251883Speter } 530251883Speter } 531251883Speter fprintf(out,"'"); 532251883Speter } 533251883Speter} 534251883Speter 535251883Speter/* 536251883Speter** Output the given string as a quoted according to C or TCL quoting rules. 537251883Speter*/ 538251883Speterstatic void output_c_string(FILE *out, const char *z){ 539251883Speter unsigned int c; 540251883Speter fputc('"', out); 541251883Speter while( (c = *(z++))!=0 ){ 542251883Speter if( c=='\\' ){ 543251883Speter fputc(c, out); 544251883Speter fputc(c, out); 545251883Speter }else if( c=='"' ){ 546251883Speter fputc('\\', out); 547251883Speter fputc('"', out); 548251883Speter }else if( c=='\t' ){ 549251883Speter fputc('\\', out); 550251883Speter fputc('t', out); 551251883Speter }else if( c=='\n' ){ 552251883Speter fputc('\\', out); 553251883Speter fputc('n', out); 554251883Speter }else if( c=='\r' ){ 555251883Speter fputc('\\', out); 556251883Speter fputc('r', out); 557251883Speter }else if( !isprint(c) ){ 558251883Speter fprintf(out, "\\%03o", c&0xff); 559251883Speter }else{ 560251883Speter fputc(c, out); 561251883Speter } 562251883Speter } 563251883Speter fputc('"', out); 564251883Speter} 565251883Speter 566251883Speter/* 567251883Speter** Output the given string with characters that are special to 568251883Speter** HTML escaped. 569251883Speter*/ 570251883Speterstatic void output_html_string(FILE *out, const char *z){ 571251883Speter int i; 572251883Speter while( *z ){ 573251883Speter for(i=0; z[i] 574251883Speter && z[i]!='<' 575251883Speter && z[i]!='&' 576251883Speter && z[i]!='>' 577251883Speter && z[i]!='\"' 578251883Speter && z[i]!='\''; 579251883Speter i++){} 580251883Speter if( i>0 ){ 581251883Speter fprintf(out,"%.*s",i,z); 582251883Speter } 583251883Speter if( z[i]=='<' ){ 584251883Speter fprintf(out,"<"); 585251883Speter }else if( z[i]=='&' ){ 586251883Speter fprintf(out,"&"); 587251883Speter }else if( z[i]=='>' ){ 588251883Speter fprintf(out,">"); 589251883Speter }else if( z[i]=='\"' ){ 590251883Speter fprintf(out,"""); 591251883Speter }else if( z[i]=='\'' ){ 592251883Speter fprintf(out,"'"); 593251883Speter }else{ 594251883Speter break; 595251883Speter } 596251883Speter z += i + 1; 597251883Speter } 598251883Speter} 599251883Speter 600251883Speter/* 601251883Speter** If a field contains any character identified by a 1 in the following 602251883Speter** array, then the string must be quoted for CSV. 603251883Speter*/ 604251883Speterstatic const char needCsvQuote[] = { 605251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 606251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 607251883Speter 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 608251883Speter 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 609251883Speter 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 610251883Speter 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 611251883Speter 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 612251883Speter 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 613251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 614251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 615251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 616251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 617251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 618251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 619251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 620251883Speter 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 621251883Speter}; 622251883Speter 623251883Speter/* 624251883Speter** Output a single term of CSV. Actually, p->separator is used for 625251883Speter** the separator, which may or may not be a comma. p->nullvalue is 626251883Speter** the null value. Strings are quoted if necessary. 627251883Speter*/ 628251883Speterstatic void output_csv(struct callback_data *p, const char *z, int bSep){ 629251883Speter FILE *out = p->out; 630251883Speter if( z==0 ){ 631251883Speter fprintf(out,"%s",p->nullvalue); 632251883Speter }else{ 633251883Speter int i; 634251883Speter int nSep = strlen30(p->separator); 635251883Speter for(i=0; z[i]; i++){ 636251883Speter if( needCsvQuote[((unsigned char*)z)[i]] 637251883Speter || (z[i]==p->separator[0] && 638251883Speter (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){ 639251883Speter i = 0; 640251883Speter break; 641251883Speter } 642251883Speter } 643251883Speter if( i==0 ){ 644251883Speter putc('"', out); 645251883Speter for(i=0; z[i]; i++){ 646251883Speter if( z[i]=='"' ) putc('"', out); 647251883Speter putc(z[i], out); 648251883Speter } 649251883Speter putc('"', out); 650251883Speter }else{ 651251883Speter fprintf(out, "%s", z); 652251883Speter } 653251883Speter } 654251883Speter if( bSep ){ 655251883Speter fprintf(p->out, "%s", p->separator); 656251883Speter } 657251883Speter} 658251883Speter 659251883Speter#ifdef SIGINT 660251883Speter/* 661251883Speter** This routine runs when the user presses Ctrl-C 662251883Speter*/ 663251883Speterstatic void interrupt_handler(int NotUsed){ 664251883Speter UNUSED_PARAMETER(NotUsed); 665251883Speter seenInterrupt = 1; 666251883Speter if( db ) sqlite3_interrupt(db); 667251883Speter} 668251883Speter#endif 669251883Speter 670251883Speter/* 671251883Speter** This is the callback routine that the shell 672251883Speter** invokes for each row of a query result. 673251883Speter*/ 674251883Speterstatic int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){ 675251883Speter int i; 676251883Speter struct callback_data *p = (struct callback_data*)pArg; 677251883Speter 678251883Speter switch( p->mode ){ 679251883Speter case MODE_Line: { 680251883Speter int w = 5; 681251883Speter if( azArg==0 ) break; 682251883Speter for(i=0; i<nArg; i++){ 683251883Speter int len = strlen30(azCol[i] ? azCol[i] : ""); 684251883Speter if( len>w ) w = len; 685251883Speter } 686251883Speter if( p->cnt++>0 ) fprintf(p->out,"\n"); 687251883Speter for(i=0; i<nArg; i++){ 688251883Speter fprintf(p->out,"%*s = %s\n", w, azCol[i], 689251883Speter azArg[i] ? azArg[i] : p->nullvalue); 690251883Speter } 691251883Speter break; 692251883Speter } 693251883Speter case MODE_Explain: 694251883Speter case MODE_Column: { 695251883Speter if( p->cnt++==0 ){ 696251883Speter for(i=0; i<nArg; i++){ 697251883Speter int w, n; 698251883Speter if( i<ArraySize(p->colWidth) ){ 699251883Speter w = p->colWidth[i]; 700251883Speter }else{ 701251883Speter w = 0; 702251883Speter } 703251883Speter if( w==0 ){ 704251883Speter w = strlen30(azCol[i] ? azCol[i] : ""); 705251883Speter if( w<10 ) w = 10; 706251883Speter n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue); 707251883Speter if( w<n ) w = n; 708251883Speter } 709251883Speter if( i<ArraySize(p->actualWidth) ){ 710251883Speter p->actualWidth[i] = w; 711251883Speter } 712251883Speter if( p->showHeader ){ 713251883Speter if( w<0 ){ 714251883Speter fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": " "); 715251883Speter }else{ 716251883Speter fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " "); 717251883Speter } 718251883Speter } 719251883Speter } 720251883Speter if( p->showHeader ){ 721251883Speter for(i=0; i<nArg; i++){ 722251883Speter int w; 723251883Speter if( i<ArraySize(p->actualWidth) ){ 724251883Speter w = p->actualWidth[i]; 725251883Speter if( w<0 ) w = -w; 726251883Speter }else{ 727251883Speter w = 10; 728251883Speter } 729251883Speter fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------" 730251883Speter "----------------------------------------------------------", 731251883Speter i==nArg-1 ? "\n": " "); 732251883Speter } 733251883Speter } 734251883Speter } 735251883Speter if( azArg==0 ) break; 736251883Speter for(i=0; i<nArg; i++){ 737251883Speter int w; 738251883Speter if( i<ArraySize(p->actualWidth) ){ 739251883Speter w = p->actualWidth[i]; 740251883Speter }else{ 741251883Speter w = 10; 742251883Speter } 743251883Speter if( p->mode==MODE_Explain && azArg[i] && 744251883Speter strlen30(azArg[i])>w ){ 745251883Speter w = strlen30(azArg[i]); 746251883Speter } 747251883Speter if( w<0 ){ 748251883Speter fprintf(p->out,"%*.*s%s",-w,-w, 749251883Speter azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); 750251883Speter }else{ 751251883Speter fprintf(p->out,"%-*.*s%s",w,w, 752251883Speter azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); 753251883Speter } 754251883Speter } 755251883Speter break; 756251883Speter } 757251883Speter case MODE_Semi: 758251883Speter case MODE_List: { 759251883Speter if( p->cnt++==0 && p->showHeader ){ 760251883Speter for(i=0; i<nArg; i++){ 761251883Speter fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator); 762251883Speter } 763251883Speter } 764251883Speter if( azArg==0 ) break; 765251883Speter for(i=0; i<nArg; i++){ 766251883Speter char *z = azArg[i]; 767251883Speter if( z==0 ) z = p->nullvalue; 768251883Speter fprintf(p->out, "%s", z); 769251883Speter if( i<nArg-1 ){ 770251883Speter fprintf(p->out, "%s", p->separator); 771251883Speter }else if( p->mode==MODE_Semi ){ 772251883Speter fprintf(p->out, ";\n"); 773251883Speter }else{ 774251883Speter fprintf(p->out, "\n"); 775251883Speter } 776251883Speter } 777251883Speter break; 778251883Speter } 779251883Speter case MODE_Html: { 780251883Speter if( p->cnt++==0 && p->showHeader ){ 781251883Speter fprintf(p->out,"<TR>"); 782251883Speter for(i=0; i<nArg; i++){ 783251883Speter fprintf(p->out,"<TH>"); 784251883Speter output_html_string(p->out, azCol[i]); 785251883Speter fprintf(p->out,"</TH>\n"); 786251883Speter } 787251883Speter fprintf(p->out,"</TR>\n"); 788251883Speter } 789251883Speter if( azArg==0 ) break; 790251883Speter fprintf(p->out,"<TR>"); 791251883Speter for(i=0; i<nArg; i++){ 792251883Speter fprintf(p->out,"<TD>"); 793251883Speter output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue); 794251883Speter fprintf(p->out,"</TD>\n"); 795251883Speter } 796251883Speter fprintf(p->out,"</TR>\n"); 797251883Speter break; 798251883Speter } 799251883Speter case MODE_Tcl: { 800251883Speter if( p->cnt++==0 && p->showHeader ){ 801251883Speter for(i=0; i<nArg; i++){ 802251883Speter output_c_string(p->out,azCol[i] ? azCol[i] : ""); 803251883Speter if(i<nArg-1) fprintf(p->out, "%s", p->separator); 804251883Speter } 805251883Speter fprintf(p->out,"\n"); 806251883Speter } 807251883Speter if( azArg==0 ) break; 808251883Speter for(i=0; i<nArg; i++){ 809251883Speter output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue); 810251883Speter if(i<nArg-1) fprintf(p->out, "%s", p->separator); 811251883Speter } 812251883Speter fprintf(p->out,"\n"); 813251883Speter break; 814251883Speter } 815251883Speter case MODE_Csv: { 816251883Speter if( p->cnt++==0 && p->showHeader ){ 817251883Speter for(i=0; i<nArg; i++){ 818251883Speter output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1); 819251883Speter } 820251883Speter fprintf(p->out,"\n"); 821251883Speter } 822251883Speter if( azArg==0 ) break; 823251883Speter for(i=0; i<nArg; i++){ 824251883Speter output_csv(p, azArg[i], i<nArg-1); 825251883Speter } 826251883Speter fprintf(p->out,"\n"); 827251883Speter break; 828251883Speter } 829251883Speter case MODE_Insert: { 830251883Speter p->cnt++; 831251883Speter if( azArg==0 ) break; 832251883Speter fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); 833251883Speter for(i=0; i<nArg; i++){ 834251883Speter char *zSep = i>0 ? ",": ""; 835251883Speter if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ 836251883Speter fprintf(p->out,"%sNULL",zSep); 837251883Speter }else if( aiType && aiType[i]==SQLITE_TEXT ){ 838251883Speter if( zSep[0] ) fprintf(p->out,"%s",zSep); 839251883Speter output_quoted_string(p->out, azArg[i]); 840251883Speter }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){ 841251883Speter fprintf(p->out,"%s%s",zSep, azArg[i]); 842251883Speter }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ 843251883Speter const void *pBlob = sqlite3_column_blob(p->pStmt, i); 844251883Speter int nBlob = sqlite3_column_bytes(p->pStmt, i); 845251883Speter if( zSep[0] ) fprintf(p->out,"%s",zSep); 846251883Speter output_hex_blob(p->out, pBlob, nBlob); 847251883Speter }else if( isNumber(azArg[i], 0) ){ 848251883Speter fprintf(p->out,"%s%s",zSep, azArg[i]); 849251883Speter }else{ 850251883Speter if( zSep[0] ) fprintf(p->out,"%s",zSep); 851251883Speter output_quoted_string(p->out, azArg[i]); 852251883Speter } 853251883Speter } 854251883Speter fprintf(p->out,");\n"); 855251883Speter break; 856251883Speter } 857251883Speter } 858251883Speter return 0; 859251883Speter} 860251883Speter 861251883Speter/* 862251883Speter** This is the callback routine that the SQLite library 863251883Speter** invokes for each row of a query result. 864251883Speter*/ 865251883Speterstatic int callback(void *pArg, int nArg, char **azArg, char **azCol){ 866251883Speter /* since we don't have type info, call the shell_callback with a NULL value */ 867251883Speter return shell_callback(pArg, nArg, azArg, azCol, NULL); 868251883Speter} 869251883Speter 870251883Speter/* 871251883Speter** Set the destination table field of the callback_data structure to 872251883Speter** the name of the table given. Escape any quote characters in the 873251883Speter** table name. 874251883Speter*/ 875251883Speterstatic void set_table_name(struct callback_data *p, const char *zName){ 876251883Speter int i, n; 877251883Speter int needQuote; 878251883Speter char *z; 879251883Speter 880251883Speter if( p->zDestTable ){ 881251883Speter free(p->zDestTable); 882251883Speter p->zDestTable = 0; 883251883Speter } 884251883Speter if( zName==0 ) return; 885251883Speter needQuote = !isalpha((unsigned char)*zName) && *zName!='_'; 886251883Speter for(i=n=0; zName[i]; i++, n++){ 887251883Speter if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){ 888251883Speter needQuote = 1; 889251883Speter if( zName[i]=='\'' ) n++; 890251883Speter } 891251883Speter } 892251883Speter if( needQuote ) n += 2; 893251883Speter z = p->zDestTable = malloc( n+1 ); 894251883Speter if( z==0 ){ 895251883Speter fprintf(stderr,"Error: out of memory\n"); 896251883Speter exit(1); 897251883Speter } 898251883Speter n = 0; 899251883Speter if( needQuote ) z[n++] = '\''; 900251883Speter for(i=0; zName[i]; i++){ 901251883Speter z[n++] = zName[i]; 902251883Speter if( zName[i]=='\'' ) z[n++] = '\''; 903251883Speter } 904251883Speter if( needQuote ) z[n++] = '\''; 905251883Speter z[n] = 0; 906251883Speter} 907251883Speter 908251883Speter/* zIn is either a pointer to a NULL-terminated string in memory obtained 909251883Speter** from malloc(), or a NULL pointer. The string pointed to by zAppend is 910251883Speter** added to zIn, and the result returned in memory obtained from malloc(). 911251883Speter** zIn, if it was not NULL, is freed. 912251883Speter** 913251883Speter** If the third argument, quote, is not '\0', then it is used as a 914251883Speter** quote character for zAppend. 915251883Speter*/ 916251883Speterstatic char *appendText(char *zIn, char const *zAppend, char quote){ 917251883Speter int len; 918251883Speter int i; 919251883Speter int nAppend = strlen30(zAppend); 920251883Speter int nIn = (zIn?strlen30(zIn):0); 921251883Speter 922251883Speter len = nAppend+nIn+1; 923251883Speter if( quote ){ 924251883Speter len += 2; 925251883Speter for(i=0; i<nAppend; i++){ 926251883Speter if( zAppend[i]==quote ) len++; 927251883Speter } 928251883Speter } 929251883Speter 930251883Speter zIn = (char *)realloc(zIn, len); 931251883Speter if( !zIn ){ 932251883Speter return 0; 933251883Speter } 934251883Speter 935251883Speter if( quote ){ 936251883Speter char *zCsr = &zIn[nIn]; 937251883Speter *zCsr++ = quote; 938251883Speter for(i=0; i<nAppend; i++){ 939251883Speter *zCsr++ = zAppend[i]; 940251883Speter if( zAppend[i]==quote ) *zCsr++ = quote; 941251883Speter } 942251883Speter *zCsr++ = quote; 943251883Speter *zCsr++ = '\0'; 944251883Speter assert( (zCsr-zIn)==len ); 945251883Speter }else{ 946251883Speter memcpy(&zIn[nIn], zAppend, nAppend); 947251883Speter zIn[len-1] = '\0'; 948251883Speter } 949251883Speter 950251883Speter return zIn; 951251883Speter} 952251883Speter 953251883Speter 954251883Speter/* 955251883Speter** Execute a query statement that will generate SQL output. Print 956251883Speter** the result columns, comma-separated, on a line and then add a 957251883Speter** semicolon terminator to the end of that line. 958251883Speter** 959251883Speter** If the number of columns is 1 and that column contains text "--" 960251883Speter** then write the semicolon on a separate line. That way, if a 961251883Speter** "--" comment occurs at the end of the statement, the comment 962251883Speter** won't consume the semicolon terminator. 963251883Speter*/ 964251883Speterstatic int run_table_dump_query( 965251883Speter struct callback_data *p, /* Query context */ 966251883Speter const char *zSelect, /* SELECT statement to extract content */ 967251883Speter const char *zFirstRow /* Print before first row, if not NULL */ 968251883Speter){ 969251883Speter sqlite3_stmt *pSelect; 970251883Speter int rc; 971251883Speter int nResult; 972251883Speter int i; 973251883Speter const char *z; 974251883Speter rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0); 975251883Speter if( rc!=SQLITE_OK || !pSelect ){ 976251883Speter fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); 977251883Speter p->nErr++; 978251883Speter return rc; 979251883Speter } 980251883Speter rc = sqlite3_step(pSelect); 981251883Speter nResult = sqlite3_column_count(pSelect); 982251883Speter while( rc==SQLITE_ROW ){ 983251883Speter if( zFirstRow ){ 984251883Speter fprintf(p->out, "%s", zFirstRow); 985251883Speter zFirstRow = 0; 986251883Speter } 987251883Speter z = (const char*)sqlite3_column_text(pSelect, 0); 988251883Speter fprintf(p->out, "%s", z); 989251883Speter for(i=1; i<nResult; i++){ 990251883Speter fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i)); 991251883Speter } 992251883Speter if( z==0 ) z = ""; 993251883Speter while( z[0] && (z[0]!='-' || z[1]!='-') ) z++; 994251883Speter if( z[0] ){ 995251883Speter fprintf(p->out, "\n;\n"); 996251883Speter }else{ 997251883Speter fprintf(p->out, ";\n"); 998251883Speter } 999251883Speter rc = sqlite3_step(pSelect); 1000251883Speter } 1001251883Speter rc = sqlite3_finalize(pSelect); 1002251883Speter if( rc!=SQLITE_OK ){ 1003251883Speter fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); 1004251883Speter p->nErr++; 1005251883Speter } 1006251883Speter return rc; 1007251883Speter} 1008251883Speter 1009251883Speter/* 1010251883Speter** Allocate space and save off current error string. 1011251883Speter*/ 1012251883Speterstatic char *save_err_msg( 1013251883Speter sqlite3 *db /* Database to query */ 1014251883Speter){ 1015251883Speter int nErrMsg = 1+strlen30(sqlite3_errmsg(db)); 1016251883Speter char *zErrMsg = sqlite3_malloc(nErrMsg); 1017251883Speter if( zErrMsg ){ 1018251883Speter memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg); 1019251883Speter } 1020251883Speter return zErrMsg; 1021251883Speter} 1022251883Speter 1023251883Speter/* 1024251883Speter** Display memory stats. 1025251883Speter*/ 1026251883Speterstatic int display_stats( 1027251883Speter sqlite3 *db, /* Database to query */ 1028251883Speter struct callback_data *pArg, /* Pointer to struct callback_data */ 1029251883Speter int bReset /* True to reset the stats */ 1030251883Speter){ 1031251883Speter int iCur; 1032251883Speter int iHiwtr; 1033251883Speter 1034251883Speter if( pArg && pArg->out ){ 1035251883Speter 1036251883Speter iHiwtr = iCur = -1; 1037251883Speter sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset); 1038251883Speter fprintf(pArg->out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr); 1039251883Speter iHiwtr = iCur = -1; 1040251883Speter sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); 1041251883Speter fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr); 1042251883Speter/* 1043251883Speter** Not currently used by the CLI. 1044251883Speter** iHiwtr = iCur = -1; 1045251883Speter** sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); 1046251883Speter** fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); 1047251883Speter*/ 1048251883Speter iHiwtr = iCur = -1; 1049251883Speter sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); 1050251883Speter fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); 1051251883Speter/* 1052251883Speter** Not currently used by the CLI. 1053251883Speter** iHiwtr = iCur = -1; 1054251883Speter** sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); 1055251883Speter** fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); 1056251883Speter*/ 1057251883Speter iHiwtr = iCur = -1; 1058251883Speter sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset); 1059251883Speter fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); 1060251883Speter iHiwtr = iCur = -1; 1061251883Speter sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset); 1062251883Speter fprintf(pArg->out, "Largest Allocation: %d bytes\n", iHiwtr); 1063251883Speter iHiwtr = iCur = -1; 1064251883Speter sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset); 1065251883Speter fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", iHiwtr); 1066251883Speter iHiwtr = iCur = -1; 1067251883Speter sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset); 1068251883Speter fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", iHiwtr); 1069251883Speter#ifdef YYTRACKMAXSTACKDEPTH 1070251883Speter iHiwtr = iCur = -1; 1071251883Speter sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset); 1072251883Speter fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr); 1073251883Speter#endif 1074251883Speter } 1075251883Speter 1076251883Speter if( pArg && pArg->out && db ){ 1077251883Speter iHiwtr = iCur = -1; 1078251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); 1079251883Speter fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); 1080251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset); 1081251883Speter fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr); 1082251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset); 1083251883Speter fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr); 1084251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset); 1085251883Speter fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr); 1086251883Speter iHiwtr = iCur = -1; 1087251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); 1088251883Speter fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1; 1089251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); 1090251883Speter fprintf(pArg->out, "Page cache hits: %d\n", iCur); 1091251883Speter iHiwtr = iCur = -1; 1092251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); 1093251883Speter fprintf(pArg->out, "Page cache misses: %d\n", iCur); 1094251883Speter iHiwtr = iCur = -1; 1095251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1); 1096251883Speter fprintf(pArg->out, "Page cache writes: %d\n", iCur); 1097251883Speter iHiwtr = iCur = -1; 1098251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); 1099251883Speter fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur); 1100251883Speter iHiwtr = iCur = -1; 1101251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); 1102251883Speter fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); 1103251883Speter } 1104251883Speter 1105251883Speter if( pArg && pArg->out && db && pArg->pStmt ){ 1106251883Speter iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); 1107251883Speter fprintf(pArg->out, "Fullscan Steps: %d\n", iCur); 1108251883Speter iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); 1109251883Speter fprintf(pArg->out, "Sort Operations: %d\n", iCur); 1110251883Speter iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); 1111251883Speter fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); 1112251883Speter } 1113251883Speter 1114251883Speter return 0; 1115251883Speter} 1116251883Speter 1117251883Speter/* 1118251883Speter** Execute a statement or set of statements. Print 1119251883Speter** any result rows/columns depending on the current mode 1120251883Speter** set via the supplied callback. 1121251883Speter** 1122251883Speter** This is very similar to SQLite's built-in sqlite3_exec() 1123251883Speter** function except it takes a slightly different callback 1124251883Speter** and callback data argument. 1125251883Speter*/ 1126251883Speterstatic int shell_exec( 1127251883Speter sqlite3 *db, /* An open database */ 1128251883Speter const char *zSql, /* SQL to be evaluated */ 1129251883Speter int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */ 1130251883Speter /* (not the same as sqlite3_exec) */ 1131251883Speter struct callback_data *pArg, /* Pointer to struct callback_data */ 1132251883Speter char **pzErrMsg /* Error msg written here */ 1133251883Speter){ 1134251883Speter sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ 1135251883Speter int rc = SQLITE_OK; /* Return Code */ 1136251883Speter int rc2; 1137251883Speter const char *zLeftover; /* Tail of unprocessed SQL */ 1138251883Speter 1139251883Speter if( pzErrMsg ){ 1140251883Speter *pzErrMsg = NULL; 1141251883Speter } 1142251883Speter 1143251883Speter while( zSql[0] && (SQLITE_OK == rc) ){ 1144251883Speter rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); 1145251883Speter if( SQLITE_OK != rc ){ 1146251883Speter if( pzErrMsg ){ 1147251883Speter *pzErrMsg = save_err_msg(db); 1148251883Speter } 1149251883Speter }else{ 1150251883Speter if( !pStmt ){ 1151251883Speter /* this happens for a comment or white-space */ 1152251883Speter zSql = zLeftover; 1153251883Speter while( IsSpace(zSql[0]) ) zSql++; 1154251883Speter continue; 1155251883Speter } 1156251883Speter 1157251883Speter /* save off the prepared statment handle and reset row count */ 1158251883Speter if( pArg ){ 1159251883Speter pArg->pStmt = pStmt; 1160251883Speter pArg->cnt = 0; 1161251883Speter } 1162251883Speter 1163251883Speter /* echo the sql statement if echo on */ 1164251883Speter if( pArg && pArg->echoOn ){ 1165251883Speter const char *zStmtSql = sqlite3_sql(pStmt); 1166251883Speter fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); 1167251883Speter } 1168251883Speter 1169251883Speter /* Output TESTCTRL_EXPLAIN text of requested */ 1170251883Speter if( pArg && pArg->mode==MODE_Explain ){ 1171251883Speter const char *zExplain = 0; 1172251883Speter sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain); 1173251883Speter if( zExplain && zExplain[0] ){ 1174251883Speter fprintf(pArg->out, "%s", zExplain); 1175251883Speter } 1176251883Speter } 1177251883Speter 1178251883Speter /* perform the first step. this will tell us if we 1179251883Speter ** have a result set or not and how wide it is. 1180251883Speter */ 1181251883Speter rc = sqlite3_step(pStmt); 1182251883Speter /* if we have a result set... */ 1183251883Speter if( SQLITE_ROW == rc ){ 1184251883Speter /* if we have a callback... */ 1185251883Speter if( xCallback ){ 1186251883Speter /* allocate space for col name ptr, value ptr, and type */ 1187251883Speter int nCol = sqlite3_column_count(pStmt); 1188251883Speter void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1); 1189251883Speter if( !pData ){ 1190251883Speter rc = SQLITE_NOMEM; 1191251883Speter }else{ 1192251883Speter char **azCols = (char **)pData; /* Names of result columns */ 1193251883Speter char **azVals = &azCols[nCol]; /* Results */ 1194251883Speter int *aiTypes = (int *)&azVals[nCol]; /* Result types */ 1195251883Speter int i; 1196251883Speter assert(sizeof(int) <= sizeof(char *)); 1197251883Speter /* save off ptrs to column names */ 1198251883Speter for(i=0; i<nCol; i++){ 1199251883Speter azCols[i] = (char *)sqlite3_column_name(pStmt, i); 1200251883Speter } 1201251883Speter do{ 1202251883Speter /* extract the data and data types */ 1203251883Speter for(i=0; i<nCol; i++){ 1204251883Speter azVals[i] = (char *)sqlite3_column_text(pStmt, i); 1205251883Speter aiTypes[i] = sqlite3_column_type(pStmt, i); 1206251883Speter if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ 1207251883Speter rc = SQLITE_NOMEM; 1208251883Speter break; /* from for */ 1209251883Speter } 1210251883Speter } /* end for */ 1211251883Speter 1212251883Speter /* if data and types extracted successfully... */ 1213251883Speter if( SQLITE_ROW == rc ){ 1214251883Speter /* call the supplied callback with the result row data */ 1215251883Speter if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){ 1216251883Speter rc = SQLITE_ABORT; 1217251883Speter }else{ 1218251883Speter rc = sqlite3_step(pStmt); 1219251883Speter } 1220251883Speter } 1221251883Speter } while( SQLITE_ROW == rc ); 1222251883Speter sqlite3_free(pData); 1223251883Speter } 1224251883Speter }else{ 1225251883Speter do{ 1226251883Speter rc = sqlite3_step(pStmt); 1227251883Speter } while( rc == SQLITE_ROW ); 1228251883Speter } 1229251883Speter } 1230251883Speter 1231251883Speter /* print usage stats if stats on */ 1232251883Speter if( pArg && pArg->statsOn ){ 1233251883Speter display_stats(db, pArg, 0); 1234251883Speter } 1235251883Speter 1236251883Speter /* Finalize the statement just executed. If this fails, save a 1237251883Speter ** copy of the error message. Otherwise, set zSql to point to the 1238251883Speter ** next statement to execute. */ 1239251883Speter rc2 = sqlite3_finalize(pStmt); 1240251883Speter if( rc!=SQLITE_NOMEM ) rc = rc2; 1241251883Speter if( rc==SQLITE_OK ){ 1242251883Speter zSql = zLeftover; 1243251883Speter while( IsSpace(zSql[0]) ) zSql++; 1244251883Speter }else if( pzErrMsg ){ 1245251883Speter *pzErrMsg = save_err_msg(db); 1246251883Speter } 1247251883Speter 1248251883Speter /* clear saved stmt handle */ 1249251883Speter if( pArg ){ 1250251883Speter pArg->pStmt = NULL; 1251251883Speter } 1252251883Speter } 1253251883Speter } /* end while */ 1254251883Speter 1255251883Speter return rc; 1256251883Speter} 1257251883Speter 1258251883Speter 1259251883Speter/* 1260251883Speter** This is a different callback routine used for dumping the database. 1261251883Speter** Each row received by this callback consists of a table name, 1262251883Speter** the table type ("index" or "table") and SQL to create the table. 1263251883Speter** This routine should print text sufficient to recreate the table. 1264251883Speter*/ 1265251883Speterstatic int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ 1266251883Speter int rc; 1267251883Speter const char *zTable; 1268251883Speter const char *zType; 1269251883Speter const char *zSql; 1270251883Speter const char *zPrepStmt = 0; 1271251883Speter struct callback_data *p = (struct callback_data *)pArg; 1272251883Speter 1273251883Speter UNUSED_PARAMETER(azCol); 1274251883Speter if( nArg!=3 ) return 1; 1275251883Speter zTable = azArg[0]; 1276251883Speter zType = azArg[1]; 1277251883Speter zSql = azArg[2]; 1278251883Speter 1279251883Speter if( strcmp(zTable, "sqlite_sequence")==0 ){ 1280251883Speter zPrepStmt = "DELETE FROM sqlite_sequence;\n"; 1281251883Speter }else if( strcmp(zTable, "sqlite_stat1")==0 ){ 1282251883Speter fprintf(p->out, "ANALYZE sqlite_master;\n"); 1283251883Speter }else if( strncmp(zTable, "sqlite_", 7)==0 ){ 1284251883Speter return 0; 1285251883Speter }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ 1286251883Speter char *zIns; 1287251883Speter if( !p->writableSchema ){ 1288251883Speter fprintf(p->out, "PRAGMA writable_schema=ON;\n"); 1289251883Speter p->writableSchema = 1; 1290251883Speter } 1291251883Speter zIns = sqlite3_mprintf( 1292251883Speter "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" 1293251883Speter "VALUES('table','%q','%q',0,'%q');", 1294251883Speter zTable, zTable, zSql); 1295251883Speter fprintf(p->out, "%s\n", zIns); 1296251883Speter sqlite3_free(zIns); 1297251883Speter return 0; 1298251883Speter }else{ 1299251883Speter fprintf(p->out, "%s;\n", zSql); 1300251883Speter } 1301251883Speter 1302251883Speter if( strcmp(zType, "table")==0 ){ 1303251883Speter sqlite3_stmt *pTableInfo = 0; 1304251883Speter char *zSelect = 0; 1305251883Speter char *zTableInfo = 0; 1306251883Speter char *zTmp = 0; 1307251883Speter int nRow = 0; 1308251883Speter 1309251883Speter zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0); 1310251883Speter zTableInfo = appendText(zTableInfo, zTable, '"'); 1311251883Speter zTableInfo = appendText(zTableInfo, ");", 0); 1312251883Speter 1313251883Speter rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0); 1314251883Speter free(zTableInfo); 1315251883Speter if( rc!=SQLITE_OK || !pTableInfo ){ 1316251883Speter return 1; 1317251883Speter } 1318251883Speter 1319251883Speter zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0); 1320251883Speter /* Always quote the table name, even if it appears to be pure ascii, 1321251883Speter ** in case it is a keyword. Ex: INSERT INTO "table" ... */ 1322251883Speter zTmp = appendText(zTmp, zTable, '"'); 1323251883Speter if( zTmp ){ 1324251883Speter zSelect = appendText(zSelect, zTmp, '\''); 1325251883Speter free(zTmp); 1326251883Speter } 1327251883Speter zSelect = appendText(zSelect, " || ' VALUES(' || ", 0); 1328251883Speter rc = sqlite3_step(pTableInfo); 1329251883Speter while( rc==SQLITE_ROW ){ 1330251883Speter const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1); 1331251883Speter zSelect = appendText(zSelect, "quote(", 0); 1332251883Speter zSelect = appendText(zSelect, zText, '"'); 1333251883Speter rc = sqlite3_step(pTableInfo); 1334251883Speter if( rc==SQLITE_ROW ){ 1335251883Speter zSelect = appendText(zSelect, "), ", 0); 1336251883Speter }else{ 1337251883Speter zSelect = appendText(zSelect, ") ", 0); 1338251883Speter } 1339251883Speter nRow++; 1340251883Speter } 1341251883Speter rc = sqlite3_finalize(pTableInfo); 1342251883Speter if( rc!=SQLITE_OK || nRow==0 ){ 1343251883Speter free(zSelect); 1344251883Speter return 1; 1345251883Speter } 1346251883Speter zSelect = appendText(zSelect, "|| ')' FROM ", 0); 1347251883Speter zSelect = appendText(zSelect, zTable, '"'); 1348251883Speter 1349251883Speter rc = run_table_dump_query(p, zSelect, zPrepStmt); 1350251883Speter if( rc==SQLITE_CORRUPT ){ 1351251883Speter zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); 1352251883Speter run_table_dump_query(p, zSelect, 0); 1353251883Speter } 1354251883Speter free(zSelect); 1355251883Speter } 1356251883Speter return 0; 1357251883Speter} 1358251883Speter 1359251883Speter/* 1360251883Speter** Run zQuery. Use dump_callback() as the callback routine so that 1361251883Speter** the contents of the query are output as SQL statements. 1362251883Speter** 1363251883Speter** If we get a SQLITE_CORRUPT error, rerun the query after appending 1364251883Speter** "ORDER BY rowid DESC" to the end. 1365251883Speter*/ 1366251883Speterstatic int run_schema_dump_query( 1367251883Speter struct callback_data *p, 1368251883Speter const char *zQuery 1369251883Speter){ 1370251883Speter int rc; 1371251883Speter char *zErr = 0; 1372251883Speter rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); 1373251883Speter if( rc==SQLITE_CORRUPT ){ 1374251883Speter char *zQ2; 1375251883Speter int len = strlen30(zQuery); 1376251883Speter fprintf(p->out, "/****** CORRUPTION ERROR *******/\n"); 1377251883Speter if( zErr ){ 1378251883Speter fprintf(p->out, "/****** %s ******/\n", zErr); 1379251883Speter sqlite3_free(zErr); 1380251883Speter zErr = 0; 1381251883Speter } 1382251883Speter zQ2 = malloc( len+100 ); 1383251883Speter if( zQ2==0 ) return rc; 1384251883Speter sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery); 1385251883Speter rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); 1386251883Speter if( rc ){ 1387251883Speter fprintf(p->out, "/****** ERROR: %s ******/\n", zErr); 1388251883Speter }else{ 1389251883Speter rc = SQLITE_CORRUPT; 1390251883Speter } 1391251883Speter sqlite3_free(zErr); 1392251883Speter free(zQ2); 1393251883Speter } 1394251883Speter return rc; 1395251883Speter} 1396251883Speter 1397251883Speter/* 1398251883Speter** Text of a help message 1399251883Speter*/ 1400251883Speterstatic char zHelp[] = 1401251883Speter ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" 1402251883Speter ".bail ON|OFF Stop after hitting an error. Default OFF\n" 1403251883Speter ".databases List names and files of attached databases\n" 1404251883Speter ".dump ?TABLE? ... Dump the database in an SQL text format\n" 1405251883Speter " If TABLE specified, only dump tables matching\n" 1406251883Speter " LIKE pattern TABLE.\n" 1407251883Speter ".echo ON|OFF Turn command echo on or off\n" 1408251883Speter ".exit Exit this program\n" 1409251883Speter ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" 1410251883Speter " With no args, it turns EXPLAIN on.\n" 1411251883Speter ".header(s) ON|OFF Turn display of headers on or off\n" 1412251883Speter ".help Show this message\n" 1413251883Speter ".import FILE TABLE Import data from FILE into TABLE\n" 1414251883Speter ".indices ?TABLE? Show names of all indices\n" 1415251883Speter " If TABLE specified, only show indices for tables\n" 1416251883Speter " matching LIKE pattern TABLE.\n" 1417251883Speter#ifdef SQLITE_ENABLE_IOTRACE 1418251883Speter ".iotrace FILE Enable I/O diagnostic logging to FILE\n" 1419251883Speter#endif 1420251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION 1421251883Speter ".load FILE ?ENTRY? Load an extension library\n" 1422251883Speter#endif 1423251883Speter ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n" 1424251883Speter ".mode MODE ?TABLE? Set output mode where MODE is one of:\n" 1425251883Speter " csv Comma-separated values\n" 1426251883Speter " column Left-aligned columns. (See .width)\n" 1427251883Speter " html HTML <table> code\n" 1428251883Speter " insert SQL insert statements for TABLE\n" 1429251883Speter " line One value per line\n" 1430251883Speter " list Values delimited by .separator string\n" 1431251883Speter " tabs Tab-separated values\n" 1432251883Speter " tcl TCL list elements\n" 1433251883Speter ".nullvalue STRING Use STRING in place of NULL values\n" 1434251883Speter ".output FILENAME Send output to FILENAME\n" 1435251883Speter ".output stdout Send output to the screen\n" 1436251883Speter ".print STRING... Print literal STRING\n" 1437251883Speter ".prompt MAIN CONTINUE Replace the standard prompts\n" 1438251883Speter ".quit Exit this program\n" 1439251883Speter ".read FILENAME Execute SQL in FILENAME\n" 1440251883Speter ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" 1441251883Speter ".schema ?TABLE? Show the CREATE statements\n" 1442251883Speter " If TABLE specified, only show tables matching\n" 1443251883Speter " LIKE pattern TABLE.\n" 1444251883Speter ".separator STRING Change separator used by output mode and .import\n" 1445251883Speter ".show Show the current values for various settings\n" 1446251883Speter ".stats ON|OFF Turn stats on or off\n" 1447251883Speter ".tables ?TABLE? List names of tables\n" 1448251883Speter " If TABLE specified, only list tables matching\n" 1449251883Speter " LIKE pattern TABLE.\n" 1450251883Speter ".timeout MS Try opening locked tables for MS milliseconds\n" 1451251883Speter ".trace FILE|off Output each SQL statement as it is run\n" 1452251883Speter ".vfsname ?AUX? Print the name of the VFS stack\n" 1453251883Speter ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n" 1454251883Speter; 1455251883Speter 1456251883Speterstatic char zTimerHelp[] = 1457251883Speter ".timer ON|OFF Turn the CPU timer measurement on or off\n" 1458251883Speter; 1459251883Speter 1460251883Speter/* Forward reference */ 1461251883Speterstatic int process_input(struct callback_data *p, FILE *in); 1462251883Speter 1463251883Speter/* 1464251883Speter** Make sure the database is open. If it is not, then open it. If 1465251883Speter** the database fails to open, print an error message and exit. 1466251883Speter*/ 1467251883Speterstatic void open_db(struct callback_data *p){ 1468251883Speter if( p->db==0 ){ 1469251883Speter sqlite3_initialize(); 1470251883Speter sqlite3_open(p->zDbFilename, &p->db); 1471251883Speter db = p->db; 1472251883Speter if( db && sqlite3_errcode(db)==SQLITE_OK ){ 1473251883Speter sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0, 1474251883Speter shellstaticFunc, 0, 0); 1475251883Speter } 1476251883Speter if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){ 1477251883Speter fprintf(stderr,"Error: unable to open database \"%s\": %s\n", 1478251883Speter p->zDbFilename, sqlite3_errmsg(db)); 1479251883Speter exit(1); 1480251883Speter } 1481251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION 1482251883Speter sqlite3_enable_load_extension(p->db, 1); 1483251883Speter#endif 1484251883Speter } 1485251883Speter} 1486251883Speter 1487251883Speter/* 1488251883Speter** Do C-language style dequoting. 1489251883Speter** 1490251883Speter** \t -> tab 1491251883Speter** \n -> newline 1492251883Speter** \r -> carriage return 1493251883Speter** \NNN -> ascii character NNN in octal 1494251883Speter** \\ -> backslash 1495251883Speter*/ 1496251883Speterstatic void resolve_backslashes(char *z){ 1497251883Speter int i, j; 1498251883Speter char c; 1499251883Speter for(i=j=0; (c = z[i])!=0; i++, j++){ 1500251883Speter if( c=='\\' ){ 1501251883Speter c = z[++i]; 1502251883Speter if( c=='n' ){ 1503251883Speter c = '\n'; 1504251883Speter }else if( c=='t' ){ 1505251883Speter c = '\t'; 1506251883Speter }else if( c=='r' ){ 1507251883Speter c = '\r'; 1508251883Speter }else if( c>='0' && c<='7' ){ 1509251883Speter c -= '0'; 1510251883Speter if( z[i+1]>='0' && z[i+1]<='7' ){ 1511251883Speter i++; 1512251883Speter c = (c<<3) + z[i] - '0'; 1513251883Speter if( z[i+1]>='0' && z[i+1]<='7' ){ 1514251883Speter i++; 1515251883Speter c = (c<<3) + z[i] - '0'; 1516251883Speter } 1517251883Speter } 1518251883Speter } 1519251883Speter } 1520251883Speter z[j] = c; 1521251883Speter } 1522251883Speter z[j] = 0; 1523251883Speter} 1524251883Speter 1525251883Speter/* 1526251883Speter** Interpret zArg as a boolean value. Return either 0 or 1. 1527251883Speter*/ 1528251883Speterstatic int booleanValue(char *zArg){ 1529251883Speter int i; 1530251883Speter for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} 1531251883Speter if( i>0 && zArg[i]==0 ) return atoi(zArg); 1532251883Speter if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ 1533251883Speter return 1; 1534251883Speter } 1535251883Speter if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ 1536251883Speter return 0; 1537251883Speter } 1538251883Speter fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", 1539251883Speter zArg); 1540251883Speter return 0; 1541251883Speter} 1542251883Speter 1543251883Speter/* 1544251883Speter** Interpret zArg as an integer value, possibly with suffixes. 1545251883Speter*/ 1546251883Speterstatic sqlite3_int64 integerValue(const char *zArg){ 1547251883Speter sqlite3_int64 v = 0; 1548251883Speter static const struct { char *zSuffix; int iMult; } aMult[] = { 1549251883Speter { "KiB", 1024 }, 1550251883Speter { "MiB", 1024*1024 }, 1551251883Speter { "GiB", 1024*1024*1024 }, 1552251883Speter { "KB", 1000 }, 1553251883Speter { "MB", 1000000 }, 1554251883Speter { "GB", 1000000000 }, 1555251883Speter { "K", 1000 }, 1556251883Speter { "M", 1000000 }, 1557251883Speter { "G", 1000000000 }, 1558251883Speter }; 1559251883Speter int i; 1560251883Speter int isNeg = 0; 1561251883Speter if( zArg[0]=='-' ){ 1562251883Speter isNeg = 1; 1563251883Speter zArg++; 1564251883Speter }else if( zArg[0]=='+' ){ 1565251883Speter zArg++; 1566251883Speter } 1567251883Speter while( isdigit(zArg[0]) ){ 1568251883Speter v = v*10 + zArg[0] - '0'; 1569251883Speter zArg++; 1570251883Speter } 1571251883Speter for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){ 1572251883Speter if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ 1573251883Speter v *= aMult[i].iMult; 1574251883Speter break; 1575251883Speter } 1576251883Speter } 1577251883Speter return isNeg? -v : v; 1578251883Speter} 1579251883Speter 1580251883Speter/* 1581251883Speter** Close an output file, assuming it is not stderr or stdout 1582251883Speter*/ 1583251883Speterstatic void output_file_close(FILE *f){ 1584251883Speter if( f && f!=stdout && f!=stderr ) fclose(f); 1585251883Speter} 1586251883Speter 1587251883Speter/* 1588251883Speter** Try to open an output file. The names "stdout" and "stderr" are 1589251883Speter** recognized and do the right thing. NULL is returned if the output 1590251883Speter** filename is "off". 1591251883Speter*/ 1592251883Speterstatic FILE *output_file_open(const char *zFile){ 1593251883Speter FILE *f; 1594251883Speter if( strcmp(zFile,"stdout")==0 ){ 1595251883Speter f = stdout; 1596251883Speter }else if( strcmp(zFile, "stderr")==0 ){ 1597251883Speter f = stderr; 1598251883Speter }else if( strcmp(zFile, "off")==0 ){ 1599251883Speter f = 0; 1600251883Speter }else{ 1601251883Speter f = fopen(zFile, "wb"); 1602251883Speter if( f==0 ){ 1603251883Speter fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); 1604251883Speter } 1605251883Speter } 1606251883Speter return f; 1607251883Speter} 1608251883Speter 1609251883Speter/* 1610251883Speter** A routine for handling output from sqlite3_trace(). 1611251883Speter*/ 1612251883Speterstatic void sql_trace_callback(void *pArg, const char *z){ 1613251883Speter FILE *f = (FILE*)pArg; 1614251883Speter if( f ) fprintf(f, "%s\n", z); 1615251883Speter} 1616251883Speter 1617251883Speter/* 1618251883Speter** A no-op routine that runs with the ".breakpoint" doc-command. This is 1619251883Speter** a useful spot to set a debugger breakpoint. 1620251883Speter*/ 1621251883Speterstatic void test_breakpoint(void){ 1622251883Speter static int nCall = 0; 1623251883Speter nCall++; 1624251883Speter} 1625251883Speter 1626251883Speter/* 1627251883Speter** If an input line begins with "." then invoke this routine to 1628251883Speter** process that line. 1629251883Speter** 1630251883Speter** Return 1 on error, 2 to exit, and 0 otherwise. 1631251883Speter*/ 1632251883Speterstatic int do_meta_command(char *zLine, struct callback_data *p){ 1633251883Speter int i = 1; 1634251883Speter int nArg = 0; 1635251883Speter int n, c; 1636251883Speter int rc = 0; 1637251883Speter char *azArg[50]; 1638251883Speter 1639251883Speter /* Parse the input line into tokens. 1640251883Speter */ 1641251883Speter while( zLine[i] && nArg<ArraySize(azArg) ){ 1642251883Speter while( IsSpace(zLine[i]) ){ i++; } 1643251883Speter if( zLine[i]==0 ) break; 1644251883Speter if( zLine[i]=='\'' || zLine[i]=='"' ){ 1645251883Speter int delim = zLine[i++]; 1646251883Speter azArg[nArg++] = &zLine[i]; 1647251883Speter while( zLine[i] && zLine[i]!=delim ){ i++; } 1648251883Speter if( zLine[i]==delim ){ 1649251883Speter zLine[i++] = 0; 1650251883Speter } 1651251883Speter if( delim=='"' ) resolve_backslashes(azArg[nArg-1]); 1652251883Speter }else{ 1653251883Speter azArg[nArg++] = &zLine[i]; 1654251883Speter while( zLine[i] && !IsSpace(zLine[i]) ){ i++; } 1655251883Speter if( zLine[i] ) zLine[i++] = 0; 1656251883Speter resolve_backslashes(azArg[nArg-1]); 1657251883Speter } 1658251883Speter } 1659251883Speter 1660251883Speter /* Process the input line. 1661251883Speter */ 1662251883Speter if( nArg==0 ) return 0; /* no tokens, no error */ 1663251883Speter n = strlen30(azArg[0]); 1664251883Speter c = azArg[0][0]; 1665251883Speter if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){ 1666251883Speter const char *zDestFile = 0; 1667251883Speter const char *zDb = 0; 1668251883Speter const char *zKey = 0; 1669251883Speter sqlite3 *pDest; 1670251883Speter sqlite3_backup *pBackup; 1671251883Speter int j; 1672251883Speter for(j=1; j<nArg; j++){ 1673251883Speter const char *z = azArg[j]; 1674251883Speter if( z[0]=='-' ){ 1675251883Speter while( z[0]=='-' ) z++; 1676251883Speter if( strcmp(z,"key")==0 && j<nArg-1 ){ 1677251883Speter zKey = azArg[++j]; 1678251883Speter }else 1679251883Speter { 1680251883Speter fprintf(stderr, "unknown option: %s\n", azArg[j]); 1681251883Speter return 1; 1682251883Speter } 1683251883Speter }else if( zDestFile==0 ){ 1684251883Speter zDestFile = azArg[j]; 1685251883Speter }else if( zDb==0 ){ 1686251883Speter zDb = zDestFile; 1687251883Speter zDestFile = azArg[j]; 1688251883Speter }else{ 1689251883Speter fprintf(stderr, "too many arguments to .backup\n"); 1690251883Speter return 1; 1691251883Speter } 1692251883Speter } 1693251883Speter if( zDestFile==0 ){ 1694251883Speter fprintf(stderr, "missing FILENAME argument on .backup\n"); 1695251883Speter return 1; 1696251883Speter } 1697251883Speter if( zDb==0 ) zDb = "main"; 1698251883Speter rc = sqlite3_open(zDestFile, &pDest); 1699251883Speter if( rc!=SQLITE_OK ){ 1700251883Speter fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile); 1701251883Speter sqlite3_close(pDest); 1702251883Speter return 1; 1703251883Speter } 1704251883Speter#ifdef SQLITE_HAS_CODEC 1705251883Speter sqlite3_key(pDest, zKey, (int)strlen(zKey)); 1706251883Speter#else 1707251883Speter (void)zKey; 1708251883Speter#endif 1709251883Speter open_db(p); 1710251883Speter pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); 1711251883Speter if( pBackup==0 ){ 1712251883Speter fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); 1713251883Speter sqlite3_close(pDest); 1714251883Speter return 1; 1715251883Speter } 1716251883Speter while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} 1717251883Speter sqlite3_backup_finish(pBackup); 1718251883Speter if( rc==SQLITE_DONE ){ 1719251883Speter rc = 0; 1720251883Speter }else{ 1721251883Speter fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); 1722251883Speter rc = 1; 1723251883Speter } 1724251883Speter sqlite3_close(pDest); 1725251883Speter }else 1726251883Speter 1727251883Speter if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){ 1728251883Speter bail_on_error = booleanValue(azArg[1]); 1729251883Speter }else 1730251883Speter 1731251883Speter /* The undocumented ".breakpoint" command causes a call to the no-op 1732251883Speter ** routine named test_breakpoint(). 1733251883Speter */ 1734251883Speter if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ 1735251883Speter test_breakpoint(); 1736251883Speter }else 1737251883Speter 1738251883Speter if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){ 1739251883Speter struct callback_data data; 1740251883Speter char *zErrMsg = 0; 1741251883Speter open_db(p); 1742251883Speter memcpy(&data, p, sizeof(data)); 1743251883Speter data.showHeader = 1; 1744251883Speter data.mode = MODE_Column; 1745251883Speter data.colWidth[0] = 3; 1746251883Speter data.colWidth[1] = 15; 1747251883Speter data.colWidth[2] = 58; 1748251883Speter data.cnt = 0; 1749251883Speter sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg); 1750251883Speter if( zErrMsg ){ 1751251883Speter fprintf(stderr,"Error: %s\n", zErrMsg); 1752251883Speter sqlite3_free(zErrMsg); 1753251883Speter rc = 1; 1754251883Speter } 1755251883Speter }else 1756251883Speter 1757251883Speter if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ 1758251883Speter open_db(p); 1759251883Speter /* When playing back a "dump", the content might appear in an order 1760251883Speter ** which causes immediate foreign key constraints to be violated. 1761251883Speter ** So disable foreign-key constraint enforcement to prevent problems. */ 1762251883Speter fprintf(p->out, "PRAGMA foreign_keys=OFF;\n"); 1763251883Speter fprintf(p->out, "BEGIN TRANSACTION;\n"); 1764251883Speter p->writableSchema = 0; 1765251883Speter sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); 1766251883Speter p->nErr = 0; 1767251883Speter if( nArg==1 ){ 1768251883Speter run_schema_dump_query(p, 1769251883Speter "SELECT name, type, sql FROM sqlite_master " 1770251883Speter "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'" 1771251883Speter ); 1772251883Speter run_schema_dump_query(p, 1773251883Speter "SELECT name, type, sql FROM sqlite_master " 1774251883Speter "WHERE name=='sqlite_sequence'" 1775251883Speter ); 1776251883Speter run_table_dump_query(p, 1777251883Speter "SELECT sql FROM sqlite_master " 1778251883Speter "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 1779251883Speter ); 1780251883Speter }else{ 1781251883Speter int i; 1782251883Speter for(i=1; i<nArg; i++){ 1783251883Speter zShellStatic = azArg[i]; 1784251883Speter run_schema_dump_query(p, 1785251883Speter "SELECT name, type, sql FROM sqlite_master " 1786251883Speter "WHERE tbl_name LIKE shellstatic() AND type=='table'" 1787251883Speter " AND sql NOT NULL"); 1788251883Speter run_table_dump_query(p, 1789251883Speter "SELECT sql FROM sqlite_master " 1790251883Speter "WHERE sql NOT NULL" 1791251883Speter " AND type IN ('index','trigger','view')" 1792251883Speter " AND tbl_name LIKE shellstatic()", 0 1793251883Speter ); 1794251883Speter zShellStatic = 0; 1795251883Speter } 1796251883Speter } 1797251883Speter if( p->writableSchema ){ 1798251883Speter fprintf(p->out, "PRAGMA writable_schema=OFF;\n"); 1799251883Speter p->writableSchema = 0; 1800251883Speter } 1801251883Speter sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); 1802251883Speter sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); 1803251883Speter fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); 1804251883Speter }else 1805251883Speter 1806251883Speter if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ 1807251883Speter p->echoOn = booleanValue(azArg[1]); 1808251883Speter }else 1809251883Speter 1810251883Speter if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ 1811251883Speter if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc); 1812251883Speter rc = 2; 1813251883Speter }else 1814251883Speter 1815251883Speter if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){ 1816251883Speter int val = nArg>=2 ? booleanValue(azArg[1]) : 1; 1817251883Speter if(val == 1) { 1818251883Speter if(!p->explainPrev.valid) { 1819251883Speter p->explainPrev.valid = 1; 1820251883Speter p->explainPrev.mode = p->mode; 1821251883Speter p->explainPrev.showHeader = p->showHeader; 1822251883Speter memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth)); 1823251883Speter } 1824251883Speter /* We could put this code under the !p->explainValid 1825251883Speter ** condition so that it does not execute if we are already in 1826251883Speter ** explain mode. However, always executing it allows us an easy 1827251883Speter ** was to reset to explain mode in case the user previously 1828251883Speter ** did an .explain followed by a .width, .mode or .header 1829251883Speter ** command. 1830251883Speter */ 1831251883Speter p->mode = MODE_Explain; 1832251883Speter p->showHeader = 1; 1833251883Speter memset(p->colWidth,0,ArraySize(p->colWidth)); 1834251883Speter p->colWidth[0] = 4; /* addr */ 1835251883Speter p->colWidth[1] = 13; /* opcode */ 1836251883Speter p->colWidth[2] = 4; /* P1 */ 1837251883Speter p->colWidth[3] = 4; /* P2 */ 1838251883Speter p->colWidth[4] = 4; /* P3 */ 1839251883Speter p->colWidth[5] = 13; /* P4 */ 1840251883Speter p->colWidth[6] = 2; /* P5 */ 1841251883Speter p->colWidth[7] = 13; /* Comment */ 1842251883Speter }else if (p->explainPrev.valid) { 1843251883Speter p->explainPrev.valid = 0; 1844251883Speter p->mode = p->explainPrev.mode; 1845251883Speter p->showHeader = p->explainPrev.showHeader; 1846251883Speter memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth)); 1847251883Speter } 1848251883Speter }else 1849251883Speter 1850251883Speter if( c=='h' && (strncmp(azArg[0], "header", n)==0 || 1851251883Speter strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){ 1852251883Speter p->showHeader = booleanValue(azArg[1]); 1853251883Speter }else 1854251883Speter 1855251883Speter if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ 1856251883Speter fprintf(stderr,"%s",zHelp); 1857251883Speter if( HAS_TIMER ){ 1858251883Speter fprintf(stderr,"%s",zTimerHelp); 1859251883Speter } 1860251883Speter }else 1861251883Speter 1862251883Speter if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){ 1863251883Speter char *zTable = azArg[2]; /* Insert data into this table */ 1864251883Speter char *zFile = azArg[1]; /* The file from which to extract data */ 1865251883Speter sqlite3_stmt *pStmt = NULL; /* A statement */ 1866251883Speter int nCol; /* Number of columns in the table */ 1867251883Speter int nByte; /* Number of bytes in an SQL string */ 1868251883Speter int i, j; /* Loop counters */ 1869251883Speter int nSep; /* Number of bytes in p->separator[] */ 1870251883Speter char *zSql; /* An SQL statement */ 1871251883Speter char *zLine; /* A single line of input from the file */ 1872251883Speter char **azCol; /* zLine[] broken up into columns */ 1873251883Speter char *zCommit; /* How to commit changes */ 1874251883Speter FILE *in; /* The input file */ 1875251883Speter int lineno = 0; /* Line number of input file */ 1876251883Speter 1877251883Speter open_db(p); 1878251883Speter nSep = strlen30(p->separator); 1879251883Speter if( nSep==0 ){ 1880251883Speter fprintf(stderr, "Error: non-null separator required for import\n"); 1881251883Speter return 1; 1882251883Speter } 1883251883Speter zSql = sqlite3_mprintf("SELECT * FROM %s", zTable); 1884251883Speter if( zSql==0 ){ 1885251883Speter fprintf(stderr, "Error: out of memory\n"); 1886251883Speter return 1; 1887251883Speter } 1888251883Speter nByte = strlen30(zSql); 1889251883Speter rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); 1890251883Speter sqlite3_free(zSql); 1891251883Speter if( rc ){ 1892251883Speter if (pStmt) sqlite3_finalize(pStmt); 1893251883Speter fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); 1894251883Speter return 1; 1895251883Speter } 1896251883Speter nCol = sqlite3_column_count(pStmt); 1897251883Speter sqlite3_finalize(pStmt); 1898251883Speter pStmt = 0; 1899251883Speter if( nCol==0 ) return 0; /* no columns, no error */ 1900251883Speter zSql = malloc( nByte + 20 + nCol*2 ); 1901251883Speter if( zSql==0 ){ 1902251883Speter fprintf(stderr, "Error: out of memory\n"); 1903251883Speter return 1; 1904251883Speter } 1905251883Speter sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zTable); 1906251883Speter j = strlen30(zSql); 1907251883Speter for(i=1; i<nCol; i++){ 1908251883Speter zSql[j++] = ','; 1909251883Speter zSql[j++] = '?'; 1910251883Speter } 1911251883Speter zSql[j++] = ')'; 1912251883Speter zSql[j] = 0; 1913251883Speter rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); 1914251883Speter free(zSql); 1915251883Speter if( rc ){ 1916251883Speter fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); 1917251883Speter if (pStmt) sqlite3_finalize(pStmt); 1918251883Speter return 1; 1919251883Speter } 1920251883Speter in = fopen(zFile, "rb"); 1921251883Speter if( in==0 ){ 1922251883Speter fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); 1923251883Speter sqlite3_finalize(pStmt); 1924251883Speter return 1; 1925251883Speter } 1926251883Speter azCol = malloc( sizeof(azCol[0])*(nCol+1) ); 1927251883Speter if( azCol==0 ){ 1928251883Speter fprintf(stderr, "Error: out of memory\n"); 1929251883Speter fclose(in); 1930251883Speter sqlite3_finalize(pStmt); 1931251883Speter return 1; 1932251883Speter } 1933251883Speter sqlite3_exec(p->db, "BEGIN", 0, 0, 0); 1934251883Speter zCommit = "COMMIT"; 1935251883Speter while( (zLine = local_getline(0, in, 1))!=0 ){ 1936251883Speter char *z, c; 1937251883Speter int inQuote = 0; 1938251883Speter lineno++; 1939251883Speter azCol[0] = zLine; 1940251883Speter for(i=0, z=zLine; (c = *z)!=0; z++){ 1941251883Speter if( c=='"' ) inQuote = !inQuote; 1942251883Speter if( c=='\n' ) lineno++; 1943251883Speter if( !inQuote && c==p->separator[0] && strncmp(z,p->separator,nSep)==0 ){ 1944251883Speter *z = 0; 1945251883Speter i++; 1946251883Speter if( i<nCol ){ 1947251883Speter azCol[i] = &z[nSep]; 1948251883Speter z += nSep-1; 1949251883Speter } 1950251883Speter } 1951251883Speter } /* end for */ 1952251883Speter *z = 0; 1953251883Speter if( i+1!=nCol ){ 1954251883Speter fprintf(stderr, 1955251883Speter "Error: %s line %d: expected %d columns of data but found %d\n", 1956251883Speter zFile, lineno, nCol, i+1); 1957251883Speter zCommit = "ROLLBACK"; 1958251883Speter free(zLine); 1959251883Speter rc = 1; 1960251883Speter break; /* from while */ 1961251883Speter } 1962251883Speter for(i=0; i<nCol; i++){ 1963251883Speter if( azCol[i][0]=='"' ){ 1964251883Speter int k; 1965251883Speter for(z=azCol[i], j=1, k=0; z[j]; j++){ 1966251883Speter if( z[j]=='"' ){ j++; if( z[j]==0 ) break; } 1967251883Speter z[k++] = z[j]; 1968251883Speter } 1969251883Speter z[k] = 0; 1970251883Speter } 1971251883Speter sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); 1972251883Speter } 1973251883Speter sqlite3_step(pStmt); 1974251883Speter rc = sqlite3_reset(pStmt); 1975251883Speter free(zLine); 1976251883Speter if( rc!=SQLITE_OK ){ 1977251883Speter fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); 1978251883Speter zCommit = "ROLLBACK"; 1979251883Speter rc = 1; 1980251883Speter break; /* from while */ 1981251883Speter } 1982251883Speter } /* end while */ 1983251883Speter free(azCol); 1984251883Speter fclose(in); 1985251883Speter sqlite3_finalize(pStmt); 1986251883Speter sqlite3_exec(p->db, zCommit, 0, 0, 0); 1987251883Speter }else 1988251883Speter 1989251883Speter if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){ 1990251883Speter struct callback_data data; 1991251883Speter char *zErrMsg = 0; 1992251883Speter open_db(p); 1993251883Speter memcpy(&data, p, sizeof(data)); 1994251883Speter data.showHeader = 0; 1995251883Speter data.mode = MODE_List; 1996251883Speter if( nArg==1 ){ 1997251883Speter rc = sqlite3_exec(p->db, 1998251883Speter "SELECT name FROM sqlite_master " 1999251883Speter "WHERE type='index' AND name NOT LIKE 'sqlite_%' " 2000251883Speter "UNION ALL " 2001251883Speter "SELECT name FROM sqlite_temp_master " 2002251883Speter "WHERE type='index' " 2003251883Speter "ORDER BY 1", 2004251883Speter callback, &data, &zErrMsg 2005251883Speter ); 2006251883Speter }else{ 2007251883Speter zShellStatic = azArg[1]; 2008251883Speter rc = sqlite3_exec(p->db, 2009251883Speter "SELECT name FROM sqlite_master " 2010251883Speter "WHERE type='index' AND tbl_name LIKE shellstatic() " 2011251883Speter "UNION ALL " 2012251883Speter "SELECT name FROM sqlite_temp_master " 2013251883Speter "WHERE type='index' AND tbl_name LIKE shellstatic() " 2014251883Speter "ORDER BY 1", 2015251883Speter callback, &data, &zErrMsg 2016251883Speter ); 2017251883Speter zShellStatic = 0; 2018251883Speter } 2019251883Speter if( zErrMsg ){ 2020251883Speter fprintf(stderr,"Error: %s\n", zErrMsg); 2021251883Speter sqlite3_free(zErrMsg); 2022251883Speter rc = 1; 2023251883Speter }else if( rc != SQLITE_OK ){ 2024251883Speter fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n"); 2025251883Speter rc = 1; 2026251883Speter } 2027251883Speter }else 2028251883Speter 2029251883Speter#ifdef SQLITE_ENABLE_IOTRACE 2030251883Speter if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){ 2031251883Speter extern void (*sqlite3IoTrace)(const char*, ...); 2032251883Speter if( iotrace && iotrace!=stdout ) fclose(iotrace); 2033251883Speter iotrace = 0; 2034251883Speter if( nArg<2 ){ 2035251883Speter sqlite3IoTrace = 0; 2036251883Speter }else if( strcmp(azArg[1], "-")==0 ){ 2037251883Speter sqlite3IoTrace = iotracePrintf; 2038251883Speter iotrace = stdout; 2039251883Speter }else{ 2040251883Speter iotrace = fopen(azArg[1], "w"); 2041251883Speter if( iotrace==0 ){ 2042251883Speter fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); 2043251883Speter sqlite3IoTrace = 0; 2044251883Speter rc = 1; 2045251883Speter }else{ 2046251883Speter sqlite3IoTrace = iotracePrintf; 2047251883Speter } 2048251883Speter } 2049251883Speter }else 2050251883Speter#endif 2051251883Speter 2052251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION 2053251883Speter if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){ 2054251883Speter const char *zFile, *zProc; 2055251883Speter char *zErrMsg = 0; 2056251883Speter zFile = azArg[1]; 2057251883Speter zProc = nArg>=3 ? azArg[2] : 0; 2058251883Speter open_db(p); 2059251883Speter rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); 2060251883Speter if( rc!=SQLITE_OK ){ 2061251883Speter fprintf(stderr, "Error: %s\n", zErrMsg); 2062251883Speter sqlite3_free(zErrMsg); 2063251883Speter rc = 1; 2064251883Speter } 2065251883Speter }else 2066251883Speter#endif 2067251883Speter 2068251883Speter if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){ 2069251883Speter const char *zFile = azArg[1]; 2070251883Speter output_file_close(p->pLog); 2071251883Speter p->pLog = output_file_open(zFile); 2072251883Speter }else 2073251883Speter 2074251883Speter if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){ 2075251883Speter int n2 = strlen30(azArg[1]); 2076251883Speter if( (n2==4 && strncmp(azArg[1],"line",n2)==0) 2077251883Speter || 2078251883Speter (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){ 2079251883Speter p->mode = MODE_Line; 2080251883Speter }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0) 2081251883Speter || 2082251883Speter (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){ 2083251883Speter p->mode = MODE_Column; 2084251883Speter }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){ 2085251883Speter p->mode = MODE_List; 2086251883Speter }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){ 2087251883Speter p->mode = MODE_Html; 2088251883Speter }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){ 2089251883Speter p->mode = MODE_Tcl; 2090251883Speter sqlite3_snprintf(sizeof(p->separator), p->separator, " "); 2091251883Speter }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){ 2092251883Speter p->mode = MODE_Csv; 2093251883Speter sqlite3_snprintf(sizeof(p->separator), p->separator, ","); 2094251883Speter }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){ 2095251883Speter p->mode = MODE_List; 2096251883Speter sqlite3_snprintf(sizeof(p->separator), p->separator, "\t"); 2097251883Speter }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){ 2098251883Speter p->mode = MODE_Insert; 2099251883Speter set_table_name(p, "table"); 2100251883Speter }else { 2101251883Speter fprintf(stderr,"Error: mode should be one of: " 2102251883Speter "column csv html insert line list tabs tcl\n"); 2103251883Speter rc = 1; 2104251883Speter } 2105251883Speter }else 2106251883Speter 2107251883Speter if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){ 2108251883Speter int n2 = strlen30(azArg[1]); 2109251883Speter if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){ 2110251883Speter p->mode = MODE_Insert; 2111251883Speter set_table_name(p, azArg[2]); 2112251883Speter }else { 2113251883Speter fprintf(stderr, "Error: invalid arguments: " 2114251883Speter " \"%s\". Enter \".help\" for help\n", azArg[2]); 2115251883Speter rc = 1; 2116251883Speter } 2117251883Speter }else 2118251883Speter 2119251883Speter if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) { 2120251883Speter sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue, 2121251883Speter "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]); 2122251883Speter }else 2123251883Speter 2124251883Speter if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){ 2125251883Speter if( p->outfile[0]=='|' ){ 2126251883Speter pclose(p->out); 2127251883Speter }else{ 2128251883Speter output_file_close(p->out); 2129251883Speter } 2130251883Speter p->outfile[0] = 0; 2131251883Speter if( azArg[1][0]=='|' ){ 2132251883Speter p->out = popen(&azArg[1][1], "w"); 2133251883Speter if( p->out==0 ){ 2134251883Speter fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]); 2135251883Speter p->out = stdout; 2136251883Speter rc = 1; 2137251883Speter }else{ 2138251883Speter sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); 2139251883Speter } 2140251883Speter }else{ 2141251883Speter p->out = output_file_open(azArg[1]); 2142251883Speter if( p->out==0 ){ 2143251883Speter if( strcmp(azArg[1],"off")!=0 ){ 2144251883Speter fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]); 2145251883Speter } 2146251883Speter p->out = stdout; 2147251883Speter rc = 1; 2148251883Speter } else { 2149251883Speter sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); 2150251883Speter } 2151251883Speter } 2152251883Speter }else 2153251883Speter 2154251883Speter if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){ 2155251883Speter int i; 2156251883Speter for(i=1; i<nArg; i++){ 2157251883Speter if( i>1 ) fprintf(p->out, " "); 2158251883Speter fprintf(p->out, "%s", azArg[i]); 2159251883Speter } 2160251883Speter fprintf(p->out, "\n"); 2161251883Speter }else 2162251883Speter 2163251883Speter if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){ 2164251883Speter if( nArg >= 2) { 2165251883Speter strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); 2166251883Speter } 2167251883Speter if( nArg >= 3) { 2168251883Speter strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1); 2169251883Speter } 2170251883Speter }else 2171251883Speter 2172251883Speter if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){ 2173251883Speter rc = 2; 2174251883Speter }else 2175251883Speter 2176251883Speter if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){ 2177251883Speter FILE *alt = fopen(azArg[1], "rb"); 2178251883Speter if( alt==0 ){ 2179251883Speter fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); 2180251883Speter rc = 1; 2181251883Speter }else{ 2182251883Speter rc = process_input(p, alt); 2183251883Speter fclose(alt); 2184251883Speter } 2185251883Speter }else 2186251883Speter 2187251883Speter if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){ 2188251883Speter const char *zSrcFile; 2189251883Speter const char *zDb; 2190251883Speter sqlite3 *pSrc; 2191251883Speter sqlite3_backup *pBackup; 2192251883Speter int nTimeout = 0; 2193251883Speter 2194251883Speter if( nArg==2 ){ 2195251883Speter zSrcFile = azArg[1]; 2196251883Speter zDb = "main"; 2197251883Speter }else{ 2198251883Speter zSrcFile = azArg[2]; 2199251883Speter zDb = azArg[1]; 2200251883Speter } 2201251883Speter rc = sqlite3_open(zSrcFile, &pSrc); 2202251883Speter if( rc!=SQLITE_OK ){ 2203251883Speter fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); 2204251883Speter sqlite3_close(pSrc); 2205251883Speter return 1; 2206251883Speter } 2207251883Speter open_db(p); 2208251883Speter pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); 2209251883Speter if( pBackup==0 ){ 2210251883Speter fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); 2211251883Speter sqlite3_close(pSrc); 2212251883Speter return 1; 2213251883Speter } 2214251883Speter while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK 2215251883Speter || rc==SQLITE_BUSY ){ 2216251883Speter if( rc==SQLITE_BUSY ){ 2217251883Speter if( nTimeout++ >= 3 ) break; 2218251883Speter sqlite3_sleep(100); 2219251883Speter } 2220251883Speter } 2221251883Speter sqlite3_backup_finish(pBackup); 2222251883Speter if( rc==SQLITE_DONE ){ 2223251883Speter rc = 0; 2224251883Speter }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ 2225251883Speter fprintf(stderr, "Error: source database is busy\n"); 2226251883Speter rc = 1; 2227251883Speter }else{ 2228251883Speter fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); 2229251883Speter rc = 1; 2230251883Speter } 2231251883Speter sqlite3_close(pSrc); 2232251883Speter }else 2233251883Speter 2234251883Speter if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){ 2235251883Speter struct callback_data data; 2236251883Speter char *zErrMsg = 0; 2237251883Speter open_db(p); 2238251883Speter memcpy(&data, p, sizeof(data)); 2239251883Speter data.showHeader = 0; 2240251883Speter data.mode = MODE_Semi; 2241251883Speter if( nArg>1 ){ 2242251883Speter int i; 2243251883Speter for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]); 2244251883Speter if( strcmp(azArg[1],"sqlite_master")==0 ){ 2245251883Speter char *new_argv[2], *new_colv[2]; 2246251883Speter new_argv[0] = "CREATE TABLE sqlite_master (\n" 2247251883Speter " type text,\n" 2248251883Speter " name text,\n" 2249251883Speter " tbl_name text,\n" 2250251883Speter " rootpage integer,\n" 2251251883Speter " sql text\n" 2252251883Speter ")"; 2253251883Speter new_argv[1] = 0; 2254251883Speter new_colv[0] = "sql"; 2255251883Speter new_colv[1] = 0; 2256251883Speter callback(&data, 1, new_argv, new_colv); 2257251883Speter rc = SQLITE_OK; 2258251883Speter }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){ 2259251883Speter char *new_argv[2], *new_colv[2]; 2260251883Speter new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n" 2261251883Speter " type text,\n" 2262251883Speter " name text,\n" 2263251883Speter " tbl_name text,\n" 2264251883Speter " rootpage integer,\n" 2265251883Speter " sql text\n" 2266251883Speter ")"; 2267251883Speter new_argv[1] = 0; 2268251883Speter new_colv[0] = "sql"; 2269251883Speter new_colv[1] = 0; 2270251883Speter callback(&data, 1, new_argv, new_colv); 2271251883Speter rc = SQLITE_OK; 2272251883Speter }else{ 2273251883Speter zShellStatic = azArg[1]; 2274251883Speter rc = sqlite3_exec(p->db, 2275251883Speter "SELECT sql FROM " 2276251883Speter " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" 2277251883Speter " FROM sqlite_master UNION ALL" 2278251883Speter " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " 2279251883Speter "WHERE lower(tbl_name) LIKE shellstatic()" 2280251883Speter " AND type!='meta' AND sql NOTNULL " 2281251883Speter "ORDER BY rowid", 2282251883Speter callback, &data, &zErrMsg); 2283251883Speter zShellStatic = 0; 2284251883Speter } 2285251883Speter }else{ 2286251883Speter rc = sqlite3_exec(p->db, 2287251883Speter "SELECT sql FROM " 2288251883Speter " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" 2289251883Speter " FROM sqlite_master UNION ALL" 2290251883Speter " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " 2291251883Speter "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" 2292251883Speter "ORDER BY rowid", 2293251883Speter callback, &data, &zErrMsg 2294251883Speter ); 2295251883Speter } 2296251883Speter if( zErrMsg ){ 2297251883Speter fprintf(stderr,"Error: %s\n", zErrMsg); 2298251883Speter sqlite3_free(zErrMsg); 2299251883Speter rc = 1; 2300251883Speter }else if( rc != SQLITE_OK ){ 2301251883Speter fprintf(stderr,"Error: querying schema information\n"); 2302251883Speter rc = 1; 2303251883Speter }else{ 2304251883Speter rc = 0; 2305251883Speter } 2306251883Speter }else 2307251883Speter 2308251883Speter if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ 2309251883Speter sqlite3_snprintf(sizeof(p->separator), p->separator, 2310251883Speter "%.*s", (int)sizeof(p->separator)-1, azArg[1]); 2311251883Speter }else 2312251883Speter 2313251883Speter if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){ 2314251883Speter int i; 2315251883Speter fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); 2316251883Speter fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off"); 2317251883Speter fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off"); 2318251883Speter fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]); 2319251883Speter fprintf(p->out,"%9.9s: ", "nullvalue"); 2320251883Speter output_c_string(p->out, p->nullvalue); 2321251883Speter fprintf(p->out, "\n"); 2322251883Speter fprintf(p->out,"%9.9s: %s\n","output", 2323251883Speter strlen30(p->outfile) ? p->outfile : "stdout"); 2324251883Speter fprintf(p->out,"%9.9s: ", "separator"); 2325251883Speter output_c_string(p->out, p->separator); 2326251883Speter fprintf(p->out, "\n"); 2327251883Speter fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off"); 2328251883Speter fprintf(p->out,"%9.9s: ","width"); 2329251883Speter for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { 2330251883Speter fprintf(p->out,"%d ",p->colWidth[i]); 2331251883Speter } 2332251883Speter fprintf(p->out,"\n"); 2333251883Speter }else 2334251883Speter 2335251883Speter if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){ 2336251883Speter p->statsOn = booleanValue(azArg[1]); 2337251883Speter }else 2338251883Speter 2339251883Speter if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){ 2340251883Speter sqlite3_stmt *pStmt; 2341251883Speter char **azResult; 2342251883Speter int nRow, nAlloc; 2343251883Speter char *zSql = 0; 2344251883Speter int ii; 2345251883Speter open_db(p); 2346251883Speter rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); 2347251883Speter if( rc ) return rc; 2348251883Speter zSql = sqlite3_mprintf( 2349251883Speter "SELECT name FROM sqlite_master" 2350251883Speter " WHERE type IN ('table','view')" 2351251883Speter " AND name NOT LIKE 'sqlite_%%'" 2352251883Speter " AND name LIKE ?1"); 2353251883Speter while( sqlite3_step(pStmt)==SQLITE_ROW ){ 2354251883Speter const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); 2355251883Speter if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue; 2356251883Speter if( strcmp(zDbName,"temp")==0 ){ 2357251883Speter zSql = sqlite3_mprintf( 2358251883Speter "%z UNION ALL " 2359251883Speter "SELECT 'temp.' || name FROM sqlite_temp_master" 2360251883Speter " WHERE type IN ('table','view')" 2361251883Speter " AND name NOT LIKE 'sqlite_%%'" 2362251883Speter " AND name LIKE ?1", zSql); 2363251883Speter }else{ 2364251883Speter zSql = sqlite3_mprintf( 2365251883Speter "%z UNION ALL " 2366251883Speter "SELECT '%q.' || name FROM \"%w\".sqlite_master" 2367251883Speter " WHERE type IN ('table','view')" 2368251883Speter " AND name NOT LIKE 'sqlite_%%'" 2369251883Speter " AND name LIKE ?1", zSql, zDbName, zDbName); 2370251883Speter } 2371251883Speter } 2372251883Speter sqlite3_finalize(pStmt); 2373251883Speter zSql = sqlite3_mprintf("%z ORDER BY 1", zSql); 2374251883Speter rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); 2375251883Speter sqlite3_free(zSql); 2376251883Speter if( rc ) return rc; 2377251883Speter nRow = nAlloc = 0; 2378251883Speter azResult = 0; 2379251883Speter if( nArg>1 ){ 2380251883Speter sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT); 2381251883Speter }else{ 2382251883Speter sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC); 2383251883Speter } 2384251883Speter while( sqlite3_step(pStmt)==SQLITE_ROW ){ 2385251883Speter if( nRow>=nAlloc ){ 2386251883Speter char **azNew; 2387251883Speter int n = nAlloc*2 + 10; 2388251883Speter azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n); 2389251883Speter if( azNew==0 ){ 2390251883Speter fprintf(stderr, "Error: out of memory\n"); 2391251883Speter break; 2392251883Speter } 2393251883Speter nAlloc = n; 2394251883Speter azResult = azNew; 2395251883Speter } 2396251883Speter azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); 2397251883Speter if( azResult[nRow] ) nRow++; 2398251883Speter } 2399251883Speter sqlite3_finalize(pStmt); 2400251883Speter if( nRow>0 ){ 2401251883Speter int len, maxlen = 0; 2402251883Speter int i, j; 2403251883Speter int nPrintCol, nPrintRow; 2404251883Speter for(i=0; i<nRow; i++){ 2405251883Speter len = strlen30(azResult[i]); 2406251883Speter if( len>maxlen ) maxlen = len; 2407251883Speter } 2408251883Speter nPrintCol = 80/(maxlen+2); 2409251883Speter if( nPrintCol<1 ) nPrintCol = 1; 2410251883Speter nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; 2411251883Speter for(i=0; i<nPrintRow; i++){ 2412251883Speter for(j=i; j<nRow; j+=nPrintRow){ 2413251883Speter char *zSp = j<nPrintRow ? "" : " "; 2414251883Speter fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : ""); 2415251883Speter } 2416251883Speter fprintf(p->out, "\n"); 2417251883Speter } 2418251883Speter } 2419251883Speter for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]); 2420251883Speter sqlite3_free(azResult); 2421251883Speter }else 2422251883Speter 2423251883Speter if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){ 2424251883Speter static const struct { 2425251883Speter const char *zCtrlName; /* Name of a test-control option */ 2426251883Speter int ctrlCode; /* Integer code for that option */ 2427251883Speter } aCtrl[] = { 2428251883Speter { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE }, 2429251883Speter { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE }, 2430251883Speter { "prng_reset", SQLITE_TESTCTRL_PRNG_RESET }, 2431251883Speter { "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST }, 2432251883Speter { "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL }, 2433251883Speter { "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS }, 2434251883Speter { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE }, 2435251883Speter { "assert", SQLITE_TESTCTRL_ASSERT }, 2436251883Speter { "always", SQLITE_TESTCTRL_ALWAYS }, 2437251883Speter { "reserve", SQLITE_TESTCTRL_RESERVE }, 2438251883Speter { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS }, 2439251883Speter { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD }, 2440251883Speter { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC }, 2441251883Speter }; 2442251883Speter int testctrl = -1; 2443251883Speter int rc = 0; 2444251883Speter int i, n; 2445251883Speter open_db(p); 2446251883Speter 2447251883Speter /* convert testctrl text option to value. allow any unique prefix 2448251883Speter ** of the option name, or a numerical value. */ 2449251883Speter n = strlen30(azArg[1]); 2450251883Speter for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){ 2451251883Speter if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){ 2452251883Speter if( testctrl<0 ){ 2453251883Speter testctrl = aCtrl[i].ctrlCode; 2454251883Speter }else{ 2455251883Speter fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]); 2456251883Speter testctrl = -1; 2457251883Speter break; 2458251883Speter } 2459251883Speter } 2460251883Speter } 2461251883Speter if( testctrl<0 ) testctrl = atoi(azArg[1]); 2462251883Speter if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){ 2463251883Speter fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]); 2464251883Speter }else{ 2465251883Speter switch(testctrl){ 2466251883Speter 2467251883Speter /* sqlite3_test_control(int, db, int) */ 2468251883Speter case SQLITE_TESTCTRL_OPTIMIZATIONS: 2469251883Speter case SQLITE_TESTCTRL_RESERVE: 2470251883Speter if( nArg==3 ){ 2471251883Speter int opt = (int)strtol(azArg[2], 0, 0); 2472251883Speter rc = sqlite3_test_control(testctrl, p->db, opt); 2473251883Speter fprintf(p->out, "%d (0x%08x)\n", rc, rc); 2474251883Speter } else { 2475251883Speter fprintf(stderr,"Error: testctrl %s takes a single int option\n", 2476251883Speter azArg[1]); 2477251883Speter } 2478251883Speter break; 2479251883Speter 2480251883Speter /* sqlite3_test_control(int) */ 2481251883Speter case SQLITE_TESTCTRL_PRNG_SAVE: 2482251883Speter case SQLITE_TESTCTRL_PRNG_RESTORE: 2483251883Speter case SQLITE_TESTCTRL_PRNG_RESET: 2484251883Speter if( nArg==2 ){ 2485251883Speter rc = sqlite3_test_control(testctrl); 2486251883Speter fprintf(p->out, "%d (0x%08x)\n", rc, rc); 2487251883Speter } else { 2488251883Speter fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]); 2489251883Speter } 2490251883Speter break; 2491251883Speter 2492251883Speter /* sqlite3_test_control(int, uint) */ 2493251883Speter case SQLITE_TESTCTRL_PENDING_BYTE: 2494251883Speter if( nArg==3 ){ 2495251883Speter unsigned int opt = (unsigned int)integerValue(azArg[2]); 2496251883Speter rc = sqlite3_test_control(testctrl, opt); 2497251883Speter fprintf(p->out, "%d (0x%08x)\n", rc, rc); 2498251883Speter } else { 2499251883Speter fprintf(stderr,"Error: testctrl %s takes a single unsigned" 2500251883Speter " int option\n", azArg[1]); 2501251883Speter } 2502251883Speter break; 2503251883Speter 2504251883Speter /* sqlite3_test_control(int, int) */ 2505251883Speter case SQLITE_TESTCTRL_ASSERT: 2506251883Speter case SQLITE_TESTCTRL_ALWAYS: 2507251883Speter if( nArg==3 ){ 2508251883Speter int opt = atoi(azArg[2]); 2509251883Speter rc = sqlite3_test_control(testctrl, opt); 2510251883Speter fprintf(p->out, "%d (0x%08x)\n", rc, rc); 2511251883Speter } else { 2512251883Speter fprintf(stderr,"Error: testctrl %s takes a single int option\n", 2513251883Speter azArg[1]); 2514251883Speter } 2515251883Speter break; 2516251883Speter 2517251883Speter /* sqlite3_test_control(int, char *) */ 2518251883Speter#ifdef SQLITE_N_KEYWORD 2519251883Speter case SQLITE_TESTCTRL_ISKEYWORD: 2520251883Speter if( nArg==3 ){ 2521251883Speter const char *opt = azArg[2]; 2522251883Speter rc = sqlite3_test_control(testctrl, opt); 2523251883Speter fprintf(p->out, "%d (0x%08x)\n", rc, rc); 2524251883Speter } else { 2525251883Speter fprintf(stderr,"Error: testctrl %s takes a single char * option\n", 2526251883Speter azArg[1]); 2527251883Speter } 2528251883Speter break; 2529251883Speter#endif 2530251883Speter 2531251883Speter case SQLITE_TESTCTRL_BITVEC_TEST: 2532251883Speter case SQLITE_TESTCTRL_FAULT_INSTALL: 2533251883Speter case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: 2534251883Speter case SQLITE_TESTCTRL_SCRATCHMALLOC: 2535251883Speter default: 2536251883Speter fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n", 2537251883Speter azArg[1]); 2538251883Speter break; 2539251883Speter } 2540251883Speter } 2541251883Speter }else 2542251883Speter 2543251883Speter if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ 2544251883Speter open_db(p); 2545251883Speter sqlite3_busy_timeout(p->db, atoi(azArg[1])); 2546251883Speter }else 2547251883Speter 2548251883Speter if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 2549251883Speter && nArg==2 2550251883Speter ){ 2551251883Speter enableTimer = booleanValue(azArg[1]); 2552251883Speter }else 2553251883Speter 2554251883Speter if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){ 2555251883Speter open_db(p); 2556251883Speter output_file_close(p->traceOut); 2557251883Speter p->traceOut = output_file_open(azArg[1]); 2558251883Speter#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) 2559251883Speter if( p->traceOut==0 ){ 2560251883Speter sqlite3_trace(p->db, 0, 0); 2561251883Speter }else{ 2562251883Speter sqlite3_trace(p->db, sql_trace_callback, p->traceOut); 2563251883Speter } 2564251883Speter#endif 2565251883Speter }else 2566251883Speter 2567251883Speter if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ 2568251883Speter fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/, 2569251883Speter sqlite3_libversion(), sqlite3_sourceid()); 2570251883Speter }else 2571251883Speter 2572251883Speter if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){ 2573251883Speter const char *zDbName = nArg==2 ? azArg[1] : "main"; 2574251883Speter char *zVfsName = 0; 2575251883Speter if( p->db ){ 2576251883Speter sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName); 2577251883Speter if( zVfsName ){ 2578251883Speter fprintf(p->out, "%s\n", zVfsName); 2579251883Speter sqlite3_free(zVfsName); 2580251883Speter } 2581251883Speter } 2582251883Speter }else 2583251883Speter 2584251883Speter#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) 2585251883Speter if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ 2586251883Speter extern int sqlite3WhereTrace; 2587251883Speter sqlite3WhereTrace = booleanValue(azArg[1]); 2588251883Speter }else 2589251883Speter#endif 2590251883Speter 2591251883Speter if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){ 2592251883Speter int j; 2593251883Speter assert( nArg<=ArraySize(azArg) ); 2594251883Speter for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ 2595251883Speter p->colWidth[j-1] = atoi(azArg[j]); 2596251883Speter } 2597251883Speter }else 2598251883Speter 2599251883Speter { 2600251883Speter fprintf(stderr, "Error: unknown command or invalid arguments: " 2601251883Speter " \"%s\". Enter \".help\" for help\n", azArg[0]); 2602251883Speter rc = 1; 2603251883Speter } 2604251883Speter 2605251883Speter return rc; 2606251883Speter} 2607251883Speter 2608251883Speter/* 2609251883Speter** Return TRUE if a semicolon occurs anywhere in the first N characters 2610251883Speter** of string z[]. 2611251883Speter*/ 2612251883Speterstatic int _contains_semicolon(const char *z, int N){ 2613251883Speter int i; 2614251883Speter for(i=0; i<N; i++){ if( z[i]==';' ) return 1; } 2615251883Speter return 0; 2616251883Speter} 2617251883Speter 2618251883Speter/* 2619251883Speter** Test to see if a line consists entirely of whitespace. 2620251883Speter*/ 2621251883Speterstatic int _all_whitespace(const char *z){ 2622251883Speter for(; *z; z++){ 2623251883Speter if( IsSpace(z[0]) ) continue; 2624251883Speter if( *z=='/' && z[1]=='*' ){ 2625251883Speter z += 2; 2626251883Speter while( *z && (*z!='*' || z[1]!='/') ){ z++; } 2627251883Speter if( *z==0 ) return 0; 2628251883Speter z++; 2629251883Speter continue; 2630251883Speter } 2631251883Speter if( *z=='-' && z[1]=='-' ){ 2632251883Speter z += 2; 2633251883Speter while( *z && *z!='\n' ){ z++; } 2634251883Speter if( *z==0 ) return 1; 2635251883Speter continue; 2636251883Speter } 2637251883Speter return 0; 2638251883Speter } 2639251883Speter return 1; 2640251883Speter} 2641251883Speter 2642251883Speter/* 2643251883Speter** Return TRUE if the line typed in is an SQL command terminator other 2644251883Speter** than a semi-colon. The SQL Server style "go" command is understood 2645251883Speter** as is the Oracle "/". 2646251883Speter*/ 2647251883Speterstatic int _is_command_terminator(const char *zLine){ 2648251883Speter while( IsSpace(zLine[0]) ){ zLine++; }; 2649251883Speter if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){ 2650251883Speter return 1; /* Oracle */ 2651251883Speter } 2652251883Speter if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' 2653251883Speter && _all_whitespace(&zLine[2]) ){ 2654251883Speter return 1; /* SQL Server */ 2655251883Speter } 2656251883Speter return 0; 2657251883Speter} 2658251883Speter 2659251883Speter/* 2660251883Speter** Return true if zSql is a complete SQL statement. Return false if it 2661251883Speter** ends in the middle of a string literal or C-style comment. 2662251883Speter*/ 2663251883Speterstatic int _is_complete(char *zSql, int nSql){ 2664251883Speter int rc; 2665251883Speter if( zSql==0 ) return 1; 2666251883Speter zSql[nSql] = ';'; 2667251883Speter zSql[nSql+1] = 0; 2668251883Speter rc = sqlite3_complete(zSql); 2669251883Speter zSql[nSql] = 0; 2670251883Speter return rc; 2671251883Speter} 2672251883Speter 2673251883Speter/* 2674251883Speter** Read input from *in and process it. If *in==0 then input 2675251883Speter** is interactive - the user is typing it it. Otherwise, input 2676251883Speter** is coming from a file or device. A prompt is issued and history 2677251883Speter** is saved only if input is interactive. An interrupt signal will 2678251883Speter** cause this routine to exit immediately, unless input is interactive. 2679251883Speter** 2680251883Speter** Return the number of errors. 2681251883Speter*/ 2682251883Speterstatic int process_input(struct callback_data *p, FILE *in){ 2683251883Speter char *zLine = 0; 2684251883Speter char *zSql = 0; 2685251883Speter int nSql = 0; 2686251883Speter int nSqlPrior = 0; 2687251883Speter char *zErrMsg; 2688251883Speter int rc; 2689251883Speter int errCnt = 0; 2690251883Speter int lineno = 0; 2691251883Speter int startline = 0; 2692251883Speter 2693251883Speter while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){ 2694251883Speter fflush(p->out); 2695251883Speter free(zLine); 2696251883Speter zLine = one_input_line(zSql, in); 2697251883Speter if( zLine==0 ){ 2698251883Speter /* End of input */ 2699251883Speter if( stdin_is_interactive ) printf("\n"); 2700251883Speter break; 2701251883Speter } 2702251883Speter if( seenInterrupt ){ 2703251883Speter if( in!=0 ) break; 2704251883Speter seenInterrupt = 0; 2705251883Speter } 2706251883Speter lineno++; 2707251883Speter if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue; 2708251883Speter if( zLine && zLine[0]=='.' && nSql==0 ){ 2709251883Speter if( p->echoOn ) printf("%s\n", zLine); 2710251883Speter rc = do_meta_command(zLine, p); 2711251883Speter if( rc==2 ){ /* exit requested */ 2712251883Speter break; 2713251883Speter }else if( rc ){ 2714251883Speter errCnt++; 2715251883Speter } 2716251883Speter continue; 2717251883Speter } 2718251883Speter if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){ 2719251883Speter memcpy(zLine,";",2); 2720251883Speter } 2721251883Speter nSqlPrior = nSql; 2722251883Speter if( zSql==0 ){ 2723251883Speter int i; 2724251883Speter for(i=0; zLine[i] && IsSpace(zLine[i]); i++){} 2725251883Speter if( zLine[i]!=0 ){ 2726251883Speter nSql = strlen30(zLine); 2727251883Speter zSql = malloc( nSql+3 ); 2728251883Speter if( zSql==0 ){ 2729251883Speter fprintf(stderr, "Error: out of memory\n"); 2730251883Speter exit(1); 2731251883Speter } 2732251883Speter memcpy(zSql, zLine, nSql+1); 2733251883Speter startline = lineno; 2734251883Speter } 2735251883Speter }else{ 2736251883Speter int len = strlen30(zLine); 2737251883Speter zSql = realloc( zSql, nSql + len + 4 ); 2738251883Speter if( zSql==0 ){ 2739251883Speter fprintf(stderr,"Error: out of memory\n"); 2740251883Speter exit(1); 2741251883Speter } 2742251883Speter zSql[nSql++] = '\n'; 2743251883Speter memcpy(&zSql[nSql], zLine, len+1); 2744251883Speter nSql += len; 2745251883Speter } 2746251883Speter if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) 2747251883Speter && sqlite3_complete(zSql) ){ 2748251883Speter p->cnt = 0; 2749251883Speter open_db(p); 2750251883Speter BEGIN_TIMER; 2751251883Speter rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg); 2752251883Speter END_TIMER; 2753251883Speter if( rc || zErrMsg ){ 2754251883Speter char zPrefix[100]; 2755251883Speter if( in!=0 || !stdin_is_interactive ){ 2756251883Speter sqlite3_snprintf(sizeof(zPrefix), zPrefix, 2757251883Speter "Error: near line %d:", startline); 2758251883Speter }else{ 2759251883Speter sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:"); 2760251883Speter } 2761251883Speter if( zErrMsg!=0 ){ 2762251883Speter fprintf(stderr, "%s %s\n", zPrefix, zErrMsg); 2763251883Speter sqlite3_free(zErrMsg); 2764251883Speter zErrMsg = 0; 2765251883Speter }else{ 2766251883Speter fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); 2767251883Speter } 2768251883Speter errCnt++; 2769251883Speter } 2770251883Speter free(zSql); 2771251883Speter zSql = 0; 2772251883Speter nSql = 0; 2773251883Speter }else if( zSql && _all_whitespace(zSql) ){ 2774251883Speter free(zSql); 2775251883Speter zSql = 0; 2776251883Speter nSql = 0; 2777251883Speter } 2778251883Speter } 2779251883Speter if( zSql ){ 2780251883Speter if( !_all_whitespace(zSql) ){ 2781251883Speter fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); 2782251883Speter } 2783251883Speter free(zSql); 2784251883Speter } 2785251883Speter free(zLine); 2786251883Speter return errCnt>0; 2787251883Speter} 2788251883Speter 2789251883Speter/* 2790251883Speter** Return a pathname which is the user's home directory. A 2791251883Speter** 0 return indicates an error of some kind. 2792251883Speter*/ 2793251883Speterstatic char *find_home_dir(void){ 2794251883Speter static char *home_dir = NULL; 2795251883Speter if( home_dir ) return home_dir; 2796251883Speter 2797251883Speter#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL) 2798251883Speter { 2799251883Speter struct passwd *pwent; 2800251883Speter uid_t uid = getuid(); 2801251883Speter if( (pwent=getpwuid(uid)) != NULL) { 2802251883Speter home_dir = pwent->pw_dir; 2803251883Speter } 2804251883Speter } 2805251883Speter#endif 2806251883Speter 2807251883Speter#if defined(_WIN32_WCE) 2808251883Speter /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv() 2809251883Speter */ 2810251883Speter home_dir = "/"; 2811251883Speter#else 2812251883Speter 2813251883Speter#if defined(_WIN32) || defined(WIN32) 2814251883Speter if (!home_dir) { 2815251883Speter home_dir = getenv("USERPROFILE"); 2816251883Speter } 2817251883Speter#endif 2818251883Speter 2819251883Speter if (!home_dir) { 2820251883Speter home_dir = getenv("HOME"); 2821251883Speter } 2822251883Speter 2823251883Speter#if defined(_WIN32) || defined(WIN32) 2824251883Speter if (!home_dir) { 2825251883Speter char *zDrive, *zPath; 2826251883Speter int n; 2827251883Speter zDrive = getenv("HOMEDRIVE"); 2828251883Speter zPath = getenv("HOMEPATH"); 2829251883Speter if( zDrive && zPath ){ 2830251883Speter n = strlen30(zDrive) + strlen30(zPath) + 1; 2831251883Speter home_dir = malloc( n ); 2832251883Speter if( home_dir==0 ) return 0; 2833251883Speter sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath); 2834251883Speter return home_dir; 2835251883Speter } 2836251883Speter home_dir = "c:\\"; 2837251883Speter } 2838251883Speter#endif 2839251883Speter 2840251883Speter#endif /* !_WIN32_WCE */ 2841251883Speter 2842251883Speter if( home_dir ){ 2843251883Speter int n = strlen30(home_dir) + 1; 2844251883Speter char *z = malloc( n ); 2845251883Speter if( z ) memcpy(z, home_dir, n); 2846251883Speter home_dir = z; 2847251883Speter } 2848251883Speter 2849251883Speter return home_dir; 2850251883Speter} 2851251883Speter 2852251883Speter/* 2853251883Speter** Read input from the file given by sqliterc_override. Or if that 2854251883Speter** parameter is NULL, take input from ~/.sqliterc 2855251883Speter** 2856251883Speter** Returns the number of errors. 2857251883Speter*/ 2858251883Speterstatic int process_sqliterc( 2859251883Speter struct callback_data *p, /* Configuration data */ 2860251883Speter const char *sqliterc_override /* Name of config file. NULL to use default */ 2861251883Speter){ 2862251883Speter char *home_dir = NULL; 2863251883Speter const char *sqliterc = sqliterc_override; 2864251883Speter char *zBuf = 0; 2865251883Speter FILE *in = NULL; 2866251883Speter int rc = 0; 2867251883Speter 2868251883Speter if (sqliterc == NULL) { 2869251883Speter home_dir = find_home_dir(); 2870251883Speter if( home_dir==0 ){ 2871251883Speter#if !defined(__RTP__) && !defined(_WRS_KERNEL) 2872251883Speter fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0); 2873251883Speter#endif 2874251883Speter return 1; 2875251883Speter } 2876251883Speter sqlite3_initialize(); 2877251883Speter zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); 2878251883Speter sqliterc = zBuf; 2879251883Speter } 2880251883Speter in = fopen(sqliterc,"rb"); 2881251883Speter if( in ){ 2882251883Speter if( stdin_is_interactive ){ 2883251883Speter fprintf(stderr,"-- Loading resources from %s\n",sqliterc); 2884251883Speter } 2885251883Speter rc = process_input(p,in); 2886251883Speter fclose(in); 2887251883Speter } 2888251883Speter sqlite3_free(zBuf); 2889251883Speter return rc; 2890251883Speter} 2891251883Speter 2892251883Speter/* 2893251883Speter** Show available command line options 2894251883Speter*/ 2895251883Speterstatic const char zOptions[] = 2896251883Speter " -bail stop after hitting an error\n" 2897251883Speter " -batch force batch I/O\n" 2898251883Speter " -column set output mode to 'column'\n" 2899251883Speter " -cmd COMMAND run \"COMMAND\" before reading stdin\n" 2900251883Speter " -csv set output mode to 'csv'\n" 2901251883Speter " -echo print commands before execution\n" 2902251883Speter " -init FILENAME read/process named file\n" 2903251883Speter " -[no]header turn headers on or off\n" 2904251883Speter#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) 2905251883Speter " -heap SIZE Size of heap for memsys3 or memsys5\n" 2906251883Speter#endif 2907251883Speter " -help show this message\n" 2908251883Speter " -html set output mode to HTML\n" 2909251883Speter " -interactive force interactive I/O\n" 2910251883Speter " -line set output mode to 'line'\n" 2911251883Speter " -list set output mode to 'list'\n" 2912251883Speter " -mmap N default mmap size set to N\n" 2913251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX 2914251883Speter " -multiplex enable the multiplexor VFS\n" 2915251883Speter#endif 2916251883Speter " -nullvalue TEXT set text string for NULL values. Default ''\n" 2917251883Speter " -separator SEP set output field separator. Default: '|'\n" 2918251883Speter " -stats print memory stats before each finalize\n" 2919251883Speter " -version show SQLite version\n" 2920251883Speter " -vfs NAME use NAME as the default VFS\n" 2921251883Speter#ifdef SQLITE_ENABLE_VFSTRACE 2922251883Speter " -vfstrace enable tracing of all VFS calls\n" 2923251883Speter#endif 2924251883Speter; 2925251883Speterstatic void usage(int showDetail){ 2926251883Speter fprintf(stderr, 2927251883Speter "Usage: %s [OPTIONS] FILENAME [SQL]\n" 2928251883Speter "FILENAME is the name of an SQLite database. A new database is created\n" 2929251883Speter "if the file does not previously exist.\n", Argv0); 2930251883Speter if( showDetail ){ 2931251883Speter fprintf(stderr, "OPTIONS include:\n%s", zOptions); 2932251883Speter }else{ 2933251883Speter fprintf(stderr, "Use the -help option for additional information\n"); 2934251883Speter } 2935251883Speter exit(1); 2936251883Speter} 2937251883Speter 2938251883Speter/* 2939251883Speter** Initialize the state information in data 2940251883Speter*/ 2941251883Speterstatic void main_init(struct callback_data *data) { 2942251883Speter memset(data, 0, sizeof(*data)); 2943251883Speter data->mode = MODE_List; 2944251883Speter memcpy(data->separator,"|", 2); 2945251883Speter data->showHeader = 0; 2946251883Speter sqlite3_config(SQLITE_CONFIG_URI, 1); 2947251883Speter sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); 2948251883Speter sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); 2949251883Speter sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); 2950251883Speter sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); 2951251883Speter} 2952251883Speter 2953251883Speter/* 2954251883Speter** Get the argument to an --option. Throw an error and die if no argument 2955251883Speter** is available. 2956251883Speter*/ 2957251883Speterstatic char *cmdline_option_value(int argc, char **argv, int i){ 2958251883Speter if( i==argc ){ 2959251883Speter fprintf(stderr, "%s: Error: missing argument to %s\n", 2960251883Speter argv[0], argv[argc-1]); 2961251883Speter exit(1); 2962251883Speter } 2963251883Speter return argv[i]; 2964251883Speter} 2965251883Speter 2966251883Speterint main(int argc, char **argv){ 2967251883Speter char *zErrMsg = 0; 2968251883Speter struct callback_data data; 2969251883Speter const char *zInitFile = 0; 2970251883Speter char *zFirstCmd = 0; 2971251883Speter int i; 2972251883Speter int rc = 0; 2973251883Speter 2974251883Speter if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){ 2975251883Speter fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", 2976251883Speter sqlite3_sourceid(), SQLITE_SOURCE_ID); 2977251883Speter exit(1); 2978251883Speter } 2979251883Speter Argv0 = argv[0]; 2980251883Speter main_init(&data); 2981251883Speter stdin_is_interactive = isatty(0); 2982251883Speter 2983251883Speter /* Make sure we have a valid signal handler early, before anything 2984251883Speter ** else is done. 2985251883Speter */ 2986251883Speter#ifdef SIGINT 2987251883Speter signal(SIGINT, interrupt_handler); 2988251883Speter#endif 2989251883Speter 2990251883Speter /* Do an initial pass through the command-line argument to locate 2991251883Speter ** the name of the database file, the name of the initialization file, 2992251883Speter ** the size of the alternative malloc heap, 2993251883Speter ** and the first command to execute. 2994251883Speter */ 2995251883Speter for(i=1; i<argc; i++){ 2996251883Speter char *z; 2997251883Speter z = argv[i]; 2998251883Speter if( z[0]!='-' ){ 2999251883Speter if( data.zDbFilename==0 ){ 3000251883Speter data.zDbFilename = z; 3001251883Speter continue; 3002251883Speter } 3003251883Speter if( zFirstCmd==0 ){ 3004251883Speter zFirstCmd = z; 3005251883Speter continue; 3006251883Speter } 3007251883Speter fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]); 3008251883Speter fprintf(stderr,"Use -help for a list of options.\n"); 3009251883Speter return 1; 3010251883Speter } 3011251883Speter if( z[1]=='-' ) z++; 3012251883Speter if( strcmp(z,"-separator")==0 3013251883Speter || strcmp(z,"-nullvalue")==0 3014251883Speter || strcmp(z,"-cmd")==0 3015251883Speter ){ 3016251883Speter (void)cmdline_option_value(argc, argv, ++i); 3017251883Speter }else if( strcmp(z,"-init")==0 ){ 3018251883Speter zInitFile = cmdline_option_value(argc, argv, ++i); 3019251883Speter }else if( strcmp(z,"-batch")==0 ){ 3020251883Speter /* Need to check for batch mode here to so we can avoid printing 3021251883Speter ** informational messages (like from process_sqliterc) before 3022251883Speter ** we do the actual processing of arguments later in a second pass. 3023251883Speter */ 3024251883Speter stdin_is_interactive = 0; 3025251883Speter }else if( strcmp(z,"-heap")==0 ){ 3026251883Speter#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) 3027251883Speter int j, c; 3028251883Speter const char *zSize; 3029251883Speter sqlite3_int64 szHeap; 3030251883Speter 3031251883Speter zSize = cmdline_option_value(argc, argv, ++i); 3032251883Speter szHeap = integerValue(zSize); 3033251883Speter if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; 3034251883Speter sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); 3035251883Speter#endif 3036251883Speter#ifdef SQLITE_ENABLE_VFSTRACE 3037251883Speter }else if( strcmp(z,"-vfstrace")==0 ){ 3038251883Speter extern int vfstrace_register( 3039251883Speter const char *zTraceName, 3040251883Speter const char *zOldVfsName, 3041251883Speter int (*xOut)(const char*,void*), 3042251883Speter void *pOutArg, 3043251883Speter int makeDefault 3044251883Speter ); 3045251883Speter vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); 3046251883Speter#endif 3047251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX 3048251883Speter }else if( strcmp(z,"-multiplex")==0 ){ 3049251883Speter extern int sqlite3_multiple_initialize(const char*,int); 3050251883Speter sqlite3_multiplex_initialize(0, 1); 3051251883Speter#endif 3052251883Speter }else if( strcmp(z,"-mmap")==0 ){ 3053251883Speter sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); 3054251883Speter sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz); 3055251883Speter }else if( strcmp(z,"-vfs")==0 ){ 3056251883Speter sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i)); 3057251883Speter if( pVfs ){ 3058251883Speter sqlite3_vfs_register(pVfs, 1); 3059251883Speter }else{ 3060251883Speter fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]); 3061251883Speter exit(1); 3062251883Speter } 3063251883Speter } 3064251883Speter } 3065251883Speter if( data.zDbFilename==0 ){ 3066251883Speter#ifndef SQLITE_OMIT_MEMORYDB 3067251883Speter data.zDbFilename = ":memory:"; 3068251883Speter#else 3069251883Speter fprintf(stderr,"%s: Error: no database filename specified\n", Argv0); 3070251883Speter return 1; 3071251883Speter#endif 3072251883Speter } 3073251883Speter data.out = stdout; 3074251883Speter 3075251883Speter /* Go ahead and open the database file if it already exists. If the 3076251883Speter ** file does not exist, delay opening it. This prevents empty database 3077251883Speter ** files from being created if a user mistypes the database name argument 3078251883Speter ** to the sqlite command-line tool. 3079251883Speter */ 3080251883Speter if( access(data.zDbFilename, 0)==0 ){ 3081251883Speter open_db(&data); 3082251883Speter } 3083251883Speter 3084251883Speter /* Process the initialization file if there is one. If no -init option 3085251883Speter ** is given on the command line, look for a file named ~/.sqliterc and 3086251883Speter ** try to process it. 3087251883Speter */ 3088251883Speter rc = process_sqliterc(&data,zInitFile); 3089251883Speter if( rc>0 ){ 3090251883Speter return rc; 3091251883Speter } 3092251883Speter 3093251883Speter /* Make a second pass through the command-line argument and set 3094251883Speter ** options. This second pass is delayed until after the initialization 3095251883Speter ** file is processed so that the command-line arguments will override 3096251883Speter ** settings in the initialization file. 3097251883Speter */ 3098251883Speter for(i=1; i<argc; i++){ 3099251883Speter char *z = argv[i]; 3100251883Speter if( z[0]!='-' ) continue; 3101251883Speter if( z[1]=='-' ){ z++; } 3102251883Speter if( strcmp(z,"-init")==0 ){ 3103251883Speter i++; 3104251883Speter }else if( strcmp(z,"-html")==0 ){ 3105251883Speter data.mode = MODE_Html; 3106251883Speter }else if( strcmp(z,"-list")==0 ){ 3107251883Speter data.mode = MODE_List; 3108251883Speter }else if( strcmp(z,"-line")==0 ){ 3109251883Speter data.mode = MODE_Line; 3110251883Speter }else if( strcmp(z,"-column")==0 ){ 3111251883Speter data.mode = MODE_Column; 3112251883Speter }else if( strcmp(z,"-csv")==0 ){ 3113251883Speter data.mode = MODE_Csv; 3114251883Speter memcpy(data.separator,",",2); 3115251883Speter }else if( strcmp(z,"-separator")==0 ){ 3116251883Speter sqlite3_snprintf(sizeof(data.separator), data.separator, 3117251883Speter "%s",cmdline_option_value(argc,argv,++i)); 3118251883Speter }else if( strcmp(z,"-nullvalue")==0 ){ 3119251883Speter sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue, 3120251883Speter "%s",cmdline_option_value(argc,argv,++i)); 3121251883Speter }else if( strcmp(z,"-header")==0 ){ 3122251883Speter data.showHeader = 1; 3123251883Speter }else if( strcmp(z,"-noheader")==0 ){ 3124251883Speter data.showHeader = 0; 3125251883Speter }else if( strcmp(z,"-echo")==0 ){ 3126251883Speter data.echoOn = 1; 3127251883Speter }else if( strcmp(z,"-stats")==0 ){ 3128251883Speter data.statsOn = 1; 3129251883Speter }else if( strcmp(z,"-bail")==0 ){ 3130251883Speter bail_on_error = 1; 3131251883Speter }else if( strcmp(z,"-version")==0 ){ 3132251883Speter printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid()); 3133251883Speter return 0; 3134251883Speter }else if( strcmp(z,"-interactive")==0 ){ 3135251883Speter stdin_is_interactive = 1; 3136251883Speter }else if( strcmp(z,"-batch")==0 ){ 3137251883Speter stdin_is_interactive = 0; 3138251883Speter }else if( strcmp(z,"-heap")==0 ){ 3139251883Speter i++; 3140251883Speter }else if( strcmp(z,"-mmap")==0 ){ 3141251883Speter i++; 3142251883Speter }else if( strcmp(z,"-vfs")==0 ){ 3143251883Speter i++; 3144251883Speter#ifdef SQLITE_ENABLE_VFSTRACE 3145251883Speter }else if( strcmp(z,"-vfstrace")==0 ){ 3146251883Speter i++; 3147251883Speter#endif 3148251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX 3149251883Speter }else if( strcmp(z,"-multiplex")==0 ){ 3150251883Speter i++; 3151251883Speter#endif 3152251883Speter }else if( strcmp(z,"-help")==0 ){ 3153251883Speter usage(1); 3154251883Speter }else if( strcmp(z,"-cmd")==0 ){ 3155251883Speter if( i==argc-1 ) break; 3156251883Speter z = cmdline_option_value(argc,argv,++i); 3157251883Speter if( z[0]=='.' ){ 3158251883Speter rc = do_meta_command(z, &data); 3159251883Speter if( rc && bail_on_error ) return rc==2 ? 0 : rc; 3160251883Speter }else{ 3161251883Speter open_db(&data); 3162251883Speter rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg); 3163251883Speter if( zErrMsg!=0 ){ 3164251883Speter fprintf(stderr,"Error: %s\n", zErrMsg); 3165251883Speter if( bail_on_error ) return rc!=0 ? rc : 1; 3166251883Speter }else if( rc!=0 ){ 3167251883Speter fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z); 3168251883Speter if( bail_on_error ) return rc; 3169251883Speter } 3170251883Speter } 3171251883Speter }else{ 3172251883Speter fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); 3173251883Speter fprintf(stderr,"Use -help for a list of options.\n"); 3174251883Speter return 1; 3175251883Speter } 3176251883Speter } 3177251883Speter 3178251883Speter if( zFirstCmd ){ 3179251883Speter /* Run just the command that follows the database name 3180251883Speter */ 3181251883Speter if( zFirstCmd[0]=='.' ){ 3182251883Speter rc = do_meta_command(zFirstCmd, &data); 3183251883Speter if( rc==2 ) rc = 0; 3184251883Speter }else{ 3185251883Speter open_db(&data); 3186251883Speter rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg); 3187251883Speter if( zErrMsg!=0 ){ 3188251883Speter fprintf(stderr,"Error: %s\n", zErrMsg); 3189251883Speter return rc!=0 ? rc : 1; 3190251883Speter }else if( rc!=0 ){ 3191251883Speter fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd); 3192251883Speter return rc; 3193251883Speter } 3194251883Speter } 3195251883Speter }else{ 3196251883Speter /* Run commands received from standard input 3197251883Speter */ 3198251883Speter if( stdin_is_interactive ){ 3199251883Speter char *zHome; 3200251883Speter char *zHistory = 0; 3201251883Speter int nHistory; 3202251883Speter printf( 3203251883Speter "SQLite version %s %.19s\n" /*extra-version-info*/ 3204251883Speter "Enter \".help\" for instructions\n" 3205251883Speter "Enter SQL statements terminated with a \";\"\n", 3206251883Speter sqlite3_libversion(), sqlite3_sourceid() 3207251883Speter ); 3208251883Speter zHome = find_home_dir(); 3209251883Speter if( zHome ){ 3210251883Speter nHistory = strlen30(zHome) + 20; 3211251883Speter if( (zHistory = malloc(nHistory))!=0 ){ 3212251883Speter sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome); 3213251883Speter } 3214251883Speter } 3215251883Speter#if defined(HAVE_READLINE) && HAVE_READLINE==1 3216251883Speter if( zHistory ) read_history(zHistory); 3217251883Speter#endif 3218251883Speter rc = process_input(&data, 0); 3219251883Speter if( zHistory ){ 3220251883Speter stifle_history(100); 3221251883Speter write_history(zHistory); 3222251883Speter free(zHistory); 3223251883Speter } 3224251883Speter }else{ 3225251883Speter rc = process_input(&data, stdin); 3226251883Speter } 3227251883Speter } 3228251883Speter set_table_name(&data, 0); 3229251883Speter if( data.db ){ 3230251883Speter sqlite3_close(data.db); 3231251883Speter } 3232251883Speter return rc; 3233251883Speter} 3234