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/* 21289166Speter** If requested, include the SQLite compiler options file for MSVC. 22289166Speter*/ 23289166Speter#if defined(INCLUDE_MSVC_H) 24289166Speter#include "msvc.h" 25289166Speter#endif 26289166Speter 27289166Speter/* 28289166Speter** No support for loadable extensions in VxWorks. 29289166Speter*/ 30289166Speter#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION 31289166Speter# define SQLITE_OMIT_LOAD_EXTENSION 1 32289166Speter#endif 33289166Speter 34289166Speter/* 35251883Speter** Enable large-file support for fopen() and friends on unix. 36251883Speter*/ 37251883Speter#ifndef SQLITE_DISABLE_LFS 38251883Speter# define _LARGE_FILE 1 39251883Speter# ifndef _FILE_OFFSET_BITS 40251883Speter# define _FILE_OFFSET_BITS 64 41251883Speter# endif 42251883Speter# define _LARGEFILE_SOURCE 1 43251883Speter#endif 44251883Speter 45251883Speter#include <stdlib.h> 46251883Speter#include <string.h> 47251883Speter#include <stdio.h> 48251883Speter#include <assert.h> 49251883Speter#include "sqlite3.h" 50289166Speter#if SQLITE_USER_AUTHENTICATION 51289166Speter# include "sqlite3userauth.h" 52289166Speter#endif 53251883Speter#include <ctype.h> 54251883Speter#include <stdarg.h> 55251883Speter 56251883Speter#if !defined(_WIN32) && !defined(WIN32) 57251883Speter# include <signal.h> 58251883Speter# if !defined(__RTP__) && !defined(_WRS_KERNEL) 59251883Speter# include <pwd.h> 60251883Speter# endif 61251883Speter# include <unistd.h> 62251883Speter# include <sys/types.h> 63251883Speter#endif 64251883Speter 65289166Speter#if HAVE_READLINE 66251883Speter# include <readline/readline.h> 67251883Speter# include <readline/history.h> 68251883Speter#endif 69289166Speter 70289166Speter#if HAVE_EDITLINE 71289166Speter# include <editline/readline.h> 72251883Speter#endif 73251883Speter 74289166Speter#if HAVE_EDITLINE || HAVE_READLINE 75289166Speter 76289166Speter# define shell_add_history(X) add_history(X) 77289166Speter# define shell_read_history(X) read_history(X) 78289166Speter# define shell_write_history(X) write_history(X) 79289166Speter# define shell_stifle_history(X) stifle_history(X) 80289166Speter# define shell_readline(X) readline(X) 81289166Speter 82289166Speter#elif HAVE_LINENOISE 83289166Speter 84289166Speter# include "linenoise.h" 85289166Speter# define shell_add_history(X) linenoiseHistoryAdd(X) 86289166Speter# define shell_read_history(X) linenoiseHistoryLoad(X) 87289166Speter# define shell_write_history(X) linenoiseHistorySave(X) 88289166Speter# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X) 89289166Speter# define shell_readline(X) linenoise(X) 90289166Speter 91289166Speter#else 92289166Speter 93305003Scy# define shell_read_history(X) 94289166Speter# define shell_write_history(X) 95289166Speter# define shell_stifle_history(X) 96289166Speter 97289166Speter# define SHELL_USE_LOCAL_GETLINE 1 98289166Speter#endif 99289166Speter 100289166Speter 101251883Speter#if defined(_WIN32) || defined(WIN32) 102251883Speter# include <io.h> 103289166Speter# include <fcntl.h> 104289166Speter# define isatty(h) _isatty(h) 105289166Speter# ifndef access 106289166Speter# define access(f,m) _access((f),(m)) 107289166Speter# endif 108289166Speter# undef popen 109289166Speter# define popen _popen 110289166Speter# undef pclose 111289166Speter# define pclose _pclose 112251883Speter#else 113289166Speter /* Make sure isatty() has a prototype. */ 114289166Speter extern int isatty(int); 115289166Speter 116289166Speter# if !defined(__RTP__) && !defined(_WRS_KERNEL) 117289166Speter /* popen and pclose are not C89 functions and so are 118289166Speter ** sometimes omitted from the <stdio.h> header */ 119289166Speter extern FILE *popen(const char*,const char*); 120289166Speter extern int pclose(FILE*); 121289166Speter# else 122289166Speter# define SQLITE_OMIT_POPEN 1 123289166Speter# endif 124251883Speter#endif 125251883Speter 126251883Speter#if defined(_WIN32_WCE) 127251883Speter/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() 128251883Speter * thus we always assume that we have a console. That can be 129251883Speter * overridden with the -batch command line option. 130251883Speter */ 131251883Speter#define isatty(x) 1 132251883Speter#endif 133251883Speter 134251883Speter/* ctype macros that work with signed characters */ 135251883Speter#define IsSpace(X) isspace((unsigned char)X) 136251883Speter#define IsDigit(X) isdigit((unsigned char)X) 137251883Speter#define ToLower(X) (char)tolower((unsigned char)X) 138251883Speter 139305003Scy#if defined(_WIN32) || defined(WIN32) 140305003Scy#include <windows.h> 141305003Scy 142305003Scy/* string conversion routines only needed on Win32 */ 143305003Scyextern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); 144305003Scyextern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int); 145305003Scyextern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int); 146305003Scy#endif 147305003Scy 148289166Speter/* On Windows, we normally run with output mode of TEXT so that \n characters 149289166Speter** are automatically translated into \r\n. However, this behavior needs 150289166Speter** to be disabled in some cases (ex: when generating CSV output and when 151289166Speter** rendering quoted strings that contain \n characters). The following 152289166Speter** routines take care of that. 153289166Speter*/ 154289166Speter#if defined(_WIN32) || defined(WIN32) 155305003Scystatic void setBinaryMode(FILE *file, int isOutput){ 156305003Scy if( isOutput ) fflush(file); 157305003Scy _setmode(_fileno(file), _O_BINARY); 158289166Speter} 159305003Scystatic void setTextMode(FILE *file, int isOutput){ 160305003Scy if( isOutput ) fflush(file); 161305003Scy _setmode(_fileno(file), _O_TEXT); 162289166Speter} 163289166Speter#else 164305003Scy# define setBinaryMode(X,Y) 165305003Scy# define setTextMode(X,Y) 166289166Speter#endif 167289166Speter 168289166Speter 169289166Speter/* True if the timer is enabled */ 170289166Speterstatic int enableTimer = 0; 171289166Speter 172289166Speter/* Return the current wall-clock time */ 173289166Speterstatic sqlite3_int64 timeOfDay(void){ 174289166Speter static sqlite3_vfs *clockVfs = 0; 175289166Speter sqlite3_int64 t; 176289166Speter if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); 177305003Scy if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ 178289166Speter clockVfs->xCurrentTimeInt64(clockVfs, &t); 179289166Speter }else{ 180289166Speter double r; 181289166Speter clockVfs->xCurrentTime(clockVfs, &r); 182289166Speter t = (sqlite3_int64)(r*86400000.0); 183289166Speter } 184289166Speter return t; 185289166Speter} 186289166Speter 187289166Speter#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) 188251883Speter#include <sys/time.h> 189251883Speter#include <sys/resource.h> 190251883Speter 191289166Speter/* VxWorks does not support getrusage() as far as we can determine */ 192289166Speter#if defined(_WRS_KERNEL) || defined(__RTP__) 193289166Speterstruct rusage { 194289166Speter struct timeval ru_utime; /* user CPU time used */ 195289166Speter struct timeval ru_stime; /* system CPU time used */ 196289166Speter}; 197289166Speter#define getrusage(A,B) memset(B,0,sizeof(*B)) 198289166Speter#endif 199289166Speter 200251883Speter/* Saved resource information for the beginning of an operation */ 201289166Speterstatic struct rusage sBegin; /* CPU time at start */ 202289166Speterstatic sqlite3_int64 iBegin; /* Wall-clock time at start */ 203251883Speter 204251883Speter/* 205251883Speter** Begin timing an operation 206251883Speter*/ 207251883Speterstatic void beginTimer(void){ 208251883Speter if( enableTimer ){ 209251883Speter getrusage(RUSAGE_SELF, &sBegin); 210289166Speter iBegin = timeOfDay(); 211251883Speter } 212251883Speter} 213251883Speter 214251883Speter/* Return the difference of two time_structs in seconds */ 215251883Speterstatic double timeDiff(struct timeval *pStart, struct timeval *pEnd){ 216305003Scy return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + 217251883Speter (double)(pEnd->tv_sec - pStart->tv_sec); 218251883Speter} 219251883Speter 220251883Speter/* 221251883Speter** Print the timing results. 222251883Speter*/ 223251883Speterstatic void endTimer(void){ 224251883Speter if( enableTimer ){ 225289166Speter sqlite3_int64 iEnd = timeOfDay(); 226251883Speter struct rusage sEnd; 227251883Speter getrusage(RUSAGE_SELF, &sEnd); 228289166Speter printf("Run Time: real %.3f user %f sys %f\n", 229289166Speter (iEnd - iBegin)*0.001, 230251883Speter timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), 231251883Speter timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); 232251883Speter } 233251883Speter} 234251883Speter 235251883Speter#define BEGIN_TIMER beginTimer() 236251883Speter#define END_TIMER endTimer() 237251883Speter#define HAS_TIMER 1 238251883Speter 239251883Speter#elif (defined(_WIN32) || defined(WIN32)) 240251883Speter 241251883Speter/* Saved resource information for the beginning of an operation */ 242251883Speterstatic HANDLE hProcess; 243251883Speterstatic FILETIME ftKernelBegin; 244251883Speterstatic FILETIME ftUserBegin; 245289166Speterstatic sqlite3_int64 ftWallBegin; 246289166Spetertypedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, 247289166Speter LPFILETIME, LPFILETIME); 248251883Speterstatic GETPROCTIMES getProcessTimesAddr = NULL; 249251883Speter 250251883Speter/* 251251883Speter** Check to see if we have timer support. Return 1 if necessary 252251883Speter** support found (or found previously). 253251883Speter*/ 254251883Speterstatic int hasTimer(void){ 255251883Speter if( getProcessTimesAddr ){ 256251883Speter return 1; 257251883Speter } else { 258289166Speter /* GetProcessTimes() isn't supported in WIN95 and some other Windows 259289166Speter ** versions. See if the version we are running on has it, and if it 260289166Speter ** does, save off a pointer to it and the current process handle. 261251883Speter */ 262251883Speter hProcess = GetCurrentProcess(); 263251883Speter if( hProcess ){ 264251883Speter HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); 265251883Speter if( NULL != hinstLib ){ 266289166Speter getProcessTimesAddr = 267289166Speter (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); 268251883Speter if( NULL != getProcessTimesAddr ){ 269251883Speter return 1; 270251883Speter } 271305003Scy FreeLibrary(hinstLib); 272251883Speter } 273251883Speter } 274251883Speter } 275251883Speter return 0; 276251883Speter} 277251883Speter 278251883Speter/* 279251883Speter** Begin timing an operation 280251883Speter*/ 281251883Speterstatic void beginTimer(void){ 282251883Speter if( enableTimer && getProcessTimesAddr ){ 283251883Speter FILETIME ftCreation, ftExit; 284289166Speter getProcessTimesAddr(hProcess,&ftCreation,&ftExit, 285289166Speter &ftKernelBegin,&ftUserBegin); 286289166Speter ftWallBegin = timeOfDay(); 287251883Speter } 288251883Speter} 289251883Speter 290251883Speter/* Return the difference of two FILETIME structs in seconds */ 291251883Speterstatic double timeDiff(FILETIME *pStart, FILETIME *pEnd){ 292251883Speter sqlite_int64 i64Start = *((sqlite_int64 *) pStart); 293251883Speter sqlite_int64 i64End = *((sqlite_int64 *) pEnd); 294251883Speter return (double) ((i64End - i64Start) / 10000000.0); 295251883Speter} 296251883Speter 297251883Speter/* 298251883Speter** Print the timing results. 299251883Speter*/ 300251883Speterstatic void endTimer(void){ 301251883Speter if( enableTimer && getProcessTimesAddr){ 302251883Speter FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; 303289166Speter sqlite3_int64 ftWallEnd = timeOfDay(); 304289166Speter getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); 305289166Speter printf("Run Time: real %.3f user %f sys %f\n", 306289166Speter (ftWallEnd - ftWallBegin)*0.001, 307251883Speter timeDiff(&ftUserBegin, &ftUserEnd), 308251883Speter timeDiff(&ftKernelBegin, &ftKernelEnd)); 309251883Speter } 310251883Speter} 311251883Speter 312251883Speter#define BEGIN_TIMER beginTimer() 313251883Speter#define END_TIMER endTimer() 314251883Speter#define HAS_TIMER hasTimer() 315251883Speter 316251883Speter#else 317305003Scy#define BEGIN_TIMER 318251883Speter#define END_TIMER 319251883Speter#define HAS_TIMER 0 320251883Speter#endif 321251883Speter 322251883Speter/* 323251883Speter** Used to prevent warnings about unused parameters 324251883Speter*/ 325251883Speter#define UNUSED_PARAMETER(x) (void)(x) 326251883Speter 327251883Speter/* 328251883Speter** If the following flag is set, then command execution stops 329251883Speter** at an error if we are not interactive. 330251883Speter*/ 331251883Speterstatic int bail_on_error = 0; 332251883Speter 333251883Speter/* 334251883Speter** Threat stdin as an interactive input if the following variable 335251883Speter** is true. Otherwise, assume stdin is connected to a file or pipe. 336251883Speter*/ 337251883Speterstatic int stdin_is_interactive = 1; 338251883Speter 339251883Speter/* 340305003Scy** On Windows systems we have to know if standard output is a console 341305003Scy** in order to translate UTF-8 into MBCS. The following variable is 342305003Scy** true if translation is required. 343305003Scy*/ 344305003Scystatic int stdout_is_console = 1; 345305003Scy 346305003Scy/* 347251883Speter** The following is the open SQLite database. We make a pointer 348251883Speter** to this database a static variable so that it can be accessed 349251883Speter** by the SIGINT handler to interrupt database processing. 350251883Speter*/ 351289166Speterstatic sqlite3 *globalDb = 0; 352251883Speter 353251883Speter/* 354251883Speter** True if an interrupt (Control-C) has been received. 355251883Speter*/ 356251883Speterstatic volatile int seenInterrupt = 0; 357251883Speter 358251883Speter/* 359251883Speter** This is the name of our program. It is set in main(), used 360251883Speter** in a number of other places, mostly for error messages. 361251883Speter*/ 362251883Speterstatic char *Argv0; 363251883Speter 364251883Speter/* 365251883Speter** Prompt strings. Initialized in main. Settable with 366251883Speter** .prompt main continue 367251883Speter*/ 368251883Speterstatic char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/ 369251883Speterstatic char continuePrompt[20]; /* Continuation prompt. default: " ...> " */ 370251883Speter 371251883Speter/* 372305003Scy** Render output like fprintf(). Except, if the output is going to the 373305003Scy** console and if this is running on a Windows machine, translate the 374305003Scy** output from UTF-8 into MBCS. 375305003Scy*/ 376305003Scy#if defined(_WIN32) || defined(WIN32) 377305003Scyvoid utf8_printf(FILE *out, const char *zFormat, ...){ 378305003Scy va_list ap; 379305003Scy va_start(ap, zFormat); 380305003Scy if( stdout_is_console && (out==stdout || out==stderr) ){ 381305003Scy char *z1 = sqlite3_vmprintf(zFormat, ap); 382305003Scy char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0); 383305003Scy sqlite3_free(z1); 384305003Scy fputs(z2, out); 385305003Scy sqlite3_free(z2); 386305003Scy }else{ 387305003Scy vfprintf(out, zFormat, ap); 388305003Scy } 389305003Scy va_end(ap); 390305003Scy} 391305003Scy#elif !defined(utf8_printf) 392305003Scy# define utf8_printf fprintf 393305003Scy#endif 394305003Scy 395305003Scy/* 396305003Scy** Render output like fprintf(). This should not be used on anything that 397305003Scy** includes string formatting (e.g. "%s"). 398305003Scy*/ 399305003Scy#if !defined(raw_printf) 400305003Scy# define raw_printf fprintf 401305003Scy#endif 402305003Scy 403305003Scy/* 404251883Speter** Write I/O traces to the following stream. 405251883Speter*/ 406251883Speter#ifdef SQLITE_ENABLE_IOTRACE 407251883Speterstatic FILE *iotrace = 0; 408251883Speter#endif 409251883Speter 410251883Speter/* 411251883Speter** This routine works like printf in that its first argument is a 412251883Speter** format string and subsequent arguments are values to be substituted 413251883Speter** in place of % fields. The result of formatting this string 414251883Speter** is written to iotrace. 415251883Speter*/ 416251883Speter#ifdef SQLITE_ENABLE_IOTRACE 417289166Speterstatic void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ 418251883Speter va_list ap; 419251883Speter char *z; 420251883Speter if( iotrace==0 ) return; 421251883Speter va_start(ap, zFormat); 422251883Speter z = sqlite3_vmprintf(zFormat, ap); 423251883Speter va_end(ap); 424305003Scy utf8_printf(iotrace, "%s", z); 425251883Speter sqlite3_free(z); 426251883Speter} 427251883Speter#endif 428251883Speter 429251883Speter 430251883Speter/* 431251883Speter** Determines if a string is a number of not. 432251883Speter*/ 433251883Speterstatic int isNumber(const char *z, int *realnum){ 434251883Speter if( *z=='-' || *z=='+' ) z++; 435251883Speter if( !IsDigit(*z) ){ 436251883Speter return 0; 437251883Speter } 438251883Speter z++; 439251883Speter if( realnum ) *realnum = 0; 440251883Speter while( IsDigit(*z) ){ z++; } 441251883Speter if( *z=='.' ){ 442251883Speter z++; 443251883Speter if( !IsDigit(*z) ) return 0; 444251883Speter while( IsDigit(*z) ){ z++; } 445251883Speter if( realnum ) *realnum = 1; 446251883Speter } 447251883Speter if( *z=='e' || *z=='E' ){ 448251883Speter z++; 449251883Speter if( *z=='+' || *z=='-' ) z++; 450251883Speter if( !IsDigit(*z) ) return 0; 451251883Speter while( IsDigit(*z) ){ z++; } 452251883Speter if( realnum ) *realnum = 1; 453251883Speter } 454251883Speter return *z==0; 455251883Speter} 456251883Speter 457251883Speter/* 458305003Scy** A global char* and an SQL function to access its current value 459305003Scy** from within an SQL statement. This program used to use the 460251883Speter** sqlite_exec_printf() API to substitue a string into an SQL statement. 461251883Speter** The correct way to do this with sqlite3 is to use the bind API, but 462251883Speter** since the shell is built around the callback paradigm it would be a lot 463251883Speter** of work. Instead just use this hack, which is quite harmless. 464251883Speter*/ 465251883Speterstatic const char *zShellStatic = 0; 466251883Speterstatic void shellstaticFunc( 467251883Speter sqlite3_context *context, 468251883Speter int argc, 469251883Speter sqlite3_value **argv 470251883Speter){ 471251883Speter assert( 0==argc ); 472251883Speter assert( zShellStatic ); 473251883Speter UNUSED_PARAMETER(argc); 474251883Speter UNUSED_PARAMETER(argv); 475251883Speter sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC); 476251883Speter} 477251883Speter 478251883Speter 479251883Speter/* 480305003Scy** Compute a string length that is limited to what can be stored in 481305003Scy** lower 30 bits of a 32-bit signed integer. 482305003Scy*/ 483305003Scystatic int strlen30(const char *z){ 484305003Scy const char *z2 = z; 485305003Scy while( *z2 ){ z2++; } 486305003Scy return 0x3fffffff & (int)(z2 - z); 487305003Scy} 488305003Scy 489305003Scy/* 490251883Speter** This routine reads a line of text from FILE in, stores 491251883Speter** the text in memory obtained from malloc() and returns a pointer 492251883Speter** to the text. NULL is returned at end of file, or if malloc() 493251883Speter** fails. 494251883Speter** 495289166Speter** If zLine is not NULL then it is a malloced buffer returned from 496289166Speter** a previous call to this routine that may be reused. 497251883Speter*/ 498289166Speterstatic char *local_getline(char *zLine, FILE *in){ 499289166Speter int nLine = zLine==0 ? 0 : 100; 500289166Speter int n = 0; 501251883Speter 502251883Speter while( 1 ){ 503251883Speter if( n+100>nLine ){ 504251883Speter nLine = nLine*2 + 100; 505251883Speter zLine = realloc(zLine, nLine); 506251883Speter if( zLine==0 ) return 0; 507251883Speter } 508251883Speter if( fgets(&zLine[n], nLine - n, in)==0 ){ 509251883Speter if( n==0 ){ 510251883Speter free(zLine); 511251883Speter return 0; 512251883Speter } 513251883Speter zLine[n] = 0; 514251883Speter break; 515251883Speter } 516289166Speter while( zLine[n] ) n++; 517289166Speter if( n>0 && zLine[n-1]=='\n' ){ 518251883Speter n--; 519251883Speter if( n>0 && zLine[n-1]=='\r' ) n--; 520251883Speter zLine[n] = 0; 521251883Speter break; 522251883Speter } 523251883Speter } 524305003Scy#if defined(_WIN32) || defined(WIN32) 525305003Scy /* For interactive input on Windows systems, translate the 526305003Scy ** multi-byte characterset characters into UTF-8. */ 527305003Scy if( stdin_is_interactive ){ 528305003Scy char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); 529305003Scy if( zTrans ){ 530305003Scy int nTrans = strlen30(zTrans)+1; 531305003Scy if( nTrans>nLine ){ 532305003Scy zLine = realloc(zLine, nTrans); 533305003Scy if( zLine==0 ){ 534305003Scy sqlite3_free(zTrans); 535305003Scy return 0; 536305003Scy } 537305003Scy } 538305003Scy memcpy(zLine, zTrans, nTrans); 539305003Scy sqlite3_free(zTrans); 540305003Scy } 541305003Scy } 542305003Scy#endif /* defined(_WIN32) || defined(WIN32) */ 543251883Speter return zLine; 544251883Speter} 545251883Speter 546251883Speter/* 547251883Speter** Retrieve a single line of input text. 548251883Speter** 549289166Speter** If in==0 then read from standard input and prompt before each line. 550289166Speter** If isContinuation is true, then a continuation prompt is appropriate. 551289166Speter** If isContinuation is zero, then the main prompt should be used. 552289166Speter** 553289166Speter** If zPrior is not NULL then it is a buffer from a prior call to this 554289166Speter** routine that can be reused. 555289166Speter** 556289166Speter** The result is stored in space obtained from malloc() and must either 557289166Speter** be freed by the caller or else passed back into this routine via the 558289166Speter** zPrior argument for reuse. 559251883Speter*/ 560289166Speterstatic char *one_input_line(FILE *in, char *zPrior, int isContinuation){ 561251883Speter char *zPrompt; 562251883Speter char *zResult; 563251883Speter if( in!=0 ){ 564289166Speter zResult = local_getline(zPrior, in); 565251883Speter }else{ 566289166Speter zPrompt = isContinuation ? continuePrompt : mainPrompt; 567289166Speter#if SHELL_USE_LOCAL_GETLINE 568289166Speter printf("%s", zPrompt); 569289166Speter fflush(stdout); 570289166Speter zResult = local_getline(zPrior, stdin); 571289166Speter#else 572289166Speter free(zPrior); 573289166Speter zResult = shell_readline(zPrompt); 574289166Speter if( zResult && *zResult ) shell_add_history(zResult); 575289166Speter#endif 576251883Speter } 577251883Speter return zResult; 578251883Speter} 579251883Speter 580305003Scy#if defined(SQLITE_ENABLE_SESSION) 581289166Speter/* 582305003Scy** State information for a single open session 583305003Scy*/ 584305003Scytypedef struct OpenSession OpenSession; 585305003Scystruct OpenSession { 586305003Scy char *zName; /* Symbolic name for this session */ 587305003Scy int nFilter; /* Number of xFilter rejection GLOB patterns */ 588305003Scy char **azFilter; /* Array of xFilter rejection GLOB patterns */ 589305003Scy sqlite3_session *p; /* The open session */ 590305003Scy}; 591305003Scy#endif 592305003Scy 593305003Scy/* 594305003Scy** Shell output mode information from before ".explain on", 595289166Speter** saved so that it can be restored by ".explain off" 596289166Speter*/ 597289166Spetertypedef struct SavedModeInfo SavedModeInfo; 598289166Speterstruct SavedModeInfo { 599289166Speter int valid; /* Is there legit data in here? */ 600289166Speter int mode; /* Mode prior to ".explain on" */ 601289166Speter int showHeader; /* The ".header" setting prior to ".explain on" */ 602289166Speter int colWidth[100]; /* Column widths prior to ".explain on" */ 603251883Speter}; 604251883Speter 605251883Speter/* 606289166Speter** State information about the database connection is contained in an 607289166Speter** instance of the following structure. 608251883Speter*/ 609289166Spetertypedef struct ShellState ShellState; 610289166Speterstruct ShellState { 611251883Speter sqlite3 *db; /* The database */ 612251883Speter int echoOn; /* True to echo input commands */ 613305003Scy int autoExplain; /* Automatically turn on .explain mode */ 614289166Speter int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ 615251883Speter int statsOn; /* True to display memory stats before each finalize */ 616289166Speter int scanstatsOn; /* True to display scan stats before each finalize */ 617305003Scy int countChanges; /* True to display change counts */ 618289166Speter int backslashOn; /* Resolve C-style \x escapes in SQL input text */ 619289166Speter int outCount; /* Revert to stdout when reaching zero */ 620251883Speter int cnt; /* Number of records displayed so far */ 621251883Speter FILE *out; /* Write results here */ 622251883Speter FILE *traceOut; /* Output for sqlite3_trace() */ 623251883Speter int nErr; /* Number of errors seen */ 624251883Speter int mode; /* An output mode setting */ 625305003Scy int cMode; /* temporary output mode for the current query */ 626305003Scy int normalMode; /* Output mode before ".explain on" */ 627251883Speter int writableSchema; /* True if PRAGMA writable_schema=ON */ 628251883Speter int showHeader; /* True to show column names in List or Column mode */ 629289166Speter unsigned shellFlgs; /* Various flags */ 630251883Speter char *zDestTable; /* Name of destination table when MODE_Insert */ 631289166Speter char colSeparator[20]; /* Column separator character for several modes */ 632289166Speter char rowSeparator[20]; /* Row separator character for MODE_Ascii */ 633251883Speter int colWidth[100]; /* Requested width of each column when in column mode*/ 634251883Speter int actualWidth[100]; /* Actual width of each column */ 635289166Speter char nullValue[20]; /* The text to print when a NULL comes back from 636251883Speter ** the database */ 637251883Speter char outfile[FILENAME_MAX]; /* Filename for *out */ 638251883Speter const char *zDbFilename; /* name of the database file */ 639289166Speter char *zFreeOnClose; /* Filename to free when closing */ 640251883Speter const char *zVfs; /* Name of VFS to use */ 641251883Speter sqlite3_stmt *pStmt; /* Current statement if any. */ 642251883Speter FILE *pLog; /* Write log output here */ 643289166Speter int *aiIndent; /* Array of indents used in MODE_Explain */ 644289166Speter int nIndent; /* Size of array aiIndent[] */ 645289166Speter int iIndent; /* Index of current op in aiIndent[] */ 646305003Scy#if defined(SQLITE_ENABLE_SESSION) 647305003Scy int nSession; /* Number of active sessions */ 648305003Scy OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */ 649305003Scy#endif 650251883Speter}; 651251883Speter 652251883Speter/* 653289166Speter** These are the allowed shellFlgs values 654289166Speter*/ 655289166Speter#define SHFLG_Scratch 0x00001 /* The --scratch option is used */ 656289166Speter#define SHFLG_Pagecache 0x00002 /* The --pagecache option is used */ 657289166Speter#define SHFLG_Lookaside 0x00004 /* Lookaside memory is used */ 658289166Speter 659289166Speter/* 660251883Speter** These are the allowed modes. 661251883Speter*/ 662251883Speter#define MODE_Line 0 /* One column per line. Blank line between records */ 663251883Speter#define MODE_Column 1 /* One record per line in neat columns */ 664251883Speter#define MODE_List 2 /* One record per line with a separator */ 665251883Speter#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */ 666251883Speter#define MODE_Html 4 /* Generate an XHTML table */ 667251883Speter#define MODE_Insert 5 /* Generate SQL "insert" statements */ 668251883Speter#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */ 669251883Speter#define MODE_Csv 7 /* Quote strings, numbers are plain */ 670251883Speter#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */ 671289166Speter#define MODE_Ascii 9 /* Use ASCII unit and record separators (0x1F/0x1E) */ 672305003Scy#define MODE_Pretty 10 /* Pretty-print schemas */ 673251883Speter 674251883Speterstatic const char *modeDescr[] = { 675251883Speter "line", 676251883Speter "column", 677251883Speter "list", 678251883Speter "semi", 679251883Speter "html", 680251883Speter "insert", 681251883Speter "tcl", 682251883Speter "csv", 683251883Speter "explain", 684289166Speter "ascii", 685305003Scy "prettyprint", 686251883Speter}; 687251883Speter 688251883Speter/* 689289166Speter** These are the column/row/line separators used by the various 690289166Speter** import/export modes. 691289166Speter*/ 692289166Speter#define SEP_Column "|" 693289166Speter#define SEP_Row "\n" 694289166Speter#define SEP_Tab "\t" 695289166Speter#define SEP_Space " " 696289166Speter#define SEP_Comma "," 697289166Speter#define SEP_CrLf "\r\n" 698289166Speter#define SEP_Unit "\x1F" 699289166Speter#define SEP_Record "\x1E" 700289166Speter 701289166Speter/* 702251883Speter** Number of elements in an array 703251883Speter*/ 704251883Speter#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) 705251883Speter 706251883Speter/* 707251883Speter** A callback for the sqlite3_log() interface. 708251883Speter*/ 709251883Speterstatic void shellLog(void *pArg, int iErrCode, const char *zMsg){ 710289166Speter ShellState *p = (ShellState*)pArg; 711251883Speter if( p->pLog==0 ) return; 712305003Scy utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg); 713251883Speter fflush(p->pLog); 714251883Speter} 715251883Speter 716251883Speter/* 717251883Speter** Output the given string as a hex-encoded blob (eg. X'1234' ) 718251883Speter*/ 719251883Speterstatic void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ 720251883Speter int i; 721251883Speter char *zBlob = (char *)pBlob; 722305003Scy raw_printf(out,"X'"); 723305003Scy for(i=0; i<nBlob; i++){ raw_printf(out,"%02x",zBlob[i]&0xff); } 724305003Scy raw_printf(out,"'"); 725251883Speter} 726251883Speter 727251883Speter/* 728251883Speter** Output the given string as a quoted string using SQL quoting conventions. 729251883Speter*/ 730251883Speterstatic void output_quoted_string(FILE *out, const char *z){ 731251883Speter int i; 732251883Speter int nSingle = 0; 733305003Scy setBinaryMode(out, 1); 734251883Speter for(i=0; z[i]; i++){ 735251883Speter if( z[i]=='\'' ) nSingle++; 736251883Speter } 737251883Speter if( nSingle==0 ){ 738305003Scy utf8_printf(out,"'%s'",z); 739251883Speter }else{ 740305003Scy raw_printf(out,"'"); 741251883Speter while( *z ){ 742251883Speter for(i=0; z[i] && z[i]!='\''; i++){} 743251883Speter if( i==0 ){ 744305003Scy raw_printf(out,"''"); 745251883Speter z++; 746251883Speter }else if( z[i]=='\'' ){ 747305003Scy utf8_printf(out,"%.*s''",i,z); 748251883Speter z += i+1; 749251883Speter }else{ 750305003Scy utf8_printf(out,"%s",z); 751251883Speter break; 752251883Speter } 753251883Speter } 754305003Scy raw_printf(out,"'"); 755251883Speter } 756305003Scy setTextMode(out, 1); 757251883Speter} 758251883Speter 759251883Speter/* 760251883Speter** Output the given string as a quoted according to C or TCL quoting rules. 761251883Speter*/ 762251883Speterstatic void output_c_string(FILE *out, const char *z){ 763251883Speter unsigned int c; 764251883Speter fputc('"', out); 765251883Speter while( (c = *(z++))!=0 ){ 766251883Speter if( c=='\\' ){ 767251883Speter fputc(c, out); 768251883Speter fputc(c, out); 769251883Speter }else if( c=='"' ){ 770251883Speter fputc('\\', out); 771251883Speter fputc('"', out); 772251883Speter }else if( c=='\t' ){ 773251883Speter fputc('\\', out); 774251883Speter fputc('t', out); 775251883Speter }else if( c=='\n' ){ 776251883Speter fputc('\\', out); 777251883Speter fputc('n', out); 778251883Speter }else if( c=='\r' ){ 779251883Speter fputc('\\', out); 780251883Speter fputc('r', out); 781289166Speter }else if( !isprint(c&0xff) ){ 782305003Scy raw_printf(out, "\\%03o", c&0xff); 783251883Speter }else{ 784251883Speter fputc(c, out); 785251883Speter } 786251883Speter } 787251883Speter fputc('"', out); 788251883Speter} 789251883Speter 790251883Speter/* 791251883Speter** Output the given string with characters that are special to 792251883Speter** HTML escaped. 793251883Speter*/ 794251883Speterstatic void output_html_string(FILE *out, const char *z){ 795251883Speter int i; 796289166Speter if( z==0 ) z = ""; 797251883Speter while( *z ){ 798305003Scy for(i=0; z[i] 799305003Scy && z[i]!='<' 800305003Scy && z[i]!='&' 801305003Scy && z[i]!='>' 802305003Scy && z[i]!='\"' 803251883Speter && z[i]!='\''; 804251883Speter i++){} 805251883Speter if( i>0 ){ 806305003Scy utf8_printf(out,"%.*s",i,z); 807251883Speter } 808251883Speter if( z[i]=='<' ){ 809305003Scy raw_printf(out,"<"); 810251883Speter }else if( z[i]=='&' ){ 811305003Scy raw_printf(out,"&"); 812251883Speter }else if( z[i]=='>' ){ 813305003Scy raw_printf(out,">"); 814251883Speter }else if( z[i]=='\"' ){ 815305003Scy raw_printf(out,"""); 816251883Speter }else if( z[i]=='\'' ){ 817305003Scy raw_printf(out,"'"); 818251883Speter }else{ 819251883Speter break; 820251883Speter } 821251883Speter z += i + 1; 822251883Speter } 823251883Speter} 824251883Speter 825251883Speter/* 826251883Speter** If a field contains any character identified by a 1 in the following 827251883Speter** array, then the string must be quoted for CSV. 828251883Speter*/ 829251883Speterstatic const char needCsvQuote[] = { 830305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 831305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 832305003Scy 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 833305003Scy 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 834305003Scy 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 835305003Scy 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 836305003Scy 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 837305003Scy 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 838305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 839305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 840305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 841305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 842305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 843305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 844305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 845305003Scy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 846251883Speter}; 847251883Speter 848251883Speter/* 849289166Speter** Output a single term of CSV. Actually, p->colSeparator is used for 850289166Speter** the separator, which may or may not be a comma. p->nullValue is 851289166Speter** the null value. Strings are quoted if necessary. The separator 852289166Speter** is only issued if bSep is true. 853251883Speter*/ 854289166Speterstatic void output_csv(ShellState *p, const char *z, int bSep){ 855251883Speter FILE *out = p->out; 856251883Speter if( z==0 ){ 857305003Scy utf8_printf(out,"%s",p->nullValue); 858251883Speter }else{ 859251883Speter int i; 860289166Speter int nSep = strlen30(p->colSeparator); 861251883Speter for(i=0; z[i]; i++){ 862305003Scy if( needCsvQuote[((unsigned char*)z)[i]] 863305003Scy || (z[i]==p->colSeparator[0] && 864289166Speter (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){ 865251883Speter i = 0; 866251883Speter break; 867251883Speter } 868251883Speter } 869251883Speter if( i==0 ){ 870251883Speter putc('"', out); 871251883Speter for(i=0; z[i]; i++){ 872251883Speter if( z[i]=='"' ) putc('"', out); 873251883Speter putc(z[i], out); 874251883Speter } 875251883Speter putc('"', out); 876251883Speter }else{ 877305003Scy utf8_printf(out, "%s", z); 878251883Speter } 879251883Speter } 880251883Speter if( bSep ){ 881305003Scy utf8_printf(p->out, "%s", p->colSeparator); 882251883Speter } 883251883Speter} 884251883Speter 885251883Speter#ifdef SIGINT 886251883Speter/* 887251883Speter** This routine runs when the user presses Ctrl-C 888251883Speter*/ 889251883Speterstatic void interrupt_handler(int NotUsed){ 890251883Speter UNUSED_PARAMETER(NotUsed); 891289166Speter seenInterrupt++; 892289166Speter if( seenInterrupt>2 ) exit(1); 893289166Speter if( globalDb ) sqlite3_interrupt(globalDb); 894251883Speter} 895251883Speter#endif 896251883Speter 897251883Speter/* 898305003Scy** When the ".auth ON" is set, the following authorizer callback is 899305003Scy** invoked. It always returns SQLITE_OK. 900305003Scy*/ 901305003Scystatic int shellAuth( 902305003Scy void *pClientData, 903305003Scy int op, 904305003Scy const char *zA1, 905305003Scy const char *zA2, 906305003Scy const char *zA3, 907305003Scy const char *zA4 908305003Scy){ 909305003Scy ShellState *p = (ShellState*)pClientData; 910305003Scy static const char *azAction[] = { 0, 911305003Scy "CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX", 912305003Scy "CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW", 913305003Scy "CREATE_TRIGGER", "CREATE_VIEW", "DELETE", 914305003Scy "DROP_INDEX", "DROP_TABLE", "DROP_TEMP_INDEX", 915305003Scy "DROP_TEMP_TABLE", "DROP_TEMP_TRIGGER", "DROP_TEMP_VIEW", 916305003Scy "DROP_TRIGGER", "DROP_VIEW", "INSERT", 917305003Scy "PRAGMA", "READ", "SELECT", 918305003Scy "TRANSACTION", "UPDATE", "ATTACH", 919305003Scy "DETACH", "ALTER_TABLE", "REINDEX", 920305003Scy "ANALYZE", "CREATE_VTABLE", "DROP_VTABLE", 921305003Scy "FUNCTION", "SAVEPOINT", "RECURSIVE" 922305003Scy }; 923305003Scy int i; 924305003Scy const char *az[4]; 925305003Scy az[0] = zA1; 926305003Scy az[1] = zA2; 927305003Scy az[2] = zA3; 928305003Scy az[3] = zA4; 929305003Scy raw_printf(p->out, "authorizer: %s", azAction[op]); 930305003Scy for(i=0; i<4; i++){ 931305003Scy raw_printf(p->out, " "); 932305003Scy if( az[i] ){ 933305003Scy output_c_string(p->out, az[i]); 934305003Scy }else{ 935305003Scy raw_printf(p->out, "NULL"); 936305003Scy } 937305003Scy } 938305003Scy raw_printf(p->out, "\n"); 939305003Scy return SQLITE_OK; 940305003Scy} 941305003Scy 942305003Scy 943305003Scy/* 944251883Speter** This is the callback routine that the shell 945251883Speter** invokes for each row of a query result. 946251883Speter*/ 947289166Speterstatic int shell_callback( 948289166Speter void *pArg, 949289166Speter int nArg, /* Number of result columns */ 950289166Speter char **azArg, /* Text of each result column */ 951289166Speter char **azCol, /* Column names */ 952289166Speter int *aiType /* Column types */ 953289166Speter){ 954251883Speter int i; 955289166Speter ShellState *p = (ShellState*)pArg; 956251883Speter 957305003Scy switch( p->cMode ){ 958251883Speter case MODE_Line: { 959251883Speter int w = 5; 960251883Speter if( azArg==0 ) break; 961251883Speter for(i=0; i<nArg; i++){ 962251883Speter int len = strlen30(azCol[i] ? azCol[i] : ""); 963251883Speter if( len>w ) w = len; 964251883Speter } 965305003Scy if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator); 966251883Speter for(i=0; i<nArg; i++){ 967305003Scy utf8_printf(p->out,"%*s = %s%s", w, azCol[i], 968289166Speter azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator); 969251883Speter } 970251883Speter break; 971251883Speter } 972251883Speter case MODE_Explain: 973251883Speter case MODE_Column: { 974305003Scy static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13}; 975305003Scy const int *colWidth; 976305003Scy int showHdr; 977305003Scy char *rowSep; 978305003Scy if( p->cMode==MODE_Column ){ 979305003Scy colWidth = p->colWidth; 980305003Scy showHdr = p->showHeader; 981305003Scy rowSep = p->rowSeparator; 982305003Scy }else{ 983305003Scy colWidth = aExplainWidths; 984305003Scy showHdr = 1; 985305003Scy rowSep = SEP_Row; 986305003Scy } 987251883Speter if( p->cnt++==0 ){ 988251883Speter for(i=0; i<nArg; i++){ 989251883Speter int w, n; 990251883Speter if( i<ArraySize(p->colWidth) ){ 991305003Scy w = colWidth[i]; 992251883Speter }else{ 993251883Speter w = 0; 994251883Speter } 995251883Speter if( w==0 ){ 996251883Speter w = strlen30(azCol[i] ? azCol[i] : ""); 997251883Speter if( w<10 ) w = 10; 998289166Speter n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue); 999251883Speter if( w<n ) w = n; 1000251883Speter } 1001251883Speter if( i<ArraySize(p->actualWidth) ){ 1002251883Speter p->actualWidth[i] = w; 1003251883Speter } 1004305003Scy if( showHdr ){ 1005251883Speter if( w<0 ){ 1006305003Scy utf8_printf(p->out,"%*.*s%s",-w,-w,azCol[i], 1007305003Scy i==nArg-1 ? rowSep : " "); 1008251883Speter }else{ 1009305003Scy utf8_printf(p->out,"%-*.*s%s",w,w,azCol[i], 1010305003Scy i==nArg-1 ? rowSep : " "); 1011251883Speter } 1012251883Speter } 1013251883Speter } 1014305003Scy if( showHdr ){ 1015251883Speter for(i=0; i<nArg; i++){ 1016251883Speter int w; 1017251883Speter if( i<ArraySize(p->actualWidth) ){ 1018251883Speter w = p->actualWidth[i]; 1019251883Speter if( w<0 ) w = -w; 1020251883Speter }else{ 1021251883Speter w = 10; 1022251883Speter } 1023305003Scy utf8_printf(p->out,"%-*.*s%s",w,w, 1024305003Scy "----------------------------------------------------------" 1025251883Speter "----------------------------------------------------------", 1026305003Scy i==nArg-1 ? rowSep : " "); 1027251883Speter } 1028251883Speter } 1029251883Speter } 1030251883Speter if( azArg==0 ) break; 1031251883Speter for(i=0; i<nArg; i++){ 1032251883Speter int w; 1033251883Speter if( i<ArraySize(p->actualWidth) ){ 1034251883Speter w = p->actualWidth[i]; 1035251883Speter }else{ 1036251883Speter w = 10; 1037251883Speter } 1038305003Scy if( p->cMode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){ 1039251883Speter w = strlen30(azArg[i]); 1040251883Speter } 1041289166Speter if( i==1 && p->aiIndent && p->pStmt ){ 1042289166Speter if( p->iIndent<p->nIndent ){ 1043305003Scy utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); 1044289166Speter } 1045289166Speter p->iIndent++; 1046289166Speter } 1047251883Speter if( w<0 ){ 1048305003Scy utf8_printf(p->out,"%*.*s%s",-w,-w, 1049289166Speter azArg[i] ? azArg[i] : p->nullValue, 1050305003Scy i==nArg-1 ? rowSep : " "); 1051251883Speter }else{ 1052305003Scy utf8_printf(p->out,"%-*.*s%s",w,w, 1053289166Speter azArg[i] ? azArg[i] : p->nullValue, 1054305003Scy i==nArg-1 ? rowSep : " "); 1055251883Speter } 1056251883Speter } 1057251883Speter break; 1058251883Speter } 1059305003Scy case MODE_Semi: { /* .schema and .fullschema output */ 1060305003Scy utf8_printf(p->out, "%s;\n", azArg[0]); 1061305003Scy break; 1062305003Scy } 1063305003Scy case MODE_Pretty: { /* .schema and .fullschema with --indent */ 1064305003Scy char *z; 1065305003Scy int j; 1066305003Scy int nParen = 0; 1067305003Scy char cEnd = 0; 1068305003Scy char c; 1069305003Scy int nLine = 0; 1070305003Scy assert( nArg==1 ); 1071305003Scy if( azArg[0]==0 ) break; 1072305003Scy if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0 1073305003Scy || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0 1074305003Scy ){ 1075305003Scy utf8_printf(p->out, "%s;\n", azArg[0]); 1076305003Scy break; 1077305003Scy } 1078305003Scy z = sqlite3_mprintf("%s", azArg[0]); 1079305003Scy j = 0; 1080305003Scy for(i=0; IsSpace(z[i]); i++){} 1081305003Scy for(; (c = z[i])!=0; i++){ 1082305003Scy if( IsSpace(c) ){ 1083305003Scy if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue; 1084305003Scy }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){ 1085305003Scy j--; 1086305003Scy } 1087305003Scy z[j++] = c; 1088305003Scy } 1089305003Scy while( j>0 && IsSpace(z[j-1]) ){ j--; } 1090305003Scy z[j] = 0; 1091305003Scy if( strlen30(z)>=79 ){ 1092305003Scy for(i=j=0; (c = z[i])!=0; i++){ 1093305003Scy if( c==cEnd ){ 1094305003Scy cEnd = 0; 1095305003Scy }else if( c=='"' || c=='\'' || c=='`' ){ 1096305003Scy cEnd = c; 1097305003Scy }else if( c=='[' ){ 1098305003Scy cEnd = ']'; 1099305003Scy }else if( c=='(' ){ 1100305003Scy nParen++; 1101305003Scy }else if( c==')' ){ 1102305003Scy nParen--; 1103305003Scy if( nLine>0 && nParen==0 && j>0 ){ 1104305003Scy utf8_printf(p->out, "%.*s\n", j, z); 1105305003Scy j = 0; 1106305003Scy } 1107305003Scy } 1108305003Scy z[j++] = c; 1109305003Scy if( nParen==1 && (c=='(' || c==',' || c=='\n') ){ 1110305003Scy if( c=='\n' ) j--; 1111305003Scy utf8_printf(p->out, "%.*s\n ", j, z); 1112305003Scy j = 0; 1113305003Scy nLine++; 1114305003Scy while( IsSpace(z[i+1]) ){ i++; } 1115305003Scy } 1116305003Scy } 1117305003Scy z[j] = 0; 1118305003Scy } 1119305003Scy utf8_printf(p->out, "%s;\n", z); 1120305003Scy sqlite3_free(z); 1121305003Scy break; 1122305003Scy } 1123251883Speter case MODE_List: { 1124251883Speter if( p->cnt++==0 && p->showHeader ){ 1125251883Speter for(i=0; i<nArg; i++){ 1126305003Scy utf8_printf(p->out,"%s%s",azCol[i], 1127289166Speter i==nArg-1 ? p->rowSeparator : p->colSeparator); 1128251883Speter } 1129251883Speter } 1130251883Speter if( azArg==0 ) break; 1131251883Speter for(i=0; i<nArg; i++){ 1132251883Speter char *z = azArg[i]; 1133289166Speter if( z==0 ) z = p->nullValue; 1134305003Scy utf8_printf(p->out, "%s", z); 1135251883Speter if( i<nArg-1 ){ 1136305003Scy utf8_printf(p->out, "%s", p->colSeparator); 1137251883Speter }else{ 1138305003Scy utf8_printf(p->out, "%s", p->rowSeparator); 1139251883Speter } 1140251883Speter } 1141251883Speter break; 1142251883Speter } 1143251883Speter case MODE_Html: { 1144251883Speter if( p->cnt++==0 && p->showHeader ){ 1145305003Scy raw_printf(p->out,"<TR>"); 1146251883Speter for(i=0; i<nArg; i++){ 1147305003Scy raw_printf(p->out,"<TH>"); 1148251883Speter output_html_string(p->out, azCol[i]); 1149305003Scy raw_printf(p->out,"</TH>\n"); 1150251883Speter } 1151305003Scy raw_printf(p->out,"</TR>\n"); 1152251883Speter } 1153251883Speter if( azArg==0 ) break; 1154305003Scy raw_printf(p->out,"<TR>"); 1155251883Speter for(i=0; i<nArg; i++){ 1156305003Scy raw_printf(p->out,"<TD>"); 1157289166Speter output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue); 1158305003Scy raw_printf(p->out,"</TD>\n"); 1159251883Speter } 1160305003Scy raw_printf(p->out,"</TR>\n"); 1161251883Speter break; 1162251883Speter } 1163251883Speter case MODE_Tcl: { 1164251883Speter if( p->cnt++==0 && p->showHeader ){ 1165251883Speter for(i=0; i<nArg; i++){ 1166251883Speter output_c_string(p->out,azCol[i] ? azCol[i] : ""); 1167305003Scy if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator); 1168251883Speter } 1169305003Scy utf8_printf(p->out, "%s", p->rowSeparator); 1170251883Speter } 1171251883Speter if( azArg==0 ) break; 1172251883Speter for(i=0; i<nArg; i++){ 1173289166Speter output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue); 1174305003Scy if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator); 1175251883Speter } 1176305003Scy utf8_printf(p->out, "%s", p->rowSeparator); 1177251883Speter break; 1178251883Speter } 1179251883Speter case MODE_Csv: { 1180305003Scy setBinaryMode(p->out, 1); 1181251883Speter if( p->cnt++==0 && p->showHeader ){ 1182251883Speter for(i=0; i<nArg; i++){ 1183251883Speter output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1); 1184251883Speter } 1185305003Scy utf8_printf(p->out, "%s", p->rowSeparator); 1186251883Speter } 1187289166Speter if( nArg>0 ){ 1188289166Speter for(i=0; i<nArg; i++){ 1189289166Speter output_csv(p, azArg[i], i<nArg-1); 1190289166Speter } 1191305003Scy utf8_printf(p->out, "%s", p->rowSeparator); 1192251883Speter } 1193305003Scy setTextMode(p->out, 1); 1194251883Speter break; 1195251883Speter } 1196251883Speter case MODE_Insert: { 1197251883Speter p->cnt++; 1198251883Speter if( azArg==0 ) break; 1199305003Scy utf8_printf(p->out,"INSERT INTO %s",p->zDestTable); 1200289166Speter if( p->showHeader ){ 1201305003Scy raw_printf(p->out,"("); 1202289166Speter for(i=0; i<nArg; i++){ 1203289166Speter char *zSep = i>0 ? ",": ""; 1204305003Scy utf8_printf(p->out, "%s%s", zSep, azCol[i]); 1205289166Speter } 1206305003Scy raw_printf(p->out,")"); 1207289166Speter } 1208305003Scy raw_printf(p->out," VALUES("); 1209251883Speter for(i=0; i<nArg; i++){ 1210251883Speter char *zSep = i>0 ? ",": ""; 1211251883Speter if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ 1212305003Scy utf8_printf(p->out,"%sNULL",zSep); 1213251883Speter }else if( aiType && aiType[i]==SQLITE_TEXT ){ 1214305003Scy if( zSep[0] ) utf8_printf(p->out,"%s",zSep); 1215251883Speter output_quoted_string(p->out, azArg[i]); 1216289166Speter }else if( aiType && (aiType[i]==SQLITE_INTEGER 1217289166Speter || aiType[i]==SQLITE_FLOAT) ){ 1218305003Scy utf8_printf(p->out,"%s%s",zSep, azArg[i]); 1219251883Speter }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ 1220251883Speter const void *pBlob = sqlite3_column_blob(p->pStmt, i); 1221251883Speter int nBlob = sqlite3_column_bytes(p->pStmt, i); 1222305003Scy if( zSep[0] ) utf8_printf(p->out,"%s",zSep); 1223251883Speter output_hex_blob(p->out, pBlob, nBlob); 1224251883Speter }else if( isNumber(azArg[i], 0) ){ 1225305003Scy utf8_printf(p->out,"%s%s",zSep, azArg[i]); 1226251883Speter }else{ 1227305003Scy if( zSep[0] ) utf8_printf(p->out,"%s",zSep); 1228251883Speter output_quoted_string(p->out, azArg[i]); 1229251883Speter } 1230251883Speter } 1231305003Scy raw_printf(p->out,");\n"); 1232251883Speter break; 1233251883Speter } 1234289166Speter case MODE_Ascii: { 1235289166Speter if( p->cnt++==0 && p->showHeader ){ 1236289166Speter for(i=0; i<nArg; i++){ 1237305003Scy if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator); 1238305003Scy utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : ""); 1239289166Speter } 1240305003Scy utf8_printf(p->out, "%s", p->rowSeparator); 1241289166Speter } 1242289166Speter if( azArg==0 ) break; 1243289166Speter for(i=0; i<nArg; i++){ 1244305003Scy if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator); 1245305003Scy utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue); 1246289166Speter } 1247305003Scy utf8_printf(p->out, "%s", p->rowSeparator); 1248289166Speter break; 1249289166Speter } 1250251883Speter } 1251251883Speter return 0; 1252251883Speter} 1253251883Speter 1254251883Speter/* 1255251883Speter** This is the callback routine that the SQLite library 1256251883Speter** invokes for each row of a query result. 1257251883Speter*/ 1258251883Speterstatic int callback(void *pArg, int nArg, char **azArg, char **azCol){ 1259251883Speter /* since we don't have type info, call the shell_callback with a NULL value */ 1260251883Speter return shell_callback(pArg, nArg, azArg, azCol, NULL); 1261251883Speter} 1262251883Speter 1263251883Speter/* 1264289166Speter** Set the destination table field of the ShellState structure to 1265251883Speter** the name of the table given. Escape any quote characters in the 1266251883Speter** table name. 1267251883Speter*/ 1268289166Speterstatic void set_table_name(ShellState *p, const char *zName){ 1269251883Speter int i, n; 1270251883Speter int needQuote; 1271251883Speter char *z; 1272251883Speter 1273251883Speter if( p->zDestTable ){ 1274251883Speter free(p->zDestTable); 1275251883Speter p->zDestTable = 0; 1276251883Speter } 1277251883Speter if( zName==0 ) return; 1278251883Speter needQuote = !isalpha((unsigned char)*zName) && *zName!='_'; 1279251883Speter for(i=n=0; zName[i]; i++, n++){ 1280251883Speter if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){ 1281251883Speter needQuote = 1; 1282251883Speter if( zName[i]=='\'' ) n++; 1283251883Speter } 1284251883Speter } 1285251883Speter if( needQuote ) n += 2; 1286251883Speter z = p->zDestTable = malloc( n+1 ); 1287251883Speter if( z==0 ){ 1288305003Scy raw_printf(stderr,"Error: out of memory\n"); 1289251883Speter exit(1); 1290251883Speter } 1291251883Speter n = 0; 1292251883Speter if( needQuote ) z[n++] = '\''; 1293251883Speter for(i=0; zName[i]; i++){ 1294251883Speter z[n++] = zName[i]; 1295251883Speter if( zName[i]=='\'' ) z[n++] = '\''; 1296251883Speter } 1297251883Speter if( needQuote ) z[n++] = '\''; 1298251883Speter z[n] = 0; 1299251883Speter} 1300251883Speter 1301251883Speter/* zIn is either a pointer to a NULL-terminated string in memory obtained 1302251883Speter** from malloc(), or a NULL pointer. The string pointed to by zAppend is 1303251883Speter** added to zIn, and the result returned in memory obtained from malloc(). 1304251883Speter** zIn, if it was not NULL, is freed. 1305251883Speter** 1306305003Scy** If the third argument, quote, is not '\0', then it is used as a 1307251883Speter** quote character for zAppend. 1308251883Speter*/ 1309251883Speterstatic char *appendText(char *zIn, char const *zAppend, char quote){ 1310251883Speter int len; 1311251883Speter int i; 1312251883Speter int nAppend = strlen30(zAppend); 1313251883Speter int nIn = (zIn?strlen30(zIn):0); 1314251883Speter 1315251883Speter len = nAppend+nIn+1; 1316251883Speter if( quote ){ 1317251883Speter len += 2; 1318251883Speter for(i=0; i<nAppend; i++){ 1319251883Speter if( zAppend[i]==quote ) len++; 1320251883Speter } 1321251883Speter } 1322251883Speter 1323251883Speter zIn = (char *)realloc(zIn, len); 1324251883Speter if( !zIn ){ 1325251883Speter return 0; 1326251883Speter } 1327251883Speter 1328251883Speter if( quote ){ 1329251883Speter char *zCsr = &zIn[nIn]; 1330251883Speter *zCsr++ = quote; 1331251883Speter for(i=0; i<nAppend; i++){ 1332251883Speter *zCsr++ = zAppend[i]; 1333251883Speter if( zAppend[i]==quote ) *zCsr++ = quote; 1334251883Speter } 1335251883Speter *zCsr++ = quote; 1336251883Speter *zCsr++ = '\0'; 1337251883Speter assert( (zCsr-zIn)==len ); 1338251883Speter }else{ 1339251883Speter memcpy(&zIn[nIn], zAppend, nAppend); 1340251883Speter zIn[len-1] = '\0'; 1341251883Speter } 1342251883Speter 1343251883Speter return zIn; 1344251883Speter} 1345251883Speter 1346251883Speter 1347251883Speter/* 1348251883Speter** Execute a query statement that will generate SQL output. Print 1349251883Speter** the result columns, comma-separated, on a line and then add a 1350251883Speter** semicolon terminator to the end of that line. 1351251883Speter** 1352251883Speter** If the number of columns is 1 and that column contains text "--" 1353305003Scy** then write the semicolon on a separate line. That way, if a 1354251883Speter** "--" comment occurs at the end of the statement, the comment 1355251883Speter** won't consume the semicolon terminator. 1356251883Speter*/ 1357251883Speterstatic int run_table_dump_query( 1358289166Speter ShellState *p, /* Query context */ 1359251883Speter const char *zSelect, /* SELECT statement to extract content */ 1360251883Speter const char *zFirstRow /* Print before first row, if not NULL */ 1361251883Speter){ 1362251883Speter sqlite3_stmt *pSelect; 1363251883Speter int rc; 1364251883Speter int nResult; 1365251883Speter int i; 1366251883Speter const char *z; 1367289166Speter rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0); 1368251883Speter if( rc!=SQLITE_OK || !pSelect ){ 1369305003Scy utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, 1370305003Scy sqlite3_errmsg(p->db)); 1371289166Speter if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; 1372251883Speter return rc; 1373251883Speter } 1374251883Speter rc = sqlite3_step(pSelect); 1375251883Speter nResult = sqlite3_column_count(pSelect); 1376251883Speter while( rc==SQLITE_ROW ){ 1377251883Speter if( zFirstRow ){ 1378305003Scy utf8_printf(p->out, "%s", zFirstRow); 1379251883Speter zFirstRow = 0; 1380251883Speter } 1381251883Speter z = (const char*)sqlite3_column_text(pSelect, 0); 1382305003Scy utf8_printf(p->out, "%s", z); 1383305003Scy for(i=1; i<nResult; i++){ 1384305003Scy utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i)); 1385251883Speter } 1386251883Speter if( z==0 ) z = ""; 1387251883Speter while( z[0] && (z[0]!='-' || z[1]!='-') ) z++; 1388251883Speter if( z[0] ){ 1389305003Scy raw_printf(p->out, "\n;\n"); 1390251883Speter }else{ 1391305003Scy raw_printf(p->out, ";\n"); 1392305003Scy } 1393251883Speter rc = sqlite3_step(pSelect); 1394251883Speter } 1395251883Speter rc = sqlite3_finalize(pSelect); 1396251883Speter if( rc!=SQLITE_OK ){ 1397305003Scy utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, 1398305003Scy sqlite3_errmsg(p->db)); 1399289166Speter if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; 1400251883Speter } 1401251883Speter return rc; 1402251883Speter} 1403251883Speter 1404251883Speter/* 1405251883Speter** Allocate space and save off current error string. 1406251883Speter*/ 1407251883Speterstatic char *save_err_msg( 1408251883Speter sqlite3 *db /* Database to query */ 1409251883Speter){ 1410251883Speter int nErrMsg = 1+strlen30(sqlite3_errmsg(db)); 1411289166Speter char *zErrMsg = sqlite3_malloc64(nErrMsg); 1412251883Speter if( zErrMsg ){ 1413251883Speter memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg); 1414251883Speter } 1415251883Speter return zErrMsg; 1416251883Speter} 1417251883Speter 1418305003Scy#ifdef __linux__ 1419251883Speter/* 1420305003Scy** Attempt to display I/O stats on Linux using /proc/PID/io 1421305003Scy*/ 1422305003Scystatic void displayLinuxIoStats(FILE *out){ 1423305003Scy FILE *in; 1424305003Scy char z[200]; 1425305003Scy sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid()); 1426305003Scy in = fopen(z, "rb"); 1427305003Scy if( in==0 ) return; 1428305003Scy while( fgets(z, sizeof(z), in)!=0 ){ 1429305003Scy static const struct { 1430305003Scy const char *zPattern; 1431305003Scy const char *zDesc; 1432305003Scy } aTrans[] = { 1433305003Scy { "rchar: ", "Bytes received by read():" }, 1434305003Scy { "wchar: ", "Bytes sent to write():" }, 1435305003Scy { "syscr: ", "Read() system calls:" }, 1436305003Scy { "syscw: ", "Write() system calls:" }, 1437305003Scy { "read_bytes: ", "Bytes read from storage:" }, 1438305003Scy { "write_bytes: ", "Bytes written to storage:" }, 1439305003Scy { "cancelled_write_bytes: ", "Cancelled write bytes:" }, 1440305003Scy }; 1441305003Scy int i; 1442305003Scy for(i=0; i<ArraySize(aTrans); i++){ 1443305003Scy int n = (int)strlen(aTrans[i].zPattern); 1444305003Scy if( strncmp(aTrans[i].zPattern, z, n)==0 ){ 1445305003Scy raw_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]); 1446305003Scy break; 1447305003Scy } 1448305003Scy } 1449305003Scy } 1450305003Scy fclose(in); 1451305003Scy} 1452305003Scy#endif 1453305003Scy 1454305003Scy 1455305003Scy/* 1456251883Speter** Display memory stats. 1457251883Speter*/ 1458251883Speterstatic int display_stats( 1459251883Speter sqlite3 *db, /* Database to query */ 1460289166Speter ShellState *pArg, /* Pointer to ShellState */ 1461251883Speter int bReset /* True to reset the stats */ 1462251883Speter){ 1463251883Speter int iCur; 1464251883Speter int iHiwtr; 1465251883Speter 1466251883Speter if( pArg && pArg->out ){ 1467305003Scy 1468251883Speter iHiwtr = iCur = -1; 1469251883Speter sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset); 1470305003Scy raw_printf(pArg->out, 1471289166Speter "Memory Used: %d (max %d) bytes\n", 1472289166Speter iCur, iHiwtr); 1473251883Speter iHiwtr = iCur = -1; 1474251883Speter sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); 1475305003Scy raw_printf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", 1476289166Speter iCur, iHiwtr); 1477289166Speter if( pArg->shellFlgs & SHFLG_Pagecache ){ 1478289166Speter iHiwtr = iCur = -1; 1479289166Speter sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); 1480305003Scy raw_printf(pArg->out, 1481289166Speter "Number of Pcache Pages Used: %d (max %d) pages\n", 1482289166Speter iCur, iHiwtr); 1483289166Speter } 1484251883Speter iHiwtr = iCur = -1; 1485251883Speter sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); 1486305003Scy raw_printf(pArg->out, 1487289166Speter "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", 1488289166Speter iCur, iHiwtr); 1489289166Speter if( pArg->shellFlgs & SHFLG_Scratch ){ 1490289166Speter iHiwtr = iCur = -1; 1491289166Speter sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); 1492305003Scy raw_printf(pArg->out, 1493305003Scy "Number of Scratch Allocations Used: %d (max %d)\n", 1494289166Speter iCur, iHiwtr); 1495289166Speter } 1496251883Speter iHiwtr = iCur = -1; 1497251883Speter sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset); 1498305003Scy raw_printf(pArg->out, 1499289166Speter "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", 1500289166Speter iCur, iHiwtr); 1501251883Speter iHiwtr = iCur = -1; 1502251883Speter sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset); 1503305003Scy raw_printf(pArg->out, "Largest Allocation: %d bytes\n", 1504289166Speter iHiwtr); 1505251883Speter iHiwtr = iCur = -1; 1506251883Speter sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset); 1507305003Scy raw_printf(pArg->out, "Largest Pcache Allocation: %d bytes\n", 1508289166Speter iHiwtr); 1509251883Speter iHiwtr = iCur = -1; 1510251883Speter sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset); 1511305003Scy raw_printf(pArg->out, "Largest Scratch Allocation: %d bytes\n", 1512289166Speter iHiwtr); 1513251883Speter#ifdef YYTRACKMAXSTACKDEPTH 1514251883Speter iHiwtr = iCur = -1; 1515251883Speter sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset); 1516305003Scy raw_printf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", 1517289166Speter iCur, iHiwtr); 1518251883Speter#endif 1519251883Speter } 1520251883Speter 1521251883Speter if( pArg && pArg->out && db ){ 1522289166Speter if( pArg->shellFlgs & SHFLG_Lookaside ){ 1523289166Speter iHiwtr = iCur = -1; 1524289166Speter sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, 1525289166Speter &iCur, &iHiwtr, bReset); 1526305003Scy raw_printf(pArg->out, 1527305003Scy "Lookaside Slots Used: %d (max %d)\n", 1528289166Speter iCur, iHiwtr); 1529289166Speter sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, 1530289166Speter &iCur, &iHiwtr, bReset); 1531305003Scy raw_printf(pArg->out, "Successful lookaside attempts: %d\n", 1532305003Scy iHiwtr); 1533289166Speter sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, 1534289166Speter &iCur, &iHiwtr, bReset); 1535305003Scy raw_printf(pArg->out, "Lookaside failures due to size: %d\n", 1536305003Scy iHiwtr); 1537289166Speter sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, 1538289166Speter &iCur, &iHiwtr, bReset); 1539305003Scy raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n", 1540305003Scy iHiwtr); 1541289166Speter } 1542251883Speter iHiwtr = iCur = -1; 1543289166Speter sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); 1544305003Scy raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n", 1545305003Scy iCur); 1546251883Speter iHiwtr = iCur = -1; 1547251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); 1548305003Scy raw_printf(pArg->out, "Page cache hits: %d\n", iCur); 1549251883Speter iHiwtr = iCur = -1; 1550251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); 1551305003Scy raw_printf(pArg->out, "Page cache misses: %d\n", iCur); 1552251883Speter iHiwtr = iCur = -1; 1553251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1); 1554305003Scy raw_printf(pArg->out, "Page cache writes: %d\n", iCur); 1555251883Speter iHiwtr = iCur = -1; 1556251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); 1557305003Scy raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n", 1558305003Scy iCur); 1559251883Speter iHiwtr = iCur = -1; 1560251883Speter sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); 1561305003Scy raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", 1562305003Scy iCur); 1563251883Speter } 1564251883Speter 1565251883Speter if( pArg && pArg->out && db && pArg->pStmt ){ 1566289166Speter iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1567289166Speter bReset); 1568305003Scy raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur); 1569251883Speter iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); 1570305003Scy raw_printf(pArg->out, "Sort Operations: %d\n", iCur); 1571289166Speter iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); 1572305003Scy raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur); 1573289166Speter iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); 1574305003Scy raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur); 1575251883Speter } 1576251883Speter 1577305003Scy#ifdef __linux__ 1578305003Scy displayLinuxIoStats(pArg->out); 1579305003Scy#endif 1580305003Scy 1581305003Scy /* Do not remove this machine readable comment: extra-stats-output-here */ 1582305003Scy 1583251883Speter return 0; 1584251883Speter} 1585251883Speter 1586251883Speter/* 1587289166Speter** Display scan stats. 1588289166Speter*/ 1589289166Speterstatic void display_scanstats( 1590289166Speter sqlite3 *db, /* Database to query */ 1591289166Speter ShellState *pArg /* Pointer to ShellState */ 1592289166Speter){ 1593289166Speter#ifndef SQLITE_ENABLE_STMT_SCANSTATUS 1594289166Speter UNUSED_PARAMETER(db); 1595289166Speter UNUSED_PARAMETER(pArg); 1596289166Speter#else 1597289166Speter int i, k, n, mx; 1598305003Scy raw_printf(pArg->out, "-------- scanstats --------\n"); 1599289166Speter mx = 0; 1600289166Speter for(k=0; k<=mx; k++){ 1601289166Speter double rEstLoop = 1.0; 1602289166Speter for(i=n=0; 1; i++){ 1603289166Speter sqlite3_stmt *p = pArg->pStmt; 1604289166Speter sqlite3_int64 nLoop, nVisit; 1605289166Speter double rEst; 1606289166Speter int iSid; 1607289166Speter const char *zExplain; 1608289166Speter if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ 1609289166Speter break; 1610289166Speter } 1611289166Speter sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); 1612289166Speter if( iSid>mx ) mx = iSid; 1613289166Speter if( iSid!=k ) continue; 1614289166Speter if( n==0 ){ 1615289166Speter rEstLoop = (double)nLoop; 1616305003Scy if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k); 1617289166Speter } 1618289166Speter n++; 1619289166Speter sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); 1620289166Speter sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); 1621289166Speter sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); 1622305003Scy utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain); 1623289166Speter rEstLoop *= rEst; 1624305003Scy raw_printf(pArg->out, 1625289166Speter " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", 1626289166Speter nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst 1627289166Speter ); 1628289166Speter } 1629289166Speter } 1630305003Scy raw_printf(pArg->out, "---------------------------\n"); 1631289166Speter#endif 1632289166Speter} 1633289166Speter 1634289166Speter/* 1635289166Speter** Parameter azArray points to a zero-terminated array of strings. zStr 1636289166Speter** points to a single nul-terminated string. Return non-zero if zStr 1637289166Speter** is equal, according to strcmp(), to any of the strings in the array. 1638289166Speter** Otherwise, return zero. 1639289166Speter*/ 1640289166Speterstatic int str_in_array(const char *zStr, const char **azArray){ 1641289166Speter int i; 1642289166Speter for(i=0; azArray[i]; i++){ 1643289166Speter if( 0==strcmp(zStr, azArray[i]) ) return 1; 1644289166Speter } 1645289166Speter return 0; 1646289166Speter} 1647289166Speter 1648289166Speter/* 1649289166Speter** If compiled statement pSql appears to be an EXPLAIN statement, allocate 1650289166Speter** and populate the ShellState.aiIndent[] array with the number of 1651305003Scy** spaces each opcode should be indented before it is output. 1652289166Speter** 1653289166Speter** The indenting rules are: 1654289166Speter** 1655289166Speter** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent 1656289166Speter** all opcodes that occur between the p2 jump destination and the opcode 1657289166Speter** itself by 2 spaces. 1658289166Speter** 1659289166Speter** * For each "Goto", if the jump destination is earlier in the program 1660289166Speter** and ends on one of: 1661289166Speter** Yield SeekGt SeekLt RowSetRead Rewind 1662289166Speter** or if the P1 parameter is one instead of zero, 1663289166Speter** then indent all opcodes between the earlier instruction 1664289166Speter** and "Goto" by 2 spaces. 1665289166Speter*/ 1666289166Speterstatic void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ 1667289166Speter const char *zSql; /* The text of the SQL statement */ 1668289166Speter const char *z; /* Used to check if this is an EXPLAIN */ 1669289166Speter int *abYield = 0; /* True if op is an OP_Yield */ 1670289166Speter int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */ 1671289166Speter int iOp; /* Index of operation in p->aiIndent[] */ 1672289166Speter 1673289166Speter const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 1674289166Speter "NextIfOpen", "PrevIfOpen", 0 }; 1675289166Speter const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", 1676289166Speter "Rewind", 0 }; 1677289166Speter const char *azGoto[] = { "Goto", 0 }; 1678289166Speter 1679289166Speter /* Try to figure out if this is really an EXPLAIN statement. If this 1680289166Speter ** cannot be verified, return early. */ 1681305003Scy if( sqlite3_column_count(pSql)!=8 ){ 1682305003Scy p->cMode = p->mode; 1683305003Scy return; 1684305003Scy } 1685289166Speter zSql = sqlite3_sql(pSql); 1686289166Speter if( zSql==0 ) return; 1687289166Speter for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++); 1688305003Scy if( sqlite3_strnicmp(z, "explain", 7) ){ 1689305003Scy p->cMode = p->mode; 1690305003Scy return; 1691305003Scy } 1692289166Speter 1693289166Speter for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){ 1694289166Speter int i; 1695289166Speter int iAddr = sqlite3_column_int(pSql, 0); 1696289166Speter const char *zOp = (const char*)sqlite3_column_text(pSql, 1); 1697289166Speter 1698289166Speter /* Set p2 to the P2 field of the current opcode. Then, assuming that 1699289166Speter ** p2 is an instruction address, set variable p2op to the index of that 1700289166Speter ** instruction in the aiIndent[] array. p2 and p2op may be different if 1701289166Speter ** the current instruction is part of a sub-program generated by an 1702289166Speter ** SQL trigger or foreign key. */ 1703289166Speter int p2 = sqlite3_column_int(pSql, 3); 1704289166Speter int p2op = (p2 + (iOp-iAddr)); 1705289166Speter 1706289166Speter /* Grow the p->aiIndent array as required */ 1707289166Speter if( iOp>=nAlloc ){ 1708305003Scy if( iOp==0 ){ 1709305003Scy /* Do further verfication that this is explain output. Abort if 1710305003Scy ** it is not */ 1711305003Scy static const char *explainCols[] = { 1712305003Scy "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" }; 1713305003Scy int jj; 1714305003Scy for(jj=0; jj<ArraySize(explainCols); jj++){ 1715305003Scy if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){ 1716305003Scy p->cMode = p->mode; 1717305003Scy sqlite3_reset(pSql); 1718305003Scy return; 1719305003Scy } 1720305003Scy } 1721305003Scy } 1722289166Speter nAlloc += 100; 1723289166Speter p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int)); 1724289166Speter abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int)); 1725289166Speter } 1726289166Speter abYield[iOp] = str_in_array(zOp, azYield); 1727289166Speter p->aiIndent[iOp] = 0; 1728289166Speter p->nIndent = iOp+1; 1729289166Speter 1730289166Speter if( str_in_array(zOp, azNext) ){ 1731289166Speter for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2; 1732289166Speter } 1733289166Speter if( str_in_array(zOp, azGoto) && p2op<p->nIndent 1734289166Speter && (abYield[p2op] || sqlite3_column_int(pSql, 2)) 1735289166Speter ){ 1736305003Scy for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2; 1737289166Speter } 1738289166Speter } 1739289166Speter 1740289166Speter p->iIndent = 0; 1741289166Speter sqlite3_free(abYield); 1742289166Speter sqlite3_reset(pSql); 1743289166Speter} 1744289166Speter 1745289166Speter/* 1746289166Speter** Free the array allocated by explain_data_prepare(). 1747289166Speter*/ 1748289166Speterstatic void explain_data_delete(ShellState *p){ 1749289166Speter sqlite3_free(p->aiIndent); 1750289166Speter p->aiIndent = 0; 1751289166Speter p->nIndent = 0; 1752289166Speter p->iIndent = 0; 1753289166Speter} 1754289166Speter 1755289166Speter/* 1756305003Scy** Disable and restore .wheretrace and .selecttrace settings. 1757305003Scy*/ 1758305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) 1759305003Scyextern int sqlite3SelectTrace; 1760305003Scystatic int savedSelectTrace; 1761305003Scy#endif 1762305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) 1763305003Scyextern int sqlite3WhereTrace; 1764305003Scystatic int savedWhereTrace; 1765305003Scy#endif 1766305003Scystatic void disable_debug_trace_modes(void){ 1767305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) 1768305003Scy savedSelectTrace = sqlite3SelectTrace; 1769305003Scy sqlite3SelectTrace = 0; 1770305003Scy#endif 1771305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) 1772305003Scy savedWhereTrace = sqlite3WhereTrace; 1773305003Scy sqlite3WhereTrace = 0; 1774305003Scy#endif 1775305003Scy} 1776305003Scystatic void restore_debug_trace_modes(void){ 1777305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) 1778305003Scy sqlite3SelectTrace = savedSelectTrace; 1779305003Scy#endif 1780305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) 1781305003Scy sqlite3WhereTrace = savedWhereTrace; 1782305003Scy#endif 1783305003Scy} 1784305003Scy 1785305003Scy/* 1786305003Scy** Run a prepared statement 1787305003Scy*/ 1788305003Scystatic void exec_prepared_stmt( 1789305003Scy ShellState *pArg, /* Pointer to ShellState */ 1790305003Scy sqlite3_stmt *pStmt, /* Statment to run */ 1791305003Scy int (*xCallback)(void*,int,char**,char**,int*) /* Callback function */ 1792305003Scy){ 1793305003Scy int rc; 1794305003Scy 1795305003Scy /* perform the first step. this will tell us if we 1796305003Scy ** have a result set or not and how wide it is. 1797305003Scy */ 1798305003Scy rc = sqlite3_step(pStmt); 1799305003Scy /* if we have a result set... */ 1800305003Scy if( SQLITE_ROW == rc ){ 1801305003Scy /* if we have a callback... */ 1802305003Scy if( xCallback ){ 1803305003Scy /* allocate space for col name ptr, value ptr, and type */ 1804305003Scy int nCol = sqlite3_column_count(pStmt); 1805305003Scy void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1); 1806305003Scy if( !pData ){ 1807305003Scy rc = SQLITE_NOMEM; 1808305003Scy }else{ 1809305003Scy char **azCols = (char **)pData; /* Names of result columns */ 1810305003Scy char **azVals = &azCols[nCol]; /* Results */ 1811305003Scy int *aiTypes = (int *)&azVals[nCol]; /* Result types */ 1812305003Scy int i, x; 1813305003Scy assert(sizeof(int) <= sizeof(char *)); 1814305003Scy /* save off ptrs to column names */ 1815305003Scy for(i=0; i<nCol; i++){ 1816305003Scy azCols[i] = (char *)sqlite3_column_name(pStmt, i); 1817305003Scy } 1818305003Scy do{ 1819305003Scy /* extract the data and data types */ 1820305003Scy for(i=0; i<nCol; i++){ 1821305003Scy aiTypes[i] = x = sqlite3_column_type(pStmt, i); 1822305003Scy if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){ 1823305003Scy azVals[i] = ""; 1824305003Scy }else{ 1825305003Scy azVals[i] = (char*)sqlite3_column_text(pStmt, i); 1826305003Scy } 1827305003Scy if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ 1828305003Scy rc = SQLITE_NOMEM; 1829305003Scy break; /* from for */ 1830305003Scy } 1831305003Scy } /* end for */ 1832305003Scy 1833305003Scy /* if data and types extracted successfully... */ 1834305003Scy if( SQLITE_ROW == rc ){ 1835305003Scy /* call the supplied callback with the result row data */ 1836305003Scy if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){ 1837305003Scy rc = SQLITE_ABORT; 1838305003Scy }else{ 1839305003Scy rc = sqlite3_step(pStmt); 1840305003Scy } 1841305003Scy } 1842305003Scy } while( SQLITE_ROW == rc ); 1843305003Scy sqlite3_free(pData); 1844305003Scy } 1845305003Scy }else{ 1846305003Scy do{ 1847305003Scy rc = sqlite3_step(pStmt); 1848305003Scy } while( rc == SQLITE_ROW ); 1849305003Scy } 1850305003Scy } 1851305003Scy} 1852305003Scy 1853305003Scy/* 1854305003Scy** Execute a statement or set of statements. Print 1855305003Scy** any result rows/columns depending on the current mode 1856251883Speter** set via the supplied callback. 1857251883Speter** 1858305003Scy** This is very similar to SQLite's built-in sqlite3_exec() 1859305003Scy** function except it takes a slightly different callback 1860251883Speter** and callback data argument. 1861251883Speter*/ 1862251883Speterstatic int shell_exec( 1863289166Speter sqlite3 *db, /* An open database */ 1864289166Speter const char *zSql, /* SQL to be evaluated */ 1865251883Speter int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */ 1866289166Speter /* (not the same as sqlite3_exec) */ 1867289166Speter ShellState *pArg, /* Pointer to ShellState */ 1868289166Speter char **pzErrMsg /* Error msg written here */ 1869251883Speter){ 1870251883Speter sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ 1871251883Speter int rc = SQLITE_OK; /* Return Code */ 1872251883Speter int rc2; 1873251883Speter const char *zLeftover; /* Tail of unprocessed SQL */ 1874251883Speter 1875251883Speter if( pzErrMsg ){ 1876251883Speter *pzErrMsg = NULL; 1877251883Speter } 1878251883Speter 1879251883Speter while( zSql[0] && (SQLITE_OK == rc) ){ 1880305003Scy static const char *zStmtSql; 1881251883Speter rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); 1882251883Speter if( SQLITE_OK != rc ){ 1883251883Speter if( pzErrMsg ){ 1884251883Speter *pzErrMsg = save_err_msg(db); 1885251883Speter } 1886251883Speter }else{ 1887251883Speter if( !pStmt ){ 1888251883Speter /* this happens for a comment or white-space */ 1889251883Speter zSql = zLeftover; 1890251883Speter while( IsSpace(zSql[0]) ) zSql++; 1891251883Speter continue; 1892251883Speter } 1893305003Scy zStmtSql = sqlite3_sql(pStmt); 1894305003Scy while( IsSpace(zStmtSql[0]) ) zStmtSql++; 1895251883Speter 1896251883Speter /* save off the prepared statment handle and reset row count */ 1897251883Speter if( pArg ){ 1898251883Speter pArg->pStmt = pStmt; 1899251883Speter pArg->cnt = 0; 1900251883Speter } 1901251883Speter 1902251883Speter /* echo the sql statement if echo on */ 1903251883Speter if( pArg && pArg->echoOn ){ 1904305003Scy utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); 1905251883Speter } 1906251883Speter 1907289166Speter /* Show the EXPLAIN QUERY PLAN if .eqp is on */ 1908305003Scy if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){ 1909289166Speter sqlite3_stmt *pExplain; 1910305003Scy char *zEQP; 1911305003Scy disable_debug_trace_modes(); 1912305003Scy zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql); 1913289166Speter rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); 1914289166Speter if( rc==SQLITE_OK ){ 1915289166Speter while( sqlite3_step(pExplain)==SQLITE_ROW ){ 1916305003Scy raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0)); 1917305003Scy raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1)); 1918305003Scy raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2)); 1919305003Scy utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3)); 1920289166Speter } 1921251883Speter } 1922289166Speter sqlite3_finalize(pExplain); 1923289166Speter sqlite3_free(zEQP); 1924305003Scy if( pArg->autoEQP>=2 ){ 1925305003Scy /* Also do an EXPLAIN for ".eqp full" mode */ 1926305003Scy zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql); 1927305003Scy rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); 1928305003Scy if( rc==SQLITE_OK ){ 1929305003Scy pArg->cMode = MODE_Explain; 1930305003Scy explain_data_prepare(pArg, pExplain); 1931305003Scy exec_prepared_stmt(pArg, pExplain, xCallback); 1932305003Scy explain_data_delete(pArg); 1933305003Scy } 1934305003Scy sqlite3_finalize(pExplain); 1935305003Scy sqlite3_free(zEQP); 1936305003Scy } 1937305003Scy restore_debug_trace_modes(); 1938251883Speter } 1939251883Speter 1940305003Scy if( pArg ){ 1941305003Scy pArg->cMode = pArg->mode; 1942305003Scy if( pArg->autoExplain 1943305003Scy && sqlite3_column_count(pStmt)==8 1944305003Scy && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0 1945305003Scy ){ 1946305003Scy pArg->cMode = MODE_Explain; 1947305003Scy } 1948289166Speter 1949305003Scy /* If the shell is currently in ".explain" mode, gather the extra 1950305003Scy ** data required to add indents to the output.*/ 1951305003Scy if( pArg->cMode==MODE_Explain ){ 1952305003Scy explain_data_prepare(pArg, pStmt); 1953251883Speter } 1954251883Speter } 1955251883Speter 1956305003Scy exec_prepared_stmt(pArg, pStmt, xCallback); 1957289166Speter explain_data_delete(pArg); 1958289166Speter 1959251883Speter /* print usage stats if stats on */ 1960251883Speter if( pArg && pArg->statsOn ){ 1961251883Speter display_stats(db, pArg, 0); 1962251883Speter } 1963251883Speter 1964289166Speter /* print loop-counters if required */ 1965289166Speter if( pArg && pArg->scanstatsOn ){ 1966289166Speter display_scanstats(db, pArg); 1967289166Speter } 1968289166Speter 1969305003Scy /* Finalize the statement just executed. If this fails, save a 1970251883Speter ** copy of the error message. Otherwise, set zSql to point to the 1971251883Speter ** next statement to execute. */ 1972251883Speter rc2 = sqlite3_finalize(pStmt); 1973251883Speter if( rc!=SQLITE_NOMEM ) rc = rc2; 1974251883Speter if( rc==SQLITE_OK ){ 1975251883Speter zSql = zLeftover; 1976251883Speter while( IsSpace(zSql[0]) ) zSql++; 1977251883Speter }else if( pzErrMsg ){ 1978251883Speter *pzErrMsg = save_err_msg(db); 1979251883Speter } 1980251883Speter 1981251883Speter /* clear saved stmt handle */ 1982251883Speter if( pArg ){ 1983251883Speter pArg->pStmt = NULL; 1984251883Speter } 1985251883Speter } 1986251883Speter } /* end while */ 1987251883Speter 1988251883Speter return rc; 1989251883Speter} 1990251883Speter 1991251883Speter 1992251883Speter/* 1993251883Speter** This is a different callback routine used for dumping the database. 1994251883Speter** Each row received by this callback consists of a table name, 1995251883Speter** the table type ("index" or "table") and SQL to create the table. 1996251883Speter** This routine should print text sufficient to recreate the table. 1997251883Speter*/ 1998251883Speterstatic int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ 1999251883Speter int rc; 2000251883Speter const char *zTable; 2001251883Speter const char *zType; 2002251883Speter const char *zSql; 2003251883Speter const char *zPrepStmt = 0; 2004289166Speter ShellState *p = (ShellState *)pArg; 2005251883Speter 2006251883Speter UNUSED_PARAMETER(azCol); 2007251883Speter if( nArg!=3 ) return 1; 2008251883Speter zTable = azArg[0]; 2009251883Speter zType = azArg[1]; 2010251883Speter zSql = azArg[2]; 2011305003Scy 2012251883Speter if( strcmp(zTable, "sqlite_sequence")==0 ){ 2013251883Speter zPrepStmt = "DELETE FROM sqlite_sequence;\n"; 2014289166Speter }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){ 2015305003Scy raw_printf(p->out, "ANALYZE sqlite_master;\n"); 2016251883Speter }else if( strncmp(zTable, "sqlite_", 7)==0 ){ 2017251883Speter return 0; 2018251883Speter }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ 2019251883Speter char *zIns; 2020251883Speter if( !p->writableSchema ){ 2021305003Scy raw_printf(p->out, "PRAGMA writable_schema=ON;\n"); 2022251883Speter p->writableSchema = 1; 2023251883Speter } 2024251883Speter zIns = sqlite3_mprintf( 2025251883Speter "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" 2026251883Speter "VALUES('table','%q','%q',0,'%q');", 2027251883Speter zTable, zTable, zSql); 2028305003Scy utf8_printf(p->out, "%s\n", zIns); 2029251883Speter sqlite3_free(zIns); 2030251883Speter return 0; 2031251883Speter }else{ 2032305003Scy utf8_printf(p->out, "%s;\n", zSql); 2033251883Speter } 2034251883Speter 2035251883Speter if( strcmp(zType, "table")==0 ){ 2036251883Speter sqlite3_stmt *pTableInfo = 0; 2037251883Speter char *zSelect = 0; 2038251883Speter char *zTableInfo = 0; 2039251883Speter char *zTmp = 0; 2040251883Speter int nRow = 0; 2041305003Scy 2042251883Speter zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0); 2043251883Speter zTableInfo = appendText(zTableInfo, zTable, '"'); 2044251883Speter zTableInfo = appendText(zTableInfo, ");", 0); 2045251883Speter 2046289166Speter rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0); 2047251883Speter free(zTableInfo); 2048251883Speter if( rc!=SQLITE_OK || !pTableInfo ){ 2049251883Speter return 1; 2050251883Speter } 2051251883Speter 2052251883Speter zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0); 2053251883Speter /* Always quote the table name, even if it appears to be pure ascii, 2054251883Speter ** in case it is a keyword. Ex: INSERT INTO "table" ... */ 2055251883Speter zTmp = appendText(zTmp, zTable, '"'); 2056251883Speter if( zTmp ){ 2057251883Speter zSelect = appendText(zSelect, zTmp, '\''); 2058251883Speter free(zTmp); 2059251883Speter } 2060251883Speter zSelect = appendText(zSelect, " || ' VALUES(' || ", 0); 2061251883Speter rc = sqlite3_step(pTableInfo); 2062251883Speter while( rc==SQLITE_ROW ){ 2063251883Speter const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1); 2064251883Speter zSelect = appendText(zSelect, "quote(", 0); 2065251883Speter zSelect = appendText(zSelect, zText, '"'); 2066251883Speter rc = sqlite3_step(pTableInfo); 2067251883Speter if( rc==SQLITE_ROW ){ 2068251883Speter zSelect = appendText(zSelect, "), ", 0); 2069251883Speter }else{ 2070251883Speter zSelect = appendText(zSelect, ") ", 0); 2071251883Speter } 2072251883Speter nRow++; 2073251883Speter } 2074251883Speter rc = sqlite3_finalize(pTableInfo); 2075251883Speter if( rc!=SQLITE_OK || nRow==0 ){ 2076251883Speter free(zSelect); 2077251883Speter return 1; 2078251883Speter } 2079251883Speter zSelect = appendText(zSelect, "|| ')' FROM ", 0); 2080251883Speter zSelect = appendText(zSelect, zTable, '"'); 2081251883Speter 2082251883Speter rc = run_table_dump_query(p, zSelect, zPrepStmt); 2083251883Speter if( rc==SQLITE_CORRUPT ){ 2084251883Speter zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); 2085251883Speter run_table_dump_query(p, zSelect, 0); 2086251883Speter } 2087251883Speter free(zSelect); 2088251883Speter } 2089251883Speter return 0; 2090251883Speter} 2091251883Speter 2092251883Speter/* 2093251883Speter** Run zQuery. Use dump_callback() as the callback routine so that 2094251883Speter** the contents of the query are output as SQL statements. 2095251883Speter** 2096251883Speter** If we get a SQLITE_CORRUPT error, rerun the query after appending 2097251883Speter** "ORDER BY rowid DESC" to the end. 2098251883Speter*/ 2099251883Speterstatic int run_schema_dump_query( 2100305003Scy ShellState *p, 2101251883Speter const char *zQuery 2102251883Speter){ 2103251883Speter int rc; 2104251883Speter char *zErr = 0; 2105251883Speter rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); 2106251883Speter if( rc==SQLITE_CORRUPT ){ 2107251883Speter char *zQ2; 2108251883Speter int len = strlen30(zQuery); 2109305003Scy raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); 2110251883Speter if( zErr ){ 2111305003Scy utf8_printf(p->out, "/****** %s ******/\n", zErr); 2112251883Speter sqlite3_free(zErr); 2113251883Speter zErr = 0; 2114251883Speter } 2115251883Speter zQ2 = malloc( len+100 ); 2116251883Speter if( zQ2==0 ) return rc; 2117251883Speter sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery); 2118251883Speter rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); 2119251883Speter if( rc ){ 2120305003Scy utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr); 2121251883Speter }else{ 2122251883Speter rc = SQLITE_CORRUPT; 2123251883Speter } 2124251883Speter sqlite3_free(zErr); 2125251883Speter free(zQ2); 2126251883Speter } 2127251883Speter return rc; 2128251883Speter} 2129251883Speter 2130251883Speter/* 2131251883Speter** Text of a help message 2132251883Speter*/ 2133251883Speterstatic char zHelp[] = 2134305003Scy ".auth ON|OFF Show authorizer callbacks\n" 2135251883Speter ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" 2136289166Speter ".bail on|off Stop after hitting an error. Default OFF\n" 2137289166Speter ".binary on|off Turn binary output on or off. Default OFF\n" 2138305003Scy ".changes on|off Show number of rows changed by SQL\n" 2139289166Speter ".clone NEWDB Clone data into NEWDB from the existing database\n" 2140251883Speter ".databases List names and files of attached databases\n" 2141289166Speter ".dbinfo ?DB? Show status information about the database\n" 2142251883Speter ".dump ?TABLE? ... Dump the database in an SQL text format\n" 2143251883Speter " If TABLE specified, only dump tables matching\n" 2144251883Speter " LIKE pattern TABLE.\n" 2145289166Speter ".echo on|off Turn command echo on or off\n" 2146305003Scy ".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n" 2147251883Speter ".exit Exit this program\n" 2148305003Scy ".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n" 2149305003Scy ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n" 2150289166Speter ".headers on|off Turn display of headers on or off\n" 2151251883Speter ".help Show this message\n" 2152251883Speter ".import FILE TABLE Import data from FILE into TABLE\n" 2153289166Speter ".indexes ?TABLE? Show names of all indexes\n" 2154289166Speter " If TABLE specified, only show indexes for tables\n" 2155251883Speter " matching LIKE pattern TABLE.\n" 2156251883Speter#ifdef SQLITE_ENABLE_IOTRACE 2157251883Speter ".iotrace FILE Enable I/O diagnostic logging to FILE\n" 2158251883Speter#endif 2159289166Speter ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n" 2160251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION 2161251883Speter ".load FILE ?ENTRY? Load an extension library\n" 2162251883Speter#endif 2163251883Speter ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n" 2164251883Speter ".mode MODE ?TABLE? Set output mode where MODE is one of:\n" 2165289166Speter " ascii Columns/rows delimited by 0x1F and 0x1E\n" 2166251883Speter " csv Comma-separated values\n" 2167251883Speter " column Left-aligned columns. (See .width)\n" 2168251883Speter " html HTML <table> code\n" 2169251883Speter " insert SQL insert statements for TABLE\n" 2170251883Speter " line One value per line\n" 2171289166Speter " list Values delimited by .separator strings\n" 2172251883Speter " tabs Tab-separated values\n" 2173251883Speter " tcl TCL list elements\n" 2174251883Speter ".nullvalue STRING Use STRING in place of NULL values\n" 2175289166Speter ".once FILENAME Output for the next SQL command only to FILENAME\n" 2176289166Speter ".open ?FILENAME? Close existing database and reopen FILENAME\n" 2177289166Speter ".output ?FILENAME? Send output to FILENAME or stdout\n" 2178251883Speter ".print STRING... Print literal STRING\n" 2179251883Speter ".prompt MAIN CONTINUE Replace the standard prompts\n" 2180251883Speter ".quit Exit this program\n" 2181251883Speter ".read FILENAME Execute SQL in FILENAME\n" 2182251883Speter ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" 2183289166Speter ".save FILE Write in-memory database into FILE\n" 2184289166Speter ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n" 2185305003Scy ".schema ?PATTERN? Show the CREATE statements matching PATTERN\n" 2186305003Scy " Add --indent for pretty-printing\n" 2187289166Speter ".separator COL ?ROW? Change the column separator and optionally the row\n" 2188289166Speter " separator for both the output mode and .import\n" 2189305003Scy#if defined(SQLITE_ENABLE_SESSION) 2190305003Scy ".session CMD ... Create or control sessions\n" 2191305003Scy#endif 2192289166Speter ".shell CMD ARGS... Run CMD ARGS... in a system shell\n" 2193251883Speter ".show Show the current values for various settings\n" 2194305003Scy ".stats ?on|off? Show stats or turn stats on or off\n" 2195289166Speter ".system CMD ARGS... Run CMD ARGS... in a system shell\n" 2196251883Speter ".tables ?TABLE? List names of tables\n" 2197251883Speter " If TABLE specified, only list tables matching\n" 2198251883Speter " LIKE pattern TABLE.\n" 2199251883Speter ".timeout MS Try opening locked tables for MS milliseconds\n" 2200289166Speter ".timer on|off Turn SQL timer on or off\n" 2201251883Speter ".trace FILE|off Output each SQL statement as it is run\n" 2202305003Scy ".vfsinfo ?AUX? Information about the top-level VFS\n" 2203305003Scy ".vfslist List all available VFSes\n" 2204251883Speter ".vfsname ?AUX? Print the name of the VFS stack\n" 2205251883Speter ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n" 2206289166Speter " Negative values right-justify\n" 2207251883Speter; 2208251883Speter 2209305003Scy#if defined(SQLITE_ENABLE_SESSION) 2210305003Scy/* 2211305003Scy** Print help information for the ".sessions" command 2212305003Scy*/ 2213305003Scyvoid session_help(ShellState *p){ 2214305003Scy raw_printf(p->out, 2215305003Scy ".session ?NAME? SUBCOMMAND ?ARGS...?\n" 2216305003Scy "If ?NAME? is omitted, the first defined session is used.\n" 2217305003Scy "Subcommands:\n" 2218305003Scy " attach TABLE Attach TABLE\n" 2219305003Scy " changeset FILE Write a changeset into FILE\n" 2220305003Scy " close Close one session\n" 2221305003Scy " enable ?BOOLEAN? Set or query the enable bit\n" 2222305003Scy " filter GLOB... Reject tables matching GLOBs\n" 2223305003Scy " indirect ?BOOLEAN? Mark or query the indirect status\n" 2224305003Scy " isempty Query whether the session is empty\n" 2225305003Scy " list List currently open session names\n" 2226305003Scy " open DB NAME Open a new session on DB\n" 2227305003Scy " patchset FILE Write a patchset into FILE\n" 2228305003Scy ); 2229305003Scy} 2230305003Scy#endif 2231305003Scy 2232305003Scy 2233251883Speter/* Forward reference */ 2234289166Speterstatic int process_input(ShellState *p, FILE *in); 2235289166Speter/* 2236289166Speter** Implementation of the "readfile(X)" SQL function. The entire content 2237289166Speter** of the file named X is read and returned as a BLOB. NULL is returned 2238289166Speter** if the file does not exist or is unreadable. 2239289166Speter*/ 2240289166Speterstatic void readfileFunc( 2241289166Speter sqlite3_context *context, 2242289166Speter int argc, 2243289166Speter sqlite3_value **argv 2244289166Speter){ 2245289166Speter const char *zName; 2246289166Speter FILE *in; 2247289166Speter long nIn; 2248289166Speter void *pBuf; 2249251883Speter 2250289166Speter UNUSED_PARAMETER(argc); 2251289166Speter zName = (const char*)sqlite3_value_text(argv[0]); 2252289166Speter if( zName==0 ) return; 2253289166Speter in = fopen(zName, "rb"); 2254289166Speter if( in==0 ) return; 2255289166Speter fseek(in, 0, SEEK_END); 2256289166Speter nIn = ftell(in); 2257289166Speter rewind(in); 2258289166Speter pBuf = sqlite3_malloc64( nIn ); 2259289166Speter if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ 2260289166Speter sqlite3_result_blob(context, pBuf, nIn, sqlite3_free); 2261289166Speter }else{ 2262289166Speter sqlite3_free(pBuf); 2263289166Speter } 2264289166Speter fclose(in); 2265289166Speter} 2266289166Speter 2267251883Speter/* 2268289166Speter** Implementation of the "writefile(X,Y)" SQL function. The argument Y 2269289166Speter** is written into file X. The number of bytes written is returned. Or 2270289166Speter** NULL is returned if something goes wrong, such as being unable to open 2271289166Speter** file X for writing. 2272289166Speter*/ 2273289166Speterstatic void writefileFunc( 2274289166Speter sqlite3_context *context, 2275289166Speter int argc, 2276289166Speter sqlite3_value **argv 2277289166Speter){ 2278289166Speter FILE *out; 2279289166Speter const char *z; 2280289166Speter sqlite3_int64 rc; 2281289166Speter const char *zFile; 2282289166Speter 2283289166Speter UNUSED_PARAMETER(argc); 2284289166Speter zFile = (const char*)sqlite3_value_text(argv[0]); 2285289166Speter if( zFile==0 ) return; 2286289166Speter out = fopen(zFile, "wb"); 2287289166Speter if( out==0 ) return; 2288289166Speter z = (const char*)sqlite3_value_blob(argv[1]); 2289289166Speter if( z==0 ){ 2290289166Speter rc = 0; 2291289166Speter }else{ 2292289166Speter rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out); 2293289166Speter } 2294289166Speter fclose(out); 2295289166Speter sqlite3_result_int64(context, rc); 2296289166Speter} 2297289166Speter 2298305003Scy#if defined(SQLITE_ENABLE_SESSION) 2299289166Speter/* 2300305003Scy** Close a single OpenSession object and release all of its associated 2301305003Scy** resources. 2302305003Scy*/ 2303305003Scystatic void session_close(OpenSession *pSession){ 2304305003Scy int i; 2305305003Scy sqlite3session_delete(pSession->p); 2306305003Scy sqlite3_free(pSession->zName); 2307305003Scy for(i=0; i<pSession->nFilter; i++){ 2308305003Scy sqlite3_free(pSession->azFilter[i]); 2309305003Scy } 2310305003Scy sqlite3_free(pSession->azFilter); 2311305003Scy memset(pSession, 0, sizeof(OpenSession)); 2312305003Scy} 2313305003Scy#endif 2314305003Scy 2315305003Scy/* 2316305003Scy** Close all OpenSession objects and release all associated resources. 2317305003Scy*/ 2318305003Scy#if defined(SQLITE_ENABLE_SESSION) 2319305003Scystatic void session_close_all(ShellState *p){ 2320305003Scy int i; 2321305003Scy for(i=0; i<p->nSession; i++){ 2322305003Scy session_close(&p->aSession[i]); 2323305003Scy } 2324305003Scy p->nSession = 0; 2325305003Scy} 2326305003Scy#else 2327305003Scy# define session_close_all(X) 2328305003Scy#endif 2329305003Scy 2330305003Scy/* 2331305003Scy** Implementation of the xFilter function for an open session. Omit 2332305003Scy** any tables named by ".session filter" but let all other table through. 2333305003Scy*/ 2334305003Scy#if defined(SQLITE_ENABLE_SESSION) 2335305003Scystatic int session_filter(void *pCtx, const char *zTab){ 2336305003Scy OpenSession *pSession = (OpenSession*)pCtx; 2337305003Scy int i; 2338305003Scy for(i=0; i<pSession->nFilter; i++){ 2339305003Scy if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0; 2340305003Scy } 2341305003Scy return 1; 2342305003Scy} 2343305003Scy#endif 2344305003Scy 2345305003Scy/* 2346251883Speter** Make sure the database is open. If it is not, then open it. If 2347251883Speter** the database fails to open, print an error message and exit. 2348251883Speter*/ 2349289166Speterstatic void open_db(ShellState *p, int keepAlive){ 2350251883Speter if( p->db==0 ){ 2351251883Speter sqlite3_initialize(); 2352251883Speter sqlite3_open(p->zDbFilename, &p->db); 2353289166Speter globalDb = p->db; 2354289166Speter if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){ 2355289166Speter sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0, 2356251883Speter shellstaticFunc, 0, 0); 2357251883Speter } 2358289166Speter if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ 2359305003Scy utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", 2360289166Speter p->zDbFilename, sqlite3_errmsg(p->db)); 2361289166Speter if( keepAlive ) return; 2362251883Speter exit(1); 2363251883Speter } 2364251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION 2365251883Speter sqlite3_enable_load_extension(p->db, 1); 2366251883Speter#endif 2367289166Speter sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0, 2368289166Speter readfileFunc, 0, 0); 2369289166Speter sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0, 2370289166Speter writefileFunc, 0, 0); 2371251883Speter } 2372251883Speter} 2373251883Speter 2374251883Speter/* 2375251883Speter** Do C-language style dequoting. 2376251883Speter** 2377289166Speter** \a -> alarm 2378289166Speter** \b -> backspace 2379251883Speter** \t -> tab 2380251883Speter** \n -> newline 2381289166Speter** \v -> vertical tab 2382289166Speter** \f -> form feed 2383251883Speter** \r -> carriage return 2384289166Speter** \s -> space 2385289166Speter** \" -> " 2386289166Speter** \' -> ' 2387289166Speter** \\ -> backslash 2388251883Speter** \NNN -> ascii character NNN in octal 2389251883Speter*/ 2390251883Speterstatic void resolve_backslashes(char *z){ 2391251883Speter int i, j; 2392251883Speter char c; 2393289166Speter while( *z && *z!='\\' ) z++; 2394251883Speter for(i=j=0; (c = z[i])!=0; i++, j++){ 2395289166Speter if( c=='\\' && z[i+1]!=0 ){ 2396251883Speter c = z[++i]; 2397289166Speter if( c=='a' ){ 2398289166Speter c = '\a'; 2399289166Speter }else if( c=='b' ){ 2400289166Speter c = '\b'; 2401251883Speter }else if( c=='t' ){ 2402251883Speter c = '\t'; 2403289166Speter }else if( c=='n' ){ 2404289166Speter c = '\n'; 2405289166Speter }else if( c=='v' ){ 2406289166Speter c = '\v'; 2407289166Speter }else if( c=='f' ){ 2408289166Speter c = '\f'; 2409251883Speter }else if( c=='r' ){ 2410251883Speter c = '\r'; 2411289166Speter }else if( c=='"' ){ 2412289166Speter c = '"'; 2413289166Speter }else if( c=='\'' ){ 2414289166Speter c = '\''; 2415289166Speter }else if( c=='\\' ){ 2416289166Speter c = '\\'; 2417251883Speter }else if( c>='0' && c<='7' ){ 2418251883Speter c -= '0'; 2419251883Speter if( z[i+1]>='0' && z[i+1]<='7' ){ 2420251883Speter i++; 2421251883Speter c = (c<<3) + z[i] - '0'; 2422251883Speter if( z[i+1]>='0' && z[i+1]<='7' ){ 2423251883Speter i++; 2424251883Speter c = (c<<3) + z[i] - '0'; 2425251883Speter } 2426251883Speter } 2427251883Speter } 2428251883Speter } 2429251883Speter z[j] = c; 2430251883Speter } 2431289166Speter if( j<i ) z[j] = 0; 2432251883Speter} 2433251883Speter 2434251883Speter/* 2435289166Speter** Return the value of a hexadecimal digit. Return -1 if the input 2436289166Speter** is not a hex digit. 2437251883Speter*/ 2438289166Speterstatic int hexDigitValue(char c){ 2439289166Speter if( c>='0' && c<='9' ) return c - '0'; 2440289166Speter if( c>='a' && c<='f' ) return c - 'a' + 10; 2441289166Speter if( c>='A' && c<='F' ) return c - 'A' + 10; 2442289166Speter return -1; 2443251883Speter} 2444251883Speter 2445251883Speter/* 2446251883Speter** Interpret zArg as an integer value, possibly with suffixes. 2447251883Speter*/ 2448251883Speterstatic sqlite3_int64 integerValue(const char *zArg){ 2449251883Speter sqlite3_int64 v = 0; 2450251883Speter static const struct { char *zSuffix; int iMult; } aMult[] = { 2451251883Speter { "KiB", 1024 }, 2452251883Speter { "MiB", 1024*1024 }, 2453251883Speter { "GiB", 1024*1024*1024 }, 2454251883Speter { "KB", 1000 }, 2455251883Speter { "MB", 1000000 }, 2456251883Speter { "GB", 1000000000 }, 2457251883Speter { "K", 1000 }, 2458251883Speter { "M", 1000000 }, 2459251883Speter { "G", 1000000000 }, 2460251883Speter }; 2461251883Speter int i; 2462251883Speter int isNeg = 0; 2463251883Speter if( zArg[0]=='-' ){ 2464251883Speter isNeg = 1; 2465251883Speter zArg++; 2466251883Speter }else if( zArg[0]=='+' ){ 2467251883Speter zArg++; 2468251883Speter } 2469289166Speter if( zArg[0]=='0' && zArg[1]=='x' ){ 2470289166Speter int x; 2471289166Speter zArg += 2; 2472289166Speter while( (x = hexDigitValue(zArg[0]))>=0 ){ 2473289166Speter v = (v<<4) + x; 2474289166Speter zArg++; 2475289166Speter } 2476289166Speter }else{ 2477289166Speter while( IsDigit(zArg[0]) ){ 2478289166Speter v = v*10 + zArg[0] - '0'; 2479289166Speter zArg++; 2480289166Speter } 2481251883Speter } 2482289166Speter for(i=0; i<ArraySize(aMult); i++){ 2483251883Speter if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ 2484251883Speter v *= aMult[i].iMult; 2485251883Speter break; 2486251883Speter } 2487251883Speter } 2488251883Speter return isNeg? -v : v; 2489251883Speter} 2490251883Speter 2491251883Speter/* 2492289166Speter** Interpret zArg as either an integer or a boolean value. Return 1 or 0 2493289166Speter** for TRUE and FALSE. Return the integer value if appropriate. 2494289166Speter*/ 2495289166Speterstatic int booleanValue(char *zArg){ 2496289166Speter int i; 2497289166Speter if( zArg[0]=='0' && zArg[1]=='x' ){ 2498289166Speter for(i=2; hexDigitValue(zArg[i])>=0; i++){} 2499289166Speter }else{ 2500289166Speter for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} 2501289166Speter } 2502289166Speter if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff); 2503289166Speter if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ 2504289166Speter return 1; 2505289166Speter } 2506289166Speter if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ 2507289166Speter return 0; 2508289166Speter } 2509305003Scy utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", 2510289166Speter zArg); 2511289166Speter return 0; 2512289166Speter} 2513289166Speter 2514289166Speter/* 2515251883Speter** Close an output file, assuming it is not stderr or stdout 2516251883Speter*/ 2517251883Speterstatic void output_file_close(FILE *f){ 2518251883Speter if( f && f!=stdout && f!=stderr ) fclose(f); 2519251883Speter} 2520251883Speter 2521251883Speter/* 2522251883Speter** Try to open an output file. The names "stdout" and "stderr" are 2523305003Scy** recognized and do the right thing. NULL is returned if the output 2524251883Speter** filename is "off". 2525251883Speter*/ 2526251883Speterstatic FILE *output_file_open(const char *zFile){ 2527251883Speter FILE *f; 2528251883Speter if( strcmp(zFile,"stdout")==0 ){ 2529251883Speter f = stdout; 2530251883Speter }else if( strcmp(zFile, "stderr")==0 ){ 2531251883Speter f = stderr; 2532251883Speter }else if( strcmp(zFile, "off")==0 ){ 2533251883Speter f = 0; 2534251883Speter }else{ 2535251883Speter f = fopen(zFile, "wb"); 2536251883Speter if( f==0 ){ 2537305003Scy utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); 2538251883Speter } 2539251883Speter } 2540251883Speter return f; 2541251883Speter} 2542251883Speter 2543251883Speter/* 2544251883Speter** A routine for handling output from sqlite3_trace(). 2545251883Speter*/ 2546305003Scystatic int sql_trace_callback( 2547305003Scy unsigned mType, 2548305003Scy void *pArg, 2549305003Scy void *pP, 2550305003Scy void *pX 2551305003Scy){ 2552251883Speter FILE *f = (FILE*)pArg; 2553305003Scy UNUSED_PARAMETER(mType); 2554305003Scy UNUSED_PARAMETER(pP); 2555289166Speter if( f ){ 2556305003Scy const char *z = (const char*)pX; 2557289166Speter int i = (int)strlen(z); 2558289166Speter while( i>0 && z[i-1]==';' ){ i--; } 2559305003Scy utf8_printf(f, "%.*s;\n", i, z); 2560289166Speter } 2561305003Scy return 0; 2562251883Speter} 2563251883Speter 2564251883Speter/* 2565251883Speter** A no-op routine that runs with the ".breakpoint" doc-command. This is 2566251883Speter** a useful spot to set a debugger breakpoint. 2567251883Speter*/ 2568251883Speterstatic void test_breakpoint(void){ 2569251883Speter static int nCall = 0; 2570251883Speter nCall++; 2571251883Speter} 2572251883Speter 2573251883Speter/* 2574289166Speter** An object used to read a CSV and other files for import. 2575289166Speter*/ 2576289166Spetertypedef struct ImportCtx ImportCtx; 2577289166Speterstruct ImportCtx { 2578289166Speter const char *zFile; /* Name of the input file */ 2579289166Speter FILE *in; /* Read the CSV text from this input stream */ 2580289166Speter char *z; /* Accumulated text for a field */ 2581289166Speter int n; /* Number of bytes in z */ 2582289166Speter int nAlloc; /* Space allocated for z[] */ 2583289166Speter int nLine; /* Current line number */ 2584289166Speter int cTerm; /* Character that terminated the most recent field */ 2585289166Speter int cColSep; /* The column separator character. (Usually ",") */ 2586289166Speter int cRowSep; /* The row separator character. (Usually "\n") */ 2587289166Speter}; 2588289166Speter 2589289166Speter/* Append a single byte to z[] */ 2590289166Speterstatic void import_append_char(ImportCtx *p, int c){ 2591289166Speter if( p->n+1>=p->nAlloc ){ 2592289166Speter p->nAlloc += p->nAlloc + 100; 2593289166Speter p->z = sqlite3_realloc64(p->z, p->nAlloc); 2594289166Speter if( p->z==0 ){ 2595305003Scy raw_printf(stderr, "out of memory\n"); 2596289166Speter exit(1); 2597289166Speter } 2598289166Speter } 2599289166Speter p->z[p->n++] = (char)c; 2600289166Speter} 2601289166Speter 2602289166Speter/* Read a single field of CSV text. Compatible with rfc4180 and extended 2603289166Speter** with the option of having a separator other than ",". 2604289166Speter** 2605289166Speter** + Input comes from p->in. 2606289166Speter** + Store results in p->z of length p->n. Space to hold p->z comes 2607289166Speter** from sqlite3_malloc64(). 2608289166Speter** + Use p->cSep as the column separator. The default is ",". 2609289166Speter** + Use p->rSep as the row separator. The default is "\n". 2610289166Speter** + Keep track of the line number in p->nLine. 2611289166Speter** + Store the character that terminates the field in p->cTerm. Store 2612289166Speter** EOF on end-of-file. 2613289166Speter** + Report syntax errors on stderr 2614289166Speter*/ 2615289166Speterstatic char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){ 2616289166Speter int c; 2617289166Speter int cSep = p->cColSep; 2618289166Speter int rSep = p->cRowSep; 2619289166Speter p->n = 0; 2620289166Speter c = fgetc(p->in); 2621289166Speter if( c==EOF || seenInterrupt ){ 2622289166Speter p->cTerm = EOF; 2623289166Speter return 0; 2624289166Speter } 2625289166Speter if( c=='"' ){ 2626289166Speter int pc, ppc; 2627289166Speter int startLine = p->nLine; 2628289166Speter int cQuote = c; 2629289166Speter pc = ppc = 0; 2630289166Speter while( 1 ){ 2631289166Speter c = fgetc(p->in); 2632289166Speter if( c==rSep ) p->nLine++; 2633289166Speter if( c==cQuote ){ 2634289166Speter if( pc==cQuote ){ 2635289166Speter pc = 0; 2636289166Speter continue; 2637289166Speter } 2638289166Speter } 2639289166Speter if( (c==cSep && pc==cQuote) 2640289166Speter || (c==rSep && pc==cQuote) 2641289166Speter || (c==rSep && pc=='\r' && ppc==cQuote) 2642289166Speter || (c==EOF && pc==cQuote) 2643289166Speter ){ 2644289166Speter do{ p->n--; }while( p->z[p->n]!=cQuote ); 2645289166Speter p->cTerm = c; 2646289166Speter break; 2647289166Speter } 2648289166Speter if( pc==cQuote && c!='\r' ){ 2649305003Scy utf8_printf(stderr, "%s:%d: unescaped %c character\n", 2650289166Speter p->zFile, p->nLine, cQuote); 2651289166Speter } 2652289166Speter if( c==EOF ){ 2653305003Scy utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n", 2654289166Speter p->zFile, startLine, cQuote); 2655289166Speter p->cTerm = c; 2656289166Speter break; 2657289166Speter } 2658289166Speter import_append_char(p, c); 2659289166Speter ppc = pc; 2660289166Speter pc = c; 2661289166Speter } 2662289166Speter }else{ 2663289166Speter while( c!=EOF && c!=cSep && c!=rSep ){ 2664289166Speter import_append_char(p, c); 2665289166Speter c = fgetc(p->in); 2666289166Speter } 2667289166Speter if( c==rSep ){ 2668289166Speter p->nLine++; 2669289166Speter if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; 2670289166Speter } 2671289166Speter p->cTerm = c; 2672289166Speter } 2673289166Speter if( p->z ) p->z[p->n] = 0; 2674289166Speter return p->z; 2675289166Speter} 2676289166Speter 2677289166Speter/* Read a single field of ASCII delimited text. 2678289166Speter** 2679289166Speter** + Input comes from p->in. 2680289166Speter** + Store results in p->z of length p->n. Space to hold p->z comes 2681289166Speter** from sqlite3_malloc64(). 2682289166Speter** + Use p->cSep as the column separator. The default is "\x1F". 2683289166Speter** + Use p->rSep as the row separator. The default is "\x1E". 2684289166Speter** + Keep track of the row number in p->nLine. 2685289166Speter** + Store the character that terminates the field in p->cTerm. Store 2686289166Speter** EOF on end-of-file. 2687289166Speter** + Report syntax errors on stderr 2688289166Speter*/ 2689289166Speterstatic char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){ 2690289166Speter int c; 2691289166Speter int cSep = p->cColSep; 2692289166Speter int rSep = p->cRowSep; 2693289166Speter p->n = 0; 2694289166Speter c = fgetc(p->in); 2695289166Speter if( c==EOF || seenInterrupt ){ 2696289166Speter p->cTerm = EOF; 2697289166Speter return 0; 2698289166Speter } 2699289166Speter while( c!=EOF && c!=cSep && c!=rSep ){ 2700289166Speter import_append_char(p, c); 2701289166Speter c = fgetc(p->in); 2702289166Speter } 2703289166Speter if( c==rSep ){ 2704289166Speter p->nLine++; 2705289166Speter } 2706289166Speter p->cTerm = c; 2707289166Speter if( p->z ) p->z[p->n] = 0; 2708289166Speter return p->z; 2709289166Speter} 2710289166Speter 2711289166Speter/* 2712289166Speter** Try to transfer data for table zTable. If an error is seen while 2713289166Speter** moving forward, try to go backwards. The backwards movement won't 2714289166Speter** work for WITHOUT ROWID tables. 2715289166Speter*/ 2716289166Speterstatic void tryToCloneData( 2717289166Speter ShellState *p, 2718289166Speter sqlite3 *newDb, 2719289166Speter const char *zTable 2720289166Speter){ 2721305003Scy sqlite3_stmt *pQuery = 0; 2722289166Speter sqlite3_stmt *pInsert = 0; 2723289166Speter char *zQuery = 0; 2724289166Speter char *zInsert = 0; 2725289166Speter int rc; 2726289166Speter int i, j, n; 2727289166Speter int nTable = (int)strlen(zTable); 2728289166Speter int k = 0; 2729289166Speter int cnt = 0; 2730289166Speter const int spinRate = 10000; 2731289166Speter 2732289166Speter zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); 2733289166Speter rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); 2734289166Speter if( rc ){ 2735305003Scy utf8_printf(stderr, "Error %d: %s on [%s]\n", 2736289166Speter sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), 2737289166Speter zQuery); 2738289166Speter goto end_data_xfer; 2739289166Speter } 2740289166Speter n = sqlite3_column_count(pQuery); 2741289166Speter zInsert = sqlite3_malloc64(200 + nTable + n*3); 2742289166Speter if( zInsert==0 ){ 2743305003Scy raw_printf(stderr, "out of memory\n"); 2744289166Speter goto end_data_xfer; 2745289166Speter } 2746289166Speter sqlite3_snprintf(200+nTable,zInsert, 2747289166Speter "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable); 2748289166Speter i = (int)strlen(zInsert); 2749289166Speter for(j=1; j<n; j++){ 2750289166Speter memcpy(zInsert+i, ",?", 2); 2751289166Speter i += 2; 2752289166Speter } 2753289166Speter memcpy(zInsert+i, ");", 3); 2754289166Speter rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0); 2755289166Speter if( rc ){ 2756305003Scy utf8_printf(stderr, "Error %d: %s on [%s]\n", 2757289166Speter sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb), 2758289166Speter zQuery); 2759289166Speter goto end_data_xfer; 2760289166Speter } 2761289166Speter for(k=0; k<2; k++){ 2762289166Speter while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ 2763289166Speter for(i=0; i<n; i++){ 2764289166Speter switch( sqlite3_column_type(pQuery, i) ){ 2765289166Speter case SQLITE_NULL: { 2766289166Speter sqlite3_bind_null(pInsert, i+1); 2767289166Speter break; 2768289166Speter } 2769289166Speter case SQLITE_INTEGER: { 2770289166Speter sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i)); 2771289166Speter break; 2772289166Speter } 2773289166Speter case SQLITE_FLOAT: { 2774289166Speter sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i)); 2775289166Speter break; 2776289166Speter } 2777289166Speter case SQLITE_TEXT: { 2778289166Speter sqlite3_bind_text(pInsert, i+1, 2779289166Speter (const char*)sqlite3_column_text(pQuery,i), 2780289166Speter -1, SQLITE_STATIC); 2781289166Speter break; 2782289166Speter } 2783289166Speter case SQLITE_BLOB: { 2784289166Speter sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i), 2785289166Speter sqlite3_column_bytes(pQuery,i), 2786289166Speter SQLITE_STATIC); 2787289166Speter break; 2788289166Speter } 2789289166Speter } 2790289166Speter } /* End for */ 2791289166Speter rc = sqlite3_step(pInsert); 2792289166Speter if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ 2793305003Scy utf8_printf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb), 2794289166Speter sqlite3_errmsg(newDb)); 2795289166Speter } 2796289166Speter sqlite3_reset(pInsert); 2797289166Speter cnt++; 2798289166Speter if( (cnt%spinRate)==0 ){ 2799289166Speter printf("%c\b", "|/-\\"[(cnt/spinRate)%4]); 2800289166Speter fflush(stdout); 2801289166Speter } 2802289166Speter } /* End while */ 2803289166Speter if( rc==SQLITE_DONE ) break; 2804289166Speter sqlite3_finalize(pQuery); 2805289166Speter sqlite3_free(zQuery); 2806289166Speter zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;", 2807289166Speter zTable); 2808289166Speter rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); 2809289166Speter if( rc ){ 2810305003Scy utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable); 2811289166Speter break; 2812289166Speter } 2813289166Speter } /* End for(k=0...) */ 2814289166Speter 2815289166Speterend_data_xfer: 2816289166Speter sqlite3_finalize(pQuery); 2817289166Speter sqlite3_finalize(pInsert); 2818289166Speter sqlite3_free(zQuery); 2819289166Speter sqlite3_free(zInsert); 2820289166Speter} 2821289166Speter 2822289166Speter 2823289166Speter/* 2824289166Speter** Try to transfer all rows of the schema that match zWhere. For 2825289166Speter** each row, invoke xForEach() on the object defined by that row. 2826289166Speter** If an error is encountered while moving forward through the 2827289166Speter** sqlite_master table, try again moving backwards. 2828289166Speter*/ 2829289166Speterstatic void tryToCloneSchema( 2830289166Speter ShellState *p, 2831289166Speter sqlite3 *newDb, 2832289166Speter const char *zWhere, 2833289166Speter void (*xForEach)(ShellState*,sqlite3*,const char*) 2834289166Speter){ 2835289166Speter sqlite3_stmt *pQuery = 0; 2836289166Speter char *zQuery = 0; 2837289166Speter int rc; 2838289166Speter const unsigned char *zName; 2839289166Speter const unsigned char *zSql; 2840289166Speter char *zErrMsg = 0; 2841289166Speter 2842289166Speter zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master" 2843289166Speter " WHERE %s", zWhere); 2844289166Speter rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); 2845289166Speter if( rc ){ 2846305003Scy utf8_printf(stderr, "Error: (%d) %s on [%s]\n", 2847289166Speter sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), 2848289166Speter zQuery); 2849289166Speter goto end_schema_xfer; 2850289166Speter } 2851289166Speter while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ 2852289166Speter zName = sqlite3_column_text(pQuery, 0); 2853289166Speter zSql = sqlite3_column_text(pQuery, 1); 2854289166Speter printf("%s... ", zName); fflush(stdout); 2855289166Speter sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); 2856289166Speter if( zErrMsg ){ 2857305003Scy utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); 2858289166Speter sqlite3_free(zErrMsg); 2859289166Speter zErrMsg = 0; 2860289166Speter } 2861289166Speter if( xForEach ){ 2862289166Speter xForEach(p, newDb, (const char*)zName); 2863289166Speter } 2864289166Speter printf("done\n"); 2865289166Speter } 2866289166Speter if( rc!=SQLITE_DONE ){ 2867289166Speter sqlite3_finalize(pQuery); 2868289166Speter sqlite3_free(zQuery); 2869289166Speter zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master" 2870289166Speter " WHERE %s ORDER BY rowid DESC", zWhere); 2871289166Speter rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); 2872289166Speter if( rc ){ 2873305003Scy utf8_printf(stderr, "Error: (%d) %s on [%s]\n", 2874289166Speter sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), 2875289166Speter zQuery); 2876289166Speter goto end_schema_xfer; 2877289166Speter } 2878289166Speter while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ 2879289166Speter zName = sqlite3_column_text(pQuery, 0); 2880289166Speter zSql = sqlite3_column_text(pQuery, 1); 2881289166Speter printf("%s... ", zName); fflush(stdout); 2882289166Speter sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); 2883289166Speter if( zErrMsg ){ 2884305003Scy utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); 2885289166Speter sqlite3_free(zErrMsg); 2886289166Speter zErrMsg = 0; 2887289166Speter } 2888289166Speter if( xForEach ){ 2889289166Speter xForEach(p, newDb, (const char*)zName); 2890289166Speter } 2891289166Speter printf("done\n"); 2892289166Speter } 2893289166Speter } 2894289166Speterend_schema_xfer: 2895289166Speter sqlite3_finalize(pQuery); 2896289166Speter sqlite3_free(zQuery); 2897289166Speter} 2898289166Speter 2899289166Speter/* 2900289166Speter** Open a new database file named "zNewDb". Try to recover as much information 2901289166Speter** as possible out of the main database (which might be corrupt) and write it 2902289166Speter** into zNewDb. 2903289166Speter*/ 2904289166Speterstatic void tryToClone(ShellState *p, const char *zNewDb){ 2905289166Speter int rc; 2906289166Speter sqlite3 *newDb = 0; 2907289166Speter if( access(zNewDb,0)==0 ){ 2908305003Scy utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb); 2909289166Speter return; 2910289166Speter } 2911289166Speter rc = sqlite3_open(zNewDb, &newDb); 2912289166Speter if( rc ){ 2913305003Scy utf8_printf(stderr, "Cannot create output database: %s\n", 2914289166Speter sqlite3_errmsg(newDb)); 2915289166Speter }else{ 2916289166Speter sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0); 2917289166Speter sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); 2918289166Speter tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); 2919289166Speter tryToCloneSchema(p, newDb, "type!='table'", 0); 2920289166Speter sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); 2921289166Speter sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); 2922289166Speter } 2923289166Speter sqlite3_close(newDb); 2924289166Speter} 2925289166Speter 2926289166Speter/* 2927289166Speter** Change the output file back to stdout 2928289166Speter*/ 2929289166Speterstatic void output_reset(ShellState *p){ 2930289166Speter if( p->outfile[0]=='|' ){ 2931289166Speter#ifndef SQLITE_OMIT_POPEN 2932289166Speter pclose(p->out); 2933289166Speter#endif 2934289166Speter }else{ 2935289166Speter output_file_close(p->out); 2936289166Speter } 2937289166Speter p->outfile[0] = 0; 2938289166Speter p->out = stdout; 2939289166Speter} 2940289166Speter 2941289166Speter/* 2942289166Speter** Run an SQL command and return the single integer result. 2943289166Speter*/ 2944289166Speterstatic int db_int(ShellState *p, const char *zSql){ 2945289166Speter sqlite3_stmt *pStmt; 2946289166Speter int res = 0; 2947289166Speter sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); 2948289166Speter if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ 2949289166Speter res = sqlite3_column_int(pStmt,0); 2950289166Speter } 2951289166Speter sqlite3_finalize(pStmt); 2952289166Speter return res; 2953289166Speter} 2954289166Speter 2955289166Speter/* 2956289166Speter** Convert a 2-byte or 4-byte big-endian integer into a native integer 2957289166Speter*/ 2958305003Scystatic unsigned int get2byteInt(unsigned char *a){ 2959289166Speter return (a[0]<<8) + a[1]; 2960289166Speter} 2961305003Scystatic unsigned int get4byteInt(unsigned char *a){ 2962289166Speter return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; 2963289166Speter} 2964289166Speter 2965289166Speter/* 2966289166Speter** Implementation of the ".info" command. 2967289166Speter** 2968289166Speter** Return 1 on error, 2 to exit, and 0 otherwise. 2969289166Speter*/ 2970289166Speterstatic int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){ 2971289166Speter static const struct { const char *zName; int ofst; } aField[] = { 2972289166Speter { "file change counter:", 24 }, 2973289166Speter { "database page count:", 28 }, 2974289166Speter { "freelist page count:", 36 }, 2975289166Speter { "schema cookie:", 40 }, 2976289166Speter { "schema format:", 44 }, 2977289166Speter { "default cache size:", 48 }, 2978289166Speter { "autovacuum top root:", 52 }, 2979289166Speter { "incremental vacuum:", 64 }, 2980289166Speter { "text encoding:", 56 }, 2981289166Speter { "user version:", 60 }, 2982289166Speter { "application id:", 68 }, 2983289166Speter { "software version:", 96 }, 2984289166Speter }; 2985289166Speter static const struct { const char *zName; const char *zSql; } aQuery[] = { 2986289166Speter { "number of tables:", 2987289166Speter "SELECT count(*) FROM %s WHERE type='table'" }, 2988289166Speter { "number of indexes:", 2989289166Speter "SELECT count(*) FROM %s WHERE type='index'" }, 2990289166Speter { "number of triggers:", 2991289166Speter "SELECT count(*) FROM %s WHERE type='trigger'" }, 2992289166Speter { "number of views:", 2993289166Speter "SELECT count(*) FROM %s WHERE type='view'" }, 2994289166Speter { "schema size:", 2995289166Speter "SELECT total(length(sql)) FROM %s" }, 2996289166Speter }; 2997305003Scy sqlite3_file *pFile = 0; 2998289166Speter int i; 2999289166Speter char *zSchemaTab; 3000289166Speter char *zDb = nArg>=2 ? azArg[1] : "main"; 3001289166Speter unsigned char aHdr[100]; 3002289166Speter open_db(p, 0); 3003289166Speter if( p->db==0 ) return 1; 3004289166Speter sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile); 3005289166Speter if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){ 3006289166Speter return 1; 3007289166Speter } 3008289166Speter i = pFile->pMethods->xRead(pFile, aHdr, 100, 0); 3009289166Speter if( i!=SQLITE_OK ){ 3010305003Scy raw_printf(stderr, "unable to read database header\n"); 3011289166Speter return 1; 3012289166Speter } 3013289166Speter i = get2byteInt(aHdr+16); 3014289166Speter if( i==1 ) i = 65536; 3015305003Scy utf8_printf(p->out, "%-20s %d\n", "database page size:", i); 3016305003Scy utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]); 3017305003Scy utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]); 3018305003Scy utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]); 3019289166Speter for(i=0; i<ArraySize(aField); i++){ 3020289166Speter int ofst = aField[i].ofst; 3021289166Speter unsigned int val = get4byteInt(aHdr + ofst); 3022305003Scy utf8_printf(p->out, "%-20s %u", aField[i].zName, val); 3023289166Speter switch( ofst ){ 3024289166Speter case 56: { 3025305003Scy if( val==1 ) raw_printf(p->out, " (utf8)"); 3026305003Scy if( val==2 ) raw_printf(p->out, " (utf16le)"); 3027305003Scy if( val==3 ) raw_printf(p->out, " (utf16be)"); 3028289166Speter } 3029289166Speter } 3030305003Scy raw_printf(p->out, "\n"); 3031289166Speter } 3032289166Speter if( zDb==0 ){ 3033289166Speter zSchemaTab = sqlite3_mprintf("main.sqlite_master"); 3034289166Speter }else if( strcmp(zDb,"temp")==0 ){ 3035289166Speter zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master"); 3036289166Speter }else{ 3037289166Speter zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb); 3038289166Speter } 3039289166Speter for(i=0; i<ArraySize(aQuery); i++){ 3040289166Speter char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab); 3041289166Speter int val = db_int(p, zSql); 3042289166Speter sqlite3_free(zSql); 3043305003Scy utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val); 3044289166Speter } 3045289166Speter sqlite3_free(zSchemaTab); 3046289166Speter return 0; 3047289166Speter} 3048289166Speter 3049305003Scy/* 3050305003Scy** Print the current sqlite3_errmsg() value to stderr and return 1. 3051305003Scy*/ 3052305003Scystatic int shellDatabaseError(sqlite3 *db){ 3053305003Scy const char *zErr = sqlite3_errmsg(db); 3054305003Scy utf8_printf(stderr, "Error: %s\n", zErr); 3055305003Scy return 1; 3056305003Scy} 3057289166Speter 3058289166Speter/* 3059305003Scy** Print an out-of-memory message to stderr and return 1. 3060305003Scy*/ 3061305003Scystatic int shellNomemError(void){ 3062305003Scy raw_printf(stderr, "Error: out of memory\n"); 3063305003Scy return 1; 3064305003Scy} 3065305003Scy 3066305003Scy/* 3067305003Scy** Compare the string as a command-line option with either one or two 3068305003Scy** initial "-" characters. 3069305003Scy*/ 3070305003Scystatic int optionMatch(const char *zStr, const char *zOpt){ 3071305003Scy if( zStr[0]!='-' ) return 0; 3072305003Scy zStr++; 3073305003Scy if( zStr[0]=='-' ) zStr++; 3074305003Scy return strcmp(zStr, zOpt)==0; 3075305003Scy} 3076305003Scy 3077305003Scy/* 3078251883Speter** If an input line begins with "." then invoke this routine to 3079251883Speter** process that line. 3080251883Speter** 3081251883Speter** Return 1 on error, 2 to exit, and 0 otherwise. 3082251883Speter*/ 3083289166Speterstatic int do_meta_command(char *zLine, ShellState *p){ 3084289166Speter int h = 1; 3085251883Speter int nArg = 0; 3086251883Speter int n, c; 3087251883Speter int rc = 0; 3088251883Speter char *azArg[50]; 3089251883Speter 3090251883Speter /* Parse the input line into tokens. 3091251883Speter */ 3092289166Speter while( zLine[h] && nArg<ArraySize(azArg) ){ 3093289166Speter while( IsSpace(zLine[h]) ){ h++; } 3094289166Speter if( zLine[h]==0 ) break; 3095289166Speter if( zLine[h]=='\'' || zLine[h]=='"' ){ 3096289166Speter int delim = zLine[h++]; 3097289166Speter azArg[nArg++] = &zLine[h]; 3098305003Scy while( zLine[h] && zLine[h]!=delim ){ 3099289166Speter if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++; 3100305003Scy h++; 3101251883Speter } 3102289166Speter if( zLine[h]==delim ){ 3103289166Speter zLine[h++] = 0; 3104289166Speter } 3105251883Speter if( delim=='"' ) resolve_backslashes(azArg[nArg-1]); 3106251883Speter }else{ 3107289166Speter azArg[nArg++] = &zLine[h]; 3108289166Speter while( zLine[h] && !IsSpace(zLine[h]) ){ h++; } 3109289166Speter if( zLine[h] ) zLine[h++] = 0; 3110251883Speter resolve_backslashes(azArg[nArg-1]); 3111251883Speter } 3112251883Speter } 3113251883Speter 3114251883Speter /* Process the input line. 3115251883Speter */ 3116251883Speter if( nArg==0 ) return 0; /* no tokens, no error */ 3117251883Speter n = strlen30(azArg[0]); 3118251883Speter c = azArg[0][0]; 3119305003Scy 3120305003Scy if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){ 3121305003Scy if( nArg!=2 ){ 3122305003Scy raw_printf(stderr, "Usage: .auth ON|OFF\n"); 3123305003Scy rc = 1; 3124305003Scy goto meta_command_exit; 3125305003Scy } 3126305003Scy open_db(p, 0); 3127305003Scy if( booleanValue(azArg[1]) ){ 3128305003Scy sqlite3_set_authorizer(p->db, shellAuth, p); 3129305003Scy }else{ 3130305003Scy sqlite3_set_authorizer(p->db, 0, 0); 3131305003Scy } 3132305003Scy }else 3133305003Scy 3134289166Speter if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0) 3135289166Speter || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0) 3136289166Speter ){ 3137251883Speter const char *zDestFile = 0; 3138251883Speter const char *zDb = 0; 3139251883Speter sqlite3 *pDest; 3140251883Speter sqlite3_backup *pBackup; 3141251883Speter int j; 3142251883Speter for(j=1; j<nArg; j++){ 3143251883Speter const char *z = azArg[j]; 3144251883Speter if( z[0]=='-' ){ 3145251883Speter while( z[0]=='-' ) z++; 3146289166Speter /* No options to process at this time */ 3147251883Speter { 3148305003Scy utf8_printf(stderr, "unknown option: %s\n", azArg[j]); 3149251883Speter return 1; 3150251883Speter } 3151251883Speter }else if( zDestFile==0 ){ 3152251883Speter zDestFile = azArg[j]; 3153251883Speter }else if( zDb==0 ){ 3154251883Speter zDb = zDestFile; 3155251883Speter zDestFile = azArg[j]; 3156251883Speter }else{ 3157305003Scy raw_printf(stderr, "too many arguments to .backup\n"); 3158251883Speter return 1; 3159251883Speter } 3160251883Speter } 3161251883Speter if( zDestFile==0 ){ 3162305003Scy raw_printf(stderr, "missing FILENAME argument on .backup\n"); 3163251883Speter return 1; 3164251883Speter } 3165251883Speter if( zDb==0 ) zDb = "main"; 3166251883Speter rc = sqlite3_open(zDestFile, &pDest); 3167251883Speter if( rc!=SQLITE_OK ){ 3168305003Scy utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile); 3169251883Speter sqlite3_close(pDest); 3170251883Speter return 1; 3171251883Speter } 3172289166Speter open_db(p, 0); 3173251883Speter pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); 3174251883Speter if( pBackup==0 ){ 3175305003Scy utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); 3176251883Speter sqlite3_close(pDest); 3177251883Speter return 1; 3178251883Speter } 3179251883Speter while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} 3180251883Speter sqlite3_backup_finish(pBackup); 3181251883Speter if( rc==SQLITE_DONE ){ 3182251883Speter rc = 0; 3183251883Speter }else{ 3184305003Scy utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); 3185251883Speter rc = 1; 3186251883Speter } 3187251883Speter sqlite3_close(pDest); 3188251883Speter }else 3189251883Speter 3190289166Speter if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){ 3191289166Speter if( nArg==2 ){ 3192289166Speter bail_on_error = booleanValue(azArg[1]); 3193289166Speter }else{ 3194305003Scy raw_printf(stderr, "Usage: .bail on|off\n"); 3195289166Speter rc = 1; 3196289166Speter } 3197251883Speter }else 3198251883Speter 3199289166Speter if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){ 3200289166Speter if( nArg==2 ){ 3201289166Speter if( booleanValue(azArg[1]) ){ 3202305003Scy setBinaryMode(p->out, 1); 3203289166Speter }else{ 3204305003Scy setTextMode(p->out, 1); 3205289166Speter } 3206289166Speter }else{ 3207305003Scy raw_printf(stderr, "Usage: .binary on|off\n"); 3208289166Speter rc = 1; 3209289166Speter } 3210289166Speter }else 3211289166Speter 3212251883Speter /* The undocumented ".breakpoint" command causes a call to the no-op 3213251883Speter ** routine named test_breakpoint(). 3214251883Speter */ 3215251883Speter if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ 3216251883Speter test_breakpoint(); 3217251883Speter }else 3218251883Speter 3219305003Scy if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){ 3220305003Scy if( nArg==2 ){ 3221305003Scy p->countChanges = booleanValue(azArg[1]); 3222305003Scy }else{ 3223305003Scy raw_printf(stderr, "Usage: .changes on|off\n"); 3224305003Scy rc = 1; 3225305003Scy } 3226305003Scy }else 3227305003Scy 3228289166Speter if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){ 3229289166Speter if( nArg==2 ){ 3230289166Speter tryToClone(p, azArg[1]); 3231289166Speter }else{ 3232305003Scy raw_printf(stderr, "Usage: .clone FILENAME\n"); 3233289166Speter rc = 1; 3234289166Speter } 3235289166Speter }else 3236289166Speter 3237289166Speter if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ 3238289166Speter ShellState data; 3239251883Speter char *zErrMsg = 0; 3240289166Speter open_db(p, 0); 3241251883Speter memcpy(&data, p, sizeof(data)); 3242251883Speter data.showHeader = 1; 3243305003Scy data.cMode = data.mode = MODE_Column; 3244251883Speter data.colWidth[0] = 3; 3245251883Speter data.colWidth[1] = 15; 3246251883Speter data.colWidth[2] = 58; 3247251883Speter data.cnt = 0; 3248251883Speter sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg); 3249251883Speter if( zErrMsg ){ 3250305003Scy utf8_printf(stderr,"Error: %s\n", zErrMsg); 3251251883Speter sqlite3_free(zErrMsg); 3252251883Speter rc = 1; 3253251883Speter } 3254251883Speter }else 3255251883Speter 3256289166Speter if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){ 3257289166Speter rc = shell_dbinfo_command(p, nArg, azArg); 3258289166Speter }else 3259289166Speter 3260289166Speter if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ 3261289166Speter open_db(p, 0); 3262251883Speter /* When playing back a "dump", the content might appear in an order 3263251883Speter ** which causes immediate foreign key constraints to be violated. 3264251883Speter ** So disable foreign-key constraint enforcement to prevent problems. */ 3265289166Speter if( nArg!=1 && nArg!=2 ){ 3266305003Scy raw_printf(stderr, "Usage: .dump ?LIKE-PATTERN?\n"); 3267289166Speter rc = 1; 3268289166Speter goto meta_command_exit; 3269289166Speter } 3270305003Scy raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n"); 3271305003Scy raw_printf(p->out, "BEGIN TRANSACTION;\n"); 3272251883Speter p->writableSchema = 0; 3273251883Speter sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); 3274251883Speter p->nErr = 0; 3275251883Speter if( nArg==1 ){ 3276305003Scy run_schema_dump_query(p, 3277251883Speter "SELECT name, type, sql FROM sqlite_master " 3278251883Speter "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'" 3279251883Speter ); 3280305003Scy run_schema_dump_query(p, 3281251883Speter "SELECT name, type, sql FROM sqlite_master " 3282251883Speter "WHERE name=='sqlite_sequence'" 3283251883Speter ); 3284251883Speter run_table_dump_query(p, 3285251883Speter "SELECT sql FROM sqlite_master " 3286251883Speter "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 3287251883Speter ); 3288251883Speter }else{ 3289251883Speter int i; 3290251883Speter for(i=1; i<nArg; i++){ 3291251883Speter zShellStatic = azArg[i]; 3292251883Speter run_schema_dump_query(p, 3293251883Speter "SELECT name, type, sql FROM sqlite_master " 3294251883Speter "WHERE tbl_name LIKE shellstatic() AND type=='table'" 3295251883Speter " AND sql NOT NULL"); 3296251883Speter run_table_dump_query(p, 3297251883Speter "SELECT sql FROM sqlite_master " 3298251883Speter "WHERE sql NOT NULL" 3299251883Speter " AND type IN ('index','trigger','view')" 3300251883Speter " AND tbl_name LIKE shellstatic()", 0 3301251883Speter ); 3302251883Speter zShellStatic = 0; 3303251883Speter } 3304251883Speter } 3305251883Speter if( p->writableSchema ){ 3306305003Scy raw_printf(p->out, "PRAGMA writable_schema=OFF;\n"); 3307251883Speter p->writableSchema = 0; 3308251883Speter } 3309251883Speter sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); 3310251883Speter sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); 3311305003Scy raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); 3312251883Speter }else 3313251883Speter 3314289166Speter if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){ 3315289166Speter if( nArg==2 ){ 3316289166Speter p->echoOn = booleanValue(azArg[1]); 3317289166Speter }else{ 3318305003Scy raw_printf(stderr, "Usage: .echo on|off\n"); 3319289166Speter rc = 1; 3320289166Speter } 3321251883Speter }else 3322251883Speter 3323289166Speter if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){ 3324289166Speter if( nArg==2 ){ 3325305003Scy if( strcmp(azArg[1],"full")==0 ){ 3326305003Scy p->autoEQP = 2; 3327305003Scy }else{ 3328305003Scy p->autoEQP = booleanValue(azArg[1]); 3329305003Scy } 3330289166Speter }else{ 3331305003Scy raw_printf(stderr, "Usage: .eqp on|off|full\n"); 3332289166Speter rc = 1; 3333305003Scy } 3334289166Speter }else 3335289166Speter 3336251883Speter if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ 3337289166Speter if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc); 3338251883Speter rc = 2; 3339251883Speter }else 3340251883Speter 3341289166Speter if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ 3342305003Scy int val = 1; 3343305003Scy if( nArg>=2 ){ 3344305003Scy if( strcmp(azArg[1],"auto")==0 ){ 3345305003Scy val = 99; 3346305003Scy }else{ 3347305003Scy val = booleanValue(azArg[1]); 3348251883Speter } 3349305003Scy } 3350305003Scy if( val==1 && p->mode!=MODE_Explain ){ 3351305003Scy p->normalMode = p->mode; 3352251883Speter p->mode = MODE_Explain; 3353305003Scy p->autoExplain = 0; 3354305003Scy }else if( val==0 ){ 3355305003Scy if( p->mode==MODE_Explain ) p->mode = p->normalMode; 3356305003Scy p->autoExplain = 0; 3357305003Scy }else if( val==99 ){ 3358305003Scy if( p->mode==MODE_Explain ) p->mode = p->normalMode; 3359305003Scy p->autoExplain = 1; 3360251883Speter } 3361251883Speter }else 3362251883Speter 3363289166Speter if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ 3364289166Speter ShellState data; 3365289166Speter char *zErrMsg = 0; 3366289166Speter int doStats = 0; 3367305003Scy memcpy(&data, p, sizeof(data)); 3368305003Scy data.showHeader = 0; 3369305003Scy data.cMode = data.mode = MODE_Semi; 3370305003Scy if( nArg==2 && optionMatch(azArg[1], "indent") ){ 3371305003Scy data.cMode = data.mode = MODE_Pretty; 3372305003Scy nArg = 1; 3373305003Scy } 3374289166Speter if( nArg!=1 ){ 3375305003Scy raw_printf(stderr, "Usage: .fullschema ?--indent?\n"); 3376289166Speter rc = 1; 3377289166Speter goto meta_command_exit; 3378289166Speter } 3379289166Speter open_db(p, 0); 3380289166Speter rc = sqlite3_exec(p->db, 3381289166Speter "SELECT sql FROM" 3382289166Speter " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" 3383289166Speter " FROM sqlite_master UNION ALL" 3384289166Speter " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " 3385289166Speter "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " 3386289166Speter "ORDER BY rowid", 3387289166Speter callback, &data, &zErrMsg 3388289166Speter ); 3389289166Speter if( rc==SQLITE_OK ){ 3390289166Speter sqlite3_stmt *pStmt; 3391289166Speter rc = sqlite3_prepare_v2(p->db, 3392289166Speter "SELECT rowid FROM sqlite_master" 3393289166Speter " WHERE name GLOB 'sqlite_stat[134]'", 3394289166Speter -1, &pStmt, 0); 3395289166Speter doStats = sqlite3_step(pStmt)==SQLITE_ROW; 3396289166Speter sqlite3_finalize(pStmt); 3397289166Speter } 3398289166Speter if( doStats==0 ){ 3399305003Scy raw_printf(p->out, "/* No STAT tables available */\n"); 3400289166Speter }else{ 3401305003Scy raw_printf(p->out, "ANALYZE sqlite_master;\n"); 3402289166Speter sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'", 3403289166Speter callback, &data, &zErrMsg); 3404305003Scy data.cMode = data.mode = MODE_Insert; 3405289166Speter data.zDestTable = "sqlite_stat1"; 3406289166Speter shell_exec(p->db, "SELECT * FROM sqlite_stat1", 3407289166Speter shell_callback, &data,&zErrMsg); 3408289166Speter data.zDestTable = "sqlite_stat3"; 3409289166Speter shell_exec(p->db, "SELECT * FROM sqlite_stat3", 3410289166Speter shell_callback, &data,&zErrMsg); 3411289166Speter data.zDestTable = "sqlite_stat4"; 3412289166Speter shell_exec(p->db, "SELECT * FROM sqlite_stat4", 3413289166Speter shell_callback, &data, &zErrMsg); 3414305003Scy raw_printf(p->out, "ANALYZE sqlite_master;\n"); 3415289166Speter } 3416251883Speter }else 3417251883Speter 3418289166Speter if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){ 3419289166Speter if( nArg==2 ){ 3420289166Speter p->showHeader = booleanValue(azArg[1]); 3421289166Speter }else{ 3422305003Scy raw_printf(stderr, "Usage: .headers on|off\n"); 3423289166Speter rc = 1; 3424251883Speter } 3425251883Speter }else 3426251883Speter 3427289166Speter if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ 3428305003Scy utf8_printf(p->out, "%s", zHelp); 3429289166Speter }else 3430289166Speter 3431289166Speter if( c=='i' && strncmp(azArg[0], "import", n)==0 ){ 3432289166Speter char *zTable; /* Insert data into this table */ 3433289166Speter char *zFile; /* Name of file to extra content from */ 3434251883Speter sqlite3_stmt *pStmt = NULL; /* A statement */ 3435251883Speter int nCol; /* Number of columns in the table */ 3436251883Speter int nByte; /* Number of bytes in an SQL string */ 3437251883Speter int i, j; /* Loop counters */ 3438289166Speter int needCommit; /* True to COMMIT or ROLLBACK at end */ 3439289166Speter int nSep; /* Number of bytes in p->colSeparator[] */ 3440251883Speter char *zSql; /* An SQL statement */ 3441289166Speter ImportCtx sCtx; /* Reader context */ 3442289166Speter char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */ 3443289166Speter int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */ 3444251883Speter 3445289166Speter if( nArg!=3 ){ 3446305003Scy raw_printf(stderr, "Usage: .import FILE TABLE\n"); 3447289166Speter goto meta_command_exit; 3448289166Speter } 3449289166Speter zFile = azArg[1]; 3450289166Speter zTable = azArg[2]; 3451289166Speter seenInterrupt = 0; 3452289166Speter memset(&sCtx, 0, sizeof(sCtx)); 3453289166Speter open_db(p, 0); 3454289166Speter nSep = strlen30(p->colSeparator); 3455251883Speter if( nSep==0 ){ 3456305003Scy raw_printf(stderr, 3457305003Scy "Error: non-null column separator required for import\n"); 3458251883Speter return 1; 3459251883Speter } 3460289166Speter if( nSep>1 ){ 3461305003Scy raw_printf(stderr, "Error: multi-character column separators not allowed" 3462289166Speter " for import\n"); 3463289166Speter return 1; 3464289166Speter } 3465289166Speter nSep = strlen30(p->rowSeparator); 3466289166Speter if( nSep==0 ){ 3467305003Scy raw_printf(stderr, "Error: non-null row separator required for import\n"); 3468289166Speter return 1; 3469289166Speter } 3470289166Speter if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){ 3471289166Speter /* When importing CSV (only), if the row separator is set to the 3472289166Speter ** default output row separator, change it to the default input 3473289166Speter ** row separator. This avoids having to maintain different input 3474289166Speter ** and output row separators. */ 3475289166Speter sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); 3476289166Speter nSep = strlen30(p->rowSeparator); 3477289166Speter } 3478289166Speter if( nSep>1 ){ 3479305003Scy raw_printf(stderr, "Error: multi-character row separators not allowed" 3480289166Speter " for import\n"); 3481289166Speter return 1; 3482289166Speter } 3483289166Speter sCtx.zFile = zFile; 3484289166Speter sCtx.nLine = 1; 3485289166Speter if( sCtx.zFile[0]=='|' ){ 3486289166Speter#ifdef SQLITE_OMIT_POPEN 3487305003Scy raw_printf(stderr, "Error: pipes are not supported in this OS\n"); 3488289166Speter return 1; 3489289166Speter#else 3490289166Speter sCtx.in = popen(sCtx.zFile+1, "r"); 3491289166Speter sCtx.zFile = "<pipe>"; 3492289166Speter xCloser = pclose; 3493289166Speter#endif 3494289166Speter }else{ 3495289166Speter sCtx.in = fopen(sCtx.zFile, "rb"); 3496289166Speter xCloser = fclose; 3497289166Speter } 3498289166Speter if( p->mode==MODE_Ascii ){ 3499289166Speter xRead = ascii_read_one_field; 3500289166Speter }else{ 3501289166Speter xRead = csv_read_one_field; 3502289166Speter } 3503289166Speter if( sCtx.in==0 ){ 3504305003Scy utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); 3505289166Speter return 1; 3506289166Speter } 3507289166Speter sCtx.cColSep = p->colSeparator[0]; 3508289166Speter sCtx.cRowSep = p->rowSeparator[0]; 3509251883Speter zSql = sqlite3_mprintf("SELECT * FROM %s", zTable); 3510251883Speter if( zSql==0 ){ 3511305003Scy raw_printf(stderr, "Error: out of memory\n"); 3512289166Speter xCloser(sCtx.in); 3513251883Speter return 1; 3514251883Speter } 3515251883Speter nByte = strlen30(zSql); 3516289166Speter rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); 3517289166Speter import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ 3518289166Speter if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){ 3519289166Speter char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable); 3520289166Speter char cSep = '('; 3521289166Speter while( xRead(&sCtx) ){ 3522305003Scy zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z); 3523289166Speter cSep = ','; 3524289166Speter if( sCtx.cTerm!=sCtx.cColSep ) break; 3525289166Speter } 3526289166Speter if( cSep=='(' ){ 3527289166Speter sqlite3_free(zCreate); 3528289166Speter sqlite3_free(sCtx.z); 3529289166Speter xCloser(sCtx.in); 3530305003Scy utf8_printf(stderr,"%s: empty file\n", sCtx.zFile); 3531289166Speter return 1; 3532289166Speter } 3533289166Speter zCreate = sqlite3_mprintf("%z\n)", zCreate); 3534289166Speter rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); 3535289166Speter sqlite3_free(zCreate); 3536289166Speter if( rc ){ 3537305003Scy utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable, 3538289166Speter sqlite3_errmsg(p->db)); 3539289166Speter sqlite3_free(sCtx.z); 3540289166Speter xCloser(sCtx.in); 3541289166Speter return 1; 3542289166Speter } 3543289166Speter rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); 3544289166Speter } 3545251883Speter sqlite3_free(zSql); 3546251883Speter if( rc ){ 3547251883Speter if (pStmt) sqlite3_finalize(pStmt); 3548305003Scy utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db)); 3549289166Speter xCloser(sCtx.in); 3550251883Speter return 1; 3551251883Speter } 3552251883Speter nCol = sqlite3_column_count(pStmt); 3553251883Speter sqlite3_finalize(pStmt); 3554251883Speter pStmt = 0; 3555251883Speter if( nCol==0 ) return 0; /* no columns, no error */ 3556289166Speter zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 ); 3557251883Speter if( zSql==0 ){ 3558305003Scy raw_printf(stderr, "Error: out of memory\n"); 3559289166Speter xCloser(sCtx.in); 3560251883Speter return 1; 3561251883Speter } 3562289166Speter sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); 3563251883Speter j = strlen30(zSql); 3564251883Speter for(i=1; i<nCol; i++){ 3565251883Speter zSql[j++] = ','; 3566251883Speter zSql[j++] = '?'; 3567251883Speter } 3568251883Speter zSql[j++] = ')'; 3569251883Speter zSql[j] = 0; 3570289166Speter rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); 3571289166Speter sqlite3_free(zSql); 3572251883Speter if( rc ){ 3573305003Scy utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); 3574251883Speter if (pStmt) sqlite3_finalize(pStmt); 3575289166Speter xCloser(sCtx.in); 3576251883Speter return 1; 3577251883Speter } 3578289166Speter needCommit = sqlite3_get_autocommit(p->db); 3579289166Speter if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0); 3580289166Speter do{ 3581289166Speter int startLine = sCtx.nLine; 3582289166Speter for(i=0; i<nCol; i++){ 3583289166Speter char *z = xRead(&sCtx); 3584289166Speter /* 3585289166Speter ** Did we reach end-of-file before finding any columns? 3586289166Speter ** If so, stop instead of NULL filling the remaining columns. 3587289166Speter */ 3588289166Speter if( z==0 && i==0 ) break; 3589289166Speter /* 3590289166Speter ** Did we reach end-of-file OR end-of-line before finding any 3591289166Speter ** columns in ASCII mode? If so, stop instead of NULL filling 3592289166Speter ** the remaining columns. 3593289166Speter */ 3594289166Speter if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break; 3595289166Speter sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT); 3596289166Speter if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){ 3597305003Scy utf8_printf(stderr, "%s:%d: expected %d columns but found %d - " 3598289166Speter "filling the rest with NULL\n", 3599289166Speter sCtx.zFile, startLine, nCol, i+1); 3600289166Speter i += 2; 3601289166Speter while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; } 3602251883Speter } 3603251883Speter } 3604289166Speter if( sCtx.cTerm==sCtx.cColSep ){ 3605289166Speter do{ 3606289166Speter xRead(&sCtx); 3607289166Speter i++; 3608289166Speter }while( sCtx.cTerm==sCtx.cColSep ); 3609305003Scy utf8_printf(stderr, "%s:%d: expected %d columns but found %d - " 3610289166Speter "extras ignored\n", 3611289166Speter sCtx.zFile, startLine, nCol, i); 3612289166Speter } 3613289166Speter if( i>=nCol ){ 3614289166Speter sqlite3_step(pStmt); 3615289166Speter rc = sqlite3_reset(pStmt); 3616289166Speter if( rc!=SQLITE_OK ){ 3617305003Scy utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, 3618305003Scy startLine, sqlite3_errmsg(p->db)); 3619251883Speter } 3620251883Speter } 3621289166Speter }while( sCtx.cTerm!=EOF ); 3622289166Speter 3623289166Speter xCloser(sCtx.in); 3624289166Speter sqlite3_free(sCtx.z); 3625251883Speter sqlite3_finalize(pStmt); 3626289166Speter if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0); 3627251883Speter }else 3628251883Speter 3629289166Speter if( c=='i' && (strncmp(azArg[0], "indices", n)==0 3630289166Speter || strncmp(azArg[0], "indexes", n)==0) ){ 3631289166Speter ShellState data; 3632251883Speter char *zErrMsg = 0; 3633289166Speter open_db(p, 0); 3634251883Speter memcpy(&data, p, sizeof(data)); 3635251883Speter data.showHeader = 0; 3636305003Scy data.cMode = data.mode = MODE_List; 3637251883Speter if( nArg==1 ){ 3638251883Speter rc = sqlite3_exec(p->db, 3639251883Speter "SELECT name FROM sqlite_master " 3640251883Speter "WHERE type='index' AND name NOT LIKE 'sqlite_%' " 3641251883Speter "UNION ALL " 3642251883Speter "SELECT name FROM sqlite_temp_master " 3643251883Speter "WHERE type='index' " 3644251883Speter "ORDER BY 1", 3645251883Speter callback, &data, &zErrMsg 3646251883Speter ); 3647289166Speter }else if( nArg==2 ){ 3648251883Speter zShellStatic = azArg[1]; 3649251883Speter rc = sqlite3_exec(p->db, 3650251883Speter "SELECT name FROM sqlite_master " 3651251883Speter "WHERE type='index' AND tbl_name LIKE shellstatic() " 3652251883Speter "UNION ALL " 3653251883Speter "SELECT name FROM sqlite_temp_master " 3654251883Speter "WHERE type='index' AND tbl_name LIKE shellstatic() " 3655251883Speter "ORDER BY 1", 3656251883Speter callback, &data, &zErrMsg 3657251883Speter ); 3658251883Speter zShellStatic = 0; 3659289166Speter }else{ 3660305003Scy raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); 3661289166Speter rc = 1; 3662289166Speter goto meta_command_exit; 3663251883Speter } 3664251883Speter if( zErrMsg ){ 3665305003Scy utf8_printf(stderr,"Error: %s\n", zErrMsg); 3666251883Speter sqlite3_free(zErrMsg); 3667251883Speter rc = 1; 3668251883Speter }else if( rc != SQLITE_OK ){ 3669305003Scy raw_printf(stderr, 3670305003Scy "Error: querying sqlite_master and sqlite_temp_master\n"); 3671251883Speter rc = 1; 3672251883Speter } 3673251883Speter }else 3674251883Speter 3675251883Speter#ifdef SQLITE_ENABLE_IOTRACE 3676251883Speter if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){ 3677289166Speter SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...); 3678251883Speter if( iotrace && iotrace!=stdout ) fclose(iotrace); 3679251883Speter iotrace = 0; 3680251883Speter if( nArg<2 ){ 3681251883Speter sqlite3IoTrace = 0; 3682251883Speter }else if( strcmp(azArg[1], "-")==0 ){ 3683251883Speter sqlite3IoTrace = iotracePrintf; 3684251883Speter iotrace = stdout; 3685251883Speter }else{ 3686251883Speter iotrace = fopen(azArg[1], "w"); 3687251883Speter if( iotrace==0 ){ 3688305003Scy utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); 3689251883Speter sqlite3IoTrace = 0; 3690251883Speter rc = 1; 3691251883Speter }else{ 3692251883Speter sqlite3IoTrace = iotracePrintf; 3693251883Speter } 3694251883Speter } 3695251883Speter }else 3696251883Speter#endif 3697289166Speter if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){ 3698289166Speter static const struct { 3699289166Speter const char *zLimitName; /* Name of a limit */ 3700289166Speter int limitCode; /* Integer code for that limit */ 3701289166Speter } aLimit[] = { 3702289166Speter { "length", SQLITE_LIMIT_LENGTH }, 3703289166Speter { "sql_length", SQLITE_LIMIT_SQL_LENGTH }, 3704289166Speter { "column", SQLITE_LIMIT_COLUMN }, 3705289166Speter { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH }, 3706289166Speter { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT }, 3707289166Speter { "vdbe_op", SQLITE_LIMIT_VDBE_OP }, 3708289166Speter { "function_arg", SQLITE_LIMIT_FUNCTION_ARG }, 3709289166Speter { "attached", SQLITE_LIMIT_ATTACHED }, 3710289166Speter { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, 3711289166Speter { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER }, 3712289166Speter { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH }, 3713289166Speter { "worker_threads", SQLITE_LIMIT_WORKER_THREADS }, 3714289166Speter }; 3715289166Speter int i, n2; 3716289166Speter open_db(p, 0); 3717289166Speter if( nArg==1 ){ 3718289166Speter for(i=0; i<ArraySize(aLimit); i++){ 3719305003Scy printf("%20s %d\n", aLimit[i].zLimitName, 3720289166Speter sqlite3_limit(p->db, aLimit[i].limitCode, -1)); 3721289166Speter } 3722289166Speter }else if( nArg>3 ){ 3723305003Scy raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n"); 3724289166Speter rc = 1; 3725289166Speter goto meta_command_exit; 3726289166Speter }else{ 3727289166Speter int iLimit = -1; 3728289166Speter n2 = strlen30(azArg[1]); 3729289166Speter for(i=0; i<ArraySize(aLimit); i++){ 3730289166Speter if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){ 3731289166Speter if( iLimit<0 ){ 3732289166Speter iLimit = i; 3733289166Speter }else{ 3734305003Scy utf8_printf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]); 3735289166Speter rc = 1; 3736289166Speter goto meta_command_exit; 3737289166Speter } 3738289166Speter } 3739289166Speter } 3740289166Speter if( iLimit<0 ){ 3741305003Scy utf8_printf(stderr, "unknown limit: \"%s\"\n" 3742289166Speter "enter \".limits\" with no arguments for a list.\n", 3743289166Speter azArg[1]); 3744289166Speter rc = 1; 3745289166Speter goto meta_command_exit; 3746289166Speter } 3747289166Speter if( nArg==3 ){ 3748289166Speter sqlite3_limit(p->db, aLimit[iLimit].limitCode, 3749289166Speter (int)integerValue(azArg[2])); 3750289166Speter } 3751289166Speter printf("%20s %d\n", aLimit[iLimit].zLimitName, 3752289166Speter sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); 3753289166Speter } 3754289166Speter }else 3755251883Speter 3756251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION 3757289166Speter if( c=='l' && strncmp(azArg[0], "load", n)==0 ){ 3758251883Speter const char *zFile, *zProc; 3759251883Speter char *zErrMsg = 0; 3760289166Speter if( nArg<2 ){ 3761305003Scy raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); 3762289166Speter rc = 1; 3763289166Speter goto meta_command_exit; 3764289166Speter } 3765251883Speter zFile = azArg[1]; 3766251883Speter zProc = nArg>=3 ? azArg[2] : 0; 3767289166Speter open_db(p, 0); 3768251883Speter rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); 3769251883Speter if( rc!=SQLITE_OK ){ 3770305003Scy utf8_printf(stderr, "Error: %s\n", zErrMsg); 3771251883Speter sqlite3_free(zErrMsg); 3772251883Speter rc = 1; 3773251883Speter } 3774251883Speter }else 3775251883Speter#endif 3776251883Speter 3777289166Speter if( c=='l' && strncmp(azArg[0], "log", n)==0 ){ 3778289166Speter if( nArg!=2 ){ 3779305003Scy raw_printf(stderr, "Usage: .log FILENAME\n"); 3780289166Speter rc = 1; 3781289166Speter }else{ 3782289166Speter const char *zFile = azArg[1]; 3783289166Speter output_file_close(p->pLog); 3784289166Speter p->pLog = output_file_open(zFile); 3785289166Speter } 3786251883Speter }else 3787251883Speter 3788289166Speter if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){ 3789289166Speter const char *zMode = nArg>=2 ? azArg[1] : ""; 3790289166Speter int n2 = (int)strlen(zMode); 3791289166Speter int c2 = zMode[0]; 3792289166Speter if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){ 3793251883Speter p->mode = MODE_Line; 3794289166Speter }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){ 3795251883Speter p->mode = MODE_Column; 3796289166Speter }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){ 3797251883Speter p->mode = MODE_List; 3798289166Speter }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){ 3799251883Speter p->mode = MODE_Html; 3800289166Speter }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){ 3801251883Speter p->mode = MODE_Tcl; 3802289166Speter sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space); 3803289166Speter }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){ 3804251883Speter p->mode = MODE_Csv; 3805289166Speter sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); 3806289166Speter sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); 3807289166Speter }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){ 3808251883Speter p->mode = MODE_List; 3809289166Speter sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab); 3810289166Speter }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ 3811251883Speter p->mode = MODE_Insert; 3812289166Speter set_table_name(p, nArg>=3 ? azArg[2] : "table"); 3813289166Speter }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){ 3814289166Speter p->mode = MODE_Ascii; 3815289166Speter sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit); 3816289166Speter sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record); 3817251883Speter }else { 3818305003Scy raw_printf(stderr, "Error: mode should be one of: " 3819289166Speter "ascii column csv html insert line list tabs tcl\n"); 3820251883Speter rc = 1; 3821251883Speter } 3822305003Scy p->cMode = p->mode; 3823251883Speter }else 3824251883Speter 3825289166Speter if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){ 3826289166Speter if( nArg==2 ){ 3827289166Speter sqlite3_snprintf(sizeof(p->nullValue), p->nullValue, 3828289166Speter "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]); 3829289166Speter }else{ 3830305003Scy raw_printf(stderr, "Usage: .nullvalue STRING\n"); 3831251883Speter rc = 1; 3832251883Speter } 3833251883Speter }else 3834251883Speter 3835289166Speter if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){ 3836289166Speter sqlite3 *savedDb = p->db; 3837289166Speter const char *zSavedFilename = p->zDbFilename; 3838289166Speter char *zNewFilename = 0; 3839289166Speter p->db = 0; 3840289166Speter if( nArg>=2 ) zNewFilename = sqlite3_mprintf("%s", azArg[1]); 3841289166Speter p->zDbFilename = zNewFilename; 3842289166Speter open_db(p, 1); 3843289166Speter if( p->db!=0 ){ 3844305003Scy session_close_all(p); 3845289166Speter sqlite3_close(savedDb); 3846289166Speter sqlite3_free(p->zFreeOnClose); 3847289166Speter p->zFreeOnClose = zNewFilename; 3848289166Speter }else{ 3849289166Speter sqlite3_free(zNewFilename); 3850289166Speter p->db = savedDb; 3851289166Speter p->zDbFilename = zSavedFilename; 3852289166Speter } 3853251883Speter }else 3854251883Speter 3855289166Speter if( c=='o' 3856289166Speter && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0) 3857289166Speter ){ 3858289166Speter const char *zFile = nArg>=2 ? azArg[1] : "stdout"; 3859289166Speter if( nArg>2 ){ 3860305003Scy utf8_printf(stderr, "Usage: .%s FILE\n", azArg[0]); 3861289166Speter rc = 1; 3862289166Speter goto meta_command_exit; 3863289166Speter } 3864289166Speter if( n>1 && strncmp(azArg[0], "once", n)==0 ){ 3865289166Speter if( nArg<2 ){ 3866305003Scy raw_printf(stderr, "Usage: .once FILE\n"); 3867289166Speter rc = 1; 3868289166Speter goto meta_command_exit; 3869289166Speter } 3870289166Speter p->outCount = 2; 3871251883Speter }else{ 3872289166Speter p->outCount = 0; 3873251883Speter } 3874289166Speter output_reset(p); 3875289166Speter if( zFile[0]=='|' ){ 3876289166Speter#ifdef SQLITE_OMIT_POPEN 3877305003Scy raw_printf(stderr, "Error: pipes are not supported in this OS\n"); 3878289166Speter rc = 1; 3879289166Speter p->out = stdout; 3880289166Speter#else 3881289166Speter p->out = popen(zFile + 1, "w"); 3882251883Speter if( p->out==0 ){ 3883305003Scy utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); 3884251883Speter p->out = stdout; 3885251883Speter rc = 1; 3886251883Speter }else{ 3887289166Speter sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); 3888251883Speter } 3889289166Speter#endif 3890251883Speter }else{ 3891289166Speter p->out = output_file_open(zFile); 3892251883Speter if( p->out==0 ){ 3893289166Speter if( strcmp(zFile,"off")!=0 ){ 3894305003Scy utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile); 3895251883Speter } 3896251883Speter p->out = stdout; 3897251883Speter rc = 1; 3898251883Speter } else { 3899289166Speter sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); 3900251883Speter } 3901251883Speter } 3902251883Speter }else 3903251883Speter 3904251883Speter if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){ 3905251883Speter int i; 3906251883Speter for(i=1; i<nArg; i++){ 3907305003Scy if( i>1 ) raw_printf(p->out, " "); 3908305003Scy utf8_printf(p->out, "%s", azArg[i]); 3909251883Speter } 3910305003Scy raw_printf(p->out, "\n"); 3911251883Speter }else 3912251883Speter 3913289166Speter if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){ 3914251883Speter if( nArg >= 2) { 3915251883Speter strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); 3916251883Speter } 3917251883Speter if( nArg >= 3) { 3918251883Speter strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1); 3919251883Speter } 3920251883Speter }else 3921251883Speter 3922289166Speter if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){ 3923251883Speter rc = 2; 3924251883Speter }else 3925251883Speter 3926289166Speter if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){ 3927289166Speter FILE *alt; 3928289166Speter if( nArg!=2 ){ 3929305003Scy raw_printf(stderr, "Usage: .read FILE\n"); 3930289166Speter rc = 1; 3931289166Speter goto meta_command_exit; 3932289166Speter } 3933289166Speter alt = fopen(azArg[1], "rb"); 3934251883Speter if( alt==0 ){ 3935305003Scy utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); 3936251883Speter rc = 1; 3937251883Speter }else{ 3938251883Speter rc = process_input(p, alt); 3939251883Speter fclose(alt); 3940251883Speter } 3941251883Speter }else 3942251883Speter 3943289166Speter if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){ 3944251883Speter const char *zSrcFile; 3945251883Speter const char *zDb; 3946251883Speter sqlite3 *pSrc; 3947251883Speter sqlite3_backup *pBackup; 3948251883Speter int nTimeout = 0; 3949251883Speter 3950251883Speter if( nArg==2 ){ 3951251883Speter zSrcFile = azArg[1]; 3952251883Speter zDb = "main"; 3953289166Speter }else if( nArg==3 ){ 3954251883Speter zSrcFile = azArg[2]; 3955251883Speter zDb = azArg[1]; 3956289166Speter }else{ 3957305003Scy raw_printf(stderr, "Usage: .restore ?DB? FILE\n"); 3958289166Speter rc = 1; 3959289166Speter goto meta_command_exit; 3960251883Speter } 3961251883Speter rc = sqlite3_open(zSrcFile, &pSrc); 3962251883Speter if( rc!=SQLITE_OK ){ 3963305003Scy utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); 3964251883Speter sqlite3_close(pSrc); 3965251883Speter return 1; 3966251883Speter } 3967289166Speter open_db(p, 0); 3968251883Speter pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); 3969251883Speter if( pBackup==0 ){ 3970305003Scy utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); 3971251883Speter sqlite3_close(pSrc); 3972251883Speter return 1; 3973251883Speter } 3974251883Speter while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK 3975251883Speter || rc==SQLITE_BUSY ){ 3976251883Speter if( rc==SQLITE_BUSY ){ 3977251883Speter if( nTimeout++ >= 3 ) break; 3978251883Speter sqlite3_sleep(100); 3979251883Speter } 3980251883Speter } 3981251883Speter sqlite3_backup_finish(pBackup); 3982251883Speter if( rc==SQLITE_DONE ){ 3983251883Speter rc = 0; 3984251883Speter }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ 3985305003Scy raw_printf(stderr, "Error: source database is busy\n"); 3986251883Speter rc = 1; 3987251883Speter }else{ 3988305003Scy utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); 3989251883Speter rc = 1; 3990251883Speter } 3991251883Speter sqlite3_close(pSrc); 3992251883Speter }else 3993251883Speter 3994289166Speter 3995289166Speter if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ 3996289166Speter if( nArg==2 ){ 3997289166Speter p->scanstatsOn = booleanValue(azArg[1]); 3998289166Speter#ifndef SQLITE_ENABLE_STMT_SCANSTATUS 3999305003Scy raw_printf(stderr, "Warning: .scanstats not available in this build.\n"); 4000289166Speter#endif 4001289166Speter }else{ 4002305003Scy raw_printf(stderr, "Usage: .scanstats on|off\n"); 4003289166Speter rc = 1; 4004289166Speter } 4005289166Speter }else 4006289166Speter 4007289166Speter if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ 4008289166Speter ShellState data; 4009251883Speter char *zErrMsg = 0; 4010289166Speter open_db(p, 0); 4011251883Speter memcpy(&data, p, sizeof(data)); 4012251883Speter data.showHeader = 0; 4013305003Scy data.cMode = data.mode = MODE_Semi; 4014305003Scy if( nArg>=2 && optionMatch(azArg[1], "indent") ){ 4015305003Scy data.cMode = data.mode = MODE_Pretty; 4016305003Scy nArg--; 4017305003Scy if( nArg==2 ) azArg[1] = azArg[2]; 4018305003Scy } 4019305003Scy if( nArg==2 && azArg[1][0]!='-' ){ 4020251883Speter int i; 4021251883Speter for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]); 4022251883Speter if( strcmp(azArg[1],"sqlite_master")==0 ){ 4023251883Speter char *new_argv[2], *new_colv[2]; 4024251883Speter new_argv[0] = "CREATE TABLE sqlite_master (\n" 4025251883Speter " type text,\n" 4026251883Speter " name text,\n" 4027251883Speter " tbl_name text,\n" 4028251883Speter " rootpage integer,\n" 4029251883Speter " sql text\n" 4030251883Speter ")"; 4031251883Speter new_argv[1] = 0; 4032251883Speter new_colv[0] = "sql"; 4033251883Speter new_colv[1] = 0; 4034251883Speter callback(&data, 1, new_argv, new_colv); 4035251883Speter rc = SQLITE_OK; 4036251883Speter }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){ 4037251883Speter char *new_argv[2], *new_colv[2]; 4038251883Speter new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n" 4039251883Speter " type text,\n" 4040251883Speter " name text,\n" 4041251883Speter " tbl_name text,\n" 4042251883Speter " rootpage integer,\n" 4043251883Speter " sql text\n" 4044251883Speter ")"; 4045251883Speter new_argv[1] = 0; 4046251883Speter new_colv[0] = "sql"; 4047251883Speter new_colv[1] = 0; 4048251883Speter callback(&data, 1, new_argv, new_colv); 4049251883Speter rc = SQLITE_OK; 4050251883Speter }else{ 4051251883Speter zShellStatic = azArg[1]; 4052251883Speter rc = sqlite3_exec(p->db, 4053251883Speter "SELECT sql FROM " 4054251883Speter " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" 4055251883Speter " FROM sqlite_master UNION ALL" 4056251883Speter " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " 4057251883Speter "WHERE lower(tbl_name) LIKE shellstatic()" 4058251883Speter " AND type!='meta' AND sql NOTNULL " 4059251883Speter "ORDER BY rowid", 4060251883Speter callback, &data, &zErrMsg); 4061251883Speter zShellStatic = 0; 4062251883Speter } 4063289166Speter }else if( nArg==1 ){ 4064251883Speter rc = sqlite3_exec(p->db, 4065251883Speter "SELECT sql FROM " 4066251883Speter " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" 4067251883Speter " FROM sqlite_master UNION ALL" 4068251883Speter " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " 4069289166Speter "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " 4070251883Speter "ORDER BY rowid", 4071251883Speter callback, &data, &zErrMsg 4072251883Speter ); 4073289166Speter }else{ 4074305003Scy raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n"); 4075289166Speter rc = 1; 4076289166Speter goto meta_command_exit; 4077251883Speter } 4078251883Speter if( zErrMsg ){ 4079305003Scy utf8_printf(stderr,"Error: %s\n", zErrMsg); 4080251883Speter sqlite3_free(zErrMsg); 4081251883Speter rc = 1; 4082251883Speter }else if( rc != SQLITE_OK ){ 4083305003Scy raw_printf(stderr,"Error: querying schema information\n"); 4084251883Speter rc = 1; 4085251883Speter }else{ 4086251883Speter rc = 0; 4087251883Speter } 4088251883Speter }else 4089251883Speter 4090289166Speter#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) 4091289166Speter if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){ 4092289166Speter sqlite3SelectTrace = integerValue(azArg[1]); 4093251883Speter }else 4094289166Speter#endif 4095251883Speter 4096305003Scy#if defined(SQLITE_ENABLE_SESSION) 4097305003Scy if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){ 4098305003Scy OpenSession *pSession = &p->aSession[0]; 4099305003Scy char **azCmd = &azArg[1]; 4100305003Scy int iSes = 0; 4101305003Scy int nCmd = nArg - 1; 4102305003Scy int i; 4103305003Scy if( nArg<=1 ) goto session_syntax_error; 4104305003Scy open_db(p, 0); 4105305003Scy if( nArg>=3 ){ 4106305003Scy for(iSes=0; iSes<p->nSession; iSes++){ 4107305003Scy if( strcmp(p->aSession[iSes].zName, azArg[1])==0 ) break; 4108305003Scy } 4109305003Scy if( iSes<p->nSession ){ 4110305003Scy pSession = &p->aSession[iSes]; 4111305003Scy azCmd++; 4112305003Scy nCmd--; 4113305003Scy }else{ 4114305003Scy pSession = &p->aSession[0]; 4115305003Scy iSes = 0; 4116305003Scy } 4117305003Scy } 4118289166Speter 4119305003Scy /* .session attach TABLE 4120305003Scy ** Invoke the sqlite3session_attach() interface to attach a particular 4121305003Scy ** table so that it is never filtered. 4122305003Scy */ 4123305003Scy if( strcmp(azCmd[0],"attach")==0 ){ 4124305003Scy if( nCmd!=2 ) goto session_syntax_error; 4125305003Scy if( pSession->p==0 ){ 4126305003Scy session_not_open: 4127305003Scy raw_printf(stderr, "ERROR: No sessions are open\n"); 4128305003Scy }else{ 4129305003Scy rc = sqlite3session_attach(pSession->p, azCmd[1]); 4130305003Scy if( rc ){ 4131305003Scy raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc); 4132305003Scy rc = 0; 4133305003Scy } 4134305003Scy } 4135305003Scy }else 4136305003Scy 4137305003Scy /* .session changeset FILE 4138305003Scy ** .session patchset FILE 4139305003Scy ** Write a changeset or patchset into a file. The file is overwritten. 4140305003Scy */ 4141305003Scy if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){ 4142305003Scy FILE *out = 0; 4143305003Scy if( nCmd!=2 ) goto session_syntax_error; 4144305003Scy if( pSession->p==0 ) goto session_not_open; 4145305003Scy out = fopen(azCmd[1], "wb"); 4146305003Scy if( out==0 ){ 4147305003Scy utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]); 4148305003Scy }else{ 4149305003Scy int szChng; 4150305003Scy void *pChng; 4151305003Scy if( azCmd[0][0]=='c' ){ 4152305003Scy rc = sqlite3session_changeset(pSession->p, &szChng, &pChng); 4153305003Scy }else{ 4154305003Scy rc = sqlite3session_patchset(pSession->p, &szChng, &pChng); 4155305003Scy } 4156305003Scy if( rc ){ 4157305003Scy printf("Error: error code %d\n", rc); 4158305003Scy rc = 0; 4159305003Scy } 4160305003Scy if( pChng 4161305003Scy && fwrite(pChng, szChng, 1, out)!=1 ){ 4162305003Scy raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n", 4163305003Scy szChng); 4164305003Scy } 4165305003Scy sqlite3_free(pChng); 4166305003Scy fclose(out); 4167305003Scy } 4168305003Scy }else 4169305003Scy 4170305003Scy /* .session close 4171305003Scy ** Close the identified session 4172305003Scy */ 4173305003Scy if( strcmp(azCmd[0], "close")==0 ){ 4174305003Scy if( nCmd!=1 ) goto session_syntax_error; 4175305003Scy if( p->nSession ){ 4176305003Scy session_close(pSession); 4177305003Scy p->aSession[iSes] = p->aSession[--p->nSession]; 4178305003Scy } 4179305003Scy }else 4180305003Scy 4181305003Scy /* .session enable ?BOOLEAN? 4182305003Scy ** Query or set the enable flag 4183305003Scy */ 4184305003Scy if( strcmp(azCmd[0], "enable")==0 ){ 4185305003Scy int ii; 4186305003Scy if( nCmd>2 ) goto session_syntax_error; 4187305003Scy ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); 4188305003Scy if( p->nSession ){ 4189305003Scy ii = sqlite3session_enable(pSession->p, ii); 4190305003Scy utf8_printf(p->out, "session %s enable flag = %d\n", 4191305003Scy pSession->zName, ii); 4192305003Scy } 4193305003Scy }else 4194305003Scy 4195305003Scy /* .session filter GLOB .... 4196305003Scy ** Set a list of GLOB patterns of table names to be excluded. 4197305003Scy */ 4198305003Scy if( strcmp(azCmd[0], "filter")==0 ){ 4199305003Scy int ii, nByte; 4200305003Scy if( nCmd<2 ) goto session_syntax_error; 4201305003Scy if( p->nSession ){ 4202305003Scy for(ii=0; ii<pSession->nFilter; ii++){ 4203305003Scy sqlite3_free(pSession->azFilter[ii]); 4204305003Scy } 4205305003Scy sqlite3_free(pSession->azFilter); 4206305003Scy nByte = sizeof(pSession->azFilter[0])*(nCmd-1); 4207305003Scy pSession->azFilter = sqlite3_malloc( nByte ); 4208305003Scy if( pSession->azFilter==0 ){ 4209305003Scy raw_printf(stderr, "Error: out or memory\n"); 4210305003Scy exit(1); 4211305003Scy } 4212305003Scy for(ii=1; ii<nCmd; ii++){ 4213305003Scy pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]); 4214305003Scy } 4215305003Scy pSession->nFilter = ii-1; 4216305003Scy } 4217305003Scy }else 4218305003Scy 4219305003Scy /* .session indirect ?BOOLEAN? 4220305003Scy ** Query or set the indirect flag 4221305003Scy */ 4222305003Scy if( strcmp(azCmd[0], "indirect")==0 ){ 4223305003Scy int ii; 4224305003Scy if( nCmd>2 ) goto session_syntax_error; 4225305003Scy ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); 4226305003Scy if( p->nSession ){ 4227305003Scy ii = sqlite3session_indirect(pSession->p, ii); 4228305003Scy utf8_printf(p->out, "session %s indirect flag = %d\n", 4229305003Scy pSession->zName, ii); 4230305003Scy } 4231305003Scy }else 4232305003Scy 4233305003Scy /* .session isempty 4234305003Scy ** Determine if the session is empty 4235305003Scy */ 4236305003Scy if( strcmp(azCmd[0], "isempty")==0 ){ 4237305003Scy int ii; 4238305003Scy if( nCmd!=1 ) goto session_syntax_error; 4239305003Scy if( p->nSession ){ 4240305003Scy ii = sqlite3session_isempty(pSession->p); 4241305003Scy utf8_printf(p->out, "session %s isempty flag = %d\n", 4242305003Scy pSession->zName, ii); 4243305003Scy } 4244305003Scy }else 4245305003Scy 4246305003Scy /* .session list 4247305003Scy ** List all currently open sessions 4248305003Scy */ 4249305003Scy if( strcmp(azCmd[0],"list")==0 ){ 4250305003Scy for(i=0; i<p->nSession; i++){ 4251305003Scy utf8_printf(p->out, "%d %s\n", i, p->aSession[i].zName); 4252305003Scy } 4253305003Scy }else 4254305003Scy 4255305003Scy /* .session open DB NAME 4256305003Scy ** Open a new session called NAME on the attached database DB. 4257305003Scy ** DB is normally "main". 4258305003Scy */ 4259305003Scy if( strcmp(azCmd[0],"open")==0 ){ 4260305003Scy char *zName; 4261305003Scy if( nCmd!=3 ) goto session_syntax_error; 4262305003Scy zName = azCmd[2]; 4263305003Scy if( zName[0]==0 ) goto session_syntax_error; 4264305003Scy for(i=0; i<p->nSession; i++){ 4265305003Scy if( strcmp(p->aSession[i].zName,zName)==0 ){ 4266305003Scy utf8_printf(stderr, "Session \"%s\" already exists\n", zName); 4267305003Scy goto meta_command_exit; 4268305003Scy } 4269305003Scy } 4270305003Scy if( p->nSession>=ArraySize(p->aSession) ){ 4271305003Scy raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(p->aSession)); 4272305003Scy goto meta_command_exit; 4273305003Scy } 4274305003Scy pSession = &p->aSession[p->nSession]; 4275305003Scy rc = sqlite3session_create(p->db, azCmd[1], &pSession->p); 4276305003Scy if( rc ){ 4277305003Scy raw_printf(stderr, "Cannot open session: error code=%d\n", rc); 4278305003Scy rc = 0; 4279305003Scy goto meta_command_exit; 4280305003Scy } 4281305003Scy pSession->nFilter = 0; 4282305003Scy sqlite3session_table_filter(pSession->p, session_filter, pSession); 4283305003Scy p->nSession++; 4284305003Scy pSession->zName = sqlite3_mprintf("%s", zName); 4285305003Scy }else 4286305003Scy /* If no command name matches, show a syntax error */ 4287305003Scy session_syntax_error: 4288305003Scy session_help(p); 4289305003Scy }else 4290305003Scy#endif 4291305003Scy 4292289166Speter#ifdef SQLITE_DEBUG 4293289166Speter /* Undocumented commands for internal testing. Subject to change 4294289166Speter ** without notice. */ 4295289166Speter if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ 4296289166Speter if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){ 4297289166Speter int i, v; 4298289166Speter for(i=1; i<nArg; i++){ 4299289166Speter v = booleanValue(azArg[i]); 4300305003Scy utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v); 4301289166Speter } 4302289166Speter } 4303289166Speter if( strncmp(azArg[0]+9, "integer", n-9)==0 ){ 4304289166Speter int i; sqlite3_int64 v; 4305289166Speter for(i=1; i<nArg; i++){ 4306289166Speter char zBuf[200]; 4307289166Speter v = integerValue(azArg[i]); 4308289166Speter sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v); 4309305003Scy utf8_printf(p->out, "%s", zBuf); 4310289166Speter } 4311289166Speter } 4312289166Speter }else 4313289166Speter#endif 4314289166Speter 4315289166Speter if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){ 4316289166Speter if( nArg<2 || nArg>3 ){ 4317305003Scy raw_printf(stderr, "Usage: .separator COL ?ROW?\n"); 4318289166Speter rc = 1; 4319289166Speter } 4320289166Speter if( nArg>=2 ){ 4321289166Speter sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, 4322289166Speter "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]); 4323289166Speter } 4324289166Speter if( nArg>=3 ){ 4325289166Speter sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, 4326289166Speter "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]); 4327289166Speter } 4328289166Speter }else 4329289166Speter 4330289166Speter if( c=='s' 4331289166Speter && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0) 4332289166Speter ){ 4333289166Speter char *zCmd; 4334289166Speter int i, x; 4335289166Speter if( nArg<2 ){ 4336305003Scy raw_printf(stderr, "Usage: .system COMMAND\n"); 4337289166Speter rc = 1; 4338289166Speter goto meta_command_exit; 4339289166Speter } 4340289166Speter zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); 4341289166Speter for(i=2; i<nArg; i++){ 4342289166Speter zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"", 4343289166Speter zCmd, azArg[i]); 4344289166Speter } 4345289166Speter x = system(zCmd); 4346289166Speter sqlite3_free(zCmd); 4347305003Scy if( x ) raw_printf(stderr, "System command returns %d\n", x); 4348289166Speter }else 4349289166Speter 4350289166Speter if( c=='s' && strncmp(azArg[0], "show", n)==0 ){ 4351305003Scy static const char *azBool[] = { "off", "on", "full", "unk" }; 4352251883Speter int i; 4353289166Speter if( nArg!=1 ){ 4354305003Scy raw_printf(stderr, "Usage: .show\n"); 4355289166Speter rc = 1; 4356289166Speter goto meta_command_exit; 4357289166Speter } 4358305003Scy utf8_printf(p->out, "%12.12s: %s\n","echo", azBool[p->echoOn!=0]); 4359305003Scy utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]); 4360305003Scy utf8_printf(p->out, "%12.12s: %s\n","explain", 4361305003Scy p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off"); 4362305003Scy utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]); 4363305003Scy utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]); 4364305003Scy utf8_printf(p->out, "%12.12s: ", "nullvalue"); 4365289166Speter output_c_string(p->out, p->nullValue); 4366305003Scy raw_printf(p->out, "\n"); 4367305003Scy utf8_printf(p->out,"%12.12s: %s\n","output", 4368251883Speter strlen30(p->outfile) ? p->outfile : "stdout"); 4369305003Scy utf8_printf(p->out,"%12.12s: ", "colseparator"); 4370289166Speter output_c_string(p->out, p->colSeparator); 4371305003Scy raw_printf(p->out, "\n"); 4372305003Scy utf8_printf(p->out,"%12.12s: ", "rowseparator"); 4373289166Speter output_c_string(p->out, p->rowSeparator); 4374305003Scy raw_printf(p->out, "\n"); 4375305003Scy utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]); 4376305003Scy utf8_printf(p->out, "%12.12s: ", "width"); 4377251883Speter for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { 4378305003Scy raw_printf(p->out, "%d ", p->colWidth[i]); 4379251883Speter } 4380305003Scy raw_printf(p->out, "\n"); 4381251883Speter }else 4382251883Speter 4383289166Speter if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){ 4384289166Speter if( nArg==2 ){ 4385289166Speter p->statsOn = booleanValue(azArg[1]); 4386305003Scy }else if( nArg==1 ){ 4387305003Scy display_stats(p->db, p, 0); 4388289166Speter }else{ 4389305003Scy raw_printf(stderr, "Usage: .stats ?on|off?\n"); 4390289166Speter rc = 1; 4391289166Speter } 4392251883Speter }else 4393251883Speter 4394289166Speter if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){ 4395251883Speter sqlite3_stmt *pStmt; 4396251883Speter char **azResult; 4397251883Speter int nRow, nAlloc; 4398251883Speter char *zSql = 0; 4399251883Speter int ii; 4400289166Speter open_db(p, 0); 4401251883Speter rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); 4402305003Scy if( rc ) return shellDatabaseError(p->db); 4403305003Scy 4404305003Scy /* Create an SQL statement to query for the list of tables in the 4405305003Scy ** main and all attached databases where the table name matches the 4406305003Scy ** LIKE pattern bound to variable "?1". */ 4407251883Speter zSql = sqlite3_mprintf( 4408251883Speter "SELECT name FROM sqlite_master" 4409251883Speter " WHERE type IN ('table','view')" 4410251883Speter " AND name NOT LIKE 'sqlite_%%'" 4411251883Speter " AND name LIKE ?1"); 4412305003Scy while( zSql && sqlite3_step(pStmt)==SQLITE_ROW ){ 4413251883Speter const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); 4414251883Speter if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue; 4415251883Speter if( strcmp(zDbName,"temp")==0 ){ 4416251883Speter zSql = sqlite3_mprintf( 4417251883Speter "%z UNION ALL " 4418251883Speter "SELECT 'temp.' || name FROM sqlite_temp_master" 4419251883Speter " WHERE type IN ('table','view')" 4420251883Speter " AND name NOT LIKE 'sqlite_%%'" 4421251883Speter " AND name LIKE ?1", zSql); 4422251883Speter }else{ 4423251883Speter zSql = sqlite3_mprintf( 4424251883Speter "%z UNION ALL " 4425251883Speter "SELECT '%q.' || name FROM \"%w\".sqlite_master" 4426251883Speter " WHERE type IN ('table','view')" 4427251883Speter " AND name NOT LIKE 'sqlite_%%'" 4428251883Speter " AND name LIKE ?1", zSql, zDbName, zDbName); 4429251883Speter } 4430251883Speter } 4431305003Scy rc = sqlite3_finalize(pStmt); 4432305003Scy if( zSql && rc==SQLITE_OK ){ 4433305003Scy zSql = sqlite3_mprintf("%z ORDER BY 1", zSql); 4434305003Scy if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); 4435305003Scy } 4436251883Speter sqlite3_free(zSql); 4437305003Scy if( !zSql ) return shellNomemError(); 4438305003Scy if( rc ) return shellDatabaseError(p->db); 4439305003Scy 4440305003Scy /* Run the SQL statement prepared by the above block. Store the results 4441305003Scy ** as an array of nul-terminated strings in azResult[]. */ 4442251883Speter nRow = nAlloc = 0; 4443251883Speter azResult = 0; 4444251883Speter if( nArg>1 ){ 4445251883Speter sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT); 4446251883Speter }else{ 4447251883Speter sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC); 4448251883Speter } 4449251883Speter while( sqlite3_step(pStmt)==SQLITE_ROW ){ 4450251883Speter if( nRow>=nAlloc ){ 4451251883Speter char **azNew; 4452289166Speter int n2 = nAlloc*2 + 10; 4453289166Speter azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2); 4454251883Speter if( azNew==0 ){ 4455305003Scy rc = shellNomemError(); 4456251883Speter break; 4457251883Speter } 4458289166Speter nAlloc = n2; 4459251883Speter azResult = azNew; 4460251883Speter } 4461251883Speter azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); 4462305003Scy if( 0==azResult[nRow] ){ 4463305003Scy rc = shellNomemError(); 4464305003Scy break; 4465305003Scy } 4466305003Scy nRow++; 4467251883Speter } 4468305003Scy if( sqlite3_finalize(pStmt)!=SQLITE_OK ){ 4469305003Scy rc = shellDatabaseError(p->db); 4470305003Scy } 4471305003Scy 4472305003Scy /* Pretty-print the contents of array azResult[] to the output */ 4473305003Scy if( rc==0 && nRow>0 ){ 4474251883Speter int len, maxlen = 0; 4475251883Speter int i, j; 4476251883Speter int nPrintCol, nPrintRow; 4477251883Speter for(i=0; i<nRow; i++){ 4478251883Speter len = strlen30(azResult[i]); 4479251883Speter if( len>maxlen ) maxlen = len; 4480251883Speter } 4481251883Speter nPrintCol = 80/(maxlen+2); 4482251883Speter if( nPrintCol<1 ) nPrintCol = 1; 4483251883Speter nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; 4484251883Speter for(i=0; i<nPrintRow; i++){ 4485251883Speter for(j=i; j<nRow; j+=nPrintRow){ 4486251883Speter char *zSp = j<nPrintRow ? "" : " "; 4487305003Scy utf8_printf(p->out, "%s%-*s", zSp, maxlen, 4488305003Scy azResult[j] ? azResult[j]:""); 4489251883Speter } 4490305003Scy raw_printf(p->out, "\n"); 4491251883Speter } 4492251883Speter } 4493305003Scy 4494251883Speter for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]); 4495251883Speter sqlite3_free(azResult); 4496251883Speter }else 4497251883Speter 4498251883Speter if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){ 4499251883Speter static const struct { 4500251883Speter const char *zCtrlName; /* Name of a test-control option */ 4501251883Speter int ctrlCode; /* Integer code for that option */ 4502251883Speter } aCtrl[] = { 4503251883Speter { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE }, 4504251883Speter { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE }, 4505251883Speter { "prng_reset", SQLITE_TESTCTRL_PRNG_RESET }, 4506251883Speter { "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST }, 4507251883Speter { "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL }, 4508251883Speter { "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS }, 4509251883Speter { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE }, 4510251883Speter { "assert", SQLITE_TESTCTRL_ASSERT }, 4511251883Speter { "always", SQLITE_TESTCTRL_ALWAYS }, 4512251883Speter { "reserve", SQLITE_TESTCTRL_RESERVE }, 4513251883Speter { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS }, 4514251883Speter { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD }, 4515251883Speter { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC }, 4516289166Speter { "byteorder", SQLITE_TESTCTRL_BYTEORDER }, 4517289166Speter { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT }, 4518289166Speter { "imposter", SQLITE_TESTCTRL_IMPOSTER }, 4519251883Speter }; 4520251883Speter int testctrl = -1; 4521289166Speter int rc2 = 0; 4522289166Speter int i, n2; 4523289166Speter open_db(p, 0); 4524251883Speter 4525251883Speter /* convert testctrl text option to value. allow any unique prefix 4526251883Speter ** of the option name, or a numerical value. */ 4527289166Speter n2 = strlen30(azArg[1]); 4528289166Speter for(i=0; i<ArraySize(aCtrl); i++){ 4529289166Speter if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){ 4530251883Speter if( testctrl<0 ){ 4531251883Speter testctrl = aCtrl[i].ctrlCode; 4532251883Speter }else{ 4533305003Scy utf8_printf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]); 4534251883Speter testctrl = -1; 4535251883Speter break; 4536251883Speter } 4537251883Speter } 4538251883Speter } 4539289166Speter if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]); 4540251883Speter if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){ 4541305003Scy utf8_printf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]); 4542251883Speter }else{ 4543251883Speter switch(testctrl){ 4544251883Speter 4545251883Speter /* sqlite3_test_control(int, db, int) */ 4546251883Speter case SQLITE_TESTCTRL_OPTIMIZATIONS: 4547305003Scy case SQLITE_TESTCTRL_RESERVE: 4548251883Speter if( nArg==3 ){ 4549305003Scy int opt = (int)strtol(azArg[2], 0, 0); 4550289166Speter rc2 = sqlite3_test_control(testctrl, p->db, opt); 4551305003Scy raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2); 4552251883Speter } else { 4553305003Scy utf8_printf(stderr,"Error: testctrl %s takes a single int option\n", 4554251883Speter azArg[1]); 4555251883Speter } 4556251883Speter break; 4557251883Speter 4558251883Speter /* sqlite3_test_control(int) */ 4559289166Speter case SQLITE_TESTCTRL_PRNG_SAVE: 4560289166Speter case SQLITE_TESTCTRL_PRNG_RESTORE: 4561251883Speter case SQLITE_TESTCTRL_PRNG_RESET: 4562289166Speter case SQLITE_TESTCTRL_BYTEORDER: 4563251883Speter if( nArg==2 ){ 4564289166Speter rc2 = sqlite3_test_control(testctrl); 4565305003Scy raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2); 4566251883Speter } else { 4567305003Scy utf8_printf(stderr,"Error: testctrl %s takes no options\n", 4568305003Scy azArg[1]); 4569251883Speter } 4570251883Speter break; 4571251883Speter 4572251883Speter /* sqlite3_test_control(int, uint) */ 4573305003Scy case SQLITE_TESTCTRL_PENDING_BYTE: 4574251883Speter if( nArg==3 ){ 4575289166Speter unsigned int opt = (unsigned int)integerValue(azArg[2]); 4576289166Speter rc2 = sqlite3_test_control(testctrl, opt); 4577305003Scy raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2); 4578251883Speter } else { 4579305003Scy utf8_printf(stderr,"Error: testctrl %s takes a single unsigned" 4580251883Speter " int option\n", azArg[1]); 4581251883Speter } 4582251883Speter break; 4583305003Scy 4584251883Speter /* sqlite3_test_control(int, int) */ 4585305003Scy case SQLITE_TESTCTRL_ASSERT: 4586305003Scy case SQLITE_TESTCTRL_ALWAYS: 4587305003Scy case SQLITE_TESTCTRL_NEVER_CORRUPT: 4588251883Speter if( nArg==3 ){ 4589305003Scy int opt = booleanValue(azArg[2]); 4590289166Speter rc2 = sqlite3_test_control(testctrl, opt); 4591305003Scy raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2); 4592251883Speter } else { 4593305003Scy utf8_printf(stderr,"Error: testctrl %s takes a single int option\n", 4594251883Speter azArg[1]); 4595251883Speter } 4596251883Speter break; 4597251883Speter 4598251883Speter /* sqlite3_test_control(int, char *) */ 4599251883Speter#ifdef SQLITE_N_KEYWORD 4600305003Scy case SQLITE_TESTCTRL_ISKEYWORD: 4601251883Speter if( nArg==3 ){ 4602305003Scy const char *opt = azArg[2]; 4603289166Speter rc2 = sqlite3_test_control(testctrl, opt); 4604305003Scy raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2); 4605251883Speter } else { 4606305003Scy utf8_printf(stderr, 4607305003Scy "Error: testctrl %s takes a single char * option\n", 4608305003Scy azArg[1]); 4609251883Speter } 4610251883Speter break; 4611251883Speter#endif 4612251883Speter 4613289166Speter case SQLITE_TESTCTRL_IMPOSTER: 4614289166Speter if( nArg==5 ){ 4615305003Scy rc2 = sqlite3_test_control(testctrl, p->db, 4616289166Speter azArg[2], 4617289166Speter integerValue(azArg[3]), 4618289166Speter integerValue(azArg[4])); 4619305003Scy raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2); 4620289166Speter }else{ 4621305003Scy raw_printf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n"); 4622289166Speter } 4623289166Speter break; 4624289166Speter 4625305003Scy case SQLITE_TESTCTRL_BITVEC_TEST: 4626305003Scy case SQLITE_TESTCTRL_FAULT_INSTALL: 4627305003Scy case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: 4628305003Scy case SQLITE_TESTCTRL_SCRATCHMALLOC: 4629251883Speter default: 4630305003Scy utf8_printf(stderr, 4631305003Scy "Error: CLI support for testctrl %s not implemented\n", 4632305003Scy azArg[1]); 4633251883Speter break; 4634251883Speter } 4635251883Speter } 4636251883Speter }else 4637251883Speter 4638289166Speter if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){ 4639289166Speter open_db(p, 0); 4640289166Speter sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0); 4641251883Speter }else 4642305003Scy 4643289166Speter if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){ 4644289166Speter if( nArg==2 ){ 4645289166Speter enableTimer = booleanValue(azArg[1]); 4646289166Speter if( enableTimer && !HAS_TIMER ){ 4647305003Scy raw_printf(stderr, "Error: timer not available on this system.\n"); 4648289166Speter enableTimer = 0; 4649289166Speter } 4650289166Speter }else{ 4651305003Scy raw_printf(stderr, "Usage: .timer on|off\n"); 4652289166Speter rc = 1; 4653289166Speter } 4654251883Speter }else 4655305003Scy 4656289166Speter if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){ 4657289166Speter open_db(p, 0); 4658289166Speter if( nArg!=2 ){ 4659305003Scy raw_printf(stderr, "Usage: .trace FILE|off\n"); 4660289166Speter rc = 1; 4661289166Speter goto meta_command_exit; 4662289166Speter } 4663251883Speter output_file_close(p->traceOut); 4664251883Speter p->traceOut = output_file_open(azArg[1]); 4665251883Speter#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) 4666251883Speter if( p->traceOut==0 ){ 4667305003Scy sqlite3_trace_v2(p->db, 0, 0, 0); 4668251883Speter }else{ 4669305003Scy sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut); 4670251883Speter } 4671251883Speter#endif 4672251883Speter }else 4673251883Speter 4674289166Speter#if SQLITE_USER_AUTHENTICATION 4675289166Speter if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ 4676289166Speter if( nArg<2 ){ 4677305003Scy raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n"); 4678289166Speter rc = 1; 4679289166Speter goto meta_command_exit; 4680289166Speter } 4681289166Speter open_db(p, 0); 4682289166Speter if( strcmp(azArg[1],"login")==0 ){ 4683289166Speter if( nArg!=4 ){ 4684305003Scy raw_printf(stderr, "Usage: .user login USER PASSWORD\n"); 4685289166Speter rc = 1; 4686289166Speter goto meta_command_exit; 4687289166Speter } 4688289166Speter rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], 4689289166Speter (int)strlen(azArg[3])); 4690289166Speter if( rc ){ 4691305003Scy utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]); 4692289166Speter rc = 1; 4693289166Speter } 4694289166Speter }else if( strcmp(azArg[1],"add")==0 ){ 4695289166Speter if( nArg!=5 ){ 4696305003Scy raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n"); 4697289166Speter rc = 1; 4698289166Speter goto meta_command_exit; 4699289166Speter } 4700289166Speter rc = sqlite3_user_add(p->db, azArg[2], 4701289166Speter azArg[3], (int)strlen(azArg[3]), 4702289166Speter booleanValue(azArg[4])); 4703289166Speter if( rc ){ 4704305003Scy raw_printf(stderr, "User-Add failed: %d\n", rc); 4705289166Speter rc = 1; 4706289166Speter } 4707289166Speter }else if( strcmp(azArg[1],"edit")==0 ){ 4708289166Speter if( nArg!=5 ){ 4709305003Scy raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n"); 4710289166Speter rc = 1; 4711289166Speter goto meta_command_exit; 4712289166Speter } 4713289166Speter rc = sqlite3_user_change(p->db, azArg[2], 4714289166Speter azArg[3], (int)strlen(azArg[3]), 4715289166Speter booleanValue(azArg[4])); 4716289166Speter if( rc ){ 4717305003Scy raw_printf(stderr, "User-Edit failed: %d\n", rc); 4718289166Speter rc = 1; 4719289166Speter } 4720289166Speter }else if( strcmp(azArg[1],"delete")==0 ){ 4721289166Speter if( nArg!=3 ){ 4722305003Scy raw_printf(stderr, "Usage: .user delete USER\n"); 4723289166Speter rc = 1; 4724289166Speter goto meta_command_exit; 4725289166Speter } 4726289166Speter rc = sqlite3_user_delete(p->db, azArg[2]); 4727289166Speter if( rc ){ 4728305003Scy raw_printf(stderr, "User-Delete failed: %d\n", rc); 4729289166Speter rc = 1; 4730289166Speter } 4731289166Speter }else{ 4732305003Scy raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n"); 4733289166Speter rc = 1; 4734289166Speter goto meta_command_exit; 4735305003Scy } 4736289166Speter }else 4737289166Speter#endif /* SQLITE_USER_AUTHENTICATION */ 4738289166Speter 4739251883Speter if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ 4740305003Scy utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/, 4741251883Speter sqlite3_libversion(), sqlite3_sourceid()); 4742251883Speter }else 4743251883Speter 4744305003Scy if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){ 4745305003Scy const char *zDbName = nArg==2 ? azArg[1] : "main"; 4746305003Scy sqlite3_vfs *pVfs; 4747305003Scy if( p->db ){ 4748305003Scy sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs); 4749305003Scy if( pVfs ){ 4750305003Scy utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName); 4751305003Scy raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); 4752305003Scy raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); 4753305003Scy raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); 4754305003Scy } 4755305003Scy } 4756305003Scy }else 4757305003Scy 4758305003Scy if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){ 4759305003Scy sqlite3_vfs *pVfs; 4760305003Scy sqlite3_vfs *pCurrent = 0; 4761305003Scy if( p->db ){ 4762305003Scy sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent); 4763305003Scy } 4764305003Scy for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){ 4765305003Scy utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName, 4766305003Scy pVfs==pCurrent ? " <--- CURRENT" : ""); 4767305003Scy raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); 4768305003Scy raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); 4769305003Scy raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); 4770305003Scy if( pVfs->pNext ){ 4771305003Scy raw_printf(p->out, "-----------------------------------\n"); 4772305003Scy } 4773305003Scy } 4774305003Scy }else 4775305003Scy 4776251883Speter if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){ 4777251883Speter const char *zDbName = nArg==2 ? azArg[1] : "main"; 4778251883Speter char *zVfsName = 0; 4779251883Speter if( p->db ){ 4780251883Speter sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName); 4781251883Speter if( zVfsName ){ 4782305003Scy utf8_printf(p->out, "%s\n", zVfsName); 4783251883Speter sqlite3_free(zVfsName); 4784251883Speter } 4785251883Speter } 4786251883Speter }else 4787251883Speter 4788251883Speter#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) 4789251883Speter if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ 4790289166Speter sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff; 4791251883Speter }else 4792251883Speter#endif 4793251883Speter 4794289166Speter if( c=='w' && strncmp(azArg[0], "width", n)==0 ){ 4795251883Speter int j; 4796251883Speter assert( nArg<=ArraySize(azArg) ); 4797251883Speter for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ 4798289166Speter p->colWidth[j-1] = (int)integerValue(azArg[j]); 4799251883Speter } 4800251883Speter }else 4801251883Speter 4802251883Speter { 4803305003Scy utf8_printf(stderr, "Error: unknown command or invalid arguments: " 4804251883Speter " \"%s\". Enter \".help\" for help\n", azArg[0]); 4805251883Speter rc = 1; 4806251883Speter } 4807251883Speter 4808289166Spetermeta_command_exit: 4809289166Speter if( p->outCount ){ 4810289166Speter p->outCount--; 4811289166Speter if( p->outCount==0 ) output_reset(p); 4812289166Speter } 4813251883Speter return rc; 4814251883Speter} 4815251883Speter 4816251883Speter/* 4817251883Speter** Return TRUE if a semicolon occurs anywhere in the first N characters 4818251883Speter** of string z[]. 4819251883Speter*/ 4820289166Speterstatic int line_contains_semicolon(const char *z, int N){ 4821251883Speter int i; 4822251883Speter for(i=0; i<N; i++){ if( z[i]==';' ) return 1; } 4823251883Speter return 0; 4824251883Speter} 4825251883Speter 4826251883Speter/* 4827251883Speter** Test to see if a line consists entirely of whitespace. 4828251883Speter*/ 4829251883Speterstatic int _all_whitespace(const char *z){ 4830251883Speter for(; *z; z++){ 4831251883Speter if( IsSpace(z[0]) ) continue; 4832251883Speter if( *z=='/' && z[1]=='*' ){ 4833251883Speter z += 2; 4834251883Speter while( *z && (*z!='*' || z[1]!='/') ){ z++; } 4835251883Speter if( *z==0 ) return 0; 4836251883Speter z++; 4837251883Speter continue; 4838251883Speter } 4839251883Speter if( *z=='-' && z[1]=='-' ){ 4840251883Speter z += 2; 4841251883Speter while( *z && *z!='\n' ){ z++; } 4842251883Speter if( *z==0 ) return 1; 4843251883Speter continue; 4844251883Speter } 4845251883Speter return 0; 4846251883Speter } 4847251883Speter return 1; 4848251883Speter} 4849251883Speter 4850251883Speter/* 4851251883Speter** Return TRUE if the line typed in is an SQL command terminator other 4852251883Speter** than a semi-colon. The SQL Server style "go" command is understood 4853251883Speter** as is the Oracle "/". 4854251883Speter*/ 4855289166Speterstatic int line_is_command_terminator(const char *zLine){ 4856251883Speter while( IsSpace(zLine[0]) ){ zLine++; }; 4857251883Speter if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){ 4858251883Speter return 1; /* Oracle */ 4859251883Speter } 4860251883Speter if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' 4861251883Speter && _all_whitespace(&zLine[2]) ){ 4862251883Speter return 1; /* SQL Server */ 4863251883Speter } 4864251883Speter return 0; 4865251883Speter} 4866251883Speter 4867251883Speter/* 4868251883Speter** Return true if zSql is a complete SQL statement. Return false if it 4869251883Speter** ends in the middle of a string literal or C-style comment. 4870251883Speter*/ 4871289166Speterstatic int line_is_complete(char *zSql, int nSql){ 4872251883Speter int rc; 4873251883Speter if( zSql==0 ) return 1; 4874251883Speter zSql[nSql] = ';'; 4875251883Speter zSql[nSql+1] = 0; 4876251883Speter rc = sqlite3_complete(zSql); 4877251883Speter zSql[nSql] = 0; 4878251883Speter return rc; 4879251883Speter} 4880251883Speter 4881251883Speter/* 4882251883Speter** Read input from *in and process it. If *in==0 then input 4883251883Speter** is interactive - the user is typing it it. Otherwise, input 4884251883Speter** is coming from a file or device. A prompt is issued and history 4885251883Speter** is saved only if input is interactive. An interrupt signal will 4886251883Speter** cause this routine to exit immediately, unless input is interactive. 4887251883Speter** 4888251883Speter** Return the number of errors. 4889251883Speter*/ 4890289166Speterstatic int process_input(ShellState *p, FILE *in){ 4891289166Speter char *zLine = 0; /* A single input line */ 4892289166Speter char *zSql = 0; /* Accumulated SQL text */ 4893289166Speter int nLine; /* Length of current line */ 4894289166Speter int nSql = 0; /* Bytes of zSql[] used */ 4895289166Speter int nAlloc = 0; /* Allocated zSql[] space */ 4896289166Speter int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */ 4897289166Speter char *zErrMsg; /* Error message returned */ 4898289166Speter int rc; /* Error code */ 4899289166Speter int errCnt = 0; /* Number of errors seen */ 4900289166Speter int lineno = 0; /* Current line number */ 4901289166Speter int startline = 0; /* Line number for start of current input */ 4902251883Speter 4903251883Speter while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){ 4904251883Speter fflush(p->out); 4905289166Speter zLine = one_input_line(in, zLine, nSql>0); 4906251883Speter if( zLine==0 ){ 4907251883Speter /* End of input */ 4908251883Speter if( stdin_is_interactive ) printf("\n"); 4909251883Speter break; 4910251883Speter } 4911251883Speter if( seenInterrupt ){ 4912251883Speter if( in!=0 ) break; 4913251883Speter seenInterrupt = 0; 4914251883Speter } 4915251883Speter lineno++; 4916289166Speter if( nSql==0 && _all_whitespace(zLine) ){ 4917289166Speter if( p->echoOn ) printf("%s\n", zLine); 4918289166Speter continue; 4919289166Speter } 4920251883Speter if( zLine && zLine[0]=='.' && nSql==0 ){ 4921251883Speter if( p->echoOn ) printf("%s\n", zLine); 4922251883Speter rc = do_meta_command(zLine, p); 4923251883Speter if( rc==2 ){ /* exit requested */ 4924251883Speter break; 4925251883Speter }else if( rc ){ 4926251883Speter errCnt++; 4927251883Speter } 4928251883Speter continue; 4929251883Speter } 4930289166Speter if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){ 4931251883Speter memcpy(zLine,";",2); 4932251883Speter } 4933289166Speter nLine = strlen30(zLine); 4934289166Speter if( nSql+nLine+2>=nAlloc ){ 4935289166Speter nAlloc = nSql+nLine+100; 4936289166Speter zSql = realloc(zSql, nAlloc); 4937289166Speter if( zSql==0 ){ 4938305003Scy raw_printf(stderr, "Error: out of memory\n"); 4939289166Speter exit(1); 4940289166Speter } 4941289166Speter } 4942251883Speter nSqlPrior = nSql; 4943289166Speter if( nSql==0 ){ 4944251883Speter int i; 4945251883Speter for(i=0; zLine[i] && IsSpace(zLine[i]); i++){} 4946289166Speter assert( nAlloc>0 && zSql!=0 ); 4947289166Speter memcpy(zSql, zLine+i, nLine+1-i); 4948289166Speter startline = lineno; 4949289166Speter nSql = nLine-i; 4950251883Speter }else{ 4951251883Speter zSql[nSql++] = '\n'; 4952289166Speter memcpy(zSql+nSql, zLine, nLine+1); 4953289166Speter nSql += nLine; 4954251883Speter } 4955289166Speter if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) 4956251883Speter && sqlite3_complete(zSql) ){ 4957251883Speter p->cnt = 0; 4958289166Speter open_db(p, 0); 4959289166Speter if( p->backslashOn ) resolve_backslashes(zSql); 4960251883Speter BEGIN_TIMER; 4961251883Speter rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg); 4962251883Speter END_TIMER; 4963251883Speter if( rc || zErrMsg ){ 4964251883Speter char zPrefix[100]; 4965251883Speter if( in!=0 || !stdin_is_interactive ){ 4966305003Scy sqlite3_snprintf(sizeof(zPrefix), zPrefix, 4967251883Speter "Error: near line %d:", startline); 4968251883Speter }else{ 4969251883Speter sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:"); 4970251883Speter } 4971251883Speter if( zErrMsg!=0 ){ 4972305003Scy utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg); 4973251883Speter sqlite3_free(zErrMsg); 4974251883Speter zErrMsg = 0; 4975251883Speter }else{ 4976305003Scy utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); 4977251883Speter } 4978251883Speter errCnt++; 4979305003Scy }else if( p->countChanges ){ 4980305003Scy raw_printf(p->out, "changes: %3d total_changes: %d\n", 4981305003Scy sqlite3_changes(p->db), sqlite3_total_changes(p->db)); 4982251883Speter } 4983251883Speter nSql = 0; 4984289166Speter if( p->outCount ){ 4985289166Speter output_reset(p); 4986289166Speter p->outCount = 0; 4987289166Speter } 4988289166Speter }else if( nSql && _all_whitespace(zSql) ){ 4989289166Speter if( p->echoOn ) printf("%s\n", zSql); 4990251883Speter nSql = 0; 4991251883Speter } 4992251883Speter } 4993289166Speter if( nSql ){ 4994251883Speter if( !_all_whitespace(zSql) ){ 4995305003Scy utf8_printf(stderr, "Error: incomplete SQL: %s\n", zSql); 4996289166Speter errCnt++; 4997251883Speter } 4998251883Speter } 4999305003Scy free(zSql); 5000251883Speter free(zLine); 5001251883Speter return errCnt>0; 5002251883Speter} 5003251883Speter 5004251883Speter/* 5005251883Speter** Return a pathname which is the user's home directory. A 5006251883Speter** 0 return indicates an error of some kind. 5007251883Speter*/ 5008251883Speterstatic char *find_home_dir(void){ 5009251883Speter static char *home_dir = NULL; 5010251883Speter if( home_dir ) return home_dir; 5011251883Speter 5012289166Speter#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \ 5013289166Speter && !defined(__RTP__) && !defined(_WRS_KERNEL) 5014251883Speter { 5015251883Speter struct passwd *pwent; 5016251883Speter uid_t uid = getuid(); 5017251883Speter if( (pwent=getpwuid(uid)) != NULL) { 5018251883Speter home_dir = pwent->pw_dir; 5019251883Speter } 5020251883Speter } 5021251883Speter#endif 5022251883Speter 5023251883Speter#if defined(_WIN32_WCE) 5024251883Speter /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv() 5025251883Speter */ 5026251883Speter home_dir = "/"; 5027251883Speter#else 5028251883Speter 5029251883Speter#if defined(_WIN32) || defined(WIN32) 5030251883Speter if (!home_dir) { 5031251883Speter home_dir = getenv("USERPROFILE"); 5032251883Speter } 5033251883Speter#endif 5034251883Speter 5035251883Speter if (!home_dir) { 5036251883Speter home_dir = getenv("HOME"); 5037251883Speter } 5038251883Speter 5039251883Speter#if defined(_WIN32) || defined(WIN32) 5040251883Speter if (!home_dir) { 5041251883Speter char *zDrive, *zPath; 5042251883Speter int n; 5043251883Speter zDrive = getenv("HOMEDRIVE"); 5044251883Speter zPath = getenv("HOMEPATH"); 5045251883Speter if( zDrive && zPath ){ 5046251883Speter n = strlen30(zDrive) + strlen30(zPath) + 1; 5047251883Speter home_dir = malloc( n ); 5048251883Speter if( home_dir==0 ) return 0; 5049251883Speter sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath); 5050251883Speter return home_dir; 5051251883Speter } 5052251883Speter home_dir = "c:\\"; 5053251883Speter } 5054251883Speter#endif 5055251883Speter 5056251883Speter#endif /* !_WIN32_WCE */ 5057251883Speter 5058251883Speter if( home_dir ){ 5059251883Speter int n = strlen30(home_dir) + 1; 5060251883Speter char *z = malloc( n ); 5061251883Speter if( z ) memcpy(z, home_dir, n); 5062251883Speter home_dir = z; 5063251883Speter } 5064251883Speter 5065251883Speter return home_dir; 5066251883Speter} 5067251883Speter 5068251883Speter/* 5069251883Speter** Read input from the file given by sqliterc_override. Or if that 5070251883Speter** parameter is NULL, take input from ~/.sqliterc 5071251883Speter** 5072251883Speter** Returns the number of errors. 5073251883Speter*/ 5074289166Speterstatic void process_sqliterc( 5075289166Speter ShellState *p, /* Configuration data */ 5076251883Speter const char *sqliterc_override /* Name of config file. NULL to use default */ 5077251883Speter){ 5078251883Speter char *home_dir = NULL; 5079251883Speter const char *sqliterc = sqliterc_override; 5080251883Speter char *zBuf = 0; 5081251883Speter FILE *in = NULL; 5082251883Speter 5083251883Speter if (sqliterc == NULL) { 5084251883Speter home_dir = find_home_dir(); 5085251883Speter if( home_dir==0 ){ 5086305003Scy raw_printf(stderr, "-- warning: cannot find home directory;" 5087289166Speter " cannot read ~/.sqliterc\n"); 5088289166Speter return; 5089251883Speter } 5090251883Speter sqlite3_initialize(); 5091251883Speter zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); 5092251883Speter sqliterc = zBuf; 5093251883Speter } 5094251883Speter in = fopen(sqliterc,"rb"); 5095251883Speter if( in ){ 5096251883Speter if( stdin_is_interactive ){ 5097305003Scy utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc); 5098251883Speter } 5099289166Speter process_input(p,in); 5100251883Speter fclose(in); 5101251883Speter } 5102251883Speter sqlite3_free(zBuf); 5103251883Speter} 5104251883Speter 5105251883Speter/* 5106251883Speter** Show available command line options 5107251883Speter*/ 5108305003Scystatic const char zOptions[] = 5109289166Speter " -ascii set output mode to 'ascii'\n" 5110251883Speter " -bail stop after hitting an error\n" 5111251883Speter " -batch force batch I/O\n" 5112251883Speter " -column set output mode to 'column'\n" 5113251883Speter " -cmd COMMAND run \"COMMAND\" before reading stdin\n" 5114251883Speter " -csv set output mode to 'csv'\n" 5115251883Speter " -echo print commands before execution\n" 5116251883Speter " -init FILENAME read/process named file\n" 5117251883Speter " -[no]header turn headers on or off\n" 5118251883Speter#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) 5119251883Speter " -heap SIZE Size of heap for memsys3 or memsys5\n" 5120251883Speter#endif 5121251883Speter " -help show this message\n" 5122251883Speter " -html set output mode to HTML\n" 5123251883Speter " -interactive force interactive I/O\n" 5124251883Speter " -line set output mode to 'line'\n" 5125251883Speter " -list set output mode to 'list'\n" 5126289166Speter " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" 5127251883Speter " -mmap N default mmap size set to N\n" 5128251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX 5129251883Speter " -multiplex enable the multiplexor VFS\n" 5130251883Speter#endif 5131289166Speter " -newline SEP set output row separator. Default: '\\n'\n" 5132251883Speter " -nullvalue TEXT set text string for NULL values. Default ''\n" 5133289166Speter " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" 5134289166Speter " -scratch SIZE N use N slots of SZ bytes each for scratch memory\n" 5135289166Speter " -separator SEP set output column separator. Default: '|'\n" 5136251883Speter " -stats print memory stats before each finalize\n" 5137251883Speter " -version show SQLite version\n" 5138251883Speter " -vfs NAME use NAME as the default VFS\n" 5139251883Speter#ifdef SQLITE_ENABLE_VFSTRACE 5140251883Speter " -vfstrace enable tracing of all VFS calls\n" 5141251883Speter#endif 5142251883Speter; 5143251883Speterstatic void usage(int showDetail){ 5144305003Scy utf8_printf(stderr, 5145305003Scy "Usage: %s [OPTIONS] FILENAME [SQL]\n" 5146251883Speter "FILENAME is the name of an SQLite database. A new database is created\n" 5147251883Speter "if the file does not previously exist.\n", Argv0); 5148251883Speter if( showDetail ){ 5149305003Scy utf8_printf(stderr, "OPTIONS include:\n%s", zOptions); 5150251883Speter }else{ 5151305003Scy raw_printf(stderr, "Use the -help option for additional information\n"); 5152251883Speter } 5153251883Speter exit(1); 5154251883Speter} 5155251883Speter 5156251883Speter/* 5157251883Speter** Initialize the state information in data 5158251883Speter*/ 5159289166Speterstatic void main_init(ShellState *data) { 5160251883Speter memset(data, 0, sizeof(*data)); 5161305003Scy data->normalMode = data->cMode = data->mode = MODE_List; 5162305003Scy data->autoExplain = 1; 5163289166Speter memcpy(data->colSeparator,SEP_Column, 2); 5164289166Speter memcpy(data->rowSeparator,SEP_Row, 2); 5165251883Speter data->showHeader = 0; 5166289166Speter data->shellFlgs = SHFLG_Lookaside; 5167251883Speter sqlite3_config(SQLITE_CONFIG_URI, 1); 5168251883Speter sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); 5169289166Speter sqlite3_config(SQLITE_CONFIG_MULTITHREAD); 5170251883Speter sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); 5171251883Speter sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); 5172251883Speter} 5173251883Speter 5174251883Speter/* 5175289166Speter** Output text to the console in a font that attracts extra attention. 5176289166Speter*/ 5177289166Speter#ifdef _WIN32 5178289166Speterstatic void printBold(const char *zText){ 5179289166Speter HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); 5180289166Speter CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo; 5181289166Speter GetConsoleScreenBufferInfo(out, &defaultScreenInfo); 5182289166Speter SetConsoleTextAttribute(out, 5183289166Speter FOREGROUND_RED|FOREGROUND_INTENSITY 5184289166Speter ); 5185289166Speter printf("%s", zText); 5186289166Speter SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes); 5187289166Speter} 5188289166Speter#else 5189289166Speterstatic void printBold(const char *zText){ 5190289166Speter printf("\033[1m%s\033[0m", zText); 5191289166Speter} 5192289166Speter#endif 5193289166Speter 5194289166Speter/* 5195251883Speter** Get the argument to an --option. Throw an error and die if no argument 5196251883Speter** is available. 5197251883Speter*/ 5198251883Speterstatic char *cmdline_option_value(int argc, char **argv, int i){ 5199251883Speter if( i==argc ){ 5200305003Scy utf8_printf(stderr, "%s: Error: missing argument to %s\n", 5201251883Speter argv[0], argv[argc-1]); 5202251883Speter exit(1); 5203251883Speter } 5204251883Speter return argv[i]; 5205251883Speter} 5206251883Speter 5207305003Scy#ifndef SQLITE_SHELL_IS_UTF8 5208305003Scy# if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) 5209305003Scy# define SQLITE_SHELL_IS_UTF8 (0) 5210305003Scy# else 5211305003Scy# define SQLITE_SHELL_IS_UTF8 (1) 5212305003Scy# endif 5213305003Scy#endif 5214305003Scy 5215305003Scy#if SQLITE_SHELL_IS_UTF8 5216289166Speterint SQLITE_CDECL main(int argc, char **argv){ 5217305003Scy#else 5218305003Scyint SQLITE_CDECL wmain(int argc, wchar_t **wargv){ 5219305003Scy char **argv; 5220305003Scy#endif 5221251883Speter char *zErrMsg = 0; 5222289166Speter ShellState data; 5223251883Speter const char *zInitFile = 0; 5224251883Speter int i; 5225251883Speter int rc = 0; 5226289166Speter int warnInmemoryDb = 0; 5227289166Speter int readStdin = 1; 5228289166Speter int nCmd = 0; 5229289166Speter char **azCmd = 0; 5230251883Speter 5231305003Scy setBinaryMode(stdin, 0); 5232305003Scy setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ 5233305003Scy stdin_is_interactive = isatty(0); 5234305003Scy stdout_is_console = isatty(1); 5235305003Scy 5236289166Speter#if USE_SYSTEM_SQLITE+0!=1 5237251883Speter if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){ 5238305003Scy utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", 5239251883Speter sqlite3_sourceid(), SQLITE_SOURCE_ID); 5240251883Speter exit(1); 5241251883Speter } 5242289166Speter#endif 5243305003Scy main_init(&data); 5244305003Scy#if !SQLITE_SHELL_IS_UTF8 5245305003Scy sqlite3_initialize(); 5246305003Scy argv = sqlite3_malloc64(sizeof(argv[0])*argc); 5247305003Scy if( argv==0 ){ 5248305003Scy raw_printf(stderr, "out of memory\n"); 5249305003Scy exit(1); 5250305003Scy } 5251305003Scy for(i=0; i<argc; i++){ 5252305003Scy argv[i] = sqlite3_win32_unicode_to_utf8(wargv[i]); 5253305003Scy if( argv[i]==0 ){ 5254305003Scy raw_printf(stderr, "out of memory\n"); 5255305003Scy exit(1); 5256305003Scy } 5257305003Scy } 5258305003Scy#endif 5259305003Scy assert( argc>=1 && argv && argv[0] ); 5260251883Speter Argv0 = argv[0]; 5261251883Speter 5262251883Speter /* Make sure we have a valid signal handler early, before anything 5263251883Speter ** else is done. 5264251883Speter */ 5265251883Speter#ifdef SIGINT 5266251883Speter signal(SIGINT, interrupt_handler); 5267251883Speter#endif 5268251883Speter 5269289166Speter#ifdef SQLITE_SHELL_DBNAME_PROC 5270289166Speter { 5271289166Speter /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name 5272289166Speter ** of a C-function that will provide the name of the database file. Use 5273289166Speter ** this compile-time option to embed this shell program in larger 5274289166Speter ** applications. */ 5275289166Speter extern void SQLITE_SHELL_DBNAME_PROC(const char**); 5276289166Speter SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename); 5277289166Speter warnInmemoryDb = 0; 5278289166Speter } 5279289166Speter#endif 5280289166Speter 5281251883Speter /* Do an initial pass through the command-line argument to locate 5282251883Speter ** the name of the database file, the name of the initialization file, 5283251883Speter ** the size of the alternative malloc heap, 5284251883Speter ** and the first command to execute. 5285251883Speter */ 5286251883Speter for(i=1; i<argc; i++){ 5287251883Speter char *z; 5288251883Speter z = argv[i]; 5289251883Speter if( z[0]!='-' ){ 5290251883Speter if( data.zDbFilename==0 ){ 5291251883Speter data.zDbFilename = z; 5292289166Speter }else{ 5293289166Speter /* Excesss arguments are interpreted as SQL (or dot-commands) and 5294289166Speter ** mean that nothing is read from stdin */ 5295289166Speter readStdin = 0; 5296289166Speter nCmd++; 5297289166Speter azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); 5298289166Speter if( azCmd==0 ){ 5299305003Scy raw_printf(stderr, "out of memory\n"); 5300289166Speter exit(1); 5301289166Speter } 5302289166Speter azCmd[nCmd-1] = z; 5303251883Speter } 5304251883Speter } 5305251883Speter if( z[1]=='-' ) z++; 5306251883Speter if( strcmp(z,"-separator")==0 5307251883Speter || strcmp(z,"-nullvalue")==0 5308289166Speter || strcmp(z,"-newline")==0 5309251883Speter || strcmp(z,"-cmd")==0 5310251883Speter ){ 5311251883Speter (void)cmdline_option_value(argc, argv, ++i); 5312251883Speter }else if( strcmp(z,"-init")==0 ){ 5313251883Speter zInitFile = cmdline_option_value(argc, argv, ++i); 5314251883Speter }else if( strcmp(z,"-batch")==0 ){ 5315251883Speter /* Need to check for batch mode here to so we can avoid printing 5316305003Scy ** informational messages (like from process_sqliterc) before 5317251883Speter ** we do the actual processing of arguments later in a second pass. 5318251883Speter */ 5319251883Speter stdin_is_interactive = 0; 5320251883Speter }else if( strcmp(z,"-heap")==0 ){ 5321251883Speter#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) 5322251883Speter const char *zSize; 5323251883Speter sqlite3_int64 szHeap; 5324251883Speter 5325251883Speter zSize = cmdline_option_value(argc, argv, ++i); 5326251883Speter szHeap = integerValue(zSize); 5327251883Speter if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; 5328251883Speter sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); 5329305003Scy#else 5330305003Scy (void)cmdline_option_value(argc, argv, ++i); 5331251883Speter#endif 5332289166Speter }else if( strcmp(z,"-scratch")==0 ){ 5333289166Speter int n, sz; 5334289166Speter sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); 5335289166Speter if( sz>400000 ) sz = 400000; 5336289166Speter if( sz<2500 ) sz = 2500; 5337289166Speter n = (int)integerValue(cmdline_option_value(argc,argv,++i)); 5338289166Speter if( n>10 ) n = 10; 5339289166Speter if( n<1 ) n = 1; 5340289166Speter sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n); 5341289166Speter data.shellFlgs |= SHFLG_Scratch; 5342289166Speter }else if( strcmp(z,"-pagecache")==0 ){ 5343289166Speter int n, sz; 5344289166Speter sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); 5345289166Speter if( sz>70000 ) sz = 70000; 5346305003Scy if( sz<0 ) sz = 0; 5347289166Speter n = (int)integerValue(cmdline_option_value(argc,argv,++i)); 5348305003Scy sqlite3_config(SQLITE_CONFIG_PAGECACHE, 5349305003Scy (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n); 5350289166Speter data.shellFlgs |= SHFLG_Pagecache; 5351289166Speter }else if( strcmp(z,"-lookaside")==0 ){ 5352289166Speter int n, sz; 5353289166Speter sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); 5354289166Speter if( sz<0 ) sz = 0; 5355289166Speter n = (int)integerValue(cmdline_option_value(argc,argv,++i)); 5356289166Speter if( n<0 ) n = 0; 5357289166Speter sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n); 5358289166Speter if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside; 5359251883Speter#ifdef SQLITE_ENABLE_VFSTRACE 5360251883Speter }else if( strcmp(z,"-vfstrace")==0 ){ 5361251883Speter extern int vfstrace_register( 5362251883Speter const char *zTraceName, 5363251883Speter const char *zOldVfsName, 5364251883Speter int (*xOut)(const char*,void*), 5365251883Speter void *pOutArg, 5366251883Speter int makeDefault 5367251883Speter ); 5368251883Speter vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); 5369251883Speter#endif 5370251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX 5371251883Speter }else if( strcmp(z,"-multiplex")==0 ){ 5372251883Speter extern int sqlite3_multiple_initialize(const char*,int); 5373251883Speter sqlite3_multiplex_initialize(0, 1); 5374251883Speter#endif 5375251883Speter }else if( strcmp(z,"-mmap")==0 ){ 5376251883Speter sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); 5377251883Speter sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz); 5378251883Speter }else if( strcmp(z,"-vfs")==0 ){ 5379251883Speter sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i)); 5380251883Speter if( pVfs ){ 5381251883Speter sqlite3_vfs_register(pVfs, 1); 5382251883Speter }else{ 5383305003Scy utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]); 5384251883Speter exit(1); 5385251883Speter } 5386251883Speter } 5387251883Speter } 5388251883Speter if( data.zDbFilename==0 ){ 5389251883Speter#ifndef SQLITE_OMIT_MEMORYDB 5390251883Speter data.zDbFilename = ":memory:"; 5391289166Speter warnInmemoryDb = argc==1; 5392251883Speter#else 5393305003Scy utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0); 5394251883Speter return 1; 5395251883Speter#endif 5396251883Speter } 5397251883Speter data.out = stdout; 5398251883Speter 5399251883Speter /* Go ahead and open the database file if it already exists. If the 5400251883Speter ** file does not exist, delay opening it. This prevents empty database 5401251883Speter ** files from being created if a user mistypes the database name argument 5402251883Speter ** to the sqlite command-line tool. 5403251883Speter */ 5404251883Speter if( access(data.zDbFilename, 0)==0 ){ 5405289166Speter open_db(&data, 0); 5406251883Speter } 5407251883Speter 5408251883Speter /* Process the initialization file if there is one. If no -init option 5409251883Speter ** is given on the command line, look for a file named ~/.sqliterc and 5410251883Speter ** try to process it. 5411251883Speter */ 5412289166Speter process_sqliterc(&data,zInitFile); 5413251883Speter 5414251883Speter /* Make a second pass through the command-line argument and set 5415251883Speter ** options. This second pass is delayed until after the initialization 5416251883Speter ** file is processed so that the command-line arguments will override 5417251883Speter ** settings in the initialization file. 5418251883Speter */ 5419251883Speter for(i=1; i<argc; i++){ 5420251883Speter char *z = argv[i]; 5421251883Speter if( z[0]!='-' ) continue; 5422251883Speter if( z[1]=='-' ){ z++; } 5423251883Speter if( strcmp(z,"-init")==0 ){ 5424251883Speter i++; 5425251883Speter }else if( strcmp(z,"-html")==0 ){ 5426251883Speter data.mode = MODE_Html; 5427251883Speter }else if( strcmp(z,"-list")==0 ){ 5428251883Speter data.mode = MODE_List; 5429251883Speter }else if( strcmp(z,"-line")==0 ){ 5430251883Speter data.mode = MODE_Line; 5431251883Speter }else if( strcmp(z,"-column")==0 ){ 5432251883Speter data.mode = MODE_Column; 5433251883Speter }else if( strcmp(z,"-csv")==0 ){ 5434251883Speter data.mode = MODE_Csv; 5435289166Speter memcpy(data.colSeparator,",",2); 5436289166Speter }else if( strcmp(z,"-ascii")==0 ){ 5437289166Speter data.mode = MODE_Ascii; 5438289166Speter sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, 5439289166Speter SEP_Unit); 5440289166Speter sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, 5441289166Speter SEP_Record); 5442251883Speter }else if( strcmp(z,"-separator")==0 ){ 5443289166Speter sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, 5444251883Speter "%s",cmdline_option_value(argc,argv,++i)); 5445289166Speter }else if( strcmp(z,"-newline")==0 ){ 5446289166Speter sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, 5447289166Speter "%s",cmdline_option_value(argc,argv,++i)); 5448251883Speter }else if( strcmp(z,"-nullvalue")==0 ){ 5449289166Speter sqlite3_snprintf(sizeof(data.nullValue), data.nullValue, 5450251883Speter "%s",cmdline_option_value(argc,argv,++i)); 5451251883Speter }else if( strcmp(z,"-header")==0 ){ 5452251883Speter data.showHeader = 1; 5453251883Speter }else if( strcmp(z,"-noheader")==0 ){ 5454251883Speter data.showHeader = 0; 5455251883Speter }else if( strcmp(z,"-echo")==0 ){ 5456251883Speter data.echoOn = 1; 5457289166Speter }else if( strcmp(z,"-eqp")==0 ){ 5458289166Speter data.autoEQP = 1; 5459305003Scy }else if( strcmp(z,"-eqpfull")==0 ){ 5460305003Scy data.autoEQP = 2; 5461251883Speter }else if( strcmp(z,"-stats")==0 ){ 5462251883Speter data.statsOn = 1; 5463289166Speter }else if( strcmp(z,"-scanstats")==0 ){ 5464289166Speter data.scanstatsOn = 1; 5465289166Speter }else if( strcmp(z,"-backslash")==0 ){ 5466289166Speter /* Undocumented command-line option: -backslash 5467289166Speter ** Causes C-style backslash escapes to be evaluated in SQL statements 5468289166Speter ** prior to sending the SQL into SQLite. Useful for injecting 5469289166Speter ** crazy bytes in the middle of SQL statements for testing and debugging. 5470289166Speter */ 5471289166Speter data.backslashOn = 1; 5472251883Speter }else if( strcmp(z,"-bail")==0 ){ 5473251883Speter bail_on_error = 1; 5474251883Speter }else if( strcmp(z,"-version")==0 ){ 5475251883Speter printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid()); 5476251883Speter return 0; 5477251883Speter }else if( strcmp(z,"-interactive")==0 ){ 5478251883Speter stdin_is_interactive = 1; 5479251883Speter }else if( strcmp(z,"-batch")==0 ){ 5480251883Speter stdin_is_interactive = 0; 5481251883Speter }else if( strcmp(z,"-heap")==0 ){ 5482251883Speter i++; 5483289166Speter }else if( strcmp(z,"-scratch")==0 ){ 5484289166Speter i+=2; 5485289166Speter }else if( strcmp(z,"-pagecache")==0 ){ 5486289166Speter i+=2; 5487289166Speter }else if( strcmp(z,"-lookaside")==0 ){ 5488289166Speter i+=2; 5489251883Speter }else if( strcmp(z,"-mmap")==0 ){ 5490251883Speter i++; 5491251883Speter }else if( strcmp(z,"-vfs")==0 ){ 5492251883Speter i++; 5493251883Speter#ifdef SQLITE_ENABLE_VFSTRACE 5494251883Speter }else if( strcmp(z,"-vfstrace")==0 ){ 5495251883Speter i++; 5496251883Speter#endif 5497251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX 5498251883Speter }else if( strcmp(z,"-multiplex")==0 ){ 5499251883Speter i++; 5500251883Speter#endif 5501251883Speter }else if( strcmp(z,"-help")==0 ){ 5502251883Speter usage(1); 5503251883Speter }else if( strcmp(z,"-cmd")==0 ){ 5504289166Speter /* Run commands that follow -cmd first and separately from commands 5505289166Speter ** that simply appear on the command-line. This seems goofy. It would 5506289166Speter ** be better if all commands ran in the order that they appear. But 5507289166Speter ** we retain the goofy behavior for historical compatibility. */ 5508251883Speter if( i==argc-1 ) break; 5509251883Speter z = cmdline_option_value(argc,argv,++i); 5510251883Speter if( z[0]=='.' ){ 5511251883Speter rc = do_meta_command(z, &data); 5512251883Speter if( rc && bail_on_error ) return rc==2 ? 0 : rc; 5513251883Speter }else{ 5514289166Speter open_db(&data, 0); 5515251883Speter rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg); 5516251883Speter if( zErrMsg!=0 ){ 5517305003Scy utf8_printf(stderr,"Error: %s\n", zErrMsg); 5518251883Speter if( bail_on_error ) return rc!=0 ? rc : 1; 5519251883Speter }else if( rc!=0 ){ 5520305003Scy utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z); 5521251883Speter if( bail_on_error ) return rc; 5522251883Speter } 5523251883Speter } 5524251883Speter }else{ 5525305003Scy utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); 5526305003Scy raw_printf(stderr,"Use -help for a list of options.\n"); 5527251883Speter return 1; 5528251883Speter } 5529305003Scy data.cMode = data.mode; 5530251883Speter } 5531251883Speter 5532289166Speter if( !readStdin ){ 5533289166Speter /* Run all arguments that do not begin with '-' as if they were separate 5534289166Speter ** command-line inputs, except for the argToSkip argument which contains 5535289166Speter ** the database filename. 5536251883Speter */ 5537289166Speter for(i=0; i<nCmd; i++){ 5538289166Speter if( azCmd[i][0]=='.' ){ 5539289166Speter rc = do_meta_command(azCmd[i], &data); 5540289166Speter if( rc ) return rc==2 ? 0 : rc; 5541289166Speter }else{ 5542289166Speter open_db(&data, 0); 5543289166Speter rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg); 5544289166Speter if( zErrMsg!=0 ){ 5545305003Scy utf8_printf(stderr,"Error: %s\n", zErrMsg); 5546289166Speter return rc!=0 ? rc : 1; 5547289166Speter }else if( rc!=0 ){ 5548305003Scy utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]); 5549289166Speter return rc; 5550289166Speter } 5551251883Speter } 5552251883Speter } 5553289166Speter free(azCmd); 5554251883Speter }else{ 5555251883Speter /* Run commands received from standard input 5556251883Speter */ 5557251883Speter if( stdin_is_interactive ){ 5558251883Speter char *zHome; 5559251883Speter char *zHistory = 0; 5560251883Speter int nHistory; 5561251883Speter printf( 5562251883Speter "SQLite version %s %.19s\n" /*extra-version-info*/ 5563289166Speter "Enter \".help\" for usage hints.\n", 5564251883Speter sqlite3_libversion(), sqlite3_sourceid() 5565251883Speter ); 5566289166Speter if( warnInmemoryDb ){ 5567289166Speter printf("Connected to a "); 5568289166Speter printBold("transient in-memory database"); 5569289166Speter printf(".\nUse \".open FILENAME\" to reopen on a " 5570289166Speter "persistent database.\n"); 5571289166Speter } 5572251883Speter zHome = find_home_dir(); 5573251883Speter if( zHome ){ 5574251883Speter nHistory = strlen30(zHome) + 20; 5575251883Speter if( (zHistory = malloc(nHistory))!=0 ){ 5576251883Speter sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome); 5577251883Speter } 5578251883Speter } 5579289166Speter if( zHistory ){ shell_read_history(zHistory); } 5580251883Speter rc = process_input(&data, 0); 5581251883Speter if( zHistory ){ 5582289166Speter shell_stifle_history(100); 5583289166Speter shell_write_history(zHistory); 5584251883Speter free(zHistory); 5585251883Speter } 5586251883Speter }else{ 5587251883Speter rc = process_input(&data, stdin); 5588251883Speter } 5589251883Speter } 5590251883Speter set_table_name(&data, 0); 5591251883Speter if( data.db ){ 5592305003Scy session_close_all(&data); 5593251883Speter sqlite3_close(data.db); 5594251883Speter } 5595305003Scy sqlite3_free(data.zFreeOnClose); 5596305003Scy#if !SQLITE_SHELL_IS_UTF8 5597305003Scy for(i=0; i<argc; i++) sqlite3_free(argv[i]); 5598305003Scy sqlite3_free(argv); 5599305003Scy#endif 5600251883Speter return rc; 5601251883Speter} 5602