/spatialite-tools-2.4.0/shell.c
C | 3445 lines | 2982 code | 118 blank | 345 comment | 804 complexity | c462441889d950c6b40ae76155ded14e MD5 | raw file
Possible License(s): GPL-3.0
Large files files are truncated, but you can click here to view the full file
- /*
- / spatialite
- /
- / a CLI backend for SpatiaLite
- /
- / version 1.0, 2008 Decmber 11
- /
- / Author: Sandro Furieri a.furieri@lqt.it
- /
- / Copyright (C) 2008 Alessandro Furieri
- /
- / This program is free software: you can redistribute it and/or modify
- / it under the terms of the GNU General Public License as published by
- / the Free Software Foundation, either version 3 of the License, or
- / (at your option) any later version.
- /
- / This program is distributed in the hope that it will be useful,
- / but WITHOUT ANY WARRANTY; without even the implied warranty of
- / MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- / GNU General Public License for more details.
- /
- / You should have received a copy of the GNU General Public License
- / along with this program. If not, see <http://www.gnu.org/licenses/>.
- /
- */
- /*
- DISCLAIMER
- ==========
-
- This file is the original SQLite command-line backend
- slightly modified by Alessandro Furieri in order to
- fully support the SpatiaLite extensions
- */
- /* Sandro Furieri 30 May 2008
- / #include "sqlite3.h"
- */
- #ifdef SPATIALITE_AMALGAMATION
- #include <spatialite/sqlite3.h>
- #else
- #include <sqlite3.h>
- #endif
- #include <spatialite.h>
- #ifdef __MINGW32__
- #define LIBICONV_STATIC
- #endif
- #include <iconv.h>
- /* end Sandro Furieri 30 May 2008 */
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <assert.h>
- #include <ctype.h>
- #include <stdarg.h>
- #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
- # include <signal.h>
- # include <pwd.h>
- # include <unistd.h>
- # include <sys/types.h>
- #endif
- #ifdef __OS2__
- # include <unistd.h>
- #endif
- #if defined(HAVE_READLINE) && HAVE_READLINE==1
- # include <readline/readline.h>
- # include <readline/history.h>
- #else
- # define readline(p) local_getline(p,stdin)
- # define add_history(X)
- # define read_history(X)
- # define write_history(X)
- # define stifle_history(X)
- #endif
- #if defined(_WIN32) || defined(WIN32)
- # include <io.h>
- #define isatty _isatty
- #define access _access
- #else
- /* Make sure isatty() has a prototype.
- */
- extern int isatty ();
- #endif
- #if defined(_WIN32_WCE)
- /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
- * thus we always assume that we have a console. That can be
- * overridden with the -batch command line option.
- */
- #define isatty(x) 1
- #endif
- #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
- #include <sys/time.h>
- #include <sys/resource.h>
- /* Saved resource information for the beginning of an operation */
- static struct rusage sBegin;
- /* True if the timer is enabled */
- static int enableTimer = 0;
- /*
- ** Begin timing an operation
- */
- static void
- beginTimer (void)
- {
- if (enableTimer)
- {
- getrusage (RUSAGE_SELF, &sBegin);
- }
- }
- /* Return the difference of two time_structs in microseconds */
- static int
- timeDiff (struct timeval *pStart, struct timeval *pEnd)
- {
- return (pEnd->tv_usec - pStart->tv_usec) +
- 1000000 * (pEnd->tv_sec - pStart->tv_sec);
- }
- /*
- ** Print the timing results.
- */
- static void
- endTimer (void)
- {
- if (enableTimer)
- {
- struct rusage sEnd;
- getrusage (RUSAGE_SELF, &sEnd);
- printf ("CPU Time: user %f sys %f\n",
- 0.000001 * timeDiff (&sBegin.ru_utime, &sEnd.ru_utime),
- 0.000001 * timeDiff (&sBegin.ru_stime, &sEnd.ru_stime));
- }
- }
- #define BEGIN_TIMER beginTimer()
- #define END_TIMER endTimer()
- #define HAS_TIMER 1
- #else
- #define BEGIN_TIMER
- #define END_TIMER
- #define HAS_TIMER 0
- #endif
- /*
- ** If the following flag is set, then command execution stops
- ** at an error if we are not interactive.
- */
- static int bail_on_error = 0;
- /*
- ** Threat stdin as an interactive input if the following variable
- ** is true. Otherwise, assume stdin is connected to a file or pipe.
- */
- static int stdin_is_interactive = 1;
- /*
- ** The following is the open SQLite database. We make a pointer
- ** to this database a static variable so that it can be accessed
- ** by the SIGINT handler to interrupt database processing.
- */
- static sqlite3 *db = 0;
- /*
- ** True if an interrupt (Control-C) has been received.
- */
- static volatile int seenInterrupt = 0;
- /*
- ** This is the name of our program. It is set in main(), used
- ** in a number of other places, mostly for error messages.
- */
- static char *Argv0;
- /*
- ** Prompt strings. Initialized in main. Settable with
- ** .prompt main continue
- */
- static char mainPrompt[20]; /* First line prompt. default: "sqlite> " */
- static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
- /*
- ** Write I/O traces to the following stream.
- */
- #ifdef SQLITE_ENABLE_IOTRACE
- static FILE *iotrace = 0;
- #endif
- /*
- ** This routine works like printf in that its first argument is a
- ** format string and subsequent arguments are values to be substituted
- ** in place of % fields. The result of formatting this string
- ** is written to iotrace.
- */
- #ifdef SQLITE_ENABLE_IOTRACE
- static void
- iotracePrintf (const char *zFormat, ...)
- {
- va_list ap;
- char *z;
- if (iotrace == 0)
- return;
- va_start (ap, zFormat);
- z = sqlite3_vmprintf (zFormat, ap);
- va_end (ap);
- fprintf (iotrace, "%s", z);
- sqlite3_free (z);
- }
- #endif
- /*
- Sandro Furieri 2008-11-20
- implementing AUTO FDO
- */
- struct auto_fdo_table
- {
- char *name;
- struct auto_fdo_table *next;
- };
- struct auto_fdo_tables
- {
- struct auto_fdo_table *first;
- struct auto_fdo_table *last;
- };
- static struct auto_fdo_tables *
- fdo_tables_alloc ()
- {
- struct auto_fdo_tables *p = malloc (sizeof (struct auto_fdo_tables));
- p->first = NULL;
- p->last = NULL;
- return p;
- }
- static void
- fdo_tables_free (struct auto_fdo_tables *p)
- {
- struct auto_fdo_table *pt;
- struct auto_fdo_table *ptn;
- if (!p)
- return;
- pt = p->first;
- while (pt)
- {
- ptn = pt->next;
- free (pt->name);
- free (pt);
- pt = ptn;
- }
- free (p);
- }
- static void
- add_to_fdo_tables (struct auto_fdo_tables *pt, const char *name, int len)
- {
- struct auto_fdo_table *p = malloc (sizeof (struct auto_fdo_table));
- p->name = malloc (len + 1);
- strcpy (p->name, name);
- p->next = NULL;
- if (!(pt->first))
- pt->first = p;
- if (pt->last)
- pt->last->next = p;
- pt->last = p;
- }
- static void
- auto_fdo_start (sqlite3 * db)
- {
- /* trying to start the FDO-OGR auto-wrapper */
- int ret;
- const char *name;
- int i;
- char **results;
- int rows;
- int columns;
- char sql[1024];
- int count = 0;
- int len;
- int spatial_type = 0;
- struct auto_fdo_tables *tables;
- struct auto_fdo_table *p;
- if (!db)
- return;
- strcpy (sql, "SELECT CheckSpatialMetadata()");
- ret = sqlite3_get_table (db, sql, &results, &rows, &columns, NULL);
- if (ret != SQLITE_OK)
- goto error1;
- if (rows < 1)
- ;
- else
- {
- for (i = 1; i <= rows; i++)
- spatial_type = atoi (results[(i * columns) + 0]);
- }
- sqlite3_free_table (results);
- error1:
- if (spatial_type == 2)
- {
- /* ok, creating VirtualFDO tables */
- tables = fdo_tables_alloc ();
- strcpy (sql, "SELECT DISTINCT f_table_name FROM geometry_columns");
- ret = sqlite3_get_table (db, sql, &results, &rows, &columns, NULL);
- if (ret != SQLITE_OK)
- goto error;
- if (rows < 1)
- ;
- else
- {
- for (i = 1; i <= rows; i++)
- {
- name = results[(i * columns) + 0];
- if (name)
- {
- len = strlen (name);
- add_to_fdo_tables (tables, name, len);
- }
- }
- }
- sqlite3_free_table (results);
- p = tables->first;
- if (p)
- printf
- ("\n================ FDO-OGR Spatial Metadata detected ===============\n");
- while (p)
- {
- /* destroying the VirtualFDO table [if existing] */
- sprintf (sql, "DROP TABLE IF EXISTS fdo_%s", p->name);
- ret = sqlite3_exec (db, sql, NULL, 0, NULL);
- if (ret != SQLITE_OK)
- goto error;
- /* creating the VirtualFDO table */
- sprintf (sql,
- "CREATE VIRTUAL TABLE fdo_%s USING VirtualFDO(%s)",
- p->name, p->name);
- ret = sqlite3_exec (db, sql, NULL, 0, NULL);
- if (ret != SQLITE_OK)
- goto error;
- printf ("\tcreated VirtualFDO table 'fdo_%s'\n", p->name);
- count++;
- p = p->next;
- }
- error:
- if (count++)
- {
- printf
- ("Accessing these fdo_XX tables you can take full advantage of\n");
- printf ("FDO-OGR auto-wrapping facility\n");
- printf
- ("This allows you to access any specific FDO-OGR Geometry as if it\n");
- printf
- ("where native SpatiaLite ones in a completely transparent way\n");
- printf
- ("==================================================================\n\n");
- fdo_tables_free (tables);
- }
- return;
- }
- }
- static void
- auto_fdo_stop (sqlite3 * db)
- {
- /* trying to stop the FDO-OGR auto-wrapper */
- int ret;
- const char *name;
- int i;
- char **results;
- int rows;
- int columns;
- char sql[1024];
- int count = 0;
- int len;
- int spatial_type = 0;
- struct auto_fdo_tables *tables;
- struct auto_fdo_table *p;
- if (!db)
- return;
- strcpy (sql, "SELECT CheckSpatialMetadata()");
- ret = sqlite3_get_table (db, sql, &results, &rows, &columns, NULL);
- if (ret != SQLITE_OK)
- goto error1;
- if (rows < 1)
- ;
- else
- {
- for (i = 1; i <= rows; i++)
- spatial_type = atoi (results[(i * columns) + 0]);
- }
- sqlite3_free_table (results);
- error1:
- if (spatial_type == 2)
- {
- /* ok, destroying VirtualFDO tables */
- tables = fdo_tables_alloc ();
- strcpy (sql, "SELECT DISTINCT f_table_name FROM geometry_columns");
- ret = sqlite3_get_table (db, sql, &results, &rows, &columns, NULL);
- if (ret != SQLITE_OK)
- goto error;
- if (rows < 1)
- ;
- else
- {
- for (i = 1; i <= rows; i++)
- {
- name = results[(i * columns) + 0];
- if (name)
- {
- len = strlen (name);
- add_to_fdo_tables (tables, name, len);
- }
- }
- }
- sqlite3_free_table (results);
- p = tables->first;
- while (p)
- {
- /* destroying the VirtualFDO table [if existing] */
- sprintf (sql, "DROP TABLE IF EXISTS fdo_%s", p->name);
- ret = sqlite3_exec (db, sql, NULL, 0, NULL);
- if (ret != SQLITE_OK)
- goto error;
- count++;
- p = p->next;
- }
- error:
- if (count++)
- printf ("\n*** FDO-OGR auto-wrapping shutdown done ***\n");
- fdo_tables_free (tables);
- return;
- }
- }
- /* end Sandro Furieri 11 July 2008 */
- /*
- Sandro Furieri 11 July 2008
- implementing full UNICODE support
- */
- static iconv_t locale_to_utf8 = NULL;
- static iconv_t utf8_to_locale = NULL;
- static iconv_t in_charset_to_utf8 = NULL;
- static char spatialite_charset[1024] = "";
- static void
- create_utf8_converter (char *charset)
- {
- /* creating the UTF8 structs */
- *spatialite_charset = '\0';
- if (locale_to_utf8)
- {
- /* destroying old converter, if exists */
- iconv_close (locale_to_utf8);
- locale_to_utf8 = NULL;
- }
- if (utf8_to_locale)
- {
- /* destroying old converter, if exists */
- iconv_close (utf8_to_locale);
- utf8_to_locale = NULL;
- }
- /* creating new converters */
- locale_to_utf8 = iconv_open ("UTF-8", charset);
- if (locale_to_utf8 == (iconv_t) (-1))
- {
- locale_to_utf8 = NULL;
- fprintf (stderr,
- "*** charset ERROR *** cannot convert from '%s' to 'UTF-8'\n",
- charset);
- fflush (stderr);
- return;
- }
- utf8_to_locale = iconv_open (charset, "UTF-8");
- if (utf8_to_locale == (iconv_t) (-1))
- {
- utf8_to_locale = NULL;
- fprintf (stderr,
- "*** charset ERROR *** cannot convert from 'UTF-8' to '%s'\n",
- charset);
- fflush (stderr);
- return;
- }
- strncpy (spatialite_charset, charset, sizeof (spatialite_charset) - 1);
- spatialite_charset[sizeof (spatialite_charset) - 1] = '\0';
- }
- static void
- create_input_utf8_converter (char *charset)
- {
- /* creating the UTF8 structs */
- if (in_charset_to_utf8)
- {
- /* destroying old converter, if exists */
- iconv_close (in_charset_to_utf8);
- in_charset_to_utf8 = NULL;
- }
- /* creating new converter */
- in_charset_to_utf8 = iconv_open ("UTF-8", charset);
- if (in_charset_to_utf8 == (iconv_t) (-1))
- {
- in_charset_to_utf8 = NULL;
- fprintf (stderr,
- "*** charset ERROR *** cannot convert from '%s' to 'UTF-8'\n",
- charset);
- fflush (stderr);
- return;
- }
- }
- static void
- convert_from_utf8 (char *buf, int maxlen)
- {
- /* converting from UTF8 to locale charset */
- char *utf8buf = 0;
- #ifdef __MINGW32__
- const char *pBuf;
- #else
- char *pBuf;
- #endif
- size_t len;
- size_t utf8len;
- char *pUtf8buf;
- if (!utf8_to_locale)
- return;
- utf8buf = malloc (maxlen);
- if (utf8buf == 0)
- {
- fprintf (stderr, "out of memory!\n");
- exit (1);
- }
- len = strlen (buf);
- utf8len = maxlen;
- pBuf = buf;
- pUtf8buf = utf8buf;
- if (iconv (utf8_to_locale, &pBuf, &len, &pUtf8buf, &utf8len) ==
- (size_t) (-1))
- {
- fprintf (stderr, "\n*** ILLEGAL CHARACTER SEQUENCE ***\n\n");
- fflush (stderr);
- free (utf8buf);
- return;
- }
- utf8buf[maxlen - utf8len] = '\0';
- memcpy (buf, utf8buf, (maxlen - utf8len) + 1);
- free (utf8buf);
- }
- static void
- convert_to_utf8 (char *buf, int maxlen)
- {
- /* converting from locale charset to UTF8 */
- char *utf8buf = 0;
- #ifdef __MINGW32__
- const char *pBuf;
- #else
- char *pBuf;
- #endif
- size_t len;
- size_t utf8len;
- char *pUtf8buf;
- if (!locale_to_utf8)
- return;
- utf8buf = malloc (maxlen);
- if (utf8buf == 0)
- {
- fprintf (stderr, "out of memory!\n");
- exit (1);
- }
- len = strlen (buf);
- utf8len = maxlen;
- pBuf = buf;
- pUtf8buf = utf8buf;
- if (iconv (locale_to_utf8, &pBuf, &len, &pUtf8buf, &utf8len) ==
- (size_t) (-1))
- {
- fprintf (stderr, "\n*** ILLEGAL CHARACTER SEQUENCE ***\n\n");
- fflush (stderr);
- free (utf8buf);
- return;
- }
- utf8buf[maxlen - utf8len] = '\0';
- memcpy (buf, utf8buf, (maxlen - utf8len) + 1);
- free (utf8buf);
- }
- static void
- convert_input_to_utf8 (char *buf, int maxlen)
- {
- /* converting from required charset to UTF8 */
- char *utf8buf = 0;
- #ifdef __MINGW32__
- const char *pBuf;
- #else
- char *pBuf;
- #endif
- size_t len;
- size_t utf8len;
- char *pUtf8buf;
- if (!in_charset_to_utf8)
- return;
- utf8buf = malloc (maxlen);
- if (utf8buf == 0)
- {
- fprintf (stderr, "out of memory!\n");
- exit (1);
- }
- len = strlen (buf);
- utf8len = maxlen;
- pBuf = buf;
- pUtf8buf = utf8buf;
- if (iconv (in_charset_to_utf8, &pBuf, &len, &pUtf8buf, &utf8len) ==
- (size_t) (-1))
- {
- fprintf (stderr, "\n*** ILLEGAL CHARACTER SEQUENCE ***\n\n");
- fflush (stderr);
- free (utf8buf);
- return;
- }
- utf8buf[maxlen - utf8len] = '\0';
- memcpy (buf, utf8buf, (maxlen - utf8len) + 1);
- free (utf8buf);
- }
- /* end Sandro Furieri 11 July 2008 */
- /*
- ** Determines if a string is a number of not.
- */
- static int
- isNumber (const char *z, int *realnum)
- {
- if (*z == '-' || *z == '+')
- z++;
- if (!isdigit (*z))
- {
- return 0;
- }
- z++;
- if (realnum)
- *realnum = 0;
- while (isdigit (*z))
- {
- z++;
- }
- if (*z == '.')
- {
- z++;
- if (!isdigit (*z))
- return 0;
- while (isdigit (*z))
- {
- z++;
- }
- if (realnum)
- *realnum = 1;
- }
- if (*z == 'e' || *z == 'E')
- {
- z++;
- if (*z == '+' || *z == '-')
- z++;
- if (!isdigit (*z))
- return 0;
- while (isdigit (*z))
- {
- z++;
- }
- if (realnum)
- *realnum = 1;
- }
- return *z == 0;
- }
- /*
- ** A global char* and an SQL function to access its current value
- ** from within an SQL statement. This program used to use the
- ** sqlite_exec_printf() API to substitue a string into an SQL statement.
- ** The correct way to do this with sqlite3 is to use the bind API, but
- ** since the shell is built around the callback paradigm it would be a lot
- ** of work. Instead just use this hack, which is quite harmless.
- */
- static const char *zShellStatic = 0;
- static void
- shellstaticFunc (sqlite3_context * context, int argc, sqlite3_value ** argv)
- {
- assert (0 == argc);
- assert (zShellStatic);
- sqlite3_result_text (context, zShellStatic, -1, SQLITE_STATIC);
- }
- /*
- ** This routine reads a line of text from FILE in, stores
- ** the text in memory obtained from malloc() and returns a pointer
- ** to the text. NULL is returned at end of file, or if malloc()
- ** fails.
- **
- ** The interface is like "readline" but no command-line editing
- ** is done.
- */
- static char *
- local_getline (char *zPrompt, FILE * in)
- {
- char *zLine;
- int nLine;
- int n;
- int eol;
- if (zPrompt && *zPrompt)
- {
- printf ("%s", zPrompt);
- fflush (stdout);
- }
- nLine = 100;
- zLine = malloc (nLine);
- if (zLine == 0)
- return 0;
- n = 0;
- eol = 0;
- while (!eol)
- {
- if (n + 100 > nLine)
- {
- nLine = nLine * 2 + 100;
- zLine = realloc (zLine, nLine);
- if (zLine == 0)
- return 0;
- }
- if (fgets (&zLine[n], nLine - n, in) == 0)
- {
- if (n == 0)
- {
- free (zLine);
- return 0;
- }
- zLine[n] = 0;
- eol = 1;
- break;
- }
- while (zLine[n])
- {
- n++;
- }
- if (n > 0 && zLine[n - 1] == '\n')
- {
- n--;
- zLine[n] = 0;
- eol = 1;
- }
- }
- zLine = realloc (zLine, n + 1);
- return zLine;
- }
- /*
- ** Retrieve a single line of input text.
- **
- ** zPrior is a string of prior text retrieved. If not the empty
- ** string, then issue a continuation prompt.
- */
- static char *
- one_input_line (const char *zPrior, FILE * in)
- {
- char *zPrompt;
- char *zResult;
- if (in != 0)
- {
- return local_getline (0, in);
- }
- if (zPrior && zPrior[0])
- {
- zPrompt = continuePrompt;
- }
- else
- {
- zPrompt = mainPrompt;
- }
- zResult = readline (zPrompt);
- #if defined(HAVE_READLINE) && HAVE_READLINE==1
- if (zResult && *zResult)
- add_history (zResult);
- #endif
- return zResult;
- }
- struct previous_mode_data
- {
- int valid; /* Is there legit data in here? */
- int mode;
- int showHeader;
- int colWidth[100];
- };
- /*
- ** An pointer to an instance of this structure is passed from
- ** the main program to the callback. This is used to communicate
- ** state and mode information.
- */
- struct callback_data
- {
- sqlite3 *db; /* The database */
- int echoOn; /* True to echo input commands */
- int cnt; /* Number of records displayed so far */
- FILE *out; /* Write results here */
- int mode; /* An output mode setting */
- int writableSchema; /* True if PRAGMA writable_schema=ON */
- int showHeader; /* True to show column names in List or Column mode */
- char *zDestTable; /* Name of destination table when MODE_Insert */
- char separator[20]; /* Separator character for MODE_List */
- int colWidth[100]; /* Requested width of each column when in column mode */
- int actualWidth[100]; /* Actual width of each column */
- char nullvalue[20]; /* The text to print when a NULL comes back from
- ** the database */
- struct previous_mode_data explainPrev;
- /* Holds the mode information just before
- ** .explain ON */
- char outfile[FILENAME_MAX]; /* Filename for *out */
- const char *zDbFilename; /* name of the database file */
- };
- /*
- ** These are the allowed modes.
- */
- #define MODE_Line 0 /* One column per line. Blank line between records */
- #define MODE_Column 1 /* One record per line in neat columns */
- #define MODE_List 2 /* One record per line with a separator */
- #define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
- #define MODE_Html 4 /* Generate an XHTML table */
- #define MODE_Insert 5 /* Generate SQL "insert" statements */
- #define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
- #define MODE_Csv 7 /* Quote strings, numbers are plain */
- #define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
- static const char *modeDescr[] = {
- "line",
- "column",
- "list",
- "semi",
- "html",
- "insert",
- "tcl",
- "csv",
- "explain",
- };
- /*
- ** Number of elements in an array
- */
- #define ArraySize(X) (sizeof(X)/sizeof(X[0]))
- /*
- ** Output the given string as a quoted string using SQL quoting conventions.
- */
- static void
- output_quoted_string (FILE * out, const char *z)
- {
- int i;
- int nSingle = 0;
- for (i = 0; z[i]; i++)
- {
- if (z[i] == '\'')
- nSingle++;
- }
- if (nSingle == 0)
- {
- fprintf (out, "'%s'", z);
- }
- else
- {
- fprintf (out, "'");
- while (*z)
- {
- for (i = 0; z[i] && z[i] != '\''; i++)
- {
- }
- if (i == 0)
- {
- fprintf (out, "''");
- z++;
- }
- else if (z[i] == '\'')
- {
- fprintf (out, "%.*s''", i, z);
- z += i + 1;
- }
- else
- {
- fprintf (out, "%s", z);
- break;
- }
- }
- fprintf (out, "'");
- }
- }
- /*
- ** Output the given string as a quoted according to C or TCL quoting rules.
- */
- static void
- output_c_string (FILE * out, const char *z)
- {
- unsigned int c;
- fputc ('"', out);
- while ((c = *(z++)) != 0)
- {
- if (c == '\\')
- {
- fputc (c, out);
- fputc (c, out);
- }
- else if (c == '\t')
- {
- fputc ('\\', out);
- fputc ('t', out);
- }
- else if (c == '\n')
- {
- fputc ('\\', out);
- fputc ('n', out);
- }
- else if (c == '\r')
- {
- fputc ('\\', out);
- fputc ('r', out);
- }
- else if (!isprint (c))
- {
- fprintf (out, "\\%03o", c & 0xff);
- }
- else
- {
- fputc (c, out);
- }
- }
- fputc ('"', out);
- }
- /*
- ** Output the given string with characters that are special to
- ** HTML escaped.
- */
- static void
- output_html_string (FILE * out, const char *z)
- {
- int i;
- while (*z)
- {
- for (i = 0; z[i] && z[i] != '<' && z[i] != '&'; i++)
- {
- }
- if (i > 0)
- {
- fprintf (out, "%.*s", i, z);
- }
- if (z[i] == '<')
- {
- fprintf (out, "<");
- }
- else if (z[i] == '&')
- {
- fprintf (out, "&");
- }
- else
- {
- break;
- }
- z += i + 1;
- }
- }
- /*
- ** If a field contains any character identified by a 1 in the following
- ** array, then the string must be quoted for CSV.
- */
- static const char needCsvQuote[] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- };
- /*
- ** Output a single term of CSV. Actually, p->separator is used for
- ** the separator, which may or may not be a comma. p->nullvalue is
- ** the null value. Strings are quoted using ANSI-C rules. Numbers
- ** appear outside of quotes.
- */
- static void
- output_csv (struct callback_data *p, const char *z, int bSep)
- {
- FILE *out = p->out;
- if (z == 0)
- {
- fprintf (out, "%s", p->nullvalue);
- }
- else
- {
- int i;
- int nSep = strlen (p->separator);
- for (i = 0; z[i]; i++)
- {
- if (needCsvQuote[((unsigned char *) z)[i]]
- || (z[i] == p->separator[0] &&
- (nSep == 1 || memcmp (z, p->separator, nSep) == 0)))
- {
- i = 0;
- break;
- }
- }
- if (i == 0)
- {
- putc ('"', out);
- for (i = 0; z[i]; i++)
- {
- if (z[i] == '"')
- putc ('"', out);
- putc (z[i], out);
- }
- putc ('"', out);
- }
- else
- {
- fprintf (out, "%s", z);
- }
- }
- if (bSep)
- {
- fprintf (p->out, "%s", p->separator);
- }
- }
- #ifdef SIGINT
- /*
- ** This routine runs when the user presses Ctrl-C
- */
- static void
- interrupt_handler (int NotUsed)
- {
- seenInterrupt = 1;
- if (db)
- sqlite3_interrupt (db);
- }
- #endif
- /*
- ** This is the callback routine that the SQLite library
- ** invokes for each row of a query result.
- */
- static int
- callback (void *pArg, int nArg, char **azArg, char **azCol)
- {
- int i;
- /* Sandro Furieri 11 July 2008 - supporting full UNICODE */
- char *buf = NULL;
- int len;
- /* end Sandro Furieri 11 July 2008 */
- struct callback_data *p = (struct callback_data *) pArg;
- switch (p->mode)
- {
- case MODE_Line:
- {
- int w = 5;
- if (azArg == 0)
- break;
- for (i = 0; i < nArg; i++)
- {
- int len = strlen (azCol[i] ? azCol[i] : "");
- if (len > w)
- w = len;
- }
- if (p->cnt++ > 0)
- fprintf (p->out, "\n");
- for (i = 0; i < nArg; i++)
- {
- /* Sandro Furieri 11 July 2008
- fprintf (p->out, "%*s = %s\n", w, azCol[i],
- azArg[i] ? azArg[i] : p->nullvalue);
- */
- if (azArg[i] == 0)
- fprintf (p->out, "%*s = %s\n", w, azCol[i],
- p->nullvalue);
- else
- {
- len = strlen (azArg[i]) + 1;
- if (buf)
- free (buf);
- buf = malloc (len * 4);
- strcpy (buf, azArg[i]);
- convert_from_utf8 (buf, len * 4);
- fprintf (p->out, "%*s = %s\n", w, azCol[i],
- azArg[i] ? buf : p->nullvalue);
- }
- /* end Sandro Furieri 11 July 2008 */
- }
- break;
- }
- case MODE_Explain:
- case MODE_Column:
- {
- if (p->cnt++ == 0)
- {
- for (i = 0; i < nArg; i++)
- {
- int w, n;
- if (i < ArraySize (p->colWidth))
- {
- w = p->colWidth[i];
- }
- else
- {
- w = 0;
- }
- if (w <= 0)
- {
- w = strlen (azCol[i] ? azCol[i] : "");
- if (w < 10)
- w = 10;
- n = strlen (azArg
- && azArg[i] ? azArg[i] :
- p->nullvalue);
- if (w < n)
- w = n;
- }
- if (i < ArraySize (p->actualWidth))
- {
- p->actualWidth[i] = w;
- }
- if (p->showHeader)
- {
- fprintf (p->out, "%-*.*s%s", w, w, azCol[i],
- i == nArg - 1 ? "\n" : " ");
- }
- }
- if (p->showHeader)
- {
- for (i = 0; i < nArg; i++)
- {
- int w;
- if (i < ArraySize (p->actualWidth))
- {
- w = p->actualWidth[i];
- }
- else
- {
- w = 10;
- }
- fprintf (p->out, "%-*.*s%s", w, w,
- "-----------------------------------"
- "----------------------------------------------------------",
- i == nArg - 1 ? "\n" : " ");
- }
- }
- }
- if (azArg == 0)
- break;
- for (i = 0; i < nArg; i++)
- {
- int w;
- if (i < ArraySize (p->actualWidth))
- {
- w = p->actualWidth[i];
- }
- else
- {
- w = 10;
- }
- if (p->mode == MODE_Explain && azArg[i]
- && (int) strlen (azArg[i]) > w)
- {
- w = strlen (azArg[i]);
- }
- /* Sandro Furieri 11 July 2008
- fprintf (p->out, "%-*.*s%s", w, w,
- azArg[i] ? azArg[i] : p->nullvalue,
- i == nArg - 1 ? "\n" : " ");
- */
- if (azArg[i] == 0)
- fprintf (p->out, "%-*.*s%s", w, w, p->nullvalue,
- i == nArg - 1 ? "\n" : " ");
- else
- {
- len = strlen (azArg[i]) + 1;
- if (buf)
- free (buf);
- buf = malloc (len * 4);
- strcpy (buf, azArg[i]);
- convert_from_utf8 (buf, len * 4);
- fprintf (p->out, "%-*.*s%s", w, w,
- azArg[i] ? buf : p->nullvalue,
- i == nArg - 1 ? "\n" : " ");
- }
- /* end Sandro Furieri 11 July 2008 */
- }
- break;
- }
- case MODE_Semi:
- case MODE_List:
- {
- if (p->cnt++ == 0 && p->showHeader)
- {
- for (i = 0; i < nArg; i++)
- {
- fprintf (p->out, "%s%s", azCol[i],
- i == nArg - 1 ? "\n" : p->separator);
- }
- }
- if (azArg == 0)
- break;
- for (i = 0; i < nArg; i++)
- {
- /* Sandro Furieri 11 July 2008
- char *z = azArg[i];
- if (z == 0)
- z = p->nullvalue;
- */
- char *z;
- if (azArg[i] == 0)
- z = p->nullvalue;
- else
- {
- len = strlen (azArg[i]) + 1;
- if (buf)
- free (buf);
- buf = malloc (len * 4);
- z = buf;
- strcpy (buf, azArg[i]);
- convert_from_utf8 (buf, len * 4);
- }
- /* end Sandro Furieri 11 July 2008 */
- fprintf (p->out, "%s", z);
- if (i < nArg - 1)
- {
- fprintf (p->out, "%s", p->separator);
- }
- else if (p->mode == MODE_Semi)
- {
- fprintf (p->out, ";\n");
- }
- else
- {
- fprintf (p->out, "\n");
- }
- }
- break;
- }
- case MODE_Html:
- {
- if (p->cnt++ == 0 && p->showHeader)
- {
- fprintf (p->out, "<TR>");
- for (i = 0; i < nArg; i++)
- {
- fprintf (p->out, "<TH>%s</TH>", azCol[i]);
- }
- fprintf (p->out, "</TR>\n");
- }
- if (azArg == 0)
- break;
- fprintf (p->out, "<TR>");
- for (i = 0; i < nArg; i++)
- {
- fprintf (p->out, "<TD>");
- /* Sandro Furieri 11 July 2008
- output_html_string (p->out,
- azArg[i] ? azArg[i] : p->nullvalue);
- */
- if (azArg[i] == 0)
- output_html_string (p->out, p->nullvalue);
- else
- {
- len = strlen (azArg[i]) + 1;
- if (buf)
- free (buf);
- buf = malloc (len * 4);
- strcpy (buf, azArg[i]);
- convert_from_utf8 (buf, len * 4);
- output_html_string (p->out,
- azArg[i] ? buf : p->nullvalue);
- }
- /* end Sandro Furieri 11 July 2008 */
- fprintf (p->out, "</TD>\n");
- }
- fprintf (p->out, "</TR>\n");
- break;
- }
- case MODE_Tcl:
- {
- if (p->cnt++ == 0 && p->showHeader)
- {
- for (i = 0; i < nArg; i++)
- {
- output_c_string (p->out, azCol[i] ? azCol[i] : "");
- fprintf (p->out, "%s", p->separator);
- }
- fprintf (p->out, "\n");
- }
- if (azArg == 0)
- break;
- for (i = 0; i < nArg; i++)
- {
- /* Sandro Furieri 11 July 2008
- output_c_string (p->out,
- azArg[i] ? azArg[i] : p->nullvalue);
- */
- if (azArg[i] == 0)
- output_c_string (p->out, p->nullvalue);
- else
- {
- len = strlen (azArg[i]) + 1;
- if (buf)
- free (buf);
- buf = malloc (len * 4);
- strcpy (buf, azArg[i]);
- convert_from_utf8 (buf, len * 4);
- output_c_string (p->out,
- azArg[i] ? buf : p->nullvalue);
- }
- /* end Sandro Furieri 11 July 2008 */
- fprintf (p->out, "%s", p->separator);
- }
- fprintf (p->out, "\n");
- break;
- }
- case MODE_Csv:
- {
- if (p->cnt++ == 0 && p->showHeader)
- {
- for (i = 0; i < nArg; i++)
- {
- output_csv (p, azCol[i] ? azCol[i] : "",
- i < nArg - 1);
- }
- fprintf (p->out, "\n");
- }
- if (azArg == 0)
- break;
- for (i = 0; i < nArg; i++)
- {
- /* Sandro Furieri 11 July 2008
- output_csv (p, azArg[i], i < nArg - 1);
- */
- if (azArg[i] == 0)
- output_csv (p, azArg[i], i < nArg - 1);
- else
- {
- len = strlen (azArg[i]) + 1;
- if (buf)
- free (buf);
- buf = malloc (len * 4);
- strcpy (buf, azArg[i]);
- convert_from_utf8 (buf, len * 4);
- output_csv (p, buf, i < nArg - 1);
- }
- /* end Sandro Furieri 11 July 2008 */
- }
- fprintf (p->out, "\n");
- break;
- }
- case MODE_Insert:
- {
- if (azArg == 0)
- break;
- fprintf (p->out, "INSERT INTO %s VALUES(", p->zDestTable);
- for (i = 0; i < nArg; i++)
- {
- char *zSep = i > 0 ? "," : "";
- if (azArg[i] == 0)
- {
- fprintf (p->out, "%sNULL", zSep);
- }
- else if (isNumber (azArg[i], 0))
- {
- fprintf (p->out, "%s%s", zSep, azArg[i]);
- }
- else
- {
- if (zSep[0])
- fprintf (p->out, "%s", zSep);
- /* Sandro Furieri 11 July 2008
- output_quoted_string (p->out, azArg[i]);
- */
- if (azArg[i] == 0)
- output_quoted_string (p->out, azArg[i]);
- else
- {
- len = strlen (azArg[i]) + 1;
- if (buf)
- free (buf);
- buf = malloc (len * 4);
- strcpy (buf, azArg[i]);
- convert_from_utf8 (buf, len * 4);
- output_quoted_string (p->out, buf);
- }
- /* end Sandro Furieri 11 July 2008 */
- }
- }
- fprintf (p->out, ");\n");
- break;
- }
- }
- if (buf)
- free (buf);
- return 0;
- }
- /*
- ** Set the destination table field of the callback_data structure to
- ** the name of the table given. Escape any quote characters in the
- ** table name.
- */
- static void
- set_table_name (struct callback_data *p, const char *zName)
- {
- int i, n;
- int needQuote;
- char *z;
- if (p->zDestTable)
- {
- free (p->zDestTable);
- p->zDestTable = 0;
- }
- if (zName == 0)
- return;
- needQuote = !isalpha ((unsigned char) *zName) && *zName != '_';
- for (i = n = 0; zName[i]; i++, n++)
- {
- if (!isalnum ((unsigned char) zName[i]) && zName[i] != '_')
- {
- needQuote = 1;
- if (zName[i] == '\'')
- n++;
- }
- }
- if (needQuote)
- n += 2;
- z = p->zDestTable = malloc (n + 1);
- if (z == 0)
- {
- fprintf (stderr, "Out of memory!\n");
- exit (1);
- }
- n = 0;
- if (needQuote)
- z[n++] = '\'';
- for (i = 0; zName[i]; i++)
- {
- z[n++] = zName[i];
- if (zName[i] == '\'')
- z[n++] = '\'';
- }
- if (needQuote)
- z[n++] = '\'';
- z[n] = 0;
- }
- /* zIn is either a pointer to a NULL-terminated string in memory obtained
- ** from malloc(), or a NULL pointer. The string pointed to by zAppend is
- ** added to zIn, and the result returned in memory obtained from malloc().
- ** zIn, if it was not NULL, is freed.
- **
- ** If the third argument, quote, is not '\0', then it is used as a
- ** quote character for zAppend.
- */
- static char *
- appendText (char *zIn, char const *zAppend, char quote)
- {
- int len;
- int i;
- int nAppend = strlen (zAppend);
- int nIn = (zIn ? strlen (zIn) : 0);
- len = nAppend + nIn + 1;
- if (quote)
- {
- len += 2;
- for (i = 0; i < nAppend; i++)
- {
- if (zAppend[i] == quote)
- len++;
- }
- }
- zIn = (char *) realloc (zIn, len);
- if (!zIn)
- {
- return 0;
- }
- if (quote)
- {
- char *zCsr = &zIn[nIn];
- *zCsr++ = quote;
- for (i = 0; i < nAppend; i++)
- {
- *zCsr++ = zAppend[i];
- if (zAppend[i] == quote)
- *zCsr++ = quote;
- }
- *zCsr++ = quote;
- *zCsr++ = '\0';
- assert ((zCsr - zIn) == len);
- }
- else
- {
- memcpy (&zIn[nIn], zAppend, nAppend);
- zIn[len - 1] = '\0';
- }
- return zIn;
- }
- /*
- ** Execute a query statement that has a single result column. Print
- ** that result column on a line by itself with a semicolon terminator.
- **
- ** This is used, for example, to show the schema of the database by
- ** querying the SQLITE_MASTER table.
- */
- static int
- run_table_dump_query (FILE * out, sqlite3 * db, const char *zSelect)
- {
- sqlite3_stmt *pSelect;
- int rc;
- rc = sqlite3_prepare (db, zSelect, -1, &pSelect, 0);
- if (rc != SQLITE_OK || !pSelect)
- {
- return rc;
- }
- rc = sqlite3_step (pSelect);
- while (rc == SQLITE_ROW)
- {
- fprintf (out, "%s;\n", sqlite3_column_text (pSelect, 0));
- rc = sqlite3_step (pSelect);
- }
- return sqlite3_finalize (pSelect);
- }
- /*
- ** This is a different callback routine used for dumping the database.
- ** Each row received by this callback consists of a table name,
- ** the table type ("index" or "table") and SQL to create the table.
- ** This routine should print text sufficient to recreate the table.
- */
- static int
- dump_callback (void *pArg, int nArg, char **azArg, char **azCol)
- {
- int rc;
- const char *zTable;
- const char *zType;
- const char *zSql;
- struct callback_data *p = (struct callback_data *) pArg;
- if (nArg != 3)
- return 1;
- zTable = azArg[0];
- zType = azArg[1];
- zSql = azArg[2];
- if (strcmp (zTable, "sqlite_sequence") == 0)
- {
- fprintf (p->out, "DELETE FROM sqlite_sequence;\n");
- }
- else if (strcmp (zTable, "sqlite_stat1") == 0)
- {
- fprintf (p->out, "ANALYZE sqlite_master;\n");
- }
- else if (strncmp (zTable, "sqlite_", 7) == 0)
- {
- return 0;
- }
- else if (strncmp (zSql, "CREATE VIRTUAL TABLE", 20) == 0)
- {
- char *zIns;
- if (!p->writableSchema)
- {
- fprintf (p->out, "PRAGMA writable_schema=ON;\n");
- p->writableSchema = 1;
- }
- zIns =
- sqlite3_mprintf
- ("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
- "VALUES('table','%q','%q',0,'%q');", zTable, zTable, zSql);
- fprintf (p->out, "%s\n", zIns);
- sqlite3_free (zIns);
- return 0;
- }
- else
- {
- fprintf (p->out, "%s;\n", zSql);
- }
- if (strcmp (zType, "table") == 0)
- {
- sqlite3_stmt *pTableInfo = 0;
- char *zSelect = 0;
- char *zTableInfo = 0;
- char *zTmp = 0;
- zTableInfo = appendText (zTableInfo, "PRAGMA table_info(", 0);
- zTableInfo = appendText (zTableInfo, zTable, '"');
- zTableInfo = appendText (zTableInfo, ");", 0);
- rc = sqlite3_prepare (p->db, zTableInfo, -1, &pTableInfo, 0);
- if (zTableInfo)
- free (zTableInfo);
- if (rc != SQLITE_OK || !pTableInfo)
- {
- return 1;
- }
- zSelect = appendText (zSelect, "SELECT 'INSERT INTO ' || ", 0);
- zTmp = appendText (zTmp, zTable, '"');
- if (zTmp)
- {
- zSelect = appendText (zSelect, zTmp, '\'');
- free (zTmp);
- }
- zSelect = appendText (zSelect, " || ' VALUES(' || ", 0);
- rc = sqlite3_step (pTableInfo);
- while (rc == SQLITE_ROW)
- {
- const char *zText =
- (const char *) sqlite3_column_text (pTableInfo, 1);
- zSelect = appendText (zSelect, "quote(", 0);
- zSelect = appendText (zSelect, zText, '"');
- rc = sqlite3_step (pTableInfo);
- if (rc == SQLITE_ROW)
- {
- zSelect = appendText (zSelect, ") || ',' || ", 0);
- }
- else
- {
- zSelect = appendText (zSelect, ") ", 0);
- }
- }
- rc = sqlite3_finalize (pTableInfo);
- if (rc != SQLITE_OK)
- {
- if (zSelect)
- free (zSelect);
- return 1;
- }
- zSelect = appendText (zSelect, "|| ')' FROM ", 0);
- zSelect = appendText (zSelect, zTable, '"');
- rc = run_table_dump_query (p->out, p->db, zSelect);
- if (rc == SQLITE_CORRUPT)
- {
- zSelect = appendText (zSelect, " ORDER BY rowid DESC", 0);
- rc = run_table_dump_query (p->out, p->db, zSelect);
- }
- if (zSelect)
- free (zSelect);
- }
- return 0;
- }
- static void
- spatialite_autocreate (sqlite3 * db)
- {
- /* attempting to perform self-initialization for a newly created DB */
- int ret;
- char sql[1024];
- char *err_msg = NULL;
- int count;
- int i;
- char **results;
- int rows;
- int columns;
- /* checking if this DB is really empty */
- strcpy (sql, "SELECT Count(*) from sqlite_master");
- ret = sqlite3_get_table (db, sql, &results, &rows, &columns, NULL);
- if (ret != SQLITE_OK)
- return;
- if (rows < 1)
- ;
- else
- {
- for (i = 1; i <= rows; i++)
- count = atoi (results[(i * columns) + 0]);
- }
- sqlite3_free_table (results);
- if (count > 0)
- return;
- /* all right, it's empty: proceding to initialize */
- strcpy (sql, "SELECT InitSpatialMetadata()");
- ret = sqlite3_exec (db, sql, NULL, NULL, &err_msg);
- if (ret != SQLITE_OK)
- {
- fprintf (stderr, "InitSpatialMetadata() error: %s\n", err_msg);
- sqlite3_free (err_msg);
- return;
- }
- spatial_ref_sys_init (db, 1);
- }
- /*
- ** Run zQuery. Use dump_callback() as the callback routine so that
- ** the contents of the query are output as SQL statements.
- **
- ** If we get a SQLITE_CORRUPT error, rerun the query after appending
- ** "ORDER BY rowid DESC" to the end.
- */
- static int
- run_schema_dump_query (struct callback_data *p,
- const char *zQuery, char **pzErrMsg)
- {
- int rc;
- rc = sqlite3_exec (p->db, zQuery, dump_callback, p, pzErrMsg);
- if (rc == SQLITE_CORRUPT)
- {
- char *zQ2;
- int len = strlen (zQuery);
- if (pzErrMsg)
- sqlite3_free (*pzErrMsg);
- zQ2 = malloc (len + 100);
- if (zQ2 == 0)
- return rc;
- sqlite3_snprintf (sizeof (zQ2), zQ2, "%s ORDER BY rowid DESC",
- zQuery);
- rc = sqlite3_exec (p->db, zQ2, dump_callback, p, pzErrMsg);
- free (zQ2);
- }
- return rc;
- }
- /*
- ** Text of a help message
- */
- static char zHelp[] =
- ".bail ON|OFF Stop after hitting an error. Default OFF\n"
- ".databases List names and files of attached databases\n"
- ".dump ?TABLE? ... Dump the database in an SQL text format\n"
- ".echo ON|OFF Turn command echo on or off\n"
- ".exit Exit this program\n"
- ".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
- ".header(s) ON|OFF Turn display of headers on or off\n"
- ".help Show this message\n"
- ".import FILE TABLE Import data from FILE into TABLE\n"
- ".indices TABLE Show names of all indices on TABLE\n"
- #ifdef SQLITE_ENABLE_IOTRACE
- ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
- #endif
- #ifndef SQLITE_OMIT_LOAD_EXTENSION
- ".load FILE ?ENTRY? Load an extension library\n"
- #endif
- ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
- " csv Comma-separated values\n"
- " column Left-aligned columns. (See .width)\n"
- " html HTML <table> code\n"
- " insert SQL insert statements for TABLE\n"
- " line One value per line\n"
- " list Values delimited by .separator string\n"
- " tabs Tab-separated values\n"
- " tcl TCL list elements\n"
- ".nullvalue STRING Print STRING in place of NULL values\n"
- ".output FILENAME Send output to FILENAME\n"
- ".output stdout Send output to the screen\n"
- ".prompt MAIN CONTINUE Replace the standard prompts\n"
- ".quit Exit this program\n"
- ".schema ?TABLE? Show the CREATE statements\n"
- ".separator STRING Change separator used by output mode and .import\n"
- ".show Show the current values for various settings\n"
- ".tables ?PATTERN? List names of tables matching a LIKE pattern\n"
- ".timeout MS Try opening locked tables for MS milliseconds\n"
- #if HAS_TIMER
- ".timer ON|OFF Turn the CPU timer measurement on or off\n"
- #endif
- ".width NUM NUM ... Set column widths for \"column\" mode\n"
- /* Sandro Furieri 2008-06-20 */
- "\n====================== SpatiaLite ========================================\n\n"
- ".charset Report the current locale charset setting\n\n"
- ".charset <charset-name>\n"
- " Set the charset encoding according to the command shell\n"
- " e.g.: when working on Windows Command Prompt, if you notice\n"
- " 'strange' chars, a very good idea may be to type\n"
- " the following command:\n"
- " .charset CP850\n"
- " [use the Windows CHCP command in order to check better\n"
- " which one charset is used on your Command Prompt]\n\n"
- ".loadshp <args> Loads a SHAPEFILE into a SpatiaLite table\n"
- " arg_list: shp_path table_name charset [SRID] [column_name] [2d] [compressed]\n\n"
- ".dumpshp <args> Dumps a SpatiaLite table into a SHAPEFILE\n"
- " arg_list: table_name column_name shp_path charset [geom_type]\n"
- " geom_type={ POINT | LINESTRING | POLYGON | MULTIPOINT }\n\n"
- ".loaddbf <args> Loads a DBF into a SpatiaLite table\n"
- " arg_list: dbf_path table_name charset\n\n"
- ".read <args> Execute an SQL script\n"
- " arg_list: script_path charset\n"
- /* end Sandro Furieri 2008-06-20 */
- ;
- /* Forward reference */
- static int process_input (struct callback_data *p, FILE * in, char *in_charset);
- /*
- ** Make sure the database is open. If it is not, then open it. If
- ** the database fails to open, print an error message and exit.
- */
- static void
- open_db (struct callback_data *p)
- {
- if (p->db == 0)
- {
- sqlite3_open (p->zDbFilename, &p->db);
- db = p->db;
- if (db && sqlite3_errcode (db) == SQLITE_OK)
- {
- sqlite3_create_function (db, "shellstatic", 0, SQLITE_UTF8, 0,
- shellstaticFunc, 0, 0);
- }
- if (db == 0 || SQLITE_OK != sqlite3_errcode (db))
- {
- fprintf (stderr, "Unable to open database \"%s\": %s\n",
- p->zDbFilename, sqlite3_errmsg (db));
- exit (1);
- }
- #ifndef SQLITE_OMIT_LOAD_EXTENSION
- sqlite3_enable_load_extension (p->db, 1);
- #endif
- /* Sandro Furieri 2009-11-08 */
- sqlite3_exec (p->db, "PRAGMA foreign_keys = 1", NULL, 0, NULL);
- /* end Sandro Furieri 2008-11-08 */
- /* Sandro Furieri 2010-08-07 */
- spatialite_autocreate (p->db);
- /* end Sandro Furieri 2010-08-07 */
- }
- }
- /*
- ** Do C-language style dequoting.
- **
- ** \t -> tab
- ** \n -> newline
- ** \r -> carriage return
- ** \NNN -> ascii character NNN in octal
- ** \\ -> backslash
- */
- static void
- resolve_backslashes (char *z)
- {
- int i, j, c;
- for (i = j = 0; (c = z[i]) != 0; i++, j++)
- {
- if (c == '\\')
- {
- c = z[++i];
- if (c == 'n')
- {
- c = '\n';
- }
- else if (c == 't')
- {
- c = '\t';
- }
- else if (c == 'r')
- {
- c = '\r';
- }
- else if (c >= '0' && c <= '7')
- {
- c -= '0';
- if (z[i + 1] >= '0' && z[i + 1] <= '7')
- {
- i++;
- c = (c << 3) + z[i] - '0';
- if (z[i + 1] >= '0' && z[i + 1] <= '7')
- {
- i++;
- c = (c << 3) + z[i] - '0';
- }
- }
- }
- }
- z[j] = c;
- }
- z[j] = 0;
- }
- /*
- ** Interpret zArg as a boolean value. Return either 0 or 1.
- */
- static int
- booleanValue (char *zArg)
- {
- int val = atoi (zArg);
- int j;
- for (j = 0; zArg[j]; j++)
- {
- zArg[j] = tolower (zArg[j]);
- }
- if (strcmp (zArg, "on") == 0)
- {
- val = 1;
- }
- else if (strcmp (zArg, "yes") == 0)
- {
- val = 1;
- }
- return val;
- }
- /*
- ** If an input line begins with "." then invoke this routine to
- ** process that line.
- **
- ** Return 1 on error, 2 to exit, and 0 otherwise.
- */
- static int
- do_meta_command (char *zLine, struct callback_data *p)
- {
- int i = 1;
- int nArg = 0;
- int n, c;
- int rc = 0;
- char *azArg[50];
- /* Parse the input line into tokens.
- */
- while (zLine[i] && nArg < ArraySize (azArg))
- {
- while (isspace ((unsigned char) zLine[i]))
- {
- i++;
- }
- if (zLine[i] == 0)
- break;
- if (zLine[i] == '\'' || zLine[i] == '"')
- {
- int delim = zLine[i++];
- azArg[nArg++] = &zLine[i];
- while (zLine[i] && zLine[i] != delim)
- {
- i++;
- }
- if (zLine[i] == delim)
- {
- zLine[i++] = 0;
- }
- if (delim == '"')
- resolve_backslashes (azArg[nArg - 1]);
- }
- else
- {
- azArg[nArg++] = &zLine[i];
- while (zLine[i] && !isspace ((unsigned char) zLine[i]))
- {
- i++;
- }
- if (zLine[i])
- zLine[i++] = 0;
- resolve_backslashes (azArg[nArg - 1]);
- }
- }
- /* Process the input line.
- */
- if (nArg == 0)
- return rc;
- n = strlen (azArg[0]);
- c = azArg[0][0];
- /* Sandro Furieri 2008-06-20 */
- if (c == 'c' && n > 1 && strncmp (azArg[0], "charset", n) == 0 && nArg == 1)
- {
- /* reporting the charset */
- if (*spatialite_charset == '\0')
- {
- printf
- ("the shell's default LOCALE CHARSET is currently in use\n");
- fflush (stdout);
- }
- else
- {
- printf ("the %s charset is currently used as LOCALE CHARSET\n",
- spatialite_charset);
- fflush (stdout);
- }
- }
- else if (c == 'c' && n > 1 && strncmp (azArg[0], "charset", n) == 0
- && nArg == 2)
- {
- /* setting the charset */
- create_utf8_converter (azArg[1]);
- }
- else if (c == 'd' && n > 1 && strncmp (azArg[0], "dumpshp", n) == 0
- && (nArg == 5 || nArg == 6))
- {
- /* dumping a spatial table to SHAPEFILE */
- char *table = azArg[1];
- char *column = azArg[2];
- char *shp_path = azArg[3];
- char *outCS = azArg[4];
- char *type = NULL;
- if (nArg == 6)
- type = azArg[5];
- open_db (p);
- dump_shapefile (p->db, table, column, shp_path, outCS, type, 1, NULL);
- }
- else if (c == 'l' && n > 1 && strncmp (azArg[0], "loadshp", n) == 0
- && (nArg == 4 || nArg == 5 || nArg == 6 || nArg == 7 || nArg == 8))
- {
- char *shp_path = azArg[1];
- char *table = azArg[2];
- char *inCS = azArg[3];
- int srid = -1;
- int coerce2d = 0;
- int compressed = 0;
- char *column = NULL;
- if (nArg >= 5)
- srid = atoi (azArg[4]);
- if (nArg == 6)
- column = azArg[5];
- if (nArg >= 7)
- coerce2d = 1;
- if (nArg == 8)
- compressed = 1;
- open_db (p);
- load_shapefile (p->db, shp_path, table, inCS, srid, column, coerce2d,
- compressed, 1, NULL);
- }
- else if (c == 'l' && n > 1 && strncmp (azArg[0], "loaddbf", n) == 0
- && nArg == 4)
- {
- char *dbf_path = azArg[1];
- char *table = azArg[2];
- char *inCS = azArg[3];
- open_db (p);
- load_dbf (p->db, dbf_path, table, inCS, 1, NULL);
- }
- else if (c == 'r' && strncmp (azArg[0], "read", n) == 0)
- {
- FILE *alt;
- if (nArg != 3)
- {
- fprintf (stderr,
- "invalid arguments: .read script_path charset\n");
- return rc;
- }
- alt = fopen (azArg[1], "rb");
- if (alt == 0)
- {
- fprintf (stderr, "can't open \"%s\"\n", azArg[1]);
- }
- else
- {
- process_input (p, alt, azArg[2]);
- fclose (alt);
- }
- }
- else if (c == 'b' && n > 1 && strncmp (azArg[0], "bail", n) == 0
- && nArg > 1)
- {
- bail_on_error = booleanValue (azArg[1]);
- }
- else if (c == 'd' && n > 1 && strncmp (azArg[0], "databases", n) == 0)
- {
- struct callback_data data;
- char *zErrMsg = 0;
- open_db (p);
- memcpy (&data, p, sizeof (data));
- data.showHeader = 1;
- data.mode = MODE_Column;
- data.colWidth[0] = 3;
- data.colWidth[1] = 15;
- data.colWidth[2] = 58;
- data.cnt = 0;
- sqlite3_exec (p->db, "PRAGMA database_list; ", callback, &data,
- &zErrMsg);
- if (zErrMs…
Large files files are truncated, but you can click here to view the full file