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