diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 7f3d09b0..971aed12 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -879,14 +879,12 @@ void MainWindow::exportDatabaseToSQL() defaultlocation, "Text files(*.sql *.txt)"); - if (fileName.size() > 0) + if(fileName.size()) { - if (!db.dump(fileName)) - { - QMessageBox::warning( this, QApplication::applicationName(), "Could not create export file." ); - } else { - QMessageBox::information( this, QApplication::applicationName(), "Export completed." ); - } + if(!db.dump(fileName)) + QMessageBox::warning(this, QApplication::applicationName(), "Export cancelled or failed."); + else + QMessageBox::information(this, QApplication::applicationName(), "Export completed."); } } diff --git a/src/sqlbrowser_util.c b/src/sqlbrowser_util.c index c44f367e..a5687245 100644 --- a/src/sqlbrowser_util.c +++ b/src/sqlbrowser_util.c @@ -3,328 +3,10 @@ #include #include #include +#include /*following routines extracted from shell.c for dump support*/ -/* -** 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; -} - - -char *modeDescr[MODE_NUM_OF] = { - "line", - "column", - "list", - "semi", - "html", - "insert" -}; - -/* -** 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 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; - } -} - -/* -** 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; - struct callback_data *p = (struct callback_data*)pArg; - switch( p->mode ){ - case MODE_Line: { - int w = 5; - if( azArg==0 ) break; - for(i=0; iw ) w = len; - } - if( p->cnt++>0 ) fprintf(p->out,"\n"); - for(i=0; iout,"%*s = %s\n", w, azCol[i], - azArg[i] ? azArg[i] : p->nullvalue); - } - break; - } - case MODE_Column: { - if( p->cnt++==0 ){ - for(i=0; icolWidth) ){ - 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( wactualWidth) ){ - 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; iactualWidth) ){ - 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; iactualWidth) ){ - w = p->actualWidth[i]; - }else{ - w = 10; - } - fprintf(p->out,"%-*.*s%s",w,w, - azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); - } - break; - } - case MODE_Semi: - case MODE_List: { - if( p->cnt++==0 && p->showHeader ){ - for(i=0; iout,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator); - } - } - if( azArg==0 ) break; - for(i=0; inullvalue; - fprintf(p->out, "%s", z); - if( iout, "%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,""); - for(i=0; iout,"%s",azCol[i]); - } - fprintf(p->out,"\n"); - } - if( azArg==0 ) break; - fprintf(p->out,""); - for(i=0; iout,""); - output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue); - fprintf(p->out,"\n"); - } - fprintf(p->out,"\n"); - break; - } - case MODE_Insert: { - if( azArg==0 ) break; - fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); - for(i=0; i0 ? ",": ""; - 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); - output_quoted_string(p->out, azArg[i]); - } - } - fprintf(p->out,");\n"); - break; - } - } - 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(*zName) && *zName!='_'; - for(i=n=0; zName[i]; i++, n++){ - if( !isalnum(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; -} - -/* -** 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){ - struct callback_data *p = (struct callback_data *)pArg; - if( nArg!=3 ) return 1; - fprintf(p->out, "%s;\n", azArg[2]); - if( strcmp(azArg[1],"table")==0 ){ - struct callback_data d2; - char* stmt; - d2 = *p; - d2.mode = MODE_Insert; - d2.zDestTable = 0; - set_table_name(&d2, azArg[0]); - stmt = sqlite3_mprintf("SELECT * FROM `%q`", azArg[0]); - sqlite3_exec(p->db,stmt, callback, &d2, 0); - sqlite3_free(stmt); - set_table_name(&d2, 0); - } - return 0; -} - -/* -/Dump database to a file -*/ -int dump_database(sqlite3 * db, FILE * outfile){ - int rc = 0; - char *zErrMsg = 0; - struct callback_data p; - memset(&p, 0, sizeof(p)); - p.db = db; - p.mode = MODE_List; - strcpy(p.separator,"|"); - p.showHeader = 0; - p.out = outfile; - //open_db(p); - fprintf(p.out, "BEGIN TRANSACTION;\n"); - sqlite3_exec(p.db, - "SELECT name, type, sql FROM sqlite_master " - "WHERE type!='meta' AND sql NOT NULL " - "ORDER BY substr(type,2,1), name", - dump_callback, &p, &zErrMsg - ); - if( zErrMsg ){ - /*fprintf(stderr,"Error: %s\n", zErrMsg);*/ - free(zErrMsg); - }else{ - fprintf(p.out, "COMMIT;\n"); - } - return rc; -} - /* /Dump database to a file */ @@ -466,4 +148,3 @@ void process_input(sqlite3 * db, FILE *in, int * lineErr){ } /* end of shell.c routines*/ - diff --git a/src/sqlbrowser_util.h b/src/sqlbrowser_util.h index 6b23f57d..8dd56d26 100644 --- a/src/sqlbrowser_util.h +++ b/src/sqlbrowser_util.h @@ -5,54 +5,9 @@ extern "C" { #endif -#include #include #include - -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 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_NUM_OF 6 /* The number of modes (not a mode itself) */ - -int dump_database(sqlite3 * db, FILE * outfile); int load_database(sqlite3 * db, FILE * infile, int * lineErr); void process_input(sqlite3 * db, FILE *in, int * lineErr); char *sqlbrowser_getline(FILE *in); diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 3b8f1cb6..c5cd8231 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -5,6 +5,7 @@ #include #include "SQLLogDock.h" #include +#include void DBBrowserObject::addField(int order, const QString& wfield,const QString& wtype) { @@ -260,16 +261,92 @@ bool DBBrowserDB::reload( const QString & filename, int * lineErr) return true; } -bool DBBrowserDB::dump( const QString & filename) +bool DBBrowserDB::dump(const QString& filename) { - FILE * cfile = fopen(filename.toUtf8(), (const char *) "w"); - if (!cfile) + // Open file + QFile file(filename); + if(file.open(QIODevice::WriteOnly)) { + // Create progress dialog. For this count the number of all table rows to be exported first; this does neither take the table creation itself nor + // indices, views or triggers into account but compared to the number of rows those should be neglectable + unsigned int numRecordsTotal = 0, numRecordsCurrent = 0; + QList tables = objMap.values("table"); + for(QList::ConstIterator it=tables.begin();it!=tables.end();++it) + numRecordsTotal += getFindResults(QString("SELECT COUNT(*) FROM `%1`;").arg((*it).getname())).value(0).toInt(); + QProgressDialog progress("Exporting database to SQL file...", "Cancel", 0, numRecordsTotal); + progress.setWindowModality(Qt::ApplicationModal); + + // Regular expression to check for numeric strings + QRegExp regexpIsNumeric("\\d*"); + + // Open text stream to the file + QTextStream stream(&file); + + // Put the SQL commands in a transaction block + stream << "BEGIN TRANSACTION;\n"; + + // Loop through all tables first as they are required to generate views, indices etc. later + for(QList::ConstIterator it=tables.begin();it!=tables.end();++it) + { + // Write the SQL string used to create this table to the output file + stream << (*it).getsql() << ";\n"; + + // Get data of this table + browseTable((*it).getname()); + + // Dump all the content of the table + rowList data = browseRecs; + for(int row=0;rowprocessEvents(); + if(progress.wasCanceled()) + { + file.close(); + file.remove(); + return false; + } + } + } + + // Now dump all the other objects + for(objectMap::ConstIterator it=objMap.begin();it!=objMap.end();++it) + { + // Make sure it's not a table again + if(it.value().gettype() == "table") + continue; + + // Write the SQL string used to create this object to the output file + stream << (*it).getsql() << ";\n"; + } + + // Done + stream << "COMMIT;\n"; + file.close(); + return true; + } else { return false; } - dump_database(_db, cfile); - fclose(cfile); - return true; } bool DBBrowserDB::executeSQL ( const QString & statement, bool dirtyDB, bool logsql)