blob: 0581807b5f68024c093a3bfda5e6e372eb2fcccf [file] [log] [blame]
drh75897232000-05-29 14:26:00 +00001/*
drhb19a2bc2001-09-16 00:13:26 +00002** 2001 September 15
drh75897232000-05-29 14:26:00 +00003**
drhb19a2bc2001-09-16 00:13:26 +00004** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
drh75897232000-05-29 14:26:00 +00006**
drhb19a2bc2001-09-16 00:13:26 +00007** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
drh75897232000-05-29 14:26:00 +000010**
11*************************************************************************
12** This file contains code to implement the "sqlite" command line
13** utility for accessing SQLite databases.
14**
drh1822eee2008-12-04 12:26:00 +000015** $Id: shell.c,v 1.189 2008/12/04 12:26:01 drh Exp $
drh75897232000-05-29 14:26:00 +000016*/
17#include <stdlib.h>
18#include <string.h>
19#include <stdio.h>
danielk19772a02e332004-06-05 08:04:36 +000020#include <assert.h>
drh1d482dd2004-05-31 18:23:07 +000021#include "sqlite3.h"
drh75897232000-05-29 14:26:00 +000022#include <ctype.h>
drhb0603412007-02-28 04:47:26 +000023#include <stdarg.h>
persicom7e2dfdd2002-04-18 02:46:52 +000024
drh454ad582007-11-26 22:54:27 +000025#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
drh4c504392000-10-16 22:06:40 +000026# include <signal.h>
chw97185482008-11-17 08:05:31 +000027# if !defined(__RTP__) && !defined(_WRS_KERNEL)
28# include <pwd.h>
29# endif
drhdd45df82002-04-18 12:39:03 +000030# include <unistd.h>
31# include <sys/types.h>
drh4c504392000-10-16 22:06:40 +000032#endif
drh75897232000-05-29 14:26:00 +000033
drhcdb36b72006-06-12 12:57:45 +000034#ifdef __OS2__
35# include <unistd.h>
36#endif
37
drh16e59552000-07-31 11:57:37 +000038#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh8e7e7a22000-05-30 18:45:23 +000039# include <readline/readline.h>
40# include <readline/history.h>
41#else
drh9347b202003-07-18 01:30:59 +000042# define readline(p) local_getline(p,stdin)
persicom1d0b8722002-04-18 02:53:04 +000043# define add_history(X)
drh67505e72002-04-19 12:34:06 +000044# define read_history(X)
45# define write_history(X)
46# define stifle_history(X)
drh75897232000-05-29 14:26:00 +000047#endif
48
adamd2e8464a2006-09-06 21:39:40 +000049#if defined(_WIN32) || defined(WIN32)
50# include <io.h>
51#else
drh4328c8b2003-04-26 02:50:11 +000052/* Make sure isatty() has a prototype.
53*/
54extern int isatty();
adamd2e8464a2006-09-06 21:39:40 +000055#endif
drh4328c8b2003-04-26 02:50:11 +000056
chw65d3c132007-11-12 21:09:10 +000057#if defined(_WIN32_WCE)
58/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
59 * thus we always assume that we have a console. That can be
60 * overridden with the -batch command line option.
61 */
62#define isatty(x) 1
63#endif
64
chw97185482008-11-17 08:05:31 +000065#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
drh3b1a9882007-11-02 12:53:03 +000066#include <sys/time.h>
67#include <sys/resource.h>
68
69/* Saved resource information for the beginning of an operation */
70static struct rusage sBegin;
71
72/* True if the timer is enabled */
73static int enableTimer = 0;
74
75/*
76** Begin timing an operation
77*/
78static void beginTimer(void){
79 if( enableTimer ){
80 getrusage(RUSAGE_SELF, &sBegin);
81 }
82}
83
drhf4608092008-07-11 17:23:24 +000084/* Return the difference of two time_structs in seconds */
85static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
86 return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
87 (double)(pEnd->tv_sec - pStart->tv_sec);
drh3b1a9882007-11-02 12:53:03 +000088}
89
90/*
91** Print the timing results.
92*/
93static void endTimer(void){
94 if( enableTimer ){
95 struct rusage sEnd;
96 getrusage(RUSAGE_SELF, &sEnd);
97 printf("CPU Time: user %f sys %f\n",
drhf4608092008-07-11 17:23:24 +000098 timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
99 timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
drh3b1a9882007-11-02 12:53:03 +0000100 }
101}
102#define BEGIN_TIMER beginTimer()
103#define END_TIMER endTimer()
104#define HAS_TIMER 1
105#else
106#define BEGIN_TIMER
107#define END_TIMER
108#define HAS_TIMER 0
109#endif
110
111
drh75897232000-05-29 14:26:00 +0000112/*
drhc49f44e2006-10-26 18:15:42 +0000113** If the following flag is set, then command execution stops
114** at an error if we are not interactive.
115*/
116static int bail_on_error = 0;
117
118/*
drhc28490c2006-10-26 14:25:58 +0000119** Threat stdin as an interactive input if the following variable
120** is true. Otherwise, assume stdin is connected to a file or pipe.
121*/
122static int stdin_is_interactive = 1;
123
124/*
drh4c504392000-10-16 22:06:40 +0000125** The following is the open SQLite database. We make a pointer
126** to this database a static variable so that it can be accessed
127** by the SIGINT handler to interrupt database processing.
128*/
danielk197792f9a1b2004-06-19 09:08:16 +0000129static sqlite3 *db = 0;
drh4c504392000-10-16 22:06:40 +0000130
131/*
drh67505e72002-04-19 12:34:06 +0000132** True if an interrupt (Control-C) has been received.
133*/
drh43617e92006-03-06 20:55:46 +0000134static volatile int seenInterrupt = 0;
drh67505e72002-04-19 12:34:06 +0000135
136/*
persicom7e2dfdd2002-04-18 02:46:52 +0000137** This is the name of our program. It is set in main(), used
138** in a number of other places, mostly for error messages.
139*/
140static char *Argv0;
141
142/*
143** Prompt strings. Initialized in main. Settable with
144** .prompt main continue
145*/
146static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
147static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
148
drhb0603412007-02-28 04:47:26 +0000149/*
150** Write I/O traces to the following stream.
151*/
rsebe0a9092007-07-30 18:24:38 +0000152#ifdef SQLITE_ENABLE_IOTRACE
drhb0603412007-02-28 04:47:26 +0000153static FILE *iotrace = 0;
rsebe0a9092007-07-30 18:24:38 +0000154#endif
drhb0603412007-02-28 04:47:26 +0000155
156/*
157** This routine works like printf in that its first argument is a
158** format string and subsequent arguments are values to be substituted
159** in place of % fields. The result of formatting this string
160** is written to iotrace.
161*/
rsebe0a9092007-07-30 18:24:38 +0000162#ifdef SQLITE_ENABLE_IOTRACE
drhb0603412007-02-28 04:47:26 +0000163static void iotracePrintf(const char *zFormat, ...){
164 va_list ap;
drhf075cd02007-02-28 06:14:25 +0000165 char *z;
drhb0603412007-02-28 04:47:26 +0000166 if( iotrace==0 ) return;
167 va_start(ap, zFormat);
drhf075cd02007-02-28 06:14:25 +0000168 z = sqlite3_vmprintf(zFormat, ap);
drhb0603412007-02-28 04:47:26 +0000169 va_end(ap);
drhf075cd02007-02-28 06:14:25 +0000170 fprintf(iotrace, "%s", z);
171 sqlite3_free(z);
drhb0603412007-02-28 04:47:26 +0000172}
rsebe0a9092007-07-30 18:24:38 +0000173#endif
drhb0603412007-02-28 04:47:26 +0000174
drh44c2eb12003-04-30 11:38:26 +0000175
persicom7e2dfdd2002-04-18 02:46:52 +0000176/*
drh83965662003-04-17 02:54:13 +0000177** Determines if a string is a number of not.
178*/
danielk19772e588c72005-12-09 14:25:08 +0000179static int isNumber(const char *z, int *realnum){
drhc8d74412004-08-31 23:41:26 +0000180 if( *z=='-' || *z=='+' ) z++;
181 if( !isdigit(*z) ){
182 return 0;
183 }
184 z++;
185 if( realnum ) *realnum = 0;
186 while( isdigit(*z) ){ z++; }
187 if( *z=='.' ){
188 z++;
189 if( !isdigit(*z) ) return 0;
190 while( isdigit(*z) ){ z++; }
191 if( realnum ) *realnum = 1;
192 }
193 if( *z=='e' || *z=='E' ){
194 z++;
195 if( *z=='+' || *z=='-' ) z++;
196 if( !isdigit(*z) ) return 0;
197 while( isdigit(*z) ){ z++; }
198 if( realnum ) *realnum = 1;
199 }
200 return *z==0;
201}
drh83965662003-04-17 02:54:13 +0000202
203/*
danielk1977bc6ada42004-06-30 08:20:16 +0000204** A global char* and an SQL function to access its current value
205** from within an SQL statement. This program used to use the
206** sqlite_exec_printf() API to substitue a string into an SQL statement.
207** The correct way to do this with sqlite3 is to use the bind API, but
208** since the shell is built around the callback paradigm it would be a lot
209** of work. Instead just use this hack, which is quite harmless.
210*/
211static const char *zShellStatic = 0;
212static void shellstaticFunc(
213 sqlite3_context *context,
214 int argc,
215 sqlite3_value **argv
216){
217 assert( 0==argc );
218 assert( zShellStatic );
219 sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
220}
221
222
223/*
drhfeac5f82004-08-01 00:10:45 +0000224** This routine reads a line of text from FILE in, stores
drh8e7e7a22000-05-30 18:45:23 +0000225** the text in memory obtained from malloc() and returns a pointer
226** to the text. NULL is returned at end of file, or if malloc()
227** fails.
228**
229** The interface is like "readline" but no command-line editing
230** is done.
231*/
drh9347b202003-07-18 01:30:59 +0000232static char *local_getline(char *zPrompt, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +0000233 char *zLine;
234 int nLine;
drh8e7e7a22000-05-30 18:45:23 +0000235 int n;
236 int eol;
237
238 if( zPrompt && *zPrompt ){
239 printf("%s",zPrompt);
240 fflush(stdout);
241 }
242 nLine = 100;
243 zLine = malloc( nLine );
244 if( zLine==0 ) return 0;
245 n = 0;
246 eol = 0;
247 while( !eol ){
248 if( n+100>nLine ){
249 nLine = nLine*2 + 100;
250 zLine = realloc(zLine, nLine);
251 if( zLine==0 ) return 0;
252 }
drhdaffd0e2001-04-11 14:28:42 +0000253 if( fgets(&zLine[n], nLine - n, in)==0 ){
drh8e7e7a22000-05-30 18:45:23 +0000254 if( n==0 ){
255 free(zLine);
256 return 0;
257 }
258 zLine[n] = 0;
259 eol = 1;
260 break;
261 }
262 while( zLine[n] ){ n++; }
263 if( n>0 && zLine[n-1]=='\n' ){
264 n--;
265 zLine[n] = 0;
266 eol = 1;
267 }
268 }
269 zLine = realloc( zLine, n+1 );
270 return zLine;
271}
272
273/*
drhc28490c2006-10-26 14:25:58 +0000274** Retrieve a single line of input text.
drh8e7e7a22000-05-30 18:45:23 +0000275**
276** zPrior is a string of prior text retrieved. If not the empty
277** string, then issue a continuation prompt.
278*/
drhdaffd0e2001-04-11 14:28:42 +0000279static char *one_input_line(const char *zPrior, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +0000280 char *zPrompt;
281 char *zResult;
drhdaffd0e2001-04-11 14:28:42 +0000282 if( in!=0 ){
drh9347b202003-07-18 01:30:59 +0000283 return local_getline(0, in);
drh8e7e7a22000-05-30 18:45:23 +0000284 }
285 if( zPrior && zPrior[0] ){
persicom7e2dfdd2002-04-18 02:46:52 +0000286 zPrompt = continuePrompt;
drh8e7e7a22000-05-30 18:45:23 +0000287 }else{
persicom7e2dfdd2002-04-18 02:46:52 +0000288 zPrompt = mainPrompt;
drh8e7e7a22000-05-30 18:45:23 +0000289 }
290 zResult = readline(zPrompt);
danielk19774af00c62005-01-23 23:43:21 +0000291#if defined(HAVE_READLINE) && HAVE_READLINE==1
drheb741d52006-06-03 17:37:25 +0000292 if( zResult && *zResult ) add_history(zResult);
danielk19774af00c62005-01-23 23:43:21 +0000293#endif
drh8e7e7a22000-05-30 18:45:23 +0000294 return zResult;
295}
296
persicom7e2dfdd2002-04-18 02:46:52 +0000297struct previous_mode_data {
298 int valid; /* Is there legit data in here? */
299 int mode;
300 int showHeader;
301 int colWidth[100];
302};
drh45e29d82006-11-20 16:21:10 +0000303
drh8e7e7a22000-05-30 18:45:23 +0000304/*
drh75897232000-05-29 14:26:00 +0000305** An pointer to an instance of this structure is passed from
306** the main program to the callback. This is used to communicate
307** state and mode information.
308*/
309struct callback_data {
danielk197792f9a1b2004-06-19 09:08:16 +0000310 sqlite3 *db; /* The database */
drhdaffd0e2001-04-11 14:28:42 +0000311 int echoOn; /* True to echo input commands */
drh28bd4bc2000-06-15 15:57:22 +0000312 int cnt; /* Number of records displayed so far */
313 FILE *out; /* Write results here */
314 int mode; /* An output mode setting */
drh45e29d82006-11-20 16:21:10 +0000315 int writableSchema; /* True if PRAGMA writable_schema=ON */
drh28bd4bc2000-06-15 15:57:22 +0000316 int showHeader; /* True to show column names in List or Column mode */
drh33048c02001-10-01 14:29:22 +0000317 char *zDestTable; /* Name of destination table when MODE_Insert */
drh28bd4bc2000-06-15 15:57:22 +0000318 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +0000319 int colWidth[100]; /* Requested width of each column when in column mode*/
320 int actualWidth[100]; /* Actual width of each column */
drh83965662003-04-17 02:54:13 +0000321 char nullvalue[20]; /* The text to print when a NULL comes back from
322 ** the database */
persicom7e2dfdd2002-04-18 02:46:52 +0000323 struct previous_mode_data explainPrev;
drh83965662003-04-17 02:54:13 +0000324 /* Holds the mode information just before
325 ** .explain ON */
drh44c2eb12003-04-30 11:38:26 +0000326 char outfile[FILENAME_MAX]; /* Filename for *out */
327 const char *zDbFilename; /* name of the database file */
drh75897232000-05-29 14:26:00 +0000328};
329
330/*
331** These are the allowed modes.
332*/
drh967e8b72000-06-21 13:59:10 +0000333#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000334#define MODE_Column 1 /* One record per line in neat columns */
335#define MODE_List 2 /* One record per line with a separator */
drhe3710332000-09-29 13:30:53 +0000336#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
337#define MODE_Html 4 /* Generate an XHTML table */
338#define MODE_Insert 5 /* Generate SQL "insert" statements */
drhfeac5f82004-08-01 00:10:45 +0000339#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
drh8e64d1c2004-10-07 00:32:39 +0000340#define MODE_Csv 7 /* Quote strings, numbers are plain */
drh66ce4d02008-02-15 17:38:06 +0000341#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
persicom7e2dfdd2002-04-18 02:46:52 +0000342
drh66ce4d02008-02-15 17:38:06 +0000343static const char *modeDescr[] = {
persicom7e2dfdd2002-04-18 02:46:52 +0000344 "line",
345 "column",
346 "list",
347 "semi",
348 "html",
drhfeac5f82004-08-01 00:10:45 +0000349 "insert",
350 "tcl",
drh8e64d1c2004-10-07 00:32:39 +0000351 "csv",
drh66ce4d02008-02-15 17:38:06 +0000352 "explain",
persicom7e2dfdd2002-04-18 02:46:52 +0000353};
drh75897232000-05-29 14:26:00 +0000354
355/*
356** Number of elements in an array
357*/
358#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
359
360/*
drh28bd4bc2000-06-15 15:57:22 +0000361** Output the given string as a quoted string using SQL quoting conventions.
362*/
363static void output_quoted_string(FILE *out, const char *z){
364 int i;
365 int nSingle = 0;
drh28bd4bc2000-06-15 15:57:22 +0000366 for(i=0; z[i]; i++){
367 if( z[i]=='\'' ) nSingle++;
drh28bd4bc2000-06-15 15:57:22 +0000368 }
369 if( nSingle==0 ){
370 fprintf(out,"'%s'",z);
drh28bd4bc2000-06-15 15:57:22 +0000371 }else{
372 fprintf(out,"'");
373 while( *z ){
374 for(i=0; z[i] && z[i]!='\''; i++){}
375 if( i==0 ){
376 fprintf(out,"''");
377 z++;
378 }else if( z[i]=='\'' ){
379 fprintf(out,"%.*s''",i,z);
380 z += i+1;
381 }else{
drhcd7d2732002-02-26 23:24:26 +0000382 fprintf(out,"%s",z);
drh28bd4bc2000-06-15 15:57:22 +0000383 break;
384 }
385 }
drhcd7d2732002-02-26 23:24:26 +0000386 fprintf(out,"'");
drh28bd4bc2000-06-15 15:57:22 +0000387 }
388}
389
390/*
drhfeac5f82004-08-01 00:10:45 +0000391** Output the given string as a quoted according to C or TCL quoting rules.
392*/
393static void output_c_string(FILE *out, const char *z){
394 unsigned int c;
395 fputc('"', out);
396 while( (c = *(z++))!=0 ){
397 if( c=='\\' ){
398 fputc(c, out);
399 fputc(c, out);
400 }else if( c=='\t' ){
401 fputc('\\', out);
402 fputc('t', out);
403 }else if( c=='\n' ){
404 fputc('\\', out);
405 fputc('n', out);
406 }else if( c=='\r' ){
407 fputc('\\', out);
408 fputc('r', out);
409 }else if( !isprint(c) ){
drh0a8640d2005-08-30 20:12:02 +0000410 fprintf(out, "\\%03o", c&0xff);
drhfeac5f82004-08-01 00:10:45 +0000411 }else{
412 fputc(c, out);
413 }
414 }
415 fputc('"', out);
416}
417
418/*
drhc08a4f12000-06-15 16:49:48 +0000419** Output the given string with characters that are special to
420** HTML escaped.
421*/
422static void output_html_string(FILE *out, const char *z){
423 int i;
424 while( *z ){
425 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
426 if( i>0 ){
427 fprintf(out,"%.*s",i,z);
428 }
429 if( z[i]=='<' ){
430 fprintf(out,"&lt;");
431 }else if( z[i]=='&' ){
432 fprintf(out,"&amp;");
433 }else{
434 break;
435 }
436 z += i + 1;
437 }
438}
439
440/*
drhc49f44e2006-10-26 18:15:42 +0000441** If a field contains any character identified by a 1 in the following
442** array, then the string must be quoted for CSV.
443*/
444static const char needCsvQuote[] = {
445 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
446 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
447 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
448 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
449 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
450 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
451 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
452 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
454 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
455 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
456 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
457 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
458 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
459 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
460 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
461};
462
463/*
drh8e64d1c2004-10-07 00:32:39 +0000464** Output a single term of CSV. Actually, p->separator is used for
465** the separator, which may or may not be a comma. p->nullvalue is
466** the null value. Strings are quoted using ANSI-C rules. Numbers
467** appear outside of quotes.
468*/
469static void output_csv(struct callback_data *p, const char *z, int bSep){
drhc49f44e2006-10-26 18:15:42 +0000470 FILE *out = p->out;
drh8e64d1c2004-10-07 00:32:39 +0000471 if( z==0 ){
drhc49f44e2006-10-26 18:15:42 +0000472 fprintf(out,"%s",p->nullvalue);
drh8e64d1c2004-10-07 00:32:39 +0000473 }else{
drhc49f44e2006-10-26 18:15:42 +0000474 int i;
drhc85375d2007-12-18 15:41:44 +0000475 int nSep = strlen(p->separator);
drhc49f44e2006-10-26 18:15:42 +0000476 for(i=0; z[i]; i++){
drhc85375d2007-12-18 15:41:44 +0000477 if( needCsvQuote[((unsigned char*)z)[i]]
478 || (z[i]==p->separator[0] &&
479 (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
drhc49f44e2006-10-26 18:15:42 +0000480 i = 0;
481 break;
482 }
483 }
484 if( i==0 ){
485 putc('"', out);
486 for(i=0; z[i]; i++){
487 if( z[i]=='"' ) putc('"', out);
488 putc(z[i], out);
489 }
490 putc('"', out);
491 }else{
492 fprintf(out, "%s", z);
493 }
drh8e64d1c2004-10-07 00:32:39 +0000494 }
495 if( bSep ){
drhd0e77882008-01-14 15:20:08 +0000496 fprintf(p->out, "%s", p->separator);
drh8e64d1c2004-10-07 00:32:39 +0000497 }
498}
499
danielk19774af00c62005-01-23 23:43:21 +0000500#ifdef SIGINT
drh8e64d1c2004-10-07 00:32:39 +0000501/*
drh4c504392000-10-16 22:06:40 +0000502** This routine runs when the user presses Ctrl-C
503*/
504static void interrupt_handler(int NotUsed){
drh67505e72002-04-19 12:34:06 +0000505 seenInterrupt = 1;
danielk19776f8a5032004-05-10 10:34:51 +0000506 if( db ) sqlite3_interrupt(db);
drh4c504392000-10-16 22:06:40 +0000507}
danielk19774af00c62005-01-23 23:43:21 +0000508#endif
drh4c504392000-10-16 22:06:40 +0000509
510/*
drh75897232000-05-29 14:26:00 +0000511** This is the callback routine that the SQLite library
512** invokes for each row of a query result.
513*/
514static int callback(void *pArg, int nArg, char **azArg, char **azCol){
515 int i;
516 struct callback_data *p = (struct callback_data*)pArg;
517 switch( p->mode ){
518 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +0000519 int w = 5;
drh6a535342001-10-19 16:44:56 +0000520 if( azArg==0 ) break;
drhe3710332000-09-29 13:30:53 +0000521 for(i=0; i<nArg; i++){
drh2cc55692006-06-27 20:39:04 +0000522 int len = strlen(azCol[i] ? azCol[i] : "");
drhe3710332000-09-29 13:30:53 +0000523 if( len>w ) w = len;
524 }
drh75897232000-05-29 14:26:00 +0000525 if( p->cnt++>0 ) fprintf(p->out,"\n");
526 for(i=0; i<nArg; i++){
drh2cc55692006-06-27 20:39:04 +0000527 fprintf(p->out,"%*s = %s\n", w, azCol[i],
drha69d9162003-04-17 22:57:53 +0000528 azArg[i] ? azArg[i] : p->nullvalue);
drh75897232000-05-29 14:26:00 +0000529 }
530 break;
531 }
danielk19770d78bae2008-01-03 07:09:48 +0000532 case MODE_Explain:
drh75897232000-05-29 14:26:00 +0000533 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000534 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000535 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000536 int w, n;
537 if( i<ArraySize(p->colWidth) ){
danielk19770d78bae2008-01-03 07:09:48 +0000538 w = p->colWidth[i];
drh75897232000-05-29 14:26:00 +0000539 }else{
danielk19770d78bae2008-01-03 07:09:48 +0000540 w = 0;
drh75897232000-05-29 14:26:00 +0000541 }
drha0c66f52000-07-29 13:20:21 +0000542 if( w<=0 ){
drhff6e9112000-08-28 16:21:58 +0000543 w = strlen(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +0000544 if( w<10 ) w = 10;
persicom7e2dfdd2002-04-18 02:46:52 +0000545 n = strlen(azArg && azArg[i] ? azArg[i] : p->nullvalue);
drha0c66f52000-07-29 13:20:21 +0000546 if( w<n ) w = n;
547 }
548 if( i<ArraySize(p->actualWidth) ){
persicom1d0b8722002-04-18 02:53:04 +0000549 p->actualWidth[i] = w;
drha0c66f52000-07-29 13:20:21 +0000550 }
551 if( p->showHeader ){
552 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
553 }
554 }
555 if( p->showHeader ){
556 for(i=0; i<nArg; i++){
557 int w;
558 if( i<ArraySize(p->actualWidth) ){
559 w = p->actualWidth[i];
560 }else{
561 w = 10;
562 }
563 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
564 "----------------------------------------------------------",
565 i==nArg-1 ? "\n": " ");
566 }
drh75897232000-05-29 14:26:00 +0000567 }
568 }
drh6a535342001-10-19 16:44:56 +0000569 if( azArg==0 ) break;
drh75897232000-05-29 14:26:00 +0000570 for(i=0; i<nArg; i++){
571 int w;
drha0c66f52000-07-29 13:20:21 +0000572 if( i<ArraySize(p->actualWidth) ){
573 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000574 }else{
575 w = 10;
576 }
danielk19770d78bae2008-01-03 07:09:48 +0000577 if( p->mode==MODE_Explain && azArg[i] && strlen(azArg[i])>w ){
578 w = strlen(azArg[i]);
579 }
drhc61053b2000-06-04 12:58:36 +0000580 fprintf(p->out,"%-*.*s%s",w,w,
persicom7e2dfdd2002-04-18 02:46:52 +0000581 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000582 }
583 break;
584 }
drhe3710332000-09-29 13:30:53 +0000585 case MODE_Semi:
drh75897232000-05-29 14:26:00 +0000586 case MODE_List: {
587 if( p->cnt++==0 && p->showHeader ){
588 for(i=0; i<nArg; i++){
589 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
590 }
591 }
drh6a535342001-10-19 16:44:56 +0000592 if( azArg==0 ) break;
drh75897232000-05-29 14:26:00 +0000593 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000594 char *z = azArg[i];
persicom7e2dfdd2002-04-18 02:46:52 +0000595 if( z==0 ) z = p->nullvalue;
drh71172c52002-01-24 00:00:21 +0000596 fprintf(p->out, "%s", z);
drhe3710332000-09-29 13:30:53 +0000597 if( i<nArg-1 ){
598 fprintf(p->out, "%s", p->separator);
599 }else if( p->mode==MODE_Semi ){
600 fprintf(p->out, ";\n");
601 }else{
602 fprintf(p->out, "\n");
603 }
drh75897232000-05-29 14:26:00 +0000604 }
605 break;
606 }
drh1e5d0e92000-05-31 23:33:17 +0000607 case MODE_Html: {
608 if( p->cnt++==0 && p->showHeader ){
mihailim57c591a2008-06-23 21:26:05 +0000609 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000610 for(i=0; i<nArg; i++){
mihailim57c591a2008-06-23 21:26:05 +0000611 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
drh1e5d0e92000-05-31 23:33:17 +0000612 }
mihailim57c591a2008-06-23 21:26:05 +0000613 fprintf(p->out,"</TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000614 }
drh6a535342001-10-19 16:44:56 +0000615 if( azArg==0 ) break;
mihailim57c591a2008-06-23 21:26:05 +0000616 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000617 for(i=0; i<nArg; i++){
mihailim57c591a2008-06-23 21:26:05 +0000618 fprintf(p->out,"<TD>");
persicom7e2dfdd2002-04-18 02:46:52 +0000619 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
mihailim57c591a2008-06-23 21:26:05 +0000620 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000621 }
mihailim57c591a2008-06-23 21:26:05 +0000622 fprintf(p->out,"</TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000623 break;
624 }
drhfeac5f82004-08-01 00:10:45 +0000625 case MODE_Tcl: {
626 if( p->cnt++==0 && p->showHeader ){
627 for(i=0; i<nArg; i++){
drh2cc55692006-06-27 20:39:04 +0000628 output_c_string(p->out,azCol[i] ? azCol[i] : "");
drhfeac5f82004-08-01 00:10:45 +0000629 fprintf(p->out, "%s", p->separator);
630 }
631 fprintf(p->out,"\n");
632 }
633 if( azArg==0 ) break;
634 for(i=0; i<nArg; i++){
635 output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
636 fprintf(p->out, "%s", p->separator);
637 }
638 fprintf(p->out,"\n");
639 break;
640 }
drh8e64d1c2004-10-07 00:32:39 +0000641 case MODE_Csv: {
642 if( p->cnt++==0 && p->showHeader ){
643 for(i=0; i<nArg; i++){
drh2cc55692006-06-27 20:39:04 +0000644 output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
drh8e64d1c2004-10-07 00:32:39 +0000645 }
646 fprintf(p->out,"\n");
647 }
648 if( azArg==0 ) break;
649 for(i=0; i<nArg; i++){
650 output_csv(p, azArg[i], i<nArg-1);
651 }
652 fprintf(p->out,"\n");
653 break;
654 }
drh28bd4bc2000-06-15 15:57:22 +0000655 case MODE_Insert: {
drh6a535342001-10-19 16:44:56 +0000656 if( azArg==0 ) break;
drh33048c02001-10-01 14:29:22 +0000657 fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
drh28bd4bc2000-06-15 15:57:22 +0000658 for(i=0; i<nArg; i++){
659 char *zSep = i>0 ? ",": "";
660 if( azArg[i]==0 ){
661 fprintf(p->out,"%sNULL",zSep);
drhc8d74412004-08-31 23:41:26 +0000662 }else if( isNumber(azArg[i], 0) ){
drh28bd4bc2000-06-15 15:57:22 +0000663 fprintf(p->out,"%s%s",zSep, azArg[i]);
664 }else{
665 if( zSep[0] ) fprintf(p->out,"%s",zSep);
666 output_quoted_string(p->out, azArg[i]);
667 }
668 }
669 fprintf(p->out,");\n");
drh6a535342001-10-19 16:44:56 +0000670 break;
drh28bd4bc2000-06-15 15:57:22 +0000671 }
persicom1d0b8722002-04-18 02:53:04 +0000672 }
drh75897232000-05-29 14:26:00 +0000673 return 0;
674}
675
676/*
drh33048c02001-10-01 14:29:22 +0000677** Set the destination table field of the callback_data structure to
678** the name of the table given. Escape any quote characters in the
679** table name.
680*/
681static void set_table_name(struct callback_data *p, const char *zName){
682 int i, n;
683 int needQuote;
684 char *z;
685
686 if( p->zDestTable ){
687 free(p->zDestTable);
688 p->zDestTable = 0;
689 }
690 if( zName==0 ) return;
drh4c755c02004-08-08 20:22:17 +0000691 needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
drh33048c02001-10-01 14:29:22 +0000692 for(i=n=0; zName[i]; i++, n++){
drh4c755c02004-08-08 20:22:17 +0000693 if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
drh33048c02001-10-01 14:29:22 +0000694 needQuote = 1;
695 if( zName[i]=='\'' ) n++;
696 }
697 }
698 if( needQuote ) n += 2;
699 z = p->zDestTable = malloc( n+1 );
700 if( z==0 ){
701 fprintf(stderr,"Out of memory!\n");
702 exit(1);
703 }
704 n = 0;
705 if( needQuote ) z[n++] = '\'';
706 for(i=0; zName[i]; i++){
707 z[n++] = zName[i];
708 if( zName[i]=='\'' ) z[n++] = '\'';
709 }
710 if( needQuote ) z[n++] = '\'';
711 z[n] = 0;
712}
713
danielk19772a02e332004-06-05 08:04:36 +0000714/* zIn is either a pointer to a NULL-terminated string in memory obtained
715** from malloc(), or a NULL pointer. The string pointed to by zAppend is
716** added to zIn, and the result returned in memory obtained from malloc().
717** zIn, if it was not NULL, is freed.
718**
719** If the third argument, quote, is not '\0', then it is used as a
720** quote character for zAppend.
721*/
drhc28490c2006-10-26 14:25:58 +0000722static char *appendText(char *zIn, char const *zAppend, char quote){
danielk19772a02e332004-06-05 08:04:36 +0000723 int len;
724 int i;
725 int nAppend = strlen(zAppend);
726 int nIn = (zIn?strlen(zIn):0);
727
728 len = nAppend+nIn+1;
729 if( quote ){
730 len += 2;
731 for(i=0; i<nAppend; i++){
732 if( zAppend[i]==quote ) len++;
733 }
734 }
735
736 zIn = (char *)realloc(zIn, len);
737 if( !zIn ){
738 return 0;
739 }
740
741 if( quote ){
742 char *zCsr = &zIn[nIn];
743 *zCsr++ = quote;
744 for(i=0; i<nAppend; i++){
745 *zCsr++ = zAppend[i];
746 if( zAppend[i]==quote ) *zCsr++ = quote;
747 }
748 *zCsr++ = quote;
749 *zCsr++ = '\0';
750 assert( (zCsr-zIn)==len );
751 }else{
752 memcpy(&zIn[nIn], zAppend, nAppend);
753 zIn[len-1] = '\0';
754 }
755
756 return zIn;
757}
758
drhdd3d4592004-08-30 01:54:05 +0000759
760/*
761** Execute a query statement that has a single result column. Print
762** that result column on a line by itself with a semicolon terminator.
drh45e29d82006-11-20 16:21:10 +0000763**
764** This is used, for example, to show the schema of the database by
765** querying the SQLITE_MASTER table.
drhdd3d4592004-08-30 01:54:05 +0000766*/
767static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
768 sqlite3_stmt *pSelect;
769 int rc;
770 rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
771 if( rc!=SQLITE_OK || !pSelect ){
772 return rc;
773 }
774 rc = sqlite3_step(pSelect);
775 while( rc==SQLITE_ROW ){
776 fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
777 rc = sqlite3_step(pSelect);
778 }
779 return sqlite3_finalize(pSelect);
780}
781
782
drh33048c02001-10-01 14:29:22 +0000783/*
drh4c653a02000-06-07 01:27:47 +0000784** This is a different callback routine used for dumping the database.
785** Each row received by this callback consists of a table name,
786** the table type ("index" or "table") and SQL to create the table.
787** This routine should print text sufficient to recreate the table.
788*/
789static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
danielk19772a02e332004-06-05 08:04:36 +0000790 int rc;
791 const char *zTable;
792 const char *zType;
793 const char *zSql;
drhdaffd0e2001-04-11 14:28:42 +0000794 struct callback_data *p = (struct callback_data *)pArg;
danielk19772a02e332004-06-05 08:04:36 +0000795
drh4c653a02000-06-07 01:27:47 +0000796 if( nArg!=3 ) return 1;
danielk19772a02e332004-06-05 08:04:36 +0000797 zTable = azArg[0];
798 zType = azArg[1];
799 zSql = azArg[2];
800
drh00b950d2005-09-11 02:03:03 +0000801 if( strcmp(zTable, "sqlite_sequence")==0 ){
drhf8eb96a2005-02-03 00:42:34 +0000802 fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
drh00b950d2005-09-11 02:03:03 +0000803 }else if( strcmp(zTable, "sqlite_stat1")==0 ){
804 fprintf(p->out, "ANALYZE sqlite_master;\n");
805 }else if( strncmp(zTable, "sqlite_", 7)==0 ){
806 return 0;
drh45e29d82006-11-20 16:21:10 +0000807 }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
808 char *zIns;
809 if( !p->writableSchema ){
810 fprintf(p->out, "PRAGMA writable_schema=ON;\n");
811 p->writableSchema = 1;
812 }
813 zIns = sqlite3_mprintf(
814 "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
815 "VALUES('table','%q','%q',0,'%q');",
816 zTable, zTable, zSql);
817 fprintf(p->out, "%s\n", zIns);
818 sqlite3_free(zIns);
819 return 0;
drh00b950d2005-09-11 02:03:03 +0000820 }else{
821 fprintf(p->out, "%s;\n", zSql);
drhf8eb96a2005-02-03 00:42:34 +0000822 }
danielk19772a02e332004-06-05 08:04:36 +0000823
824 if( strcmp(zType, "table")==0 ){
825 sqlite3_stmt *pTableInfo = 0;
danielk19772a02e332004-06-05 08:04:36 +0000826 char *zSelect = 0;
827 char *zTableInfo = 0;
828 char *zTmp = 0;
829
830 zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
831 zTableInfo = appendText(zTableInfo, zTable, '"');
832 zTableInfo = appendText(zTableInfo, ");", 0);
833
834 rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
835 if( zTableInfo ) free(zTableInfo);
836 if( rc!=SQLITE_OK || !pTableInfo ){
837 return 1;
838 }
839
840 zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
841 zTmp = appendText(zTmp, zTable, '"');
842 if( zTmp ){
843 zSelect = appendText(zSelect, zTmp, '\'');
844 }
845 zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
846 rc = sqlite3_step(pTableInfo);
847 while( rc==SQLITE_ROW ){
danielk19772e588c72005-12-09 14:25:08 +0000848 const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
danielk19773f41e972004-06-08 00:39:01 +0000849 zSelect = appendText(zSelect, "quote(", 0);
danielk19772e588c72005-12-09 14:25:08 +0000850 zSelect = appendText(zSelect, zText, '"');
danielk19772a02e332004-06-05 08:04:36 +0000851 rc = sqlite3_step(pTableInfo);
852 if( rc==SQLITE_ROW ){
drh45e29d82006-11-20 16:21:10 +0000853 zSelect = appendText(zSelect, ") || ',' || ", 0);
danielk19772a02e332004-06-05 08:04:36 +0000854 }else{
855 zSelect = appendText(zSelect, ") ", 0);
856 }
857 }
858 rc = sqlite3_finalize(pTableInfo);
859 if( rc!=SQLITE_OK ){
860 if( zSelect ) free(zSelect);
861 return 1;
862 }
863 zSelect = appendText(zSelect, "|| ')' FROM ", 0);
864 zSelect = appendText(zSelect, zTable, '"');
865
drhdd3d4592004-08-30 01:54:05 +0000866 rc = run_table_dump_query(p->out, p->db, zSelect);
867 if( rc==SQLITE_CORRUPT ){
868 zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
869 rc = run_table_dump_query(p->out, p->db, zSelect);
870 }
danielk19772a02e332004-06-05 08:04:36 +0000871 if( zSelect ) free(zSelect);
drh4c653a02000-06-07 01:27:47 +0000872 }
drh4c653a02000-06-07 01:27:47 +0000873 return 0;
874}
875
876/*
drh45e29d82006-11-20 16:21:10 +0000877** Run zQuery. Use dump_callback() as the callback routine so that
878** the contents of the query are output as SQL statements.
879**
drhdd3d4592004-08-30 01:54:05 +0000880** If we get a SQLITE_CORRUPT error, rerun the query after appending
881** "ORDER BY rowid DESC" to the end.
882*/
883static int run_schema_dump_query(
884 struct callback_data *p,
885 const char *zQuery,
886 char **pzErrMsg
887){
888 int rc;
889 rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg);
890 if( rc==SQLITE_CORRUPT ){
891 char *zQ2;
892 int len = strlen(zQuery);
893 if( pzErrMsg ) sqlite3_free(*pzErrMsg);
894 zQ2 = malloc( len+100 );
895 if( zQ2==0 ) return rc;
drh5bb3eb92007-05-04 13:15:55 +0000896 sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery);
drhdd3d4592004-08-30 01:54:05 +0000897 rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
898 free(zQ2);
899 }
900 return rc;
901}
902
903/*
drh75897232000-05-29 14:26:00 +0000904** Text of a help message
905*/
persicom1d0b8722002-04-18 02:53:04 +0000906static char zHelp[] =
drh20f99c42007-01-08 14:31:35 +0000907 ".bail ON|OFF Stop after hitting an error. Default OFF\n"
jplyon6a65bb32003-05-04 07:25:57 +0000908 ".databases List names and files of attached databases\n"
drhb860bc92004-08-04 15:16:55 +0000909 ".dump ?TABLE? ... Dump the database in an SQL text format\n"
drhdaffd0e2001-04-11 14:28:42 +0000910 ".echo ON|OFF Turn command echo on or off\n"
drh75897232000-05-29 14:26:00 +0000911 ".exit Exit this program\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000912 ".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000913 ".header(s) ON|OFF Turn display of headers on or off\n"
drh75897232000-05-29 14:26:00 +0000914 ".help Show this message\n"
drhb860bc92004-08-04 15:16:55 +0000915 ".import FILE TABLE Import data from FILE into TABLE\n"
drh75897232000-05-29 14:26:00 +0000916 ".indices TABLE Show names of all indices on TABLE\n"
drhae5e4452007-05-03 17:18:36 +0000917#ifdef SQLITE_ENABLE_IOTRACE
918 ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
919#endif
drh70df4fe2006-06-13 15:12:21 +0000920#ifndef SQLITE_OMIT_LOAD_EXTENSION
drh1e397f82006-06-08 15:28:43 +0000921 ".load FILE ?ENTRY? Load an extension library\n"
drh70df4fe2006-06-13 15:12:21 +0000922#endif
danielk19776b77a362005-01-13 11:10:25 +0000923 ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
drh3b584fa2004-09-24 12:50:03 +0000924 " csv Comma-separated values\n"
drhb860bc92004-08-04 15:16:55 +0000925 " column Left-aligned columns. (See .width)\n"
926 " html HTML <table> code\n"
927 " insert SQL insert statements for TABLE\n"
928 " line One value per line\n"
929 " list Values delimited by .separator string\n"
930 " tabs Tab-separated values\n"
931 " tcl TCL list elements\n"
932 ".nullvalue STRING Print STRING in place of NULL values\n"
drh75897232000-05-29 14:26:00 +0000933 ".output FILENAME Send output to FILENAME\n"
934 ".output stdout Send output to the screen\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000935 ".prompt MAIN CONTINUE Replace the standard prompts\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000936 ".quit Exit this program\n"
drhdaffd0e2001-04-11 14:28:42 +0000937 ".read FILENAME Execute SQL in FILENAME\n"
drh75897232000-05-29 14:26:00 +0000938 ".schema ?TABLE? Show the CREATE statements\n"
drhb860bc92004-08-04 15:16:55 +0000939 ".separator STRING Change separator used by output mode and .import\n"
drhdd45df82002-04-18 12:39:03 +0000940 ".show Show the current values for various settings\n"
drhfeac5f82004-08-01 00:10:45 +0000941 ".tables ?PATTERN? List names of tables matching a LIKE pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000942 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh3b1a9882007-11-02 12:53:03 +0000943#if HAS_TIMER
944 ".timer ON|OFF Turn the CPU timer measurement on or off\n"
945#endif
drh75897232000-05-29 14:26:00 +0000946 ".width NUM NUM ... Set column widths for \"column\" mode\n"
947;
948
drhdaffd0e2001-04-11 14:28:42 +0000949/* Forward reference */
drhc28490c2006-10-26 14:25:58 +0000950static int process_input(struct callback_data *p, FILE *in);
drhdaffd0e2001-04-11 14:28:42 +0000951
drh75897232000-05-29 14:26:00 +0000952/*
drh44c2eb12003-04-30 11:38:26 +0000953** Make sure the database is open. If it is not, then open it. If
954** the database fails to open, print an error message and exit.
955*/
956static void open_db(struct callback_data *p){
957 if( p->db==0 ){
danielk19774f057f92004-06-08 00:02:33 +0000958 sqlite3_open(p->zDbFilename, &p->db);
danielk197780290862004-05-22 09:21:21 +0000959 db = p->db;
drh4cea5ba2008-05-05 16:27:24 +0000960 if( db && sqlite3_errcode(db)==SQLITE_OK ){
961 sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
962 shellstaticFunc, 0, 0);
963 }
964 if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
danielk197780290862004-05-22 09:21:21 +0000965 fprintf(stderr,"Unable to open database \"%s\": %s\n",
966 p->zDbFilename, sqlite3_errmsg(db));
drh22fbcb82004-02-01 01:22:50 +0000967 exit(1);
drh44c2eb12003-04-30 11:38:26 +0000968 }
drhc2e87a32006-06-27 15:16:14 +0000969#ifndef SQLITE_OMIT_LOAD_EXTENSION
970 sqlite3_enable_load_extension(p->db, 1);
971#endif
drh44c2eb12003-04-30 11:38:26 +0000972 }
973}
974
975/*
drhfeac5f82004-08-01 00:10:45 +0000976** Do C-language style dequoting.
977**
978** \t -> tab
979** \n -> newline
980** \r -> carriage return
981** \NNN -> ascii character NNN in octal
982** \\ -> backslash
983*/
984static void resolve_backslashes(char *z){
985 int i, j, c;
986 for(i=j=0; (c = z[i])!=0; i++, j++){
987 if( c=='\\' ){
988 c = z[++i];
989 if( c=='n' ){
990 c = '\n';
991 }else if( c=='t' ){
992 c = '\t';
993 }else if( c=='r' ){
994 c = '\r';
995 }else if( c>='0' && c<='7' ){
drhaa816082005-12-29 12:53:09 +0000996 c -= '0';
drhfeac5f82004-08-01 00:10:45 +0000997 if( z[i+1]>='0' && z[i+1]<='7' ){
998 i++;
999 c = (c<<3) + z[i] - '0';
1000 if( z[i+1]>='0' && z[i+1]<='7' ){
1001 i++;
1002 c = (c<<3) + z[i] - '0';
1003 }
1004 }
1005 }
1006 }
1007 z[j] = c;
1008 }
1009 z[j] = 0;
1010}
1011
1012/*
drhc28490c2006-10-26 14:25:58 +00001013** Interpret zArg as a boolean value. Return either 0 or 1.
1014*/
1015static int booleanValue(char *zArg){
1016 int val = atoi(zArg);
1017 int j;
1018 for(j=0; zArg[j]; j++){
1019 zArg[j] = tolower(zArg[j]);
1020 }
1021 if( strcmp(zArg,"on")==0 ){
1022 val = 1;
1023 }else if( strcmp(zArg,"yes")==0 ){
1024 val = 1;
1025 }
1026 return val;
1027}
1028
1029/*
drh75897232000-05-29 14:26:00 +00001030** If an input line begins with "." then invoke this routine to
1031** process that line.
drh67505e72002-04-19 12:34:06 +00001032**
drh47ad6842006-11-08 12:25:42 +00001033** Return 1 on error, 2 to exit, and 0 otherwise.
drh75897232000-05-29 14:26:00 +00001034*/
drh44c2eb12003-04-30 11:38:26 +00001035static int do_meta_command(char *zLine, struct callback_data *p){
drh75897232000-05-29 14:26:00 +00001036 int i = 1;
1037 int nArg = 0;
1038 int n, c;
drh67505e72002-04-19 12:34:06 +00001039 int rc = 0;
drh75897232000-05-29 14:26:00 +00001040 char *azArg[50];
1041
1042 /* Parse the input line into tokens.
1043 */
1044 while( zLine[i] && nArg<ArraySize(azArg) ){
drh4c755c02004-08-08 20:22:17 +00001045 while( isspace((unsigned char)zLine[i]) ){ i++; }
drh06333682004-03-09 13:37:45 +00001046 if( zLine[i]==0 ) break;
drh75897232000-05-29 14:26:00 +00001047 if( zLine[i]=='\'' || zLine[i]=='"' ){
1048 int delim = zLine[i++];
1049 azArg[nArg++] = &zLine[i];
1050 while( zLine[i] && zLine[i]!=delim ){ i++; }
1051 if( zLine[i]==delim ){
1052 zLine[i++] = 0;
1053 }
drhfeac5f82004-08-01 00:10:45 +00001054 if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
drh75897232000-05-29 14:26:00 +00001055 }else{
1056 azArg[nArg++] = &zLine[i];
drh4c755c02004-08-08 20:22:17 +00001057 while( zLine[i] && !isspace((unsigned char)zLine[i]) ){ i++; }
drh75897232000-05-29 14:26:00 +00001058 if( zLine[i] ) zLine[i++] = 0;
drhfeac5f82004-08-01 00:10:45 +00001059 resolve_backslashes(azArg[nArg-1]);
drh75897232000-05-29 14:26:00 +00001060 }
1061 }
1062
1063 /* Process the input line.
1064 */
drh67505e72002-04-19 12:34:06 +00001065 if( nArg==0 ) return rc;
drh75897232000-05-29 14:26:00 +00001066 n = strlen(azArg[0]);
1067 c = azArg[0][0];
drhc49f44e2006-10-26 18:15:42 +00001068 if( c=='b' && n>1 && strncmp(azArg[0], "bail", n)==0 && nArg>1 ){
1069 bail_on_error = booleanValue(azArg[1]);
1070 }else
1071
jplyon6a65bb32003-05-04 07:25:57 +00001072 if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
jplyon672a1ed2003-05-11 20:07:05 +00001073 struct callback_data data;
1074 char *zErrMsg = 0;
jplyon6a65bb32003-05-04 07:25:57 +00001075 open_db(p);
jplyon672a1ed2003-05-11 20:07:05 +00001076 memcpy(&data, p, sizeof(data));
drhd8885442004-03-17 23:42:12 +00001077 data.showHeader = 1;
jplyon672a1ed2003-05-11 20:07:05 +00001078 data.mode = MODE_Column;
drhd8885442004-03-17 23:42:12 +00001079 data.colWidth[0] = 3;
1080 data.colWidth[1] = 15;
1081 data.colWidth[2] = 58;
drh0b2110c2004-10-26 00:08:10 +00001082 data.cnt = 0;
danielk19776f8a5032004-05-10 10:34:51 +00001083 sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
jplyon672a1ed2003-05-11 20:07:05 +00001084 if( zErrMsg ){
1085 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00001086 sqlite3_free(zErrMsg);
jplyon6a65bb32003-05-04 07:25:57 +00001087 }
1088 }else
1089
drh4c653a02000-06-07 01:27:47 +00001090 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
1091 char *zErrMsg = 0;
drh44c2eb12003-04-30 11:38:26 +00001092 open_db(p);
drh33048c02001-10-01 14:29:22 +00001093 fprintf(p->out, "BEGIN TRANSACTION;\n");
drh45e29d82006-11-20 16:21:10 +00001094 p->writableSchema = 0;
drh93f41e52008-08-11 19:12:34 +00001095 sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0);
drh4c653a02000-06-07 01:27:47 +00001096 if( nArg==1 ){
drhdd3d4592004-08-30 01:54:05 +00001097 run_schema_dump_query(p,
drha18c5682000-10-08 22:20:57 +00001098 "SELECT name, type, sql FROM sqlite_master "
drh45e29d82006-11-20 16:21:10 +00001099 "WHERE sql NOT NULL AND type=='table'", 0
drh0b9a5942006-09-13 20:22:02 +00001100 );
1101 run_table_dump_query(p->out, p->db,
1102 "SELECT sql FROM sqlite_master "
drh45e29d82006-11-20 16:21:10 +00001103 "WHERE sql NOT NULL AND type IN ('index','trigger','view')"
drha18c5682000-10-08 22:20:57 +00001104 );
drh4c653a02000-06-07 01:27:47 +00001105 }else{
1106 int i;
drhdd3d4592004-08-30 01:54:05 +00001107 for(i=1; i<nArg; i++){
danielk1977bc6ada42004-06-30 08:20:16 +00001108 zShellStatic = azArg[i];
drhdd3d4592004-08-30 01:54:05 +00001109 run_schema_dump_query(p,
drha18c5682000-10-08 22:20:57 +00001110 "SELECT name, type, sql FROM sqlite_master "
drhdd3d4592004-08-30 01:54:05 +00001111 "WHERE tbl_name LIKE shellstatic() AND type=='table'"
drh45e29d82006-11-20 16:21:10 +00001112 " AND sql NOT NULL", 0);
drh0b9a5942006-09-13 20:22:02 +00001113 run_table_dump_query(p->out, p->db,
1114 "SELECT sql FROM sqlite_master "
drh45e29d82006-11-20 16:21:10 +00001115 "WHERE sql NOT NULL"
1116 " AND type IN ('index','trigger','view')"
drh0b9a5942006-09-13 20:22:02 +00001117 " AND tbl_name LIKE shellstatic()"
1118 );
danielk1977bc6ada42004-06-30 08:20:16 +00001119 zShellStatic = 0;
drh4c653a02000-06-07 01:27:47 +00001120 }
1121 }
drh45e29d82006-11-20 16:21:10 +00001122 if( p->writableSchema ){
1123 fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
1124 p->writableSchema = 0;
1125 }
drh93f41e52008-08-11 19:12:34 +00001126 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF", 0, 0, 0);
drh4c653a02000-06-07 01:27:47 +00001127 if( zErrMsg ){
1128 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00001129 sqlite3_free(zErrMsg);
drh33048c02001-10-01 14:29:22 +00001130 }else{
1131 fprintf(p->out, "COMMIT;\n");
drh4c653a02000-06-07 01:27:47 +00001132 }
1133 }else
drh75897232000-05-29 14:26:00 +00001134
drhdaffd0e2001-04-11 14:28:42 +00001135 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
drhc28490c2006-10-26 14:25:58 +00001136 p->echoOn = booleanValue(azArg[1]);
drhdaffd0e2001-04-11 14:28:42 +00001137 }else
1138
drh75897232000-05-29 14:26:00 +00001139 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
drh47ad6842006-11-08 12:25:42 +00001140 rc = 2;
drh75897232000-05-29 14:26:00 +00001141 }else
1142
drhdd45df82002-04-18 12:39:03 +00001143 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
drhc28490c2006-10-26 14:25:58 +00001144 int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
persicom7e2dfdd2002-04-18 02:46:52 +00001145 if(val == 1) {
1146 if(!p->explainPrev.valid) {
1147 p->explainPrev.valid = 1;
1148 p->explainPrev.mode = p->mode;
1149 p->explainPrev.showHeader = p->showHeader;
1150 memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
1151 }
1152 /* We could put this code under the !p->explainValid
1153 ** condition so that it does not execute if we are already in
1154 ** explain mode. However, always executing it allows us an easy
1155 ** was to reset to explain mode in case the user previously
1156 ** did an .explain followed by a .width, .mode or .header
1157 ** command.
1158 */
danielk19770d78bae2008-01-03 07:09:48 +00001159 p->mode = MODE_Explain;
persicom7e2dfdd2002-04-18 02:46:52 +00001160 p->showHeader = 1;
1161 memset(p->colWidth,0,ArraySize(p->colWidth));
danielk19770d78bae2008-01-03 07:09:48 +00001162 p->colWidth[0] = 4; /* addr */
drh60a713c2008-01-21 16:22:45 +00001163 p->colWidth[1] = 13; /* opcode */
1164 p->colWidth[2] = 4; /* P1 */
1165 p->colWidth[3] = 4; /* P2 */
1166 p->colWidth[4] = 4; /* P3 */
1167 p->colWidth[5] = 13; /* P4 */
danielk19770d78bae2008-01-03 07:09:48 +00001168 p->colWidth[6] = 2; /* P5 */
drh60a713c2008-01-21 16:22:45 +00001169 p->colWidth[7] = 13; /* Comment */
persicom7e2dfdd2002-04-18 02:46:52 +00001170 }else if (p->explainPrev.valid) {
1171 p->explainPrev.valid = 0;
1172 p->mode = p->explainPrev.mode;
1173 p->showHeader = p->explainPrev.showHeader;
1174 memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
1175 }
drh75897232000-05-29 14:26:00 +00001176 }else
1177
drhc28490c2006-10-26 14:25:58 +00001178 if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
persicom7e2dfdd2002-04-18 02:46:52 +00001179 strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
drhc28490c2006-10-26 14:25:58 +00001180 p->showHeader = booleanValue(azArg[1]);
drh75897232000-05-29 14:26:00 +00001181 }else
1182
1183 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
1184 fprintf(stderr,zHelp);
1185 }else
1186
drhfeac5f82004-08-01 00:10:45 +00001187 if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg>=3 ){
1188 char *zTable = azArg[2]; /* Insert data into this table */
1189 char *zFile = azArg[1]; /* The file from which to extract data */
1190 sqlite3_stmt *pStmt; /* A statement */
1191 int rc; /* Result code */
1192 int nCol; /* Number of columns in the table */
1193 int nByte; /* Number of bytes in an SQL string */
1194 int i, j; /* Loop counters */
1195 int nSep; /* Number of bytes in p->separator[] */
1196 char *zSql; /* An SQL statement */
1197 char *zLine; /* A single line of input from the file */
1198 char **azCol; /* zLine[] broken up into columns */
1199 char *zCommit; /* How to commit changes */
drhb860bc92004-08-04 15:16:55 +00001200 FILE *in; /* The input file */
1201 int lineno = 0; /* Line number of input file */
drhfeac5f82004-08-01 00:10:45 +00001202
drha543c822006-06-08 16:10:14 +00001203 open_db(p);
drhfeac5f82004-08-01 00:10:45 +00001204 nSep = strlen(p->separator);
1205 if( nSep==0 ){
1206 fprintf(stderr, "non-null separator required for import\n");
1207 return 0;
1208 }
1209 zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
1210 if( zSql==0 ) return 0;
1211 nByte = strlen(zSql);
drh5e6078b2006-01-31 19:07:22 +00001212 rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
drhfeac5f82004-08-01 00:10:45 +00001213 sqlite3_free(zSql);
1214 if( rc ){
1215 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
1216 nCol = 0;
drh47ad6842006-11-08 12:25:42 +00001217 rc = 1;
drhfeac5f82004-08-01 00:10:45 +00001218 }else{
1219 nCol = sqlite3_column_count(pStmt);
1220 }
1221 sqlite3_finalize(pStmt);
1222 if( nCol==0 ) return 0;
1223 zSql = malloc( nByte + 20 + nCol*2 );
1224 if( zSql==0 ) return 0;
1225 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable);
1226 j = strlen(zSql);
1227 for(i=1; i<nCol; i++){
1228 zSql[j++] = ',';
1229 zSql[j++] = '?';
1230 }
1231 zSql[j++] = ')';
1232 zSql[j] = 0;
drh5e6078b2006-01-31 19:07:22 +00001233 rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
drhfeac5f82004-08-01 00:10:45 +00001234 free(zSql);
1235 if( rc ){
1236 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
1237 sqlite3_finalize(pStmt);
drh47ad6842006-11-08 12:25:42 +00001238 return 1;
drhfeac5f82004-08-01 00:10:45 +00001239 }
1240 in = fopen(zFile, "rb");
1241 if( in==0 ){
1242 fprintf(stderr, "cannot open file: %s\n", zFile);
1243 sqlite3_finalize(pStmt);
1244 return 0;
1245 }
1246 azCol = malloc( sizeof(azCol[0])*(nCol+1) );
drh43617e92006-03-06 20:55:46 +00001247 if( azCol==0 ){
1248 fclose(in);
1249 return 0;
1250 }
drhfeac5f82004-08-01 00:10:45 +00001251 sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
1252 zCommit = "COMMIT";
1253 while( (zLine = local_getline(0, in))!=0 ){
1254 char *z;
1255 i = 0;
drhb860bc92004-08-04 15:16:55 +00001256 lineno++;
drhfeac5f82004-08-01 00:10:45 +00001257 azCol[0] = zLine;
drh36d4e972004-10-06 14:39:06 +00001258 for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){
drhfeac5f82004-08-01 00:10:45 +00001259 if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
1260 *z = 0;
1261 i++;
drhb860bc92004-08-04 15:16:55 +00001262 if( i<nCol ){
1263 azCol[i] = &z[nSep];
1264 z += nSep-1;
1265 }
drhfeac5f82004-08-01 00:10:45 +00001266 }
1267 }
drh1cd7f832005-08-05 18:50:51 +00001268 *z = 0;
drhb860bc92004-08-04 15:16:55 +00001269 if( i+1!=nCol ){
1270 fprintf(stderr,"%s line %d: expected %d columns of data but found %d\n",
1271 zFile, lineno, nCol, i+1);
1272 zCommit = "ROLLBACK";
drh1822eee2008-12-04 12:26:00 +00001273 free(zLine);
drhb860bc92004-08-04 15:16:55 +00001274 break;
1275 }
drhfeac5f82004-08-01 00:10:45 +00001276 for(i=0; i<nCol; i++){
1277 sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
1278 }
1279 sqlite3_step(pStmt);
1280 rc = sqlite3_reset(pStmt);
1281 free(zLine);
1282 if( rc!=SQLITE_OK ){
1283 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
1284 zCommit = "ROLLBACK";
drh47ad6842006-11-08 12:25:42 +00001285 rc = 1;
drhfeac5f82004-08-01 00:10:45 +00001286 break;
1287 }
1288 }
1289 free(azCol);
1290 fclose(in);
1291 sqlite3_finalize(pStmt);
drhb860bc92004-08-04 15:16:55 +00001292 sqlite3_exec(p->db, zCommit, 0, 0, 0);
drhfeac5f82004-08-01 00:10:45 +00001293 }else
1294
drh75897232000-05-29 14:26:00 +00001295 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
1296 struct callback_data data;
1297 char *zErrMsg = 0;
drh44c2eb12003-04-30 11:38:26 +00001298 open_db(p);
drh75897232000-05-29 14:26:00 +00001299 memcpy(&data, p, sizeof(data));
1300 data.showHeader = 0;
1301 data.mode = MODE_List;
danielk1977bc6ada42004-06-30 08:20:16 +00001302 zShellStatic = azArg[1];
1303 sqlite3_exec(p->db,
drha18c5682000-10-08 22:20:57 +00001304 "SELECT name FROM sqlite_master "
danielk1977bc6ada42004-06-30 08:20:16 +00001305 "WHERE type='index' AND tbl_name LIKE shellstatic() "
drhe0bc4042002-06-25 01:09:11 +00001306 "UNION ALL "
1307 "SELECT name FROM sqlite_temp_master "
danielk1977bc6ada42004-06-30 08:20:16 +00001308 "WHERE type='index' AND tbl_name LIKE shellstatic() "
drhe0bc4042002-06-25 01:09:11 +00001309 "ORDER BY 1",
danielk1977bc6ada42004-06-30 08:20:16 +00001310 callback, &data, &zErrMsg
drha18c5682000-10-08 22:20:57 +00001311 );
danielk1977bc6ada42004-06-30 08:20:16 +00001312 zShellStatic = 0;
drh75897232000-05-29 14:26:00 +00001313 if( zErrMsg ){
1314 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00001315 sqlite3_free(zErrMsg);
drh75897232000-05-29 14:26:00 +00001316 }
1317 }else
1318
drhae5e4452007-05-03 17:18:36 +00001319#ifdef SQLITE_ENABLE_IOTRACE
drhb0603412007-02-28 04:47:26 +00001320 if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
mlcreech3a00f902008-03-04 17:45:01 +00001321 extern void (*sqlite3IoTrace)(const char*, ...);
drhb0603412007-02-28 04:47:26 +00001322 if( iotrace && iotrace!=stdout ) fclose(iotrace);
1323 iotrace = 0;
1324 if( nArg<2 ){
mlcreech3a00f902008-03-04 17:45:01 +00001325 sqlite3IoTrace = 0;
drhb0603412007-02-28 04:47:26 +00001326 }else if( strcmp(azArg[1], "-")==0 ){
mlcreech3a00f902008-03-04 17:45:01 +00001327 sqlite3IoTrace = iotracePrintf;
drhb0603412007-02-28 04:47:26 +00001328 iotrace = stdout;
1329 }else{
1330 iotrace = fopen(azArg[1], "w");
1331 if( iotrace==0 ){
1332 fprintf(stderr, "cannot open \"%s\"\n", azArg[1]);
mlcreech3a00f902008-03-04 17:45:01 +00001333 sqlite3IoTrace = 0;
drhb0603412007-02-28 04:47:26 +00001334 }else{
mlcreech3a00f902008-03-04 17:45:01 +00001335 sqlite3IoTrace = iotracePrintf;
drhb0603412007-02-28 04:47:26 +00001336 }
1337 }
1338 }else
drhae5e4452007-05-03 17:18:36 +00001339#endif
drhb0603412007-02-28 04:47:26 +00001340
drh70df4fe2006-06-13 15:12:21 +00001341#ifndef SQLITE_OMIT_LOAD_EXTENSION
drh1e397f82006-06-08 15:28:43 +00001342 if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
1343 const char *zFile, *zProc;
1344 char *zErrMsg = 0;
1345 int rc;
1346 zFile = azArg[1];
1347 zProc = nArg>=3 ? azArg[2] : 0;
1348 open_db(p);
1349 rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
1350 if( rc!=SQLITE_OK ){
1351 fprintf(stderr, "%s\n", zErrMsg);
1352 sqlite3_free(zErrMsg);
drh47ad6842006-11-08 12:25:42 +00001353 rc = 1;
drh1e397f82006-06-08 15:28:43 +00001354 }
1355 }else
drh70df4fe2006-06-13 15:12:21 +00001356#endif
drh1e397f82006-06-08 15:28:43 +00001357
drh28bd4bc2000-06-15 15:57:22 +00001358 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +00001359 int n2 = strlen(azArg[1]);
persicom7e2dfdd2002-04-18 02:46:52 +00001360 if( strncmp(azArg[1],"line",n2)==0
1361 ||
1362 strncmp(azArg[1],"lines",n2)==0 ){
drh75897232000-05-29 14:26:00 +00001363 p->mode = MODE_Line;
persicom7e2dfdd2002-04-18 02:46:52 +00001364 }else if( strncmp(azArg[1],"column",n2)==0
1365 ||
1366 strncmp(azArg[1],"columns",n2)==0 ){
drh75897232000-05-29 14:26:00 +00001367 p->mode = MODE_Column;
1368 }else if( strncmp(azArg[1],"list",n2)==0 ){
1369 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +00001370 }else if( strncmp(azArg[1],"html",n2)==0 ){
1371 p->mode = MODE_Html;
drhfeac5f82004-08-01 00:10:45 +00001372 }else if( strncmp(azArg[1],"tcl",n2)==0 ){
1373 p->mode = MODE_Tcl;
1374 }else if( strncmp(azArg[1],"csv",n2)==0 ){
drh8e64d1c2004-10-07 00:32:39 +00001375 p->mode = MODE_Csv;
drh5bb3eb92007-05-04 13:15:55 +00001376 sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
drhfeac5f82004-08-01 00:10:45 +00001377 }else if( strncmp(azArg[1],"tabs",n2)==0 ){
1378 p->mode = MODE_List;
drh5bb3eb92007-05-04 13:15:55 +00001379 sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
drh28bd4bc2000-06-15 15:57:22 +00001380 }else if( strncmp(azArg[1],"insert",n2)==0 ){
1381 p->mode = MODE_Insert;
1382 if( nArg>=3 ){
drh33048c02001-10-01 14:29:22 +00001383 set_table_name(p, azArg[2]);
drh28bd4bc2000-06-15 15:57:22 +00001384 }else{
drh33048c02001-10-01 14:29:22 +00001385 set_table_name(p, "table");
drh28bd4bc2000-06-15 15:57:22 +00001386 }
drhdaffd0e2001-04-11 14:28:42 +00001387 }else {
drhcf68ae92006-12-19 18:47:41 +00001388 fprintf(stderr,"mode should be one of: "
drhfeac5f82004-08-01 00:10:45 +00001389 "column csv html insert line list tabs tcl\n");
drh75897232000-05-29 14:26:00 +00001390 }
1391 }else
1392
persicom7e2dfdd2002-04-18 02:46:52 +00001393 if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
drh5bb3eb92007-05-04 13:15:55 +00001394 sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
1395 "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
persicom7e2dfdd2002-04-18 02:46:52 +00001396 }else
1397
drh75897232000-05-29 14:26:00 +00001398 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
1399 if( p->out!=stdout ){
1400 fclose(p->out);
1401 }
1402 if( strcmp(azArg[1],"stdout")==0 ){
1403 p->out = stdout;
drh5bb3eb92007-05-04 13:15:55 +00001404 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
drh75897232000-05-29 14:26:00 +00001405 }else{
drha1f9b5e2004-02-14 16:31:02 +00001406 p->out = fopen(azArg[1], "wb");
drh75897232000-05-29 14:26:00 +00001407 if( p->out==0 ){
1408 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
1409 p->out = stdout;
persicom7e2dfdd2002-04-18 02:46:52 +00001410 } else {
drh5bb3eb92007-05-04 13:15:55 +00001411 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
drh75897232000-05-29 14:26:00 +00001412 }
1413 }
1414 }else
1415
drhdd45df82002-04-18 12:39:03 +00001416 if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
persicom7e2dfdd2002-04-18 02:46:52 +00001417 if( nArg >= 2) {
1418 strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
1419 }
1420 if( nArg >= 3) {
1421 strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
1422 }
1423 }else
1424
1425 if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
drh47ad6842006-11-08 12:25:42 +00001426 rc = 2;
persicom7e2dfdd2002-04-18 02:46:52 +00001427 }else
1428
drhdaffd0e2001-04-11 14:28:42 +00001429 if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
drha1f9b5e2004-02-14 16:31:02 +00001430 FILE *alt = fopen(azArg[1], "rb");
drhdaffd0e2001-04-11 14:28:42 +00001431 if( alt==0 ){
1432 fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
1433 }else{
1434 process_input(p, alt);
1435 fclose(alt);
1436 }
1437 }else
1438
drh75897232000-05-29 14:26:00 +00001439 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
1440 struct callback_data data;
1441 char *zErrMsg = 0;
drh44c2eb12003-04-30 11:38:26 +00001442 open_db(p);
drh75897232000-05-29 14:26:00 +00001443 memcpy(&data, p, sizeof(data));
1444 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +00001445 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +00001446 if( nArg>1 ){
drhc8d74412004-08-31 23:41:26 +00001447 int i;
1448 for(i=0; azArg[1][i]; i++) azArg[1][i] = tolower(azArg[1][i]);
1449 if( strcmp(azArg[1],"sqlite_master")==0 ){
drha18c5682000-10-08 22:20:57 +00001450 char *new_argv[2], *new_colv[2];
1451 new_argv[0] = "CREATE TABLE sqlite_master (\n"
1452 " type text,\n"
1453 " name text,\n"
1454 " tbl_name text,\n"
drhadbca9c2001-09-27 15:11:53 +00001455 " rootpage integer,\n"
drha18c5682000-10-08 22:20:57 +00001456 " sql text\n"
1457 ")";
1458 new_argv[1] = 0;
1459 new_colv[0] = "sql";
1460 new_colv[1] = 0;
1461 callback(&data, 1, new_argv, new_colv);
drhc8d74412004-08-31 23:41:26 +00001462 }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
drhe0bc4042002-06-25 01:09:11 +00001463 char *new_argv[2], *new_colv[2];
1464 new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
1465 " type text,\n"
1466 " name text,\n"
1467 " tbl_name text,\n"
1468 " rootpage integer,\n"
1469 " sql text\n"
1470 ")";
1471 new_argv[1] = 0;
1472 new_colv[0] = "sql";
1473 new_colv[1] = 0;
1474 callback(&data, 1, new_argv, new_colv);
drha18c5682000-10-08 22:20:57 +00001475 }else{
danielk1977bc6ada42004-06-30 08:20:16 +00001476 zShellStatic = azArg[1];
1477 sqlite3_exec(p->db,
drhe0bc4042002-06-25 01:09:11 +00001478 "SELECT sql FROM "
1479 " (SELECT * FROM sqlite_master UNION ALL"
1480 " SELECT * FROM sqlite_temp_master) "
danielk1977bc6ada42004-06-30 08:20:16 +00001481 "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTNULL "
drhe0bc4042002-06-25 01:09:11 +00001482 "ORDER BY substr(type,2,1), name",
danielk1977bc6ada42004-06-30 08:20:16 +00001483 callback, &data, &zErrMsg);
1484 zShellStatic = 0;
drha18c5682000-10-08 22:20:57 +00001485 }
drh75897232000-05-29 14:26:00 +00001486 }else{
danielk19776f8a5032004-05-10 10:34:51 +00001487 sqlite3_exec(p->db,
drhe0bc4042002-06-25 01:09:11 +00001488 "SELECT sql FROM "
1489 " (SELECT * FROM sqlite_master UNION ALL"
1490 " SELECT * FROM sqlite_temp_master) "
drh0c356672005-09-10 22:40:53 +00001491 "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
drhe0bc4042002-06-25 01:09:11 +00001492 "ORDER BY substr(type,2,1), name",
drha18c5682000-10-08 22:20:57 +00001493 callback, &data, &zErrMsg
1494 );
drh75897232000-05-29 14:26:00 +00001495 }
drh75897232000-05-29 14:26:00 +00001496 if( zErrMsg ){
1497 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00001498 sqlite3_free(zErrMsg);
drh75897232000-05-29 14:26:00 +00001499 }
1500 }else
1501
1502 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
drh5bb3eb92007-05-04 13:15:55 +00001503 sqlite3_snprintf(sizeof(p->separator), p->separator,
1504 "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
drh75897232000-05-29 14:26:00 +00001505 }else
1506
persicom7e2dfdd2002-04-18 02:46:52 +00001507 if( c=='s' && strncmp(azArg[0], "show", n)==0){
1508 int i;
1509 fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
drh67505e72002-04-19 12:34:06 +00001510 fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
drhdd45df82002-04-18 12:39:03 +00001511 fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
persicom7e2dfdd2002-04-18 02:46:52 +00001512 fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
drhfeac5f82004-08-01 00:10:45 +00001513 fprintf(p->out,"%9.9s: ", "nullvalue");
1514 output_c_string(p->out, p->nullvalue);
1515 fprintf(p->out, "\n");
drh67505e72002-04-19 12:34:06 +00001516 fprintf(p->out,"%9.9s: %s\n","output",
1517 strlen(p->outfile) ? p->outfile : "stdout");
drhfeac5f82004-08-01 00:10:45 +00001518 fprintf(p->out,"%9.9s: ", "separator");
1519 output_c_string(p->out, p->separator);
1520 fprintf(p->out, "\n");
persicom7e2dfdd2002-04-18 02:46:52 +00001521 fprintf(p->out,"%9.9s: ","width");
1522 for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
drhfeac5f82004-08-01 00:10:45 +00001523 fprintf(p->out,"%d ",p->colWidth[i]);
persicom7e2dfdd2002-04-18 02:46:52 +00001524 }
drhfeac5f82004-08-01 00:10:45 +00001525 fprintf(p->out,"\n");
persicom7e2dfdd2002-04-18 02:46:52 +00001526 }else
1527
drh2dfbbca2000-07-28 14:32:48 +00001528 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +00001529 char **azResult;
1530 int nRow, rc;
1531 char *zErrMsg;
drh44c2eb12003-04-30 11:38:26 +00001532 open_db(p);
drha50da102000-08-08 20:19:09 +00001533 if( nArg==1 ){
danielk19776f8a5032004-05-10 10:34:51 +00001534 rc = sqlite3_get_table(p->db,
drha50da102000-08-08 20:19:09 +00001535 "SELECT name FROM sqlite_master "
drh0c356672005-09-10 22:40:53 +00001536 "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'"
drhe0bc4042002-06-25 01:09:11 +00001537 "UNION ALL "
1538 "SELECT name FROM sqlite_temp_master "
1539 "WHERE type IN ('table','view') "
1540 "ORDER BY 1",
drha18c5682000-10-08 22:20:57 +00001541 &azResult, &nRow, 0, &zErrMsg
1542 );
drha50da102000-08-08 20:19:09 +00001543 }else{
danielk1977bc6ada42004-06-30 08:20:16 +00001544 zShellStatic = azArg[1];
1545 rc = sqlite3_get_table(p->db,
drha50da102000-08-08 20:19:09 +00001546 "SELECT name FROM sqlite_master "
danielk1977bc6ada42004-06-30 08:20:16 +00001547 "WHERE type IN ('table','view') AND name LIKE '%'||shellstatic()||'%' "
drhe0bc4042002-06-25 01:09:11 +00001548 "UNION ALL "
1549 "SELECT name FROM sqlite_temp_master "
danielk1977bc6ada42004-06-30 08:20:16 +00001550 "WHERE type IN ('table','view') AND name LIKE '%'||shellstatic()||'%' "
drhe0bc4042002-06-25 01:09:11 +00001551 "ORDER BY 1",
danielk1977bc6ada42004-06-30 08:20:16 +00001552 &azResult, &nRow, 0, &zErrMsg
drha18c5682000-10-08 22:20:57 +00001553 );
danielk1977bc6ada42004-06-30 08:20:16 +00001554 zShellStatic = 0;
drha50da102000-08-08 20:19:09 +00001555 }
drh75897232000-05-29 14:26:00 +00001556 if( zErrMsg ){
1557 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00001558 sqlite3_free(zErrMsg);
drh75897232000-05-29 14:26:00 +00001559 }
drhe3710332000-09-29 13:30:53 +00001560 if( rc==SQLITE_OK ){
1561 int len, maxlen = 0;
1562 int i, j;
1563 int nPrintCol, nPrintRow;
1564 for(i=1; i<=nRow; i++){
1565 if( azResult[i]==0 ) continue;
1566 len = strlen(azResult[i]);
1567 if( len>maxlen ) maxlen = len;
1568 }
1569 nPrintCol = 80/(maxlen+2);
1570 if( nPrintCol<1 ) nPrintCol = 1;
1571 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
1572 for(i=0; i<nPrintRow; i++){
1573 for(j=i+1; j<=nRow; j+=nPrintRow){
1574 char *zSp = j<=nPrintRow ? "" : " ";
1575 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
1576 }
1577 printf("\n");
1578 }
drh47ad6842006-11-08 12:25:42 +00001579 }else{
1580 rc = 1;
drhe3710332000-09-29 13:30:53 +00001581 }
danielk19776f8a5032004-05-10 10:34:51 +00001582 sqlite3_free_table(azResult);
drh75897232000-05-29 14:26:00 +00001583 }else
1584
drh3b1a9882007-11-02 12:53:03 +00001585 if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
drh44c2eb12003-04-30 11:38:26 +00001586 open_db(p);
danielk19776f8a5032004-05-10 10:34:51 +00001587 sqlite3_busy_timeout(p->db, atoi(azArg[1]));
drh2dfbbca2000-07-28 14:32:48 +00001588 }else
drh3b1a9882007-11-02 12:53:03 +00001589
1590#if HAS_TIMER
1591 if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg>1 ){
1592 enableTimer = booleanValue(azArg[1]);
1593 }else
1594#endif
drh2dfbbca2000-07-28 14:32:48 +00001595
drh75897232000-05-29 14:26:00 +00001596 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
1597 int j;
drh43617e92006-03-06 20:55:46 +00001598 assert( nArg<=ArraySize(azArg) );
drh75897232000-05-29 14:26:00 +00001599 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
1600 p->colWidth[j-1] = atoi(azArg[j]);
1601 }
1602 }else
1603
drh3b1a9882007-11-02 12:53:03 +00001604
drh75897232000-05-29 14:26:00 +00001605 {
drh67505e72002-04-19 12:34:06 +00001606 fprintf(stderr, "unknown command or invalid arguments: "
1607 " \"%s\". Enter \".help\" for help\n", azArg[0]);
drh75897232000-05-29 14:26:00 +00001608 }
drh67505e72002-04-19 12:34:06 +00001609
1610 return rc;
drh75897232000-05-29 14:26:00 +00001611}
1612
drh67505e72002-04-19 12:34:06 +00001613/*
drh91a66392007-09-07 01:12:32 +00001614** Return TRUE if a semicolon occurs anywhere in the first N characters
1615** of string z[].
drh324ccef2003-02-05 14:06:20 +00001616*/
drh91a66392007-09-07 01:12:32 +00001617static int _contains_semicolon(const char *z, int N){
1618 int i;
1619 for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
1620 return 0;
drh324ccef2003-02-05 14:06:20 +00001621}
1622
1623/*
drh70c7a4b2003-04-26 03:03:06 +00001624** Test to see if a line consists entirely of whitespace.
1625*/
1626static int _all_whitespace(const char *z){
1627 for(; *z; z++){
drh4c755c02004-08-08 20:22:17 +00001628 if( isspace(*(unsigned char*)z) ) continue;
drh70c7a4b2003-04-26 03:03:06 +00001629 if( *z=='/' && z[1]=='*' ){
1630 z += 2;
1631 while( *z && (*z!='*' || z[1]!='/') ){ z++; }
1632 if( *z==0 ) return 0;
1633 z++;
1634 continue;
1635 }
1636 if( *z=='-' && z[1]=='-' ){
1637 z += 2;
1638 while( *z && *z!='\n' ){ z++; }
1639 if( *z==0 ) return 1;
1640 continue;
1641 }
1642 return 0;
1643 }
1644 return 1;
1645}
1646
1647/*
drha9b17162003-04-29 18:01:28 +00001648** Return TRUE if the line typed in is an SQL command terminator other
1649** than a semi-colon. The SQL Server style "go" command is understood
1650** as is the Oracle "/".
1651*/
1652static int _is_command_terminator(const char *zLine){
drh4c755c02004-08-08 20:22:17 +00001653 while( isspace(*(unsigned char*)zLine) ){ zLine++; };
drha9b17162003-04-29 18:01:28 +00001654 if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ) return 1; /* Oracle */
drhc8d74412004-08-31 23:41:26 +00001655 if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o'
1656 && _all_whitespace(&zLine[2]) ){
drha9b17162003-04-29 18:01:28 +00001657 return 1; /* SQL Server */
1658 }
1659 return 0;
1660}
1661
1662/*
drh67505e72002-04-19 12:34:06 +00001663** Read input from *in and process it. If *in==0 then input
1664** is interactive - the user is typing it it. Otherwise, input
1665** is coming from a file or device. A prompt is issued and history
1666** is saved only if input is interactive. An interrupt signal will
1667** cause this routine to exit immediately, unless input is interactive.
drhc28490c2006-10-26 14:25:58 +00001668**
1669** Return the number of errors.
drh67505e72002-04-19 12:34:06 +00001670*/
drhc28490c2006-10-26 14:25:58 +00001671static int process_input(struct callback_data *p, FILE *in){
danielk19772ac27622007-07-03 05:31:16 +00001672 char *zLine = 0;
drhdaffd0e2001-04-11 14:28:42 +00001673 char *zSql = 0;
1674 int nSql = 0;
drh91a66392007-09-07 01:12:32 +00001675 int nSqlPrior = 0;
drhdaffd0e2001-04-11 14:28:42 +00001676 char *zErrMsg;
drhc49f44e2006-10-26 18:15:42 +00001677 int rc;
1678 int errCnt = 0;
drhc28490c2006-10-26 14:25:58 +00001679 int lineno = 0;
1680 int startline = 0;
drhc49f44e2006-10-26 18:15:42 +00001681
1682 while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
1683 fflush(p->out);
danielk19772ac27622007-07-03 05:31:16 +00001684 free(zLine);
drhc49f44e2006-10-26 18:15:42 +00001685 zLine = one_input_line(zSql, in);
1686 if( zLine==0 ){
1687 break; /* We have reached EOF */
1688 }
drh67505e72002-04-19 12:34:06 +00001689 if( seenInterrupt ){
1690 if( in!=0 ) break;
1691 seenInterrupt = 0;
1692 }
drhc28490c2006-10-26 14:25:58 +00001693 lineno++;
drhdaffd0e2001-04-11 14:28:42 +00001694 if( p->echoOn ) printf("%s\n", zLine);
drhf817b6b2003-06-16 00:16:41 +00001695 if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
drh2af0b2d2002-02-21 02:25:02 +00001696 if( zLine && zLine[0]=='.' && nSql==0 ){
drhc49f44e2006-10-26 18:15:42 +00001697 rc = do_meta_command(zLine, p);
drh47ad6842006-11-08 12:25:42 +00001698 if( rc==2 ){
1699 break;
1700 }else if( rc ){
drhc49f44e2006-10-26 18:15:42 +00001701 errCnt++;
1702 }
drhdaffd0e2001-04-11 14:28:42 +00001703 continue;
1704 }
drhc717b382008-11-11 00:30:11 +00001705 if( _is_command_terminator(zLine) && sqlite3_complete(zSql) ){
drh5bb3eb92007-05-04 13:15:55 +00001706 memcpy(zLine,";",2);
drha9b17162003-04-29 18:01:28 +00001707 }
drh91a66392007-09-07 01:12:32 +00001708 nSqlPrior = nSql;
drhdaffd0e2001-04-11 14:28:42 +00001709 if( zSql==0 ){
1710 int i;
drh4c755c02004-08-08 20:22:17 +00001711 for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){}
drhdaffd0e2001-04-11 14:28:42 +00001712 if( zLine[i]!=0 ){
1713 nSql = strlen(zLine);
1714 zSql = malloc( nSql+1 );
drhc1f44942006-05-10 14:39:13 +00001715 if( zSql==0 ){
1716 fprintf(stderr, "out of memory\n");
1717 exit(1);
1718 }
drh5bb3eb92007-05-04 13:15:55 +00001719 memcpy(zSql, zLine, nSql+1);
drhc28490c2006-10-26 14:25:58 +00001720 startline = lineno;
drhdaffd0e2001-04-11 14:28:42 +00001721 }
1722 }else{
1723 int len = strlen(zLine);
1724 zSql = realloc( zSql, nSql + len + 2 );
1725 if( zSql==0 ){
1726 fprintf(stderr,"%s: out of memory!\n", Argv0);
1727 exit(1);
1728 }
drh5bb3eb92007-05-04 13:15:55 +00001729 zSql[nSql++] = '\n';
1730 memcpy(&zSql[nSql], zLine, len+1);
drhdaffd0e2001-04-11 14:28:42 +00001731 nSql += len;
1732 }
drh91a66392007-09-07 01:12:32 +00001733 if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
1734 && sqlite3_complete(zSql) ){
drhdaffd0e2001-04-11 14:28:42 +00001735 p->cnt = 0;
drh44c2eb12003-04-30 11:38:26 +00001736 open_db(p);
drh3b1a9882007-11-02 12:53:03 +00001737 BEGIN_TIMER;
danielk19776f8a5032004-05-10 10:34:51 +00001738 rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
drh3b1a9882007-11-02 12:53:03 +00001739 END_TIMER;
drh7f953e22002-07-13 17:33:45 +00001740 if( rc || zErrMsg ){
drhc28490c2006-10-26 14:25:58 +00001741 char zPrefix[100];
1742 if( in!=0 || !stdin_is_interactive ){
drh5bb3eb92007-05-04 13:15:55 +00001743 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
1744 "SQL error near line %d:", startline);
drhc28490c2006-10-26 14:25:58 +00001745 }else{
drh5bb3eb92007-05-04 13:15:55 +00001746 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "SQL error:");
drhc28490c2006-10-26 14:25:58 +00001747 }
drh7f953e22002-07-13 17:33:45 +00001748 if( zErrMsg!=0 ){
drhc28490c2006-10-26 14:25:58 +00001749 printf("%s %s\n", zPrefix, zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00001750 sqlite3_free(zErrMsg);
drh7f953e22002-07-13 17:33:45 +00001751 zErrMsg = 0;
1752 }else{
drhc28490c2006-10-26 14:25:58 +00001753 printf("%s %s\n", zPrefix, sqlite3_errmsg(p->db));
drh7f953e22002-07-13 17:33:45 +00001754 }
drhc49f44e2006-10-26 18:15:42 +00001755 errCnt++;
drhdaffd0e2001-04-11 14:28:42 +00001756 }
1757 free(zSql);
1758 zSql = 0;
1759 nSql = 0;
1760 }
1761 }
1762 if( zSql ){
drhdfef4992008-11-11 18:55:03 +00001763 if( !_all_whitespace(zSql) ) fprintf(stderr, "Incomplete SQL: %s\n", zSql);
drhdaffd0e2001-04-11 14:28:42 +00001764 free(zSql);
1765 }
danielk19772ac27622007-07-03 05:31:16 +00001766 free(zLine);
drhc49f44e2006-10-26 18:15:42 +00001767 return errCnt;
drhdaffd0e2001-04-11 14:28:42 +00001768}
1769
drh67505e72002-04-19 12:34:06 +00001770/*
1771** Return a pathname which is the user's home directory. A
1772** 0 return indicates an error of some kind. Space to hold the
1773** resulting string is obtained from malloc(). The calling
1774** function should free the result.
1775*/
1776static char *find_home_dir(void){
1777 char *home_dir = NULL;
persicom7e2dfdd2002-04-18 02:46:52 +00001778
chw97185482008-11-17 08:05:31 +00001779#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
drh67505e72002-04-19 12:34:06 +00001780 struct passwd *pwent;
1781 uid_t uid = getuid();
drhbd842ba2002-08-21 11:26:41 +00001782 if( (pwent=getpwuid(uid)) != NULL) {
1783 home_dir = pwent->pw_dir;
drh67505e72002-04-19 12:34:06 +00001784 }
1785#endif
1786
chw65d3c132007-11-12 21:09:10 +00001787#if defined(_WIN32_WCE)
1788 /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
1789 */
1790 home_dir = strdup("/");
1791#else
1792
drh164a1b62006-08-19 11:15:20 +00001793#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
1794 if (!home_dir) {
1795 home_dir = getenv("USERPROFILE");
1796 }
1797#endif
1798
drh67505e72002-04-19 12:34:06 +00001799 if (!home_dir) {
1800 home_dir = getenv("HOME");
drh67505e72002-04-19 12:34:06 +00001801 }
1802
drhcdb36b72006-06-12 12:57:45 +00001803#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
drhe98d4fa2002-04-21 19:06:22 +00001804 if (!home_dir) {
drh164a1b62006-08-19 11:15:20 +00001805 char *zDrive, *zPath;
1806 int n;
1807 zDrive = getenv("HOMEDRIVE");
1808 zPath = getenv("HOMEPATH");
1809 if( zDrive && zPath ){
1810 n = strlen(zDrive) + strlen(zPath) + 1;
1811 home_dir = malloc( n );
1812 if( home_dir==0 ) return 0;
1813 sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
1814 return home_dir;
1815 }
1816 home_dir = "c:\\";
drhe98d4fa2002-04-21 19:06:22 +00001817 }
1818#endif
1819
chw65d3c132007-11-12 21:09:10 +00001820#endif /* !_WIN32_WCE */
1821
drh67505e72002-04-19 12:34:06 +00001822 if( home_dir ){
drh5bb3eb92007-05-04 13:15:55 +00001823 int n = strlen(home_dir) + 1;
1824 char *z = malloc( n );
1825 if( z ) memcpy(z, home_dir, n);
drh67505e72002-04-19 12:34:06 +00001826 home_dir = z;
1827 }
drhe98d4fa2002-04-21 19:06:22 +00001828
drh67505e72002-04-19 12:34:06 +00001829 return home_dir;
1830}
1831
1832/*
1833** Read input from the file given by sqliterc_override. Or if that
1834** parameter is NULL, take input from ~/.sqliterc
1835*/
drh22fbcb82004-02-01 01:22:50 +00001836static void process_sqliterc(
1837 struct callback_data *p, /* Configuration data */
1838 const char *sqliterc_override /* Name of config file. NULL to use default */
1839){
persicom7e2dfdd2002-04-18 02:46:52 +00001840 char *home_dir = NULL;
drh22fbcb82004-02-01 01:22:50 +00001841 const char *sqliterc = sqliterc_override;
drh43617e92006-03-06 20:55:46 +00001842 char *zBuf = 0;
persicom7e2dfdd2002-04-18 02:46:52 +00001843 FILE *in = NULL;
drha959ac42007-06-20 13:10:00 +00001844 int nBuf;
persicom7e2dfdd2002-04-18 02:46:52 +00001845
1846 if (sqliterc == NULL) {
drh67505e72002-04-19 12:34:06 +00001847 home_dir = find_home_dir();
drhe98d4fa2002-04-21 19:06:22 +00001848 if( home_dir==0 ){
chw97185482008-11-17 08:05:31 +00001849#if !defined(__RTP__) && !defined(_WRS_KERNEL)
drhe98d4fa2002-04-21 19:06:22 +00001850 fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
chw97185482008-11-17 08:05:31 +00001851#endif
drhe98d4fa2002-04-21 19:06:22 +00001852 return;
1853 }
drha959ac42007-06-20 13:10:00 +00001854 nBuf = strlen(home_dir) + 16;
1855 zBuf = malloc( nBuf );
drh22fbcb82004-02-01 01:22:50 +00001856 if( zBuf==0 ){
persicom7e2dfdd2002-04-18 02:46:52 +00001857 fprintf(stderr,"%s: out of memory!\n", Argv0);
1858 exit(1);
1859 }
drha959ac42007-06-20 13:10:00 +00001860 sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir);
drh67505e72002-04-19 12:34:06 +00001861 free(home_dir);
drh22fbcb82004-02-01 01:22:50 +00001862 sqliterc = (const char*)zBuf;
persicom7e2dfdd2002-04-18 02:46:52 +00001863 }
drha1f9b5e2004-02-14 16:31:02 +00001864 in = fopen(sqliterc,"rb");
drh22fbcb82004-02-01 01:22:50 +00001865 if( in ){
drhc28490c2006-10-26 14:25:58 +00001866 if( stdin_is_interactive ){
drhb695aca2007-07-30 20:41:52 +00001867 printf("-- Loading resources from %s\n",sqliterc);
drh22fbcb82004-02-01 01:22:50 +00001868 }
persicom7e2dfdd2002-04-18 02:46:52 +00001869 process_input(p,in);
drhdd45df82002-04-18 12:39:03 +00001870 fclose(in);
persicom7e2dfdd2002-04-18 02:46:52 +00001871 }
drh43617e92006-03-06 20:55:46 +00001872 free(zBuf);
persicom7e2dfdd2002-04-18 02:46:52 +00001873 return;
1874}
1875
drh67505e72002-04-19 12:34:06 +00001876/*
drhe1e38c42003-05-04 18:30:59 +00001877** Show available command line options
1878*/
1879static const char zOptions[] =
1880 " -init filename read/process named file\n"
1881 " -echo print commands before execution\n"
1882 " -[no]header turn headers on or off\n"
drhc49f44e2006-10-26 18:15:42 +00001883 " -bail stop after hitting an error\n"
1884 " -interactive force interactive I/O\n"
1885 " -batch force batch I/O\n"
drhe1e38c42003-05-04 18:30:59 +00001886 " -column set output mode to 'column'\n"
drhc49f44e2006-10-26 18:15:42 +00001887 " -csv set output mode to 'csv'\n"
drhe1e38c42003-05-04 18:30:59 +00001888 " -html set output mode to HTML\n"
1889 " -line set output mode to 'line'\n"
1890 " -list set output mode to 'list'\n"
1891 " -separator 'x' set output field separator (|)\n"
1892 " -nullvalue 'text' set text string for NULL values\n"
1893 " -version show SQLite version\n"
drhe1e38c42003-05-04 18:30:59 +00001894;
1895static void usage(int showDetail){
drh80e8be92006-08-29 12:04:19 +00001896 fprintf(stderr,
1897 "Usage: %s [OPTIONS] FILENAME [SQL]\n"
1898 "FILENAME is the name of an SQLite database. A new database is created\n"
1899 "if the file does not previously exist.\n", Argv0);
drhe1e38c42003-05-04 18:30:59 +00001900 if( showDetail ){
drh80e8be92006-08-29 12:04:19 +00001901 fprintf(stderr, "OPTIONS include:\n%s", zOptions);
drhe1e38c42003-05-04 18:30:59 +00001902 }else{
1903 fprintf(stderr, "Use the -help option for additional information\n");
1904 }
1905 exit(1);
1906}
1907
1908/*
drh67505e72002-04-19 12:34:06 +00001909** Initialize the state information in data
1910*/
drh0850b532006-01-31 19:31:43 +00001911static void main_init(struct callback_data *data) {
persicom7e2dfdd2002-04-18 02:46:52 +00001912 memset(data, 0, sizeof(*data));
1913 data->mode = MODE_List;
drh5bb3eb92007-05-04 13:15:55 +00001914 memcpy(data->separator,"|", 2);
persicom7e2dfdd2002-04-18 02:46:52 +00001915 data->showHeader = 0;
drh5bb3eb92007-05-04 13:15:55 +00001916 sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
1917 sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
persicom7e2dfdd2002-04-18 02:46:52 +00001918}
1919
drh75897232000-05-29 14:26:00 +00001920int main(int argc, char **argv){
drh75897232000-05-29 14:26:00 +00001921 char *zErrMsg = 0;
1922 struct callback_data data;
drh22fbcb82004-02-01 01:22:50 +00001923 const char *zInitFile = 0;
1924 char *zFirstCmd = 0;
drh44c2eb12003-04-30 11:38:26 +00001925 int i;
drhc28490c2006-10-26 14:25:58 +00001926 int rc = 0;
drh75897232000-05-29 14:26:00 +00001927
drhdaffd0e2001-04-11 14:28:42 +00001928 Argv0 = argv[0];
persicom7e2dfdd2002-04-18 02:46:52 +00001929 main_init(&data);
drhc28490c2006-10-26 14:25:58 +00001930 stdin_is_interactive = isatty(0);
persicom7e2dfdd2002-04-18 02:46:52 +00001931
drh44c2eb12003-04-30 11:38:26 +00001932 /* Make sure we have a valid signal handler early, before anything
1933 ** else is done.
1934 */
drh4c504392000-10-16 22:06:40 +00001935#ifdef SIGINT
1936 signal(SIGINT, interrupt_handler);
1937#endif
drh44c2eb12003-04-30 11:38:26 +00001938
drh22fbcb82004-02-01 01:22:50 +00001939 /* Do an initial pass through the command-line argument to locate
1940 ** the name of the database file, the name of the initialization file,
1941 ** and the first command to execute.
drh44c2eb12003-04-30 11:38:26 +00001942 */
drh22fbcb82004-02-01 01:22:50 +00001943 for(i=1; i<argc-1; i++){
drhc28490c2006-10-26 14:25:58 +00001944 char *z;
drh44c2eb12003-04-30 11:38:26 +00001945 if( argv[i][0]!='-' ) break;
drhc28490c2006-10-26 14:25:58 +00001946 z = argv[i];
1947 if( z[0]=='-' && z[1]=='-' ) z++;
drh44c2eb12003-04-30 11:38:26 +00001948 if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
1949 i++;
drh22fbcb82004-02-01 01:22:50 +00001950 }else if( strcmp(argv[i],"-init")==0 ){
1951 i++;
1952 zInitFile = argv[i];
drh44c2eb12003-04-30 11:38:26 +00001953 }
1954 }
drh22fbcb82004-02-01 01:22:50 +00001955 if( i<argc ){
danielk197729bafea2008-06-26 10:41:19 +00001956#if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2
pweilbacherd190be82008-04-15 18:50:02 +00001957 data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] );
1958#else
drh22fbcb82004-02-01 01:22:50 +00001959 data.zDbFilename = argv[i++];
pweilbacherd190be82008-04-15 18:50:02 +00001960#endif
drh22fbcb82004-02-01 01:22:50 +00001961 }else{
danielk197703aded42004-11-22 05:26:27 +00001962#ifndef SQLITE_OMIT_MEMORYDB
drh22fbcb82004-02-01 01:22:50 +00001963 data.zDbFilename = ":memory:";
danielk197703aded42004-11-22 05:26:27 +00001964#else
1965 data.zDbFilename = 0;
1966#endif
drh22fbcb82004-02-01 01:22:50 +00001967 }
1968 if( i<argc ){
1969 zFirstCmd = argv[i++];
1970 }
drh44c2eb12003-04-30 11:38:26 +00001971 data.out = stdout;
1972
drh01b41712005-08-29 23:06:23 +00001973#ifdef SQLITE_OMIT_MEMORYDB
1974 if( data.zDbFilename==0 ){
1975 fprintf(stderr,"%s: no database filename specified\n", argv[0]);
1976 exit(1);
1977 }
1978#endif
1979
drh44c2eb12003-04-30 11:38:26 +00001980 /* Go ahead and open the database file if it already exists. If the
1981 ** file does not exist, delay opening it. This prevents empty database
1982 ** files from being created if a user mistypes the database name argument
1983 ** to the sqlite command-line tool.
1984 */
drhc8d74412004-08-31 23:41:26 +00001985 if( access(data.zDbFilename, 0)==0 ){
drh44c2eb12003-04-30 11:38:26 +00001986 open_db(&data);
1987 }
1988
drh22fbcb82004-02-01 01:22:50 +00001989 /* Process the initialization file if there is one. If no -init option
1990 ** is given on the command line, look for a file named ~/.sqliterc and
1991 ** try to process it.
drh44c2eb12003-04-30 11:38:26 +00001992 */
drh22fbcb82004-02-01 01:22:50 +00001993 process_sqliterc(&data,zInitFile);
drh44c2eb12003-04-30 11:38:26 +00001994
drh22fbcb82004-02-01 01:22:50 +00001995 /* Make a second pass through the command-line argument and set
1996 ** options. This second pass is delayed until after the initialization
1997 ** file is processed so that the command-line arguments will override
1998 ** settings in the initialization file.
drh44c2eb12003-04-30 11:38:26 +00001999 */
drh22fbcb82004-02-01 01:22:50 +00002000 for(i=1; i<argc && argv[i][0]=='-'; i++){
2001 char *z = argv[i];
drhc28490c2006-10-26 14:25:58 +00002002 if( z[1]=='-' ){ z++; }
drh2e584cd2006-09-25 13:09:22 +00002003 if( strcmp(z,"-init")==0 ){
drh22fbcb82004-02-01 01:22:50 +00002004 i++;
2005 }else if( strcmp(z,"-html")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00002006 data.mode = MODE_Html;
drh22fbcb82004-02-01 01:22:50 +00002007 }else if( strcmp(z,"-list")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00002008 data.mode = MODE_List;
drh22fbcb82004-02-01 01:22:50 +00002009 }else if( strcmp(z,"-line")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00002010 data.mode = MODE_Line;
drh22fbcb82004-02-01 01:22:50 +00002011 }else if( strcmp(z,"-column")==0 ){
drh8b32e172002-04-08 02:42:57 +00002012 data.mode = MODE_Column;
drhc49f44e2006-10-26 18:15:42 +00002013 }else if( strcmp(z,"-csv")==0 ){
2014 data.mode = MODE_Csv;
drh5bb3eb92007-05-04 13:15:55 +00002015 memcpy(data.separator,",",2);
drh22fbcb82004-02-01 01:22:50 +00002016 }else if( strcmp(z,"-separator")==0 ){
2017 i++;
drh5bb3eb92007-05-04 13:15:55 +00002018 sqlite3_snprintf(sizeof(data.separator), data.separator,
2019 "%.*s",(int)sizeof(data.separator)-1,argv[i]);
drh22fbcb82004-02-01 01:22:50 +00002020 }else if( strcmp(z,"-nullvalue")==0 ){
2021 i++;
drh5bb3eb92007-05-04 13:15:55 +00002022 sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
2023 "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
drh22fbcb82004-02-01 01:22:50 +00002024 }else if( strcmp(z,"-header")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00002025 data.showHeader = 1;
drh22fbcb82004-02-01 01:22:50 +00002026 }else if( strcmp(z,"-noheader")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00002027 data.showHeader = 0;
drh22fbcb82004-02-01 01:22:50 +00002028 }else if( strcmp(z,"-echo")==0 ){
drhdaffd0e2001-04-11 14:28:42 +00002029 data.echoOn = 1;
drhc49f44e2006-10-26 18:15:42 +00002030 }else if( strcmp(z,"-bail")==0 ){
2031 bail_on_error = 1;
drh22fbcb82004-02-01 01:22:50 +00002032 }else if( strcmp(z,"-version")==0 ){
drhc8d74412004-08-31 23:41:26 +00002033 printf("%s\n", sqlite3_libversion());
drh151e3e12006-06-06 12:32:21 +00002034 return 0;
drhc28490c2006-10-26 14:25:58 +00002035 }else if( strcmp(z,"-interactive")==0 ){
2036 stdin_is_interactive = 1;
2037 }else if( strcmp(z,"-batch")==0 ){
2038 stdin_is_interactive = 0;
drh80e8be92006-08-29 12:04:19 +00002039 }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
drhe1e38c42003-05-04 18:30:59 +00002040 usage(1);
drh1e5d0e92000-05-31 23:33:17 +00002041 }else{
drh22fbcb82004-02-01 01:22:50 +00002042 fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
drhe1e38c42003-05-04 18:30:59 +00002043 fprintf(stderr,"Use -help for a list of options.\n");
drh1e5d0e92000-05-31 23:33:17 +00002044 return 1;
2045 }
2046 }
drh44c2eb12003-04-30 11:38:26 +00002047
drh22fbcb82004-02-01 01:22:50 +00002048 if( zFirstCmd ){
drh44c2eb12003-04-30 11:38:26 +00002049 /* Run just the command that follows the database name
2050 */
drh22fbcb82004-02-01 01:22:50 +00002051 if( zFirstCmd[0]=='.' ){
2052 do_meta_command(zFirstCmd, &data);
drh6ff13852001-11-25 13:18:23 +00002053 exit(0);
2054 }else{
2055 int rc;
drh44c2eb12003-04-30 11:38:26 +00002056 open_db(&data);
danielk19776f8a5032004-05-10 10:34:51 +00002057 rc = sqlite3_exec(data.db, zFirstCmd, callback, &data, &zErrMsg);
drh6ff13852001-11-25 13:18:23 +00002058 if( rc!=0 && zErrMsg!=0 ){
2059 fprintf(stderr,"SQL error: %s\n", zErrMsg);
2060 exit(1);
2061 }
drh75897232000-05-29 14:26:00 +00002062 }
2063 }else{
drh44c2eb12003-04-30 11:38:26 +00002064 /* Run commands received from standard input
2065 */
drhc28490c2006-10-26 14:25:58 +00002066 if( stdin_is_interactive ){
drh67505e72002-04-19 12:34:06 +00002067 char *zHome;
2068 char *zHistory = 0;
drh5bb3eb92007-05-04 13:15:55 +00002069 int nHistory;
drh75897232000-05-29 14:26:00 +00002070 printf(
drhb217a572000-08-22 13:40:18 +00002071 "SQLite version %s\n"
mihailim65df9db2008-06-28 11:29:22 +00002072 "Enter \".help\" for instructions\n"
2073 "Enter SQL statements terminated with a \";\"\n",
drhc8d74412004-08-31 23:41:26 +00002074 sqlite3_libversion()
drh75897232000-05-29 14:26:00 +00002075 );
drh67505e72002-04-19 12:34:06 +00002076 zHome = find_home_dir();
drh5bb3eb92007-05-04 13:15:55 +00002077 if( zHome && (zHistory = malloc(nHistory = strlen(zHome)+20))!=0 ){
2078 sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
drh67505e72002-04-19 12:34:06 +00002079 }
danielk19774af00c62005-01-23 23:43:21 +00002080#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh67505e72002-04-19 12:34:06 +00002081 if( zHistory ) read_history(zHistory);
danielk19774af00c62005-01-23 23:43:21 +00002082#endif
drhc28490c2006-10-26 14:25:58 +00002083 rc = process_input(&data, 0);
drh67505e72002-04-19 12:34:06 +00002084 if( zHistory ){
2085 stifle_history(100);
2086 write_history(zHistory);
adamd0a3daa32006-07-28 20:16:14 +00002087 free(zHistory);
drh67505e72002-04-19 12:34:06 +00002088 }
adamd0a3daa32006-07-28 20:16:14 +00002089 free(zHome);
drhdaffd0e2001-04-11 14:28:42 +00002090 }else{
drhc28490c2006-10-26 14:25:58 +00002091 rc = process_input(&data, stdin);
drh75897232000-05-29 14:26:00 +00002092 }
2093 }
drh33048c02001-10-01 14:29:22 +00002094 set_table_name(&data, 0);
adamd0a3daa32006-07-28 20:16:14 +00002095 if( db ){
2096 if( sqlite3_close(db)!=SQLITE_OK ){
2097 fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
2098 }
2099 }
drhc28490c2006-10-26 14:25:58 +00002100 return rc;
drh75897232000-05-29 14:26:00 +00002101}