@@ -488,7 +488,7 @@ bool DBBrowserDB::close()
488
488
}
489
489
490
490
bool DBBrowserDB::dump (const QString& filename,
491
- const QStringList & tablesToDump,
491
+ const QStringList& tablesToDump,
492
492
bool insertColNames,
493
493
bool insertNewSyntx,
494
494
bool exportSchema,
@@ -501,6 +501,7 @@ bool DBBrowserDB::dump(const QString& filename,
501
501
{
502
502
QApplication::setOverrideCursor (Qt::WaitCursor);
503
503
504
+ // Count the total number of all records in all tables for the progress dialog
504
505
size_t numRecordsTotal = 0 , numRecordsCurrent = 0 ;
505
506
objectMap objMap = schemata[" main" ]; // We only always export the main database, not the attached databases
506
507
QList<sqlb::ObjectPtr> tables = objMap.values (" table" );
@@ -509,8 +510,8 @@ bool DBBrowserDB::dump(const QString& filename,
509
510
{
510
511
it.next ();
511
512
512
- // Remove the sqlite_stat1 table if there is one
513
- if (it.value ()->name () == " sqlite_stat1" || it.value ()->name () == " sqlite_sequence" )
513
+ // Remove the sqlite_stat1 and the sqlite_sequence tables if they exist. Also remove any tables which are not selected for export.
514
+ if (it.value ()->name () == " sqlite_stat1" || it.value ()->name () == " sqlite_sequence" || !tablesToDump. contains (it. value ()-> name ()) )
514
515
{
515
516
it.remove ();
516
517
} else {
@@ -533,140 +534,141 @@ bool DBBrowserDB::dump(const QString& filename,
533
534
// Put the SQL commands in a transaction block
534
535
stream << " BEGIN TRANSACTION;\n " ;
535
536
536
- // Loop through all tables first as they are required to generate views, indices etc. later
537
- for (auto it=tables.constBegin ();it!=tables.constEnd ();++it)
537
+ // First export the schema of all selected tables. We need to export the schema of all tables before we export the first INSERT statement to
538
+ // make sure foreign keys are working properly.
539
+ if (exportSchema)
538
540
{
539
- if (tablesToDump.indexOf ((*it)->name ()) == -1 )
540
- continue ;
541
-
542
- // Write the SQL string used to create this table to the output file
543
- if (exportSchema)
541
+ for (auto it : tables)
544
542
{
543
+ // Write the SQL string used to create this table to the output file
545
544
if (!keepOldSchema)
546
- stream << QString (" DROP TABLE IF EXISTS %1;\n " ).arg (sqlb::escapeIdentifier ((*it) ->name ()));
545
+ stream << QString (" DROP TABLE IF EXISTS %1;\n " ).arg (sqlb::escapeIdentifier (it ->name ()));
547
546
548
- if ((*it) ->fullyParsed ())
549
- stream << (*it) ->sql (" main" , true ) << " \n " ;
547
+ if (it ->fullyParsed ())
548
+ stream << it ->sql (" main" , true ) << " \n " ;
550
549
else
551
- stream << (*it)->originalSql () << " ;\n " ;
552
- }
553
-
554
- // If the user doesn't want the data to be exported skip the rest of the loop block here
555
- if (!exportData)
556
- continue ;
557
-
558
- // get columns
559
- QStringList cols ((*it).dynamicCast <sqlb::Table>()->fieldNames ());
560
-
561
- QString sQuery = QString (" SELECT * FROM %1;" ).arg (sqlb::escapeIdentifier ((*it)->name ()));
562
- QByteArray utf8Query = sQuery .toUtf8 ();
563
- sqlite3_stmt *stmt;
564
- QString lineSep (QString (" )%1\n " ).arg (insertNewSyntx?' ,' :' ;' ));
550
+ stream << it->originalSql () << " ;\n " ;
551
+ }
552
+ }
565
553
566
- int status = sqlite3_prepare_v2 (this ->_db , utf8Query.data (), utf8Query.size (), &stmt, NULL );
567
- if (SQLITE_OK == status)
554
+ // Now export the data as well
555
+ if (exportData)
556
+ {
557
+ for (auto it : tables)
568
558
{
569
- int columns = sqlite3_column_count (stmt);
570
- size_t counter = 0 ;
571
- qApp->processEvents ();
572
- while (sqlite3_step (stmt) == SQLITE_ROW)
573
- {
574
- if (counter) stream << lineSep;
559
+ // get columns
560
+ QStringList cols (it.dynamicCast <sqlb::Table>()->fieldNames ());
575
561
576
- if (!insertNewSyntx || !counter)
577
- {
578
- stream << " INSERT INTO " << sqlb::escapeIdentifier ((*it)->name ());
579
- if (insertColNames)
580
- stream << " (" << cols.join (" ," ) << " )" ;
581
- stream << " VALUES (" ;
582
- }
583
- else
584
- {
585
- stream << " (" ;
586
- }
562
+ QString sQuery = QString (" SELECT * FROM %1;" ).arg (sqlb::escapeIdentifier (it->name ()));
563
+ QByteArray utf8Query = sQuery .toUtf8 ();
564
+ sqlite3_stmt *stmt;
565
+ QString lineSep (QString (" )%1\n " ).arg (insertNewSyntx?' ,' :' ;' ));
587
566
588
- for (int i = 0 ; i < columns; ++i)
567
+ int status = sqlite3_prepare_v2 (this ->_db , utf8Query.data (), utf8Query.size (), &stmt, NULL );
568
+ if (SQLITE_OK == status)
569
+ {
570
+ int columns = sqlite3_column_count (stmt);
571
+ size_t counter = 0 ;
572
+ qApp->processEvents ();
573
+ while (sqlite3_step (stmt) == SQLITE_ROW)
589
574
{
590
- int fieldsize = sqlite3_column_bytes (stmt, i);
591
- int fieldtype = sqlite3_column_type (stmt, i);
592
- QByteArray bcontent (
593
- (const char *)sqlite3_column_blob (stmt, i),
594
- fieldsize);
575
+ if (counter) stream << lineSep;
595
576
596
- if (bcontent. left ( 2048 ). contains ( ' \0 ' )) // binary check
577
+ if (!insertNewSyntx || !counter)
597
578
{
598
- stream << QString (" X'%1'" ).arg (QString (bcontent.toHex ()));
579
+ stream << " INSERT INTO " << sqlb::escapeIdentifier (it->name ());
580
+ if (insertColNames)
581
+ stream << " (" << cols.join (" ," ) << " )" ;
582
+ stream << " VALUES (" ;
599
583
}
600
584
else
601
585
{
602
- switch (fieldtype)
586
+ stream << " (" ;
587
+ }
588
+
589
+ for (int i = 0 ; i < columns; ++i)
590
+ {
591
+ int fieldsize = sqlite3_column_bytes (stmt, i);
592
+ int fieldtype = sqlite3_column_type (stmt, i);
593
+ QByteArray bcontent (
594
+ (const char *)sqlite3_column_blob (stmt, i),
595
+ fieldsize);
596
+
597
+ if (bcontent.left (2048 ).contains (' \0 ' )) // binary check
603
598
{
604
- case SQLITE_TEXT:
605
- case SQLITE_BLOB:
606
- stream << " '" << bcontent.replace (" '" , " ''" ) << " '" ;
607
- break ;
608
- case SQLITE_NULL:
609
- stream << " NULL" ;
610
- break ;
611
- case SQLITE_FLOAT:
612
- if (bcontent.indexOf (" Inf" ) != -1 )
613
- stream << " '" << bcontent << " '" ;
614
- else
599
+ stream << QString (" X'%1'" ).arg (QString (bcontent.toHex ()));
600
+ }
601
+ else
602
+ {
603
+ switch (fieldtype)
604
+ {
605
+ case SQLITE_TEXT:
606
+ case SQLITE_BLOB:
607
+ stream << " '" << bcontent.replace (" '" , " ''" ) << " '" ;
608
+ break ;
609
+ case SQLITE_NULL:
610
+ stream << " NULL" ;
611
+ break ;
612
+ case SQLITE_FLOAT:
613
+ if (bcontent.indexOf (" Inf" ) != -1 )
614
+ stream << " '" << bcontent << " '" ;
615
+ else
616
+ stream << bcontent;
617
+ break ;
618
+ default :
615
619
stream << bcontent;
616
- break ;
617
- default :
618
- stream << bcontent;
620
+ }
619
621
}
622
+ if (i != columns - 1 )
623
+ stream << ' ,' ;
620
624
}
621
- if (i != columns - 1 )
622
- stream << ' ,' ;
623
- }
624
625
625
- progress.setValue (++numRecordsCurrent);
626
- if (counter % 5000 == 0 )
627
- qApp->processEvents ();
628
- counter++;
626
+ progress.setValue (++numRecordsCurrent);
627
+ if (counter % 5000 == 0 )
628
+ qApp->processEvents ();
629
+ counter++;
629
630
630
- if (progress.wasCanceled ())
631
- {
632
- sqlite3_finalize (stmt);
633
- file.close ();
634
- file.remove ();
635
- QApplication::restoreOverrideCursor ();
636
- return false ;
631
+ if (progress.wasCanceled ())
632
+ {
633
+ sqlite3_finalize (stmt);
634
+ file.close ();
635
+ file.remove ();
636
+ QApplication::restoreOverrideCursor ();
637
+ return false ;
638
+ }
637
639
}
640
+ if (counter > 0 ) stream << " );\n " ;
638
641
}
639
- if (counter > 0 ) stream << " ); \n " ;
642
+ sqlite3_finalize (stmt) ;
640
643
}
641
- sqlite3_finalize (stmt);
642
644
}
643
645
644
- // Now dump all the other objects (but only if we are exporting the schema)
646
+ // Finally export all objects other than tables
645
647
if (exportSchema)
646
648
{
647
- for (auto it= objMap. constBegin ();it!=objMap. constEnd ();++it )
649
+ for (auto it : objMap)
648
650
{
649
651
// Make sure it's not a table again
650
- if (it. value () ->type () == sqlb::Object::Types::Table)
652
+ if (it->type () == sqlb::Object::Types::Table)
651
653
continue ;
652
654
653
655
// If this object is based on a table (e.g. is an index for that table) it depends on the existence of this table.
654
656
// So if we didn't export the base table this depends on, don't export this object either.
655
- if (!(*it) ->baseTable ().isEmpty () && !tablesToDump.contains ((*it) ->baseTable ()))
657
+ if (!it ->baseTable ().isEmpty () && !tablesToDump.contains (it ->baseTable ()))
656
658
continue ;
657
659
658
660
// Write the SQL string used to create this object to the output file
659
- if (!(*it) ->originalSql ().isEmpty ())
661
+ if (!it ->originalSql ().isEmpty ())
660
662
{
661
663
if (!keepOldSchema)
662
664
stream << QString (" DROP %1 IF EXISTS %2;\n " )
663
- .arg (sqlb::Object::typeToString ((*it) ->type ()).toUpper ())
664
- .arg (sqlb::escapeIdentifier ((*it) ->name ()));
665
+ .arg (sqlb::Object::typeToString (it ->type ()).toUpper ())
666
+ .arg (sqlb::escapeIdentifier (it ->name ()));
665
667
666
- if ((*it) ->fullyParsed ())
667
- stream << (*it) ->sql (" main" , true ) << " \n " ;
668
+ if (it ->fullyParsed ())
669
+ stream << it ->sql (" main" , true ) << " \n " ;
668
670
else
669
- stream << (*it) ->originalSql () << " ;\n " ;
671
+ stream << it ->originalSql () << " ;\n " ;
670
672
}
671
673
}
672
674
}
0 commit comments