| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #include "sqlite3.h" |
| | #include <stdarg.h> |
| | #include <string.h> |
| | #include <ctype.h> |
| |
|
| | |
| | |
| | |
| | typedef struct DState DState; |
| | struct DState { |
| | sqlite3 *db; |
| | int nErr; |
| | int rc; |
| | int writableSchema; |
| | int (*xCallback)(const char*,void*); |
| | void *pArg; |
| | }; |
| |
|
| | |
| | |
| | |
| | typedef struct DText DText; |
| | struct DText { |
| | char *z; |
| | sqlite3_int64 n; |
| | sqlite3_int64 nAlloc; |
| | }; |
| |
|
| | |
| | |
| | |
| | static void initText(DText *p){ |
| | memset(p, 0, sizeof(*p)); |
| | } |
| | static void freeText(DText *p){ |
| | sqlite3_free(p->z); |
| | initText(p); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void appendText(DText *p, char const *zAppend, char quote){ |
| | int len; |
| | int i; |
| | int nAppend = (int)(strlen(zAppend) & 0x3fffffff); |
| |
|
| | len = nAppend+p->n+1; |
| | if( quote ){ |
| | len += 2; |
| | for(i=0; i<nAppend; i++){ |
| | if( zAppend[i]==quote ) len++; |
| | } |
| | } |
| |
|
| | if( p->n+len>=p->nAlloc ){ |
| | char *zNew; |
| | p->nAlloc = p->nAlloc*2 + len + 20; |
| | zNew = sqlite3_realloc64(p->z, p->nAlloc); |
| | if( zNew==0 ){ |
| | freeText(p); |
| | return; |
| | } |
| | p->z = zNew; |
| | } |
| |
|
| | if( quote ){ |
| | char *zCsr = p->z+p->n; |
| | *zCsr++ = quote; |
| | for(i=0; i<nAppend; i++){ |
| | *zCsr++ = zAppend[i]; |
| | if( zAppend[i]==quote ) *zCsr++ = quote; |
| | } |
| | *zCsr++ = quote; |
| | p->n = (int)(zCsr - p->z); |
| | *zCsr = '\0'; |
| | }else{ |
| | memcpy(p->z+p->n, zAppend, nAppend); |
| | p->n += nAppend; |
| | p->z[p->n] = '\0'; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static char quoteChar(const char *zName){ |
| | int i; |
| | if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"'; |
| | for(i=0; zName[i]; i++){ |
| | if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"'; |
| | } |
| | return sqlite3_keyword_check(zName, i) ? '"' : 0; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | static void freeColumnList(char **azCol){ |
| | int i; |
| | for(i=1; azCol[i]; i++){ |
| | sqlite3_free(azCol[i]); |
| | } |
| | |
| | sqlite3_free(azCol); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static char **tableColumnList(DState *p, const char *zTab){ |
| | char **azCol = 0; |
| | sqlite3_stmt *pStmt = 0; |
| | char *zSql; |
| | sqlite3_int64 nCol = 0; |
| | sqlite3_int64 nAlloc = 0; |
| | int nPK = 0; |
| | int isIPK = 0; |
| | int preserveRowid = 1; |
| | int rc; |
| |
|
| | zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab); |
| | if( zSql==0 ) return 0; |
| | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| | sqlite3_free(zSql); |
| | if( rc ) return 0; |
| | while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
| | if( nCol>=nAlloc-2 ){ |
| | char **azNew; |
| | nAlloc = nAlloc*2 + nCol + 10; |
| | azNew = sqlite3_realloc64(azCol, nAlloc*sizeof(azCol[0])); |
| | if( azNew==0 ) goto col_oom; |
| | azCol = azNew; |
| | azCol[0] = 0; |
| | } |
| | azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); |
| | if( azCol[nCol]==0 ) goto col_oom; |
| | if( sqlite3_column_int(pStmt, 5) ){ |
| | nPK++; |
| | if( nPK==1 |
| | && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2), |
| | "INTEGER")==0 |
| | ){ |
| | isIPK = 1; |
| | }else{ |
| | isIPK = 0; |
| | } |
| | } |
| | } |
| | sqlite3_finalize(pStmt); |
| | pStmt = 0; |
| | azCol[nCol+1] = 0; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | if( isIPK ){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)" |
| | " WHERE origin='pk'", zTab); |
| | if( zSql==0 ) goto col_oom; |
| | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| | sqlite3_free(zSql); |
| | if( rc ){ |
| | freeColumnList(azCol); |
| | return 0; |
| | } |
| | rc = sqlite3_step(pStmt); |
| | sqlite3_finalize(pStmt); |
| | pStmt = 0; |
| | preserveRowid = rc==SQLITE_ROW; |
| | } |
| | if( preserveRowid ){ |
| | |
| | |
| | static char *azRowid[] = { "rowid", "_rowid_", "oid" }; |
| | int i, j; |
| | for(j=0; j<3; j++){ |
| | for(i=1; i<=nCol; i++){ |
| | if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break; |
| | } |
| | if( i>nCol ){ |
| | |
| | |
| | |
| | |
| | rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0); |
| | if( rc==SQLITE_OK ) azCol[0] = azRowid[j]; |
| | break; |
| | } |
| | } |
| | } |
| | return azCol; |
| |
|
| | col_oom: |
| | sqlite3_finalize(pStmt); |
| | freeColumnList(azCol); |
| | p->nErr++; |
| | p->rc = SQLITE_NOMEM; |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | static void output_formatted(DState *p, const char *zFormat, ...){ |
| | va_list ap; |
| | char *z; |
| | va_start(ap, zFormat); |
| | z = sqlite3_vmprintf(zFormat, ap); |
| | va_end(ap); |
| | p->xCallback(z, p->pArg); |
| | sqlite3_free(z); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static const char *unused_string( |
| | const char *z, |
| | const char *zA, const char *zB, |
| | char *zBuf |
| | ){ |
| | unsigned i = 0; |
| | if( strstr(z, zA)==0 ) return zA; |
| | if( strstr(z, zB)==0 ) return zB; |
| | do{ |
| | sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++); |
| | }while( strstr(z,zBuf)!=0 ); |
| | return zBuf; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static void output_quoted_escaped_string(DState *p, const char *z){ |
| | int i; |
| | char c; |
| | for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){} |
| | if( c==0 ){ |
| | output_formatted(p,"'%s'",z); |
| | }else{ |
| | const char *zNL = 0; |
| | const char *zCR = 0; |
| | int nNL = 0; |
| | int nCR = 0; |
| | char zBuf1[20], zBuf2[20]; |
| | for(i=0; z[i]; i++){ |
| | if( z[i]=='\n' ) nNL++; |
| | if( z[i]=='\r' ) nCR++; |
| | } |
| | if( nNL ){ |
| | p->xCallback("replace(", p->pArg); |
| | zNL = unused_string(z, "\\n", "\\012", zBuf1); |
| | } |
| | if( nCR ){ |
| | p->xCallback("replace(", p->pArg); |
| | zCR = unused_string(z, "\\r", "\\015", zBuf2); |
| | } |
| | p->xCallback("'", p->pArg); |
| | while( *z ){ |
| | for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){} |
| | if( c=='\'' ) i++; |
| | if( i ){ |
| | output_formatted(p, "%.*s", i, z); |
| | z += i; |
| | } |
| | if( c=='\'' ){ |
| | p->xCallback("'", p->pArg); |
| | continue; |
| | } |
| | if( c==0 ){ |
| | break; |
| | } |
| | z++; |
| | if( c=='\n' ){ |
| | p->xCallback(zNL, p->pArg); |
| | continue; |
| | } |
| | p->xCallback(zCR, p->pArg); |
| | } |
| | p->xCallback("'", p->pArg); |
| | if( nCR ){ |
| | output_formatted(p, ",'%s',char(13))", zCR); |
| | } |
| | if( nNL ){ |
| | output_formatted(p, ",'%s',char(10))", zNL); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ |
| | int rc; |
| | const char *zTable; |
| | const char *zType; |
| | const char *zSql; |
| | DState *p = (DState*)pArg; |
| | sqlite3_stmt *pStmt; |
| |
|
| | (void)azCol; |
| | if( nArg!=3 ) return 1; |
| | zTable = azArg[0]; |
| | zType = azArg[1]; |
| | zSql = azArg[2]; |
| |
|
| | if( strcmp(zTable, "sqlite_sequence")==0 ){ |
| | p->xCallback("DELETE FROM sqlite_sequence;\n", p->pArg); |
| | }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){ |
| | p->xCallback("ANALYZE sqlite_schema;\n", p->pArg); |
| | }else if( strncmp(zTable, "sqlite_", 7)==0 ){ |
| | return 0; |
| | }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ |
| | if( !p->writableSchema ){ |
| | p->xCallback("PRAGMA writable_schema=ON;\n", p->pArg); |
| | p->writableSchema = 1; |
| | } |
| | output_formatted(p, |
| | "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)" |
| | "VALUES('table','%q','%q',0,'%q');", |
| | zTable, zTable, zSql); |
| | return 0; |
| | }else{ |
| | if( sqlite3_strglob("CREATE TABLE ['\"]*", zSql)==0 ){ |
| | p->xCallback("CREATE TABLE IF NOT EXISTS ", p->pArg); |
| | p->xCallback(zSql+13, p->pArg); |
| | }else{ |
| | p->xCallback(zSql, p->pArg); |
| | } |
| | p->xCallback(";\n", p->pArg); |
| | } |
| |
|
| | if( strcmp(zType, "table")==0 ){ |
| | DText sSelect; |
| | DText sTable; |
| | char **azTCol; |
| | int i; |
| | int nCol; |
| |
|
| | azTCol = tableColumnList(p, zTable); |
| | if( azTCol==0 ) return 0; |
| |
|
| | initText(&sTable); |
| | appendText(&sTable, "INSERT INTO ", 0); |
| |
|
| | |
| | |
| | appendText(&sTable, zTable, quoteChar(zTable)); |
| |
|
| | |
| | |
| | |
| | |
| | if( azTCol[0] ){ |
| | appendText(&sTable, "(", 0); |
| | appendText(&sTable, azTCol[0], 0); |
| | for(i=1; azTCol[i]; i++){ |
| | appendText(&sTable, ",", 0); |
| | appendText(&sTable, azTCol[i], quoteChar(azTCol[i])); |
| | } |
| | appendText(&sTable, ")", 0); |
| | } |
| | appendText(&sTable, " VALUES(", 0); |
| |
|
| | |
| | initText(&sSelect); |
| | appendText(&sSelect, "SELECT ", 0); |
| | if( azTCol[0] ){ |
| | appendText(&sSelect, azTCol[0], 0); |
| | appendText(&sSelect, ",", 0); |
| | } |
| | for(i=1; azTCol[i]; i++){ |
| | appendText(&sSelect, azTCol[i], quoteChar(azTCol[i])); |
| | if( azTCol[i+1] ){ |
| | appendText(&sSelect, ",", 0); |
| | } |
| | } |
| | nCol = i; |
| | if( azTCol[0]==0 ) nCol--; |
| | freeColumnList(azTCol); |
| | appendText(&sSelect, " FROM ", 0); |
| | appendText(&sSelect, zTable, quoteChar(zTable)); |
| |
|
| | rc = sqlite3_prepare_v2(p->db, sSelect.z, -1, &pStmt, 0); |
| | if( rc!=SQLITE_OK ){ |
| | p->nErr++; |
| | if( p->rc==SQLITE_OK ) p->rc = rc; |
| | }else{ |
| | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| | p->xCallback(sTable.z, p->pArg); |
| | for(i=0; i<nCol; i++){ |
| | if( i ) p->xCallback(",", p->pArg); |
| | switch( sqlite3_column_type(pStmt,i) ){ |
| | case SQLITE_INTEGER: { |
| | output_formatted(p, "%lld", sqlite3_column_int64(pStmt,i)); |
| | break; |
| | } |
| | case SQLITE_FLOAT: { |
| | double r = sqlite3_column_double(pStmt,i); |
| | sqlite3_uint64 ur; |
| | memcpy(&ur,&r,sizeof(r)); |
| | if( ur==0x7ff0000000000000LL ){ |
| | p->xCallback("1e999", p->pArg); |
| | }else if( ur==0xfff0000000000000LL ){ |
| | p->xCallback("-1e999", p->pArg); |
| | }else{ |
| | output_formatted(p, "%!.20g", r); |
| | } |
| | break; |
| | } |
| | case SQLITE_NULL: { |
| | p->xCallback("NULL", p->pArg); |
| | break; |
| | } |
| | case SQLITE_TEXT: { |
| | output_quoted_escaped_string(p, |
| | (const char*)sqlite3_column_text(pStmt,i)); |
| | break; |
| | } |
| | case SQLITE_BLOB: { |
| | int nByte = sqlite3_column_bytes(pStmt,i); |
| | unsigned char *a = (unsigned char*)sqlite3_column_blob(pStmt,i); |
| | int j; |
| | p->xCallback("x'", p->pArg); |
| | for(j=0; j<nByte; j++){ |
| | char zWord[3]; |
| | zWord[0] = "0123456789abcdef"[(a[j]>>4)&15]; |
| | zWord[1] = "0123456789abcdef"[a[j]&15]; |
| | zWord[2] = 0; |
| | p->xCallback(zWord, p->pArg); |
| | } |
| | p->xCallback("'", p->pArg); |
| | break; |
| | } |
| | } |
| | } |
| | p->xCallback(");\n", p->pArg); |
| | } |
| | } |
| | sqlite3_finalize(pStmt); |
| | freeText(&sTable); |
| | freeText(&sSelect); |
| | } |
| | return 0; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void output_sql_from_query( |
| | DState *p, |
| | const char *zSelect, |
| | ... |
| | ){ |
| | sqlite3_stmt *pSelect; |
| | int rc; |
| | int nResult; |
| | int i; |
| | const char *z; |
| | char *zSql; |
| | va_list ap; |
| | va_start(ap, zSelect); |
| | zSql = sqlite3_vmprintf(zSelect, ap); |
| | va_end(ap); |
| | if( zSql==0 ){ |
| | p->rc = SQLITE_NOMEM; |
| | p->nErr++; |
| | return; |
| | } |
| | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pSelect, 0); |
| | sqlite3_free(zSql); |
| | if( rc!=SQLITE_OK || !pSelect ){ |
| | output_formatted(p, "/**** ERROR: (%d) %s *****/\n", rc, |
| | sqlite3_errmsg(p->db)); |
| | p->nErr++; |
| | return; |
| | } |
| | rc = sqlite3_step(pSelect); |
| | nResult = sqlite3_column_count(pSelect); |
| | while( rc==SQLITE_ROW ){ |
| | z = (const char*)sqlite3_column_text(pSelect, 0); |
| | p->xCallback(z, p->pArg); |
| | for(i=1; i<nResult; i++){ |
| | p->xCallback(",", p->pArg); |
| | p->xCallback((const char*)sqlite3_column_text(pSelect,i), p->pArg); |
| | } |
| | if( z==0 ) z = ""; |
| | while( z[0] && (z[0]!='-' || z[1]!='-') ) z++; |
| | if( z[0] ){ |
| | p->xCallback("\n;\n", p->pArg); |
| | }else{ |
| | p->xCallback(";\n", p->pArg); |
| | } |
| | rc = sqlite3_step(pSelect); |
| | } |
| | rc = sqlite3_finalize(pSelect); |
| | if( rc!=SQLITE_OK ){ |
| | output_formatted(p, "/**** ERROR: (%d) %s *****/\n", rc, |
| | sqlite3_errmsg(p->db)); |
| | if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void run_schema_dump_query( |
| | DState *p, |
| | const char *zQuery, |
| | ... |
| | ){ |
| | char *zErr = 0; |
| | char *z; |
| | va_list ap; |
| | va_start(ap, zQuery); |
| | z = sqlite3_vmprintf(zQuery, ap); |
| | va_end(ap); |
| | sqlite3_exec(p->db, z, dump_callback, p, &zErr); |
| | sqlite3_free(z); |
| | if( zErr ){ |
| | output_formatted(p, "/****** %s ******/\n", zErr); |
| | sqlite3_free(zErr); |
| | p->nErr++; |
| | zErr = 0; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | int sqlite3_db_dump( |
| | sqlite3 *db, |
| | const char *zSchema, |
| | const char *zTable, |
| | int (*xCallback)(const char*,void*), |
| | void *pArg |
| | ){ |
| | DState x; |
| | memset(&x, 0, sizeof(x)); |
| | x.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); |
| | if( x.rc ) return x.rc; |
| | x.db = db; |
| | x.xCallback = xCallback; |
| | x.pArg = pArg; |
| | xCallback("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n", pArg); |
| | if( zTable==0 ){ |
| | run_schema_dump_query(&x, |
| | "SELECT name, type, sql FROM \"%w\".sqlite_schema " |
| | "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", |
| | zSchema |
| | ); |
| | run_schema_dump_query(&x, |
| | "SELECT name, type, sql FROM \"%w\".sqlite_schema " |
| | "WHERE name=='sqlite_sequence'", zSchema |
| | ); |
| | output_sql_from_query(&x, |
| | "SELECT sql FROM sqlite_schema " |
| | "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 |
| | ); |
| | }else{ |
| | run_schema_dump_query(&x, |
| | "SELECT name, type, sql FROM \"%w\".sqlite_schema " |
| | "WHERE tbl_name=%Q COLLATE nocase AND type=='table'" |
| | " AND sql NOT NULL", |
| | zSchema, zTable |
| | ); |
| | output_sql_from_query(&x, |
| | "SELECT sql FROM \"%w\".sqlite_schema " |
| | "WHERE sql NOT NULL" |
| | " AND type IN ('index','trigger','view')" |
| | " AND tbl_name=%Q COLLATE nocase", |
| | zSchema, zTable |
| | ); |
| | } |
| | if( x.writableSchema ){ |
| | xCallback("PRAGMA writable_schema=OFF;\n", pArg); |
| | } |
| | xCallback(x.nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n", pArg); |
| | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| | return x.rc; |
| | } |
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | #ifdef DBDUMP_STANDALONE |
| | #include <stdio.h> |
| |
|
| | |
| | |
| | |
| | int main(int argc, char **argv){ |
| | sqlite3 *db; |
| | const char *zDb; |
| | const char *zSchema; |
| | const char *zTable = 0; |
| | int rc; |
| |
|
| | if( argc<2 || argc>4 ){ |
| | fprintf(stderr, "Usage: %s DATABASE ?SCHEMA? ?TABLE?\n", argv[0]); |
| | return 1; |
| | } |
| | zDb = argv[1]; |
| | zSchema = argc>=3 ? argv[2] : "main"; |
| | zTable = argc==4 ? argv[3] : 0; |
| |
|
| | rc = sqlite3_open(zDb, &db); |
| | if( rc ){ |
| | fprintf(stderr, "Cannot open \"%s\": %s\n", zDb, sqlite3_errmsg(db)); |
| | sqlite3_close(db); |
| | return 1; |
| | } |
| | rc = sqlite3_db_dump(db, zSchema, zTable, |
| | (int(*)(const char*,void*))fputs, (void*)stdout); |
| | if( rc ){ |
| | fprintf(stderr, "Error: sqlite3_db_dump() returns %d\n", rc); |
| | } |
| | sqlite3_close(db); |
| | return rc!=SQLITE_OK; |
| | } |
| | #endif |
| |
|