blob: 5f912f4306364e37afacdaa745f0e2f91f873dc1 [file] [log] [blame]
drh75897232000-05-29 14:26:00 +00001/*
drhb19a2bc2001-09-16 00:13:26 +00002** 2001 September 15
drh75897232000-05-29 14:26:00 +00003**
drhb19a2bc2001-09-16 00:13:26 +00004** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
drh75897232000-05-29 14:26:00 +00006**
drhb19a2bc2001-09-16 00:13:26 +00007** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
drh75897232000-05-29 14:26:00 +000010**
11*************************************************************************
12** This file contains code to implement the "sqlite" command line
13** utility for accessing SQLite databases.
drh75897232000-05-29 14:26:00 +000014*/
shane18e526c2008-12-10 22:30:24 +000015#if defined(_WIN32) || defined(WIN32)
16/* This needs to come before any includes for MSVC compiler */
17#define _CRT_SECURE_NO_WARNINGS
18#endif
19
drh75897232000-05-29 14:26:00 +000020#include <stdlib.h>
21#include <string.h>
22#include <stdio.h>
danielk19772a02e332004-06-05 08:04:36 +000023#include <assert.h>
drh1d482dd2004-05-31 18:23:07 +000024#include "sqlite3.h"
drh75897232000-05-29 14:26:00 +000025#include <ctype.h>
drhb0603412007-02-28 04:47:26 +000026#include <stdarg.h>
persicom7e2dfdd2002-04-18 02:46:52 +000027
drh454ad582007-11-26 22:54:27 +000028#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
drh4c504392000-10-16 22:06:40 +000029# include <signal.h>
chw97185482008-11-17 08:05:31 +000030# if !defined(__RTP__) && !defined(_WRS_KERNEL)
31# include <pwd.h>
32# endif
drhdd45df82002-04-18 12:39:03 +000033# include <unistd.h>
34# include <sys/types.h>
drh4c504392000-10-16 22:06:40 +000035#endif
drh75897232000-05-29 14:26:00 +000036
drhcdb36b72006-06-12 12:57:45 +000037#ifdef __OS2__
38# include <unistd.h>
39#endif
40
drh16e59552000-07-31 11:57:37 +000041#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh8e7e7a22000-05-30 18:45:23 +000042# include <readline/readline.h>
43# include <readline/history.h>
44#else
drh9347b202003-07-18 01:30:59 +000045# define readline(p) local_getline(p,stdin)
persicom1d0b8722002-04-18 02:53:04 +000046# define add_history(X)
drh67505e72002-04-19 12:34:06 +000047# define read_history(X)
48# define write_history(X)
49# define stifle_history(X)
drh75897232000-05-29 14:26:00 +000050#endif
51
adamd2e8464a2006-09-06 21:39:40 +000052#if defined(_WIN32) || defined(WIN32)
53# include <io.h>
shane18e526c2008-12-10 22:30:24 +000054#define isatty(h) _isatty(h)
55#define access(f,m) _access((f),(m))
adamd2e8464a2006-09-06 21:39:40 +000056#else
drh4328c8b2003-04-26 02:50:11 +000057/* Make sure isatty() has a prototype.
58*/
59extern int isatty();
adamd2e8464a2006-09-06 21:39:40 +000060#endif
drh4328c8b2003-04-26 02:50:11 +000061
chw65d3c132007-11-12 21:09:10 +000062#if defined(_WIN32_WCE)
63/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
64 * thus we always assume that we have a console. That can be
65 * overridden with the -batch command line option.
66 */
67#define isatty(x) 1
68#endif
69
chw97185482008-11-17 08:05:31 +000070#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
drh3b1a9882007-11-02 12:53:03 +000071#include <sys/time.h>
72#include <sys/resource.h>
73
drhda108222009-02-25 19:07:24 +000074/* Saved resource information for the beginning of an operation */
75static struct rusage sBegin;
76
77/* True if the timer is enabled */
78static int enableTimer = 0;
79
80/*
81** Begin timing an operation
82*/
83static void beginTimer(void){
84 if( enableTimer ){
85 getrusage(RUSAGE_SELF, &sBegin);
86 }
87}
88
89/* Return the difference of two time_structs in seconds */
90static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
91 return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
92 (double)(pEnd->tv_sec - pStart->tv_sec);
93}
94
95/*
96** Print the timing results.
97*/
98static void endTimer(void){
99 if( enableTimer ){
100 struct rusage sEnd;
101 getrusage(RUSAGE_SELF, &sEnd);
102 printf("CPU Time: user %f sys %f\n",
103 timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
104 timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
105 }
106}
shaneb320ccd2009-10-21 03:42:58 +0000107
drhda108222009-02-25 19:07:24 +0000108#define BEGIN_TIMER beginTimer()
109#define END_TIMER endTimer()
110#define HAS_TIMER 1
shaneb320ccd2009-10-21 03:42:58 +0000111
112#elif (defined(_WIN32) || defined(WIN32))
113
114#include <windows.h>
115
116/* Saved resource information for the beginning of an operation */
117static HANDLE hProcess;
118static FILETIME ftKernelBegin;
119static FILETIME ftUserBegin;
120typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
121static GETPROCTIMES getProcessTimesAddr = NULL;
122
123/* True if the timer is enabled */
124static int enableTimer = 0;
125
126/*
127** Check to see if we have timer support. Return 1 if necessary
128** support found (or found previously).
129*/
130static int hasTimer(void){
131 if( getProcessTimesAddr ){
132 return 1;
133 } else {
134 /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions.
135 ** See if the version we are running on has it, and if it does, save off
136 ** a pointer to it and the current process handle.
137 */
138 hProcess = GetCurrentProcess();
139 if( hProcess ){
140 HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
141 if( NULL != hinstLib ){
142 getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
143 if( NULL != getProcessTimesAddr ){
144 return 1;
145 }
146 FreeLibrary(hinstLib);
147 }
148 }
149 }
150 return 0;
151}
152
153/*
154** Begin timing an operation
155*/
156static void beginTimer(void){
157 if( enableTimer && getProcessTimesAddr ){
158 FILETIME ftCreation, ftExit;
159 getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
160 }
161}
162
163/* Return the difference of two FILETIME structs in seconds */
164static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
165 sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
166 sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
167 return (double) ((i64End - i64Start) / 10000000.0);
168}
169
170/*
171** Print the timing results.
172*/
173static void endTimer(void){
174 if( enableTimer && getProcessTimesAddr){
175 FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
176 getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
177 printf("CPU Time: user %f sys %f\n",
178 timeDiff(&ftUserBegin, &ftUserEnd),
179 timeDiff(&ftKernelBegin, &ftKernelEnd));
180 }
181}
182
183#define BEGIN_TIMER beginTimer()
184#define END_TIMER endTimer()
185#define HAS_TIMER hasTimer()
186
drhda108222009-02-25 19:07:24 +0000187#else
188#define BEGIN_TIMER
189#define END_TIMER
190#define HAS_TIMER 0
191#endif
192
shanec0688ea2009-03-05 03:48:06 +0000193/*
194** Used to prevent warnings about unused parameters
195*/
196#define UNUSED_PARAMETER(x) (void)(x)
197
danielk1977c8c70692009-02-25 15:22:02 +0000198
199/**************************************************************************
200***************************************************************************
201** Begin genfkey logic.
202*/
203#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined SQLITE_OMIT_SUBQUERY
204
205#define GENFKEY_ERROR 1
206#define GENFKEY_DROPTRIGGER 2
207#define GENFKEY_CREATETRIGGER 3
208static int genfkey_create_triggers(sqlite3 *, const char *, void *,
209 int (*)(void *, int, const char *)
210);
211
212struct GenfkeyCb {
213 void *pCtx;
214 int eType;
215 int (*xData)(void *, int, const char *);
216};
217typedef struct GenfkeyCb GenfkeyCb;
218
219/* The code in this file defines a sqlite3 virtual-table module that
220** provides a read-only view of the current database schema. There is one
221** row in the schema table for each column in the database schema.
222*/
223#define SCHEMA \
224"CREATE TABLE x(" \
225 "database," /* Name of database (i.e. main, temp etc.) */ \
226 "tablename," /* Name of table */ \
227 "cid," /* Column number (from left-to-right, 0 upward) */ \
228 "name," /* Column name */ \
229 "type," /* Specified type (i.e. VARCHAR(32)) */ \
230 "not_null," /* Boolean. True if NOT NULL was specified */ \
231 "dflt_value," /* Default value for this column */ \
232 "pk" /* True if this column is part of the primary key */ \
233")"
234
235#define SCHEMA2 \
236"CREATE TABLE x(" \
237 "database," /* Name of database (i.e. main, temp etc.) */ \
238 "from_tbl," /* Name of table */ \
239 "fkid," \
240 "seq," \
241 "to_tbl," \
242 "from_col," \
243 "to_col," \
244 "on_update," \
245 "on_delete," \
246 "match" \
247")"
248
249#define SCHEMA3 \
250"CREATE TABLE x(" \
251 "database," /* Name of database (i.e. main, temp etc.) */ \
252 "tablename," /* Name of table */ \
253 "seq," \
254 "name," \
255 "isunique" \
256")"
257
258#define SCHEMA4 \
259"CREATE TABLE x(" \
260 "database," /* Name of database (i.e. main, temp etc.) */ \
261 "indexname," /* Name of table */ \
262 "seqno," \
263 "cid," \
264 "name" \
265")"
266
267#define SCHEMA5 \
268"CREATE TABLE x(" \
269 "database," /* Name of database (i.e. main, temp etc.) */ \
270 "triggername," /* Name of trigger */ \
271 "dummy" /* Unused */ \
272")"
273
274typedef struct SchemaTable SchemaTable;
shane16f954c2009-10-21 13:53:58 +0000275static struct SchemaTable {
danielk1977c8c70692009-02-25 15:22:02 +0000276 const char *zName;
277 const char *zObject;
278 const char *zPragma;
279 const char *zSchema;
280} aSchemaTable[] = {
281 { "table_info", "table", "PRAGMA %Q.table_info(%Q)", SCHEMA },
282 { "foreign_key_list", "table", "PRAGMA %Q.foreign_key_list(%Q)", SCHEMA2 },
283 { "index_list", "table", "PRAGMA %Q.index_list(%Q)", SCHEMA3 },
284 { "index_info", "index", "PRAGMA %Q.index_info(%Q)", SCHEMA4 },
285 { "trigger_list", "trigger", "SELECT 1", SCHEMA5 },
286 { 0, 0, 0, 0 }
287};
288
289typedef struct schema_vtab schema_vtab;
290typedef struct schema_cursor schema_cursor;
291
292/* A schema table object */
293struct schema_vtab {
294 sqlite3_vtab base;
295 sqlite3 *db;
296 SchemaTable *pType;
297};
298
299/* A schema table cursor object */
300struct schema_cursor {
301 sqlite3_vtab_cursor base;
302 sqlite3_stmt *pDbList;
303 sqlite3_stmt *pTableList;
304 sqlite3_stmt *pColumnList;
305 int rowid;
306};
307
308/*
309** Table destructor for the schema module.
310*/
311static int schemaDestroy(sqlite3_vtab *pVtab){
312 sqlite3_free(pVtab);
313 return 0;
314}
315
316/*
317** Table constructor for the schema module.
318*/
319static int schemaCreate(
320 sqlite3 *db,
321 void *pAux,
322 int argc, const char *const*argv,
323 sqlite3_vtab **ppVtab,
324 char **pzErr
325){
326 int rc = SQLITE_NOMEM;
327 schema_vtab *pVtab;
328 SchemaTable *pType = &aSchemaTable[0];
329
shanec0688ea2009-03-05 03:48:06 +0000330 UNUSED_PARAMETER(pzErr);
danielk1977c8c70692009-02-25 15:22:02 +0000331 if( argc>3 ){
332 int i;
333 pType = 0;
334 for(i=0; aSchemaTable[i].zName; i++){
335 if( 0==strcmp(argv[3], aSchemaTable[i].zName) ){
336 pType = &aSchemaTable[i];
337 }
338 }
339 if( !pType ){
340 return SQLITE_ERROR;
341 }
342 }
343
344 pVtab = sqlite3_malloc(sizeof(schema_vtab));
345 if( pVtab ){
346 memset(pVtab, 0, sizeof(schema_vtab));
347 pVtab->db = (sqlite3 *)pAux;
348 pVtab->pType = pType;
349 rc = sqlite3_declare_vtab(db, pType->zSchema);
350 }
351 *ppVtab = (sqlite3_vtab *)pVtab;
352 return rc;
353}
354
355/*
356** Open a new cursor on the schema table.
357*/
358static int schemaOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
359 int rc = SQLITE_NOMEM;
360 schema_cursor *pCur;
shanec0688ea2009-03-05 03:48:06 +0000361 UNUSED_PARAMETER(pVTab);
danielk1977c8c70692009-02-25 15:22:02 +0000362 pCur = sqlite3_malloc(sizeof(schema_cursor));
363 if( pCur ){
364 memset(pCur, 0, sizeof(schema_cursor));
365 *ppCursor = (sqlite3_vtab_cursor *)pCur;
366 rc = SQLITE_OK;
367 }
368 return rc;
369}
370
371/*
372** Close a schema table cursor.
373*/
374static int schemaClose(sqlite3_vtab_cursor *cur){
375 schema_cursor *pCur = (schema_cursor *)cur;
376 sqlite3_finalize(pCur->pDbList);
377 sqlite3_finalize(pCur->pTableList);
378 sqlite3_finalize(pCur->pColumnList);
379 sqlite3_free(pCur);
380 return SQLITE_OK;
381}
382
383static void columnToResult(sqlite3_context *ctx, sqlite3_stmt *pStmt, int iCol){
384 switch( sqlite3_column_type(pStmt, iCol) ){
385 case SQLITE_NULL:
386 sqlite3_result_null(ctx);
387 break;
388 case SQLITE_INTEGER:
389 sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
390 break;
391 case SQLITE_FLOAT:
392 sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
393 break;
394 case SQLITE_TEXT: {
395 const char *z = (const char *)sqlite3_column_text(pStmt, iCol);
396 sqlite3_result_text(ctx, z, -1, SQLITE_TRANSIENT);
397 break;
398 }
399 }
400}
401
402/*
403** Retrieve a column of data.
404*/
405static int schemaColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
406 schema_cursor *pCur = (schema_cursor *)cur;
407 switch( i ){
408 case 0:
409 columnToResult(ctx, pCur->pDbList, 1);
410 break;
411 case 1:
412 columnToResult(ctx, pCur->pTableList, 0);
413 break;
414 default:
415 columnToResult(ctx, pCur->pColumnList, i-2);
416 break;
417 }
418 return SQLITE_OK;
419}
420
421/*
422** Retrieve the current rowid.
423*/
424static int schemaRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
425 schema_cursor *pCur = (schema_cursor *)cur;
426 *pRowid = pCur->rowid;
427 return SQLITE_OK;
428}
429
430static int finalize(sqlite3_stmt **ppStmt){
431 int rc = sqlite3_finalize(*ppStmt);
432 *ppStmt = 0;
433 return rc;
434}
435
436static int schemaEof(sqlite3_vtab_cursor *cur){
437 schema_cursor *pCur = (schema_cursor *)cur;
438 return (pCur->pDbList ? 0 : 1);
439}
440
441/*
442** Advance the cursor to the next row.
443*/
444static int schemaNext(sqlite3_vtab_cursor *cur){
445 int rc = SQLITE_OK;
446 schema_cursor *pCur = (schema_cursor *)cur;
447 schema_vtab *pVtab = (schema_vtab *)(cur->pVtab);
448 char *zSql = 0;
449
450 while( !pCur->pColumnList || SQLITE_ROW!=sqlite3_step(pCur->pColumnList) ){
451 if( SQLITE_OK!=(rc = finalize(&pCur->pColumnList)) ) goto next_exit;
452
453 while( !pCur->pTableList || SQLITE_ROW!=sqlite3_step(pCur->pTableList) ){
454 if( SQLITE_OK!=(rc = finalize(&pCur->pTableList)) ) goto next_exit;
455
456 assert(pCur->pDbList);
457 while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){
458 rc = finalize(&pCur->pDbList);
459 goto next_exit;
460 }
461
462 /* Set zSql to the SQL to pull the list of tables from the
463 ** sqlite_master (or sqlite_temp_master) table of the database
464 ** identfied by the row pointed to by the SQL statement pCur->pDbList
465 ** (iterating through a "PRAGMA database_list;" statement).
466 */
467 if( sqlite3_column_int(pCur->pDbList, 0)==1 ){
468 zSql = sqlite3_mprintf(
469 "SELECT name FROM sqlite_temp_master WHERE type=%Q",
470 pVtab->pType->zObject
471 );
472 }else{
473 sqlite3_stmt *pDbList = pCur->pDbList;
474 zSql = sqlite3_mprintf(
475 "SELECT name FROM %Q.sqlite_master WHERE type=%Q",
476 sqlite3_column_text(pDbList, 1), pVtab->pType->zObject
477 );
478 }
479 if( !zSql ){
480 rc = SQLITE_NOMEM;
481 goto next_exit;
482 }
483
484 rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pTableList, 0);
485 sqlite3_free(zSql);
486 if( rc!=SQLITE_OK ) goto next_exit;
487 }
488
489 /* Set zSql to the SQL to the table_info pragma for the table currently
490 ** identified by the rows pointed to by statements pCur->pDbList and
491 ** pCur->pTableList.
492 */
493 zSql = sqlite3_mprintf(pVtab->pType->zPragma,
494 sqlite3_column_text(pCur->pDbList, 1),
495 sqlite3_column_text(pCur->pTableList, 0)
496 );
497
498 if( !zSql ){
499 rc = SQLITE_NOMEM;
500 goto next_exit;
501 }
502 rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pColumnList, 0);
503 sqlite3_free(zSql);
504 if( rc!=SQLITE_OK ) goto next_exit;
505 }
506 pCur->rowid++;
507
508next_exit:
509 /* TODO: Handle rc */
510 return rc;
511}
512
513/*
514** Reset a schema table cursor.
515*/
516static int schemaFilter(
517 sqlite3_vtab_cursor *pVtabCursor,
518 int idxNum, const char *idxStr,
519 int argc, sqlite3_value **argv
520){
521 int rc;
522 schema_vtab *pVtab = (schema_vtab *)(pVtabCursor->pVtab);
523 schema_cursor *pCur = (schema_cursor *)pVtabCursor;
shanec0688ea2009-03-05 03:48:06 +0000524 UNUSED_PARAMETER(idxNum);
525 UNUSED_PARAMETER(idxStr);
526 UNUSED_PARAMETER(argc);
527 UNUSED_PARAMETER(argv);
danielk1977c8c70692009-02-25 15:22:02 +0000528 pCur->rowid = 0;
529 finalize(&pCur->pTableList);
530 finalize(&pCur->pColumnList);
531 finalize(&pCur->pDbList);
532 rc = sqlite3_prepare(pVtab->db,"SELECT 0, 'main'", -1, &pCur->pDbList, 0);
533 return (rc==SQLITE_OK ? schemaNext(pVtabCursor) : rc);
534}
535
536/*
537** Analyse the WHERE condition.
538*/
539static int schemaBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
shanec0688ea2009-03-05 03:48:06 +0000540 UNUSED_PARAMETER(tab);
541 UNUSED_PARAMETER(pIdxInfo);
danielk1977c8c70692009-02-25 15:22:02 +0000542 return SQLITE_OK;
543}
544
545/*
546** A virtual table module that merely echos method calls into TCL
547** variables.
548*/
549static sqlite3_module schemaModule = {
550 0, /* iVersion */
551 schemaCreate,
552 schemaCreate,
553 schemaBestIndex,
554 schemaDestroy,
555 schemaDestroy,
556 schemaOpen, /* xOpen - open a cursor */
557 schemaClose, /* xClose - close a cursor */
558 schemaFilter, /* xFilter - configure scan constraints */
559 schemaNext, /* xNext - advance a cursor */
560 schemaEof, /* xEof */
561 schemaColumn, /* xColumn - read data */
562 schemaRowid, /* xRowid - read data */
563 0, /* xUpdate */
564 0, /* xBegin */
565 0, /* xSync */
566 0, /* xCommit */
567 0, /* xRollback */
568 0, /* xFindMethod */
569 0, /* xRename */
570};
571
572/*
573** Extension load function.
574*/
575static int installSchemaModule(sqlite3 *db, sqlite3 *sdb){
576 sqlite3_create_module(db, "schema", &schemaModule, (void *)sdb);
577 return 0;
578}
579
580/*
581** sj(zValue, zJoin)
582**
583** The following block contains the implementation of an aggregate
584** function that returns a string. Each time the function is stepped,
585** it appends data to an internal buffer. When the aggregate is finalized,
586** the contents of the buffer are returned.
587**
588** The first time the aggregate is stepped the buffer is set to a copy
589** of the first argument. The second time and subsequent times it is
590** stepped a copy of the second argument is appended to the buffer, then
591** a copy of the first.
592**
593** Example:
594**
595** INSERT INTO t1(a) VALUES('1');
596** INSERT INTO t1(a) VALUES('2');
597** INSERT INTO t1(a) VALUES('3');
598** SELECT sj(a, ', ') FROM t1;
599**
600** => "1, 2, 3"
601**
602*/
603struct StrBuffer {
604 char *zBuf;
605};
606typedef struct StrBuffer StrBuffer;
607static void joinFinalize(sqlite3_context *context){
608 StrBuffer *p;
609 p = (StrBuffer *)sqlite3_aggregate_context(context, sizeof(StrBuffer));
610 sqlite3_result_text(context, p->zBuf, -1, SQLITE_TRANSIENT);
611 sqlite3_free(p->zBuf);
612}
613static void joinStep(
614 sqlite3_context *context,
615 int argc,
616 sqlite3_value **argv
617){
618 StrBuffer *p;
shanec0688ea2009-03-05 03:48:06 +0000619 UNUSED_PARAMETER(argc);
danielk1977c8c70692009-02-25 15:22:02 +0000620 p = (StrBuffer *)sqlite3_aggregate_context(context, sizeof(StrBuffer));
621 if( p->zBuf==0 ){
622 p->zBuf = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
623 }else{
624 char *zTmp = p->zBuf;
625 p->zBuf = sqlite3_mprintf("%s%s%s",
626 zTmp, sqlite3_value_text(argv[1]), sqlite3_value_text(argv[0])
627 );
628 sqlite3_free(zTmp);
629 }
630}
631
632/*
633** dq(zString)
634**
635** This scalar function accepts a single argument and interprets it as
636** a text value. The return value is the argument enclosed in double
637** quotes. If any double quote characters are present in the argument,
638** these are escaped.
639**
640** dq('the raven "Nevermore."') == '"the raven ""Nevermore."""'
641*/
642static void doublequote(
643 sqlite3_context *context,
644 int argc,
645 sqlite3_value **argv
646){
647 int ii;
648 char *zOut;
649 char *zCsr;
650 const char *zIn = (const char *)sqlite3_value_text(argv[0]);
651 int nIn = sqlite3_value_bytes(argv[0]);
652
shanec0688ea2009-03-05 03:48:06 +0000653 UNUSED_PARAMETER(argc);
danielk1977c8c70692009-02-25 15:22:02 +0000654 zOut = sqlite3_malloc(nIn*2+3);
655 zCsr = zOut;
656 *zCsr++ = '"';
657 for(ii=0; ii<nIn; ii++){
658 *zCsr++ = zIn[ii];
659 if( zIn[ii]=='"' ){
660 *zCsr++ = '"';
661 }
662 }
663 *zCsr++ = '"';
664 *zCsr++ = '\0';
665
666 sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
667 sqlite3_free(zOut);
668}
669
670/*
671** multireplace(zString, zSearch1, zReplace1, ...)
672*/
673static void multireplace(
674 sqlite3_context *context,
675 int argc,
676 sqlite3_value **argv
677){
678 int i = 0;
679 char *zOut = 0;
680 int nOut = 0;
681 int nMalloc = 0;
682 const char *zIn = (const char *)sqlite3_value_text(argv[0]);
683 int nIn = sqlite3_value_bytes(argv[0]);
684
685 while( i<nIn ){
686 const char *zCopy = &zIn[i];
687 int nCopy = 1;
688 int nReplace = 1;
689 int j;
690 for(j=1; j<(argc-1); j+=2){
691 const char *z = (const char *)sqlite3_value_text(argv[j]);
692 int n = sqlite3_value_bytes(argv[j]);
693 if( n<=(nIn-i) && 0==strncmp(z, zCopy, n) ){
694 zCopy = (const char *)sqlite3_value_text(argv[j+1]);
695 nCopy = sqlite3_value_bytes(argv[j+1]);
696 nReplace = n;
697 break;
698 }
699 }
700 if( (nOut+nCopy)>nMalloc ){
drhde7446b2009-05-31 17:16:09 +0000701 char *zNew;
danielk19779365c672009-03-13 15:32:53 +0000702 nMalloc = 16 + (nOut+nCopy)*2;
drhde7446b2009-05-31 17:16:09 +0000703 zNew = (char*)sqlite3_realloc(zOut, nMalloc);
704 if( zNew==0 ){
705 sqlite3_result_error_nomem(context);
706 return;
707 }else{
708 zOut = zNew;
709 }
danielk1977c8c70692009-02-25 15:22:02 +0000710 }
danielk19779365c672009-03-13 15:32:53 +0000711 assert( nMalloc>=(nOut+nCopy) );
danielk1977c8c70692009-02-25 15:22:02 +0000712 memcpy(&zOut[nOut], zCopy, nCopy);
713 i += nReplace;
714 nOut += nCopy;
715 }
716
717 sqlite3_result_text(context, zOut, nOut, SQLITE_TRANSIENT);
718 sqlite3_free(zOut);
719}
720
721/*
722** A callback for sqlite3_exec() invokes the callback specified by the
723** GenfkeyCb structure pointed to by the void* passed as the first argument.
724*/
725static int invokeCallback(void *p, int nArg, char **azArg, char **azCol){
726 GenfkeyCb *pCb = (GenfkeyCb *)p;
shanec0688ea2009-03-05 03:48:06 +0000727 UNUSED_PARAMETER(nArg);
728 UNUSED_PARAMETER(azCol);
danielk1977c8c70692009-02-25 15:22:02 +0000729 return pCb->xData(pCb->pCtx, pCb->eType, azArg[0]);
730}
731
shane16f954c2009-10-21 13:53:58 +0000732static int detectSchemaProblem(
danielk1977c8c70692009-02-25 15:22:02 +0000733 sqlite3 *db, /* Database connection */
734 const char *zMessage, /* English language error message */
735 const char *zSql, /* SQL statement to run */
736 GenfkeyCb *pCb
737){
738 sqlite3_stmt *pStmt;
739 int rc;
740 rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
741 if( rc!=SQLITE_OK ){
742 return rc;
743 }
744 while( SQLITE_ROW==sqlite3_step(pStmt) ){
745 char *zDel;
746 int iFk = sqlite3_column_int(pStmt, 0);
747 const char *zTab = (const char *)sqlite3_column_text(pStmt, 1);
748 zDel = sqlite3_mprintf("Error in table %s: %s", zTab, zMessage);
749 rc = pCb->xData(pCb->pCtx, pCb->eType, zDel);
750 sqlite3_free(zDel);
751 if( rc!=SQLITE_OK ) return rc;
752 zDel = sqlite3_mprintf(
753 "DELETE FROM temp.fkey WHERE from_tbl = %Q AND fkid = %d"
754 , zTab, iFk
755 );
756 sqlite3_exec(db, zDel, 0, 0, 0);
757 sqlite3_free(zDel);
758 }
759 sqlite3_finalize(pStmt);
760 return SQLITE_OK;
761}
762
763/*
764** Create and populate temporary table "fkey".
765*/
766static int populateTempTable(sqlite3 *db, GenfkeyCb *pCallback){
767 int rc;
768
769 rc = sqlite3_exec(db,
770 "CREATE VIRTUAL TABLE temp.v_fkey USING schema(foreign_key_list);"
771 "CREATE VIRTUAL TABLE temp.v_col USING schema(table_info);"
772 "CREATE VIRTUAL TABLE temp.v_idxlist USING schema(index_list);"
773 "CREATE VIRTUAL TABLE temp.v_idxinfo USING schema(index_info);"
774 "CREATE VIRTUAL TABLE temp.v_triggers USING schema(trigger_list);"
775 "CREATE TABLE temp.fkey AS "
776 "SELECT from_tbl, to_tbl, fkid, from_col, to_col, on_update, on_delete "
777 "FROM temp.v_fkey WHERE database = 'main';"
778 , 0, 0, 0
779 );
780 if( rc!=SQLITE_OK ) return rc;
781
782 rc = detectSchemaProblem(db, "foreign key columns do not exist",
783 "SELECT fkid, from_tbl "
784 "FROM temp.fkey "
785 "WHERE to_col IS NOT NULL AND NOT EXISTS (SELECT 1 "
786 "FROM temp.v_col WHERE tablename=to_tbl AND name==to_col"
787 ")", pCallback
788 );
789 if( rc!=SQLITE_OK ) return rc;
790
791 /* At this point the temp.fkey table is mostly populated. If any foreign
792 ** keys were specified so that they implicitly refer to they primary
793 ** key of the parent table, the "to_col" values of the temp.fkey rows
794 ** are still set to NULL.
795 **
796 ** This is easily fixed for single column primary keys, but not for
797 ** composites. With a composite primary key, there is no way to reliably
798 ** query sqlite for the order in which the columns that make up the
799 ** composite key were declared i.e. there is no way to tell if the
800 ** schema actually contains "PRIMARY KEY(a, b)" or "PRIMARY KEY(b, a)".
801 ** Therefore, this case is not handled. The following function call
802 ** detects instances of this case.
803 */
804 rc = detectSchemaProblem(db, "implicit mapping to composite primary key",
805 "SELECT fkid, from_tbl "
806 "FROM temp.fkey "
807 "WHERE to_col IS NULL "
808 "GROUP BY fkid, from_tbl HAVING count(*) > 1", pCallback
809 );
810 if( rc!=SQLITE_OK ) return rc;
811
812 /* Detect attempts to implicitly map to the primary key of a table
813 ** that has no primary key column.
814 */
815 rc = detectSchemaProblem(db, "implicit mapping to non-existant primary key",
816 "SELECT fkid, from_tbl "
817 "FROM temp.fkey "
818 "WHERE to_col IS NULL AND NOT EXISTS "
819 "(SELECT 1 FROM temp.v_col WHERE pk AND tablename = temp.fkey.to_tbl)"
820 , pCallback
821 );
822 if( rc!=SQLITE_OK ) return rc;
823
824 /* Fix all the implicit primary key mappings in the temp.fkey table. */
825 rc = sqlite3_exec(db,
826 "UPDATE temp.fkey SET to_col = "
827 "(SELECT name FROM temp.v_col WHERE pk AND tablename=temp.fkey.to_tbl)"
828 " WHERE to_col IS NULL;"
829 , 0, 0, 0
830 );
831 if( rc!=SQLITE_OK ) return rc;
832
833 /* Now check that all all parent keys are either primary keys or
834 ** subject to a unique constraint.
835 */
836 rc = sqlite3_exec(db,
837 "CREATE TABLE temp.idx2 AS SELECT "
838 "il.tablename AS tablename,"
839 "ii.indexname AS indexname,"
840 "ii.name AS col "
841 "FROM temp.v_idxlist AS il, temp.v_idxinfo AS ii "
842 "WHERE il.isunique AND il.database='main' AND ii.indexname = il.name;"
843 "INSERT INTO temp.idx2 "
844 "SELECT tablename, 'pk', name FROM temp.v_col WHERE pk;"
845
846 "CREATE TABLE temp.idx AS SELECT "
847 "tablename, indexname, sj(dq(col),',') AS cols "
848 "FROM (SELECT * FROM temp.idx2 ORDER BY col) "
849 "GROUP BY tablename, indexname;"
850
851 "CREATE TABLE temp.fkey2 AS SELECT "
852 "fkid, from_tbl, to_tbl, sj(dq(to_col),',') AS cols "
853 "FROM (SELECT * FROM temp.fkey ORDER BY to_col) "
854 "GROUP BY fkid, from_tbl;"
855
856 "CREATE TABLE temp.triggers AS SELECT "
857 "triggername FROM temp.v_triggers WHERE database='main' AND "
858 "triggername LIKE 'genfkey%';"
859 , 0, 0, 0
860 );
861 if( rc!=SQLITE_OK ) return rc;
862 rc = detectSchemaProblem(db, "foreign key is not unique",
863 "SELECT fkid, from_tbl "
864 "FROM temp.fkey2 "
865 "WHERE NOT EXISTS (SELECT 1 "
866 "FROM temp.idx WHERE tablename=to_tbl AND fkey2.cols==idx.cols"
867 ")", pCallback
868 );
869 if( rc!=SQLITE_OK ) return rc;
870
871 return rc;
872}
873
874#define GENFKEY_ERROR 1
875#define GENFKEY_DROPTRIGGER 2
876#define GENFKEY_CREATETRIGGER 3
877static int genfkey_create_triggers(
878 sqlite3 *sdb, /* Connection to read schema from */
879 const char *zDb, /* Name of db to read ("main", "temp") */
880 void *pCtx, /* Context pointer to pass to xData */
881 int (*xData)(void *, int, const char *)
882){
883 const char *zSql =
884 "SELECT multireplace('"
885
886 "-- Triggers for foreign key mapping:\n"
887 "--\n"
888 "-- /from_readable/ REFERENCES /to_readable/\n"
889 "-- on delete /on_delete/\n"
890 "-- on update /on_update/\n"
891 "--\n"
892
893 /* The "BEFORE INSERT ON <referencing>" trigger. This trigger's job is to
894 ** throw an exception if the user tries to insert a row into the
895 ** referencing table for which there is no corresponding row in
896 ** the referenced table.
897 */
898 "CREATE TRIGGER /name/_insert_referencing BEFORE INSERT ON /tbl/ WHEN \n"
899 " /key_notnull/ AND NOT EXISTS (SELECT 1 FROM /ref/ WHERE /cond1/)\n"
900 "BEGIN\n"
901 " SELECT RAISE(ABORT, ''constraint failed'');\n"
902 "END;\n"
903
904 /* The "BEFORE UPDATE ON <referencing>" trigger. This trigger's job
905 ** is to throw an exception if the user tries to update a row in the
906 ** referencing table causing it to correspond to no row in the
907 ** referenced table.
908 */
909 "CREATE TRIGGER /name/_update_referencing BEFORE\n"
910 " UPDATE OF /rkey_list/ ON /tbl/ WHEN \n"
911 " /key_notnull/ AND \n"
912 " NOT EXISTS (SELECT 1 FROM /ref/ WHERE /cond1/)\n"
913 "BEGIN\n"
914 " SELECT RAISE(ABORT, ''constraint failed'');\n"
915 "END;\n"
916
917
918 /* The "BEFORE DELETE ON <referenced>" trigger. This trigger's job
919 ** is to detect when a row is deleted from the referenced table to
920 ** which rows in the referencing table correspond. The action taken
921 ** depends on the value of the 'ON DELETE' clause.
922 */
923 "CREATE TRIGGER /name/_delete_referenced BEFORE DELETE ON /ref/ WHEN\n"
924 " EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n"
925 "BEGIN\n"
926 " /delete_action/\n"
927 "END;\n"
928
dan1da40a32009-09-19 17:00:31 +0000929 /* The "AFTER UPDATE ON <referenced>" trigger. This trigger's job
danielk1977c8c70692009-02-25 15:22:02 +0000930 ** is to detect when the key columns of a row in the referenced table
931 ** to which one or more rows in the referencing table correspond are
932 ** updated. The action taken depends on the value of the 'ON UPDATE'
933 ** clause.
934 */
935 "CREATE TRIGGER /name/_update_referenced AFTER\n"
936 " UPDATE OF /fkey_list/ ON /ref/ WHEN \n"
937 " EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n"
938 "BEGIN\n"
939 " /update_action/\n"
940 "END;\n"
941 "'"
942
943 /* These are used in the SQL comment written above each set of triggers */
944 ", '/from_readable/', from_tbl || '(' || sj(from_col, ', ') || ')'"
945 ", '/to_readable/', to_tbl || '(' || sj(to_col, ', ') || ')'"
946 ", '/on_delete/', on_delete"
947 ", '/on_update/', on_update"
948
949 ", '/name/', 'genfkey' || min(rowid)"
950 ", '/tbl/', dq(from_tbl)"
951 ", '/ref/', dq(to_tbl)"
952 ", '/key_notnull/', sj('new.' || dq(from_col) || ' IS NOT NULL', ' AND ')"
953
dan8b6d37d2009-10-08 13:42:28 +0000954 ", '/fkey_list/', sj(dq(to_col), ', ')"
955 ", '/rkey_list/', sj(dq(from_col), ', ')"
danielk1977c8c70692009-02-25 15:22:02 +0000956
957 ", '/cond1/', sj(multireplace('new./from/ == /to/'"
958 ", '/from/', dq(from_col)"
959 ", '/to/', dq(to_col)"
960 "), ' AND ')"
961 ", '/cond2/', sj(multireplace('old./to/ == /from/'"
962 ", '/from/', dq(from_col)"
963 ", '/to/', dq(to_col)"
964 "), ' AND ')"
965
966 ", '/update_action/', CASE on_update "
967 "WHEN 'SET NULL' THEN "
968 "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
dan8b6d37d2009-10-08 13:42:28 +0000969 ", '/setlist/', sj(dq(from_col)||' = NULL',', ')"
danielk1977c8c70692009-02-25 15:22:02 +0000970 ", '/tbl/', dq(from_tbl)"
dan8b6d37d2009-10-08 13:42:28 +0000971 ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
danielk1977c8c70692009-02-25 15:22:02 +0000972 ")"
973 "WHEN 'CASCADE' THEN "
974 "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
975 ", '/setlist/', sj(dq(from_col)||' = new.'||dq(to_col),', ')"
976 ", '/tbl/', dq(from_tbl)"
977 ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
978 ")"
979 "ELSE "
980 " 'SELECT RAISE(ABORT, ''constraint failed'');'"
981 "END "
982
983 ", '/delete_action/', CASE on_delete "
984 "WHEN 'SET NULL' THEN "
985 "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
dan8b6d37d2009-10-08 13:42:28 +0000986 ", '/setlist/', sj(dq(from_col)||' = NULL',', ')"
danielk1977c8c70692009-02-25 15:22:02 +0000987 ", '/tbl/', dq(from_tbl)"
dan8b6d37d2009-10-08 13:42:28 +0000988 ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
danielk1977c8c70692009-02-25 15:22:02 +0000989 ")"
990 "WHEN 'CASCADE' THEN "
991 "multireplace('DELETE FROM /tbl/ WHERE /where/;' "
992 ", '/tbl/', dq(from_tbl)"
993 ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
994 ")"
995 "ELSE "
996 " 'SELECT RAISE(ABORT, ''constraint failed'');'"
997 "END "
998
999 ") FROM temp.fkey "
1000 "GROUP BY from_tbl, fkid"
1001 ;
1002
1003 int rc;
1004 const int enc = SQLITE_UTF8;
1005 sqlite3 *db = 0;
1006
1007 GenfkeyCb cb;
1008 cb.xData = xData;
1009 cb.pCtx = pCtx;
1010
shanec0688ea2009-03-05 03:48:06 +00001011 UNUSED_PARAMETER(zDb);
1012
danielk1977c8c70692009-02-25 15:22:02 +00001013 /* Open the working database handle. */
1014 rc = sqlite3_open(":memory:", &db);
1015 if( rc!=SQLITE_OK ) goto genfkey_exit;
1016
1017 /* Create the special scalar and aggregate functions used by this program. */
1018 sqlite3_create_function(db, "dq", 1, enc, 0, doublequote, 0, 0);
1019 sqlite3_create_function(db, "multireplace", -1, enc, db, multireplace, 0, 0);
1020 sqlite3_create_function(db, "sj", 2, enc, 0, 0, joinStep, joinFinalize);
1021
1022 /* Install the "schema" virtual table module */
1023 installSchemaModule(db, sdb);
1024
1025 /* Create and populate a temp table with the information required to
1026 ** build the foreign key triggers. See function populateTempTable()
1027 ** for details.
1028 */
1029 cb.eType = GENFKEY_ERROR;
1030 rc = populateTempTable(db, &cb);
1031 if( rc!=SQLITE_OK ) goto genfkey_exit;
1032
1033 /* Unless the --no-drop option was specified, generate DROP TRIGGER
1034 ** statements to drop any triggers in the database generated by a
1035 ** previous run of this program.
1036 */
1037 cb.eType = GENFKEY_DROPTRIGGER;
1038 rc = sqlite3_exec(db,
1039 "SELECT 'DROP TRIGGER main.' || dq(triggername) || ';' FROM triggers"
1040 ,invokeCallback, (void *)&cb, 0
1041 );
1042 if( rc!=SQLITE_OK ) goto genfkey_exit;
1043
1044 /* Run the main query to create the trigger definitions. */
1045 cb.eType = GENFKEY_CREATETRIGGER;
1046 rc = sqlite3_exec(db, zSql, invokeCallback, (void *)&cb, 0);
1047 if( rc!=SQLITE_OK ) goto genfkey_exit;
1048
1049genfkey_exit:
1050 sqlite3_close(db);
1051 return rc;
1052}
1053
1054
1055#endif
1056/* End genfkey logic. */
1057/*************************************************************************/
1058/*************************************************************************/
1059
drhe91d16b2008-12-08 18:27:31 +00001060/*
drhc49f44e2006-10-26 18:15:42 +00001061** If the following flag is set, then command execution stops
1062** at an error if we are not interactive.
1063*/
1064static int bail_on_error = 0;
1065
1066/*
drhc28490c2006-10-26 14:25:58 +00001067** Threat stdin as an interactive input if the following variable
1068** is true. Otherwise, assume stdin is connected to a file or pipe.
1069*/
1070static int stdin_is_interactive = 1;
1071
1072/*
drh4c504392000-10-16 22:06:40 +00001073** The following is the open SQLite database. We make a pointer
1074** to this database a static variable so that it can be accessed
1075** by the SIGINT handler to interrupt database processing.
1076*/
danielk197792f9a1b2004-06-19 09:08:16 +00001077static sqlite3 *db = 0;
drh4c504392000-10-16 22:06:40 +00001078
1079/*
drh67505e72002-04-19 12:34:06 +00001080** True if an interrupt (Control-C) has been received.
1081*/
drh43617e92006-03-06 20:55:46 +00001082static volatile int seenInterrupt = 0;
drh67505e72002-04-19 12:34:06 +00001083
1084/*
persicom7e2dfdd2002-04-18 02:46:52 +00001085** This is the name of our program. It is set in main(), used
1086** in a number of other places, mostly for error messages.
1087*/
1088static char *Argv0;
1089
1090/*
1091** Prompt strings. Initialized in main. Settable with
1092** .prompt main continue
1093*/
1094static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
1095static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
1096
drhb0603412007-02-28 04:47:26 +00001097/*
1098** Write I/O traces to the following stream.
1099*/
rsebe0a9092007-07-30 18:24:38 +00001100#ifdef SQLITE_ENABLE_IOTRACE
drhb0603412007-02-28 04:47:26 +00001101static FILE *iotrace = 0;
rsebe0a9092007-07-30 18:24:38 +00001102#endif
drhb0603412007-02-28 04:47:26 +00001103
1104/*
1105** This routine works like printf in that its first argument is a
1106** format string and subsequent arguments are values to be substituted
1107** in place of % fields. The result of formatting this string
1108** is written to iotrace.
1109*/
rsebe0a9092007-07-30 18:24:38 +00001110#ifdef SQLITE_ENABLE_IOTRACE
drhb0603412007-02-28 04:47:26 +00001111static void iotracePrintf(const char *zFormat, ...){
1112 va_list ap;
drhf075cd02007-02-28 06:14:25 +00001113 char *z;
drhb0603412007-02-28 04:47:26 +00001114 if( iotrace==0 ) return;
1115 va_start(ap, zFormat);
drhf075cd02007-02-28 06:14:25 +00001116 z = sqlite3_vmprintf(zFormat, ap);
drhb0603412007-02-28 04:47:26 +00001117 va_end(ap);
drhf075cd02007-02-28 06:14:25 +00001118 fprintf(iotrace, "%s", z);
1119 sqlite3_free(z);
drhb0603412007-02-28 04:47:26 +00001120}
rsebe0a9092007-07-30 18:24:38 +00001121#endif
drhb0603412007-02-28 04:47:26 +00001122
drh44c2eb12003-04-30 11:38:26 +00001123
persicom7e2dfdd2002-04-18 02:46:52 +00001124/*
drh83965662003-04-17 02:54:13 +00001125** Determines if a string is a number of not.
1126*/
danielk19772e588c72005-12-09 14:25:08 +00001127static int isNumber(const char *z, int *realnum){
drhc8d74412004-08-31 23:41:26 +00001128 if( *z=='-' || *z=='+' ) z++;
1129 if( !isdigit(*z) ){
1130 return 0;
1131 }
1132 z++;
1133 if( realnum ) *realnum = 0;
1134 while( isdigit(*z) ){ z++; }
1135 if( *z=='.' ){
1136 z++;
1137 if( !isdigit(*z) ) return 0;
1138 while( isdigit(*z) ){ z++; }
1139 if( realnum ) *realnum = 1;
1140 }
1141 if( *z=='e' || *z=='E' ){
1142 z++;
1143 if( *z=='+' || *z=='-' ) z++;
1144 if( !isdigit(*z) ) return 0;
1145 while( isdigit(*z) ){ z++; }
1146 if( realnum ) *realnum = 1;
1147 }
1148 return *z==0;
1149}
drh83965662003-04-17 02:54:13 +00001150
1151/*
danielk1977bc6ada42004-06-30 08:20:16 +00001152** A global char* and an SQL function to access its current value
1153** from within an SQL statement. This program used to use the
1154** sqlite_exec_printf() API to substitue a string into an SQL statement.
1155** The correct way to do this with sqlite3 is to use the bind API, but
1156** since the shell is built around the callback paradigm it would be a lot
1157** of work. Instead just use this hack, which is quite harmless.
1158*/
1159static const char *zShellStatic = 0;
1160static void shellstaticFunc(
1161 sqlite3_context *context,
1162 int argc,
1163 sqlite3_value **argv
1164){
1165 assert( 0==argc );
1166 assert( zShellStatic );
shaned87897d2009-01-30 05:40:27 +00001167 UNUSED_PARAMETER(argc);
drh902b9ee2008-12-05 17:17:07 +00001168 UNUSED_PARAMETER(argv);
danielk1977bc6ada42004-06-30 08:20:16 +00001169 sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
1170}
1171
1172
1173/*
drhfeac5f82004-08-01 00:10:45 +00001174** This routine reads a line of text from FILE in, stores
drh8e7e7a22000-05-30 18:45:23 +00001175** the text in memory obtained from malloc() and returns a pointer
1176** to the text. NULL is returned at end of file, or if malloc()
1177** fails.
1178**
1179** The interface is like "readline" but no command-line editing
1180** is done.
1181*/
drh9347b202003-07-18 01:30:59 +00001182static char *local_getline(char *zPrompt, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +00001183 char *zLine;
1184 int nLine;
drh8e7e7a22000-05-30 18:45:23 +00001185 int n;
1186 int eol;
1187
1188 if( zPrompt && *zPrompt ){
1189 printf("%s",zPrompt);
1190 fflush(stdout);
1191 }
1192 nLine = 100;
1193 zLine = malloc( nLine );
1194 if( zLine==0 ) return 0;
1195 n = 0;
1196 eol = 0;
1197 while( !eol ){
1198 if( n+100>nLine ){
1199 nLine = nLine*2 + 100;
1200 zLine = realloc(zLine, nLine);
1201 if( zLine==0 ) return 0;
1202 }
drhdaffd0e2001-04-11 14:28:42 +00001203 if( fgets(&zLine[n], nLine - n, in)==0 ){
drh8e7e7a22000-05-30 18:45:23 +00001204 if( n==0 ){
1205 free(zLine);
1206 return 0;
1207 }
1208 zLine[n] = 0;
1209 eol = 1;
1210 break;
1211 }
1212 while( zLine[n] ){ n++; }
1213 if( n>0 && zLine[n-1]=='\n' ){
1214 n--;
shaneh13b36022009-12-17 21:07:15 +00001215 if( n>0 && zLine[n-1]=='\r' ) n--;
drh8e7e7a22000-05-30 18:45:23 +00001216 zLine[n] = 0;
1217 eol = 1;
1218 }
1219 }
1220 zLine = realloc( zLine, n+1 );
1221 return zLine;
1222}
1223
1224/*
drhc28490c2006-10-26 14:25:58 +00001225** Retrieve a single line of input text.
drh8e7e7a22000-05-30 18:45:23 +00001226**
1227** zPrior is a string of prior text retrieved. If not the empty
1228** string, then issue a continuation prompt.
1229*/
drhdaffd0e2001-04-11 14:28:42 +00001230static char *one_input_line(const char *zPrior, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +00001231 char *zPrompt;
1232 char *zResult;
drhdaffd0e2001-04-11 14:28:42 +00001233 if( in!=0 ){
drh9347b202003-07-18 01:30:59 +00001234 return local_getline(0, in);
drh8e7e7a22000-05-30 18:45:23 +00001235 }
1236 if( zPrior && zPrior[0] ){
persicom7e2dfdd2002-04-18 02:46:52 +00001237 zPrompt = continuePrompt;
drh8e7e7a22000-05-30 18:45:23 +00001238 }else{
persicom7e2dfdd2002-04-18 02:46:52 +00001239 zPrompt = mainPrompt;
drh8e7e7a22000-05-30 18:45:23 +00001240 }
1241 zResult = readline(zPrompt);
danielk19774af00c62005-01-23 23:43:21 +00001242#if defined(HAVE_READLINE) && HAVE_READLINE==1
drheb741d52006-06-03 17:37:25 +00001243 if( zResult && *zResult ) add_history(zResult);
danielk19774af00c62005-01-23 23:43:21 +00001244#endif
drh8e7e7a22000-05-30 18:45:23 +00001245 return zResult;
1246}
1247
persicom7e2dfdd2002-04-18 02:46:52 +00001248struct previous_mode_data {
1249 int valid; /* Is there legit data in here? */
1250 int mode;
1251 int showHeader;
1252 int colWidth[100];
1253};
drh45e29d82006-11-20 16:21:10 +00001254
drh8e7e7a22000-05-30 18:45:23 +00001255/*
drh75897232000-05-29 14:26:00 +00001256** An pointer to an instance of this structure is passed from
1257** the main program to the callback. This is used to communicate
1258** state and mode information.
1259*/
1260struct callback_data {
shane626a6e42009-10-22 17:30:15 +00001261 sqlite3 *db; /* The database */
drhdaffd0e2001-04-11 14:28:42 +00001262 int echoOn; /* True to echo input commands */
drh28bd4bc2000-06-15 15:57:22 +00001263 int cnt; /* Number of records displayed so far */
1264 FILE *out; /* Write results here */
1265 int mode; /* An output mode setting */
drh45e29d82006-11-20 16:21:10 +00001266 int writableSchema; /* True if PRAGMA writable_schema=ON */
drh28bd4bc2000-06-15 15:57:22 +00001267 int showHeader; /* True to show column names in List or Column mode */
drh33048c02001-10-01 14:29:22 +00001268 char *zDestTable; /* Name of destination table when MODE_Insert */
drh28bd4bc2000-06-15 15:57:22 +00001269 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +00001270 int colWidth[100]; /* Requested width of each column when in column mode*/
1271 int actualWidth[100]; /* Actual width of each column */
drh83965662003-04-17 02:54:13 +00001272 char nullvalue[20]; /* The text to print when a NULL comes back from
1273 ** the database */
persicom7e2dfdd2002-04-18 02:46:52 +00001274 struct previous_mode_data explainPrev;
drh83965662003-04-17 02:54:13 +00001275 /* Holds the mode information just before
1276 ** .explain ON */
drh44c2eb12003-04-30 11:38:26 +00001277 char outfile[FILENAME_MAX]; /* Filename for *out */
1278 const char *zDbFilename; /* name of the database file */
shane626a6e42009-10-22 17:30:15 +00001279 sqlite3_stmt *pStmt; /* Current statement if any. */
drh75897232000-05-29 14:26:00 +00001280};
1281
1282/*
1283** These are the allowed modes.
1284*/
drh967e8b72000-06-21 13:59:10 +00001285#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +00001286#define MODE_Column 1 /* One record per line in neat columns */
1287#define MODE_List 2 /* One record per line with a separator */
drhe3710332000-09-29 13:30:53 +00001288#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
1289#define MODE_Html 4 /* Generate an XHTML table */
1290#define MODE_Insert 5 /* Generate SQL "insert" statements */
drhfeac5f82004-08-01 00:10:45 +00001291#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
drh8e64d1c2004-10-07 00:32:39 +00001292#define MODE_Csv 7 /* Quote strings, numbers are plain */
drh66ce4d02008-02-15 17:38:06 +00001293#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
persicom7e2dfdd2002-04-18 02:46:52 +00001294
drh66ce4d02008-02-15 17:38:06 +00001295static const char *modeDescr[] = {
persicom7e2dfdd2002-04-18 02:46:52 +00001296 "line",
1297 "column",
1298 "list",
1299 "semi",
1300 "html",
drhfeac5f82004-08-01 00:10:45 +00001301 "insert",
1302 "tcl",
drh8e64d1c2004-10-07 00:32:39 +00001303 "csv",
drh66ce4d02008-02-15 17:38:06 +00001304 "explain",
persicom7e2dfdd2002-04-18 02:46:52 +00001305};
drh75897232000-05-29 14:26:00 +00001306
1307/*
1308** Number of elements in an array
1309*/
drh902b9ee2008-12-05 17:17:07 +00001310#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
drh75897232000-05-29 14:26:00 +00001311
1312/*
drhea678832008-12-10 19:26:22 +00001313** Compute a string length that is limited to what can be stored in
1314** lower 30 bits of a 32-bit signed integer.
1315*/
drh4f21c4a2008-12-10 22:15:00 +00001316static int strlen30(const char *z){
drhea678832008-12-10 19:26:22 +00001317 const char *z2 = z;
1318 while( *z2 ){ z2++; }
1319 return 0x3fffffff & (int)(z2 - z);
1320}
1321
1322/*
shane626a6e42009-10-22 17:30:15 +00001323** Output the given string as a hex-encoded blob (eg. X'1234' )
1324*/
1325static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
1326 int i;
1327 char *zBlob = (char *)pBlob;
1328 fprintf(out,"X'");
1329 for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]); }
1330 fprintf(out,"'");
1331}
1332
1333/*
drh28bd4bc2000-06-15 15:57:22 +00001334** Output the given string as a quoted string using SQL quoting conventions.
1335*/
1336static void output_quoted_string(FILE *out, const char *z){
1337 int i;
1338 int nSingle = 0;
drh28bd4bc2000-06-15 15:57:22 +00001339 for(i=0; z[i]; i++){
1340 if( z[i]=='\'' ) nSingle++;
drh28bd4bc2000-06-15 15:57:22 +00001341 }
1342 if( nSingle==0 ){
1343 fprintf(out,"'%s'",z);
drh28bd4bc2000-06-15 15:57:22 +00001344 }else{
1345 fprintf(out,"'");
1346 while( *z ){
1347 for(i=0; z[i] && z[i]!='\''; i++){}
1348 if( i==0 ){
1349 fprintf(out,"''");
1350 z++;
1351 }else if( z[i]=='\'' ){
1352 fprintf(out,"%.*s''",i,z);
1353 z += i+1;
1354 }else{
drhcd7d2732002-02-26 23:24:26 +00001355 fprintf(out,"%s",z);
drh28bd4bc2000-06-15 15:57:22 +00001356 break;
1357 }
1358 }
drhcd7d2732002-02-26 23:24:26 +00001359 fprintf(out,"'");
drh28bd4bc2000-06-15 15:57:22 +00001360 }
1361}
1362
1363/*
drhfeac5f82004-08-01 00:10:45 +00001364** Output the given string as a quoted according to C or TCL quoting rules.
1365*/
1366static void output_c_string(FILE *out, const char *z){
1367 unsigned int c;
1368 fputc('"', out);
1369 while( (c = *(z++))!=0 ){
1370 if( c=='\\' ){
1371 fputc(c, out);
1372 fputc(c, out);
1373 }else if( c=='\t' ){
1374 fputc('\\', out);
1375 fputc('t', out);
1376 }else if( c=='\n' ){
1377 fputc('\\', out);
1378 fputc('n', out);
1379 }else if( c=='\r' ){
1380 fputc('\\', out);
1381 fputc('r', out);
1382 }else if( !isprint(c) ){
drh0a8640d2005-08-30 20:12:02 +00001383 fprintf(out, "\\%03o", c&0xff);
drhfeac5f82004-08-01 00:10:45 +00001384 }else{
1385 fputc(c, out);
1386 }
1387 }
1388 fputc('"', out);
1389}
1390
1391/*
drhc08a4f12000-06-15 16:49:48 +00001392** Output the given string with characters that are special to
1393** HTML escaped.
1394*/
1395static void output_html_string(FILE *out, const char *z){
1396 int i;
1397 while( *z ){
shane43d9cb22009-10-21 14:11:48 +00001398 for(i=0; z[i]
1399 && z[i]!='<'
1400 && z[i]!='&'
1401 && z[i]!='>'
1402 && z[i]!='\"'
1403 && z[i]!='\'';
1404 i++){}
drhc08a4f12000-06-15 16:49:48 +00001405 if( i>0 ){
1406 fprintf(out,"%.*s",i,z);
1407 }
1408 if( z[i]=='<' ){
1409 fprintf(out,"&lt;");
1410 }else if( z[i]=='&' ){
1411 fprintf(out,"&amp;");
shane43d9cb22009-10-21 14:11:48 +00001412 }else if( z[i]=='>' ){
1413 fprintf(out,"&gt;");
1414 }else if( z[i]=='\"' ){
1415 fprintf(out,"&quot;");
1416 }else if( z[i]=='\'' ){
1417 fprintf(out,"&#39;");
drhc08a4f12000-06-15 16:49:48 +00001418 }else{
1419 break;
1420 }
1421 z += i + 1;
1422 }
1423}
1424
1425/*
drhc49f44e2006-10-26 18:15:42 +00001426** If a field contains any character identified by a 1 in the following
1427** array, then the string must be quoted for CSV.
1428*/
1429static const char needCsvQuote[] = {
1430 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1432 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1434 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1439 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1440 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1441 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1442 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1443 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1444 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1445 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1446};
1447
1448/*
drh8e64d1c2004-10-07 00:32:39 +00001449** Output a single term of CSV. Actually, p->separator is used for
1450** the separator, which may or may not be a comma. p->nullvalue is
1451** the null value. Strings are quoted using ANSI-C rules. Numbers
1452** appear outside of quotes.
1453*/
1454static void output_csv(struct callback_data *p, const char *z, int bSep){
drhc49f44e2006-10-26 18:15:42 +00001455 FILE *out = p->out;
drh8e64d1c2004-10-07 00:32:39 +00001456 if( z==0 ){
drhc49f44e2006-10-26 18:15:42 +00001457 fprintf(out,"%s",p->nullvalue);
drh8e64d1c2004-10-07 00:32:39 +00001458 }else{
drhc49f44e2006-10-26 18:15:42 +00001459 int i;
drh4f21c4a2008-12-10 22:15:00 +00001460 int nSep = strlen30(p->separator);
drhc49f44e2006-10-26 18:15:42 +00001461 for(i=0; z[i]; i++){
drhc85375d2007-12-18 15:41:44 +00001462 if( needCsvQuote[((unsigned char*)z)[i]]
1463 || (z[i]==p->separator[0] &&
1464 (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
drhc49f44e2006-10-26 18:15:42 +00001465 i = 0;
1466 break;
1467 }
1468 }
1469 if( i==0 ){
1470 putc('"', out);
1471 for(i=0; z[i]; i++){
1472 if( z[i]=='"' ) putc('"', out);
1473 putc(z[i], out);
1474 }
1475 putc('"', out);
1476 }else{
1477 fprintf(out, "%s", z);
1478 }
drh8e64d1c2004-10-07 00:32:39 +00001479 }
1480 if( bSep ){
drhd0e77882008-01-14 15:20:08 +00001481 fprintf(p->out, "%s", p->separator);
drh8e64d1c2004-10-07 00:32:39 +00001482 }
1483}
1484
danielk19774af00c62005-01-23 23:43:21 +00001485#ifdef SIGINT
drh8e64d1c2004-10-07 00:32:39 +00001486/*
drh4c504392000-10-16 22:06:40 +00001487** This routine runs when the user presses Ctrl-C
1488*/
1489static void interrupt_handler(int NotUsed){
drh902b9ee2008-12-05 17:17:07 +00001490 UNUSED_PARAMETER(NotUsed);
drh67505e72002-04-19 12:34:06 +00001491 seenInterrupt = 1;
danielk19776f8a5032004-05-10 10:34:51 +00001492 if( db ) sqlite3_interrupt(db);
drh4c504392000-10-16 22:06:40 +00001493}
danielk19774af00c62005-01-23 23:43:21 +00001494#endif
drh4c504392000-10-16 22:06:40 +00001495
1496/*
shane626a6e42009-10-22 17:30:15 +00001497** This is the callback routine that the shell
drh75897232000-05-29 14:26:00 +00001498** invokes for each row of a query result.
1499*/
shane626a6e42009-10-22 17:30:15 +00001500static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){
drh75897232000-05-29 14:26:00 +00001501 int i;
1502 struct callback_data *p = (struct callback_data*)pArg;
shaneb9fc17d2009-10-22 21:23:35 +00001503
drh75897232000-05-29 14:26:00 +00001504 switch( p->mode ){
1505 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +00001506 int w = 5;
drh6a535342001-10-19 16:44:56 +00001507 if( azArg==0 ) break;
drhe3710332000-09-29 13:30:53 +00001508 for(i=0; i<nArg; i++){
drh4f21c4a2008-12-10 22:15:00 +00001509 int len = strlen30(azCol[i] ? azCol[i] : "");
drhe3710332000-09-29 13:30:53 +00001510 if( len>w ) w = len;
1511 }
drh75897232000-05-29 14:26:00 +00001512 if( p->cnt++>0 ) fprintf(p->out,"\n");
1513 for(i=0; i<nArg; i++){
drh2cc55692006-06-27 20:39:04 +00001514 fprintf(p->out,"%*s = %s\n", w, azCol[i],
drha69d9162003-04-17 22:57:53 +00001515 azArg[i] ? azArg[i] : p->nullvalue);
drh75897232000-05-29 14:26:00 +00001516 }
1517 break;
1518 }
danielk19770d78bae2008-01-03 07:09:48 +00001519 case MODE_Explain:
drh75897232000-05-29 14:26:00 +00001520 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +00001521 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +00001522 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +00001523 int w, n;
1524 if( i<ArraySize(p->colWidth) ){
danielk19770d78bae2008-01-03 07:09:48 +00001525 w = p->colWidth[i];
drh75897232000-05-29 14:26:00 +00001526 }else{
danielk19770d78bae2008-01-03 07:09:48 +00001527 w = 0;
drh75897232000-05-29 14:26:00 +00001528 }
drha0c66f52000-07-29 13:20:21 +00001529 if( w<=0 ){
drh4f21c4a2008-12-10 22:15:00 +00001530 w = strlen30(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +00001531 if( w<10 ) w = 10;
drh4f21c4a2008-12-10 22:15:00 +00001532 n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
drha0c66f52000-07-29 13:20:21 +00001533 if( w<n ) w = n;
1534 }
1535 if( i<ArraySize(p->actualWidth) ){
persicom1d0b8722002-04-18 02:53:04 +00001536 p->actualWidth[i] = w;
drha0c66f52000-07-29 13:20:21 +00001537 }
1538 if( p->showHeader ){
1539 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
1540 }
1541 }
1542 if( p->showHeader ){
1543 for(i=0; i<nArg; i++){
1544 int w;
1545 if( i<ArraySize(p->actualWidth) ){
1546 w = p->actualWidth[i];
1547 }else{
1548 w = 10;
1549 }
1550 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
1551 "----------------------------------------------------------",
1552 i==nArg-1 ? "\n": " ");
1553 }
drh75897232000-05-29 14:26:00 +00001554 }
1555 }
drh6a535342001-10-19 16:44:56 +00001556 if( azArg==0 ) break;
drh75897232000-05-29 14:26:00 +00001557 for(i=0; i<nArg; i++){
1558 int w;
drha0c66f52000-07-29 13:20:21 +00001559 if( i<ArraySize(p->actualWidth) ){
1560 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +00001561 }else{
1562 w = 10;
1563 }
drhea678832008-12-10 19:26:22 +00001564 if( p->mode==MODE_Explain && azArg[i] &&
drh4f21c4a2008-12-10 22:15:00 +00001565 strlen30(azArg[i])>w ){
1566 w = strlen30(azArg[i]);
danielk19770d78bae2008-01-03 07:09:48 +00001567 }
drhc61053b2000-06-04 12:58:36 +00001568 fprintf(p->out,"%-*.*s%s",w,w,
persicom7e2dfdd2002-04-18 02:46:52 +00001569 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +00001570 }
1571 break;
1572 }
drhe3710332000-09-29 13:30:53 +00001573 case MODE_Semi:
drh75897232000-05-29 14:26:00 +00001574 case MODE_List: {
1575 if( p->cnt++==0 && p->showHeader ){
1576 for(i=0; i<nArg; i++){
1577 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
1578 }
1579 }
drh6a535342001-10-19 16:44:56 +00001580 if( azArg==0 ) break;
drh75897232000-05-29 14:26:00 +00001581 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +00001582 char *z = azArg[i];
persicom7e2dfdd2002-04-18 02:46:52 +00001583 if( z==0 ) z = p->nullvalue;
drh71172c52002-01-24 00:00:21 +00001584 fprintf(p->out, "%s", z);
drhe3710332000-09-29 13:30:53 +00001585 if( i<nArg-1 ){
1586 fprintf(p->out, "%s", p->separator);
1587 }else if( p->mode==MODE_Semi ){
1588 fprintf(p->out, ";\n");
1589 }else{
1590 fprintf(p->out, "\n");
1591 }
drh75897232000-05-29 14:26:00 +00001592 }
1593 break;
1594 }
drh1e5d0e92000-05-31 23:33:17 +00001595 case MODE_Html: {
1596 if( p->cnt++==0 && p->showHeader ){
mihailim57c591a2008-06-23 21:26:05 +00001597 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +00001598 for(i=0; i<nArg; i++){
shane43d9cb22009-10-21 14:11:48 +00001599 fprintf(p->out,"<TH>");
1600 output_html_string(p->out, azCol[i]);
1601 fprintf(p->out,"</TH>\n");
drh1e5d0e92000-05-31 23:33:17 +00001602 }
mihailim57c591a2008-06-23 21:26:05 +00001603 fprintf(p->out,"</TR>\n");
drh1e5d0e92000-05-31 23:33:17 +00001604 }
drh6a535342001-10-19 16:44:56 +00001605 if( azArg==0 ) break;
mihailim57c591a2008-06-23 21:26:05 +00001606 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +00001607 for(i=0; i<nArg; i++){
mihailim57c591a2008-06-23 21:26:05 +00001608 fprintf(p->out,"<TD>");
persicom7e2dfdd2002-04-18 02:46:52 +00001609 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
mihailim57c591a2008-06-23 21:26:05 +00001610 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +00001611 }
mihailim57c591a2008-06-23 21:26:05 +00001612 fprintf(p->out,"</TR>\n");
drh1e5d0e92000-05-31 23:33:17 +00001613 break;
1614 }
drhfeac5f82004-08-01 00:10:45 +00001615 case MODE_Tcl: {
1616 if( p->cnt++==0 && p->showHeader ){
1617 for(i=0; i<nArg; i++){
drh2cc55692006-06-27 20:39:04 +00001618 output_c_string(p->out,azCol[i] ? azCol[i] : "");
drhfeac5f82004-08-01 00:10:45 +00001619 fprintf(p->out, "%s", p->separator);
1620 }
1621 fprintf(p->out,"\n");
1622 }
1623 if( azArg==0 ) break;
1624 for(i=0; i<nArg; i++){
1625 output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
1626 fprintf(p->out, "%s", p->separator);
1627 }
1628 fprintf(p->out,"\n");
1629 break;
1630 }
drh8e64d1c2004-10-07 00:32:39 +00001631 case MODE_Csv: {
1632 if( p->cnt++==0 && p->showHeader ){
1633 for(i=0; i<nArg; i++){
drh2cc55692006-06-27 20:39:04 +00001634 output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
drh8e64d1c2004-10-07 00:32:39 +00001635 }
1636 fprintf(p->out,"\n");
1637 }
1638 if( azArg==0 ) break;
1639 for(i=0; i<nArg; i++){
1640 output_csv(p, azArg[i], i<nArg-1);
1641 }
1642 fprintf(p->out,"\n");
1643 break;
1644 }
drh28bd4bc2000-06-15 15:57:22 +00001645 case MODE_Insert: {
shaneb9fc17d2009-10-22 21:23:35 +00001646 p->cnt++;
drh6a535342001-10-19 16:44:56 +00001647 if( azArg==0 ) break;
drh33048c02001-10-01 14:29:22 +00001648 fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
drh28bd4bc2000-06-15 15:57:22 +00001649 for(i=0; i<nArg; i++){
1650 char *zSep = i>0 ? ",": "";
shanead6b8d02009-10-22 18:12:58 +00001651 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
drh28bd4bc2000-06-15 15:57:22 +00001652 fprintf(p->out,"%sNULL",zSep);
shanead6b8d02009-10-22 18:12:58 +00001653 }else if( aiType && aiType[i]==SQLITE_TEXT ){
1654 if( zSep[0] ) fprintf(p->out,"%s",zSep);
1655 output_quoted_string(p->out, azArg[i]);
1656 }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){
1657 fprintf(p->out,"%s%s",zSep, azArg[i]);
shane626a6e42009-10-22 17:30:15 +00001658 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
1659 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
1660 int nBlob = sqlite3_column_bytes(p->pStmt, i);
1661 if( zSep[0] ) fprintf(p->out,"%s",zSep);
1662 output_hex_blob(p->out, pBlob, nBlob);
drhc8d74412004-08-31 23:41:26 +00001663 }else if( isNumber(azArg[i], 0) ){
drh28bd4bc2000-06-15 15:57:22 +00001664 fprintf(p->out,"%s%s",zSep, azArg[i]);
1665 }else{
1666 if( zSep[0] ) fprintf(p->out,"%s",zSep);
1667 output_quoted_string(p->out, azArg[i]);
1668 }
1669 }
1670 fprintf(p->out,");\n");
drh6a535342001-10-19 16:44:56 +00001671 break;
drh28bd4bc2000-06-15 15:57:22 +00001672 }
persicom1d0b8722002-04-18 02:53:04 +00001673 }
drh75897232000-05-29 14:26:00 +00001674 return 0;
1675}
1676
1677/*
shane626a6e42009-10-22 17:30:15 +00001678** This is the callback routine that the SQLite library
1679** invokes for each row of a query result.
1680*/
1681static int callback(void *pArg, int nArg, char **azArg, char **azCol){
1682 /* since we don't have type info, call the shell_callback with a NULL value */
1683 return shell_callback(pArg, nArg, azArg, azCol, NULL);
1684}
1685
1686/*
drh33048c02001-10-01 14:29:22 +00001687** Set the destination table field of the callback_data structure to
1688** the name of the table given. Escape any quote characters in the
1689** table name.
1690*/
1691static void set_table_name(struct callback_data *p, const char *zName){
1692 int i, n;
1693 int needQuote;
1694 char *z;
1695
1696 if( p->zDestTable ){
1697 free(p->zDestTable);
1698 p->zDestTable = 0;
1699 }
1700 if( zName==0 ) return;
drh4c755c02004-08-08 20:22:17 +00001701 needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
drh33048c02001-10-01 14:29:22 +00001702 for(i=n=0; zName[i]; i++, n++){
drh4c755c02004-08-08 20:22:17 +00001703 if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
drh33048c02001-10-01 14:29:22 +00001704 needQuote = 1;
1705 if( zName[i]=='\'' ) n++;
1706 }
1707 }
1708 if( needQuote ) n += 2;
1709 z = p->zDestTable = malloc( n+1 );
1710 if( z==0 ){
shane86f5bdb2009-10-24 02:00:07 +00001711 fprintf(stderr,"Error: out of memory\n");
drh33048c02001-10-01 14:29:22 +00001712 exit(1);
1713 }
1714 n = 0;
1715 if( needQuote ) z[n++] = '\'';
1716 for(i=0; zName[i]; i++){
1717 z[n++] = zName[i];
1718 if( zName[i]=='\'' ) z[n++] = '\'';
1719 }
1720 if( needQuote ) z[n++] = '\'';
1721 z[n] = 0;
1722}
1723
danielk19772a02e332004-06-05 08:04:36 +00001724/* zIn is either a pointer to a NULL-terminated string in memory obtained
1725** from malloc(), or a NULL pointer. The string pointed to by zAppend is
1726** added to zIn, and the result returned in memory obtained from malloc().
1727** zIn, if it was not NULL, is freed.
1728**
1729** If the third argument, quote, is not '\0', then it is used as a
1730** quote character for zAppend.
1731*/
drhc28490c2006-10-26 14:25:58 +00001732static char *appendText(char *zIn, char const *zAppend, char quote){
danielk19772a02e332004-06-05 08:04:36 +00001733 int len;
1734 int i;
drh4f21c4a2008-12-10 22:15:00 +00001735 int nAppend = strlen30(zAppend);
1736 int nIn = (zIn?strlen30(zIn):0);
danielk19772a02e332004-06-05 08:04:36 +00001737
1738 len = nAppend+nIn+1;
1739 if( quote ){
1740 len += 2;
1741 for(i=0; i<nAppend; i++){
1742 if( zAppend[i]==quote ) len++;
1743 }
1744 }
1745
1746 zIn = (char *)realloc(zIn, len);
1747 if( !zIn ){
1748 return 0;
1749 }
1750
1751 if( quote ){
1752 char *zCsr = &zIn[nIn];
1753 *zCsr++ = quote;
1754 for(i=0; i<nAppend; i++){
1755 *zCsr++ = zAppend[i];
1756 if( zAppend[i]==quote ) *zCsr++ = quote;
1757 }
1758 *zCsr++ = quote;
1759 *zCsr++ = '\0';
1760 assert( (zCsr-zIn)==len );
1761 }else{
1762 memcpy(&zIn[nIn], zAppend, nAppend);
1763 zIn[len-1] = '\0';
1764 }
1765
1766 return zIn;
1767}
1768
drhdd3d4592004-08-30 01:54:05 +00001769
1770/*
1771** Execute a query statement that has a single result column. Print
1772** that result column on a line by itself with a semicolon terminator.
drh45e29d82006-11-20 16:21:10 +00001773**
1774** This is used, for example, to show the schema of the database by
1775** querying the SQLITE_MASTER table.
drhdd3d4592004-08-30 01:54:05 +00001776*/
drh157e29a2009-05-21 15:15:00 +00001777static int run_table_dump_query(
1778 FILE *out, /* Send output here */
1779 sqlite3 *db, /* Database to query */
1780 const char *zSelect, /* SELECT statement to extract content */
1781 const char *zFirstRow /* Print before first row, if not NULL */
1782){
drhdd3d4592004-08-30 01:54:05 +00001783 sqlite3_stmt *pSelect;
1784 int rc;
1785 rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
1786 if( rc!=SQLITE_OK || !pSelect ){
1787 return rc;
1788 }
1789 rc = sqlite3_step(pSelect);
1790 while( rc==SQLITE_ROW ){
drh157e29a2009-05-21 15:15:00 +00001791 if( zFirstRow ){
1792 fprintf(out, "%s", zFirstRow);
1793 zFirstRow = 0;
1794 }
drhdd3d4592004-08-30 01:54:05 +00001795 fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
1796 rc = sqlite3_step(pSelect);
1797 }
1798 return sqlite3_finalize(pSelect);
1799}
1800
shane626a6e42009-10-22 17:30:15 +00001801/*
1802** Allocate space and save off current error string.
1803*/
1804static char *save_err_msg(
1805 sqlite3 *db /* Database to query */
1806){
1807 int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
1808 char *zErrMsg = sqlite3_malloc(nErrMsg);
1809 if( zErrMsg ){
1810 memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
1811 }
1812 return zErrMsg;
1813}
1814
1815/*
1816** Execute a statement or set of statements. Print
1817** any result rows/columns depending on the current mode
1818** set via the supplied callback.
1819**
1820** This is very similar to SQLite's built-in sqlite3_exec()
1821** function except it takes a slightly different callback
1822** and callback data argument.
1823*/
1824static int shell_exec(
1825 sqlite3 *db, /* An open database */
1826 const char *zSql, /* SQL to be evaluated */
1827 int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */
1828 /* (not the same as sqlite3_exec) */
1829 struct callback_data *pArg, /* Pointer to struct callback_data */
1830 char **pzErrMsg /* Error msg written here */
1831){
dan4564ced2010-01-05 04:59:56 +00001832 sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
1833 int rc = SQLITE_OK; /* Return Code */
1834 const char *zLeftover; /* Tail of unprocessed SQL */
shane626a6e42009-10-22 17:30:15 +00001835
1836 if( pzErrMsg ){
1837 *pzErrMsg = NULL;
1838 }
1839
shaneb9fc17d2009-10-22 21:23:35 +00001840 while( zSql[0] && (SQLITE_OK == rc) ){
1841 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
1842 if( SQLITE_OK != rc ){
shane626a6e42009-10-22 17:30:15 +00001843 if( pzErrMsg ){
1844 *pzErrMsg = save_err_msg(db);
1845 }
1846 }else{
shaneb9fc17d2009-10-22 21:23:35 +00001847 if( !pStmt ){
1848 /* this happens for a comment or white-space */
1849 zSql = zLeftover;
1850 while( isspace(zSql[0]) ) zSql++;
1851 continue;
1852 }
shane626a6e42009-10-22 17:30:15 +00001853
shanehb7977c52010-01-18 18:17:10 +00001854 /* echo the sql statement if echo on */
1855 if( pArg->echoOn ){
drha8c62df2010-02-15 15:47:18 +00001856 const char *zStmtSql = sqlite3_sql(pStmt);
shanehb7977c52010-01-18 18:17:10 +00001857 fprintf(pArg->out,"%s\n", zStmtSql ? zStmtSql : zSql);
drha8c62df2010-02-15 15:47:18 +00001858 }
shanehb7977c52010-01-18 18:17:10 +00001859
shaneb9fc17d2009-10-22 21:23:35 +00001860 /* perform the first step. this will tell us if we
1861 ** have a result set or not and how wide it is.
1862 */
1863 rc = sqlite3_step(pStmt);
1864 /* if we have a result set... */
1865 if( SQLITE_ROW == rc ){
1866 /* if we have a callback... */
1867 if( xCallback ){
1868 /* allocate space for col name ptr, value ptr, and type */
1869 int nCol = sqlite3_column_count(pStmt);
1870 void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
1871 if( !pData ){
1872 rc = SQLITE_NOMEM;
1873 }else{
1874 char **azCols = (char **)pData; /* Names of result columns */
1875 char **azVals = &azCols[nCol]; /* Results */
1876 int *aiTypes = (int *)&azVals[nCol]; /* Result types */
1877 int i;
1878 assert(sizeof(int) <= sizeof(char *));
1879 /* save off ptrs to column names */
1880 for(i=0; i<nCol; i++){
1881 azCols[i] = (char *)sqlite3_column_name(pStmt, i);
1882 }
1883 /* save off the prepared statment handle and reset row count */
1884 if( pArg ){
1885 pArg->pStmt = pStmt;
1886 pArg->cnt = 0;
1887 }
1888 do{
1889 /* extract the data and data types */
1890 for(i=0; i<nCol; i++){
1891 azVals[i] = (char *)sqlite3_column_text(pStmt, i);
1892 aiTypes[i] = sqlite3_column_type(pStmt, i);
1893 if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
1894 rc = SQLITE_NOMEM;
1895 break; /* from for */
1896 }
1897 } /* end for */
1898
1899 /* if data and types extracted successfully... */
1900 if( SQLITE_ROW == rc ){
1901 /* call the supplied callback with the result row data */
1902 if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
1903 rc = SQLITE_ABORT;
1904 }else{
1905 rc = sqlite3_step(pStmt);
1906 }
1907 }
1908 } while( SQLITE_ROW == rc );
1909 sqlite3_free(pData);
1910 if( pArg ){
1911 pArg->pStmt = NULL;
1912 }
1913 }
1914 }else{
1915 do{
1916 rc = sqlite3_step(pStmt);
1917 } while( rc == SQLITE_ROW );
1918 }
1919 }
1920
dan4564ced2010-01-05 04:59:56 +00001921 /* Finalize the statement just executed. If this fails, save a
1922 ** copy of the error message. Otherwise, set zSql to point to the
1923 ** next statement to execute. */
1924 rc = sqlite3_finalize(pStmt);
1925 if( rc==SQLITE_OK ){
shaneb9fc17d2009-10-22 21:23:35 +00001926 zSql = zLeftover;
1927 while( isspace(zSql[0]) ) zSql++;
dan4564ced2010-01-05 04:59:56 +00001928 }else if( pzErrMsg ){
1929 *pzErrMsg = save_err_msg(db);
shane626a6e42009-10-22 17:30:15 +00001930 }
1931 }
shaneb9fc17d2009-10-22 21:23:35 +00001932 } /* end while */
shane626a6e42009-10-22 17:30:15 +00001933
1934 return rc;
1935}
1936
drhdd3d4592004-08-30 01:54:05 +00001937
drh33048c02001-10-01 14:29:22 +00001938/*
drh4c653a02000-06-07 01:27:47 +00001939** This is a different callback routine used for dumping the database.
1940** Each row received by this callback consists of a table name,
1941** the table type ("index" or "table") and SQL to create the table.
1942** This routine should print text sufficient to recreate the table.
1943*/
1944static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
danielk19772a02e332004-06-05 08:04:36 +00001945 int rc;
1946 const char *zTable;
1947 const char *zType;
1948 const char *zSql;
drh157e29a2009-05-21 15:15:00 +00001949 const char *zPrepStmt = 0;
drhdaffd0e2001-04-11 14:28:42 +00001950 struct callback_data *p = (struct callback_data *)pArg;
danielk19772a02e332004-06-05 08:04:36 +00001951
drh902b9ee2008-12-05 17:17:07 +00001952 UNUSED_PARAMETER(azCol);
drh4c653a02000-06-07 01:27:47 +00001953 if( nArg!=3 ) return 1;
danielk19772a02e332004-06-05 08:04:36 +00001954 zTable = azArg[0];
1955 zType = azArg[1];
1956 zSql = azArg[2];
1957
drh00b950d2005-09-11 02:03:03 +00001958 if( strcmp(zTable, "sqlite_sequence")==0 ){
drh157e29a2009-05-21 15:15:00 +00001959 zPrepStmt = "DELETE FROM sqlite_sequence;\n";
drh00b950d2005-09-11 02:03:03 +00001960 }else if( strcmp(zTable, "sqlite_stat1")==0 ){
1961 fprintf(p->out, "ANALYZE sqlite_master;\n");
1962 }else if( strncmp(zTable, "sqlite_", 7)==0 ){
1963 return 0;
drh45e29d82006-11-20 16:21:10 +00001964 }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
1965 char *zIns;
1966 if( !p->writableSchema ){
1967 fprintf(p->out, "PRAGMA writable_schema=ON;\n");
1968 p->writableSchema = 1;
1969 }
1970 zIns = sqlite3_mprintf(
1971 "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
1972 "VALUES('table','%q','%q',0,'%q');",
1973 zTable, zTable, zSql);
1974 fprintf(p->out, "%s\n", zIns);
1975 sqlite3_free(zIns);
1976 return 0;
drh00b950d2005-09-11 02:03:03 +00001977 }else{
1978 fprintf(p->out, "%s;\n", zSql);
drhf8eb96a2005-02-03 00:42:34 +00001979 }
danielk19772a02e332004-06-05 08:04:36 +00001980
1981 if( strcmp(zType, "table")==0 ){
1982 sqlite3_stmt *pTableInfo = 0;
danielk19772a02e332004-06-05 08:04:36 +00001983 char *zSelect = 0;
1984 char *zTableInfo = 0;
1985 char *zTmp = 0;
drh157e29a2009-05-21 15:15:00 +00001986 int nRow = 0;
danielk19772a02e332004-06-05 08:04:36 +00001987
1988 zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
1989 zTableInfo = appendText(zTableInfo, zTable, '"');
1990 zTableInfo = appendText(zTableInfo, ");", 0);
1991
1992 rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
drh157e29a2009-05-21 15:15:00 +00001993 free(zTableInfo);
danielk19772a02e332004-06-05 08:04:36 +00001994 if( rc!=SQLITE_OK || !pTableInfo ){
1995 return 1;
1996 }
1997
1998 zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
1999 zTmp = appendText(zTmp, zTable, '"');
2000 if( zTmp ){
2001 zSelect = appendText(zSelect, zTmp, '\'');
2002 }
2003 zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
2004 rc = sqlite3_step(pTableInfo);
2005 while( rc==SQLITE_ROW ){
danielk19772e588c72005-12-09 14:25:08 +00002006 const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
danielk19773f41e972004-06-08 00:39:01 +00002007 zSelect = appendText(zSelect, "quote(", 0);
danielk19772e588c72005-12-09 14:25:08 +00002008 zSelect = appendText(zSelect, zText, '"');
danielk19772a02e332004-06-05 08:04:36 +00002009 rc = sqlite3_step(pTableInfo);
2010 if( rc==SQLITE_ROW ){
drh45e29d82006-11-20 16:21:10 +00002011 zSelect = appendText(zSelect, ") || ',' || ", 0);
danielk19772a02e332004-06-05 08:04:36 +00002012 }else{
2013 zSelect = appendText(zSelect, ") ", 0);
2014 }
drh157e29a2009-05-21 15:15:00 +00002015 nRow++;
danielk19772a02e332004-06-05 08:04:36 +00002016 }
2017 rc = sqlite3_finalize(pTableInfo);
drh157e29a2009-05-21 15:15:00 +00002018 if( rc!=SQLITE_OK || nRow==0 ){
2019 free(zSelect);
danielk19772a02e332004-06-05 08:04:36 +00002020 return 1;
2021 }
2022 zSelect = appendText(zSelect, "|| ')' FROM ", 0);
2023 zSelect = appendText(zSelect, zTable, '"');
2024
drh157e29a2009-05-21 15:15:00 +00002025 rc = run_table_dump_query(p->out, p->db, zSelect, zPrepStmt);
drhdd3d4592004-08-30 01:54:05 +00002026 if( rc==SQLITE_CORRUPT ){
2027 zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
drh157e29a2009-05-21 15:15:00 +00002028 rc = run_table_dump_query(p->out, p->db, zSelect, 0);
drhdd3d4592004-08-30 01:54:05 +00002029 }
danielk19772a02e332004-06-05 08:04:36 +00002030 if( zSelect ) free(zSelect);
drh4c653a02000-06-07 01:27:47 +00002031 }
drh4c653a02000-06-07 01:27:47 +00002032 return 0;
2033}
2034
2035/*
drh45e29d82006-11-20 16:21:10 +00002036** Run zQuery. Use dump_callback() as the callback routine so that
2037** the contents of the query are output as SQL statements.
2038**
drhdd3d4592004-08-30 01:54:05 +00002039** If we get a SQLITE_CORRUPT error, rerun the query after appending
2040** "ORDER BY rowid DESC" to the end.
2041*/
2042static int run_schema_dump_query(
2043 struct callback_data *p,
2044 const char *zQuery,
2045 char **pzErrMsg
2046){
2047 int rc;
2048 rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg);
2049 if( rc==SQLITE_CORRUPT ){
2050 char *zQ2;
drh4f21c4a2008-12-10 22:15:00 +00002051 int len = strlen30(zQuery);
drhdd3d4592004-08-30 01:54:05 +00002052 if( pzErrMsg ) sqlite3_free(*pzErrMsg);
2053 zQ2 = malloc( len+100 );
2054 if( zQ2==0 ) return rc;
drh5bb3eb92007-05-04 13:15:55 +00002055 sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery);
drhdd3d4592004-08-30 01:54:05 +00002056 rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
2057 free(zQ2);
2058 }
2059 return rc;
2060}
2061
danielk1977c8c70692009-02-25 15:22:02 +00002062#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
2063struct GenfkeyCmd {
2064 sqlite3 *db; /* Database handle */
2065 struct callback_data *pCb; /* Callback data */
2066 int isIgnoreErrors; /* True for --ignore-errors */
2067 int isExec; /* True for --exec */
2068 int isNoDrop; /* True for --no-drop */
2069 int nErr; /* Number of errors seen so far */
2070};
2071typedef struct GenfkeyCmd GenfkeyCmd;
2072
2073static int genfkeyParseArgs(GenfkeyCmd *p, char **azArg, int nArg){
2074 int ii;
2075 memset(p, 0, sizeof(GenfkeyCmd));
2076
2077 for(ii=0; ii<nArg; ii++){
drh93a989c2009-03-16 10:59:44 +00002078 int n = strlen30(azArg[ii]);
danielk1977c8c70692009-02-25 15:22:02 +00002079
2080 if( n>2 && n<10 && 0==strncmp(azArg[ii], "--no-drop", n) ){
2081 p->isNoDrop = 1;
2082 }else if( n>2 && n<16 && 0==strncmp(azArg[ii], "--ignore-errors", n) ){
2083 p->isIgnoreErrors = 1;
2084 }else if( n>2 && n<7 && 0==strncmp(azArg[ii], "--exec", n) ){
2085 p->isExec = 1;
2086 }else{
2087 fprintf(stderr, "unknown option: %s\n", azArg[ii]);
2088 return -1;
2089 }
2090 }
2091
2092 return SQLITE_OK;
2093}
2094
2095static int genfkeyCmdCb(void *pCtx, int eType, const char *z){
2096 GenfkeyCmd *p = (GenfkeyCmd *)pCtx;
2097 if( eType==GENFKEY_ERROR && !p->isIgnoreErrors ){
2098 p->nErr++;
2099 fprintf(stderr, "%s\n", z);
2100 }
2101
2102 if( p->nErr==0 && (
2103 (eType==GENFKEY_CREATETRIGGER)
2104 || (eType==GENFKEY_DROPTRIGGER && !p->isNoDrop)
2105 )){
2106 if( p->isExec ){
2107 sqlite3_exec(p->db, z, 0, 0, 0);
2108 }else{
2109 char *zCol = "sql";
2110 callback((void *)p->pCb, 1, (char **)&z, (char **)&zCol);
2111 }
2112 }
2113
2114 return SQLITE_OK;
2115}
2116#endif
2117
drhdd3d4592004-08-30 01:54:05 +00002118/*
drh75897232000-05-29 14:26:00 +00002119** Text of a help message
2120*/
persicom1d0b8722002-04-18 02:53:04 +00002121static char zHelp[] =
drh9ff849f2009-02-04 20:55:57 +00002122 ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
drh20f99c42007-01-08 14:31:35 +00002123 ".bail ON|OFF Stop after hitting an error. Default OFF\n"
jplyon6a65bb32003-05-04 07:25:57 +00002124 ".databases List names and files of attached databases\n"
drhb860bc92004-08-04 15:16:55 +00002125 ".dump ?TABLE? ... Dump the database in an SQL text format\n"
shane86f5bdb2009-10-24 02:00:07 +00002126 " If TABLE specified, only dump tables matching\n"
2127 " LIKE pattern TABLE.\n"
drhdaffd0e2001-04-11 14:28:42 +00002128 ".echo ON|OFF Turn command echo on or off\n"
drh75897232000-05-29 14:26:00 +00002129 ".exit Exit this program\n"
shanehe2aa9d72009-11-06 17:20:17 +00002130 ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n"
2131 " With no args, it turns EXPLAIN on.\n"
danielk1977c8c70692009-02-25 15:22:02 +00002132#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
2133 ".genfkey ?OPTIONS? Options are:\n"
2134 " --no-drop: Do not drop old fkey triggers.\n"
2135 " --ignore-errors: Ignore tables with fkey errors\n"
2136 " --exec: Execute generated SQL immediately\n"
danielk1977e6320042009-02-25 15:43:57 +00002137 " See file tool/genfkey.README in the source \n"
2138 " distribution for further information.\n"
danielk1977c8c70692009-02-25 15:22:02 +00002139#endif
persicom7e2dfdd2002-04-18 02:46:52 +00002140 ".header(s) ON|OFF Turn display of headers on or off\n"
drh75897232000-05-29 14:26:00 +00002141 ".help Show this message\n"
drhb860bc92004-08-04 15:16:55 +00002142 ".import FILE TABLE Import data from FILE into TABLE\n"
shane86f5bdb2009-10-24 02:00:07 +00002143 ".indices ?TABLE? Show names of all indices\n"
2144 " If TABLE specified, only show indices for tables\n"
2145 " matching LIKE pattern TABLE.\n"
drhae5e4452007-05-03 17:18:36 +00002146#ifdef SQLITE_ENABLE_IOTRACE
2147 ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
2148#endif
drh70df4fe2006-06-13 15:12:21 +00002149#ifndef SQLITE_OMIT_LOAD_EXTENSION
drh1e397f82006-06-08 15:28:43 +00002150 ".load FILE ?ENTRY? Load an extension library\n"
drh70df4fe2006-06-13 15:12:21 +00002151#endif
danielk19776b77a362005-01-13 11:10:25 +00002152 ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
drh3b584fa2004-09-24 12:50:03 +00002153 " csv Comma-separated values\n"
drhb860bc92004-08-04 15:16:55 +00002154 " column Left-aligned columns. (See .width)\n"
2155 " html HTML <table> code\n"
2156 " insert SQL insert statements for TABLE\n"
2157 " line One value per line\n"
2158 " list Values delimited by .separator string\n"
2159 " tabs Tab-separated values\n"
2160 " tcl TCL list elements\n"
2161 ".nullvalue STRING Print STRING in place of NULL values\n"
drh75897232000-05-29 14:26:00 +00002162 ".output FILENAME Send output to FILENAME\n"
2163 ".output stdout Send output to the screen\n"
persicom7e2dfdd2002-04-18 02:46:52 +00002164 ".prompt MAIN CONTINUE Replace the standard prompts\n"
persicom7e2dfdd2002-04-18 02:46:52 +00002165 ".quit Exit this program\n"
drhdaffd0e2001-04-11 14:28:42 +00002166 ".read FILENAME Execute SQL in FILENAME\n"
drh9ff849f2009-02-04 20:55:57 +00002167 ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
drh75897232000-05-29 14:26:00 +00002168 ".schema ?TABLE? Show the CREATE statements\n"
shane86f5bdb2009-10-24 02:00:07 +00002169 " If TABLE specified, only show tables matching\n"
2170 " LIKE pattern TABLE.\n"
drhb860bc92004-08-04 15:16:55 +00002171 ".separator STRING Change separator used by output mode and .import\n"
drhdd45df82002-04-18 12:39:03 +00002172 ".show Show the current values for various settings\n"
shane86f5bdb2009-10-24 02:00:07 +00002173 ".tables ?TABLE? List names of tables\n"
2174 " If TABLE specified, only list tables matching\n"
2175 " LIKE pattern TABLE.\n"
drh2dfbbca2000-07-28 14:32:48 +00002176 ".timeout MS Try opening locked tables for MS milliseconds\n"
shanehe2aa9d72009-11-06 17:20:17 +00002177 ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
drh75897232000-05-29 14:26:00 +00002178;
2179
shaneb320ccd2009-10-21 03:42:58 +00002180static char zTimerHelp[] =
2181 ".timer ON|OFF Turn the CPU timer measurement on or off\n"
2182;
2183
drhdaffd0e2001-04-11 14:28:42 +00002184/* Forward reference */
drhc28490c2006-10-26 14:25:58 +00002185static int process_input(struct callback_data *p, FILE *in);
drhdaffd0e2001-04-11 14:28:42 +00002186
drh75897232000-05-29 14:26:00 +00002187/*
drh44c2eb12003-04-30 11:38:26 +00002188** Make sure the database is open. If it is not, then open it. If
2189** the database fails to open, print an error message and exit.
2190*/
2191static void open_db(struct callback_data *p){
2192 if( p->db==0 ){
danielk19774f057f92004-06-08 00:02:33 +00002193 sqlite3_open(p->zDbFilename, &p->db);
danielk197780290862004-05-22 09:21:21 +00002194 db = p->db;
drh4cea5ba2008-05-05 16:27:24 +00002195 if( db && sqlite3_errcode(db)==SQLITE_OK ){
2196 sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
2197 shellstaticFunc, 0, 0);
2198 }
2199 if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
shane86f5bdb2009-10-24 02:00:07 +00002200 fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
danielk197780290862004-05-22 09:21:21 +00002201 p->zDbFilename, sqlite3_errmsg(db));
drh22fbcb82004-02-01 01:22:50 +00002202 exit(1);
drh44c2eb12003-04-30 11:38:26 +00002203 }
drhc2e87a32006-06-27 15:16:14 +00002204#ifndef SQLITE_OMIT_LOAD_EXTENSION
2205 sqlite3_enable_load_extension(p->db, 1);
2206#endif
drh44c2eb12003-04-30 11:38:26 +00002207 }
2208}
2209
2210/*
drhfeac5f82004-08-01 00:10:45 +00002211** Do C-language style dequoting.
2212**
2213** \t -> tab
2214** \n -> newline
2215** \r -> carriage return
2216** \NNN -> ascii character NNN in octal
2217** \\ -> backslash
2218*/
2219static void resolve_backslashes(char *z){
shane7d3846a2008-12-11 02:58:26 +00002220 int i, j;
2221 char c;
drhfeac5f82004-08-01 00:10:45 +00002222 for(i=j=0; (c = z[i])!=0; i++, j++){
2223 if( c=='\\' ){
2224 c = z[++i];
2225 if( c=='n' ){
2226 c = '\n';
2227 }else if( c=='t' ){
2228 c = '\t';
2229 }else if( c=='r' ){
2230 c = '\r';
2231 }else if( c>='0' && c<='7' ){
drhaa816082005-12-29 12:53:09 +00002232 c -= '0';
drhfeac5f82004-08-01 00:10:45 +00002233 if( z[i+1]>='0' && z[i+1]<='7' ){
2234 i++;
2235 c = (c<<3) + z[i] - '0';
2236 if( z[i+1]>='0' && z[i+1]<='7' ){
2237 i++;
2238 c = (c<<3) + z[i] - '0';
2239 }
2240 }
2241 }
2242 }
2243 z[j] = c;
2244 }
2245 z[j] = 0;
2246}
2247
2248/*
drhc28490c2006-10-26 14:25:58 +00002249** Interpret zArg as a boolean value. Return either 0 or 1.
2250*/
2251static int booleanValue(char *zArg){
2252 int val = atoi(zArg);
2253 int j;
2254 for(j=0; zArg[j]; j++){
shane7d3846a2008-12-11 02:58:26 +00002255 zArg[j] = (char)tolower(zArg[j]);
drhc28490c2006-10-26 14:25:58 +00002256 }
2257 if( strcmp(zArg,"on")==0 ){
2258 val = 1;
2259 }else if( strcmp(zArg,"yes")==0 ){
2260 val = 1;
2261 }
2262 return val;
2263}
2264
2265/*
drh75897232000-05-29 14:26:00 +00002266** If an input line begins with "." then invoke this routine to
2267** process that line.
drh67505e72002-04-19 12:34:06 +00002268**
drh47ad6842006-11-08 12:25:42 +00002269** Return 1 on error, 2 to exit, and 0 otherwise.
drh75897232000-05-29 14:26:00 +00002270*/
drh44c2eb12003-04-30 11:38:26 +00002271static int do_meta_command(char *zLine, struct callback_data *p){
drh75897232000-05-29 14:26:00 +00002272 int i = 1;
2273 int nArg = 0;
2274 int n, c;
drh67505e72002-04-19 12:34:06 +00002275 int rc = 0;
drh75897232000-05-29 14:26:00 +00002276 char *azArg[50];
2277
2278 /* Parse the input line into tokens.
2279 */
2280 while( zLine[i] && nArg<ArraySize(azArg) ){
drh4c755c02004-08-08 20:22:17 +00002281 while( isspace((unsigned char)zLine[i]) ){ i++; }
drh06333682004-03-09 13:37:45 +00002282 if( zLine[i]==0 ) break;
drh75897232000-05-29 14:26:00 +00002283 if( zLine[i]=='\'' || zLine[i]=='"' ){
2284 int delim = zLine[i++];
2285 azArg[nArg++] = &zLine[i];
2286 while( zLine[i] && zLine[i]!=delim ){ i++; }
2287 if( zLine[i]==delim ){
2288 zLine[i++] = 0;
2289 }
drhfeac5f82004-08-01 00:10:45 +00002290 if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
drh75897232000-05-29 14:26:00 +00002291 }else{
2292 azArg[nArg++] = &zLine[i];
drh4c755c02004-08-08 20:22:17 +00002293 while( zLine[i] && !isspace((unsigned char)zLine[i]) ){ i++; }
drh75897232000-05-29 14:26:00 +00002294 if( zLine[i] ) zLine[i++] = 0;
drhfeac5f82004-08-01 00:10:45 +00002295 resolve_backslashes(azArg[nArg-1]);
drh75897232000-05-29 14:26:00 +00002296 }
2297 }
2298
2299 /* Process the input line.
2300 */
shane9bd1b442009-10-23 01:27:39 +00002301 if( nArg==0 ) return 0; /* no tokens, no error */
drh4f21c4a2008-12-10 22:15:00 +00002302 n = strlen30(azArg[0]);
drh75897232000-05-29 14:26:00 +00002303 c = azArg[0][0];
shanehe2aa9d72009-11-06 17:20:17 +00002304 if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){
drh9ff849f2009-02-04 20:55:57 +00002305 const char *zDestFile;
2306 const char *zDb;
2307 sqlite3 *pDest;
2308 sqlite3_backup *pBackup;
drh9ff849f2009-02-04 20:55:57 +00002309 if( nArg==2 ){
2310 zDestFile = azArg[1];
2311 zDb = "main";
2312 }else{
2313 zDestFile = azArg[2];
2314 zDb = azArg[1];
2315 }
2316 rc = sqlite3_open(zDestFile, &pDest);
2317 if( rc!=SQLITE_OK ){
shane9bd1b442009-10-23 01:27:39 +00002318 fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
drh9ff849f2009-02-04 20:55:57 +00002319 sqlite3_close(pDest);
2320 return 1;
2321 }
drhdc2c4912009-02-04 22:46:47 +00002322 open_db(p);
drh9ff849f2009-02-04 20:55:57 +00002323 pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
2324 if( pBackup==0 ){
2325 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
2326 sqlite3_close(pDest);
2327 return 1;
2328 }
2329 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
2330 sqlite3_backup_finish(pBackup);
2331 if( rc==SQLITE_DONE ){
shane9bd1b442009-10-23 01:27:39 +00002332 rc = 0;
drh9ff849f2009-02-04 20:55:57 +00002333 }else{
2334 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
shane9bd1b442009-10-23 01:27:39 +00002335 rc = 1;
drh9ff849f2009-02-04 20:55:57 +00002336 }
2337 sqlite3_close(pDest);
2338 }else
2339
shanehe2aa9d72009-11-06 17:20:17 +00002340 if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){
drhc49f44e2006-10-26 18:15:42 +00002341 bail_on_error = booleanValue(azArg[1]);
2342 }else
2343
shanehe2aa9d72009-11-06 17:20:17 +00002344 if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
jplyon672a1ed2003-05-11 20:07:05 +00002345 struct callback_data data;
2346 char *zErrMsg = 0;
jplyon6a65bb32003-05-04 07:25:57 +00002347 open_db(p);
jplyon672a1ed2003-05-11 20:07:05 +00002348 memcpy(&data, p, sizeof(data));
drhd8885442004-03-17 23:42:12 +00002349 data.showHeader = 1;
jplyon672a1ed2003-05-11 20:07:05 +00002350 data.mode = MODE_Column;
drhd8885442004-03-17 23:42:12 +00002351 data.colWidth[0] = 3;
2352 data.colWidth[1] = 15;
2353 data.colWidth[2] = 58;
drh0b2110c2004-10-26 00:08:10 +00002354 data.cnt = 0;
danielk19776f8a5032004-05-10 10:34:51 +00002355 sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
jplyon672a1ed2003-05-11 20:07:05 +00002356 if( zErrMsg ){
2357 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00002358 sqlite3_free(zErrMsg);
shane9bd1b442009-10-23 01:27:39 +00002359 rc = 1;
jplyon6a65bb32003-05-04 07:25:57 +00002360 }
2361 }else
2362
shanehe2aa9d72009-11-06 17:20:17 +00002363 if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
drh4c653a02000-06-07 01:27:47 +00002364 char *zErrMsg = 0;
drh44c2eb12003-04-30 11:38:26 +00002365 open_db(p);
drhf1dfc4f2009-09-23 15:51:35 +00002366 /* When playing back a "dump", the content might appear in an order
2367 ** which causes immediate foreign key constraints to be violated.
2368 ** So disable foreign-key constraint enforcement to prevent problems. */
2369 fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
drh33048c02001-10-01 14:29:22 +00002370 fprintf(p->out, "BEGIN TRANSACTION;\n");
drh45e29d82006-11-20 16:21:10 +00002371 p->writableSchema = 0;
drh93f41e52008-08-11 19:12:34 +00002372 sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0);
drh4c653a02000-06-07 01:27:47 +00002373 if( nArg==1 ){
drhdd3d4592004-08-30 01:54:05 +00002374 run_schema_dump_query(p,
drha18c5682000-10-08 22:20:57 +00002375 "SELECT name, type, sql FROM sqlite_master "
drh4f324762009-05-21 14:51:03 +00002376 "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0
2377 );
2378 run_schema_dump_query(p,
2379 "SELECT name, type, sql FROM sqlite_master "
2380 "WHERE name=='sqlite_sequence'", 0
drh0b9a5942006-09-13 20:22:02 +00002381 );
2382 run_table_dump_query(p->out, p->db,
2383 "SELECT sql FROM sqlite_master "
drh157e29a2009-05-21 15:15:00 +00002384 "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
drha18c5682000-10-08 22:20:57 +00002385 );
drh4c653a02000-06-07 01:27:47 +00002386 }else{
2387 int i;
drhdd3d4592004-08-30 01:54:05 +00002388 for(i=1; i<nArg; i++){
danielk1977bc6ada42004-06-30 08:20:16 +00002389 zShellStatic = azArg[i];
drhdd3d4592004-08-30 01:54:05 +00002390 run_schema_dump_query(p,
drha18c5682000-10-08 22:20:57 +00002391 "SELECT name, type, sql FROM sqlite_master "
drhdd3d4592004-08-30 01:54:05 +00002392 "WHERE tbl_name LIKE shellstatic() AND type=='table'"
drh45e29d82006-11-20 16:21:10 +00002393 " AND sql NOT NULL", 0);
drh0b9a5942006-09-13 20:22:02 +00002394 run_table_dump_query(p->out, p->db,
2395 "SELECT sql FROM sqlite_master "
drh45e29d82006-11-20 16:21:10 +00002396 "WHERE sql NOT NULL"
2397 " AND type IN ('index','trigger','view')"
drh157e29a2009-05-21 15:15:00 +00002398 " AND tbl_name LIKE shellstatic()", 0
drh0b9a5942006-09-13 20:22:02 +00002399 );
danielk1977bc6ada42004-06-30 08:20:16 +00002400 zShellStatic = 0;
drh4c653a02000-06-07 01:27:47 +00002401 }
2402 }
drh45e29d82006-11-20 16:21:10 +00002403 if( p->writableSchema ){
2404 fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
2405 p->writableSchema = 0;
2406 }
drh93f41e52008-08-11 19:12:34 +00002407 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF", 0, 0, 0);
drh4c653a02000-06-07 01:27:47 +00002408 if( zErrMsg ){
2409 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00002410 sqlite3_free(zErrMsg);
drh33048c02001-10-01 14:29:22 +00002411 }else{
2412 fprintf(p->out, "COMMIT;\n");
drh4c653a02000-06-07 01:27:47 +00002413 }
2414 }else
drh75897232000-05-29 14:26:00 +00002415
shanehe2aa9d72009-11-06 17:20:17 +00002416 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
drhc28490c2006-10-26 14:25:58 +00002417 p->echoOn = booleanValue(azArg[1]);
drhdaffd0e2001-04-11 14:28:42 +00002418 }else
2419
shanehe2aa9d72009-11-06 17:20:17 +00002420 if( c=='e' && strncmp(azArg[0], "exit", n)==0 && nArg==1 ){
drh47ad6842006-11-08 12:25:42 +00002421 rc = 2;
drh75897232000-05-29 14:26:00 +00002422 }else
2423
shanehe2aa9d72009-11-06 17:20:17 +00002424 if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
drhc28490c2006-10-26 14:25:58 +00002425 int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
persicom7e2dfdd2002-04-18 02:46:52 +00002426 if(val == 1) {
2427 if(!p->explainPrev.valid) {
2428 p->explainPrev.valid = 1;
2429 p->explainPrev.mode = p->mode;
2430 p->explainPrev.showHeader = p->showHeader;
2431 memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
2432 }
2433 /* We could put this code under the !p->explainValid
2434 ** condition so that it does not execute if we are already in
2435 ** explain mode. However, always executing it allows us an easy
2436 ** was to reset to explain mode in case the user previously
2437 ** did an .explain followed by a .width, .mode or .header
2438 ** command.
2439 */
danielk19770d78bae2008-01-03 07:09:48 +00002440 p->mode = MODE_Explain;
persicom7e2dfdd2002-04-18 02:46:52 +00002441 p->showHeader = 1;
2442 memset(p->colWidth,0,ArraySize(p->colWidth));
danielk19770d78bae2008-01-03 07:09:48 +00002443 p->colWidth[0] = 4; /* addr */
drh60a713c2008-01-21 16:22:45 +00002444 p->colWidth[1] = 13; /* opcode */
2445 p->colWidth[2] = 4; /* P1 */
2446 p->colWidth[3] = 4; /* P2 */
2447 p->colWidth[4] = 4; /* P3 */
2448 p->colWidth[5] = 13; /* P4 */
danielk19770d78bae2008-01-03 07:09:48 +00002449 p->colWidth[6] = 2; /* P5 */
drh60a713c2008-01-21 16:22:45 +00002450 p->colWidth[7] = 13; /* Comment */
persicom7e2dfdd2002-04-18 02:46:52 +00002451 }else if (p->explainPrev.valid) {
2452 p->explainPrev.valid = 0;
2453 p->mode = p->explainPrev.mode;
2454 p->showHeader = p->explainPrev.showHeader;
2455 memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
2456 }
drh75897232000-05-29 14:26:00 +00002457 }else
2458
danielk1977c8c70692009-02-25 15:22:02 +00002459#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
2460 if( c=='g' && strncmp(azArg[0], "genfkey", n)==0 ){
2461 GenfkeyCmd cmd;
2462 if( 0==genfkeyParseArgs(&cmd, &azArg[1], nArg-1) ){
2463 cmd.db = p->db;
2464 cmd.pCb = p;
2465 genfkey_create_triggers(p->db, "main", (void *)&cmd, genfkeyCmdCb);
2466 }
2467 }else
2468#endif
2469
drhc28490c2006-10-26 14:25:58 +00002470 if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
shanehe2aa9d72009-11-06 17:20:17 +00002471 strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){
drhc28490c2006-10-26 14:25:58 +00002472 p->showHeader = booleanValue(azArg[1]);
drh75897232000-05-29 14:26:00 +00002473 }else
2474
2475 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
drha81c64a2009-01-14 23:38:02 +00002476 fprintf(stderr,"%s",zHelp);
shaneb320ccd2009-10-21 03:42:58 +00002477 if( HAS_TIMER ){
2478 fprintf(stderr,"%s",zTimerHelp);
2479 }
drh75897232000-05-29 14:26:00 +00002480 }else
2481
shanehe2aa9d72009-11-06 17:20:17 +00002482 if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
drhfeac5f82004-08-01 00:10:45 +00002483 char *zTable = azArg[2]; /* Insert data into this table */
2484 char *zFile = azArg[1]; /* The file from which to extract data */
shane916f9612009-10-23 00:37:15 +00002485 sqlite3_stmt *pStmt = NULL; /* A statement */
drhfeac5f82004-08-01 00:10:45 +00002486 int nCol; /* Number of columns in the table */
2487 int nByte; /* Number of bytes in an SQL string */
2488 int i, j; /* Loop counters */
2489 int nSep; /* Number of bytes in p->separator[] */
2490 char *zSql; /* An SQL statement */
2491 char *zLine; /* A single line of input from the file */
2492 char **azCol; /* zLine[] broken up into columns */
2493 char *zCommit; /* How to commit changes */
drhb860bc92004-08-04 15:16:55 +00002494 FILE *in; /* The input file */
2495 int lineno = 0; /* Line number of input file */
drhfeac5f82004-08-01 00:10:45 +00002496
drha543c822006-06-08 16:10:14 +00002497 open_db(p);
drh4f21c4a2008-12-10 22:15:00 +00002498 nSep = strlen30(p->separator);
drhfeac5f82004-08-01 00:10:45 +00002499 if( nSep==0 ){
shane916f9612009-10-23 00:37:15 +00002500 fprintf(stderr, "Error: non-null separator required for import\n");
2501 return 1;
drhfeac5f82004-08-01 00:10:45 +00002502 }
2503 zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
shane916f9612009-10-23 00:37:15 +00002504 if( zSql==0 ){
2505 fprintf(stderr, "Error: out of memory\n");
2506 return 1;
2507 }
drh4f21c4a2008-12-10 22:15:00 +00002508 nByte = strlen30(zSql);
drh5e6078b2006-01-31 19:07:22 +00002509 rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
drhfeac5f82004-08-01 00:10:45 +00002510 sqlite3_free(zSql);
2511 if( rc ){
shane916f9612009-10-23 00:37:15 +00002512 if (pStmt) sqlite3_finalize(pStmt);
drhfeac5f82004-08-01 00:10:45 +00002513 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
shane916f9612009-10-23 00:37:15 +00002514 return 1;
drhfeac5f82004-08-01 00:10:45 +00002515 }
shane916f9612009-10-23 00:37:15 +00002516 nCol = sqlite3_column_count(pStmt);
drhfeac5f82004-08-01 00:10:45 +00002517 sqlite3_finalize(pStmt);
shane916f9612009-10-23 00:37:15 +00002518 pStmt = 0;
shane9bd1b442009-10-23 01:27:39 +00002519 if( nCol==0 ) return 0; /* no columns, no error */
drhfeac5f82004-08-01 00:10:45 +00002520 zSql = malloc( nByte + 20 + nCol*2 );
shane916f9612009-10-23 00:37:15 +00002521 if( zSql==0 ){
2522 fprintf(stderr, "Error: out of memory\n");
2523 return 1;
2524 }
drhfeac5f82004-08-01 00:10:45 +00002525 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable);
drh4f21c4a2008-12-10 22:15:00 +00002526 j = strlen30(zSql);
drhfeac5f82004-08-01 00:10:45 +00002527 for(i=1; i<nCol; i++){
2528 zSql[j++] = ',';
2529 zSql[j++] = '?';
2530 }
2531 zSql[j++] = ')';
2532 zSql[j] = 0;
drh5e6078b2006-01-31 19:07:22 +00002533 rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
drhfeac5f82004-08-01 00:10:45 +00002534 free(zSql);
2535 if( rc ){
2536 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
shane916f9612009-10-23 00:37:15 +00002537 if (pStmt) sqlite3_finalize(pStmt);
drh47ad6842006-11-08 12:25:42 +00002538 return 1;
drhfeac5f82004-08-01 00:10:45 +00002539 }
2540 in = fopen(zFile, "rb");
2541 if( in==0 ){
shane9bd1b442009-10-23 01:27:39 +00002542 fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
drhfeac5f82004-08-01 00:10:45 +00002543 sqlite3_finalize(pStmt);
shane916f9612009-10-23 00:37:15 +00002544 return 1;
drhfeac5f82004-08-01 00:10:45 +00002545 }
2546 azCol = malloc( sizeof(azCol[0])*(nCol+1) );
drh43617e92006-03-06 20:55:46 +00002547 if( azCol==0 ){
shane916f9612009-10-23 00:37:15 +00002548 fprintf(stderr, "Error: out of memory\n");
drh43617e92006-03-06 20:55:46 +00002549 fclose(in);
shane916f9612009-10-23 00:37:15 +00002550 sqlite3_finalize(pStmt);
2551 return 1;
drh43617e92006-03-06 20:55:46 +00002552 }
drhfeac5f82004-08-01 00:10:45 +00002553 sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
2554 zCommit = "COMMIT";
2555 while( (zLine = local_getline(0, in))!=0 ){
2556 char *z;
2557 i = 0;
drhb860bc92004-08-04 15:16:55 +00002558 lineno++;
drhfeac5f82004-08-01 00:10:45 +00002559 azCol[0] = zLine;
drh36d4e972004-10-06 14:39:06 +00002560 for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){
drhfeac5f82004-08-01 00:10:45 +00002561 if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
2562 *z = 0;
2563 i++;
drhb860bc92004-08-04 15:16:55 +00002564 if( i<nCol ){
2565 azCol[i] = &z[nSep];
2566 z += nSep-1;
2567 }
drhfeac5f82004-08-01 00:10:45 +00002568 }
shane916f9612009-10-23 00:37:15 +00002569 } /* end for */
drh1cd7f832005-08-05 18:50:51 +00002570 *z = 0;
drhb860bc92004-08-04 15:16:55 +00002571 if( i+1!=nCol ){
shane916f9612009-10-23 00:37:15 +00002572 fprintf(stderr,
2573 "Error: %s line %d: expected %d columns of data but found %d\n",
2574 zFile, lineno, nCol, i+1);
drhb860bc92004-08-04 15:16:55 +00002575 zCommit = "ROLLBACK";
drh1822eee2008-12-04 12:26:00 +00002576 free(zLine);
shane916f9612009-10-23 00:37:15 +00002577 rc = 1;
2578 break; /* from while */
drhb860bc92004-08-04 15:16:55 +00002579 }
drhfeac5f82004-08-01 00:10:45 +00002580 for(i=0; i<nCol; i++){
2581 sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
2582 }
2583 sqlite3_step(pStmt);
2584 rc = sqlite3_reset(pStmt);
2585 free(zLine);
2586 if( rc!=SQLITE_OK ){
2587 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
2588 zCommit = "ROLLBACK";
drh47ad6842006-11-08 12:25:42 +00002589 rc = 1;
shane916f9612009-10-23 00:37:15 +00002590 break; /* from while */
drhfeac5f82004-08-01 00:10:45 +00002591 }
shane916f9612009-10-23 00:37:15 +00002592 } /* end while */
drhfeac5f82004-08-01 00:10:45 +00002593 free(azCol);
2594 fclose(in);
2595 sqlite3_finalize(pStmt);
drhb860bc92004-08-04 15:16:55 +00002596 sqlite3_exec(p->db, zCommit, 0, 0, 0);
drhfeac5f82004-08-01 00:10:45 +00002597 }else
2598
shanehe2aa9d72009-11-06 17:20:17 +00002599 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
drh75897232000-05-29 14:26:00 +00002600 struct callback_data data;
2601 char *zErrMsg = 0;
drh44c2eb12003-04-30 11:38:26 +00002602 open_db(p);
drh75897232000-05-29 14:26:00 +00002603 memcpy(&data, p, sizeof(data));
2604 data.showHeader = 0;
2605 data.mode = MODE_List;
shane86f5bdb2009-10-24 02:00:07 +00002606 if( nArg==1 ){
2607 rc = sqlite3_exec(p->db,
2608 "SELECT name FROM sqlite_master "
2609 "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
2610 "UNION ALL "
2611 "SELECT name FROM sqlite_temp_master "
2612 "WHERE type='index' "
2613 "ORDER BY 1",
2614 callback, &data, &zErrMsg
2615 );
2616 }else{
2617 zShellStatic = azArg[1];
2618 rc = sqlite3_exec(p->db,
2619 "SELECT name FROM sqlite_master "
2620 "WHERE type='index' AND tbl_name LIKE shellstatic() "
2621 "UNION ALL "
2622 "SELECT name FROM sqlite_temp_master "
2623 "WHERE type='index' AND tbl_name LIKE shellstatic() "
2624 "ORDER BY 1",
2625 callback, &data, &zErrMsg
2626 );
2627 zShellStatic = 0;
2628 }
drh75897232000-05-29 14:26:00 +00002629 if( zErrMsg ){
2630 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00002631 sqlite3_free(zErrMsg);
shane9bd1b442009-10-23 01:27:39 +00002632 rc = 1;
shane86f5bdb2009-10-24 02:00:07 +00002633 }else if( rc != SQLITE_OK ){
2634 fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
2635 rc = 1;
drh75897232000-05-29 14:26:00 +00002636 }
2637 }else
2638
drhae5e4452007-05-03 17:18:36 +00002639#ifdef SQLITE_ENABLE_IOTRACE
drhb0603412007-02-28 04:47:26 +00002640 if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
mlcreech3a00f902008-03-04 17:45:01 +00002641 extern void (*sqlite3IoTrace)(const char*, ...);
drhb0603412007-02-28 04:47:26 +00002642 if( iotrace && iotrace!=stdout ) fclose(iotrace);
2643 iotrace = 0;
2644 if( nArg<2 ){
mlcreech3a00f902008-03-04 17:45:01 +00002645 sqlite3IoTrace = 0;
drhb0603412007-02-28 04:47:26 +00002646 }else if( strcmp(azArg[1], "-")==0 ){
mlcreech3a00f902008-03-04 17:45:01 +00002647 sqlite3IoTrace = iotracePrintf;
drhb0603412007-02-28 04:47:26 +00002648 iotrace = stdout;
2649 }else{
2650 iotrace = fopen(azArg[1], "w");
2651 if( iotrace==0 ){
shane9bd1b442009-10-23 01:27:39 +00002652 fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
mlcreech3a00f902008-03-04 17:45:01 +00002653 sqlite3IoTrace = 0;
shane9bd1b442009-10-23 01:27:39 +00002654 rc = 1;
drhb0603412007-02-28 04:47:26 +00002655 }else{
mlcreech3a00f902008-03-04 17:45:01 +00002656 sqlite3IoTrace = iotracePrintf;
drhb0603412007-02-28 04:47:26 +00002657 }
2658 }
2659 }else
drhae5e4452007-05-03 17:18:36 +00002660#endif
drhb0603412007-02-28 04:47:26 +00002661
drh70df4fe2006-06-13 15:12:21 +00002662#ifndef SQLITE_OMIT_LOAD_EXTENSION
drh1e397f82006-06-08 15:28:43 +00002663 if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
2664 const char *zFile, *zProc;
2665 char *zErrMsg = 0;
drh1e397f82006-06-08 15:28:43 +00002666 zFile = azArg[1];
2667 zProc = nArg>=3 ? azArg[2] : 0;
2668 open_db(p);
2669 rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
2670 if( rc!=SQLITE_OK ){
shane9bd1b442009-10-23 01:27:39 +00002671 fprintf(stderr, "Error: %s\n", zErrMsg);
drh1e397f82006-06-08 15:28:43 +00002672 sqlite3_free(zErrMsg);
drh47ad6842006-11-08 12:25:42 +00002673 rc = 1;
drh1e397f82006-06-08 15:28:43 +00002674 }
2675 }else
drh70df4fe2006-06-13 15:12:21 +00002676#endif
drh1e397f82006-06-08 15:28:43 +00002677
shanehe2aa9d72009-11-06 17:20:17 +00002678 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
drh4f21c4a2008-12-10 22:15:00 +00002679 int n2 = strlen30(azArg[1]);
shanehe2aa9d72009-11-06 17:20:17 +00002680 if( (n2==4 && strncmp(azArg[1],"line",n2)==0)
persicom7e2dfdd2002-04-18 02:46:52 +00002681 ||
shanehe2aa9d72009-11-06 17:20:17 +00002682 (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){
drh75897232000-05-29 14:26:00 +00002683 p->mode = MODE_Line;
shanehe2aa9d72009-11-06 17:20:17 +00002684 }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0)
persicom7e2dfdd2002-04-18 02:46:52 +00002685 ||
shanehe2aa9d72009-11-06 17:20:17 +00002686 (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){
drh75897232000-05-29 14:26:00 +00002687 p->mode = MODE_Column;
shanehe2aa9d72009-11-06 17:20:17 +00002688 }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){
drh75897232000-05-29 14:26:00 +00002689 p->mode = MODE_List;
shanehe2aa9d72009-11-06 17:20:17 +00002690 }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){
drh1e5d0e92000-05-31 23:33:17 +00002691 p->mode = MODE_Html;
shanehe2aa9d72009-11-06 17:20:17 +00002692 }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){
drhfeac5f82004-08-01 00:10:45 +00002693 p->mode = MODE_Tcl;
shanehe2aa9d72009-11-06 17:20:17 +00002694 }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){
drh8e64d1c2004-10-07 00:32:39 +00002695 p->mode = MODE_Csv;
drh5bb3eb92007-05-04 13:15:55 +00002696 sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
shanehe2aa9d72009-11-06 17:20:17 +00002697 }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){
drhfeac5f82004-08-01 00:10:45 +00002698 p->mode = MODE_List;
drh5bb3eb92007-05-04 13:15:55 +00002699 sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
shanehe2aa9d72009-11-06 17:20:17 +00002700 }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
drh28bd4bc2000-06-15 15:57:22 +00002701 p->mode = MODE_Insert;
shanehe2aa9d72009-11-06 17:20:17 +00002702 set_table_name(p, "table");
drhdaffd0e2001-04-11 14:28:42 +00002703 }else {
shane9bd1b442009-10-23 01:27:39 +00002704 fprintf(stderr,"Error: mode should be one of: "
drhfeac5f82004-08-01 00:10:45 +00002705 "column csv html insert line list tabs tcl\n");
shane9bd1b442009-10-23 01:27:39 +00002706 rc = 1;
drh75897232000-05-29 14:26:00 +00002707 }
2708 }else
2709
shanehe2aa9d72009-11-06 17:20:17 +00002710 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){
2711 int n2 = strlen30(azArg[1]);
2712 if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
2713 p->mode = MODE_Insert;
2714 set_table_name(p, azArg[2]);
2715 }else {
2716 fprintf(stderr, "Error: invalid arguments: "
2717 " \"%s\". Enter \".help\" for help\n", azArg[2]);
2718 rc = 1;
2719 }
2720 }else
2721
persicom7e2dfdd2002-04-18 02:46:52 +00002722 if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
drh5bb3eb92007-05-04 13:15:55 +00002723 sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
2724 "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
persicom7e2dfdd2002-04-18 02:46:52 +00002725 }else
2726
drh75897232000-05-29 14:26:00 +00002727 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
2728 if( p->out!=stdout ){
2729 fclose(p->out);
2730 }
2731 if( strcmp(azArg[1],"stdout")==0 ){
2732 p->out = stdout;
drh5bb3eb92007-05-04 13:15:55 +00002733 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
drh75897232000-05-29 14:26:00 +00002734 }else{
drha1f9b5e2004-02-14 16:31:02 +00002735 p->out = fopen(azArg[1], "wb");
drh75897232000-05-29 14:26:00 +00002736 if( p->out==0 ){
shane9bd1b442009-10-23 01:27:39 +00002737 fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
drh75897232000-05-29 14:26:00 +00002738 p->out = stdout;
shane9bd1b442009-10-23 01:27:39 +00002739 rc = 1;
persicom7e2dfdd2002-04-18 02:46:52 +00002740 } else {
drh5bb3eb92007-05-04 13:15:55 +00002741 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
drh75897232000-05-29 14:26:00 +00002742 }
2743 }
2744 }else
2745
drhdd45df82002-04-18 12:39:03 +00002746 if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
persicom7e2dfdd2002-04-18 02:46:52 +00002747 if( nArg >= 2) {
2748 strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
2749 }
2750 if( nArg >= 3) {
2751 strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
2752 }
2753 }else
2754
shanehe2aa9d72009-11-06 17:20:17 +00002755 if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){
drh47ad6842006-11-08 12:25:42 +00002756 rc = 2;
persicom7e2dfdd2002-04-18 02:46:52 +00002757 }else
2758
drh9ff849f2009-02-04 20:55:57 +00002759 if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
drha1f9b5e2004-02-14 16:31:02 +00002760 FILE *alt = fopen(azArg[1], "rb");
drhdaffd0e2001-04-11 14:28:42 +00002761 if( alt==0 ){
shane9bd1b442009-10-23 01:27:39 +00002762 fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
2763 rc = 1;
drhdaffd0e2001-04-11 14:28:42 +00002764 }else{
shane9bd1b442009-10-23 01:27:39 +00002765 rc = process_input(p, alt);
drhdaffd0e2001-04-11 14:28:42 +00002766 fclose(alt);
2767 }
2768 }else
2769
shanehe2aa9d72009-11-06 17:20:17 +00002770 if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){
drh9ff849f2009-02-04 20:55:57 +00002771 const char *zSrcFile;
2772 const char *zDb;
2773 sqlite3 *pSrc;
2774 sqlite3_backup *pBackup;
drhdc2c4912009-02-04 22:46:47 +00002775 int nTimeout = 0;
2776
drh9ff849f2009-02-04 20:55:57 +00002777 if( nArg==2 ){
2778 zSrcFile = azArg[1];
2779 zDb = "main";
2780 }else{
2781 zSrcFile = azArg[2];
2782 zDb = azArg[1];
2783 }
2784 rc = sqlite3_open(zSrcFile, &pSrc);
2785 if( rc!=SQLITE_OK ){
shane9bd1b442009-10-23 01:27:39 +00002786 fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
drh9ff849f2009-02-04 20:55:57 +00002787 sqlite3_close(pSrc);
2788 return 1;
2789 }
drhdc2c4912009-02-04 22:46:47 +00002790 open_db(p);
drh9ff849f2009-02-04 20:55:57 +00002791 pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
2792 if( pBackup==0 ){
2793 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
2794 sqlite3_close(pSrc);
2795 return 1;
2796 }
drhdc2c4912009-02-04 22:46:47 +00002797 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
2798 || rc==SQLITE_BUSY ){
2799 if( rc==SQLITE_BUSY ){
2800 if( nTimeout++ >= 3 ) break;
2801 sqlite3_sleep(100);
drh9ff849f2009-02-04 20:55:57 +00002802 }
2803 }
2804 sqlite3_backup_finish(pBackup);
2805 if( rc==SQLITE_DONE ){
shane9bd1b442009-10-23 01:27:39 +00002806 rc = 0;
drhdc2c4912009-02-04 22:46:47 +00002807 }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
shane9bd1b442009-10-23 01:27:39 +00002808 fprintf(stderr, "Error: source database is busy\n");
2809 rc = 1;
drh9ff849f2009-02-04 20:55:57 +00002810 }else{
2811 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
shane9bd1b442009-10-23 01:27:39 +00002812 rc = 1;
drh9ff849f2009-02-04 20:55:57 +00002813 }
2814 sqlite3_close(pSrc);
2815 }else
2816
shanehe2aa9d72009-11-06 17:20:17 +00002817 if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
drh75897232000-05-29 14:26:00 +00002818 struct callback_data data;
2819 char *zErrMsg = 0;
drh44c2eb12003-04-30 11:38:26 +00002820 open_db(p);
drh75897232000-05-29 14:26:00 +00002821 memcpy(&data, p, sizeof(data));
2822 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +00002823 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +00002824 if( nArg>1 ){
drhc8d74412004-08-31 23:41:26 +00002825 int i;
shane7d3846a2008-12-11 02:58:26 +00002826 for(i=0; azArg[1][i]; i++) azArg[1][i] = (char)tolower(azArg[1][i]);
drhc8d74412004-08-31 23:41:26 +00002827 if( strcmp(azArg[1],"sqlite_master")==0 ){
drha18c5682000-10-08 22:20:57 +00002828 char *new_argv[2], *new_colv[2];
2829 new_argv[0] = "CREATE TABLE sqlite_master (\n"
2830 " type text,\n"
2831 " name text,\n"
2832 " tbl_name text,\n"
drhadbca9c2001-09-27 15:11:53 +00002833 " rootpage integer,\n"
drha18c5682000-10-08 22:20:57 +00002834 " sql text\n"
2835 ")";
2836 new_argv[1] = 0;
2837 new_colv[0] = "sql";
2838 new_colv[1] = 0;
2839 callback(&data, 1, new_argv, new_colv);
shane9bd1b442009-10-23 01:27:39 +00002840 rc = SQLITE_OK;
drhc8d74412004-08-31 23:41:26 +00002841 }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
drhe0bc4042002-06-25 01:09:11 +00002842 char *new_argv[2], *new_colv[2];
2843 new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
2844 " type text,\n"
2845 " name text,\n"
2846 " tbl_name text,\n"
2847 " rootpage integer,\n"
2848 " sql text\n"
2849 ")";
2850 new_argv[1] = 0;
2851 new_colv[0] = "sql";
2852 new_colv[1] = 0;
2853 callback(&data, 1, new_argv, new_colv);
shane9bd1b442009-10-23 01:27:39 +00002854 rc = SQLITE_OK;
drha18c5682000-10-08 22:20:57 +00002855 }else{
danielk1977bc6ada42004-06-30 08:20:16 +00002856 zShellStatic = azArg[1];
shane9bd1b442009-10-23 01:27:39 +00002857 rc = sqlite3_exec(p->db,
drhe0bc4042002-06-25 01:09:11 +00002858 "SELECT sql FROM "
drh8f800a72009-01-14 23:17:55 +00002859 " (SELECT sql sql, type type, tbl_name tbl_name, name name"
2860 " FROM sqlite_master UNION ALL"
2861 " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) "
danielk1977bc6ada42004-06-30 08:20:16 +00002862 "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTNULL "
drhe0bc4042002-06-25 01:09:11 +00002863 "ORDER BY substr(type,2,1), name",
danielk1977bc6ada42004-06-30 08:20:16 +00002864 callback, &data, &zErrMsg);
2865 zShellStatic = 0;
drha18c5682000-10-08 22:20:57 +00002866 }
drh75897232000-05-29 14:26:00 +00002867 }else{
shane9bd1b442009-10-23 01:27:39 +00002868 rc = sqlite3_exec(p->db,
drhe0bc4042002-06-25 01:09:11 +00002869 "SELECT sql FROM "
drh8f800a72009-01-14 23:17:55 +00002870 " (SELECT sql sql, type type, tbl_name tbl_name, name name"
2871 " FROM sqlite_master UNION ALL"
2872 " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) "
drh0c356672005-09-10 22:40:53 +00002873 "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
drhe0bc4042002-06-25 01:09:11 +00002874 "ORDER BY substr(type,2,1), name",
drha18c5682000-10-08 22:20:57 +00002875 callback, &data, &zErrMsg
2876 );
drh75897232000-05-29 14:26:00 +00002877 }
drh75897232000-05-29 14:26:00 +00002878 if( zErrMsg ){
2879 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00002880 sqlite3_free(zErrMsg);
shane9bd1b442009-10-23 01:27:39 +00002881 rc = 1;
2882 }else if( rc != SQLITE_OK ){
2883 fprintf(stderr,"Error: querying schema information\n");
2884 rc = 1;
2885 }else{
2886 rc = 0;
drh75897232000-05-29 14:26:00 +00002887 }
2888 }else
2889
2890 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
drh5bb3eb92007-05-04 13:15:55 +00002891 sqlite3_snprintf(sizeof(p->separator), p->separator,
2892 "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
drh75897232000-05-29 14:26:00 +00002893 }else
2894
shanehe2aa9d72009-11-06 17:20:17 +00002895 if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
persicom7e2dfdd2002-04-18 02:46:52 +00002896 int i;
2897 fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
drh67505e72002-04-19 12:34:06 +00002898 fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
drhdd45df82002-04-18 12:39:03 +00002899 fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
persicom7e2dfdd2002-04-18 02:46:52 +00002900 fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
drhfeac5f82004-08-01 00:10:45 +00002901 fprintf(p->out,"%9.9s: ", "nullvalue");
2902 output_c_string(p->out, p->nullvalue);
2903 fprintf(p->out, "\n");
drh67505e72002-04-19 12:34:06 +00002904 fprintf(p->out,"%9.9s: %s\n","output",
drh4f21c4a2008-12-10 22:15:00 +00002905 strlen30(p->outfile) ? p->outfile : "stdout");
drhfeac5f82004-08-01 00:10:45 +00002906 fprintf(p->out,"%9.9s: ", "separator");
2907 output_c_string(p->out, p->separator);
2908 fprintf(p->out, "\n");
persicom7e2dfdd2002-04-18 02:46:52 +00002909 fprintf(p->out,"%9.9s: ","width");
2910 for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
drhfeac5f82004-08-01 00:10:45 +00002911 fprintf(p->out,"%d ",p->colWidth[i]);
persicom7e2dfdd2002-04-18 02:46:52 +00002912 }
drhfeac5f82004-08-01 00:10:45 +00002913 fprintf(p->out,"\n");
persicom7e2dfdd2002-04-18 02:46:52 +00002914 }else
2915
shanehe2aa9d72009-11-06 17:20:17 +00002916 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
drhe3710332000-09-29 13:30:53 +00002917 char **azResult;
shane9bd1b442009-10-23 01:27:39 +00002918 int nRow;
drhe3710332000-09-29 13:30:53 +00002919 char *zErrMsg;
drh44c2eb12003-04-30 11:38:26 +00002920 open_db(p);
drha50da102000-08-08 20:19:09 +00002921 if( nArg==1 ){
danielk19776f8a5032004-05-10 10:34:51 +00002922 rc = sqlite3_get_table(p->db,
drha50da102000-08-08 20:19:09 +00002923 "SELECT name FROM sqlite_master "
shane86f5bdb2009-10-24 02:00:07 +00002924 "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' "
drhe0bc4042002-06-25 01:09:11 +00002925 "UNION ALL "
2926 "SELECT name FROM sqlite_temp_master "
2927 "WHERE type IN ('table','view') "
2928 "ORDER BY 1",
drha18c5682000-10-08 22:20:57 +00002929 &azResult, &nRow, 0, &zErrMsg
2930 );
drha50da102000-08-08 20:19:09 +00002931 }else{
danielk1977bc6ada42004-06-30 08:20:16 +00002932 zShellStatic = azArg[1];
2933 rc = sqlite3_get_table(p->db,
drha50da102000-08-08 20:19:09 +00002934 "SELECT name FROM sqlite_master "
shane86f5bdb2009-10-24 02:00:07 +00002935 "WHERE type IN ('table','view') AND name LIKE shellstatic() "
drhe0bc4042002-06-25 01:09:11 +00002936 "UNION ALL "
2937 "SELECT name FROM sqlite_temp_master "
shane86f5bdb2009-10-24 02:00:07 +00002938 "WHERE type IN ('table','view') AND name LIKE shellstatic() "
drhe0bc4042002-06-25 01:09:11 +00002939 "ORDER BY 1",
danielk1977bc6ada42004-06-30 08:20:16 +00002940 &azResult, &nRow, 0, &zErrMsg
drha18c5682000-10-08 22:20:57 +00002941 );
danielk1977bc6ada42004-06-30 08:20:16 +00002942 zShellStatic = 0;
drha50da102000-08-08 20:19:09 +00002943 }
drh75897232000-05-29 14:26:00 +00002944 if( zErrMsg ){
2945 fprintf(stderr,"Error: %s\n", zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00002946 sqlite3_free(zErrMsg);
shane9bd1b442009-10-23 01:27:39 +00002947 rc = 1;
2948 }else if( rc != SQLITE_OK ){
2949 fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
2950 rc = 1;
2951 }else{
drhe3710332000-09-29 13:30:53 +00002952 int len, maxlen = 0;
2953 int i, j;
2954 int nPrintCol, nPrintRow;
2955 for(i=1; i<=nRow; i++){
2956 if( azResult[i]==0 ) continue;
drh4f21c4a2008-12-10 22:15:00 +00002957 len = strlen30(azResult[i]);
drhe3710332000-09-29 13:30:53 +00002958 if( len>maxlen ) maxlen = len;
2959 }
2960 nPrintCol = 80/(maxlen+2);
2961 if( nPrintCol<1 ) nPrintCol = 1;
2962 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
2963 for(i=0; i<nPrintRow; i++){
2964 for(j=i+1; j<=nRow; j+=nPrintRow){
2965 char *zSp = j<=nPrintRow ? "" : " ";
2966 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
2967 }
2968 printf("\n");
2969 }
2970 }
danielk19776f8a5032004-05-10 10:34:51 +00002971 sqlite3_free_table(azResult);
drh75897232000-05-29 14:26:00 +00002972 }else
2973
shanehe2aa9d72009-11-06 17:20:17 +00002974 if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
drh44c2eb12003-04-30 11:38:26 +00002975 open_db(p);
danielk19776f8a5032004-05-10 10:34:51 +00002976 sqlite3_busy_timeout(p->db, atoi(azArg[1]));
shanehe2aa9d72009-11-06 17:20:17 +00002977 }else
2978
2979 if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg==2 ){
drh3b1a9882007-11-02 12:53:03 +00002980 enableTimer = booleanValue(azArg[1]);
shanehe2aa9d72009-11-06 17:20:17 +00002981 }else
2982
2983 if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
drh75897232000-05-29 14:26:00 +00002984 int j;
drh43617e92006-03-06 20:55:46 +00002985 assert( nArg<=ArraySize(azArg) );
drh75897232000-05-29 14:26:00 +00002986 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
2987 p->colWidth[j-1] = atoi(azArg[j]);
2988 }
2989 }else
2990
2991 {
shane9bd1b442009-10-23 01:27:39 +00002992 fprintf(stderr, "Error: unknown command or invalid arguments: "
drh67505e72002-04-19 12:34:06 +00002993 " \"%s\". Enter \".help\" for help\n", azArg[0]);
shane9bd1b442009-10-23 01:27:39 +00002994 rc = 1;
drh75897232000-05-29 14:26:00 +00002995 }
drh67505e72002-04-19 12:34:06 +00002996
2997 return rc;
drh75897232000-05-29 14:26:00 +00002998}
2999
drh67505e72002-04-19 12:34:06 +00003000/*
drh91a66392007-09-07 01:12:32 +00003001** Return TRUE if a semicolon occurs anywhere in the first N characters
3002** of string z[].
drh324ccef2003-02-05 14:06:20 +00003003*/
drh91a66392007-09-07 01:12:32 +00003004static int _contains_semicolon(const char *z, int N){
3005 int i;
3006 for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
3007 return 0;
drh324ccef2003-02-05 14:06:20 +00003008}
3009
3010/*
drh70c7a4b2003-04-26 03:03:06 +00003011** Test to see if a line consists entirely of whitespace.
3012*/
3013static int _all_whitespace(const char *z){
3014 for(; *z; z++){
drh4c755c02004-08-08 20:22:17 +00003015 if( isspace(*(unsigned char*)z) ) continue;
drh70c7a4b2003-04-26 03:03:06 +00003016 if( *z=='/' && z[1]=='*' ){
3017 z += 2;
3018 while( *z && (*z!='*' || z[1]!='/') ){ z++; }
3019 if( *z==0 ) return 0;
3020 z++;
3021 continue;
3022 }
3023 if( *z=='-' && z[1]=='-' ){
3024 z += 2;
3025 while( *z && *z!='\n' ){ z++; }
3026 if( *z==0 ) return 1;
3027 continue;
3028 }
3029 return 0;
3030 }
3031 return 1;
3032}
3033
3034/*
drha9b17162003-04-29 18:01:28 +00003035** Return TRUE if the line typed in is an SQL command terminator other
3036** than a semi-colon. The SQL Server style "go" command is understood
3037** as is the Oracle "/".
3038*/
3039static int _is_command_terminator(const char *zLine){
drh4c755c02004-08-08 20:22:17 +00003040 while( isspace(*(unsigned char*)zLine) ){ zLine++; };
drh233a5312008-12-18 22:25:13 +00003041 if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
3042 return 1; /* Oracle */
3043 }
drhc8d74412004-08-31 23:41:26 +00003044 if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o'
3045 && _all_whitespace(&zLine[2]) ){
drha9b17162003-04-29 18:01:28 +00003046 return 1; /* SQL Server */
3047 }
3048 return 0;
3049}
3050
3051/*
drh233a5312008-12-18 22:25:13 +00003052** Return true if zSql is a complete SQL statement. Return false if it
3053** ends in the middle of a string literal or C-style comment.
3054*/
3055static int _is_complete(char *zSql, int nSql){
3056 int rc;
3057 if( zSql==0 ) return 1;
3058 zSql[nSql] = ';';
3059 zSql[nSql+1] = 0;
3060 rc = sqlite3_complete(zSql);
3061 zSql[nSql] = 0;
3062 return rc;
3063}
3064
3065/*
drh67505e72002-04-19 12:34:06 +00003066** Read input from *in and process it. If *in==0 then input
3067** is interactive - the user is typing it it. Otherwise, input
3068** is coming from a file or device. A prompt is issued and history
3069** is saved only if input is interactive. An interrupt signal will
3070** cause this routine to exit immediately, unless input is interactive.
drhc28490c2006-10-26 14:25:58 +00003071**
3072** Return the number of errors.
drh67505e72002-04-19 12:34:06 +00003073*/
drhc28490c2006-10-26 14:25:58 +00003074static int process_input(struct callback_data *p, FILE *in){
danielk19772ac27622007-07-03 05:31:16 +00003075 char *zLine = 0;
drhdaffd0e2001-04-11 14:28:42 +00003076 char *zSql = 0;
3077 int nSql = 0;
drh91a66392007-09-07 01:12:32 +00003078 int nSqlPrior = 0;
drhdaffd0e2001-04-11 14:28:42 +00003079 char *zErrMsg;
drhc49f44e2006-10-26 18:15:42 +00003080 int rc;
3081 int errCnt = 0;
drhc28490c2006-10-26 14:25:58 +00003082 int lineno = 0;
3083 int startline = 0;
drhc49f44e2006-10-26 18:15:42 +00003084
3085 while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
3086 fflush(p->out);
danielk19772ac27622007-07-03 05:31:16 +00003087 free(zLine);
drhc49f44e2006-10-26 18:15:42 +00003088 zLine = one_input_line(zSql, in);
3089 if( zLine==0 ){
3090 break; /* We have reached EOF */
3091 }
drh67505e72002-04-19 12:34:06 +00003092 if( seenInterrupt ){
3093 if( in!=0 ) break;
3094 seenInterrupt = 0;
3095 }
drhc28490c2006-10-26 14:25:58 +00003096 lineno++;
drhf817b6b2003-06-16 00:16:41 +00003097 if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
drh2af0b2d2002-02-21 02:25:02 +00003098 if( zLine && zLine[0]=='.' && nSql==0 ){
shaneb9fc17d2009-10-22 21:23:35 +00003099 if( p->echoOn ) printf("%s\n", zLine);
drhc49f44e2006-10-26 18:15:42 +00003100 rc = do_meta_command(zLine, p);
shane916f9612009-10-23 00:37:15 +00003101 if( rc==2 ){ /* exit requested */
drh47ad6842006-11-08 12:25:42 +00003102 break;
3103 }else if( rc ){
drhc49f44e2006-10-26 18:15:42 +00003104 errCnt++;
3105 }
drhdaffd0e2001-04-11 14:28:42 +00003106 continue;
3107 }
drh233a5312008-12-18 22:25:13 +00003108 if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){
drh5bb3eb92007-05-04 13:15:55 +00003109 memcpy(zLine,";",2);
drha9b17162003-04-29 18:01:28 +00003110 }
drh91a66392007-09-07 01:12:32 +00003111 nSqlPrior = nSql;
drhdaffd0e2001-04-11 14:28:42 +00003112 if( zSql==0 ){
3113 int i;
drh4c755c02004-08-08 20:22:17 +00003114 for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){}
drhdaffd0e2001-04-11 14:28:42 +00003115 if( zLine[i]!=0 ){
drh4f21c4a2008-12-10 22:15:00 +00003116 nSql = strlen30(zLine);
drh233a5312008-12-18 22:25:13 +00003117 zSql = malloc( nSql+3 );
drhc1f44942006-05-10 14:39:13 +00003118 if( zSql==0 ){
shane9bd1b442009-10-23 01:27:39 +00003119 fprintf(stderr, "Error: out of memory\n");
drhc1f44942006-05-10 14:39:13 +00003120 exit(1);
3121 }
drh5bb3eb92007-05-04 13:15:55 +00003122 memcpy(zSql, zLine, nSql+1);
drhc28490c2006-10-26 14:25:58 +00003123 startline = lineno;
drhdaffd0e2001-04-11 14:28:42 +00003124 }
3125 }else{
drh4f21c4a2008-12-10 22:15:00 +00003126 int len = strlen30(zLine);
drh233a5312008-12-18 22:25:13 +00003127 zSql = realloc( zSql, nSql + len + 4 );
drhdaffd0e2001-04-11 14:28:42 +00003128 if( zSql==0 ){
shane9bd1b442009-10-23 01:27:39 +00003129 fprintf(stderr,"Error: out of memory\n");
drhdaffd0e2001-04-11 14:28:42 +00003130 exit(1);
3131 }
drh5bb3eb92007-05-04 13:15:55 +00003132 zSql[nSql++] = '\n';
3133 memcpy(&zSql[nSql], zLine, len+1);
drhdaffd0e2001-04-11 14:28:42 +00003134 nSql += len;
3135 }
drh91a66392007-09-07 01:12:32 +00003136 if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
3137 && sqlite3_complete(zSql) ){
drhdaffd0e2001-04-11 14:28:42 +00003138 p->cnt = 0;
drh44c2eb12003-04-30 11:38:26 +00003139 open_db(p);
drh3b1a9882007-11-02 12:53:03 +00003140 BEGIN_TIMER;
shane626a6e42009-10-22 17:30:15 +00003141 rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
drh3b1a9882007-11-02 12:53:03 +00003142 END_TIMER;
drh7f953e22002-07-13 17:33:45 +00003143 if( rc || zErrMsg ){
drhc28490c2006-10-26 14:25:58 +00003144 char zPrefix[100];
3145 if( in!=0 || !stdin_is_interactive ){
drh5bb3eb92007-05-04 13:15:55 +00003146 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
shane9bd1b442009-10-23 01:27:39 +00003147 "Error: near line %d:", startline);
drhc28490c2006-10-26 14:25:58 +00003148 }else{
shane9bd1b442009-10-23 01:27:39 +00003149 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
drhc28490c2006-10-26 14:25:58 +00003150 }
drh7f953e22002-07-13 17:33:45 +00003151 if( zErrMsg!=0 ){
shaned2bed1c2009-10-21 03:56:54 +00003152 fprintf(stderr, "%s %s\n", zPrefix, zErrMsg);
drh3f4fedb2004-05-31 19:34:33 +00003153 sqlite3_free(zErrMsg);
drh7f953e22002-07-13 17:33:45 +00003154 zErrMsg = 0;
3155 }else{
shaned2bed1c2009-10-21 03:56:54 +00003156 fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
drh7f953e22002-07-13 17:33:45 +00003157 }
drhc49f44e2006-10-26 18:15:42 +00003158 errCnt++;
drhdaffd0e2001-04-11 14:28:42 +00003159 }
3160 free(zSql);
3161 zSql = 0;
3162 nSql = 0;
3163 }
3164 }
3165 if( zSql ){
shane86f5bdb2009-10-24 02:00:07 +00003166 if( !_all_whitespace(zSql) ) fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
drhdaffd0e2001-04-11 14:28:42 +00003167 free(zSql);
3168 }
danielk19772ac27622007-07-03 05:31:16 +00003169 free(zLine);
drhc49f44e2006-10-26 18:15:42 +00003170 return errCnt;
drhdaffd0e2001-04-11 14:28:42 +00003171}
3172
drh67505e72002-04-19 12:34:06 +00003173/*
3174** Return a pathname which is the user's home directory. A
3175** 0 return indicates an error of some kind. Space to hold the
3176** resulting string is obtained from malloc(). The calling
3177** function should free the result.
3178*/
3179static char *find_home_dir(void){
3180 char *home_dir = NULL;
persicom7e2dfdd2002-04-18 02:46:52 +00003181
chw97185482008-11-17 08:05:31 +00003182#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
drh67505e72002-04-19 12:34:06 +00003183 struct passwd *pwent;
3184 uid_t uid = getuid();
drhbd842ba2002-08-21 11:26:41 +00003185 if( (pwent=getpwuid(uid)) != NULL) {
3186 home_dir = pwent->pw_dir;
drh67505e72002-04-19 12:34:06 +00003187 }
3188#endif
3189
chw65d3c132007-11-12 21:09:10 +00003190#if defined(_WIN32_WCE)
3191 /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
3192 */
3193 home_dir = strdup("/");
3194#else
3195
drh164a1b62006-08-19 11:15:20 +00003196#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
3197 if (!home_dir) {
3198 home_dir = getenv("USERPROFILE");
3199 }
3200#endif
3201
drh67505e72002-04-19 12:34:06 +00003202 if (!home_dir) {
3203 home_dir = getenv("HOME");
drh67505e72002-04-19 12:34:06 +00003204 }
3205
drhcdb36b72006-06-12 12:57:45 +00003206#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
drhe98d4fa2002-04-21 19:06:22 +00003207 if (!home_dir) {
drh164a1b62006-08-19 11:15:20 +00003208 char *zDrive, *zPath;
3209 int n;
3210 zDrive = getenv("HOMEDRIVE");
3211 zPath = getenv("HOMEPATH");
3212 if( zDrive && zPath ){
drh4f21c4a2008-12-10 22:15:00 +00003213 n = strlen30(zDrive) + strlen30(zPath) + 1;
drh164a1b62006-08-19 11:15:20 +00003214 home_dir = malloc( n );
3215 if( home_dir==0 ) return 0;
3216 sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
3217 return home_dir;
3218 }
3219 home_dir = "c:\\";
drhe98d4fa2002-04-21 19:06:22 +00003220 }
3221#endif
3222
chw65d3c132007-11-12 21:09:10 +00003223#endif /* !_WIN32_WCE */
3224
drh67505e72002-04-19 12:34:06 +00003225 if( home_dir ){
drh4f21c4a2008-12-10 22:15:00 +00003226 int n = strlen30(home_dir) + 1;
drh5bb3eb92007-05-04 13:15:55 +00003227 char *z = malloc( n );
3228 if( z ) memcpy(z, home_dir, n);
drh67505e72002-04-19 12:34:06 +00003229 home_dir = z;
3230 }
drhe98d4fa2002-04-21 19:06:22 +00003231
drh67505e72002-04-19 12:34:06 +00003232 return home_dir;
3233}
3234
3235/*
3236** Read input from the file given by sqliterc_override. Or if that
3237** parameter is NULL, take input from ~/.sqliterc
shane9bd1b442009-10-23 01:27:39 +00003238**
3239** Returns the number of errors.
drh67505e72002-04-19 12:34:06 +00003240*/
shane9bd1b442009-10-23 01:27:39 +00003241static int process_sqliterc(
drh22fbcb82004-02-01 01:22:50 +00003242 struct callback_data *p, /* Configuration data */
3243 const char *sqliterc_override /* Name of config file. NULL to use default */
3244){
persicom7e2dfdd2002-04-18 02:46:52 +00003245 char *home_dir = NULL;
drh22fbcb82004-02-01 01:22:50 +00003246 const char *sqliterc = sqliterc_override;
drh43617e92006-03-06 20:55:46 +00003247 char *zBuf = 0;
persicom7e2dfdd2002-04-18 02:46:52 +00003248 FILE *in = NULL;
drha959ac42007-06-20 13:10:00 +00003249 int nBuf;
shane9bd1b442009-10-23 01:27:39 +00003250 int rc = 0;
persicom7e2dfdd2002-04-18 02:46:52 +00003251
3252 if (sqliterc == NULL) {
drh67505e72002-04-19 12:34:06 +00003253 home_dir = find_home_dir();
drhe98d4fa2002-04-21 19:06:22 +00003254 if( home_dir==0 ){
chw97185482008-11-17 08:05:31 +00003255#if !defined(__RTP__) && !defined(_WRS_KERNEL)
shane86f5bdb2009-10-24 02:00:07 +00003256 fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0);
chw97185482008-11-17 08:05:31 +00003257#endif
shane9bd1b442009-10-23 01:27:39 +00003258 return 1;
drhe98d4fa2002-04-21 19:06:22 +00003259 }
drh4f21c4a2008-12-10 22:15:00 +00003260 nBuf = strlen30(home_dir) + 16;
drha959ac42007-06-20 13:10:00 +00003261 zBuf = malloc( nBuf );
drh22fbcb82004-02-01 01:22:50 +00003262 if( zBuf==0 ){
shane86f5bdb2009-10-24 02:00:07 +00003263 fprintf(stderr,"%s: Error: out of memory\n",Argv0);
3264 return 1;
persicom7e2dfdd2002-04-18 02:46:52 +00003265 }
drha959ac42007-06-20 13:10:00 +00003266 sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir);
drh67505e72002-04-19 12:34:06 +00003267 free(home_dir);
drh22fbcb82004-02-01 01:22:50 +00003268 sqliterc = (const char*)zBuf;
persicom7e2dfdd2002-04-18 02:46:52 +00003269 }
drha1f9b5e2004-02-14 16:31:02 +00003270 in = fopen(sqliterc,"rb");
drh22fbcb82004-02-01 01:22:50 +00003271 if( in ){
drhc28490c2006-10-26 14:25:58 +00003272 if( stdin_is_interactive ){
shane86f5bdb2009-10-24 02:00:07 +00003273 fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
drh22fbcb82004-02-01 01:22:50 +00003274 }
shane9bd1b442009-10-23 01:27:39 +00003275 rc = process_input(p,in);
drhdd45df82002-04-18 12:39:03 +00003276 fclose(in);
persicom7e2dfdd2002-04-18 02:46:52 +00003277 }
drh43617e92006-03-06 20:55:46 +00003278 free(zBuf);
shane9bd1b442009-10-23 01:27:39 +00003279 return rc;
persicom7e2dfdd2002-04-18 02:46:52 +00003280}
3281
drh67505e72002-04-19 12:34:06 +00003282/*
drhe1e38c42003-05-04 18:30:59 +00003283** Show available command line options
3284*/
3285static const char zOptions[] =
shaneh5fc25012009-11-11 04:17:07 +00003286 " -help show this message\n"
drhe1e38c42003-05-04 18:30:59 +00003287 " -init filename read/process named file\n"
3288 " -echo print commands before execution\n"
3289 " -[no]header turn headers on or off\n"
drhc49f44e2006-10-26 18:15:42 +00003290 " -bail stop after hitting an error\n"
3291 " -interactive force interactive I/O\n"
3292 " -batch force batch I/O\n"
drhe1e38c42003-05-04 18:30:59 +00003293 " -column set output mode to 'column'\n"
drhc49f44e2006-10-26 18:15:42 +00003294 " -csv set output mode to 'csv'\n"
drhe1e38c42003-05-04 18:30:59 +00003295 " -html set output mode to HTML\n"
3296 " -line set output mode to 'line'\n"
3297 " -list set output mode to 'list'\n"
3298 " -separator 'x' set output field separator (|)\n"
3299 " -nullvalue 'text' set text string for NULL values\n"
3300 " -version show SQLite version\n"
drhe1e38c42003-05-04 18:30:59 +00003301;
3302static void usage(int showDetail){
drh80e8be92006-08-29 12:04:19 +00003303 fprintf(stderr,
3304 "Usage: %s [OPTIONS] FILENAME [SQL]\n"
3305 "FILENAME is the name of an SQLite database. A new database is created\n"
3306 "if the file does not previously exist.\n", Argv0);
drhe1e38c42003-05-04 18:30:59 +00003307 if( showDetail ){
drh80e8be92006-08-29 12:04:19 +00003308 fprintf(stderr, "OPTIONS include:\n%s", zOptions);
drhe1e38c42003-05-04 18:30:59 +00003309 }else{
3310 fprintf(stderr, "Use the -help option for additional information\n");
3311 }
3312 exit(1);
3313}
3314
3315/*
drh67505e72002-04-19 12:34:06 +00003316** Initialize the state information in data
3317*/
drh0850b532006-01-31 19:31:43 +00003318static void main_init(struct callback_data *data) {
persicom7e2dfdd2002-04-18 02:46:52 +00003319 memset(data, 0, sizeof(*data));
3320 data->mode = MODE_List;
drh5bb3eb92007-05-04 13:15:55 +00003321 memcpy(data->separator,"|", 2);
persicom7e2dfdd2002-04-18 02:46:52 +00003322 data->showHeader = 0;
drh5bb3eb92007-05-04 13:15:55 +00003323 sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
3324 sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
persicom7e2dfdd2002-04-18 02:46:52 +00003325}
3326
drh75897232000-05-29 14:26:00 +00003327int main(int argc, char **argv){
drh75897232000-05-29 14:26:00 +00003328 char *zErrMsg = 0;
3329 struct callback_data data;
drh22fbcb82004-02-01 01:22:50 +00003330 const char *zInitFile = 0;
3331 char *zFirstCmd = 0;
drh44c2eb12003-04-30 11:38:26 +00003332 int i;
drhc28490c2006-10-26 14:25:58 +00003333 int rc = 0;
drh75897232000-05-29 14:26:00 +00003334
drhdaffd0e2001-04-11 14:28:42 +00003335 Argv0 = argv[0];
persicom7e2dfdd2002-04-18 02:46:52 +00003336 main_init(&data);
drhc28490c2006-10-26 14:25:58 +00003337 stdin_is_interactive = isatty(0);
persicom7e2dfdd2002-04-18 02:46:52 +00003338
drh44c2eb12003-04-30 11:38:26 +00003339 /* Make sure we have a valid signal handler early, before anything
3340 ** else is done.
3341 */
drh4c504392000-10-16 22:06:40 +00003342#ifdef SIGINT
3343 signal(SIGINT, interrupt_handler);
3344#endif
drh44c2eb12003-04-30 11:38:26 +00003345
drh22fbcb82004-02-01 01:22:50 +00003346 /* Do an initial pass through the command-line argument to locate
3347 ** the name of the database file, the name of the initialization file,
3348 ** and the first command to execute.
drh44c2eb12003-04-30 11:38:26 +00003349 */
drh22fbcb82004-02-01 01:22:50 +00003350 for(i=1; i<argc-1; i++){
drhc28490c2006-10-26 14:25:58 +00003351 char *z;
drh44c2eb12003-04-30 11:38:26 +00003352 if( argv[i][0]!='-' ) break;
drhc28490c2006-10-26 14:25:58 +00003353 z = argv[i];
3354 if( z[0]=='-' && z[1]=='-' ) z++;
drh44c2eb12003-04-30 11:38:26 +00003355 if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
3356 i++;
drh22fbcb82004-02-01 01:22:50 +00003357 }else if( strcmp(argv[i],"-init")==0 ){
3358 i++;
3359 zInitFile = argv[i];
shanef69573d2009-10-24 02:06:14 +00003360 /* Need to check for batch mode here to so we can avoid printing
3361 ** informational messages (like from process_sqliterc) before
3362 ** we do the actual processing of arguments later in a second pass.
3363 */
3364 }else if( strcmp(argv[i],"-batch")==0 ){
shanef69573d2009-10-24 02:06:14 +00003365 stdin_is_interactive = 0;
drh44c2eb12003-04-30 11:38:26 +00003366 }
3367 }
drh22fbcb82004-02-01 01:22:50 +00003368 if( i<argc ){
danielk197729bafea2008-06-26 10:41:19 +00003369#if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2
pweilbacherd190be82008-04-15 18:50:02 +00003370 data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] );
3371#else
drh22fbcb82004-02-01 01:22:50 +00003372 data.zDbFilename = argv[i++];
pweilbacherd190be82008-04-15 18:50:02 +00003373#endif
drh22fbcb82004-02-01 01:22:50 +00003374 }else{
danielk197703aded42004-11-22 05:26:27 +00003375#ifndef SQLITE_OMIT_MEMORYDB
drh22fbcb82004-02-01 01:22:50 +00003376 data.zDbFilename = ":memory:";
danielk197703aded42004-11-22 05:26:27 +00003377#else
3378 data.zDbFilename = 0;
3379#endif
drh22fbcb82004-02-01 01:22:50 +00003380 }
3381 if( i<argc ){
3382 zFirstCmd = argv[i++];
3383 }
shaneh5fc25012009-11-11 04:17:07 +00003384 if( i<argc ){
3385 fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
3386 fprintf(stderr,"Use -help for a list of options.\n");
3387 return 1;
3388 }
drh44c2eb12003-04-30 11:38:26 +00003389 data.out = stdout;
3390
drh01b41712005-08-29 23:06:23 +00003391#ifdef SQLITE_OMIT_MEMORYDB
3392 if( data.zDbFilename==0 ){
shane86f5bdb2009-10-24 02:00:07 +00003393 fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
3394 return 1;
drh01b41712005-08-29 23:06:23 +00003395 }
3396#endif
3397
drh44c2eb12003-04-30 11:38:26 +00003398 /* Go ahead and open the database file if it already exists. If the
3399 ** file does not exist, delay opening it. This prevents empty database
3400 ** files from being created if a user mistypes the database name argument
3401 ** to the sqlite command-line tool.
3402 */
drhc8d74412004-08-31 23:41:26 +00003403 if( access(data.zDbFilename, 0)==0 ){
drh44c2eb12003-04-30 11:38:26 +00003404 open_db(&data);
3405 }
3406
drh22fbcb82004-02-01 01:22:50 +00003407 /* Process the initialization file if there is one. If no -init option
3408 ** is given on the command line, look for a file named ~/.sqliterc and
3409 ** try to process it.
drh44c2eb12003-04-30 11:38:26 +00003410 */
shane86f5bdb2009-10-24 02:00:07 +00003411 rc = process_sqliterc(&data,zInitFile);
3412 if( rc>0 ){
3413 return rc;
3414 }
drh44c2eb12003-04-30 11:38:26 +00003415
drh22fbcb82004-02-01 01:22:50 +00003416 /* Make a second pass through the command-line argument and set
3417 ** options. This second pass is delayed until after the initialization
3418 ** file is processed so that the command-line arguments will override
3419 ** settings in the initialization file.
drh44c2eb12003-04-30 11:38:26 +00003420 */
drh22fbcb82004-02-01 01:22:50 +00003421 for(i=1; i<argc && argv[i][0]=='-'; i++){
3422 char *z = argv[i];
drhc28490c2006-10-26 14:25:58 +00003423 if( z[1]=='-' ){ z++; }
drh2e584cd2006-09-25 13:09:22 +00003424 if( strcmp(z,"-init")==0 ){
drh22fbcb82004-02-01 01:22:50 +00003425 i++;
3426 }else if( strcmp(z,"-html")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00003427 data.mode = MODE_Html;
drh22fbcb82004-02-01 01:22:50 +00003428 }else if( strcmp(z,"-list")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00003429 data.mode = MODE_List;
drh22fbcb82004-02-01 01:22:50 +00003430 }else if( strcmp(z,"-line")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00003431 data.mode = MODE_Line;
drh22fbcb82004-02-01 01:22:50 +00003432 }else if( strcmp(z,"-column")==0 ){
drh8b32e172002-04-08 02:42:57 +00003433 data.mode = MODE_Column;
drhc49f44e2006-10-26 18:15:42 +00003434 }else if( strcmp(z,"-csv")==0 ){
3435 data.mode = MODE_Csv;
drh5bb3eb92007-05-04 13:15:55 +00003436 memcpy(data.separator,",",2);
drh22fbcb82004-02-01 01:22:50 +00003437 }else if( strcmp(z,"-separator")==0 ){
3438 i++;
shaneh5fc25012009-11-11 04:17:07 +00003439 if(i>=argc){
3440 fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);
3441 fprintf(stderr,"Use -help for a list of options.\n");
3442 return 1;
3443 }
drh5bb3eb92007-05-04 13:15:55 +00003444 sqlite3_snprintf(sizeof(data.separator), data.separator,
3445 "%.*s",(int)sizeof(data.separator)-1,argv[i]);
drh22fbcb82004-02-01 01:22:50 +00003446 }else if( strcmp(z,"-nullvalue")==0 ){
3447 i++;
shaneh5fc25012009-11-11 04:17:07 +00003448 if(i>=argc){
3449 fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);
3450 fprintf(stderr,"Use -help for a list of options.\n");
3451 return 1;
3452 }
drh5bb3eb92007-05-04 13:15:55 +00003453 sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
3454 "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
drh22fbcb82004-02-01 01:22:50 +00003455 }else if( strcmp(z,"-header")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00003456 data.showHeader = 1;
drh22fbcb82004-02-01 01:22:50 +00003457 }else if( strcmp(z,"-noheader")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00003458 data.showHeader = 0;
drh22fbcb82004-02-01 01:22:50 +00003459 }else if( strcmp(z,"-echo")==0 ){
drhdaffd0e2001-04-11 14:28:42 +00003460 data.echoOn = 1;
drhc49f44e2006-10-26 18:15:42 +00003461 }else if( strcmp(z,"-bail")==0 ){
3462 bail_on_error = 1;
drh22fbcb82004-02-01 01:22:50 +00003463 }else if( strcmp(z,"-version")==0 ){
drhc8d74412004-08-31 23:41:26 +00003464 printf("%s\n", sqlite3_libversion());
drh151e3e12006-06-06 12:32:21 +00003465 return 0;
drhc28490c2006-10-26 14:25:58 +00003466 }else if( strcmp(z,"-interactive")==0 ){
3467 stdin_is_interactive = 1;
3468 }else if( strcmp(z,"-batch")==0 ){
3469 stdin_is_interactive = 0;
drh80e8be92006-08-29 12:04:19 +00003470 }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
drhe1e38c42003-05-04 18:30:59 +00003471 usage(1);
drh1e5d0e92000-05-31 23:33:17 +00003472 }else{
shane86f5bdb2009-10-24 02:00:07 +00003473 fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
drhe1e38c42003-05-04 18:30:59 +00003474 fprintf(stderr,"Use -help for a list of options.\n");
drh1e5d0e92000-05-31 23:33:17 +00003475 return 1;
3476 }
3477 }
drh44c2eb12003-04-30 11:38:26 +00003478
drh22fbcb82004-02-01 01:22:50 +00003479 if( zFirstCmd ){
drh44c2eb12003-04-30 11:38:26 +00003480 /* Run just the command that follows the database name
3481 */
drh22fbcb82004-02-01 01:22:50 +00003482 if( zFirstCmd[0]=='.' ){
shane916f9612009-10-23 00:37:15 +00003483 rc = do_meta_command(zFirstCmd, &data);
shane86f5bdb2009-10-24 02:00:07 +00003484 return rc;
drh6ff13852001-11-25 13:18:23 +00003485 }else{
drh44c2eb12003-04-30 11:38:26 +00003486 open_db(&data);
shane626a6e42009-10-22 17:30:15 +00003487 rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
shane86f5bdb2009-10-24 02:00:07 +00003488 if( zErrMsg!=0 ){
3489 fprintf(stderr,"Error: %s\n", zErrMsg);
3490 return rc!=0 ? rc : 1;
3491 }else if( rc!=0 ){
3492 fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);
3493 return rc;
drh6ff13852001-11-25 13:18:23 +00003494 }
drh75897232000-05-29 14:26:00 +00003495 }
3496 }else{
drh44c2eb12003-04-30 11:38:26 +00003497 /* Run commands received from standard input
3498 */
drhc28490c2006-10-26 14:25:58 +00003499 if( stdin_is_interactive ){
drh67505e72002-04-19 12:34:06 +00003500 char *zHome;
3501 char *zHistory = 0;
drh5bb3eb92007-05-04 13:15:55 +00003502 int nHistory;
drh75897232000-05-29 14:26:00 +00003503 printf(
drhb217a572000-08-22 13:40:18 +00003504 "SQLite version %s\n"
mihailim65df9db2008-06-28 11:29:22 +00003505 "Enter \".help\" for instructions\n"
3506 "Enter SQL statements terminated with a \";\"\n",
drhc8d74412004-08-31 23:41:26 +00003507 sqlite3_libversion()
drh75897232000-05-29 14:26:00 +00003508 );
drh67505e72002-04-19 12:34:06 +00003509 zHome = find_home_dir();
drhea678832008-12-10 19:26:22 +00003510 if( zHome ){
drh4f21c4a2008-12-10 22:15:00 +00003511 nHistory = strlen30(zHome) + 20;
drhea678832008-12-10 19:26:22 +00003512 if( (zHistory = malloc(nHistory))!=0 ){
3513 sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
3514 }
drh67505e72002-04-19 12:34:06 +00003515 }
danielk19774af00c62005-01-23 23:43:21 +00003516#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh67505e72002-04-19 12:34:06 +00003517 if( zHistory ) read_history(zHistory);
danielk19774af00c62005-01-23 23:43:21 +00003518#endif
drhc28490c2006-10-26 14:25:58 +00003519 rc = process_input(&data, 0);
drh67505e72002-04-19 12:34:06 +00003520 if( zHistory ){
3521 stifle_history(100);
3522 write_history(zHistory);
adamd0a3daa32006-07-28 20:16:14 +00003523 free(zHistory);
drh67505e72002-04-19 12:34:06 +00003524 }
adamd0a3daa32006-07-28 20:16:14 +00003525 free(zHome);
drhdaffd0e2001-04-11 14:28:42 +00003526 }else{
drhc28490c2006-10-26 14:25:58 +00003527 rc = process_input(&data, stdin);
drh75897232000-05-29 14:26:00 +00003528 }
3529 }
drh33048c02001-10-01 14:29:22 +00003530 set_table_name(&data, 0);
adamd0a3daa32006-07-28 20:16:14 +00003531 if( db ){
3532 if( sqlite3_close(db)!=SQLITE_OK ){
shane86f5bdb2009-10-24 02:00:07 +00003533 fprintf(stderr,"Error: cannot close database \"%s\"\n", sqlite3_errmsg(db));
3534 rc++;
adamd0a3daa32006-07-28 20:16:14 +00003535 }
3536 }
drhc28490c2006-10-26 14:25:58 +00003537 return rc;
drh75897232000-05-29 14:26:00 +00003538}