1434
|
1 /*
|
|
2 ** 2001 September 15
|
|
3 **
|
|
4 ** The author disclaims copyright to this source code. In place of
|
|
5 ** a legal notice, here is a blessing:
|
|
6 **
|
|
7 ** 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.
|
|
10 **
|
|
11 *************************************************************************
|
|
12 ** This file contains code to implement the "sqlite" command line
|
|
13 ** utility for accessing SQLite databases.
|
|
14 **
|
|
15 ** $Id: shell.c,v 1.138 2006/06/06 12:32:21 drh Exp $
|
|
16 */
|
|
17 #include <stdlib.h>
|
|
18 #include <string.h>
|
|
19 #include <stdio.h>
|
|
20 #include <assert.h>
|
|
21 #include "sqlite3.h"
|
|
22 #include <ctype.h>
|
|
23
|
|
24 #if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__)
|
|
25 # include <signal.h>
|
|
26 # include <pwd.h>
|
|
27 # include <unistd.h>
|
|
28 # include <sys/types.h>
|
|
29 #endif
|
|
30
|
|
31 #ifdef __MACOS__
|
|
32 # include <console.h>
|
|
33 # include <signal.h>
|
|
34 # include <unistd.h>
|
|
35 # include <extras.h>
|
|
36 # include <Files.h>
|
|
37 # include <Folders.h>
|
|
38 #endif
|
|
39
|
|
40 #if defined(HAVE_READLINE) && HAVE_READLINE==1
|
|
41 # include <readline/readline.h>
|
|
42 # include <readline/history.h>
|
|
43 #else
|
|
44 # define readline(p) local_getline(p,stdin)
|
|
45 # define add_history(X)
|
|
46 # define read_history(X)
|
|
47 # define write_history(X)
|
|
48 # define stifle_history(X)
|
|
49 #endif
|
|
50
|
|
51 /* Make sure isatty() has a prototype.
|
|
52 */
|
|
53 extern int isatty();
|
|
54
|
|
55 /*
|
|
56 ** The following is the open SQLite database. We make a pointer
|
|
57 ** to this database a static variable so that it can be accessed
|
|
58 ** by the SIGINT handler to interrupt database processing.
|
|
59 */
|
|
60 static sqlite3 *db = 0;
|
|
61
|
|
62 /*
|
|
63 ** True if an interrupt (Control-C) has been received.
|
|
64 */
|
|
65 static volatile int seenInterrupt = 0;
|
|
66
|
|
67 /*
|
|
68 ** This is the name of our program. It is set in main(), used
|
|
69 ** in a number of other places, mostly for error messages.
|
|
70 */
|
|
71 static char *Argv0;
|
|
72
|
|
73 /*
|
|
74 ** Prompt strings. Initialized in main. Settable with
|
|
75 ** .prompt main continue
|
|
76 */
|
|
77 static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
|
|
78 static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
|
|
79
|
|
80
|
|
81 /*
|
|
82 ** Determines if a string is a number of not.
|
|
83 */
|
|
84 static int isNumber(const char *z, int *realnum){
|
|
85 if( *z=='-' || *z=='+' ) z++;
|
|
86 if( !isdigit(*z) ){
|
|
87 return 0;
|
|
88 }
|
|
89 z++;
|
|
90 if( realnum ) *realnum = 0;
|
|
91 while( isdigit(*z) ){ z++; }
|
|
92 if( *z=='.' ){
|
|
93 z++;
|
|
94 if( !isdigit(*z) ) return 0;
|
|
95 while( isdigit(*z) ){ z++; }
|
|
96 if( realnum ) *realnum = 1;
|
|
97 }
|
|
98 if( *z=='e' || *z=='E' ){
|
|
99 z++;
|
|
100 if( *z=='+' || *z=='-' ) z++;
|
|
101 if( !isdigit(*z) ) return 0;
|
|
102 while( isdigit(*z) ){ z++; }
|
|
103 if( realnum ) *realnum = 1;
|
|
104 }
|
|
105 return *z==0;
|
|
106 }
|
|
107
|
|
108 /*
|
|
109 ** A global char* and an SQL function to access its current value
|
|
110 ** from within an SQL statement. This program used to use the
|
|
111 ** sqlite_exec_printf() API to substitue a string into an SQL statement.
|
|
112 ** The correct way to do this with sqlite3 is to use the bind API, but
|
|
113 ** since the shell is built around the callback paradigm it would be a lot
|
|
114 ** of work. Instead just use this hack, which is quite harmless.
|
|
115 */
|
|
116 static const char *zShellStatic = 0;
|
|
117 static void shellstaticFunc(
|
|
118 sqlite3_context *context,
|
|
119 int argc,
|
|
120 sqlite3_value **argv
|
|
121 ){
|
|
122 assert( 0==argc );
|
|
123 assert( zShellStatic );
|
|
124 sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
|
|
125 }
|
|
126
|
|
127
|
|
128 /*
|
|
129 ** This routine reads a line of text from FILE in, stores
|
|
130 ** the text in memory obtained from malloc() and returns a pointer
|
|
131 ** to the text. NULL is returned at end of file, or if malloc()
|
|
132 ** fails.
|
|
133 **
|
|
134 ** The interface is like "readline" but no command-line editing
|
|
135 ** is done.
|
|
136 */
|
|
137 static char *local_getline(char *zPrompt, FILE *in){
|
|
138 char *zLine;
|
|
139 int nLine;
|
|
140 int n;
|
|
141 int eol;
|
|
142
|
|
143 if( zPrompt && *zPrompt ){
|
|
144 printf("%s",zPrompt);
|
|
145 fflush(stdout);
|
|
146 }
|
|
147 nLine = 100;
|
|
148 zLine = malloc( nLine );
|
|
149 if( zLine==0 ) return 0;
|
|
150 n = 0;
|
|
151 eol = 0;
|
|
152 while( !eol ){
|
|
153 if( n+100>nLine ){
|
|
154 nLine = nLine*2 + 100;
|
|
155 zLine = realloc(zLine, nLine);
|
|
156 if( zLine==0 ) return 0;
|
|
157 }
|
|
158 if( fgets(&zLine[n], nLine - n, in)==0 ){
|
|
159 if( n==0 ){
|
|
160 free(zLine);
|
|
161 return 0;
|
|
162 }
|
|
163 zLine[n] = 0;
|
|
164 eol = 1;
|
|
165 break;
|
|
166 }
|
|
167 while( zLine[n] ){ n++; }
|
|
168 if( n>0 && zLine[n-1]=='\n' ){
|
|
169 n--;
|
|
170 zLine[n] = 0;
|
|
171 eol = 1;
|
|
172 }
|
|
173 }
|
|
174 zLine = realloc( zLine, n+1 );
|
|
175 return zLine;
|
|
176 }
|
|
177
|
|
178 /*
|
|
179 ** Retrieve a single line of input text. "isatty" is true if text
|
|
180 ** is coming from a terminal. In that case, we issue a prompt and
|
|
181 ** attempt to use "readline" for command-line editing. If "isatty"
|
|
182 ** is false, use "local_getline" instead of "readline" and issue no prompt.
|
|
183 **
|
|
184 ** zPrior is a string of prior text retrieved. If not the empty
|
|
185 ** string, then issue a continuation prompt.
|
|
186 */
|
|
187 static char *one_input_line(const char *zPrior, FILE *in){
|
|
188 char *zPrompt;
|
|
189 char *zResult;
|
|
190 if( in!=0 ){
|
|
191 return local_getline(0, in);
|
|
192 }
|
|
193 if( zPrior && zPrior[0] ){
|
|
194 zPrompt = continuePrompt;
|
|
195 }else{
|
|
196 zPrompt = mainPrompt;
|
|
197 }
|
|
198 zResult = readline(zPrompt);
|
|
199 #if defined(HAVE_READLINE) && HAVE_READLINE==1
|
|
200 if( zResult && *zResult ) add_history(zResult);
|
|
201 #endif
|
|
202 return zResult;
|
|
203 }
|
|
204
|
|
205 struct previous_mode_data {
|
|
206 int valid; /* Is there legit data in here? */
|
|
207 int mode;
|
|
208 int showHeader;
|
|
209 int colWidth[100];
|
|
210 };
|
|
211 /*
|
|
212 ** An pointer to an instance of this structure is passed from
|
|
213 ** the main program to the callback. This is used to communicate
|
|
214 ** state and mode information.
|
|
215 */
|
|
216 struct callback_data {
|
|
217 sqlite3 *db; /* The database */
|
|
218 int echoOn; /* True to echo input commands */
|
|
219 int cnt; /* Number of records displayed so far */
|
|
220 FILE *out; /* Write results here */
|
|
221 int mode; /* An output mode setting */
|
|
222 int showHeader; /* True to show column names in List or Column mode */
|
|
223 char *zDestTable; /* Name of destination table when MODE_Insert */
|
|
224 char separator[20]; /* Separator character for MODE_List */
|
|
225 int colWidth[100]; /* Requested width of each column when in column mode*/
|
|
226 int actualWidth[100]; /* Actual width of each column */
|
|
227 char nullvalue[20]; /* The text to print when a NULL comes back from
|
|
228 ** the database */
|
|
229 struct previous_mode_data explainPrev;
|
|
230 /* Holds the mode information just before
|
|
231 ** .explain ON */
|
|
232 char outfile[FILENAME_MAX]; /* Filename for *out */
|
|
233 const char *zDbFilename; /* name of the database file */
|
|
234 char *zKey; /* Encryption key */
|
|
235 };
|
|
236
|
|
237 /*
|
|
238 ** These are the allowed modes.
|
|
239 */
|
|
240 #define MODE_Line 0 /* One column per line. Blank line between records */
|
|
241 #define MODE_Column 1 /* One record per line in neat columns */
|
|
242 #define MODE_List 2 /* One record per line with a separator */
|
|
243 #define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
|
|
244 #define MODE_Html 4 /* Generate an XHTML table */
|
|
245 #define MODE_Insert 5 /* Generate SQL "insert" statements */
|
|
246 #define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
|
|
247 #define MODE_Csv 7 /* Quote strings, numbers are plain */
|
|
248 #define MODE_NUM_OF 8 /* The number of modes (not a mode itself) */
|
|
249
|
|
250 static const char *modeDescr[MODE_NUM_OF] = {
|
|
251 "line",
|
|
252 "column",
|
|
253 "list",
|
|
254 "semi",
|
|
255 "html",
|
|
256 "insert",
|
|
257 "tcl",
|
|
258 "csv",
|
|
259 };
|
|
260
|
|
261 /*
|
|
262 ** Number of elements in an array
|
|
263 */
|
|
264 #define ArraySize(X) (sizeof(X)/sizeof(X[0]))
|
|
265
|
|
266 /*
|
|
267 ** Output the given string as a quoted string using SQL quoting conventions.
|
|
268 */
|
|
269 static void output_quoted_string(FILE *out, const char *z){
|
|
270 int i;
|
|
271 int nSingle = 0;
|
|
272 for(i=0; z[i]; i++){
|
|
273 if( z[i]=='\'' ) nSingle++;
|
|
274 }
|
|
275 if( nSingle==0 ){
|
|
276 fprintf(out,"'%s'",z);
|
|
277 }else{
|
|
278 fprintf(out,"'");
|
|
279 while( *z ){
|
|
280 for(i=0; z[i] && z[i]!='\''; i++){}
|
|
281 if( i==0 ){
|
|
282 fprintf(out,"''");
|
|
283 z++;
|
|
284 }else if( z[i]=='\'' ){
|
|
285 fprintf(out,"%.*s''",i,z);
|
|
286 z += i+1;
|
|
287 }else{
|
|
288 fprintf(out,"%s",z);
|
|
289 break;
|
|
290 }
|
|
291 }
|
|
292 fprintf(out,"'");
|
|
293 }
|
|
294 }
|
|
295
|
|
296 /*
|
|
297 ** Output the given string as a quoted according to C or TCL quoting rules.
|
|
298 */
|
|
299 static void output_c_string(FILE *out, const char *z){
|
|
300 unsigned int c;
|
|
301 fputc('"', out);
|
|
302 while( (c = *(z++))!=0 ){
|
|
303 if( c=='\\' ){
|
|
304 fputc(c, out);
|
|
305 fputc(c, out);
|
|
306 }else if( c=='\t' ){
|
|
307 fputc('\\', out);
|
|
308 fputc('t', out);
|
|
309 }else if( c=='\n' ){
|
|
310 fputc('\\', out);
|
|
311 fputc('n', out);
|
|
312 }else if( c=='\r' ){
|
|
313 fputc('\\', out);
|
|
314 fputc('r', out);
|
|
315 }else if( !isprint(c) ){
|
|
316 fprintf(out, "\\%03o", c&0xff);
|
|
317 }else{
|
|
318 fputc(c, out);
|
|
319 }
|
|
320 }
|
|
321 fputc('"', out);
|
|
322 }
|
|
323
|
|
324 /*
|
|
325 ** Output the given string with characters that are special to
|
|
326 ** HTML escaped.
|
|
327 */
|
|
328 static void output_html_string(FILE *out, const char *z){
|
|
329 int i;
|
|
330 while( *z ){
|
|
331 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
|
|
332 if( i>0 ){
|
|
333 fprintf(out,"%.*s",i,z);
|
|
334 }
|
|
335 if( z[i]=='<' ){
|
|
336 fprintf(out,"<");
|
|
337 }else if( z[i]=='&' ){
|
|
338 fprintf(out,"&");
|
|
339 }else{
|
|
340 break;
|
|
341 }
|
|
342 z += i + 1;
|
|
343 }
|
|
344 }
|
|
345
|
|
346 /*
|
|
347 ** Output a single term of CSV. Actually, p->separator is used for
|
|
348 ** the separator, which may or may not be a comma. p->nullvalue is
|
|
349 ** the null value. Strings are quoted using ANSI-C rules. Numbers
|
|
350 ** appear outside of quotes.
|
|
351 */
|
|
352 static void output_csv(struct callback_data *p, const char *z, int bSep){
|
|
353 if( z==0 ){
|
|
354 fprintf(p->out,"%s",p->nullvalue);
|
|
355 }else if( isNumber(z, 0) ){
|
|
356 fprintf(p->out,"%s",z);
|
|
357 }else{
|
|
358 output_c_string(p->out, z);
|
|
359 }
|
|
360 if( bSep ){
|
|
361 fprintf(p->out, p->separator);
|
|
362 }
|
|
363 }
|
|
364
|
|
365 #ifdef SIGINT
|
|
366 /*
|
|
367 ** This routine runs when the user presses Ctrl-C
|
|
368 */
|
|
369 static void interrupt_handler(int NotUsed){
|
|
370 seenInterrupt = 1;
|
|
371 if( db ) sqlite3_interrupt(db);
|
|
372 }
|
|
373 #endif
|
|
374
|
|
375 /*
|
|
376 ** This is the callback routine that the SQLite library
|
|
377 ** invokes for each row of a query result.
|
|
378 */
|
|
379 static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
|
380 int i;
|
|
381 struct callback_data *p = (struct callback_data*)pArg;
|
|
382 switch( p->mode ){
|
|
383 case MODE_Line: {
|
|
384 int w = 5;
|
|
385 if( azArg==0 ) break;
|
|
386 for(i=0; i<nArg; i++){
|
|
387 int len = strlen(azCol[i]);
|
|
388 if( len>w ) w = len;
|
|
389 }
|
|
390 if( p->cnt++>0 ) fprintf(p->out,"\n");
|
|
391 for(i=0; i<nArg; i++){
|
|
392 fprintf(p->out,"%*s = %s\n", w, azCol[i],
|
|
393 azArg[i] ? azArg[i] : p->nullvalue);
|
|
394 }
|
|
395 break;
|
|
396 }
|
|
397 case MODE_Column: {
|
|
398 if( p->cnt++==0 ){
|
|
399 for(i=0; i<nArg; i++){
|
|
400 int w, n;
|
|
401 if( i<ArraySize(p->colWidth) ){
|
|
402 w = p->colWidth[i];
|
|
403 }else{
|
|
404 w = 0;
|
|
405 }
|
|
406 if( w<=0 ){
|
|
407 w = strlen(azCol[i] ? azCol[i] : "");
|
|
408 if( w<10 ) w = 10;
|
|
409 n = strlen(azArg && azArg[i] ? azArg[i] : p->nullvalue);
|
|
410 if( w<n ) w = n;
|
|
411 }
|
|
412 if( i<ArraySize(p->actualWidth) ){
|
|
413 p->actualWidth[i] = w;
|
|
414 }
|
|
415 if( p->showHeader ){
|
|
416 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
|
|
417 }
|
|
418 }
|
|
419 if( p->showHeader ){
|
|
420 for(i=0; i<nArg; i++){
|
|
421 int w;
|
|
422 if( i<ArraySize(p->actualWidth) ){
|
|
423 w = p->actualWidth[i];
|
|
424 }else{
|
|
425 w = 10;
|
|
426 }
|
|
427 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
|
|
428 "----------------------------------------------------------",
|
|
429 i==nArg-1 ? "\n": " ");
|
|
430 }
|
|
431 }
|
|
432 }
|
|
433 if( azArg==0 ) break;
|
|
434 for(i=0; i<nArg; i++){
|
|
435 int w;
|
|
436 if( i<ArraySize(p->actualWidth) ){
|
|
437 w = p->actualWidth[i];
|
|
438 }else{
|
|
439 w = 10;
|
|
440 }
|
|
441 fprintf(p->out,"%-*.*s%s",w,w,
|
|
442 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
|
|
443 }
|
|
444 break;
|
|
445 }
|
|
446 case MODE_Semi:
|
|
447 case MODE_List: {
|
|
448 if( p->cnt++==0 && p->showHeader ){
|
|
449 for(i=0; i<nArg; i++){
|
|
450 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
|
|
451 }
|
|
452 }
|
|
453 if( azArg==0 ) break;
|
|
454 for(i=0; i<nArg; i++){
|
|
455 char *z = azArg[i];
|
|
456 if( z==0 ) z = p->nullvalue;
|
|
457 fprintf(p->out, "%s", z);
|
|
458 if( i<nArg-1 ){
|
|
459 fprintf(p->out, "%s", p->separator);
|
|
460 }else if( p->mode==MODE_Semi ){
|
|
461 fprintf(p->out, ";\n");
|
|
462 }else{
|
|
463 fprintf(p->out, "\n");
|
|
464 }
|
|
465 }
|
|
466 break;
|
|
467 }
|
|
468 case MODE_Html: {
|
|
469 if( p->cnt++==0 && p->showHeader ){
|
|
470 fprintf(p->out,"<TR>");
|
|
471 for(i=0; i<nArg; i++){
|
|
472 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
|
|
473 }
|
|
474 fprintf(p->out,"</TR>\n");
|
|
475 }
|
|
476 if( azArg==0 ) break;
|
|
477 fprintf(p->out,"<TR>");
|
|
478 for(i=0; i<nArg; i++){
|
|
479 fprintf(p->out,"<TD>");
|
|
480 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
|
|
481 fprintf(p->out,"</TD>\n");
|
|
482 }
|
|
483 fprintf(p->out,"</TR>\n");
|
|
484 break;
|
|
485 }
|
|
486 case MODE_Tcl: {
|
|
487 if( p->cnt++==0 && p->showHeader ){
|
|
488 for(i=0; i<nArg; i++){
|
|
489 output_c_string(p->out,azCol[i]);
|
|
490 fprintf(p->out, "%s", p->separator);
|
|
491 }
|
|
492 fprintf(p->out,"\n");
|
|
493 }
|
|
494 if( azArg==0 ) break;
|
|
495 for(i=0; i<nArg; i++){
|
|
496 output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
|
|
497 fprintf(p->out, "%s", p->separator);
|
|
498 }
|
|
499 fprintf(p->out,"\n");
|
|
500 break;
|
|
501 }
|
|
502 case MODE_Csv: {
|
|
503 if( p->cnt++==0 && p->showHeader ){
|
|
504 for(i=0; i<nArg; i++){
|
|
505 output_csv(p, azCol[i], i<nArg-1);
|
|
506 }
|
|
507 fprintf(p->out,"\n");
|
|
508 }
|
|
509 if( azArg==0 ) break;
|
|
510 for(i=0; i<nArg; i++){
|
|
511 output_csv(p, azArg[i], i<nArg-1);
|
|
512 }
|
|
513 fprintf(p->out,"\n");
|
|
514 break;
|
|
515 }
|
|
516 case MODE_Insert: {
|
|
517 if( azArg==0 ) break;
|
|
518 fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
|
|
519 for(i=0; i<nArg; i++){
|
|
520 char *zSep = i>0 ? ",": "";
|
|
521 if( azArg[i]==0 ){
|
|
522 fprintf(p->out,"%sNULL",zSep);
|
|
523 }else if( isNumber(azArg[i], 0) ){
|
|
524 fprintf(p->out,"%s%s",zSep, azArg[i]);
|
|
525 }else{
|
|
526 if( zSep[0] ) fprintf(p->out,"%s",zSep);
|
|
527 output_quoted_string(p->out, azArg[i]);
|
|
528 }
|
|
529 }
|
|
530 fprintf(p->out,");\n");
|
|
531 break;
|
|
532 }
|
|
533 }
|
|
534 return 0;
|
|
535 }
|
|
536
|
|
537 /*
|
|
538 ** Set the destination table field of the callback_data structure to
|
|
539 ** the name of the table given. Escape any quote characters in the
|
|
540 ** table name.
|
|
541 */
|
|
542 static void set_table_name(struct callback_data *p, const char *zName){
|
|
543 int i, n;
|
|
544 int needQuote;
|
|
545 char *z;
|
|
546
|
|
547 if( p->zDestTable ){
|
|
548 free(p->zDestTable);
|
|
549 p->zDestTable = 0;
|
|
550 }
|
|
551 if( zName==0 ) return;
|
|
552 needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
|
|
553 for(i=n=0; zName[i]; i++, n++){
|
|
554 if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
|
|
555 needQuote = 1;
|
|
556 if( zName[i]=='\'' ) n++;
|
|
557 }
|
|
558 }
|
|
559 if( needQuote ) n += 2;
|
|
560 z = p->zDestTable = malloc( n+1 );
|
|
561 if( z==0 ){
|
|
562 fprintf(stderr,"Out of memory!\n");
|
|
563 exit(1);
|
|
564 }
|
|
565 n = 0;
|
|
566 if( needQuote ) z[n++] = '\'';
|
|
567 for(i=0; zName[i]; i++){
|
|
568 z[n++] = zName[i];
|
|
569 if( zName[i]=='\'' ) z[n++] = '\'';
|
|
570 }
|
|
571 if( needQuote ) z[n++] = '\'';
|
|
572 z[n] = 0;
|
|
573 }
|
|
574
|
|
575 /* zIn is either a pointer to a NULL-terminated string in memory obtained
|
|
576 ** from malloc(), or a NULL pointer. The string pointed to by zAppend is
|
|
577 ** added to zIn, and the result returned in memory obtained from malloc().
|
|
578 ** zIn, if it was not NULL, is freed.
|
|
579 **
|
|
580 ** If the third argument, quote, is not '\0', then it is used as a
|
|
581 ** quote character for zAppend.
|
|
582 */
|
|
583 static char * appendText(char *zIn, char const *zAppend, char quote){
|
|
584 int len;
|
|
585 int i;
|
|
586 int nAppend = strlen(zAppend);
|
|
587 int nIn = (zIn?strlen(zIn):0);
|
|
588
|
|
589 len = nAppend+nIn+1;
|
|
590 if( quote ){
|
|
591 len += 2;
|
|
592 for(i=0; i<nAppend; i++){
|
|
593 if( zAppend[i]==quote ) len++;
|
|
594 }
|
|
595 }
|
|
596
|
|
597 zIn = (char *)realloc(zIn, len);
|
|
598 if( !zIn ){
|
|
599 return 0;
|
|
600 }
|
|
601
|
|
602 if( quote ){
|
|
603 char *zCsr = &zIn[nIn];
|
|
604 *zCsr++ = quote;
|
|
605 for(i=0; i<nAppend; i++){
|
|
606 *zCsr++ = zAppend[i];
|
|
607 if( zAppend[i]==quote ) *zCsr++ = quote;
|
|
608 }
|
|
609 *zCsr++ = quote;
|
|
610 *zCsr++ = '\0';
|
|
611 assert( (zCsr-zIn)==len );
|
|
612 }else{
|
|
613 memcpy(&zIn[nIn], zAppend, nAppend);
|
|
614 zIn[len-1] = '\0';
|
|
615 }
|
|
616
|
|
617 return zIn;
|
|
618 }
|
|
619
|
|
620
|
|
621 /*
|
|
622 ** Execute a query statement that has a single result column. Print
|
|
623 ** that result column on a line by itself with a semicolon terminator.
|
|
624 */
|
|
625 static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
|
|
626 sqlite3_stmt *pSelect;
|
|
627 int rc;
|
|
628 rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
|
|
629 if( rc!=SQLITE_OK || !pSelect ){
|
|
630 return rc;
|
|
631 }
|
|
632 rc = sqlite3_step(pSelect);
|
|
633 while( rc==SQLITE_ROW ){
|
|
634 fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
|
|
635 rc = sqlite3_step(pSelect);
|
|
636 }
|
|
637 return sqlite3_finalize(pSelect);
|
|
638 }
|
|
639
|
|
640
|
|
641 /*
|
|
642 ** This is a different callback routine used for dumping the database.
|
|
643 ** Each row received by this callback consists of a table name,
|
|
644 ** the table type ("index" or "table") and SQL to create the table.
|
|
645 ** This routine should print text sufficient to recreate the table.
|
|
646 */
|
|
647 static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
|
648 int rc;
|
|
649 const char *zTable;
|
|
650 const char *zType;
|
|
651 const char *zSql;
|
|
652 struct callback_data *p = (struct callback_data *)pArg;
|
|
653
|
|
654 if( nArg!=3 ) return 1;
|
|
655 zTable = azArg[0];
|
|
656 zType = azArg[1];
|
|
657 zSql = azArg[2];
|
|
658
|
|
659 if( strcmp(zTable, "sqlite_sequence")==0 ){
|
|
660 fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
|
|
661 }else if( strcmp(zTable, "sqlite_stat1")==0 ){
|
|
662 fprintf(p->out, "ANALYZE sqlite_master;\n");
|
|
663 }else if( strncmp(zTable, "sqlite_", 7)==0 ){
|
|
664 return 0;
|
|
665 }else{
|
|
666 fprintf(p->out, "%s;\n", zSql);
|
|
667 }
|
|
668
|
|
669 if( strcmp(zType, "table")==0 ){
|
|
670 sqlite3_stmt *pTableInfo = 0;
|
|
671 char *zSelect = 0;
|
|
672 char *zTableInfo = 0;
|
|
673 char *zTmp = 0;
|
|
674
|
|
675 zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
|
|
676 zTableInfo = appendText(zTableInfo, zTable, '"');
|
|
677 zTableInfo = appendText(zTableInfo, ");", 0);
|
|
678
|
|
679 rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
|
|
680 if( zTableInfo ) free(zTableInfo);
|
|
681 if( rc!=SQLITE_OK || !pTableInfo ){
|
|
682 return 1;
|
|
683 }
|
|
684
|
|
685 zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
|
|
686 zTmp = appendText(zTmp, zTable, '"');
|
|
687 if( zTmp ){
|
|
688 zSelect = appendText(zSelect, zTmp, '\'');
|
|
689 }
|
|
690 zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
|
|
691 rc = sqlite3_step(pTableInfo);
|
|
692 while( rc==SQLITE_ROW ){
|
|
693 const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
|
|
694 zSelect = appendText(zSelect, "quote(", 0);
|
|
695 zSelect = appendText(zSelect, zText, '"');
|
|
696 rc = sqlite3_step(pTableInfo);
|
|
697 if( rc==SQLITE_ROW ){
|
|
698 zSelect = appendText(zSelect, ") || ', ' || ", 0);
|
|
699 }else{
|
|
700 zSelect = appendText(zSelect, ") ", 0);
|
|
701 }
|
|
702 }
|
|
703 rc = sqlite3_finalize(pTableInfo);
|
|
704 if( rc!=SQLITE_OK ){
|
|
705 if( zSelect ) free(zSelect);
|
|
706 return 1;
|
|
707 }
|
|
708 zSelect = appendText(zSelect, "|| ')' FROM ", 0);
|
|
709 zSelect = appendText(zSelect, zTable, '"');
|
|
710
|
|
711 rc = run_table_dump_query(p->out, p->db, zSelect);
|
|
712 if( rc==SQLITE_CORRUPT ){
|
|
713 zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
|
|
714 rc = run_table_dump_query(p->out, p->db, zSelect);
|
|
715 }
|
|
716 if( zSelect ) free(zSelect);
|
|
717 if( rc!=SQLITE_OK ){
|
|
718 return 1;
|
|
719 }
|
|
720 }
|
|
721 return 0;
|
|
722 }
|
|
723
|
|
724 /*
|
|
725 ** Run zQuery. Update dump_callback() as the callback routine.
|
|
726 ** If we get a SQLITE_CORRUPT error, rerun the query after appending
|
|
727 ** "ORDER BY rowid DESC" to the end.
|
|
728 */
|
|
729 static int run_schema_dump_query(
|
|
730 struct callback_data *p,
|
|
731 const char *zQuery,
|
|
732 char **pzErrMsg
|
|
733 ){
|
|
734 int rc;
|
|
735 rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg);
|
|
736 if( rc==SQLITE_CORRUPT ){
|
|
737 char *zQ2;
|
|
738 int len = strlen(zQuery);
|
|
739 if( pzErrMsg ) sqlite3_free(*pzErrMsg);
|
|
740 zQ2 = malloc( len+100 );
|
|
741 if( zQ2==0 ) return rc;
|
|
742 sprintf(zQ2, "%s ORDER BY rowid DESC", zQuery);
|
|
743 rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
|
|
744 free(zQ2);
|
|
745 }
|
|
746 return rc;
|
|
747 }
|
|
748
|
|
749 /*
|
|
750 ** Text of a help message
|
|
751 */
|
|
752 static char zHelp[] =
|
|
753 ".databases List names and files of attached databases\n"
|
|
754 ".dump ?TABLE? ... Dump the database in an SQL text format\n"
|
|
755 ".echo ON|OFF Turn command echo on or off\n"
|
|
756 ".exit Exit this program\n"
|
|
757 ".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
|
|
758 ".header(s) ON|OFF Turn display of headers on or off\n"
|
|
759 ".help Show this message\n"
|
|
760 ".import FILE TABLE Import data from FILE into TABLE\n"
|
|
761 ".indices TABLE Show names of all indices on TABLE\n"
|
|
762 ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
|
|
763 " csv Comma-separated values\n"
|
|
764 " column Left-aligned columns. (See .width)\n"
|
|
765 " html HTML <table> code\n"
|
|
766 " insert SQL insert statements for TABLE\n"
|
|
767 " line One value per line\n"
|
|
768 " list Values delimited by .separator string\n"
|
|
769 " tabs Tab-separated values\n"
|
|
770 " tcl TCL list elements\n"
|
|
771 ".nullvalue STRING Print STRING in place of NULL values\n"
|
|
772 ".output FILENAME Send output to FILENAME\n"
|
|
773 ".output stdout Send output to the screen\n"
|
|
774 ".prompt MAIN CONTINUE Replace the standard prompts\n"
|
|
775 ".quit Exit this program\n"
|
|
776 ".read FILENAME Execute SQL in FILENAME\n"
|
|
777 ".schema ?TABLE? Show the CREATE statements\n"
|
|
778 ".separator STRING Change separator used by output mode and .import\n"
|
|
779 ".show Show the current values for various settings\n"
|
|
780 ".tables ?PATTERN? List names of tables matching a LIKE pattern\n"
|
|
781 ".timeout MS Try opening locked tables for MS milliseconds\n"
|
|
782 ".width NUM NUM ... Set column widths for \"column\" mode\n"
|
|
783 ;
|
|
784
|
|
785 /* Forward reference */
|
|
786 static void process_input(struct callback_data *p, FILE *in);
|
|
787
|
|
788 /*
|
|
789 ** Make sure the database is open. If it is not, then open it. If
|
|
790 ** the database fails to open, print an error message and exit.
|
|
791 */
|
|
792 static void open_db(struct callback_data *p){
|
|
793 if( p->db==0 ){
|
|
794 sqlite3_open(p->zDbFilename, &p->db);
|
|
795 db = p->db;
|
|
796 sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
|
|
797 shellstaticFunc, 0, 0);
|
|
798 if( SQLITE_OK!=sqlite3_errcode(db) ){
|
|
799 fprintf(stderr,"Unable to open database \"%s\": %s\n",
|
|
800 p->zDbFilename, sqlite3_errmsg(db));
|
|
801 exit(1);
|
|
802 }
|
|
803 }
|
|
804 }
|
|
805
|
|
806 /*
|
|
807 ** Do C-language style dequoting.
|
|
808 **
|
|
809 ** \t -> tab
|
|
810 ** \n -> newline
|
|
811 ** \r -> carriage return
|
|
812 ** \NNN -> ascii character NNN in octal
|
|
813 ** \\ -> backslash
|
|
814 */
|
|
815 static void resolve_backslashes(char *z){
|
|
816 int i, j, c;
|
|
817 for(i=j=0; (c = z[i])!=0; i++, j++){
|
|
818 if( c=='\\' ){
|
|
819 c = z[++i];
|
|
820 if( c=='n' ){
|
|
821 c = '\n';
|
|
822 }else if( c=='t' ){
|
|
823 c = '\t';
|
|
824 }else if( c=='r' ){
|
|
825 c = '\r';
|
|
826 }else if( c>='0' && c<='7' ){
|
|
827 c -= '0';
|
|
828 if( z[i+1]>='0' && z[i+1]<='7' ){
|
|
829 i++;
|
|
830 c = (c<<3) + z[i] - '0';
|
|
831 if( z[i+1]>='0' && z[i+1]<='7' ){
|
|
832 i++;
|
|
833 c = (c<<3) + z[i] - '0';
|
|
834 }
|
|
835 }
|
|
836 }
|
|
837 }
|
|
838 z[j] = c;
|
|
839 }
|
|
840 z[j] = 0;
|
|
841 }
|
|
842
|
|
843 /*
|
|
844 ** If an input line begins with "." then invoke this routine to
|
|
845 ** process that line.
|
|
846 **
|
|
847 ** Return 1 to exit and 0 to continue.
|
|
848 */
|
|
849 static int do_meta_command(char *zLine, struct callback_data *p){
|
|
850 int i = 1;
|
|
851 int nArg = 0;
|
|
852 int n, c;
|
|
853 int rc = 0;
|
|
854 char *azArg[50];
|
|
855
|
|
856 /* Parse the input line into tokens.
|
|
857 */
|
|
858 while( zLine[i] && nArg<ArraySize(azArg) ){
|
|
859 while( isspace((unsigned char)zLine[i]) ){ i++; }
|
|
860 if( zLine[i]==0 ) break;
|
|
861 if( zLine[i]=='\'' || zLine[i]=='"' ){
|
|
862 int delim = zLine[i++];
|
|
863 azArg[nArg++] = &zLine[i];
|
|
864 while( zLine[i] && zLine[i]!=delim ){ i++; }
|
|
865 if( zLine[i]==delim ){
|
|
866 zLine[i++] = 0;
|
|
867 }
|
|
868 if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
|
|
869 }else{
|
|
870 azArg[nArg++] = &zLine[i];
|
|
871 while( zLine[i] && !isspace((unsigned char)zLine[i]) ){ i++; }
|
|
872 if( zLine[i] ) zLine[i++] = 0;
|
|
873 resolve_backslashes(azArg[nArg-1]);
|
|
874 }
|
|
875 }
|
|
876
|
|
877 /* Process the input line.
|
|
878 */
|
|
879 if( nArg==0 ) return rc;
|
|
880 n = strlen(azArg[0]);
|
|
881 c = azArg[0][0];
|
|
882 if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
|
|
883 struct callback_data data;
|
|
884 char *zErrMsg = 0;
|
|
885 open_db(p);
|
|
886 memcpy(&data, p, sizeof(data));
|
|
887 data.showHeader = 1;
|
|
888 data.mode = MODE_Column;
|
|
889 data.colWidth[0] = 3;
|
|
890 data.colWidth[1] = 15;
|
|
891 data.colWidth[2] = 58;
|
|
892 data.cnt = 0;
|
|
893 sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
|
|
894 if( zErrMsg ){
|
|
895 fprintf(stderr,"Error: %s\n", zErrMsg);
|
|
896 sqlite3_free(zErrMsg);
|
|
897 }
|
|
898 }else
|
|
899
|
|
900 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
|
|
901 char *zErrMsg = 0;
|
|
902 open_db(p);
|
|
903 fprintf(p->out, "BEGIN TRANSACTION;\n");
|
|
904 if( nArg==1 ){
|
|
905 run_schema_dump_query(p,
|
|
906 "SELECT name, type, sql FROM sqlite_master "
|
|
907 "WHERE sql NOT NULL AND type=='table'", 0
|
|
908 );
|
|
909 run_schema_dump_query(p,
|
|
910 "SELECT name, type, sql FROM sqlite_master "
|
|
911 "WHERE sql NOT NULL AND type!='table' AND type!='meta'", 0
|
|
912 );
|
|
913 }else{
|
|
914 int i;
|
|
915 for(i=1; i<nArg; i++){
|
|
916 zShellStatic = azArg[i];
|
|
917 run_schema_dump_query(p,
|
|
918 "SELECT name, type, sql FROM sqlite_master "
|
|
919 "WHERE tbl_name LIKE shellstatic() AND type=='table'"
|
|
920 " AND sql NOT NULL", 0);
|
|
921 run_schema_dump_query(p,
|
|
922 "SELECT name, type, sql FROM sqlite_master "
|
|
923 "WHERE tbl_name LIKE shellstatic() AND type!='table'"
|
|
924 " AND type!='meta' AND sql NOT NULL", 0);
|
|
925 zShellStatic = 0;
|
|
926 }
|
|
927 }
|
|
928 if( zErrMsg ){
|
|
929 fprintf(stderr,"Error: %s\n", zErrMsg);
|
|
930 sqlite3_free(zErrMsg);
|
|
931 }else{
|
|
932 fprintf(p->out, "COMMIT;\n");
|
|
933 }
|
|
934 }else
|
|
935
|
|
936 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
|
|
937 int j;
|
|
938 char *z = azArg[1];
|
|
939 int val = atoi(azArg[1]);
|
|
940 for(j=0; z[j]; j++){
|
|
941 z[j] = tolower((unsigned char)z[j]);
|
|
942 }
|
|
943 if( strcmp(z,"on")==0 ){
|
|
944 val = 1;
|
|
945 }else if( strcmp(z,"yes")==0 ){
|
|
946 val = 1;
|
|
947 }
|
|
948 p->echoOn = val;
|
|
949 }else
|
|
950
|
|
951 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
|
|
952 rc = 1;
|
|
953 }else
|
|
954
|
|
955 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
|
|
956 int j;
|
|
957 static char zOne[] = "1";
|
|
958 char *z = nArg>=2 ? azArg[1] : zOne;
|
|
959 int val = atoi(z);
|
|
960 for(j=0; z[j]; j++){
|
|
961 z[j] = tolower((unsigned char)z[j]);
|
|
962 }
|
|
963 if( strcmp(z,"on")==0 ){
|
|
964 val = 1;
|
|
965 }else if( strcmp(z,"yes")==0 ){
|
|
966 val = 1;
|
|
967 }
|
|
968 if(val == 1) {
|
|
969 if(!p->explainPrev.valid) {
|
|
970 p->explainPrev.valid = 1;
|
|
971 p->explainPrev.mode = p->mode;
|
|
972 p->explainPrev.showHeader = p->showHeader;
|
|
973 memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
|
|
974 }
|
|
975 /* We could put this code under the !p->explainValid
|
|
976 ** condition so that it does not execute if we are already in
|
|
977 ** explain mode. However, always executing it allows us an easy
|
|
978 ** was to reset to explain mode in case the user previously
|
|
979 ** did an .explain followed by a .width, .mode or .header
|
|
980 ** command.
|
|
981 */
|
|
982 p->mode = MODE_Column;
|
|
983 p->showHeader = 1;
|
|
984 memset(p->colWidth,0,ArraySize(p->colWidth));
|
|
985 p->colWidth[0] = 4;
|
|
986 p->colWidth[1] = 14;
|
|
987 p->colWidth[2] = 10;
|
|
988 p->colWidth[3] = 10;
|
|
989 p->colWidth[4] = 33;
|
|
990 }else if (p->explainPrev.valid) {
|
|
991 p->explainPrev.valid = 0;
|
|
992 p->mode = p->explainPrev.mode;
|
|
993 p->showHeader = p->explainPrev.showHeader;
|
|
994 memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
|
|
995 }
|
|
996 }else
|
|
997
|
|
998 if( c=='h' && (strncmp(azArg[0], "header", n)==0
|
|
999 ||
|
|
1000 strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
|
|
1001 int j;
|
|
1002 char *z = azArg[1];
|
|
1003 int val = atoi(azArg[1]);
|
|
1004 for(j=0; z[j]; j++){
|
|
1005 z[j] = tolower((unsigned char)z[j]);
|
|
1006 }
|
|
1007 if( strcmp(z,"on")==0 ){
|
|
1008 val = 1;
|
|
1009 }else if( strcmp(z,"yes")==0 ){
|
|
1010 val = 1;
|
|
1011 }
|
|
1012 p->showHeader = val;
|
|
1013 }else
|
|
1014
|
|
1015 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
|
|
1016 fprintf(stderr,zHelp);
|
|
1017 }else
|
|
1018
|
|
1019 if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg>=3 ){
|
|
1020 char *zTable = azArg[2]; /* Insert data into this table */
|
|
1021 char *zFile = azArg[1]; /* The file from which to extract data */
|
|
1022 sqlite3_stmt *pStmt; /* A statement */
|
|
1023 int rc; /* Result code */
|
|
1024 int nCol; /* Number of columns in the table */
|
|
1025 int nByte; /* Number of bytes in an SQL string */
|
|
1026 int i, j; /* Loop counters */
|
|
1027 int nSep; /* Number of bytes in p->separator[] */
|
|
1028 char *zSql; /* An SQL statement */
|
|
1029 char *zLine; /* A single line of input from the file */
|
|
1030 char **azCol; /* zLine[] broken up into columns */
|
|
1031 char *zCommit; /* How to commit changes */
|
|
1032 FILE *in; /* The input file */
|
|
1033 int lineno = 0; /* Line number of input file */
|
|
1034
|
|
1035 nSep = strlen(p->separator);
|
|
1036 if( nSep==0 ){
|
|
1037 fprintf(stderr, "non-null separator required for import\n");
|
|
1038 return 0;
|
|
1039 }
|
|
1040 zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
|
|
1041 if( zSql==0 ) return 0;
|
|
1042 nByte = strlen(zSql);
|
|
1043 rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
|
|
1044 sqlite3_free(zSql);
|
|
1045 if( rc ){
|
|
1046 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
|
|
1047 nCol = 0;
|
|
1048 }else{
|
|
1049 nCol = sqlite3_column_count(pStmt);
|
|
1050 }
|
|
1051 sqlite3_finalize(pStmt);
|
|
1052 if( nCol==0 ) return 0;
|
|
1053 zSql = malloc( nByte + 20 + nCol*2 );
|
|
1054 if( zSql==0 ) return 0;
|
|
1055 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable);
|
|
1056 j = strlen(zSql);
|
|
1057 for(i=1; i<nCol; i++){
|
|
1058 zSql[j++] = ',';
|
|
1059 zSql[j++] = '?';
|
|
1060 }
|
|
1061 zSql[j++] = ')';
|
|
1062 zSql[j] = 0;
|
|
1063 rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
|
|
1064 free(zSql);
|
|
1065 if( rc ){
|
|
1066 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
|
|
1067 sqlite3_finalize(pStmt);
|
|
1068 return 0;
|
|
1069 }
|
|
1070 in = fopen(zFile, "rb");
|
|
1071 if( in==0 ){
|
|
1072 fprintf(stderr, "cannot open file: %s\n", zFile);
|
|
1073 sqlite3_finalize(pStmt);
|
|
1074 return 0;
|
|
1075 }
|
|
1076 azCol = malloc( sizeof(azCol[0])*(nCol+1) );
|
|
1077 if( azCol==0 ){
|
|
1078 fclose(in);
|
|
1079 return 0;
|
|
1080 }
|
|
1081 sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
|
|
1082 zCommit = "COMMIT";
|
|
1083 while( (zLine = local_getline(0, in))!=0 ){
|
|
1084 char *z;
|
|
1085 i = 0;
|
|
1086 lineno++;
|
|
1087 azCol[0] = zLine;
|
|
1088 for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){
|
|
1089 if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
|
|
1090 *z = 0;
|
|
1091 i++;
|
|
1092 if( i<nCol ){
|
|
1093 azCol[i] = &z[nSep];
|
|
1094 z += nSep-1;
|
|
1095 }
|
|
1096 }
|
|
1097 }
|
|
1098 *z = 0;
|
|
1099 if( i+1!=nCol ){
|
|
1100 fprintf(stderr,"%s line %d: expected %d columns of data but found %d\n",
|
|
1101 zFile, lineno, nCol, i+1);
|
|
1102 zCommit = "ROLLBACK";
|
|
1103 break;
|
|
1104 }
|
|
1105 for(i=0; i<nCol; i++){
|
|
1106 sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
|
|
1107 }
|
|
1108 sqlite3_step(pStmt);
|
|
1109 rc = sqlite3_reset(pStmt);
|
|
1110 free(zLine);
|
|
1111 if( rc!=SQLITE_OK ){
|
|
1112 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
|
|
1113 zCommit = "ROLLBACK";
|
|
1114 break;
|
|
1115 }
|
|
1116 }
|
|
1117 free(azCol);
|
|
1118 fclose(in);
|
|
1119 sqlite3_finalize(pStmt);
|
|
1120 sqlite3_exec(p->db, zCommit, 0, 0, 0);
|
|
1121 }else
|
|
1122
|
|
1123 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
|
|
1124 struct callback_data data;
|
|
1125 char *zErrMsg = 0;
|
|
1126 open_db(p);
|
|
1127 memcpy(&data, p, sizeof(data));
|
|
1128 data.showHeader = 0;
|
|
1129 data.mode = MODE_List;
|
|
1130 zShellStatic = azArg[1];
|
|
1131 sqlite3_exec(p->db,
|
|
1132 "SELECT name FROM sqlite_master "
|
|
1133 "WHERE type='index' AND tbl_name LIKE shellstatic() "
|
|
1134 "UNION ALL "
|
|
1135 "SELECT name FROM sqlite_temp_master "
|
|
1136 "WHERE type='index' AND tbl_name LIKE shellstatic() "
|
|
1137 "ORDER BY 1",
|
|
1138 callback, &data, &zErrMsg
|
|
1139 );
|
|
1140 zShellStatic = 0;
|
|
1141 if( zErrMsg ){
|
|
1142 fprintf(stderr,"Error: %s\n", zErrMsg);
|
|
1143 sqlite3_free(zErrMsg);
|
|
1144 }
|
|
1145 }else
|
|
1146
|
|
1147 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
|
|
1148 int n2 = strlen(azArg[1]);
|
|
1149 if( strncmp(azArg[1],"line",n2)==0
|
|
1150 ||
|
|
1151 strncmp(azArg[1],"lines",n2)==0 ){
|
|
1152 p->mode = MODE_Line;
|
|
1153 }else if( strncmp(azArg[1],"column",n2)==0
|
|
1154 ||
|
|
1155 strncmp(azArg[1],"columns",n2)==0 ){
|
|
1156 p->mode = MODE_Column;
|
|
1157 }else if( strncmp(azArg[1],"list",n2)==0 ){
|
|
1158 p->mode = MODE_List;
|
|
1159 }else if( strncmp(azArg[1],"html",n2)==0 ){
|
|
1160 p->mode = MODE_Html;
|
|
1161 }else if( strncmp(azArg[1],"tcl",n2)==0 ){
|
|
1162 p->mode = MODE_Tcl;
|
|
1163 }else if( strncmp(azArg[1],"csv",n2)==0 ){
|
|
1164 p->mode = MODE_Csv;
|
|
1165 strcpy(p->separator, ",");
|
|
1166 }else if( strncmp(azArg[1],"tabs",n2)==0 ){
|
|
1167 p->mode = MODE_List;
|
|
1168 strcpy(p->separator, "\t");
|
|
1169 }else if( strncmp(azArg[1],"insert",n2)==0 ){
|
|
1170 p->mode = MODE_Insert;
|
|
1171 if( nArg>=3 ){
|
|
1172 set_table_name(p, azArg[2]);
|
|
1173 }else{
|
|
1174 set_table_name(p, "table");
|
|
1175 }
|
|
1176 }else {
|
|
1177 fprintf(stderr,"mode should be on of: "
|
|
1178 "column csv html insert line list tabs tcl\n");
|
|
1179 }
|
|
1180 }else
|
|
1181
|
|
1182 if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
|
|
1183 sprintf(p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
|
|
1184 }else
|
|
1185
|
|
1186 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
|
|
1187 if( p->out!=stdout ){
|
|
1188 fclose(p->out);
|
|
1189 }
|
|
1190 if( strcmp(azArg[1],"stdout")==0 ){
|
|
1191 p->out = stdout;
|
|
1192 strcpy(p->outfile,"stdout");
|
|
1193 }else{
|
|
1194 p->out = fopen(azArg[1], "wb");
|
|
1195 if( p->out==0 ){
|
|
1196 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
|
|
1197 p->out = stdout;
|
|
1198 } else {
|
|
1199 strcpy(p->outfile,azArg[1]);
|
|
1200 }
|
|
1201 }
|
|
1202 }else
|
|
1203
|
|
1204 if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
|
|
1205 if( nArg >= 2) {
|
|
1206 strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
|
|
1207 }
|
|
1208 if( nArg >= 3) {
|
|
1209 strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
|
|
1210 }
|
|
1211 }else
|
|
1212
|
|
1213 if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
|
|
1214 rc = 1;
|
|
1215 }else
|
|
1216
|
|
1217 if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
|
|
1218 FILE *alt = fopen(azArg[1], "rb");
|
|
1219 if( alt==0 ){
|
|
1220 fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
|
|
1221 }else{
|
|
1222 process_input(p, alt);
|
|
1223 fclose(alt);
|
|
1224 }
|
|
1225 }else
|
|
1226
|
|
1227 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
|
|
1228 struct callback_data data;
|
|
1229 char *zErrMsg = 0;
|
|
1230 open_db(p);
|
|
1231 memcpy(&data, p, sizeof(data));
|
|
1232 data.showHeader = 0;
|
|
1233 data.mode = MODE_Semi;
|
|
1234 if( nArg>1 ){
|
|
1235 int i;
|
|
1236 for(i=0; azArg[1][i]; i++) azArg[1][i] = tolower(azArg[1][i]);
|
|
1237 if( strcmp(azArg[1],"sqlite_master")==0 ){
|
|
1238 char *new_argv[2], *new_colv[2];
|
|
1239 new_argv[0] = "CREATE TABLE sqlite_master (\n"
|
|
1240 " type text,\n"
|
|
1241 " name text,\n"
|
|
1242 " tbl_name text,\n"
|
|
1243 " rootpage integer,\n"
|
|
1244 " sql text\n"
|
|
1245 ")";
|
|
1246 new_argv[1] = 0;
|
|
1247 new_colv[0] = "sql";
|
|
1248 new_colv[1] = 0;
|
|
1249 callback(&data, 1, new_argv, new_colv);
|
|
1250 }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
|
|
1251 char *new_argv[2], *new_colv[2];
|
|
1252 new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
|
|
1253 " type text,\n"
|
|
1254 " name text,\n"
|
|
1255 " tbl_name text,\n"
|
|
1256 " rootpage integer,\n"
|
|
1257 " sql text\n"
|
|
1258 ")";
|
|
1259 new_argv[1] = 0;
|
|
1260 new_colv[0] = "sql";
|
|
1261 new_colv[1] = 0;
|
|
1262 callback(&data, 1, new_argv, new_colv);
|
|
1263 }else{
|
|
1264 zShellStatic = azArg[1];
|
|
1265 sqlite3_exec(p->db,
|
|
1266 "SELECT sql FROM "
|
|
1267 " (SELECT * FROM sqlite_master UNION ALL"
|
|
1268 " SELECT * FROM sqlite_temp_master) "
|
|
1269 "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTNULL "
|
|
1270 "ORDER BY substr(type,2,1), name",
|
|
1271 callback, &data, &zErrMsg);
|
|
1272 zShellStatic = 0;
|
|
1273 }
|
|
1274 }else{
|
|
1275 sqlite3_exec(p->db,
|
|
1276 "SELECT sql FROM "
|
|
1277 " (SELECT * FROM sqlite_master UNION ALL"
|
|
1278 " SELECT * FROM sqlite_temp_master) "
|
|
1279 "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
|
|
1280 "ORDER BY substr(type,2,1), name",
|
|
1281 callback, &data, &zErrMsg
|
|
1282 );
|
|
1283 }
|
|
1284 if( zErrMsg ){
|
|
1285 fprintf(stderr,"Error: %s\n", zErrMsg);
|
|
1286 sqlite3_free(zErrMsg);
|
|
1287 }
|
|
1288 }else
|
|
1289
|
|
1290 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
|
|
1291 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
|
|
1292 }else
|
|
1293
|
|
1294 if( c=='s' && strncmp(azArg[0], "show", n)==0){
|
|
1295 int i;
|
|
1296 fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
|
|
1297 fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
|
|
1298 fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
|
|
1299 fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
|
|
1300 fprintf(p->out,"%9.9s: ", "nullvalue");
|
|
1301 output_c_string(p->out, p->nullvalue);
|
|
1302 fprintf(p->out, "\n");
|
|
1303 fprintf(p->out,"%9.9s: %s\n","output",
|
|
1304 strlen(p->outfile) ? p->outfile : "stdout");
|
|
1305 fprintf(p->out,"%9.9s: ", "separator");
|
|
1306 output_c_string(p->out, p->separator);
|
|
1307 fprintf(p->out, "\n");
|
|
1308 fprintf(p->out,"%9.9s: ","width");
|
|
1309 for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
|
|
1310 fprintf(p->out,"%d ",p->colWidth[i]);
|
|
1311 }
|
|
1312 fprintf(p->out,"\n");
|
|
1313 }else
|
|
1314
|
|
1315 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
|
|
1316 char **azResult;
|
|
1317 int nRow, rc;
|
|
1318 char *zErrMsg;
|
|
1319 open_db(p);
|
|
1320 if( nArg==1 ){
|
|
1321 rc = sqlite3_get_table(p->db,
|
|
1322 "SELECT name FROM sqlite_master "
|
|
1323 "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'"
|
|
1324 "UNION ALL "
|
|
1325 "SELECT name FROM sqlite_temp_master "
|
|
1326 "WHERE type IN ('table','view') "
|
|
1327 "ORDER BY 1",
|
|
1328 &azResult, &nRow, 0, &zErrMsg
|
|
1329 );
|
|
1330 }else{
|
|
1331 zShellStatic = azArg[1];
|
|
1332 rc = sqlite3_get_table(p->db,
|
|
1333 "SELECT name FROM sqlite_master "
|
|
1334 "WHERE type IN ('table','view') AND name LIKE '%'||shellstatic()||'%' "
|
|
1335 "UNION ALL "
|
|
1336 "SELECT name FROM sqlite_temp_master "
|
|
1337 "WHERE type IN ('table','view') AND name LIKE '%'||shellstatic()||'%' "
|
|
1338 "ORDER BY 1",
|
|
1339 &azResult, &nRow, 0, &zErrMsg
|
|
1340 );
|
|
1341 zShellStatic = 0;
|
|
1342 }
|
|
1343 if( zErrMsg ){
|
|
1344 fprintf(stderr,"Error: %s\n", zErrMsg);
|
|
1345 sqlite3_free(zErrMsg);
|
|
1346 }
|
|
1347 if( rc==SQLITE_OK ){
|
|
1348 int len, maxlen = 0;
|
|
1349 int i, j;
|
|
1350 int nPrintCol, nPrintRow;
|
|
1351 for(i=1; i<=nRow; i++){
|
|
1352 if( azResult[i]==0 ) continue;
|
|
1353 len = strlen(azResult[i]);
|
|
1354 if( len>maxlen ) maxlen = len;
|
|
1355 }
|
|
1356 nPrintCol = 80/(maxlen+2);
|
|
1357 if( nPrintCol<1 ) nPrintCol = 1;
|
|
1358 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
|
|
1359 for(i=0; i<nPrintRow; i++){
|
|
1360 for(j=i+1; j<=nRow; j+=nPrintRow){
|
|
1361 char *zSp = j<=nPrintRow ? "" : " ";
|
|
1362 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
|
|
1363 }
|
|
1364 printf("\n");
|
|
1365 }
|
|
1366 }
|
|
1367 sqlite3_free_table(azResult);
|
|
1368 }else
|
|
1369
|
|
1370 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
|
|
1371 open_db(p);
|
|
1372 sqlite3_busy_timeout(p->db, atoi(azArg[1]));
|
|
1373 }else
|
|
1374
|
|
1375 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
|
|
1376 int j;
|
|
1377 assert( nArg<=ArraySize(azArg) );
|
|
1378 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
|
|
1379 p->colWidth[j-1] = atoi(azArg[j]);
|
|
1380 }
|
|
1381 }else
|
|
1382
|
|
1383 {
|
|
1384 fprintf(stderr, "unknown command or invalid arguments: "
|
|
1385 " \"%s\". Enter \".help\" for help\n", azArg[0]);
|
|
1386 }
|
|
1387
|
|
1388 return rc;
|
|
1389 }
|
|
1390
|
|
1391 /*
|
|
1392 ** Return TRUE if the last non-whitespace character in z[] is a semicolon.
|
|
1393 ** z[] is N characters long.
|
|
1394 */
|
|
1395 static int _ends_with_semicolon(const char *z, int N){
|
|
1396 while( N>0 && isspace((unsigned char)z[N-1]) ){ N--; }
|
|
1397 return N>0 && z[N-1]==';';
|
|
1398 }
|
|
1399
|
|
1400 /*
|
|
1401 ** Test to see if a line consists entirely of whitespace.
|
|
1402 */
|
|
1403 static int _all_whitespace(const char *z){
|
|
1404 for(; *z; z++){
|
|
1405 if( isspace(*(unsigned char*)z) ) continue;
|
|
1406 if( *z=='/' && z[1]=='*' ){
|
|
1407 z += 2;
|
|
1408 while( *z && (*z!='*' || z[1]!='/') ){ z++; }
|
|
1409 if( *z==0 ) return 0;
|
|
1410 z++;
|
|
1411 continue;
|
|
1412 }
|
|
1413 if( *z=='-' && z[1]=='-' ){
|
|
1414 z += 2;
|
|
1415 while( *z && *z!='\n' ){ z++; }
|
|
1416 if( *z==0 ) return 1;
|
|
1417 continue;
|
|
1418 }
|
|
1419 return 0;
|
|
1420 }
|
|
1421 return 1;
|
|
1422 }
|
|
1423
|
|
1424 /*
|
|
1425 ** Return TRUE if the line typed in is an SQL command terminator other
|
|
1426 ** than a semi-colon. The SQL Server style "go" command is understood
|
|
1427 ** as is the Oracle "/".
|
|
1428 */
|
|
1429 static int _is_command_terminator(const char *zLine){
|
|
1430 while( isspace(*(unsigned char*)zLine) ){ zLine++; };
|
|
1431 if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ) return 1; /* Oracle */
|
|
1432 if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o'
|
|
1433 && _all_whitespace(&zLine[2]) ){
|
|
1434 return 1; /* SQL Server */
|
|
1435 }
|
|
1436 return 0;
|
|
1437 }
|
|
1438
|
|
1439 /*
|
|
1440 ** Read input from *in and process it. If *in==0 then input
|
|
1441 ** is interactive - the user is typing it it. Otherwise, input
|
|
1442 ** is coming from a file or device. A prompt is issued and history
|
|
1443 ** is saved only if input is interactive. An interrupt signal will
|
|
1444 ** cause this routine to exit immediately, unless input is interactive.
|
|
1445 */
|
|
1446 static void process_input(struct callback_data *p, FILE *in){
|
|
1447 char *zLine;
|
|
1448 char *zSql = 0;
|
|
1449 int nSql = 0;
|
|
1450 char *zErrMsg;
|
|
1451 int rc;
|
|
1452 while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
|
|
1453 if( seenInterrupt ){
|
|
1454 if( in!=0 ) break;
|
|
1455 seenInterrupt = 0;
|
|
1456 }
|
|
1457 if( p->echoOn ) printf("%s\n", zLine);
|
|
1458 if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
|
|
1459 if( zLine && zLine[0]=='.' && nSql==0 ){
|
|
1460 int rc = do_meta_command(zLine, p);
|
|
1461 free(zLine);
|
|
1462 if( rc ) break;
|
|
1463 continue;
|
|
1464 }
|
|
1465 if( _is_command_terminator(zLine) ){
|
|
1466 strcpy(zLine,";");
|
|
1467 }
|
|
1468 if( zSql==0 ){
|
|
1469 int i;
|
|
1470 for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){}
|
|
1471 if( zLine[i]!=0 ){
|
|
1472 nSql = strlen(zLine);
|
|
1473 zSql = malloc( nSql+1 );
|
|
1474 if( zSql==0 ){
|
|
1475 fprintf(stderr, "out of memory\n");
|
|
1476 exit(1);
|
|
1477 }
|
|
1478 strcpy(zSql, zLine);
|
|
1479 }
|
|
1480 }else{
|
|
1481 int len = strlen(zLine);
|
|
1482 zSql = realloc( zSql, nSql + len + 2 );
|
|
1483 if( zSql==0 ){
|
|
1484 fprintf(stderr,"%s: out of memory!\n", Argv0);
|
|
1485 exit(1);
|
|
1486 }
|
|
1487 strcpy(&zSql[nSql++], "\n");
|
|
1488 strcpy(&zSql[nSql], zLine);
|
|
1489 nSql += len;
|
|
1490 }
|
|
1491 free(zLine);
|
|
1492 if( zSql && _ends_with_semicolon(zSql, nSql) && sqlite3_complete(zSql) ){
|
|
1493 p->cnt = 0;
|
|
1494 open_db(p);
|
|
1495 rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
|
|
1496 if( rc || zErrMsg ){
|
|
1497 /* if( in!=0 && !p->echoOn ) printf("%s\n",zSql); */
|
|
1498 if( zErrMsg!=0 ){
|
|
1499 printf("SQL error: %s\n", zErrMsg);
|
|
1500 sqlite3_free(zErrMsg);
|
|
1501 zErrMsg = 0;
|
|
1502 }else{
|
|
1503 printf("SQL error: %s\n", sqlite3_errmsg(p->db));
|
|
1504 }
|
|
1505 }
|
|
1506 free(zSql);
|
|
1507 zSql = 0;
|
|
1508 nSql = 0;
|
|
1509 }
|
|
1510 }
|
|
1511 if( zSql ){
|
|
1512 if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
|
|
1513 free(zSql);
|
|
1514 }
|
|
1515 }
|
|
1516
|
|
1517 /*
|
|
1518 ** Return a pathname which is the user's home directory. A
|
|
1519 ** 0 return indicates an error of some kind. Space to hold the
|
|
1520 ** resulting string is obtained from malloc(). The calling
|
|
1521 ** function should free the result.
|
|
1522 */
|
|
1523 static char *find_home_dir(void){
|
|
1524 char *home_dir = NULL;
|
|
1525
|
|
1526 #if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__)
|
|
1527 struct passwd *pwent;
|
|
1528 uid_t uid = getuid();
|
|
1529 if( (pwent=getpwuid(uid)) != NULL) {
|
|
1530 home_dir = pwent->pw_dir;
|
|
1531 }
|
|
1532 #endif
|
|
1533
|
|
1534 #ifdef __MACOS__
|
|
1535 char home_path[_MAX_PATH+1];
|
|
1536 home_dir = getcwd(home_path, _MAX_PATH);
|
|
1537 #endif
|
|
1538
|
|
1539 if (!home_dir) {
|
|
1540 home_dir = getenv("HOME");
|
|
1541 if (!home_dir) {
|
|
1542 home_dir = getenv("HOMEPATH"); /* Windows? */
|
|
1543 }
|
|
1544 }
|
|
1545
|
|
1546 #if defined(_WIN32) || defined(WIN32)
|
|
1547 if (!home_dir) {
|
|
1548 home_dir = "c:";
|
|
1549 }
|
|
1550 #endif
|
|
1551
|
|
1552 if( home_dir ){
|
|
1553 char *z = malloc( strlen(home_dir)+1 );
|
|
1554 if( z ) strcpy(z, home_dir);
|
|
1555 home_dir = z;
|
|
1556 }
|
|
1557
|
|
1558 return home_dir;
|
|
1559 }
|
|
1560
|
|
1561 /*
|
|
1562 ** Read input from the file given by sqliterc_override. Or if that
|
|
1563 ** parameter is NULL, take input from ~/.sqliterc
|
|
1564 */
|
|
1565 static void process_sqliterc(
|
|
1566 struct callback_data *p, /* Configuration data */
|
|
1567 const char *sqliterc_override /* Name of config file. NULL to use default */
|
|
1568 ){
|
|
1569 char *home_dir = NULL;
|
|
1570 const char *sqliterc = sqliterc_override;
|
|
1571 char *zBuf = 0;
|
|
1572 FILE *in = NULL;
|
|
1573
|
|
1574 if (sqliterc == NULL) {
|
|
1575 home_dir = find_home_dir();
|
|
1576 if( home_dir==0 ){
|
|
1577 fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
|
|
1578 return;
|
|
1579 }
|
|
1580 zBuf = malloc(strlen(home_dir) + 15);
|
|
1581 if( zBuf==0 ){
|
|
1582 fprintf(stderr,"%s: out of memory!\n", Argv0);
|
|
1583 exit(1);
|
|
1584 }
|
|
1585 sprintf(zBuf,"%s/.sqliterc",home_dir);
|
|
1586 free(home_dir);
|
|
1587 sqliterc = (const char*)zBuf;
|
|
1588 }
|
|
1589 in = fopen(sqliterc,"rb");
|
|
1590 if( in ){
|
|
1591 if( isatty(fileno(stdout)) ){
|
|
1592 printf("Loading resources from %s\n",sqliterc);
|
|
1593 }
|
|
1594 process_input(p,in);
|
|
1595 fclose(in);
|
|
1596 }
|
|
1597 free(zBuf);
|
|
1598 return;
|
|
1599 }
|
|
1600
|
|
1601 /*
|
|
1602 ** Show available command line options
|
|
1603 */
|
|
1604 static const char zOptions[] =
|
|
1605 " -init filename read/process named file\n"
|
|
1606 " -echo print commands before execution\n"
|
|
1607 " -[no]header turn headers on or off\n"
|
|
1608 " -column set output mode to 'column'\n"
|
|
1609 " -html set output mode to HTML\n"
|
|
1610 " -line set output mode to 'line'\n"
|
|
1611 " -list set output mode to 'list'\n"
|
|
1612 " -separator 'x' set output field separator (|)\n"
|
|
1613 " -nullvalue 'text' set text string for NULL values\n"
|
|
1614 " -version show SQLite version\n"
|
|
1615 " -help show this text, also show dot-commands\n"
|
|
1616 ;
|
|
1617 static void usage(int showDetail){
|
|
1618 fprintf(stderr, "Usage: %s [OPTIONS] FILENAME [SQL]\n", Argv0);
|
|
1619 if( showDetail ){
|
|
1620 fprintf(stderr, "Options are:\n%s", zOptions);
|
|
1621 }else{
|
|
1622 fprintf(stderr, "Use the -help option for additional information\n");
|
|
1623 }
|
|
1624 exit(1);
|
|
1625 }
|
|
1626
|
|
1627 /*
|
|
1628 ** Initialize the state information in data
|
|
1629 */
|
|
1630 static void main_init(struct callback_data *data) {
|
|
1631 memset(data, 0, sizeof(*data));
|
|
1632 data->mode = MODE_List;
|
|
1633 strcpy(data->separator,"|");
|
|
1634 data->showHeader = 0;
|
|
1635 strcpy(mainPrompt,"sqlite> ");
|
|
1636 strcpy(continuePrompt," ...> ");
|
|
1637 }
|
|
1638
|
|
1639 int main(int argc, char **argv){
|
|
1640 char *zErrMsg = 0;
|
|
1641 struct callback_data data;
|
|
1642 const char *zInitFile = 0;
|
|
1643 char *zFirstCmd = 0;
|
|
1644 int i;
|
|
1645
|
|
1646 #ifdef __MACOS__
|
|
1647 argc = ccommand(&argv);
|
|
1648 #endif
|
|
1649
|
|
1650 Argv0 = argv[0];
|
|
1651 main_init(&data);
|
|
1652
|
|
1653 /* Make sure we have a valid signal handler early, before anything
|
|
1654 ** else is done.
|
|
1655 */
|
|
1656 #ifdef SIGINT
|
|
1657 signal(SIGINT, interrupt_handler);
|
|
1658 #endif
|
|
1659
|
|
1660 /* Do an initial pass through the command-line argument to locate
|
|
1661 ** the name of the database file, the name of the initialization file,
|
|
1662 ** and the first command to execute.
|
|
1663 */
|
|
1664 for(i=1; i<argc-1; i++){
|
|
1665 if( argv[i][0]!='-' ) break;
|
|
1666 if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
|
|
1667 i++;
|
|
1668 }else if( strcmp(argv[i],"-init")==0 ){
|
|
1669 i++;
|
|
1670 zInitFile = argv[i];
|
|
1671 }else if( strcmp(argv[i],"-key")==0 ){
|
|
1672 i++;
|
|
1673 data.zKey = sqlite3_mprintf("%s",argv[i]);
|
|
1674 }
|
|
1675 }
|
|
1676 if( i<argc ){
|
|
1677 data.zDbFilename = argv[i++];
|
|
1678 }else{
|
|
1679 #ifndef SQLITE_OMIT_MEMORYDB
|
|
1680 data.zDbFilename = ":memory:";
|
|
1681 #else
|
|
1682 data.zDbFilename = 0;
|
|
1683 #endif
|
|
1684 }
|
|
1685 if( i<argc ){
|
|
1686 zFirstCmd = argv[i++];
|
|
1687 }
|
|
1688 data.out = stdout;
|
|
1689
|
|
1690 #ifdef SQLITE_OMIT_MEMORYDB
|
|
1691 if( data.zDbFilename==0 ){
|
|
1692 fprintf(stderr,"%s: no database filename specified\n", argv[0]);
|
|
1693 exit(1);
|
|
1694 }
|
|
1695 #endif
|
|
1696
|
|
1697 /* Go ahead and open the database file if it already exists. If the
|
|
1698 ** file does not exist, delay opening it. This prevents empty database
|
|
1699 ** files from being created if a user mistypes the database name argument
|
|
1700 ** to the sqlite command-line tool.
|
|
1701 */
|
|
1702 if( access(data.zDbFilename, 0)==0 ){
|
|
1703 open_db(&data);
|
|
1704 }
|
|
1705
|
|
1706 /* Process the initialization file if there is one. If no -init option
|
|
1707 ** is given on the command line, look for a file named ~/.sqliterc and
|
|
1708 ** try to process it.
|
|
1709 */
|
|
1710 process_sqliterc(&data,zInitFile);
|
|
1711
|
|
1712 /* Make a second pass through the command-line argument and set
|
|
1713 ** options. This second pass is delayed until after the initialization
|
|
1714 ** file is processed so that the command-line arguments will override
|
|
1715 ** settings in the initialization file.
|
|
1716 */
|
|
1717 for(i=1; i<argc && argv[i][0]=='-'; i++){
|
|
1718 char *z = argv[i];
|
|
1719 if( strcmp(z,"-init")==0 || strcmp(z,"-key")==0 ){
|
|
1720 i++;
|
|
1721 }else if( strcmp(z,"-html")==0 ){
|
|
1722 data.mode = MODE_Html;
|
|
1723 }else if( strcmp(z,"-list")==0 ){
|
|
1724 data.mode = MODE_List;
|
|
1725 }else if( strcmp(z,"-line")==0 ){
|
|
1726 data.mode = MODE_Line;
|
|
1727 }else if( strcmp(z,"-column")==0 ){
|
|
1728 data.mode = MODE_Column;
|
|
1729 }else if( strcmp(z,"-separator")==0 ){
|
|
1730 i++;
|
|
1731 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
|
|
1732 }else if( strcmp(z,"-nullvalue")==0 ){
|
|
1733 i++;
|
|
1734 sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
|
|
1735 }else if( strcmp(z,"-header")==0 ){
|
|
1736 data.showHeader = 1;
|
|
1737 }else if( strcmp(z,"-noheader")==0 ){
|
|
1738 data.showHeader = 0;
|
|
1739 }else if( strcmp(z,"-echo")==0 ){
|
|
1740 data.echoOn = 1;
|
|
1741 }else if( strcmp(z,"-version")==0 ){
|
|
1742 printf("%s\n", sqlite3_libversion());
|
|
1743 return 0;
|
|
1744 }else if( strcmp(z,"-help")==0 ){
|
|
1745 usage(1);
|
|
1746 }else{
|
|
1747 fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
|
|
1748 fprintf(stderr,"Use -help for a list of options.\n");
|
|
1749 return 1;
|
|
1750 }
|
|
1751 }
|
|
1752
|
|
1753 if( zFirstCmd ){
|
|
1754 /* Run just the command that follows the database name
|
|
1755 */
|
|
1756 if( zFirstCmd[0]=='.' ){
|
|
1757 do_meta_command(zFirstCmd, &data);
|
|
1758 exit(0);
|
|
1759 }else{
|
|
1760 int rc;
|
|
1761 open_db(&data);
|
|
1762 rc = sqlite3_exec(data.db, zFirstCmd, callback, &data, &zErrMsg);
|
|
1763 if( rc!=0 && zErrMsg!=0 ){
|
|
1764 fprintf(stderr,"SQL error: %s\n", zErrMsg);
|
|
1765 exit(1);
|
|
1766 }
|
|
1767 }
|
|
1768 }else{
|
|
1769 /* Run commands received from standard input
|
|
1770 */
|
|
1771 if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){
|
|
1772 char *zHome;
|
|
1773 char *zHistory = 0;
|
|
1774 printf(
|
|
1775 "SQLite version %s\n"
|
|
1776 "Enter \".help\" for instructions\n",
|
|
1777 sqlite3_libversion()
|
|
1778 );
|
|
1779 zHome = find_home_dir();
|
|
1780 if( zHome && (zHistory = malloc(strlen(zHome)+20))!=0 ){
|
|
1781 sprintf(zHistory,"%s/.sqlite_history", zHome);
|
|
1782 }
|
|
1783 #if defined(HAVE_READLINE) && HAVE_READLINE==1
|
|
1784 if( zHistory ) read_history(zHistory);
|
|
1785 #endif
|
|
1786 process_input(&data, 0);
|
|
1787 if( zHistory ){
|
|
1788 stifle_history(100);
|
|
1789 write_history(zHistory);
|
|
1790 }
|
|
1791 }else{
|
|
1792 process_input(&data, stdin);
|
|
1793 }
|
|
1794 }
|
|
1795 set_table_name(&data, 0);
|
|
1796 if( db ) sqlite3_close(db);
|
|
1797 return 0;
|
|
1798 }
|