From feda8a7db8d1d7c5439aa8f8feef7cc0dd2b59a0 Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Fri, 27 Jul 2018 23:51:12 -0400 Subject: New upstream version 3.2.1+dfsg1 --- SQLiteStudio3/SQLiteStudio3.pro | 18 +- .../tst_completionhelpertest.cpp | 12 +- .../DsvFormatsTest/tst_dsvformatstesttest.cpp | 29 +- SQLiteStudio3/Tests/LexerTest/LexerTest.pro | 32 + SQLiteStudio3/Tests/LexerTest/tst_lexertest.cpp | 66 + SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp | 104 +- .../SelectResolverTest/tst_selectresolvertest.cpp | 43 + .../TableModifierTest/tst_tablemodifiertest.cpp | 132 +- SQLiteStudio3/Tests/TestUtils/TestUtils.pro | 6 +- SQLiteStudio3/Tests/TestUtils/configmock.cpp | 40 + SQLiteStudio3/Tests/TestUtils/configmock.h | 9 + SQLiteStudio3/Tests/TestUtils/dbmanagermock.cpp | 2 +- SQLiteStudio3/Tests/TestUtils/dbmanagermock.h | 6 +- .../Tests/TestUtils/extensionmanagermock.cpp | 19 + .../Tests/TestUtils/extensionmanagermock.h | 17 + SQLiteStudio3/Tests/TestUtils/mocks.cpp | 2 + SQLiteStudio3/Tests/Tests.pro | 3 +- SQLiteStudio3/Tests/UtilsTest/tst_utilssqltest.cpp | 11 + .../UpdateSQLiteStudio.exe.manifest | 19 - .../UpdateSQLiteStudio/UpdateSQLiteStudio.pro | 41 - SQLiteStudio3/UpdateSQLiteStudio/main.cpp | 49 - .../UpdateSQLiteStudio/windows.manifest.autosave | 19 - SQLiteStudio3/UpdateSQLiteStudio/windows.rc | 3 - SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt | 69 + SQLiteStudio3/coreSQLiteStudio/Info.plist | 31 +- SQLiteStudio3/coreSQLiteStudio/TODO.txt | 44 - .../coreSQLiteStudio/common/bistrhash.cpp | 1 + SQLiteStudio3/coreSQLiteStudio/common/global.h | 2 +- .../coreSQLiteStudio/common/lazytrigger.cpp | 37 + .../coreSQLiteStudio/common/lazytrigger.h | 34 + SQLiteStudio3/coreSQLiteStudio/common/objectpool.h | 7 +- SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h | 4 +- SQLiteStudio3/coreSQLiteStudio/common/utils.cpp | 102 +- SQLiteStudio3/coreSQLiteStudio/common/utils.h | 10 + .../coreSQLiteStudio/common/utils_sql.cpp | 45 +- .../coreSQLiteStudio/common/valuelocker.h | 44 + .../coreSQLiteStudio/common/xmldeserializer.cpp | 84 + .../coreSQLiteStudio/common/xmldeserializer.h | 31 + .../coreSQLiteStudio/completioncomparer.cpp | 6 +- .../coreSQLiteStudio/completionhelper.cpp | 56 +- .../coreSQLiteStudio/config_builder/cfgmain.cpp | 54 + .../coreSQLiteStudio/config_builder/cfgmain.h | 15 + .../coreSQLiteStudio/coreSQLiteStudio.pro | 33 +- .../coreSQLiteStudio/coreSQLiteStudio.qrc | 5 +- SQLiteStudio3/coreSQLiteStudio/csvformat.cpp | 15 + SQLiteStudio3/coreSQLiteStudio/csvformat.h | 4 + SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp | 214 +- SQLiteStudio3/coreSQLiteStudio/csvserializer.h | 3 - SQLiteStudio3/coreSQLiteStudio/datatype.cpp | 4 +- SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp | 50 +- SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h | 4 + SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h | 69 +- SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h | 40 +- SQLiteStudio3/coreSQLiteStudio/db/db.cpp | 2 + SQLiteStudio3/coreSQLiteStudio/db/db.h | 35 +- SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp | 5 + SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h | 2 + SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp | 12 + SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h | 2 + .../coreSQLiteStudio/db/queryexecutor.cpp | 145 +- SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h | 144 + .../queryexecutorsteps/queryexecutoraddrowids.cpp | 32 +- .../db/queryexecutorsteps/queryexecutoraddrowids.h | 2 + .../queryexecutorsteps/queryexecutorcellsize.cpp | 8 +- .../db/queryexecutorsteps/queryexecutorcolumns.cpp | 5 +- .../queryexecutordatasources.cpp | 2 +- .../db/queryexecutorsteps/queryexecutorexecute.cpp | 6 +- .../db/queryexecutorsteps/queryexecutorstep.cpp | 2 +- .../db/queryexecutorsteps/queryexecutorstep.h | 2 +- SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp | 5 +- SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h | 2 +- .../coreSQLiteStudio/db/stdsqlite3driver.h | 5 +- .../coreSQLiteStudio/dbversionconverter.cpp | 32 +- .../coreSQLiteStudio/dbversionconverter.h | 15 + .../coreSQLiteStudio/diff/diff_match_patch.cpp | 28 +- .../coreSQLiteStudio/impl/dbattacherimpl.cpp | 8 +- SQLiteStudio3/coreSQLiteStudio/importworker.cpp | 5 +- .../coreSQLiteStudio/licenses/fugue_icons.txt | 65 - SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt | 14 +- SQLiteStudio3/coreSQLiteStudio/licenses/mit.txt | 24 + .../parser/ast/sqlitecreateindex.cpp | 2 +- .../parser/ast/sqlitecreatetable.cpp | 46 +- .../parser/ast/sqlitecreatetrigger.cpp | 4 +- .../coreSQLiteStudio/parser/ast/sqliteexpr.cpp | 37 +- .../coreSQLiteStudio/parser/ast/sqliteexpr.h | 2 + .../coreSQLiteStudio/parser/ast/sqliteinsert.cpp | 14 +- .../coreSQLiteStudio/parser/ast/sqliteinsert.h | 4 +- .../coreSQLiteStudio/parser/ast/sqliteselect.cpp | 66 +- .../coreSQLiteStudio/parser/ast/sqliteselect.h | 4 + .../parser/ast/sqlitestatement.cpp | 30 +- .../coreSQLiteStudio/parser/ast/sqlitestatement.h | 2 +- .../coreSQLiteStudio/parser/ast/sqliteupdate.cpp | 44 +- .../coreSQLiteStudio/parser/ast/sqliteupdate.h | 4 +- .../coreSQLiteStudio/parser/ast/sqliteupsert.cpp | 152 + .../coreSQLiteStudio/parser/ast/sqliteupsert.h | 35 + SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp | 2 + SQLiteStudio3/coreSQLiteStudio/parser/lemon.c | 5044 +++++++++++++++ SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp | 2 +- .../coreSQLiteStudio/parser/lexer_low_lev.cpp | 30 +- .../coreSQLiteStudio/parser/lexer_low_lev.h | 1 + SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp | 6 +- SQLiteStudio3/coreSQLiteStudio/parser/parser.h | 2 +- .../coreSQLiteStudio/parser/parser_helper_stubs.h | 3 +- .../coreSQLiteStudio/parser/parsercontext.cpp | 4 +- .../coreSQLiteStudio/parser/run_lemon.bat | 8 + .../coreSQLiteStudio/parser/sqlite2_parse.cpp | 90 +- .../coreSQLiteStudio/parser/sqlite2_parse.y | 36 +- .../coreSQLiteStudio/parser/sqlite3_parse.cpp | 5507 ++++++++-------- .../coreSQLiteStudio/parser/sqlite3_parse.h | 42 +- .../coreSQLiteStudio/parser/sqlite3_parse.y | 131 +- .../parser/statementtokenbuilder.cpp | 4 +- .../parser/statementtokenbuilder.h | 2 +- SQLiteStudio3/coreSQLiteStudio/parser/token.cpp | 22 +- SQLiteStudio3/coreSQLiteStudio/parser/token.h | 8 +- SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h | 2 +- .../plugins/pluginsymbolresolver.cpp | 8 +- .../plugins/populatedictionary.cpp | 2 +- .../coreSQLiteStudio/plugins/scriptingqt.cpp | 2 +- .../plugins/sqlformatterplugin.cpp | 2 +- .../coreSQLiteStudio/plugins/uiconfiguredplugin.h | 2 +- SQLiteStudio3/coreSQLiteStudio/populateworker.cpp | 7 + SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp | 4 +- SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp | 28 +- SQLiteStudio3/coreSQLiteStudio/schemaresolver.h | 2 +- SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp | 87 +- SQLiteStudio3/coreSQLiteStudio/selectresolver.h | 10 +- .../coreSQLiteStudio/services/bugreporter.cpp | 202 - .../coreSQLiteStudio/services/bugreporter.h | 62 - SQLiteStudio3/coreSQLiteStudio/services/config.h | 14 + .../coreSQLiteStudio/services/dbmanager.h | 3 +- .../coreSQLiteStudio/services/functionmanager.h | 1 + .../services/impl/collationmanagerimpl.cpp | 4 +- .../coreSQLiteStudio/services/impl/configimpl.cpp | 311 +- .../coreSQLiteStudio/services/impl/configimpl.h | 20 +- .../services/impl/dbmanagerimpl.cpp | 13 +- .../coreSQLiteStudio/services/impl/dbmanagerimpl.h | 2 +- .../services/impl/functionmanagerimpl.cpp | 8 +- .../services/impl/pluginmanagerimpl.cpp | 28 +- .../services/impl/sqliteextensionmanagerimpl.cpp | 70 + .../services/impl/sqliteextensionmanagerimpl.h | 23 + .../coreSQLiteStudio/services/pluginmanager.h | 6 +- .../services/sqliteextensionmanager.h | 34 + .../coreSQLiteStudio/services/updatemanager.cpp | 1034 +-- .../coreSQLiteStudio/services/updatemanager.h | 102 +- SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp | 14 +- SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp | 52 +- SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h | 17 +- SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp | 95 +- SQLiteStudio3/coreSQLiteStudio/tablemodifier.h | 2 + .../translations/coreSQLiteStudio_de.qm | Bin 45651 -> 34589 bytes .../translations/coreSQLiteStudio_de.ts | 318 +- .../translations/coreSQLiteStudio_es.ts | 378 +- .../translations/coreSQLiteStudio_fr.qm | Bin 41388 -> 31530 bytes .../translations/coreSQLiteStudio_fr.ts | 318 +- .../translations/coreSQLiteStudio_it.ts | 378 +- .../translations/coreSQLiteStudio_pl.qm | Bin 43087 -> 34859 bytes .../translations/coreSQLiteStudio_pl.ts | 318 +- .../translations/coreSQLiteStudio_pt_BR.qm | Bin 2939 -> 2828 bytes .../translations/coreSQLiteStudio_pt_BR.ts | 373 +- .../translations/coreSQLiteStudio_ro_RO.qm | Bin 0 -> 30 bytes .../translations/coreSQLiteStudio_ro_RO.ts | 1146 ++++ .../translations/coreSQLiteStudio_ru.qm | Bin 42098 -> 32776 bytes .../translations/coreSQLiteStudio_ru.ts | 320 +- .../translations/coreSQLiteStudio_sk.qm | Bin 6146 -> 5124 bytes .../translations/coreSQLiteStudio_sk.ts | 367 +- .../translations/coreSQLiteStudio_zh_CN.qm | Bin 107 -> 16 bytes .../translations/coreSQLiteStudio_zh_CN.ts | 373 +- SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp | 4 +- SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp | 4 +- SQLiteStudio3/create_source_dist.sh | 5 +- SQLiteStudio3/guiSQLiteStudio/.DS_Store | Bin 0 -> 8196 bytes SQLiteStudio3/guiSQLiteStudio/common/bindparam.h | 15 + .../guiSQLiteStudio/common/datawidgetmapper.cpp | 2 + .../guiSQLiteStudio/common/extactioncontainer.cpp | 11 +- .../guiSQLiteStudio/common/extactioncontainer.h | 1 + .../guiSQLiteStudio/common/userinputfilter.cpp | 17 +- .../guiSQLiteStudio/common/userinputfilter.h | 6 +- SQLiteStudio3/guiSQLiteStudio/configmapper.cpp | 16 +- .../constraints/columndefaultpanel.cpp | 14 +- .../constraints/columnforeignkeypanel.cpp | 2 +- .../constraints/columnprimarykeypanel.cpp | 6 - .../constraints/tableforeignkeypanel.cpp | 16 +- .../constraints/tablepkanduniquepanel.cpp | 11 +- .../constraints/tableprimarykeypanel.cpp | 3 +- .../guiSQLiteStudio/datagrid/sqlqueryitem.cpp | 4 +- .../datagrid/sqlqueryitemdelegate.cpp | 64 +- .../guiSQLiteStudio/datagrid/sqlquerymodel.cpp | 138 +- .../guiSQLiteStudio/datagrid/sqlquerymodel.h | 53 +- .../datagrid/sqlquerymodelcolumn.cpp | 10 +- .../guiSQLiteStudio/datagrid/sqlqueryview.cpp | 237 +- .../guiSQLiteStudio/datagrid/sqlqueryview.h | 26 +- .../guiSQLiteStudio/datagrid/sqltablemodel.cpp | 95 +- .../guiSQLiteStudio/datagrid/sqltablemodel.h | 8 + SQLiteStudio3/guiSQLiteStudio/dataview.cpp | 292 +- SQLiteStudio3/guiSQLiteStudio/dataview.h | 19 +- SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp | 2 +- SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp | 4 +- SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp | 309 +- SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h | 30 +- .../guiSQLiteStudio/dbtree/dbtreemodel.cpp | 44 +- SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h | 2 +- .../guiSQLiteStudio/dbtree/dbtreeview.cpp | 2 +- .../guiSQLiteStudio/dialogs/aboutdialog.ui | 4 +- .../guiSQLiteStudio/dialogs/bindparamsdialog.cpp | 133 + .../guiSQLiteStudio/dialogs/bindparamsdialog.h | 41 + .../guiSQLiteStudio/dialogs/bindparamsdialog.ui | 97 + .../guiSQLiteStudio/dialogs/bugdialog.cpp | 219 - SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.h | 42 - SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.ui | 208 - .../dialogs/bugreportlogindialog.cpp | 94 - .../guiSQLiteStudio/dialogs/bugreportlogindialog.h | 40 - .../dialogs/bugreportlogindialog.ui | 132 - .../guiSQLiteStudio/dialogs/columndialog.cpp | 43 +- .../guiSQLiteStudio/dialogs/columndialog.h | 3 + .../guiSQLiteStudio/dialogs/configdialog.cpp | 43 +- .../guiSQLiteStudio/dialogs/configdialog.ui | 106 +- SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp | 11 +- .../guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp | 2 +- .../guiSQLiteStudio/dialogs/execfromfiledialog.cpp | 76 + .../guiSQLiteStudio/dialogs/execfromfiledialog.h | 32 + .../guiSQLiteStudio/dialogs/execfromfiledialog.ui | 125 + .../guiSQLiteStudio/dialogs/exportdialog.cpp | 79 +- .../guiSQLiteStudio/dialogs/exportdialog.h | 4 + .../dialogs/fileexecerrorsdialog.cpp | 35 + .../guiSQLiteStudio/dialogs/fileexecerrorsdialog.h | 26 + .../dialogs/fileexecerrorsdialog.ui | 132 + .../guiSQLiteStudio/dialogs/importdialog.cpp | 50 +- .../guiSQLiteStudio/dialogs/importdialog.h | 3 + .../guiSQLiteStudio/dialogs/indexdialog.cpp | 4 +- .../guiSQLiteStudio/dialogs/indexdialog.ui | 4 +- .../guiSQLiteStudio/dialogs/newversiondialog.cpp | 11 +- .../guiSQLiteStudio/dialogs/newversiondialog.ui | 7 +- .../guiSQLiteStudio/dialogs/populatedialog.cpp | 72 +- .../guiSQLiteStudio/dialogs/populatedialog.h | 10 +- .../guiSQLiteStudio/dialogs/triggerdialog.cpp | 6 +- .../guiSQLiteStudio/dialogs/triggerdialog.ui | 6 + SQLiteStudio3/guiSQLiteStudio/formmanager.cpp | 4 +- SQLiteStudio3/guiSQLiteStudio/formview.cpp | 12 +- SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro | 34 +- SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.qrc | 2 + SQLiteStudio3/guiSQLiteStudio/iconmanager.cpp | 4 +- SQLiteStudio3/guiSQLiteStudio/iconmanager.h | 10 + SQLiteStudio3/guiSQLiteStudio/icons.qrc | 10 + SQLiteStudio3/guiSQLiteStudio/img/brick.png | Bin 0 -> 452 bytes SQLiteStudio3/guiSQLiteStudio/img/brick_add.png | Bin 0 -> 729 bytes SQLiteStudio3/guiSQLiteStudio/img/brick_delete.png | Bin 0 -> 745 bytes SQLiteStudio3/guiSQLiteStudio/img/brick_error.png | Bin 0 -> 798 bytes SQLiteStudio3/guiSQLiteStudio/img/brick_folder.png | Bin 0 -> 735 bytes .../guiSQLiteStudio/img/execute_sql_from_file.png | Bin 0 -> 793 bytes SQLiteStudio3/guiSQLiteStudio/img/save_file.png | Bin 0 -> 507 bytes SQLiteStudio3/guiSQLiteStudio/img/zoom.png | Bin 0 -> 692 bytes SQLiteStudio3/guiSQLiteStudio/img/zoom_in.png | Bin 0 -> 725 bytes SQLiteStudio3/guiSQLiteStudio/img/zoom_out.png | Bin 0 -> 708 bytes SQLiteStudio3/guiSQLiteStudio/license.txt | 502 -- SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp | 148 +- SQLiteStudio3/guiSQLiteStudio/mainwindow.h | 13 +- SQLiteStudio3/guiSQLiteStudio/mdiarea.cpp | 16 +- .../guiSQLiteStudio/multieditor/multieditor.cpp | 145 +- .../guiSQLiteStudio/multieditor/multieditor.h | 18 +- .../multieditor/multieditorbool.cpp | 10 +- .../guiSQLiteStudio/multieditor/multieditorbool.h | 2 +- .../multieditor/multieditordate.cpp | 10 +- .../guiSQLiteStudio/multieditor/multieditordate.h | 3 +- .../multieditor/multieditordatetime.cpp | 12 +- .../multieditor/multieditordatetime.h | 2 +- .../guiSQLiteStudio/multieditor/multieditorhex.cpp | 12 +- .../guiSQLiteStudio/multieditor/multieditorhex.h | 2 +- .../multieditor/multieditornumeric.cpp | 12 +- .../multieditor/multieditornumeric.h | 2 +- .../multieditor/multieditortext.cpp | 11 +- .../guiSQLiteStudio/multieditor/multieditortext.h | 2 +- .../multieditor/multieditortime.cpp | 10 +- .../guiSQLiteStudio/multieditor/multieditortime.h | 3 +- .../multieditor/multieditorwidget.cpp | 12 +- .../multieditor/multieditorwidget.h | 7 +- .../multieditor/multieditorwidgetplugin.h | 1 + SQLiteStudio3/guiSQLiteStudio/selectabledbmodel.h | 2 +- SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp | 100 +- SQLiteStudio3/guiSQLiteStudio/sqleditor.h | 17 +- .../guiSQLiteStudio/sqlitesyntaxhighlighter.cpp | 8 +- SQLiteStudio3/guiSQLiteStudio/statusfield.cpp | 6 +- SQLiteStudio3/guiSQLiteStudio/taskbar.cpp | 24 +- .../translations/guiSQLiteStudio_de.qm | Bin 131563 -> 117878 bytes .../translations/guiSQLiteStudio_de.ts | 2065 +++--- .../translations/guiSQLiteStudio_es.ts | 1962 +++--- .../translations/guiSQLiteStudio_fr.qm | Bin 136435 -> 123779 bytes .../translations/guiSQLiteStudio_fr.ts | 2399 ++++--- .../translations/guiSQLiteStudio_it.ts | 1954 +++--- .../translations/guiSQLiteStudio_pl.qm | Bin 163698 -> 170072 bytes .../translations/guiSQLiteStudio_pl.ts | 2049 +++--- .../translations/guiSQLiteStudio_pt_BR.ts | 1962 +++--- .../translations/guiSQLiteStudio_ro_RO.qm | Bin 0 -> 30 bytes .../translations/guiSQLiteStudio_ro_RO.ts | 6612 ++++++++++++++++++++ .../translations/guiSQLiteStudio_ru.qm | Bin 155959 -> 152875 bytes .../translations/guiSQLiteStudio_ru.ts | 2173 ++++--- .../translations/guiSQLiteStudio_sk.qm | Bin 96699 -> 84002 bytes .../translations/guiSQLiteStudio_sk.ts | 2036 +++--- .../translations/guiSQLiteStudio_zh_CN.qm | Bin 52503 -> 43220 bytes .../translations/guiSQLiteStudio_zh_CN.ts | 2075 +++--- SQLiteStudio3/guiSQLiteStudio/uidebug.cpp | 4 +- SQLiteStudio3/guiSQLiteStudio/uiutils.h | 2 + SQLiteStudio3/guiSQLiteStudio/widgetresizer.cpp | 5 + SQLiteStudio3/guiSQLiteStudio/widgetresizer.h | 1 + .../windows/bugreporthistorywindow.cpp | 155 - .../windows/bugreporthistorywindow.h | 65 - .../windows/bugreporthistorywindow.ui | 55 - .../guiSQLiteStudio/windows/collationseditor.cpp | 8 +- .../guiSQLiteStudio/windows/collationseditor.h | 2 +- .../guiSQLiteStudio/windows/collationseditor.ui | 6 +- .../windows/collationseditormodel.cpp | 22 +- .../windows/collationseditormodel.h | 2 +- .../guiSQLiteStudio/windows/constrainttabmodel.cpp | 8 +- .../guiSQLiteStudio/windows/ddlhistorywindow.cpp | 2 +- .../guiSQLiteStudio/windows/editorwindow.cpp | 98 +- .../guiSQLiteStudio/windows/editorwindow.h | 25 +- .../guiSQLiteStudio/windows/editorwindow.ui | 8 +- .../guiSQLiteStudio/windows/functionseditor.cpp | 10 +- .../guiSQLiteStudio/windows/functionseditor.ui | 18 +- .../windows/functionseditormodel.cpp | 18 +- .../windows/sqliteextensioneditor.cpp | 439 ++ .../windows/sqliteextensioneditor.h | 94 + .../windows/sqliteextensioneditor.ui | 191 + .../windows/sqliteextensioneditormodel.cpp | 234 + .../windows/sqliteextensioneditormodel.h | 65 + .../windows/tableconstraintsmodel.cpp | 8 +- .../windows/tablestructuremodel.cpp | 10 +- .../guiSQLiteStudio/windows/tablewindow.cpp | 18 +- .../guiSQLiteStudio/windows/viewwindow.cpp | 14 +- SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h | 1 + .../guiSQLiteStudio/windows/viewwindow.ui | 8 +- SQLiteStudio3/lang.tcl | 17 +- SQLiteStudio3/plugins.pri | 2 + SQLiteStudio3/qt_package.xml | 10 + SQLiteStudio3/sqlitestudio/installscript.qs | 64 + SQLiteStudio3/sqlitestudio/main.cpp | 67 +- SQLiteStudio3/sqlitestudio/package.xml | 17 + SQLiteStudio3/sqlitestudio/register_file_types.ui | 64 + .../singleapplication/singleapplication.cpp | 472 ++ .../singleapplication/singleapplication.h | 135 + .../singleapplication/singleapplication_p.h | 85 + SQLiteStudio3/sqlitestudio/sqlitestudio.pro | 43 +- SQLiteStudio3/sqlitestudio/sqlitestudio.qrc | 2 + .../sqlitestudio/translations/sqlitestudio_de.qm | Bin 2251 -> 2198 bytes .../sqlitestudio/translations/sqlitestudio_de.ts | 34 +- .../sqlitestudio/translations/sqlitestudio_es.ts | 36 +- .../sqlitestudio/translations/sqlitestudio_fr.qm | Bin 1824 -> 2323 bytes .../sqlitestudio/translations/sqlitestudio_fr.ts | 53 +- .../sqlitestudio/translations/sqlitestudio_it.ts | 36 +- .../sqlitestudio/translations/sqlitestudio_pl.qm | Bin 2450 -> 2810 bytes .../sqlitestudio/translations/sqlitestudio_pl.ts | 6 +- .../translations/sqlitestudio_pt_BR.ts | 36 +- .../translations/sqlitestudio_ro_RO.qm | Bin 0 -> 30 bytes .../translations/sqlitestudio_ro_RO.ts | 82 + .../sqlitestudio/translations/sqlitestudio_ru.qm | Bin 3002 -> 2949 bytes .../sqlitestudio/translations/sqlitestudio_ru.ts | 34 +- .../sqlitestudio/translations/sqlitestudio_sk.qm | Bin 834 -> 783 bytes .../sqlitestudio/translations/sqlitestudio_sk.ts | 34 +- .../translations/sqlitestudio_zh_CN.qm | Bin 406 -> 361 bytes .../translations/sqlitestudio_zh_CN.ts | 34 +- SQLiteStudio3/sqlitestudiocli/cli.cpp | 2 +- SQLiteStudio3/sqlitestudiocli/clicommandsyntax.cpp | 12 +- SQLiteStudio3/sqlitestudiocli/clicompleter.cpp | 6 +- SQLiteStudio3/sqlitestudiocli/climsghandler.cpp | 2 + SQLiteStudio3/sqlitestudiocli/cliutils.cpp | 4 +- .../sqlitestudiocli/commands/clicommand.cpp | 18 +- .../sqlitestudiocli/commands/clicommanddblist.cpp | 4 +- .../sqlitestudiocli/commands/clicommanddir.cpp | 2 +- .../sqlitestudiocli/commands/clicommandfactory.cpp | 2 +- .../sqlitestudiocli/commands/clicommandhelp.cpp | 2 +- .../sqlitestudiocli/commands/clicommandhistory.cpp | 2 +- .../sqlitestudiocli/commands/clicommandsql.cpp | 32 +- .../sqlitestudiocli/commands/clicommandtables.cpp | 4 +- .../sqlitestudiocli/commands/clicommandtree.cpp | 14 +- SQLiteStudio3/sqlitestudiocli/main.cpp | 7 - SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.pro | 8 +- SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.qrc | 2 + .../translations/sqlitestudiocli_ro_RO.qm | Bin 0 -> 30 bytes .../translations/sqlitestudiocli_ro_RO.ts | 788 +++ 378 files changed, 36997 insertions(+), 17080 deletions(-) create mode 100644 SQLiteStudio3/Tests/LexerTest/LexerTest.pro create mode 100644 SQLiteStudio3/Tests/LexerTest/tst_lexertest.cpp create mode 100644 SQLiteStudio3/Tests/TestUtils/extensionmanagermock.cpp create mode 100644 SQLiteStudio3/Tests/TestUtils/extensionmanagermock.h delete mode 100644 SQLiteStudio3/UpdateSQLiteStudio/UpdateSQLiteStudio.exe.manifest delete mode 100644 SQLiteStudio3/UpdateSQLiteStudio/UpdateSQLiteStudio.pro delete mode 100644 SQLiteStudio3/UpdateSQLiteStudio/main.cpp delete mode 100644 SQLiteStudio3/UpdateSQLiteStudio/windows.manifest.autosave delete mode 100644 SQLiteStudio3/UpdateSQLiteStudio/windows.rc create mode 100644 SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.cpp create mode 100644 SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.h create mode 100644 SQLiteStudio3/coreSQLiteStudio/common/valuelocker.h create mode 100644 SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.cpp create mode 100644 SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.h create mode 100644 SQLiteStudio3/coreSQLiteStudio/licenses/mit.txt create mode 100644 SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp create mode 100644 SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h create mode 100644 SQLiteStudio3/coreSQLiteStudio/parser/lemon.c create mode 100644 SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.bat delete mode 100644 SQLiteStudio3/coreSQLiteStudio/services/bugreporter.cpp delete mode 100644 SQLiteStudio3/coreSQLiteStudio/services/bugreporter.h create mode 100644 SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.cpp create mode 100644 SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.h create mode 100644 SQLiteStudio3/coreSQLiteStudio/services/sqliteextensionmanager.h create mode 100644 SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.qm create mode 100644 SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.ts create mode 100644 SQLiteStudio3/guiSQLiteStudio/.DS_Store create mode 100644 SQLiteStudio3/guiSQLiteStudio/common/bindparam.h create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.cpp create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.h create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.ui delete mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.cpp delete mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.h delete mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.ui delete mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.cpp delete mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.h delete mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.ui create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.cpp create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.h create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.ui create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.cpp create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.h create mode 100644 SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.ui create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/brick.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/brick_add.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/brick_delete.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/brick_error.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/brick_folder.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/execute_sql_from_file.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/save_file.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/zoom.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/zoom_in.png create mode 100644 SQLiteStudio3/guiSQLiteStudio/img/zoom_out.png delete mode 100644 SQLiteStudio3/guiSQLiteStudio/license.txt create mode 100644 SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ro_RO.qm create mode 100644 SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ro_RO.ts delete mode 100644 SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.cpp delete mode 100644 SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.h delete mode 100644 SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.ui create mode 100644 SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp create mode 100644 SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h create mode 100644 SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.ui create mode 100644 SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.cpp create mode 100644 SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.h create mode 100644 SQLiteStudio3/qt_package.xml create mode 100644 SQLiteStudio3/sqlitestudio/installscript.qs create mode 100644 SQLiteStudio3/sqlitestudio/package.xml create mode 100644 SQLiteStudio3/sqlitestudio/register_file_types.ui create mode 100644 SQLiteStudio3/sqlitestudio/singleapplication/singleapplication.cpp create mode 100644 SQLiteStudio3/sqlitestudio/singleapplication/singleapplication.h create mode 100644 SQLiteStudio3/sqlitestudio/singleapplication/singleapplication_p.h create mode 100644 SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ro_RO.qm create mode 100644 SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ro_RO.ts create mode 100644 SQLiteStudio3/sqlitestudiocli/translations/sqlitestudiocli_ro_RO.qm create mode 100644 SQLiteStudio3/sqlitestudiocli/translations/sqlitestudiocli_ro_RO.ts (limited to 'SQLiteStudio3') diff --git a/SQLiteStudio3/SQLiteStudio3.pro b/SQLiteStudio3/SQLiteStudio3.pro index 3d19c5c..7a6a433 100644 --- a/SQLiteStudio3/SQLiteStudio3.pro +++ b/SQLiteStudio3/SQLiteStudio3.pro @@ -1,5 +1,15 @@ TEMPLATE = subdirs +REQ_QT_MAJOR = 5 +REQ_QT_MINOR = 3 +REQ_QT_PATCH = 0 + +lessThan(QT_MAJOR_VERSION, $$REQ_QT_MAJOR)|lessThan(QT_MINOR_VERSION, $$REQ_QT_MINOR)|lessThan(QT_MINOR_VERSION, $$REQ_QT_PATCH) { + error($$sprintf("Required Qt version is at least %1.%2.%3. This Qt version is %4.%5.%6.", \ + $$REQ_QT_MAJOR, $$REQ_QT_MINOR, $$REQ_QT_PATCH, \ + $$QT_MAJOR_VERSION, $$QT_MINOR_VERSION, $$QT_PATCH_VERSION)) +} + core.subdir = coreSQLiteStudio tests.subdir = Tests @@ -14,9 +24,6 @@ cli.depends = core gui_app.subdir = sqlitestudio gui_app.depends = gui -update_app.subdir = UpdateSQLiteStudio -update_app.depends = core - SUBDIRS += \ core \ gui \ @@ -29,11 +36,6 @@ if(contains(DEFINES,tests)) { OUTPUT_DIR_NAME = output -win32: { - SUBDIRS += update_app -} - - macx: { bundle.commands = sh $$PWD/create_macosx_bundle.sh $$PWD/../$$OUTPUT_DIR_NAME $$QMAKE_QMAKE dmg.commands = sh $$PWD/create_macosx_bundle.sh $$PWD/../$$OUTPUT_DIR_NAME $$QMAKE_QMAKE dmg diff --git a/SQLiteStudio3/Tests/CompletionHelperTest/tst_completionhelpertest.cpp b/SQLiteStudio3/Tests/CompletionHelperTest/tst_completionhelpertest.cpp index fc21a55..fd5611a 100644 --- a/SQLiteStudio3/Tests/CompletionHelperTest/tst_completionhelpertest.cpp +++ b/SQLiteStudio3/Tests/CompletionHelperTest/tst_completionhelpertest.cpp @@ -63,7 +63,7 @@ CompletionHelperTest::CompletionHelperTest() QList CompletionHelperTest::getEntryList(QList tokens) { QList entries; - foreach (ExpectedTokenPtr expectedToken, tokens) + for (ExpectedTokenPtr expectedToken : tokens) entries += expectedToken.data(); return entries; @@ -72,7 +72,7 @@ QList CompletionHelperTest::getEntryList(QList CompletionHelperTest::getTypeList(QList tokens) { QSet entries; - foreach (ExpectedTokenPtr expectedToken, tokens) + for (ExpectedTokenPtr expectedToken : tokens) entries += expectedToken->type; return entries; @@ -101,7 +101,7 @@ bool CompletionHelperTest::contains(const QList &tokens, Expec int CompletionHelperTest::find(const QList &tokens, ExpectedToken::Type type) { int i = 0; - foreach (ExpectedTokenPtr token, tokens) + for (ExpectedTokenPtr token : tokens) { if (token->type == type) return i; @@ -114,7 +114,7 @@ int CompletionHelperTest::find(const QList &tokens, ExpectedTo int CompletionHelperTest::find(const QList &tokens, ExpectedToken::Type type, const QString &value) { int i = -1; - foreach (ExpectedTokenPtr token, tokens) + for (ExpectedTokenPtr token : tokens) { i++; if (token->type != type) @@ -129,7 +129,7 @@ int CompletionHelperTest::find(const QList &tokens, ExpectedTo int CompletionHelperTest::find(const QList &tokens, ExpectedToken::Type type, const QString &value, const QString &prefix) { int i = -1; - foreach (ExpectedTokenPtr token, tokens) + for (ExpectedTokenPtr token : tokens) { i++; if (token->type != type) @@ -147,7 +147,7 @@ int CompletionHelperTest::find(const QList &tokens, ExpectedTo int CompletionHelperTest::find(const QList &tokens, ExpectedToken::Type type, const QString &value, const QString &prefix, const QString &contextInfo) { int i = -1; - foreach (ExpectedTokenPtr token, tokens) + for (ExpectedTokenPtr token : tokens) { i++; if (token->type != type) diff --git a/SQLiteStudio3/Tests/DsvFormatsTest/tst_dsvformatstesttest.cpp b/SQLiteStudio3/Tests/DsvFormatsTest/tst_dsvformatstesttest.cpp index bd55d53..903e6f6 100644 --- a/SQLiteStudio3/Tests/DsvFormatsTest/tst_dsvformatstesttest.cpp +++ b/SQLiteStudio3/Tests/DsvFormatsTest/tst_dsvformatstesttest.cpp @@ -14,7 +14,7 @@ class DsvFormatsTestTest : public QObject public: DsvFormatsTestTest(); - private: +private: QString toString(const QList& input); QList sampleData; @@ -27,6 +27,7 @@ class DsvFormatsTestTest : public QObject void testTsv1(); void testTsv2(); void testCsv1(); + void testCsvPerformance(); }; DsvFormatsTestTest::DsvFormatsTestTest() @@ -79,7 +80,7 @@ void DsvFormatsTestTest::testTsv1() QString result = TsvSerializer::serialize(sampleData); QString common = ""; - int i; + int i = 0; if (result != sampleTsv) { int lgt = qMax(result.length(), sampleTsv.length()); @@ -105,6 +106,30 @@ void DsvFormatsTestTest::testCsv1() QVERIFY(result.first().size() == 2); } +void DsvFormatsTestTest::testCsvPerformance() +{ + QString input; + for (int i = 0; i < 10000; i++) + input += "abc,d,g,\"jkl\nh\",mno\r\n"; + + QTemporaryFile theFile; + theFile.open(); + theFile.write(input.toLatin1()); + theFile.seek(0); + QTextStream stream(&theFile); + + QTime timer; + timer.start(); + QList result = CsvSerializer::deserialize(stream, CsvFormat::DEFAULT); + int time = timer.elapsed(); + + QVERIFY(result.size() == 10000); + QVERIFY(result.first().size() == 5); + QVERIFY(result.last().size() == 5); + + qDebug() << "Deserialization time:" << time; +} + QTEST_APPLESS_MAIN(DsvFormatsTestTest) #include "tst_dsvformatstesttest.moc" diff --git a/SQLiteStudio3/Tests/LexerTest/LexerTest.pro b/SQLiteStudio3/Tests/LexerTest/LexerTest.pro new file mode 100644 index 0000000..a4f2630 --- /dev/null +++ b/SQLiteStudio3/Tests/LexerTest/LexerTest.pro @@ -0,0 +1,32 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-07-15T23:45:16 +# +#------------------------------------------------- + +include($$PWD/../TestUtils/test_common.pri) + +QT += testlib + +QT -= gui + +TARGET = tst_lexertest +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +SOURCES += \ + tst_lexertest.cpp diff --git a/SQLiteStudio3/Tests/LexerTest/tst_lexertest.cpp b/SQLiteStudio3/Tests/LexerTest/tst_lexertest.cpp new file mode 100644 index 0000000..deac898 --- /dev/null +++ b/SQLiteStudio3/Tests/LexerTest/tst_lexertest.cpp @@ -0,0 +1,66 @@ +#include "parser/lexer.h" +#include +#include + +class LexerTest : public QObject +{ + Q_OBJECT + + public: + LexerTest(); + + private Q_SLOTS: + void testStringCase1(); + void testFloat(); + void testHex1(); + void testHex2(); +}; + +LexerTest::LexerTest() +{ +} + +void LexerTest::testStringCase1() +{ + QString sql = "INSERT INTO tab VALUES (1, 2, :val); /* test"; + + Lexer lex(Dialect::Sqlite3); + TokenList tokens = lex.tokenize(sql); + QVERIFY(tokens.size() == 20); +} + +void LexerTest::testFloat() +{ + QString sql = "SELECT .2"; + + Lexer lex(Dialect::Sqlite3); + TokenList tokens = lex.tokenize(sql); + QVERIFY(tokens.size() == 3); + QVERIFY(tokens[2]->type == Token::FLOAT); +} + +void LexerTest::testHex1() +{ + QString sql = "SELECT 0x"; + + Lexer lex(Dialect::Sqlite3); + TokenList tokens = lex.tokenize(sql); + QVERIFY(tokens.size() == 3); + QVERIFY(tokens[2]->type == Token::INVALID); +} + +void LexerTest::testHex2() +{ + QString sql = "SELECT 0x5zzz"; + + Lexer lex(Dialect::Sqlite3); + TokenList tokens = lex.tokenize(sql); + QVERIFY(tokens.size() == 4); + QVERIFY(tokens[2]->type == Token::INTEGER); + QVERIFY(tokens[3]->type == Token::OTHER); + QVERIFY(tokens[3]->value == "zzz"); +} + +QTEST_APPLESS_MAIN(LexerTest) + +#include "tst_lexertest.moc" diff --git a/SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp b/SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp index 7355616..eb2a76f 100644 --- a/SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp +++ b/SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp @@ -1,12 +1,15 @@ #include "parser/parser.h" #include "parser/ast/sqliteselect.h" #include "parser/ast/sqlitecreatetable.h" +#include "parser/ast/sqliteinsert.h" +#include "parser/ast/sqlitewith.h" +#include "parser/ast/sqliteupdate.h" #include "parser/keywords.h" #include "parser/lexer.h" #include "parser/parsererror.h" +#include "common/utils_sql.h" #include #include -#include class ParserTest : public QObject { @@ -40,6 +43,12 @@ class ParserTest : public QObject void testCommentBeginMultiline(); void testBetween(); void testBigNum(); + void testSelectWith(); + void testInsertWithDoubleQuoteValues(); + void testParseAndRebuildAlias(); + void testRebuildTokensUpdate(); + void testRebuildTokensInsertUpsert(); + void testGetColumnTokensFromInsertUpsert(); void initTestCase(); void cleanupTestCase(); }; @@ -134,7 +143,7 @@ void ParserTest::testGetFullObjects() QList fullObjects = query->getContextFullObjects(); QVERIFY(fullObjects.size() == 2); - foreach (const SqliteStatement::FullObject& fullObj, fullObjects) + for (const SqliteStatement::FullObject& fullObj : fullObjects) { switch (fullObj.type) { @@ -162,7 +171,7 @@ void ParserTest::testGetFullObjects2() QList fullObjects = query->getContextFullObjects(); QVERIFY(fullObjects.size() == 5); - foreach (const SqliteStatement::FullObject& fullObj, fullObjects) + for (const SqliteStatement::FullObject& fullObj : fullObjects) { switch (fullObj.type) { @@ -401,10 +410,99 @@ void ParserTest::testUniqConflict() QVERIFY(tokens[16]->type == Token::Type::PAR_RIGHT); } +void ParserTest::testSelectWith() +{ + QString sql = "WITH m (c1, c2) AS (VALUES (1, 'a'), (2, 'b')) SELECT * FROM m;"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + const SqliteQueryPtr query = parser3->getQueries().first(); + query->rebuildTokens(); + QString detokenized = query->detokenize().replace(" ", ""); + QVERIFY(sql.replace(" ", "") == detokenized); +} + +void ParserTest::testInsertWithDoubleQuoteValues() +{ + QString sql = "REPLACE INTO _Variables (Name, TextValue) VALUES (\"varNowTime\", strftime(\"%Y-%m-%dT%H:%M:%S\", \"now\", \"localtime\"));"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + const SqliteInsertPtr insert = parser3->getQueries().first().dynamicCast(); + insert->rebuildTokens(); + QString detokenized = insert->detokenize().replace(" ", ""); + QVERIFY(sql.replace(" ", "") == detokenized); +} + +void ParserTest::testParseAndRebuildAlias() +{ + QString sql = "SELECT x AS [\"abc\".\"def\"];"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + SqliteQueryPtr query = parser3->getQueries().first(); + query->rebuildTokens(); + QString newSql = query->detokenize(); + QVERIFY(sql == newSql); +} + +void ParserTest::testRebuildTokensUpdate() +{ + QString sql = "UPDATE tab SET col1 = 1, (col2, col3) = 2 WHERE x = 3;"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + SqliteUpdatePtr update = parser3->getQueries().first().dynamicCast(); + QVERIFY(update->keyValueMap.size() == 2); + QVERIFY(update->keyValueMap[1].first.type() == QVariant::StringList); + QStringList set2List = update->keyValueMap[1].first.toStringList(); + QVERIFY(set2List[0] == "col2"); + QVERIFY(set2List[1] == "col3"); + QVERIFY(update->where); + QVERIFY(!update->table.isNull()); + QVERIFY(update->where); + update->rebuildTokens(); + QVERIFY(update->tokens.detokenize() == sql); +} + +void ParserTest::testRebuildTokensInsertUpsert() +{ + QString sql = "INSERT INTO tab (a1, a2) VALUES (123, 456) ON CONFLICT (b1, b2, b3) DO UPDATE SET col1 = 1, (col2, col3) = 2 WHERE x = 3;"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + SqliteInsertPtr insert = parser3->getQueries().first().dynamicCast(); + QVERIFY(insert->upsert); + + insert->rebuildTokens(); + QVERIFY(insert->tokens.detokenize() == sql); +} + +void ParserTest::testGetColumnTokensFromInsertUpsert() +{ + QString sql = "INSERT INTO tab (a1, a2) VALUES (123, 456) ON CONFLICT (b1, b2, b3) DO UPDATE SET col1 = 1, (col2, col3) = 2 WHERE x = 3;"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + SqliteInsertPtr insert = parser3->getQueries().first().dynamicCast(); + QVERIFY(insert->upsert); + + TokenList tk = insert->getContextColumnTokens(); + qSort(tk.begin(), tk.end(), [](const TokenPtr& t1, const TokenPtr& t2) {return t1->start < t2->start;}); + QVERIFY(tk.toValueList().join(" ") == "a1 a2 b1 b2 b3 col1 col2 col3 x"); +} + void ParserTest::initTestCase() { initKeywords(); Lexer::staticInit(); + initUtilsSql(); parser2 = new Parser(Dialect::Sqlite2); parser3 = new Parser(Dialect::Sqlite3); } diff --git a/SQLiteStudio3/Tests/SelectResolverTest/tst_selectresolvertest.cpp b/SQLiteStudio3/Tests/SelectResolverTest/tst_selectresolvertest.cpp index 2d6762e..13a30a9 100644 --- a/SQLiteStudio3/Tests/SelectResolverTest/tst_selectresolvertest.cpp +++ b/SQLiteStudio3/Tests/SelectResolverTest/tst_selectresolvertest.cpp @@ -27,7 +27,9 @@ class SelectResolverTest : public QObject void testTableHash(); void testColumnHash(); void testWithCommonTableExpression(); + void testWithCte2(); void testStarWithJoinAndError(); + void testTableFunction(); void test1(); void testSubselectWithAlias(); }; @@ -196,6 +198,26 @@ void SelectResolverTest::testWithCommonTableExpression() QVERIFY(coreColumns[0].flags & SelectResolver::Flag::FROM_CTE_SELECT); } +void SelectResolverTest::testWithCte2() +{ + QString sql = "with m(c1, c2) as (" + " values (1, 'a'), (2, 'b'), (3, 'c')" + ")" + "select * from m"; + + SelectResolver resolver(db, sql); + Parser parser(db->getDialect()); + QVERIFY(parser.parse(sql)); + + QList> columns = resolver.resolve(parser.getQueries().first().dynamicCast().data()); + QList coreColumns = columns.first(); + QVERIFY(coreColumns.size() == 2); + QVERIFY(coreColumns[0].type == SelectResolver::Column::COLUMN); + QVERIFY(coreColumns[0].flags & SelectResolver::Flag::FROM_CTE_SELECT); + QVERIFY(coreColumns[1].type == SelectResolver::Column::COLUMN); + QVERIFY(coreColumns[1].flags & SelectResolver::Flag::FROM_CTE_SELECT); +} + void SelectResolverTest::testStarWithJoinAndError() { QString sql = "SELECT t1.*, t2.* FROM test t1 JOIN test2 USING (col1)"; @@ -208,6 +230,27 @@ void SelectResolverTest::testStarWithJoinAndError() QVERIFY(resolver.hasErrors()); } +void SelectResolverTest::testTableFunction() +{ + QString sql = "select * from json_tree(json_array(1, 2, 3))"; + SelectResolver resolver(db, sql); + Parser parser(db->getDialect()); + QVERIFY(parser.parse(sql)); + + SqlQueryPtr versionResult = db->exec("select sqlite_version()"); + qDebug() << "SQLite3 version:" << versionResult->getSingleCell().toString(); + + SqliteSelectPtr select = parser.getQueries().first().dynamicCast(); + QList > columns = resolver.resolve(select.data()); + if (resolver.hasErrors()) { + for (const QString& err : resolver.getErrors()) + qWarning() << err; + } + QVERIFY(!resolver.hasErrors()); + QVERIFY(columns.first().size() == 8); + QVERIFY(columns.first().first().type == SelectResolver::Column::OTHER); +} + void SelectResolverTest::test1() { QString sql = "SELECT * FROM (SELECT count(col1), col2 FROM test)"; diff --git a/SQLiteStudio3/Tests/TableModifierTest/tst_tablemodifiertest.cpp b/SQLiteStudio3/Tests/TableModifierTest/tst_tablemodifiertest.cpp index 2630f36..7bb8c0e 100644 --- a/SQLiteStudio3/Tests/TableModifierTest/tst_tablemodifiertest.cpp +++ b/SQLiteStudio3/Tests/TableModifierTest/tst_tablemodifiertest.cpp @@ -55,23 +55,29 @@ void TableModifierTest::testCase1() QStringList sqls = mod.generateSqls(); /* + * 1. Disable FK. * 1. Create new (with new name) * 2. Copy data to new - * 3. Drop old table. - * 4. Rename referencing table to temp name. - * 5. Create new referencing table. - * 6. Copy data to new referencing table. - * 7. Drop temp table. + * 4. Rename referencing table to temp name in 2 steps. + * 5. Second step of renaming - drop old table. + * 6. Create new referencing table. + * 7. Copy data to new referencing table. + * 8. Drop temp table. + * 9. Drop old table. + * 10. Re-enable FK. */ - QVERIFY(sqls.size() == 7); + QVERIFY(sqls.size() == 10); int i = 0; + verifyRe("PRAGMA foreign_keys = 0;", sqls[i++]); verifyRe("CREATE TABLE test2 .*", sqls[i++]); verifyRe("INSERT INTO test2.*SELECT.*FROM test;", sqls[i++]); - verifyRe("DROP TABLE test;", sqls[i++]); - verifyRe("ALTER TABLE abc RENAME TO sqlitestudio_temp_table.*", sqls[i++]); + verifyRe("CREATE TABLE sqlitestudio_temp_table.*AS SELECT.*FROM abc.*", sqls[i++]); + verifyRe("DROP TABLE abc;", sqls[i++]); verifyRe("CREATE TABLE abc .*", sqls[i++]); verifyRe("INSERT INTO abc.*SELECT.*FROM sqlitestudio_temp_table.*", sqls[i++]); verifyRe("DROP TABLE sqlitestudio_temp_table.*", sqls[i++]); + verifyRe("DROP TABLE test;", sqls[i++]); + verifyRe("PRAGMA foreign_keys = 1;", sqls[i++]); } void TableModifierTest::testCase2() @@ -84,25 +90,33 @@ void TableModifierTest::testCase2() QStringList sqls = mod.generateSqls(); /* - * 1. Rename to temp. - * 2. Create new. - * 3. Copy data from temp to new one. - * 4. Drop temp table. - * 5. Rename referencing table to temp name. - * 6. Create new referencing table. - * 7. Copy data to new referencing table. - * 8. Drop temp table. + * 1. Disable FK. + * 2. Rename to temp in 2 steps. + * 3. Second step of renaming (drop). + * 4. Create new. + * 5. Copy data from temp to new one. + * 6. Rename referencing table to temp name in 2 steps. + * 7. Second step of renaming (drop). + * 8. Create new referencing table. + * 9. Copy data to new referencing table. + * 10. Drop first temp table. + * 11. Drop second temp table. + * 12. Enable FK. */ - QVERIFY(sqls.size() == 8); + QVERIFY(sqls.size() == 12); int i = 0; - verifyRe("ALTER TABLE test RENAME TO sqlitestudio_temp_table.*", sqls[i++]); + verifyRe("PRAGMA foreign_keys = 0;", sqls[i++]); + verifyRe("CREATE TABLE sqlitestudio_temp_table.*AS SELECT.*FROM test.*", sqls[i++]); + verifyRe("DROP TABLE test;", sqls[i++]); verifyRe("CREATE TABLE test .*newCol.*", sqls[i++]); verifyRe("INSERT INTO test.*SELECT.*FROM sqlitestudio_temp_table.*", sqls[i++]); - verifyRe("DROP TABLE sqlitestudio_temp_table.*", sqls[i++]); - verifyRe("ALTER TABLE abc RENAME TO sqlitestudio_temp_table.*", sqls[i++]); + verifyRe("CREATE TABLE sqlitestudio_temp_table.*AS SELECT.*FROM abc.*", sqls[i++]); + verifyRe("DROP TABLE abc;", sqls[i++]); verifyRe("CREATE TABLE abc .*xyz text REFERENCES test \\(newCol\\).*", sqls[i++]); verifyRe("INSERT INTO abc.*SELECT.*FROM sqlitestudio_temp_table.*", sqls[i++]); verifyRe("DROP TABLE sqlitestudio_temp_table.*", sqls[i++]); + verifyRe("DROP TABLE sqlitestudio_temp_table.*", sqls[i++]); + verifyRe("PRAGMA foreign_keys = 1;", sqls[i++]); } void TableModifierTest::testCase3() @@ -118,27 +132,33 @@ void TableModifierTest::testCase3() QStringList sqls = mod.generateSqls(); /* - * 1. Create new (with new name) - * 2. Copy data to new - * 3. Drop old table. - * 4. Rename referencing table to temp name. - * 5. Create new referencing table. - * 6. Copy data to new referencing table. - * 7. Drop temp table. - * 8. Re-create index i2. - * 9. Re-create index i1 with new table name and column name. + * 1. Disable FK. + * 2. Create new (with new name) + * 3. Copy data to new + * 4. Drop old table. + * 5. Rename referencing table to temp name in two steps. + * 6. Second step of renaming (drop). + * 7. Create new referencing table. + * 8. Copy data to new referencing table. + * 9. Drop temp table. + * 10. Re-create index i2. + * 11. Re-create index i1 with new table name and column name. + * 12. Disable FK. */ - QVERIFY(sqls.size() == 9); + QVERIFY(sqls.size() == 12); int i = 0; + verifyRe("PRAGMA foreign_keys = 0;", sqls[i++]); verifyRe("CREATE TABLE newTable .*", sqls[i++]); verifyRe("INSERT INTO newTable.*SELECT.*FROM test;", sqls[i++]); - verifyRe("DROP TABLE test;", sqls[i++]); - verifyRe("ALTER TABLE abc RENAME TO sqlitestudio_temp_table.*", sqls[i++]); + verifyRe("CREATE TABLE sqlitestudio_temp_table.*AS SELECT.*FROM abc.*", sqls[i++]); + verifyRe("DROP TABLE abc;", sqls[i++]); verifyRe("CREATE TABLE abc .*xyz text REFERENCES newTable \\(newCol\\).*", sqls[i++]); verifyRe("INSERT INTO abc.*SELECT.*FROM sqlitestudio_temp_table.*", sqls[i++]); verifyRe("DROP TABLE sqlitestudio_temp_table.*", sqls[i++]); verifyRe("CREATE INDEX i2 ON abc \\(id\\);", sqls[i++]); + verifyRe("DROP TABLE test;", sqls[i++]); verifyRe("CREATE INDEX i1 ON newTable \\(newCol\\);", sqls[i++]); + verifyRe("PRAGMA foreign_keys = 1;", sqls[i++]); } void TableModifierTest::testCase4() @@ -156,13 +176,16 @@ void TableModifierTest::testCase4() QStringList sqls = mod.generateSqls(); /* - * 1. Create new (with new name) - * 2. Copy data to new - * 3. Drop old table. - * 4. Recreate trigger with all subqueries updated. + * 1. Disable FK. + * 2. Create new (with new name) + * 3. Copy data to new + * 4. Drop old table. + * 5. Recreate trigger with all subqueries updated. + * 6. Enable FK. */ - QVERIFY(sqls.size() == 4); + QVERIFY(sqls.size() == 6); int i = 0; + verifyRe("PRAGMA foreign_keys = 0;", sqls[i++]); verifyRe("CREATE TABLE newTable .*", sqls[i++]); verifyRe("INSERT INTO newTable.*SELECT.*FROM test;", sqls[i++]); verifyRe("DROP TABLE test;", sqls[i++]); @@ -172,6 +195,7 @@ void TableModifierTest::testCase4() "UPDATE newTable SET newCol = (SELECT newCol FROM newTable) WHERE x = (SELECT newCol FROM newTable); " "INSERT INTO newTable (newCol) VALUES (1); " "END;" == sqls[i++], "Trigger DDL incorrect."); + verifyRe("PRAGMA foreign_keys = 1;", sqls[i++]); } void TableModifierTest::testCase5() @@ -188,21 +212,25 @@ void TableModifierTest::testCase5() QStringList sqls = mod.generateSqls(); /* - * 1. Create new (with new name) - * 2. Copy data to new - * 3. Drop old table. - * 4. Drop old view. - * 5. Recreate view with new column and table. - * 6. Recreate trigger with all subqueries updated. + * 1. Disable FK. + * 2. Create new (with new name) + * 3. Copy data to new + * 4. Drop old table. + * 5. Drop old view. + * 6. Recreate view with new column and table. + * 7. Recreate trigger with all subqueries updated. + * 8. Enable FK. */ - QVERIFY(sqls.size() == 6); + QVERIFY(sqls.size() == 8); int i = 0; + verifyRe("PRAGMA foreign_keys = 0;", sqls[i++]); verifyRe("CREATE TABLE newTable .*", sqls[i++]); verifyRe("INSERT INTO newTable.*SELECT.*FROM test;", sqls[i++]); verifyRe("DROP TABLE test;", sqls[i++]); verifyRe("DROP VIEW v1;", sqls[i++]); verifyRe("CREATE VIEW v1 AS SELECT \\* FROM \\(SELECT newCol FROM newTable\\);", sqls[i++]); verifyRe("CREATE TRIGGER t1 INSTEAD OF INSERT ON v1 BEGIN SELECT 1; END;", sqls[i++]); + verifyRe("PRAGMA foreign_keys = 1;", sqls[i++]); } void TableModifierTest::testCase6() @@ -217,19 +245,25 @@ void TableModifierTest::testCase6() QStringList sqls = mod.generateSqls(); /* - * 1. Create new (with new name) - * 2. Copy data to new - * 3. Drop old table. - * 4. Recreate trigger with all subqueries updated. + * 1. Disable FK. + * 2. Create new (with new name) + * 3. Copy data to new + * 4. Drop old table. + * 5. Recreate trigger with all subqueries updated. + * 6. Drop view. + * 7. Recreate view with new table referenced. + * 8. Enable FK. */ - QVERIFY(sqls.size() == 6); + QVERIFY(sqls.size() == 8); int i = 0; + verifyRe("PRAGMA foreign_keys = 0;", sqls[i++]); verifyRe("CREATE TABLE newTable \\(id int, val2 text\\);", sqls[i++]); verifyRe("INSERT INTO newTable \\(id, val2\\) SELECT id, val2 FROM test;", sqls[i++]); verifyRe("DROP TABLE test;", sqls[i++]); verifyRe("CREATE TRIGGER t2 AFTER UPDATE OF Id ON newTable BEGIN SELECT NULL, Val2 FROM newTable; END;", sqls[i++]); verifyRe("DROP VIEW v1;", sqls[i++]); verifyRe("CREATE VIEW v1 AS SELECT \\* FROM \\(SELECT Id, NULL FROM newTable\\);", sqls[i++]); + verifyRe("PRAGMA foreign_keys = 1;", sqls[i++]); } void TableModifierTest::initTestCase() diff --git a/SQLiteStudio3/Tests/TestUtils/TestUtils.pro b/SQLiteStudio3/Tests/TestUtils/TestUtils.pro index f448ccb..77e0b19 100644 --- a/SQLiteStudio3/Tests/TestUtils/TestUtils.pro +++ b/SQLiteStudio3/Tests/TestUtils/TestUtils.pro @@ -23,7 +23,8 @@ SOURCES += \ mocks.cpp \ dbattachermock.cpp \ dbmanagermock.cpp \ - collationmanagermock.cpp + collationmanagermock.cpp \ + extensionmanagermock.cpp HEADERS +=\ testutils_global.h \ @@ -35,7 +36,8 @@ HEADERS +=\ mocks.h \ dbattachermock.h \ dbmanagermock.h \ - collationmanagermock.h + collationmanagermock.h \ + extensionmanagermock.h unix:!symbian { maemo5 { diff --git a/SQLiteStudio3/Tests/TestUtils/configmock.cpp b/SQLiteStudio3/Tests/TestUtils/configmock.cpp index 9bf3863..5a9169a 100644 --- a/SQLiteStudio3/Tests/TestUtils/configmock.cpp +++ b/SQLiteStudio3/Tests/TestUtils/configmock.cpp @@ -35,6 +35,11 @@ QVariant ConfigMock::get(const QString&, const QString&) return QVariant(); } +QVariant ConfigMock::get(const QString &, const QString &, const QVariant &) +{ + return QVariant(); +} + QHash ConfigMock::getAll() { return QHash(); @@ -102,6 +107,10 @@ void ConfigMock::clearSqlHistory() { } +void ConfigMock::deleteSqlHistory(const QList&) +{ +} + QAbstractItemModel* ConfigMock::getSqlHistoryModel() { return nullptr; @@ -124,6 +133,37 @@ QStringList ConfigMock::getCliHistory() const return QStringList(); } +void ConfigMock::addBindParamHistory(const QVector >&) +{ +} + +void ConfigMock::applyBindParamHistoryLimit() +{ +} + +QVector > ConfigMock::getBindParamHistory(const QStringList&) const +{ + return QVector>(); +} + +void ConfigMock::addPopulateHistory(const QString&, const QString&, int, const QHash >&) +{ +} + +void ConfigMock::applyPopulateHistoryLimit() +{ +} + +QHash> ConfigMock::getPopulateHistory(const QString&, const QString&, int&) const +{ + return QHash>(); +} + +QVariant ConfigMock::getPopulateHistory(const QString&) const +{ + return QVariant(); +} + void ConfigMock::addDdlHistory(const QString&, const QString&, const QString&) { } diff --git a/SQLiteStudio3/Tests/TestUtils/configmock.h b/SQLiteStudio3/Tests/TestUtils/configmock.h index 89c870e..7f04e98 100644 --- a/SQLiteStudio3/Tests/TestUtils/configmock.h +++ b/SQLiteStudio3/Tests/TestUtils/configmock.h @@ -16,6 +16,7 @@ class ConfigMock : public Config void rollbackMassSave(); void set(const QString&, const QString&, const QVariant&); QVariant get(const QString&, const QString&); + QVariant get(const QString&, const QString&, const QVariant&); QHash getAll(); bool addDb(const QString&, const QString&, const QHash&); bool updateDb(const QString&, const QString&, const QString&, const QHash&); @@ -30,11 +31,19 @@ class ConfigMock : public Config qint64 addSqlHistory(const QString&, const QString&, int, int); void updateSqlHistory(qint64, const QString&, const QString&, int, int); void clearSqlHistory(); + void deleteSqlHistory(const QList&); QAbstractItemModel*getSqlHistoryModel(); void addCliHistory(const QString&); void applyCliHistoryLimit(); void clearCliHistory(); QStringList getCliHistory() const; + void addBindParamHistory(const QVector>&); + void applyBindParamHistoryLimit(); + QVector> getBindParamHistory(const QStringList&) const; + void addPopulateHistory(const QString&, const QString&, int, const QHash>&); + void applyPopulateHistoryLimit(); + QHash> getPopulateHistory(const QString&, const QString&, int&) const; + QVariant getPopulateHistory(const QString&) const; void addDdlHistory(const QString&, const QString&, const QString&); QList getDdlHistoryFor(const QString&, const QString&, const QDate&); DdlHistoryModel* getDdlHistoryModel(); diff --git a/SQLiteStudio3/Tests/TestUtils/dbmanagermock.cpp b/SQLiteStudio3/Tests/TestUtils/dbmanagermock.cpp index 926e57b..10caed4 100644 --- a/SQLiteStudio3/Tests/TestUtils/dbmanagermock.cpp +++ b/SQLiteStudio3/Tests/TestUtils/dbmanagermock.cpp @@ -57,7 +57,7 @@ Db* DbManagerMock::getByPath(const QString&) return nullptr; } -Db*DbManagerMock::createInMemDb() +Db*DbManagerMock::createInMemDb(bool) { return nullptr; } diff --git a/SQLiteStudio3/Tests/TestUtils/dbmanagermock.h b/SQLiteStudio3/Tests/TestUtils/dbmanagermock.h index ce7eb51..ee69fa1 100644 --- a/SQLiteStudio3/Tests/TestUtils/dbmanagermock.h +++ b/SQLiteStudio3/Tests/TestUtils/dbmanagermock.h @@ -16,9 +16,9 @@ class DbManagerMock : public DbManager QList getValidDbList(); QList getConnectedDbList(); QStringList getDbNames(); - Db*getByName(const QString&, Qt::CaseSensitivity); - Db*getByPath(const QString&); - Db*createInMemDb(); + Db* getByName(const QString&, Qt::CaseSensitivity); + Db* getByPath(const QString&); + Db* createInMemDb(bool = false); bool isTemporary(Db*); QString quickAddDb(const QString &path, const QHash &); DbPlugin* getPluginForDbFile(const QString&); diff --git a/SQLiteStudio3/Tests/TestUtils/extensionmanagermock.cpp b/SQLiteStudio3/Tests/TestUtils/extensionmanagermock.cpp new file mode 100644 index 0000000..dc4669b --- /dev/null +++ b/SQLiteStudio3/Tests/TestUtils/extensionmanagermock.cpp @@ -0,0 +1,19 @@ +#include "extensionmanagermock.h" + +ExtensionManagerMock::ExtensionManagerMock() +{ +} + +void ExtensionManagerMock::setExtensions(const QList&) +{ +} + +QList ExtensionManagerMock::getAllExtensions() const +{ + return QList(); +} + +QList ExtensionManagerMock::getExtensionForDatabase(const QString&) const +{ + return QList(); +} diff --git a/SQLiteStudio3/Tests/TestUtils/extensionmanagermock.h b/SQLiteStudio3/Tests/TestUtils/extensionmanagermock.h new file mode 100644 index 0000000..7a7a1f4 --- /dev/null +++ b/SQLiteStudio3/Tests/TestUtils/extensionmanagermock.h @@ -0,0 +1,17 @@ +#ifndef EXTENSIONMANAGERMOCK_H +#define EXTENSIONMANAGERMOCK_H + +#include "services/sqliteextensionmanager.h" + +class ExtensionManagerMock : public SqliteExtensionManager +{ + public: + ExtensionManagerMock(); + + public: + void setExtensions(const QList&); + QList getAllExtensions() const; + QList getExtensionForDatabase(const QString&) const; +}; + +#endif // EXTENSIONMANAGERMOCK_H diff --git a/SQLiteStudio3/Tests/TestUtils/mocks.cpp b/SQLiteStudio3/Tests/TestUtils/mocks.cpp index dee3bfd..bb1a226 100644 --- a/SQLiteStudio3/Tests/TestUtils/mocks.cpp +++ b/SQLiteStudio3/Tests/TestUtils/mocks.cpp @@ -7,6 +7,7 @@ #include "collationmanagermock.h" #include "dbattachermock.h" #include "dbmanagermock.h" +#include "extensionmanagermock.h" MockRepository* mockRepository = nullptr; @@ -34,4 +35,5 @@ void initMocks() SQLITESTUDIO->setDbAttacherFactory(new DbAttacherFactoryMock()); SQLITESTUDIO->setDbManager(new DbManagerMock()); SQLITESTUDIO->setCollationManager(new CollationManagerMock()); + SQLITESTUDIO->setSqliteExtensionManager(new ExtensionManagerMock()); } diff --git a/SQLiteStudio3/Tests/Tests.pro b/SQLiteStudio3/Tests/Tests.pro index 2690494..b48ea8d 100644 --- a/SQLiteStudio3/Tests/Tests.pro +++ b/SQLiteStudio3/Tests/Tests.pro @@ -32,4 +32,5 @@ SUBDIRS += \ hash_tables \ db_ver_conv \ dsv \ - UtilsTest + UtilsTest \ + LexerTest diff --git a/SQLiteStudio3/Tests/UtilsTest/tst_utilssqltest.cpp b/SQLiteStudio3/Tests/UtilsTest/tst_utilssqltest.cpp index 97c9234..2719ae4 100644 --- a/SQLiteStudio3/Tests/UtilsTest/tst_utilssqltest.cpp +++ b/SQLiteStudio3/Tests/UtilsTest/tst_utilssqltest.cpp @@ -14,6 +14,7 @@ private Q_SLOTS: void testRemoveEmpties(); void testRemoveComments(); void testRemoveCommentsAndEmpties(); + void testDoubleToString(); }; UtilsSqlTest::UtilsSqlTest() @@ -70,6 +71,16 @@ void UtilsSqlTest::testRemoveCommentsAndEmpties() QVERIFY2(sp[0] == "select 'dfgh ;sdg /*''*/ dfga' from aa;", failure.arg(sp[0]).toLatin1().data()); } +void UtilsSqlTest::testDoubleToString() +{ + QVERIFY(doubleToString(QVariant(5.001)) == "5.001"); + QVERIFY(doubleToString(QVariant(5.0000001)) == "5.0000001"); + QVERIFY(doubleToString(QVariant(5.000000000000000000000000001)) == "5.0"); // too big, considered as round 5 + QVERIFY(doubleToString(QVariant(0.0000001)) == "0.0000001"); + QVERIFY(doubleToString(QVariant(9.99999999999998)) == "9.99999999999998"); + QVERIFY(doubleToString(QVariant(0.1 + 0.1 + 0.1)) == "0.3"); +} + QTEST_APPLESS_MAIN(UtilsSqlTest) #include "tst_utilssqltest.moc" diff --git a/SQLiteStudio3/UpdateSQLiteStudio/UpdateSQLiteStudio.exe.manifest b/SQLiteStudio3/UpdateSQLiteStudio/UpdateSQLiteStudio.exe.manifest deleted file mode 100644 index 54081e5..0000000 --- a/SQLiteStudio3/UpdateSQLiteStudio/UpdateSQLiteStudio.exe.manifest +++ /dev/null @@ -1,19 +0,0 @@ - - - - SQLiteStudio updater - - - - - - - - - - - - diff --git a/SQLiteStudio3/UpdateSQLiteStudio/UpdateSQLiteStudio.pro b/SQLiteStudio3/UpdateSQLiteStudio/UpdateSQLiteStudio.pro deleted file mode 100644 index 81819af..0000000 --- a/SQLiteStudio3/UpdateSQLiteStudio/UpdateSQLiteStudio.pro +++ /dev/null @@ -1,41 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2014-08-29T20:30:14 -# -#------------------------------------------------- - -include($$PWD/../dirs.pri) -include($$PWD/../utils.pri) - -QT += core -QT -= gui - -TARGET = UpdateSQLiteStudio -#CONFIG += console -CONFIG -= app_bundle - -CONFIG += c++11 -QMAKE_CXXFLAGS += -pedantic - -LIBS += -lcoreSQLiteStudio - -TEMPLATE = app - -DEFINES += PORTABLE_CONFIG - -linux|portable { - QMAKE_LFLAGS += -Wl,-rpath,./lib -} - - -win32: { - RC_FILE = windows.rc -} - -SOURCES += main.cpp - -OTHER_FILES += \ - windows.rc \ - UpdateSQLiteStudio.exe.manifest - -HEADERS += diff --git a/SQLiteStudio3/UpdateSQLiteStudio/main.cpp b/SQLiteStudio3/UpdateSQLiteStudio/main.cpp deleted file mode 100644 index e5730d3..0000000 --- a/SQLiteStudio3/UpdateSQLiteStudio/main.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "services/updatemanager.h" -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - - QString path = app.applicationDirPath() + QLatin1Char('/') + UpdateManager::WIN_INSTALL_FILE; - QFile installFile(path); - if (QFileInfo(path).isReadable()) - { - installFile.open(QIODevice::ReadOnly); - QTextStream inStr(&installFile); - QString option = inStr.readLine(); - QString backupDir = inStr.readLine(); - QString appDir = inStr.readLine(); - installFile.close(); - installFile.remove(); - - QString tempDir = app.applicationDirPath(); - if (option == UpdateManager::UPDATE_OPTION_NAME) - { - bool res = UpdateManager::executeFinalStep(tempDir, backupDir, appDir); - if (res) - { - QFile doneFile(appDir + QLatin1Char('/') + UpdateManager::WIN_UPDATE_DONE_FILE); - doneFile.open(QIODevice::WriteOnly); - doneFile.close(); - } - else - qCritical() << QString("Could not execute final step with root priviledges: %1").arg(UpdateManager::getStaticErrorMessage()); - } - else - { - qCritical() << QString("Option passed to updater not matched: '%1' != '%2'").arg(option, UpdateManager::UPDATE_OPTION_NAME); - } - } - else - { - qCritical() << QString("Updater installation file (%1) was not readable.").arg(path); - } - - return 0; -} diff --git a/SQLiteStudio3/UpdateSQLiteStudio/windows.manifest.autosave b/SQLiteStudio3/UpdateSQLiteStudio/windows.manifest.autosave deleted file mode 100644 index 788fba6..0000000 --- a/SQLiteStudio3/UpdateSQLiteStudio/windows.manifest.autosave +++ /dev/null @@ -1,19 +0,0 @@ - - - - Gokulnathvc Really Cool App - - - - - - - - - - - - \ No newline at end of file diff --git a/SQLiteStudio3/UpdateSQLiteStudio/windows.rc b/SQLiteStudio3/UpdateSQLiteStudio/windows.rc deleted file mode 100644 index 1e4ed25..0000000 --- a/SQLiteStudio3/UpdateSQLiteStudio/windows.rc +++ /dev/null @@ -1,3 +0,0 @@ -#include - -CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "UpdateSQLiteStudio.exe.manifest" diff --git a/SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt b/SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt index c0c42cd..8f1df64 100644 --- a/SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt +++ b/SQLiteStudio3/coreSQLiteStudio/ChangeLog.txt @@ -1,3 +1,72 @@ +[3.2.1] + * [BUGFIX]: #3399 Fixed start under Linux using the pre-compiled binary distributions (it used to fail due to missing xcb dependency). + * [BUGFIX]: #3398 Fixed 'export data' checkbox in export dialog to not ignore it anymore. + * [BUGFIX]: Binary packages now include the MultiEditorImage plugin, which introduces the picture preview for BLOB values. It was introduced in 3.2.0, but missing in binary distributions. + +[3.2.0] + * [NEW]: #3188 New plugin to have images stored in database being visible as another tab in the Form View or cell's editor dialog window. + * [NEW]: #3207 #1444 #2547 Export, Import & Populate dialog settings are remembered, even after application restart. + * [NEW]: #3268 Query bind parameters are now supported by the query editor while execution - user will be asked for values for these parameters in a dedicated dialog. + * [NEW]: #3267 Added Extension Manager window, where all SQLite extensions can be registered for loading into databases. + * [NEW]: #3161 Added support for table-valued functions (https://sqlite.org/vtab.html#tabfunc2) + * [NEW]: #3349 Added support for UPSERT syntax from SQLite 3.24.0. + * [NEW]: #3292 Added possibility to execute huge SQL files directly from disk, without loading them to SQL Editor. + * [NEW]: #3265 Completely new installer for SQLiteStudio is introduced. It bases on Qt Installer Framework. This addresses numerous issues with automatic updates that SQLiteStudio had. It also allows for some new features, like automatic file association under Windows (#3178). Portable (download & run, without installation) distribution continues to be available. + * [NEW]: #2659 AutoIncrement option is now always available in PK configuration dialog. When AutoIncrement is enabled, a datatype will be enforced to INTEGER type. + * [NEW]: #2798 Added filter inputs per column as an option. + * [NEW]: #3224 Added context menu for SQL history tab to delete individual (or a range of selected) entries. Also a "delete" key can be used. + * [NEW]: #2651 Only a single instance of SQLiteStudio can be running at the time. If another instance is requested, the first one will be brought to the front of windows stack. If another instance was requested due to associated file being open, then the first instance will not only be raised, but also the requested file will be added to database list as temporary, volatile database (not added permanently to configuration). + * [NEW]: #3033 Ctrl+Shift+c copies data including headers. Also context menu entry added for the same. + * [NEW]: #2962 Pasting single value to multiple cells results in pasting the value into all selected cells, not just to first one. + * [NEW]: #2907 The "Open file's directory" menu item added to database list for database nodes. + * [NEW]: #3388 Added file association entries in the plist for MacOSX + * [NEW]: #3163 Added menubar accelerator keys. + * [CHANGE]: #3257 #3260 #3271 Bug/Feature reports are now completely managed by GitHub. Bug report dialog is no longer present in the application, but instead the menu entry opens web browser on project's GitHub page. + * [CHANGE]: #3285 SQLCipher and wxSQLite3 plugins can now be linked to system-provided libraries, which is especially useful under Linux. Instructions were added to the wiki page: https://github.com/pawelsalawa/sqlitestudio/wiki/Instructions_for_compilation_under_Linux#linking-with-system-provided-libraries + * [CHANGE]: #3284 SQLite3 upgraded to version 3.24.0 (excluding SQLCipher plugin, which is still on 3.20.1). + * [CHANGE]: API of QueryExecutor enhanced to provide custom steps at certain stages of execution. Steps can be injected by plugins. + * [CHANGE]: #3121 Column widths are kept between data reloads. + * [CHANGE]: #3024 Edit in editor action in cell's context menu stands now "show in viewer" if clicked on read-only cell. Also "set null" and "erase" are not displayed if none of selected cells is editable. + * [CHANGE]: #3142 Horizontal scroll position is now preserved between sort request on a data view. + * [CHANGE]: #2971 Column width is now mostly based on data width, not header width, but if there is little columns to be displayed, the header width is also considered. + * [CHANGE]: #3323 Disabled automatic line wrapping in SQL editor and all other code edition fields in the application. + * [BUGFIX]: #3259 #3215 #3327 Stop interpreting "+3" or "0010" as numeric types if entered to TEXT column (or any other column not declared as numeric-ish). + * [BUGFIX]: #3191 CSV import speed improved. It's 1400 times faster. It's not a joke. The bug used to cause the import to be terribly slow. Also other importing plugins gained around 400% of speed. + * [BUGFIX]: #3119 Fixed extra "empty" row of data when importing from CSV with a new, empty line at the end. + * [BUGFIX]: #3235 Crash when opening DB dialog, but file was moved. + * [BUGFIX]: #3185 Fixed creation of new tables/views if "Data" tab is configured as first. + * [BUGFIX]: #3279 Fixed reporting rows affected with DELETE statement for SQLite2. + * [BUGFIX]: #3023 Optimized SQL editor widget to work with huge contents. + * [BUGFIX]: Fixed random crashes at application close (when saving session). Most frequend on Windows platform. + * [BUGFIX]: #3252 Fixed first character input when starting to edit FK column data. + * [BUGFIX]: #3251 Fixed DEFAULT constraint dialog to work wit "literal values in double-quotes" + * [BUGFIX]: #3084 #3085 Fixed beeps under MacOSX when editing FK cell. + * [BUGFIX]: #3293 Fixed deault shortcut for code assistant under MacOSX from Cmd-Space to Ctrl-Space, so it does not conflict with Spotlight + * [BUGFIX]: #3190 Fixed handling WITHOUT ROWID and unusual column name. + * [BUGFIX]: #3177 Fixed tab indentations when selecting even part of a line. + * [BUGFIX]: #3171 Pasting object to same database is prevented. + * [BUGFIX]: #3176 Fixed exporting with Common Table Expression (the WITH statement). + * [BUGFIX]: #3162 Fixed order of column headers in Index Dialog + * [BUGFIX]: #3159 Fixed dictionary populating plugin to recognize different new-line characters. + * [BUGFIX]: #3156 Fixed recognition of double-quoted values. + * [BUGFIX]: #3093 Columns with AUTOINCREMENT statement are defaulted to null for new rows in Form View, so they get committed this way (unless manually changed) and they become an auto generated values. + * [BUGFIX]: #3086 #3187 Fixed internal task ordering when drag&dropping tasks on the taskbar, so switching between tasks with keyboard shortcut reflects order of tasks on the taskbar. + * [BUGFIX]: #3173 Added support for detecting and trimming whitespace in pasted text (thanks to nishanthkarthik for contributing this) + * [BUGFIX]: #2922 Fixed CTE execution by QueryExecutor, so it understands columns from CTE (not editable columns for now, maybe will become editable in future). + * [BUGFIX]: #2964 SQL history tab shows now local time of execution, not UTC. + * [BUGFIX]: #3290 Fixed querying data for FK dropdown from tables/columns with unusual characters in name. Also fixed name-wrapping for objects that have unescaped wrapper character inside of their name. + * [BUGFIX]: #3305 Introduced dynamic limit for number of rows per page - based on number of columns, so it's less likely to hit the memory limit. + * [BUGFIX]: #3311 Fixed floating point numbers handling. + * [BUGFIX]: #3383 Fixed JSON export plugin for quoted names. + * [BUGFIX]: #3347 #3351 Fixed QCheckBox in several places, so text() of it is not used as a valid data. This is to address issues with automatic accelerator keys. + * [BUGFIX]: Addressed some concurrency erorrs in SQLite 2 plugin + * [BUGFIX]: #3139 #3116 #3326 #3341 Various code compiling issues addressed. + * [BUGFIX]: #3145 #3165 #3179 Fixed various typos in messages/interface. + * [BUGFIX]: #3333 Fixed unit test to honor new features of TableModifier, but also fixed few bugs in TableModifier. + * [BUGFIX]: #3277 Open Source license issues addressed (specific exceptions for OpenSSL and icons) + * [BUGFIX]: #2966 Application icon added to package. + * [BUGFIX]: Few other bugfixes made on the fly, while working on other issues. + [3.1.1] * [ADDED]: WxSQLite3 plugin (with encryption support). * [ADDED]: System.Data.SQLite plugin (ADO.NET, includes encryption support). diff --git a/SQLiteStudio3/coreSQLiteStudio/Info.plist b/SQLiteStudio3/coreSQLiteStudio/Info.plist index 3ce6f15..794e404 100644 --- a/SQLiteStudio3/coreSQLiteStudio/Info.plist +++ b/SQLiteStudio3/coreSQLiteStudio/Info.plist @@ -1,7 +1,7 @@ - + NSPrincipalClass NSApplication CFBundleIconFile @@ -18,5 +18,32 @@ SQLiteStudio CFBundleIdentifier pl.com.salsoft.SQLiteStudio - + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + db + sdb + sqlite + db3 + s3db + sqlite3 + sl3 + db2 + s2db + sqlite2 + sl2 + + CFBundleTypeName + SQLite Database Document + CFBundleTypeOSTypes + + **** + + CFBundleTypeRole + Editor + + + diff --git a/SQLiteStudio3/coreSQLiteStudio/TODO.txt b/SQLiteStudio3/coreSQLiteStudio/TODO.txt index 9e0a77d..e4121f0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/TODO.txt +++ b/SQLiteStudio3/coreSQLiteStudio/TODO.txt @@ -1,52 +1,8 @@ -cannot reproduce: -2922 / 2926 / 2925 -2940 -3009 - db w emailu od goretux@gmail.com -3052 -3062 - -* Outstanding features for 3.2: -- migrate updates engine to Qt Install Framework -- loadable extensions full support -- BLOB preview engine based on plugins -- ERD plugin -- DB compare plugin -- executing query with bind params -- comments support in formatter - * Next versions: -- object names (columns, tables, etc) in dialogs should be validated against suffix/prefix whitespaces and if they appear, user should be asked for confirmation -- small useful features: generating template queries from context menu for table/view, from data view. -- code templates -- committing DataView should be async -- syntax checkers as services - per language -- code assistants as services - per language - specialized validation of expressions for DEFAULT constraint. -- "recovery" after failed startup - detecting if previous start crashed and if yes, propose cleaning of configuration. -- tcl highlighter -- highlighting occurrences of the same object in the query when cursor is on it -- plugin to do performance testing -- plugins to generate artifacts -- qtscript syntax checker -- tcl syntax checker -- dbf import -- dbf export -- code assistant as a service with plugins, so it can be extended with other langs and injected in custom functions window, collations window, etc - in configuration dialog option to disable each individual native SQL function - move "integrity check" into dedicated window, add "PRAGMA foreign_key_check" as a second stage of checking and present all in one window -- tips&tricks dialog -- crash management -- SqlEditor::refreshValidObjects() doesn't add valid object names from other databases (not yet attached). It might be tricky to implement. -- need an idea for some smart "revert" or "backup", so users are protected from accidentaly deleting table, or data in table. -- expose query executor steps chain to plugins -- complete plugin for "Search in database(s)" -- complete plugin for compare tables/databases -- executing queries with bind parameters -- completer: when suggesting table in FROM clause, look at columns after SELECT to give related tables first. - constraints tab in table window should have toolbar for adding/editing/deleting constraints -- add menu mnemonics support (underlined shortcut letters) -- per column filtering field when clicked on column header(?) -- option to show current window's DB path in top window title CLI: - plugin management commands diff --git a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp index 091121c..5f40521 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/bistrhash.cpp @@ -1,4 +1,5 @@ #include "bistrhash.h" +#include BiStrHash::BiStrHash(std::initializer_list > list) { diff --git a/SQLiteStudio3/coreSQLiteStudio/common/global.h b/SQLiteStudio3/coreSQLiteStudio/common/global.h index b1f4b01..cfd8dc0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/global.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/global.h @@ -12,7 +12,7 @@ #define DEEP_COPY_COLLECTION(T, F) \ T* _new##T; \ - foreach (T* _element, other.F) \ + for (T* _element : other.F) \ { \ _new##T = new T(*_element); \ _new##T->setParent(this); \ diff --git a/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.cpp b/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.cpp new file mode 100644 index 0000000..2c39f34 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.cpp @@ -0,0 +1,37 @@ +#include "lazytrigger.h" +#include + +LazyTrigger::LazyTrigger(int delay, QObject* parent, const char* slot) : + QObject(parent) +{ + timer = new QTimer(this); + timer->setSingleShot(true); + timer->setInterval(delay); + connect(timer, &QTimer::timeout, this, &LazyTrigger::triggered); + if (slot) + connect(timer, SIGNAL(timeout()), parent, slot); +} + +LazyTrigger::LazyTrigger(int delay, LazyTrigger::Condition condition, QObject* parent, const char* slot) : + LazyTrigger(delay, parent, slot) +{ + this->condition = condition; +} + +void LazyTrigger::setDelay(int delay) +{ + timer->setInterval(delay); +} + +void LazyTrigger::schedule() +{ + timer->stop(); + + if (!condition || condition()) + timer->start(); +} + +void LazyTrigger::cancel() +{ + timer->stop(); +} diff --git a/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.h b/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.h new file mode 100644 index 0000000..9c34395 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/lazytrigger.h @@ -0,0 +1,34 @@ +#ifndef LAZYTRIGGER_H +#define LAZYTRIGGER_H + +#include "coreSQLiteStudio_global.h" +#include +#include + +class QTimer; + +class API_EXPORT LazyTrigger : public QObject +{ + Q_OBJECT + + public: + typedef std::function Condition; + + LazyTrigger(int delay, QObject* parent = nullptr, const char* slot = nullptr); + LazyTrigger(int delay, Condition condition, QObject* parent = nullptr, const char* slot = nullptr); + + void setDelay(int delay); + + private: + QTimer* timer = nullptr; + Condition condition = nullptr; + + public slots: + void schedule(); + void cancel(); + + signals: + void triggered(); +}; + +#endif // LAZYTRIGGER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/common/objectpool.h b/SQLiteStudio3/coreSQLiteStudio/common/objectpool.h index b9f6b9f..7330efc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/objectpool.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/objectpool.h @@ -24,7 +24,7 @@ class ObjectPool }; template -ObjectPool::ObjectPool(quint32 min, quint32 max) +ObjectPool::ObjectPool(quint32 min, quint32 max) : min(min), max(max) { Q_ASSERT(min > 0); @@ -36,7 +36,8 @@ ObjectPool::ObjectPool(quint32 min, quint32 max) } } -T* ObjectPool::reserve() +template +T* ObjectPool::reserve() { mutex.lock(); @@ -73,7 +74,7 @@ T* ObjectPool::reserve() } template -void ObjectPool::release(T* obj) +void ObjectPool::release(T* obj) { mutex.lock(); pool[obj] = false; diff --git a/SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h b/SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h index 9ca6ade..c0d44b6 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/sortedhash.h @@ -74,7 +74,7 @@ class SortedHash : public QHash QList keys(const T& value) const { QList results; - foreach (const Key& k, sortedKeys) + for (const Key& k : sortedKeys) if (value(k) == value) results << k; @@ -98,7 +98,7 @@ class SortedHash : public QHash QList values() const { QList results; - foreach (const Key& k, sortedKeys) + for (const Key& k : sortedKeys) results << value(k); return results; diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp b/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp index e3d2e47..fd40355 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils.cpp @@ -311,7 +311,7 @@ QStringList tokenizeArgs(const QString& str) QStringList prefixEach(const QString& prefix, const QStringList& list) { QStringList result; - foreach (const QString& item, list) + for (const QString& item : list) result << (prefix + item); return result; @@ -385,7 +385,7 @@ QString longest(const QStringList& strList) { int max = 0; QString result; - foreach (const QString str, strList) + for (const QString str : strList) { if (str.size() > max) { @@ -400,7 +400,7 @@ QString shortest(const QStringList& strList) { int max = INT_MAX; QString result; - foreach (const QString str, strList) + for (const QString str : strList) { if (str.size() < max) { @@ -421,7 +421,7 @@ QString longestCommonPart(const QStringList& strList) for (int i = 0; i < first.length(); i++) { common += first[i]; - foreach (const QString& str, strList) + for (const QString& str : strList) { if (!str.startsWith(common)) return common.left(i); @@ -434,7 +434,7 @@ QStringList applyMargin(const QString& str, int margin) { QStringList lines; QString line; - foreach (QString word, str.split(" ")) + for (QString word : str.split(" ")) { if (((line + word).length() + 1) > margin) { @@ -694,9 +694,11 @@ QString getOsString() case QSysInfo::WV_WINDOWS8_1: os += " 8.1"; break; +#if QT_VERSION >= 0x050500 case QSysInfo::WV_WINDOWS10: os += " 10"; break; +#endif case QSysInfo::WV_32s: case QSysInfo::WV_95: case QSysInfo::WV_98: @@ -710,7 +712,9 @@ QString getOsString() case QSysInfo::WV_CE_5: case QSysInfo::WV_CE_6: case QSysInfo::WV_CE_based: +#if QT_VERSION >= 0x050500 case QSysInfo::WV_None: +#endif break; } #elif defined(Q_OS_LINUX) @@ -752,6 +756,9 @@ QString getOsString() case QSysInfo::MV_10_11: os += " 10.11 El Capitan"; break; + case QSysInfo::MV_10_12: + os += " 10.12 Sierra"; + break; case QSysInfo::MV_9: case QSysInfo::MV_10_0: case QSysInfo::MV_10_1: @@ -816,6 +823,42 @@ bool isHex(const QString& str) return ok; } +bool isHex(const QChar& c) +{ + return isHex(c.toLatin1()); +} + +bool isHex(const char c) +{ + switch (c) + { + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + case 'd': + case 'D': + case 'e': + case 'E': + case 'f': + case 'F': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return true; + } + return false; +} + QString formatVersion(int version) { int majorVer = version / 10000; @@ -916,9 +959,18 @@ QStringList concat(const QList& list) return result; } + QString doubleToString(const QVariant& val) { - return val.toString(); + QString str = val.toString(); + if (str.contains("e")) + str = QString::number(val.toDouble(), 'f', 14).remove(QRegExp("0*$")); + else if (!str.contains('.')) + str += ".0"; + else if (str.mid(str.indexOf('.') + 1).length() > 14) + str = QString::number(val.toDouble(), 'f', 14).remove(QRegExp("0*$")); + + return str; } void sortWithReferenceList(QList& listToSort, const QList& referenceList, Qt::CaseSensitivity cs) @@ -941,3 +993,41 @@ void sortWithReferenceList(QList& listToSort, const QList& ref return (idx1 > idx2); }); } + +QByteArray serializeToBytes(const QVariant& value) +{ + QByteArray bytes; + QDataStream stream(&bytes, QIODevice::WriteOnly); + stream << value; + return bytes; +} + +QVariant deserializeFromBytes(const QByteArray& bytes) +{ + if (bytes.isNull()) + return QVariant(); + + QVariant deserializedValue; + QDataStream stream(bytes); + stream >> deserializedValue; + return deserializedValue; +} + +QString readFileContents(const QString& path, QString* err) +{ + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + if (err) + *err = QObject::tr("Could not open file '%1' for reading: %2").arg(path).arg(file.errorString()); + + return QString(); + } + + QTextStream stream(&file); + stream.setCodec("UTF-8"); + QString contents = stream.readAll(); + file.close(); + + return contents; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils.h b/SQLiteStudio3/coreSQLiteStudio/common/utils.h index c56a4db..24ea150 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils.h +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils.h @@ -9,6 +9,8 @@ #include #include #include +#include +#include class QTextCodec; @@ -236,6 +238,8 @@ API_EXPORT int sum(const QList& integers); API_EXPORT QString getOsString(); API_EXPORT bool validateEmail(const QString& email); API_EXPORT bool isHex(const QString& str); +API_EXPORT bool isHex(const QChar& c); +API_EXPORT bool isHex(const char c); API_EXPORT QString formatVersion(int version); API_EXPORT bool copyRecursively(const QString& src, const QString& dst); API_EXPORT bool renameBetweenPartitions(const QString& src, const QString& dst); @@ -289,6 +293,12 @@ void removeDuplicates(QList& list) } } +API_EXPORT QByteArray serializeToBytes(const QVariant& value); + +API_EXPORT QVariant deserializeFromBytes(const QByteArray& bytes); + +API_EXPORT QString readFileContents(const QString& path, QString* err); + Q_DECLARE_METATYPE(QList) #endif // UTILS_H diff --git a/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp b/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp index ad37ff0..b5642ec 100644 --- a/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/common/utils_sql.cpp @@ -12,7 +12,8 @@ #include QString invalidIdCharacters = "[]()\"'@*.,+-=/%&|:; \t\n<>"; -QHash > wrapperChars; +QHash> wrapperChars; +QHash> wrapperEscapedEnding; QList sqlite3Wrappers; QList sqlite2Wrappers; @@ -23,6 +24,11 @@ void initUtilsSql() wrapperChars[NameWrapper::BACK_QUOTE] = QPair('`', '`'); wrapperChars[NameWrapper::DOUBLE_QUOTE] = QPair('"', '"'); + wrapperEscapedEnding[NameWrapper::BRACKET] = QPair(']', false); + wrapperEscapedEnding[NameWrapper::QUOTE] = QPair('\'', true); + wrapperEscapedEnding[NameWrapper::BACK_QUOTE] = QPair('`', true); + wrapperEscapedEnding[NameWrapper::DOUBLE_QUOTE] = QPair('"', true); + sqlite3Wrappers << NameWrapper::DOUBLE_QUOTE << NameWrapper::BRACKET << NameWrapper::QUOTE @@ -129,7 +135,7 @@ QPair getQuoteCharacter(QString& obj, Dialect dialect, NameWrapper } QPair wrapChars; - foreach (NameWrapper wrapper, wrappers) + for (NameWrapper wrapper : wrappers) { wrapChars = wrapperChars[wrapper]; if (obj.indexOf(wrapChars.first) > -1) @@ -277,6 +283,23 @@ bool isObjWrapped(const QString& str, Dialect dialect) return getObjWrapper(str, dialect) != NameWrapper::null; } +bool doesNotContainEndingWrapperChar(const QString& str, NameWrapper wrapper) +{ + QString innerPart = str.mid(1, str.length() - 2); + const QChar& endingChar = wrapperEscapedEnding[wrapper].first; + bool escapingAllowed = wrapperEscapedEnding[wrapper].second; + int idx = -1; + int lastIdx = innerPart.length() - 1; + while ((idx = innerPart.indexOf(endingChar, idx + 1)) > -1) + { + if (idx == lastIdx || !escapingAllowed || innerPart[idx + 1] != endingChar) + return false; + + idx++; // we had occurrence, but it was escaped, so we need to skip the second (escape) char + } + return true; +} + NameWrapper getObjWrapper(const QString& str, Dialect dialect) { if (str.isEmpty()) @@ -289,10 +312,10 @@ NameWrapper getObjWrapper(const QString& str, Dialect dialect) else wrappers = sqlite3Wrappers; - foreach (NameWrapper wrapper, wrappers) + for (NameWrapper wrapper : wrappers) { QPair chars = wrapperChars[wrapper]; - if (str[0] == chars.first && str[str.length()-1] == chars.second) + if (str[0] == chars.first && str[str.length()-1] == chars.second && doesNotContainEndingWrapperChar(str, wrapper)) return wrapper; } return NameWrapper::null; @@ -306,7 +329,7 @@ bool isWrapperChar(const QChar& c, Dialect dialect) else wrappers = sqlite3Wrappers; - foreach (NameWrapper wrapper, wrappers) + for (NameWrapper wrapper : wrappers) { QPair chars = wrapperChars[wrapper]; if (c == chars.first || c == chars.second) @@ -389,7 +412,7 @@ QList splitQueries(const TokenList& tokenizedQuery, bool* complete) int createTriggerMeter = 0; bool insideTrigger = false; bool completeQuery = false; - foreach (const TokenPtr& token, tokenizedQuery) + for (const TokenPtr& token : tokenizedQuery) { value = token->value.toUpper(); if (!token->isWhitespace()) @@ -556,7 +579,7 @@ QStringList splitQueries(const QString& sql, Dialect dialect, bool keepEmptyQuer QString query; QStringList queries; - foreach (const TokenList& queryTokens, tokenizedQueries) + for (const TokenList& queryTokens : tokenizedQueries) { query = queryTokens.detokenize(); if (keepEmptyQueries || (!query.trimmed().isEmpty() && query.trimmed() != ";")) @@ -627,10 +650,10 @@ QList getQueriesWithParamNames(const QString& query, Dialec QString queryStr; QStringList paramNames; - foreach (const TokenList& tokens, queries) + for (const TokenList& tokens : queries) { paramNames.clear(); - foreach (const TokenPtr& token, tokens.filter(Token::BIND_PARAM)) + for (const TokenPtr& token : tokens.filter(Token::BIND_PARAM)) paramNames << token->value; queryStr = tokens.detokenize().trimmed(); @@ -648,7 +671,7 @@ QList getQueriesWithParamCount(const QString& query, Dialec QList queries = splitQueries(allTokens); QString queryStr; - foreach (const TokenList& tokens, queries) + for (const TokenList& tokens : queries) { queryStr = tokens.detokenize().trimmed(); if (!queryStr.isEmpty()) @@ -663,7 +686,7 @@ QueryWithParamNames getQueryWithParamNames(const QString& query, Dialect dialect TokenList allTokens = Lexer::tokenize(query, dialect); QStringList paramNames; - foreach (const TokenPtr& token, allTokens.filter(Token::BIND_PARAM)) + for (const TokenPtr& token : allTokens.filter(Token::BIND_PARAM)) paramNames << token->value; return QueryWithParamNames(query, paramNames); diff --git a/SQLiteStudio3/coreSQLiteStudio/common/valuelocker.h b/SQLiteStudio3/coreSQLiteStudio/common/valuelocker.h new file mode 100644 index 0000000..a757506 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/valuelocker.h @@ -0,0 +1,44 @@ +#ifndef VALUELOCKER_H +#define VALUELOCKER_H + +/** + * ValueLocker is similar to QMutexLocker, but it's not intended for multithreaded locks. + * It's rather for event loop locking. + * It can be created as local scope variable with a pointer to member variable. + * It will set "unlockedValue" to that variable once the locker is destroyed (goes out of scope). + * Usually the variable used will be of boolean type, but it can be virtually any other type. + * You can also provide initial value for locked state. Otherwise you will need to set the locked + * by yourself before the lock is created. + */ +template +class ValueLocker { + public: + ValueLocker(T* valueToLock, const T& lockedValue, const T& unlockedValue); + ValueLocker(T* valueToLock, const T& unlockedValue); + ~ValueLocker(); + + private: + T* valueToLock; + T unlockedValue; +}; + +template +ValueLocker::ValueLocker(T *valueToLock, const T &lockedValue, const T &unlockedValue) : + ValueLocker(valueToLock, unlockedValue) +{ + *valueToLock = lockedValue; +} + +template +ValueLocker::ValueLocker(T *valueToLock, const T &unlockedValue) : + valueToLock(valueToLock), unlockedValue(unlockedValue) +{ +} + +template +ValueLocker::~ValueLocker() +{ + *valueToLock = unlockedValue; +} + +#endif // VALUELOCKER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.cpp b/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.cpp new file mode 100644 index 0000000..7c86088 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.cpp @@ -0,0 +1,84 @@ +/*#include "xmldeserializer.h" +#include "unused.h" +#include + +XmlDeserializer::XmlDeserializer() +{ +} + +QHash XmlDeserializer::deserialize(QIODevice *input) +{ + QXmlStreamReader reader(input); + return deserialize(reader); +} + +QHash XmlDeserializer::deserialize(const QString &input) +{ + QXmlStreamReader reader(input); + return deserialize(reader); +} + +QHash XmlDeserializer::deserialize(QXmlStreamReader &reader) +{ + ctxStack.clear(); + output.clear(); + ctx = &output; + + QXmlStreamReader::TokenType tokenType; + while ((tokenType = reader.readNext()) != QXmlStreamReader::EndDocument) + handleTokenType(reader, tokenType); + + return output; +} + +void XmlDeserializer::handleTokenType(QXmlStreamReader& reader, QXmlStreamReader::TokenType tokenType) +{ + switch (tokenType) + { + case QXmlStreamReader::Comment: + case QXmlStreamReader::EndDocument: + case QXmlStreamReader::DTD: + case QXmlStreamReader::NoToken: + case QXmlStreamReader::ProcessingInstruction: + case QXmlStreamReader::StartDocument: + case QXmlStreamReader::EntityReference: + break; + case QXmlStreamReader::Invalid: + qDebug() << "Invalid token while parsing XML:" << reader.errorString(); + break; + case QXmlStreamReader::StartElement: + handleStartElement(reader); + break; + case QXmlStreamReader::Characters: + handleText(reader); + break; + case QXmlStreamReader::EndElement: + handleEndElement(reader); + break; + } +} + +void XmlDeserializer::handleStartElement(QXmlStreamReader &reader) +{ + QString key = reader.name().toString(); + QHash newCtx; + ctx->insertMulti(key, newCtx); + + for (const QXmlStreamAttribute& attr : reader.attributes()) + ctx->insertMulti(attr.name().toString(), attr.value().toString()); + + ctxStack.push(ctx); + ctx = &((*ctx)[key]); +} + +void XmlDeserializer::handleText(QXmlStreamReader &reader) +{ + ctx->insertMulti(QString(), reader.text().toString()); +} + +void XmlDeserializer::handleEndElement(QXmlStreamReader &reader) +{ + UNUSED(reader); + ctx = ctxStack.pop(); +} +*/ diff --git a/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.h b/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.h new file mode 100644 index 0000000..52761cf --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/common/xmldeserializer.h @@ -0,0 +1,31 @@ +/*#ifndef XMLDESERIALIZER_H +#define XMLDESERIALIZER_H + +#include "coreSQLiteStudio_global.h" +#include +#include +#include +#include + +class API_EXPORT XmlDeserializer +{ + public: + XmlDeserializer(); + + QHash deserialize(QIODevice* input); + QHash deserialize(const QString& input); + + private: + QHash deserialize(QXmlStreamReader& reader); + void handleTokenType(QXmlStreamReader& reader, QXmlStreamReader::TokenType tokenType); + void handleStartElement(QXmlStreamReader& reader); + void handleText(QXmlStreamReader& reader); + void handleEndElement(QXmlStreamReader& reader); + + QHash output; + QHash* ctx; + QStack*> ctxStack; +}; + +#endif // XMLDESERIALIZER_H +*/ diff --git a/SQLiteStudio3/coreSQLiteStudio/completioncomparer.cpp b/SQLiteStudio3/coreSQLiteStudio/completioncomparer.cpp index 978395f..ae64de8 100644 --- a/SQLiteStudio3/coreSQLiteStudio/completioncomparer.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/completioncomparer.cpp @@ -72,7 +72,7 @@ void CompletionComparer::init() contextDatabases = helper->originalParsedQuery->getContextDatabases(false); } - foreach (SelectResolver::Table table, helper->selectAvailableTables + helper->parentSelectAvailableTables) + for (SelectResolver::Table table : helper->selectAvailableTables + helper->parentSelectAvailableTables) availableTableNames += table.table; } } @@ -88,7 +88,7 @@ bool CompletionComparer::initSelect() contextTables = helper->originalCurrentSelectCore->getContextTables(false); contextDatabases = helper->originalCurrentSelectCore->getContextDatabases(false); - foreach (SqliteSelect::Core* core, helper->parentSelectCores) + for (SqliteSelect::Core* core : helper->parentSelectCores) { parentContextColumns += core->getContextColumns(false); parentContextTables += core->getContextTables(false); @@ -403,7 +403,7 @@ bool CompletionComparer::isTokenOnResultColumns(const ExpectedTokenPtr &token) bool CompletionComparer::isTokenOnColumnList(const ExpectedTokenPtr &token, const QList &columnList) { - foreach (SelectResolver::Column column, columnList) + for (SelectResolver::Column column : columnList) { // If column name doesn't match, then it's not this column if (token->value.compare(column.column, Qt::CaseInsensitive) != 0) diff --git a/SQLiteStudio3/coreSQLiteStudio/completionhelper.cpp b/SQLiteStudio3/coreSQLiteStudio/completionhelper.cpp index aae4a60..f0d00a1 100644 --- a/SQLiteStudio3/coreSQLiteStudio/completionhelper.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/completionhelper.cpp @@ -149,7 +149,7 @@ CompletionHelper::Results CompletionHelper::getExpectedTokens() // Convert accepted tokens to expected tokens QList results; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) results += getExpectedTokens(token); // Filter redundant tokens from results @@ -233,7 +233,7 @@ QList CompletionHelper::getExpectedTokens(TokenPtr token) break; case Token::CTX_FK_MATCH: { - foreach (QString kw, getFkMatchKeywords()) + for (QString kw : getFkMatchKeywords()) results += getExpectedToken(ExpectedToken::KEYWORD, kw); break; @@ -296,7 +296,7 @@ QList CompletionHelper::getExpectedTokens(TokenPtr token) } case Token::CTX_JOIN_OPTS: { - foreach (QString joinKw, getJoinKeywords()) + for (QString joinKw : getJoinKeywords()) results += getExpectedToken(ExpectedToken::KEYWORD, joinKw); break; } @@ -486,7 +486,7 @@ QList CompletionHelper::getDatabases() results += getExpectedToken(ExpectedToken::DATABASE, "temp", "temp", tr("Temporary objects database")); QSet databases = schemaResolver->getDatabases(); - foreach (QString dbName, databases) + for (QString dbName : databases) { if (dbAttacher->getDbNameToAttach().containsRight(dbName, Qt::CaseInsensitive)) continue; @@ -496,7 +496,7 @@ QList CompletionHelper::getDatabases() Dialect dialect = db->getDialect(); - foreach (Db* otherDb, DBLIST->getValidDbList()) + for (Db* otherDb : DBLIST->getValidDbList()) { if (otherDb->getDialect() != dialect) continue; @@ -546,7 +546,7 @@ QList CompletionHelper::getObjects(ExpectedToken::Type type, c } QList results; - foreach (QString object, schemaResolver->getObjects(dbName, typeStr)) + for (QString object : schemaResolver->getObjects(dbName, typeStr)) results << getExpectedToken(type, object, originalDbName); return results; @@ -599,8 +599,8 @@ QList CompletionHelper::getColumnsNoPrefix() // Getting all tables for main db. If any column repeats in many tables, // then tables are stored as a list for the same column. - foreach (QString table, schemaResolver->getTables(QString::null)) - foreach (QString column, schemaResolver->getTableColumns(table)) + for (QString table : schemaResolver->getTables(QString::null)) + for (QString column : schemaResolver->getTableColumns(table)) columnList[column] += table; // Now, for each column the expected token is created. @@ -621,7 +621,7 @@ QList CompletionHelper::getColumnsNoPrefix(const QString& colu QList results; QStringList availableTableNames; - foreach (SelectResolver::Table resolverTable, selectAvailableTables + parentSelectAvailableTables) + for (SelectResolver::Table resolverTable : selectAvailableTables + parentSelectAvailableTables) { // This method is called only when collecting columns of tables in "main" database. // If here we have resolved table from other database, we don't compare it. @@ -632,11 +632,11 @@ QList CompletionHelper::getColumnsNoPrefix(const QString& colu } int availableTableCount = 0; - foreach (QString availTable, availableTableNames) + for (QString availTable : availableTableNames) if (tables.contains(availTable)) availableTableCount++; - foreach (QString table, tables) + for (QString table : tables) { // Table prefix is used only if there is more than one table in FROM clause // that has this column, or table alias was used. @@ -649,10 +649,10 @@ QList CompletionHelper::getColumnsNoPrefix(const QString& colu QString label = table; if (tableToAlias.contains(prefix)) { - foreach (prefix, tableToAlias[prefix]) + for (const QString& resolvedPrefix : tableToAlias[prefix]) { - label = prefix+" = "+table; - results << getExpectedToken(ExpectedToken::COLUMN, column, table, label, prefix); + label = resolvedPrefix+" = "+table; + results << getExpectedToken(ExpectedToken::COLUMN, column, table, label, resolvedPrefix); } } else @@ -700,7 +700,7 @@ QList CompletionHelper::getColumns(const QString &prefixTable) } // Get columns for given table in main db. - foreach (const QString& column, schemaResolver->getTableColumns(dbName, table)) + for (const QString& column : schemaResolver->getTableColumns(dbName, table)) results << getExpectedToken(ExpectedToken::COLUMN, column, table, label); return results; @@ -712,7 +712,7 @@ QList CompletionHelper::getColumns(const QString &prefixDb, co // Get columns for given table in given db. QString context = prefixDb+"."+prefixTable; - foreach (const QString& column, schemaResolver->getTableColumns(translateDatabase(prefixDb), prefixTable)) + for (const QString& column : schemaResolver->getTableColumns(translateDatabase(prefixDb), prefixTable)) results << getExpectedToken(ExpectedToken::COLUMN, column, context); return results; @@ -724,7 +724,7 @@ QList CompletionHelper::getFavoredColumns(const QListprefix.isNull() && columnsToAdd.contains(token->value)) columnsToAdd.removeOne(token->value); @@ -735,7 +735,7 @@ QList CompletionHelper::getFavoredColumns(const QList()->table; QList results; - foreach (const QString& column, columnsToAdd) + for (const QString& column : columnsToAdd) results << getExpectedToken(ExpectedToken::COLUMN, column, ctxInfo); return results; @@ -760,7 +760,7 @@ QList CompletionHelper::getFunctions(Db* db) functions << fn->toString(); QList expectedTokens; - foreach (QString function, functions) + for (QString function : functions) expectedTokens += getExpectedToken(ExpectedToken::FUNCTION, function); return expectedTokens; @@ -775,7 +775,7 @@ QList CompletionHelper::getPragmas(Dialect dialect) pragmas = sqlite3Pragmas; QList expectedTokens; - foreach (QString pragma, pragmas) + for (QString pragma : pragmas) expectedTokens += getExpectedToken(ExpectedToken::PRAGMA, pragma); return expectedTokens; @@ -790,7 +790,7 @@ QList CompletionHelper::getCollations() << results->getErrorText(); } QList expectedTokens; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) expectedTokens += getExpectedToken(ExpectedToken::COLLATION, row->value("name").toString()); return expectedTokens; @@ -911,7 +911,7 @@ void CompletionHelper::filterContextKeywords(QList &resultsSoF { bool wasJoinKw = false; bool wasFkMatchKw = false; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) { if (token->type == Token::CTX_JOIN_OPTS) wasJoinKw = true; @@ -941,7 +941,7 @@ void CompletionHelper::filterContextKeywords(QList &resultsSoF void CompletionHelper::filterOtherId(QList &resultsSoFar, const TokenList &tokens) { bool wasCtx = false; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) { switch (token->type) { @@ -1273,7 +1273,7 @@ bool CompletionHelper::testQueryToken(int tokenPosition, Token::Type type, const bool CompletionHelper::cursorAfterTokenMaps(SqliteStatement* stmt, const QStringList& mapNames) { TokenList tokens; - foreach (const QString& name, mapNames) + for (const QString& name : mapNames) { if (!stmt->tokensMap.contains(name) || stmt->tokensMap[name].size() == 0) continue; @@ -1292,7 +1292,7 @@ bool CompletionHelper::cursorAfterTokenMaps(SqliteStatement* stmt, const QString bool CompletionHelper::cursorBeforeTokenMaps(SqliteStatement* stmt, const QStringList& mapNames) { TokenList tokens; - foreach (const QString& name, mapNames) + for (const QString& name : mapNames) { if (!stmt->tokensMap.contains(name) || stmt->tokensMap[name].size() == 0) continue; @@ -1391,7 +1391,7 @@ void CompletionHelper::extractSelectAvailableColumnsAndTables() void CompletionHelper::extractTableAliasMap() { - foreach (SelectResolver::Column column, selectAvailableColumns) + for (SelectResolver::Column column : selectAvailableColumns) { if (column.type != SelectResolver::Column::COLUMN) continue; @@ -1407,7 +1407,7 @@ void CompletionHelper::extractTableAliasMap() // Given the above, we can extract table aliases in an order from deepest // to shallowest, skipping any duplicates, becase the deeper alias is mentioned, // the higher is its priority. - foreach (SelectResolver::Column column, parentSelectAvailableColumns) + for (SelectResolver::Column column : parentSelectAvailableColumns) { if (column.type != SelectResolver::Column::COLUMN) continue; @@ -1429,7 +1429,7 @@ void CompletionHelper::extractCreateTableColumns() return; SqliteCreateTablePtr createTable = parsedQuery.dynamicCast(); - foreach (SqliteCreateTable::Column* col, createTable->columns) + for (SqliteCreateTable::Column* col : createTable->columns) favoredColumnNames << col->name; } diff --git a/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.cpp b/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.cpp index fb7d199..0c7295a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.cpp @@ -2,6 +2,7 @@ #include "config_builder/cfgcategory.h" #include "config_builder/cfgentry.h" #include "common/global.h" +#include CfgMain* lastCreatedCfgMain = nullptr; QList* CfgMain::instances = nullptr; @@ -153,6 +154,39 @@ QList CfgMain::getEntries() const return entries; } +void CfgMain::setValuesFromQVariant(const QVariant& cfgMainHash) +{ + QHash mainHash = cfgMainHash.toHash(); + if (mainHash.isEmpty()) + return; + + QHash::const_iterator mainIt = mainHash.begin(); + if (mainIt.key() != name) + { + qWarning() << "Tried to set CfgMain values from QVariant which does not have such main in its registry."; + return; + } + + QHash categoriesHash = mainIt.value().toHash(); + QHash entriesHash; + QHash entries; + for (QHash::const_iterator categoryIt = childs.begin(); categoryIt != childs.end(); categoryIt++) + { + if (!categoriesHash.contains(categoryIt.key())) + continue; + + entriesHash = categoriesHash[categoryIt.key()].toHash(); + entries = categoryIt.value()->getEntries(); + for (QHash::const_iterator entryIt = entries.begin(); entryIt != entries.end(); entryIt++) + { + if (!entriesHash.contains(entryIt.key())) + continue; + + entryIt.value()->set(entriesHash[entryIt.key()]); + } + } +} + bool CfgMain::isPersistable() const { return persistable; @@ -173,6 +207,26 @@ QString CfgMain::getTitle() const return title; } +QVariant CfgMain::toQVariant() const +{ + QHash categoriesVariant; + QHash entriesVariant; + QHash entries; + for (QHash::const_iterator categoryIt = childs.begin(); categoryIt != childs.end(); categoryIt++) + { + entries = categoryIt.value()->getEntries(); + entriesVariant.clear(); + for (QHash::const_iterator entryIt = entries.begin(); entryIt != entries.end(); entryIt++) + entriesVariant[entryIt.key()] = entryIt.value()->get(); + + categoriesVariant[categoryIt.key()] = entriesVariant; + } + + QHash mainVariant; + mainVariant[name] = categoriesVariant; + return mainVariant; +} + CfgMain::operator CfgMain*() { return this; diff --git a/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.h b/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.h index ea11c6d..4e84bef 100644 --- a/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.h +++ b/SQLiteStudio3/coreSQLiteStudio/config_builder/cfgmain.h @@ -37,12 +37,27 @@ class API_EXPORT CfgMain QStringList getPaths() const; QList getEntries() const; + /** + * @brief Accepts QVariant produced by toQVariant(). + * + * This method assumes that the QVariant is actually a multi-level QHash + * produced by toQVariant() method. + * It sets all values recursivly using values from provided QVariant. + */ + void setValuesFromQVariant(const QVariant& cfgMainHash); + bool isPersistable() const; QString getName() const; const char* getMetaName() const; QString getTitle() const; operator CfgMain*(); + /** + * @brief Serializes this CfgMain to recursive QHash. + * @return Recursive QHash, where top level has one entry (name of CfgMain), then next level has keys as CfgCategory names, and last one has keys as CfgEntry names. + */ + QVariant toQVariant() const; + private: QString name; const char* metaName; diff --git a/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.pro b/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.pro index 8c3c21a..3eba953 100644 --- a/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.pro +++ b/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.pro @@ -18,8 +18,7 @@ TARGET = coreSQLiteStudio TEMPLATE = lib win32 { - LIBS += -lpsapi $$PWD/../../../lib/libquazip.a - LIBS += -limagehlp + LIBS += -lpsapi -limagehlp THE_FILE = $$PWD/qt.conf THE_DEST = $${DESTDIR} @@ -41,6 +40,7 @@ macx: { QMAKE_POST_LINK += ; $$QMAKE_MKDIR $$DESTDIR/SQLiteStudio.app QMAKE_POST_LINK += ; $$QMAKE_MKDIR $$DESTDIR/SQLiteStudio.app/Contents QMAKE_POST_LINK += ; $$QMAKE_COPY $$PWD/Info.plist $$DESTDIR/SQLiteStudio.app/Contents + LIBS += -L/usr/local/lib } LIBS += -lsqlite3 @@ -54,7 +54,8 @@ portable { CONFIG += c++11 QMAKE_CXXFLAGS += -pedantic -TRANSLATIONS += translations/coreSQLiteStudio_de.ts \ +TRANSLATIONS += translations/coreSQLiteStudio_ro_RO.ts \ + translations/coreSQLiteStudio_de.ts \ translations/coreSQLiteStudio_it.ts \ translations/coreSQLiteStudio_zh_CN.ts \ translations/coreSQLiteStudio_sk.ts \ @@ -206,7 +207,6 @@ SOURCES += sqlitestudio.cpp \ plugins/builtinplugin.cpp \ plugins/scriptingqtdbproxy.cpp \ plugins/sqlformatterplugin.cpp \ - services/bugreporter.cpp \ services/updatemanager.cpp \ config_builder/cfgmain.cpp \ config_builder/cfgcategory.cpp \ @@ -227,7 +227,11 @@ SOURCES += sqlitestudio.cpp \ common/private/blockingsocketprivate.cpp \ querygenerator.cpp \ common/bistrhash.cpp \ - plugins/dbpluginstdfilebase.cpp + plugins/dbpluginstdfilebase.cpp \ + common/xmldeserializer.cpp \ + services/impl/sqliteextensionmanagerimpl.cpp \ + common/lazytrigger.cpp \ + parser/ast/sqliteupsert.cpp HEADERS += sqlitestudio.h\ coreSQLiteStudio_global.h \ @@ -397,7 +401,6 @@ HEADERS += sqlitestudio.h\ plugins/builtinplugin.h \ plugins/scriptingqtdbproxy.h \ plugins/codeformatterplugin.h \ - services/bugreporter.h \ services/updatemanager.h \ config_builder/cfgmain.h \ config_builder/cfgcategory.h \ @@ -424,7 +427,13 @@ HEADERS += sqlitestudio.h\ parser/ast/sqliteextendedindexedcolumn.h \ querygenerator.h \ common/sortedset.h \ - plugins/dbpluginstdfilebase.h + plugins/dbpluginstdfilebase.h \ + common/xmldeserializer.h \ + common/valuelocker.h \ + services/sqliteextensionmanager.h \ + services/impl/sqliteextensionmanagerimpl.h \ + common/lazytrigger.h \ + parser/ast/sqliteupsert.h unix: { target.path = $$LIBDIR @@ -433,6 +442,7 @@ unix: { OTHER_FILES += \ parser/lempar.c \ + parser/lemon.c \ parser/sqlite3_parse.y \ parser/sqlite2_parse.y \ parser/run_lemon.sh \ @@ -444,8 +454,9 @@ OTHER_FILES += \ licenses/diff_match.txt \ licenses/gpl.txt \ ChangeLog.txt \ - qt.conf \ - Info.plist + qt.conf + \ + Info.plist FORMS += \ plugins/populatesequence.ui \ @@ -458,6 +469,10 @@ FORMS += \ RESOURCES += \ coreSQLiteStudio.qrc +DISTFILES += \ + licenses/mit.txt + + diff --git a/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.qrc b/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.qrc index d58efc1..f0bc89f 100644 --- a/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.qrc +++ b/SQLiteStudio3/coreSQLiteStudio/coreSQLiteStudio.qrc @@ -17,8 +17,10 @@ licenses/lgpl.txt licenses/diff_match.txt licenses/gpl.txt + licenses/mit.txt + translations/coreSQLiteStudio_ro_RO.qm translations/coreSQLiteStudio_pl.qm translations/coreSQLiteStudio_ru.qm translations/coreSQLiteStudio_fr.qm @@ -27,6 +29,3 @@ translations/coreSQLiteStudio_de.qm - - - diff --git a/SQLiteStudio3/coreSQLiteStudio/csvformat.cpp b/SQLiteStudio3/coreSQLiteStudio/csvformat.cpp index 151fffd..c5019c3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/csvformat.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/csvformat.cpp @@ -10,6 +10,7 @@ CsvFormat::CsvFormat() CsvFormat::CsvFormat(const QString& columnSeparator, const QString& rowSeparator) : columnSeparator(columnSeparator), rowSeparator(rowSeparator) { + calculateSeparatorMaxLengths(); } CsvFormat::CsvFormat(const QStringList &columnSeparators, const QStringList &rowSeparators) @@ -31,9 +32,23 @@ CsvFormat::CsvFormat(const QStringList &columnSeparators, const QStringList &row } else if (columnSeparators.size() > 0) this->columnSeparator = columnSeparators.first(); + + calculateSeparatorMaxLengths(); } CsvFormat::CsvFormat(const QString& columnSeparator, const QString& rowSeparator, bool strictRowSeparator, bool strictColumnSeparator) : columnSeparator(columnSeparator), rowSeparator(rowSeparator), strictColumnSeparator(strictColumnSeparator), strictRowSeparator(strictRowSeparator) { + calculateSeparatorMaxLengths(); +} + +void CsvFormat::calculateSeparatorMaxLengths() +{ + maxColumnSeparatorLength = columnSeparator.length(); + for (const QString& sep : columnSeparators) + maxColumnSeparatorLength = qMax(sep.length(), maxColumnSeparatorLength); + + maxRowSeparatorLength = rowSeparator.length(); + for (const QString& sep : rowSeparators) + maxRowSeparatorLength = qMax(sep.length(), maxRowSeparatorLength); } diff --git a/SQLiteStudio3/coreSQLiteStudio/csvformat.h b/SQLiteStudio3/coreSQLiteStudio/csvformat.h index 3e8dda2..4b6df69 100644 --- a/SQLiteStudio3/coreSQLiteStudio/csvformat.h +++ b/SQLiteStudio3/coreSQLiteStudio/csvformat.h @@ -12,6 +12,8 @@ struct API_EXPORT CsvFormat CsvFormat(const QStringList& columnSeparators, const QStringList& rowSeparators); CsvFormat(const QString& columnSeparator, const QString& rowSeparator, bool strictRowSeparator, bool strictColumnSeparator); + void calculateSeparatorMaxLengths(); + QString columnSeparator; QString rowSeparator; QStringList columnSeparators; @@ -20,6 +22,8 @@ struct API_EXPORT CsvFormat bool strictRowSeparator = false; bool multipleRowSeparators = false; bool multipleColumnSeparators = false; + int maxColumnSeparatorLength = 0; + int maxRowSeparatorLength = 0; static const CsvFormat DEFAULT; }; diff --git a/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp b/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp index ce568e9..4c4ed0e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp @@ -1,167 +1,193 @@ #include "csvserializer.h" #include +#include +#include +#include -// TODO write unit tests for CsvSerializer +template +bool isCsvSeparator(QList& ahead, const C& theChar, const QStringList& separators) +{ + for (const QString& sep : separators) + if (isCsvSeparator(ahead, theChar, sep)) + return true; + + return false; +} template -bool isCsvColumnSeparator(QTextStream& data, const C& theChar, const CsvFormat& format) +bool isCsvSeparator(QList& ahead, const C& theChar, const QString& singleSeparator) +{ + if (singleSeparator[0] != theChar) + return false; + + typename QList::const_iterator aheadIter = ahead.begin(); + int singleSeparatorSize = singleSeparator.size(); + int i = 1; + while (aheadIter != ahead.end() && i < singleSeparatorSize) + { + if (singleSeparator[i++] != *aheadIter++) + return false; + } + + if (i < singleSeparatorSize) + return false; + + for (int i = 1, total = singleSeparator.size(); i < total; ++i) + ahead.removeFirst(); + + return true; +} + +template +bool isCsvColumnSeparator(QList& ahead, const C& theChar, const CsvFormat& format) { if (!format.strictColumnSeparator) return format.columnSeparator.contains(theChar); // Strict checking (characters in defined order make a separator) - QStringList separators; if (format.multipleColumnSeparators) - separators = format.columnSeparators; - else - separators << format.columnSeparator; + return isCsvSeparator(ahead, theChar, format.columnSeparators); - qint64 origPos = data.pos(); - bool match = true; - for (const QString sep : separators) - { - match = true; - data.seek(origPos - 1); - C nextChar; - for (const QChar& c : sep) - { - data >> nextChar; - if (c != nextChar) - { - data.seek(origPos); - match = false; - break; - } - } - if (match) - break; - } - - return match; + return isCsvSeparator(ahead, theChar, format.columnSeparator); } template -bool isCsvRowSeparator(QTextStream& data, const C& theChar, const CsvFormat& format) +bool isCsvRowSeparator(QList& ahead, const C& theChar, const CsvFormat& format) { if (!format.strictRowSeparator) return format.rowSeparator.contains(theChar); // Strict checking (characters in defined order make a separator) - QStringList separators; if (format.multipleRowSeparators) - separators = format.rowSeparators; - else - separators << format.rowSeparator; + return isCsvSeparator(ahead, theChar, format.rowSeparators); + + return isCsvSeparator(ahead, theChar, format.rowSeparator); +} - qint64 origPos = data.pos(); - bool match = true; - for (const QString sep : separators) +template +void readAhead(QTextStream& data, QList& ahead, int desiredSize) +{ + C singleValue; + while (!data.atEnd() && ahead.size() < desiredSize) { - match = true; - data.seek(origPos - 1); - C nextChar; - for (const QChar& c : sep) - { - data >> nextChar; - if (data.atEnd() || c != nextChar) - { - data.seek(origPos); - match = false; - break; - } - } - if (match) - break; + data >> singleValue; + ahead << singleValue; } - - return match; } template -QList> typedDeserialize(QTextStream& data, const CsvFormat& format, bool oneEntry) +void typedDeserializeInternal(QTextStream& data, const CsvFormat& format, QList* cells, QList>* rows) { - QList> rows; - QList cells; - bool quotes = false; bool sepAsLast = false; + int separatorMaxAhead = qMax(format.maxColumnSeparatorLength, format.maxRowSeparatorLength) - 1; T field = ""; - C c0; - C c1; + field.reserve(3); + C theChar; + QList ahead; - while (!data.atEnd()) + while (!data.atEnd() || !ahead.isEmpty()) { - data >> c0; + if (!ahead.isEmpty()) + theChar = ahead.takeFirst(); + else + data >> theChar; + sepAsLast = false; - if (!quotes && c0 == '"' ) + if (!quotes && theChar == '"' ) { quotes = true; } - else if (quotes && c0 == '"' ) + else if (quotes && theChar == '"' ) { if (!data.atEnd()) { - data >> c1; - if (c1 == '"' ) + readAhead(data, ahead, 1); + if (ahead.isEmpty()) + { + field += theChar; + } + else if (ahead.first() == '"' ) { - field += c0; + field += theChar; + ahead.removeFirst(); } else { quotes = false; - data.seek(data.pos() - 1); } } else { if (field.length() == 0) - cells << field; + *cells << field; quotes = false; } } else if (!quotes) { - if (isCsvColumnSeparator(data, c0, format)) + readAhead(data, ahead, separatorMaxAhead); + if (isCsvColumnSeparator(ahead, theChar, format)) { - cells << field; - field = ""; + *cells << field; + field.truncate(0); sepAsLast = true; } - else if (isCsvRowSeparator(data, c0, format)) + else if (isCsvRowSeparator(ahead, theChar, format)) { - cells << field; - rows << cells; - cells.clear(); - field = ""; - if (oneEntry) + *cells << field; + field.truncate(0); + if (rows) + { + *rows << *cells; + cells->clear(); + } + else + { break; + } } else { - field += c0; + field += theChar; } } else { - field += c0; + field += theChar; } } if (field.size() > 0 || sepAsLast) - cells << field; + *cells << field; - if (cells.size() > 0) - rows << cells; + if (rows && cells->size() > 0) + *rows << *cells; +} +template +QList> typedDeserialize(QTextStream& data, const CsvFormat& format) +{ + QList> rows; + QList cells; + typedDeserializeInternal(data, format, &cells, &rows); return rows; } +template +QList typedDeserializeOneEntry(QTextStream& data, const CsvFormat& format) +{ + QList cells; + typedDeserializeInternal(data, format, &cells, nullptr); + return cells; +} + QString CsvSerializer::serialize(const QList& data, const CsvFormat& format) { QStringList outputRows; - foreach (const QStringList& dataRow, data) + for (const QStringList& dataRow : data) outputRows << serialize(dataRow, format); return outputRows.join(format.rowSeparator); @@ -172,7 +198,7 @@ QString CsvSerializer::serialize(const QStringList& data, const CsvFormat& forma QString value; bool hasQuote; QStringList outputCells; - foreach (const QString& rowValue, data) + for (const QString& rowValue : data) { value = rowValue; @@ -191,27 +217,19 @@ QString CsvSerializer::serialize(const QStringList& data, const CsvFormat& forma QStringList CsvSerializer::deserializeOneEntry(QTextStream& data, const CsvFormat& format) { - QList deserialized = CsvSerializer::deserialize(data, format, true); - if (deserialized.size() > 0) - return deserialized.first(); - - return QStringList(); -} - -QList CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format) -{ - return CsvSerializer::deserialize(data, format, false); + QList deserialized = typedDeserializeOneEntry(data, format); + return QStringList(deserialized); } QList> CsvSerializer::deserialize(const QByteArray& data, const CsvFormat& format) { QTextStream stream(data, QIODevice::ReadWrite); - return typedDeserialize(stream, format, false); + return typedDeserialize(stream, format); } -QList CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format, bool oneEntry) +QList CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format) { - QList> deserialized = typedDeserialize(data, format, oneEntry); + QList> deserialized = typedDeserialize(data, format); QList finalList; for (const QList& resPart : deserialized) @@ -224,6 +242,6 @@ QList CsvSerializer::deserialize(const QString& data, const CsvForm { QString dataString = data; QTextStream stream(&dataString, QIODevice::ReadWrite); - return deserialize(stream, format, false); + return deserialize(stream, format); } diff --git a/SQLiteStudio3/coreSQLiteStudio/csvserializer.h b/SQLiteStudio3/coreSQLiteStudio/csvserializer.h index 0b7e095..f3ed91f 100644 --- a/SQLiteStudio3/coreSQLiteStudio/csvserializer.h +++ b/SQLiteStudio3/coreSQLiteStudio/csvserializer.h @@ -15,9 +15,6 @@ class API_EXPORT CsvSerializer static QList> deserialize(const QByteArray& data, const CsvFormat& format); static QList deserialize(QTextStream& data, const CsvFormat& format); static QStringList deserializeOneEntry(QTextStream& data, const CsvFormat& format); - - private: - static QList deserialize(QTextStream& data, const CsvFormat& format, bool oneEntry); }; #endif // CSVSERIALIZER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/datatype.cpp b/SQLiteStudio3/coreSQLiteStudio/datatype.cpp index d90a6b0..38d47d5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/datatype.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/datatype.cpp @@ -44,9 +44,7 @@ DataType::DataType() DataType::DataType(const QString& fullTypeString) { static const QRegularExpression - re(R"(" - "^(?[^\)]*)\s*(\((?[\d\.]+)\s*(,\s*(?[\d\.])+\s*)?\))?$" - ")"); + re(R"(^(?[^\)]*)\s*(\((?[\d\.]+)\s*(,\s*(?[\d\.])+\s*)?\))?$)"); QRegularExpressionMatch match = re.match(fullTypeString); if (!match.hasMatch()) diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp index cd9b972..70037b0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.cpp @@ -8,6 +8,7 @@ #include "sqlerrorresults.h" #include "sqlerrorcodes.h" #include "services/notifymanager.h" +#include "services/sqliteextensionmanager.h" #include "log.h" #include "parser/lexer.h" #include @@ -120,7 +121,7 @@ void AbstractDb::registerAllFunctions() void AbstractDb::registerAllCollations() { - foreach (const QString& name, registeredCollations) + for (const QString& name : registeredCollations) { if (!deregisterCollation(name)) qWarning() << "Failed to deregister custom collation:" << name; @@ -128,13 +129,49 @@ void AbstractDb::registerAllCollations() registeredCollations.clear(); - foreach (const CollationManager::CollationPtr& collPtr, COLLATIONS->getCollationsForDatabase(getName())) + for (const CollationManager::CollationPtr& collPtr : COLLATIONS->getCollationsForDatabase(getName())) registerCollation(collPtr->name); disconnect(COLLATIONS, SIGNAL(collationListChanged()), this, SLOT(registerAllCollations())); connect(COLLATIONS, SIGNAL(collationListChanged()), this, SLOT(registerAllCollations())); } +void AbstractDb::loadExtensions() +{ + for (const SqliteExtensionManager::ExtensionPtr& extPtr : SQLITE_EXTENSIONS->getExtensionForDatabase(getName())) + loadedExtensionCount += loadExtension(extPtr->filePath, extPtr->initFunc) ? 1 : 0; + + connect(SQLITE_EXTENSIONS, SIGNAL(extensionListChanged()), this, SLOT(reloadExtensions())); +} + +void AbstractDb::reloadExtensions() +{ + if (!isOpen()) + return; + + bool doOpen = false; + if (loadedExtensionCount > 0) + { + if (!closeQuiet()) + { + qWarning() << "Failed to close database for extension reloading."; + return; + } + + doOpen = true; + loadedExtensionCount = 0; + disconnect(SQLITE_EXTENSIONS, SIGNAL(extensionListChanged()), this, SLOT(reloadExtensions())); + } + + if (doOpen && !openQuiet()) + { + qCritical() << "Failed to re-open database for extension reloading."; + return; + } + + loadExtensions(); +} + bool AbstractDb::isOpen() { // We use separate mutex for connection state to avoid situations, when some query is being executed, @@ -166,7 +203,7 @@ QString AbstractDb::generateUniqueDbNameNoLock() } QStringList existingDatabases; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) existingDatabases << row->value("name").toString(); return generateUniqueName("attached", existingDatabases); @@ -347,6 +384,9 @@ bool AbstractDb::openAndSetup() // Implementation specific initialization initAfterOpen(); + // Load extension + loadExtensions(); + // Custom SQL functions registerAllFunctions(); @@ -658,7 +698,7 @@ void AbstractDb::detachAll() if (!isOpenInternal()) return; - foreach (Db* db, attachedDbMap.rightValues()) + for (Db* db : attachedDbMap.rightValues()) detachInternal(db); } @@ -683,7 +723,7 @@ QString AbstractDb::getUniqueNewObjectName(const QString &attachedDbName) QSet existingNames; SqlQueryPtr results = exec(QString("SELECT name FROM %1.sqlite_master").arg(dbName)); - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) existingNames << row->value(0).toString(); return randStrNotIn(16, existingNames, false); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h index 3f2b4c0..c69c9f2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb.h @@ -86,6 +86,7 @@ class API_EXPORT AbstractDb : public Db void setTimeout(int secs); int getTimeout() const; bool isValid() const; + void loadExtensions(); protected: struct FunctionUserData @@ -445,6 +446,8 @@ class API_EXPORT AbstractDb : public Db */ QStringList registeredCollations; + int loadedExtensionCount = 0; + private slots: /** * @brief Handles asynchronous execution results. @@ -464,6 +467,7 @@ class API_EXPORT AbstractDb : public Db bool openForProbing(); void registerAllFunctions(); void registerAllCollations(); + void reloadExtensions(); }; /** diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h index 7419f8c..51465f9 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include /** * @brief Complete implementation of SQLite 2 driver for SQLiteStudio. @@ -42,9 +44,11 @@ class AbstractDb2 : public AbstractDb * All values from this constructor are just passed to AbstractDb constructor. */ AbstractDb2(const QString& name, const QString& path, const QHash& connOptions); - ~AbstractDb2(); + bool loadExtension(const QString& filePath, const QString& initFunc = QString()); + bool isComplete(const QString& sql) const; + protected: bool isOpenInternal(); void interruptExecution(); @@ -131,6 +135,7 @@ class AbstractDb2 : public AbstractDb int dbErrorCode = SQLITE_OK; QList userDataList; QList queries; + QMutex* dbOperMutex = nullptr; }; //------------------------------------------------------------------------------------ @@ -141,15 +146,31 @@ template AbstractDb2::AbstractDb2(const QString& name, const QString& path, const QHash& connOptions) : AbstractDb(name, path, connOptions) { + dbOperMutex = new QMutex(QMutex::Recursive); } template AbstractDb2::~AbstractDb2() { + safe_delete(dbOperMutex); if (isOpenInternal()) closeInternal(); } +template +bool AbstractDb2::loadExtension(const QString& filePath, const QString& initFunc) +{ + UNUSED(filePath); + UNUSED(initFunc); + return false; +} + +template +bool AbstractDb2::isComplete(const QString& sql) const +{ + return sqlite_complete(sql.toUtf8().constData()); +} + template bool AbstractDb2::isOpenInternal() { @@ -168,6 +189,7 @@ void AbstractDb2::interruptExecution() if (!isOpenInternal()) return; + QMutexLocker mutexLocker(dbOperMutex); sqlite_interrupt(dbHandle); } @@ -189,6 +211,7 @@ bool AbstractDb2::openInternal() resetError(); sqlite* handle = nullptr; char* errMsg = nullptr; + QMutexLocker mutexLocker(dbOperMutex); handle = sqlite_open(path.toUtf8().constData(), 0, &errMsg); if (!handle) { @@ -214,6 +237,7 @@ bool AbstractDb2::closeInternal() cleanUp(); + QMutexLocker mutexLocker(dbOperMutex); sqlite_close(dbHandle); dbHandle = nullptr; return true; @@ -243,6 +267,7 @@ bool AbstractDb2::deregisterFunction(const QString& name, int argCount) if (!dbHandle) return false; + QMutexLocker mutexLocker(dbOperMutex); sqlite_create_function(dbHandle, name.toLatin1().data(), argCount, nullptr, nullptr); sqlite_create_aggregate(dbHandle, name.toLatin1().data(), argCount, nullptr, nullptr, nullptr); @@ -273,6 +298,7 @@ bool AbstractDb2::registerScalarFunction(const QString& name, int argCount) userData->argCount = argCount; userDataList << userData; + QMutexLocker mutexLocker(dbOperMutex); int res = sqlite_create_function(dbHandle, name.toUtf8().constData(), argCount, &AbstractDb2::evaluateScalar, userData); @@ -291,6 +317,7 @@ bool AbstractDb2::registerAggregateFunction(const QString& name, int argCount userData->argCount = argCount; userDataList << userData; + QMutexLocker mutexLocker(dbOperMutex); int res = sqlite_create_aggregate(dbHandle, name.toUtf8().constData(), argCount, &AbstractDb2::evaluateAggregateStep, &AbstractDb2::evaluateAggregateFinal, @@ -527,6 +554,7 @@ int AbstractDb2::Query::prepareStmt(const QString& processedQuery) char* errMsg = nullptr; const char* tail; QByteArray queryBytes = processedQuery.toUtf8(); + QMutexLocker mutexLocker(db->dbOperMutex); int res = sqlite_compile(db->dbHandle, queryBytes.constData(), &tail, &stmt, &errMsg); if (res != SQLITE_OK) { @@ -556,6 +584,7 @@ int AbstractDb2::Query::resetStmt() nextRowValues.clear(); char* errMsg = nullptr; + QMutexLocker mutexLocker(db->dbOperMutex); int res = sqlite_reset(stmt, &errMsg); if (res != SQLITE_OK) { @@ -576,23 +605,27 @@ bool AbstractDb2::Query::execInternal(const QList& args) if (!checkDbState()) return false; - ReadWriteLocker locker(&(db->dbOperLock), query, Dialect::Sqlite2, flags.testFlag(Db::Flag::NO_LOCK)); + QMutexLocker mutexLocker(db->dbOperMutex); logSql(db.data(), query, args, flags); - QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite2); - QString singleStr = replaceNamedParams(queryWithParams.first); - int res; if (stmt) res = resetStmt(); else - res = prepareStmt(singleStr); + res = prepareStmt(query); if (res != SQLITE_OK) return false; - for (int paramIdx = 1; paramIdx <= queryWithParams.second; paramIdx++) + int maxParamIdx = args.size(); + if (!flags.testFlag(Db::Flag::SKIP_PARAM_COUNTING)) + { + QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite2); + maxParamIdx = qMin(maxParamIdx, queryWithParams.second); + } + + for (int paramIdx = 1; paramIdx <= maxParamIdx; paramIdx++) { res = bindParam(paramIdx, args[paramIdx-1]); if (res != SQLITE_OK) @@ -612,7 +645,7 @@ bool AbstractDb2::Query::execInternal(const QHash& args) if (!checkDbState()) return false; - ReadWriteLocker locker(&(db->dbOperLock), query, Dialect::Sqlite2, flags.testFlag(Db::Flag::NO_LOCK)); + QMutexLocker mutexLocker(db->dbOperMutex); logSql(db.data(), query, args, flags); @@ -629,7 +662,7 @@ bool AbstractDb2::Query::execInternal(const QHash& args) return false; int paramIdx = 1; - foreach (const QString& paramName, queryWithParams.second) + for (const QString& paramName : queryWithParams.second) { if (!args.contains(paramName)) { @@ -665,9 +698,7 @@ template int AbstractDb2::Query::bindParam(int paramIdx, const QVariant& value) { if (value.isNull()) - { return sqlite_bind(stmt, paramIdx, nullptr, 0, 0); - } switch (value.type()) { @@ -686,6 +717,7 @@ int AbstractDb2::Query::bindParam(int paramIdx, const QVariant& value) } } + qWarning() << "sqlite_bind() MISUSE"; return SQLITE_MISUSE; // not going to happen } template @@ -747,19 +779,14 @@ bool AbstractDb2::Query::hasNextInternal() template int AbstractDb2::Query::fetchFirst() { + QMutexLocker mutexLocker(db->dbOperMutex); rowAvailable = true; int res = fetchNext(); + affected = 0; if (res == SQLITE_OK) { - if (colCount == 0) - { - affected = 0; - } - else - { - affected = sqlite_changes(db->dbHandle); - insertRowId["ROWID"] = sqlite_last_insert_rowid(db->dbHandle); - } + affected = sqlite_changes(db->dbHandle); + insertRowId["ROWID"] = sqlite_last_insert_rowid(db->dbHandle); } return res; } @@ -783,6 +810,7 @@ QString AbstractDb2::Query::finalize() if (stmt) { char* errMsg = nullptr; + QMutexLocker mutexLocker(db->dbOperMutex); sqlite_finalize(stmt, &errMsg); stmt = nullptr; if (errMsg) @@ -814,6 +842,7 @@ int AbstractDb2::Query::fetchNext() int res; int secondsSpent = 0; + QMutexLocker mutexLocker(db->dbOperMutex); while ((res = sqlite_step(stmt, &columnsCount, &values, &columns)) == SQLITE_BUSY && secondsSpent < db->getTimeout()) { QThread::sleep(1); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h index db9bc02..f45e475 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb3.h @@ -44,6 +44,9 @@ class AbstractDb3 : public AbstractDb AbstractDb3(const QString& name, const QString& path, const QHash& connOptions); ~AbstractDb3(); + bool loadExtension(const QString& filePath, const QString& initFunc = QString()); + bool isComplete(const QString& sql) const; + protected: bool isOpenInternal(); void interruptExecution(); @@ -315,6 +318,31 @@ AbstractDb3::~AbstractDb3() closeInternal(); } +template +bool AbstractDb3::loadExtension(const QString& filePath, const QString& initFunc) +{ + char* errMsg = nullptr; + int res = T::load_extension(dbHandle, filePath.toUtf8().constData(), initFunc.isEmpty() ? nullptr : initFunc.toUtf8().constData(), &errMsg); + if (res != T::OK) + { + dbErrorMessage = QObject::tr("Could not load extension %1: %2").arg(filePath, extractLastError()); + dbErrorCode = res; + if (errMsg) + { + dbErrorMessage = QObject::tr("Could not load extension %1: %2").arg(filePath, QString::fromUtf8(errMsg)); + T::free(errMsg); + } + return false; + } + return true; +} + +template +bool AbstractDb3::isComplete(const QString& sql) const +{ + return T::complete(sql.toUtf8().constData()); +} + template bool AbstractDb3::isOpenInternal() { @@ -358,6 +386,7 @@ bool AbstractDb3::openInternal() return false; } dbHandle = handle; + T::enable_load_extension(dbHandle, 1); return true; } @@ -392,7 +421,6 @@ bool AbstractDb3::initAfterCreated() template void AbstractDb3::initAfterOpen() { - T::enable_load_extension(dbHandle, true); registerDefaultCollationRequestHandler();; exec("PRAGMA foreign_keys = 1;", Flag::NO_LOCK); exec("PRAGMA recursive_triggers = 1;", Flag::NO_LOCK); @@ -864,8 +892,6 @@ bool AbstractDb3::Query::execInternal(const QList& args) ReadWriteLocker locker(&(db->dbOperLock), query, Dialect::Sqlite3, flags.testFlag(Db::Flag::NO_LOCK)); logSql(db.data(), query, args, flags); - QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite3); - int res; if (stmt) res = resetStmt(); @@ -875,8 +901,14 @@ bool AbstractDb3::Query::execInternal(const QList& args) if (res != T::OK) return false; + int maxParamIdx = args.size(); + if (!flags.testFlag(Db::Flag::SKIP_PARAM_COUNTING)) + { + QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite3); + maxParamIdx = qMin(maxParamIdx, queryWithParams.second); + } - for (int paramIdx = 1, argCount = args.size(); paramIdx <= queryWithParams.second && paramIdx <= argCount; paramIdx++) + for (int paramIdx = 1; paramIdx <= maxParamIdx; paramIdx++) { res = bindParam(paramIdx, args[paramIdx-1]); if (res != T::OK) diff --git a/SQLiteStudio3/coreSQLiteStudio/db/db.cpp b/SQLiteStudio3/coreSQLiteStudio/db/db.cpp index 977812a..ebe6731 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/db.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/db.cpp @@ -5,10 +5,12 @@ Db::Db() { +// qDebug() << "Db::Db()" << this; } Db::~Db() { +// qDebug() << "Db::~Db()" << this; } void Db::metaInit() diff --git a/SQLiteStudio3/coreSQLiteStudio/db/db.h b/SQLiteStudio3/coreSQLiteStudio/db/db.h index 4a9e80a..2ee79aa 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/db.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/db.h @@ -1,6 +1,7 @@ #ifndef DB_H #define DB_H +#include #include "returncode.h" #include "dialect.h" #include "services/functionmanager.h" @@ -10,13 +11,13 @@ #include "interruptable.h" #include "dbobjecttype.h" #include -#include #include #include #include #include #include #include +#include /** @file */ @@ -147,8 +148,13 @@ class API_EXPORT Db : public QObject, public Interruptable * of code, where the lock on Db was already set. Never (!) use this to ommit lock from different * threads. Justified situation is when you implement Db::initialDbSetup() in the derived class, * or when you implement SqlFunctionPlugin. Don't use it for the usual cases. + * This flag is ignored by SQLite2 plugin, because SQLite2 is not prepared for multithreaded + * processing, therefore all operations must be synchronized. */ - SKIP_DROP_DETECTION = 0x4, /**< Query execution will not notify about any detected objects dropped by the query. */ + SKIP_DROP_DETECTION = 0x4, /**< Query execution will not notify about any detected objects dropped by the query. + * Benefit is that it speeds up execution. */ + SKIP_PARAM_COUNTING = 0x8, /**< During execution with arguments as list the number of bind parameters will not be verified. + * This speeds up execution at cost of possible error if bind params in query don't match number of args. */ }; Q_DECLARE_FLAGS(Flags, Flag) @@ -478,6 +484,12 @@ class API_EXPORT Db : public QObject, public Interruptable */ virtual bool isReadable() = 0; + /** + * @brief Tells whether given SQL is a complete statement or not. + * @return true if given SQL is complete SQL (or more), or it misses some part. + */ + virtual bool isComplete(const QString& sql) const = 0; + /** * @brief Checks if the database is writable at the moment. * @return true if the database is writable, or false otherwise. @@ -623,7 +635,7 @@ class API_EXPORT Db : public QObject, public Interruptable * This method is used only to let the database know, that the given function exists in FunctionManager and we want it to be visible * in this database's context. When the function is called from SQL query, then the function execution is delegated to the FunctionManager. * - * For details about usage of custom SQL functions see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_SQL_functions + * For details about usage of custom SQL functions see https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-sql-functions * * @see FunctionManager */ @@ -646,7 +658,7 @@ class API_EXPORT Db : public QObject, public Interruptable * This method is used only to let the database know, that the given function exists in FunctionManager and we want it to be visible * in this database's context. When the function is called from SQL query, then the function execution is delegated to the FunctionManager. * - * For details about usage of custom SQL functions see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_SQL_functions + * For details about usage of custom SQL functions see https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-sql-functions * * @see FunctionManager */ @@ -663,7 +675,7 @@ class API_EXPORT Db : public QObject, public Interruptable * when comparing 2 values in the database in order to sort query results. The name passed to this method is a name of the collation * as it is used in SQL queries and also the same name must be used when defining collation in Collations editor window. * - * For details about usage of custom collations see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_collations + * For details about usage of custom collations see https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-sql-functions * * @see CollationManager */ @@ -678,6 +690,19 @@ class API_EXPORT Db : public QObject, public Interruptable */ virtual bool deregisterCollation(const QString& name) = 0; + /** + * @brief Loads a SQLite extension. + * @param filePath Absolute path to the extension file (dll/so/dylib). + * @param initFunc Optional entry point function. If empty, SQLite's default will be used. + * @return true on success, or false on failure. + * + * This function works only on SQLite 3 drivers, as SQLite 2 does not support extensions. + * More details can be found at https://sqlite.org/c3ref/load_extension.html + * + * If function returns false, use getErrorText() to discover details. + */ + virtual bool loadExtension(const QString& filePath, const QString& initFunc = QString()) = 0; + signals: /** * @brief Emitted when the connection to the database was established. diff --git a/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp b/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp index a4a8b73..4778bb2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.cpp @@ -9,3 +9,8 @@ DbSqlite3::DbSqlite3(const QString& name, const QString& path) : DbSqlite3(name, path, QHash()) { } + +bool DbSqlite3::complete(const QString& sql) +{ + return Sqlite3::complete(sql.toUtf8().constData()); +} diff --git a/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h b/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h index 29db5a8..1509dff 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/dbsqlite3.h @@ -28,6 +28,8 @@ class API_EXPORT DbSqlite3 : public AbstractDb3 * @overload */ DbSqlite3(const QString& name, const QString& path); + + static bool complete(const QString& sql); }; #endif // DBSQLITE3_H diff --git a/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp b/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp index bdf3ef6..5e210f2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.cpp @@ -325,6 +325,18 @@ void InvalidDb::setError(const QString& value) error = value; } +bool InvalidDb::loadExtension(const QString& filePath, const QString& initFunc) +{ + UNUSED(filePath); + UNUSED(initFunc); + return false; +} + +bool InvalidDb::isComplete(const QString& sql) const +{ + UNUSED(sql); + return false; +} void InvalidDb::interrupt() { diff --git a/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h b/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h index a9d58e0..3bc91a4 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/invaliddb.h @@ -59,6 +59,8 @@ class API_EXPORT InvalidDb : public Db bool isValid() const; QString getError() const; void setError(const QString& value); + bool loadExtension(const QString& filePath, const QString& initFunc); + bool isComplete(const QString& sql) const; public slots: bool open(); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp index 4a1c2f6..4160e41 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.cpp @@ -33,6 +33,10 @@ // TODO modify all executor steps to use rebuildTokensFromContents() method, instead of replacing tokens manually. +QHash> QueryExecutor::additionalStatelessSteps; +QList QueryExecutor::allAdditionalStatelsssSteps; +QHash> QueryExecutor::additionalStatefulStepFactories; + QueryExecutor::QueryExecutor(Db* db, const QString& query, QObject *parent) : QObject(parent) { @@ -46,8 +50,7 @@ QueryExecutor::QueryExecutor(Db* db, const QString& query, QObject *parent) : connect(this, SIGNAL(executionFailed(int,QString)), this, SLOT(cleanupAfterExecFailed(int,QString))); connect(DBLIST, SIGNAL(dbAboutToBeUnloaded(Db*, DbPlugin*)), this, SLOT(cleanupBeforeDbDestroy(Db*))); connect(DBLIST, SIGNAL(dbRemoved(Db*)), this, SLOT(cleanupBeforeDbDestroy(Db*))); - connect(simpleExecutor, SIGNAL(finished(SqlQueryPtr)), this, SLOT(simpleExecutionFinished(SqlQueryPtr))); - + connect(simpleExecutor, &ChainExecutor::finished, this, &QueryExecutor::simpleExecutionFinished, Qt::DirectConnection); } QueryExecutor::~QueryExecutor() @@ -58,38 +61,79 @@ QueryExecutor::~QueryExecutor() void QueryExecutor::setupExecutionChain() { + executionChain.append(additionalStatelessSteps[FIRST]); + executionChain.append(createSteps(FIRST)); + executionChain << new QueryExecutorParseQuery("initial") << new QueryExecutorDetectSchemaAlter() << new QueryExecutorExplainMode() << new QueryExecutorValuesMode() << new QueryExecutorAttaches() // needs to be at the begining, because columns needs to know real databases - << new QueryExecutorParseQuery("after Attaches") - << new QueryExecutorDataSources() + << new QueryExecutorParseQuery("after Attaches"); + + executionChain.append(additionalStatelessSteps[AFTER_ATTACHES]); + executionChain.append(createSteps(AFTER_ATTACHES)); + + executionChain << new QueryExecutorDataSources() << new QueryExecutorReplaceViews() - << new QueryExecutorParseQuery("after ReplaceViews") - << new QueryExecutorAddRowIds() - << new QueryExecutorParseQuery("after AddRowIds") - << new QueryExecutorColumns() - << new QueryExecutorParseQuery("after Columns") - //<< new QueryExecutorColumnAliases() - << new QueryExecutorOrder() - << new QueryExecutorWrapDistinctResults() - << new QueryExecutorParseQuery("after WrapDistinctResults") - << new QueryExecutorCellSize() + << new QueryExecutorParseQuery("after ReplaceViews"); + + executionChain.append(additionalStatelessSteps[AFTER_REPLACED_VIEWS]); + executionChain.append(createSteps(AFTER_REPLACED_VIEWS)); + + executionChain << new QueryExecutorAddRowIds() + << new QueryExecutorParseQuery("after AddRowIds"); + + executionChain.append(additionalStatelessSteps[AFTER_ROW_IDS]); + executionChain.append(createSteps(AFTER_ROW_IDS)); + + executionChain << new QueryExecutorColumns() + << new QueryExecutorParseQuery("after Columns"); + + executionChain.append(additionalStatelessSteps[AFTER_REPLACED_COLUMNS]); + executionChain.append(createSteps(AFTER_REPLACED_COLUMNS)); + + executionChain << new QueryExecutorOrder(); + + executionChain.append(additionalStatelessSteps[AFTER_ORDER]); + executionChain.append(createSteps(AFTER_ORDER)); + + executionChain << new QueryExecutorWrapDistinctResults() + << new QueryExecutorParseQuery("after WrapDistinctResults"); + + executionChain.append(additionalStatelessSteps[AFTER_DISTINCT_WRAP]); + executionChain.append(createSteps(AFTER_DISTINCT_WRAP)); + + executionChain << new QueryExecutorCellSize() << new QueryExecutorCountResults() - << new QueryExecutorParseQuery("after Order") - << new QueryExecutorLimit() - << new QueryExecutorParseQuery("after Limit") - << new QueryExecutorExecute(); + << new QueryExecutorParseQuery("after CellSize"); + + executionChain.append(additionalStatelessSteps[AFTER_CELL_SIZE_LIMIT]); + executionChain.append(createSteps(AFTER_CELL_SIZE_LIMIT)); - foreach (QueryExecutorStep* step, executionChain) + executionChain << new QueryExecutorLimit() + << new QueryExecutorParseQuery("after Limit"); + + executionChain.append(additionalStatelessSteps[AFTER_ROW_LIMIT_AND_OFFSET]); + executionChain.append(createSteps(AFTER_ROW_LIMIT_AND_OFFSET)); + executionChain.append(additionalStatelessSteps[JUST_BEFORE_EXECUTION]); + executionChain.append(createSteps(JUST_BEFORE_EXECUTION)); + executionChain.append(additionalStatelessSteps[LAST]); + executionChain.append(createSteps(LAST)); + + executionChain << new QueryExecutorExecute(); + + for (QueryExecutorStep* step : executionChain) step->init(this, context); } void QueryExecutor::clearChain() { - foreach (QueryExecutorStep* step, executionChain) - delete step; + for (QueryExecutorStep* step : executionChain) + { + if (!allAdditionalStatelsssSteps.contains(step)) + delete step; + } executionChain.clear(); } @@ -98,7 +142,7 @@ void QueryExecutor::executeChain() { // Go through all remaining steps bool result; - foreach (QueryExecutorStep* currentStep, executionChain) + for (QueryExecutorStep* currentStep : executionChain) { if (isInterrupted()) { @@ -249,6 +293,7 @@ void QueryExecutor::execInternal() context->noMetaColumns = noMetaColumns; context->resultsHandler = resultsHandler; context->preloadResults = preloadResults; + context->queryParameters = queryParameters; // Start the execution setupExecutionChain(); @@ -372,7 +417,12 @@ QSet QueryExecutor::getEditionForbiddenGl void QueryExecutor::setParam(const QString& name, const QVariant& value) { - context->queryParameters[name] = value; + queryParameters[name] = value; +} + +void QueryExecutor::setParams(const QHash& params) +{ + queryParameters = params; } void QueryExecutor::arg(const QVariant& value) @@ -454,7 +504,7 @@ void QueryExecutor::simpleExecutionFinished(SqlQueryPtr results) ResultColumnPtr resCol; context->resultColumns.clear(); - foreach (const QString& colName, results->getColumnNames()) + for (const QString& colName : results->getColumnNames()) { resCol = ResultColumnPtr::create(); resCol->displayName = colName; @@ -487,19 +537,19 @@ bool QueryExecutor::simpleExecIsSelect() tokens.trim(); // First check if it's explicit "SELECT" or "VALUES" (the latter one added in SQLite 3.8.4). - TokenPtr token = tokens.first(); - QString upper = token->value.toUpper(); - if (token->type == Token::KEYWORD && (upper == "SELECT" || upper == "VALUES")) + TokenPtr firstToken = tokens.first(); + QString upper = firstToken->value.toUpper(); + if (firstToken->type == Token::KEYWORD && (upper == "SELECT" || upper == "VALUES")) return true; // Now it's only possible to be a SELECT if it starts with "WITH" statement. - if (token->type != Token::KEYWORD || upper != "WITH") + if (firstToken->type != Token::KEYWORD || upper != "WITH") return false; // Go through all tokens and find which one appears first (exclude contents indise parenthesis, // cause there will always be a SELECT for Common Table Expression). int depth = 0; - foreach (token, tokens) + for (const TokenPtr& token : tokens) { switch (token->type) { @@ -533,7 +583,7 @@ bool QueryExecutor::simpleExecIsSelect() void QueryExecutor::cleanup() { Db* attDb = nullptr; - foreach (const QString& attDbName, context->dbNameToAttach.leftValues()) + for (const QString& attDbName : context->dbNameToAttach.leftValues()) { attDb = DBLIST->getByName(attDbName, Qt::CaseInsensitive); if (attDbName.isNull()) @@ -575,8 +625,10 @@ bool QueryExecutor::handleRowCountingResults(quint32 asyncId, SqlQueryPtr result QStringList QueryExecutor::applyLimitForSimpleMethod(const QStringList &queries) { static_qstring(tpl, "SELECT * FROM (%1) LIMIT %2 OFFSET %3"); - QStringList result = queries; + if (page < 0) + return queries; // no paging requested + QStringList result = queries; QString lastQuery = queries.last(); bool isSelect = false; @@ -589,6 +641,15 @@ QStringList QueryExecutor::applyLimitForSimpleMethod(const QStringList &queries) return result; } +QList QueryExecutor::createSteps(QueryExecutor::StepPosition position) +{ + QList steps; + for (StepFactory* factory : additionalStatefulStepFactories[position]) + steps << factory->produceQueryExecutorStep(); + + return steps; +} + int QueryExecutor::getQueryCountLimitForSmartMode() const { return queryCountLimitForSmartMode; @@ -599,6 +660,28 @@ void QueryExecutor::setQueryCountLimitForSmartMode(int value) queryCountLimitForSmartMode = value; } +void QueryExecutor::registerStep(StepPosition position, QueryExecutorStep *step) +{ + additionalStatelessSteps[position] += step; + allAdditionalStatelsssSteps += step; +} + +void QueryExecutor::registerStep(QueryExecutor::StepPosition position, QueryExecutor::StepFactory* stepFactory) +{ + additionalStatefulStepFactories[position] += stepFactory; +} + +void QueryExecutor::deregisterStep(StepPosition position, QueryExecutorStep *step) +{ + additionalStatelessSteps[position].removeOne(step); + allAdditionalStatelsssSteps.removeOne(step); +} + +void QueryExecutor::deregisterStep(QueryExecutor::StepPosition position, QueryExecutor::StepFactory* stepFactory) +{ + additionalStatefulStepFactories[position].removeOne(stepFactory); +} + bool QueryExecutor::getForceSimpleMode() const { return forceSimpleMode; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h index 4830e36..85c39bf 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutor.h @@ -646,6 +646,53 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable QString errorMessageFromSmartExecution; }; + /** + * @brief Position for custom executor steps. + * + * These position define where in query executor chain of steps the new, registered step will be placed. + * It's used in arguments of registerStep() method. + * + * If multiple steps are registered at same position, they will be executed in order they were registered. + * + * Values of positions determin what actions have been already taken by the executor, so for example + * AFTER_ATTACHES means, that executor already attached referenced databases and replaced occurrences of objects + * from that databases. + * + * Enumerations are in order as the steps are executed. + * + * If you need more detailed description about certain steps performed by query executor, see documentation + * of their classes - all these classes name start with QueryExecutor prefix. + */ + enum StepPosition { + FIRST, /**< As first step */ + AFTER_ATTACHES, /**< After transparent attaching is applied (detected tables are defined to be attached first). */ + AFTER_REPLACED_VIEWS, /**< After referenced views have been replaced with subqueries */ + AFTER_ROW_IDS, /**< After ROWID columns have been added to result columns */ + AFTER_REPLACED_COLUMNS, /**< After all columns have been explicitly listed in result list, together with unique alias names */ + AFTER_ORDER, /**< After order clause was applied/modified */ + AFTER_DISTINCT_WRAP, /**< After wrapping SELECT was added in case of DISTINCT or GROUP BY clauses were used */ + AFTER_CELL_SIZE_LIMIT, /**< After cell result size was limited to save memory usage */ + AFTER_ROW_LIMIT_AND_OFFSET, /**< After LIMIT and ORDER clauses were added/modified. This is the last possible moment, directly ahead of final query execution */ + JUST_BEFORE_EXECUTION, /**< Same as AFTER_ROW_LIMIT_AND_OFFSET */ + LAST /**< Same as AFTER_ROW_LIMIT_AND_OFFSET */ + }; + + /** + * @brief Interface for producing query executor steps. + * + * It can be used for overloaded version of registerStep() method, + * in case a step is stateful and needs to be created/deleted for every query executor processing. + * + * If step is stateless, it can be registered directly as an instance, using the other version of registerStep() method. + * + * This is an abstract class and not pointer to function, because it has to be comparable (and std::function is not), + * so it's possible to deregister the factory later on. + */ + class StepFactory { + public: + virtual QueryExecutorStep* produceQueryExecutorStep() = 0; + }; + /** * @brief Creates query executor, initializes internal context object. * @param db Optional database. If not provided, it has to be defined later with setDb(). @@ -808,6 +855,15 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable */ void setParam(const QString& name, const QVariant& value); + /** + * @brief Assigns all query parameters at once. + * @param params All bind parameters for the query. + * + * This is same as setParam(), except it overrides all current params with given ones. + * It allows for setting all params at once. + */ + void setParams(const QHash& params); + /** * @brief Replaces placeholder in the query. * @param value Value to replace placeholder with. @@ -1038,6 +1094,49 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable int getQueryCountLimitForSmartMode() const; void setQueryCountLimitForSmartMode(int value); + /** + * @brief Adds new step to the chain of execution + * @param position Where in chain should the step be placed. + * @param step Step implementation instance. + * + * If multiple steps are registered for the same position, they will be executed in the order they were registered. + * + * If step is registered with a plugin, remember to deregister the step upon plugin unload. + * Best place for that is in Plugin::deinit(). + */ + static void registerStep(StepPosition position, QueryExecutorStep* step); + + /** + * @brief Adds new step to chain of execution + * @param position Where in chain should the step be placed. + * @param stepFactory Factory for creating instance of the step. + * + * This is overloaded method for cases when the step is stateful and needs to be recreated for every invokation of query executor. + */ + static void registerStep(StepPosition position, StepFactory* stepFactory); + + /** + * @brief Removes extra step from the execution chain. + * @param position Position from which the step should be removed. + * @param step Step implementation instance. + * + * Removes step from list of additional steps to be performed. If such step was not on the list, this method does nothing. + * + * There is a position parameter to this method, becuase a step could be added to multiple different positions + * and you decide from which you want to deregister it. + */ + static void deregisterStep(StepPosition position, QueryExecutorStep* step); + + /** + * @brief Removes extra step from the execution chain. + * @param position Position from which the step should be removed. + * @param stepFactory Factory to deregister. + * + * This is overloaded method to remove factory instead of instance of a step. To be used together with registerStep() + * that also takes factory in parameters. + */ + static void deregisterStep(StepPosition position, StepFactory* stepFactory); + private: /** * @brief Executes query. @@ -1125,6 +1224,13 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable QStringList applyLimitForSimpleMethod(const QStringList &queries); + /** + * @brief Creates instances of steps for all registered factories for given position. + * @param position Position for which factories will be used. + * @return List of instances of steps from given factories. + */ + QList createSteps(StepPosition position); + /** * @brief Query executor context object. * @@ -1316,6 +1422,37 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable */ QList executionChain; + /** + * @brief List of registered additional steps to be performed + * + * It's a map, where keys describe where in chain should the steps be placed + * and values are list of steps to be inserted at that position. + * + * They are added/removed by methods: registerStep() and deregisterStep(). + */ + static QHash> additionalStatelessSteps; + + /** + * @brief List of all registered additional steps + * + * This is a list of all registered additional steps (registered instances of steps), regardless of their position. + * This is used to identify registered stateless steps, so they are not deleted on query executor cleanup. + * + * Only steps created with a factory are deleted upon executor cleanup (and of course all internal steps created by the executor itself). + */ + static QList allAdditionalStatelsssSteps; + + /** + * @brief List of registered factories that create additional steps to be performed + * + * This is similar to additionalSteps, except it holds factories, instead of step instances. + * + * Steps created with a factory are appended after stateless steps registered as direct + * instances (held by additionalSteps) - that is for case when both instance and factory + * are registered for the same step position. + */ + static QHash> additionalStatefulStepFactories; + /** * @brief Execution results handler. * @@ -1327,6 +1464,13 @@ class API_EXPORT QueryExecutor : public QObject, public QRunnable */ Db::QueryResultsHandler resultsHandler = nullptr; + /** + * @brief Parameters for query execution. + * + * It's defined by setParam(). + */ + QHash queryParameters; + bool forceSimpleMode = false; ChainExecutor* simpleExecutor = nullptr; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp index d417072..d59d73c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.cpp @@ -54,7 +54,7 @@ QHash> QueryExecutorAddRowIds::addR return rowIdColsMap; // Go trough subselects to add ROWID result columns there and collect rowId mapping to use here. - foreach (SqliteSelect* subSelect, getSubSelects(core)) + for (SqliteSelect* subSelect : getSubSelects(core)) { rowIdColsMap.unite(addRowIdForTables(subSelect, ok, false)); if (!ok) @@ -66,11 +66,14 @@ QHash> QueryExecutorAddRowIds::addR resolver.resolveMultiCore = false; // multicore subselects result in not editable columns, skip them QSet tables = resolver.resolveTables(core); - foreach (const SelectResolver::Table& table, tables) + for (const SelectResolver::Table& table : tables) { if (table.flags & (SelectResolver::FROM_COMPOUND_SELECT | SelectResolver::FROM_DISTINCT_SELECT | SelectResolver::FROM_GROUPED_SELECT)) continue; // we don't get ROWID from compound, distinct or aggregated subselects + if (checkInWithClause(table, select->with)) + continue; // we don't get ROWID from WITH clause, as it's likely to be recurrent and difficult. TODO: support columns from WITH clause + if (!addResultColumns(core, table, rowIdColsMap, isTopSelect)) { ok = false; @@ -89,7 +92,7 @@ QList QueryExecutorAddRowIds::getSubSelects(SqliteSelect::Core* c if (core->from->singleSource && core->from->singleSource->select) selects << core->from->singleSource->select; - foreach (SqliteSelect::Core::JoinSourceOther* otherSource, core->from->otherSources) + for (SqliteSelect::Core::JoinSourceOther* otherSource : core->from->otherSources) { if (!otherSource->singleSource->select) continue; @@ -137,7 +140,7 @@ QHash QueryExecutorAddRowIds::getNextColNames(const SelectResol SqliteCreateTable::Constraint* tableConstr = dynamic_cast(primaryKey); if (tableConstr) { - foreach (SqliteIndexedColumn* idxCol, tableConstr->indexedColumns) + for (SqliteIndexedColumn* idxCol : tableConstr->indexedColumns) colNames[getNextColName()] = idxCol->name; return colNames; @@ -205,6 +208,27 @@ bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const Se return true; } +bool QueryExecutorAddRowIds::checkInWithClause(const SelectResolver::Table &table, SqliteWith *with) +{ + if (!table.database.isNull() || !with) + return false; + + SqliteWith::CommonTableExpression* cte = nullptr; + QString nameToCompareWith = table.tableAlias.isNull() ? table.table : table.tableAlias; + for (SqliteWith::CommonTableExpression* cteItem : with->cteList) + { + if (cteItem->table == nameToCompareWith) + { + cte = cteItem; + break; + } + } + if (!cte) + return false; + + return true; +} + bool QueryExecutorAddRowIds::addResultColumns(SqliteSelect::Core* core, const SelectResolver::Table& table, const QString& queryExecutorColumn, const QString& realColumn, bool aliasOnlyAsSelectColumn) { diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h index 61bc302..1669542 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutoraddrowids.h @@ -76,6 +76,8 @@ class QueryExecutorAddRowIds : public QueryExecutorStep * @return Map of query executor alias to real database column name. */ QHash getNextColNames(const SelectResolver::Table& table); + + bool checkInWithClause(const SelectResolver::Table& table, SqliteWith *with); }; #endif // QUERYEXECUTORADDROWIDS_H diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcellsize.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcellsize.cpp index 54bd35a..352c74b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcellsize.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcellsize.cpp @@ -10,7 +10,7 @@ bool QueryExecutorCellSize::exec() if (!select || select->explain) return true; - foreach (SqliteSelect::Core* core, select->coreSelects) + for (SqliteSelect::Core* core : select->coreSelects) { if (!applyDataLimit(select.data(), core)) return false; @@ -31,7 +31,7 @@ bool QueryExecutorCellSize::applyDataLimit(SqliteSelect* select, SqliteSelect::C bool first = true; TokenList tokens; - foreach (const QueryExecutor::ResultColumnPtr& col, context->resultColumns) + for (const QueryExecutor::ResultColumnPtr& col : context->resultColumns) { if (!first) tokens += getSeparatorTokens(); @@ -40,7 +40,7 @@ bool QueryExecutorCellSize::applyDataLimit(SqliteSelect* select, SqliteSelect::C first = false; } - foreach (const QueryExecutor::ResultRowIdColumnPtr& col, context->rowIdColumns) + for (const QueryExecutor::ResultRowIdColumnPtr& col : context->rowIdColumns) { if (!first) tokens += getSeparatorTokens(); @@ -112,7 +112,7 @@ TokenList QueryExecutorCellSize::getNoLimitTokens(const QueryExecutor::ResultRow { TokenList newTokens; bool first = true; - foreach (const QString& col, resCol->queryExecutorAliasToColumn.keys()) + for (const QString& col : resCol->queryExecutorAliasToColumn.keys()) { if (!first) newTokens += getSeparatorTokens(); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp index 30a4f5d..0cb6b7a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorcolumns.cpp @@ -108,6 +108,9 @@ QueryExecutor::ResultColumnPtr QueryExecutorColumns::getResultColumn(const Selec if (resolvedColumn.flags & SelectResolver::FROM_DISTINCT_SELECT) resultColumn->editionForbiddenReasons << QueryExecutor::ColumnEditionForbiddenReason::DISTINCT_RESULTS; + if (resolvedColumn.flags & SelectResolver::FROM_CTE_SELECT) + resultColumn->editionForbiddenReasons << QueryExecutor::ColumnEditionForbiddenReason::COMM_TAB_EXPR; + resultColumn->database = resolvedColumn.originalDatabase; resultColumn->table = resolvedColumn.table; resultColumn->column = resolvedColumn.column; @@ -200,7 +203,7 @@ QString QueryExecutorColumns::resolveAttachedDatabases(const QString &dbName) bool QueryExecutorColumns::isRowIdColumnAlias(const QString& alias) { - foreach (QueryExecutor::ResultRowIdColumnPtr rowIdColumn, context->rowIdColumns) + for (QueryExecutor::ResultRowIdColumnPtr rowIdColumn : context->rowIdColumns) { if (rowIdColumn->queryExecutorAliasToColumn.keys().contains(alias)) return true; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp index 4a422d3..88c957b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutordatasources.cpp @@ -19,7 +19,7 @@ bool QueryExecutorDataSources::exec() SqliteSelect::Core* core = select->coreSelects.first(); QSet tables = resolver.resolveTables(core); - foreach (SelectResolver::Table resolvedTable, tables) + for (SelectResolver::Table resolvedTable : tables) { QueryExecutor::SourceTablePtr table = QueryExecutor::SourceTablePtr::create(); table->database = resolvedTable.database; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp index aaa8014..0a97c1e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorexecute.cpp @@ -23,7 +23,7 @@ bool QueryExecutorExecute::exec() void QueryExecutorExecute::provideResultColumns(SqlQueryPtr results) { QueryExecutor::ResultColumnPtr resCol; - foreach (const QString& colName, results->getColumnNames()) + for (const QString& colName : results->getColumnNames()) { resCol = QueryExecutor::ResultColumnPtr::create(); resCol->displayName = colName; @@ -124,8 +124,8 @@ void QueryExecutorExecute::handleFailResult(SqlQueryPtr results) QHash QueryExecutorExecute::getBindParamsForQuery(SqliteQueryPtr query) { QHash queryParams; - QStringList bindParams = query->tokens.filter(Token::BIND_PARAM).toStringList(); - foreach (const QString& bindParam, bindParams) + QStringList bindParams = query->tokens.filter(Token::BIND_PARAM).toValueList(); + for (const QString& bindParam : bindParams) { if (context->queryParameters.contains(bindParam)) queryParams.insert(bindParam, context->queryParameters[bindParam]); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.cpp b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.cpp index d64ea2e..8fbf026 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.cpp @@ -18,7 +18,7 @@ void QueryExecutorStep::init(QueryExecutor *queryExecutor, QueryExecutor::Contex void QueryExecutorStep::updateQueries() { QString newQuery; - foreach (SqliteQueryPtr query, context->parsedQueries) + for (SqliteQueryPtr query : context->parsedQueries) { newQuery += query->detokenize(); newQuery += "\n"; diff --git a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.h b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.h index a15ad9c..9a89b26 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/queryexecutorsteps/queryexecutorstep.h @@ -37,7 +37,7 @@ * * To access database object, that the query is executed on, use QueryExecutor::getDb(). */ -class QueryExecutorStep : public QObject +class API_EXPORT QueryExecutorStep : public QObject { Q_OBJECT diff --git a/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp b/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp index 4217711..94799d9 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.cpp @@ -1,5 +1,6 @@ #include "sqlquery.h" #include "db/sqlerrorcodes.h" +#include "common/utils_sql.h" SqlQuery::~SqlQuery() { @@ -115,7 +116,7 @@ void SqlQuery::setArgs(const QHash& args) } -void RowIdConditionBuilder::setRowId(const RowId& rowId) +void RowIdConditionBuilder::setRowId(const RowId& rowId, Dialect dialect) { static const QString argTempalate = QStringLiteral(":rowIdArg%1"); @@ -127,7 +128,7 @@ void RowIdConditionBuilder::setRowId(const RowId& rowId) it.next(); arg = argTempalate.arg(i++); queryArgs[arg] = it.value(); - conditions << it.key() + " = " + arg; + conditions << wrapObjIfNeeded(it.key(), dialect) + " = " + arg; } } diff --git a/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h b/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h index 4e0d9cf..ed78d80 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/sqlquery.h @@ -304,7 +304,7 @@ class API_EXPORT SqlQuery class API_EXPORT RowIdConditionBuilder { public: - void setRowId(const RowId& rowId); + void setRowId(const RowId& rowId, Dialect dialect); const QHash& getQueryArgs(); QString build(); diff --git a/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h b/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h index 6b0c422..94a0413 100644 --- a/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h +++ b/SQLiteStudio3/coreSQLiteStudio/db/stdsqlite3driver.h @@ -2,7 +2,7 @@ #define STDSQLITE3DRIVER_H #define STD_SQLITE3_DRIVER(Name, Label, Prefix, UppercasePrefix) \ - struct Name \ + struct API_EXPORT Name \ { \ static_char* label = Label; \ \ @@ -69,7 +69,9 @@ static int step(stmt* arg) {return Prefix##sqlite3_step(arg);} \ static int reset(stmt* arg) {return Prefix##sqlite3_reset(arg);} \ static int close(handle* arg) {return Prefix##sqlite3_close(arg);} \ + static void free(void* arg) {return Prefix##sqlite3_free(arg);} \ static int enable_load_extension(handle* arg1, int arg2) {return Prefix##sqlite3_enable_load_extension(arg1, arg2);} \ + static int load_extension(handle *arg1, const char *arg2, const char *arg3, char **arg4) {return Prefix##sqlite3_load_extension(arg1, arg2, arg3, arg4);} \ static void* user_data(context* arg) {return Prefix##sqlite3_user_data(arg);} \ static void* aggregate_context(context* arg1, int arg2) {return Prefix##sqlite3_aggregate_context(arg1, arg2);} \ static int collation_needed(handle* a1, void* a2, void(*a3)(void*,handle*,int eTextRep,const char*)) {return Prefix##sqlite3_collation_needed(a1, a2, a3);} \ @@ -80,6 +82,7 @@ {return Prefix##sqlite3_create_function_v2(a1, a2, a3, a4, a5, a6, a7, a8, a9);} \ static int create_collation_v2(handle* a1, const char *a2, int a3, void *a4, int(*a5)(void*,int,const void*,int,const void*), void(*a6)(void*)) \ {return Prefix##sqlite3_create_collation_v2(a1, a2, a3, a4, a5, a6);} \ + static int complete(const char* arg) {return Prefix##sqlite3_complete(arg);} \ }; #endif // STDSQLITE3DRIVER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.cpp b/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.cpp index 96f73d7..0ef924d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.cpp @@ -23,6 +23,7 @@ #include "parser/ast/sqlitesavepoint.h" #include "parser/ast/sqliteupdate.h" #include "parser/ast/sqlitevacuum.h" +#include "parser/ast/sqliteupsert.h" #include "services/pluginmanager.h" #include "plugins/dbplugin.h" #include "services/dbmanager.h" @@ -207,7 +208,8 @@ SqliteQueryPtr DbVersionConverter::convert3To2(SqliteQueryPtr query) if (!modifyDeleteForVersion2(newQuery.dynamicCast().data())) { newQuery = SqliteEmptyQueryPtr::create(); - storeErrorDiff(query.data()); + if (diffsForNonDDL) + storeErrorDiff(query.data()); } break; case SqliteQueryType::Detach: @@ -230,7 +232,8 @@ SqliteQueryPtr DbVersionConverter::convert3To2(SqliteQueryPtr query) if (!modifyInsertForVersion2(newQuery.dynamicCast().data())) { newQuery = SqliteEmptyQueryPtr::create(); - storeErrorDiff(query.data()); + if (diffsForNonDDL) + storeErrorDiff(query.data()); } break; case SqliteQueryType::Pragma: @@ -260,7 +263,8 @@ SqliteQueryPtr DbVersionConverter::convert3To2(SqliteQueryPtr query) if (!modifySelectForVersion2(newQuery.dynamicCast().data())) { newQuery = SqliteEmptyQueryPtr::create(); - storeErrorDiff(query.data()); + if (diffsForNonDDL) + storeErrorDiff(query.data()); } break; } @@ -269,7 +273,8 @@ SqliteQueryPtr DbVersionConverter::convert3To2(SqliteQueryPtr query) if (!modifyUpdateForVersion2(newQuery.dynamicCast().data())) { newQuery = SqliteEmptyQueryPtr::create(); - storeErrorDiff(query.data()); + if (diffsForNonDDL) + storeErrorDiff(query.data()); } break; case SqliteQueryType::Vacuum: @@ -450,7 +455,9 @@ bool DbVersionConverter::modifySelectForVersion2(SqliteSelect* select) if (!modifyAllExprsForVersion2(select)) return false; - storeDiff(sql1, select); + if (diffsForNonDDL) + storeDiff(sql1, select); + return true; } @@ -471,7 +478,9 @@ bool DbVersionConverter::modifyDeleteForVersion2(SqliteDelete* del) if (!modifyAllExprsForVersion2(del)) return false; - storeDiff(sql1, del); + if (diffsForNonDDL) + storeDiff(sql1, del); + return true; } @@ -497,6 +506,9 @@ bool DbVersionConverter::modifyInsertForVersion2(SqliteInsert* insert) QString sql1 = getSqlForDiff(insert); + if (insert->upsert) + safe_delete(insert->upsert); + // Modifying SELECT deals with "VALUES" completely. if (!modifySelectForVersion2(insert->select)) return false; @@ -504,7 +516,9 @@ bool DbVersionConverter::modifyInsertForVersion2(SqliteInsert* insert) if (!modifyAllExprsForVersion2(insert)) return false; - storeDiff(sql1, insert); + if (diffsForNonDDL) + storeDiff(sql1, insert); + return true; } @@ -525,7 +539,9 @@ bool DbVersionConverter::modifyUpdateForVersion2(SqliteUpdate* update) update->indexedByKw = false; update->notIndexedKw = false; - storeDiff(sql1, update); + if (diffsForNonDDL) + storeDiff(sql1, update); + return true; } diff --git a/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.h b/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.h index 9486f1b..5fafc93 100644 --- a/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.h +++ b/SQLiteStudio3/coreSQLiteStudio/dbversionconverter.h @@ -127,6 +127,21 @@ class API_EXPORT DbVersionConverter : public QObject bool interrupted = false; QMutex interruptMutex; + /** + * @brief Whether to include non-DDL statements in diff list. + * + * The non-DDL statements are INSERTs, SELECTs, etc. + * Normally, for DB conversion we only care about DDL modifications, + * that is for CREATE statements. Other statements may appear inside of + * triggers or views, but we don't need their diffs separately. + * + * This variable is not used currently, but may be in future, + * when for example individual INSERT statement would need to be converted. + * Right now there's no such need, but it would be pity to remove the code + * from that non-DDL statements. + */ + bool diffsForNonDDL = false; + private slots: void conversionError(Db* db, const QString& errMsg); void confirmConversion(); diff --git a/SQLiteStudio3/coreSQLiteStudio/diff/diff_match_patch.cpp b/SQLiteStudio3/coreSQLiteStudio/diff/diff_match_patch.cpp index 4f0022e..aa5765a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/diff/diff_match_patch.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/diff/diff_match_patch.cpp @@ -142,7 +142,7 @@ QString Patch::toString() { text = QString("@@ -") + coords1 + QString(" +") + coords2 + QString(" @@\n"); // Escape the body of the patch with %xx notation. - foreach (Diff aDiff, diffs) { + for (Diff aDiff : diffs) { switch (aDiff.operation) { case INSERT: text += QString('+'); @@ -1251,7 +1251,7 @@ int diff_match_patch::diff_xIndex(const QList &diffs, int loc) { int last_chars1 = 0; int last_chars2 = 0; Diff lastDiff; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { if (aDiff.operation != INSERT) { // Equality or deletion. chars1 += aDiff.text.length(); @@ -1280,7 +1280,7 @@ int diff_match_patch::diff_xIndex(const QList &diffs, int loc) { QString diff_match_patch::diff_prettyHtml(const QList &diffs) { QString html; QString text; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { text = aDiff.text; text.replace("&", "&").replace("<", "<") .replace(">", ">").replace("\n", "¶
"); @@ -1304,7 +1304,7 @@ QString diff_match_patch::diff_prettyHtml(const QList &diffs) { QString diff_match_patch::diff_text1(const QList &diffs) { QString text; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { if (aDiff.operation != INSERT) { text += aDiff.text; } @@ -1315,7 +1315,7 @@ QString diff_match_patch::diff_text1(const QList &diffs) { QString diff_match_patch::diff_text2(const QList &diffs) { QString text; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { if (aDiff.operation != DELETE) { text += aDiff.text; } @@ -1328,7 +1328,7 @@ int diff_match_patch::diff_levenshtein(const QList &diffs) { int levenshtein = 0; int insertions = 0; int deletions = 0; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { switch (aDiff.operation) { case INSERT: insertions += aDiff.text.length(); @@ -1351,7 +1351,7 @@ int diff_match_patch::diff_levenshtein(const QList &diffs) { QString diff_match_patch::diff_toDelta(const QList &diffs) { QString text; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { switch (aDiff.operation) { case INSERT: { QString encoded = QString(QUrl::toPercentEncoding(aDiff.text, @@ -1382,7 +1382,7 @@ QList diff_match_patch::diff_fromDelta(const QString &text1, QList diffs; int pointer = 0; // Cursor in text1 QStringList tokens = delta.split("\t"); - foreach(QString token, tokens) { + for (QString token : tokens) { if (token.isEmpty()) { // Blank tokens are ok (from a trailing \t). continue; @@ -1682,7 +1682,7 @@ QList diff_match_patch::patch_make(const QString &text1, // context info. QString prepatch_text = text1; QString postpatch_text = text1; - foreach(Diff aDiff, diffs) { + for (Diff aDiff : diffs) { if (patch.diffs.isEmpty() && aDiff.operation != EQUAL) { // A new patch starts here. patch.start1 = char_count1; @@ -1748,9 +1748,9 @@ QList diff_match_patch::patch_make(const QString &text1, QList diff_match_patch::patch_deepCopy(QList &patches) { QList patchesCopy; - foreach(Patch aPatch, patches) { + for (Patch aPatch : patches) { Patch patchCopy = Patch(); - foreach(Diff aDiff, aPatch.diffs) { + for (Diff aDiff : aPatch.diffs) { Diff diffCopy = Diff(aDiff.operation, aDiff.text); patchCopy.diffs.append(diffCopy); } @@ -1785,7 +1785,7 @@ QPair > diff_match_patch::patch_apply( // has an effective expected position of 22. int delta = 0; QVector results(patchesCopy.size()); - foreach(Patch aPatch, patchesCopy) { + for (Patch aPatch : patchesCopy) { int expected_loc = aPatch.start2 + delta; QString text1 = diff_text1(aPatch.diffs); int start_loc; @@ -1836,7 +1836,7 @@ QPair > diff_match_patch::patch_apply( } else { diff_cleanupSemanticLossless(diffs); int index1 = 0; - foreach(Diff aDiff, aPatch.diffs) { + for (Diff aDiff : aPatch.diffs) { if (aDiff.operation != EQUAL) { int index2 = diff_xIndex(diffs, index1); if (aDiff.operation == INSERT) { @@ -2030,7 +2030,7 @@ void diff_match_patch::patch_splitMax(QList &patches) { QString diff_match_patch::patch_toText(const QList &patches) { QString text; - foreach(Patch aPatch, patches) { + for (Patch aPatch : patches) { text.append(aPatch.toString()); } return text; diff --git a/SQLiteStudio3/coreSQLiteStudio/impl/dbattacherimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/impl/dbattacherimpl.cpp index 7d9c1ba..59f4ac5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/impl/dbattacherimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/impl/dbattacherimpl.cpp @@ -61,7 +61,7 @@ bool DbAttacherImpl::attachDatabases() TokenList DbAttacherImpl::getDbTokens() { TokenList dbTokens; - foreach (SqliteQueryPtr query, queries) + for (SqliteQueryPtr query : queries) dbTokens += query->getContextDatabaseTokens(); return dbTokens; @@ -78,7 +78,7 @@ void DbAttacherImpl::detachAttached() void DbAttacherImpl::prepareNameToDbMap() { - foreach (Db* db, DBLIST->getValidDbList()) + for (Db* db : DBLIST->getValidDbList()) nameToDbMap[db->getName()] = db; } @@ -153,7 +153,7 @@ void DbAttacherImpl::replaceTokensInQueries(const QHash& tok while (it.hasNext()) { it.next(); - foreach (SqliteQueryPtr query, queries) + for (SqliteQueryPtr query : queries) { idx = query->tokens.indexOf(it.key()); if (idx < 0) @@ -177,7 +177,7 @@ BiStrHash DbAttacherImpl::getDbNameToAttach() const QString DbAttacherImpl::getQuery() const { QStringList queryStrings; - foreach (SqliteQueryPtr query, queries) + for (SqliteQueryPtr query : queries) queryStrings << query->detokenize(); return queryStrings.join(";"); diff --git a/SQLiteStudio3/coreSQLiteStudio/importworker.cpp b/SQLiteStudio3/coreSQLiteStudio/importworker.cpp index ea6c40d..1496571 100644 --- a/SQLiteStudio3/coreSQLiteStudio/importworker.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/importworker.cpp @@ -149,6 +149,7 @@ bool ImportWorker::importData() QString theInsert = insertTemplate.arg(wrapObjIfNeeded(table, db->getDialect()), valList.join(", ")); SqlQueryPtr query = db->prepare(theInsert); + query->setFlags(Db::Flag::SKIP_DROP_DETECTION|Db::Flag::SKIP_PARAM_COUNTING|Db::Flag::NO_LOCK); int rowCnt = 0; QList row; @@ -161,10 +162,6 @@ bool ImportWorker::importData() // Assign argument values query->setArgs(row.mid(0, colCount)); - // No transactions = already in transaction, skip locking - if (config->skipTransaction) - query->setFlags(Db::Flag::NO_LOCK); - if (!query->execute()) { if (config->ignoreErrors) diff --git a/SQLiteStudio3/coreSQLiteStudio/licenses/fugue_icons.txt b/SQLiteStudio3/coreSQLiteStudio/licenses/fugue_icons.txt index 4fc7b75..22b0655 100644 --- a/SQLiteStudio3/coreSQLiteStudio/licenses/fugue_icons.txt +++ b/SQLiteStudio3/coreSQLiteStudio/licenses/fugue_icons.txt @@ -13,68 +13,3 @@ purchase a royalty-free license. I'm unavailable for custom icon design work. But your suggestions are always welcome! - ------------------------------------------------------------- - -All logos and trademarks in some icons are property of their -respective owners. - ------------------------------------------------------------- - -- geotag - - (C) Geotag Icon Project. All rights reserved. - - - Geotag icon is licensed under a Creative Commons - Attribution-Share Alike 3.0 License or LGPL. - - - -- language - - (C) Language Icon Project. All rights reserved. - - - Language icon is licensed under a Creative Commons - Attribution-Share Alike 3.0 License. - - -- open-share - - (C) Open Share Icon Project. All rights reserved. - - - Open Share icon is licensed under a Creative Commons - Attribution-Share Alike 3.0 License. - - -- opml - - (C) OPML Icon Project. All rights reserved. - - - OPML icon is licensed under a Creative Commons - Attribution-Share Alike 2.5 License. - - -- share - - (C) Share Icon Project. All rights reserved. - - - Share icon is licensed under a GPL or LGPL or BSD or - Creative Commons Attribution 2.5 License. - - - - - -- xfn - - (C) Wolfgang Bartelme. All rights reserved. - - - XFN icon is licensed under a Creative Commons - Attribution-Share Alike 2.5 License. - \ No newline at end of file diff --git a/SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt b/SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt index 10926e8..5225330 100644 --- a/SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt +++ b/SQLiteStudio3/coreSQLiteStudio/licenses/gpl.txt @@ -1,3 +1,16 @@ +SQLiteStudio is licensed under the GNU General Public License version 3 with the +addition of the following special exception: + +In addition, as a special exception, the copyright holders give +permission to link the code of portions of this program with the OpenSSL +library. +You must obey the GNU General Public License in all respects for all of +the code used other than OpenSSL. If you modify file(s) with this +exception, you may extend this exception to your version of the file(s), +but you are not obligated to do so. If you do not wish to do so, delete +this exception statement from your version. If you delete this exception +statement from all source files in the program, then also delete it here. + GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 @@ -672,4 +685,3 @@ may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . - diff --git a/SQLiteStudio3/coreSQLiteStudio/licenses/mit.txt b/SQLiteStudio3/coreSQLiteStudio/licenses/mit.txt new file mode 100644 index 0000000..85b2a14 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/licenses/mit.txt @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) Itay Grudev 2015 - 2016 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Note: Some of the examples include code not distributed under the terms of the +MIT License. diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp index fdbadf8..5c11ff5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp @@ -57,7 +57,7 @@ SqliteCreateIndex::SqliteCreateIndex(bool unique, bool ifNotExists, const QStrin table = name3; this->indexedColumns = columns; - foreach (SqliteOrderBy* idxCol, columns) + for (SqliteOrderBy* idxCol : columns) idxCol->setParent(this); this->where = where; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp index 2ac6c04..eb4ae85 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp @@ -22,11 +22,10 @@ SqliteCreateTable::SqliteCreateTable(bool ifNotExistsKw, int temp, const QString { init(ifNotExistsKw, temp, name1, name2); this->columns = columns; - foreach (Column* column, columns) + for (Column* column : columns) column->setParent(this); - SqliteCreateTable::Constraint* constr = nullptr; - foreach (constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) { if (this->constraints.size() > 0 && this->constraints.last()->type == SqliteCreateTable::Constraint::NAME_ONLY) @@ -66,7 +65,7 @@ SqliteStatement*SqliteCreateTable::clone() QList SqliteCreateTable::getConstraints(SqliteCreateTable::Constraint::Type type) const { QList results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == type) results << constr; @@ -75,11 +74,11 @@ QList SqliteCreateTable::getConstraints(SqliteCr SqliteStatement* SqliteCreateTable::getPrimaryKey() const { - foreach (Constraint* constr, getConstraints(Constraint::PRIMARY_KEY)) + for (Constraint* constr : getConstraints(Constraint::PRIMARY_KEY)) return constr; Column::Constraint* colConstr = nullptr; - foreach (Column* col, columns) + for (Column* col : columns) { colConstr = col->getConstraint(Column::Constraint::PRIMARY_KEY); if (colConstr) @@ -106,7 +105,7 @@ QStringList SqliteCreateTable::getPrimaryKeyColumns() const SqliteCreateTable::Constraint* tableConstr = dynamic_cast(primaryKey); if (tableConstr) { - foreach (SqliteIndexedColumn* idxCol, tableConstr->indexedColumns) + for (SqliteIndexedColumn* idxCol : tableConstr->indexedColumns) colNames << idxCol->name; } return colNames; @@ -114,7 +113,7 @@ QStringList SqliteCreateTable::getPrimaryKeyColumns() const SqliteCreateTable::Column* SqliteCreateTable::getColumn(const QString& colName) { - foreach (Column* col, columns) + for (Column* col : columns) { if (col->name.compare(colName, Qt::CaseInsensitive) == 0) return col; @@ -125,7 +124,7 @@ SqliteCreateTable::Column* SqliteCreateTable::getColumn(const QString& colName) QList SqliteCreateTable::getForeignKeysByTable(const QString& foreignTable) const { QList results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == Constraint::FOREIGN_KEY && constr->foreignKey->foreignTable.compare(foreignTable, Qt::CaseInsensitive) == 0) results << constr; @@ -135,7 +134,7 @@ QList SqliteCreateTable::getForeignKeysByTable(c QList SqliteCreateTable::getColumnForeignKeysByTable(const QString& foreignTable) const { QList results; - foreach (Column* col, columns) + for (Column* col : columns) results += col->getForeignKeysByTable(foreignTable); return results; @@ -144,7 +143,7 @@ QList SqliteCreateTable::getColumnForeig QStringList SqliteCreateTable::getColumnNames() const { QStringList names; - foreach (Column* col, columns) + for (Column* col : columns) names << col->name; return names; @@ -154,7 +153,7 @@ QHash SqliteCreateTable::getModifiedColumnsMap(bool lowercaseK { QHash colMap; QString key; - foreach (Column* col, columns) + for (Column* col : columns) { key = lowercaseKeys ? col->originalName.toLower() : col->originalName; if (col->name.compare(col->originalName, cs) != 0) @@ -385,10 +384,10 @@ void SqliteCreateTable::Column::Constraint::initFk(const QString& table, const Q foreignKey = fk; fk->setParent(this); - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(fk); - foreach (SqliteForeignKey::Condition* cond, conditions) + for (SqliteForeignKey::Condition* cond : conditions) cond->setParent(fk); } @@ -466,7 +465,7 @@ void SqliteCreateTable::Constraint::initPk(const QList &i autoincrKw = autoincr; onConflict = algo; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); } @@ -476,7 +475,7 @@ void SqliteCreateTable::Constraint::initUnique(const QListindexedColumns = indexedColumns; onConflict = algo; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); } @@ -499,7 +498,7 @@ void SqliteCreateTable::Constraint::initFk(const QList &i this->type = SqliteCreateTable::Constraint::FOREIGN_KEY; this->indexedColumns = indexedColumns; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); SqliteForeignKey* fk = new SqliteForeignKey(); @@ -511,10 +510,10 @@ void SqliteCreateTable::Constraint::initFk(const QList &i fk->setParent(this); - foreach (SqliteIndexedColumn* idxCol, fkColumns) + for (SqliteIndexedColumn* idxCol : fkColumns) idxCol->setParent(fk); - foreach (SqliteForeignKey::Condition* cond, conditions) + for (SqliteForeignKey::Condition* cond : conditions) cond->setParent(fk); this->foreignKey = fk; @@ -528,7 +527,7 @@ bool SqliteCreateTable::Constraint::doesAffectColumn(const QString& columnName) int SqliteCreateTable::Constraint::getAffectedColumnIdx(const QString& columnName) { int i = 0; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) { if (idxCol->name.compare(columnName, Qt::CaseInsensitive) == 0) return i; @@ -619,8 +618,7 @@ SqliteCreateTable::Column::Column(const QString &name, SqliteColumnType *type, c if (type) type->setParent(this); - SqliteCreateTable::Column::Constraint* constr = nullptr; - foreach (constr, constraints) + for (SqliteCreateTable::Column::Constraint* constr : constraints) { // If last constraint on list is NAME_ONLY we apply the name // to current constraint and remove NAME_ONLY. @@ -689,7 +687,7 @@ QList SqliteCreateTable::Column::getCons QList SqliteCreateTable::Column::getForeignKeysByTable(const QString& foreignTable) const { QList results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == Constraint::FOREIGN_KEY && constr->foreignKey->foreignTable.compare(foreignTable, Qt::CaseInsensitive) == 0) results << constr; @@ -748,7 +746,7 @@ TokenList SqliteCreateTable::Column::Constraint::rebuildTokensFromContents() { builder.withKeyword("DEFAULT").withSpace(); if (!id.isNull()) - builder.withOther(id); + builder.withOther(id, dialect); else if (!ctime.isNull()) builder.withKeyword(ctime.toUpper()); else if (expr) diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp index e15ddd6..001dd2d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp @@ -22,7 +22,7 @@ SqliteCreateTrigger::SqliteCreateTrigger(const SqliteCreateTrigger& other) : // Special case of deep collection copy SqliteQuery* newQuery = nullptr; - foreach (SqliteQuery* query, other.queries) + for (SqliteQuery* query : other.queries) { switch (query->queryType) { @@ -95,7 +95,7 @@ SqliteCreateTrigger::SqliteCreateTrigger(int temp, bool ifNotExists, const QStri if (when) when->setParent(this); - foreach (SqliteQuery* q, queries) + for (SqliteQuery* q : queries) q->setParent(this); } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp index 5dc830b..d17205a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp @@ -269,7 +269,7 @@ void SqliteExpr::initIn(SqliteExpr *expr, bool notKw, const QList& expr1 = expr; this->notKw = notKw; this->exprList = exprList; - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) expr->setParent(this); } @@ -331,7 +331,7 @@ void SqliteExpr::initCase(SqliteExpr *expr1, const QList& exprList, if (expr2) expr2->setParent(this); - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) expr->setParent(this); } @@ -341,6 +341,28 @@ void SqliteExpr::initRaise(const QString& type, const QString& text) raiseFunction = new SqliteRaise(type, text); } +void SqliteExpr::detectDoubleQuotes(bool recursively) +{ + if (doubleQuotesChecked) + return; + + doubleQuotesChecked = true; + + if (tokens.size() > 0) + { + QString val = tokens.first()->value; + if (val[0] == '"' && val[0] == val[val.length() - 1]) + possibleDoubleQuotedString = true; + } + + for (SqliteStatement* stmt : childStatements()) + { + SqliteExpr* subExpr = dynamic_cast(stmt); + if (subExpr) + subExpr->detectDoubleQuotes(recursively); + } +} + QStringList SqliteExpr::getColumnsInStatement() { return getStrListFromValue(column); @@ -533,12 +555,7 @@ TokenList SqliteExpr::rebuildTokensFromContents() void SqliteExpr::evaluatePostParsing() { - if (tokens.size() > 0) - { - QString val = tokens.first()->value; - if (val[0] == '"' && val[0] == val[val.length() - 1]) - possibleDoubleQuotedString = true; - } + detectDoubleQuotes(false); // not recursively, as SqliteStatement will take care of recursiveness } TokenList SqliteExpr::rebuildId() @@ -550,7 +567,7 @@ TokenList SqliteExpr::rebuildId() if (!table.isNull()) builder.withOther(table, dialect).withOperator("."); - if (possibleDoubleQuotedString) + if (table.isNull() && possibleDoubleQuotedString) builder.withStringPossiblyOther(column, dialect); else builder.withOther(column, dialect); @@ -652,7 +669,7 @@ TokenList SqliteExpr::rebuildCase() builder.withSpace(); bool then = false; - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) { if (then) builder.withKeyword("THEN"); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h index 4d5bb03..c65a8e2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h @@ -92,6 +92,7 @@ class API_EXPORT SqliteExpr : public SqliteStatement void initSubSelect(SqliteSelect* select); void initCase(SqliteExpr* expr1, const QList& exprList, SqliteExpr* expr2); void initRaise(const QString& type, const QString& text = QString::null); + void detectDoubleQuotes(bool recursively = true); Mode mode = Mode::null; QVariant literalValue = QVariant(); @@ -132,6 +133,7 @@ class API_EXPORT SqliteExpr : public SqliteStatement void evaluatePostParsing(); private: + bool doubleQuotesChecked = false; TokenList rebuildId(); TokenList rebuildLike(); TokenList rebuildNotNull(); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp index cb85377..e48cffb 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp @@ -5,6 +5,7 @@ #include "parser/statementtokenbuilder.h" #include "common/global.h" #include "sqlitewith.h" +#include "sqliteupsert.h" SqliteInsert::SqliteInsert() { @@ -18,6 +19,7 @@ SqliteInsert::SqliteInsert(const SqliteInsert& other) : DEEP_COPY_COLLECTION(SqliteExpr, values); DEEP_COPY_FIELD(SqliteSelect, select); DEEP_COPY_FIELD(SqliteWith, with); + DEEP_COPY_FIELD(SqliteUpsert, upsert); } SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QList &columns, @@ -33,12 +35,12 @@ SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QS if (with) with->setParent(this); - foreach (SqliteExpr* expr, row) + for (SqliteExpr* expr : row) expr->setParent(this); } SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QList &columns, - SqliteSelect *select, SqliteWith* with) : + SqliteSelect *select, SqliteWith* with, SqliteUpsert* upsert) : SqliteInsert() { initName(name1, name2); @@ -48,6 +50,10 @@ SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QS if (with) with->setParent(this); + this->upsert = upsert; + if (upsert) + upsert->setParent(this); + columnNames = columns; this->select = select; if (select) @@ -98,7 +104,7 @@ QStringList SqliteInsert::getDatabasesInStatement() TokenList SqliteInsert::getColumnTokensInStatement() { TokenList list; - foreach (TokenPtr token, getTokenListFromNamedKey("inscollist_opt", -1)) + for (TokenPtr token : getTokenListFromNamedKey("idlist_opt", -1)) { if (token->type != Token::OTHER && token->type != Token::KEYWORD) continue; @@ -201,6 +207,8 @@ TokenList SqliteInsert::rebuildTokensFromContents() if (select) { builder.withStatement(select); + if (upsert) + builder.withSpace().withStatement(upsert); } else if (dialect == Dialect::Sqlite2) // Sqlite2 uses classic single row values { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h index 4287680..2ee4965 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h @@ -9,6 +9,7 @@ class SqliteSelect; class SqliteExpr; class SqliteWith; +class SqliteUpsert; class API_EXPORT SqliteInsert : public SqliteQuery { @@ -19,7 +20,7 @@ class API_EXPORT SqliteInsert : public SqliteQuery const QString& name2, const QList& columns, const QList& row, SqliteWith* with); SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString& name1, - const QString& name2, const QList& columns, SqliteSelect* select, SqliteWith* with); + const QString& name2, const QList& columns, SqliteSelect* select, SqliteWith* with, SqliteUpsert* upsert = nullptr); SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString& name1, const QString& name2, const QList& columns, SqliteWith* with); ~SqliteInsert(); @@ -50,6 +51,7 @@ class API_EXPORT SqliteInsert : public SqliteQuery QList values; SqliteSelect* select = nullptr; SqliteWith* with = nullptr; + SqliteUpsert* upsert = nullptr; }; typedef QSharedPointer SqliteInsertPtr; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp index f1b1929..8038cb6 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp @@ -50,7 +50,7 @@ SqliteSelect* SqliteSelect::append(SqliteSelect* select, SqliteSelect::CompoundO Core::ResultColumn* resCol = nullptr; QList resColList; - foreach (const QList& singleValues, values) + for (const QList& singleValues : values) { Core* core = new Core(); core->setParent(select); @@ -64,9 +64,10 @@ SqliteSelect* SqliteSelect::append(SqliteSelect* select, SqliteSelect::CompoundO select->coreSelects << core; resColList.clear(); - foreach (SqliteExpr* value, singleValues) + for (SqliteExpr* value : singleValues) { resCol = new Core::ResultColumn(value, false, QString::null); + value->detectDoubleQuotes(); // invoke explicitly before rebuilding tokens not to lose this information resCol->rebuildTokens(); resCol->setParent(core); core->resultColumns << resCol; @@ -116,7 +117,7 @@ SqliteSelect::CompoundOperator SqliteSelect::compoundOperator(const QString& op) void SqliteSelect::reset() { - foreach (Core* core, coreSelects) + for (Core* core : coreSelects) delete core; coreSelects.clear(); @@ -172,13 +173,13 @@ SqliteSelect::Core::Core(int distinct, const QList &resCols, Sql if (limit) limit->setParent(this); - foreach (SqliteOrderBy* order, orderBy) + for (SqliteOrderBy* order : orderBy) order->setParent(this); - foreach (SqliteExpr* expr, groupBy) + for (SqliteExpr* expr : groupBy) expr->setParent(this); - foreach (SqliteSelect::Core::ResultColumn* resCol, resCols) + for (SqliteSelect::Core::ResultColumn* resCol : resCols) resCol->setParent(this); } @@ -293,6 +294,24 @@ SqliteSelect::Core::SingleSource::SingleSource(const QString& name1, const QStri this->notIndexedKw = notIndexedKw; } +SqliteSelect::Core::SingleSource::SingleSource(const QString &name1, const QString &name2, bool asKw, const QString &alias, const QList &exprList) +{ + if (!name2.isNull()) + { + database = name1; + funcName = name2; + } + else + funcName = name1; + + funcParams.append(exprList); + for (SqliteExpr* expr : exprList) + expr->setParent(this); + + this->asKw = asKw; + this->alias = alias; +} + SqliteSelect::Core::SingleSource::SingleSource(SqliteSelect *select, bool asKw, const QString &alias) { this->select = select; @@ -409,7 +428,7 @@ QStringList SqliteSelect::Core::JoinConstraint::getColumnsInStatement() TokenList SqliteSelect::Core::JoinConstraint::getColumnTokensInStatement() { TokenList list; - foreach (TokenPtr token, getTokenListFromNamedKey("inscollist", -1)) + for (TokenPtr token : getTokenListFromNamedKey("idlist", -1)) { if (token->type == Token::OPERATOR) // a COMMA continue; @@ -539,7 +558,7 @@ SqliteSelect::Core::JoinSource::JoinSource(SqliteSelect::Core::SingleSource *sin if (singleSource) singleSource->setParent(this); - foreach (JoinSourceOther* other, otherSources) + for (JoinSourceOther* other : otherSources) other->setParent(this); } @@ -590,12 +609,27 @@ TokenList SqliteSelect::Core::SingleSource::rebuildTokensFromContents() builder.withSpace().withKeyword("AS"); builder.withSpace().withOther(alias, dialect); + } + } + else if (!funcName.isNull()) + { + if (!database.isNull()) + builder.withOther(database, dialect).withOperator("."); - if (indexedByKw) - builder.withSpace().withKeyword("INDEXED").withSpace().withKeyword("BY").withSpace().withOther(indexedBy, dialect); - else if (notIndexedKw) - builder.withSpace().withKeyword("NOT").withSpace().withKeyword("INDEXED"); + builder.withOther(funcName, dialect).withParLeft().withStatementList(funcParams).withParRight(); + + if (!alias.isNull()) + { + if (asKw) + builder.withSpace().withKeyword("AS"); + + builder.withSpace().withOther(alias, dialect); } + + if (indexedByKw) + builder.withSpace().withKeyword("INDEXED").withSpace().withKeyword("BY").withSpace().withOther(indexedBy, dialect); + else if (notIndexedKw) + builder.withSpace().withKeyword("NOT").withSpace().withKeyword("INDEXED"); } else if (select) { @@ -723,7 +757,11 @@ TokenList SqliteSelect::Core::rebuildTokensFromContents() StatementTokenBuilder builder; if (valuesMode) { - builder.withKeyword("VALUES").withSpace().withParLeft().withStatementList(resultColumns).withParRight(); + SqliteSelect* select = dynamic_cast(parentStatement()); + if (select->coreSelects.indexOf(this) == 0) // this is first core in series of cores of values mode of the SELECT + builder.withKeyword("VALUES").withSpace(); + + builder.withParLeft().withStatementList(resultColumns).withParRight(); return builder.build(); } @@ -763,7 +801,7 @@ TokenList SqliteSelect::rebuildTokensFromContents() if (with) builder.withStatement(with); - foreach (SqliteSelect::Core* core, coreSelects) + for (SqliteSelect::Core* core : coreSelects) { if (core->compoundOp == CompoundOperator::UNION_ALL) { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h index 22d1921..b6f537d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h @@ -63,6 +63,8 @@ class API_EXPORT SqliteSelect : public SqliteQuery SingleSource(const SingleSource& other); SingleSource(const QString& name1, const QString& name2, bool asKw, const QString& alias, bool notIndexedKw, const QString& indexedBy); + SingleSource(const QString& name1, const QString& name2, + bool asKw, const QString& alias, const QList& exprList); SingleSource(SqliteSelect* select, bool asKw, const QString& alias); SingleSource(JoinSource* src, bool asKw, const QString& alias); @@ -71,6 +73,8 @@ class API_EXPORT SqliteSelect : public SqliteQuery QString database = QString::null; QString table = QString::null; QString alias = QString::null; + QString funcName = QString::null; + QList funcParams; bool asKw = false; bool indexedByKw = false; bool notIndexedKw = false; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp index f14273d..119461a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp @@ -90,7 +90,7 @@ QList SqliteStatement::getContextFullObjects(bool c void SqliteStatement::setSqliteDialect(Dialect dialect) { this->dialect = dialect; - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) stmt->setSqliteDialect(dialect); } @@ -106,14 +106,14 @@ SqliteStatementPtr SqliteStatement::detach() void SqliteStatement::processPostParsing() { evaluatePostParsing(); - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) stmt->processPostParsing(); } QStringList SqliteStatement::getContextColumns(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getColumnsInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextColumns(this, checkParent, checkChilds); return results; @@ -122,7 +122,7 @@ QStringList SqliteStatement::getContextColumns(SqliteStatement *caller, bool che QStringList SqliteStatement::getContextTables(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getTablesInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextTables(this, checkParent, checkChilds); return results; @@ -131,7 +131,7 @@ QStringList SqliteStatement::getContextTables(SqliteStatement *caller, bool chec QStringList SqliteStatement::getContextDatabases(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getDatabasesInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextDatabases(this, checkParent, checkChilds); return results; @@ -140,7 +140,7 @@ QStringList SqliteStatement::getContextDatabases(SqliteStatement *caller, bool c TokenList SqliteStatement::getContextColumnTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getColumnTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextColumnTokens(this, checkParent, checkChilds); return results; @@ -149,7 +149,7 @@ TokenList SqliteStatement::getContextColumnTokens(SqliteStatement *caller, bool TokenList SqliteStatement::getContextTableTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getTableTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextTableTokens(this, checkParent, checkChilds); return results; @@ -158,7 +158,7 @@ TokenList SqliteStatement::getContextTableTokens(SqliteStatement *caller, bool c TokenList SqliteStatement::getContextDatabaseTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getDatabaseTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextDatabaseTokens(this, checkParent, checkChilds); return results; @@ -167,7 +167,7 @@ TokenList SqliteStatement::getContextDatabaseTokens(SqliteStatement *caller, boo QList SqliteStatement::getContextFullObjects(SqliteStatement* caller, bool checkParent, bool checkChilds) { QList results = getFullObjectsInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) { stmt->setContextDbForFullObject(dbTokenForFullObjects); results += stmt->getContextFullObjects(this, checkParent, checkChilds); @@ -231,12 +231,12 @@ QList SqliteStatement::getContextStatements(SqliteStatement * if (checkChilds) { - foreach (stmt, childStatements()) + for (SqliteStatement* childStmt : childStatements()) { - if (stmt == caller) + if (childStmt == caller) continue; - results += stmt; + results += childStmt; } } @@ -246,7 +246,7 @@ QList SqliteStatement::getContextStatements(SqliteStatement * TokenList SqliteStatement::extractPrintableTokens(const TokenList &tokens, bool skipMeaningless) { TokenList list; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) { switch (token->type) { @@ -488,7 +488,7 @@ Range SqliteStatement::getRange() SqliteStatement *SqliteStatement::findStatementWithToken(TokenPtr token) { SqliteStatement* stmtWithToken = nullptr; - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) { stmtWithToken = stmt->findStatementWithToken(token); if (stmtWithToken) @@ -521,7 +521,7 @@ SqliteStatement *SqliteStatement::parentStatement() QList SqliteStatement::childStatements() { QList results; - foreach (QObject* obj, children()) + for (QObject* obj : children()) results += dynamic_cast(obj); return results; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h index bacb2d7..779bea3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h @@ -249,7 +249,7 @@ class API_EXPORT SqliteStatement : public QObject if (casted) results << casted; - foreach (SqliteStatement* stmt, getContextStatements(this, false, true)) + for (SqliteStatement* stmt : getContextStatements(this, false, true)) results += stmt->getAllTypedStatements(); return results; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp index df892fb..2063e0e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp @@ -17,7 +17,7 @@ SqliteUpdate::SqliteUpdate(const SqliteUpdate& other) : { // Special case of deep collection copy SqliteExpr* newExpr = nullptr; - foreach (const ColumnAndValue& keyValue, other.keyValueMap) + for (const ColumnAndValue& keyValue : other.keyValueMap) { newExpr = new SqliteExpr(*keyValue.second); newExpr->setParent(this); @@ -33,7 +33,7 @@ SqliteUpdate::~SqliteUpdate() } SqliteUpdate::SqliteUpdate(SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, bool notIndexedKw, const QString &indexedBy, - const QList > values, SqliteExpr *where, SqliteWith* with) + const QList& values, SqliteExpr *where, SqliteWith* with) : SqliteUpdate() { this->onConflict = onConflict; @@ -59,7 +59,7 @@ SqliteUpdate::SqliteUpdate(SqliteConflictAlgo onConflict, const QString &name1, if (with) with->setParent(this); - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) keyValue.second->setParent(this); } @@ -70,7 +70,7 @@ SqliteStatement*SqliteUpdate::clone() SqliteExpr* SqliteUpdate::getValueForColumnSet(const QString& column) { - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) { if (keyValue.first == column) return keyValue.second; @@ -81,8 +81,13 @@ SqliteExpr* SqliteUpdate::getValueForColumnSet(const QString& column) QStringList SqliteUpdate::getColumnsInStatement() { QStringList columns; - foreach (const ColumnAndValue& keyValue, keyValueMap) - columns += keyValue.first; + for (const ColumnAndValue& keyValue : keyValueMap) + { + if (keyValue.first.type() == QVariant::StringList) + columns += keyValue.first.toStringList(); + else + columns += keyValue.first.toString(); + } return columns; } @@ -105,20 +110,26 @@ TokenList SqliteUpdate::getColumnTokensInStatement() // for each 'expr' we get its first token, then locate it // in entire "setlist", get back 2 tokens to get what's before "=". TokenList list; - TokenList setListTokens = getTokenListFromNamedKey("setlist"); + TokenList setListTokens = getTokenListFromNamedKey("setlist", -1); int setListTokensSize = setListTokens.size(); - int colNameTokenIdx; + int end; + int start = 0; SqliteExpr* expr = nullptr; - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) { expr = keyValue.second; - colNameTokenIdx = setListTokens.indexOf(expr->tokens[0]) - 2; - if (colNameTokenIdx < 0 || colNameTokenIdx > setListTokensSize) + end = setListTokens.indexOf(expr->tokens[0]); + if (end < 0 || end >= setListTokensSize) { qCritical() << "Went out of bounds while looking for column tokens in SqliteUpdate::getColumnTokensInStatement()."; continue; } - list << setListTokens[colNameTokenIdx]; + + // Before expression tokens there will be only column(s) token(s) + // and commans, and equal operator. Let's take only ID tokens, which are columns. + list += setListTokens.mid(start, end - start - 1).filter(Token::OTHER); + + start = end + expr->tokens.size(); } return list; } @@ -189,12 +200,17 @@ TokenList SqliteUpdate::rebuildTokensFromContents() builder.withKeyword("SET").withSpace(); bool first = true; - foreach (const ColumnAndValue& keyVal, keyValueMap) + for (const ColumnAndValue& keyVal : keyValueMap) { if (!first) builder.withOperator(",").withSpace(); - builder.withOther(keyVal.first, dialect).withSpace().withOperator("=").withStatement(keyVal.second); + if (keyVal.first.type() == QVariant::StringList) + builder.withParLeft().withOtherList(keyVal.first.toStringList(), dialect).withParRight(); + else + builder.withOther(keyVal.first.toString(), dialect); + + builder.withSpace().withOperator("=").withStatement(keyVal.second); first = false; } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h index 7d6e0c1..642473c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h @@ -13,13 +13,13 @@ class SqliteWith; class API_EXPORT SqliteUpdate : public SqliteQuery { public: - typedef QPair ColumnAndValue; + typedef QPair ColumnAndValue; SqliteUpdate(); SqliteUpdate(const SqliteUpdate& other); ~SqliteUpdate(); SqliteUpdate(SqliteConflictAlgo onConflict, const QString& name1, const QString& name2, - bool notIndexedKw, const QString& indexedBy, const QList > values, + bool notIndexedKw, const QString& indexedBy, const QList& values, SqliteExpr* where, SqliteWith* with); SqliteStatement* clone(); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp new file mode 100644 index 0000000..ced9c2d --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp @@ -0,0 +1,152 @@ +#include "sqliteupsert.h" +#include "common/global.h" +#include "parser/ast/sqliteorderby.h" +#include "parser/ast/sqliteexpr.h" +#include "parser/statementtokenbuilder.h" +#include + +SqliteUpsert::SqliteUpsert() +{ + doNothing = true; +} + +SqliteUpsert::SqliteUpsert(const QList& conflictColumns, SqliteExpr* conflictWhere) +{ + this->conflictColumns = conflictColumns; + this->conflictWhere = conflictWhere; + + if (this->conflictWhere) + this->conflictWhere->setParent(this); + + for (SqliteOrderBy* idxCol : conflictColumns) + idxCol->setParent(this); + + doNothing = true; +} + +SqliteUpsert::SqliteUpsert(const QList& conflictColumns, SqliteExpr* conflictWhere, const QList& values, SqliteExpr* setWhere) +{ + this->conflictColumns = conflictColumns; + this->conflictWhere = conflictWhere; + this->keyValueMap = values; + this->setWhere = setWhere; + + if (this->conflictWhere) + this->conflictWhere->setParent(this); + + if (this->setWhere) + this->setWhere->setParent(this); + + for (SqliteOrderBy* idxCol : conflictColumns) + idxCol->setParent(this); + + doNothing = false; +} + +SqliteUpsert::SqliteUpsert(const SqliteUpsert& other) + : SqliteStatement(other), doNothing(other.doNothing) +{ + DEEP_COPY_COLLECTION(SqliteOrderBy, conflictColumns); + + // Special case of deep collection copy + SqliteExpr* newExpr = nullptr; + for (const ColumnAndValue& keyValue : other.keyValueMap) + { + newExpr = new SqliteExpr(*keyValue.second); + newExpr->setParent(this); + keyValueMap << ColumnAndValue(keyValue.first, newExpr); + } + + DEEP_COPY_FIELD(SqliteExpr, conflictWhere); + DEEP_COPY_FIELD(SqliteExpr, setWhere); +} + +SqliteStatement* SqliteUpsert::clone() +{ + return new SqliteUpsert(*this); +} + +TokenList SqliteUpsert::rebuildTokensFromContents() +{ + StatementTokenBuilder builder; + + builder.withKeyword("ON").withSpace().withKeyword("CONFLICT"); + if (!conflictColumns.isEmpty()) + { + builder.withSpace().withParLeft().withStatementList(conflictColumns).withParRight(); + if (conflictWhere) + builder.withSpace().withKeyword("WHERE").withStatement(conflictWhere); + } + + builder.withSpace().withKeyword("DO").withSpace(); + + if (doNothing) + { + builder.withKeyword("NOTHING"); + } + else + { + builder.withKeyword("UPDATE").withSpace().withKeyword("SET").withSpace(); + bool first = true; + for (const ColumnAndValue& keyVal : keyValueMap) + { + if (!first) + builder.withOperator(",").withSpace(); + + if (keyVal.first.type() == QVariant::StringList) + builder.withParLeft().withOtherList(keyVal.first.toStringList(), dialect).withParRight(); + else + builder.withOther(keyVal.first.toString(), dialect); + + builder.withSpace().withOperator("=").withStatement(keyVal.second); + first = false; + } + + if (setWhere) + builder.withSpace().withKeyword("WHERE").withStatement(setWhere); + } + + return builder.build(); +} + +QStringList SqliteUpsert::getColumnsInStatement() +{ + QStringList columns; + for (const ColumnAndValue& keyValue : keyValueMap) + { + if (keyValue.first.type() == QVariant::StringList) + columns += keyValue.first.toStringList(); + else + columns += keyValue.first.toString(); + } + + return columns; +} + +TokenList SqliteUpsert::getColumnTokensInStatement() +{ + // Alrorithm same as in UPDATE. See comments there for details. + TokenList list; + TokenList setListTokens = getTokenListFromNamedKey("setlist", -1); + int setListTokensSize = setListTokens.size(); + int end; + int start = 0; + SqliteExpr* expr = nullptr; + for (const ColumnAndValue& keyValue : keyValueMap) + { + expr = keyValue.second; + end = setListTokens.indexOf(expr->tokens[0]); + if (end < 0 || end >= setListTokensSize) + { + qCritical() << "Went out of bounds while looking for column tokens in SqliteUpdate::getColumnTokensInStatement()."; + continue; + } + + // Before expression tokens there will be only column(s) token(s) + // and commans, and equal operator. Let's take only ID tokens, which are columns. + list += setListTokens.mid(start, end - start - 1).filter(Token::OTHER); + + start = end + expr->tokens.size(); + } + return list; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h new file mode 100644 index 0000000..4a245cd --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h @@ -0,0 +1,35 @@ +#ifndef SQLITEUPSERT_H +#define SQLITEUPSERT_H + + +#include "sqlitestatement.h" +#include "sqliteindexedcolumn.h" + +class SqliteExpr; +class SqliteOrderBy; + +class SqliteUpsert : public SqliteStatement +{ + public: + typedef QPair ColumnAndValue; + + SqliteUpsert(); + SqliteUpsert(const QList& conflictColumns, SqliteExpr* conflictWhere); + SqliteUpsert(const QList& conflictColumns, SqliteExpr* conflictWhere, const QList& values, SqliteExpr* setWhere); + SqliteUpsert(const SqliteUpsert& other); + + SqliteStatement* clone(); + + QList conflictColumns; + SqliteExpr* conflictWhere = nullptr; + QList keyValueMap; + SqliteExpr* setWhere = nullptr; + bool doNothing = false; + + protected: + TokenList rebuildTokensFromContents(); + QStringList getColumnsInStatement(); + TokenList getColumnTokensInStatement(); +}; + +#endif // SQLITEUPSERT_H diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp index 2088ff2..bc8112e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp @@ -106,6 +106,8 @@ void initKeywords() keywords3["NOTNULL"] = TK3_NOTNULL; keywords3["NOT"] = TK3_NOT; keywords3["NO"] = TK3_NO; + keywords3["DO"] = TK3_DO; + keywords3["NOTHING"] = TK3_NOTHING; keywords3["NULL"] = TK3_NULL; keywords3["LIKE"] = TK3_LIKE_KW; keywords3["CASCADE"] = TK3_CASCADE; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lemon.c b/SQLiteStudio3/coreSQLiteStudio/parser/lemon.c new file mode 100644 index 0000000..4a2d68d --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/lemon.c @@ -0,0 +1,5044 @@ +/* + * This is a version of lemon that works with grammar files used by SQLiteStudio. + * It's taken from one of older SQLite versions. Code from new SQLite codebase is incompatible, unfortunately. + * +** This file contains all sources (including headers) to the LEMON +** LALR(1) parser generator. The sources have been combined into a +** single file to make it easy to include LEMON in the source tree +** and Makefile of another program. +** +** The author of this program disclaims copyright. +*/ +#include +#include +#include +#include +#include +#include + +#ifndef __WIN32__ +# if defined(_WIN32) || defined(WIN32) +# define __WIN32__ +# endif +#endif + +#ifdef __WIN32__ +#ifdef __cplusplus +extern "C" { +#endif +extern int access(const char *path, int mode); +#ifdef __cplusplus +} +#endif +#else +#include +#endif + +/* #define PRIVATE static */ +#define PRIVATE + +#ifdef TEST +#define MAXRHS 5 /* Set low to exercise exception code */ +#else +#define MAXRHS 1000 +#endif + +static int showPrecedenceConflict = 0; +static char *msort(char*,char**,int(*)(const char*,const char*)); + +/* +** Compilers are getting increasingly pedantic about type conversions +** as C evolves ever closer to Ada.... To work around the latest problems +** we have to define the following variant of strlen(). +*/ +#define lemonStrlen(X) ((int)strlen(X)) + +/* +** Compilers are starting to complain about the use of sprintf() and strcpy(), +** saying they are unsafe. So we define our own versions of those routines too. +** +** There are three routines here: lemon_sprintf(), lemon_vsprintf(), and +** lemon_addtext(). The first two are replacements for sprintf() and vsprintf(). +** The third is a helper routine for vsnprintf() that adds texts to the end of a +** buffer, making sure the buffer is always zero-terminated. +** +** The string formatter is a minimal subset of stdlib sprintf() supporting only +** a few simply conversions: +** +** %d +** %s +** %.*s +** +*/ +static void lemon_addtext( + char *zBuf, /* The buffer to which text is added */ + int *pnUsed, /* Slots of the buffer used so far */ + const char *zIn, /* Text to add */ + int nIn, /* Bytes of text to add. -1 to use strlen() */ + int iWidth /* Field width. Negative to left justify */ +){ + if( nIn<0 ) for(nIn=0; zIn[nIn]; nIn++){} + while( iWidth>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth--; } + if( nIn==0 ) return; + memcpy(&zBuf[*pnUsed], zIn, nIn); + *pnUsed += nIn; + while( (-iWidth)>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth++; } + zBuf[*pnUsed] = 0; +} +static int lemon_vsprintf(char *str, const char *zFormat, va_list ap){ + int i, j, k, c; + int nUsed = 0; + const char *z; + char zTemp[50]; + str[0] = 0; + for(i=j=0; (c = zFormat[i])!=0; i++){ + if( c=='%' ){ + int iWidth = 0; + lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0); + c = zFormat[++i]; + if( isdigit(c) || (c=='-' && isdigit(zFormat[i+1])) ){ + if( c=='-' ) i++; + while( isdigit(zFormat[i]) ) iWidth = iWidth*10 + zFormat[i++] - '0'; + if( c=='-' ) iWidth = -iWidth; + c = zFormat[i]; + } + if( c=='d' ){ + int v = va_arg(ap, int); + if( v<0 ){ + lemon_addtext(str, &nUsed, "-", 1, iWidth); + v = -v; + }else if( v==0 ){ + lemon_addtext(str, &nUsed, "0", 1, iWidth); + } + k = 0; + while( v>0 ){ + k++; + zTemp[sizeof(zTemp)-k] = (v%10) + '0'; + v /= 10; + } + lemon_addtext(str, &nUsed, &zTemp[sizeof(zTemp)-k], k, iWidth); + }else if( c=='s' ){ + z = va_arg(ap, const char*); + lemon_addtext(str, &nUsed, z, -1, iWidth); + }else if( c=='.' && memcmp(&zFormat[i], ".*s", 3)==0 ){ + i += 2; + k = va_arg(ap, int); + z = va_arg(ap, const char*); + lemon_addtext(str, &nUsed, z, k, iWidth); + }else if( c=='%' ){ + lemon_addtext(str, &nUsed, "%", 1, 0); + }else{ + fprintf(stderr, "illegal format\n"); + exit(1); + } + j = i+1; + } + } + lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0); + return nUsed; +} +static int lemon_sprintf(char *str, const char *format, ...){ + va_list ap; + int rc; + va_start(ap, format); + rc = lemon_vsprintf(str, format, ap); + va_end(ap); + return rc; +} +static void lemon_strcpy(char *dest, const char *src){ + while( (*(dest++) = *(src++))!=0 ){} +} +static void lemon_strcat(char *dest, const char *src){ + while( *dest ) dest++; + lemon_strcpy(dest, src); +} + + +/* a few forward declarations... */ +struct rule; +struct lemon; +struct action; + +static struct action *Action_new(void); +static struct action *Action_sort(struct action *); + +/********** From the file "build.h" ************************************/ +void FindRulePrecedences(); +void FindFirstSets(); +void FindStates(); +void FindLinks(); +void FindFollowSets(); +void FindActions(); + +/********* From the file "configlist.h" *********************************/ +void Configlist_init(void); +struct config *Configlist_add(struct rule *, int); +struct config *Configlist_addbasis(struct rule *, int); +void Configlist_closure(struct lemon *); +void Configlist_sort(void); +void Configlist_sortbasis(void); +struct config *Configlist_return(void); +struct config *Configlist_basis(void); +void Configlist_eat(struct config *); +void Configlist_reset(void); + +/********* From the file "error.h" ***************************************/ +void ErrorMsg(const char *, int,const char *, ...); + +/****** From the file "option.h" ******************************************/ +enum option_type { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, + OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR}; +struct s_options { + enum option_type type; + const char *label; + char *arg; + const char *message; +}; +int OptInit(char**,struct s_options*,FILE*); +int OptNArgs(void); +char *OptArg(int); +void OptErr(int); +void OptPrint(void); + +/******** From the file "parse.h" *****************************************/ +void Parse(struct lemon *lemp); + +/********* From the file "plink.h" ***************************************/ +struct plink *Plink_new(void); +void Plink_add(struct plink **, struct config *); +void Plink_copy(struct plink **, struct plink *); +void Plink_delete(struct plink *); + +/********** From the file "report.h" *************************************/ +void Reprint(struct lemon *); +void ReportOutput(struct lemon *); +void ReportTable(struct lemon *, int); +void ReportHeader(struct lemon *); +void CompressTables(struct lemon *); +void ResortStates(struct lemon *); + +/********** From the file "set.h" ****************************************/ +void SetSize(int); /* All sets will be of size N */ +char *SetNew(void); /* A new set for element 0..N */ +void SetFree(char*); /* Deallocate a set */ +int SetAdd(char*,int); /* Add element to a set */ +int SetUnion(char *,char *); /* A <- A U B, thru element N */ +#define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ + +/********** From the file "struct.h" *************************************/ +/* +** Principal data structures for the LEMON parser generator. +*/ + +typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean; + +/* Symbols (terminals and nonterminals) of the grammar are stored +** in the following: */ +enum symbol_type { + TERMINAL, + NONTERMINAL, + MULTITERMINAL +}; +enum e_assoc { + LEFT, + RIGHT, + NONE, + UNK +}; +struct symbol { + const char *name; /* Name of the symbol */ + int index; /* Index number for this symbol */ + enum symbol_type type; /* Symbols are all either TERMINALS or NTs */ + struct rule *rule; /* Linked list of rules of this (if an NT) */ + struct symbol *fallback; /* fallback token in case this token doesn't parse */ + int prec; /* Precedence if defined (-1 otherwise) */ + enum e_assoc assoc; /* Associativity if precedence is defined */ + char *firstset; /* First-set for all rules of this symbol */ + Boolean lambda; /* True if NT and can generate an empty string */ + int useCnt; /* Number of times used */ + char *destructor; /* Code which executes whenever this symbol is + ** popped from the stack during error processing */ + int destLineno; /* Line number for start of destructor */ + char *datatype; /* The data type of information held by this + ** object. Only used if type==NONTERMINAL */ + int dtnum; /* The data type number. In the parser, the value + ** stack is a union. The .yy%d element of this + ** union is the correct data type for this object */ + /* The following fields are used by MULTITERMINALs only */ + int nsubsym; /* Number of constituent symbols in the MULTI */ + struct symbol **subsym; /* Array of constituent symbols */ +}; + +/* Each production rule in the grammar is stored in the following +** structure. */ +struct rule { + struct symbol *lhs; /* Left-hand side of the rule */ + const char *lhsalias; /* Alias for the LHS (NULL if none) */ + int lhsStart; /* True if left-hand side is the start symbol */ + int ruleline; /* Line number for the rule */ + int nrhs; /* Number of RHS symbols */ + struct symbol **rhs; /* The RHS symbols */ + const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ + int line; /* Line number at which code begins */ + const char *code; /* The code executed when this rule is reduced */ + struct symbol *precsym; /* Precedence symbol for this rule */ + int index; /* An index number for this rule */ + Boolean canReduce; /* True if this rule is ever reduced */ + struct rule *nextlhs; /* Next rule with the same LHS */ + struct rule *next; /* Next rule in the global list */ +}; + +/* A configuration is a production rule of the grammar together with +** a mark (dot) showing how much of that rule has been processed so far. +** Configurations also contain a follow-set which is a list of terminal +** symbols which are allowed to immediately follow the end of the rule. +** Every configuration is recorded as an instance of the following: */ +enum cfgstatus { + COMPLETE, + INCOMPLETE +}; +struct config { + struct rule *rp; /* The rule upon which the configuration is based */ + int dot; /* The parse point */ + char *fws; /* Follow-set for this configuration only */ + struct plink *fplp; /* Follow-set forward propagation links */ + struct plink *bplp; /* Follow-set backwards propagation links */ + struct state *stp; /* Pointer to state which contains this */ + enum cfgstatus status; /* used during followset and shift computations */ + struct config *next; /* Next configuration in the state */ + struct config *bp; /* The next basis configuration */ +}; + +enum e_action { + SHIFT, + ACCEPT, + REDUCE, + ERROR, + SSCONFLICT, /* A shift/shift conflict */ + SRCONFLICT, /* Was a reduce, but part of a conflict */ + RRCONFLICT, /* Was a reduce, but part of a conflict */ + SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ + RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ + NOT_USED /* Deleted by compression */ +}; + +/* Every shift or reduce operation is stored as one of the following */ +struct action { + struct symbol *sp; /* The look-ahead symbol */ + enum e_action type; + union { + struct state *stp; /* The new state, if a shift */ + struct rule *rp; /* The rule, if a reduce */ + } x; + struct action *next; /* Next action for this state */ + struct action *collide; /* Next action with the same hash */ +}; + +/* Each state of the generated parser's finite state machine +** is encoded as an instance of the following structure. */ +struct state { + struct config *bp; /* The basis configurations for this state */ + struct config *cfp; /* All configurations in this set */ + int statenum; /* Sequential number for this state */ + struct action *ap; /* Array of actions for this state */ + int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ + int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ + int iDflt; /* Default action */ +}; +#define NO_OFFSET (-2147483647) + +/* A followset propagation link indicates that the contents of one +** configuration followset should be propagated to another whenever +** the first changes. */ +struct plink { + struct config *cfp; /* The configuration to which linked */ + struct plink *next; /* The next propagate link */ +}; + +/* The state vector for the entire parser generator is recorded as +** follows. (LEMON uses no global variables and makes little use of +** static variables. Fields in the following structure can be thought +** of as begin global variables in the program.) */ +struct lemon { + struct state **sorted; /* Table of states sorted by state number */ + struct rule *rule; /* List of all rules */ + int nstate; /* Number of states */ + int nrule; /* Number of rules */ + int nsymbol; /* Number of terminal and nonterminal symbols */ + int nterminal; /* Number of terminal symbols */ + struct symbol **symbols; /* Sorted array of pointers to symbols */ + int errorcnt; /* Number of errors */ + struct symbol *errsym; /* The error symbol */ + struct symbol *wildcard; /* Token that matches anything */ + char *name; /* Name of the generated parser */ + char *arg; /* Declaration of the 3th argument to parser */ + char *tokentype; /* Type of terminal symbols in the parser stack */ + char *vartype; /* The default type of non-terminal symbols */ + char *start; /* Name of the start symbol for the grammar */ + char *stacksize; /* Size of the parser stack */ + char *include; /* Code to put at the start of the C file */ + char *error; /* Code to execute when an error is seen */ + char *overflow; /* Code to execute on a stack overflow */ + char *failure; /* Code to execute on parser failure */ + char *accept; /* Code to execute when the parser excepts */ + char *extracode; /* Code appended to the generated file */ + char *tokendest; /* Code to execute to destroy token data */ + char *vardest; /* Code for the default non-terminal destructor */ + char *filename; /* Name of the input file */ + char *outname; /* Name of the current output file */ + char *tokenprefix; /* A prefix added to token names in the .h file */ + int nconflict; /* Number of parsing conflicts */ + int tablesize; /* Size of the parse tables */ + int basisflag; /* Print only basis configurations */ + int has_fallback; /* True if any %fallback is seen in the grammar */ + int nolinenosflag; /* True if #line statements should not be printed */ + char *argv0; /* Name of the program */ +}; + +#define MemoryCheck(X) if((X)==0){ \ + extern void memory_error(); \ + memory_error(); \ +} + +/**************** From the file "table.h" *********************************/ +/* +** All code in this file has been automatically generated +** from a specification in the file +** "table.q" +** by the associative array code building program "aagen". +** Do not edit this file! Instead, edit the specification +** file, then rerun aagen. +*/ +/* +** Code for processing tables in the LEMON parser generator. +*/ +/* Routines for handling a strings */ + +const char *Strsafe(const char *); + +void Strsafe_init(void); +int Strsafe_insert(const char *); +const char *Strsafe_find(const char *); + +/* Routines for handling symbols of the grammar */ + +struct symbol *Symbol_new(const char *); +int Symbolcmpp(const void *, const void *); +void Symbol_init(void); +int Symbol_insert(struct symbol *, const char *); +struct symbol *Symbol_find(const char *); +struct symbol *Symbol_Nth(int); +int Symbol_count(void); +struct symbol **Symbol_arrayof(void); + +/* Routines to manage the state table */ + +int Configcmp(const char *, const char *); +struct state *State_new(void); +void State_init(void); +int State_insert(struct state *, struct config *); +struct state *State_find(struct config *); +struct state **State_arrayof(/* */); + +/* Routines used for efficiency in Configlist_add */ + +void Configtable_init(void); +int Configtable_insert(struct config *); +struct config *Configtable_find(struct config *); +void Configtable_clear(int(*)(struct config *)); + +/****************** From the file "action.c" *******************************/ +/* +** Routines processing parser actions in the LEMON parser generator. +*/ + +/* Allocate a new parser action */ +static struct action *Action_new(void){ + static struct action *freelist = 0; + struct action *newaction; + + if( freelist==0 ){ + int i; + int amt = 100; + freelist = (struct action *)calloc(amt, sizeof(struct action)); + if( freelist==0 ){ + fprintf(stderr,"Unable to allocate memory for a new parser action."); + exit(1); + } + for(i=0; inext; + return newaction; +} + +/* Compare two actions for sorting purposes. Return negative, zero, or +** positive if the first action is less than, equal to, or greater than +** the first +*/ +static int actioncmp( + struct action *ap1, + struct action *ap2 +){ + int rc; + rc = ap1->sp->index - ap2->sp->index; + if( rc==0 ){ + rc = (int)ap1->type - (int)ap2->type; + } + if( rc==0 && ap1->type==REDUCE ){ + rc = ap1->x.rp->index - ap2->x.rp->index; + } + if( rc==0 ){ + rc = (int) (ap2 - ap1); + } + return rc; +} + +/* Sort parser actions */ +static struct action *Action_sort( + struct action *ap +){ + ap = (struct action *)msort((char *)ap,(char **)&ap->next, + (int(*)(const char*,const char*))actioncmp); + return ap; +} + +void Action_add( + struct action **app, + enum e_action type, + struct symbol *sp, + char *arg +){ + struct action *newaction; + newaction = Action_new(); + newaction->next = *app; + *app = newaction; + newaction->type = type; + newaction->sp = sp; + if( type==SHIFT ){ + newaction->x.stp = (struct state *)arg; + }else{ + newaction->x.rp = (struct rule *)arg; + } +} +/********************** New code to implement the "acttab" module ***********/ +/* +** This module implements routines use to construct the yy_action[] table. +*/ + +/* +** The state of the yy_action table under construction is an instance of +** the following structure. +** +** The yy_action table maps the pair (state_number, lookahead) into an +** action_number. The table is an array of integers pairs. The state_number +** determines an initial offset into the yy_action array. The lookahead +** value is then added to this initial offset to get an index X into the +** yy_action array. If the aAction[X].lookahead equals the value of the +** of the lookahead input, then the value of the action_number output is +** aAction[X].action. If the lookaheads do not match then the +** default action for the state_number is returned. +** +** All actions associated with a single state_number are first entered +** into aLookahead[] using multiple calls to acttab_action(). Then the +** actions for that single state_number are placed into the aAction[] +** array with a single call to acttab_insert(). The acttab_insert() call +** also resets the aLookahead[] array in preparation for the next +** state number. +*/ +struct lookahead_action { + int lookahead; /* Value of the lookahead token */ + int action; /* Action to take on the given lookahead */ +}; +typedef struct acttab acttab; +struct acttab { + int nAction; /* Number of used slots in aAction[] */ + int nActionAlloc; /* Slots allocated for aAction[] */ + struct lookahead_action + *aAction, /* The yy_action[] table under construction */ + *aLookahead; /* A single new transaction set */ + int mnLookahead; /* Minimum aLookahead[].lookahead */ + int mnAction; /* Action associated with mnLookahead */ + int mxLookahead; /* Maximum aLookahead[].lookahead */ + int nLookahead; /* Used slots in aLookahead[] */ + int nLookaheadAlloc; /* Slots allocated in aLookahead[] */ +}; + +/* Return the number of entries in the yy_action table */ +#define acttab_size(X) ((X)->nAction) + +/* The value for the N-th entry in yy_action */ +#define acttab_yyaction(X,N) ((X)->aAction[N].action) + +/* The value for the N-th entry in yy_lookahead */ +#define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead) + +/* Free all memory associated with the given acttab */ +void acttab_free(acttab *p){ + free( p->aAction ); + free( p->aLookahead ); + free( p ); +} + +/* Allocate a new acttab structure */ +acttab *acttab_alloc(void){ + acttab *p = (acttab *) calloc( 1, sizeof(*p) ); + if( p==0 ){ + fprintf(stderr,"Unable to allocate memory for a new acttab."); + exit(1); + } + memset(p, 0, sizeof(*p)); + return p; +} + +/* Add a new action to the current transaction set. +** +** This routine is called once for each lookahead for a particular +** state. +*/ +void acttab_action(acttab *p, int lookahead, int action){ + if( p->nLookahead>=p->nLookaheadAlloc ){ + p->nLookaheadAlloc += 25; + p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead, + sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); + if( p->aLookahead==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + } + if( p->nLookahead==0 ){ + p->mxLookahead = lookahead; + p->mnLookahead = lookahead; + p->mnAction = action; + }else{ + if( p->mxLookaheadmxLookahead = lookahead; + if( p->mnLookahead>lookahead ){ + p->mnLookahead = lookahead; + p->mnAction = action; + } + } + p->aLookahead[p->nLookahead].lookahead = lookahead; + p->aLookahead[p->nLookahead].action = action; + p->nLookahead++; +} + +/* +** Add the transaction set built up with prior calls to acttab_action() +** into the current action table. Then reset the transaction set back +** to an empty set in preparation for a new round of acttab_action() calls. +** +** Return the offset into the action table of the new transaction. +*/ +int acttab_insert(acttab *p){ + int i, j, k, n; + assert( p->nLookahead>0 ); + + /* Make sure we have enough space to hold the expanded action table + ** in the worst case. The worst case occurs if the transaction set + ** must be appended to the current action table + */ + n = p->mxLookahead + 1; + if( p->nAction + n >= p->nActionAlloc ){ + int oldAlloc = p->nActionAlloc; + p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20; + p->aAction = (struct lookahead_action *) realloc( p->aAction, + sizeof(p->aAction[0])*p->nActionAlloc); + if( p->aAction==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + for(i=oldAlloc; inActionAlloc; i++){ + p->aAction[i].lookahead = -1; + p->aAction[i].action = -1; + } + } + + /* Scan the existing action table looking for an offset that is a + ** duplicate of the current transaction set. Fall out of the loop + ** if and when the duplicate is found. + ** + ** i is the index in p->aAction[] where p->mnLookahead is inserted. + */ + for(i=p->nAction-1; i>=0; i--){ + if( p->aAction[i].lookahead==p->mnLookahead ){ + /* All lookaheads and actions in the aLookahead[] transaction + ** must match against the candidate aAction[i] entry. */ + if( p->aAction[i].action!=p->mnAction ) continue; + for(j=0; jnLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + if( k<0 || k>=p->nAction ) break; + if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break; + if( p->aLookahead[j].action!=p->aAction[k].action ) break; + } + if( jnLookahead ) continue; + + /* No possible lookahead value that is not in the aLookahead[] + ** transaction is allowed to match aAction[i] */ + n = 0; + for(j=0; jnAction; j++){ + if( p->aAction[j].lookahead<0 ) continue; + if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++; + } + if( n==p->nLookahead ){ + break; /* An exact match is found at offset i */ + } + } + } + + /* If no existing offsets exactly match the current transaction, find an + ** an empty offset in the aAction[] table in which we can add the + ** aLookahead[] transaction. + */ + if( i<0 ){ + /* Look for holes in the aAction[] table that fit the current + ** aLookahead[] transaction. Leave i set to the offset of the hole. + ** If no holes are found, i is left at p->nAction, which means the + ** transaction will be appended. */ + for(i=0; inActionAlloc - p->mxLookahead; i++){ + if( p->aAction[i].lookahead<0 ){ + for(j=0; jnLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + if( k<0 ) break; + if( p->aAction[k].lookahead>=0 ) break; + } + if( jnLookahead ) continue; + for(j=0; jnAction; j++){ + if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; + } + if( j==p->nAction ){ + break; /* Fits in empty slots */ + } + } + } + } + /* Insert transaction set at index i. */ + for(j=0; jnLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + p->aAction[k] = p->aLookahead[j]; + if( k>=p->nAction ) p->nAction = k+1; + } + p->nLookahead = 0; + + /* Return the offset that is added to the lookahead in order to get the + ** index into yy_action of the action */ + return i - p->mnLookahead; +} + +/********************** From the file "build.c" *****************************/ +/* +** Routines to construction the finite state machine for the LEMON +** parser generator. +*/ + +/* Find a precedence symbol of every rule in the grammar. +** +** Those rules which have a precedence symbol coded in the input +** grammar using the "[symbol]" construct will already have the +** rp->precsym field filled. Other rules take as their precedence +** symbol the first RHS symbol with a defined precedence. If there +** are not RHS symbols with a defined precedence, the precedence +** symbol field is left blank. +*/ +void FindRulePrecedences(struct lemon *xp) +{ + struct rule *rp; + for(rp=xp->rule; rp; rp=rp->next){ + if( rp->precsym==0 ){ + int i, j; + for(i=0; inrhs && rp->precsym==0; i++){ + struct symbol *sp = rp->rhs[i]; + if( sp->type==MULTITERMINAL ){ + for(j=0; jnsubsym; j++){ + if( sp->subsym[j]->prec>=0 ){ + rp->precsym = sp->subsym[j]; + break; + } + } + }else if( sp->prec>=0 ){ + rp->precsym = rp->rhs[i]; + } + } + } + } + return; +} + +/* Find all nonterminals which will generate the empty string. +** Then go back and compute the first sets of every nonterminal. +** The first set is the set of all terminal symbols which can begin +** a string generated by that nonterminal. +*/ +void FindFirstSets(struct lemon *lemp) +{ + int i, j; + struct rule *rp; + int progress; + + for(i=0; insymbol; i++){ + lemp->symbols[i]->lambda = LEMON_FALSE; + } + for(i=lemp->nterminal; insymbol; i++){ + lemp->symbols[i]->firstset = SetNew(); + } + + /* First compute all lambdas */ + do{ + progress = 0; + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->lhs->lambda ) continue; + for(i=0; inrhs; i++){ + struct symbol *sp = rp->rhs[i]; + assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE ); + if( sp->lambda==LEMON_FALSE ) break; + } + if( i==rp->nrhs ){ + rp->lhs->lambda = LEMON_TRUE; + progress = 1; + } + } + }while( progress ); + + /* Now compute all first sets */ + do{ + struct symbol *s1, *s2; + progress = 0; + for(rp=lemp->rule; rp; rp=rp->next){ + s1 = rp->lhs; + for(i=0; inrhs; i++){ + s2 = rp->rhs[i]; + if( s2->type==TERMINAL ){ + progress += SetAdd(s1->firstset,s2->index); + break; + }else if( s2->type==MULTITERMINAL ){ + for(j=0; jnsubsym; j++){ + progress += SetAdd(s1->firstset,s2->subsym[j]->index); + } + break; + }else if( s1==s2 ){ + if( s1->lambda==LEMON_FALSE ) break; + }else{ + progress += SetUnion(s1->firstset,s2->firstset); + if( s2->lambda==LEMON_FALSE ) break; + } + } + } + }while( progress ); + return; +} + +/* Compute all LR(0) states for the grammar. Links +** are added to between some states so that the LR(1) follow sets +** can be computed later. +*/ +PRIVATE struct state *getstate(struct lemon *); /* forward reference */ +void FindStates(struct lemon *lemp) +{ + struct symbol *sp; + struct rule *rp; + + Configlist_init(); + + /* Find the start symbol */ + if( lemp->start ){ + sp = Symbol_find(lemp->start); + if( sp==0 ){ + ErrorMsg(lemp->filename,0, +"The specified start symbol \"%s\" is not \ +in a nonterminal of the grammar. \"%s\" will be used as the start \ +symbol instead.",lemp->start,lemp->rule->lhs->name); + lemp->errorcnt++; + sp = lemp->rule->lhs; + } + }else{ + sp = lemp->rule->lhs; + } + + /* Make sure the start symbol doesn't occur on the right-hand side of + ** any rule. Report an error if it does. (YACC would generate a new + ** start symbol in this case.) */ + for(rp=lemp->rule; rp; rp=rp->next){ + int i; + for(i=0; inrhs; i++){ + if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */ + ErrorMsg(lemp->filename,0, +"The start symbol \"%s\" occurs on the \ +right-hand side of a rule. This will result in a parser which \ +does not work properly.",sp->name); + lemp->errorcnt++; + } + } + } + + /* The basis configuration set for the first state + ** is all rules which have the start symbol as their + ** left-hand side */ + for(rp=sp->rule; rp; rp=rp->nextlhs){ + struct config *newcfp; + rp->lhsStart = 1; + newcfp = Configlist_addbasis(rp,0); + SetAdd(newcfp->fws,0); + } + + /* Compute the first state. All other states will be + ** computed automatically during the computation of the first one. + ** The returned pointer to the first state is not used. */ + (void)getstate(lemp); + return; +} + +/* Return a pointer to a state which is described by the configuration +** list which has been built from calls to Configlist_add. +*/ +PRIVATE void buildshifts(struct lemon *, struct state *); /* Forwd ref */ +PRIVATE struct state *getstate(struct lemon *lemp) +{ + struct config *cfp, *bp; + struct state *stp; + + /* Extract the sorted basis of the new state. The basis was constructed + ** by prior calls to "Configlist_addbasis()". */ + Configlist_sortbasis(); + bp = Configlist_basis(); + + /* Get a state with the same basis */ + stp = State_find(bp); + if( stp ){ + /* A state with the same basis already exists! Copy all the follow-set + ** propagation links from the state under construction into the + ** preexisting state, then return a pointer to the preexisting state */ + struct config *x, *y; + for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){ + Plink_copy(&y->bplp,x->bplp); + Plink_delete(x->fplp); + x->fplp = x->bplp = 0; + } + cfp = Configlist_return(); + Configlist_eat(cfp); + }else{ + /* This really is a new state. Construct all the details */ + Configlist_closure(lemp); /* Compute the configuration closure */ + Configlist_sort(); /* Sort the configuration closure */ + cfp = Configlist_return(); /* Get a pointer to the config list */ + stp = State_new(); /* A new state structure */ + MemoryCheck(stp); + stp->bp = bp; /* Remember the configuration basis */ + stp->cfp = cfp; /* Remember the configuration closure */ + stp->statenum = lemp->nstate++; /* Every state gets a sequence number */ + stp->ap = 0; /* No actions, yet. */ + State_insert(stp,stp->bp); /* Add to the state table */ + buildshifts(lemp,stp); /* Recursively compute successor states */ + } + return stp; +} + +/* +** Return true if two symbols are the same. +*/ +int same_symbol(struct symbol *a, struct symbol *b) +{ + int i; + if( a==b ) return 1; + if( a->type!=MULTITERMINAL ) return 0; + if( b->type!=MULTITERMINAL ) return 0; + if( a->nsubsym!=b->nsubsym ) return 0; + for(i=0; insubsym; i++){ + if( a->subsym[i]!=b->subsym[i] ) return 0; + } + return 1; +} + +/* Construct all successor states to the given state. A "successor" +** state is any state which can be reached by a shift action. +*/ +PRIVATE void buildshifts(struct lemon *lemp, struct state *stp) +{ + struct config *cfp; /* For looping thru the config closure of "stp" */ + struct config *bcfp; /* For the inner loop on config closure of "stp" */ + struct config *newcfg; /* */ + struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ + struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ + struct state *newstp; /* A pointer to a successor state */ + + /* Each configuration becomes complete after it contibutes to a successor + ** state. Initially, all configurations are incomplete */ + for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE; + + /* Loop through all configurations of the state "stp" */ + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */ + if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */ + Configlist_reset(); /* Reset the new config set */ + sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */ + + /* For every configuration in the state "stp" which has the symbol "sp" + ** following its dot, add the same configuration to the basis set under + ** construction but with the dot shifted one symbol to the right. */ + for(bcfp=cfp; bcfp; bcfp=bcfp->next){ + if( bcfp->status==COMPLETE ) continue; /* Already used */ + if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */ + bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */ + if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */ + bcfp->status = COMPLETE; /* Mark this config as used */ + newcfg = Configlist_addbasis(bcfp->rp,bcfp->dot+1); + Plink_add(&newcfg->bplp,bcfp); + } + + /* Get a pointer to the state described by the basis configuration set + ** constructed in the preceding loop */ + newstp = getstate(lemp); + + /* The state "newstp" is reached from the state "stp" by a shift action + ** on the symbol "sp" */ + if( sp->type==MULTITERMINAL ){ + int i; + for(i=0; insubsym; i++){ + Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp); + } + }else{ + Action_add(&stp->ap,SHIFT,sp,(char *)newstp); + } + } +} + +/* +** Construct the propagation links +*/ +void FindLinks(struct lemon *lemp) +{ + int i; + struct config *cfp, *other; + struct state *stp; + struct plink *plp; + + /* Housekeeping detail: + ** Add to every propagate link a pointer back to the state to + ** which the link is attached. */ + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + cfp->stp = stp; + } + } + + /* Convert all backlinks into forward links. Only the forward + ** links are used in the follow-set computation. */ + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + for(plp=cfp->bplp; plp; plp=plp->next){ + other = plp->cfp; + Plink_add(&other->fplp,cfp); + } + } + } +} + +/* Compute all followsets. +** +** A followset is the set of all symbols which can come immediately +** after a configuration. +*/ +void FindFollowSets(struct lemon *lemp) +{ + int i; + struct config *cfp; + struct plink *plp; + int progress; + int change; + + for(i=0; instate; i++){ + for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ + cfp->status = INCOMPLETE; + } + } + + do{ + progress = 0; + for(i=0; instate; i++){ + for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ + if( cfp->status==COMPLETE ) continue; + for(plp=cfp->fplp; plp; plp=plp->next){ + change = SetUnion(plp->cfp->fws,cfp->fws); + if( change ){ + plp->cfp->status = INCOMPLETE; + progress = 1; + } + } + cfp->status = COMPLETE; + } + } + }while( progress ); +} + +static int resolve_conflict(struct action *,struct action *); + +/* Compute the reduce actions, and resolve conflicts. +*/ +void FindActions(struct lemon *lemp) +{ + int i,j; + struct config *cfp; + struct state *stp; + struct symbol *sp; + struct rule *rp; + + /* Add all of the reduce actions + ** A reduce action is added for each element of the followset of + ** a configuration which has its dot at the extreme right. + */ + for(i=0; instate; i++){ /* Loop over all states */ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ /* Loop over all configurations */ + if( cfp->rp->nrhs==cfp->dot ){ /* Is dot at extreme right? */ + for(j=0; jnterminal; j++){ + if( SetFind(cfp->fws,j) ){ + /* Add a reduce action to the state "stp" which will reduce by the + ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */ + Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp); + } + } + } + } + } + + /* Add the accepting token */ + if( lemp->start ){ + sp = Symbol_find(lemp->start); + if( sp==0 ) sp = lemp->rule->lhs; + }else{ + sp = lemp->rule->lhs; + } + /* Add to the first state (which is always the starting state of the + ** finite state machine) an action to ACCEPT if the lookahead is the + ** start nonterminal. */ + Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0); + + /* Resolve conflicts */ + for(i=0; instate; i++){ + struct action *ap, *nap; + struct state *stp; + stp = lemp->sorted[i]; + /* assert( stp->ap ); */ + stp->ap = Action_sort(stp->ap); + for(ap=stp->ap; ap && ap->next; ap=ap->next){ + for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){ + /* The two actions "ap" and "nap" have the same lookahead. + ** Figure out which one should be used */ + lemp->nconflict += resolve_conflict(ap,nap); + } + } + } + + /* Report an error for each rule that can never be reduced. */ + for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE; + for(i=0; instate; i++){ + struct action *ap; + for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ + if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE; + } + } + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->canReduce ) continue; + ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n"); + lemp->errorcnt++; + } +} + +/* Resolve a conflict between the two given actions. If the +** conflict can't be resolved, return non-zero. +** +** NO LONGER TRUE: +** To resolve a conflict, first look to see if either action +** is on an error rule. In that case, take the action which +** is not associated with the error rule. If neither or both +** actions are associated with an error rule, then try to +** use precedence to resolve the conflict. +** +** If either action is a SHIFT, then it must be apx. This +** function won't work if apx->type==REDUCE and apy->type==SHIFT. +*/ +static int resolve_conflict( + struct action *apx, + struct action *apy +){ + struct symbol *spx, *spy; + int errcnt = 0; + assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ + if( apx->type==SHIFT && apy->type==SHIFT ){ + apy->type = SSCONFLICT; + errcnt++; + } + if( apx->type==SHIFT && apy->type==REDUCE ){ + spx = apx->sp; + spy = apy->x.rp->precsym; + if( spy==0 || spx->prec<0 || spy->prec<0 ){ + /* Not enough precedence information. */ + apy->type = SRCONFLICT; + errcnt++; + }else if( spx->prec>spy->prec ){ /* higher precedence wins */ + apy->type = RD_RESOLVED; + }else if( spx->precprec ){ + apx->type = SH_RESOLVED; + }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */ + apy->type = RD_RESOLVED; /* associativity */ + }else if( spx->prec==spy->prec && spx->assoc==LEFT ){ /* to break tie */ + apx->type = SH_RESOLVED; + }else{ + assert( spx->prec==spy->prec && spx->assoc==NONE ); + apy->type = SRCONFLICT; + errcnt++; + } + }else if( apx->type==REDUCE && apy->type==REDUCE ){ + spx = apx->x.rp->precsym; + spy = apy->x.rp->precsym; + if( spx==0 || spy==0 || spx->prec<0 || + spy->prec<0 || spx->prec==spy->prec ){ + apy->type = RRCONFLICT; + errcnt++; + }else if( spx->prec>spy->prec ){ + apy->type = RD_RESOLVED; + }else if( spx->precprec ){ + apx->type = RD_RESOLVED; + } + }else{ + assert( + apx->type==SH_RESOLVED || + apx->type==RD_RESOLVED || + apx->type==SSCONFLICT || + apx->type==SRCONFLICT || + apx->type==RRCONFLICT || + apy->type==SH_RESOLVED || + apy->type==RD_RESOLVED || + apy->type==SSCONFLICT || + apy->type==SRCONFLICT || + apy->type==RRCONFLICT + ); + /* The REDUCE/SHIFT case cannot happen because SHIFTs come before + ** REDUCEs on the list. If we reach this point it must be because + ** the parser conflict had already been resolved. */ + } + return errcnt; +} +/********************* From the file "configlist.c" *************************/ +/* +** Routines to processing a configuration list and building a state +** in the LEMON parser generator. +*/ + +static struct config *freelist = 0; /* List of free configurations */ +static struct config *current = 0; /* Top of list of configurations */ +static struct config **currentend = 0; /* Last on list of configs */ +static struct config *basis = 0; /* Top of list of basis configs */ +static struct config **basisend = 0; /* End of list of basis configs */ + +/* Return a pointer to a new configuration */ +PRIVATE struct config *newconfig(){ + struct config *newcfg; + if( freelist==0 ){ + int i; + int amt = 3; + freelist = (struct config *)calloc( amt, sizeof(struct config) ); + if( freelist==0 ){ + fprintf(stderr,"Unable to allocate memory for a new configuration."); + exit(1); + } + for(i=0; inext; + return newcfg; +} + +/* The configuration "old" is no longer used */ +PRIVATE void deleteconfig(struct config *old) +{ + old->next = freelist; + freelist = old; +} + +/* Initialized the configuration list builder */ +void Configlist_init(){ + current = 0; + currentend = ¤t; + basis = 0; + basisend = &basis; + Configtable_init(); + return; +} + +/* Initialized the configuration list builder */ +void Configlist_reset(){ + current = 0; + currentend = ¤t; + basis = 0; + basisend = &basis; + Configtable_clear(0); + return; +} + +/* Add another configuration to the configuration list */ +struct config *Configlist_add( + struct rule *rp, /* The rule */ + int dot /* Index into the RHS of the rule where the dot goes */ +){ + struct config *cfp, model; + + assert( currentend!=0 ); + model.rp = rp; + model.dot = dot; + cfp = Configtable_find(&model); + if( cfp==0 ){ + cfp = newconfig(); + cfp->rp = rp; + cfp->dot = dot; + cfp->fws = SetNew(); + cfp->stp = 0; + cfp->fplp = cfp->bplp = 0; + cfp->next = 0; + cfp->bp = 0; + *currentend = cfp; + currentend = &cfp->next; + Configtable_insert(cfp); + } + return cfp; +} + +/* Add a basis configuration to the configuration list */ +struct config *Configlist_addbasis(struct rule *rp, int dot) +{ + struct config *cfp, model; + + assert( basisend!=0 ); + assert( currentend!=0 ); + model.rp = rp; + model.dot = dot; + cfp = Configtable_find(&model); + if( cfp==0 ){ + cfp = newconfig(); + cfp->rp = rp; + cfp->dot = dot; + cfp->fws = SetNew(); + cfp->stp = 0; + cfp->fplp = cfp->bplp = 0; + cfp->next = 0; + cfp->bp = 0; + *currentend = cfp; + currentend = &cfp->next; + *basisend = cfp; + basisend = &cfp->bp; + Configtable_insert(cfp); + } + return cfp; +} + +/* Compute the closure of the configuration list */ +void Configlist_closure(struct lemon *lemp) +{ + struct config *cfp, *newcfp; + struct rule *rp, *newrp; + struct symbol *sp, *xsp; + int i, dot; + + assert( currentend!=0 ); + for(cfp=current; cfp; cfp=cfp->next){ + rp = cfp->rp; + dot = cfp->dot; + if( dot>=rp->nrhs ) continue; + sp = rp->rhs[dot]; + if( sp->type==NONTERMINAL ){ + if( sp->rule==0 && sp!=lemp->errsym ){ + ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.", + sp->name); + lemp->errorcnt++; + } + for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){ + newcfp = Configlist_add(newrp,0); + for(i=dot+1; inrhs; i++){ + xsp = rp->rhs[i]; + if( xsp->type==TERMINAL ){ + SetAdd(newcfp->fws,xsp->index); + break; + }else if( xsp->type==MULTITERMINAL ){ + int k; + for(k=0; knsubsym; k++){ + SetAdd(newcfp->fws, xsp->subsym[k]->index); + } + break; + }else{ + SetUnion(newcfp->fws,xsp->firstset); + if( xsp->lambda==LEMON_FALSE ) break; + } + } + if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp); + } + } + } + return; +} + +/* Sort the configuration list */ +void Configlist_sort(){ + current = (struct config *)msort((char *)current,(char **)&(current->next),Configcmp); + currentend = 0; + return; +} + +/* Sort the basis configuration list */ +void Configlist_sortbasis(){ + basis = (struct config *)msort((char *)current,(char **)&(current->bp),Configcmp); + basisend = 0; + return; +} + +/* Return a pointer to the head of the configuration list and +** reset the list */ +struct config *Configlist_return(){ + struct config *old; + old = current; + current = 0; + currentend = 0; + return old; +} + +/* Return a pointer to the head of the configuration list and +** reset the list */ +struct config *Configlist_basis(){ + struct config *old; + old = basis; + basis = 0; + basisend = 0; + return old; +} + +/* Free all elements of the given configuration list */ +void Configlist_eat(struct config *cfp) +{ + struct config *nextcfp; + for(; cfp; cfp=nextcfp){ + nextcfp = cfp->next; + assert( cfp->fplp==0 ); + assert( cfp->bplp==0 ); + if( cfp->fws ) SetFree(cfp->fws); + deleteconfig(cfp); + } + return; +} +/***************** From the file "error.c" *********************************/ +/* +** Code for printing error message. +*/ + +void ErrorMsg(const char *filename, int lineno, const char *format, ...){ + va_list ap; + fprintf(stderr, "%s:%d: ", filename, lineno); + va_start(ap, format); + vfprintf(stderr,format,ap); + va_end(ap); + fprintf(stderr, "\n"); +} +/**************** From the file "main.c" ************************************/ +/* +** Main program file for the LEMON parser generator. +*/ + +/* Report an out-of-memory condition and abort. This function +** is used mostly by the "MemoryCheck" macro in struct.h +*/ +void memory_error(){ + fprintf(stderr,"Out of memory. Aborting...\n"); + exit(1); +} + +static int nDefine = 0; /* Number of -D options on the command line */ +static char **azDefine = 0; /* Name of the -D macros */ + +/* This routine is called with the argument to each -D command-line option. +** Add the macro defined to the azDefine array. +*/ +static void handle_D_option(char *z){ + char **paz; + nDefine++; + azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine); + if( azDefine==0 ){ + fprintf(stderr,"out of memory\n"); + exit(1); + } + paz = &azDefine[nDefine-1]; + *paz = (char *) malloc( lemonStrlen(z)+1 ); + if( *paz==0 ){ + fprintf(stderr,"out of memory\n"); + exit(1); + } + lemon_strcpy(*paz, z); + for(z=*paz; *z && *z!='='; z++){} + *z = 0; +} + +static char *user_templatename = NULL; +static void handle_T_option(char *z){ + user_templatename = (char *) malloc( lemonStrlen(z)+1 ); + if( user_templatename==0 ){ + memory_error(); + } + lemon_strcpy(user_templatename, z); +} + +/* The main program. Parse the command line and do it... */ +int main(int argc, char **argv) +{ + static int version = 0; + static int rpflag = 0; + static int basisflag = 0; + static int compress = 0; + static int quiet = 0; + static int statistics = 0; + static int mhflag = 0; + static int nolinenosflag = 0; + static int noResort = 0; + static struct s_options options[] = { + {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, + {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, + {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, + {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, + {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, + {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, + {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, + {OPT_FLAG, "p", (char*)&showPrecedenceConflict, + "Show conflicts resolved by precedence rules"}, + {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, + {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"}, + {OPT_FLAG, "s", (char*)&statistics, + "Print parser stats to standard output."}, + {OPT_FLAG, "x", (char*)&version, "Print the version number."}, + {OPT_FLAG,0,0,0} + }; + int i; + int exitcode; + struct lemon lem; + + OptInit(argv,options,stderr); + if( version ){ + printf("Lemon version 1.0\n"); + exit(0); + } + if( OptNArgs()!=1 ){ + fprintf(stderr,"Exactly one filename argument is required.\n"); + exit(1); + } + memset(&lem, 0, sizeof(lem)); + lem.errorcnt = 0; + + /* Initialize the machine */ + Strsafe_init(); + Symbol_init(); + State_init(); + lem.argv0 = argv[0]; + lem.filename = OptArg(0); + lem.basisflag = basisflag; + lem.nolinenosflag = nolinenosflag; + Symbol_new("$"); + lem.errsym = Symbol_new("error"); + lem.errsym->useCnt = 0; + + /* Parse the input file */ + Parse(&lem); + if( lem.errorcnt ) exit(lem.errorcnt); + if( lem.nrule==0 ){ + fprintf(stderr,"Empty grammar.\n"); + exit(1); + } + + /* Count and index the symbols of the grammar */ + Symbol_new("{default}"); + lem.nsymbol = Symbol_count(); + lem.symbols = Symbol_arrayof(); + for(i=0; iindex = i; + qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*), Symbolcmpp); + for(i=0; iindex = i; + while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; } + assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 ); + lem.nsymbol = i - 1; + for(i=1; isupper(lem.symbols[i]->name[0]); i++); + lem.nterminal = i; + + /* Generate a reprint of the grammar, if requested on the command line */ + if( rpflag ){ + Reprint(&lem); + }else{ + /* Initialize the size for all follow and first sets */ + SetSize(lem.nterminal+1); + + /* Find the precedence for every production rule (that has one) */ + FindRulePrecedences(&lem); + + /* Compute the lambda-nonterminals and the first-sets for every + ** nonterminal */ + FindFirstSets(&lem); + + /* Compute all LR(0) states. Also record follow-set propagation + ** links so that the follow-set can be computed later */ + lem.nstate = 0; + FindStates(&lem); + lem.sorted = State_arrayof(); + + /* Tie up loose ends on the propagation links */ + FindLinks(&lem); + + /* Compute the follow set of every reducible configuration */ + FindFollowSets(&lem); + + /* Compute the action tables */ + FindActions(&lem); + + /* Compress the action tables */ + if( compress==0 ) CompressTables(&lem); + + /* Reorder and renumber the states so that states with fewer choices + ** occur at the end. This is an optimization that helps make the + ** generated parser tables smaller. */ + if( noResort==0 ) ResortStates(&lem); + + /* Generate a report of the parser generated. (the "y.output" file) */ + if( !quiet ) ReportOutput(&lem); + + /* Generate the source code for the parser */ + ReportTable(&lem, mhflag); + + /* Produce a header file for use by the scanner. (This step is + ** omitted if the "-m" option is used because makeheaders will + ** generate the file for us.) */ + if( !mhflag ) ReportHeader(&lem); + } + if( statistics ){ + printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", + lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); + printf(" %d states, %d parser table entries, %d conflicts\n", + lem.nstate, lem.tablesize, lem.nconflict); + } + if( lem.nconflict > 0 ){ + fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); + } + + /* return 0 on success, 1 on failure. */ + exitcode = ((lem.errorcnt > 0) || (lem.nconflict > 0)) ? 1 : 0; + exit(exitcode); + return (exitcode); +} +/******************** From the file "msort.c" *******************************/ +/* +** A generic merge-sort program. +** +** USAGE: +** Let "ptr" be a pointer to some structure which is at the head of +** a null-terminated list. Then to sort the list call: +** +** ptr = msort(ptr,&(ptr->next),cmpfnc); +** +** In the above, "cmpfnc" is a pointer to a function which compares +** two instances of the structure and returns an integer, as in +** strcmp. The second argument is a pointer to the pointer to the +** second element of the linked list. This address is used to compute +** the offset to the "next" field within the structure. The offset to +** the "next" field must be constant for all structures in the list. +** +** The function returns a new pointer which is the head of the list +** after sorting. +** +** ALGORITHM: +** Merge-sort. +*/ + +/* +** Return a pointer to the next structure in the linked list. +*/ +#define NEXT(A) (*(char**)(((char*)A)+offset)) + +/* +** Inputs: +** a: A sorted, null-terminated linked list. (May be null). +** b: A sorted, null-terminated linked list. (May be null). +** cmp: A pointer to the comparison function. +** offset: Offset in the structure to the "next" field. +** +** Return Value: +** A pointer to the head of a sorted list containing the elements +** of both a and b. +** +** Side effects: +** The "next" pointers for elements in the lists a and b are +** changed. +*/ +static char *merge( + char *a, + char *b, + int (*cmp)(const char*,const char*), + int offset +){ + char *ptr, *head; + + if( a==0 ){ + head = b; + }else if( b==0 ){ + head = a; + }else{ + if( (*cmp)(a,b)<=0 ){ + ptr = a; + a = NEXT(a); + }else{ + ptr = b; + b = NEXT(b); + } + head = ptr; + while( a && b ){ + if( (*cmp)(a,b)<=0 ){ + NEXT(ptr) = a; + ptr = a; + a = NEXT(a); + }else{ + NEXT(ptr) = b; + ptr = b; + b = NEXT(b); + } + } + if( a ) NEXT(ptr) = a; + else NEXT(ptr) = b; + } + return head; +} + +/* +** Inputs: +** list: Pointer to a singly-linked list of structures. +** next: Pointer to pointer to the second element of the list. +** cmp: A comparison function. +** +** Return Value: +** A pointer to the head of a sorted list containing the elements +** orginally in list. +** +** Side effects: +** The "next" pointers for elements in list are changed. +*/ +#define LISTSIZE 30 +static char *msort( + char *list, + char **next, + int (*cmp)(const char*,const char*) +){ + unsigned long offset; + char *ep; + char *set[LISTSIZE]; + int i; + offset = (unsigned long)next - (unsigned long)list; + for(i=0; istate = WAITING_FOR_DECL_KEYWORD; + }else if( islower(x[0]) ){ + psp->lhs = Symbol_new(x); + psp->nrhs = 0; + psp->lhsalias = 0; + psp->state = WAITING_FOR_ARROW; + }else if( x[0]=='{' ){ + if( psp->prevrule==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"There is no prior rule upon which to attach the code \ +fragment which begins on this line."); + psp->errorcnt++; + }else if( psp->prevrule->code!=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"Code fragment beginning on this line is not the first \ +to follow the previous rule."); + psp->errorcnt++; + }else{ + psp->prevrule->line = psp->tokenlineno; + psp->prevrule->code = &x[1]; + } + }else if( x[0]=='[' ){ + psp->state = PRECEDENCE_MARK_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Token \"%s\" should be either \"%%\" or a nonterminal name.", + x); + psp->errorcnt++; + } + break; + case PRECEDENCE_MARK_1: + if( !isupper(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "The precedence symbol must be a terminal."); + psp->errorcnt++; + }else if( psp->prevrule==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "There is no prior rule to assign precedence \"[%s]\".",x); + psp->errorcnt++; + }else if( psp->prevrule->precsym!=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"Precedence mark on this line is not the first \ +to follow the previous rule."); + psp->errorcnt++; + }else{ + psp->prevrule->precsym = Symbol_new(x); + } + psp->state = PRECEDENCE_MARK_2; + break; + case PRECEDENCE_MARK_2: + if( x[0]!=']' ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \"]\" on precedence mark."); + psp->errorcnt++; + } + psp->state = WAITING_FOR_DECL_OR_RULE; + break; + case WAITING_FOR_ARROW: + if( x[0]==':' && x[1]==':' && x[2]=='=' ){ + psp->state = IN_RHS; + }else if( x[0]=='(' ){ + psp->state = LHS_ALIAS_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Expected to see a \":\" following the LHS symbol \"%s\".", + psp->lhs->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_1: + if( isalpha(x[0]) ){ + psp->lhsalias = x; + psp->state = LHS_ALIAS_2; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "\"%s\" is not a valid alias for the LHS \"%s\"\n", + x,psp->lhs->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_2: + if( x[0]==')' ){ + psp->state = LHS_ALIAS_3; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_3: + if( x[0]==':' && x[1]==':' && x[2]=='=' ){ + psp->state = IN_RHS; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \"->\" following: \"%s(%s)\".", + psp->lhs->name,psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case IN_RHS: + if( x[0]=='.' ){ + struct rule *rp; + rp = (struct rule *)calloc( sizeof(struct rule) + + sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1); + if( rp==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Can't allocate enough memory for this rule."); + psp->errorcnt++; + psp->prevrule = 0; + }else{ + int i; + rp->ruleline = psp->tokenlineno; + rp->rhs = (struct symbol**)&rp[1]; + rp->rhsalias = (const char**)&(rp->rhs[psp->nrhs]); + for(i=0; inrhs; i++){ + rp->rhs[i] = psp->rhs[i]; + rp->rhsalias[i] = psp->alias[i]; + } + rp->lhs = psp->lhs; + rp->lhsalias = psp->lhsalias; + rp->nrhs = psp->nrhs; + rp->code = 0; + rp->precsym = 0; + rp->index = psp->gp->nrule++; + rp->nextlhs = rp->lhs->rule; + rp->lhs->rule = rp; + rp->next = 0; + if( psp->firstrule==0 ){ + psp->firstrule = psp->lastrule = rp; + }else{ + psp->lastrule->next = rp; + psp->lastrule = rp; + } + psp->prevrule = rp; + } + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( isalpha(x[0]) ){ + if( psp->nrhs>=MAXRHS ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Too many symbols on RHS of rule beginning at \"%s\".", + x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + }else{ + psp->rhs[psp->nrhs] = Symbol_new(x); + psp->alias[psp->nrhs] = 0; + psp->nrhs++; + } + }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){ + struct symbol *msp = psp->rhs[psp->nrhs-1]; + if( msp->type!=MULTITERMINAL ){ + struct symbol *origsp = msp; + msp = (struct symbol *) calloc(1,sizeof(*msp)); + memset(msp, 0, sizeof(*msp)); + msp->type = MULTITERMINAL; + msp->nsubsym = 1; + msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*)); + msp->subsym[0] = origsp; + msp->name = origsp->name; + psp->rhs[psp->nrhs-1] = msp; + } + msp->nsubsym++; + msp->subsym = (struct symbol **) realloc(msp->subsym, + sizeof(struct symbol*)*msp->nsubsym); + msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]); + if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Cannot form a compound containing a non-terminal"); + psp->errorcnt++; + } + }else if( x[0]=='(' && psp->nrhs>0 ){ + psp->state = RHS_ALIAS_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal character on RHS of rule: \"%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case RHS_ALIAS_1: + if( isalpha(x[0]) ){ + psp->alias[psp->nrhs-1] = x; + psp->state = RHS_ALIAS_2; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n", + x,psp->rhs[psp->nrhs-1]->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case RHS_ALIAS_2: + if( x[0]==')' ){ + psp->state = IN_RHS; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case WAITING_FOR_DECL_KEYWORD: + if( isalpha(x[0]) ){ + psp->declkeyword = x; + psp->declargslot = 0; + psp->decllinenoslot = 0; + psp->insertLineMacro = 1; + psp->state = WAITING_FOR_DECL_ARG; + if( strcmp(x,"name")==0 ){ + psp->declargslot = &(psp->gp->name); + psp->insertLineMacro = 0; + }else if( strcmp(x,"include")==0 ){ + psp->declargslot = &(psp->gp->include); + }else if( strcmp(x,"code")==0 ){ + psp->declargslot = &(psp->gp->extracode); + }else if( strcmp(x,"token_destructor")==0 ){ + psp->declargslot = &psp->gp->tokendest; + }else if( strcmp(x,"default_destructor")==0 ){ + psp->declargslot = &psp->gp->vardest; + }else if( strcmp(x,"token_prefix")==0 ){ + psp->declargslot = &psp->gp->tokenprefix; + psp->insertLineMacro = 0; + }else if( strcmp(x,"syntax_error")==0 ){ + psp->declargslot = &(psp->gp->error); + }else if( strcmp(x,"parse_accept")==0 ){ + psp->declargslot = &(psp->gp->accept); + }else if( strcmp(x,"parse_failure")==0 ){ + psp->declargslot = &(psp->gp->failure); + }else if( strcmp(x,"stack_overflow")==0 ){ + psp->declargslot = &(psp->gp->overflow); + }else if( strcmp(x,"extra_argument")==0 ){ + psp->declargslot = &(psp->gp->arg); + psp->insertLineMacro = 0; + }else if( strcmp(x,"token_type")==0 ){ + psp->declargslot = &(psp->gp->tokentype); + psp->insertLineMacro = 0; + }else if( strcmp(x,"default_type")==0 ){ + psp->declargslot = &(psp->gp->vartype); + psp->insertLineMacro = 0; + }else if( strcmp(x,"stack_size")==0 ){ + psp->declargslot = &(psp->gp->stacksize); + psp->insertLineMacro = 0; + }else if( strcmp(x,"start_symbol")==0 ){ + psp->declargslot = &(psp->gp->start); + psp->insertLineMacro = 0; + }else if( strcmp(x,"left")==0 ){ + psp->preccounter++; + psp->declassoc = LEFT; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"right")==0 ){ + psp->preccounter++; + psp->declassoc = RIGHT; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"nonassoc")==0 ){ + psp->preccounter++; + psp->declassoc = NONE; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"destructor")==0 ){ + psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL; + }else if( strcmp(x,"type")==0 ){ + psp->state = WAITING_FOR_DATATYPE_SYMBOL; + }else if( strcmp(x,"fallback")==0 ){ + psp->fallback = 0; + psp->state = WAITING_FOR_FALLBACK_ID; + }else if( strcmp(x,"wildcard")==0 ){ + psp->state = WAITING_FOR_WILDCARD_ID; + }else if( strcmp(x,"token_class")==0 ){ + psp->state = WAITING_FOR_CLASS_ID; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Unknown declaration keyword: \"%%%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal declaration keyword: \"%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + break; + case WAITING_FOR_DESTRUCTOR_SYMBOL: + if( !isalpha(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol name missing after %%destructor keyword"); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + struct symbol *sp = Symbol_new(x); + psp->declargslot = &sp->destructor; + psp->decllinenoslot = &sp->destLineno; + psp->insertLineMacro = 1; + psp->state = WAITING_FOR_DECL_ARG; + } + break; + case WAITING_FOR_DATATYPE_SYMBOL: + if( !isalpha(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol name missing after %%type keyword"); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + struct symbol *sp = Symbol_find(x); + if((sp) && (sp->datatype)){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol %%type \"%s\" already defined", x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + if (!sp){ + sp = Symbol_new(x); + } + psp->declargslot = &sp->datatype; + psp->insertLineMacro = 0; + psp->state = WAITING_FOR_DECL_ARG; + } + } + break; + case WAITING_FOR_PRECEDENCE_SYMBOL: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( isupper(x[0]) ){ + struct symbol *sp; + sp = Symbol_new(x); + if( sp->prec>=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol \"%s\" has already be given a precedence.",x); + psp->errorcnt++; + }else{ + sp->prec = psp->preccounter; + sp->assoc = psp->declassoc; + } + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Can't assign a precedence to \"%s\".",x); + psp->errorcnt++; + } + break; + case WAITING_FOR_DECL_ARG: + if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ + const char *zOld, *zNew; + char *zBuf, *z; + int nOld, n, nLine, nNew, nBack; + int addLineMacro; + char zLine[50]; + zNew = x; + if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; + nNew = lemonStrlen(zNew); + if( *psp->declargslot ){ + zOld = *psp->declargslot; + }else{ + zOld = ""; + } + nOld = lemonStrlen(zOld); + n = nOld + nNew + 20; + addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && + (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); + if( addLineMacro ){ + for(z=psp->filename, nBack=0; *z; z++){ + if( *z=='\\' ) nBack++; + } + lemon_sprintf(zLine, "#line %d ", psp->tokenlineno); + nLine = lemonStrlen(zLine); + n += nLine + lemonStrlen(psp->filename) + nBack; + } + *psp->declargslot = (char *) realloc(*psp->declargslot, n); + zBuf = *psp->declargslot + nOld; + if( addLineMacro ){ + if( nOld && zBuf[-1]!='\n' ){ + *(zBuf++) = '\n'; + } + memcpy(zBuf, zLine, nLine); + zBuf += nLine; + *(zBuf++) = '"'; + for(z=psp->filename; *z; z++){ + if( *z=='\\' ){ + *(zBuf++) = '\\'; + } + *(zBuf++) = *z; + } + *(zBuf++) = '"'; + *(zBuf++) = '\n'; + } + if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ + psp->decllinenoslot[0] = psp->tokenlineno; + } + memcpy(zBuf, zNew, nNew); + zBuf += nNew; + *zBuf = 0; + psp->state = WAITING_FOR_DECL_OR_RULE; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal argument to %%%s: %s",psp->declkeyword,x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + break; + case WAITING_FOR_FALLBACK_ID: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( !isupper(x[0]) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%fallback argument \"%s\" should be a token", x); + psp->errorcnt++; + }else{ + struct symbol *sp = Symbol_new(x); + if( psp->fallback==0 ){ + psp->fallback = sp; + }else if( sp->fallback ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "More than one fallback assigned to token %s", x); + psp->errorcnt++; + }else{ + sp->fallback = psp->fallback; + psp->gp->has_fallback = 1; + } + } + break; + case WAITING_FOR_WILDCARD_ID: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( !isupper(x[0]) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%wildcard argument \"%s\" should be a token", x); + psp->errorcnt++; + }else{ + struct symbol *sp = Symbol_new(x); + if( psp->gp->wildcard==0 ){ + psp->gp->wildcard = sp; + }else{ + ErrorMsg(psp->filename, psp->tokenlineno, + "Extra wildcard to token: %s", x); + psp->errorcnt++; + } + } + break; + case WAITING_FOR_CLASS_ID: + if( !islower(x[0]) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%token_class must be followed by an identifier: ", x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else if( Symbol_find(x) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "Symbol \"%s\" already used", x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + psp->tkclass = Symbol_new(x); + psp->tkclass->type = MULTITERMINAL; + psp->state = WAITING_FOR_CLASS_TOKEN; + } + break; + case WAITING_FOR_CLASS_TOKEN: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( isupper(x[0]) || ((x[0]=='|' || x[0]=='/') && isupper(x[1])) ){ + struct symbol *msp = psp->tkclass; + msp->nsubsym++; + msp->subsym = (struct symbol **) realloc(msp->subsym, + sizeof(struct symbol*)*msp->nsubsym); + if( !isupper(x[0]) ) x++; + msp->subsym[msp->nsubsym-1] = Symbol_new(x); + }else{ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%token_class argument \"%s\" should be a token", x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + break; + case RESYNC_AFTER_RULE_ERROR: +/* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; +** break; */ + case RESYNC_AFTER_DECL_ERROR: + if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; + if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD; + break; + } +} + +/* Run the preprocessor over the input file text. The global variables +** azDefine[0] through azDefine[nDefine-1] contains the names of all defined +** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and +** comments them out. Text in between is also commented out as appropriate. +*/ +static void preprocess_input(char *z){ + int i, j, k, n; + int exclude = 0; + int start = 0; + int lineno = 1; + int start_lineno = 1; + for(i=0; z[i]; i++){ + if( z[i]=='\n' ) lineno++; + if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue; + if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){ + if( exclude ){ + exclude--; + if( exclude==0 ){ + for(j=start; jfilename; + ps.errorcnt = 0; + ps.state = INITIALIZE; + + /* Begin by reading the input file */ + fp = fopen(ps.filename,"rb"); + if( fp==0 ){ + ErrorMsg(ps.filename,0,"Can't open this file for reading."); + gp->errorcnt++; + return; + } + fseek(fp,0,2); + filesize = ftell(fp); + rewind(fp); + filebuf = (char *)malloc( filesize+1 ); + if( filesize>100000000 || filebuf==0 ){ + ErrorMsg(ps.filename,0,"Input file too large."); + gp->errorcnt++; + fclose(fp); + return; + } + if( fread(filebuf,1,filesize,fp)!=filesize ){ + ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", + filesize); + free(filebuf); + gp->errorcnt++; + fclose(fp); + return; + } + fclose(fp); + filebuf[filesize] = 0; + + /* Make an initial pass through the file to handle %ifdef and %ifndef */ + preprocess_input(filebuf); + + /* Now scan the text of the input file */ + lineno = 1; + for(cp=filebuf; (c= *cp)!=0; ){ + if( c=='\n' ) lineno++; /* Keep track of the line number */ + if( isspace(c) ){ cp++; continue; } /* Skip all white space */ + if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ + cp+=2; + while( (c= *cp)!=0 && c!='\n' ) cp++; + continue; + } + if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */ + cp+=2; + while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){ + if( c=='\n' ) lineno++; + cp++; + } + if( c ) cp++; + continue; + } + ps.tokenstart = cp; /* Mark the beginning of the token */ + ps.tokenlineno = lineno; /* Linenumber on which token begins */ + if( c=='\"' ){ /* String literals */ + cp++; + while( (c= *cp)!=0 && c!='\"' ){ + if( c=='\n' ) lineno++; + cp++; + } + if( c==0 ){ + ErrorMsg(ps.filename,startline, +"String starting on this line is not terminated before the end of the file."); + ps.errorcnt++; + nextcp = cp; + }else{ + nextcp = cp+1; + } + }else if( c=='{' ){ /* A block of C code */ + int level; + cp++; + for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){ + if( c=='\n' ) lineno++; + else if( c=='{' ) level++; + else if( c=='}' ) level--; + else if( c=='/' && cp[1]=='*' ){ /* Skip comments */ + int prevc; + cp = &cp[2]; + prevc = 0; + while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){ + if( c=='\n' ) lineno++; + prevc = c; + cp++; + } + }else if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments too */ + cp = &cp[2]; + while( (c= *cp)!=0 && c!='\n' ) cp++; + if( c ) lineno++; + }else if( c=='\'' || c=='\"' ){ /* String a character literals */ + int startchar, prevc; + startchar = c; + prevc = 0; + for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){ + if( c=='\n' ) lineno++; + if( prevc=='\\' ) prevc = 0; + else prevc = c; + } + } + } + if( c==0 ){ + ErrorMsg(ps.filename,ps.tokenlineno, +"C code starting on this line is not terminated before the end of the file."); + ps.errorcnt++; + nextcp = cp; + }else{ + nextcp = cp+1; + } + }else if( isalnum(c) ){ /* Identifiers */ + while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++; + nextcp = cp; + }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */ + cp += 3; + nextcp = cp; + }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){ + cp += 2; + while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++; + nextcp = cp; + }else{ /* All other (one character) operators */ + cp++; + nextcp = cp; + } + c = *cp; + *cp = 0; /* Null terminate the token */ + parseonetoken(&ps); /* Parse the token */ + *cp = c; /* Restore the buffer */ + cp = nextcp; + } + free(filebuf); /* Release the buffer after parsing */ + gp->rule = ps.firstrule; + gp->errorcnt = ps.errorcnt; +} +/*************************** From the file "plink.c" *********************/ +/* +** Routines processing configuration follow-set propagation links +** in the LEMON parser generator. +*/ +static struct plink *plink_freelist = 0; + +/* Allocate a new plink */ +struct plink *Plink_new(){ + struct plink *newlink; + + if( plink_freelist==0 ){ + int i; + int amt = 100; + plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) ); + if( plink_freelist==0 ){ + fprintf(stderr, + "Unable to allocate memory for a new follow-set propagation link.\n"); + exit(1); + } + for(i=0; inext; + return newlink; +} + +/* Add a plink to a plink list */ +void Plink_add(struct plink **plpp, struct config *cfp) +{ + struct plink *newlink; + newlink = Plink_new(); + newlink->next = *plpp; + *plpp = newlink; + newlink->cfp = cfp; +} + +/* Transfer every plink on the list "from" to the list "to" */ +void Plink_copy(struct plink **to, struct plink *from) +{ + struct plink *nextpl; + while( from ){ + nextpl = from->next; + from->next = *to; + *to = from; + from = nextpl; + } +} + +/* Delete every plink on the list */ +void Plink_delete(struct plink *plp) +{ + struct plink *nextpl; + + while( plp ){ + nextpl = plp->next; + plp->next = plink_freelist; + plink_freelist = plp; + plp = nextpl; + } +} +/*********************** From the file "report.c" **************************/ +/* +** Procedures for generating reports and tables in the LEMON parser generator. +*/ + +/* Generate a filename with the given suffix. Space to hold the +** name comes from malloc() and must be freed by the calling +** function. +*/ +PRIVATE char *file_makename(struct lemon *lemp, const char *suffix) +{ + char *name; + char *cp; + + name = (char*)malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 ); + if( name==0 ){ + fprintf(stderr,"Can't allocate space for a filename.\n"); + exit(1); + } + lemon_strcpy(name,lemp->filename); + cp = strrchr(name,'.'); + if( cp ) *cp = 0; + lemon_strcat(name,suffix); + return name; +} + +/* Open a file with a name based on the name of the input file, +** but with a different (specified) suffix, and return a pointer +** to the stream */ +PRIVATE FILE *file_open( + struct lemon *lemp, + const char *suffix, + const char *mode +){ + FILE *fp; + + if( lemp->outname ) free(lemp->outname); + lemp->outname = file_makename(lemp, suffix); + fp = fopen(lemp->outname,mode); + if( fp==0 && *mode=='w' ){ + fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname); + lemp->errorcnt++; + return 0; + } + return fp; +} + +/* Duplicate the input file without comments and without actions +** on rules */ +void Reprint(struct lemon *lemp) +{ + struct rule *rp; + struct symbol *sp; + int i, j, maxlen, len, ncolumns, skip; + printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename); + maxlen = 10; + for(i=0; insymbol; i++){ + sp = lemp->symbols[i]; + len = lemonStrlen(sp->name); + if( len>maxlen ) maxlen = len; + } + ncolumns = 76/(maxlen+5); + if( ncolumns<1 ) ncolumns = 1; + skip = (lemp->nsymbol + ncolumns - 1)/ncolumns; + for(i=0; insymbol; j+=skip){ + sp = lemp->symbols[j]; + assert( sp->index==j ); + printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name); + } + printf("\n"); + } + for(rp=lemp->rule; rp; rp=rp->next){ + printf("%s",rp->lhs->name); + /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */ + printf(" ::="); + for(i=0; inrhs; i++){ + sp = rp->rhs[i]; + if( sp->type==MULTITERMINAL ){ + printf(" %s", sp->subsym[0]->name); + for(j=1; jnsubsym; j++){ + printf("|%s", sp->subsym[j]->name); + } + }else{ + printf(" %s", sp->name); + } + /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */ + } + printf("."); + if( rp->precsym ) printf(" [%s]",rp->precsym->name); + /* if( rp->code ) printf("\n %s",rp->code); */ + printf("\n"); + } +} + +void ConfigPrint(FILE *fp, struct config *cfp) +{ + struct rule *rp; + struct symbol *sp; + int i, j; + rp = cfp->rp; + fprintf(fp,"%s ::=",rp->lhs->name); + for(i=0; i<=rp->nrhs; i++){ + if( i==cfp->dot ) fprintf(fp," *"); + if( i==rp->nrhs ) break; + sp = rp->rhs[i]; + if( sp->type==MULTITERMINAL ){ + fprintf(fp," %s", sp->subsym[0]->name); + for(j=1; jnsubsym; j++){ + fprintf(fp,"|%s",sp->subsym[j]->name); + } + }else{ + fprintf(fp," %s", sp->name); + } + } +} + +/* #define TEST */ +#if 0 +/* Print a set */ +PRIVATE void SetPrint(out,set,lemp) +FILE *out; +char *set; +struct lemon *lemp; +{ + int i; + char *spacer; + spacer = ""; + fprintf(out,"%12s[",""); + for(i=0; interminal; i++){ + if( SetFind(set,i) ){ + fprintf(out,"%s%s",spacer,lemp->symbols[i]->name); + spacer = " "; + } + } + fprintf(out,"]\n"); +} + +/* Print a plink chain */ +PRIVATE void PlinkPrint(out,plp,tag) +FILE *out; +struct plink *plp; +char *tag; +{ + while( plp ){ + fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum); + ConfigPrint(out,plp->cfp); + fprintf(out,"\n"); + plp = plp->next; + } +} +#endif + +/* Print an action to the given file descriptor. Return FALSE if +** nothing was actually printed. +*/ +int PrintAction(struct action *ap, FILE *fp, int indent){ + int result = 1; + switch( ap->type ){ + case SHIFT: + fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); + break; + case REDUCE: + fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index); + break; + case ACCEPT: + fprintf(fp,"%*s accept",indent,ap->sp->name); + break; + case ERROR: + fprintf(fp,"%*s error",indent,ap->sp->name); + break; + case SRCONFLICT: + case RRCONFLICT: + fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", + indent,ap->sp->name,ap->x.rp->index); + break; + case SSCONFLICT: + fprintf(fp,"%*s shift %-3d ** Parsing conflict **", + indent,ap->sp->name,ap->x.stp->statenum); + break; + case SH_RESOLVED: + if( showPrecedenceConflict ){ + fprintf(fp,"%*s shift %-3d -- dropped by precedence", + indent,ap->sp->name,ap->x.stp->statenum); + }else{ + result = 0; + } + break; + case RD_RESOLVED: + if( showPrecedenceConflict ){ + fprintf(fp,"%*s reduce %-3d -- dropped by precedence", + indent,ap->sp->name,ap->x.rp->index); + }else{ + result = 0; + } + break; + case NOT_USED: + result = 0; + break; + } + return result; +} + +/* Generate the "y.output" log file */ +void ReportOutput(struct lemon *lemp) +{ + int i; + struct state *stp; + struct config *cfp; + struct action *ap; + FILE *fp; + + fp = file_open(lemp,".out","wb"); + if( fp==0 ) return; + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + fprintf(fp,"State %d:\n",stp->statenum); + if( lemp->basisflag ) cfp=stp->bp; + else cfp=stp->cfp; + while( cfp ){ + char buf[20]; + if( cfp->dot==cfp->rp->nrhs ){ + lemon_sprintf(buf,"(%d)",cfp->rp->index); + fprintf(fp," %5s ",buf); + }else{ + fprintf(fp," "); + } + ConfigPrint(fp,cfp); + fprintf(fp,"\n"); +#if 0 + SetPrint(fp,cfp->fws,lemp); + PlinkPrint(fp,cfp->fplp,"To "); + PlinkPrint(fp,cfp->bplp,"From"); +#endif + if( lemp->basisflag ) cfp=cfp->bp; + else cfp=cfp->next; + } + fprintf(fp,"\n"); + for(ap=stp->ap; ap; ap=ap->next){ + if( PrintAction(ap,fp,30) ) fprintf(fp,"\n"); + } + fprintf(fp,"\n"); + } + fprintf(fp, "----------------------------------------------------\n"); + fprintf(fp, "Symbols:\n"); + for(i=0; insymbol; i++){ + int j; + struct symbol *sp; + + sp = lemp->symbols[i]; + fprintf(fp, " %3d: %s", i, sp->name); + if( sp->type==NONTERMINAL ){ + fprintf(fp, ":"); + if( sp->lambda ){ + fprintf(fp, " "); + } + for(j=0; jnterminal; j++){ + if( sp->firstset && SetFind(sp->firstset, j) ){ + fprintf(fp, " %s", lemp->symbols[j]->name); + } + } + } + fprintf(fp, "\n"); + } + fclose(fp); + return; +} + +/* Search for the file "name" which is in the same directory as +** the exacutable */ +PRIVATE char *pathsearch(char *argv0, char *name, int modemask) +{ + const char *pathlist; + char *pathbufptr; + char *pathbuf; + char *path,*cp; + char c; + +#ifdef __WIN32__ + cp = strrchr(argv0,'\\'); +#else + cp = strrchr(argv0,'/'); +#endif + if( cp ){ + c = *cp; + *cp = 0; + path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); + if( path ) lemon_sprintf(path,"%s/%s",argv0,name); + *cp = c; + }else{ + pathlist = getenv("PATH"); + if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; + pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 ); + path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); + if( (pathbuf != 0) && (path!=0) ){ + pathbufptr = pathbuf; + lemon_strcpy(pathbuf, pathlist); + while( *pathbuf ){ + cp = strchr(pathbuf,':'); + if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)]; + c = *cp; + *cp = 0; + lemon_sprintf(path,"%s/%s",pathbuf,name); + *cp = c; + if( c==0 ) pathbuf[0] = 0; + else pathbuf = &cp[1]; + if( access(path,modemask)==0 ) break; + } + free(pathbufptr); + } + } + return path; +} + +/* Given an action, compute the integer value for that action +** which is to be put in the action table of the generated machine. +** Return negative if no action should be generated. +*/ +PRIVATE int compute_action(struct lemon *lemp, struct action *ap) +{ + int act; + switch( ap->type ){ + case SHIFT: act = ap->x.stp->statenum; break; + case REDUCE: act = ap->x.rp->index + lemp->nstate; break; + case ERROR: act = lemp->nstate + lemp->nrule; break; + case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break; + default: act = -1; break; + } + return act; +} + +#define LINESIZE 1000 +/* The next cluster of routines are for reading the template file +** and writing the results to the generated parser */ +/* The first function transfers data from "in" to "out" until +** a line is seen which begins with "%%". The line number is +** tracked. +** +** if name!=0, then any word that begin with "Parse" is changed to +** begin with *name instead. +*/ +PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno) +{ + int i, iStart; + char line[LINESIZE]; + while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){ + (*lineno)++; + iStart = 0; + if( name ){ + for(i=0; line[i]; i++){ + if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0 + && (i==0 || !isalpha(line[i-1])) + ){ + if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]); + fprintf(out,"%s",name); + i += 4; + iStart = i+1; + } + } + } + fprintf(out,"%s",&line[iStart]); + } +} + +/* The next function finds the template file and opens it, returning +** a pointer to the opened file. */ +PRIVATE FILE *tplt_open(struct lemon *lemp) +{ + static char templatename[] = "lempar.c"; + char buf[1000]; + FILE *in; + char *tpltname; + char *cp; + + /* first, see if user specified a template filename on the command line. */ + if (user_templatename != 0) { + if( access(user_templatename,004)==-1 ){ + fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", + user_templatename); + lemp->errorcnt++; + return 0; + } + in = fopen(user_templatename,"rb"); + if( in==0 ){ + fprintf(stderr,"Can't open the template file \"%s\".\n",user_templatename); + lemp->errorcnt++; + return 0; + } + return in; + } + + cp = strrchr(lemp->filename,'.'); + if( cp ){ + lemon_sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename); + }else{ + lemon_sprintf(buf,"%s.lt",lemp->filename); + } + if( access(buf,004)==0 ){ + tpltname = buf; + }else if( access(templatename,004)==0 ){ + tpltname = templatename; + }else{ + tpltname = pathsearch(lemp->argv0,templatename,0); + } + if( tpltname==0 ){ + fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", + templatename); + lemp->errorcnt++; + return 0; + } + in = fopen(tpltname,"rb"); + if( in==0 ){ + fprintf(stderr,"Can't open the template file \"%s\".\n",templatename); + lemp->errorcnt++; + return 0; + } + return in; +} + +/* Print a #line directive line to the output file. */ +PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename) +{ + fprintf(out,"#line %d \"",lineno); + while( *filename ){ + if( *filename == '\\' ) putc('\\',out); + putc(*filename,out); + filename++; + } + fprintf(out,"\"\n"); +} + +/* Print a string to the file and keep the linenumber up to date */ +PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno) +{ + if( str==0 ) return; + while( *str ){ + putc(*str,out); + if( *str=='\n' ) (*lineno)++; + str++; + } + if( str[-1]!='\n' ){ + putc('\n',out); + (*lineno)++; + } + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + return; +} + +/* +** The following routine emits code for the destructor for the +** symbol sp +*/ +void emit_destructor_code( + FILE *out, + struct symbol *sp, + struct lemon *lemp, + int *lineno +){ + char *cp = 0; + + if( sp->type==TERMINAL ){ + cp = lemp->tokendest; + if( cp==0 ) return; + fprintf(out,"{\n"); (*lineno)++; + }else if( sp->destructor ){ + cp = sp->destructor; + fprintf(out,"{\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,sp->destLineno,lemp->filename); } + }else if( lemp->vardest ){ + cp = lemp->vardest; + if( cp==0 ) return; + fprintf(out,"{\n"); (*lineno)++; + }else{ + assert( 0 ); /* Cannot happen */ + } + for(; *cp; cp++){ + if( *cp=='$' && cp[1]=='$' ){ + fprintf(out,"(yypminor->yy%d)",sp->dtnum); + cp++; + continue; + } + if( *cp=='\n' ) (*lineno)++; + fputc(*cp,out); + } + fprintf(out,"\n"); (*lineno)++; + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + fprintf(out,"}\n"); (*lineno)++; + return; +} + +/* +** Return TRUE (non-zero) if the given symbol has a destructor. +*/ +int has_destructor(struct symbol *sp, struct lemon *lemp) +{ + int ret; + if( sp->type==TERMINAL ){ + ret = lemp->tokendest!=0; + }else{ + ret = lemp->vardest!=0 || sp->destructor!=0; + } + return ret; +} + +/* +** Append text to a dynamically allocated string. If zText is 0 then +** reset the string to be empty again. Always return the complete text +** of the string (which is overwritten with each call). +** +** n bytes of zText are stored. If n==0 then all of zText up to the first +** \000 terminator is stored. zText can contain up to two instances of +** %d. The values of p1 and p2 are written into the first and second +** %d. +** +** If n==-1, then the previous character is overwritten. +*/ +PRIVATE char *append_str(const char *zText, int n, int p1, int p2){ + static char empty[1] = { 0 }; + static char *z = 0; + static int alloced = 0; + static int used = 0; + int c; + char zInt[40]; + if( zText==0 ){ + used = 0; + return z; + } + if( n<=0 ){ + if( n<0 ){ + used += n; + assert( used>=0 ); + } + n = lemonStrlen(zText); + } + if( (int) (n+sizeof(zInt)*2+used) >= alloced ){ + alloced = n + sizeof(zInt)*2 + used + 200; + z = (char *) realloc(z, alloced); + } + if( z==0 ) return empty; + while( n-- > 0 ){ + c = *(zText++); + if( c=='%' && n>0 && zText[0]=='d' ){ + lemon_sprintf(zInt, "%d", p1); + p1 = p2; + lemon_strcpy(&z[used], zInt); + used += lemonStrlen(&z[used]); + zText++; + n--; + }else{ + z[used++] = c; + } + } + z[used] = 0; + return z; +} + +/* +** zCode is a string that is the action associated with a rule. Expand +** the symbols in this string so that the refer to elements of the parser +** stack. +*/ +PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ + char *cp, *xp; + int i; + char lhsused = 0; /* True if the LHS element has been used */ + char used[MAXRHS]; /* True for each RHS element which is used */ + + for(i=0; inrhs; i++) used[i] = 0; + lhsused = 0; + + if( rp->code==0 ){ + static char newlinestr[2] = { '\n', '\0' }; + rp->code = newlinestr; + rp->line = rp->ruleline; + } + + append_str(0,0,0,0); + + /* This const cast is wrong but harmless, if we're careful. */ + for(cp=(char *)rp->code; *cp; cp++){ + if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ + char saved; + for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++); + saved = *xp; + *xp = 0; + if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ + append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0); + cp = xp; + lhsused = 1; + }else{ + for(i=0; inrhs; i++){ + if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ + if( cp!=rp->code && cp[-1]=='@' ){ + /* If the argument is of the form @X then substituted + ** the token number of X, not the value of X */ + append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0); + }else{ + struct symbol *sp = rp->rhs[i]; + int dtnum; + if( sp->type==MULTITERMINAL ){ + dtnum = sp->subsym[0]->dtnum; + }else{ + dtnum = sp->dtnum; + } + append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum); + } + cp = xp; + used[i] = 1; + break; + } + } + } + *xp = saved; + } + append_str(cp, 1, 0, 0); + } /* End loop */ + + /* Check to make sure the LHS has been used */ + if( rp->lhsalias && !lhsused ){ + ErrorMsg(lemp->filename,rp->ruleline, + "Label \"%s\" for \"%s(%s)\" is never used.", + rp->lhsalias,rp->lhs->name,rp->lhsalias); + lemp->errorcnt++; + } + + /* Generate destructor code for RHS symbols which are not used in the + ** reduce code */ + for(i=0; inrhs; i++){ + if( rp->rhsalias[i] && !used[i] ){ + ErrorMsg(lemp->filename,rp->ruleline, + "Label %s for \"%s(%s)\" is never used.", + rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); + lemp->errorcnt++; + }else if( rp->rhsalias[i]==0 ){ + if( has_destructor(rp->rhs[i],lemp) ){ + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, + rp->rhs[i]->index,i-rp->nrhs+1); + }else{ + /* No destructor defined for this term */ + } + } + } + if( rp->code ){ + cp = append_str(0,0,0,0); + rp->code = Strsafe(cp?cp:""); + } +} + +/* +** Generate code which executes when the rule "rp" is reduced. Write +** the code to "out". Make sure lineno stays up-to-date. +*/ +PRIVATE void emit_code( + FILE *out, + struct rule *rp, + struct lemon *lemp, + int *lineno +){ + const char *cp; + + /* Generate code to do the reduce action */ + if( rp->code ){ + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,rp->line,lemp->filename); } + fprintf(out,"{%s",rp->code); + for(cp=rp->code; *cp; cp++){ + if( *cp=='\n' ) (*lineno)++; + } /* End loop */ + fprintf(out,"}\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); } + } /* End if( rp->code ) */ + + return; +} + +/* +** Print the definition of the union used for the parser's data stack. +** This union contains fields for every possible data type for tokens +** and nonterminals. In the process of computing and printing this +** union, also set the ".dtnum" field of every terminal and nonterminal +** symbol. +*/ +void print_stack_union( + FILE *out, /* The output stream */ + struct lemon *lemp, /* The main info structure for this parser */ + int *plineno, /* Pointer to the line number */ + int mhflag /* True if generating makeheaders output */ +){ + int lineno = *plineno; /* The line number of the output */ + char **types; /* A hash table of datatypes */ + int arraysize; /* Size of the "types" array */ + int maxdtlength; /* Maximum length of any ".datatype" field. */ + char *stddt; /* Standardized name for a datatype */ + int i,j; /* Loop counters */ + unsigned hash; /* For hashing the name of a type */ + const char *name; /* Name of the parser */ + + /* Allocate and initialize types[] and allocate stddt[] */ + arraysize = lemp->nsymbol * 2; + types = (char**)calloc( arraysize, sizeof(char*) ); + if( types==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + for(i=0; ivartype ){ + maxdtlength = lemonStrlen(lemp->vartype); + } + for(i=0; insymbol; i++){ + int len; + struct symbol *sp = lemp->symbols[i]; + if( sp->datatype==0 ) continue; + len = lemonStrlen(sp->datatype); + if( len>maxdtlength ) maxdtlength = len; + } + stddt = (char*)malloc( maxdtlength*2 + 1 ); + if( stddt==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + + /* Build a hash table of datatypes. The ".dtnum" field of each symbol + ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is + ** used for terminal symbols. If there is no %default_type defined then + ** 0 is also used as the .dtnum value for nonterminals which do not specify + ** a datatype using the %type directive. + */ + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + char *cp; + if( sp==lemp->errsym ){ + sp->dtnum = arraysize+1; + continue; + } + if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){ + sp->dtnum = 0; + continue; + } + cp = sp->datatype; + if( cp==0 ) cp = lemp->vartype; + j = 0; + while( isspace(*cp) ) cp++; + while( *cp ) stddt[j++] = *cp++; + while( j>0 && isspace(stddt[j-1]) ) j--; + stddt[j] = 0; + if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){ + sp->dtnum = 0; + continue; + } + hash = 0; + for(j=0; stddt[j]; j++){ + hash = hash*53 + stddt[j]; + } + hash = (hash & 0x7fffffff)%arraysize; + while( types[hash] ){ + if( strcmp(types[hash],stddt)==0 ){ + sp->dtnum = hash + 1; + break; + } + hash++; + if( hash>=(unsigned)arraysize ) hash = 0; + } + if( types[hash]==0 ){ + sp->dtnum = hash + 1; + types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); + if( types[hash]==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + lemon_strcpy(types[hash],stddt); + } + } + + /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */ + name = lemp->name ? lemp->name : "Parse"; + lineno = *plineno; + if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; } + fprintf(out,"#define %sTOKENTYPE %s\n",name, + lemp->tokentype?lemp->tokentype:"void*"); lineno++; + if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } + fprintf(out,"typedef union {\n"); lineno++; + fprintf(out," int yyinit;\n"); lineno++; + fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; + for(i=0; ierrsym->useCnt ){ + fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++; + } + free(stddt); + free(types); + fprintf(out,"} YYMINORTYPE;\n"); lineno++; + *plineno = lineno; +} + +/* +** Return the name of a C datatype able to represent values between +** lwr and upr, inclusive. +*/ +static const char *minimum_size_type(int lwr, int upr){ + if( lwr>=0 ){ + if( upr<=255 ){ + return "unsigned char"; + }else if( upr<65535 ){ + return "unsigned short int"; + }else{ + return "unsigned int"; + } + }else if( lwr>=-127 && upr<=127 ){ + return "signed char"; + }else if( lwr>=-32767 && upr<32767 ){ + return "short"; + }else{ + return "int"; + } +} + +/* +** Each state contains a set of token transaction and a set of +** nonterminal transactions. Each of these sets makes an instance +** of the following structure. An array of these structures is used +** to order the creation of entries in the yy_action[] table. +*/ +struct axset { + struct state *stp; /* A pointer to a state */ + int isTkn; /* True to use tokens. False for non-terminals */ + int nAction; /* Number of actions */ + int iOrder; /* Original order of action sets */ +}; + +/* +** Compare to axset structures for sorting purposes +*/ +static int axset_compare(const void *a, const void *b){ + struct axset *p1 = (struct axset*)a; + struct axset *p2 = (struct axset*)b; + int c; + c = p2->nAction - p1->nAction; + if( c==0 ){ + c = p2->iOrder - p1->iOrder; + } + assert( c!=0 || p1==p2 ); + return c; +} + +/* +** Write text on "out" that describes the rule "rp". +*/ +static void writeRuleText(FILE *out, struct rule *rp){ + int j; + fprintf(out,"%s ::=", rp->lhs->name); + for(j=0; jnrhs; j++){ + struct symbol *sp = rp->rhs[j]; + if( sp->type!=MULTITERMINAL ){ + fprintf(out," %s", sp->name); + }else{ + int k; + fprintf(out," %s", sp->subsym[0]->name); + for(k=1; knsubsym; k++){ + fprintf(out,"|%s",sp->subsym[k]->name); + } + } + } +} + + +/* Generate C source code for the parser */ +void ReportTable( + struct lemon *lemp, + int mhflag /* Output in makeheaders format if true */ +){ + FILE *out, *in; + char line[LINESIZE]; + int lineno; + struct state *stp; + struct action *ap; + struct rule *rp; + struct acttab *pActtab; + int i, j, n; + const char *name; + int mnTknOfst, mxTknOfst; + int mnNtOfst, mxNtOfst; + struct axset *ax; + + in = tplt_open(lemp); + if( in==0 ) return; + out = file_open(lemp,".c","wb"); + if( out==0 ){ + fclose(in); + return; + } + lineno = 1; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the include code, if any */ + tplt_print(out,lemp,lemp->include,&lineno); + if( mhflag ){ + char *name = file_makename(lemp, ".h"); + fprintf(out,"#include \"%s\"\n", name); lineno++; + free(name); + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate #defines for all tokens */ + if( mhflag ){ + const char *prefix; + fprintf(out,"#if INTERFACE\n"); lineno++; + if( lemp->tokenprefix ) prefix = lemp->tokenprefix; + else prefix = ""; + for(i=1; interminal; i++){ + fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); + lineno++; + } + fprintf(out,"#endif\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the defines */ + fprintf(out,"#define YYCODETYPE %s\n", + minimum_size_type(0, lemp->nsymbol+1)); lineno++; + fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; + fprintf(out,"#define YYACTIONTYPE %s\n", + minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; + if( lemp->wildcard ){ + fprintf(out,"#define YYWILDCARD %d\n", + lemp->wildcard->index); lineno++; + } + print_stack_union(out,lemp,&lineno,mhflag); + fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++; + if( lemp->stacksize ){ + fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++; + }else{ + fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++; + } + fprintf(out, "#endif\n"); lineno++; + if( mhflag ){ + fprintf(out,"#if INTERFACE\n"); lineno++; + } + name = lemp->name ? lemp->name : "Parse"; + if( lemp->arg && lemp->arg[0] ){ + int i; + i = lemonStrlen(lemp->arg); + while( i>=1 && isspace(lemp->arg[i-1]) ) i--; + while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; + fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; + fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++; + fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n", + name,lemp->arg,&lemp->arg[i]); lineno++; + fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n", + name,&lemp->arg[i],&lemp->arg[i]); lineno++; + }else{ + fprintf(out,"#define %sARG_SDECL\n",name); lineno++; + fprintf(out,"#define %sARG_PDECL\n",name); lineno++; + fprintf(out,"#define %sARG_FETCH\n",name); lineno++; + fprintf(out,"#define %sARG_STORE\n",name); lineno++; + } + if( mhflag ){ + fprintf(out,"#endif\n"); lineno++; + } + fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++; + fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; + if( lemp->errsym->useCnt ){ + fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; + fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; + } + if( lemp->has_fallback ){ + fprintf(out,"#define YYFALLBACK 1\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the action table and its associates: + ** + ** yy_action[] A single table containing all actions. + ** yy_lookahead[] A table containing the lookahead for each entry in + ** yy_action. Used to detect hash collisions. + ** yy_shift_ofst[] For each state, the offset into yy_action for + ** shifting terminals. + ** yy_reduce_ofst[] For each state, the offset into yy_action for + ** shifting non-terminals after a reduce. + ** yy_default[] Default action for each state. + */ + + /* Compute the actions on all states and count them up */ + ax = (struct axset *) calloc(lemp->nstate*2, sizeof(ax[0])); + if( ax==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + ax[i*2].stp = stp; + ax[i*2].isTkn = 1; + ax[i*2].nAction = stp->nTknAct; + ax[i*2+1].stp = stp; + ax[i*2+1].isTkn = 0; + ax[i*2+1].nAction = stp->nNtAct; + } + mxTknOfst = mnTknOfst = 0; + mxNtOfst = mnNtOfst = 0; + + /* Compute the action table. In order to try to keep the size of the + ** action table to a minimum, the heuristic of placing the largest action + ** sets first is used. + */ + for(i=0; instate*2; i++) ax[i].iOrder = i; + qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); + pActtab = acttab_alloc(); + for(i=0; instate*2 && ax[i].nAction>0; i++){ + stp = ax[i].stp; + if( ax[i].isTkn ){ + for(ap=stp->ap; ap; ap=ap->next){ + int action; + if( ap->sp->index>=lemp->nterminal ) continue; + action = compute_action(lemp, ap); + if( action<0 ) continue; + acttab_action(pActtab, ap->sp->index, action); + } + stp->iTknOfst = acttab_insert(pActtab); + if( stp->iTknOfstiTknOfst; + if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst; + }else{ + for(ap=stp->ap; ap; ap=ap->next){ + int action; + if( ap->sp->indexnterminal ) continue; + if( ap->sp->index==lemp->nsymbol ) continue; + action = compute_action(lemp, ap); + if( action<0 ) continue; + acttab_action(pActtab, ap->sp->index, action); + } + stp->iNtOfst = acttab_insert(pActtab); + if( stp->iNtOfstiNtOfst; + if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; + } + } + free(ax); + + /* Output the yy_action table */ + n = acttab_size(pActtab); + fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++; + fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; + for(i=j=0; instate + lemp->nrule + 2; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", action); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_lookahead table */ + fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; + for(i=j=0; insymbol; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", la); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_shift_ofst[] table */ + fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; + n = lemp->nstate; + while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; + fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; + fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; + fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; + fprintf(out, "static const %s yy_shift_ofst[] = {\n", + minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; + for(i=j=0; isorted[i]; + ofst = stp->iTknOfst; + if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", ofst); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_reduce_ofst[] table */ + fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; + n = lemp->nstate; + while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; + fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++; + fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; + fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++; + fprintf(out, "static const %s yy_reduce_ofst[] = {\n", + minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; + for(i=j=0; isorted[i]; + ofst = stp->iNtOfst; + if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", ofst); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the default action table */ + fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; + n = lemp->nstate; + for(i=j=0; isorted[i]; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", stp->iDflt); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the table of fallback tokens. + */ + if( lemp->has_fallback ){ + int mx = lemp->nterminal - 1; + while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } + for(i=0; i<=mx; i++){ + struct symbol *p = lemp->symbols[i]; + if( p->fallback==0 ){ + fprintf(out, " 0, /* %10s => nothing */\n", p->name); + }else{ + fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index, + p->name, p->fallback->name); + } + lineno++; + } + } + tplt_xfer(lemp->name, in, out, &lineno); + + /* Generate a table containing the symbolic name of every symbol + */ + for(i=0; insymbol; i++){ + lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name); + fprintf(out," %-15s",line); + if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; } + } + if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate a table containing a text string that describes every + ** rule in the rule set of the grammar. This information is used + ** when tracing REDUCE actions. + */ + for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ + assert( rp->index==i ); + fprintf(out," /* %3d */ \"", i); + writeRuleText(out, rp); + fprintf(out,"\",\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes every time a symbol is popped from + ** the stack while processing errors or while destroying the parser. + ** (In other words, generate the %destructor actions) + */ + if( lemp->tokendest ){ + int once = 1; + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type!=TERMINAL ) continue; + if( once ){ + fprintf(out, " /* TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + } + for(i=0; insymbol && lemp->symbols[i]->type!=TERMINAL; i++); + if( insymbol ){ + emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); + fprintf(out," break;\n"); lineno++; + } + } + if( lemp->vardest ){ + struct symbol *dflt_sp = 0; + int once = 1; + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type==TERMINAL || + sp->index<=0 || sp->destructor!=0 ) continue; + if( once ){ + fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + dflt_sp = sp; + } + if( dflt_sp!=0 ){ + emit_destructor_code(out,dflt_sp,lemp,&lineno); + } + fprintf(out," break;\n"); lineno++; + } + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + + /* Combine duplicate destructors into a single case */ + for(j=i+1; jnsymbol; j++){ + struct symbol *sp2 = lemp->symbols[j]; + if( sp2 && sp2->type!=TERMINAL && sp2->destructor + && sp2->dtnum==sp->dtnum + && strcmp(sp->destructor,sp2->destructor)==0 ){ + fprintf(out," case %d: /* %s */\n", + sp2->index, sp2->name); lineno++; + sp2->destructor = 0; + } + } + + emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); + fprintf(out," break;\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes whenever the parser stack overflows */ + tplt_print(out,lemp,lemp->overflow,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the table of rule information + ** + ** Note: This code depends on the fact that rules are number + ** sequentually beginning with 0. + */ + for(rp=lemp->rule; rp; rp=rp->next){ + fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which execution during each REDUCE action */ + for(rp=lemp->rule; rp; rp=rp->next){ + translate_code(lemp, rp); + } + /* First output rules other than the default: rule */ + for(rp=lemp->rule; rp; rp=rp->next){ + struct rule *rp2; /* Other rules with the same action */ + if( rp->code==0 ) continue; + if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ + fprintf(out," case %d: /* ", rp->index); + writeRuleText(out, rp); + fprintf(out, " */\n"); lineno++; + for(rp2=rp->next; rp2; rp2=rp2->next){ + if( rp2->code==rp->code ){ + fprintf(out," case %d: /* ", rp2->index); + writeRuleText(out, rp2); + fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++; + rp2->code = 0; + } + } + emit_code(out,rp,lemp,&lineno); + fprintf(out," break;\n"); lineno++; + rp->code = 0; + } + /* Finally, output the default: rule. We choose as the default: all + ** empty actions. */ + fprintf(out," default:\n"); lineno++; + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->code==0 ) continue; + assert( rp->code[0]=='\n' && rp->code[1]==0 ); + fprintf(out," /* (%d) ", rp->index); + writeRuleText(out, rp); + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->index); lineno++; + } + fprintf(out," break;\n"); lineno++; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes if a parse fails */ + tplt_print(out,lemp,lemp->failure,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes when a syntax error occurs */ + tplt_print(out,lemp,lemp->error,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes when the parser accepts its input */ + tplt_print(out,lemp,lemp->accept,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Append any addition code the user desires */ + tplt_print(out,lemp,lemp->extracode,&lineno); + + fclose(in); + fclose(out); + return; +} + +/* Generate a header file for the parser */ +void ReportHeader(struct lemon *lemp) +{ + FILE *out, *in; + const char *prefix; + char line[LINESIZE]; + char pattern[LINESIZE]; + int i; + + if( lemp->tokenprefix ) prefix = lemp->tokenprefix; + else prefix = ""; + in = file_open(lemp,".h","rb"); + if( in ){ + int nextChar; + for(i=1; interminal && fgets(line,LINESIZE,in); i++){ + lemon_sprintf(pattern,"#define %s%-30s %3d\n", + prefix,lemp->symbols[i]->name,i); + if( strcmp(line,pattern) ) break; + } + nextChar = fgetc(in); + fclose(in); + if( i==lemp->nterminal && nextChar==EOF ){ + /* No change in the file. Don't rewrite it. */ + return; + } + } + out = file_open(lemp,".h","wb"); + if( out ){ + for(i=1; interminal; i++){ + fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i); + } + fclose(out); + } + return; +} + +/* Reduce the size of the action tables, if possible, by making use +** of defaults. +** +** In this version, we take the most frequent REDUCE action and make +** it the default. Except, there is no default if the wildcard token +** is a possible look-ahead. +*/ +void CompressTables(struct lemon *lemp) +{ + struct state *stp; + struct action *ap, *ap2; + struct rule *rp, *rp2, *rbest; + int nbest, n; + int i; + int usesWildcard; + + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + nbest = 0; + rbest = 0; + usesWildcard = 0; + + for(ap=stp->ap; ap; ap=ap->next){ + if( ap->type==SHIFT && ap->sp==lemp->wildcard ){ + usesWildcard = 1; + } + if( ap->type!=REDUCE ) continue; + rp = ap->x.rp; + if( rp->lhsStart ) continue; + if( rp==rbest ) continue; + n = 1; + for(ap2=ap->next; ap2; ap2=ap2->next){ + if( ap2->type!=REDUCE ) continue; + rp2 = ap2->x.rp; + if( rp2==rbest ) continue; + if( rp2==rp ) n++; + } + if( n>nbest ){ + nbest = n; + rbest = rp; + } + } + + /* Do not make a default if the number of rules to default + ** is not at least 1 or if the wildcard token is a possible + ** lookahead. + */ + if( nbest<1 || usesWildcard ) continue; + + + /* Combine matching REDUCE actions into a single default */ + for(ap=stp->ap; ap; ap=ap->next){ + if( ap->type==REDUCE && ap->x.rp==rbest ) break; + } + assert( ap ); + ap->sp = Symbol_new("{default}"); + for(ap=ap->next; ap; ap=ap->next){ + if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; + } + stp->ap = Action_sort(stp->ap); + } +} + + +/* +** Compare two states for sorting purposes. The smaller state is the +** one with the most non-terminal actions. If they have the same number +** of non-terminal actions, then the smaller is the one with the most +** token actions. +*/ +static int stateResortCompare(const void *a, const void *b){ + const struct state *pA = *(const struct state**)a; + const struct state *pB = *(const struct state**)b; + int n; + + n = pB->nNtAct - pA->nNtAct; + if( n==0 ){ + n = pB->nTknAct - pA->nTknAct; + if( n==0 ){ + n = pB->statenum - pA->statenum; + } + } + assert( n!=0 ); + return n; +} + + +/* +** Renumber and resort states so that states with fewer choices +** occur at the end. Except, keep state 0 as the first state. +*/ +void ResortStates(struct lemon *lemp) +{ + int i; + struct state *stp; + struct action *ap; + + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + stp->nTknAct = stp->nNtAct = 0; + stp->iDflt = lemp->nstate + lemp->nrule; + stp->iTknOfst = NO_OFFSET; + stp->iNtOfst = NO_OFFSET; + for(ap=stp->ap; ap; ap=ap->next){ + if( compute_action(lemp,ap)>=0 ){ + if( ap->sp->indexnterminal ){ + stp->nTknAct++; + }else if( ap->sp->indexnsymbol ){ + stp->nNtAct++; + }else{ + stp->iDflt = compute_action(lemp, ap); + } + } + } + } + qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]), + stateResortCompare); + for(i=0; instate; i++){ + lemp->sorted[i]->statenum = i; + } +} + + +/***************** From the file "set.c" ************************************/ +/* +** Set manipulation routines for the LEMON parser generator. +*/ + +static int size = 0; + +/* Set the set size */ +void SetSize(int n) +{ + size = n+1; +} + +/* Allocate a new set */ +char *SetNew(){ + char *s; + s = (char*)calloc( size, 1); + if( s==0 ){ + extern void memory_error(); + memory_error(); + } + return s; +} + +/* Deallocate a set */ +void SetFree(char *s) +{ + free(s); +} + +/* Add a new element to the set. Return TRUE if the element was added +** and FALSE if it was already there. */ +int SetAdd(char *s, int e) +{ + int rv; + assert( e>=0 && esize = 1024; + x1a->count = 0; + x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*)); + if( x1a->tbl==0 ){ + free(x1a); + x1a = 0; + }else{ + int i; + x1a->ht = (x1node**)&(x1a->tbl[1024]); + for(i=0; i<1024; i++) x1a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Strsafe_insert(const char *data) +{ + x1node *np; + unsigned h; + unsigned ph; + + if( x1a==0 ) return 0; + ph = strhash(data); + h = ph & (x1a->size-1); + np = x1a->ht[h]; + while( np ){ + if( strcmp(np->data,data)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x1a->count>=x1a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x1 array; + array.size = size = x1a->size*2; + array.count = x1a->count; + array.tbl = (x1node*)calloc(size, sizeof(x1node) + sizeof(x1node*)); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x1node**)&(array.tbl[size]); + for(i=0; icount; i++){ + x1node *oldnp, *newnp; + oldnp = &(x1a->tbl[i]); + h = strhash(oldnp->data) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x1a->tbl); + *x1a = array; + } + /* Insert the new data */ + h = ph & (x1a->size-1); + np = &(x1a->tbl[x1a->count++]); + np->data = data; + if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next); + np->next = x1a->ht[h]; + x1a->ht[h] = np; + np->from = &(x1a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +const char *Strsafe_find(const char *key) +{ + unsigned h; + x1node *np; + + if( x1a==0 ) return 0; + h = strhash(key) & (x1a->size-1); + np = x1a->ht[h]; + while( np ){ + if( strcmp(np->data,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return a pointer to the (terminal or nonterminal) symbol "x". +** Create a new symbol if this is the first time "x" has been seen. +*/ +struct symbol *Symbol_new(const char *x) +{ + struct symbol *sp; + + sp = Symbol_find(x); + if( sp==0 ){ + sp = (struct symbol *)calloc(1, sizeof(struct symbol) ); + MemoryCheck(sp); + sp->name = Strsafe(x); + sp->type = isupper(*x) ? TERMINAL : NONTERMINAL; + sp->rule = 0; + sp->fallback = 0; + sp->prec = -1; + sp->assoc = UNK; + sp->firstset = 0; + sp->lambda = LEMON_FALSE; + sp->destructor = 0; + sp->destLineno = 0; + sp->datatype = 0; + sp->useCnt = 0; + Symbol_insert(sp,sp->name); + } + sp->useCnt++; + return sp; +} + +/* Compare two symbols for sorting purposes. Return negative, +** zero, or positive if a is less then, equal to, or greater +** than b. +** +** Symbols that begin with upper case letters (terminals or tokens) +** must sort before symbols that begin with lower case letters +** (non-terminals). And MULTITERMINAL symbols (created using the +** %token_class directive) must sort at the very end. Other than +** that, the order does not matter. +** +** We find experimentally that leaving the symbols in their original +** order (the order they appeared in the grammar file) gives the +** smallest parser tables in SQLite. +*/ +int Symbolcmpp(const void *_a, const void *_b) +{ + const struct symbol *a = *(const struct symbol **) _a; + const struct symbol *b = *(const struct symbol **) _b; + int i1 = a->type==MULTITERMINAL ? 3 : a->name[0]>'Z' ? 2 : 1; + int i2 = b->type==MULTITERMINAL ? 3 : b->name[0]>'Z' ? 2 : 1; + return i1==i2 ? a->index - b->index : i1 - i2; +} + +/* There is one instance of the following structure for each +** associative array of type "x2". +*/ +struct s_x2 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x2node *tbl; /* The data stored here */ + struct s_x2node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x2". +*/ +typedef struct s_x2node { + struct symbol *data; /* The data */ + const char *key; /* The key */ + struct s_x2node *next; /* Next entry with the same hash */ + struct s_x2node **from; /* Previous link */ +} x2node; + +/* There is only one instance of the array, which is the following */ +static struct s_x2 *x2a; + +/* Allocate a new associative array */ +void Symbol_init(){ + if( x2a ) return; + x2a = (struct s_x2*)malloc( sizeof(struct s_x2) ); + if( x2a ){ + x2a->size = 128; + x2a->count = 0; + x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*)); + if( x2a->tbl==0 ){ + free(x2a); + x2a = 0; + }else{ + int i; + x2a->ht = (x2node**)&(x2a->tbl[128]); + for(i=0; i<128; i++) x2a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Symbol_insert(struct symbol *data, const char *key) +{ + x2node *np; + unsigned h; + unsigned ph; + + if( x2a==0 ) return 0; + ph = strhash(key); + h = ph & (x2a->size-1); + np = x2a->ht[h]; + while( np ){ + if( strcmp(np->key,key)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x2a->count>=x2a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x2 array; + array.size = size = x2a->size*2; + array.count = x2a->count; + array.tbl = (x2node*)calloc(size, sizeof(x2node) + sizeof(x2node*)); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x2node**)&(array.tbl[size]); + for(i=0; icount; i++){ + x2node *oldnp, *newnp; + oldnp = &(x2a->tbl[i]); + h = strhash(oldnp->key) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->key = oldnp->key; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x2a->tbl); + *x2a = array; + } + /* Insert the new data */ + h = ph & (x2a->size-1); + np = &(x2a->tbl[x2a->count++]); + np->key = key; + np->data = data; + if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next); + np->next = x2a->ht[h]; + x2a->ht[h] = np; + np->from = &(x2a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct symbol *Symbol_find(const char *key) +{ + unsigned h; + x2node *np; + + if( x2a==0 ) return 0; + h = strhash(key) & (x2a->size-1); + np = x2a->ht[h]; + while( np ){ + if( strcmp(np->key,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return the n-th data. Return NULL if n is out of range. */ +struct symbol *Symbol_Nth(int n) +{ + struct symbol *data; + if( x2a && n>0 && n<=x2a->count ){ + data = x2a->tbl[n-1].data; + }else{ + data = 0; + } + return data; +} + +/* Return the size of the array */ +int Symbol_count() +{ + return x2a ? x2a->count : 0; +} + +/* Return an array of pointers to all data in the table. +** The array is obtained from malloc. Return NULL if memory allocation +** problems, or if the array is empty. */ +struct symbol **Symbol_arrayof() +{ + struct symbol **array; + int i,size; + if( x2a==0 ) return 0; + size = x2a->count; + array = (struct symbol **)calloc(size, sizeof(struct symbol *)); + if( array ){ + for(i=0; itbl[i].data; + } + return array; +} + +/* Compare two configurations */ +int Configcmp(const char *_a,const char *_b) +{ + const struct config *a = (struct config *) _a; + const struct config *b = (struct config *) _b; + int x; + x = a->rp->index - b->rp->index; + if( x==0 ) x = a->dot - b->dot; + return x; +} + +/* Compare two states */ +PRIVATE int statecmp(struct config *a, struct config *b) +{ + int rc; + for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){ + rc = a->rp->index - b->rp->index; + if( rc==0 ) rc = a->dot - b->dot; + } + if( rc==0 ){ + if( a ) rc = 1; + if( b ) rc = -1; + } + return rc; +} + +/* Hash a state */ +PRIVATE unsigned statehash(struct config *a) +{ + unsigned h=0; + while( a ){ + h = h*571 + a->rp->index*37 + a->dot; + a = a->bp; + } + return h; +} + +/* Allocate a new state structure */ +struct state *State_new() +{ + struct state *newstate; + newstate = (struct state *)calloc(1, sizeof(struct state) ); + MemoryCheck(newstate); + return newstate; +} + +/* There is one instance of the following structure for each +** associative array of type "x3". +*/ +struct s_x3 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x3node *tbl; /* The data stored here */ + struct s_x3node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x3". +*/ +typedef struct s_x3node { + struct state *data; /* The data */ + struct config *key; /* The key */ + struct s_x3node *next; /* Next entry with the same hash */ + struct s_x3node **from; /* Previous link */ +} x3node; + +/* There is only one instance of the array, which is the following */ +static struct s_x3 *x3a; + +/* Allocate a new associative array */ +void State_init(){ + if( x3a ) return; + x3a = (struct s_x3*)malloc( sizeof(struct s_x3) ); + if( x3a ){ + x3a->size = 128; + x3a->count = 0; + x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*)); + if( x3a->tbl==0 ){ + free(x3a); + x3a = 0; + }else{ + int i; + x3a->ht = (x3node**)&(x3a->tbl[128]); + for(i=0; i<128; i++) x3a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int State_insert(struct state *data, struct config *key) +{ + x3node *np; + unsigned h; + unsigned ph; + + if( x3a==0 ) return 0; + ph = statehash(key); + h = ph & (x3a->size-1); + np = x3a->ht[h]; + while( np ){ + if( statecmp(np->key,key)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x3a->count>=x3a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x3 array; + array.size = size = x3a->size*2; + array.count = x3a->count; + array.tbl = (x3node*)calloc(size, sizeof(x3node) + sizeof(x3node*)); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x3node**)&(array.tbl[size]); + for(i=0; icount; i++){ + x3node *oldnp, *newnp; + oldnp = &(x3a->tbl[i]); + h = statehash(oldnp->key) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->key = oldnp->key; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x3a->tbl); + *x3a = array; + } + /* Insert the new data */ + h = ph & (x3a->size-1); + np = &(x3a->tbl[x3a->count++]); + np->key = key; + np->data = data; + if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next); + np->next = x3a->ht[h]; + x3a->ht[h] = np; + np->from = &(x3a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct state *State_find(struct config *key) +{ + unsigned h; + x3node *np; + + if( x3a==0 ) return 0; + h = statehash(key) & (x3a->size-1); + np = x3a->ht[h]; + while( np ){ + if( statecmp(np->key,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return an array of pointers to all data in the table. +** The array is obtained from malloc. Return NULL if memory allocation +** problems, or if the array is empty. */ +struct state **State_arrayof() +{ + struct state **array; + int i,size; + if( x3a==0 ) return 0; + size = x3a->count; + array = (struct state **)calloc(size, sizeof(struct state *)); + if( array ){ + for(i=0; itbl[i].data; + } + return array; +} + +/* Hash a configuration */ +PRIVATE unsigned confighash(struct config *a) +{ + unsigned h=0; + h = h*571 + a->rp->index*37 + a->dot; + return h; +} + +/* There is one instance of the following structure for each +** associative array of type "x4". +*/ +struct s_x4 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x4node *tbl; /* The data stored here */ + struct s_x4node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x4". +*/ +typedef struct s_x4node { + struct config *data; /* The data */ + struct s_x4node *next; /* Next entry with the same hash */ + struct s_x4node **from; /* Previous link */ +} x4node; + +/* There is only one instance of the array, which is the following */ +static struct s_x4 *x4a; + +/* Allocate a new associative array */ +void Configtable_init(){ + if( x4a ) return; + x4a = (struct s_x4*)malloc( sizeof(struct s_x4) ); + if( x4a ){ + x4a->size = 64; + x4a->count = 0; + x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*)); + if( x4a->tbl==0 ){ + free(x4a); + x4a = 0; + }else{ + int i; + x4a->ht = (x4node**)&(x4a->tbl[64]); + for(i=0; i<64; i++) x4a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Configtable_insert(struct config *data) +{ + x4node *np; + unsigned h; + unsigned ph; + + if( x4a==0 ) return 0; + ph = confighash(data); + h = ph & (x4a->size-1); + np = x4a->ht[h]; + while( np ){ + if( Configcmp((const char *) np->data,(const char *) data)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x4a->count>=x4a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x4 array; + array.size = size = x4a->size*2; + array.count = x4a->count; + array.tbl = (x4node*)calloc(size, sizeof(x4node) + sizeof(x4node*)); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x4node**)&(array.tbl[size]); + for(i=0; icount; i++){ + x4node *oldnp, *newnp; + oldnp = &(x4a->tbl[i]); + h = confighash(oldnp->data) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x4a->tbl); + *x4a = array; + } + /* Insert the new data */ + h = ph & (x4a->size-1); + np = &(x4a->tbl[x4a->count++]); + np->data = data; + if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next); + np->next = x4a->ht[h]; + x4a->ht[h] = np; + np->from = &(x4a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct config *Configtable_find(struct config *key) +{ + int h; + x4node *np; + + if( x4a==0 ) return 0; + h = confighash(key) & (x4a->size-1); + np = x4a->ht[h]; + while( np ){ + if( Configcmp((const char *) np->data,(const char *) key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Remove all data from the table. Pass each data to the function "f" +** as it is removed. ("f" may be null to avoid this step.) */ +void Configtable_clear(int(*f)(struct config *)) +{ + int i; + if( x4a==0 || x4a->count==0 ) return; + if( f ) for(i=0; icount; i++) (*f)(x4a->tbl[i].data); + for(i=0; isize; i++) x4a->ht[i] = 0; + x4a->count = 0; + return; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp index 77036f7..f6a23a0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp @@ -282,7 +282,7 @@ QString Lexer::detokenize(const TokenList& tokens) return ""; QString str; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) str += detokenize(token); return str; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp index 0f9aa91..9a0d3d2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp @@ -51,7 +51,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole { if (charAt(z, 1) == '-') { - for (i=2; (c = charAt(z, i)) != 0 && c != '\n'; i++) {} + for (i=2; !(c = charAt(z, i)).isNull() && c != '\n'; i++) {} token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT; token->type = Token::COMMENT; return i; @@ -99,7 +99,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole return 1; } - if ( charAt(z, 2) == 0 ) + if ( charAt(z, 2).isNull() ) { token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT; token->type = Token::COMMENT; @@ -108,12 +108,16 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole return 2; } - for (i = 3, c = charAt(z, 2); (c != '*' || charAt(z, i) != '/') && (c = charAt(z, i)) != 0; i++) {} + for (i = 3, c = charAt(z, 2); (c != '*' || charAt(z, i) != '/') && !(c = charAt(z, i)).isNull(); i++) {} if (tolerant && (c != '*' || charAt(z, i) != '/')) token.dynamicCast()->invalid = true; +#if QT_VERSION >= 0x050800 + if ( c.unicode() > 0 ) +#else if ( c > 0 ) +#endif i++; token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT; token->type = Token::COMMENT; @@ -232,7 +236,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole z0 == '"') { QChar delim = z0; - for (i = 1; (c = charAt(z, i)) != 0; i++) + for (i = 1; !(c = charAt(z, i)).isNull(); i++) { if ( c == delim ) { @@ -248,7 +252,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole token->type = Token::STRING; return i+1; } - else if ( c != 0 ) + else if ( !c.isNull() ) { token->lemonType = v3 ? TK3_ID : TK2_ID; token->type = Token::OTHER; @@ -289,7 +293,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole * number that begins with ".". Fall thru into the next case */ } - if (z0.isDigit()) + if (z0.isDigit() || z0 == '.') { token->lemonType = v3 ? TK3_INTEGER : TK2_INTEGER; token->type = Token::INTEGER; @@ -331,7 +335,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole } if (z0 == '[') { - for (i = 1, c = z0; c!=']' && (c = charAt(z, i)) != 0; i++) {} + for (i = 1, c = z0; c!=']' && !(c = charAt(z, i)).isNull(); i++) {} if (c == ']') { token->lemonType = v3 ? TK3_ID : TK2_ID; @@ -364,7 +368,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole int n = 0; token->lemonType = v3 ? TK3_VARIABLE : TK2_VARIABLE; token->type = Token::BIND_PARAM; - for (i = 1; (c = charAt(z, i)) != 0; i++) + for (i = 1; !(c = charAt(z, i)).isNull(); i++) { if ( isIdChar(c) ) { @@ -376,7 +380,7 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole { i++; } - while ( (c = charAt(z, i)) != 0 && !c.isSpace() && c != ')' ); + while ( !(c = charAt(z, i)).isNull() && !c.isSpace() && c != ')' ); if ( c==')' ) { @@ -428,10 +432,18 @@ int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tole token->lemonType = TK3_ILLEGAL; token->type = Token::INVALID; } +#if QT_VERSION >= 0x050800 + while (charAt(z, i).unicode() > 0 && charAt(z, i).unicode() != '\'') +#else while (charAt(z, i) > 0 && charAt(z, i) != '\'') +#endif i++; } +#if QT_VERSION >= 0x050800 + if ( charAt(z, i).unicode() > 0 ) +#else if ( charAt(z, i) > 0 ) +#endif i++; return i; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h index 87ba7e5..9027d04 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h @@ -3,6 +3,7 @@ #include "parser/token.h" #include +#include /** @file */ diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp index 23a4b55..55669a5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp @@ -55,7 +55,7 @@ void Parser::cleanUp() void Parser::fillSqliteDialect() { - foreach (SqliteQueryPtr query, context->parsedQueries) + for (SqliteQueryPtr query : context->parsedQueries) query->setSqliteDialect(dialect); } @@ -263,7 +263,7 @@ void Parser::expectedTokenLookup(void* pParser) Token::CTX_ROWID_KW, Token::INVALID }); - foreach (TokenPtr token, tokenSet) + for (TokenPtr token : tokenSet) { parse(pParser, token->lemonType, token, &tempContext); @@ -290,7 +290,7 @@ const QList &Parser::getErrors() QString Parser::getErrorString() { QStringList msgs; - foreach (ParserError* error, getErrors()) + for (ParserError* error : getErrors()) { msgs += error->getMessage(); } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser.h b/SQLiteStudio3/coreSQLiteStudio/parser/parser.h index aaf3962..8fe25f2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/parser.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser.h @@ -23,7 +23,7 @@ class ParserError; * { * QList queries = parser.getQueries(); * qDebug() << "number of queries parsed:" << queries.size(); - * foreach (SqliteQueryPtr query, queries) + * for (SqliteQueryPtr query : queries) * { * // do stuff with parsed queries * // ... diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h b/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h index 97a6393..ae52989 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h @@ -73,10 +73,9 @@ typedef QList ParserFkConditionList; typedef QList ParserExprList; typedef QList ParserResultColumnList; typedef QList ParserOtherSourceList; -typedef QList ParserStringList; typedef QList ParserOrderByList; typedef QList ParserQueryList; -typedef QPair ParserSetValue; +typedef QPair ParserSetValue; typedef QList ParserSetValueList; typedef QList ParserIndexedColumnList; typedef QList ParserExprNestedList; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp index 7f8ad7a..d9832bc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp @@ -130,7 +130,7 @@ TokenPtr ParserContext::getTokenPtr(Token* token) TokenList ParserContext::getTokenPtrList(const QList& tokens) { TokenList resList; - foreach (Token* token, tokens) + for (Token* token : tokens) resList << getTokenPtr(token); return resList; @@ -196,7 +196,7 @@ bool ParserContext::isCandidateForMaxNegativeNumber() const void ParserContext::cleanUp() { - foreach (ParserError* err, errors) + for (ParserError* err : errors) delete err; parsedQueries.clear(); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.bat b/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.bat new file mode 100644 index 0000000..961e21e --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.bat @@ -0,0 +1,8 @@ +set LEMON=C:\utils\lemon.exe + +rem %LEMON% -l -q -s sqlite3_parse.y +%LEMON% -l -q sqlite3_parse.y +move sqlite3_parse.c sqlite3_parse.cpp + +%LEMON% -l -q sqlite2_parse.y +move sqlite2_parse.c sqlite2_parse.cpp diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp index 81e242d..ea60ecc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp @@ -120,6 +120,7 @@ typedef union { QVariant* yy69; SqliteCreateTrigger::Scope* yy83; ParserStubExplain* yy91; + QStringList* yy95; ParserFullName* yy120; SqliteSelect::Core::SingleSource* yy121; ParserOtherSourceList* yy131; @@ -131,7 +132,6 @@ typedef union { SqliteExpr* yy192; ParserSetValueList* yy201; SqliteQuery* yy203; - ParserStringList* yy207; ParserResultColumnList* yy213; SqliteSelect::Core::JoinOp* yy221; int* yy226; @@ -347,7 +347,7 @@ static const YYACTIONTYPE yy_action[] = { /* 1050 */ 523, 328, 523, 570, 65, 531, 500, 13, 523, 101, /* 1060 */ 185, 184, 35, 570, 172, 171, 170, 197, 290, 503, /* 1070 */ 328, 523, 75, 570, 531, 301, 13, 523, 32, 33, - /* 1080 */ 380, 35, 10, 568, 567, 479, 34, 489, 540, 539, + /* 1080 */ 380, 35, 10, 568, 567, 479, 34, 490, 540, 539, /* 1090 */ 568, 567, 570, 325, 7, 211, 666, 32, 33, 523, /* 1100 */ 179, 423, 336, 335, 570, 34, 549, 548, 550, 80, /* 1110 */ 569, 570, 490, 7, 480, 489, 391, 570, 523, 568, @@ -983,9 +983,9 @@ static const char *const yyTokenName[] = { "from", "where_opt", "groupby_opt", "having_opt", "orderby_opt", "limit_opt", "sclp", "as", "joinsrc", "singlesrc", "seltablist", "joinop", - "joinconstr_opt", "dbnm", "inscollist", "sortlist", + "joinconstr_opt", "dbnm", "idlist", "sortlist", "collate", "nexprlist", "delete_stmt", "update_stmt", - "setlist", "insert_stmt", "insert_cmd", "inscollist_opt", + "setlist", "insert_stmt", "insert_cmd", "idlist_opt", "exprlist", "exprx", "not_opt", "likeop", "case_operand", "case_exprlist", "case_else", "raisetype", "uniqueflag", "idxlist_single", "nmnum", "number", @@ -1151,7 +1151,7 @@ static const char *const yyRuleName[] = { /* 150 */ "singlesrc ::= nm DOT ID_VIEW", /* 151 */ "singlesrc ::= ID_DB|ID_VIEW", /* 152 */ "joinconstr_opt ::= ON expr", - /* 153 */ "joinconstr_opt ::= USING LP inscollist RP", + /* 153 */ "joinconstr_opt ::= USING LP idlist RP", /* 154 */ "joinconstr_opt ::=", /* 155 */ "dbnm ::=", /* 156 */ "dbnm ::= DOT nm", @@ -1202,21 +1202,21 @@ static const char *const yyRuleName[] = { /* 201 */ "setlist ::= setlist COMMA ID_COL", /* 202 */ "setlist ::= ID_COL", /* 203 */ "cmd ::= insert_stmt", - /* 204 */ "insert_stmt ::= insert_cmd INTO fullname inscollist_opt VALUES LP exprlist RP", - /* 205 */ "insert_stmt ::= insert_cmd INTO fullname inscollist_opt select", + /* 204 */ "insert_stmt ::= insert_cmd INTO fullname idlist_opt VALUES LP exprlist RP", + /* 205 */ "insert_stmt ::= insert_cmd INTO fullname idlist_opt select", /* 206 */ "insert_stmt ::= insert_cmd INTO", /* 207 */ "insert_stmt ::= insert_cmd INTO nm DOT", /* 208 */ "insert_stmt ::= insert_cmd INTO ID_DB|ID_TAB", /* 209 */ "insert_stmt ::= insert_cmd INTO nm DOT ID_TAB", /* 210 */ "insert_cmd ::= INSERT orconf", /* 211 */ "insert_cmd ::= REPLACE", - /* 212 */ "inscollist_opt ::=", - /* 213 */ "inscollist_opt ::= LP inscollist RP", - /* 214 */ "inscollist ::= inscollist COMMA nm", - /* 215 */ "inscollist ::= nm", - /* 216 */ "inscollist ::=", - /* 217 */ "inscollist ::= inscollist COMMA ID_COL", - /* 218 */ "inscollist ::= ID_COL", + /* 212 */ "idlist_opt ::=", + /* 213 */ "idlist_opt ::= LP idlist RP", + /* 214 */ "idlist ::= idlist COMMA nm", + /* 215 */ "idlist ::= nm", + /* 216 */ "idlist ::=", + /* 217 */ "idlist ::= idlist COMMA ID_COL", + /* 218 */ "idlist ::= ID_COL", /* 219 */ "exprx ::= NULL", /* 220 */ "exprx ::= INTEGER", /* 221 */ "exprx ::= FLOAT", @@ -1328,7 +1328,7 @@ static const char *const yyRuleName[] = { /* 327 */ "trigger_event ::= DELETE", /* 328 */ "trigger_event ::= INSERT", /* 329 */ "trigger_event ::= UPDATE", - /* 330 */ "trigger_event ::= UPDATE OF inscollist", + /* 330 */ "trigger_event ::= UPDATE OF idlist", /* 331 */ "foreach_clause ::=", /* 332 */ "foreach_clause ::= FOR EACH ROW", /* 333 */ "foreach_clause ::= FOR EACH STATEMENT", @@ -1654,10 +1654,10 @@ delete (yypminor->yy221); delete (yypminor->yy455); } break; - case 210: /* inscollist */ - case 219: /* inscollist_opt */ + case 210: /* idlist */ + case 219: /* idlist_opt */ { -delete (yypminor->yy207); +delete (yypminor->yy95); } break; case 212: /* collate */ @@ -3223,10 +3223,10 @@ static void yy_reduce( objectForTokens = yygotominor.yy455; } break; - case 153: /* joinconstr_opt ::= USING LP inscollist RP */ + case 153: /* joinconstr_opt ::= USING LP idlist RP */ { - yygotominor.yy455 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy207)); - delete yymsp[-1].minor.yy207; + yygotominor.yy455 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy95)); + delete yymsp[-1].minor.yy95; objectForTokens = yygotominor.yy455; } break; @@ -3540,39 +3540,39 @@ static void yy_reduce( { yy_destructor(yypParser,216,&yymsp[-2].minor); } break; - case 204: /* insert_stmt ::= insert_cmd INTO fullname inscollist_opt VALUES LP exprlist RP */ + case 204: /* insert_stmt ::= insert_cmd INTO fullname idlist_opt VALUES LP exprlist RP */ { yygotominor.yy203 = new SqliteInsert( yymsp[-7].minor.yy344->replace, yymsp[-7].minor.yy344->orConflict, yymsp[-5].minor.yy120->name1, yymsp[-5].minor.yy120->name2, - *(yymsp[-4].minor.yy207), + *(yymsp[-4].minor.yy95), *(yymsp[-1].minor.yy231), nullptr ); delete yymsp[-5].minor.yy120; delete yymsp[-7].minor.yy344; delete yymsp[-1].minor.yy231; - delete yymsp[-4].minor.yy207; + delete yymsp[-4].minor.yy95; // since it's used in trigger: objectForTokens = yygotominor.yy203; } break; - case 205: /* insert_stmt ::= insert_cmd INTO fullname inscollist_opt select */ + case 205: /* insert_stmt ::= insert_cmd INTO fullname idlist_opt select */ { yygotominor.yy203 = new SqliteInsert( yymsp[-4].minor.yy344->replace, yymsp[-4].minor.yy344->orConflict, yymsp[-2].minor.yy120->name1, yymsp[-2].minor.yy120->name2, - *(yymsp[-1].minor.yy207), + *(yymsp[-1].minor.yy95), yymsp[0].minor.yy153, nullptr ); delete yymsp[-2].minor.yy120; delete yymsp[-4].minor.yy344; - delete yymsp[-1].minor.yy207; + delete yymsp[-1].minor.yy95; // since it's used in trigger: objectForTokens = yygotominor.yy203; } @@ -3619,35 +3619,35 @@ static void yy_reduce( case 211: /* insert_cmd ::= REPLACE */ {yygotominor.yy344 = new ParserStubInsertOrReplace(true);} break; - case 212: /* inscollist_opt ::= */ -{yygotominor.yy207 = new ParserStringList();} + case 212: /* idlist_opt ::= */ +{yygotominor.yy95 = new QStringList();} break; - case 213: /* inscollist_opt ::= LP inscollist RP */ -{yygotominor.yy207 = yymsp[-1].minor.yy207;} + case 213: /* idlist_opt ::= LP idlist RP */ +{yygotominor.yy95 = yymsp[-1].minor.yy95;} break; - case 214: /* inscollist ::= inscollist COMMA nm */ + case 214: /* idlist ::= idlist COMMA nm */ { - yymsp[-2].minor.yy207->append(*(yymsp[0].minor.yy319)); - yygotominor.yy207 = yymsp[-2].minor.yy207; + yymsp[-2].minor.yy95->append(*(yymsp[0].minor.yy319)); + yygotominor.yy95 = yymsp[-2].minor.yy95; delete yymsp[0].minor.yy319; - DONT_INHERIT_TOKENS("inscollist"); + DONT_INHERIT_TOKENS("idlist"); } break; - case 215: /* inscollist ::= nm */ + case 215: /* idlist ::= nm */ { - yygotominor.yy207 = new ParserStringList(); - yygotominor.yy207->append(*(yymsp[0].minor.yy319)); + yygotominor.yy95 = new QStringList(); + yygotominor.yy95->append(*(yymsp[0].minor.yy319)); delete yymsp[0].minor.yy319; } break; - case 216: /* inscollist ::= */ + case 216: /* idlist ::= */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy207 = new ParserStringList(); + yygotominor.yy95 = new QStringList(); } break; - case 217: /* inscollist ::= inscollist COMMA ID_COL */ - case 218: /* inscollist ::= ID_COL */ yytestcase(yyruleno==218); + case 217: /* idlist ::= idlist COMMA ID_COL */ + case 218: /* idlist ::= ID_COL */ yytestcase(yyruleno==218); { yy_destructor(yypParser,210,&yymsp[-2].minor); } break; @@ -4256,10 +4256,10 @@ static void yy_reduce( objectForTokens = yygotominor.yy151; } break; - case 330: /* trigger_event ::= UPDATE OF inscollist */ + case 330: /* trigger_event ::= UPDATE OF idlist */ { - yygotominor.yy151 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy207)); - delete yymsp[0].minor.yy207; + yygotominor.yy151 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy95)); + delete yymsp[0].minor.yy95; objectForTokens = yygotominor.yy151; } break; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y index 472725e..621d92e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y @@ -907,7 +907,7 @@ joinconstr_opt(X) ::= ON expr(E). { objectForTokens = X; } joinconstr_opt(X) ::= USING LP - inscollist(L) RP. { + idlist(L) RP. { X = new SqliteSelect::Core::JoinConstraint(*(L)); delete L; objectForTokens = X; @@ -1227,7 +1227,7 @@ cmd(X) ::= insert_stmt(S). { %type insert_stmt {SqliteQuery*} %destructor insert_stmt {delete $$;} insert_stmt(X) ::= insert_cmd(C) INTO - fullname(N) inscollist_opt(I) + fullname(N) idlist_opt(I) VALUES LP exprlist(L) RP. { X = new SqliteInsert( C->replace, @@ -1246,7 +1246,7 @@ insert_stmt(X) ::= insert_cmd(C) INTO objectForTokens = X; } insert_stmt(X) ::= insert_cmd(C) INTO - fullname(N) inscollist_opt(I) + fullname(N) idlist_opt(I) select(S). { X = new SqliteInsert( C->replace, @@ -1298,32 +1298,32 @@ insert_cmd(X) ::= INSERT orconf(C). { } insert_cmd(X) ::= REPLACE. {X = new ParserStubInsertOrReplace(true);} -%type inscollist_opt {ParserStringList*} -%destructor inscollist_opt {delete $$;} -inscollist_opt(X) ::= . {X = new ParserStringList();} -inscollist_opt(X) ::= LP inscollist(L) RP. {X = L;} +%type idlist_opt {QStringList*} +%destructor idlist_opt {delete $$;} +idlist_opt(X) ::= . {X = new QStringList();} +idlist_opt(X) ::= LP idlist(L) RP. {X = L;} -%type inscollist {ParserStringList*} -%destructor inscollist {delete $$;} -inscollist(X) ::= inscollist(L) COMMA +%type idlist {QStringList*} +%destructor idlist {delete $$;} +idlist(X) ::= idlist(L) COMMA nm(N). { L->append(*(N)); X = L; delete N; - DONT_INHERIT_TOKENS("inscollist"); + DONT_INHERIT_TOKENS("idlist"); } -inscollist(X) ::= nm(N). { - X = new ParserStringList(); +idlist(X) ::= nm(N). { + X = new QStringList(); X->append(*(N)); delete N; } -inscollist(X) ::= . { +idlist(X) ::= . { parserContext->minorErrorBeforeNextToken("Syntax error"); - X = new ParserStringList(); + X = new QStringList(); } -inscollist ::= inscollist COMMA ID_COL. {} -inscollist ::= ID_COL. {} +idlist ::= idlist COMMA ID_COL. {} +idlist ::= ID_COL. {} /////////////////////////// Expression Processing ///////////////////////////// @@ -1984,7 +1984,7 @@ trigger_event(X) ::= UPDATE. { objectForTokens = X; } trigger_event(X) ::= UPDATE OF - inscollist(L). { + idlist(L). { X = new SqliteCreateTrigger::Event(*(L)); delete L; objectForTokens = X; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp index 3884655..ffe6981 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp @@ -49,6 +49,7 @@ #include "parser/ast/sqliteindexedcolumn.h" #include "parser/ast/sqliteforeignkey.h" #include "parser/ast/sqlitewith.h" +#include "parser/ast/sqliteupsert.h" #include #include #include @@ -106,62 +107,63 @@ ** defined, then do no error processing. */ #define YYCODETYPE unsigned short int -#define YYNOCODE 278 +#define YYNOCODE 281 #define YYACTIONTYPE unsigned short int #define YYWILDCARD 61 #define sqlite3_parseTOKENTYPE Token* typedef union { int yyinit; sqlite3_parseTOKENTYPE yy0; - SqliteCreateTable::Column::Constraint* yy4; - SqliteCreateTable::Constraint* yy8; - ParserExprList* yy13; - QVariant* yy21; - ParserStubAlias* yy28; - SqliteConflictAlgo* yy30; - ParserFullName* yy66; - ParserCreateTableConstraintList* yy87; - SqliteIndexedColumn* yy90; - ParserFkConditionList* yy108; - SqliteSelect::Core::JoinConstraint* yy117; - ParserCreateTableColumnList* yy118; - SqliteSelect* yy123; - SqliteLimit* yy128; - ParserDeferSubClause* yy131; - ParserIndexedColumnList* yy139; - SqliteCreateTrigger::Time* yy152; - SqliteSelect::CompoundOperator* yy168; - SqliteSelect::Core::SingleSource* yy173; - QString* yy211; - ParserQueryList* yy214; - ParserStubExplain* yy225; - SqliteSortOrder* yy226; - bool* yy237; - ParserStubInsertOrReplace* yy250; - ParserResultColumnList* yy263; - SqliteForeignKey::Condition* yy271; - SqliteColumnType* yy299; - ParserStubTransDetails* yy300; - SqliteCreateTrigger::Event* yy309; - SqliteForeignKey::Condition::Reaction* yy312; - ParserOtherSourceList* yy359; - SqliteWith* yy367; - SqliteSelect::Core::JoinSource* yy373; - SqliteExpr::LikeOp* yy374; - int* yy376; - ParserSetValueList* yy381; - SqliteQuery* yy399; - SqliteCreateTrigger::Scope* yy409; - ParserExprNestedList* yy416; - SqliteCreateTable::Column* yy425; - ParserStringList* yy445; - ParserCreateTableColumnConstraintList* yy449; - SqliteSelect::Core* yy468; - ParserIndexedBy* yy472; - SqliteSelect::Core::JoinOp* yy473; - SqliteExpr* yy490; - ParserOrderByList* yy495; - SqliteInitially* yy498; + SqliteCreateTrigger::Scope* yy3; + ParserCreateTableColumnConstraintList* yy51; + QStringList* yy95; + SqliteForeignKey::Condition::Reaction* yy104; + ParserStubInsertOrReplace* yy105; + SqliteIndexedColumn* yy108; + ParserOtherSourceList* yy131; + SqliteCreateTrigger::Time* yy132; + int* yy146; + ParserOrderByList* yy163; + ParserExprNestedList* yy166; + ParserFkConditionList* yy184; + ParserIndexedBy* yy192; + ParserStubAlias* yy200; + SqliteSelect::Core::SingleSource* yy201; + ParserCreateTableColumnList* yy202; + ParserIndexedColumnList* yy223; + SqliteCreateTable::Column* yy227; + SqliteQuery* yy283; + SqliteSelect::Core::JoinConstraint* yy295; + SqliteSelect::Core::JoinOp* yy301; + SqliteCreateTable::Column::Constraint* yy304; + SqliteSortOrder* yy309; + SqliteSelect::Core* yy310; + SqliteWith* yy321; + ParserDeferSubClause* yy329; + ParserCreateTableConstraintList* yy333; + SqliteConflictAlgo* yy338; + SqliteForeignKey::Condition* yy347; + SqliteExpr* yy352; + ParserFullName* yy360; + ParserResultColumnList* yy373; + SqliteInitially* yy392; + QString* yy399; + ParserStubTransDetails* yy404; + SqliteCreateTable::Constraint* yy406; + ParserStubExplain* yy411; + ParserQueryList* yy430; + bool* yy451; + SqliteSelect::CompoundOperator* yy462; + QVariant* yy469; + SqliteSelect* yy473; + SqliteLimit* yy484; + SqliteSelect::Core::JoinSource* yy511; + SqliteExpr::LikeOp* yy520; + ParserSetValueList* yy521; + SqliteColumnType* yy537; + ParserExprList* yy551; + SqliteCreateTrigger::Event* yy552; + SqliteUpsert* yy560; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 @@ -170,8 +172,8 @@ typedef union { #define sqlite3_parseARG_PDECL ,ParserContext* parserContext #define sqlite3_parseARG_FETCH ParserContext* parserContext = yypParser->parserContext #define sqlite3_parseARG_STORE yypParser->parserContext = parserContext -#define YYNSTATE 725 -#define YYNRULE 424 +#define YYNSTATE 754 +#define YYNRULE 431 #define YYFALLBACK 1 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) @@ -243,629 +245,658 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ -#define YY_ACTTAB_COUNT (2271) +#define YY_ACTTAB_COUNT (2384) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 432, 565, 566, 717, 50, 50, 49, 49, 49, 48, - /* 10 */ 215, 420, 53, 53, 53, 53, 28, 51, 51, 51, - /* 20 */ 51, 50, 50, 49, 49, 49, 48, 215, 717, 1026, - /* 30 */ 1026, 336, 666, 665, 53, 53, 53, 53, 425, 51, - /* 40 */ 51, 51, 51, 50, 50, 49, 49, 49, 48, 215, - /* 50 */ 722, 81, 205, 204, 203, 672, 592, 592, 1026, 1026, - /* 60 */ 41, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - /* 70 */ 1026, 1026, 639, 1026, 1026, 1026, 1026, 38, 39, 1026, - /* 80 */ 1026, 1026, 1026, 1026, 40, 432, 529, 285, 717, 56, - /* 90 */ 108, 684, 3, 717, 668, 301, 420, 678, 661, 417, - /* 100 */ 716, 67, 688, 430, 552, 715, 714, 691, 130, 331, - /* 110 */ 60, 377, 374, 373, 678, 690, 689, 688, 674, 507, - /* 120 */ 61, 216, 717, 425, 49, 49, 49, 48, 215, 372, - /* 130 */ 715, 714, 212, 131, 1143, 1143, 242, 629, 246, 674, - /* 140 */ 672, 421, 685, 48, 215, 41, 508, 510, 678, 509, - /* 150 */ 9, 678, 33, 669, 144, 95, 281, 380, 276, 379, - /* 160 */ 132, 674, 38, 39, 609, 229, 228, 7, 356, 40, - /* 170 */ 885, 717, 403, 717, 274, 484, 685, 3, 885, 529, - /* 180 */ 248, 610, 678, 68, 417, 885, 411, 688, 430, 209, - /* 190 */ 715, 714, 691, 684, 457, 715, 714, 717, 209, 678, - /* 200 */ 690, 689, 688, 663, 662, 432, 453, 459, 460, 458, - /* 210 */ 306, 486, 507, 61, 717, 885, 420, 885, 885, 492, - /* 220 */ 725, 716, 320, 885, 715, 714, 461, 462, 885, 885, - /* 230 */ 885, 885, 885, 678, 297, 9, 678, 772, 669, 508, - /* 240 */ 510, 687, 509, 425, 717, 339, 244, 51, 51, 51, - /* 250 */ 51, 50, 50, 49, 49, 49, 48, 215, 543, 570, - /* 260 */ 672, 357, 713, 283, 688, 41, 544, 711, 448, 691, - /* 270 */ 445, 577, 712, 715, 714, 715, 714, 690, 689, 688, - /* 280 */ 492, 576, 38, 39, 449, 448, 512, 445, 487, 40, - /* 290 */ 947, 463, 661, 389, 497, 603, 602, 3, 947, 715, - /* 300 */ 714, 230, 678, 684, 417, 947, 13, 688, 430, 723, - /* 310 */ 17, 617, 691, 448, 513, 445, 715, 714, 81, 678, - /* 320 */ 690, 689, 688, 307, 1135, 679, 460, 654, 618, 360, - /* 330 */ 774, 1135, 1028, 1028, 89, 947, 1, 947, 947, 716, - /* 340 */ 110, 595, 716, 617, 461, 342, 715, 714, 947, 947, - /* 350 */ 947, 947, 1080, 678, 692, 9, 678, 497, 669, 693, - /* 360 */ 717, 54, 55, 427, 295, 1028, 1028, 681, 681, 52, - /* 370 */ 52, 53, 53, 53, 53, 717, 51, 51, 51, 51, - /* 380 */ 50, 50, 49, 49, 49, 48, 215, 432, 496, 382, - /* 390 */ 717, 553, 347, 254, 363, 258, 298, 139, 420, 218, - /* 400 */ 539, 69, 286, 287, 716, 684, 143, 231, 390, 343, - /* 410 */ 661, 54, 55, 427, 295, 716, 716, 681, 681, 52, - /* 420 */ 52, 53, 53, 53, 53, 425, 51, 51, 51, 51, - /* 430 */ 50, 50, 49, 49, 49, 48, 215, 684, 954, 608, - /* 440 */ 628, 692, 672, 663, 662, 585, 693, 41, 429, 207, - /* 450 */ 601, 491, 388, 954, 130, 652, 499, 377, 374, 373, - /* 460 */ 500, 431, 715, 714, 38, 39, 651, 199, 198, 673, - /* 470 */ 186, 40, 932, 699, 685, 372, 717, 715, 714, 3, - /* 480 */ 932, 351, 57, 653, 678, 616, 417, 932, 135, 688, - /* 490 */ 430, 59, 688, 157, 691, 717, 680, 691, 340, 1046, - /* 500 */ 954, 678, 690, 689, 688, 690, 689, 688, 685, 419, - /* 510 */ 666, 665, 724, 2, 1028, 1028, 636, 932, 208, 932, - /* 520 */ 932, 43, 386, 141, 294, 615, 611, 264, 284, 267, - /* 530 */ 932, 139, 932, 932, 122, 678, 400, 9, 678, 684, - /* 540 */ 669, 716, 142, 54, 55, 427, 295, 1028, 1028, 681, - /* 550 */ 681, 52, 52, 53, 53, 53, 53, 339, 51, 51, - /* 560 */ 51, 51, 50, 50, 49, 49, 49, 48, 215, 652, - /* 570 */ 91, 299, 483, 483, 628, 717, 661, 717, 715, 714, - /* 580 */ 651, 18, 717, 605, 717, 37, 677, 399, 311, 717, - /* 590 */ 34, 535, 535, 1028, 1028, 427, 295, 715, 714, 681, - /* 600 */ 681, 52, 52, 53, 53, 53, 53, 234, 51, 51, - /* 610 */ 51, 51, 50, 50, 49, 49, 49, 48, 215, 1027, - /* 620 */ 1027, 723, 54, 55, 427, 295, 1028, 1028, 681, 681, - /* 630 */ 52, 52, 53, 53, 53, 53, 42, 51, 51, 51, - /* 640 */ 51, 50, 50, 49, 49, 49, 48, 215, 1027, 1027, - /* 650 */ 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, - /* 660 */ 1027, 1027, 717, 1027, 1027, 1027, 1027, 1027, 1027, 1027, - /* 670 */ 1027, 1027, 1027, 1027, 1028, 1028, 718, 715, 714, 715, - /* 680 */ 714, 454, 324, 201, 715, 714, 715, 714, 321, 695, - /* 690 */ 315, 715, 714, 658, 554, 214, 676, 46, 568, 32, - /* 700 */ 81, 88, 675, 54, 55, 427, 295, 1028, 1028, 681, - /* 710 */ 681, 52, 52, 53, 53, 53, 53, 1095, 51, 51, - /* 720 */ 51, 51, 50, 50, 49, 49, 49, 48, 215, 54, - /* 730 */ 55, 427, 295, 667, 423, 681, 681, 52, 52, 53, - /* 740 */ 53, 53, 53, 454, 51, 51, 51, 51, 50, 50, - /* 750 */ 49, 49, 49, 48, 215, 358, 955, 656, 643, 1150, - /* 760 */ 154, 436, 2, 487, 715, 714, 350, 54, 55, 427, - /* 770 */ 295, 955, 484, 681, 681, 52, 52, 53, 53, 53, - /* 780 */ 53, 160, 51, 51, 51, 51, 50, 50, 49, 49, - /* 790 */ 49, 48, 215, 600, 1095, 22, 717, 280, 307, 1134, - /* 800 */ 34, 717, 501, 502, 353, 629, 1134, 306, 485, 697, - /* 810 */ 268, 717, 229, 228, 337, 279, 717, 558, 955, 54, - /* 820 */ 55, 427, 295, 716, 717, 681, 681, 52, 52, 53, - /* 830 */ 53, 53, 53, 655, 51, 51, 51, 51, 50, 50, - /* 840 */ 49, 49, 49, 48, 215, 432, 1109, 81, 717, 225, - /* 850 */ 663, 662, 54, 55, 427, 295, 420, 153, 681, 681, - /* 860 */ 52, 52, 53, 53, 53, 53, 641, 51, 51, 51, - /* 870 */ 51, 50, 50, 49, 49, 49, 48, 215, 586, 89, - /* 880 */ 717, 231, 390, 425, 15, 717, 694, 413, 13, 895, - /* 890 */ 721, 207, 601, 617, 388, 435, 81, 574, 715, 714, - /* 900 */ 672, 272, 553, 715, 714, 41, 529, 537, 89, 14, - /* 910 */ 618, 698, 69, 715, 714, 716, 13, 209, 715, 714, - /* 920 */ 359, 617, 38, 39, 159, 617, 715, 714, 645, 40, - /* 930 */ 1143, 1143, 717, 345, 222, 674, 540, 3, 618, 469, - /* 940 */ 61, 285, 678, 625, 417, 473, 716, 688, 430, 45, - /* 950 */ 715, 714, 691, 617, 716, 416, 674, 402, 581, 678, - /* 960 */ 690, 689, 688, 429, 901, 901, 468, 467, 284, 466, - /* 970 */ 629, 81, 706, 633, 495, 580, 431, 526, 674, 1143, - /* 980 */ 1143, 716, 715, 714, 673, 92, 716, 715, 714, 91, - /* 990 */ 473, 401, 438, 678, 526, 9, 678, 370, 669, 409, - /* 1000 */ 54, 55, 427, 295, 89, 505, 681, 681, 52, 52, - /* 1010 */ 53, 53, 53, 53, 620, 51, 51, 51, 51, 50, - /* 1020 */ 50, 49, 49, 49, 48, 215, 717, 638, 311, 717, - /* 1030 */ 406, 658, 418, 214, 715, 714, 90, 642, 131, 334, - /* 1040 */ 415, 644, 54, 55, 427, 295, 451, 640, 681, 681, - /* 1050 */ 52, 52, 53, 53, 53, 53, 158, 51, 51, 51, - /* 1060 */ 51, 50, 50, 49, 49, 49, 48, 215, 369, 54, - /* 1070 */ 55, 427, 295, 12, 451, 681, 681, 52, 52, 53, - /* 1080 */ 53, 53, 53, 633, 51, 51, 51, 51, 50, 50, - /* 1090 */ 49, 49, 49, 48, 215, 36, 716, 8, 209, 54, - /* 1100 */ 55, 427, 295, 34, 589, 681, 681, 52, 52, 53, - /* 1110 */ 53, 53, 53, 704, 51, 51, 51, 51, 50, 50, - /* 1120 */ 49, 49, 49, 48, 215, 87, 138, 320, 715, 714, - /* 1130 */ 412, 715, 714, 274, 572, 54, 55, 427, 295, 30, - /* 1140 */ 624, 681, 681, 52, 52, 53, 53, 53, 53, 326, - /* 1150 */ 51, 51, 51, 51, 50, 50, 49, 49, 49, 48, - /* 1160 */ 215, 408, 717, 137, 91, 54, 55, 427, 295, 614, - /* 1170 */ 271, 681, 681, 52, 52, 53, 53, 53, 53, 465, - /* 1180 */ 51, 51, 51, 51, 50, 50, 49, 49, 49, 48, - /* 1190 */ 215, 136, 716, 538, 612, 91, 99, 54, 55, 427, - /* 1200 */ 295, 23, 607, 681, 681, 52, 52, 53, 53, 53, - /* 1210 */ 53, 395, 51, 51, 51, 51, 50, 50, 49, 49, - /* 1220 */ 49, 48, 215, 533, 1110, 516, 717, 91, 54, 55, - /* 1230 */ 427, 295, 141, 393, 681, 681, 52, 52, 53, 53, - /* 1240 */ 53, 53, 5, 51, 51, 51, 51, 50, 50, 49, - /* 1250 */ 49, 49, 48, 215, 717, 1108, 606, 91, 717, 476, - /* 1260 */ 54, 55, 427, 295, 715, 714, 681, 681, 52, 52, - /* 1270 */ 53, 53, 53, 53, 684, 51, 51, 51, 51, 50, - /* 1280 */ 50, 49, 49, 49, 48, 215, 684, 54, 58, 427, - /* 1290 */ 295, 476, 717, 681, 681, 52, 52, 53, 53, 53, - /* 1300 */ 53, 633, 51, 51, 51, 51, 50, 50, 49, 49, - /* 1310 */ 49, 48, 215, 432, 716, 251, 518, 604, 1035, 11, - /* 1320 */ 107, 629, 36, 531, 420, 55, 427, 295, 715, 714, - /* 1330 */ 681, 681, 52, 52, 53, 53, 53, 53, 224, 51, - /* 1340 */ 51, 51, 51, 50, 50, 49, 49, 49, 48, 215, - /* 1350 */ 91, 425, 717, 583, 531, 582, 715, 714, 429, 20, - /* 1360 */ 715, 714, 429, 684, 429, 619, 384, 352, 672, 562, - /* 1370 */ 387, 431, 623, 41, 489, 431, 684, 431, 657, 673, - /* 1380 */ 186, 308, 717, 673, 186, 673, 186, 622, 684, 470, - /* 1390 */ 38, 39, 599, 597, 715, 714, 432, 40, 719, 683, - /* 1400 */ 91, 830, 634, 596, 91, 3, 571, 420, 541, 591, - /* 1410 */ 678, 716, 417, 391, 385, 688, 430, 332, 707, 333, - /* 1420 */ 691, 525, 429, 582, 717, 65, 429, 678, 690, 689, - /* 1430 */ 688, 716, 316, 717, 425, 431, 316, 564, 316, 431, - /* 1440 */ 717, 590, 376, 673, 186, 64, 429, 673, 186, 429, - /* 1450 */ 273, 672, 19, 470, 715, 714, 41, 371, 378, 431, - /* 1460 */ 684, 678, 431, 9, 678, 684, 669, 673, 186, 563, - /* 1470 */ 673, 92, 717, 38, 39, 63, 648, 391, 383, 432, - /* 1480 */ 40, 391, 392, 129, 715, 714, 717, 279, 3, 270, - /* 1490 */ 420, 367, 613, 678, 705, 417, 316, 534, 688, 430, - /* 1500 */ 316, 404, 4, 691, 717, 553, 717, 716, 156, 284, - /* 1510 */ 678, 690, 689, 688, 441, 69, 325, 425, 716, 630, - /* 1520 */ 316, 717, 716, 642, 125, 79, 715, 714, 703, 27, - /* 1530 */ 26, 85, 517, 77, 672, 715, 714, 520, 447, 41, - /* 1540 */ 717, 716, 715, 714, 678, 549, 9, 678, 717, 669, - /* 1550 */ 511, 329, 700, 506, 520, 354, 38, 39, 504, 702, - /* 1560 */ 83, 432, 684, 40, 265, 716, 447, 286, 266, 226, - /* 1570 */ 141, 3, 420, 556, 715, 714, 678, 716, 417, 696, - /* 1580 */ 716, 688, 430, 515, 686, 422, 691, 717, 715, 714, - /* 1590 */ 498, 429, 716, 678, 690, 689, 688, 716, 716, 425, - /* 1600 */ 515, 480, 335, 439, 431, 253, 715, 714, 715, 714, - /* 1610 */ 119, 479, 673, 194, 250, 260, 672, 717, 480, 220, - /* 1620 */ 439, 41, 717, 715, 714, 10, 152, 678, 716, 9, - /* 1630 */ 678, 161, 669, 1036, 286, 594, 456, 455, 38, 39, - /* 1640 */ 72, 111, 715, 714, 432, 40, 635, 716, 646, 429, - /* 1650 */ 715, 714, 338, 3, 1038, 420, 437, 209, 678, 716, - /* 1660 */ 417, 202, 431, 688, 430, 642, 429, 96, 691, 221, - /* 1670 */ 673, 181, 631, 717, 223, 678, 690, 689, 688, 431, - /* 1680 */ 717, 429, 425, 206, 86, 716, 717, 673, 185, 715, - /* 1690 */ 714, 319, 626, 257, 431, 429, 522, 219, 720, 672, - /* 1700 */ 530, 559, 673, 189, 41, 716, 716, 318, 431, 678, - /* 1710 */ 710, 9, 678, 717, 669, 646, 673, 187, 490, 715, - /* 1720 */ 714, 38, 39, 642, 715, 714, 432, 150, 40, 134, - /* 1730 */ 709, 542, 429, 717, 149, 429, 3, 420, 708, 286, - /* 1740 */ 642, 678, 716, 417, 434, 431, 688, 430, 431, 286, - /* 1750 */ 429, 691, 716, 673, 195, 642, 673, 193, 678, 690, - /* 1760 */ 689, 688, 716, 431, 425, 398, 256, 621, 368, 642, - /* 1770 */ 255, 673, 196, 147, 328, 715, 714, 429, 716, 716, - /* 1780 */ 716, 672, 715, 714, 327, 82, 41, 433, 715, 714, - /* 1790 */ 431, 16, 678, 701, 9, 678, 598, 669, 673, 200, - /* 1800 */ 503, 532, 145, 38, 39, 215, 642, 232, 432, 642, - /* 1810 */ 40, 47, 671, 247, 31, 715, 714, 482, 3, 420, - /* 1820 */ 646, 275, 475, 678, 642, 417, 716, 528, 715, 430, - /* 1830 */ 646, 569, 429, 691, 716, 715, 714, 550, 231, 291, - /* 1840 */ 678, 690, 689, 688, 716, 431, 425, 524, 245, 18, - /* 1850 */ 716, 642, 478, 673, 233, 98, 290, 239, 243, 217, - /* 1860 */ 429, 716, 474, 672, 717, 241, 35, 405, 238, 471, - /* 1870 */ 303, 716, 289, 431, 678, 288, 9, 678, 716, 669, - /* 1880 */ 235, 673, 296, 670, 322, 38, 39, 414, 102, 44, - /* 1890 */ 717, 300, 40, 716, 407, 302, 148, 66, 227, 151, - /* 1900 */ 3, 213, 81, 269, 97, 678, 642, 417, 410, 140, - /* 1910 */ 688, 430, 717, 262, 429, 691, 716, 361, 109, 348, - /* 1920 */ 394, 390, 678, 690, 689, 688, 716, 431, 584, 429, - /* 1930 */ 716, 429, 716, 429, 642, 673, 192, 593, 133, 304, - /* 1940 */ 717, 146, 431, 381, 431, 579, 431, 429, 277, 429, - /* 1950 */ 673, 184, 673, 172, 673, 163, 678, 578, 9, 678, - /* 1960 */ 431, 669, 431, 330, 429, 575, 715, 714, 673, 171, - /* 1970 */ 673, 183, 717, 574, 717, 573, 429, 431, 317, 310, - /* 1980 */ 548, 555, 443, 547, 546, 673, 188, 429, 642, 431, - /* 1990 */ 545, 309, 715, 714, 536, 716, 128, 673, 314, 428, - /* 2000 */ 431, 80, 127, 642, 519, 642, 429, 642, 673, 313, - /* 2010 */ 366, 429, 716, 341, 715, 714, 717, 106, 429, 431, - /* 2020 */ 211, 642, 261, 642, 431, 472, 493, 673, 312, 126, - /* 2030 */ 717, 431, 673, 170, 355, 429, 282, 25, 642, 673, - /* 2040 */ 93, 429, 715, 714, 124, 527, 429, 263, 431, 716, - /* 2050 */ 642, 429, 252, 78, 431, 105, 673, 169, 249, 431, - /* 2060 */ 716, 642, 673, 168, 431, 716, 429, 673, 166, 429, - /* 2070 */ 84, 716, 673, 165, 715, 714, 715, 714, 717, 431, - /* 2080 */ 642, 717, 431, 429, 123, 642, 444, 673, 182, 429, - /* 2090 */ 673, 164, 642, 240, 236, 364, 431, 717, 121, 464, - /* 2100 */ 429, 717, 431, 477, 673, 190, 716, 716, 717, 642, - /* 2110 */ 673, 191, 442, 431, 429, 642, 155, 429, 715, 714, - /* 2120 */ 642, 673, 174, 717, 429, 642, 514, 431, 429, 237, - /* 2130 */ 431, 429, 715, 714, 429, 673, 173, 431, 673, 175, - /* 2140 */ 642, 431, 716, 642, 431, 673, 178, 431, 429, 673, - /* 2150 */ 94, 349, 673, 177, 429, 673, 176, 642, 104, 120, - /* 2160 */ 494, 431, 103, 642, 429, 346, 118, 431, 344, 673, - /* 2170 */ 180, 117, 76, 75, 642, 673, 179, 431, 647, 116, - /* 2180 */ 715, 714, 74, 715, 714, 673, 167, 115, 642, 73, - /* 2190 */ 114, 642, 481, 643, 323, 113, 397, 24, 642, 715, - /* 2200 */ 714, 452, 642, 715, 714, 642, 21, 450, 642, 431, - /* 2210 */ 715, 714, 101, 100, 446, 112, 62, 673, 70, 440, - /* 2220 */ 162, 292, 642, 664, 552, 715, 714, 570, 642, 632, - /* 2230 */ 426, 650, 637, 627, 278, 197, 375, 660, 642, 259, - /* 2240 */ 362, 523, 6, 305, 682, 659, 649, 557, 210, 521, - /* 2250 */ 29, 365, 424, 293, 71, 567, 561, 560, 488, 588, - /* 2260 */ 587, 81, 551, 1151, 1151, 1151, 1151, 1151, 1151, 1151, - /* 2270 */ 642, + /* 0 */ 457, 54, 54, 53, 53, 53, 52, 225, 277, 746, + /* 10 */ 280, 445, 57, 57, 57, 57, 32, 55, 55, 55, + /* 20 */ 55, 54, 54, 53, 53, 53, 52, 225, 658, 1062, + /* 30 */ 1062, 63, 746, 165, 57, 57, 57, 57, 450, 55, + /* 40 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 50 */ 697, 87, 312, 644, 746, 701, 143, 71, 1062, 1062, + /* 60 */ 45, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 70 */ 1062, 1062, 652, 1062, 1062, 1062, 1062, 42, 43, 1062, + /* 80 */ 1062, 1062, 1062, 1062, 44, 457, 53, 53, 53, 52, + /* 90 */ 225, 746, 3, 643, 639, 717, 445, 707, 751, 442, + /* 100 */ 720, 1, 717, 455, 293, 454, 623, 720, 719, 718, + /* 110 */ 717, 744, 743, 411, 707, 719, 718, 717, 456, 746, + /* 120 */ 454, 683, 292, 450, 15, 485, 702, 196, 96, 645, + /* 130 */ 1179, 1179, 665, 456, 744, 743, 378, 454, 745, 149, + /* 140 */ 701, 702, 196, 486, 487, 45, 646, 98, 707, 537, + /* 150 */ 456, 473, 10, 707, 658, 698, 744, 743, 702, 196, + /* 160 */ 350, 645, 42, 43, 637, 543, 298, 474, 473, 44, + /* 170 */ 914, 721, 931, 931, 722, 424, 407, 3, 914, 745, + /* 180 */ 329, 87, 707, 746, 442, 914, 138, 717, 455, 401, + /* 190 */ 398, 397, 720, 744, 743, 329, 473, 457, 638, 707, + /* 200 */ 719, 718, 717, 724, 914, 454, 139, 396, 445, 488, + /* 210 */ 690, 92, 410, 349, 307, 1116, 219, 914, 456, 914, + /* 220 */ 914, 744, 743, 914, 746, 241, 702, 99, 914, 914, + /* 230 */ 914, 914, 914, 707, 19, 450, 222, 10, 707, 314, + /* 240 */ 698, 55, 55, 55, 55, 54, 54, 53, 53, 53, + /* 250 */ 52, 225, 701, 427, 746, 454, 746, 45, 152, 102, + /* 260 */ 294, 404, 289, 403, 140, 310, 436, 550, 456, 215, + /* 270 */ 214, 213, 431, 296, 42, 43, 702, 196, 287, 746, + /* 280 */ 671, 44, 977, 746, 580, 744, 743, 426, 138, 3, + /* 290 */ 977, 401, 398, 397, 707, 333, 442, 977, 509, 717, + /* 300 */ 455, 593, 594, 557, 720, 413, 668, 631, 630, 396, + /* 310 */ 351, 707, 719, 718, 717, 521, 977, 457, 509, 365, + /* 320 */ 508, 508, 526, 527, 371, 713, 744, 743, 445, 977, + /* 330 */ 329, 977, 977, 319, 511, 636, 532, 65, 613, 226, + /* 340 */ 977, 977, 977, 977, 64, 707, 15, 977, 703, 10, + /* 350 */ 707, 645, 698, 319, 510, 450, 744, 743, 744, 743, + /* 360 */ 209, 208, 524, 533, 535, 746, 525, 534, 646, 703, + /* 370 */ 714, 609, 701, 52, 225, 61, 470, 45, 516, 620, + /* 380 */ 620, 744, 743, 645, 454, 717, 375, 369, 608, 633, + /* 390 */ 720, 703, 408, 470, 42, 43, 38, 456, 719, 718, + /* 400 */ 717, 44, 962, 746, 714, 702, 196, 358, 605, 3, + /* 410 */ 962, 512, 60, 116, 707, 713, 442, 962, 604, 717, + /* 420 */ 455, 470, 538, 801, 720, 742, 98, 713, 1082, 686, + /* 430 */ 740, 707, 719, 718, 717, 741, 962, 485, 328, 424, + /* 440 */ 409, 687, 582, 224, 1064, 1064, 320, 1171, 297, 962, + /* 450 */ 745, 962, 962, 300, 1171, 486, 360, 91, 12, 329, + /* 460 */ 962, 745, 962, 962, 628, 707, 745, 744, 743, 10, + /* 470 */ 707, 38, 698, 58, 59, 452, 308, 1064, 1064, 710, + /* 480 */ 710, 56, 56, 57, 57, 57, 57, 219, 55, 55, + /* 490 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 563, + /* 500 */ 563, 265, 387, 271, 478, 744, 743, 667, 324, 148, + /* 510 */ 581, 242, 414, 549, 803, 311, 377, 713, 245, 567, + /* 520 */ 73, 361, 690, 745, 1064, 1064, 58, 59, 452, 308, + /* 530 */ 119, 47, 710, 710, 56, 56, 57, 57, 57, 57, + /* 540 */ 406, 55, 55, 55, 55, 54, 54, 53, 53, 53, + /* 550 */ 52, 225, 657, 58, 59, 452, 308, 1064, 1064, 710, + /* 560 */ 710, 56, 56, 57, 57, 57, 57, 334, 55, 55, + /* 570 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 681, + /* 580 */ 687, 443, 224, 581, 1186, 162, 461, 2, 240, 239, + /* 590 */ 680, 285, 466, 73, 721, 41, 745, 722, 96, 58, + /* 600 */ 59, 452, 308, 1064, 1064, 710, 710, 56, 56, 57, + /* 610 */ 57, 57, 57, 96, 55, 55, 55, 55, 54, 54, + /* 620 */ 53, 53, 53, 52, 225, 49, 692, 691, 151, 1063, + /* 630 */ 1063, 602, 58, 59, 452, 308, 1064, 1064, 710, 710, + /* 640 */ 56, 56, 57, 57, 57, 57, 368, 55, 55, 55, + /* 650 */ 55, 54, 54, 53, 53, 53, 52, 225, 1063, 1063, + /* 660 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 670 */ 1063, 1063, 746, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 680 */ 1063, 1063, 1063, 1063, 1064, 1064, 452, 308, 692, 691, + /* 690 */ 710, 710, 56, 56, 57, 57, 57, 57, 34, 55, + /* 700 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 710 */ 713, 95, 709, 58, 59, 452, 308, 1064, 1064, 710, + /* 720 */ 710, 56, 56, 57, 57, 57, 57, 708, 55, 55, + /* 730 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 58, + /* 740 */ 59, 452, 308, 746, 218, 710, 710, 56, 56, 57, + /* 750 */ 57, 57, 57, 150, 55, 55, 55, 55, 54, 54, + /* 760 */ 53, 53, 53, 52, 225, 658, 984, 253, 672, 257, + /* 770 */ 512, 50, 706, 36, 744, 743, 58, 59, 452, 308, + /* 780 */ 746, 984, 710, 710, 56, 56, 57, 57, 57, 57, + /* 790 */ 161, 55, 55, 55, 55, 54, 54, 53, 53, 53, + /* 800 */ 52, 225, 6, 985, 148, 320, 1170, 217, 629, 648, + /* 810 */ 412, 259, 713, 1170, 58, 59, 452, 308, 985, 17, + /* 820 */ 710, 710, 56, 56, 57, 57, 57, 57, 984, 55, + /* 830 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 840 */ 498, 986, 299, 394, 16, 744, 743, 657, 1131, 438, + /* 850 */ 96, 58, 59, 452, 308, 745, 986, 710, 710, 56, + /* 860 */ 56, 57, 57, 57, 57, 985, 55, 55, 55, 55, + /* 870 */ 54, 54, 53, 53, 53, 52, 225, 554, 987, 255, + /* 880 */ 337, 211, 744, 743, 383, 498, 658, 354, 695, 694, + /* 890 */ 444, 695, 694, 987, 554, 746, 705, 745, 58, 59, + /* 900 */ 452, 308, 24, 986, 710, 710, 56, 56, 57, 57, + /* 910 */ 57, 57, 112, 55, 55, 55, 55, 54, 54, 53, + /* 920 */ 53, 53, 52, 225, 682, 1131, 58, 59, 452, 308, + /* 930 */ 647, 746, 710, 710, 56, 56, 57, 57, 57, 57, + /* 940 */ 987, 55, 55, 55, 55, 54, 54, 53, 53, 53, + /* 950 */ 52, 225, 457, 1145, 229, 690, 704, 441, 690, 20, + /* 960 */ 571, 598, 46, 445, 58, 59, 452, 308, 572, 139, + /* 970 */ 710, 710, 56, 56, 57, 57, 57, 57, 746, 55, + /* 980 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 990 */ 450, 98, 746, 37, 713, 696, 580, 744, 743, 393, + /* 1000 */ 97, 454, 298, 87, 454, 685, 662, 701, 240, 239, + /* 1010 */ 754, 581, 45, 428, 456, 745, 168, 456, 454, 745, + /* 1020 */ 727, 73, 702, 196, 745, 702, 99, 557, 281, 42, + /* 1030 */ 43, 456, 355, 744, 743, 357, 44, 482, 684, 702, + /* 1040 */ 196, 745, 703, 233, 3, 568, 692, 691, 746, 707, + /* 1050 */ 484, 442, 483, 167, 717, 455, 424, 425, 333, 720, + /* 1060 */ 532, 65, 87, 703, 287, 446, 707, 719, 718, 717, + /* 1070 */ 384, 340, 352, 424, 415, 517, 329, 149, 674, 671, + /* 1080 */ 744, 743, 1179, 1179, 297, 703, 72, 533, 535, 746, + /* 1090 */ 383, 534, 423, 329, 744, 743, 713, 745, 363, 752, + /* 1100 */ 707, 382, 440, 745, 10, 707, 714, 698, 149, 8, + /* 1110 */ 374, 745, 58, 59, 452, 308, 434, 376, 710, 710, + /* 1120 */ 56, 56, 57, 57, 57, 57, 98, 55, 55, 55, + /* 1130 */ 55, 54, 54, 53, 53, 53, 52, 225, 517, 166, + /* 1140 */ 714, 662, 681, 422, 324, 278, 454, 617, 273, 279, + /* 1150 */ 744, 743, 231, 680, 745, 437, 746, 673, 745, 456, + /* 1160 */ 228, 745, 651, 58, 59, 452, 308, 702, 204, 710, + /* 1170 */ 710, 56, 56, 57, 57, 57, 57, 650, 55, 55, + /* 1180 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 98, + /* 1190 */ 546, 744, 743, 58, 59, 452, 308, 149, 600, 710, + /* 1200 */ 710, 56, 56, 57, 57, 57, 57, 344, 55, 55, + /* 1210 */ 55, 55, 54, 54, 53, 53, 53, 52, 225, 14, + /* 1220 */ 746, 671, 433, 566, 40, 726, 659, 266, 284, 58, + /* 1230 */ 59, 452, 308, 586, 40, 710, 710, 56, 56, 57, + /* 1240 */ 57, 57, 57, 747, 55, 55, 55, 55, 54, 54, + /* 1250 */ 53, 53, 53, 52, 225, 9, 98, 98, 744, 743, + /* 1260 */ 38, 58, 59, 452, 308, 25, 94, 710, 710, 56, + /* 1270 */ 56, 57, 57, 57, 57, 653, 55, 55, 55, 55, + /* 1280 */ 54, 54, 53, 53, 53, 52, 225, 561, 1146, 262, + /* 1290 */ 713, 58, 59, 452, 308, 267, 40, 710, 710, 56, + /* 1300 */ 56, 57, 57, 57, 57, 147, 55, 55, 55, 55, + /* 1310 */ 54, 54, 53, 53, 53, 52, 225, 522, 1144, 746, + /* 1320 */ 614, 98, 744, 743, 58, 59, 452, 308, 723, 98, + /* 1330 */ 710, 710, 56, 56, 57, 57, 57, 57, 146, 55, + /* 1340 */ 55, 55, 55, 54, 54, 53, 53, 53, 52, 225, + /* 1350 */ 670, 58, 62, 452, 308, 357, 746, 710, 710, 56, + /* 1360 */ 56, 57, 57, 57, 57, 454, 55, 55, 55, 55, + /* 1370 */ 54, 54, 53, 53, 53, 52, 225, 457, 456, 611, + /* 1380 */ 746, 610, 522, 106, 148, 746, 702, 196, 445, 59, + /* 1390 */ 452, 308, 713, 746, 710, 710, 56, 56, 57, 57, + /* 1400 */ 57, 57, 219, 55, 55, 55, 55, 54, 54, 53, + /* 1410 */ 53, 53, 52, 225, 592, 450, 559, 514, 297, 752, + /* 1420 */ 429, 744, 743, 750, 321, 490, 145, 657, 460, 299, + /* 1430 */ 454, 745, 701, 144, 859, 402, 635, 45, 745, 557, + /* 1440 */ 329, 569, 745, 456, 87, 640, 591, 559, 746, 753, + /* 1450 */ 2, 702, 99, 479, 42, 43, 669, 418, 744, 743, + /* 1460 */ 457, 44, 748, 746, 353, 416, 746, 735, 746, 3, + /* 1470 */ 599, 445, 494, 65, 707, 745, 442, 746, 237, 717, + /* 1480 */ 455, 746, 744, 743, 720, 15, 924, 744, 743, 5, + /* 1490 */ 645, 707, 719, 718, 717, 744, 743, 338, 450, 493, + /* 1500 */ 492, 736, 746, 491, 746, 671, 299, 646, 219, 217, + /* 1510 */ 629, 675, 412, 634, 745, 701, 553, 479, 610, 745, + /* 1520 */ 45, 13, 645, 1179, 1179, 707, 463, 746, 347, 10, + /* 1530 */ 707, 746, 698, 716, 454, 746, 662, 42, 43, 381, + /* 1540 */ 632, 232, 627, 457, 44, 495, 1071, 456, 662, 745, + /* 1550 */ 744, 743, 3, 283, 445, 702, 191, 707, 625, 442, + /* 1560 */ 501, 745, 717, 455, 728, 744, 743, 720, 744, 743, + /* 1570 */ 744, 743, 115, 662, 707, 719, 718, 717, 624, 744, + /* 1580 */ 743, 450, 619, 744, 743, 746, 745, 734, 675, 235, + /* 1590 */ 746, 476, 501, 618, 286, 472, 590, 732, 701, 548, + /* 1600 */ 745, 540, 343, 45, 744, 743, 744, 743, 707, 671, + /* 1610 */ 745, 495, 10, 707, 342, 698, 548, 22, 540, 476, + /* 1620 */ 42, 43, 448, 472, 505, 457, 658, 44, 69, 744, + /* 1630 */ 743, 454, 464, 744, 743, 3, 445, 744, 743, 370, + /* 1640 */ 707, 505, 442, 87, 456, 717, 455, 242, 414, 464, + /* 1650 */ 720, 454, 702, 195, 454, 400, 68, 707, 719, 718, + /* 1660 */ 717, 454, 21, 450, 456, 299, 395, 456, 746, 67, + /* 1670 */ 236, 729, 702, 199, 456, 702, 197, 530, 745, 663, + /* 1680 */ 701, 725, 702, 205, 745, 45, 137, 744, 743, 391, + /* 1690 */ 292, 707, 744, 743, 745, 10, 707, 577, 698, 1072, + /* 1700 */ 346, 746, 42, 43, 570, 4, 671, 713, 457, 44, + /* 1710 */ 562, 746, 454, 164, 133, 31, 85, 3, 1074, 445, + /* 1720 */ 83, 30, 707, 29, 442, 456, 671, 717, 455, 671, + /* 1730 */ 28, 454, 720, 702, 203, 715, 671, 454, 746, 707, + /* 1740 */ 719, 718, 717, 454, 456, 341, 450, 675, 745, 746, + /* 1750 */ 456, 82, 702, 206, 454, 733, 456, 339, 702, 210, + /* 1760 */ 81, 454, 541, 701, 702, 244, 447, 456, 45, 542, + /* 1770 */ 744, 743, 372, 707, 456, 702, 309, 10, 707, 745, + /* 1780 */ 698, 664, 702, 202, 660, 42, 43, 671, 731, 270, + /* 1790 */ 457, 536, 44, 230, 745, 454, 529, 745, 531, 149, + /* 1800 */ 3, 445, 745, 744, 743, 707, 671, 442, 456, 713, + /* 1810 */ 717, 455, 671, 744, 743, 720, 702, 194, 671, 655, + /* 1820 */ 712, 454, 707, 719, 718, 717, 454, 89, 450, 671, + /* 1830 */ 523, 264, 745, 457, 456, 128, 671, 11, 261, 456, + /* 1840 */ 744, 743, 702, 180, 445, 701, 76, 702, 171, 160, + /* 1850 */ 45, 744, 743, 654, 169, 504, 707, 120, 481, 356, + /* 1860 */ 10, 707, 454, 698, 480, 103, 746, 42, 43, 462, + /* 1870 */ 671, 450, 596, 746, 44, 456, 216, 269, 642, 219, + /* 1880 */ 746, 268, 3, 702, 179, 234, 93, 707, 701, 442, + /* 1890 */ 745, 332, 744, 455, 212, 749, 671, 720, 331, 454, + /* 1900 */ 158, 671, 454, 739, 707, 719, 718, 717, 737, 258, + /* 1910 */ 42, 43, 456, 507, 256, 456, 738, 44, 503, 157, + /* 1920 */ 702, 193, 745, 702, 198, 3, 459, 745, 88, 713, + /* 1930 */ 707, 392, 442, 155, 18, 717, 455, 671, 707, 454, + /* 1940 */ 720, 454, 10, 707, 458, 698, 746, 707, 719, 718, + /* 1950 */ 717, 105, 456, 250, 456, 227, 746, 454, 142, 421, + /* 1960 */ 702, 327, 702, 326, 249, 153, 316, 730, 744, 743, + /* 1970 */ 456, 745, 745, 225, 671, 744, 743, 671, 702, 325, + /* 1980 */ 454, 707, 744, 743, 109, 10, 707, 313, 698, 243, + /* 1990 */ 454, 315, 156, 456, 622, 159, 454, 649, 87, 51, + /* 2000 */ 104, 702, 178, 456, 626, 35, 454, 700, 242, 456, + /* 2010 */ 745, 702, 100, 641, 671, 20, 671, 702, 177, 456, + /* 2020 */ 303, 299, 304, 454, 301, 454, 520, 702, 176, 430, + /* 2030 */ 454, 713, 671, 746, 745, 317, 456, 154, 456, 302, + /* 2040 */ 454, 39, 677, 456, 702, 174, 702, 173, 744, 743, + /* 2050 */ 432, 702, 192, 456, 454, 671, 345, 288, 744, 743, + /* 2060 */ 587, 702, 172, 746, 454, 671, 746, 456, 699, 454, + /* 2070 */ 745, 671, 746, 48, 330, 702, 200, 456, 439, 254, + /* 2080 */ 70, 671, 456, 499, 560, 702, 201, 238, 223, 252, + /* 2090 */ 702, 184, 745, 496, 597, 454, 746, 454, 671, 435, + /* 2100 */ 671, 454, 745, 675, 117, 671, 746, 745, 456, 118, + /* 2110 */ 456, 359, 454, 746, 456, 671, 702, 183, 702, 182, + /* 2120 */ 746, 417, 702, 181, 713, 456, 414, 454, 746, 671, + /* 2130 */ 454, 621, 454, 702, 185, 744, 743, 454, 746, 671, + /* 2140 */ 456, 746, 454, 456, 671, 456, 746, 141, 702, 188, + /* 2150 */ 456, 702, 101, 702, 187, 456, 746, 612, 702, 186, + /* 2160 */ 454, 746, 565, 702, 190, 744, 743, 454, 744, 743, + /* 2170 */ 671, 420, 671, 456, 744, 743, 671, 528, 746, 405, + /* 2180 */ 456, 702, 189, 746, 456, 607, 556, 671, 702, 175, + /* 2190 */ 578, 746, 702, 74, 746, 558, 746, 606, 744, 743, + /* 2200 */ 348, 282, 671, 745, 290, 671, 275, 671, 744, 743, + /* 2210 */ 552, 603, 671, 602, 745, 744, 743, 671, 601, 745, + /* 2220 */ 547, 576, 744, 743, 515, 246, 713, 518, 323, 335, + /* 2230 */ 744, 743, 366, 575, 506, 671, 583, 584, 745, 468, + /* 2240 */ 744, 743, 671, 744, 743, 745, 671, 574, 744, 743, + /* 2250 */ 136, 573, 745, 564, 86, 453, 295, 276, 744, 743, + /* 2260 */ 322, 135, 390, 744, 743, 385, 263, 502, 745, 745, + /* 2270 */ 745, 114, 134, 221, 467, 469, 260, 251, 745, 745, + /* 2280 */ 744, 743, 247, 500, 274, 744, 743, 672, 373, 745, + /* 2290 */ 745, 248, 388, 744, 743, 745, 744, 743, 744, 743, + /* 2300 */ 27, 132, 555, 113, 745, 84, 131, 130, 163, 497, + /* 2310 */ 90, 380, 379, 539, 545, 111, 129, 489, 367, 519, + /* 2320 */ 110, 127, 364, 80, 362, 126, 79, 125, 124, 78, + /* 2330 */ 77, 676, 123, 122, 26, 477, 336, 23, 475, 108, + /* 2340 */ 66, 107, 661, 471, 121, 465, 305, 170, 693, 689, + /* 2350 */ 679, 291, 451, 598, 399, 666, 207, 551, 656, 272, + /* 2360 */ 544, 386, 318, 711, 688, 7, 220, 33, 678, 585, + /* 2370 */ 306, 389, 449, 75, 595, 589, 588, 616, 615, 87, + /* 2380 */ 1187, 579, 1187, 513, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 4, 110, 111, 4, 81, 82, 83, 84, 85, 86, - /* 10 */ 87, 15, 72, 73, 74, 75, 76, 77, 78, 79, - /* 20 */ 80, 81, 82, 83, 84, 85, 86, 87, 4, 33, - /* 30 */ 34, 194, 195, 196, 72, 73, 74, 75, 42, 77, + /* 0 */ 4, 81, 82, 83, 84, 85, 86, 87, 51, 4, + /* 10 */ 53, 15, 72, 73, 74, 75, 76, 77, 78, 79, + /* 20 */ 80, 81, 82, 83, 84, 85, 86, 87, 193, 33, + /* 30 */ 34, 96, 4, 98, 72, 73, 74, 75, 42, 77, /* 40 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - /* 50 */ 89, 55, 124, 125, 126, 59, 33, 34, 62, 63, + /* 50 */ 97, 55, 95, 104, 4, 59, 107, 104, 62, 63, /* 60 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - /* 70 */ 74, 75, 104, 77, 78, 79, 80, 81, 82, 83, - /* 80 */ 84, 85, 86, 87, 88, 4, 185, 177, 4, 66, - /* 90 */ 67, 4, 96, 4, 97, 93, 15, 101, 261, 103, - /* 100 */ 190, 104, 106, 107, 105, 106, 107, 111, 109, 64, - /* 110 */ 142, 112, 113, 114, 118, 119, 120, 121, 5, 218, - /* 120 */ 219, 96, 4, 42, 83, 84, 85, 86, 87, 130, - /* 130 */ 106, 107, 87, 34, 138, 139, 51, 191, 53, 26, - /* 140 */ 59, 28, 118, 86, 87, 64, 245, 246, 152, 248, - /* 150 */ 154, 155, 123, 157, 109, 110, 111, 112, 113, 114, - /* 160 */ 115, 48, 81, 82, 83, 81, 82, 266, 267, 88, - /* 170 */ 89, 4, 143, 4, 129, 61, 152, 96, 97, 185, - /* 180 */ 95, 235, 101, 96, 103, 104, 276, 106, 107, 252, - /* 190 */ 106, 107, 111, 106, 110, 106, 107, 4, 252, 118, - /* 200 */ 119, 120, 121, 119, 120, 4, 269, 123, 177, 125, - /* 210 */ 96, 97, 218, 219, 4, 134, 15, 136, 137, 101, - /* 220 */ 0, 190, 123, 142, 106, 107, 195, 196, 147, 148, - /* 230 */ 149, 150, 151, 152, 97, 154, 155, 99, 157, 245, - /* 240 */ 246, 152, 248, 42, 4, 25, 161, 77, 78, 79, - /* 250 */ 80, 81, 82, 83, 84, 85, 86, 87, 205, 206, - /* 260 */ 59, 267, 19, 104, 106, 64, 213, 24, 101, 111, - /* 270 */ 101, 19, 29, 106, 107, 106, 107, 119, 120, 121, - /* 280 */ 162, 29, 81, 82, 117, 118, 23, 118, 61, 88, - /* 290 */ 89, 260, 261, 134, 101, 136, 137, 96, 97, 106, - /* 300 */ 107, 225, 101, 4, 103, 104, 96, 106, 107, 89, - /* 310 */ 234, 101, 111, 146, 45, 146, 106, 107, 55, 118, - /* 320 */ 119, 120, 121, 96, 97, 23, 177, 97, 118, 177, - /* 330 */ 99, 104, 33, 34, 104, 134, 96, 136, 137, 190, - /* 340 */ 99, 101, 190, 133, 195, 196, 106, 107, 147, 148, - /* 350 */ 149, 150, 89, 152, 135, 154, 155, 164, 157, 140, - /* 360 */ 4, 62, 63, 64, 65, 66, 67, 68, 69, 70, - /* 370 */ 71, 72, 73, 74, 75, 4, 77, 78, 79, 80, - /* 380 */ 81, 82, 83, 84, 85, 86, 87, 4, 50, 83, - /* 390 */ 4, 177, 54, 124, 125, 126, 182, 98, 15, 247, - /* 400 */ 186, 187, 177, 177, 190, 106, 99, 138, 139, 260, - /* 410 */ 261, 62, 63, 64, 65, 190, 190, 68, 69, 70, - /* 420 */ 71, 72, 73, 74, 75, 42, 77, 78, 79, 80, - /* 430 */ 81, 82, 83, 84, 85, 86, 87, 4, 89, 83, - /* 440 */ 141, 135, 59, 119, 120, 59, 140, 64, 177, 220, - /* 450 */ 221, 113, 223, 104, 109, 9, 7, 112, 113, 114, - /* 460 */ 11, 190, 106, 107, 81, 82, 20, 81, 82, 198, - /* 470 */ 199, 88, 89, 102, 118, 130, 4, 106, 107, 96, - /* 480 */ 97, 32, 96, 258, 101, 104, 103, 104, 107, 106, - /* 490 */ 107, 96, 106, 98, 111, 4, 111, 111, 58, 161, - /* 500 */ 151, 118, 119, 120, 121, 119, 120, 121, 152, 194, - /* 510 */ 195, 196, 172, 173, 33, 34, 97, 134, 96, 136, - /* 520 */ 137, 40, 251, 104, 253, 144, 145, 51, 177, 53, - /* 530 */ 147, 98, 149, 150, 104, 152, 185, 154, 155, 106, - /* 540 */ 157, 190, 104, 62, 63, 64, 65, 66, 67, 68, - /* 550 */ 69, 70, 71, 72, 73, 74, 75, 25, 77, 78, - /* 560 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 9, - /* 570 */ 219, 95, 100, 101, 141, 4, 261, 4, 106, 107, - /* 580 */ 20, 151, 4, 97, 4, 104, 97, 236, 237, 4, - /* 590 */ 104, 100, 101, 33, 34, 64, 65, 106, 107, 68, - /* 600 */ 69, 70, 71, 72, 73, 74, 75, 167, 77, 78, - /* 610 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 33, - /* 620 */ 34, 89, 62, 63, 64, 65, 66, 67, 68, 69, - /* 630 */ 70, 71, 72, 73, 74, 75, 96, 77, 78, 79, - /* 640 */ 80, 81, 82, 83, 84, 85, 86, 87, 62, 63, - /* 650 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - /* 660 */ 74, 75, 4, 77, 78, 79, 80, 81, 82, 83, - /* 670 */ 84, 85, 86, 87, 33, 34, 91, 106, 107, 106, - /* 680 */ 107, 101, 272, 273, 106, 107, 106, 107, 179, 116, - /* 690 */ 188, 106, 107, 191, 192, 193, 97, 158, 127, 160, - /* 700 */ 55, 43, 97, 62, 63, 64, 65, 66, 67, 68, - /* 710 */ 69, 70, 71, 72, 73, 74, 75, 12, 77, 78, - /* 720 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 62, - /* 730 */ 63, 64, 65, 97, 156, 68, 69, 70, 71, 72, - /* 740 */ 73, 74, 75, 163, 77, 78, 79, 80, 81, 82, - /* 750 */ 83, 84, 85, 86, 87, 110, 89, 97, 100, 170, - /* 760 */ 171, 172, 173, 61, 106, 107, 257, 62, 63, 64, - /* 770 */ 65, 104, 61, 68, 69, 70, 71, 72, 73, 74, - /* 780 */ 75, 96, 77, 78, 79, 80, 81, 82, 83, 84, - /* 790 */ 85, 86, 87, 97, 89, 38, 4, 111, 96, 97, - /* 800 */ 104, 4, 124, 125, 126, 191, 104, 96, 97, 197, - /* 810 */ 177, 4, 81, 82, 181, 129, 4, 205, 151, 62, - /* 820 */ 63, 64, 65, 190, 4, 68, 69, 70, 71, 72, - /* 830 */ 73, 74, 75, 97, 77, 78, 79, 80, 81, 82, - /* 840 */ 83, 84, 85, 86, 87, 4, 89, 55, 4, 235, - /* 850 */ 119, 120, 62, 63, 64, 65, 15, 104, 68, 69, - /* 860 */ 70, 71, 72, 73, 74, 75, 201, 77, 78, 79, - /* 870 */ 80, 81, 82, 83, 84, 85, 86, 87, 190, 104, - /* 880 */ 4, 138, 139, 42, 71, 4, 198, 98, 96, 97, - /* 890 */ 169, 220, 221, 101, 223, 174, 55, 122, 106, 107, - /* 900 */ 59, 97, 177, 106, 107, 64, 185, 100, 104, 96, - /* 910 */ 118, 186, 187, 106, 107, 190, 96, 252, 106, 107, - /* 920 */ 249, 101, 81, 82, 96, 133, 106, 107, 97, 88, - /* 930 */ 138, 139, 4, 177, 209, 5, 211, 96, 118, 218, - /* 940 */ 219, 177, 101, 146, 103, 101, 190, 106, 107, 159, - /* 950 */ 106, 107, 111, 133, 190, 185, 26, 30, 28, 118, - /* 960 */ 119, 120, 121, 177, 144, 145, 245, 246, 177, 248, - /* 970 */ 191, 55, 91, 177, 162, 45, 190, 101, 48, 138, - /* 980 */ 139, 190, 106, 107, 198, 199, 190, 106, 107, 219, - /* 990 */ 146, 64, 271, 152, 118, 154, 155, 97, 157, 98, - /* 1000 */ 62, 63, 64, 65, 104, 89, 68, 69, 70, 71, - /* 1010 */ 72, 73, 74, 75, 235, 77, 78, 79, 80, 81, - /* 1020 */ 82, 83, 84, 85, 86, 87, 4, 236, 237, 4, - /* 1030 */ 244, 191, 192, 193, 106, 107, 98, 251, 34, 243, - /* 1040 */ 276, 97, 62, 63, 64, 65, 118, 201, 68, 69, - /* 1050 */ 70, 71, 72, 73, 74, 75, 96, 77, 78, 79, - /* 1060 */ 80, 81, 82, 83, 84, 85, 86, 87, 64, 62, - /* 1070 */ 63, 64, 65, 13, 146, 68, 69, 70, 71, 72, - /* 1080 */ 73, 74, 75, 177, 77, 78, 79, 80, 81, 82, - /* 1090 */ 83, 84, 85, 86, 87, 104, 190, 13, 252, 62, - /* 1100 */ 63, 64, 65, 104, 97, 68, 69, 70, 71, 72, - /* 1110 */ 73, 74, 75, 91, 77, 78, 79, 80, 81, 82, - /* 1120 */ 83, 84, 85, 86, 87, 96, 13, 123, 106, 107, - /* 1130 */ 185, 106, 107, 129, 97, 62, 63, 64, 65, 159, - /* 1140 */ 30, 68, 69, 70, 71, 72, 73, 74, 75, 243, - /* 1150 */ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - /* 1160 */ 87, 185, 4, 97, 219, 62, 63, 64, 65, 144, - /* 1170 */ 97, 68, 69, 70, 71, 72, 73, 74, 75, 177, - /* 1180 */ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - /* 1190 */ 87, 97, 190, 185, 144, 219, 99, 62, 63, 64, - /* 1200 */ 65, 98, 83, 68, 69, 70, 71, 72, 73, 74, - /* 1210 */ 75, 99, 77, 78, 79, 80, 81, 82, 83, 84, - /* 1220 */ 85, 86, 87, 185, 89, 97, 4, 219, 62, 63, - /* 1230 */ 64, 65, 104, 104, 68, 69, 70, 71, 72, 73, - /* 1240 */ 74, 75, 96, 77, 78, 79, 80, 81, 82, 83, - /* 1250 */ 84, 85, 86, 87, 4, 89, 97, 219, 4, 101, - /* 1260 */ 62, 63, 64, 65, 106, 107, 68, 69, 70, 71, - /* 1270 */ 72, 73, 74, 75, 4, 77, 78, 79, 80, 81, - /* 1280 */ 82, 83, 84, 85, 86, 87, 4, 62, 63, 64, - /* 1290 */ 65, 133, 4, 68, 69, 70, 71, 72, 73, 74, - /* 1300 */ 75, 177, 77, 78, 79, 80, 81, 82, 83, 84, - /* 1310 */ 85, 86, 87, 4, 190, 97, 185, 135, 158, 96, - /* 1320 */ 17, 191, 104, 101, 15, 63, 64, 65, 106, 107, - /* 1330 */ 68, 69, 70, 71, 72, 73, 74, 75, 38, 77, + /* 70 */ 74, 75, 237, 77, 78, 79, 80, 81, 82, 83, + /* 80 */ 84, 85, 86, 87, 88, 4, 83, 84, 85, 86, + /* 90 */ 87, 4, 96, 144, 145, 106, 15, 101, 89, 103, + /* 100 */ 111, 96, 106, 107, 111, 179, 101, 111, 119, 120, + /* 110 */ 121, 106, 107, 187, 118, 119, 120, 121, 192, 4, + /* 120 */ 179, 97, 129, 42, 96, 179, 200, 201, 104, 101, + /* 130 */ 134, 135, 97, 192, 106, 107, 126, 179, 192, 104, + /* 140 */ 59, 200, 201, 197, 198, 64, 118, 221, 152, 23, + /* 150 */ 192, 101, 156, 157, 193, 159, 106, 107, 200, 201, + /* 160 */ 234, 133, 81, 82, 83, 155, 179, 117, 118, 88, + /* 170 */ 89, 137, 144, 145, 140, 234, 235, 96, 97, 192, + /* 180 */ 254, 55, 101, 4, 103, 104, 109, 106, 107, 112, + /* 190 */ 113, 114, 111, 106, 107, 254, 146, 4, 237, 118, + /* 200 */ 119, 120, 121, 116, 123, 179, 34, 130, 15, 263, + /* 210 */ 264, 96, 254, 64, 256, 89, 255, 136, 192, 138, + /* 220 */ 139, 106, 107, 142, 4, 227, 200, 201, 147, 148, + /* 230 */ 149, 150, 151, 152, 236, 42, 87, 156, 157, 93, + /* 240 */ 159, 77, 78, 79, 80, 81, 82, 83, 84, 85, + /* 250 */ 86, 87, 59, 30, 4, 179, 4, 64, 109, 110, + /* 260 */ 111, 112, 113, 114, 115, 97, 279, 152, 192, 124, + /* 270 */ 125, 126, 246, 104, 81, 82, 200, 201, 129, 4, + /* 280 */ 254, 88, 89, 4, 105, 106, 107, 64, 109, 96, + /* 290 */ 97, 112, 113, 114, 101, 123, 103, 104, 61, 106, + /* 300 */ 107, 110, 111, 187, 111, 136, 104, 138, 139, 130, + /* 310 */ 234, 118, 119, 120, 121, 50, 123, 4, 61, 54, + /* 320 */ 100, 101, 124, 125, 126, 4, 106, 107, 15, 136, + /* 330 */ 254, 138, 139, 96, 97, 83, 220, 221, 59, 96, + /* 340 */ 147, 148, 149, 150, 142, 152, 96, 154, 5, 156, + /* 350 */ 157, 101, 159, 96, 97, 42, 106, 107, 106, 107, + /* 360 */ 81, 82, 7, 247, 248, 4, 11, 251, 118, 26, + /* 370 */ 118, 28, 59, 86, 87, 96, 101, 64, 113, 33, + /* 380 */ 34, 106, 107, 133, 179, 106, 270, 32, 45, 97, + /* 390 */ 111, 48, 187, 118, 81, 82, 104, 192, 119, 120, + /* 400 */ 121, 88, 89, 4, 152, 200, 201, 58, 19, 96, + /* 410 */ 97, 61, 66, 67, 101, 4, 103, 104, 29, 106, + /* 420 */ 107, 146, 45, 99, 111, 19, 221, 106, 163, 108, + /* 430 */ 24, 118, 119, 120, 121, 29, 123, 179, 190, 234, + /* 440 */ 235, 193, 194, 195, 33, 34, 96, 97, 179, 136, + /* 450 */ 192, 138, 139, 179, 104, 197, 198, 96, 96, 254, + /* 460 */ 147, 192, 149, 150, 97, 152, 192, 106, 107, 156, + /* 470 */ 157, 104, 159, 62, 63, 64, 65, 66, 67, 68, + /* 480 */ 69, 70, 71, 72, 73, 74, 75, 255, 77, 78, + /* 490 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 100, + /* 500 */ 101, 124, 125, 126, 272, 106, 107, 238, 239, 98, + /* 510 */ 179, 134, 135, 152, 99, 184, 154, 106, 169, 188, + /* 520 */ 189, 263, 264, 192, 33, 34, 62, 63, 64, 65, + /* 530 */ 99, 40, 68, 69, 70, 71, 72, 73, 74, 75, + /* 540 */ 83, 77, 78, 79, 80, 81, 82, 83, 84, 85, + /* 550 */ 86, 87, 141, 62, 63, 64, 65, 66, 67, 68, + /* 560 */ 69, 70, 71, 72, 73, 74, 75, 181, 77, 78, + /* 570 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 9, + /* 580 */ 193, 194, 195, 179, 172, 173, 174, 175, 81, 82, + /* 590 */ 20, 97, 188, 189, 137, 104, 192, 140, 104, 62, + /* 600 */ 63, 64, 65, 33, 34, 68, 69, 70, 71, 72, + /* 610 */ 73, 74, 75, 104, 77, 78, 79, 80, 81, 82, + /* 620 */ 83, 84, 85, 86, 87, 161, 119, 120, 99, 33, + /* 630 */ 34, 122, 62, 63, 64, 65, 66, 67, 68, 69, + /* 640 */ 70, 71, 72, 73, 74, 75, 260, 77, 78, 79, + /* 650 */ 80, 81, 82, 83, 84, 85, 86, 87, 62, 63, + /* 660 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + /* 670 */ 74, 75, 4, 77, 78, 79, 80, 81, 82, 83, + /* 680 */ 84, 85, 86, 87, 33, 34, 64, 65, 119, 120, + /* 690 */ 68, 69, 70, 71, 72, 73, 74, 75, 161, 77, + /* 700 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 710 */ 4, 43, 111, 62, 63, 64, 65, 66, 67, 68, + /* 720 */ 69, 70, 71, 72, 73, 74, 75, 23, 77, 78, + /* 730 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 62, + /* 740 */ 63, 64, 65, 4, 96, 68, 69, 70, 71, 72, + /* 750 */ 73, 74, 75, 104, 77, 78, 79, 80, 81, 82, + /* 760 */ 83, 84, 85, 86, 87, 193, 89, 51, 100, 53, + /* 770 */ 61, 160, 97, 162, 106, 107, 62, 63, 64, 65, + /* 780 */ 4, 104, 68, 69, 70, 71, 72, 73, 74, 75, + /* 790 */ 104, 77, 78, 79, 80, 81, 82, 83, 84, 85, + /* 800 */ 86, 87, 96, 89, 98, 96, 97, 222, 223, 237, + /* 810 */ 225, 95, 106, 104, 62, 63, 64, 65, 104, 71, + /* 820 */ 68, 69, 70, 71, 72, 73, 74, 75, 151, 77, + /* 830 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 840 */ 101, 89, 179, 97, 96, 106, 107, 141, 12, 98, + /* 850 */ 104, 62, 63, 64, 65, 192, 104, 68, 69, 70, + /* 860 */ 71, 72, 73, 74, 75, 151, 77, 78, 79, 80, + /* 870 */ 81, 82, 83, 84, 85, 86, 87, 101, 89, 163, + /* 880 */ 275, 276, 106, 107, 179, 146, 193, 196, 197, 198, + /* 890 */ 196, 197, 198, 104, 118, 4, 97, 192, 62, 63, + /* 900 */ 64, 65, 38, 151, 68, 69, 70, 71, 72, 73, + /* 910 */ 74, 75, 104, 77, 78, 79, 80, 81, 82, 83, + /* 920 */ 84, 85, 86, 87, 261, 89, 62, 63, 64, 65, + /* 930 */ 237, 4, 68, 69, 70, 71, 72, 73, 74, 75, + /* 940 */ 151, 77, 78, 79, 80, 81, 82, 83, 84, 85, + /* 950 */ 86, 87, 4, 89, 249, 264, 97, 187, 264, 151, + /* 960 */ 207, 208, 96, 15, 62, 63, 64, 65, 215, 34, + /* 970 */ 68, 69, 70, 71, 72, 73, 74, 75, 4, 77, + /* 980 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 990 */ 42, 221, 4, 123, 4, 97, 105, 106, 107, 64, + /* 1000 */ 98, 179, 179, 55, 179, 97, 179, 59, 81, 82, + /* 1010 */ 0, 179, 64, 143, 192, 192, 96, 192, 179, 192, + /* 1020 */ 188, 189, 200, 201, 192, 200, 201, 187, 179, 81, + /* 1030 */ 82, 192, 183, 106, 107, 25, 88, 110, 97, 200, + /* 1040 */ 201, 192, 5, 211, 96, 213, 119, 120, 4, 101, + /* 1050 */ 123, 103, 125, 96, 106, 107, 234, 235, 123, 111, + /* 1060 */ 220, 221, 55, 26, 129, 28, 118, 119, 120, 121, + /* 1070 */ 97, 246, 245, 234, 235, 101, 254, 104, 97, 254, + /* 1080 */ 106, 107, 134, 135, 179, 48, 96, 247, 248, 4, + /* 1090 */ 179, 251, 187, 254, 106, 107, 106, 192, 179, 89, + /* 1100 */ 152, 97, 279, 192, 156, 157, 118, 159, 104, 269, + /* 1110 */ 270, 192, 62, 63, 64, 65, 98, 110, 68, 69, + /* 1120 */ 70, 71, 72, 73, 74, 75, 221, 77, 78, 79, + /* 1130 */ 80, 81, 82, 83, 84, 85, 86, 87, 164, 96, + /* 1140 */ 152, 179, 9, 238, 239, 179, 179, 97, 179, 183, + /* 1150 */ 106, 107, 183, 20, 192, 187, 4, 97, 192, 192, + /* 1160 */ 249, 192, 118, 62, 63, 64, 65, 200, 201, 68, + /* 1170 */ 69, 70, 71, 72, 73, 74, 75, 133, 77, 78, + /* 1180 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 221, + /* 1190 */ 97, 106, 107, 62, 63, 64, 65, 104, 97, 68, + /* 1200 */ 69, 70, 71, 72, 73, 74, 75, 245, 77, 78, + /* 1210 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 13, + /* 1220 */ 4, 254, 187, 187, 104, 199, 141, 97, 97, 62, + /* 1230 */ 63, 64, 65, 207, 104, 68, 69, 70, 71, 72, + /* 1240 */ 73, 74, 75, 91, 77, 78, 79, 80, 81, 82, + /* 1250 */ 83, 84, 85, 86, 87, 13, 221, 221, 106, 107, + /* 1260 */ 104, 62, 63, 64, 65, 98, 96, 68, 69, 70, + /* 1270 */ 71, 72, 73, 74, 75, 30, 77, 78, 79, 80, + /* 1280 */ 81, 82, 83, 84, 85, 86, 87, 187, 89, 97, + /* 1290 */ 4, 62, 63, 64, 65, 187, 104, 68, 69, 70, + /* 1300 */ 71, 72, 73, 74, 75, 13, 77, 78, 79, 80, + /* 1310 */ 81, 82, 83, 84, 85, 86, 87, 101, 89, 4, + /* 1320 */ 192, 221, 106, 107, 62, 63, 64, 65, 200, 221, + /* 1330 */ 68, 69, 70, 71, 72, 73, 74, 75, 97, 77, /* 1340 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - /* 1350 */ 219, 42, 4, 214, 132, 216, 106, 107, 177, 96, - /* 1360 */ 106, 107, 177, 4, 177, 235, 185, 243, 59, 6, - /* 1370 */ 185, 190, 118, 64, 97, 190, 106, 190, 108, 198, - /* 1380 */ 199, 104, 4, 198, 199, 198, 199, 133, 106, 101, - /* 1390 */ 81, 82, 97, 97, 106, 107, 4, 88, 177, 117, - /* 1400 */ 219, 97, 152, 97, 219, 96, 97, 15, 104, 97, - /* 1410 */ 101, 190, 103, 232, 233, 106, 107, 232, 177, 232, - /* 1420 */ 111, 214, 177, 216, 4, 96, 177, 118, 119, 120, - /* 1430 */ 121, 190, 251, 4, 42, 190, 251, 14, 251, 190, - /* 1440 */ 4, 97, 38, 198, 199, 96, 177, 198, 199, 177, - /* 1450 */ 97, 59, 96, 165, 106, 107, 64, 38, 35, 190, - /* 1460 */ 4, 152, 190, 154, 155, 106, 157, 198, 199, 46, - /* 1470 */ 198, 199, 4, 81, 82, 96, 117, 232, 233, 4, - /* 1480 */ 88, 232, 233, 115, 106, 107, 4, 129, 96, 97, - /* 1490 */ 15, 64, 144, 101, 177, 103, 251, 103, 106, 107, - /* 1500 */ 251, 232, 12, 111, 4, 177, 4, 190, 98, 177, - /* 1510 */ 118, 119, 120, 121, 186, 187, 244, 42, 190, 141, - /* 1520 */ 251, 4, 190, 251, 123, 142, 106, 107, 177, 71, - /* 1530 */ 71, 128, 139, 153, 59, 106, 107, 101, 118, 64, - /* 1540 */ 4, 190, 106, 107, 152, 116, 154, 155, 4, 157, - /* 1550 */ 89, 128, 177, 89, 118, 22, 81, 82, 47, 91, - /* 1560 */ 39, 4, 106, 88, 177, 190, 146, 177, 181, 237, - /* 1570 */ 104, 96, 15, 117, 106, 107, 101, 190, 103, 177, - /* 1580 */ 190, 106, 107, 101, 177, 177, 111, 4, 106, 107, - /* 1590 */ 39, 177, 190, 118, 119, 120, 121, 190, 190, 42, - /* 1600 */ 118, 101, 212, 101, 190, 161, 106, 107, 106, 107, - /* 1610 */ 123, 103, 198, 199, 95, 177, 59, 4, 118, 181, - /* 1620 */ 118, 64, 4, 106, 107, 96, 143, 152, 190, 154, - /* 1630 */ 155, 96, 157, 158, 177, 118, 97, 97, 81, 82, - /* 1640 */ 95, 93, 106, 107, 4, 88, 177, 190, 258, 177, - /* 1650 */ 106, 107, 37, 96, 97, 15, 36, 252, 101, 190, - /* 1660 */ 103, 273, 190, 106, 107, 251, 177, 189, 111, 212, - /* 1670 */ 198, 199, 177, 4, 204, 118, 119, 120, 121, 190, - /* 1680 */ 4, 177, 42, 238, 204, 190, 4, 198, 199, 106, - /* 1690 */ 107, 275, 177, 177, 190, 177, 152, 181, 176, 59, - /* 1700 */ 164, 118, 198, 199, 64, 190, 190, 275, 190, 152, - /* 1710 */ 176, 154, 155, 4, 157, 258, 198, 199, 100, 106, - /* 1720 */ 107, 81, 82, 251, 106, 107, 4, 90, 88, 177, - /* 1730 */ 176, 118, 177, 4, 178, 177, 96, 15, 49, 177, - /* 1740 */ 251, 101, 190, 103, 176, 190, 106, 107, 190, 177, - /* 1750 */ 177, 111, 190, 198, 199, 251, 198, 199, 118, 119, - /* 1760 */ 120, 121, 190, 190, 42, 177, 177, 177, 60, 251, - /* 1770 */ 181, 198, 199, 178, 212, 106, 107, 177, 190, 190, - /* 1780 */ 190, 59, 106, 107, 212, 180, 64, 183, 106, 107, - /* 1790 */ 190, 104, 152, 184, 154, 155, 64, 157, 198, 199, - /* 1800 */ 118, 132, 56, 81, 82, 87, 251, 254, 4, 251, - /* 1810 */ 88, 252, 221, 177, 158, 106, 107, 181, 96, 15, - /* 1820 */ 258, 177, 146, 101, 251, 103, 190, 118, 106, 107, - /* 1830 */ 258, 177, 177, 111, 190, 106, 107, 177, 138, 227, - /* 1840 */ 118, 119, 120, 121, 190, 190, 42, 118, 177, 151, - /* 1850 */ 190, 251, 181, 198, 199, 8, 228, 10, 177, 12, - /* 1860 */ 177, 190, 181, 59, 4, 177, 149, 148, 21, 181, - /* 1870 */ 23, 190, 229, 190, 152, 230, 154, 155, 190, 157, - /* 1880 */ 177, 198, 199, 231, 181, 81, 82, 203, 41, 150, - /* 1890 */ 4, 44, 88, 190, 147, 48, 49, 96, 259, 52, - /* 1900 */ 96, 87, 55, 177, 57, 101, 251, 103, 203, 241, - /* 1910 */ 106, 107, 4, 177, 177, 111, 190, 177, 99, 177, - /* 1920 */ 223, 139, 118, 119, 120, 121, 190, 190, 200, 177, - /* 1930 */ 190, 177, 190, 177, 251, 198, 199, 241, 99, 92, - /* 1940 */ 4, 94, 190, 123, 190, 200, 190, 177, 200, 177, - /* 1950 */ 198, 199, 198, 199, 198, 199, 152, 208, 154, 155, - /* 1960 */ 190, 157, 190, 31, 177, 202, 106, 107, 198, 199, - /* 1970 */ 198, 199, 4, 122, 4, 200, 177, 190, 131, 203, - /* 1980 */ 200, 208, 177, 200, 200, 198, 199, 177, 251, 190, - /* 1990 */ 200, 203, 106, 107, 241, 190, 99, 198, 199, 177, - /* 2000 */ 190, 180, 99, 251, 118, 251, 177, 251, 198, 199, - /* 2010 */ 203, 177, 190, 166, 106, 107, 4, 180, 177, 190, - /* 2020 */ 241, 251, 264, 251, 190, 165, 118, 198, 199, 99, - /* 2030 */ 4, 190, 198, 199, 27, 177, 177, 158, 251, 198, - /* 2040 */ 199, 177, 106, 107, 99, 227, 177, 177, 190, 190, - /* 2050 */ 251, 177, 177, 215, 190, 62, 198, 199, 177, 190, - /* 2060 */ 190, 251, 198, 199, 190, 190, 177, 198, 199, 177, - /* 2070 */ 96, 190, 198, 199, 106, 107, 106, 107, 4, 190, - /* 2080 */ 251, 4, 190, 177, 99, 251, 118, 198, 199, 177, - /* 2090 */ 198, 199, 251, 177, 177, 265, 190, 4, 99, 163, - /* 2100 */ 177, 4, 190, 133, 198, 199, 190, 190, 4, 251, - /* 2110 */ 198, 199, 100, 190, 177, 251, 250, 177, 106, 107, - /* 2120 */ 251, 198, 199, 4, 177, 251, 215, 190, 177, 177, - /* 2130 */ 190, 177, 106, 107, 177, 198, 199, 190, 198, 199, - /* 2140 */ 251, 190, 190, 251, 190, 198, 199, 190, 177, 198, - /* 2150 */ 199, 241, 198, 199, 177, 198, 199, 251, 180, 99, - /* 2160 */ 227, 190, 180, 251, 177, 241, 99, 190, 60, 198, - /* 2170 */ 199, 99, 217, 217, 251, 198, 199, 190, 152, 99, - /* 2180 */ 106, 107, 217, 106, 107, 198, 199, 99, 251, 217, - /* 2190 */ 99, 251, 118, 100, 241, 99, 177, 268, 251, 106, - /* 2200 */ 107, 18, 251, 106, 107, 251, 268, 241, 251, 190, - /* 2210 */ 106, 107, 99, 99, 241, 99, 270, 198, 199, 16, - /* 2220 */ 224, 226, 251, 261, 105, 106, 107, 206, 251, 152, - /* 2230 */ 255, 201, 240, 242, 201, 210, 202, 261, 251, 242, - /* 2240 */ 242, 227, 224, 175, 191, 191, 191, 191, 262, 152, - /* 2250 */ 256, 263, 216, 222, 239, 207, 207, 207, 274, 198, - /* 2260 */ 198, 55, 211, 277, 277, 277, 277, 277, 277, 277, - /* 2270 */ 251, + /* 1350 */ 203, 62, 63, 64, 65, 25, 4, 68, 69, 70, + /* 1360 */ 71, 72, 73, 74, 75, 179, 77, 78, 79, 80, + /* 1370 */ 81, 82, 83, 84, 85, 86, 87, 4, 192, 216, + /* 1380 */ 4, 218, 166, 99, 98, 4, 200, 201, 15, 63, + /* 1390 */ 64, 65, 106, 4, 68, 69, 70, 71, 72, 73, + /* 1400 */ 74, 75, 255, 77, 78, 79, 80, 81, 82, 83, + /* 1410 */ 84, 85, 86, 87, 14, 42, 101, 97, 179, 89, + /* 1420 */ 234, 106, 107, 171, 104, 179, 97, 141, 176, 179, + /* 1430 */ 179, 192, 59, 97, 97, 35, 83, 64, 192, 187, + /* 1440 */ 254, 104, 192, 192, 55, 144, 46, 132, 4, 174, + /* 1450 */ 175, 200, 201, 101, 81, 82, 203, 99, 106, 107, + /* 1460 */ 4, 88, 179, 4, 214, 104, 4, 91, 4, 96, + /* 1470 */ 97, 15, 220, 221, 101, 192, 103, 4, 239, 106, + /* 1480 */ 107, 4, 106, 107, 111, 96, 97, 106, 107, 96, + /* 1490 */ 101, 118, 119, 120, 121, 106, 107, 246, 42, 247, + /* 1500 */ 248, 179, 4, 251, 4, 254, 179, 118, 255, 222, + /* 1510 */ 223, 261, 225, 97, 192, 59, 216, 165, 218, 192, + /* 1520 */ 64, 96, 133, 134, 135, 152, 274, 4, 128, 156, + /* 1530 */ 157, 4, 159, 152, 179, 4, 179, 81, 82, 252, + /* 1540 */ 137, 214, 97, 4, 88, 101, 160, 192, 179, 192, + /* 1550 */ 106, 107, 96, 97, 15, 200, 201, 101, 97, 103, + /* 1560 */ 101, 192, 106, 107, 102, 106, 107, 111, 106, 107, + /* 1570 */ 106, 107, 17, 179, 118, 119, 120, 121, 97, 106, + /* 1580 */ 107, 42, 97, 106, 107, 4, 192, 179, 261, 38, + /* 1590 */ 4, 118, 133, 97, 97, 118, 6, 179, 59, 101, + /* 1600 */ 192, 101, 245, 64, 106, 107, 106, 107, 152, 254, + /* 1610 */ 192, 167, 156, 157, 245, 159, 118, 96, 118, 146, + /* 1620 */ 81, 82, 158, 146, 101, 4, 193, 88, 96, 106, + /* 1630 */ 107, 179, 101, 106, 107, 96, 15, 106, 107, 245, + /* 1640 */ 101, 118, 103, 55, 192, 106, 107, 134, 135, 118, + /* 1650 */ 111, 179, 200, 201, 179, 38, 96, 118, 119, 120, + /* 1660 */ 121, 179, 96, 42, 192, 179, 38, 192, 4, 96, + /* 1670 */ 237, 179, 200, 201, 192, 200, 201, 89, 192, 152, + /* 1680 */ 59, 179, 200, 201, 192, 64, 115, 106, 107, 64, + /* 1690 */ 129, 152, 106, 107, 192, 156, 157, 116, 159, 160, + /* 1700 */ 214, 4, 81, 82, 118, 12, 254, 4, 4, 88, + /* 1710 */ 103, 4, 179, 98, 123, 71, 142, 96, 97, 15, + /* 1720 */ 128, 71, 101, 71, 103, 192, 254, 106, 107, 254, + /* 1730 */ 71, 179, 111, 200, 201, 179, 254, 179, 4, 118, + /* 1740 */ 119, 120, 121, 179, 192, 17, 42, 261, 192, 4, + /* 1750 */ 192, 153, 200, 201, 179, 91, 192, 154, 200, 201, + /* 1760 */ 128, 179, 135, 59, 200, 201, 179, 192, 64, 155, + /* 1770 */ 106, 107, 22, 152, 192, 200, 201, 156, 157, 192, + /* 1780 */ 159, 179, 200, 201, 179, 81, 82, 254, 91, 179, + /* 1790 */ 4, 89, 88, 183, 192, 179, 47, 192, 89, 104, + /* 1800 */ 96, 15, 192, 106, 107, 101, 254, 103, 192, 106, + /* 1810 */ 106, 107, 254, 106, 107, 111, 200, 201, 254, 179, + /* 1820 */ 117, 179, 118, 119, 120, 121, 179, 39, 42, 254, + /* 1830 */ 39, 163, 192, 4, 192, 123, 254, 96, 95, 192, + /* 1840 */ 106, 107, 200, 201, 15, 59, 95, 200, 201, 143, + /* 1850 */ 64, 106, 107, 146, 96, 103, 152, 93, 97, 37, + /* 1860 */ 156, 157, 179, 159, 97, 191, 4, 81, 82, 36, + /* 1870 */ 254, 42, 127, 4, 88, 192, 240, 179, 144, 255, + /* 1880 */ 4, 183, 96, 200, 201, 206, 206, 101, 59, 103, + /* 1890 */ 192, 278, 106, 107, 276, 178, 254, 111, 278, 179, + /* 1900 */ 90, 254, 179, 178, 118, 119, 120, 121, 49, 179, + /* 1910 */ 81, 82, 192, 183, 179, 192, 178, 88, 183, 180, + /* 1920 */ 200, 201, 192, 200, 201, 96, 178, 192, 182, 4, + /* 1930 */ 101, 60, 103, 180, 104, 106, 107, 254, 152, 179, + /* 1940 */ 111, 179, 156, 157, 185, 159, 4, 118, 119, 120, + /* 1950 */ 121, 8, 192, 10, 192, 12, 4, 179, 179, 179, + /* 1960 */ 200, 201, 200, 201, 21, 56, 23, 186, 106, 107, + /* 1970 */ 192, 192, 192, 87, 254, 106, 107, 254, 200, 201, + /* 1980 */ 179, 152, 106, 107, 41, 156, 157, 44, 159, 257, + /* 1990 */ 179, 48, 49, 192, 118, 52, 179, 179, 55, 255, + /* 2000 */ 57, 200, 201, 192, 64, 160, 179, 223, 134, 192, + /* 2010 */ 192, 200, 201, 144, 254, 151, 254, 200, 201, 192, + /* 2020 */ 230, 179, 229, 179, 232, 179, 164, 200, 201, 148, + /* 2030 */ 179, 106, 254, 4, 192, 92, 192, 94, 192, 231, + /* 2040 */ 179, 149, 117, 192, 200, 201, 200, 201, 106, 107, + /* 2050 */ 147, 200, 201, 192, 179, 254, 214, 179, 106, 107, + /* 2060 */ 118, 200, 201, 4, 179, 254, 4, 192, 233, 179, + /* 2070 */ 192, 254, 4, 150, 131, 200, 201, 192, 205, 179, + /* 2080 */ 96, 254, 192, 183, 132, 200, 201, 262, 87, 179, + /* 2090 */ 200, 201, 192, 183, 179, 179, 4, 179, 254, 205, + /* 2100 */ 254, 179, 192, 261, 99, 254, 4, 192, 192, 243, + /* 2110 */ 192, 168, 179, 4, 192, 254, 200, 201, 200, 201, + /* 2120 */ 4, 225, 200, 201, 4, 192, 135, 179, 4, 254, + /* 2130 */ 179, 243, 179, 200, 201, 106, 107, 179, 4, 254, + /* 2140 */ 192, 4, 179, 192, 254, 192, 4, 99, 200, 201, + /* 2150 */ 192, 200, 201, 200, 201, 192, 4, 202, 200, 201, + /* 2160 */ 179, 4, 100, 200, 201, 106, 107, 179, 106, 107, + /* 2170 */ 254, 179, 254, 192, 106, 107, 254, 118, 4, 123, + /* 2180 */ 192, 200, 201, 4, 192, 202, 118, 254, 200, 201, + /* 2190 */ 179, 4, 200, 201, 4, 166, 4, 210, 106, 107, + /* 2200 */ 31, 179, 254, 192, 202, 254, 179, 254, 106, 107, + /* 2210 */ 118, 204, 254, 122, 192, 106, 107, 254, 202, 192, + /* 2220 */ 118, 202, 106, 107, 100, 179, 106, 118, 205, 183, + /* 2230 */ 106, 107, 179, 202, 118, 254, 210, 117, 192, 179, + /* 2240 */ 106, 107, 254, 106, 107, 192, 254, 202, 106, 107, + /* 2250 */ 99, 202, 192, 243, 182, 179, 179, 179, 106, 107, + /* 2260 */ 205, 99, 205, 106, 107, 179, 179, 133, 192, 192, + /* 2270 */ 192, 182, 99, 243, 100, 118, 179, 179, 192, 192, + /* 2280 */ 106, 107, 179, 146, 267, 106, 107, 100, 27, 192, + /* 2290 */ 192, 179, 268, 106, 107, 192, 106, 107, 106, 107, + /* 2300 */ 160, 99, 229, 62, 192, 217, 99, 99, 250, 167, + /* 2310 */ 96, 123, 229, 217, 253, 182, 99, 165, 243, 229, + /* 2320 */ 182, 99, 243, 219, 60, 99, 219, 99, 99, 219, + /* 2330 */ 219, 152, 99, 99, 271, 18, 243, 271, 243, 99, + /* 2340 */ 273, 99, 152, 243, 99, 16, 228, 226, 264, 264, + /* 2350 */ 203, 203, 258, 208, 204, 242, 212, 229, 244, 244, + /* 2360 */ 229, 244, 177, 193, 193, 226, 265, 259, 193, 193, + /* 2370 */ 224, 266, 218, 241, 209, 209, 209, 200, 200, 55, + /* 2380 */ 280, 213, 280, 277, }; -#define YY_SHIFT_USE_DFLT (-110) -#define YY_SHIFT_COUNT (435) -#define YY_SHIFT_MIN (-109) -#define YY_SHIFT_MAX (2206) +#define YY_SHIFT_USE_DFLT (-81) +#define YY_SHIFT_COUNT (460) +#define YY_SHIFT_MIN (-80) +#define YY_SHIFT_MAX (2329) static const short yy_shift_ofst[] = { - /* 0 */ 532, -4, 1847, 841, 916, 1557, 1557, 263, 383, 1475, - /* 10 */ 1722, 1640, 1640, 792, 84, 84, -1, 81, 201, 1392, - /* 20 */ 1309, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, - /* 30 */ 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, - /* 40 */ 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, - /* 50 */ 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1804, 2119, - /* 60 */ 820, 269, 2119, 2026, 2026, 2026, 2026, 731, 731, 1270, - /* 70 */ 299, 210, 1502, 1288, 844, 1158, 1500, 1482, 1436, 876, - /* 80 */ 1222, 658, 491, 2077, 2077, 2097, 1004, 2077, 2093, 2026, - /* 90 */ 1270, 743, 560, 560, 757, 386, 45, 167, 169, 356, - /* 100 */ 1420, 928, 580, 472, 118, 930, 193, 930, 240, 1254, - /* 110 */ 24, 2012, 1968, 1936, 1860, 1676, 1970, 2074, 1618, 1908, - /* 120 */ 812, 1886, 1544, 1729, 1709, 1682, 1536, 1669, 807, 1613, - /* 130 */ 1429, 571, 1583, 1517, 1348, 1025, 433, 433, 797, 1378, - /* 140 */ 433, 1250, 578, 89, 573, 371, 338, 1468, 1022, 881, - /* 150 */ 585, 2104, 2104, 2104, 220, 645, 2206, 2206, 2206, 2206, - /* 160 */ 2206, -110, -110, 481, 641, 641, 641, 641, 641, 641, - /* 170 */ 641, 641, 641, 667, 349, 705, 1166, 1135, 1103, 1073, - /* 180 */ 1037, 1007, 980, 938, 790, 1225, 1198, 1262, 531, 531, - /* 190 */ -60, -38, -38, -38, -38, 170, -77, 345, 158, 158, - /* 200 */ 41, 702, 227, 1423, 1423, 1423, 381, 159, 113, 23, - /* 210 */ 678, 449, 1456, 1359, 87, 1282, 306, 243, 430, 927, - /* 220 */ 927, 775, 1304, 99, 446, 927, 29, 446, 324, 324, - /* 230 */ -32, 219, 539, 57, 2203, 2116, 2114, 2113, 2183, 2183, - /* 240 */ 2096, 2091, 2108, 2088, 2108, 2080, 2108, 2072, 2108, 2067, - /* 250 */ 1708, 1698, 2060, 1708, 1993, 1974, 1999, 1985, 1993, 1698, - /* 260 */ 1945, 1879, 2007, 1930, 1708, 1903, 1801, 1708, 1897, 1801, - /* 270 */ 1820, 1820, 1820, 1820, 1932, 1801, 1820, 1851, 1820, 1932, - /* 280 */ 1820, 1820, 1839, 1782, 1819, 1801, 1814, 1801, 1739, 1747, - /* 290 */ 1717, 1719, 1698, 1700, 1656, 1732, 1718, 1746, 1687, 1708, - /* 300 */ 1689, 1689, 1637, 1637, 1637, 1637, -110, -110, -110, -110, - /* 310 */ -110, -110, -110, -110, -110, -110, 586, 85, 711, 114, - /* 320 */ -72, 476, 440, 813, 1277, 1218, 1128, 900, 804, -109, - /* 330 */ 252, 686, 696, 486, 419, 230, -3, 395, 1620, 1615, - /* 340 */ 1548, 1545, 1540, 1539, 1508, 1535, 1483, 1519, 1529, 1487, - /* 350 */ 1444, 1551, 1466, 1521, 1511, 1533, 1464, 1461, 1393, 1380, - /* 360 */ 1459, 1458, 1403, 1383, 1490, 1401, 1410, 1394, 1427, 1358, - /* 370 */ 1368, 1379, 1419, 1356, 1349, 1353, 1329, 1404, 1363, 1263, - /* 380 */ 1300, 1303, 1344, 1312, 1306, 1296, 1160, 1295, 1129, 1182, - /* 390 */ 1223, 999, 1159, 1146, 1129, 1119, 1112, 1097, 1050, 1094, - /* 400 */ 1066, 1110, 1113, 1029, 999, 1084, 991, 1060, 944, 960, - /* 410 */ 901, 753, 831, 828, 789, 753, 736, 685, 660, 636, - /* 420 */ 540, 605, 599, 489, 438, 422, 302, 385, 307, 241, - /* 430 */ 231, 138, 25, 137, 2, -39, + /* 0 */ 1330, -4, 1943, 948, 1588, 1621, 1621, 1621, 126, 313, + /* 10 */ 1539, 1704, 1704, 1704, 1704, 1389, 927, 927, 179, 81, + /* 20 */ 193, 1456, 1373, 1704, 1704, 1704, 1704, 1704, 1704, 1704, + /* 30 */ 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, + /* 40 */ 1786, 1704, 1704, 1704, 1704, 1786, 1704, 1704, 1704, 1704, + /* 50 */ 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, + /* 60 */ 1704, 1704, 1829, 891, 28, 377, 891, 2179, 2179, 2179, + /* 70 */ 2179, 507, 507, 321, 411, 250, 1531, 1444, 739, 1459, + /* 80 */ 1523, 361, 1500, 361, 1498, 776, 1315, 668, 399, 2190, + /* 90 */ 2190, 2190, 2190, 935, 2190, 2187, 2179, 321, 1513, 570, + /* 100 */ 570, 864, 279, 149, 50, 275, 252, 1477, 1473, 1352, + /* 110 */ 220, 974, 115, 343, 1216, 343, 5, 1044, 706, 988, + /* 120 */ 2174, 2157, 2152, 2142, 2137, 2134, 2116, 2124, 2109, 1862, + /* 130 */ 2102, 2092, 2068, 2059, 2029, 1952, 2062, 1586, 1581, 1745, + /* 140 */ 1942, 1876, 1869, 1734, 1286, 1286, 1286, 1707, 1085, 1527, + /* 150 */ 1464, 1381, 87, 1462, 265, 1697, 1664, 1376, 1152, 2192, + /* 160 */ 2192, 2192, 1010, 1007, 2324, 2324, 2324, 2324, 2324, -81, + /* 170 */ -81, 491, 651, 651, 651, 651, 651, 651, 651, 651, + /* 180 */ 651, 789, 752, 714, 677, 836, 1229, 1199, 1167, 1131, + /* 190 */ 1101, 1050, 537, 902, 464, 1289, 1262, 1326, 622, 622, + /* 200 */ -60, -38, -38, -38, -38, 164, -80, 77, -11, -11, + /* 210 */ 3, 709, 350, 1400, 1400, 1400, -51, 169, 1037, 346, + /* 220 */ 198, 355, 2120, 1925, 990, 1703, 457, 406, 808, 808, + /* 230 */ 223, 223, 509, 1337, 172, 1133, 223, 870, 1133, 569, + /* 240 */ 569, 202, 34, 611, 287, 2329, 2245, 2242, 2240, 2317, + /* 250 */ 2317, 2234, 2233, 2264, 2229, 2264, 2228, 2264, 2226, 2264, + /* 260 */ 2222, 1871, 1864, 2217, 1871, 2241, 1864, 2188, 2214, 2208, + /* 270 */ 2207, 2241, 1864, 2202, 2140, 2261, 2173, 1871, 2162, 1984, + /* 280 */ 1871, 2151, 1984, 2056, 2056, 2056, 2056, 2169, 1984, 2056, + /* 290 */ 2091, 2056, 2169, 2056, 2056, 2048, 1991, 2005, 1984, 2001, + /* 300 */ 1984, 1923, 1903, 1892, 1881, 1864, 1874, 1845, 1940, 1886, + /* 310 */ 1909, 1830, 1871, 1859, 1859, 1810, 1810, 1810, 1810, -81, + /* 320 */ -81, -81, -81, -81, -81, -81, -81, -81, -81, 596, + /* 330 */ 716, 257, 237, 145, -43, 349, 748, 1320, 1192, 10, + /* 340 */ 1130, 362, 1093, 1004, 973, 746, 494, 191, 389, -7, + /* 350 */ 367, 292, 35, 24, -47, -65, 1833, 1822, 1764, 1751, + /* 360 */ 1767, 1761, 1752, 1758, 1706, 1743, 1741, 1712, 1668, 1791, + /* 370 */ 1695, 1788, 1749, 1750, 1709, 1702, 1627, 1614, 1632, 1603, + /* 380 */ 1728, 1598, 1659, 1652, 1650, 1644, 1592, 1574, 1693, 1591, + /* 390 */ 1615, 1607, 1625, 1561, 1571, 1573, 1628, 1566, 1560, 1497, + /* 400 */ 1532, 1617, 1590, 1521, 1551, 1555, 1496, 1485, 1481, 1461, + /* 410 */ 1386, 1445, 1361, 1403, 1425, 1416, 1393, 1361, 1353, 1358, + /* 420 */ 1284, 1301, 1336, 1329, 1156, 1241, 1245, 1292, 1170, 1156, + /* 430 */ 1242, 1120, 1206, 1060, 1043, 1018, 686, 981, 957, 751, + /* 440 */ 686, 941, 920, 908, 898, 866, 859, 799, 675, 649, + /* 450 */ 648, 704, 601, 529, 431, 415, 324, 243, 168, 146, + /* 460 */ 9, }; -#define YY_REDUCE_USE_DFLT (-164) -#define YY_REDUCE_COUNT (315) -#define YY_REDUCE_MIN (-163) -#define YY_REDUCE_MAX (2068) +#define YY_REDUCE_USE_DFLT (-166) +#define YY_REDUCE_COUNT (328) +#define YY_REDUCE_MIN (-165) +#define YY_REDUCE_MAX (2185) static const short yy_reduce_ofst[] = { - /* 0 */ 589, 1181, 721, 1185, -99, 1249, 1245, -6, 1269, 271, - /* 10 */ 1272, 1187, 786, 351, 149, 31, 725, 2019, 1987, 1977, - /* 20 */ 1971, 1957, 1954, 1951, 1947, 1940, 1937, 1923, 1912, 1906, - /* 30 */ 1892, 1889, 1874, 1869, 1864, 1858, 1841, 1834, 1829, 1810, - /* 40 */ 1799, 1787, 1772, 1770, 1756, 1754, 1752, 1737, 1683, 1655, - /* 50 */ 1600, 1573, 1558, 1555, 1518, 1504, 1489, 1472, 1414, 214, - /* 60 */ 791, 671, 1328, 1572, 1562, 1457, 1390, 315, -163, 502, - /* 70 */ -54, 1332, 1703, 1688, 1681, 1671, 1636, 1589, 1516, 1438, - /* 80 */ 1387, 764, 633, 1124, 906, 152, 53, 796, -90, 225, - /* 90 */ 840, 229, 846, 665, -63, 688, 612, 1952, 1917, 1822, - /* 100 */ 1590, 1590, 1916, 1881, 1875, 1207, 1870, 1139, 1859, 1590, - /* 110 */ 1822, 1805, 1590, 1590, 1590, 1590, 1590, 1590, 1590, 1742, - /* 120 */ 1590, 1590, 1740, 1590, 1590, 1736, 1590, 1590, 1590, 1726, - /* 130 */ 1660, 1654, 1644, 1590, 1588, 1552, 1130, 779, 1515, 1495, - /* 140 */ 614, 1469, 1408, 1407, 1402, 1375, 509, 1351, 1317, 1241, - /* 150 */ 1221, 1002, 756, 226, 340, 1131, 1038, 1008, 976, 945, - /* 160 */ 770, 410, 76, 1405, 1405, 1405, 1405, 1405, 1405, 1405, - /* 170 */ 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, - /* 180 */ 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, - /* 190 */ 1405, 1405, 1405, 1405, 1405, 1405, 1405, 2051, 2062, 2061, - /* 200 */ 1405, 1984, 1984, 2050, 2049, 2048, 2015, 2031, 2036, 1994, - /* 210 */ 1988, 1986, 2056, 2055, 2054, 2053, 2018, 2068, 2014, 1998, - /* 220 */ 1997, 2034, 2025, 2021, 2033, 1991, 1992, 2030, 1976, 1962, - /* 230 */ 1995, 1996, 1975, 1405, 1946, 1753, 1973, 1966, 1938, 1929, - /* 240 */ 1953, 1753, 1972, 1753, 1965, 1753, 1956, 1753, 1955, 1924, - /* 250 */ 1982, 1933, 1910, 1978, 1911, 1866, 1753, 1753, 1838, 1818, - /* 260 */ 1753, 1830, 1758, 1779, 1837, 1753, 1807, 1821, 1753, 1788, - /* 270 */ 1790, 1784, 1783, 1780, 1773, 1776, 1775, 1763, 1748, 1749, - /* 280 */ 1745, 1728, 1696, 1697, 1668, 1705, 1639, 1684, 1652, 1645, - /* 290 */ 1643, 1628, 1612, 1591, 1553, 1559, 1405, 1609, 1604, 1605, - /* 300 */ 1595, 1556, 1568, 1554, 1534, 1522, 1432, 1416, 1388, 1480, - /* 310 */ 1470, 1445, 1405, 1405, 1405, 1478, + /* 0 */ 412, 205, 1252, -74, 840, 839, 822, -59, 116, 1186, + /* 10 */ -42, 1251, 825, 76, 26, 905, 258, -54, 832, 1992, + /* 20 */ 1988, 1981, 1963, 1958, 1953, 1951, 1948, 1933, 1922, 1918, + /* 30 */ 1916, 1890, 1885, 1875, 1861, 1851, 1846, 1844, 1827, 1817, + /* 40 */ 1811, 1801, 1778, 1762, 1760, 1723, 1720, 1683, 1647, 1642, + /* 50 */ 1616, 1582, 1575, 1564, 1558, 1552, 1533, 1482, 1475, 1472, + /* 60 */ 1452, 1355, 967, 331, 269, 1287, 404, 1842, 1486, 1327, + /* 70 */ 1250, 694, 691, 248, -39, 1239, 2046, 1910, 1900, 1735, + /* 80 */ 1730, 911, 1698, 705, 1610, 969, 966, 823, 849, 1394, + /* 90 */ 1369, 1357, 962, 753, 827, -13, 663, 387, 585, 1253, + /* 100 */ 1147, 232, 1128, 1026, 2112, 2103, 2076, 1818, 1818, 2098, + /* 110 */ 2097, 2087, 2086, 1300, 2078, 1163, 2077, 1818, 1433, 2076, + /* 120 */ 2060, 1818, 1818, 1818, 1818, 1818, 1818, 1818, 2053, 1818, + /* 130 */ 1818, 1818, 1818, 2027, 1818, 1818, 1818, 2022, 2011, 1915, + /* 140 */ 1878, 1818, 1780, 1779, 693, 572, -165, 1640, 1605, 1602, + /* 150 */ 1587, 1556, 1502, 1492, 386, 1418, 1408, 1322, 1283, 1246, + /* 160 */ 919, 274, 1275, 1108, 1100, 1036, 1035, 968, 770, 605, + /* 170 */ -2, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, + /* 180 */ 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, + /* 190 */ 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, + /* 200 */ 1624, 1624, 1624, 1624, 1624, 1624, 1624, 2168, 2178, 2177, + /* 210 */ 1624, 2106, 2106, 2167, 2166, 2165, 2132, 2146, 2154, 2108, + /* 220 */ 2105, 2101, 2176, 2175, 2171, 2170, 2139, 2185, 2131, 2128, + /* 230 */ 2117, 2115, 2150, 2144, 2145, 2148, 2114, 2113, 2147, 2085, + /* 240 */ 2084, 2118, 2121, 2094, 1624, 2067, 2010, 2100, 2095, 2066, + /* 250 */ 2063, 2093, 2010, 2111, 2010, 2110, 2010, 2107, 2010, 2104, + /* 260 */ 2079, 2138, 2090, 2075, 2133, 2096, 2083, 2061, 2058, 2010, + /* 270 */ 2010, 2088, 2073, 2010, 2024, 2017, 2030, 2089, 2010, 2057, + /* 280 */ 2072, 2010, 2055, 2049, 2045, 2031, 2019, 2026, 2023, 2016, + /* 290 */ 2007, 2002, 1987, 1983, 1955, 1888, 1896, 1866, 1894, 1825, + /* 300 */ 1873, 1835, 1792, 1808, 1790, 1793, 1784, 1732, 1744, 1624, + /* 310 */ 1781, 1759, 1746, 1753, 1739, 1748, 1738, 1725, 1717, 1620, + /* 320 */ 1613, 1618, 1680, 1679, 1636, 1624, 1624, 1624, 1674, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 730, 1038, 1143, 1026, 1143, 1026, 1026, 1143, 1026, 1026, - /* 10 */ 1026, 1026, 1026, 901, 1149, 1149, 1149, 1026, 1026, 1026, - /* 20 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - /* 30 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - /* 40 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - /* 50 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 978, 1149, - /* 60 */ 895, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 775, - /* 70 */ 891, 901, 1149, 1149, 1149, 1149, 1149, 963, 950, 941, - /* 80 */ 1149, 1149, 1149, 973, 973, 956, 843, 973, 1149, 1149, - /* 90 */ 1149, 1149, 929, 929, 1028, 1149, 767, 1113, 1118, 976, - /* 100 */ 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 902, - /* 110 */ 976, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, - /* 120 */ 1149, 964, 957, 951, 942, 1149, 1149, 1149, 1149, 1149, - /* 130 */ 1149, 1149, 1149, 1149, 1149, 1149, 891, 891, 1149, 1149, - /* 140 */ 891, 1149, 1149, 977, 1149, 1149, 764, 1149, 1149, 1149, - /* 150 */ 736, 1059, 1149, 1149, 730, 1143, 1143, 1143, 1143, 1143, - /* 160 */ 1143, 1136, 881, 936, 1032, 1033, 907, 946, 1039, 934, - /* 170 */ 938, 937, 1031, 1028, 1028, 1028, 1028, 1028, 1028, 1028, - /* 180 */ 1028, 1028, 1028, 1028, 1028, 1028, 1028, 1001, 1013, 1000, - /* 190 */ 1008, 1009, 1012, 1003, 1017, 1002, 1004, 1149, 1149, 1149, - /* 200 */ 1005, 1149, 1149, 1149, 1149, 1149, 894, 865, 1149, 1149, - /* 210 */ 1149, 1087, 1149, 1149, 777, 1149, 879, 739, 945, 919, - /* 220 */ 919, 810, 834, 799, 929, 919, 909, 929, 1149, 1149, - /* 230 */ 892, 879, 1034, 1006, 1127, 910, 910, 910, 1112, 1112, - /* 240 */ 910, 910, 856, 910, 856, 910, 856, 910, 856, 910, - /* 250 */ 761, 945, 910, 761, 847, 969, 910, 910, 847, 945, - /* 260 */ 910, 1094, 1092, 910, 761, 910, 1047, 761, 910, 1047, - /* 270 */ 845, 845, 845, 845, 826, 1047, 845, 810, 845, 826, - /* 280 */ 845, 845, 910, 1149, 910, 1047, 1053, 1047, 935, 923, - /* 290 */ 933, 930, 945, 1149, 1149, 1028, 1007, 758, 829, 761, - /* 300 */ 747, 747, 735, 735, 735, 735, 1140, 1140, 1136, 812, - /* 310 */ 812, 897, 1016, 1015, 1014, 786, 1040, 1149, 1149, 1149, - /* 320 */ 1149, 1149, 1149, 1061, 1149, 1149, 1149, 1149, 1149, 1149, - /* 330 */ 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 731, - /* 340 */ 1149, 1149, 1149, 1149, 1149, 1130, 1149, 1149, 1149, 1149, - /* 350 */ 1149, 1149, 1091, 1090, 1149, 1149, 1149, 1149, 1149, 1149, - /* 360 */ 1149, 1149, 1149, 1149, 1079, 1149, 1149, 1149, 1149, 1149, - /* 370 */ 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, - /* 380 */ 1149, 1149, 1149, 1149, 1149, 980, 1027, 1149, 868, 870, - /* 390 */ 1149, 1037, 1149, 1149, 869, 1149, 1149, 1149, 1149, 1149, - /* 400 */ 1149, 1149, 1149, 1149, 931, 1149, 924, 1149, 1149, 1149, - /* 410 */ 1149, 1145, 1149, 1149, 1149, 1144, 1149, 1149, 1149, 1149, - /* 420 */ 1149, 1149, 1149, 1149, 1149, 1149, 979, 1029, 993, 1149, - /* 430 */ 992, 991, 770, 1149, 745, 1149, 727, 732, 1129, 1126, - /* 440 */ 1128, 1123, 1124, 1122, 1125, 1121, 1119, 1120, 1117, 1115, - /* 450 */ 1114, 1116, 1111, 1107, 1067, 1065, 1063, 1072, 1071, 1070, - /* 460 */ 1069, 1068, 1064, 1062, 1066, 1060, 960, 948, 939, 863, - /* 470 */ 1106, 1104, 1105, 1058, 1056, 1057, 862, 861, 860, 855, - /* 480 */ 854, 853, 852, 1133, 1142, 1141, 1139, 1138, 1137, 1131, - /* 490 */ 1132, 1045, 1044, 1042, 1041, 1043, 763, 1083, 1086, 1085, - /* 500 */ 1084, 1089, 1088, 1081, 1093, 1098, 1097, 1102, 1101, 1100, - /* 510 */ 1099, 1096, 1078, 968, 967, 965, 970, 962, 961, 966, - /* 520 */ 953, 959, 958, 949, 952, 848, 944, 940, 943, 864, - /* 530 */ 1082, 859, 858, 857, 762, 757, 912, 756, 755, 766, - /* 540 */ 832, 833, 841, 844, 839, 842, 838, 837, 836, 840, - /* 550 */ 835, 831, 769, 768, 776, 825, 803, 801, 800, 804, - /* 560 */ 817, 816, 823, 822, 821, 820, 819, 815, 818, 814, - /* 570 */ 813, 805, 798, 797, 811, 796, 828, 827, 824, 795, - /* 580 */ 851, 850, 849, 846, 794, 793, 792, 791, 790, 789, - /* 590 */ 999, 998, 1030, 1021, 982, 981, 1020, 1018, 1029, 1019, - /* 600 */ 990, 866, 873, 872, 871, 875, 876, 886, 884, 883, - /* 610 */ 882, 918, 917, 916, 915, 914, 913, 906, 904, 900, - /* 620 */ 899, 911, 905, 903, 921, 922, 920, 898, 890, 888, - /* 630 */ 889, 887, 975, 972, 974, 971, 908, 896, 893, 880, - /* 640 */ 926, 925, 1027, 1148, 1146, 1147, 1050, 1052, 1055, 1054, - /* 650 */ 1051, 928, 927, 1049, 1048, 1022, 997, 782, 780, 781, - /* 660 */ 1075, 1074, 1077, 1076, 1073, 784, 783, 779, 778, 995, - /* 670 */ 874, 867, 989, 988, 1103, 1024, 1025, 987, 983, 1023, - /* 680 */ 1011, 1010, 996, 986, 771, 984, 994, 985, 809, 808, - /* 690 */ 807, 806, 878, 877, 788, 802, 787, 785, 765, 760, - /* 700 */ 759, 754, 752, 749, 751, 748, 753, 750, 746, 744, - /* 710 */ 743, 742, 741, 740, 774, 773, 772, 770, 738, 737, - /* 720 */ 734, 733, 729, 728, 726, + /* 0 */ 759, 1074, 1179, 1062, 1179, 1062, 1062, 1062, 1179, 1062, + /* 10 */ 1062, 1062, 1062, 1062, 1062, 931, 1185, 1185, 1185, 1062, + /* 20 */ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 30 */ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 40 */ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 50 */ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, + /* 60 */ 1062, 1062, 1014, 1185, 924, 1185, 1185, 1185, 1185, 1185, + /* 70 */ 1185, 1185, 1185, 804, 920, 931, 1185, 1185, 1185, 1185, + /* 80 */ 1185, 988, 1002, 988, 980, 971, 1185, 1185, 1185, 996, + /* 90 */ 996, 996, 996, 872, 996, 1185, 1185, 1185, 1185, 959, + /* 100 */ 959, 1064, 1185, 796, 1149, 1154, 1012, 1185, 1185, 1185, + /* 110 */ 1185, 1185, 989, 1185, 1185, 1185, 1185, 932, 920, 1012, + /* 120 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 130 */ 1003, 981, 972, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 140 */ 1185, 1185, 1185, 1185, 920, 920, 920, 1185, 1185, 1185, + /* 150 */ 1185, 1013, 1185, 1185, 793, 1185, 1185, 1185, 765, 1095, + /* 160 */ 1185, 1185, 759, 1179, 1179, 1179, 1179, 1179, 1179, 1172, + /* 170 */ 910, 966, 1068, 1069, 937, 976, 1075, 964, 968, 967, + /* 180 */ 1067, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, + /* 190 */ 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1037, 1049, 1036, + /* 200 */ 1044, 1045, 1048, 1039, 1053, 1038, 1040, 1185, 1185, 1185, + /* 210 */ 1041, 1185, 1185, 1185, 1185, 1185, 923, 894, 1185, 1185, + /* 220 */ 1185, 1123, 1185, 1185, 806, 1185, 908, 768, 975, 975, + /* 230 */ 949, 949, 839, 863, 828, 959, 949, 939, 959, 1185, + /* 240 */ 1185, 921, 908, 1070, 1042, 1163, 940, 940, 940, 1148, + /* 250 */ 1148, 940, 940, 885, 940, 885, 940, 885, 940, 885, + /* 260 */ 940, 790, 975, 940, 790, 876, 975, 1008, 992, 940, + /* 270 */ 940, 876, 975, 940, 1130, 1128, 940, 790, 940, 1083, + /* 280 */ 790, 940, 1083, 874, 874, 874, 874, 855, 1083, 874, + /* 290 */ 839, 874, 855, 874, 874, 940, 1185, 940, 1083, 1089, + /* 300 */ 1083, 965, 953, 963, 960, 975, 1185, 1185, 1064, 1043, + /* 310 */ 787, 858, 790, 776, 776, 764, 764, 764, 764, 1176, + /* 320 */ 1176, 1172, 841, 841, 926, 1052, 1051, 1050, 815, 1076, + /* 330 */ 1185, 1185, 1185, 1185, 1185, 1185, 1097, 1185, 1185, 1185, + /* 340 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 350 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 760, 1185, 1185, + /* 360 */ 1185, 1185, 1185, 1166, 1185, 1185, 1185, 1185, 1185, 1185, + /* 370 */ 1127, 1126, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 380 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1115, 1185, + /* 390 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 400 */ 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1016, + /* 410 */ 1063, 1185, 897, 902, 1185, 1185, 1185, 898, 1185, 1185, + /* 420 */ 1185, 1185, 1185, 1185, 1073, 1185, 1185, 1185, 1185, 961, + /* 430 */ 1185, 954, 1185, 1185, 1185, 1185, 1181, 1185, 1185, 1185, + /* 440 */ 1180, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, + /* 450 */ 1185, 1015, 1065, 1029, 1185, 1028, 1027, 799, 1185, 774, + /* 460 */ 1185, 756, 761, 1165, 1162, 1164, 1159, 1160, 1158, 1161, + /* 470 */ 1157, 1155, 1156, 1153, 1151, 1150, 1152, 1147, 1143, 1103, + /* 480 */ 1101, 1099, 1108, 1107, 1106, 1105, 1104, 1100, 1098, 1102, + /* 490 */ 1096, 999, 978, 969, 892, 1142, 1140, 1141, 1094, 1092, + /* 500 */ 1093, 891, 890, 889, 884, 883, 882, 881, 1169, 1178, + /* 510 */ 1177, 1175, 1174, 1173, 1167, 1168, 1081, 1080, 1078, 1077, + /* 520 */ 1079, 792, 1119, 1122, 1121, 1120, 1125, 1124, 1117, 1129, + /* 530 */ 1134, 1133, 1138, 1137, 1136, 1135, 1132, 1114, 1007, 1006, + /* 540 */ 1004, 1001, 1011, 1010, 1009, 1000, 993, 1005, 983, 991, + /* 550 */ 990, 979, 982, 877, 974, 970, 973, 893, 1118, 888, + /* 560 */ 887, 886, 791, 786, 942, 785, 784, 795, 861, 862, + /* 570 */ 870, 873, 868, 871, 867, 866, 865, 869, 864, 860, + /* 580 */ 798, 797, 805, 854, 832, 830, 829, 833, 846, 845, + /* 590 */ 852, 851, 850, 849, 848, 844, 847, 843, 842, 834, + /* 600 */ 827, 826, 840, 825, 857, 856, 853, 824, 880, 879, + /* 610 */ 878, 875, 823, 822, 821, 820, 819, 818, 1035, 1034, + /* 620 */ 1066, 1057, 1018, 1017, 1056, 1054, 1065, 1055, 1026, 895, + /* 630 */ 905, 904, 903, 900, 901, 915, 913, 912, 911, 948, + /* 640 */ 947, 946, 945, 944, 943, 936, 934, 929, 928, 941, + /* 650 */ 935, 933, 930, 951, 952, 950, 927, 919, 917, 918, + /* 660 */ 916, 998, 995, 997, 994, 938, 925, 922, 909, 956, + /* 670 */ 955, 1063, 1184, 1182, 1183, 1086, 1088, 1091, 1090, 1087, + /* 680 */ 958, 957, 1085, 1084, 1058, 1033, 811, 809, 810, 1111, + /* 690 */ 1110, 1113, 1112, 1109, 813, 812, 808, 807, 1031, 899, + /* 700 */ 896, 1025, 1024, 1139, 1060, 1061, 1023, 1019, 1059, 1047, + /* 710 */ 1046, 1032, 1022, 800, 1020, 1030, 1021, 838, 837, 836, + /* 720 */ 835, 907, 906, 817, 831, 816, 814, 794, 789, 788, + /* 730 */ 783, 781, 778, 780, 777, 782, 779, 775, 773, 772, + /* 740 */ 771, 770, 769, 803, 802, 801, 799, 767, 766, 763, + /* 750 */ 762, 758, 757, 755, }; /* The next table maps tokens into fallback tokens. If a construct @@ -1123,43 +1154,43 @@ static const char *const yyTokenName[] = { "FLOAT", "BLOB", "AUTOINCR", "ON", "INSERT", "DELETE", "UPDATE", "ID_FK_MATCH", "SET", "DEFERRABLE", "FOREIGN", "DROP", - "ID_VIEW_NEW", "ID_VIEW", "UNION", "ALL", - "EXCEPT", "INTERSECT", "SELECT", "VALUES", + "ID_VIEW_NEW", "ID_VIEW", "SELECT", "VALUES", + "UNION", "ALL", "EXCEPT", "INTERSECT", "DISTINCT", "ID_ALIAS", "FROM", "USING", "JOIN", "ID_JOIN_OPTS", "ID_IDX", "ORDER", "GROUP", "HAVING", "LIMIT", "WHERE", - "ID_COL", "INTO", "CASE", "ID_FN", - "ID_ERR_MSG", "VARIABLE", "WHEN", "THEN", - "ELSE", "INDEX", "ID_IDX_NEW", "ID_PRAGMA", - "ID_TRIG_NEW", "ID_TRIG", "ALTER", "ADD", - "error", "cmd", "input", "cmdlist", - "ecmd", "explain", "cmdx", "transtype", - "trans_opt", "nm", "savepoint_opt", "temp", - "ifnotexists", "fullname", "columnlist", "conslist_opt", - "table_options", "select", "column", "columnid", - "type", "carglist", "id", "ids", - "typetoken", "typename", "signed", "plus_num", - "minus_num", "ccons", "term", "expr", - "onconf", "sortorder", "autoinc", "idxlist_opt", - "refargs", "defer_subclause", "refarg", "refact", - "init_deferred_pred_opt", "conslist", "tconscomma", "tcons", - "idxlist", "defer_subclause_opt", "resolvetype", "orconf", - "raisetype", "ifexists", "select_stmt", "with", - "selectnowith", "oneselect", "multiselect_op", "values", - "distinct", "selcollist", "from", "where_opt", - "groupby_opt", "having_opt", "orderby_opt", "limit_opt", - "nexprlist", "exprlist", "sclp", "as", - "joinsrc", "singlesrc", "seltablist", "joinop", - "joinconstr_opt", "dbnm", "indexed_opt", "inscollist", - "sortlist", "delete_stmt", "update_stmt", "setlist", - "insert_stmt", "insert_cmd", "inscollist_opt", "exprx", - "not_opt", "case_operand", "case_exprlist", "case_else", - "likeop", "uniqueflag", "idxlist_single", "collate", - "nmnum", "number", "trigger_time", "trigger_event", - "foreach_clause", "when_clause", "trigger_cmd_list", "trigger_cmd", - "database_kw_opt", "key_opt", "kwcolumn_opt", "create_vtab", - "vtabarglist", "vtabarg", "vtabargtoken", "anylist", - "wqlist", + "ID_COL", "INTO", "DO", "NOTHING", + "CASE", "ID_FN", "ID_ERR_MSG", "VARIABLE", + "WHEN", "THEN", "ELSE", "INDEX", + "ID_IDX_NEW", "ID_PRAGMA", "ID_TRIG_NEW", "ID_TRIG", + "ALTER", "ADD", "error", "cmd", + "input", "cmdlist", "ecmd", "explain", + "cmdx", "transtype", "trans_opt", "nm", + "savepoint_opt", "temp", "ifnotexists", "fullname", + "columnlist", "conslist_opt", "table_options", "select", + "column", "columnid", "type", "carglist", + "id", "ids", "typetoken", "typename", + "signed", "plus_num", "minus_num", "ccons", + "term", "expr", "onconf", "sortorder", + "autoinc", "idxlist_opt", "refargs", "defer_subclause", + "refarg", "refact", "init_deferred_pred_opt", "conslist", + "tconscomma", "tcons", "idxlist", "defer_subclause_opt", + "resolvetype", "orconf", "raisetype", "ifexists", + "select_stmt", "with", "selectnowith", "oneselect", + "multiselect_op", "values", "distinct", "selcollist", + "from", "where_opt", "groupby_opt", "having_opt", + "orderby_opt", "limit_opt", "nexprlist", "exprlist", + "sclp", "as", "joinsrc", "singlesrc", + "seltablist", "joinop", "joinconstr_opt", "dbnm", + "indexed_opt", "idlist", "sortlist", "delete_stmt", + "update_stmt", "setlist", "idlist_opt", "insert_stmt", + "insert_cmd", "upsert", "exprx", "not_opt", + "case_operand", "case_exprlist", "case_else", "likeop", + "uniqueflag", "idxlist_single", "collate", "nmnum", + "number", "trigger_time", "trigger_event", "foreach_clause", + "when_clause", "trigger_cmd_list", "trigger_cmd", "database_kw_opt", + "key_opt", "kwcolumn_opt", "create_vtab", "vtabarglist", + "vtabarg", "vtabargtoken", "anylist", "wqlist", }; #endif /* NDEBUG */ @@ -1312,13 +1343,13 @@ static const char *const yyRuleName[] = { /* 142 */ "selectnowith ::= selectnowith multiselect_op oneselect", /* 143 */ "selectnowith ::= values", /* 144 */ "selectnowith ::= selectnowith COMMA values", - /* 145 */ "multiselect_op ::= UNION", - /* 146 */ "multiselect_op ::= UNION ALL", - /* 147 */ "multiselect_op ::= EXCEPT", - /* 148 */ "multiselect_op ::= INTERSECT", - /* 149 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 150 */ "values ::= VALUES LP nexprlist RP", - /* 151 */ "values ::= values COMMA LP exprlist RP", + /* 145 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 146 */ "values ::= VALUES LP nexprlist RP", + /* 147 */ "values ::= values COMMA LP exprlist RP", + /* 148 */ "multiselect_op ::= UNION", + /* 149 */ "multiselect_op ::= UNION ALL", + /* 150 */ "multiselect_op ::= EXCEPT", + /* 151 */ "multiselect_op ::= INTERSECT", /* 152 */ "distinct ::= DISTINCT", /* 153 */ "distinct ::= ALL", /* 154 */ "distinct ::=", @@ -1343,254 +1374,261 @@ static const char *const yyRuleName[] = { /* 173 */ "singlesrc ::= nm dbnm as indexed_opt", /* 174 */ "singlesrc ::= LP select RP as", /* 175 */ "singlesrc ::= LP joinsrc RP as", - /* 176 */ "singlesrc ::=", - /* 177 */ "singlesrc ::= nm DOT", - /* 178 */ "singlesrc ::= nm DOT ID_TAB", - /* 179 */ "singlesrc ::= ID_DB|ID_TAB", - /* 180 */ "singlesrc ::= nm DOT ID_VIEW", - /* 181 */ "singlesrc ::= ID_DB|ID_VIEW", - /* 182 */ "joinconstr_opt ::= ON expr", - /* 183 */ "joinconstr_opt ::= USING LP inscollist RP", - /* 184 */ "joinconstr_opt ::=", - /* 185 */ "dbnm ::=", - /* 186 */ "dbnm ::= DOT nm", - /* 187 */ "fullname ::= nm dbnm", - /* 188 */ "joinop ::= COMMA", - /* 189 */ "joinop ::= JOIN", - /* 190 */ "joinop ::= JOIN_KW JOIN", - /* 191 */ "joinop ::= JOIN_KW nm JOIN", - /* 192 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 193 */ "joinop ::= ID_JOIN_OPTS", - /* 194 */ "indexed_opt ::=", - /* 195 */ "indexed_opt ::= INDEXED BY nm", - /* 196 */ "indexed_opt ::= NOT INDEXED", - /* 197 */ "indexed_opt ::= INDEXED BY ID_IDX", - /* 198 */ "orderby_opt ::=", - /* 199 */ "orderby_opt ::= ORDER BY sortlist", - /* 200 */ "sortlist ::= sortlist COMMA expr sortorder", - /* 201 */ "sortlist ::= expr sortorder", - /* 202 */ "sortorder ::= ASC", - /* 203 */ "sortorder ::= DESC", - /* 204 */ "sortorder ::=", - /* 205 */ "groupby_opt ::=", - /* 206 */ "groupby_opt ::= GROUP BY nexprlist", - /* 207 */ "groupby_opt ::= GROUP BY", - /* 208 */ "having_opt ::=", - /* 209 */ "having_opt ::= HAVING expr", - /* 210 */ "limit_opt ::=", - /* 211 */ "limit_opt ::= LIMIT expr", - /* 212 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 213 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 214 */ "cmd ::= delete_stmt", - /* 215 */ "delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt", - /* 216 */ "delete_stmt ::= with DELETE FROM", - /* 217 */ "delete_stmt ::= with DELETE FROM nm DOT", - /* 218 */ "delete_stmt ::= with DELETE FROM nm DOT ID_TAB", - /* 219 */ "delete_stmt ::= with DELETE FROM ID_DB|ID_TAB", - /* 220 */ "where_opt ::=", - /* 221 */ "where_opt ::= WHERE expr", - /* 222 */ "where_opt ::= WHERE", - /* 223 */ "cmd ::= update_stmt", - /* 224 */ "update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", - /* 225 */ "update_stmt ::= with UPDATE orconf", - /* 226 */ "update_stmt ::= with UPDATE orconf nm DOT", - /* 227 */ "update_stmt ::= with UPDATE orconf nm DOT ID_TAB", - /* 228 */ "update_stmt ::= with UPDATE orconf ID_DB|ID_TAB", - /* 229 */ "setlist ::= setlist COMMA nm EQ expr", - /* 230 */ "setlist ::= nm EQ expr", - /* 231 */ "setlist ::=", - /* 232 */ "setlist ::= setlist COMMA", - /* 233 */ "setlist ::= setlist COMMA ID_COL", - /* 234 */ "setlist ::= ID_COL", - /* 235 */ "cmd ::= insert_stmt", - /* 236 */ "insert_stmt ::= with insert_cmd INTO fullname inscollist_opt select", - /* 237 */ "insert_stmt ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES", - /* 238 */ "insert_stmt ::= with insert_cmd INTO", - /* 239 */ "insert_stmt ::= with insert_cmd INTO nm DOT", - /* 240 */ "insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB", - /* 241 */ "insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB", - /* 242 */ "insert_cmd ::= INSERT orconf", - /* 243 */ "insert_cmd ::= REPLACE", - /* 244 */ "inscollist_opt ::=", - /* 245 */ "inscollist_opt ::= LP inscollist RP", - /* 246 */ "inscollist ::= inscollist COMMA nm", - /* 247 */ "inscollist ::= nm", - /* 248 */ "inscollist ::=", - /* 249 */ "inscollist ::= inscollist COMMA ID_COL", - /* 250 */ "inscollist ::= ID_COL", - /* 251 */ "exprx ::= nm DOT", - /* 252 */ "exprx ::= nm DOT nm DOT", - /* 253 */ "exprx ::= expr not_opt BETWEEN expr AND", - /* 254 */ "exprx ::= CASE case_operand case_exprlist case_else", - /* 255 */ "exprx ::= expr not_opt IN LP exprlist", - /* 256 */ "exprx ::= expr not_opt IN ID_DB", - /* 257 */ "exprx ::= expr not_opt IN nm DOT ID_TAB", - /* 258 */ "exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN", - /* 259 */ "exprx ::= nm DOT ID_TAB|ID_COL", - /* 260 */ "exprx ::= nm DOT nm DOT ID_COL", - /* 261 */ "exprx ::= expr COLLATE ID_COLLATE", - /* 262 */ "exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP", - /* 263 */ "exprx ::= term", - /* 264 */ "exprx ::= CTIME_KW", - /* 265 */ "exprx ::= LP nexprlist RP", - /* 266 */ "exprx ::= id", - /* 267 */ "exprx ::= JOIN_KW", - /* 268 */ "exprx ::= nm DOT nm", - /* 269 */ "exprx ::= nm DOT nm DOT nm", - /* 270 */ "exprx ::= VARIABLE", - /* 271 */ "exprx ::= expr COLLATE ids", - /* 272 */ "exprx ::= CAST LP expr AS typetoken RP", - /* 273 */ "exprx ::= ID LP distinct exprlist RP", - /* 274 */ "exprx ::= ID LP STAR RP", - /* 275 */ "exprx ::= expr AND expr", - /* 276 */ "exprx ::= expr OR expr", - /* 277 */ "exprx ::= expr LT|GT|GE|LE expr", - /* 278 */ "exprx ::= expr EQ|NE expr", - /* 279 */ "exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 280 */ "exprx ::= expr PLUS|MINUS expr", - /* 281 */ "exprx ::= expr STAR|SLASH|REM expr", - /* 282 */ "exprx ::= expr CONCAT expr", - /* 283 */ "exprx ::= expr not_opt likeop expr", - /* 284 */ "exprx ::= expr not_opt likeop expr ESCAPE expr", - /* 285 */ "exprx ::= expr ISNULL|NOTNULL", - /* 286 */ "exprx ::= expr NOT NULL", - /* 287 */ "exprx ::= expr IS not_opt expr", - /* 288 */ "exprx ::= NOT expr", - /* 289 */ "exprx ::= BITNOT expr", - /* 290 */ "exprx ::= MINUS expr", - /* 291 */ "exprx ::= PLUS expr", - /* 292 */ "exprx ::= expr not_opt BETWEEN expr AND expr", - /* 293 */ "exprx ::= expr not_opt IN LP exprlist RP", - /* 294 */ "exprx ::= LP select RP", - /* 295 */ "exprx ::= expr not_opt IN LP select RP", - /* 296 */ "exprx ::= expr not_opt IN nm dbnm", - /* 297 */ "exprx ::= EXISTS LP select RP", - /* 298 */ "exprx ::= CASE case_operand case_exprlist case_else END", - /* 299 */ "exprx ::= RAISE LP IGNORE RP", - /* 300 */ "exprx ::= RAISE LP raisetype COMMA nm RP", - /* 301 */ "expr ::=", - /* 302 */ "expr ::= exprx", - /* 303 */ "not_opt ::=", - /* 304 */ "not_opt ::= NOT", - /* 305 */ "likeop ::= LIKE_KW|MATCH", - /* 306 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 307 */ "case_exprlist ::= WHEN expr THEN expr", - /* 308 */ "case_else ::= ELSE expr", - /* 309 */ "case_else ::=", - /* 310 */ "case_operand ::= exprx", - /* 311 */ "case_operand ::=", - /* 312 */ "exprlist ::= nexprlist", - /* 313 */ "exprlist ::=", - /* 314 */ "nexprlist ::= nexprlist COMMA expr", - /* 315 */ "nexprlist ::= exprx", - /* 316 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 317 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB", - /* 318 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW", - /* 319 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW", - /* 320 */ "uniqueflag ::= UNIQUE", - /* 321 */ "uniqueflag ::=", - /* 322 */ "idxlist_opt ::=", - /* 323 */ "idxlist_opt ::= LP idxlist RP", - /* 324 */ "idxlist ::= idxlist COMMA idxlist_single", - /* 325 */ "idxlist ::= idxlist_single", - /* 326 */ "idxlist_single ::= nm collate sortorder", - /* 327 */ "idxlist_single ::= ID_COL", - /* 328 */ "collate ::=", - /* 329 */ "collate ::= COLLATE ids", - /* 330 */ "collate ::= COLLATE ID_COLLATE", - /* 331 */ "cmd ::= DROP INDEX ifexists fullname", - /* 332 */ "cmd ::= DROP INDEX ifexists nm DOT ID_IDX", - /* 333 */ "cmd ::= DROP INDEX ifexists ID_DB|ID_IDX", - /* 334 */ "cmd ::= VACUUM", - /* 335 */ "cmd ::= VACUUM nm", - /* 336 */ "cmd ::= PRAGMA nm dbnm", - /* 337 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 338 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 339 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 340 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 341 */ "cmd ::= PRAGMA nm DOT ID_PRAGMA", - /* 342 */ "cmd ::= PRAGMA ID_DB|ID_PRAGMA", - /* 343 */ "nmnum ::= plus_num", - /* 344 */ "nmnum ::= nm", - /* 345 */ "nmnum ::= ON", - /* 346 */ "nmnum ::= DELETE", - /* 347 */ "nmnum ::= DEFAULT", - /* 348 */ "plus_num ::= PLUS number", - /* 349 */ "plus_num ::= number", - /* 350 */ "minus_num ::= MINUS number", - /* 351 */ "number ::= INTEGER", - /* 352 */ "number ::= FLOAT", - /* 353 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END", - /* 354 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause", - /* 355 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list", - /* 356 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB", - /* 357 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW", - /* 358 */ "cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW", - /* 359 */ "trigger_time ::= BEFORE", - /* 360 */ "trigger_time ::= AFTER", - /* 361 */ "trigger_time ::= INSTEAD OF", - /* 362 */ "trigger_time ::=", - /* 363 */ "trigger_event ::= DELETE", - /* 364 */ "trigger_event ::= INSERT", - /* 365 */ "trigger_event ::= UPDATE", - /* 366 */ "trigger_event ::= UPDATE OF inscollist", - /* 367 */ "foreach_clause ::=", - /* 368 */ "foreach_clause ::= FOR EACH ROW", - /* 369 */ "when_clause ::=", - /* 370 */ "when_clause ::= WHEN expr", - /* 371 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 372 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 373 */ "trigger_cmd_list ::= SEMI", - /* 374 */ "trigger_cmd ::= update_stmt", - /* 375 */ "trigger_cmd ::= insert_stmt", - /* 376 */ "trigger_cmd ::= delete_stmt", - /* 377 */ "trigger_cmd ::= select_stmt", - /* 378 */ "raisetype ::= ROLLBACK|ABORT|FAIL", - /* 379 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 380 */ "cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG", - /* 381 */ "cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG", - /* 382 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 383 */ "cmd ::= DETACH database_kw_opt expr", - /* 384 */ "key_opt ::=", - /* 385 */ "key_opt ::= KEY expr", - /* 386 */ "database_kw_opt ::= DATABASE", - /* 387 */ "database_kw_opt ::=", - /* 388 */ "cmd ::= REINDEX", - /* 389 */ "cmd ::= REINDEX nm dbnm", - /* 390 */ "cmd ::= REINDEX ID_COLLATE", - /* 391 */ "cmd ::= REINDEX nm DOT ID_TAB|ID_IDX", - /* 392 */ "cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB", - /* 393 */ "cmd ::= ANALYZE", - /* 394 */ "cmd ::= ANALYZE nm dbnm", - /* 395 */ "cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX", - /* 396 */ "cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB", - /* 397 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 398 */ "cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column", - /* 399 */ "cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW", - /* 400 */ "cmd ::= ALTER TABLE nm DOT ID_TAB", - /* 401 */ "cmd ::= ALTER TABLE ID_DB|ID_TAB", - /* 402 */ "kwcolumn_opt ::=", - /* 403 */ "kwcolumn_opt ::= COLUMNKW", - /* 404 */ "cmd ::= create_vtab", - /* 405 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 406 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP", - /* 407 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW", - /* 408 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW", - /* 409 */ "vtabarglist ::= vtabarg", - /* 410 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 411 */ "vtabarg ::=", - /* 412 */ "vtabarg ::= vtabarg vtabargtoken", - /* 413 */ "vtabargtoken ::= ANY", - /* 414 */ "vtabargtoken ::= LP anylist RP", - /* 415 */ "anylist ::=", - /* 416 */ "anylist ::= anylist LP anylist RP", - /* 417 */ "anylist ::= anylist ANY", - /* 418 */ "with ::=", - /* 419 */ "with ::= WITH wqlist", - /* 420 */ "with ::= WITH RECURSIVE wqlist", - /* 421 */ "wqlist ::= nm idxlist_opt AS LP select RP", - /* 422 */ "wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP", - /* 423 */ "wqlist ::= ID_TAB_NEW", + /* 176 */ "singlesrc ::= nm dbnm LP exprlist RP as", + /* 177 */ "singlesrc ::=", + /* 178 */ "singlesrc ::= nm DOT", + /* 179 */ "singlesrc ::= nm DOT ID_TAB", + /* 180 */ "singlesrc ::= ID_DB|ID_TAB", + /* 181 */ "singlesrc ::= nm DOT ID_VIEW", + /* 182 */ "singlesrc ::= ID_DB|ID_VIEW", + /* 183 */ "joinconstr_opt ::= ON expr", + /* 184 */ "joinconstr_opt ::= USING LP idlist RP", + /* 185 */ "joinconstr_opt ::=", + /* 186 */ "dbnm ::=", + /* 187 */ "dbnm ::= DOT nm", + /* 188 */ "fullname ::= nm dbnm", + /* 189 */ "joinop ::= COMMA", + /* 190 */ "joinop ::= JOIN", + /* 191 */ "joinop ::= JOIN_KW JOIN", + /* 192 */ "joinop ::= JOIN_KW nm JOIN", + /* 193 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 194 */ "joinop ::= ID_JOIN_OPTS", + /* 195 */ "indexed_opt ::=", + /* 196 */ "indexed_opt ::= INDEXED BY nm", + /* 197 */ "indexed_opt ::= NOT INDEXED", + /* 198 */ "indexed_opt ::= INDEXED BY ID_IDX", + /* 199 */ "orderby_opt ::=", + /* 200 */ "orderby_opt ::= ORDER BY sortlist", + /* 201 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 202 */ "sortlist ::= expr sortorder", + /* 203 */ "sortorder ::= ASC", + /* 204 */ "sortorder ::= DESC", + /* 205 */ "sortorder ::=", + /* 206 */ "groupby_opt ::=", + /* 207 */ "groupby_opt ::= GROUP BY nexprlist", + /* 208 */ "groupby_opt ::= GROUP BY", + /* 209 */ "having_opt ::=", + /* 210 */ "having_opt ::= HAVING expr", + /* 211 */ "limit_opt ::=", + /* 212 */ "limit_opt ::= LIMIT expr", + /* 213 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 214 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 215 */ "cmd ::= delete_stmt", + /* 216 */ "delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt", + /* 217 */ "delete_stmt ::= with DELETE FROM", + /* 218 */ "delete_stmt ::= with DELETE FROM nm DOT", + /* 219 */ "delete_stmt ::= with DELETE FROM nm DOT ID_TAB", + /* 220 */ "delete_stmt ::= with DELETE FROM ID_DB|ID_TAB", + /* 221 */ "where_opt ::=", + /* 222 */ "where_opt ::= WHERE expr", + /* 223 */ "where_opt ::= WHERE", + /* 224 */ "cmd ::= update_stmt", + /* 225 */ "update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", + /* 226 */ "update_stmt ::= with UPDATE orconf", + /* 227 */ "update_stmt ::= with UPDATE orconf nm DOT", + /* 228 */ "update_stmt ::= with UPDATE orconf nm DOT ID_TAB", + /* 229 */ "update_stmt ::= with UPDATE orconf ID_DB|ID_TAB", + /* 230 */ "setlist ::= setlist COMMA nm EQ expr", + /* 231 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 232 */ "setlist ::= nm EQ expr", + /* 233 */ "setlist ::= LP idlist RP EQ expr", + /* 234 */ "setlist ::=", + /* 235 */ "setlist ::= setlist COMMA", + /* 236 */ "setlist ::= setlist COMMA ID_COL", + /* 237 */ "setlist ::= ID_COL", + /* 238 */ "idlist_opt ::=", + /* 239 */ "idlist_opt ::= LP idlist RP", + /* 240 */ "idlist ::= idlist COMMA nm", + /* 241 */ "idlist ::= nm", + /* 242 */ "idlist ::=", + /* 243 */ "idlist ::= idlist COMMA ID_COL", + /* 244 */ "idlist ::= ID_COL", + /* 245 */ "cmd ::= insert_stmt", + /* 246 */ "insert_stmt ::= with insert_cmd INTO fullname idlist_opt select upsert", + /* 247 */ "insert_stmt ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", + /* 248 */ "insert_stmt ::= with insert_cmd INTO", + /* 249 */ "insert_stmt ::= with insert_cmd INTO nm DOT", + /* 250 */ "insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB", + /* 251 */ "insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB", + /* 252 */ "insert_cmd ::= INSERT orconf", + /* 253 */ "insert_cmd ::= REPLACE", + /* 254 */ "upsert ::=", + /* 255 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt", + /* 256 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING", + /* 257 */ "upsert ::= ON CONFLICT DO NOTHING", + /* 258 */ "exprx ::= nm DOT", + /* 259 */ "exprx ::= nm DOT nm DOT", + /* 260 */ "exprx ::= expr not_opt BETWEEN expr AND", + /* 261 */ "exprx ::= CASE case_operand case_exprlist case_else", + /* 262 */ "exprx ::= expr not_opt IN LP exprlist", + /* 263 */ "exprx ::= expr not_opt IN ID_DB", + /* 264 */ "exprx ::= expr not_opt IN nm DOT ID_TAB", + /* 265 */ "exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN", + /* 266 */ "exprx ::= nm DOT ID_TAB|ID_COL", + /* 267 */ "exprx ::= nm DOT nm DOT ID_COL", + /* 268 */ "exprx ::= expr COLLATE ID_COLLATE", + /* 269 */ "exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP", + /* 270 */ "exprx ::= term", + /* 271 */ "exprx ::= CTIME_KW", + /* 272 */ "exprx ::= LP nexprlist RP", + /* 273 */ "exprx ::= id", + /* 274 */ "exprx ::= JOIN_KW", + /* 275 */ "exprx ::= nm DOT nm", + /* 276 */ "exprx ::= nm DOT nm DOT nm", + /* 277 */ "exprx ::= VARIABLE", + /* 278 */ "exprx ::= expr COLLATE ids", + /* 279 */ "exprx ::= CAST LP expr AS typetoken RP", + /* 280 */ "exprx ::= ID LP distinct exprlist RP", + /* 281 */ "exprx ::= ID LP STAR RP", + /* 282 */ "exprx ::= expr AND expr", + /* 283 */ "exprx ::= expr OR expr", + /* 284 */ "exprx ::= expr LT|GT|GE|LE expr", + /* 285 */ "exprx ::= expr EQ|NE expr", + /* 286 */ "exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 287 */ "exprx ::= expr PLUS|MINUS expr", + /* 288 */ "exprx ::= expr STAR|SLASH|REM expr", + /* 289 */ "exprx ::= expr CONCAT expr", + /* 290 */ "exprx ::= expr not_opt likeop expr", + /* 291 */ "exprx ::= expr not_opt likeop expr ESCAPE expr", + /* 292 */ "exprx ::= expr ISNULL|NOTNULL", + /* 293 */ "exprx ::= expr NOT NULL", + /* 294 */ "exprx ::= expr IS not_opt expr", + /* 295 */ "exprx ::= NOT expr", + /* 296 */ "exprx ::= BITNOT expr", + /* 297 */ "exprx ::= MINUS expr", + /* 298 */ "exprx ::= PLUS expr", + /* 299 */ "exprx ::= expr not_opt BETWEEN expr AND expr", + /* 300 */ "exprx ::= expr not_opt IN LP exprlist RP", + /* 301 */ "exprx ::= LP select RP", + /* 302 */ "exprx ::= expr not_opt IN LP select RP", + /* 303 */ "exprx ::= expr not_opt IN nm dbnm", + /* 304 */ "exprx ::= EXISTS LP select RP", + /* 305 */ "exprx ::= CASE case_operand case_exprlist case_else END", + /* 306 */ "exprx ::= RAISE LP IGNORE RP", + /* 307 */ "exprx ::= RAISE LP raisetype COMMA nm RP", + /* 308 */ "expr ::=", + /* 309 */ "expr ::= exprx", + /* 310 */ "not_opt ::=", + /* 311 */ "not_opt ::= NOT", + /* 312 */ "likeop ::= LIKE_KW|MATCH", + /* 313 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 314 */ "case_exprlist ::= WHEN expr THEN expr", + /* 315 */ "case_else ::= ELSE expr", + /* 316 */ "case_else ::=", + /* 317 */ "case_operand ::= exprx", + /* 318 */ "case_operand ::=", + /* 319 */ "exprlist ::= nexprlist", + /* 320 */ "exprlist ::=", + /* 321 */ "nexprlist ::= nexprlist COMMA expr", + /* 322 */ "nexprlist ::= exprx", + /* 323 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 324 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB", + /* 325 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW", + /* 326 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW", + /* 327 */ "uniqueflag ::= UNIQUE", + /* 328 */ "uniqueflag ::=", + /* 329 */ "idxlist_opt ::=", + /* 330 */ "idxlist_opt ::= LP idxlist RP", + /* 331 */ "idxlist ::= idxlist COMMA idxlist_single", + /* 332 */ "idxlist ::= idxlist_single", + /* 333 */ "idxlist_single ::= nm collate sortorder", + /* 334 */ "idxlist_single ::= ID_COL", + /* 335 */ "collate ::=", + /* 336 */ "collate ::= COLLATE ids", + /* 337 */ "collate ::= COLLATE ID_COLLATE", + /* 338 */ "cmd ::= DROP INDEX ifexists fullname", + /* 339 */ "cmd ::= DROP INDEX ifexists nm DOT ID_IDX", + /* 340 */ "cmd ::= DROP INDEX ifexists ID_DB|ID_IDX", + /* 341 */ "cmd ::= VACUUM", + /* 342 */ "cmd ::= VACUUM nm", + /* 343 */ "cmd ::= PRAGMA nm dbnm", + /* 344 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 345 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 346 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 347 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 348 */ "cmd ::= PRAGMA nm DOT ID_PRAGMA", + /* 349 */ "cmd ::= PRAGMA ID_DB|ID_PRAGMA", + /* 350 */ "nmnum ::= plus_num", + /* 351 */ "nmnum ::= nm", + /* 352 */ "nmnum ::= ON", + /* 353 */ "nmnum ::= DELETE", + /* 354 */ "nmnum ::= DEFAULT", + /* 355 */ "plus_num ::= PLUS number", + /* 356 */ "plus_num ::= number", + /* 357 */ "minus_num ::= MINUS number", + /* 358 */ "number ::= INTEGER", + /* 359 */ "number ::= FLOAT", + /* 360 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END", + /* 361 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause", + /* 362 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list", + /* 363 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB", + /* 364 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW", + /* 365 */ "cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW", + /* 366 */ "trigger_time ::= BEFORE", + /* 367 */ "trigger_time ::= AFTER", + /* 368 */ "trigger_time ::= INSTEAD OF", + /* 369 */ "trigger_time ::=", + /* 370 */ "trigger_event ::= DELETE", + /* 371 */ "trigger_event ::= INSERT", + /* 372 */ "trigger_event ::= UPDATE", + /* 373 */ "trigger_event ::= UPDATE OF idlist", + /* 374 */ "foreach_clause ::=", + /* 375 */ "foreach_clause ::= FOR EACH ROW", + /* 376 */ "when_clause ::=", + /* 377 */ "when_clause ::= WHEN expr", + /* 378 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 379 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 380 */ "trigger_cmd_list ::= SEMI", + /* 381 */ "trigger_cmd ::= update_stmt", + /* 382 */ "trigger_cmd ::= insert_stmt", + /* 383 */ "trigger_cmd ::= delete_stmt", + /* 384 */ "trigger_cmd ::= select_stmt", + /* 385 */ "raisetype ::= ROLLBACK|ABORT|FAIL", + /* 386 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 387 */ "cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG", + /* 388 */ "cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG", + /* 389 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 390 */ "cmd ::= DETACH database_kw_opt expr", + /* 391 */ "key_opt ::=", + /* 392 */ "key_opt ::= KEY expr", + /* 393 */ "database_kw_opt ::= DATABASE", + /* 394 */ "database_kw_opt ::=", + /* 395 */ "cmd ::= REINDEX", + /* 396 */ "cmd ::= REINDEX nm dbnm", + /* 397 */ "cmd ::= REINDEX ID_COLLATE", + /* 398 */ "cmd ::= REINDEX nm DOT ID_TAB|ID_IDX", + /* 399 */ "cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB", + /* 400 */ "cmd ::= ANALYZE", + /* 401 */ "cmd ::= ANALYZE nm dbnm", + /* 402 */ "cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX", + /* 403 */ "cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB", + /* 404 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 405 */ "cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column", + /* 406 */ "cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW", + /* 407 */ "cmd ::= ALTER TABLE nm DOT ID_TAB", + /* 408 */ "cmd ::= ALTER TABLE ID_DB|ID_TAB", + /* 409 */ "kwcolumn_opt ::=", + /* 410 */ "kwcolumn_opt ::= COLUMNKW", + /* 411 */ "cmd ::= create_vtab", + /* 412 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 413 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP", + /* 414 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW", + /* 415 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW", + /* 416 */ "vtabarglist ::= vtabarg", + /* 417 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 418 */ "vtabarg ::=", + /* 419 */ "vtabarg ::= vtabarg vtabargtoken", + /* 420 */ "vtabargtoken ::= ANY", + /* 421 */ "vtabargtoken ::= LP anylist RP", + /* 422 */ "anylist ::=", + /* 423 */ "anylist ::= anylist LP anylist RP", + /* 424 */ "anylist ::= anylist ANY", + /* 425 */ "with ::=", + /* 426 */ "with ::= WITH wqlist", + /* 427 */ "with ::= WITH RECURSIVE wqlist", + /* 428 */ "wqlist ::= nm idxlist_opt AS LP select RP", + /* 429 */ "wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP", + /* 430 */ "wqlist ::= ID_TAB_NEW", }; #endif /* NDEBUG */ @@ -1671,309 +1709,314 @@ static void yy_destructor( ** which appear on the RHS of the rule, but which are not used ** inside the C code. */ - case 169: /* cmd */ - case 172: /* ecmd */ - case 174: /* cmdx */ - case 218: /* select_stmt */ - case 245: /* delete_stmt */ - case 246: /* update_stmt */ - case 248: /* insert_stmt */ - case 267: /* trigger_cmd */ - case 271: /* create_vtab */ -{ -delete (yypminor->yy399); + case 171: /* cmd */ + case 174: /* ecmd */ + case 176: /* cmdx */ + case 220: /* select_stmt */ + case 247: /* delete_stmt */ + case 248: /* update_stmt */ + case 251: /* insert_stmt */ + case 270: /* trigger_cmd */ + case 274: /* create_vtab */ +{ +delete (yypminor->yy283); } break; - case 173: /* explain */ + case 175: /* explain */ { -delete (yypminor->yy225); +delete (yypminor->yy411); } break; - case 175: /* transtype */ - case 176: /* trans_opt */ + case 177: /* transtype */ + case 178: /* trans_opt */ { -delete (yypminor->yy300); +delete (yypminor->yy404); } break; - case 177: /* nm */ - case 184: /* table_options */ - case 187: /* columnid */ - case 190: /* id */ - case 191: /* ids */ - case 193: /* typename */ - case 241: /* dbnm */ - case 259: /* collate */ - case 273: /* vtabarg */ - case 274: /* vtabargtoken */ - case 275: /* anylist */ -{ -delete (yypminor->yy211); + case 179: /* nm */ + case 186: /* table_options */ + case 189: /* columnid */ + case 192: /* id */ + case 193: /* ids */ + case 195: /* typename */ + case 243: /* dbnm */ + case 262: /* collate */ + case 276: /* vtabarg */ + case 277: /* vtabargtoken */ + case 278: /* anylist */ +{ +delete (yypminor->yy399); } break; - case 178: /* savepoint_opt */ - case 180: /* ifnotexists */ - case 202: /* autoinc */ - case 210: /* tconscomma */ - case 217: /* ifexists */ - case 252: /* not_opt */ - case 257: /* uniqueflag */ - case 268: /* database_kw_opt */ - case 270: /* kwcolumn_opt */ -{ -delete (yypminor->yy237); + case 180: /* savepoint_opt */ + case 182: /* ifnotexists */ + case 204: /* autoinc */ + case 212: /* tconscomma */ + case 219: /* ifexists */ + case 255: /* not_opt */ + case 260: /* uniqueflag */ + case 271: /* database_kw_opt */ + case 273: /* kwcolumn_opt */ +{ +delete (yypminor->yy451); } break; - case 179: /* temp */ - case 224: /* distinct */ + case 181: /* temp */ + case 226: /* distinct */ { -delete (yypminor->yy376); +delete (yypminor->yy146); } break; - case 181: /* fullname */ + case 183: /* fullname */ { -delete (yypminor->yy66); +delete (yypminor->yy360); } break; - case 182: /* columnlist */ + case 184: /* columnlist */ { -delete (yypminor->yy118); +delete (yypminor->yy202); } break; - case 183: /* conslist_opt */ - case 209: /* conslist */ + case 185: /* conslist_opt */ + case 211: /* conslist */ { -delete (yypminor->yy87); +delete (yypminor->yy333); } break; - case 185: /* select */ - case 220: /* selectnowith */ + case 187: /* select */ + case 222: /* selectnowith */ { -delete (yypminor->yy123); +delete (yypminor->yy473); } break; - case 186: /* column */ + case 188: /* column */ { -delete (yypminor->yy425); +delete (yypminor->yy227); } break; - case 188: /* type */ - case 192: /* typetoken */ + case 190: /* type */ + case 194: /* typetoken */ { -delete (yypminor->yy299); +delete (yypminor->yy537); } break; - case 189: /* carglist */ + case 191: /* carglist */ { -delete (yypminor->yy449); +delete (yypminor->yy51); } break; - case 194: /* signed */ - case 195: /* plus_num */ - case 196: /* minus_num */ - case 198: /* term */ - case 260: /* nmnum */ - case 261: /* number */ -{ -delete (yypminor->yy21); + case 196: /* signed */ + case 197: /* plus_num */ + case 198: /* minus_num */ + case 200: /* term */ + case 263: /* nmnum */ + case 264: /* number */ +{ +delete (yypminor->yy469); } break; - case 197: /* ccons */ + case 199: /* ccons */ { -delete (yypminor->yy4); +delete (yypminor->yy304); } break; - case 199: /* expr */ - case 227: /* where_opt */ - case 229: /* having_opt */ - case 251: /* exprx */ - case 253: /* case_operand */ - case 255: /* case_else */ -{ -delete (yypminor->yy490); + case 201: /* expr */ + case 229: /* where_opt */ + case 231: /* having_opt */ + case 254: /* exprx */ + case 256: /* case_operand */ + case 258: /* case_else */ +{ +delete (yypminor->yy352); } break; - case 200: /* onconf */ - case 214: /* resolvetype */ - case 215: /* orconf */ + case 202: /* onconf */ + case 216: /* resolvetype */ + case 217: /* orconf */ { -delete (yypminor->yy30); +delete (yypminor->yy338); } break; - case 201: /* sortorder */ + case 203: /* sortorder */ { -delete (yypminor->yy226); +delete (yypminor->yy309); } break; - case 203: /* idxlist_opt */ - case 212: /* idxlist */ + case 205: /* idxlist_opt */ + case 214: /* idxlist */ { -delete (yypminor->yy139); +delete (yypminor->yy223); } break; - case 204: /* refargs */ + case 206: /* refargs */ { -delete (yypminor->yy108); +delete (yypminor->yy184); } break; - case 205: /* defer_subclause */ - case 213: /* defer_subclause_opt */ + case 207: /* defer_subclause */ + case 215: /* defer_subclause_opt */ { -delete (yypminor->yy131); +delete (yypminor->yy329); } break; - case 206: /* refarg */ + case 208: /* refarg */ { -delete (yypminor->yy271); +delete (yypminor->yy347); } break; - case 207: /* refact */ + case 209: /* refact */ { -delete (yypminor->yy312); +delete (yypminor->yy104); } break; - case 208: /* init_deferred_pred_opt */ + case 210: /* init_deferred_pred_opt */ { -delete (yypminor->yy498); +delete (yypminor->yy392); } break; - case 211: /* tcons */ + case 213: /* tcons */ { -delete (yypminor->yy8); +delete (yypminor->yy406); } break; - case 219: /* with */ - case 276: /* wqlist */ + case 221: /* with */ + case 279: /* wqlist */ { -delete (yypminor->yy367); +delete (yypminor->yy321); } break; - case 221: /* oneselect */ + case 223: /* oneselect */ { -delete (yypminor->yy468); +delete (yypminor->yy310); } break; - case 222: /* multiselect_op */ + case 224: /* multiselect_op */ { -delete (yypminor->yy168); +delete (yypminor->yy462); } break; - case 223: /* values */ + case 225: /* values */ { -delete (yypminor->yy416); +delete (yypminor->yy166); } break; - case 225: /* selcollist */ - case 234: /* sclp */ + case 227: /* selcollist */ + case 236: /* sclp */ { -delete (yypminor->yy263); +delete (yypminor->yy373); } break; - case 226: /* from */ - case 236: /* joinsrc */ + case 228: /* from */ + case 238: /* joinsrc */ { -delete (yypminor->yy373); +delete (yypminor->yy511); } break; - case 228: /* groupby_opt */ - case 232: /* nexprlist */ - case 233: /* exprlist */ - case 254: /* case_exprlist */ + case 230: /* groupby_opt */ + case 234: /* nexprlist */ + case 235: /* exprlist */ + case 257: /* case_exprlist */ { -delete (yypminor->yy13); +delete (yypminor->yy551); } break; - case 230: /* orderby_opt */ - case 244: /* sortlist */ + case 232: /* orderby_opt */ + case 246: /* sortlist */ { -delete (yypminor->yy495); +delete (yypminor->yy163); } break; - case 231: /* limit_opt */ + case 233: /* limit_opt */ { -delete (yypminor->yy128); +delete (yypminor->yy484); } break; - case 235: /* as */ + case 237: /* as */ { -delete (yypminor->yy28); +delete (yypminor->yy200); } break; - case 237: /* singlesrc */ + case 239: /* singlesrc */ { -delete (yypminor->yy173); +delete (yypminor->yy201); } break; - case 238: /* seltablist */ + case 240: /* seltablist */ { -delete (yypminor->yy359); +delete (yypminor->yy131); } break; - case 239: /* joinop */ + case 241: /* joinop */ { -delete (yypminor->yy473); +delete (yypminor->yy301); } break; - case 240: /* joinconstr_opt */ + case 242: /* joinconstr_opt */ { -delete (yypminor->yy117); +delete (yypminor->yy295); } break; - case 242: /* indexed_opt */ + case 244: /* indexed_opt */ { -delete (yypminor->yy472); +delete (yypminor->yy192); } break; - case 243: /* inscollist */ - case 250: /* inscollist_opt */ - case 272: /* vtabarglist */ + case 245: /* idlist */ + case 250: /* idlist_opt */ + case 275: /* vtabarglist */ { -delete (yypminor->yy445); +delete (yypminor->yy95); } break; - case 247: /* setlist */ + case 249: /* setlist */ { -delete (yypminor->yy381); +delete (yypminor->yy521); } break; - case 249: /* insert_cmd */ + case 252: /* insert_cmd */ { -delete (yypminor->yy250); +delete (yypminor->yy105); } break; - case 256: /* likeop */ + case 253: /* upsert */ { -delete (yypminor->yy374); +delete (yypminor->yy560); } break; - case 258: /* idxlist_single */ + case 259: /* likeop */ { -delete (yypminor->yy90); +delete (yypminor->yy520); } break; - case 262: /* trigger_time */ + case 261: /* idxlist_single */ { -delete (yypminor->yy152); +delete (yypminor->yy108); } break; - case 263: /* trigger_event */ + case 265: /* trigger_time */ { -delete (yypminor->yy309); +delete (yypminor->yy132); +} + break; + case 266: /* trigger_event */ +{ +delete (yypminor->yy552); } break; - case 264: /* foreach_clause */ + case 267: /* foreach_clause */ { -delete (yypminor->yy409); +delete (yypminor->yy3); } break; - case 265: /* when_clause */ - case 269: /* key_opt */ + case 268: /* when_clause */ + case 272: /* key_opt */ { -if ((yypminor->yy490)) delete (yypminor->yy490); +if ((yypminor->yy352)) delete (yypminor->yy352); } break; - case 266: /* trigger_cmd_list */ + case 269: /* trigger_cmd_list */ { -delete (yypminor->yy214); +delete (yypminor->yy430); } break; default: break; /* If no destructor action specified: do nothing */ @@ -2224,430 +2267,437 @@ static const struct { YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ unsigned char nrhs; /* Number of right-hand side symbols in the rule */ } yyRuleInfo[] = { - { 170, 1 }, - { 171, 2 }, - { 171, 1 }, { 172, 1 }, - { 172, 3 }, - { 173, 0 }, + { 173, 2 }, { 173, 1 }, - { 173, 3 }, { 174, 1 }, - { 169, 3 }, - { 176, 0 }, - { 176, 1 }, - { 176, 2 }, - { 176, 2 }, + { 174, 3 }, { 175, 0 }, { 175, 1 }, - { 175, 1 }, - { 175, 1 }, - { 169, 2 }, - { 169, 2 }, - { 169, 2 }, - { 178, 1 }, + { 175, 3 }, + { 176, 1 }, + { 171, 3 }, { 178, 0 }, - { 169, 2 }, - { 169, 3 }, - { 169, 5 }, - { 169, 2 }, - { 169, 3 }, - { 169, 5 }, - { 169, 10 }, - { 169, 7 }, - { 169, 7 }, - { 169, 5 }, - { 184, 0 }, - { 184, 2 }, - { 184, 2 }, - { 180, 0 }, - { 180, 3 }, - { 179, 1 }, - { 179, 0 }, - { 182, 3 }, - { 182, 1 }, - { 186, 3 }, - { 187, 1 }, - { 187, 1 }, - { 190, 1 }, - { 191, 1 }, + { 178, 1 }, + { 178, 2 }, + { 178, 2 }, + { 177, 0 }, { 177, 1 }, { 177, 1 }, { 177, 1 }, - { 188, 0 }, - { 188, 1 }, + { 171, 2 }, + { 171, 2 }, + { 171, 2 }, + { 180, 1 }, + { 180, 0 }, + { 171, 2 }, + { 171, 3 }, + { 171, 5 }, + { 171, 2 }, + { 171, 3 }, + { 171, 5 }, + { 171, 10 }, + { 171, 7 }, + { 171, 7 }, + { 171, 5 }, + { 186, 0 }, + { 186, 2 }, + { 186, 2 }, + { 182, 0 }, + { 182, 3 }, + { 181, 1 }, + { 181, 0 }, + { 184, 3 }, + { 184, 1 }, + { 188, 3 }, + { 189, 1 }, + { 189, 1 }, { 192, 1 }, - { 192, 4 }, - { 192, 6 }, - { 193, 1 }, - { 193, 2 }, { 193, 1 }, + { 179, 1 }, + { 179, 1 }, + { 179, 1 }, + { 190, 0 }, + { 190, 1 }, { 194, 1 }, - { 194, 1 }, - { 189, 2 }, - { 189, 0 }, - { 197, 2 }, - { 197, 2 }, - { 197, 4 }, - { 197, 3 }, - { 197, 3 }, - { 197, 2 }, - { 197, 2 }, - { 197, 2 }, - { 197, 3 }, - { 197, 5 }, - { 197, 2 }, - { 197, 4 }, - { 197, 4 }, - { 197, 1 }, - { 197, 2 }, - { 197, 2 }, - { 197, 2 }, - { 197, 2 }, - { 197, 3 }, - { 198, 1 }, - { 198, 1 }, - { 198, 1 }, - { 198, 1 }, - { 202, 0 }, - { 202, 1 }, + { 194, 4 }, + { 194, 6 }, + { 195, 1 }, + { 195, 2 }, + { 195, 1 }, + { 196, 1 }, + { 196, 1 }, + { 191, 2 }, + { 191, 0 }, + { 199, 2 }, + { 199, 2 }, + { 199, 4 }, + { 199, 3 }, + { 199, 3 }, + { 199, 2 }, + { 199, 2 }, + { 199, 2 }, + { 199, 3 }, + { 199, 5 }, + { 199, 2 }, + { 199, 4 }, + { 199, 4 }, + { 199, 1 }, + { 199, 2 }, + { 199, 2 }, + { 199, 2 }, + { 199, 2 }, + { 199, 3 }, + { 200, 1 }, + { 200, 1 }, + { 200, 1 }, + { 200, 1 }, { 204, 0 }, - { 204, 2 }, + { 204, 1 }, + { 206, 0 }, { 206, 2 }, - { 206, 3 }, - { 206, 3 }, - { 206, 3 }, - { 206, 2 }, - { 207, 2 }, - { 207, 2 }, - { 207, 1 }, - { 207, 1 }, - { 207, 2 }, - { 205, 3 }, - { 205, 2 }, - { 208, 0 }, { 208, 2 }, + { 208, 3 }, + { 208, 3 }, + { 208, 3 }, { 208, 2 }, - { 183, 0 }, - { 183, 2 }, - { 209, 3 }, + { 209, 2 }, + { 209, 2 }, + { 209, 1 }, { 209, 1 }, - { 210, 1 }, + { 209, 2 }, + { 207, 3 }, + { 207, 2 }, { 210, 0 }, - { 211, 2 }, - { 211, 7 }, - { 211, 5 }, - { 211, 5 }, - { 211, 10 }, - { 211, 2 }, - { 211, 7 }, - { 211, 4 }, - { 213, 0 }, - { 213, 1 }, - { 200, 0 }, - { 200, 3 }, + { 210, 2 }, + { 210, 2 }, + { 185, 0 }, + { 185, 2 }, + { 211, 3 }, + { 211, 1 }, + { 212, 1 }, + { 212, 0 }, + { 213, 2 }, + { 213, 7 }, + { 213, 5 }, + { 213, 5 }, + { 213, 10 }, + { 213, 2 }, + { 213, 7 }, + { 213, 4 }, { 215, 0 }, - { 215, 2 }, - { 214, 1 }, - { 214, 1 }, - { 214, 1 }, - { 169, 4 }, - { 169, 6 }, - { 169, 4 }, - { 217, 2 }, + { 215, 1 }, + { 202, 0 }, + { 202, 3 }, { 217, 0 }, - { 169, 8 }, - { 169, 7 }, - { 169, 5 }, - { 169, 4 }, - { 169, 6 }, - { 169, 4 }, - { 169, 1 }, - { 218, 1 }, - { 185, 2 }, - { 220, 1 }, - { 220, 3 }, + { 217, 2 }, + { 216, 1 }, + { 216, 1 }, + { 216, 1 }, + { 171, 4 }, + { 171, 6 }, + { 171, 4 }, + { 219, 2 }, + { 219, 0 }, + { 171, 8 }, + { 171, 7 }, + { 171, 5 }, + { 171, 4 }, + { 171, 6 }, + { 171, 4 }, + { 171, 1 }, { 220, 1 }, - { 220, 3 }, - { 222, 1 }, - { 222, 2 }, + { 187, 2 }, { 222, 1 }, + { 222, 3 }, { 222, 1 }, - { 221, 9 }, - { 223, 4 }, - { 223, 5 }, + { 222, 3 }, + { 223, 9 }, + { 225, 4 }, + { 225, 5 }, { 224, 1 }, + { 224, 2 }, { 224, 1 }, - { 224, 0 }, - { 234, 2 }, - { 234, 0 }, - { 225, 3 }, - { 225, 2 }, - { 225, 4 }, - { 225, 1 }, - { 225, 4 }, - { 235, 2 }, - { 235, 1 }, - { 235, 2 }, - { 235, 1 }, - { 235, 0 }, + { 224, 1 }, + { 226, 1 }, + { 226, 1 }, { 226, 0 }, - { 226, 2 }, { 236, 2 }, { 236, 0 }, - { 238, 4 }, - { 238, 0 }, - { 237, 4 }, - { 237, 4 }, - { 237, 4 }, - { 237, 0 }, + { 227, 3 }, + { 227, 2 }, + { 227, 4 }, + { 227, 1 }, + { 227, 4 }, { 237, 2 }, - { 237, 3 }, { 237, 1 }, - { 237, 3 }, + { 237, 2 }, { 237, 1 }, - { 240, 2 }, + { 237, 0 }, + { 228, 0 }, + { 228, 2 }, + { 238, 2 }, + { 238, 0 }, { 240, 4 }, { 240, 0 }, - { 241, 0 }, - { 241, 2 }, - { 181, 2 }, - { 239, 1 }, - { 239, 1 }, + { 239, 4 }, + { 239, 4 }, + { 239, 4 }, + { 239, 6 }, + { 239, 0 }, { 239, 2 }, { 239, 3 }, - { 239, 4 }, { 239, 1 }, - { 242, 0 }, - { 242, 3 }, + { 239, 3 }, + { 239, 1 }, { 242, 2 }, - { 242, 3 }, + { 242, 4 }, + { 242, 0 }, + { 243, 0 }, + { 243, 2 }, + { 183, 2 }, + { 241, 1 }, + { 241, 1 }, + { 241, 2 }, + { 241, 3 }, + { 241, 4 }, + { 241, 1 }, + { 244, 0 }, + { 244, 3 }, + { 244, 2 }, + { 244, 3 }, + { 232, 0 }, + { 232, 3 }, + { 246, 4 }, + { 246, 2 }, + { 203, 1 }, + { 203, 1 }, + { 203, 0 }, { 230, 0 }, { 230, 3 }, - { 244, 4 }, - { 244, 2 }, - { 201, 1 }, - { 201, 1 }, - { 201, 0 }, - { 228, 0 }, - { 228, 3 }, - { 228, 2 }, - { 229, 0 }, - { 229, 2 }, + { 230, 2 }, { 231, 0 }, { 231, 2 }, - { 231, 4 }, - { 231, 4 }, - { 169, 1 }, - { 245, 6 }, - { 245, 3 }, - { 245, 5 }, - { 245, 6 }, - { 245, 4 }, - { 227, 0 }, - { 227, 2 }, - { 227, 1 }, - { 169, 1 }, - { 246, 8 }, - { 246, 3 }, - { 246, 5 }, - { 246, 6 }, - { 246, 4 }, - { 247, 5 }, - { 247, 3 }, - { 247, 0 }, - { 247, 2 }, + { 233, 0 }, + { 233, 2 }, + { 233, 4 }, + { 233, 4 }, + { 171, 1 }, + { 247, 6 }, { 247, 3 }, - { 247, 1 }, - { 169, 1 }, - { 248, 6 }, - { 248, 7 }, + { 247, 5 }, + { 247, 6 }, + { 247, 4 }, + { 229, 0 }, + { 229, 2 }, + { 229, 1 }, + { 171, 1 }, + { 248, 8 }, { 248, 3 }, { 248, 5 }, - { 248, 4 }, { 248, 6 }, + { 248, 4 }, + { 249, 5 }, + { 249, 7 }, + { 249, 3 }, + { 249, 5 }, + { 249, 0 }, { 249, 2 }, + { 249, 3 }, { 249, 1 }, { 250, 0 }, { 250, 3 }, - { 243, 3 }, - { 243, 1 }, - { 243, 0 }, - { 243, 3 }, - { 243, 1 }, - { 251, 2 }, - { 251, 4 }, - { 251, 5 }, - { 251, 4 }, - { 251, 5 }, - { 251, 4 }, - { 251, 6 }, - { 251, 1 }, - { 251, 3 }, - { 251, 5 }, - { 251, 3 }, - { 251, 6 }, - { 251, 1 }, - { 251, 1 }, - { 251, 3 }, - { 251, 1 }, - { 251, 1 }, - { 251, 3 }, - { 251, 5 }, - { 251, 1 }, - { 251, 3 }, - { 251, 6 }, - { 251, 5 }, - { 251, 4 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 3 }, - { 251, 4 }, - { 251, 6 }, - { 251, 2 }, - { 251, 3 }, - { 251, 4 }, - { 251, 2 }, - { 251, 2 }, - { 251, 2 }, - { 251, 2 }, - { 251, 6 }, - { 251, 6 }, + { 245, 3 }, + { 245, 1 }, + { 245, 0 }, + { 245, 3 }, + { 245, 1 }, + { 171, 1 }, + { 251, 7 }, + { 251, 7 }, { 251, 3 }, - { 251, 6 }, - { 251, 5 }, - { 251, 4 }, { 251, 5 }, { 251, 4 }, { 251, 6 }, - { 199, 0 }, - { 199, 1 }, - { 252, 0 }, + { 252, 2 }, { 252, 1 }, - { 256, 1 }, + { 253, 0 }, + { 253, 11 }, + { 253, 8 }, + { 253, 4 }, + { 254, 2 }, + { 254, 4 }, + { 254, 5 }, + { 254, 4 }, + { 254, 5 }, + { 254, 4 }, + { 254, 6 }, + { 254, 1 }, + { 254, 3 }, + { 254, 5 }, + { 254, 3 }, + { 254, 6 }, + { 254, 1 }, + { 254, 1 }, + { 254, 3 }, + { 254, 1 }, + { 254, 1 }, + { 254, 3 }, + { 254, 5 }, + { 254, 1 }, + { 254, 3 }, + { 254, 6 }, + { 254, 5 }, + { 254, 4 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 3 }, + { 254, 4 }, + { 254, 6 }, + { 254, 2 }, + { 254, 3 }, + { 254, 4 }, + { 254, 2 }, + { 254, 2 }, + { 254, 2 }, + { 254, 2 }, + { 254, 6 }, + { 254, 6 }, + { 254, 3 }, + { 254, 6 }, { 254, 5 }, { 254, 4 }, - { 255, 2 }, + { 254, 5 }, + { 254, 4 }, + { 254, 6 }, + { 201, 0 }, + { 201, 1 }, { 255, 0 }, - { 253, 1 }, - { 253, 0 }, - { 233, 1 }, - { 233, 0 }, - { 232, 3 }, - { 232, 1 }, - { 169, 12 }, - { 169, 8 }, - { 169, 7 }, - { 169, 5 }, - { 257, 1 }, - { 257, 0 }, - { 203, 0 }, - { 203, 3 }, - { 212, 3 }, - { 212, 1 }, - { 258, 3 }, - { 258, 1 }, - { 259, 0 }, - { 259, 2 }, - { 259, 2 }, - { 169, 4 }, - { 169, 6 }, - { 169, 4 }, - { 169, 1 }, - { 169, 2 }, - { 169, 3 }, - { 169, 5 }, - { 169, 6 }, - { 169, 5 }, - { 169, 6 }, - { 169, 4 }, - { 169, 2 }, - { 260, 1 }, - { 260, 1 }, - { 260, 1 }, - { 260, 1 }, + { 255, 1 }, + { 259, 1 }, + { 257, 5 }, + { 257, 4 }, + { 258, 2 }, + { 258, 0 }, + { 256, 1 }, + { 256, 0 }, + { 235, 1 }, + { 235, 0 }, + { 234, 3 }, + { 234, 1 }, + { 171, 12 }, + { 171, 8 }, + { 171, 7 }, + { 171, 5 }, { 260, 1 }, - { 195, 2 }, - { 195, 1 }, - { 196, 2 }, - { 261, 1 }, + { 260, 0 }, + { 205, 0 }, + { 205, 3 }, + { 214, 3 }, + { 214, 1 }, + { 261, 3 }, { 261, 1 }, - { 169, 15 }, - { 169, 12 }, - { 169, 14 }, - { 169, 10 }, - { 169, 7 }, - { 169, 5 }, - { 262, 1 }, - { 262, 1 }, - { 262, 2 }, { 262, 0 }, + { 262, 2 }, + { 262, 2 }, + { 171, 4 }, + { 171, 6 }, + { 171, 4 }, + { 171, 1 }, + { 171, 2 }, + { 171, 3 }, + { 171, 5 }, + { 171, 6 }, + { 171, 5 }, + { 171, 6 }, + { 171, 4 }, + { 171, 2 }, { 263, 1 }, { 263, 1 }, { 263, 1 }, - { 263, 3 }, - { 264, 0 }, - { 264, 3 }, - { 265, 0 }, + { 263, 1 }, + { 263, 1 }, + { 197, 2 }, + { 197, 1 }, + { 198, 2 }, + { 264, 1 }, + { 264, 1 }, + { 171, 15 }, + { 171, 12 }, + { 171, 14 }, + { 171, 10 }, + { 171, 7 }, + { 171, 5 }, + { 265, 1 }, + { 265, 1 }, { 265, 2 }, - { 266, 3 }, - { 266, 2 }, + { 265, 0 }, { 266, 1 }, - { 267, 1 }, - { 267, 1 }, - { 267, 1 }, - { 267, 1 }, - { 216, 1 }, - { 169, 4 }, - { 169, 6 }, - { 169, 4 }, - { 169, 6 }, - { 169, 3 }, - { 269, 0 }, - { 269, 2 }, - { 268, 1 }, + { 266, 1 }, + { 266, 1 }, + { 266, 3 }, + { 267, 0 }, + { 267, 3 }, { 268, 0 }, - { 169, 1 }, - { 169, 3 }, - { 169, 2 }, - { 169, 4 }, - { 169, 2 }, - { 169, 1 }, - { 169, 3 }, - { 169, 4 }, - { 169, 2 }, - { 169, 6 }, - { 169, 6 }, - { 169, 6 }, - { 169, 5 }, - { 169, 3 }, - { 270, 0 }, + { 268, 2 }, + { 269, 3 }, + { 269, 2 }, + { 269, 1 }, + { 270, 1 }, + { 270, 1 }, + { 270, 1 }, { 270, 1 }, - { 169, 1 }, - { 271, 8 }, - { 271, 11 }, - { 271, 7 }, - { 271, 5 }, - { 272, 1 }, - { 272, 3 }, + { 218, 1 }, + { 171, 4 }, + { 171, 6 }, + { 171, 4 }, + { 171, 6 }, + { 171, 3 }, + { 272, 0 }, + { 272, 2 }, + { 271, 1 }, + { 271, 0 }, + { 171, 1 }, + { 171, 3 }, + { 171, 2 }, + { 171, 4 }, + { 171, 2 }, + { 171, 1 }, + { 171, 3 }, + { 171, 4 }, + { 171, 2 }, + { 171, 6 }, + { 171, 6 }, + { 171, 6 }, + { 171, 5 }, + { 171, 3 }, { 273, 0 }, - { 273, 2 }, - { 274, 1 }, - { 274, 3 }, - { 275, 0 }, - { 275, 4 }, - { 275, 2 }, - { 219, 0 }, - { 219, 2 }, - { 219, 3 }, - { 276, 6 }, - { 276, 8 }, - { 276, 1 }, + { 273, 1 }, + { 171, 1 }, + { 274, 8 }, + { 274, 11 }, + { 274, 7 }, + { 274, 5 }, + { 275, 1 }, + { 275, 3 }, + { 276, 0 }, + { 276, 2 }, + { 277, 1 }, + { 277, 3 }, + { 278, 0 }, + { 278, 4 }, + { 278, 2 }, + { 221, 0 }, + { 221, 2 }, + { 221, 3 }, + { 279, 6 }, + { 279, 8 }, + { 279, 1 }, }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -2707,119 +2757,119 @@ static void yy_reduce( ** break; */ case 1: /* cmdlist ::= cmdlist ecmd */ -{parserContext->addQuery(yymsp[0].minor.yy399); DONT_INHERIT_TOKENS("cmdlist");} +{parserContext->addQuery(yymsp[0].minor.yy283); DONT_INHERIT_TOKENS("cmdlist");} break; case 2: /* cmdlist ::= ecmd */ -{parserContext->addQuery(yymsp[0].minor.yy399);} +{parserContext->addQuery(yymsp[0].minor.yy283);} break; case 3: /* ecmd ::= SEMI */ -{yygotominor.yy399 = new SqliteEmptyQuery();} +{yygotominor.yy283 = new SqliteEmptyQuery();} break; case 4: /* ecmd ::= explain cmdx SEMI */ { - yygotominor.yy399 = yymsp[-1].minor.yy399; - yygotominor.yy399->explain = yymsp[-2].minor.yy225->explain; - yygotominor.yy399->queryPlan = yymsp[-2].minor.yy225->queryPlan; - delete yymsp[-2].minor.yy225; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = yymsp[-1].minor.yy283; + yygotominor.yy283->explain = yymsp[-2].minor.yy411->explain; + yygotominor.yy283->queryPlan = yymsp[-2].minor.yy411->queryPlan; + delete yymsp[-2].minor.yy411; + objectForTokens = yygotominor.yy283; } break; case 5: /* explain ::= */ -{yygotominor.yy225 = new ParserStubExplain(false, false);} +{yygotominor.yy411 = new ParserStubExplain(false, false);} break; case 6: /* explain ::= EXPLAIN */ -{yygotominor.yy225 = new ParserStubExplain(true, false);} +{yygotominor.yy411 = new ParserStubExplain(true, false);} break; case 7: /* explain ::= EXPLAIN QUERY PLAN */ -{yygotominor.yy225 = new ParserStubExplain(true, true);} +{yygotominor.yy411 = new ParserStubExplain(true, true);} break; case 8: /* cmdx ::= cmd */ - case 374: /* trigger_cmd ::= update_stmt */ yytestcase(yyruleno==374); - case 375: /* trigger_cmd ::= insert_stmt */ yytestcase(yyruleno==375); - case 376: /* trigger_cmd ::= delete_stmt */ yytestcase(yyruleno==376); - case 377: /* trigger_cmd ::= select_stmt */ yytestcase(yyruleno==377); - case 404: /* cmd ::= create_vtab */ yytestcase(yyruleno==404); -{yygotominor.yy399 = yymsp[0].minor.yy399;} + case 381: /* trigger_cmd ::= update_stmt */ yytestcase(yyruleno==381); + case 382: /* trigger_cmd ::= insert_stmt */ yytestcase(yyruleno==382); + case 383: /* trigger_cmd ::= delete_stmt */ yytestcase(yyruleno==383); + case 384: /* trigger_cmd ::= select_stmt */ yytestcase(yyruleno==384); + case 411: /* cmd ::= create_vtab */ yytestcase(yyruleno==411); +{yygotominor.yy283 = yymsp[0].minor.yy283;} break; case 9: /* cmd ::= BEGIN transtype trans_opt */ { - yygotominor.yy399 = new SqliteBeginTrans( - yymsp[-1].minor.yy300->type, - yymsp[0].minor.yy300->transactionKw, - yymsp[0].minor.yy300->name + yygotominor.yy283 = new SqliteBeginTrans( + yymsp[-1].minor.yy404->type, + yymsp[0].minor.yy404->transactionKw, + yymsp[0].minor.yy404->name ); - delete yymsp[0].minor.yy300; - delete yymsp[-1].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy404; + delete yymsp[-1].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 10: /* trans_opt ::= */ case 14: /* transtype ::= */ yytestcase(yyruleno==14); -{yygotominor.yy300 = new ParserStubTransDetails();} +{yygotominor.yy404 = new ParserStubTransDetails();} break; case 11: /* trans_opt ::= TRANSACTION */ { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->transactionKw = true; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->transactionKw = true; } break; case 12: /* trans_opt ::= TRANSACTION nm */ case 13: /* trans_opt ::= TRANSACTION ID_TRANS */ yytestcase(yyruleno==13); { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->transactionKw = true; - yygotominor.yy300->name = *(yymsp[0].minor.yy211); - delete yymsp[0].minor.yy211; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->transactionKw = true; + yygotominor.yy404->name = *(yymsp[0].minor.yy399); + delete yymsp[0].minor.yy399; } break; case 15: /* transtype ::= DEFERRED */ { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->type = SqliteBeginTrans::Type::DEFERRED; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->type = SqliteBeginTrans::Type::DEFERRED; } break; case 16: /* transtype ::= IMMEDIATE */ { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->type = SqliteBeginTrans::Type::IMMEDIATE; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->type = SqliteBeginTrans::Type::IMMEDIATE; } break; case 17: /* transtype ::= EXCLUSIVE */ { - yygotominor.yy300 = new ParserStubTransDetails(); - yygotominor.yy300->type = SqliteBeginTrans::Type::EXCLUSIVE; + yygotominor.yy404 = new ParserStubTransDetails(); + yygotominor.yy404->type = SqliteBeginTrans::Type::EXCLUSIVE; } break; case 18: /* cmd ::= COMMIT trans_opt */ { - yygotominor.yy399 = new SqliteCommitTrans( - yymsp[0].minor.yy300->transactionKw, - yymsp[0].minor.yy300->name, + yygotominor.yy283 = new SqliteCommitTrans( + yymsp[0].minor.yy404->transactionKw, + yymsp[0].minor.yy404->name, false ); - delete yymsp[0].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 19: /* cmd ::= END trans_opt */ { - yygotominor.yy399 = new SqliteCommitTrans( - yymsp[0].minor.yy300->transactionKw, - yymsp[0].minor.yy300->name, + yygotominor.yy283 = new SqliteCommitTrans( + yymsp[0].minor.yy404->transactionKw, + yymsp[0].minor.yy404->name, true ); - delete yymsp[0].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 20: /* cmd ::= ROLLBACK trans_opt */ { - yygotominor.yy399 = new SqliteRollback( - yymsp[0].minor.yy300->transactionKw, - yymsp[0].minor.yy300->name + yygotominor.yy283 = new SqliteRollback( + yymsp[0].minor.yy404->transactionKw, + yymsp[0].minor.yy404->name ); - delete yymsp[0].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 21: /* savepoint_opt ::= SAVEPOINT */ @@ -2827,159 +2877,159 @@ static void yy_reduce( case 86: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==86); case 108: /* tconscomma ::= COMMA */ yytestcase(yyruleno==108); case 130: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==130); - case 304: /* not_opt ::= NOT */ yytestcase(yyruleno==304); - case 320: /* uniqueflag ::= UNIQUE */ yytestcase(yyruleno==320); - case 386: /* database_kw_opt ::= DATABASE */ yytestcase(yyruleno==386); - case 402: /* kwcolumn_opt ::= */ yytestcase(yyruleno==402); -{yygotominor.yy237 = new bool(true);} + case 311: /* not_opt ::= NOT */ yytestcase(yyruleno==311); + case 327: /* uniqueflag ::= UNIQUE */ yytestcase(yyruleno==327); + case 393: /* database_kw_opt ::= DATABASE */ yytestcase(yyruleno==393); + case 409: /* kwcolumn_opt ::= */ yytestcase(yyruleno==409); +{yygotominor.yy451 = new bool(true);} break; case 22: /* savepoint_opt ::= */ case 36: /* ifnotexists ::= */ yytestcase(yyruleno==36); case 85: /* autoinc ::= */ yytestcase(yyruleno==85); case 109: /* tconscomma ::= */ yytestcase(yyruleno==109); case 131: /* ifexists ::= */ yytestcase(yyruleno==131); - case 303: /* not_opt ::= */ yytestcase(yyruleno==303); - case 321: /* uniqueflag ::= */ yytestcase(yyruleno==321); - case 387: /* database_kw_opt ::= */ yytestcase(yyruleno==387); - case 403: /* kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==403); -{yygotominor.yy237 = new bool(false);} + case 310: /* not_opt ::= */ yytestcase(yyruleno==310); + case 328: /* uniqueflag ::= */ yytestcase(yyruleno==328); + case 394: /* database_kw_opt ::= */ yytestcase(yyruleno==394); + case 410: /* kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==410); +{yygotominor.yy451 = new bool(false);} break; case 23: /* cmd ::= SAVEPOINT nm */ { - yygotominor.yy399 = new SqliteSavepoint(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteSavepoint(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; case 24: /* cmd ::= RELEASE savepoint_opt nm */ { - yygotominor.yy399 = new SqliteRelease(*(yymsp[-1].minor.yy237), *(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteRelease(*(yymsp[-1].minor.yy451), *(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; case 25: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ case 26: /* cmd ::= SAVEPOINT ID_TRANS */ yytestcase(yyruleno==26); { - yygotominor.yy399 = new SqliteRollback( - yymsp[-3].minor.yy300->transactionKw, - *(yymsp[-1].minor.yy237), - *(yymsp[0].minor.yy211) + yygotominor.yy283 = new SqliteRollback( + yymsp[-3].minor.yy404->transactionKw, + *(yymsp[-1].minor.yy451), + *(yymsp[0].minor.yy399) ); - delete yymsp[-1].minor.yy237; - delete yymsp[-3].minor.yy300; - objectForTokens = yygotominor.yy399; + delete yymsp[-1].minor.yy451; + delete yymsp[-3].minor.yy404; + objectForTokens = yygotominor.yy283; } break; case 27: /* cmd ::= RELEASE savepoint_opt ID_TRANS */ case 28: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt ID_TRANS */ yytestcase(yyruleno==28); -{ yy_destructor(yypParser,178,&yymsp[-1].minor); +{ yy_destructor(yypParser,180,&yymsp[-1].minor); } break; case 29: /* cmd ::= CREATE temp TABLE ifnotexists fullname LP columnlist conslist_opt RP table_options */ { - yygotominor.yy399 = new SqliteCreateTable( - *(yymsp[-6].minor.yy237), - *(yymsp[-8].minor.yy376), - yymsp[-5].minor.yy66->name1, - yymsp[-5].minor.yy66->name2, - *(yymsp[-3].minor.yy118), - *(yymsp[-2].minor.yy87), - *(yymsp[0].minor.yy211) + yygotominor.yy283 = new SqliteCreateTable( + *(yymsp[-6].minor.yy451), + *(yymsp[-8].minor.yy146), + yymsp[-5].minor.yy360->name1, + yymsp[-5].minor.yy360->name2, + *(yymsp[-3].minor.yy202), + *(yymsp[-2].minor.yy333), + *(yymsp[0].minor.yy399) ); - delete yymsp[-6].minor.yy237; - delete yymsp[-8].minor.yy376; - delete yymsp[-3].minor.yy118; - delete yymsp[-2].minor.yy87; - delete yymsp[-5].minor.yy66; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + delete yymsp[-6].minor.yy451; + delete yymsp[-8].minor.yy146; + delete yymsp[-3].minor.yy202; + delete yymsp[-2].minor.yy333; + delete yymsp[-5].minor.yy360; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; case 30: /* cmd ::= CREATE temp TABLE ifnotexists fullname AS select */ { - yygotominor.yy399 = new SqliteCreateTable( - *(yymsp[-3].minor.yy237), - *(yymsp[-5].minor.yy376), - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, - yymsp[0].minor.yy123 + yygotominor.yy283 = new SqliteCreateTable( + *(yymsp[-3].minor.yy451), + *(yymsp[-5].minor.yy146), + yymsp[-2].minor.yy360->name1, + yymsp[-2].minor.yy360->name2, + yymsp[0].minor.yy473 ); - delete yymsp[-3].minor.yy237; - delete yymsp[-5].minor.yy376; - delete yymsp[-2].minor.yy66; - objectForTokens = yygotominor.yy399; + delete yymsp[-3].minor.yy451; + delete yymsp[-5].minor.yy146; + delete yymsp[-2].minor.yy360; + objectForTokens = yygotominor.yy283; } break; case 31: /* cmd ::= CREATE temp TABLE ifnotexists nm DOT ID_TAB_NEW */ case 133: /* cmd ::= CREATE temp VIEW ifnotexists nm DOT ID_VIEW_NEW */ yytestcase(yyruleno==133); - case 357: /* cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW */ yytestcase(yyruleno==357); -{ yy_destructor(yypParser,179,&yymsp[-5].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 364: /* cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW */ yytestcase(yyruleno==364); +{ yy_destructor(yypParser,181,&yymsp[-5].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; case 32: /* cmd ::= CREATE temp TABLE ifnotexists ID_DB|ID_TAB_NEW */ case 134: /* cmd ::= CREATE temp VIEW ifnotexists ID_DB|ID_VIEW_NEW */ yytestcase(yyruleno==134); - case 358: /* cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW */ yytestcase(yyruleno==358); -{ yy_destructor(yypParser,179,&yymsp[-3].minor); + case 365: /* cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW */ yytestcase(yyruleno==365); +{ yy_destructor(yypParser,181,&yymsp[-3].minor); } break; case 33: /* table_options ::= */ - case 185: /* dbnm ::= */ yytestcase(yyruleno==185); - case 328: /* collate ::= */ yytestcase(yyruleno==328); - case 411: /* vtabarg ::= */ yytestcase(yyruleno==411); - case 415: /* anylist ::= */ yytestcase(yyruleno==415); -{yygotominor.yy211 = new QString();} + case 186: /* dbnm ::= */ yytestcase(yyruleno==186); + case 335: /* collate ::= */ yytestcase(yyruleno==335); + case 418: /* vtabarg ::= */ yytestcase(yyruleno==418); + case 422: /* anylist ::= */ yytestcase(yyruleno==422); +{yygotominor.yy399 = new QString();} break; case 34: /* table_options ::= WITHOUT nm */ case 35: /* table_options ::= WITHOUT CTX_ROWID_KW */ yytestcase(yyruleno==35); { - if (yymsp[0].minor.yy211->toLower() != "rowid") - parserContext->errorAtToken(QString("Invalid table option: %1").arg(*(yymsp[0].minor.yy211))); + if (yymsp[0].minor.yy399->toLower() != "rowid") + parserContext->errorAtToken(QString("Invalid table option: %1").arg(*(yymsp[0].minor.yy399))); - yygotominor.yy211 = yymsp[0].minor.yy211; + yygotominor.yy399 = yymsp[0].minor.yy399; } break; case 38: /* temp ::= TEMP */ -{yygotominor.yy376 = new int( (yymsp[0].minor.yy0->value.length() > 4) ? 2 : 1 );} +{yygotominor.yy146 = new int( (yymsp[0].minor.yy0->value.length() > 4) ? 2 : 1 );} break; case 39: /* temp ::= */ case 154: /* distinct ::= */ yytestcase(yyruleno==154); -{yygotominor.yy376 = new int(0);} +{yygotominor.yy146 = new int(0);} break; case 40: /* columnlist ::= columnlist COMMA column */ { - yymsp[-2].minor.yy118->append(yymsp[0].minor.yy425); - yygotominor.yy118 = yymsp[-2].minor.yy118; + yymsp[-2].minor.yy202->append(yymsp[0].minor.yy227); + yygotominor.yy202 = yymsp[-2].minor.yy202; DONT_INHERIT_TOKENS("columnlist"); } break; case 41: /* columnlist ::= column */ { - yygotominor.yy118 = new ParserCreateTableColumnList(); - yygotominor.yy118->append(yymsp[0].minor.yy425); + yygotominor.yy202 = new ParserCreateTableColumnList(); + yygotominor.yy202->append(yymsp[0].minor.yy227); } break; case 42: /* column ::= columnid type carglist */ { - yygotominor.yy425 = new SqliteCreateTable::Column(*(yymsp[-2].minor.yy211), yymsp[-1].minor.yy299, *(yymsp[0].minor.yy449)); - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy449; - objectForTokens = yygotominor.yy425; + yygotominor.yy227 = new SqliteCreateTable::Column(*(yymsp[-2].minor.yy399), yymsp[-1].minor.yy537, *(yymsp[0].minor.yy51)); + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy51; + objectForTokens = yygotominor.yy227; } break; case 43: /* columnid ::= nm */ case 44: /* columnid ::= ID_COL_NEW */ yytestcase(yyruleno==44); case 47: /* nm ::= id */ yytestcase(yyruleno==47); case 55: /* typename ::= ids */ yytestcase(yyruleno==55); - case 186: /* dbnm ::= DOT nm */ yytestcase(yyruleno==186); - case 329: /* collate ::= COLLATE ids */ yytestcase(yyruleno==329); - case 330: /* collate ::= COLLATE ID_COLLATE */ yytestcase(yyruleno==330); -{yygotominor.yy211 = yymsp[0].minor.yy211;} + case 187: /* dbnm ::= DOT nm */ yytestcase(yyruleno==187); + case 336: /* collate ::= COLLATE ids */ yytestcase(yyruleno==336); + case 337: /* collate ::= COLLATE ID_COLLATE */ yytestcase(yyruleno==337); +{yygotominor.yy399 = yymsp[0].minor.yy399;} break; case 45: /* id ::= ID */ { - yygotominor.yy211 = new QString( + yygotominor.yy399 = new QString( stripObjName( yymsp[0].minor.yy0->value, parserContext->dialect @@ -2989,177 +3039,177 @@ static void yy_reduce( break; case 46: /* ids ::= ID|STRING */ case 49: /* nm ::= JOIN_KW */ yytestcase(yyruleno==49); -{yygotominor.yy211 = new QString(yymsp[0].minor.yy0->value);} +{yygotominor.yy399 = new QString(yymsp[0].minor.yy0->value);} break; case 48: /* nm ::= STRING */ -{yygotominor.yy211 = new QString(stripString(yymsp[0].minor.yy0->value));} +{yygotominor.yy399 = new QString(stripString(yymsp[0].minor.yy0->value));} break; case 50: /* type ::= */ -{yygotominor.yy299 = nullptr;} +{yygotominor.yy537 = nullptr;} break; case 51: /* type ::= typetoken */ -{yygotominor.yy299 = yymsp[0].minor.yy299;} +{yygotominor.yy537 = yymsp[0].minor.yy537;} break; case 52: /* typetoken ::= typename */ { - yygotominor.yy299 = new SqliteColumnType(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy299; + yygotominor.yy537 = new SqliteColumnType(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy537; } break; case 53: /* typetoken ::= typename LP signed RP */ { - yygotominor.yy299 = new SqliteColumnType(*(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy21)); - delete yymsp[-3].minor.yy211; - delete yymsp[-1].minor.yy21; - objectForTokens = yygotominor.yy299; + yygotominor.yy537 = new SqliteColumnType(*(yymsp[-3].minor.yy399), *(yymsp[-1].minor.yy469)); + delete yymsp[-3].minor.yy399; + delete yymsp[-1].minor.yy469; + objectForTokens = yygotominor.yy537; } break; case 54: /* typetoken ::= typename LP signed COMMA signed RP */ { - yygotominor.yy299 = new SqliteColumnType(*(yymsp[-5].minor.yy211), *(yymsp[-3].minor.yy21), *(yymsp[-1].minor.yy21)); - delete yymsp[-5].minor.yy211; - delete yymsp[-3].minor.yy21; - delete yymsp[-1].minor.yy21; - objectForTokens = yygotominor.yy299; + yygotominor.yy537 = new SqliteColumnType(*(yymsp[-5].minor.yy399), *(yymsp[-3].minor.yy469), *(yymsp[-1].minor.yy469)); + delete yymsp[-5].minor.yy399; + delete yymsp[-3].minor.yy469; + delete yymsp[-1].minor.yy469; + objectForTokens = yygotominor.yy537; } break; case 56: /* typename ::= typename ids */ case 57: /* typename ::= ID_COL_TYPE */ yytestcase(yyruleno==57); { - yymsp[-1].minor.yy211->append(" " + *(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - yygotominor.yy211 = yymsp[-1].minor.yy211; + yymsp[-1].minor.yy399->append(" " + *(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + yygotominor.yy399 = yymsp[-1].minor.yy399; } break; case 58: /* signed ::= plus_num */ case 59: /* signed ::= minus_num */ yytestcase(yyruleno==59); - case 343: /* nmnum ::= plus_num */ yytestcase(yyruleno==343); - case 348: /* plus_num ::= PLUS number */ yytestcase(yyruleno==348); - case 349: /* plus_num ::= number */ yytestcase(yyruleno==349); -{yygotominor.yy21 = yymsp[0].minor.yy21;} + case 350: /* nmnum ::= plus_num */ yytestcase(yyruleno==350); + case 355: /* plus_num ::= PLUS number */ yytestcase(yyruleno==355); + case 356: /* plus_num ::= number */ yytestcase(yyruleno==356); +{yygotominor.yy469 = yymsp[0].minor.yy469;} break; case 60: /* carglist ::= carglist ccons */ { - yymsp[-1].minor.yy449->append(yymsp[0].minor.yy4); - yygotominor.yy449 = yymsp[-1].minor.yy449; + yymsp[-1].minor.yy51->append(yymsp[0].minor.yy304); + yygotominor.yy51 = yymsp[-1].minor.yy51; DONT_INHERIT_TOKENS("carglist"); } break; case 61: /* carglist ::= */ -{yygotominor.yy449 = new ParserCreateTableColumnConstraintList();} +{yygotominor.yy51 = new ParserCreateTableColumnConstraintList();} break; case 62: /* ccons ::= CONSTRAINT nm */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefNameOnly(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefNameOnly(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy304; } break; case 63: /* ccons ::= DEFAULT term */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21)); - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefTerm(*(yymsp[0].minor.yy469)); + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy304; } break; case 64: /* ccons ::= DEFAULT LP expr RP */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefExpr(yymsp[-1].minor.yy490); - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefExpr(yymsp[-1].minor.yy352); + objectForTokens = yygotominor.yy304; } break; case 65: /* ccons ::= DEFAULT PLUS term */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21), false); - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefTerm(*(yymsp[0].minor.yy469), false); + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy304; } break; case 66: /* ccons ::= DEFAULT MINUS term */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21), true); - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefTerm(*(yymsp[0].minor.yy469), true); + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy304; } break; case 67: /* ccons ::= DEFAULT id */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefId(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefId(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy304; } break; case 68: /* ccons ::= DEFAULT CTIME_KW */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefCTime(yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefCTime(yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy304; } break; case 69: /* ccons ::= NULL onconf */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initNull(*(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initNull(*(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; + objectForTokens = yygotominor.yy304; } break; case 70: /* ccons ::= NOT NULL onconf */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initNotNull(*(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initNotNull(*(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; + objectForTokens = yygotominor.yy304; } break; case 71: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initPk(*(yymsp[-2].minor.yy226), *(yymsp[-1].minor.yy30), *(yymsp[0].minor.yy237)); - delete yymsp[-2].minor.yy226; - delete yymsp[0].minor.yy237; - delete yymsp[-1].minor.yy30; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initPk(*(yymsp[-2].minor.yy309), *(yymsp[-1].minor.yy338), *(yymsp[0].minor.yy451)); + delete yymsp[-2].minor.yy309; + delete yymsp[0].minor.yy451; + delete yymsp[-1].minor.yy338; + objectForTokens = yygotominor.yy304; } break; case 72: /* ccons ::= UNIQUE onconf */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initUnique(*(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initUnique(*(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; + objectForTokens = yygotominor.yy304; } break; case 73: /* ccons ::= CHECK LP expr RP */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initCheck(yymsp[-1].minor.yy490); - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initCheck(yymsp[-1].minor.yy352); + objectForTokens = yygotominor.yy304; } break; case 74: /* ccons ::= REFERENCES nm idxlist_opt refargs */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initFk(*(yymsp[-2].minor.yy211), *(yymsp[-1].minor.yy139), *(yymsp[0].minor.yy108)); - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy108; - delete yymsp[-1].minor.yy139; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initFk(*(yymsp[-2].minor.yy399), *(yymsp[-1].minor.yy223), *(yymsp[0].minor.yy184)); + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy184; + delete yymsp[-1].minor.yy223; + objectForTokens = yygotominor.yy304; } break; case 75: /* ccons ::= defer_subclause */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initDefer(yymsp[0].minor.yy131->initially, yymsp[0].minor.yy131->deferrable); - delete yymsp[0].minor.yy131; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initDefer(yymsp[0].minor.yy329->initially, yymsp[0].minor.yy329->deferrable); + delete yymsp[0].minor.yy329; + objectForTokens = yygotominor.yy304; } break; case 76: /* ccons ::= COLLATE ids */ @@ -3167,377 +3217,377 @@ static void yy_reduce( case 78: /* ccons ::= COLLATE ID_COLLATE */ yytestcase(yyruleno==78); case 79: /* ccons ::= REFERENCES ID_TAB */ yytestcase(yyruleno==79); { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initColl(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initColl(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy304; } break; case 80: /* ccons ::= CHECK LP RP */ { - yygotominor.yy4 = new SqliteCreateTable::Column::Constraint(); - yygotominor.yy4->initCheck(); - objectForTokens = yygotominor.yy4; + yygotominor.yy304 = new SqliteCreateTable::Column::Constraint(); + yygotominor.yy304->initCheck(); + objectForTokens = yygotominor.yy304; parserContext->minorErrorAfterLastToken("Syntax error"); } break; case 81: /* term ::= NULL */ -{yygotominor.yy21 = new QVariant();} +{yygotominor.yy469 = new QVariant();} break; case 82: /* term ::= INTEGER */ - case 351: /* number ::= INTEGER */ yytestcase(yyruleno==351); -{yygotominor.yy21 = parserContext->handleNumberToken(yymsp[0].minor.yy0->value);} + case 358: /* number ::= INTEGER */ yytestcase(yyruleno==358); +{yygotominor.yy469 = parserContext->handleNumberToken(yymsp[0].minor.yy0->value);} break; case 83: /* term ::= FLOAT */ - case 352: /* number ::= FLOAT */ yytestcase(yyruleno==352); -{yygotominor.yy21 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toDouble());} + case 359: /* number ::= FLOAT */ yytestcase(yyruleno==359); +{yygotominor.yy469 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toDouble());} break; case 84: /* term ::= STRING|BLOB */ - case 345: /* nmnum ::= ON */ yytestcase(yyruleno==345); - case 346: /* nmnum ::= DELETE */ yytestcase(yyruleno==346); - case 347: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==347); -{yygotominor.yy21 = new QVariant(yymsp[0].minor.yy0->value);} + case 352: /* nmnum ::= ON */ yytestcase(yyruleno==352); + case 353: /* nmnum ::= DELETE */ yytestcase(yyruleno==353); + case 354: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==354); +{yygotominor.yy469 = new QVariant(yymsp[0].minor.yy0->value);} break; case 87: /* refargs ::= */ -{yygotominor.yy108 = new ParserFkConditionList();} +{yygotominor.yy184 = new ParserFkConditionList();} break; case 88: /* refargs ::= refargs refarg */ { - yymsp[-1].minor.yy108->append(yymsp[0].minor.yy271); - yygotominor.yy108 = yymsp[-1].minor.yy108; + yymsp[-1].minor.yy184->append(yymsp[0].minor.yy347); + yygotominor.yy184 = yymsp[-1].minor.yy184; DONT_INHERIT_TOKENS("refargs"); } break; case 89: /* refarg ::= MATCH nm */ { - yygotominor.yy271 = new SqliteForeignKey::Condition(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; + yygotominor.yy347 = new SqliteForeignKey::Condition(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; } break; case 90: /* refarg ::= ON INSERT refact */ -{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::INSERT, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;} +{yygotominor.yy347 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::INSERT, *(yymsp[0].minor.yy104)); delete yymsp[0].minor.yy104;} break; case 91: /* refarg ::= ON DELETE refact */ -{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::DELETE, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;} +{yygotominor.yy347 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::DELETE, *(yymsp[0].minor.yy104)); delete yymsp[0].minor.yy104;} break; case 92: /* refarg ::= ON UPDATE refact */ case 93: /* refarg ::= MATCH ID_FK_MATCH */ yytestcase(yyruleno==93); -{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::UPDATE, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;} +{yygotominor.yy347 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::UPDATE, *(yymsp[0].minor.yy104)); delete yymsp[0].minor.yy104;} break; case 94: /* refact ::= SET NULL */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_NULL);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_NULL);} break; case 95: /* refact ::= SET DEFAULT */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_DEFAULT);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_DEFAULT);} break; case 96: /* refact ::= CASCADE */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::CASCADE);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::CASCADE);} break; case 97: /* refact ::= RESTRICT */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::RESTRICT);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::RESTRICT);} break; case 98: /* refact ::= NO ACTION */ -{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::NO_ACTION);} +{yygotominor.yy104 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::NO_ACTION);} break; case 99: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ { - yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::NOT_DEFERRABLE, *(yymsp[0].minor.yy498)); - delete yymsp[0].minor.yy498; + yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::NOT_DEFERRABLE, *(yymsp[0].minor.yy392)); + delete yymsp[0].minor.yy392; } break; case 100: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ { - yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::DEFERRABLE, *(yymsp[0].minor.yy498)); - delete yymsp[0].minor.yy498; + yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::DEFERRABLE, *(yymsp[0].minor.yy392)); + delete yymsp[0].minor.yy392; } break; case 101: /* init_deferred_pred_opt ::= */ -{yygotominor.yy498 = new SqliteInitially(SqliteInitially::null);} +{yygotominor.yy392 = new SqliteInitially(SqliteInitially::null);} break; case 102: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ -{yygotominor.yy498 = new SqliteInitially(SqliteInitially::DEFERRED);} +{yygotominor.yy392 = new SqliteInitially(SqliteInitially::DEFERRED);} break; case 103: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yygotominor.yy498 = new SqliteInitially(SqliteInitially::IMMEDIATE);} +{yygotominor.yy392 = new SqliteInitially(SqliteInitially::IMMEDIATE);} break; case 104: /* conslist_opt ::= */ -{yygotominor.yy87 = new ParserCreateTableConstraintList();} +{yygotominor.yy333 = new ParserCreateTableConstraintList();} break; case 105: /* conslist_opt ::= COMMA conslist */ -{yygotominor.yy87 = yymsp[0].minor.yy87;} +{yygotominor.yy333 = yymsp[0].minor.yy333;} break; case 106: /* conslist ::= conslist tconscomma tcons */ { - yymsp[0].minor.yy8->afterComma = *(yymsp[-1].minor.yy237); - yymsp[-2].minor.yy87->append(yymsp[0].minor.yy8); - yygotominor.yy87 = yymsp[-2].minor.yy87; - delete yymsp[-1].minor.yy237; + yymsp[0].minor.yy406->afterComma = *(yymsp[-1].minor.yy451); + yymsp[-2].minor.yy333->append(yymsp[0].minor.yy406); + yygotominor.yy333 = yymsp[-2].minor.yy333; + delete yymsp[-1].minor.yy451; DONT_INHERIT_TOKENS("conslist"); } break; case 107: /* conslist ::= tcons */ { - yygotominor.yy87 = new ParserCreateTableConstraintList(); - yygotominor.yy87->append(yymsp[0].minor.yy8); + yygotominor.yy333 = new ParserCreateTableConstraintList(); + yygotominor.yy333->append(yymsp[0].minor.yy406); } break; case 110: /* tcons ::= CONSTRAINT nm */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initNameOnly(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initNameOnly(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy406; } break; case 111: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initPk(*(yymsp[-3].minor.yy139), *(yymsp[-2].minor.yy237), *(yymsp[0].minor.yy30)); - delete yymsp[-2].minor.yy237; - delete yymsp[0].minor.yy30; - delete yymsp[-3].minor.yy139; - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initPk(*(yymsp[-3].minor.yy223), *(yymsp[-2].minor.yy451), *(yymsp[0].minor.yy338)); + delete yymsp[-2].minor.yy451; + delete yymsp[0].minor.yy338; + delete yymsp[-3].minor.yy223; + objectForTokens = yygotominor.yy406; } break; case 112: /* tcons ::= UNIQUE LP idxlist RP onconf */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initUnique(*(yymsp[-2].minor.yy139), *(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; - delete yymsp[-2].minor.yy139; - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initUnique(*(yymsp[-2].minor.yy223), *(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; + delete yymsp[-2].minor.yy223; + objectForTokens = yygotominor.yy406; } break; case 113: /* tcons ::= CHECK LP expr RP onconf */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initCheck(yymsp[-2].minor.yy490, *(yymsp[0].minor.yy30)); - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initCheck(yymsp[-2].minor.yy352, *(yymsp[0].minor.yy338)); + objectForTokens = yygotominor.yy406; } break; case 114: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */ case 115: /* tcons ::= CONSTRAINT ID_CONSTR */ yytestcase(yyruleno==115); case 116: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES ID_TAB */ yytestcase(yyruleno==116); { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initFk( - *(yymsp[-6].minor.yy139), - *(yymsp[-3].minor.yy211), - *(yymsp[-2].minor.yy139), - *(yymsp[-1].minor.yy108), - yymsp[0].minor.yy131->initially, - yymsp[0].minor.yy131->deferrable + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initFk( + *(yymsp[-6].minor.yy223), + *(yymsp[-3].minor.yy399), + *(yymsp[-2].minor.yy223), + *(yymsp[-1].minor.yy184), + yymsp[0].minor.yy329->initially, + yymsp[0].minor.yy329->deferrable ); - delete yymsp[-3].minor.yy211; - delete yymsp[-1].minor.yy108; - delete yymsp[0].minor.yy131; - delete yymsp[-2].minor.yy139; - delete yymsp[-6].minor.yy139; - objectForTokens = yygotominor.yy8; + delete yymsp[-3].minor.yy399; + delete yymsp[-1].minor.yy184; + delete yymsp[0].minor.yy329; + delete yymsp[-2].minor.yy223; + delete yymsp[-6].minor.yy223; + objectForTokens = yygotominor.yy406; } break; case 117: /* tcons ::= CHECK LP RP onconf */ { - yygotominor.yy8 = new SqliteCreateTable::Constraint(); - yygotominor.yy8->initCheck(); - objectForTokens = yygotominor.yy8; + yygotominor.yy406 = new SqliteCreateTable::Constraint(); + yygotominor.yy406->initCheck(); + objectForTokens = yygotominor.yy406; parserContext->minorErrorAfterLastToken("Syntax error"); - yy_destructor(yypParser,200,&yymsp[0].minor); + yy_destructor(yypParser,202,&yymsp[0].minor); } break; case 118: /* defer_subclause_opt ::= */ -{yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::null, SqliteInitially::null);} +{yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::null, SqliteInitially::null);} break; case 119: /* defer_subclause_opt ::= defer_subclause */ -{yygotominor.yy131 = yymsp[0].minor.yy131;} +{yygotominor.yy329 = yymsp[0].minor.yy329;} break; case 120: /* onconf ::= */ case 122: /* orconf ::= */ yytestcase(yyruleno==122); -{yygotominor.yy30 = new SqliteConflictAlgo(SqliteConflictAlgo::null);} +{yygotominor.yy338 = new SqliteConflictAlgo(SqliteConflictAlgo::null);} break; case 121: /* onconf ::= ON CONFLICT resolvetype */ case 123: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==123); -{yygotominor.yy30 = yymsp[0].minor.yy30;} +{yygotominor.yy338 = yymsp[0].minor.yy338;} break; case 124: /* resolvetype ::= raisetype */ case 125: /* resolvetype ::= IGNORE */ yytestcase(yyruleno==125); case 126: /* resolvetype ::= REPLACE */ yytestcase(yyruleno==126); -{yygotominor.yy30 = new SqliteConflictAlgo(sqliteConflictAlgo(yymsp[0].minor.yy0->value));} +{yygotominor.yy338 = new SqliteConflictAlgo(sqliteConflictAlgo(yymsp[0].minor.yy0->value));} break; case 127: /* cmd ::= DROP TABLE ifexists fullname */ { - yygotominor.yy399 = new SqliteDropTable(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2); - delete yymsp[-1].minor.yy237; - delete yymsp[0].minor.yy66; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDropTable(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy360->name1, yymsp[0].minor.yy360->name2); + delete yymsp[-1].minor.yy451; + delete yymsp[0].minor.yy360; + objectForTokens = yygotominor.yy283; } break; case 128: /* cmd ::= DROP TABLE ifexists nm DOT ID_TAB */ case 129: /* cmd ::= DROP TABLE ifexists ID_DB|ID_TAB */ yytestcase(yyruleno==129); case 136: /* cmd ::= DROP VIEW ifexists nm DOT ID_VIEW */ yytestcase(yyruleno==136); case 137: /* cmd ::= DROP VIEW ifexists ID_DB|ID_VIEW */ yytestcase(yyruleno==137); - case 178: /* singlesrc ::= nm DOT ID_TAB */ yytestcase(yyruleno==178); - case 179: /* singlesrc ::= ID_DB|ID_TAB */ yytestcase(yyruleno==179); - case 180: /* singlesrc ::= nm DOT ID_VIEW */ yytestcase(yyruleno==180); - case 181: /* singlesrc ::= ID_DB|ID_VIEW */ yytestcase(yyruleno==181); - case 259: /* exprx ::= nm DOT ID_TAB|ID_COL */ yytestcase(yyruleno==259); - case 318: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW */ yytestcase(yyruleno==318); - case 319: /* cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW */ yytestcase(yyruleno==319); - case 332: /* cmd ::= DROP INDEX ifexists nm DOT ID_IDX */ yytestcase(yyruleno==332); - case 333: /* cmd ::= DROP INDEX ifexists ID_DB|ID_IDX */ yytestcase(yyruleno==333); - case 341: /* cmd ::= PRAGMA nm DOT ID_PRAGMA */ yytestcase(yyruleno==341); - case 342: /* cmd ::= PRAGMA ID_DB|ID_PRAGMA */ yytestcase(yyruleno==342); - case 380: /* cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG */ yytestcase(yyruleno==380); - case 381: /* cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG */ yytestcase(yyruleno==381); - case 391: /* cmd ::= REINDEX nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==391); - case 392: /* cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==392); - case 395: /* cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==395); - case 396: /* cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==396); - case 400: /* cmd ::= ALTER TABLE nm DOT ID_TAB */ yytestcase(yyruleno==400); - case 401: /* cmd ::= ALTER TABLE ID_DB|ID_TAB */ yytestcase(yyruleno==401); - case 407: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW */ yytestcase(yyruleno==407); - case 408: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW */ yytestcase(yyruleno==408); -{ yy_destructor(yypParser,177,&yymsp[-2].minor); + case 179: /* singlesrc ::= nm DOT ID_TAB */ yytestcase(yyruleno==179); + case 180: /* singlesrc ::= ID_DB|ID_TAB */ yytestcase(yyruleno==180); + case 181: /* singlesrc ::= nm DOT ID_VIEW */ yytestcase(yyruleno==181); + case 182: /* singlesrc ::= ID_DB|ID_VIEW */ yytestcase(yyruleno==182); + case 266: /* exprx ::= nm DOT ID_TAB|ID_COL */ yytestcase(yyruleno==266); + case 325: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW */ yytestcase(yyruleno==325); + case 326: /* cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW */ yytestcase(yyruleno==326); + case 339: /* cmd ::= DROP INDEX ifexists nm DOT ID_IDX */ yytestcase(yyruleno==339); + case 340: /* cmd ::= DROP INDEX ifexists ID_DB|ID_IDX */ yytestcase(yyruleno==340); + case 348: /* cmd ::= PRAGMA nm DOT ID_PRAGMA */ yytestcase(yyruleno==348); + case 349: /* cmd ::= PRAGMA ID_DB|ID_PRAGMA */ yytestcase(yyruleno==349); + case 387: /* cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG */ yytestcase(yyruleno==387); + case 388: /* cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG */ yytestcase(yyruleno==388); + case 398: /* cmd ::= REINDEX nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==398); + case 399: /* cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==399); + case 402: /* cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==402); + case 403: /* cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==403); + case 407: /* cmd ::= ALTER TABLE nm DOT ID_TAB */ yytestcase(yyruleno==407); + case 408: /* cmd ::= ALTER TABLE ID_DB|ID_TAB */ yytestcase(yyruleno==408); + case 414: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW */ yytestcase(yyruleno==414); + case 415: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW */ yytestcase(yyruleno==415); +{ yy_destructor(yypParser,179,&yymsp[-2].minor); } break; case 132: /* cmd ::= CREATE temp VIEW ifnotexists fullname idxlist_opt AS select */ { - yygotominor.yy399 = new SqliteCreateView(*(yymsp[-6].minor.yy376), *(yymsp[-4].minor.yy237), yymsp[-3].minor.yy66->name1, yymsp[-3].minor.yy66->name2, yymsp[0].minor.yy123, *(yymsp[-2].minor.yy139)); - delete yymsp[-6].minor.yy376; - delete yymsp[-4].minor.yy237; - delete yymsp[-3].minor.yy66; - delete yymsp[-2].minor.yy139; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteCreateView(*(yymsp[-6].minor.yy146), *(yymsp[-4].minor.yy451), yymsp[-3].minor.yy360->name1, yymsp[-3].minor.yy360->name2, yymsp[0].minor.yy473, *(yymsp[-2].minor.yy223)); + delete yymsp[-6].minor.yy146; + delete yymsp[-4].minor.yy451; + delete yymsp[-3].minor.yy360; + delete yymsp[-2].minor.yy223; + objectForTokens = yygotominor.yy283; } break; case 135: /* cmd ::= DROP VIEW ifexists fullname */ { - yygotominor.yy399 = new SqliteDropView(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2); - delete yymsp[-1].minor.yy237; - delete yymsp[0].minor.yy66; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDropView(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy360->name1, yymsp[0].minor.yy360->name2); + delete yymsp[-1].minor.yy451; + delete yymsp[0].minor.yy360; + objectForTokens = yygotominor.yy283; } break; case 138: /* cmd ::= select_stmt */ - case 214: /* cmd ::= delete_stmt */ yytestcase(yyruleno==214); - case 223: /* cmd ::= update_stmt */ yytestcase(yyruleno==223); - case 235: /* cmd ::= insert_stmt */ yytestcase(yyruleno==235); + case 215: /* cmd ::= delete_stmt */ yytestcase(yyruleno==215); + case 224: /* cmd ::= update_stmt */ yytestcase(yyruleno==224); + case 245: /* cmd ::= insert_stmt */ yytestcase(yyruleno==245); { - yygotominor.yy399 = yymsp[0].minor.yy399; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = yymsp[0].minor.yy283; + objectForTokens = yygotominor.yy283; } break; case 139: /* select_stmt ::= select */ { - yygotominor.yy399 = yymsp[0].minor.yy123; + yygotominor.yy283 = yymsp[0].minor.yy473; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; case 140: /* select ::= with selectnowith */ { - yygotominor.yy123 = yymsp[0].minor.yy123; - yymsp[0].minor.yy123->setWith(yymsp[-1].minor.yy367); - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = yymsp[0].minor.yy473; + yymsp[0].minor.yy473->setWith(yymsp[-1].minor.yy321); + objectForTokens = yygotominor.yy473; } break; case 141: /* selectnowith ::= oneselect */ { - yygotominor.yy123 = SqliteSelect::append(yymsp[0].minor.yy468); - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = SqliteSelect::append(yymsp[0].minor.yy310); + objectForTokens = yygotominor.yy473; } break; case 142: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - yygotominor.yy123 = SqliteSelect::append(yymsp[-2].minor.yy123, *(yymsp[-1].minor.yy168), yymsp[0].minor.yy468); - delete yymsp[-1].minor.yy168; - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = SqliteSelect::append(yymsp[-2].minor.yy473, *(yymsp[-1].minor.yy462), yymsp[0].minor.yy310); + delete yymsp[-1].minor.yy462; + objectForTokens = yygotominor.yy473; } break; case 143: /* selectnowith ::= values */ { - yygotominor.yy123 = SqliteSelect::append(*(yymsp[0].minor.yy416)); - delete yymsp[0].minor.yy416; - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = SqliteSelect::append(*(yymsp[0].minor.yy166)); + delete yymsp[0].minor.yy166; + objectForTokens = yygotominor.yy473; } break; case 144: /* selectnowith ::= selectnowith COMMA values */ { - yygotominor.yy123 = SqliteSelect::append(yymsp[-2].minor.yy123, SqliteSelect::CompoundOperator::UNION_ALL, *(yymsp[0].minor.yy416)); - delete yymsp[0].minor.yy416; - objectForTokens = yygotominor.yy123; + yygotominor.yy473 = SqliteSelect::append(yymsp[-2].minor.yy473, SqliteSelect::CompoundOperator::UNION_ALL, *(yymsp[0].minor.yy166)); + delete yymsp[0].minor.yy166; + objectForTokens = yygotominor.yy473; } break; - case 145: /* multiselect_op ::= UNION */ -{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);} - break; - case 146: /* multiselect_op ::= UNION ALL */ -{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);} - break; - case 147: /* multiselect_op ::= EXCEPT */ -{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);} - break; - case 148: /* multiselect_op ::= INTERSECT */ -{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);} - break; - case 149: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + case 145: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yygotominor.yy468 = new SqliteSelect::Core( - *(yymsp[-7].minor.yy376), - *(yymsp[-6].minor.yy263), - yymsp[-5].minor.yy373, - yymsp[-4].minor.yy490, - *(yymsp[-3].minor.yy13), - yymsp[-2].minor.yy490, - *(yymsp[-1].minor.yy495), - yymsp[0].minor.yy128 + yygotominor.yy310 = new SqliteSelect::Core( + *(yymsp[-7].minor.yy146), + *(yymsp[-6].minor.yy373), + yymsp[-5].minor.yy511, + yymsp[-4].minor.yy352, + *(yymsp[-3].minor.yy551), + yymsp[-2].minor.yy352, + *(yymsp[-1].minor.yy163), + yymsp[0].minor.yy484 ); - delete yymsp[-6].minor.yy263; - delete yymsp[-7].minor.yy376; - delete yymsp[-3].minor.yy13; - delete yymsp[-1].minor.yy495; - objectForTokens = yygotominor.yy468; + delete yymsp[-6].minor.yy373; + delete yymsp[-7].minor.yy146; + delete yymsp[-3].minor.yy551; + delete yymsp[-1].minor.yy163; + objectForTokens = yygotominor.yy310; } break; - case 150: /* values ::= VALUES LP nexprlist RP */ + case 146: /* values ::= VALUES LP nexprlist RP */ { - yygotominor.yy416 = new ParserExprNestedList(); - yygotominor.yy416->append(*(yymsp[-1].minor.yy13)); - delete yymsp[-1].minor.yy13; + yygotominor.yy166 = new ParserExprNestedList(); + yygotominor.yy166->append(*(yymsp[-1].minor.yy551)); + delete yymsp[-1].minor.yy551; } break; - case 151: /* values ::= values COMMA LP exprlist RP */ + case 147: /* values ::= values COMMA LP exprlist RP */ { - yymsp[-4].minor.yy416->append(*(yymsp[-1].minor.yy13)); - yygotominor.yy416 = yymsp[-4].minor.yy416; - delete yymsp[-1].minor.yy13; + yymsp[-4].minor.yy166->append(*(yymsp[-1].minor.yy551)); + yygotominor.yy166 = yymsp[-4].minor.yy166; + delete yymsp[-1].minor.yy551; DONT_INHERIT_TOKENS("values"); } break; + case 148: /* multiselect_op ::= UNION */ +{yygotominor.yy462 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);} + break; + case 149: /* multiselect_op ::= UNION ALL */ +{yygotominor.yy462 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);} + break; + case 150: /* multiselect_op ::= EXCEPT */ +{yygotominor.yy462 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);} + break; + case 151: /* multiselect_op ::= INTERSECT */ +{yygotominor.yy462 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);} + break; case 152: /* distinct ::= DISTINCT */ -{yygotominor.yy376 = new int(1);} +{yygotominor.yy146 = new int(1);} break; case 153: /* distinct ::= ALL */ -{yygotominor.yy376 = new int(2);} +{yygotominor.yy146 = new int(2);} break; case 155: /* sclp ::= selcollist COMMA */ -{yygotominor.yy263 = yymsp[-1].minor.yy263;} +{yygotominor.yy373 = yymsp[-1].minor.yy373;} break; case 156: /* sclp ::= */ -{yygotominor.yy263 = new ParserResultColumnList();} +{yygotominor.yy373 = new ParserResultColumnList();} break; case 157: /* selcollist ::= sclp expr as */ { SqliteSelect::Core::ResultColumn* obj = new SqliteSelect::Core::ResultColumn( - yymsp[-1].minor.yy490, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null + yymsp[-1].minor.yy352, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->asKw : false, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->name : QString::null ); - yymsp[-2].minor.yy263->append(obj); - yygotominor.yy263 = yymsp[-2].minor.yy263; - delete yymsp[0].minor.yy28; + yymsp[-2].minor.yy373->append(obj); + yygotominor.yy373 = yymsp[-2].minor.yy373; + delete yymsp[0].minor.yy200; objectForTokens = obj; DONT_INHERIT_TOKENS("sclp"); } @@ -3547,8 +3597,8 @@ static void yy_reduce( SqliteSelect::Core::ResultColumn* obj = new SqliteSelect::Core::ResultColumn(true); - yymsp[-1].minor.yy263->append(obj); - yygotominor.yy263 = yymsp[-1].minor.yy263; + yymsp[-1].minor.yy373->append(obj); + yygotominor.yy373 = yymsp[-1].minor.yy373; objectForTokens = obj; DONT_INHERIT_TOKENS("sclp"); } @@ -3558,11 +3608,11 @@ static void yy_reduce( SqliteSelect::Core::ResultColumn* obj = new SqliteSelect::Core::ResultColumn( true, - *(yymsp[-2].minor.yy211) + *(yymsp[-2].minor.yy399) ); - yymsp[-3].minor.yy263->append(obj); - yygotominor.yy263 = yymsp[-3].minor.yy263; - delete yymsp[-2].minor.yy211; + yymsp[-3].minor.yy373->append(obj); + yygotominor.yy373 = yymsp[-3].minor.yy373; + delete yymsp[-2].minor.yy399; objectForTokens = obj; DONT_INHERIT_TOKENS("sclp"); } @@ -3571,1382 +3621,1439 @@ static void yy_reduce( case 161: /* selcollist ::= sclp ID_TAB DOT STAR */ yytestcase(yyruleno==161); { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy263 = yymsp[0].minor.yy263; + yygotominor.yy373 = yymsp[0].minor.yy373; } break; case 162: /* as ::= AS nm */ { - yygotominor.yy28 = new ParserStubAlias(*(yymsp[0].minor.yy211), true); - delete yymsp[0].minor.yy211; + yygotominor.yy200 = new ParserStubAlias(*(yymsp[0].minor.yy399), true); + delete yymsp[0].minor.yy399; } break; case 163: /* as ::= ids */ case 164: /* as ::= AS ID_ALIAS */ yytestcase(yyruleno==164); case 165: /* as ::= ID_ALIAS */ yytestcase(yyruleno==165); { - yygotominor.yy28 = new ParserStubAlias(*(yymsp[0].minor.yy211), false); - delete yymsp[0].minor.yy211; + yygotominor.yy200 = new ParserStubAlias(*(yymsp[0].minor.yy399), false); + delete yymsp[0].minor.yy399; } break; case 166: /* as ::= */ -{yygotominor.yy28 = nullptr;} +{yygotominor.yy200 = nullptr;} break; case 167: /* from ::= */ -{yygotominor.yy373 = nullptr;} +{yygotominor.yy511 = nullptr;} break; case 168: /* from ::= FROM joinsrc */ -{yygotominor.yy373 = yymsp[0].minor.yy373;} +{yygotominor.yy511 = yymsp[0].minor.yy511;} break; case 169: /* joinsrc ::= singlesrc seltablist */ { - yygotominor.yy373 = new SqliteSelect::Core::JoinSource( - yymsp[-1].minor.yy173, - *(yymsp[0].minor.yy359) + yygotominor.yy511 = new SqliteSelect::Core::JoinSource( + yymsp[-1].minor.yy201, + *(yymsp[0].minor.yy131) ); - delete yymsp[0].minor.yy359; - objectForTokens = yygotominor.yy373; + delete yymsp[0].minor.yy131; + objectForTokens = yygotominor.yy511; } break; case 170: /* joinsrc ::= */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy373 = new SqliteSelect::Core::JoinSource(); - objectForTokens = yygotominor.yy373; + yygotominor.yy511 = new SqliteSelect::Core::JoinSource(); + objectForTokens = yygotominor.yy511; } break; case 171: /* seltablist ::= seltablist joinop singlesrc joinconstr_opt */ { SqliteSelect::Core::JoinSourceOther* src = - new SqliteSelect::Core::JoinSourceOther(yymsp[-2].minor.yy473, yymsp[-1].minor.yy173, yymsp[0].minor.yy117); + new SqliteSelect::Core::JoinSourceOther(yymsp[-2].minor.yy301, yymsp[-1].minor.yy201, yymsp[0].minor.yy295); - yymsp[-3].minor.yy359->append(src); - yygotominor.yy359 = yymsp[-3].minor.yy359; + yymsp[-3].minor.yy131->append(src); + yygotominor.yy131 = yymsp[-3].minor.yy131; objectForTokens = src; DONT_INHERIT_TOKENS("seltablist"); } break; case 172: /* seltablist ::= */ { - yygotominor.yy359 = new ParserOtherSourceList(); + yygotominor.yy131 = new ParserOtherSourceList(); } break; case 173: /* singlesrc ::= nm dbnm as indexed_opt */ { - yygotominor.yy173 = new SqliteSelect::Core::SingleSource( - *(yymsp[-3].minor.yy211), - *(yymsp[-2].minor.yy211), - yymsp[-1].minor.yy28 ? yymsp[-1].minor.yy28->asKw : false, - yymsp[-1].minor.yy28 ? yymsp[-1].minor.yy28->name : QString::null, - yymsp[0].minor.yy472 ? yymsp[0].minor.yy472->notIndexedKw : false, - yymsp[0].minor.yy472 ? yymsp[0].minor.yy472->indexedBy : QString::null + yygotominor.yy201 = new SqliteSelect::Core::SingleSource( + *(yymsp[-3].minor.yy399), + *(yymsp[-2].minor.yy399), + yymsp[-1].minor.yy200 ? yymsp[-1].minor.yy200->asKw : false, + yymsp[-1].minor.yy200 ? yymsp[-1].minor.yy200->name : QString::null, + yymsp[0].minor.yy192 ? yymsp[0].minor.yy192->notIndexedKw : false, + yymsp[0].minor.yy192 ? yymsp[0].minor.yy192->indexedBy : QString::null ); - delete yymsp[-3].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[-1].minor.yy28; - if (yymsp[0].minor.yy472) - delete yymsp[0].minor.yy472; - objectForTokens = yygotominor.yy173; + delete yymsp[-3].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[-1].minor.yy200; + if (yymsp[0].minor.yy192) + delete yymsp[0].minor.yy192; + objectForTokens = yygotominor.yy201; } break; case 174: /* singlesrc ::= LP select RP as */ { - yygotominor.yy173 = new SqliteSelect::Core::SingleSource( - yymsp[-2].minor.yy123, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null + yygotominor.yy201 = new SqliteSelect::Core::SingleSource( + yymsp[-2].minor.yy473, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->asKw : false, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->name : QString::null ); - delete yymsp[0].minor.yy28; - objectForTokens = yygotominor.yy173; + delete yymsp[0].minor.yy200; + objectForTokens = yygotominor.yy201; } break; case 175: /* singlesrc ::= LP joinsrc RP as */ { - yygotominor.yy173 = new SqliteSelect::Core::SingleSource( - yymsp[-2].minor.yy373, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false, - yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null + yygotominor.yy201 = new SqliteSelect::Core::SingleSource( + yymsp[-2].minor.yy511, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->asKw : false, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->name : QString::null ); - delete yymsp[0].minor.yy28; - objectForTokens = yygotominor.yy173; + delete yymsp[0].minor.yy200; + objectForTokens = yygotominor.yy201; } break; - case 176: /* singlesrc ::= */ + case 176: /* singlesrc ::= nm dbnm LP exprlist RP as */ +{ + yygotominor.yy201 = new SqliteSelect::Core::SingleSource( + *(yymsp[-5].minor.yy399), + *(yymsp[-4].minor.yy399), + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->asKw : false, + yymsp[0].minor.yy200 ? yymsp[0].minor.yy200->name : QString::null, + *(yymsp[-2].minor.yy551) + ); + delete yymsp[-5].minor.yy399; + delete yymsp[-4].minor.yy399; + delete yymsp[0].minor.yy200; + if (yymsp[-2].minor.yy551) + delete yymsp[-2].minor.yy551; + + objectForTokens = yygotominor.yy201; + } + break; + case 177: /* singlesrc ::= */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy173 = new SqliteSelect::Core::SingleSource(); - objectForTokens = yygotominor.yy173; + yygotominor.yy201 = new SqliteSelect::Core::SingleSource(); + objectForTokens = yygotominor.yy201; } break; - case 177: /* singlesrc ::= nm DOT */ + case 178: /* singlesrc ::= nm DOT */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy173 = new SqliteSelect::Core::SingleSource(); - yygotominor.yy173->database = *(yymsp[-1].minor.yy211); - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy173; + yygotominor.yy201 = new SqliteSelect::Core::SingleSource(); + yygotominor.yy201->database = *(yymsp[-1].minor.yy399); + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy201; } break; - case 182: /* joinconstr_opt ::= ON expr */ + case 183: /* joinconstr_opt ::= ON expr */ { - yygotominor.yy117 = new SqliteSelect::Core::JoinConstraint(yymsp[0].minor.yy490); - objectForTokens = yygotominor.yy117; + yygotominor.yy295 = new SqliteSelect::Core::JoinConstraint(yymsp[0].minor.yy352); + objectForTokens = yygotominor.yy295; } break; - case 183: /* joinconstr_opt ::= USING LP inscollist RP */ + case 184: /* joinconstr_opt ::= USING LP idlist RP */ { - yygotominor.yy117 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy445)); - delete yymsp[-1].minor.yy445; - objectForTokens = yygotominor.yy117; + yygotominor.yy295 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy95)); + delete yymsp[-1].minor.yy95; + objectForTokens = yygotominor.yy295; } break; - case 184: /* joinconstr_opt ::= */ -{yygotominor.yy117 = nullptr;} + case 185: /* joinconstr_opt ::= */ +{yygotominor.yy295 = nullptr;} break; - case 187: /* fullname ::= nm dbnm */ + case 188: /* fullname ::= nm dbnm */ { - yygotominor.yy66 = new ParserFullName(); - yygotominor.yy66->name1 = *(yymsp[-1].minor.yy211); - yygotominor.yy66->name2 = *(yymsp[0].minor.yy211); - delete yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; + yygotominor.yy360 = new ParserFullName(); + yygotominor.yy360->name1 = *(yymsp[-1].minor.yy399); + yygotominor.yy360->name2 = *(yymsp[0].minor.yy399); + delete yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; } break; - case 188: /* joinop ::= COMMA */ + case 189: /* joinop ::= COMMA */ { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(true); - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(true); + objectForTokens = yygotominor.yy301; } break; - case 189: /* joinop ::= JOIN */ + case 190: /* joinop ::= JOIN */ { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(false); - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(false); + objectForTokens = yygotominor.yy301; } break; - case 190: /* joinop ::= JOIN_KW JOIN */ + case 191: /* joinop ::= JOIN_KW JOIN */ { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-1].minor.yy0->value); - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(yymsp[-1].minor.yy0->value); + objectForTokens = yygotominor.yy301; } break; - case 191: /* joinop ::= JOIN_KW nm JOIN */ + case 192: /* joinop ::= JOIN_KW nm JOIN */ { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-2].minor.yy0->value, *(yymsp[-1].minor.yy211)); - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(yymsp[-2].minor.yy0->value, *(yymsp[-1].minor.yy399)); + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy301; } break; - case 192: /* joinop ::= JOIN_KW nm nm JOIN */ - case 193: /* joinop ::= ID_JOIN_OPTS */ yytestcase(yyruleno==193); + case 193: /* joinop ::= JOIN_KW nm nm JOIN */ + case 194: /* joinop ::= ID_JOIN_OPTS */ yytestcase(yyruleno==194); { - yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-3].minor.yy0->value, *(yymsp[-2].minor.yy211), *(yymsp[-1].minor.yy211)); - delete yymsp[-2].minor.yy211; - delete yymsp[-2].minor.yy211; - objectForTokens = yygotominor.yy473; + yygotominor.yy301 = new SqliteSelect::Core::JoinOp(yymsp[-3].minor.yy0->value, *(yymsp[-2].minor.yy399), *(yymsp[-1].minor.yy399)); + delete yymsp[-2].minor.yy399; + delete yymsp[-2].minor.yy399; + objectForTokens = yygotominor.yy301; } break; - case 194: /* indexed_opt ::= */ -{yygotominor.yy472 = nullptr;} + case 195: /* indexed_opt ::= */ +{yygotominor.yy192 = nullptr;} break; - case 195: /* indexed_opt ::= INDEXED BY nm */ + case 196: /* indexed_opt ::= INDEXED BY nm */ { - yygotominor.yy472 = new ParserIndexedBy(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; + yygotominor.yy192 = new ParserIndexedBy(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; } break; - case 196: /* indexed_opt ::= NOT INDEXED */ - case 197: /* indexed_opt ::= INDEXED BY ID_IDX */ yytestcase(yyruleno==197); -{yygotominor.yy472 = new ParserIndexedBy(true);} + case 197: /* indexed_opt ::= NOT INDEXED */ + case 198: /* indexed_opt ::= INDEXED BY ID_IDX */ yytestcase(yyruleno==198); +{yygotominor.yy192 = new ParserIndexedBy(true);} break; - case 198: /* orderby_opt ::= */ -{yygotominor.yy495 = new ParserOrderByList();} + case 199: /* orderby_opt ::= */ +{yygotominor.yy163 = new ParserOrderByList();} break; - case 199: /* orderby_opt ::= ORDER BY sortlist */ -{yygotominor.yy495 = yymsp[0].minor.yy495;} + case 200: /* orderby_opt ::= ORDER BY sortlist */ +{yygotominor.yy163 = yymsp[0].minor.yy163;} break; - case 200: /* sortlist ::= sortlist COMMA expr sortorder */ + case 201: /* sortlist ::= sortlist COMMA expr sortorder */ { - SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy490, *(yymsp[0].minor.yy226)); - yymsp[-3].minor.yy495->append(obj); - yygotominor.yy495 = yymsp[-3].minor.yy495; - delete yymsp[0].minor.yy226; + SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy352, *(yymsp[0].minor.yy309)); + yymsp[-3].minor.yy163->append(obj); + yygotominor.yy163 = yymsp[-3].minor.yy163; + delete yymsp[0].minor.yy309; objectForTokens = obj; DONT_INHERIT_TOKENS("sortlist"); } break; - case 201: /* sortlist ::= expr sortorder */ + case 202: /* sortlist ::= expr sortorder */ { - SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy490, *(yymsp[0].minor.yy226)); - yygotominor.yy495 = new ParserOrderByList(); - yygotominor.yy495->append(obj); - delete yymsp[0].minor.yy226; + SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy352, *(yymsp[0].minor.yy309)); + yygotominor.yy163 = new ParserOrderByList(); + yygotominor.yy163->append(obj); + delete yymsp[0].minor.yy309; objectForTokens = obj; } break; - case 202: /* sortorder ::= ASC */ -{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::ASC);} + case 203: /* sortorder ::= ASC */ +{yygotominor.yy309 = new SqliteSortOrder(SqliteSortOrder::ASC);} break; - case 203: /* sortorder ::= DESC */ -{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::DESC);} + case 204: /* sortorder ::= DESC */ +{yygotominor.yy309 = new SqliteSortOrder(SqliteSortOrder::DESC);} break; - case 204: /* sortorder ::= */ -{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::null);} + case 205: /* sortorder ::= */ +{yygotominor.yy309 = new SqliteSortOrder(SqliteSortOrder::null);} break; - case 205: /* groupby_opt ::= */ - case 313: /* exprlist ::= */ yytestcase(yyruleno==313); -{yygotominor.yy13 = new ParserExprList();} + case 206: /* groupby_opt ::= */ + case 320: /* exprlist ::= */ yytestcase(yyruleno==320); +{yygotominor.yy551 = new ParserExprList();} break; - case 206: /* groupby_opt ::= GROUP BY nexprlist */ - case 312: /* exprlist ::= nexprlist */ yytestcase(yyruleno==312); -{yygotominor.yy13 = yymsp[0].minor.yy13;} + case 207: /* groupby_opt ::= GROUP BY nexprlist */ + case 319: /* exprlist ::= nexprlist */ yytestcase(yyruleno==319); +{yygotominor.yy551 = yymsp[0].minor.yy551;} break; - case 207: /* groupby_opt ::= GROUP BY */ + case 208: /* groupby_opt ::= GROUP BY */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy13 = new ParserExprList(); + yygotominor.yy551 = new ParserExprList(); } break; - case 208: /* having_opt ::= */ - case 220: /* where_opt ::= */ yytestcase(yyruleno==220); - case 309: /* case_else ::= */ yytestcase(yyruleno==309); - case 311: /* case_operand ::= */ yytestcase(yyruleno==311); - case 369: /* when_clause ::= */ yytestcase(yyruleno==369); - case 384: /* key_opt ::= */ yytestcase(yyruleno==384); -{yygotominor.yy490 = nullptr;} + case 209: /* having_opt ::= */ + case 221: /* where_opt ::= */ yytestcase(yyruleno==221); + case 316: /* case_else ::= */ yytestcase(yyruleno==316); + case 318: /* case_operand ::= */ yytestcase(yyruleno==318); + case 376: /* when_clause ::= */ yytestcase(yyruleno==376); + case 391: /* key_opt ::= */ yytestcase(yyruleno==391); +{yygotominor.yy352 = nullptr;} break; - case 209: /* having_opt ::= HAVING expr */ - case 221: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==221); - case 302: /* expr ::= exprx */ yytestcase(yyruleno==302); - case 308: /* case_else ::= ELSE expr */ yytestcase(yyruleno==308); - case 310: /* case_operand ::= exprx */ yytestcase(yyruleno==310); - case 370: /* when_clause ::= WHEN expr */ yytestcase(yyruleno==370); - case 385: /* key_opt ::= KEY expr */ yytestcase(yyruleno==385); -{yygotominor.yy490 = yymsp[0].minor.yy490;} + case 210: /* having_opt ::= HAVING expr */ + case 222: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==222); + case 309: /* expr ::= exprx */ yytestcase(yyruleno==309); + case 315: /* case_else ::= ELSE expr */ yytestcase(yyruleno==315); + case 317: /* case_operand ::= exprx */ yytestcase(yyruleno==317); + case 377: /* when_clause ::= WHEN expr */ yytestcase(yyruleno==377); + case 392: /* key_opt ::= KEY expr */ yytestcase(yyruleno==392); +{yygotominor.yy352 = yymsp[0].minor.yy352;} break; - case 210: /* limit_opt ::= */ -{yygotominor.yy128 = nullptr;} + case 211: /* limit_opt ::= */ +{yygotominor.yy484 = nullptr;} break; - case 211: /* limit_opt ::= LIMIT expr */ + case 212: /* limit_opt ::= LIMIT expr */ { - yygotominor.yy128 = new SqliteLimit(yymsp[0].minor.yy490); - objectForTokens = yygotominor.yy128; + yygotominor.yy484 = new SqliteLimit(yymsp[0].minor.yy352); + objectForTokens = yygotominor.yy484; } break; - case 212: /* limit_opt ::= LIMIT expr OFFSET expr */ + case 213: /* limit_opt ::= LIMIT expr OFFSET expr */ { - yygotominor.yy128 = new SqliteLimit(yymsp[-2].minor.yy490, yymsp[0].minor.yy490, true); - objectForTokens = yygotominor.yy128; + yygotominor.yy484 = new SqliteLimit(yymsp[-2].minor.yy352, yymsp[0].minor.yy352, true); + objectForTokens = yygotominor.yy484; } break; - case 213: /* limit_opt ::= LIMIT expr COMMA expr */ + case 214: /* limit_opt ::= LIMIT expr COMMA expr */ { - yygotominor.yy128 = new SqliteLimit(yymsp[-2].minor.yy490, yymsp[0].minor.yy490, false); - objectForTokens = yygotominor.yy128; + yygotominor.yy484 = new SqliteLimit(yymsp[-2].minor.yy352, yymsp[0].minor.yy352, false); + objectForTokens = yygotominor.yy484; } break; - case 215: /* delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt */ + case 216: /* delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt */ { - if (yymsp[-1].minor.yy472) + if (yymsp[-1].minor.yy192) { - if (!yymsp[-1].minor.yy472->indexedBy.isNull()) + if (!yymsp[-1].minor.yy192->indexedBy.isNull()) { - yygotominor.yy399 = new SqliteDelete( - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, - yymsp[-1].minor.yy472->indexedBy, - yymsp[0].minor.yy490, - yymsp[-5].minor.yy367 + yygotominor.yy283 = new SqliteDelete( + yymsp[-2].minor.yy360->name1, + yymsp[-2].minor.yy360->name2, + yymsp[-1].minor.yy192->indexedBy, + yymsp[0].minor.yy352, + yymsp[-5].minor.yy321 ); } else { - yygotominor.yy399 = new SqliteDelete( - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, - yymsp[-1].minor.yy472->notIndexedKw, - yymsp[0].minor.yy490, - yymsp[-5].minor.yy367 + yygotominor.yy283 = new SqliteDelete( + yymsp[-2].minor.yy360->name1, + yymsp[-2].minor.yy360->name2, + yymsp[-1].minor.yy192->notIndexedKw, + yymsp[0].minor.yy352, + yymsp[-5].minor.yy321 ); } - delete yymsp[-1].minor.yy472; + delete yymsp[-1].minor.yy192; } else { - yygotominor.yy399 = new SqliteDelete( - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, + yygotominor.yy283 = new SqliteDelete( + yymsp[-2].minor.yy360->name1, + yymsp[-2].minor.yy360->name2, false, - yymsp[0].minor.yy490, - yymsp[-5].minor.yy367 + yymsp[0].minor.yy352, + yymsp[-5].minor.yy321 ); } - delete yymsp[-2].minor.yy66; + delete yymsp[-2].minor.yy360; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 216: /* delete_stmt ::= with DELETE FROM */ + case 217: /* delete_stmt ::= with DELETE FROM */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteDelete* q = new SqliteDelete(); - q->with = yymsp[-2].minor.yy367; - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; + q->with = yymsp[-2].minor.yy321; + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; } break; - case 217: /* delete_stmt ::= with DELETE FROM nm DOT */ + case 218: /* delete_stmt ::= with DELETE FROM nm DOT */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteDelete* q = new SqliteDelete(); - q->with = yymsp[-4].minor.yy367; - q->database = *(yymsp[-1].minor.yy211); - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[-1].minor.yy211; + q->with = yymsp[-4].minor.yy321; + q->database = *(yymsp[-1].minor.yy399); + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[-1].minor.yy399; } break; - case 218: /* delete_stmt ::= with DELETE FROM nm DOT ID_TAB */ - case 227: /* update_stmt ::= with UPDATE orconf nm DOT ID_TAB */ yytestcase(yyruleno==227); -{ yy_destructor(yypParser,219,&yymsp[-5].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 219: /* delete_stmt ::= with DELETE FROM nm DOT ID_TAB */ + case 228: /* update_stmt ::= with UPDATE orconf nm DOT ID_TAB */ yytestcase(yyruleno==228); +{ yy_destructor(yypParser,221,&yymsp[-5].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; - case 219: /* delete_stmt ::= with DELETE FROM ID_DB|ID_TAB */ - case 228: /* update_stmt ::= with UPDATE orconf ID_DB|ID_TAB */ yytestcase(yyruleno==228); -{ yy_destructor(yypParser,219,&yymsp[-3].minor); + case 220: /* delete_stmt ::= with DELETE FROM ID_DB|ID_TAB */ + case 229: /* update_stmt ::= with UPDATE orconf ID_DB|ID_TAB */ yytestcase(yyruleno==229); +{ yy_destructor(yypParser,221,&yymsp[-3].minor); } break; - case 222: /* where_opt ::= WHERE */ + case 223: /* where_opt ::= WHERE */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy490 = new SqliteExpr(); + yygotominor.yy352 = new SqliteExpr(); } break; - case 224: /* update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ + case 225: /* update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ { - yygotominor.yy399 = new SqliteUpdate( - *(yymsp[-5].minor.yy30), - yymsp[-4].minor.yy66->name1, - yymsp[-4].minor.yy66->name2, - yymsp[-3].minor.yy472 ? yymsp[-3].minor.yy472->notIndexedKw : false, - yymsp[-3].minor.yy472 ? yymsp[-3].minor.yy472->indexedBy : QString::null, - *(yymsp[-1].minor.yy381), - yymsp[0].minor.yy490, - yymsp[-7].minor.yy367 + yygotominor.yy283 = new SqliteUpdate( + *(yymsp[-5].minor.yy338), + yymsp[-4].minor.yy360->name1, + yymsp[-4].minor.yy360->name2, + yymsp[-3].minor.yy192 ? yymsp[-3].minor.yy192->notIndexedKw : false, + yymsp[-3].minor.yy192 ? yymsp[-3].minor.yy192->indexedBy : QString::null, + *(yymsp[-1].minor.yy521), + yymsp[0].minor.yy352, + yymsp[-7].minor.yy321 ); - delete yymsp[-5].minor.yy30; - delete yymsp[-4].minor.yy66; - delete yymsp[-1].minor.yy381; - if (yymsp[-3].minor.yy472) - delete yymsp[-3].minor.yy472; + delete yymsp[-5].minor.yy338; + delete yymsp[-4].minor.yy360; + delete yymsp[-1].minor.yy521; + if (yymsp[-3].minor.yy192) + delete yymsp[-3].minor.yy192; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 225: /* update_stmt ::= with UPDATE orconf */ + case 226: /* update_stmt ::= with UPDATE orconf */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteUpdate* q = new SqliteUpdate(); - q->with = yymsp[-2].minor.yy367; - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[0].minor.yy30; + q->with = yymsp[-2].minor.yy321; + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[0].minor.yy338; } break; - case 226: /* update_stmt ::= with UPDATE orconf nm DOT */ + case 227: /* update_stmt ::= with UPDATE orconf nm DOT */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteUpdate* q = new SqliteUpdate(); - q->with = yymsp[-4].minor.yy367; - q->database = *(yymsp[-1].minor.yy211); - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[-2].minor.yy30; - delete yymsp[-1].minor.yy211; + q->with = yymsp[-4].minor.yy321; + q->database = *(yymsp[-1].minor.yy399); + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[-2].minor.yy338; + delete yymsp[-1].minor.yy399; } break; - case 229: /* setlist ::= setlist COMMA nm EQ expr */ + case 230: /* setlist ::= setlist COMMA nm EQ expr */ { - yymsp[-4].minor.yy381->append(ParserSetValue(*(yymsp[-2].minor.yy211), yymsp[0].minor.yy490)); - yygotominor.yy381 = yymsp[-4].minor.yy381; - delete yymsp[-2].minor.yy211; - DONT_INHERIT_TOKENS("setlist"); + yymsp[-4].minor.yy521->append(ParserSetValue(*(yymsp[-2].minor.yy399), yymsp[0].minor.yy352)); + yygotominor.yy521 = yymsp[-4].minor.yy521; + delete yymsp[-2].minor.yy399; } break; - case 230: /* setlist ::= nm EQ expr */ + case 231: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { - yygotominor.yy381 = new ParserSetValueList(); - yygotominor.yy381->append(ParserSetValue(*(yymsp[-2].minor.yy211), yymsp[0].minor.yy490)); - delete yymsp[-2].minor.yy211; + yymsp[-6].minor.yy521->append(ParserSetValue(*(yymsp[-3].minor.yy95), yymsp[0].minor.yy352)); + yygotominor.yy521 = yymsp[-6].minor.yy521; + delete yymsp[-3].minor.yy95; } break; - case 231: /* setlist ::= */ + case 232: /* setlist ::= nm EQ expr */ +{ + yygotominor.yy521 = new ParserSetValueList(); + yygotominor.yy521->append(ParserSetValue(*(yymsp[-2].minor.yy399), yymsp[0].minor.yy352)); + delete yymsp[-2].minor.yy399; + } + break; + case 233: /* setlist ::= LP idlist RP EQ expr */ +{ + yygotominor.yy521 = new ParserSetValueList(); + yygotominor.yy521->append(ParserSetValue(*(yymsp[-3].minor.yy95), yymsp[0].minor.yy352)); + delete yymsp[-3].minor.yy95; + } + break; + case 234: /* setlist ::= */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy381 = new ParserSetValueList(); + yygotominor.yy521 = new ParserSetValueList(); } break; - case 232: /* setlist ::= setlist COMMA */ + case 235: /* setlist ::= setlist COMMA */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy381 = yymsp[-1].minor.yy381; + yygotominor.yy521 = yymsp[-1].minor.yy521; } break; - case 233: /* setlist ::= setlist COMMA ID_COL */ - case 234: /* setlist ::= ID_COL */ yytestcase(yyruleno==234); -{ yy_destructor(yypParser,247,&yymsp[-2].minor); + case 236: /* setlist ::= setlist COMMA ID_COL */ + case 237: /* setlist ::= ID_COL */ yytestcase(yyruleno==237); +{ yy_destructor(yypParser,249,&yymsp[-2].minor); } break; - case 236: /* insert_stmt ::= with insert_cmd INTO fullname inscollist_opt select */ + case 238: /* idlist_opt ::= */ +{yygotominor.yy95 = new QStringList();} + break; + case 239: /* idlist_opt ::= LP idlist RP */ +{yygotominor.yy95 = yymsp[-1].minor.yy95;} + break; + case 240: /* idlist ::= idlist COMMA nm */ +{ + yygotominor.yy95 = yymsp[-2].minor.yy95; + *(yygotominor.yy95) << *(yymsp[0].minor.yy399); + delete yymsp[0].minor.yy399; + } + break; + case 241: /* idlist ::= nm */ { - yygotominor.yy399 = new SqliteInsert( - yymsp[-4].minor.yy250->replace, - yymsp[-4].minor.yy250->orConflict, - yymsp[-2].minor.yy66->name1, - yymsp[-2].minor.yy66->name2, - *(yymsp[-1].minor.yy445), - yymsp[0].minor.yy123, - yymsp[-5].minor.yy367 + yygotominor.yy95 = new QStringList(); + *(yygotominor.yy95) << *(yymsp[0].minor.yy399); + delete yymsp[0].minor.yy399; + } + break; + case 242: /* idlist ::= */ +{ + parserContext->minorErrorBeforeNextToken("Syntax error"); + yygotominor.yy95 = new QStringList(); + } + break; + case 243: /* idlist ::= idlist COMMA ID_COL */ + case 244: /* idlist ::= ID_COL */ yytestcase(yyruleno==244); +{ yy_destructor(yypParser,245,&yymsp[-2].minor); +} + break; + case 246: /* insert_stmt ::= with insert_cmd INTO fullname idlist_opt select upsert */ +{ + yygotominor.yy283 = new SqliteInsert( + yymsp[-5].minor.yy105->replace, + yymsp[-5].minor.yy105->orConflict, + yymsp[-3].minor.yy360->name1, + yymsp[-3].minor.yy360->name2, + *(yymsp[-2].minor.yy95), + yymsp[-1].minor.yy473, + yymsp[-6].minor.yy321, + yymsp[0].minor.yy560 ); - delete yymsp[-2].minor.yy66; - delete yymsp[-4].minor.yy250; - delete yymsp[-1].minor.yy445; + delete yymsp[-3].minor.yy360; + delete yymsp[-5].minor.yy105; + delete yymsp[-2].minor.yy95; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 237: /* insert_stmt ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */ + case 247: /* insert_stmt ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ { - yygotominor.yy399 = new SqliteInsert( - yymsp[-5].minor.yy250->replace, - yymsp[-5].minor.yy250->orConflict, - yymsp[-3].minor.yy66->name1, - yymsp[-3].minor.yy66->name2, - *(yymsp[-2].minor.yy445), - yymsp[-6].minor.yy367 + yygotominor.yy283 = new SqliteInsert( + yymsp[-5].minor.yy105->replace, + yymsp[-5].minor.yy105->orConflict, + yymsp[-3].minor.yy360->name1, + yymsp[-3].minor.yy360->name2, + *(yymsp[-2].minor.yy95), + yymsp[-6].minor.yy321 ); - delete yymsp[-3].minor.yy66; - delete yymsp[-5].minor.yy250; - delete yymsp[-2].minor.yy445; + delete yymsp[-3].minor.yy360; + delete yymsp[-5].minor.yy105; + delete yymsp[-2].minor.yy95; // since it's used in trigger: - objectForTokens = yygotominor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 238: /* insert_stmt ::= with insert_cmd INTO */ + case 248: /* insert_stmt ::= with insert_cmd INTO */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteInsert* q = new SqliteInsert(); - q->replaceKw = yymsp[-1].minor.yy250->replace; - q->onConflict = yymsp[-1].minor.yy250->orConflict; - q->with = yymsp[-2].minor.yy367; - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[-1].minor.yy250; + q->replaceKw = yymsp[-1].minor.yy105->replace; + q->onConflict = yymsp[-1].minor.yy105->orConflict; + q->with = yymsp[-2].minor.yy321; + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[-1].minor.yy105; } break; - case 239: /* insert_stmt ::= with insert_cmd INTO nm DOT */ + case 249: /* insert_stmt ::= with insert_cmd INTO nm DOT */ { parserContext->minorErrorBeforeNextToken("Syntax error"); SqliteInsert* q = new SqliteInsert(); - q->replaceKw = yymsp[-3].minor.yy250->replace; - q->onConflict = yymsp[-3].minor.yy250->orConflict; - q->with = yymsp[-4].minor.yy367; - q->database = *(yymsp[-1].minor.yy211); - yygotominor.yy399 = q; - objectForTokens = yygotominor.yy399; - delete yymsp[-3].minor.yy250; - delete yymsp[-1].minor.yy211; - } - break; - case 240: /* insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB */ -{ yy_destructor(yypParser,219,&yymsp[-3].minor); - yy_destructor(yypParser,249,&yymsp[-2].minor); + q->replaceKw = yymsp[-3].minor.yy105->replace; + q->onConflict = yymsp[-3].minor.yy105->orConflict; + q->with = yymsp[-4].minor.yy321; + q->database = *(yymsp[-1].minor.yy399); + yygotominor.yy283 = q; + objectForTokens = yygotominor.yy283; + delete yymsp[-3].minor.yy105; + delete yymsp[-1].minor.yy399; + } + break; + case 250: /* insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB */ +{ yy_destructor(yypParser,221,&yymsp[-3].minor); + yy_destructor(yypParser,252,&yymsp[-2].minor); } break; - case 241: /* insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB */ -{ yy_destructor(yypParser,219,&yymsp[-5].minor); - yy_destructor(yypParser,249,&yymsp[-4].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 251: /* insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB */ +{ yy_destructor(yypParser,221,&yymsp[-5].minor); + yy_destructor(yypParser,252,&yymsp[-4].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; - case 242: /* insert_cmd ::= INSERT orconf */ + case 252: /* insert_cmd ::= INSERT orconf */ { - yygotominor.yy250 = new ParserStubInsertOrReplace(false, *(yymsp[0].minor.yy30)); - delete yymsp[0].minor.yy30; + yygotominor.yy105 = new ParserStubInsertOrReplace(false, *(yymsp[0].minor.yy338)); + delete yymsp[0].minor.yy338; } break; - case 243: /* insert_cmd ::= REPLACE */ -{yygotominor.yy250 = new ParserStubInsertOrReplace(true);} - break; - case 244: /* inscollist_opt ::= */ -{yygotominor.yy445 = new ParserStringList();} + case 253: /* insert_cmd ::= REPLACE */ +{yygotominor.yy105 = new ParserStubInsertOrReplace(true);} break; - case 245: /* inscollist_opt ::= LP inscollist RP */ -{yygotominor.yy445 = yymsp[-1].minor.yy445;} - break; - case 246: /* inscollist ::= inscollist COMMA nm */ + case 254: /* upsert ::= */ { - yymsp[-2].minor.yy445->append(*(yymsp[0].minor.yy211)); - yygotominor.yy445 = yymsp[-2].minor.yy445; - delete yymsp[0].minor.yy211; - DONT_INHERIT_TOKENS("inscollist"); + yygotominor.yy560 = nullptr; } break; - case 247: /* inscollist ::= nm */ + case 255: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ { - yygotominor.yy445 = new ParserStringList(); - yygotominor.yy445->append(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; + yygotominor.yy560 = new SqliteUpsert(*(yymsp[-7].minor.yy163), yymsp[-5].minor.yy352, *(yymsp[-1].minor.yy521), yymsp[0].minor.yy352); + delete yymsp[-7].minor.yy163; + delete yymsp[-1].minor.yy521; + objectForTokens = yygotominor.yy560; } break; - case 248: /* inscollist ::= */ + case 256: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ { - parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy445 = new ParserStringList(); + yygotominor.yy560 = new SqliteUpsert(*(yymsp[-4].minor.yy163), yymsp[-2].minor.yy352); + delete yymsp[-4].minor.yy163; + objectForTokens = yygotominor.yy560; } break; - case 249: /* inscollist ::= inscollist COMMA ID_COL */ - case 250: /* inscollist ::= ID_COL */ yytestcase(yyruleno==250); -{ yy_destructor(yypParser,243,&yymsp[-2].minor); -} + case 257: /* upsert ::= ON CONFLICT DO NOTHING */ +{ + yygotominor.yy560 = new SqliteUpsert(); + objectForTokens = yygotominor.yy560; + } break; - case 251: /* exprx ::= nm DOT */ + case 258: /* exprx ::= nm DOT */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[-1].minor.yy211), QString::null, QString::null); - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[-1].minor.yy399), QString::null, QString::null); + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error "); } break; - case 252: /* exprx ::= nm DOT nm DOT */ + case 259: /* exprx ::= nm DOT nm DOT */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy211), QString::null); - delete yymsp[-3].minor.yy211; - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[-3].minor.yy399), *(yymsp[-1].minor.yy399), QString::null); + delete yymsp[-3].minor.yy399; + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error "); } break; - case 253: /* exprx ::= expr not_opt BETWEEN expr AND */ + case 260: /* exprx ::= expr not_opt BETWEEN expr AND */ { - yygotominor.yy490 = new SqliteExpr(); - delete yymsp[-3].minor.yy237; - delete yymsp[-4].minor.yy490; - delete yymsp[-1].minor.yy490; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + delete yymsp[-3].minor.yy451; + delete yymsp[-4].minor.yy352; + delete yymsp[-1].minor.yy352; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error "); } break; - case 254: /* exprx ::= CASE case_operand case_exprlist case_else */ + case 261: /* exprx ::= CASE case_operand case_exprlist case_else */ { - yygotominor.yy490 = new SqliteExpr(); - delete yymsp[-1].minor.yy13; - delete yymsp[-2].minor.yy490; - delete yymsp[0].minor.yy490; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + delete yymsp[-1].minor.yy551; + delete yymsp[-2].minor.yy352; + delete yymsp[0].minor.yy352; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error "); } break; - case 255: /* exprx ::= expr not_opt IN LP exprlist */ + case 262: /* exprx ::= expr not_opt IN LP exprlist */ { - yygotominor.yy490 = new SqliteExpr(); - delete yymsp[-3].minor.yy237; - delete yymsp[0].minor.yy13; - delete yymsp[-4].minor.yy490; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + delete yymsp[-3].minor.yy451; + delete yymsp[0].minor.yy551; + delete yymsp[-4].minor.yy352; + objectForTokens = yygotominor.yy352; parserContext->minorErrorBeforeNextToken("Syntax error "); } break; - case 256: /* exprx ::= expr not_opt IN ID_DB */ -{ yy_destructor(yypParser,199,&yymsp[-3].minor); + case 263: /* exprx ::= expr not_opt IN ID_DB */ +{ yy_destructor(yypParser,201,&yymsp[-3].minor); } break; - case 257: /* exprx ::= expr not_opt IN nm DOT ID_TAB */ - case 258: /* exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN */ yytestcase(yyruleno==258); -{ yy_destructor(yypParser,199,&yymsp[-5].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 264: /* exprx ::= expr not_opt IN nm DOT ID_TAB */ + case 265: /* exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN */ yytestcase(yyruleno==265); +{ yy_destructor(yypParser,201,&yymsp[-5].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; - case 260: /* exprx ::= nm DOT nm DOT ID_COL */ -{ yy_destructor(yypParser,177,&yymsp[-4].minor); - yy_destructor(yypParser,177,&yymsp[-2].minor); + case 267: /* exprx ::= nm DOT nm DOT ID_COL */ +{ yy_destructor(yypParser,179,&yymsp[-4].minor); + yy_destructor(yypParser,179,&yymsp[-2].minor); } break; - case 261: /* exprx ::= expr COLLATE ID_COLLATE */ - case 262: /* exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP */ yytestcase(yyruleno==262); -{ yy_destructor(yypParser,199,&yymsp[-2].minor); + case 268: /* exprx ::= expr COLLATE ID_COLLATE */ + case 269: /* exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP */ yytestcase(yyruleno==269); +{ yy_destructor(yypParser,201,&yymsp[-2].minor); } break; - case 263: /* exprx ::= term */ + case 270: /* exprx ::= term */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initLiteral(*(yymsp[0].minor.yy21)); - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initLiteral(*(yymsp[0].minor.yy469)); + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy352; } break; - case 264: /* exprx ::= CTIME_KW */ + case 271: /* exprx ::= CTIME_KW */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initCTime(yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initCTime(yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 265: /* exprx ::= LP nexprlist RP */ + case 272: /* exprx ::= LP nexprlist RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initRowValue(*(yymsp[-1].minor.yy13)); - delete yymsp[-1].minor.yy13; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initRowValue(*(yymsp[-1].minor.yy551)); + delete yymsp[-1].minor.yy551; + objectForTokens = yygotominor.yy352; } break; - case 266: /* exprx ::= id */ + case 273: /* exprx ::= id */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 267: /* exprx ::= JOIN_KW */ + case 274: /* exprx ::= JOIN_KW */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 268: /* exprx ::= nm DOT nm */ + case 275: /* exprx ::= nm DOT nm */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[-2].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 269: /* exprx ::= nm DOT nm DOT nm */ + case 276: /* exprx ::= nm DOT nm DOT nm */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initId(*(yymsp[-4].minor.yy211), *(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-4].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initId(*(yymsp[-4].minor.yy399), *(yymsp[-2].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-4].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 270: /* exprx ::= VARIABLE */ + case 277: /* exprx ::= VARIABLE */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initBindParam(yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initBindParam(yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 271: /* exprx ::= expr COLLATE ids */ + case 278: /* exprx ::= expr COLLATE ids */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initCollate(yymsp[-2].minor.yy490, *(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initCollate(yymsp[-2].minor.yy352, *(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 272: /* exprx ::= CAST LP expr AS typetoken RP */ + case 279: /* exprx ::= CAST LP expr AS typetoken RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initCast(yymsp[-3].minor.yy490, yymsp[-1].minor.yy299); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initCast(yymsp[-3].minor.yy352, yymsp[-1].minor.yy537); + objectForTokens = yygotominor.yy352; } break; - case 273: /* exprx ::= ID LP distinct exprlist RP */ + case 280: /* exprx ::= ID LP distinct exprlist RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initFunction(yymsp[-4].minor.yy0->value, *(yymsp[-2].minor.yy376), *(yymsp[-1].minor.yy13)); - delete yymsp[-2].minor.yy376; - delete yymsp[-1].minor.yy13; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initFunction(yymsp[-4].minor.yy0->value, *(yymsp[-2].minor.yy146), *(yymsp[-1].minor.yy551)); + delete yymsp[-2].minor.yy146; + delete yymsp[-1].minor.yy551; + objectForTokens = yygotominor.yy352; } break; - case 274: /* exprx ::= ID LP STAR RP */ + case 281: /* exprx ::= ID LP STAR RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initFunction(yymsp[-3].minor.yy0->value, true); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initFunction(yymsp[-3].minor.yy0->value, true); + objectForTokens = yygotominor.yy352; } break; - case 275: /* exprx ::= expr AND expr */ - case 276: /* exprx ::= expr OR expr */ yytestcase(yyruleno==276); - case 277: /* exprx ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==277); - case 278: /* exprx ::= expr EQ|NE expr */ yytestcase(yyruleno==278); - case 279: /* exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==279); - case 280: /* exprx ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==280); - case 281: /* exprx ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==281); - case 282: /* exprx ::= expr CONCAT expr */ yytestcase(yyruleno==282); + case 282: /* exprx ::= expr AND expr */ + case 283: /* exprx ::= expr OR expr */ yytestcase(yyruleno==283); + case 284: /* exprx ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==284); + case 285: /* exprx ::= expr EQ|NE expr */ yytestcase(yyruleno==285); + case 286: /* exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==286); + case 287: /* exprx ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==287); + case 288: /* exprx ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==288); + case 289: /* exprx ::= expr CONCAT expr */ yytestcase(yyruleno==289); { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initBinOp(yymsp[-2].minor.yy490, yymsp[-1].minor.yy0->value, yymsp[0].minor.yy490); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initBinOp(yymsp[-2].minor.yy352, yymsp[-1].minor.yy0->value, yymsp[0].minor.yy352); + objectForTokens = yygotominor.yy352; } break; - case 283: /* exprx ::= expr not_opt likeop expr */ + case 290: /* exprx ::= expr not_opt likeop expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initLike(yymsp[-3].minor.yy490, *(yymsp[-2].minor.yy237), *(yymsp[-1].minor.yy374), yymsp[0].minor.yy490); - delete yymsp[-2].minor.yy237; - delete yymsp[-1].minor.yy374; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initLike(yymsp[-3].minor.yy352, *(yymsp[-2].minor.yy451), *(yymsp[-1].minor.yy520), yymsp[0].minor.yy352); + delete yymsp[-2].minor.yy451; + delete yymsp[-1].minor.yy520; + objectForTokens = yygotominor.yy352; } break; - case 284: /* exprx ::= expr not_opt likeop expr ESCAPE expr */ + case 291: /* exprx ::= expr not_opt likeop expr ESCAPE expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initLike(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), *(yymsp[-3].minor.yy374), yymsp[-2].minor.yy490, yymsp[0].minor.yy490); - delete yymsp[-4].minor.yy237; - delete yymsp[-3].minor.yy374; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initLike(yymsp[-5].minor.yy352, *(yymsp[-4].minor.yy451), *(yymsp[-3].minor.yy520), yymsp[-2].minor.yy352, yymsp[0].minor.yy352); + delete yymsp[-4].minor.yy451; + delete yymsp[-3].minor.yy520; + objectForTokens = yygotominor.yy352; } break; - case 285: /* exprx ::= expr ISNULL|NOTNULL */ + case 292: /* exprx ::= expr ISNULL|NOTNULL */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initNull(yymsp[-1].minor.yy490, yymsp[0].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initNull(yymsp[-1].minor.yy352, yymsp[0].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 286: /* exprx ::= expr NOT NULL */ + case 293: /* exprx ::= expr NOT NULL */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initNull(yymsp[-2].minor.yy490, "NOT NULL"); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initNull(yymsp[-2].minor.yy352, "NOT NULL"); + objectForTokens = yygotominor.yy352; } break; - case 287: /* exprx ::= expr IS not_opt expr */ + case 294: /* exprx ::= expr IS not_opt expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initIs(yymsp[-3].minor.yy490, *(yymsp[-1].minor.yy237), yymsp[0].minor.yy490); - delete yymsp[-1].minor.yy237; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initIs(yymsp[-3].minor.yy352, *(yymsp[-1].minor.yy451), yymsp[0].minor.yy352); + delete yymsp[-1].minor.yy451; + objectForTokens = yygotominor.yy352; } break; - case 288: /* exprx ::= NOT expr */ + case 295: /* exprx ::= NOT expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initUnaryOp(yymsp[0].minor.yy490, yymsp[-1].minor.yy0->value); + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initUnaryOp(yymsp[0].minor.yy352, yymsp[-1].minor.yy0->value); } break; - case 289: /* exprx ::= BITNOT expr */ - case 291: /* exprx ::= PLUS expr */ yytestcase(yyruleno==291); + case 296: /* exprx ::= BITNOT expr */ + case 298: /* exprx ::= PLUS expr */ yytestcase(yyruleno==298); { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initUnaryOp(yymsp[0].minor.yy490, yymsp[-1].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initUnaryOp(yymsp[0].minor.yy352, yymsp[-1].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 290: /* exprx ::= MINUS expr */ + case 297: /* exprx ::= MINUS expr */ { - yygotominor.yy490 = new SqliteExpr(); - if (yymsp[0].minor.yy490->mode == SqliteExpr::Mode::LITERAL_VALUE && + yygotominor.yy352 = new SqliteExpr(); + if (yymsp[0].minor.yy352->mode == SqliteExpr::Mode::LITERAL_VALUE && parserContext->isCandidateForMaxNegativeNumber() && - yymsp[0].minor.yy490->literalValue == static_cast(0L)) + yymsp[0].minor.yy352->literalValue == static_cast(0L)) { - yygotominor.yy490->initLiteral(std::numeric_limits::min()); - delete yymsp[0].minor.yy490; + yygotominor.yy352->initLiteral(std::numeric_limits::min()); + delete yymsp[0].minor.yy352; } else { - yygotominor.yy490->initUnaryOp(yymsp[0].minor.yy490, yymsp[-1].minor.yy0->value); + yygotominor.yy352->initUnaryOp(yymsp[0].minor.yy352, yymsp[-1].minor.yy0->value); } - objectForTokens = yygotominor.yy490; + objectForTokens = yygotominor.yy352; } break; - case 292: /* exprx ::= expr not_opt BETWEEN expr AND expr */ + case 299: /* exprx ::= expr not_opt BETWEEN expr AND expr */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initBetween(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), yymsp[-2].minor.yy490, yymsp[0].minor.yy490); - delete yymsp[-4].minor.yy237; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initBetween(yymsp[-5].minor.yy352, *(yymsp[-4].minor.yy451), yymsp[-2].minor.yy352, yymsp[0].minor.yy352); + delete yymsp[-4].minor.yy451; + objectForTokens = yygotominor.yy352; } break; - case 293: /* exprx ::= expr not_opt IN LP exprlist RP */ + case 300: /* exprx ::= expr not_opt IN LP exprlist RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initIn(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), *(yymsp[-1].minor.yy13)); - delete yymsp[-4].minor.yy237; - delete yymsp[-1].minor.yy13; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initIn(yymsp[-5].minor.yy352, *(yymsp[-4].minor.yy451), *(yymsp[-1].minor.yy551)); + delete yymsp[-4].minor.yy451; + delete yymsp[-1].minor.yy551; + objectForTokens = yygotominor.yy352; } break; - case 294: /* exprx ::= LP select RP */ + case 301: /* exprx ::= LP select RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initSubSelect(yymsp[-1].minor.yy123); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initSubSelect(yymsp[-1].minor.yy473); + objectForTokens = yygotominor.yy352; } break; - case 295: /* exprx ::= expr not_opt IN LP select RP */ + case 302: /* exprx ::= expr not_opt IN LP select RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initIn(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), yymsp[-1].minor.yy123); - delete yymsp[-4].minor.yy237; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initIn(yymsp[-5].minor.yy352, *(yymsp[-4].minor.yy451), yymsp[-1].minor.yy473); + delete yymsp[-4].minor.yy451; + objectForTokens = yygotominor.yy352; } break; - case 296: /* exprx ::= expr not_opt IN nm dbnm */ + case 303: /* exprx ::= expr not_opt IN nm dbnm */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initIn(yymsp[-4].minor.yy490, *(yymsp[-3].minor.yy237), *(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-3].minor.yy237; - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initIn(yymsp[-4].minor.yy352, *(yymsp[-3].minor.yy451), *(yymsp[-1].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-3].minor.yy451; + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 297: /* exprx ::= EXISTS LP select RP */ + case 304: /* exprx ::= EXISTS LP select RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initExists(yymsp[-1].minor.yy123); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initExists(yymsp[-1].minor.yy473); + objectForTokens = yygotominor.yy352; } break; - case 298: /* exprx ::= CASE case_operand case_exprlist case_else END */ + case 305: /* exprx ::= CASE case_operand case_exprlist case_else END */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initCase(yymsp[-3].minor.yy490, *(yymsp[-2].minor.yy13), yymsp[-1].minor.yy490); - delete yymsp[-2].minor.yy13; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initCase(yymsp[-3].minor.yy352, *(yymsp[-2].minor.yy551), yymsp[-1].minor.yy352); + delete yymsp[-2].minor.yy551; + objectForTokens = yygotominor.yy352; } break; - case 299: /* exprx ::= RAISE LP IGNORE RP */ + case 306: /* exprx ::= RAISE LP IGNORE RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initRaise(yymsp[-1].minor.yy0->value); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initRaise(yymsp[-1].minor.yy0->value); + objectForTokens = yygotominor.yy352; } break; - case 300: /* exprx ::= RAISE LP raisetype COMMA nm RP */ + case 307: /* exprx ::= RAISE LP raisetype COMMA nm RP */ { - yygotominor.yy490 = new SqliteExpr(); - yygotominor.yy490->initRaise(yymsp[-3].minor.yy0->value, *(yymsp[-1].minor.yy211)); - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + yygotominor.yy352->initRaise(yymsp[-3].minor.yy0->value, *(yymsp[-1].minor.yy399)); + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy352; } break; - case 301: /* expr ::= */ + case 308: /* expr ::= */ { - yygotominor.yy490 = new SqliteExpr(); - objectForTokens = yygotominor.yy490; + yygotominor.yy352 = new SqliteExpr(); + objectForTokens = yygotominor.yy352; parserContext->minorErrorAfterLastToken("Syntax error "); } break; - case 305: /* likeop ::= LIKE_KW|MATCH */ -{yygotominor.yy374 = new SqliteExpr::LikeOp(SqliteExpr::likeOp(yymsp[0].minor.yy0->value));} + case 312: /* likeop ::= LIKE_KW|MATCH */ +{yygotominor.yy520 = new SqliteExpr::LikeOp(SqliteExpr::likeOp(yymsp[0].minor.yy0->value));} break; - case 306: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 313: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yymsp[-4].minor.yy13->append(yymsp[-2].minor.yy490); - yymsp[-4].minor.yy13->append(yymsp[0].minor.yy490); - yygotominor.yy13 = yymsp[-4].minor.yy13; + yymsp[-4].minor.yy551->append(yymsp[-2].minor.yy352); + yymsp[-4].minor.yy551->append(yymsp[0].minor.yy352); + yygotominor.yy551 = yymsp[-4].minor.yy551; } break; - case 307: /* case_exprlist ::= WHEN expr THEN expr */ + case 314: /* case_exprlist ::= WHEN expr THEN expr */ { - yygotominor.yy13 = new ParserExprList(); - yygotominor.yy13->append(yymsp[-2].minor.yy490); - yygotominor.yy13->append(yymsp[0].minor.yy490); + yygotominor.yy551 = new ParserExprList(); + yygotominor.yy551->append(yymsp[-2].minor.yy352); + yygotominor.yy551->append(yymsp[0].minor.yy352); } break; - case 314: /* nexprlist ::= nexprlist COMMA expr */ + case 321: /* nexprlist ::= nexprlist COMMA expr */ { - yymsp[-2].minor.yy13->append(yymsp[0].minor.yy490); - yygotominor.yy13 = yymsp[-2].minor.yy13; + yymsp[-2].minor.yy551->append(yymsp[0].minor.yy352); + yygotominor.yy551 = yymsp[-2].minor.yy551; DONT_INHERIT_TOKENS("nexprlist"); } break; - case 315: /* nexprlist ::= exprx */ + case 322: /* nexprlist ::= exprx */ { - yygotominor.yy13 = new ParserExprList(); - yygotominor.yy13->append(yymsp[0].minor.yy490); + yygotominor.yy551 = new ParserExprList(); + yygotominor.yy551->append(yymsp[0].minor.yy352); } break; - case 316: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 323: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { - yygotominor.yy399 = new SqliteCreateIndex( - *(yymsp[-10].minor.yy237), - *(yymsp[-8].minor.yy237), - *(yymsp[-7].minor.yy211), - *(yymsp[-6].minor.yy211), - *(yymsp[-4].minor.yy211), - *(yymsp[-2].minor.yy495), - yymsp[0].minor.yy490 + yygotominor.yy283 = new SqliteCreateIndex( + *(yymsp[-10].minor.yy451), + *(yymsp[-8].minor.yy451), + *(yymsp[-7].minor.yy399), + *(yymsp[-6].minor.yy399), + *(yymsp[-4].minor.yy399), + *(yymsp[-2].minor.yy163), + yymsp[0].minor.yy352 ); - delete yymsp[-8].minor.yy237; - delete yymsp[-10].minor.yy237; - delete yymsp[-7].minor.yy211; - delete yymsp[-6].minor.yy211; - delete yymsp[-4].minor.yy211; - delete yymsp[-2].minor.yy495; - objectForTokens = yygotominor.yy399; + delete yymsp[-8].minor.yy451; + delete yymsp[-10].minor.yy451; + delete yymsp[-7].minor.yy399; + delete yymsp[-6].minor.yy399; + delete yymsp[-4].minor.yy399; + delete yymsp[-2].minor.yy163; + objectForTokens = yygotominor.yy283; } break; - case 317: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB */ -{ yy_destructor(yypParser,177,&yymsp[-3].minor); + case 324: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB */ +{ yy_destructor(yypParser,179,&yymsp[-3].minor); } break; - case 322: /* idxlist_opt ::= */ -{yygotominor.yy139 = new ParserIndexedColumnList();} + case 329: /* idxlist_opt ::= */ +{yygotominor.yy223 = new ParserIndexedColumnList();} break; - case 323: /* idxlist_opt ::= LP idxlist RP */ -{yygotominor.yy139 = yymsp[-1].minor.yy139;} + case 330: /* idxlist_opt ::= LP idxlist RP */ +{yygotominor.yy223 = yymsp[-1].minor.yy223;} break; - case 324: /* idxlist ::= idxlist COMMA idxlist_single */ + case 331: /* idxlist ::= idxlist COMMA idxlist_single */ { - yymsp[-2].minor.yy139->append(yymsp[0].minor.yy90); - yygotominor.yy139 = yymsp[-2].minor.yy139; + yymsp[-2].minor.yy223->append(yymsp[0].minor.yy108); + yygotominor.yy223 = yymsp[-2].minor.yy223; DONT_INHERIT_TOKENS("idxlist"); } break; - case 325: /* idxlist ::= idxlist_single */ + case 332: /* idxlist ::= idxlist_single */ { - yygotominor.yy139 = new ParserIndexedColumnList(); - yygotominor.yy139->append(yymsp[0].minor.yy90); + yygotominor.yy223 = new ParserIndexedColumnList(); + yygotominor.yy223->append(yymsp[0].minor.yy108); } break; - case 326: /* idxlist_single ::= nm collate sortorder */ - case 327: /* idxlist_single ::= ID_COL */ yytestcase(yyruleno==327); + case 333: /* idxlist_single ::= nm collate sortorder */ + case 334: /* idxlist_single ::= ID_COL */ yytestcase(yyruleno==334); { SqliteIndexedColumn* obj = new SqliteIndexedColumn( - *(yymsp[-2].minor.yy211), - *(yymsp[-1].minor.yy211), - *(yymsp[0].minor.yy226) + *(yymsp[-2].minor.yy399), + *(yymsp[-1].minor.yy399), + *(yymsp[0].minor.yy309) ); - yygotominor.yy90 = obj; - delete yymsp[0].minor.yy226; - delete yymsp[-2].minor.yy211; - delete yymsp[-1].minor.yy211; - objectForTokens = yygotominor.yy90; + yygotominor.yy108 = obj; + delete yymsp[0].minor.yy309; + delete yymsp[-2].minor.yy399; + delete yymsp[-1].minor.yy399; + objectForTokens = yygotominor.yy108; } break; - case 331: /* cmd ::= DROP INDEX ifexists fullname */ + case 338: /* cmd ::= DROP INDEX ifexists fullname */ { - yygotominor.yy399 = new SqliteDropIndex(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2); - delete yymsp[-1].minor.yy237; - delete yymsp[0].minor.yy66; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDropIndex(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy360->name1, yymsp[0].minor.yy360->name2); + delete yymsp[-1].minor.yy451; + delete yymsp[0].minor.yy360; + objectForTokens = yygotominor.yy283; } break; - case 334: /* cmd ::= VACUUM */ + case 341: /* cmd ::= VACUUM */ { - yygotominor.yy399 = new SqliteVacuum(); - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteVacuum(); + objectForTokens = yygotominor.yy283; } break; - case 335: /* cmd ::= VACUUM nm */ + case 342: /* cmd ::= VACUUM nm */ { - yygotominor.yy399 = new SqliteVacuum(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteVacuum(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 336: /* cmd ::= PRAGMA nm dbnm */ + case 343: /* cmd ::= PRAGMA nm dbnm */ { - yygotominor.yy399 = new SqlitePragma(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqlitePragma(*(yymsp[-1].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 337: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ - case 339: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ yytestcase(yyruleno==339); + case 344: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 346: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ yytestcase(yyruleno==346); { - yygotominor.yy399 = new SqlitePragma(*(yymsp[-3].minor.yy211), *(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy21), true); - delete yymsp[-3].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy21; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqlitePragma(*(yymsp[-3].minor.yy399), *(yymsp[-2].minor.yy399), *(yymsp[0].minor.yy469), true); + delete yymsp[-3].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy469; + objectForTokens = yygotominor.yy283; } break; - case 338: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ - case 340: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ yytestcase(yyruleno==340); + case 345: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 347: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ yytestcase(yyruleno==347); { - yygotominor.yy399 = new SqlitePragma(*(yymsp[-4].minor.yy211), *(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy21), false); - delete yymsp[-4].minor.yy211; - delete yymsp[-3].minor.yy211; - delete yymsp[-1].minor.yy21; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqlitePragma(*(yymsp[-4].minor.yy399), *(yymsp[-3].minor.yy399), *(yymsp[-1].minor.yy469), false); + delete yymsp[-4].minor.yy399; + delete yymsp[-3].minor.yy399; + delete yymsp[-1].minor.yy469; + objectForTokens = yygotominor.yy283; } break; - case 344: /* nmnum ::= nm */ + case 351: /* nmnum ::= nm */ { - yygotominor.yy21 = new QVariant(*(yymsp[0].minor.yy211)); - delete yymsp[0].minor.yy211; + yygotominor.yy469 = new QVariant(*(yymsp[0].minor.yy399)); + delete yymsp[0].minor.yy399; } break; - case 350: /* minus_num ::= MINUS number */ + case 357: /* minus_num ::= MINUS number */ { - if (yymsp[0].minor.yy21->type() == QVariant::Double) - *(yymsp[0].minor.yy21) = -(yymsp[0].minor.yy21->toDouble()); - else if (yymsp[0].minor.yy21->type() == QVariant::LongLong) + if (yymsp[0].minor.yy469->type() == QVariant::Double) + *(yymsp[0].minor.yy469) = -(yymsp[0].minor.yy469->toDouble()); + else if (yymsp[0].minor.yy469->type() == QVariant::LongLong) { if (parserContext->isCandidateForMaxNegativeNumber()) - *(yymsp[0].minor.yy21) = std::numeric_limits::min(); + *(yymsp[0].minor.yy469) = std::numeric_limits::min(); else - *(yymsp[0].minor.yy21) = -(yymsp[0].minor.yy21->toLongLong()); + *(yymsp[0].minor.yy469) = -(yymsp[0].minor.yy469->toLongLong()); } else Q_ASSERT_X(true, "producing minus number", "QVariant is neither of Double or LongLong."); - yygotominor.yy21 = yymsp[0].minor.yy21; - } - break; - case 353: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END */ -{ - yygotominor.yy399 = new SqliteCreateTrigger( - *(yymsp[-13].minor.yy376), - *(yymsp[-11].minor.yy237), - *(yymsp[-10].minor.yy211), - *(yymsp[-9].minor.yy211), - *(yymsp[-5].minor.yy211), - *(yymsp[-8].minor.yy152), - yymsp[-7].minor.yy309, - *(yymsp[-4].minor.yy409), - yymsp[-3].minor.yy490, - *(yymsp[-1].minor.yy214), + yygotominor.yy469 = yymsp[0].minor.yy469; + } + break; + case 360: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END */ +{ + yygotominor.yy283 = new SqliteCreateTrigger( + *(yymsp[-13].minor.yy146), + *(yymsp[-11].minor.yy451), + *(yymsp[-10].minor.yy399), + *(yymsp[-9].minor.yy399), + *(yymsp[-5].minor.yy399), + *(yymsp[-8].minor.yy132), + yymsp[-7].minor.yy552, + *(yymsp[-4].minor.yy3), + yymsp[-3].minor.yy352, + *(yymsp[-1].minor.yy430), 3 ); - delete yymsp[-11].minor.yy237; - delete yymsp[-13].minor.yy376; - delete yymsp[-8].minor.yy152; - delete yymsp[-4].minor.yy409; - delete yymsp[-10].minor.yy211; - delete yymsp[-5].minor.yy211; - delete yymsp[-9].minor.yy211; - delete yymsp[-1].minor.yy214; - objectForTokens = yygotominor.yy399; + delete yymsp[-11].minor.yy451; + delete yymsp[-13].minor.yy146; + delete yymsp[-8].minor.yy132; + delete yymsp[-4].minor.yy3; + delete yymsp[-10].minor.yy399; + delete yymsp[-5].minor.yy399; + delete yymsp[-9].minor.yy399; + delete yymsp[-1].minor.yy430; + objectForTokens = yygotominor.yy283; } break; - case 354: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause */ + case 361: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause */ { QList CL; - yygotominor.yy399 = new SqliteCreateTrigger( - *(yymsp[-10].minor.yy376), - *(yymsp[-8].minor.yy237), - *(yymsp[-7].minor.yy211), - *(yymsp[-6].minor.yy211), - *(yymsp[-2].minor.yy211), - *(yymsp[-5].minor.yy152), - yymsp[-4].minor.yy309, - *(yymsp[-1].minor.yy409), - yymsp[0].minor.yy490, + yygotominor.yy283 = new SqliteCreateTrigger( + *(yymsp[-10].minor.yy146), + *(yymsp[-8].minor.yy451), + *(yymsp[-7].minor.yy399), + *(yymsp[-6].minor.yy399), + *(yymsp[-2].minor.yy399), + *(yymsp[-5].minor.yy132), + yymsp[-4].minor.yy552, + *(yymsp[-1].minor.yy3), + yymsp[0].minor.yy352, CL, 3 ); - delete yymsp[-8].minor.yy237; - delete yymsp[-10].minor.yy376; - delete yymsp[-5].minor.yy152; - delete yymsp[-1].minor.yy409; - delete yymsp[-7].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[-6].minor.yy211; - objectForTokens = yygotominor.yy399; + delete yymsp[-8].minor.yy451; + delete yymsp[-10].minor.yy146; + delete yymsp[-5].minor.yy132; + delete yymsp[-1].minor.yy3; + delete yymsp[-7].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[-6].minor.yy399; + objectForTokens = yygotominor.yy283; parserContext->minorErrorAfterLastToken("Syntax error"); } break; - case 355: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list */ + case 362: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list */ { - yygotominor.yy399 = new SqliteCreateTrigger( - *(yymsp[-12].minor.yy376), - *(yymsp[-10].minor.yy237), - *(yymsp[-9].minor.yy211), - *(yymsp[-8].minor.yy211), - *(yymsp[-4].minor.yy211), - *(yymsp[-7].minor.yy152), - yymsp[-6].minor.yy309, - *(yymsp[-3].minor.yy409), - yymsp[-2].minor.yy490, - *(yymsp[0].minor.yy214), + yygotominor.yy283 = new SqliteCreateTrigger( + *(yymsp[-12].minor.yy146), + *(yymsp[-10].minor.yy451), + *(yymsp[-9].minor.yy399), + *(yymsp[-8].minor.yy399), + *(yymsp[-4].minor.yy399), + *(yymsp[-7].minor.yy132), + yymsp[-6].minor.yy552, + *(yymsp[-3].minor.yy3), + yymsp[-2].minor.yy352, + *(yymsp[0].minor.yy430), 3 ); - delete yymsp[-10].minor.yy237; - delete yymsp[-12].minor.yy376; - delete yymsp[-7].minor.yy152; - delete yymsp[-3].minor.yy409; - delete yymsp[-9].minor.yy211; - delete yymsp[-4].minor.yy211; - delete yymsp[-8].minor.yy211; - delete yymsp[0].minor.yy214; - objectForTokens = yygotominor.yy399; + delete yymsp[-10].minor.yy451; + delete yymsp[-12].minor.yy146; + delete yymsp[-7].minor.yy132; + delete yymsp[-3].minor.yy3; + delete yymsp[-9].minor.yy399; + delete yymsp[-4].minor.yy399; + delete yymsp[-8].minor.yy399; + delete yymsp[0].minor.yy430; + objectForTokens = yygotominor.yy283; parserContext->minorErrorAfterLastToken("Syntax error"); } break; - case 356: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB */ -{ yy_destructor(yypParser,179,&yymsp[-8].minor); - yy_destructor(yypParser,177,&yymsp[-5].minor); - yy_destructor(yypParser,262,&yymsp[-3].minor); - yy_destructor(yypParser,263,&yymsp[-2].minor); + case 363: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB */ +{ yy_destructor(yypParser,181,&yymsp[-8].minor); + yy_destructor(yypParser,179,&yymsp[-5].minor); + yy_destructor(yypParser,265,&yymsp[-3].minor); + yy_destructor(yypParser,266,&yymsp[-2].minor); } break; - case 359: /* trigger_time ::= BEFORE */ -{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::BEFORE);} + case 366: /* trigger_time ::= BEFORE */ +{yygotominor.yy132 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::BEFORE);} break; - case 360: /* trigger_time ::= AFTER */ -{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::AFTER);} + case 367: /* trigger_time ::= AFTER */ +{yygotominor.yy132 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::AFTER);} break; - case 361: /* trigger_time ::= INSTEAD OF */ -{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::INSTEAD_OF);} + case 368: /* trigger_time ::= INSTEAD OF */ +{yygotominor.yy132 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::INSTEAD_OF);} break; - case 362: /* trigger_time ::= */ -{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::null);} + case 369: /* trigger_time ::= */ +{yygotominor.yy132 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::null);} break; - case 363: /* trigger_event ::= DELETE */ + case 370: /* trigger_event ::= DELETE */ { - yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::DELETE); - objectForTokens = yygotominor.yy309; + yygotominor.yy552 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::DELETE); + objectForTokens = yygotominor.yy552; } break; - case 364: /* trigger_event ::= INSERT */ + case 371: /* trigger_event ::= INSERT */ { - yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::INSERT); - objectForTokens = yygotominor.yy309; + yygotominor.yy552 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::INSERT); + objectForTokens = yygotominor.yy552; } break; - case 365: /* trigger_event ::= UPDATE */ + case 372: /* trigger_event ::= UPDATE */ { - yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::UPDATE); - objectForTokens = yygotominor.yy309; + yygotominor.yy552 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::UPDATE); + objectForTokens = yygotominor.yy552; } break; - case 366: /* trigger_event ::= UPDATE OF inscollist */ + case 373: /* trigger_event ::= UPDATE OF idlist */ { - yygotominor.yy309 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy445)); - delete yymsp[0].minor.yy445; - objectForTokens = yygotominor.yy309; + yygotominor.yy552 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy95)); + delete yymsp[0].minor.yy95; + objectForTokens = yygotominor.yy552; } break; - case 367: /* foreach_clause ::= */ -{yygotominor.yy409 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::null);} + case 374: /* foreach_clause ::= */ +{yygotominor.yy3 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::null);} break; - case 368: /* foreach_clause ::= FOR EACH ROW */ -{yygotominor.yy409 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_ROW);} + case 375: /* foreach_clause ::= FOR EACH ROW */ +{yygotominor.yy3 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_ROW);} break; - case 371: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 378: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - yymsp[-2].minor.yy214->append(yymsp[-1].minor.yy399); - yygotominor.yy214 = yymsp[-2].minor.yy214; + yymsp[-2].minor.yy430->append(yymsp[-1].minor.yy283); + yygotominor.yy430 = yymsp[-2].minor.yy430; DONT_INHERIT_TOKENS("trigger_cmd_list"); } break; - case 372: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 379: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - yygotominor.yy214 = new ParserQueryList(); - yygotominor.yy214->append(yymsp[-1].minor.yy399); + yygotominor.yy430 = new ParserQueryList(); + yygotominor.yy430->append(yymsp[-1].minor.yy283); } break; - case 373: /* trigger_cmd_list ::= SEMI */ + case 380: /* trigger_cmd_list ::= SEMI */ { - yygotominor.yy214 = new ParserQueryList(); + yygotominor.yy430 = new ParserQueryList(); parserContext->minorErrorAfterLastToken("Syntax error"); } break; - case 378: /* raisetype ::= ROLLBACK|ABORT|FAIL */ + case 385: /* raisetype ::= ROLLBACK|ABORT|FAIL */ {yygotominor.yy0 = yymsp[0].minor.yy0;} break; - case 379: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 386: /* cmd ::= DROP TRIGGER ifexists fullname */ { - yygotominor.yy399 = new SqliteDropTrigger(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2); - delete yymsp[-1].minor.yy237; - delete yymsp[0].minor.yy66; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDropTrigger(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy360->name1, yymsp[0].minor.yy360->name2); + delete yymsp[-1].minor.yy451; + delete yymsp[0].minor.yy360; + objectForTokens = yygotominor.yy283; } break; - case 382: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 389: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { - yygotominor.yy399 = new SqliteAttach(*(yymsp[-4].minor.yy237), yymsp[-3].minor.yy490, yymsp[-1].minor.yy490, yymsp[0].minor.yy490); - delete yymsp[-4].minor.yy237; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteAttach(*(yymsp[-4].minor.yy451), yymsp[-3].minor.yy352, yymsp[-1].minor.yy352, yymsp[0].minor.yy352); + delete yymsp[-4].minor.yy451; + objectForTokens = yygotominor.yy283; } break; - case 383: /* cmd ::= DETACH database_kw_opt expr */ + case 390: /* cmd ::= DETACH database_kw_opt expr */ { - yygotominor.yy399 = new SqliteDetach(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy490); - delete yymsp[-1].minor.yy237; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteDetach(*(yymsp[-1].minor.yy451), yymsp[0].minor.yy352); + delete yymsp[-1].minor.yy451; + objectForTokens = yygotominor.yy283; } break; - case 388: /* cmd ::= REINDEX */ -{yygotominor.yy399 = new SqliteReindex();} + case 395: /* cmd ::= REINDEX */ +{yygotominor.yy283 = new SqliteReindex();} break; - case 389: /* cmd ::= REINDEX nm dbnm */ - case 390: /* cmd ::= REINDEX ID_COLLATE */ yytestcase(yyruleno==390); + case 396: /* cmd ::= REINDEX nm dbnm */ + case 397: /* cmd ::= REINDEX ID_COLLATE */ yytestcase(yyruleno==397); { - yygotominor.yy399 = new SqliteReindex(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteReindex(*(yymsp[-1].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 393: /* cmd ::= ANALYZE */ + case 400: /* cmd ::= ANALYZE */ { - yygotominor.yy399 = new SqliteAnalyze(); - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteAnalyze(); + objectForTokens = yygotominor.yy283; } break; - case 394: /* cmd ::= ANALYZE nm dbnm */ + case 401: /* cmd ::= ANALYZE nm dbnm */ { - yygotominor.yy399 = new SqliteAnalyze(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211)); - delete yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + yygotominor.yy283 = new SqliteAnalyze(*(yymsp[-1].minor.yy399), *(yymsp[0].minor.yy399)); + delete yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 397: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 404: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - yygotominor.yy399 = new SqliteAlterTable( - yymsp[-3].minor.yy66->name1, - yymsp[-3].minor.yy66->name2, - *(yymsp[0].minor.yy211) + yygotominor.yy283 = new SqliteAlterTable( + yymsp[-3].minor.yy360->name1, + yymsp[-3].minor.yy360->name2, + *(yymsp[0].minor.yy399) ); - delete yymsp[0].minor.yy211; - delete yymsp[-3].minor.yy66; - objectForTokens = yygotominor.yy399; + delete yymsp[0].minor.yy399; + delete yymsp[-3].minor.yy360; + objectForTokens = yygotominor.yy283; } break; - case 398: /* cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column */ + case 405: /* cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column */ { - yygotominor.yy399 = new SqliteAlterTable( - yymsp[-3].minor.yy66->name1, - yymsp[-3].minor.yy66->name2, - *(yymsp[-1].minor.yy237), - yymsp[0].minor.yy425 + yygotominor.yy283 = new SqliteAlterTable( + yymsp[-3].minor.yy360->name1, + yymsp[-3].minor.yy360->name2, + *(yymsp[-1].minor.yy451), + yymsp[0].minor.yy227 ); - delete yymsp[-1].minor.yy237; - delete yymsp[-3].minor.yy66; - objectForTokens = yygotominor.yy399; + delete yymsp[-1].minor.yy451; + delete yymsp[-3].minor.yy360; + objectForTokens = yygotominor.yy283; } break; - case 399: /* cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW */ -{ yy_destructor(yypParser,181,&yymsp[-3].minor); + case 406: /* cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW */ +{ yy_destructor(yypParser,183,&yymsp[-3].minor); } break; - case 405: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 412: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - yygotominor.yy399 = new SqliteCreateVirtualTable( - *(yymsp[-4].minor.yy237), - *(yymsp[-3].minor.yy211), - *(yymsp[-2].minor.yy211), - *(yymsp[0].minor.yy211) + yygotominor.yy283 = new SqliteCreateVirtualTable( + *(yymsp[-4].minor.yy451), + *(yymsp[-3].minor.yy399), + *(yymsp[-2].minor.yy399), + *(yymsp[0].minor.yy399) ); - delete yymsp[-4].minor.yy237; - delete yymsp[-3].minor.yy211; - delete yymsp[-2].minor.yy211; - delete yymsp[0].minor.yy211; - objectForTokens = yygotominor.yy399; + delete yymsp[-4].minor.yy451; + delete yymsp[-3].minor.yy399; + delete yymsp[-2].minor.yy399; + delete yymsp[0].minor.yy399; + objectForTokens = yygotominor.yy283; } break; - case 406: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP */ + case 413: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP */ { - yygotominor.yy399 = new SqliteCreateVirtualTable( - *(yymsp[-7].minor.yy237), - *(yymsp[-6].minor.yy211), - *(yymsp[-5].minor.yy211), - *(yymsp[-3].minor.yy211), - *(yymsp[-1].minor.yy445) + yygotominor.yy283 = new SqliteCreateVirtualTable( + *(yymsp[-7].minor.yy451), + *(yymsp[-6].minor.yy399), + *(yymsp[-5].minor.yy399), + *(yymsp[-3].minor.yy399), + *(yymsp[-1].minor.yy95) ); - delete yymsp[-6].minor.yy211; - delete yymsp[-5].minor.yy211; - delete yymsp[-3].minor.yy211; - delete yymsp[-7].minor.yy237; - delete yymsp[-1].minor.yy445; - objectForTokens = yygotominor.yy399; + delete yymsp[-6].minor.yy399; + delete yymsp[-5].minor.yy399; + delete yymsp[-3].minor.yy399; + delete yymsp[-7].minor.yy451; + delete yymsp[-1].minor.yy95; + objectForTokens = yygotominor.yy283; } break; - case 409: /* vtabarglist ::= vtabarg */ + case 416: /* vtabarglist ::= vtabarg */ { - yygotominor.yy445 = new ParserStringList(); - yygotominor.yy445->append((yymsp[0].minor.yy211)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg - delete yymsp[0].minor.yy211; + yygotominor.yy95 = new QStringList(); + yygotominor.yy95->append((yymsp[0].minor.yy399)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg + delete yymsp[0].minor.yy399; } break; - case 410: /* vtabarglist ::= vtabarglist COMMA vtabarg */ + case 417: /* vtabarglist ::= vtabarglist COMMA vtabarg */ { - yymsp[-2].minor.yy445->append((yymsp[0].minor.yy211)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg - yygotominor.yy445 = yymsp[-2].minor.yy445; - delete yymsp[0].minor.yy211; + yymsp[-2].minor.yy95->append((yymsp[0].minor.yy399)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg + yygotominor.yy95 = yymsp[-2].minor.yy95; + delete yymsp[0].minor.yy399; DONT_INHERIT_TOKENS("vtabarglist"); } break; - case 412: /* vtabarg ::= vtabarg vtabargtoken */ + case 419: /* vtabarg ::= vtabarg vtabargtoken */ { - yymsp[-1].minor.yy211->append(" "+ *(yymsp[0].minor.yy211)); - yygotominor.yy211 = yymsp[-1].minor.yy211; - delete yymsp[0].minor.yy211; + yymsp[-1].minor.yy399->append(" "+ *(yymsp[0].minor.yy399)); + yygotominor.yy399 = yymsp[-1].minor.yy399; + delete yymsp[0].minor.yy399; } break; - case 413: /* vtabargtoken ::= ANY */ + case 420: /* vtabargtoken ::= ANY */ { - yygotominor.yy211 = new QString(yymsp[0].minor.yy0->value); + yygotominor.yy399 = new QString(yymsp[0].minor.yy0->value); } break; - case 414: /* vtabargtoken ::= LP anylist RP */ + case 421: /* vtabargtoken ::= LP anylist RP */ { - yygotominor.yy211 = new QString("("); - yygotominor.yy211->append(*(yymsp[-1].minor.yy211)); - yygotominor.yy211->append(")"); - delete yymsp[-1].minor.yy211; + yygotominor.yy399 = new QString("("); + yygotominor.yy399->append(*(yymsp[-1].minor.yy399)); + yygotominor.yy399->append(")"); + delete yymsp[-1].minor.yy399; } break; - case 416: /* anylist ::= anylist LP anylist RP */ + case 423: /* anylist ::= anylist LP anylist RP */ { - yygotominor.yy211 = yymsp[-3].minor.yy211; - yygotominor.yy211->append("("); - yygotominor.yy211->append(*(yymsp[-1].minor.yy211)); - yygotominor.yy211->append(")"); - delete yymsp[-1].minor.yy211; + yygotominor.yy399 = yymsp[-3].minor.yy399; + yygotominor.yy399->append("("); + yygotominor.yy399->append(*(yymsp[-1].minor.yy399)); + yygotominor.yy399->append(")"); + delete yymsp[-1].minor.yy399; DONT_INHERIT_TOKENS("anylist"); } break; - case 417: /* anylist ::= anylist ANY */ + case 424: /* anylist ::= anylist ANY */ { - yygotominor.yy211 = yymsp[-1].minor.yy211; - yygotominor.yy211->append(yymsp[0].minor.yy0->value); + yygotominor.yy399 = yymsp[-1].minor.yy399; + yygotominor.yy399->append(yymsp[0].minor.yy0->value); DONT_INHERIT_TOKENS("anylist"); } break; - case 418: /* with ::= */ -{yygotominor.yy367 = nullptr;} + case 425: /* with ::= */ +{yygotominor.yy321 = nullptr;} break; - case 419: /* with ::= WITH wqlist */ + case 426: /* with ::= WITH wqlist */ { - yygotominor.yy367 = yymsp[0].minor.yy367; - objectForTokens = yygotominor.yy367; + yygotominor.yy321 = yymsp[0].minor.yy321; + objectForTokens = yygotominor.yy321; } break; - case 420: /* with ::= WITH RECURSIVE wqlist */ + case 427: /* with ::= WITH RECURSIVE wqlist */ { - yygotominor.yy367 = yymsp[0].minor.yy367; - yygotominor.yy367->recursive = true; - objectForTokens = yygotominor.yy367; + yygotominor.yy321 = yymsp[0].minor.yy321; + yygotominor.yy321->recursive = true; + objectForTokens = yygotominor.yy321; } break; - case 421: /* wqlist ::= nm idxlist_opt AS LP select RP */ + case 428: /* wqlist ::= nm idxlist_opt AS LP select RP */ { - yygotominor.yy367 = SqliteWith::append(*(yymsp[-5].minor.yy211), *(yymsp[-4].minor.yy139), yymsp[-1].minor.yy123); - delete yymsp[-5].minor.yy211; - delete yymsp[-4].minor.yy139; + yygotominor.yy321 = SqliteWith::append(*(yymsp[-5].minor.yy399), *(yymsp[-4].minor.yy223), yymsp[-1].minor.yy473); + delete yymsp[-5].minor.yy399; + delete yymsp[-4].minor.yy223; } break; - case 422: /* wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP */ + case 429: /* wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP */ { - yygotominor.yy367 = SqliteWith::append(yymsp[-7].minor.yy367, *(yymsp[-5].minor.yy211), *(yymsp[-4].minor.yy139), yymsp[-1].minor.yy123); - delete yymsp[-5].minor.yy211; - delete yymsp[-4].minor.yy139; + yygotominor.yy321 = SqliteWith::append(yymsp[-7].minor.yy321, *(yymsp[-5].minor.yy399), *(yymsp[-4].minor.yy223), yymsp[-1].minor.yy473); + delete yymsp[-5].minor.yy399; + delete yymsp[-4].minor.yy223; DONT_INHERIT_TOKENS("wqlist"); } break; - case 423: /* wqlist ::= ID_TAB_NEW */ + case 430: /* wqlist ::= ID_TAB_NEW */ { parserContext->minorErrorBeforeNextToken("Syntax error"); - yygotominor.yy367 = new SqliteWith(); + yygotominor.yy321 = new SqliteWith(); } break; default: diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h index 92a40ca..050ebd3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h @@ -131,12 +131,12 @@ #define TK3_DROP 131 #define TK3_ID_VIEW_NEW 132 #define TK3_ID_VIEW 133 -#define TK3_UNION 134 -#define TK3_ALL 135 -#define TK3_EXCEPT 136 -#define TK3_INTERSECT 137 -#define TK3_SELECT 138 -#define TK3_VALUES 139 +#define TK3_SELECT 134 +#define TK3_VALUES 135 +#define TK3_UNION 136 +#define TK3_ALL 137 +#define TK3_EXCEPT 138 +#define TK3_INTERSECT 139 #define TK3_DISTINCT 140 #define TK3_ID_ALIAS 141 #define TK3_FROM 142 @@ -151,17 +151,19 @@ #define TK3_WHERE 151 #define TK3_ID_COL 152 #define TK3_INTO 153 -#define TK3_CASE 154 -#define TK3_ID_FN 155 -#define TK3_ID_ERR_MSG 156 -#define TK3_VARIABLE 157 -#define TK3_WHEN 158 -#define TK3_THEN 159 -#define TK3_ELSE 160 -#define TK3_INDEX 161 -#define TK3_ID_IDX_NEW 162 -#define TK3_ID_PRAGMA 163 -#define TK3_ID_TRIG_NEW 164 -#define TK3_ID_TRIG 165 -#define TK3_ALTER 166 -#define TK3_ADD 167 +#define TK3_DO 154 +#define TK3_NOTHING 155 +#define TK3_CASE 156 +#define TK3_ID_FN 157 +#define TK3_ID_ERR_MSG 158 +#define TK3_VARIABLE 159 +#define TK3_WHEN 160 +#define TK3_THEN 161 +#define TK3_ELSE 162 +#define TK3_INDEX 163 +#define TK3_ID_IDX_NEW 164 +#define TK3_ID_PRAGMA 165 +#define TK3_ID_TRIG_NEW 166 +#define TK3_ID_TRIG 167 +#define TK3_ALTER 168 +#define TK3_ADD 169 diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y index 0dc9154..7e29506 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y +++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y @@ -55,6 +55,7 @@ #include "parser/ast/sqliteindexedcolumn.h" #include "parser/ast/sqliteforeignkey.h" #include "parser/ast/sqlitewith.h" +#include "parser/ast/sqliteupsert.h" #include #include #include @@ -810,14 +811,6 @@ selectnowith(X) ::= selectnowith(S1) delete V; objectForTokens = X; } - -%type multiselect_op {SqliteSelect::CompoundOperator*} -%destructor multiselect_op {delete $$;} -multiselect_op(X) ::= UNION. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);} -multiselect_op(X) ::= UNION ALL. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);} -multiselect_op(X) ::= EXCEPT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);} -multiselect_op(X) ::= INTERSECT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);} - %type oneselect {SqliteSelect::Core*} %destructor oneselect {delete $$;} oneselect(X) ::= SELECT distinct(D) @@ -857,6 +850,13 @@ values(X) ::= values(L) COMMA LP DONT_INHERIT_TOKENS("values"); } +%type multiselect_op {SqliteSelect::CompoundOperator*} +%destructor multiselect_op {delete $$;} +multiselect_op(X) ::= UNION. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);} +multiselect_op(X) ::= UNION ALL. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);} +multiselect_op(X) ::= EXCEPT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);} +multiselect_op(X) ::= INTERSECT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);} + %type distinct {int*} %destructor distinct {delete $$;} distinct(X) ::= DISTINCT. {X = new int(1);} @@ -1005,6 +1005,23 @@ singlesrc(X) ::= LP joinsrc(J) RP as(A). { delete A; objectForTokens = X; } +singlesrc(X) ::= nm(N1) dbnm(N2) + LP exprlist(E) RP as(A). { + X = new SqliteSelect::Core::SingleSource( + *(N1), + *(N2), + A ? A->asKw : false, + A ? A->name : QString::null, + *(E) + ); + delete N1; + delete N2; + delete A; + if (E) + delete E; + + objectForTokens = X; + } singlesrc(X) ::= . { parserContext->minorErrorBeforeNextToken("Syntax error"); X = new SqliteSelect::Core::SingleSource(); @@ -1030,7 +1047,7 @@ joinconstr_opt(X) ::= ON expr(E). { objectForTokens = X; } joinconstr_opt(X) ::= USING LP - inscollist(L) RP. { + idlist(L) RP. { X = new SqliteSelect::Core::JoinConstraint(*(L)); delete L; objectForTokens = X; @@ -1321,13 +1338,23 @@ setlist(X) ::= setlist(L) COMMA nm(N) EQ L->append(ParserSetValue(*(N), E)); X = L; delete N; - DONT_INHERIT_TOKENS("setlist"); + } +setlist(X) ::= setlist(L) COMMA LP + idlist(N) RP EQ expr(E). { + L->append(ParserSetValue(*(N), E)); + X = L; + delete N; } setlist(X) ::= nm(N) EQ expr(E). { X = new ParserSetValueList(); X->append(ParserSetValue(*(N), E)); delete N; } +setlist(X) ::= LP idlist(N) RP EQ expr(E). { + X = new ParserSetValueList(); + X->append(ParserSetValue(*(N), E)); + delete N; + } setlist(X) ::= . { parserContext->minorErrorBeforeNextToken("Syntax error"); X = new ParserSetValueList(); @@ -1340,6 +1367,31 @@ setlist(X) ::= setlist(L) COMMA. { setlist ::= setlist COMMA ID_COL. {} setlist ::= ID_COL. {} +%type idlist_opt {QStringList*} +%destructor idlist_opt {delete $$;} +idlist_opt(X) ::= . {X = new QStringList();} +idlist_opt(X) ::= LP idlist(L) RP. {X = L;} + +%type idlist {QStringList*} +%destructor idlist {delete $$;} +idlist(X) ::= idlist(L) COMMA nm(N). { + X = L; + *(X) << *(N); + delete N; + } +idlist(X) ::= nm(N). { + X = new QStringList(); + *(X) << *(N); + delete N; + } +idlist(X) ::= . { + parserContext->minorErrorBeforeNextToken("Syntax error"); + X = new QStringList(); + } + +idlist ::= idlist COMMA ID_COL. {} +idlist ::= ID_COL. {} + ////////////////////////// The INSERT command ///////////////////////////////// cmd(X) ::= insert_stmt(S). { @@ -1352,7 +1404,8 @@ cmd(X) ::= insert_stmt(S). { insert_stmt(X) ::= with(W) insert_cmd(C) INTO fullname(N) - inscollist_opt(I) select(S). { + idlist_opt(I) select(S) + upsert(U). { X = new SqliteInsert( C->replace, C->orConflict, @@ -1360,7 +1413,8 @@ insert_stmt(X) ::= with(W) insert_cmd(C) N->name2, *(I), S, - W + W, + U ); delete N; delete C; @@ -1370,7 +1424,7 @@ insert_stmt(X) ::= with(W) insert_cmd(C) } insert_stmt(X) ::= with(W) insert_cmd(C) INTO fullname(N) - inscollist_opt(I) DEFAULT + idlist_opt(I) DEFAULT VALUES. { X = new SqliteInsert( C->replace, @@ -1424,32 +1478,33 @@ insert_cmd(X) ::= INSERT orconf(C). { } insert_cmd(X) ::= REPLACE. {X = new ParserStubInsertOrReplace(true);} -%type inscollist_opt {ParserStringList*} -%destructor inscollist_opt {delete $$;} -inscollist_opt(X) ::= . {X = new ParserStringList();} -inscollist_opt(X) ::= LP inscollist(L) RP. {X = L;} -%type inscollist {ParserStringList*} -%destructor inscollist {delete $$;} -inscollist(X) ::= inscollist(L) COMMA - nm(N). { - L->append(*(N)); - X = L; - delete N; - DONT_INHERIT_TOKENS("inscollist"); +%type upsert {SqliteUpsert*} +%destructor upsert {delete $$;} + +upsert(X) ::= . { + X = nullptr; } -inscollist(X) ::= nm(N). { - X = new ParserStringList(); - X->append(*(N)); - delete N; +upsert(X) ::= ON CONFLICT LP sortlist(C) RP + where_opt(CW) + DO UPDATE SET setlist(S) + where_opt(SW). + { + X = new SqliteUpsert(*(C), CW, *(S), SW); + delete C; + delete S; + objectForTokens = X; } -inscollist(X) ::= . { - parserContext->minorErrorBeforeNextToken("Syntax error"); - X = new ParserStringList(); +upsert(X) ::= ON CONFLICT LP sortlist(C) RP + where_opt(CW) DO NOTHING. { + X = new SqliteUpsert(*(C), CW); + delete C; + objectForTokens = X; + } +upsert(X) ::= ON CONFLICT DO NOTHING. { + X = new SqliteUpsert(); + objectForTokens = X; } - -inscollist ::= inscollist COMMA ID_COL. {} -inscollist ::= ID_COL. {} /////////////////////////// Expression Processing ///////////////////////////// @@ -2149,7 +2204,7 @@ trigger_event(X) ::= UPDATE. { objectForTokens = X; } trigger_event(X) ::= UPDATE OF - inscollist(L). { + idlist(L). { X = new SqliteCreateTrigger::Event(*(L)); delete L; objectForTokens = X; @@ -2341,10 +2396,10 @@ create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW. {} -%type vtabarglist {ParserStringList*} +%type vtabarglist {QStringList*} %destructor vtabarglist {delete $$;} vtabarglist(X) ::= vtabarg(A). { - X = new ParserStringList(); + X = new QStringList(); X->append((A)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg delete A; } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp index a0a0e3a..07d1976 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp @@ -29,7 +29,7 @@ StatementTokenBuilder&StatementTokenBuilder::withStringPossiblyOther(const QStri StatementTokenBuilder& StatementTokenBuilder::withOtherList(const QList& value, Dialect dialect, const QString& separator) { bool first = true; - foreach (const QString& str, value) + for (const QString& str : value) { if (!first) { @@ -47,7 +47,7 @@ StatementTokenBuilder& StatementTokenBuilder::withOtherList(const QList StatementTokenBuilder& StatementTokenBuilder::withOtherList(const QList& value, const QString& separator) { bool first = true; - foreach (const QString& str, value) + for (const QString& str : value) { if (!first) { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h index 14856e7..9ccfaa3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h @@ -238,7 +238,7 @@ class StatementTokenBuilder StatementTokenBuilder& withStatementList(QList stmtList, const QString& separator = ",") { bool first = true; - foreach (T* stmt, stmtList) + for (T* stmt : stmtList) { if (!first) { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp index 5396edd..cd7e4b0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp @@ -210,13 +210,21 @@ QString TokenList::toString() const QStringList TokenList::toStringList() const { QStringList strList; - TokenPtr t; - foreach (t, *this) + for (const TokenPtr& t : *this) strList << t->toString(); return strList; } +QStringList TokenList::toValueList() const +{ + QStringList strList; + for (const TokenPtr& t : *this) + strList << t->value; + + return strList; +} + int TokenList::indexOf(TokenPtr token) const { return QList::indexOf(token); @@ -301,7 +309,7 @@ TokenPtr TokenList::findLast(const QString& value, Qt::CaseSensitivity caseSensi TokenPtr TokenList::atCursorPosition(quint64 cursorPosition) const { - foreach (TokenPtr token, *this) + for (TokenPtr token : *this) { if (token->getRange().contains(cursorPosition)) return token; @@ -311,7 +319,7 @@ TokenPtr TokenList::atCursorPosition(quint64 cursorPosition) const void TokenList::insert(int i, const TokenList &list) { - foreach (TokenPtr token, list) + for (TokenPtr token : list) QList::insert(i++, token); } @@ -483,7 +491,7 @@ TokenList& TokenList::trim(Token::Type type, const QString& alsoTrim) TokenList TokenList::filter(Token::Type type) const { TokenList filtered; - foreach (TokenPtr token, *this) + for (TokenPtr token : *this) if (token->type == type) filtered << token; @@ -493,7 +501,7 @@ TokenList TokenList::filter(Token::Type type) const TokenList TokenList::filterOut(Token::Type type) const { TokenList filtered; - foreach (TokenPtr token, *this) + for (TokenPtr token : *this) if (token->type != type) filtered << token; @@ -503,7 +511,7 @@ TokenList TokenList::filterOut(Token::Type type) const TokenList TokenList::filterWhiteSpaces(bool includeComments) const { TokenList filtered; - foreach (TokenPtr token, *this) + for (TokenPtr token : *this) if (!token->isWhitespace(includeComments)) filtered << token; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/token.h b/SQLiteStudio3/coreSQLiteStudio/parser/token.h index aeb505c..85c46c1 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/token.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/token.h @@ -253,7 +253,7 @@ struct API_EXPORT Token /** * @brief Literal value of the token, captured directly from the query. */ - QString value = QString::null; + QString value; /** * @brief Start position (first character index) of the token in the query. @@ -334,6 +334,12 @@ class API_EXPORT TokenList : public QList */ QStringList toStringList() const; + /** + * @brief Converts list of tokens into list of their values. + * @return List of tokens values. + */ + QStringList toValueList() const; + /** * @brief Provides index of first occurrence of the token in the list. * @param token Token to look for. diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h b/SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h index 183adf7..8cbbe78 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/plugin.h @@ -34,7 +34,7 @@ class CfgMain; * }; * @endcode * - * Full tutorial for writting plugins is at: http://wiki.sqlitestudio.pl/index.php/Writting_plugins + * Full tutorial for writting plugins is at: https://github.com/pawelsalawa/sqlitestudio/wiki/Writting_plugins * * SQLiteStudio looks for plugins in following directories: *
    diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/pluginsymbolresolver.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/pluginsymbolresolver.cpp index 39988bd..43540b0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/pluginsymbolresolver.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/pluginsymbolresolver.cpp @@ -19,14 +19,14 @@ void PluginSymbolResolver::addLookupSubFolder(const QString &name) bool PluginSymbolResolver::load() { QStringList paths = qApp->libraryPaths(); - foreach (QString path, paths) - foreach (QString subFolder, subFolders) + for (QString path : paths) + for (QString subFolder : subFolders) paths << path + "/" + subFolder; - foreach (QString path, paths) + for (QString path : paths) { QDir dir(path); - foreach (QString file, dir.entryList(nameFilters)) + for (QString file : dir.entryList(nameFilters)) { lib.setFileName(path+"/"+file); if (lib.load()) diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/populatedictionary.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/populatedictionary.cpp index 3d78de5..fd654ad 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/populatedictionary.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/populatedictionary.cpp @@ -35,7 +35,7 @@ bool PopulateDictionaryEngine::beforePopulating(Db* db, const QString& table) file.close(); if (cfg.PopulateDictionary.Lines.get()) - dictionary = dataStr.split("\n"); + dictionary = dataStr.split(QRegExp("(\r\n|\n|\r)")); else dictionary = dataStr.split(QRegExp("\\s+")); diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp index 334c0cc..79824dc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp @@ -221,7 +221,7 @@ bool ScriptingQt::init() void ScriptingQt::deinit() { - foreach (Context* ctx, contexts) + for (Context* ctx : contexts) delete ctx; contexts.clear(); diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/sqlformatterplugin.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/sqlformatterplugin.cpp index 5e1d610..350c024 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/sqlformatterplugin.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/sqlformatterplugin.cpp @@ -17,7 +17,7 @@ QString SqlFormatterPlugin::format(const QString& code, Db* contextDb) } QStringList formattedQueries; - foreach (SqliteQueryPtr query, parser.getQueries()) + for (SqliteQueryPtr query : parser.getQueries()) formattedQueries << format(query); return formattedQueries.join("\n"); diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/uiconfiguredplugin.h b/SQLiteStudio3/coreSQLiteStudio/plugins/uiconfiguredplugin.h index 1426117..b2a0b8d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/uiconfiguredplugin.h +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/uiconfiguredplugin.h @@ -15,7 +15,7 @@ class API_EXPORT UiConfiguredPlugin * * This method should return the object name of the top-most widget found in the provided *.ui file. * - * For more details see: http://wiki.sqlitestudio.pl/index.php/Plugin_UI_forms + * For more details see: https://github.com/pawelsalawa/sqlitestudio/wiki/Plugin_UI_forms */ virtual QString getConfigUiForm() const = 0; diff --git a/SQLiteStudio3/coreSQLiteStudio/populateworker.cpp b/SQLiteStudio3/coreSQLiteStudio/populateworker.cpp index f25a6ac..e1c207a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/populateworker.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/populateworker.cpp @@ -57,6 +57,13 @@ void PopulateWorker::run() for (PopulateEngine* engine : engines) args << engine->nextValue(nextValueError); + if (nextValueError) + { + db->rollback(); + emit finished(false); + return; + } + query->setArgs(args); if (!query->execute()) { diff --git a/SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp b/SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp index c10e8f7..75b0e89 100644 --- a/SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/querygenerator.cpp @@ -41,7 +41,7 @@ QString QueryGenerator::generateInsertToTable(Db* db, const QString& database, c if (values.isEmpty()) { QStringList valueList = wrapStrings(tableCols); - QList wrappedCols = wrapObjNamesIfNeeded(tableCols, dialect); + QStringList wrappedCols = wrapObjNamesIfNeeded(tableCols, dialect); return tpl.arg(target, wrappedCols.join(", "), rowTpl.arg(valueList.join(", "))); } @@ -54,7 +54,7 @@ QString QueryGenerator::generateInsertToTable(Db* db, const QString& database, c QString valueStr = rowTpl.arg(valueSets.join("), (")); // Wrap given column names - QList wrappedCols = wrapObjNamesIfNeeded(valueCols, dialect); + QStringList wrappedCols = wrapObjNamesIfNeeded(valueCols, dialect); return tpl.arg(target, wrappedCols.join(", "), valueStr); } diff --git a/SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp b/SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp index 48fe541..62a685c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/schemaresolver.cpp @@ -76,7 +76,7 @@ StrHash< QStringList> SchemaResolver::getGroupedObjects(const QString &database, SqliteQueryPtr parsedQuery; SqliteTableRelatedDdlPtr tableRelatedDdl; - foreach (QString object, inputList) + for (QString object : inputList) { parsedQuery = getParsedObject(database, object, ANY); if (!parsedQuery) @@ -136,7 +136,7 @@ QStringList SchemaResolver::getTableColumns(const QString &database, const QStri if (!createTable && !createVirtualTable) { qDebug() << "Parsed DDL is neither a CREATE TABLE or CREATE VIRTUAL TABLE statement. It's: " - << sqliteQueryTypeToString(query->queryType); + << sqliteQueryTypeToString(query->queryType) << "when trying to parse DDL of" << database << table; return columns; } @@ -150,7 +150,7 @@ QStringList SchemaResolver::getTableColumns(const QString &database, const QStri } // Now we have a regular table, let's extract columns. - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) columns << column->name; return columns; @@ -193,7 +193,7 @@ QList SchemaResolver::getTableColumnDataTypes(const QString& database, StrHash SchemaResolver::getAllTableColumns(const QString &database) { StrHash< QStringList> tableColumns; - foreach (QString table, getTables(database)) + for (QString table : getTables(database)) tableColumns[table] = getTableColumns(database, table); return tableColumns; @@ -208,7 +208,7 @@ QStringList SchemaResolver::getViewColumns(const QString& database, const QStrin { QList resolvedColumns = getViewColumnObjects(database, view); QStringList columns; - foreach (const SelectResolver::Column& col, resolvedColumns) + for (const SelectResolver::Column& col : resolvedColumns) columns << col.displayName; return columns; @@ -555,7 +555,7 @@ SqliteQueryPtr SchemaResolver::getParsedDdl(const QString& ddl) if (!parser->parse(ddl)) { qDebug() << "Could not parse DDL for parsing object by SchemaResolver. Errors are:"; - foreach (ParserError* err, parser->getErrors()) + for (ParserError* err : parser->getErrors()) qDebug() << err->getMessage(); return SqliteQueryPtr(); @@ -591,7 +591,7 @@ QStringList SchemaResolver::getObjects(const QString &database, const QString &t SqlQueryPtr results = db->exec(QString("SELECT name FROM %1.sqlite_master WHERE type = ?;").arg(dbName), {type}, dbFlags); QString value; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) { value = row->value(0).toString(); if (!isFilteredOut(value, type)) @@ -623,7 +623,7 @@ QStringList SchemaResolver::getAllObjects(const QString& database) QString value; QString type; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) { value = row->value("name").toString(); type = row->value("type").toString(); @@ -720,7 +720,7 @@ QStringList SchemaResolver::getFkReferencingTables(const QString& table, const Q QStringList SchemaResolver::getIndexesForTable(const QString& database, const QString& table) { QStringList names; - foreach (SqliteCreateIndexPtr idx, getParsedIndexesForTable(database, table)) + for (SqliteCreateIndexPtr idx : getParsedIndexesForTable(database, table)) names << idx->index; return names; @@ -734,7 +734,7 @@ QStringList SchemaResolver::getIndexesForTable(const QString& table) QStringList SchemaResolver::getTriggersForTable(const QString& database, const QString& table) { QStringList names; - foreach (SqliteCreateTriggerPtr trig, getParsedTriggersForTable(database, table)) + for (SqliteCreateTriggerPtr trig : getParsedTriggersForTable(database, table)) names << trig->trigger; return names; @@ -748,7 +748,7 @@ QStringList SchemaResolver::getTriggersForTable(const QString& table) QStringList SchemaResolver::getTriggersForView(const QString& database, const QString& view) { QStringList names; - foreach (SqliteCreateTriggerPtr trig, getParsedTriggersForView(database, view)) + for (SqliteCreateTriggerPtr trig : getParsedTriggersForView(database, view)) names << trig->trigger; return names; @@ -762,7 +762,7 @@ QStringList SchemaResolver::getTriggersForView(const QString& view) QStringList SchemaResolver::getViewsForTable(const QString& database, const QString& table) { QStringList names; - foreach (SqliteCreateViewPtr view, getParsedViewsForTable(database, table)) + for (SqliteCreateViewPtr view : getParsedViewsForTable(database, table)) names << view->view; return names; @@ -885,7 +885,7 @@ QList SchemaResolver::getParsedTriggersForTableOrView(co QStringList triggers = getTriggers(database); SqliteQueryPtr query; SqliteCreateTriggerPtr createTrigger; - foreach (const QString& trig, triggers) + for (const QString& trig : triggers) { query = getParsedObject(database, trig, TRIGGER); if (!query) @@ -963,7 +963,7 @@ QList SchemaResolver::getParsedViewsForTable(const QString& QStringList views = getViews(database); SqliteQueryPtr query; SqliteCreateViewPtr createView; - foreach (const QString& view, views) + for (const QString& view : views) { query = getParsedObject(database, view, VIEW); if (!query) diff --git a/SQLiteStudio3/coreSQLiteStudio/schemaresolver.h b/SQLiteStudio3/coreSQLiteStudio/schemaresolver.h index 676d0f5..fb19cee 100644 --- a/SQLiteStudio3/coreSQLiteStudio/schemaresolver.h +++ b/SQLiteStudio3/coreSQLiteStudio/schemaresolver.h @@ -234,7 +234,7 @@ StrHash> SchemaResolver::getAllParsedObjectsForType(const QStr QString name; SqliteQueryPtr parsedObject; QSharedPointer castedObject; - foreach (SqlResultsRowPtr row, results->getAll()) + for (SqlResultsRowPtr row : results->getAll()) { name = row->value("name").toString(); parsedObject = getParsedDdl(row->value("sql").toString()); diff --git a/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp b/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp index 1b7e33d..64da5b2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/selectresolver.cpp @@ -47,12 +47,14 @@ QList> SelectResolver::resolveColumns() QList SelectResolver::resolve(SqliteSelect::Core *selectCore) { errors.clear(); + extractCte(selectCore); return resolveCore(selectCore); } QList> SelectResolver::resolve(SqliteSelect *select) { errors.clear(); + extractCte(select); QList > results; for (SqliteSelect::Core* core : select->coreSelects) { @@ -66,12 +68,14 @@ QList> SelectResolver::resolve(SqliteSelect *selec QList SelectResolver::resolveAvailableColumns(SqliteSelect::Core *selectCore) { errors.clear(); + extractCte(selectCore); return resolveAvailableCoreColumns(selectCore); } QList > SelectResolver::resolveAvailableColumns(SqliteSelect *select) { errors.clear(); + extractCte(select); QList > results; for (SqliteSelect::Core* core : select->coreSelects) results << resolveAvailableCoreColumns(core); @@ -82,6 +86,7 @@ QList > SelectResolver::resolveAvailableColumns(Sq QSet SelectResolver::resolveTables(SqliteSelect::Core *selectCore) { QSet tables; + extractCte(selectCore); QList columns = resolveAvailableColumns(selectCore); for (const Column& col : columns) { @@ -97,6 +102,7 @@ QSet SelectResolver::resolveTables(SqliteSelect::Core *se QList > SelectResolver::resolveTables(SqliteSelect *select) { QList > results; + extractCte(select); QList > columnLists = resolveAvailableColumns(select); for (const QList& columns : columnLists) { @@ -118,6 +124,7 @@ QList > SelectResolver::resolveTables(SqliteSelect * QList SelectResolver::translateToColumns(SqliteSelect* select, const TokenList& columnTokens) { errors.clear(); + extractCte(select); QList results; for (const TokenPtr& token : columnTokens) results << translateTokenToColumn(select, token); @@ -175,7 +182,7 @@ QList SelectResolver::resolveAvailableCoreColumns(Sqlite SqliteSelect* select = dynamic_cast(selectCore->parentStatement()); if (select && select->with) - markCteColumns(); + markCteColumns(&columns); return columns; } @@ -237,9 +244,9 @@ void SelectResolver::markCompoundColumns() markCurrentColumnsWithFlag(FROM_COMPOUND_SELECT); } -void SelectResolver::markCteColumns() +void SelectResolver::markCteColumns(QList* columnList) { - markCurrentColumnsWithFlag(FROM_CTE_SELECT); + markCurrentColumnsWithFlag(FROM_CTE_SELECT, columnList); } void SelectResolver::markGroupedColumns() @@ -283,9 +290,9 @@ void SelectResolver::fixColumnNames() } } -void SelectResolver::markCurrentColumnsWithFlag(SelectResolver::Flag flag) +void SelectResolver::markCurrentColumnsWithFlag(SelectResolver::Flag flag, QList* columnList) { - QMutableListIterator it(currentCoreResults); + QMutableListIterator it(columnList ? *columnList : currentCoreResults); while (it.hasNext()) it.next().flags |= flag; } @@ -528,6 +535,24 @@ TokenList SelectResolver::getResColTokensWithoutAlias(SqliteSelect::Core::Result return allTokens; } +void SelectResolver::extractCte(SqliteSelect *select) +{ + cteList.clear(); + if (!select->with) + return; + + for (SqliteWith::CommonTableExpression* cte : select->with->cteList) + cteList[cte->table] = cte; +} + +void SelectResolver::extractCte(SqliteSelect::Core *core) +{ + if (!core->parentStatement()) + return; + + extractCte(dynamic_cast(core->parentStatement())); +} + QList SelectResolver::resolveJoinSource(SqliteSelect::Core::JoinSource *joinSrc) { QList columnSources; @@ -549,28 +574,56 @@ QList SelectResolver::resolveSingleSource(SqliteSelect:: if (joinSrc->joinSource) return resolveJoinSource(joinSrc->joinSource); + if (!joinSrc->funcName.isNull()) + return resolveTableFunctionColumns(joinSrc); + if (isView(joinSrc->database, joinSrc->table)) return resolveView(joinSrc->database, joinSrc->table, joinSrc->alias); QList columnSources; QStringList columns = getTableColumns(joinSrc->database, joinSrc->table, joinSrc->alias); Column column; + column.type = Column::COLUMN; + column.table = joinSrc->table;; + column.database = joinSrc->database; + column.originalDatabase = resolveDatabase(joinSrc->database); + if (!joinSrc->alias.isNull()) + column.tableAlias = joinSrc->alias; + for (const QString& columnName : columns) { - column.type = Column::COLUMN; column.column = columnName; - column.table = joinSrc->table;; - column.database = joinSrc->database; - column.originalDatabase = resolveDatabase(joinSrc->database); - if (!joinSrc->alias.isNull()) - column.tableAlias = joinSrc->alias; - columnSources << column; } return columnSources; } +QList SelectResolver::resolveTableFunctionColumns(SqliteSelect::Core::SingleSource *joinSrc) +{ + static_qstring(columnSqlTpl, "SELECT * FROM %1 LIMIT 0"); + SqlQueryPtr result = db->exec(columnSqlTpl.arg(joinSrc->detokenize())); + if (result->isError()) + errors << result->getErrorText(); + + QStringList columnNames = result->getColumnNames(); + + QList columnSources; + Column column; + column.type = Column::OTHER; + column.database = joinSrc->database; + column.originalDatabase = resolveDatabase(joinSrc->database); + if (!joinSrc->alias.isNull()) + column.tableAlias = joinSrc->alias; + + for (const QString& columnName : columnNames) + { + column.column = columnName; + columnSources << column; + } + return columnSources; +} + QList SelectResolver::resolveSingleSourceSubSelect(SqliteSelect::Core::SingleSource *joinSrc) { QList columnSources = resolveSubSelect(joinSrc->select); @@ -652,7 +705,17 @@ QStringList SelectResolver::getTableColumns(const QString &database, const QStri dbTable.tableAlias = alias; if (tableColumnsCache.contains(dbTable)) + { return tableColumnsCache.value(dbTable); + } + else if (database.isNull() && cteList.contains(table)) + { + QStringList columns; + for (SqliteIndexedColumn* idxCol : cteList[table]->indexedColumns) + columns << idxCol->name; + + return columns; + } else { QStringList columns = schemaResolver->getTableColumns(database, table); diff --git a/SQLiteStudio3/coreSQLiteStudio/selectresolver.h b/SQLiteStudio3/coreSQLiteStudio/selectresolver.h index 7640fc6..92924ea 100644 --- a/SQLiteStudio3/coreSQLiteStudio/selectresolver.h +++ b/SQLiteStudio3/coreSQLiteStudio/selectresolver.h @@ -5,6 +5,7 @@ #include "common/bistrhash.h" #include "dialect.h" #include "expectedtoken.h" +#include "parser/ast/sqlitewith.h" #include #include #include @@ -106,7 +107,6 @@ class API_EXPORT SelectResolver QString alias; QString displayName; bool aliasDefinedInSubQuery = false; - int flags = 0; SqliteSelect::Core::ResultColumn* originalColumn = nullptr; int operator==(const Column& other); @@ -204,6 +204,7 @@ class API_EXPORT SelectResolver QList resolveJoinSource(SqliteSelect::Core::JoinSource* joinSrc); QList resolveSingleSource(SqliteSelect::Core::SingleSource* joinSrc); + QList resolveTableFunctionColumns(SqliteSelect::Core::SingleSource* joinSrc); QList resolveSingleSourceSubSelect(SqliteSelect::Core::SingleSource* joinSrc); QList resolveOtherSource(SqliteSelect::Core::JoinSourceOther *otherSrc); QList resolveSubSelect(SqliteSelect* select); @@ -216,16 +217,19 @@ class API_EXPORT SelectResolver void markDistinctColumns(); void markCompoundColumns(); - void markCteColumns(); + void markCteColumns(QList* columnList = nullptr); void markGroupedColumns(); void fixColumnNames(); - void markCurrentColumnsWithFlag(Flag flag); + void markCurrentColumnsWithFlag(Flag flag, QList* columnList = nullptr); bool matchTable(const Column& sourceColumn, const QString& table); TokenList getResColTokensWithoutAlias(SqliteSelect::Core::ResultColumn *resCol); + void extractCte(SqliteSelect* select); + void extractCte(SqliteSelect::Core* core); Db* db = nullptr; QString query; SqliteSelectPtr originalQueryParsed; + QHash cteList; /** * @brief Database name to attach name map. diff --git a/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.cpp b/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.cpp deleted file mode 100644 index 54b0905..0000000 --- a/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "bugreporter.h" -#include "services/config.h" -#include "services/notifymanager.h" -#include -#include -#include -#include - -BugReporter::BugReporter(QObject *parent) : - QObject(parent) -{ - networkManager = new QNetworkAccessManager(this); - connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*))); -} - -QUrl BugReporter::getReporterEmailHelpUrl() const -{ - return QUrl(QString::fromLatin1(reporterEmailHelpUrl)); -} - -QUrl BugReporter::getReporterUserAndPasswordHelpUrl() const -{ - return QUrl(QString::fromLatin1(reporterUserPassHelpUrl)); -} - -void BugReporter::validateBugReportCredentials(const QString& login, const QString& password) -{ - if (credentialsValidationInProgress) - { - credentialsValidationInProgress->abort(); - credentialsValidationInProgress->deleteLater(); - } - - QUrlQuery query; - query.addQueryItem("validateUser", login); - query.addQueryItem("password", password); - - QUrl url = QUrl(QString::fromLatin1(bugReportServiceUrl) + "?" + query.query(QUrl::FullyEncoded)); - QNetworkRequest request(url); - credentialsValidationInProgress = networkManager->get(request); - replyToHandler[credentialsValidationInProgress] = [this](bool success, const QString& data) - { - if (success && data.trimmed() != "OK") - { - success = false; - emit credentialsValidationResult(success, tr("Invalid login or password")); - } - else - { - emit credentialsValidationResult(success, success ? QString() : data); - } - }; -} - -void BugReporter::abortCredentialsValidation() -{ - if (credentialsValidationInProgress) - { - credentialsValidationInProgress->abort(); - credentialsValidationInProgress->deleteLater(); - credentialsValidationInProgress = nullptr; - } -} - -void BugReporter::useBugReportCredentials(const QString& login, const QString& password) -{ - CFG_CORE.Internal.BugReportUser.set(login); - CFG_CORE.Internal.BugReportPassword.set(password); -} - -void BugReporter::clearBugReportCredentials() -{ - CFG_CORE.Internal.BugReportUser.set(QString()); - CFG_CORE.Internal.BugReportPassword.set(QString()); -} - -void BugReporter::reportBug(const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, BugReporter::ResponseHandler responseHandler, const QString& urlSuffix) -{ - static_qstring(contentsTpl, "%1\n\nPlugins loaded:\n%2\n\nVersion:\n%3\n\nOperating System:\n%4"); - QString contents = contentsTpl.arg(escapeParam(details), plugins, version, os); - - QUrlQuery query; - query.addQueryItem("brief", escapeParam(title)); - query.addQueryItem("contents", contents); - query.addQueryItem("os", os); - query.addQueryItem("version", version); - query.addQueryItem("featureRequest", "0"); - - QUrl url = QUrl(QString::fromLatin1(bugReportServiceUrl) + "?" + escapeUrl(query.query(QUrl::FullyEncoded) + urlSuffix)); - QNetworkRequest request(url); - QNetworkReply* reply = networkManager->get(request); - if (responseHandler) - replyToHandler[reply] = responseHandler; - - replyToTypeAndTitle[reply] = QPair(false, title); -} - -void BugReporter::requestFeature(const QString& title, const QString& details, BugReporter::ResponseHandler responseHandler, const QString& urlSuffix) -{ - QUrlQuery query; - query.addQueryItem("brief", escapeParam(title)); - query.addQueryItem("contents", escapeParam(details)); - query.addQueryItem("featureRequest", "1"); - - QUrl url = QUrl(QString::fromLatin1(bugReportServiceUrl) + "?" + escapeUrl(query.query(QUrl::FullyEncoded) + urlSuffix)); - QNetworkRequest request(url); - QNetworkReply* reply = networkManager->get(request); - if (responseHandler) - replyToHandler[reply] = responseHandler; - - replyToTypeAndTitle[reply] = QPair(true, title); -} - -QString BugReporter::escapeParam(const QString &input) -{ - return input.toHtmlEscaped(); -} - -QString BugReporter::escapeUrl(const QString &input) -{ - // For some reason the ";" character is not encodedy by QUrlQuery when using FullEncoded. Pity. We have to do it manually. - QString copy = input; - return copy.replace(";", "%3B"); -} - -void BugReporter::finished(QNetworkReply* reply) -{ - if (reply == credentialsValidationInProgress) - credentialsValidationInProgress = nullptr; - - if (!replyToHandler.contains(reply)) - { - reply->deleteLater(); - return; - } - - bool success = (reply->error() == QNetworkReply::NoError); - QString data; - if (success) - data = QString::fromLatin1(reply->readAll()); - else - data = reply->errorString(); - - replyToHandler[reply](success, data); - replyToHandler.remove(reply); - - if (replyToTypeAndTitle.contains(reply)) - { - if (success) - CFG->addReportHistory(replyToTypeAndTitle[reply].first, replyToTypeAndTitle[reply].second, data); - - replyToTypeAndTitle.remove(reply); - } - - reply->deleteLater(); -} - -void BugReporter::reportBug(const QString& email, const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, - ResponseHandler responseHandler) -{ - QUrlQuery query; - query.addQueryItem("byEmail", email); - QString urlSuffix = "&" + query.query(QUrl::FullyEncoded); - - reportBug(title, details, version, os, plugins, responseHandler, urlSuffix); -} - -void BugReporter::reportBug(const QString& title, const QString& details, const QString& version, const QString& os, - const QString& plugins, ResponseHandler responseHandler) -{ - QString user = CFG_CORE.Internal.BugReportUser.get(); - QString pass = CFG_CORE.Internal.BugReportPassword.get(); - - QUrlQuery query; - query.addQueryItem("byUser", user); - query.addQueryItem("password", pass); - QString urlSuffix = "&" + query.query(QUrl::FullyEncoded); - - reportBug(title, details, version, os, plugins, responseHandler, urlSuffix); -} - -void BugReporter::requestFeature(const QString& email, const QString& title, const QString& details, ResponseHandler responseHandler) -{ - QUrlQuery query; - query.addQueryItem("byEmail", email); - QString urlSuffix = "&" + query.query(QUrl::FullyEncoded); - - requestFeature(title, details, responseHandler, urlSuffix); -} - -void BugReporter::requestFeature(const QString& title, const QString& details, ResponseHandler responseHandler) -{ - QString user = CFG_CORE.Internal.BugReportUser.get(); - QString pass = CFG_CORE.Internal.BugReportPassword.get(); - - QUrlQuery query; - query.addQueryItem("byUser", user); - query.addQueryItem("password", pass); - QString urlSuffix = "&" + query.query(QUrl::FullyEncoded); - - requestFeature(title, details, responseHandler, urlSuffix); -} diff --git a/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.h b/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.h deleted file mode 100644 index 3e8eb8d..0000000 --- a/SQLiteStudio3/coreSQLiteStudio/services/bugreporter.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef BUGREPORTER_H -#define BUGREPORTER_H - -#include "common/global.h" -#include "sqlitestudio.h" -#include -#include - -class QNetworkAccessManager; -class QNetworkReply; - -class API_EXPORT BugReporter : public QObject -{ - Q_OBJECT - - public: - typedef std::function ResponseHandler; - - explicit BugReporter(QObject *parent = 0); - - QUrl getReporterEmailHelpUrl() const; - QUrl getReporterUserAndPasswordHelpUrl() const; - void validateBugReportCredentials(const QString& login, const QString& password); - void abortCredentialsValidation(); - void useBugReportCredentials(const QString& login, const QString& password); - void clearBugReportCredentials(); - - private: - void reportBug(const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, - ResponseHandler responseHandler, const QString& urlSuffix); - void requestFeature(const QString& title, const QString& details, ResponseHandler responseHandler, const QString& urlSuffix); - - static QString escapeParam(const QString& input); - static QString escapeUrl(const QString& input); - - QNetworkAccessManager* networkManager = nullptr; - QHash replyToHandler; - QHash> replyToTypeAndTitle; - QNetworkReply* credentialsValidationInProgress = nullptr; - - static_char* bugReportServiceUrl = "http://sqlitestudio.pl/report_bug3.rvt"; - static_char* reporterEmailHelpUrl = "http://wiki.sqlitestudio.pl/index.php/User_Manual#Reporter_email_address"; - static_char* reporterUserPassHelpUrl = "http://wiki.sqlitestudio.pl/index.php/User_Manual#Reporter_user_and_password"; - - signals: - void credentialsValidationResult(bool success, const QString& errorMessage); - - private slots: - void finished(QNetworkReply* reply); - - public slots: - void reportBug(const QString& email, const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, - ResponseHandler responseHandler = nullptr); - void reportBug(const QString& title, const QString& details, const QString& version, const QString& os, const QString& plugins, - ResponseHandler responseHandler = nullptr); - void requestFeature(const QString& email, const QString& title, const QString& details, ResponseHandler responseHandler = nullptr); - void requestFeature(const QString& title, const QString& details, ResponseHandler responseHandler = nullptr); -}; - -#define BUGS SQLITESTUDIO->getBugReporter() - -#endif // BUGREPORTER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/services/config.h b/SQLiteStudio3/coreSQLiteStudio/services/config.h index 1e4c410..202120a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/config.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/config.h @@ -20,6 +20,8 @@ CFG_CATEGORIES(Core, CFG_CATEGORY(General, CFG_ENTRY(int, SqlHistorySize, 10000) CFG_ENTRY(int, DdlHistorySize, 1000) + CFG_ENTRY(int, BindParamsCacheSize, 1000) + CFG_ENTRY(int, PopulateHistorySize, 100) CFG_ENTRY(QString, LoadedPlugins, "") CFG_ENTRY(QVariantHash, ActiveCodeFormatter, QVariantHash()) CFG_ENTRY(bool, CheckUpdatesOnStartup, true) @@ -31,6 +33,7 @@ CFG_CATEGORIES(Core, CFG_CATEGORY(Internal, CFG_ENTRY(QVariantList, Functions, QVariantList()) CFG_ENTRY(QVariantList, Collations, QVariantList()) + CFG_ENTRY(QVariantList, Extensions, QVariantList()) CFG_ENTRY(QString, BugReportUser, QString()) CFG_ENTRY(QString, BugReportPassword, QString()) CFG_ENTRY(QString, BugReportRecentTitle, QString()) @@ -118,6 +121,7 @@ class API_EXPORT Config : public QObject virtual bool isMassSaving() const = 0; virtual void set(const QString& group, const QString& key, const QVariant& value) = 0; virtual QVariant get(const QString& group, const QString& key) = 0; + virtual QVariant get(const QString& group, const QString& key, const QVariant& defaultValue) = 0; virtual QHash getAll() = 0; virtual bool addDb(const QString& name, const QString& path, const QHash &options) = 0; @@ -144,6 +148,7 @@ class API_EXPORT Config : public QObject virtual qint64 addSqlHistory(const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected) = 0; virtual void updateSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected) = 0; virtual void clearSqlHistory() = 0; + virtual void deleteSqlHistory(const QList& ids) = 0; virtual QAbstractItemModel* getSqlHistoryModel() = 0; virtual void addCliHistory(const QString& text) = 0; @@ -151,6 +156,15 @@ class API_EXPORT Config : public QObject virtual void clearCliHistory() = 0; virtual QStringList getCliHistory() const = 0; + virtual void addBindParamHistory(const QVector>& params) = 0; + virtual void applyBindParamHistoryLimit() = 0; + virtual QVector> getBindParamHistory(const QStringList& paramNames) const = 0; + + virtual void addPopulateHistory(const QString& database, const QString& table, int rows, const QHash>& columnsPluginsConfig) = 0; + virtual void applyPopulateHistoryLimit() = 0; + virtual QHash> getPopulateHistory(const QString& database, const QString& table, int& rows) const = 0; + virtual QVariant getPopulateHistory(const QString& pluginName) const = 0; + virtual void addDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile) = 0; virtual QList getDdlHistoryFor(const QString& dbName, const QString& dbFile, const QDate& date) = 0; virtual DdlHistoryModel* getDdlHistoryModel() = 0; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/dbmanager.h b/SQLiteStudio3/coreSQLiteStudio/services/dbmanager.h index 52746e4..2b5fa41 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/dbmanager.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/dbmanager.h @@ -144,12 +144,13 @@ class API_EXPORT DbManager : public QObject /** * @brief Creates in-memory SQLite3 database. + * @param pureInit If true, avoids registering collations/functions/extensions in a database. Skips rich initialization and gives pure database connection. * @return Created database. * * Created database can be used for any purpose. Note that DbManager doesn't own created * database and it's up to the caller to delete the database when it's no longer needed. */ - virtual Db* createInMemDb() = 0; + virtual Db* createInMemDb(bool pureInit = false) = 0; /** * @brief Tells if given database is temporary. diff --git a/SQLiteStudio3/coreSQLiteStudio/services/functionmanager.h b/SQLiteStudio3/coreSQLiteStudio/services/functionmanager.h index 2581b4f..5fb4908 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/functionmanager.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/functionmanager.h @@ -3,6 +3,7 @@ #include "coreSQLiteStudio_global.h" #include "common/global.h" +#include #include #include #include diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/collationmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/collationmanagerimpl.cpp index 5876021..7d24e47 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/collationmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/collationmanagerimpl.cpp @@ -27,7 +27,7 @@ QList CollationManagerImpl::getAllCollations() c QList CollationManagerImpl::getCollationsForDatabase(const QString& dbName) const { QList results; - foreach (const CollationPtr& coll, collations) + for (const CollationPtr& coll : collations) { if (coll->allDatabases || coll->databases.contains(dbName, Qt::CaseInsensitive)) results << coll; @@ -120,6 +120,6 @@ void CollationManagerImpl::loadFromConfig() void CollationManagerImpl::refreshCollationsByKey() { collationsByKey.clear(); - foreach (CollationPtr collation, collations) + for (CollationPtr collation : collations) collationsByKey[collation->name] = collation; } diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp index cf8b115..860e828 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp @@ -4,6 +4,7 @@ #include "services/notifymanager.h" #include "sqlitestudio.h" #include "db/dbsqlite3.h" +#include "common/utils.h" #include #include #include @@ -94,11 +95,7 @@ bool ConfigImpl::isMassSaving() const void ConfigImpl::set(const QString &group, const QString &key, const QVariant &value) { - QByteArray bytes; - QDataStream stream(&bytes, QIODevice::WriteOnly); - stream << value; - - db->exec("INSERT OR REPLACE INTO settings VALUES (?, ?, ?)", {group, key, bytes}); + db->exec("INSERT OR REPLACE INTO settings VALUES (?, ?, ?)", {group, key, serializeToBytes(value)}); } QVariant ConfigImpl::get(const QString &group, const QString &key) @@ -107,6 +104,15 @@ QVariant ConfigImpl::get(const QString &group, const QString &key) return deserializeValue(results->getSingleCell()); } +QVariant ConfigImpl::get(const QString &group, const QString &key, const QVariant &defaultValue) +{ + QVariant value = get(group, key); + if (!value.isValid() || value.isNull()) + return defaultValue; + + return value; +} + QHash ConfigImpl::getAll() { SqlQueryPtr results = db->exec("SELECT [group], [key], value FROM settings"); @@ -225,7 +231,7 @@ void ConfigImpl::storeGroups(const QList& groups) db->begin(); db->exec("DELETE FROM groups"); - foreach (const DbGroupPtr& group, groups) + for (const DbGroupPtr& group : groups) storeGroup(group); db->commit(); @@ -241,7 +247,7 @@ void ConfigImpl::storeGroup(const ConfigImpl::DbGroupPtr &group, qint64 parentId {group->name, group->order, parent, group->open, group->referencedDbName}); qint64 newParentId = results->getRegularInsertRowId(); - foreach (const DbGroupPtr& childGroup, group->childs) + for (const DbGroupPtr& childGroup : group->childs) storeGroup(childGroup, newParentId); } @@ -304,6 +310,11 @@ void ConfigImpl::clearSqlHistory() QtConcurrent::run(this, &ConfigImpl::asyncClearSqlHistory); } +void ConfigImpl::deleteSqlHistory(const QList& ids) +{ + QtConcurrent::run(this, &ConfigImpl::asyncDeleteSqlHistory, ids); +} + QAbstractItemModel* ConfigImpl::getSqlHistoryModel() { if (!sqlHistoryModel) @@ -338,6 +349,122 @@ QStringList ConfigImpl::getCliHistory() const return results->columnAsList("text"); } +void ConfigImpl::addBindParamHistory(const QVector >& params) +{ + QtConcurrent::run(this, &ConfigImpl::asyncAddBindParamHistory, params); +} + +void ConfigImpl::applyBindParamHistoryLimit() +{ + QtConcurrent::run(this, &ConfigImpl::asyncApplyBindParamHistoryLimit); +} + +QVector> ConfigImpl::getBindParamHistory(const QStringList& paramNames) const +{ + static_qstring(directQuery, "SELECT id FROM bind_params WHERE pattern = ? ORDER BY id DESC"); + static_qstring(paramsByIdQuery, "SELECT name, value FROM bind_param_values WHERE bind_params_id = ? ORDER BY position"); + static_qstring(singleParamQuery, "SELECT value FROM bind_param_values WHERE %1 = ? ORDER BY id DESC LIMIT 1;"); + static_qstring(singleParamName, "name"); + static_qstring(singleParamPosition, "position"); + + QVector> bindParams; + bindParams.reserve(paramNames.size()); + + SqlQueryPtr results = db->exec(directQuery, {paramNames.join(",")}); + if (results->isError()) + { + qWarning() << "Error while getting BindParams (1):" << db->getErrorText(); + return bindParams; + } + + // Got an exact match? Extract values and return. + QVariant exactMatch = results->getSingleCell(); + if (!exactMatch.isNull()) + { + results = db->exec(paramsByIdQuery, {exactMatch.toLongLong()}); + if (results->isError()) + { + qWarning() << "Error while getting BindParams (2):" << db->getErrorText(); + } + else + { + for (const SqlResultsRowPtr& row : results->getAll()) + bindParams << QPair(row->value("name").toString(), row->value("value")); + } + return bindParams; + } + + // No exact match. Will look for values one by one using param name and position. + int position = 0; + for (const QString& bindParam : paramNames) + { + if (bindParam == "?") + results = db->exec(singleParamQuery.arg(singleParamPosition), {position}); + else + results = db->exec(singleParamQuery.arg(singleParamName), {bindParam}); + + bindParams << QPair(bindParam, results->getSingleCell()); + position++; + } + return bindParams; +} + +void ConfigImpl::addPopulateHistory(const QString& database, const QString& table, int rows, const QHash >& columnsPluginsConfig) +{ + QtConcurrent::run(this, &ConfigImpl::asyncAddPopulateHistory, database, table, rows, columnsPluginsConfig); +} + +void ConfigImpl::applyPopulateHistoryLimit() +{ + QtConcurrent::run(this, &ConfigImpl::asyncApplyPopulateHistoryLimit); +} + +QHash> ConfigImpl::getPopulateHistory(const QString& database, const QString& table, int& rows) const +{ + static_qstring(initialQuery, "SELECT id, rows FROM populate_history WHERE [database] = ? AND [table] = ? ORDER BY id DESC LIMIT 1"); + static_qstring(columnsQuery, "SELECT column_name, plugin_name, plugin_config FROM populate_column_history WHERE populate_history_id = ?"); + + QHash> historyEntry; + SqlQueryPtr results = db->exec(initialQuery, {database, table}); + if (results->isError()) + { + qWarning() << "Error while getting Populating history entry (1):" << db->getErrorText(); + return historyEntry; + } + + if (!results->hasNext()) + return historyEntry; + + SqlResultsRowPtr row = results->next(); + qint64 historyEntryId = row->value("id").toLongLong(); + rows = row->value("rows").toInt(); + + results = db->exec(columnsQuery, {historyEntryId}); + QVariant value; + while (results->hasNext()) + { + row = results->next(); + value = deserializeValue(row->value("plugin_config")); + historyEntry[row->value("column_name").toString()] = QPair(row->value("plugin_name").toString(), value); + } + + return historyEntry; +} + +QVariant ConfigImpl::getPopulateHistory(const QString& pluginName) const +{ + static_qstring(columnsQuery, "SELECT plugin_config FROM populate_column_history WHERE plugin_name = ? ORDER BY id DESC LiMIT 1"); + + SqlQueryPtr results = db->exec(columnsQuery, {pluginName}); + if (results->isError()) + { + qWarning() << "Error while getting Populating history entry (2):" << db->getErrorText(); + return QVariant(); + } + + return deserializeValue(results->getSingleCell()); +} + void ConfigImpl::addDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile) { QtConcurrent::run(this, &ConfigImpl::asyncAddDdlHistory, queries, dbName, dbFile); @@ -503,9 +630,9 @@ QString ConfigImpl::getPortableConfigPath() if (!file.isDir() || !file.isReadable() || !file.isWritable()) continue; - foreach (file, dir.entryInfoList()) + for (const QFileInfo& entryFile : dir.entryInfoList()) { - if (!file.isReadable() || !file.isWritable()) + if (!entryFile.isReadable() || !entryFile.isWritable()) continue; } @@ -522,8 +649,7 @@ void ConfigImpl::initTables() if (!tables.contains("version")) { - QString table; - foreach (table, tables) + for (const QString& table : tables) db->exec("DROP TABLE "+table); tables.clear(); @@ -554,6 +680,34 @@ void ConfigImpl::initTables() if (!tables.contains("reports_history")) db->exec("CREATE TABLE reports_history (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, feature_request BOOLEAN, title TEXT, url TEXT)"); + + if (!tables.contains("bind_params")) + { + db->exec("CREATE TABLE bind_params (id INTEGER PRIMARY KEY AUTOINCREMENT, pattern TEXT NOT NULL)"); + db->exec("CREATE INDEX bind_params_patt_idx ON bind_params (pattern);"); + } + + if (!tables.contains("bind_param_values")) + { + db->exec("CREATE TABLE bind_param_values (id INTEGER PRIMARY KEY AUTOINCREMENT, bind_params_id INTEGER REFERENCES bind_params (id) " + "ON DELETE CASCADE ON UPDATE CASCADE NOT NULL, position INTEGER NOT NULL, name TEXT NOT NULL, value)"); + db->exec("CREATE INDEX bind_param_values_fk_idx ON bind_param_values (bind_params_id);"); + } + + if (!tables.contains("populate_history")) + { + db->exec("CREATE TABLE populate_history (id INTEGER PRIMARY KEY AUTOINCREMENT, [database] TEXT NOT NULL, [table] TEXT NOT NULL, rows INTEGER NOT NULL)"); + } + + if (!tables.contains("populate_column_history")) + { + db->exec("CREATE TABLE populate_column_history (id INTEGER PRIMARY KEY AUTOINCREMENT, populate_history_id INTEGER REFERENCES populate_history (id) " + "ON DELETE CASCADE ON UPDATE CASCADE NOT NULL, column_name TEXT NOT NULL, plugin_name TEXT NOT NULL, plugin_config BLOB)"); + db->exec("CREATE INDEX populate_plugin_history_idx ON populate_column_history (plugin_name)"); + } + + if (!tables.contains("reports_history")) + db->exec("CREATE TABLE reports_history (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, feature_request BOOLEAN, title TEXT, url TEXT)"); } void ConfigImpl::initDbFile() @@ -646,19 +800,13 @@ bool ConfigImpl::tryInitDbFile(const QPair &dbPath) return true; } -QVariant ConfigImpl::deserializeValue(const QVariant &value) +QVariant ConfigImpl::deserializeValue(const QVariant &value) const { if (!value.isValid()) return QVariant(); QByteArray bytes = value.toByteArray(); - if (bytes.isNull()) - return QVariant(); - - QVariant deserializedValue; - QDataStream stream(bytes); - stream >> deserializedValue; - return deserializedValue; + return deserializeFromBytes(bytes); } void ConfigImpl::asyncAddSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected) @@ -709,6 +857,23 @@ void ConfigImpl::asyncClearSqlHistory() emit sqlHistoryRefreshNeeded(); } +void ConfigImpl::asyncDeleteSqlHistory(const QList& ids) +{ + if (!db->begin()) { + NOTIFY_MANAGER->warn(tr("Could not start database transaction for deleting SQL history, therefore it's not deleted.")); + return; + } + for (const qint64& id : ids) + db->exec("DELETE FROM sqleditor_history WHERE id = ?", id); + + if (!db->commit()) { + NOTIFY_MANAGER->warn(tr("Could not commit database transaction for deleting SQL history, therefore it's not deleted.")); + db->rollback(); + return; + } + emit sqlHistoryRefreshNeeded(); +} + void ConfigImpl::asyncAddCliHistory(const QString& text) { static_qstring(insertQuery, "INSERT INTO cli_history (text) VALUES (?)"); @@ -722,7 +887,7 @@ void ConfigImpl::asyncAddCliHistory(const QString& text) void ConfigImpl::asyncApplyCliHistoryLimit() { - static_qstring(limitQuery, "DELETE FROM cli_history WHERE id >= (SELECT id FROM cli_history ORDER BY id LIMIT 1 OFFSET %1)"); + static_qstring(limitQuery, "DELETE FROM cli_history WHERE id <= (SELECT id FROM cli_history ORDER BY id DESC LIMIT 1 OFFSET %1)"); SqlQueryPtr results = db->exec(limitQuery.arg(CFG_CORE.Console.HistorySize.get())); if (results->isError()) @@ -738,6 +903,105 @@ void ConfigImpl::asyncClearCliHistory() qWarning() << "Error while clearing CLI history:" << db->getErrorText(); } +void ConfigImpl::asyncAddBindParamHistory(const QVector >& params) +{ + static_qstring(insertParamsQuery, "INSERT INTO bind_params (pattern) VALUES (?)"); + static_qstring(insertValuesQuery, "INSERT INTO bind_param_values (bind_params_id, position, name, value) VALUES (?, ?, ?, ?)"); + + if (!db->begin()) + { + qWarning() << "Failed to store BindParam cache, because could not begin SQL transaction. Details:" << db->getErrorText(); + return; + } + + QStringList paramNames; + for (const QPair& paramPair : params) + paramNames << paramPair.first; + + SqlQueryPtr results = db->exec(insertParamsQuery, {paramNames.join(",")}); + RowId rowId = results->getInsertRowId(); + qint64 bindParamsId = rowId["ROWID"].toLongLong(); + + int position = 0; + for (const QPair& paramPair : params) + { + results = db->exec(insertValuesQuery, {bindParamsId, position++, paramPair.first, paramPair.second}); + if (results->isError()) + { + qWarning() << "Failed to store BindParam cache, due to SQL error:" << db->getErrorText(); + db->rollback(); + return; + } + } + + if (!db->commit()) + { + qWarning() << "Failed to store BindParam cache, because could not commit SQL transaction. Details:" << db->getErrorText(); + db->rollback(); + } + + asyncApplyBindParamHistoryLimit(); +} + +void ConfigImpl::asyncApplyBindParamHistoryLimit() +{ + static_qstring(findBindParamIdQuery, "SELECT bind_params_id FROM bind_param_values ORDER BY id DESC LIMIT 1 OFFSET %1"); + static_qstring(limitBindParamsQuery, "DELETE FROM bind_params WHERE id <= ?"); // will cascade with FK to bind_param_values + + SqlQueryPtr results = db->exec(findBindParamIdQuery.arg(CFG_CORE.General.BindParamsCacheSize.get())); + if (results->isError()) + qWarning() << "Error while limiting BindParam history (step 1):" << db->getErrorText(); + + qint64 bindParamId = results->getSingleCell().toLongLong(); + results = db->exec(limitBindParamsQuery, {bindParamId}); + if (results->isError()) + qWarning() << "Error while limiting BindParam history (step 2):" << db->getErrorText(); +} + +void ConfigImpl::asyncAddPopulateHistory(const QString& database, const QString& table, int rows, const QHash>& columnsPluginsConfig) +{ + static_qstring(insertQuery, "INSERT INTO populate_history ([database], [table], rows) VALUES (?, ?, ?)"); + static_qstring(insertColumnQuery, "INSERT INTO populate_column_history (populate_history_id, column_name, plugin_name, plugin_config) VALUES (?, ?, ?, ?)"); + + if (!db->begin()) + { + qWarning() << "Failed to store Populating history entry, because could not begin SQL transaction. Details:" << db->getErrorText(); + return; + } + + SqlQueryPtr results = db->exec(insertQuery, {database, table, rows}); + RowId rowId = results->getInsertRowId(); + qint64 populateHistoryId = rowId["ROWID"].toLongLong(); + + for (QHash>::const_iterator colIt = columnsPluginsConfig.begin(); colIt != columnsPluginsConfig.end(); colIt++) + { + results = db->exec(insertColumnQuery, {populateHistoryId, colIt.key(), colIt.value().first, serializeToBytes(colIt.value().second)}); + if (results->isError()) + { + qWarning() << "Failed to store Populating history entry, due to SQL error:" << db->getErrorText(); + db->rollback(); + return; + } + } + + if (!db->commit()) + { + qWarning() << "Failed to store Populating history entry, because could not commit SQL transaction. Details:" << db->getErrorText(); + db->rollback(); + } + + asyncApplyPopulateHistoryLimit(); +} + +void ConfigImpl::asyncApplyPopulateHistoryLimit() +{ + static_qstring(limitQuery, "DELETE FROM populate_history WHERE id <= (SELECT id FROM populate_history ORDER BY id DESC LIMIT 1 OFFSET %1)"); + + SqlQueryPtr results = db->exec(limitQuery.arg(CFG_CORE.General.PopulateHistorySize.get())); + if (results->isError()) + qWarning() << "Error while limiting Populating history:" << db->getErrorText(); +} + void ConfigImpl::asyncAddDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile) { static_qstring(insert, "INSERT INTO ddl_history (dbname, file, timestamp, queries) VALUES (?, ?, ?, ?)"); @@ -799,7 +1063,12 @@ void ConfigImpl::mergeMasterConfig() if (masterConfigFile.isEmpty()) return; - qInfo() << "Updating settings from master configuration file: " << masterConfigFile; +#if QT_VERSION >= 0x050500 + qInfo() +#else + qDebug() +#endif + << "Updating settings from master configuration file: " << masterConfigFile; Db* masterDb = new DbSqlite3("SQLiteStudio master settings", masterConfigFile, {{DB_PURE_INIT, true}}); if (!masterDb->open()) diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h index 08bcec7..561aab4 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h @@ -29,6 +29,7 @@ class API_EXPORT ConfigImpl : public Config bool isMassSaving() const; void set(const QString& group, const QString& key, const QVariant& value); QVariant get(const QString& group, const QString& key); + QVariant get(const QString& group, const QString& key, const QVariant& defaultValue); QHash getAll(); bool addDb(const QString& name, const QString& path, const QHash &options); @@ -56,6 +57,7 @@ class API_EXPORT ConfigImpl : public Config qint64 addSqlHistory(const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected); void updateSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected); void clearSqlHistory(); + void deleteSqlHistory(const QList& ids); QAbstractItemModel* getSqlHistoryModel(); void addCliHistory(const QString& text); @@ -63,6 +65,15 @@ class API_EXPORT ConfigImpl : public Config void clearCliHistory(); QStringList getCliHistory() const; + void addBindParamHistory(const QVector>& params); + void applyBindParamHistoryLimit(); + QVector> getBindParamHistory(const QStringList& paramNames) const; + + void addPopulateHistory(const QString& database, const QString& table, int rows, const QHash>& columnsPluginsConfig); + void applyPopulateHistoryLimit(); + QHash> getPopulateHistory(const QString& database, const QString& table, int& rows) const; + QVariant getPopulateHistory(const QString& pluginName) const; + void addDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile); QList getDdlHistoryFor(const QString& dbName, const QString& dbFile, const QDate& date); DdlHistoryModel* getDdlHistoryModel(); @@ -94,16 +105,23 @@ class API_EXPORT ConfigImpl : public Config void initTables(); void initDbFile(); bool tryInitDbFile(const QPair& dbPath); - QVariant deserializeValue(const QVariant& value); + QVariant deserializeValue(const QVariant& value) const; void asyncAddSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected); void asyncUpdateSqlHistory(qint64 id, const QString& sql, const QString& dbName, int timeSpentMillis, int rowsAffected); void asyncClearSqlHistory(); + void asyncDeleteSqlHistory(const QList &ids); void asyncAddCliHistory(const QString& text); void asyncApplyCliHistoryLimit(); void asyncClearCliHistory(); + void asyncAddBindParamHistory(const QVector>& params); + void asyncApplyBindParamHistoryLimit(); + + void asyncAddPopulateHistory(const QString& database, const QString& table, int rows, const QHash>& columnsPluginsConfig); + void asyncApplyPopulateHistoryLimit(); + void asyncAddDdlHistory(const QString& queries, const QString& dbName, const QString& dbFile); void asyncClearDdlHistory(); diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.cpp index 74f482f..217c2b7 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.cpp @@ -23,7 +23,8 @@ DbManagerImpl::DbManagerImpl(QObject *parent) : DbManagerImpl::~DbManagerImpl() { - foreach (Db* db, dbList) +// qDebug() << "DbManagerImpl::~DbManagerImpl()"; + for (Db* db : dbList) { disconnect(db, SIGNAL(disconnected()), this, SLOT(dbDisconnectedSlot())); disconnect(db, SIGNAL(aboutToDisconnect(bool&)), this, SLOT(dbAboutToDisconnect(bool&))); @@ -261,12 +262,16 @@ Db* DbManagerImpl::getByPath(const QString &path) return pathToDb.value(pathDir.absolutePath()); } -Db* DbManagerImpl::createInMemDb() +Db* DbManagerImpl::createInMemDb(bool pureInit) { if (!inMemDbCreatorPlugin) return nullptr; - return inMemDbCreatorPlugin->getInstance("", ":memory:", {}); + QHash opts; + if (pureInit) + opts[DB_PURE_INIT] = true; + + return inMemDbCreatorPlugin->getInstance("", ":memory:", opts); } bool DbManagerImpl::isTemporary(Db* db) @@ -341,7 +346,7 @@ void DbManagerImpl::loadInitialDbList() { QUrl url; InvalidDb* db = nullptr; - foreach (const Config::CfgDbPtr& cfgDb, CFG->dbList()) + for (const Config::CfgDbPtr& cfgDb : CFG->dbList()) { db = new InvalidDb(cfgDb->name, cfgDb->path, cfgDb->options); diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.h b/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.h index 2e3630a..5f99f86 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/dbmanagerimpl.h @@ -42,7 +42,7 @@ class API_EXPORT DbManagerImpl : public DbManager QStringList getDbNames(); Db* getByName(const QString& name, Qt::CaseSensitivity cs = Qt::CaseInsensitive); Db* getByPath(const QString& path); - Db* createInMemDb(); + Db* createInMemDb(bool pureInit = false); bool isTemporary(Db* db); QString quickAddDb(const QString &path, const QHash &options); DbPlugin* getPluginForDbFile(const QString& filePath); diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp index 826b34b..2fcc689 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp @@ -40,7 +40,7 @@ QList FunctionManagerImpl::getAllScriptFunctio QList FunctionManagerImpl::getScriptFunctionsForDatabase(const QString& dbName) const { QList results; - foreach (ScriptFunction* func, functions) + for (ScriptFunction* func : functions) { if (func->allDatabases || func->databases.contains(dbName, Qt::CaseInsensitive)) results << func; @@ -280,10 +280,10 @@ void FunctionManagerImpl::initNativeFunctions() void FunctionManagerImpl::refreshFunctionsByKey() { functionsByKey.clear(); - foreach (ScriptFunction* func, functions) + for (ScriptFunction* func : functions) functionsByKey[Key(func)] = func; - foreach (NativeFunction* func, nativeFunctions) + for (NativeFunction* func : nativeFunctions) nativeFunctionsByKey[Key(func)] = func; } @@ -291,7 +291,7 @@ void FunctionManagerImpl::storeInConfig() { QVariantList list; QHash fnHash; - foreach (ScriptFunction* func, functions) + for (ScriptFunction* func : functions) { fnHash["name"] = func->name; fnHash["lang"] = func->lang; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/pluginmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/pluginmanagerimpl.cpp index 9fe21de..c67156c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/pluginmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/pluginmanagerimpl.cpp @@ -50,7 +50,7 @@ void PluginManagerImpl::deinit() emit aboutToQuit(); // Plugin containers and their plugins - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) { if (container->builtIn) { @@ -61,13 +61,13 @@ void PluginManagerImpl::deinit() unload(container->name); } - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) delete container; pluginContainer.clear(); // Types - foreach (PluginType* type, registeredPluginTypes) + for (PluginType* type : registeredPluginTypes) delete type; registeredPluginTypes.clear(); @@ -113,10 +113,10 @@ void PluginManagerImpl::scanPlugins() nameFilters << "*.so" << "*.dll" << "*.dylib"; QPluginLoader* loader = nullptr; - foreach (QString pluginDirPath, pluginDirs) + for (QString pluginDirPath : pluginDirs) { QDir pluginDir(pluginDirPath); - foreach (QString fileName, pluginDir.entryList(nameFilters, QDir::Files)) + for (QString fileName : pluginDir.entryList(nameFilters, QDir::Files)) { fileName = pluginDir.absoluteFilePath(fileName); loader = new QPluginLoader(fileName); @@ -158,7 +158,7 @@ bool PluginManagerImpl::initPlugin(QPluginLoader* loader, const QString& fileNam QJsonObject pluginMetaData = loader->metaData(); QString pluginTypeName = pluginMetaData.value("MetaData").toObject().value("type").toString(); PluginType* pluginType = nullptr; - foreach (PluginType* type, registeredPluginTypes) + for (PluginType* type : registeredPluginTypes) { if (type->getName() == pluginTypeName) { @@ -169,7 +169,7 @@ bool PluginManagerImpl::initPlugin(QPluginLoader* loader, const QString& fileNam if (!pluginType) { - qWarning() << "Could not load plugin" + fileName + "because its type was not recognized:" << pluginTypeName; + qWarning() << "Could not load plugin" << fileName << "because its type was not recognized:" << pluginTypeName; return false; } @@ -305,7 +305,7 @@ bool PluginManagerImpl::initPlugin(Plugin* plugin) { QString pluginName = plugin->getName(); PluginType* pluginType = nullptr; - foreach (PluginType* type, registeredPluginTypes) + for (PluginType* type : registeredPluginTypes) { if (type->test(plugin)) { @@ -316,7 +316,7 @@ bool PluginManagerImpl::initPlugin(Plugin* plugin) if (!pluginType) { - qWarning() << "Could not load built-in plugin" + pluginName + "because its type was not recognized."; + qWarning() << "Could not load built-in plugin" << pluginName << "because its type was not recognized."; return false; } @@ -363,7 +363,7 @@ QStringList PluginManagerImpl::getAllPluginNames(PluginType* type) const if (!pluginCategories.contains(type)) return names; - foreach (PluginContainer* container, pluginCategories[type]) + for (PluginContainer* container : pluginCategories[type]) names << container->name; return names; @@ -685,7 +685,7 @@ QList PluginManagerImpl::getLoadedPlugins(PluginType* type) const if (!pluginCategories.contains(type)) return list; - foreach (PluginContainer* container, pluginCategories[type]) + for (PluginContainer* container : pluginCategories[type]) { if (container->loaded) list << container->plugin; @@ -769,7 +769,7 @@ bool PluginManagerImpl::arePluginsInitiallyLoaded() const QList PluginManagerImpl::getLoadedPlugins() const { QList plugins; - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) { if (container->loaded) plugins << container->plugin; @@ -780,7 +780,7 @@ QList PluginManagerImpl::getLoadedPlugins() const QStringList PluginManagerImpl::getLoadedPluginNames() const { QStringList names; - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) { if (container->loaded) names << container->name; @@ -792,7 +792,7 @@ QList PluginManagerImpl::getAllPluginDetails() con { QList results; PluginManager::PluginDetails details; - foreach (PluginContainer* container, pluginContainer.values()) + for (PluginContainer* container : pluginContainer.values()) { details.name = container->name; details.title = container->title; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.cpp new file mode 100644 index 0000000..63dbaf6 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.cpp @@ -0,0 +1,70 @@ +#include "sqliteextensionmanagerimpl.h" +#include "services/notifymanager.h" +#include "services/dbmanager.h" + +SqliteExtensionManagerImpl::SqliteExtensionManagerImpl() +{ + init(); +} + +void SqliteExtensionManagerImpl::setExtensions(const QList& newExtensions) +{ + extensions = newExtensions; + storeInConfig(); + emit extensionListChanged(); +} + +QList SqliteExtensionManagerImpl::getAllExtensions() const +{ + return extensions; +} + +QList SqliteExtensionManagerImpl::getExtensionForDatabase(const QString& dbName) const +{ + QList results; + for (const ExtensionPtr& ext : extensions) + { + if (ext->allDatabases || ext->databases.contains(dbName, Qt::CaseInsensitive)) + results << ext; + } + return results; +} + +void SqliteExtensionManagerImpl::init() +{ + loadFromConfig(); +} + +void SqliteExtensionManagerImpl::storeInConfig() +{ + QVariantList list; + QHash extHash; + for (ExtensionPtr ext : extensions) + { + extHash["filePath"] = ext->filePath; + extHash["initFunc"] = ext->initFunc; + extHash["allDatabases"] = ext->allDatabases; + extHash["databases"] =common(DBLIST->getDbNames(), ext->databases); + list << extHash; + } + CFG_CORE.Internal.Extensions.set(list); +} + +void SqliteExtensionManagerImpl::loadFromConfig() +{ + extensions.clear(); + + QVariantList list = CFG_CORE.Internal.Extensions.get(); + QHash extHash; + ExtensionPtr ext; + for (const QVariant& var : list) + { + extHash = var.toHash(); + ext = ExtensionPtr::create(); + ext->filePath = extHash["filePath"].toString(); + ext->initFunc = extHash["initFunc"].toString(); + ext->databases = extHash["databases"].toStringList(); + ext->allDatabases = extHash["allDatabases"].toBool(); + extensions << ext; + } +} diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.h b/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.h new file mode 100644 index 0000000..6fd7f46 --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/sqliteextensionmanagerimpl.h @@ -0,0 +1,23 @@ +#ifndef SQLITEEXTENSIONMANAGERIMPL_H +#define SQLITEEXTENSIONMANAGERIMPL_H + +#include "services/sqliteextensionmanager.h" + +class SqliteExtensionManagerImpl : public SqliteExtensionManager +{ + public: + SqliteExtensionManagerImpl(); + + void setExtensions(const QList& newExtensions); + QList getAllExtensions() const; + QList getExtensionForDatabase(const QString& dbName) const; + + private: + void init(); + void storeInConfig(); + void loadFromConfig(); + + QList extensions; +}; + +#endif // SQLITEEXTENSIONMANAGERIMPL_H diff --git a/SQLiteStudio3/coreSQLiteStudio/services/pluginmanager.h b/SQLiteStudio3/coreSQLiteStudio/services/pluginmanager.h index 4f822bc..f771c2c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/pluginmanager.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/pluginmanager.h @@ -380,7 +380,7 @@ class API_EXPORT PluginManager : public QObject template PluginType* getPluginType() const { - foreach (PluginType* type, getPluginTypes()) + for (PluginType* type : getPluginTypes()) { if (!dynamic_cast*>(type)) continue; @@ -406,7 +406,7 @@ class API_EXPORT PluginManager : public QObject if (!type) return typedPlugins; - foreach (Plugin* plugin, getLoadedPlugins(type)) + for (Plugin* plugin : getLoadedPlugins(type)) typedPlugins << dynamic_cast(plugin); return typedPlugins; @@ -427,7 +427,7 @@ class API_EXPORT PluginManager : public QObject if (!type) return names; - foreach (Plugin* plugin, getLoadedPlugins(type)) + for (Plugin* plugin : getLoadedPlugins(type)) names << plugin->getName(); return names; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/sqliteextensionmanager.h b/SQLiteStudio3/coreSQLiteStudio/services/sqliteextensionmanager.h new file mode 100644 index 0000000..a135f3b --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/services/sqliteextensionmanager.h @@ -0,0 +1,34 @@ +#ifndef SQLITEEXTENSIONMANAGER_H +#define SQLITEEXTENSIONMANAGER_H + +#include "coreSQLiteStudio_global.h" +#include "sqlitestudio.h" +#include +#include + +class API_EXPORT SqliteExtensionManager : public QObject +{ + Q_OBJECT + + public: + struct API_EXPORT Extension + { + QString filePath; + QString initFunc; + QStringList databases; + bool allDatabases = true; + }; + + typedef QSharedPointer ExtensionPtr; + + virtual void setExtensions(const QList& newExtensions) = 0; + virtual QList getAllExtensions() const = 0; + virtual QList getExtensionForDatabase(const QString& dbName) const = 0; + + signals: + void extensionListChanged(); +}; + +#define SQLITE_EXTENSIONS SQLITESTUDIO->getSqliteExtensionManager() + +#endif // SQLITEEXTENSIONMANAGER_H diff --git a/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.cpp b/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.cpp index 3663a1b..87df73b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.cpp @@ -1,461 +1,100 @@ #ifdef PORTABLE_CONFIG #include "updatemanager.h" -#include "services/pluginmanager.h" #include "services/notifymanager.h" #include "common/unused.h" -#include -#include -#include -#include -#include -#include #include +#include #include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_WIN32 -#include "JlCompress.h" -#include -#include -#endif - -// Note on creating update packages: -// Packages for Linux and MacOSX should be an archive of _contents_ of SQLiteStudio directory, -// while for Windows it should be an archive of SQLiteStudio directory itself. - -QString UpdateManager::staticErrorMessage; -UpdateManager::RetryFunction UpdateManager::retryFunction = nullptr; +#include +#include UpdateManager::UpdateManager(QObject *parent) : QObject(parent) { - networkManager = new QNetworkAccessManager(this); - connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*))); - connect(this, SIGNAL(updatingError(QString)), NOTIFY_MANAGER, SLOT(error(QString))); -} - -UpdateManager::~UpdateManager() -{ - cleanup(); -} + qRegisterMetaType>(); -void UpdateManager::checkForUpdates(bool force) -{ - getUpdatesMetadata(updatesCheckReply, force); -} - -void UpdateManager::update() -{ - if (updatesGetUrlsReply || updatesInProgress) - return; - - getUpdatesMetadata(updatesGetUrlsReply); -} + connect(this, SIGNAL(updatingError(QString)), NOTIFY_MANAGER, SLOT(error(QString))); -QString UpdateManager::getPlatformForUpdate() const -{ -#if defined(Q_OS_LINUX) - if (QSysInfo::WordSize == 64) - return "linux64"; - else - return "linux32"; -#elif defined(Q_OS_WIN) - return "win32"; + QString updateBinary = +#if defined(Q_OS_WIN) + "UpdateSQLiteStudio.exe"; +#elif defined(Q_OS_LINUX) + "UpdateSQLiteStudio"; #elif defined(Q_OS_OSX) - return "macosx"; + "../../UpdateSQLiteStudio.app/Contents/MacOS/UpdateSQLiteStudio"; #else - return QString(); + ""; #endif -} - -QString UpdateManager::getCurrentVersions() const -{ - QJsonArray versionsArray; - - QJsonObject arrayEntry; - arrayEntry["component"] = "SQLiteStudio"; - arrayEntry["version"] = SQLITESTUDIO->getVersionString(); - versionsArray.append(arrayEntry); - - for (const PluginManager::PluginDetails& details : PLUGINS->getAllPluginDetails()) - { - if (details.builtIn) - continue; - arrayEntry["component"] = details.name; - arrayEntry["version"] = details.versionString; - versionsArray.append(arrayEntry); + if (!updateBinary.isEmpty()) { + updateBinaryAbsolutePath = QFileInfo(QCoreApplication::applicationDirPath() + "/" + updateBinary).absoluteFilePath(); } - - QJsonObject topObj; - topObj["versions"] = versionsArray; - - QJsonDocument doc(topObj); - return QString::fromLatin1(doc.toJson(QJsonDocument::Compact)); -} - -bool UpdateManager::isPlatformEligibleForUpdate() const -{ - return !getPlatformForUpdate().isNull() && getDistributionType() != DistributionType::OS_MANAGED; -} - -#if defined(Q_OS_WIN32) -bool UpdateManager::executePreFinalStepWin(const QString &tempDir, const QString &backupDir, const QString &appDir, bool reqAdmin) -{ - bool res; - if (reqAdmin) - res = executeFinalStepAsRootWin(tempDir, backupDir, appDir); - else - res = executeFinalStep(tempDir, backupDir, appDir); - - if (res) - { - QFileInfo path(qApp->applicationFilePath()); - QProcess::startDetached(appDir + "/" + path.fileName(), {WIN_POST_FINAL_UPDATE_OPTION_NAME, tempDir}); - } - return res; } -#endif -void UpdateManager::handleAvailableUpdatesReply(QNetworkReply* reply) -{ - if (reply->error() != QNetworkReply::NoError) - { - updatingFailed(tr("An error occurred while checking for updates: %1.").arg(reply->errorString())); - reply->deleteLater(); - return; - } - - QJsonParseError err; - QByteArray data = reply->readAll(); - reply->deleteLater(); - - QJsonDocument doc = QJsonDocument::fromJson(data, &err); - if (err.error != QJsonParseError::NoError) - { - qWarning() << "Invalid response from update service:" << err.errorString() << "\n" << "The data was:" << QString::fromLatin1(data); - notifyWarn(tr("Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning.")); - return; - } - - QList updates = readMetadata(doc); - if (updates.size() > 0) - emit updatesAvailable(updates); - else - emit noUpdatesAvailable(); -} - -void UpdateManager::getUpdatesMetadata(QNetworkReply*& replyStoragePointer, bool force) +UpdateManager::~UpdateManager() { -#ifdef PORTABLE_CONFIG - if ((!CFG_CORE.General.CheckUpdatesOnStartup.get() && !force) || !isPlatformEligibleForUpdate() || replyStoragePointer) - return; - - QUrlQuery query; - query.addQueryItem("platform", getPlatformForUpdate()); - query.addQueryItem("data", getCurrentVersions()); - QUrl url(QString::fromLatin1(updateServiceUrl) + "?" + query.query(QUrl::FullyEncoded)); - QNetworkRequest request(url); - replyStoragePointer = networkManager->get(request); -#endif } -void UpdateManager::handleUpdatesMetadata(QNetworkReply* reply) +void UpdateManager::checkForUpdates() { - if (reply->error() != QNetworkReply::NoError) - { - updatingFailed(tr("An error occurred while reading updates metadata: %1.").arg(reply->errorString())); - reply->deleteLater(); + if (!CFG_CORE.General.CheckUpdatesOnStartup.get()) return; - } - QJsonParseError err; - QByteArray data = reply->readAll(); - reply->deleteLater(); - - QJsonDocument doc = QJsonDocument::fromJson(data, &err); - if (err.error != QJsonParseError::NoError) - { - qWarning() << "Invalid response from update service for getting metadata:" << err.errorString() << "\n" << "The data was:" << QString::fromLatin1(data); - notifyWarn(tr("Could not download updates, because server responded with invalid message format. " - "You can try again later or download and install updates manually. See User Manual for details.").arg(manualUpdatesHelpUrl)); + if (updateBinaryAbsolutePath.isEmpty()) { + qDebug() << "Updater binary not defined. Skipping updates checking."; return; } - tempDir = new QTemporaryDir(); - if (!tempDir->isValid()) { - notifyWarn(tr("Could not create temporary directory for downloading the update. Updating aborted.")); + if (!QFileInfo(updateBinaryAbsolutePath).exists()) { + QString errorDetails = tr("Updates installer executable is missing."); + emit updatingError(tr("Unable to check for updates (%1)").arg(errorDetails.trimmed())); + qWarning() << "Error while checking for updates: " << errorDetails; return; } - updatesInProgress = true; - updatesToDownload = readMetadata(doc); - totalDownloadsCount = updatesToDownload.size(); - totalPercent = 0; - - if (totalDownloadsCount == 0) - { - updatingFailed(tr("There was no updates to download. Updating aborted.")); - return; - } - - downloadUpdates(); + QtConcurrent::run(this, &UpdateManager::checkForUpdatesAsync); } -QList UpdateManager::readMetadata(const QJsonDocument& doc) +void UpdateManager::checkForUpdatesAsync() { - QList updates; - UpdateEntry entry; - QJsonObject obj = doc.object(); - QJsonArray versionsArray = obj["newVersions"].toArray(); - QJsonObject entryObj; - for (const QJsonValue& value : versionsArray) - { - entryObj = value.toObject(); - entry.compontent = entryObj["component"].toString(); - entry.version = entryObj["version"].toString(); - entry.url = entryObj["url"].toString(); - updates << entry; - } - - return updates; -} - -void UpdateManager::downloadUpdates() -{ - if (updatesToDownload.size() == 0) + QProcess proc; + proc.start(updateBinaryAbsolutePath, {"--checkupdates"}); + if (!waitForProcess(proc)) { - QtConcurrent::run(this, &UpdateManager::installUpdates); - return; - } + QString errorDetails = QString::fromLocal8Bit(proc.readAllStandardError()); - UpdateEntry entry = updatesToDownload.takeFirst(); - currentJobTitle = tr("Downloading: %1").arg(entry.compontent); - emit updatingProgress(currentJobTitle, 0, totalPercent); + if (errorDetails.toLower().contains("no updates")) { + emit noUpdatesAvailable(); + return; + } - QStringList parts = entry.url.split("/"); - if (parts.size() < 1) - { - updatingFailed(tr("Could not determinate file name from update URL: %1. Updating aborted.").arg(entry.url)); - return; - } + if (errorDetails.isEmpty()) + errorDetails = tr("details are unknown"); - QString path = tempDir->path() + QLatin1Char('/') + parts.last(); - currentDownloadFile = new QFile(path); - if (!currentDownloadFile->open(QIODevice::WriteOnly)) - { - updatingFailed(tr("Failed to open file '%1' for writting: %2. Updating aborted.").arg(path, currentDownloadFile->errorString())); + emit updatingError(tr("Unable to check for updates (%1)").arg(errorDetails.trimmed())); + qWarning() << "Error while checking for updates: " << errorDetails; return; } - updatesToInstall[entry.compontent] = path; - - QNetworkRequest request(QUrl(entry.url)); - updatesGetReply = networkManager->get(request); - connect(updatesGetReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64))); - connect(updatesGetReply, SIGNAL(readyRead()), this, SLOT(readDownload())); + processCheckResults(proc.readAllStandardOutput()); } -void UpdateManager::updatingFailed(const QString& errMsg) -{ - cleanup(); - updatesInProgress = false; - emit updatingError(errMsg); -} - -void UpdateManager::installUpdates() +void UpdateManager::update() { - currentJobTitle = tr("Installing updates."); - totalPercent = (totalDownloadsCount - updatesToDownload.size()) * 100 / (totalDownloadsCount + 1); - emit updatingProgress(currentJobTitle, 0, totalPercent); - - requireAdmin = doRequireAdminPrivileges(); - - QTemporaryDir installTempDir; - QString appDirName = QDir(getAppDirPath()).dirName(); - QString targetDir = installTempDir.path() + QLatin1Char('/') + appDirName; - if (!copyRecursively(getAppDirPath(), targetDir)) + bool success = QProcess::startDetached(updateBinaryAbsolutePath, {"--updater"}); + if (!success) { - updatingFailed(tr("Could not copy current application directory into %1 directory.").arg(installTempDir.path())); + emit updatingError(tr("Unable to run updater application (%1). Please report this.").arg(updateBinaryAbsolutePath)); return; } - emit updatingProgress(currentJobTitle, 40, totalPercent); - - int i = 0; - int updatesCnt = updatesToInstall.size(); - for (const QString& component : updatesToInstall.keys()) - { - if (!installComponent(component, targetDir)) - { - cleanup(); - updatesInProgress = false; - return; - } - i++; - emit updatingProgress(currentJobTitle, (30 + (50 / updatesCnt * i)), totalPercent); - } - - if (!executeFinalStep(targetDir)) - { - cleanup(); - updatesInProgress = false; - return; - } - - currentJobTitle = QString(); - totalPercent = 100; - emit updatingProgress(currentJobTitle, 100, totalPercent); - cleanup(); - updatesInProgress = false; -#ifdef Q_OS_WIN32 - installTempDir.setAutoRemove(false); -#endif - - SQLITESTUDIO->setImmediateQuit(true); qApp->exit(0); } -bool UpdateManager::executeFinalStep(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ - bool isWin = false; -#ifdef Q_OS_WIN32 - isWin = true; - - // Windows needs to wait for previus process to exit - QThread::sleep(3); - - QDir dir(backupDir); - QString dirName = dir.dirName(); - dir.cdUp(); - if (!dir.mkdir(dirName)) - { - staticUpdatingFailed(tr("Could not create directory %1.").arg(backupDir)); - return false; - } -#endif - while (!moveDir(appDir, backupDir, isWin)) - { - if (!retryFunction) - { - staticUpdatingFailed(tr("Could not rename directory %1 to %2.\nDetails: %3").arg(appDir, backupDir, staticErrorMessage)); - return false; - } - - if (!retryFunction(tr("Cannot not rename directory %1 to %2.\nDetails: %3").arg(appDir, backupDir, staticErrorMessage))) - return false; - } - - if (!moveDir(tempDir, appDir, isWin)) - { - if (!moveDir(backupDir, appDir, isWin)) - { - staticUpdatingFailed(tr("Could not move directory %1 to %2 and also failed to restore original directory, " - "so the original SQLiteStudio directory is now located at: %3").arg(tempDir, appDir, backupDir)); - } - else - { - staticUpdatingFailed(tr("Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version.").arg(tempDir, appDir)); - } - deleteDir(backupDir); - return false; - } - - deleteDir(backupDir); - return true; -} - -bool UpdateManager::handleUpdateOptions(const QStringList& argList, int& returnCode) -{ - if (argList.size() == 5 && argList[1] == UPDATE_OPTION_NAME) - { - bool result = UpdateManager::executeFinalStep(argList[2], argList[3], argList[4]); - if (result) - returnCode = 0; - else - returnCode = 1; - - return true; - } - -#ifdef Q_OS_WIN32 - if (argList.size() == 6 && argList[1] == WIN_PRE_FINAL_UPDATE_OPTION_NAME) - { - bool result = UpdateManager::executePreFinalStepWin(argList[2], argList[3], argList[4], (bool)argList[5].toInt()); - if (result) - returnCode = 0; - else - returnCode = -1; - - return true; - } - - if (argList.size() == 3 && argList[1] == WIN_POST_FINAL_UPDATE_OPTION_NAME) - { - QThread::sleep(1); // to make sure that the previous process has quit - returnCode = 0; - UpdateManager::executePostFinalStepWin(argList[2]); - return true; - } -#endif - - return false; -} - -QString UpdateManager::getStaticErrorMessage() -{ - return staticErrorMessage; -} - -bool UpdateManager::executeFinalStep(const QString& tempDir) -{ - QString appDir = getAppDirPath(); - - // Find inexisting dir name next to app dir - QDir backupDir(getBackupDir(appDir)); - -#if defined(Q_OS_WIN32) - return runAnotherInstanceForUpdate(tempDir, backupDir.absolutePath(), qApp->applicationDirPath(), requireAdmin); -#else - bool res; - if (requireAdmin) - res = executeFinalStepAsRoot(tempDir, backupDir.absolutePath(), appDir); - else - res = executeFinalStep(tempDir, backupDir.absolutePath(), appDir); - - if (res) - QProcess::startDetached(qApp->applicationFilePath(), QStringList()); - - return res; -#endif -} - -bool UpdateManager::installComponent(const QString& component, const QString& tempDir) -{ - if (!unpackToDir(updatesToInstall[component], tempDir)) - { - updatingFailed(tr("Could not unpack component %1 into %2 directory.").arg(component, tempDir)); - return false; - } - - // In future here we might also delete/change some files, according to some update script. - return true; -} - -void UpdateManager::cleanup() +bool UpdateManager::isPlatformEligibleForUpdate() const { - safe_delete(currentDownloadFile); - safe_delete(tempDir); - updatesToDownload.clear(); - updatesToInstall.clear(); - requireAdmin = false; + return getDistributionType() != DistributionType::OS_MANAGED; } bool UpdateManager::waitForProcess(QProcess& proc) @@ -481,582 +120,33 @@ bool UpdateManager::waitForProcess(QProcess& proc) return true; } -QString UpdateManager::readError(QProcess& proc, bool reverseOrder) -{ - QString err = QString::fromLocal8Bit(reverseOrder ? proc.readAllStandardOutput() : proc.readAllStandardError()); - if (err.isEmpty()) - err = QString::fromLocal8Bit(reverseOrder ? proc.readAllStandardError() : proc.readAllStandardOutput()); - - QString errStr = proc.errorString(); - if (!errStr.isEmpty()) - err += "\n" + errStr; - - return err; -} - -void UpdateManager::staticUpdatingFailed(const QString& errMsg) +void UpdateManager::processCheckResults(const QByteArray &results) { -#if defined(Q_OS_WIN32) - staticErrorMessage = errMsg; -#else - UPDATES->handleStaticFail(errMsg); -#endif - qCritical() << errMsg; -} - -bool UpdateManager::executeFinalStepAsRoot(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ -#if defined(Q_OS_LINUX) - return executeFinalStepAsRootLinux(tempDir, backupDir, appDir); -#elif defined(Q_OS_WIN32) - return executeFinalStepAsRootWin(tempDir, backupDir, appDir); -#elif defined(Q_OS_MACX) - return executeFinalStepAsRootMac(tempDir, backupDir, appDir); -#else - qCritical() << "Unknown update platform in UpdateManager::executeFinalStepAsRoot() for package" << packagePath; - return false; -#endif -} - -#if defined(Q_OS_LINUX) -bool UpdateManager::executeFinalStepAsRootLinux(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ - QStringList args = {qApp->applicationFilePath(), UPDATE_OPTION_NAME, tempDir, backupDir, appDir}; - - QProcess proc; - LinuxPermElevator elevator = findPermElevatorForLinux(); - switch (elevator) - { - case LinuxPermElevator::KDESU: - proc.setProgram("kdesu"); - args.prepend("-t"); - proc.setArguments(args); - break; - case LinuxPermElevator::GKSU: - proc.setProgram("gksu"); // TODO test gksu updates - proc.setArguments(args); - break; - case LinuxPermElevator::PKEXEC: - { - // We call CLI for doing final step, because pkexec runs cmd completly in root env, so there's no X server. - args[0] += "cli"; - - QStringList newArgs; - for (const QString& arg : args) - newArgs << wrapCmdLineArgument(arg); - - QString cmd = "cd " + wrapCmdLineArgument(qApp->applicationDirPath()) +"; " + newArgs.join(" "); - - proc.setProgram("pkexec"); - proc.setArguments({"sh", "-c", cmd}); - } - break; - case LinuxPermElevator::NONE: - updatingFailed(tr("Could not find permissions elevator application to run update as a root. Looked for: %1").arg("kdesu, gksu, pkexec")); - return false; - } - - proc.start(); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Could not execute final updating steps as root: %1").arg(readError(proc, (elevator == LinuxPermElevator::KDESU)))); - return false; - } - - return true; -} -#endif - -#ifdef Q_OS_MACX -bool UpdateManager::executeFinalStepAsRootMac(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ - // Prepare script for updater - // osascript -e "do shell script \"stufftorunasroot\" with administrator privileges" - QStringList args = {wrapCmdLineArgument(qApp->applicationFilePath() + "cli"), - UPDATE_OPTION_NAME, - wrapCmdLineArgument(tempDir), - wrapCmdLineArgument(backupDir), - wrapCmdLineArgument(appDir)}; - QProcess proc; - - QString innerCmd = wrapCmdLineArgument(args.join(" ")); - - static_qstring(scriptTpl, "do shell script %1 with administrator privileges"); - QString scriptCmd = scriptTpl.arg(innerCmd); - - // Prepare updater temporary directory - QTemporaryDir updaterDir; - if (!updaterDir.isValid()) - { - updatingFailed(tr("Could not execute final updating steps as admin: %1").arg(tr("Cannot create temporary directory for updater."))); - return false; - } - - // Create updater script - QString scriptPath = updaterDir.path() + "/UpdateSQLiteStudio.scpt"; - QFile updaterScript(scriptPath); - if (!updaterScript.open(QIODevice::WriteOnly)) - { - updatingFailed(tr("Could not execute final updating steps as admin: %1").arg(tr("Cannot create updater script file."))); - return false; - } - updaterScript.write(scriptCmd.toLocal8Bit()); - updaterScript.close(); - - // Compile script to updater application - QString updaterApp = updaterDir.path() + "/UpdateSQLiteStudio.app"; - proc.setProgram("osacompile"); - proc.setArguments({"-o", updaterApp, scriptPath}); - proc.start(); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Could not execute final updating steps as admin: %1").arg(readError(proc))); - return false; - } - - // Execute updater - proc.setProgram(updaterApp + "/Contents/MacOS/applet"); - proc.setArguments({}); - proc.start(); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Could not execute final updating steps as admin: %1").arg(readError(proc))); - return false; - } - - // Validating update - // The updater script will not return error if the user canceled the password prompt. - // We need to check if the update was actually made and return true only then. - if (QDir(tempDir).exists()) - { - // Temp dir still exists, so it was not moved by root process - updatingFailed(tr("Updating canceled.")); - return false; - } - - return true; -} -#endif - -#ifdef Q_OS_WIN32 -bool UpdateManager::executeFinalStepAsRootWin(const QString& tempDir, const QString& backupDir, const QString& appDir) -{ - QString updateBin = qApp->applicationDirPath() + "/" + WIN_UPDATER_BINARY; - - QString installFilePath = tempDir + "/" + WIN_INSTALL_FILE; - QFile installFile(installFilePath); - installFile.open(QIODevice::WriteOnly); - QString nl("\n"); - installFile.write(UPDATE_OPTION_NAME); - installFile.write(nl.toLocal8Bit()); - installFile.write(backupDir.toLocal8Bit()); - installFile.write(nl.toLocal8Bit()); - installFile.write(appDir.toLocal8Bit()); - installFile.write(nl.toLocal8Bit()); - installFile.close(); - - int res = (int)::ShellExecuteA(0, "runas", updateBin.toUtf8().constData(), 0, 0, SW_SHOWNORMAL); - if (res < 32) - { - staticUpdatingFailed(tr("Could not execute final updating steps as administrator.")); - return false; - } - - // Since I suck as a developer and I cannot implement a simple synchronous app call under Windows - // (QProcess does it somehow, but I'm too lazy to look it up and probably the solution wouldn't be compatible - // with our "privileges elevation" trick above... so after all I think we're stuck with this solution for now), - // I do the workaround here, which makes this process wait for the other process to create the "done" - // file when it's done, so this process knows when the other has ended. This way we can proceed with this - // process and we will delete some directories later on, which were required by that other process. - if (!waitForFileToDisappear(installFilePath, 10)) - { - staticUpdatingFailed(tr("Could not execute final updating steps as administrator. Updater startup timed out.")); - return false; - } - - if (!waitForFileToAppear(appDir + QLatin1Char('/') + WIN_UPDATE_DONE_FILE, 30)) - { - staticUpdatingFailed(tr("Could not execute final updating steps as administrator. Updater operation timed out.")); - return false; - } - - return true; -} -#endif - -#if defined(Q_OS_WIN32) -bool UpdateManager::executePostFinalStepWin(const QString &tempDir) -{ - QString doneFile = qApp->applicationDirPath() + QLatin1Char('/') + WIN_UPDATE_DONE_FILE; - QFile::remove(doneFile); - - QDir dir(tempDir); - dir.cdUp(); - if (!deleteDir(dir.absolutePath())) - staticUpdatingFailed(tr("Could not clean up temporary directory %1. You can delete it manually at any time.").arg(dir.absolutePath())); - - QProcess::startDetached(qApp->applicationFilePath(), QStringList()); - return true; -} - -bool UpdateManager::waitForFileToDisappear(const QString &filePath, int seconds) -{ - QFile file(filePath); - while (file.exists() && seconds > 0) - { - QThread::sleep(1); - seconds--; - } - - return !file.exists(); -} - -bool UpdateManager::waitForFileToAppear(const QString &filePath, int seconds) -{ - QFile file(filePath); - while (!file.exists() && seconds > 0) - { - QThread::sleep(1); - seconds--; - } - - return file.exists(); -} - -bool UpdateManager::runAnotherInstanceForUpdate(const QString &tempDir, const QString &backupDir, const QString &appDir, bool reqAdmin) -{ - bool res = QProcess::startDetached(tempDir + "/SQLiteStudio.exe", {WIN_PRE_FINAL_UPDATE_OPTION_NAME, tempDir, backupDir, appDir, - QString::number((int)reqAdmin)}); - if (!res) - { - updatingFailed(tr("Could not run new version for continuing update.")); - return false; - } - - return true; -} -#endif - -UpdateManager::LinuxPermElevator UpdateManager::findPermElevatorForLinux() -{ -#if defined(Q_OS_LINUX) - QProcess proc; - proc.setProgram("which"); - - if (!SQLITESTUDIO->getEnv("DISPLAY").isEmpty()) - { - proc.setArguments({"kdesu"}); - proc.start(); - if (waitForProcess(proc)) - return LinuxPermElevator::KDESU; - - proc.setArguments({"gksu"}); - proc.start(); - if (waitForProcess(proc)) - return LinuxPermElevator::GKSU; - } - - proc.setArguments({"pkexec"}); - proc.start(); - if (waitForProcess(proc)) - return LinuxPermElevator::PKEXEC; -#endif - - return LinuxPermElevator::NONE; -} - -QString UpdateManager::wrapCmdLineArgument(const QString& arg) -{ - return "\"" + escapeCmdLineArgument(arg) + "\""; -} - -QString UpdateManager::escapeCmdLineArgument(const QString& arg) -{ - if (!arg.contains("\\") && !arg.contains("\"")) - return arg; - - QString str = arg; - return str.replace("\\", "\\\\").replace("\"", "\\\""); -} - -QString UpdateManager::getBackupDir(const QString &appDir) -{ - static_qstring(bakDirTpl, "%1.old%2"); - QDir backupDir(bakDirTpl.arg(appDir, "")); - int cnt = 1; - while (backupDir.exists()) - backupDir = QDir(bakDirTpl.arg(appDir, QString::number(cnt))); - - return backupDir.absolutePath(); -} - -bool UpdateManager::unpackToDir(const QString& packagePath, const QString& outputDir) -{ -#if defined(Q_OS_LINUX) - return unpackToDirLinux(packagePath, outputDir); -#elif defined(Q_OS_WIN32) - return unpackToDirWin(packagePath, outputDir); -#elif defined(Q_OS_MACX) - return unpackToDirMac(packagePath, outputDir); -#else - qCritical() << "Unknown update platform in UpdateManager::unpackToDir() for package" << packagePath; - return false; -#endif -} - -#if defined(Q_OS_LINUX) -bool UpdateManager::unpackToDirLinux(const QString &packagePath, const QString &outputDir) -{ - QProcess proc; - proc.setWorkingDirectory(outputDir); - proc.setStandardOutputFile(QProcess::nullDevice()); - proc.setStandardErrorFile(QProcess::nullDevice()); - - if (!packagePath.endsWith("tar.gz")) - { - updatingFailed(tr("Package not in tar.gz format, cannot install: %1").arg(packagePath)); - return false; - } - - proc.start("mv", {packagePath, outputDir}); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Package %1 cannot be installed, because cannot move it to directory: %2").arg(packagePath, outputDir)); - return false; - } - - QString fileName = packagePath.split("/").last(); - QString newPath = outputDir + "/" + fileName; - proc.start("tar", {"-xzf", newPath}); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Package %1 cannot be installed, because cannot unpack it: %2").arg(packagePath, readError(proc))); - return false; - } - - QProcess::execute("rm", {"-f", newPath}); - return true; -} -#endif - -#if defined(Q_OS_MACX) -bool UpdateManager::unpackToDirMac(const QString &packagePath, const QString &outputDir) -{ - QProcess proc; - proc.setWorkingDirectory(outputDir); - proc.setStandardOutputFile(QProcess::nullDevice()); - proc.setStandardErrorFile(QProcess::nullDevice()); - - if (!packagePath.endsWith("zip")) - { - updatingFailed(tr("Package not in zip format, cannot install: %1").arg(packagePath)); - return false; - } - - proc.start("unzip", {"-o", "-d", outputDir, packagePath}); - if (!waitForProcess(proc)) - { - updatingFailed(tr("Package %1 cannot be installed, because cannot unzip it to directory %2: %3") - .arg(packagePath, outputDir, readError(proc))); - return false; - } - - return true; -} -#endif - -#if defined(Q_OS_WIN32) -bool UpdateManager::unpackToDirWin(const QString& packagePath, const QString& outputDir) -{ - if (JlCompress::extractDir(packagePath, outputDir + "/..").isEmpty()) - { - updatingFailed(tr("Package %1 cannot be installed, because cannot unzip it to directory: %2").arg(packagePath, outputDir)); - return false; - } - - return true; -} -#endif - -void UpdateManager::handleStaticFail(const QString& errMsg) -{ - emit updatingFailed(errMsg); -} - -QString UpdateManager::getAppDirPath() const -{ - static QString appDir; - if (appDir.isNull()) - { - appDir = qApp->applicationDirPath(); -#ifdef Q_OS_MACX - QDir tmpAppDir(appDir); - tmpAppDir.cdUp(); - tmpAppDir.cdUp(); - appDir = tmpAppDir.absolutePath(); -#endif - } - return appDir; -} - -bool UpdateManager::moveDir(const QString& src, const QString& dst, bool contentsOnly) -{ - // If we're doing a rename in the very same parent directory then we don't want - // the 'move between partitions' to be involved, cause any failure to rename - // is due to permissions or file lock. - QFileInfo srcFi(src); - QFileInfo dstFi(dst); - bool sameParentDir = (srcFi.dir() == dstFi.dir()); - - QDir dir; - if (contentsOnly) - { - QString localSrc; - QString localDst; - QDir srcDir(src); - for (const QFileInfo& entry : srcDir.entryInfoList(QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot|QDir::Hidden|QDir::System)) - { - localSrc = entry.absoluteFilePath(); - localDst = dst + "/" + entry.fileName(); - if (!dir.rename(localSrc, localDst) && (sameParentDir || !renameBetweenPartitions(localSrc, localDst))) - { - staticUpdatingFailed(tr("Could not rename directory %1 to %2.").arg(localSrc, localDst)); - return false; - } - } - } - else - { - if (!dir.rename(src, dst) && (sameParentDir || !renameBetweenPartitions(src, dst))) - { - staticUpdatingFailed(tr("Could not rename directory %1 to %2.").arg(src, dst)); - return false; - } - } - - return true; -} - -bool UpdateManager::deleteDir(const QString& path) -{ - QDir dir(path); - if (!dir.removeRecursively()) - { - staticUpdatingFailed(tr("Could not delete directory %1.").arg(path)); - return false; - } - - return true; -} - -bool UpdateManager::execCmd(const QString& cmd, const QStringList& args, QString* errorMsg) -{ - QProcess proc; - proc.start(cmd, args); - QString cmdString = QString("%1 \"%2\"").arg(cmd, args.join("\\\" \\\"")); - - if (!waitForProcess(proc)) - { - if (errorMsg) - *errorMsg = tr("Error executing update command: %1\nError message: %2").arg(cmdString).arg(readError(proc)); - - return false; - } - - return true; -} - -void UpdateManager::setRetryFunction(const RetryFunction &value) -{ - retryFunction = value; -} - -bool UpdateManager::doRequireAdminPrivileges() -{ - QString appDirPath = getAppDirPath(); - QDir appDir(appDirPath); - bool isWritable = isWritableRecursively(appDir.absolutePath()); - - appDir.cdUp(); - QFileInfo fi(appDir.absolutePath()); - isWritable &= fi.isWritable(); - - if (isWritable) - { - QDir backupDir(getBackupDir(appDirPath)); - QString backupDirName = backupDir.dirName(); - backupDir.cdUp(); - if (backupDir.mkdir(backupDirName)) - backupDir.rmdir(backupDirName); - else - isWritable = false; - } - - return !isWritable; -} - -void UpdateManager::finished(QNetworkReply* reply) -{ - if (reply == updatesCheckReply) - { - updatesCheckReply = nullptr; - handleAvailableUpdatesReply(reply); - return; - } - - if (reply == updatesGetUrlsReply) - { - updatesGetUrlsReply = nullptr; - handleUpdatesMetadata(reply); + if (results.trimmed().isEmpty()) { + emit noUpdatesAvailable(); return; } - if (reply == updatesGetReply) - { - handleDownloadReply(reply); - if (reply == updatesGetReply) // if no new download is requested - updatesGetReply = nullptr; + QRegularExpression re(R"(\]+)\>)"); + QRegularExpression versionRe(R"(version\=\"([\d\.]+)\")"); + QRegularExpression nameRe(R"(name\=\"([^\"]+)\")"); - return; - } -} - -void UpdateManager::handleDownloadReply(QNetworkReply* reply) -{ - if (reply->error() != QNetworkReply::NoError) + QRegularExpressionMatchIterator reIter = re.globalMatch(results); + QString updateNode; + UpdateEntry theUpdate; + QList updates; + while (reIter.hasNext()) { - updatingFailed(tr("An error occurred while downloading updates: %1. Updating aborted.").arg(reply->errorString())); - reply->deleteLater(); - return; + updateNode = reIter.next().captured(1); + theUpdate.version = versionRe.match(updateNode).captured(1); + theUpdate.compontent = nameRe.match(updateNode).captured(1); + updates << theUpdate; } - totalPercent = (totalDownloadsCount - updatesToDownload.size()) * 100 / (totalDownloadsCount + 1); - - readDownload(); - currentDownloadFile->close(); - - safe_delete(currentDownloadFile); - - reply->deleteLater(); - downloadUpdates(); -} - -void UpdateManager::downloadProgress(qint64 bytesReceived, qint64 totalBytes) -{ - int perc; - if (totalBytes < 0) - perc = -1; - else if (totalBytes == 0) - perc = 100; + if (updates.isEmpty()) + emit noUpdatesAvailable(); else - perc = bytesReceived * 100 / totalBytes; - - emit updatingProgress(currentJobTitle, perc, totalPercent); -} - -void UpdateManager::readDownload() -{ - currentDownloadFile->write(updatesGetReply->readAll()); + emit updatesAvailable(updates); } #endif // PORTABLE_CONFIG diff --git a/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.h b/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.h index bb33487..50f4b6b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/updatemanager.h @@ -18,122 +18,34 @@ class API_EXPORT UpdateManager : public QObject { Q_OBJECT public: - typedef std::function RetryFunction; - struct UpdateEntry { QString compontent; QString version; - QString url; }; explicit UpdateManager(QObject *parent = 0); ~UpdateManager(); - void checkForUpdates(bool force = false); + void checkForUpdates(); void update(); bool isPlatformEligibleForUpdate() const; - static bool executeFinalStep(const QString& tempDir, const QString& backupDir, const QString& appDir); - static bool handleUpdateOptions(const QStringList& argList, int& returnCode); - static QString getStaticErrorMessage(); - - static void setRetryFunction(const RetryFunction &value); - - static_char* UPDATE_OPTION_NAME = "--update-final-step"; - static_char* WIN_INSTALL_FILE = "install.dat"; - static_char* WIN_UPDATE_DONE_FILE = "UpdateFinished.lck"; private: - enum class LinuxPermElevator - { - KDESU, - GKSU, - PKEXEC, - NONE - }; + QString updateBinaryAbsolutePath; - QString getPlatformForUpdate() const; - QString getCurrentVersions() const; - void handleAvailableUpdatesReply(QNetworkReply* reply); - void handleDownloadReply(QNetworkReply* reply); - void getUpdatesMetadata(QNetworkReply*& replyStoragePointer, bool force = false); - void handleUpdatesMetadata(QNetworkReply* reply); - QList readMetadata(const QJsonDocument& doc); - void downloadUpdates(); - void updatingFailed(const QString& errMsg); - void installUpdates(); - bool installComponent(const QString& component, const QString& tempDir); - bool executeFinalStep(const QString& tempDir); - bool executeFinalStepAsRoot(const QString& tempDir, const QString& backupDir, const QString& appDir); -#if defined(Q_OS_LINUX) - bool executeFinalStepAsRootLinux(const QString& tempDir, const QString& backupDir, const QString& appDir); - bool unpackToDirLinux(const QString& packagePath, const QString& outputDir); -#elif defined(Q_OS_MACX) - bool unpackToDirMac(const QString& packagePath, const QString& outputDir); - bool executeFinalStepAsRootMac(const QString& tempDir, const QString& backupDir, const QString& appDir); -#elif defined(Q_OS_WIN32) - bool runAnotherInstanceForUpdate(const QString& tempDir, const QString& backupDir, const QString& appDir, bool reqAdmin); - bool unpackToDirWin(const QString& packagePath, const QString& outputDir); -#endif - bool doRequireAdminPrivileges(); - bool unpackToDir(const QString& packagePath, const QString& outputDir); - void handleStaticFail(const QString& errMsg); - QString getAppDirPath() const; - void cleanup(); - - static bool moveDir(const QString& src, const QString& dst, bool contentsOnly = false); - static bool deleteDir(const QString& path); - static bool execCmd(const QString& cmd, const QStringList& args, QString* errorMsg = nullptr); - static bool waitForProcess(QProcess& proc); - static QString readError(QProcess& proc, bool reverseOrder = false); - static void staticUpdatingFailed(const QString& errMsg); - static LinuxPermElevator findPermElevatorForLinux(); - static QString wrapCmdLineArgument(const QString& arg); - static QString escapeCmdLineArgument(const QString& arg); - static QString getBackupDir(const QString& appDir); -#if defined(Q_OS_WIN32) - static bool executePreFinalStepWin(const QString& tempDir, const QString& backupDir, const QString& appDir, bool reqAdmin); - static bool executeFinalStepAsRootWin(const QString& tempDir, const QString& backupDir, const QString& appDir); - static bool executePostFinalStepWin(const QString& tempDir); - static bool waitForFileToDisappear(const QString& filePath, int seconds); - static bool waitForFileToAppear(const QString& filePath, int seconds); -#endif - - QNetworkAccessManager* networkManager = nullptr; - QNetworkReply* updatesCheckReply = nullptr; - QNetworkReply* updatesGetUrlsReply = nullptr; - QNetworkReply* updatesGetReply = nullptr; - bool updatesInProgress = false; - QList updatesToDownload; - QHash updatesToInstall; - QTemporaryDir* tempDir = nullptr; - QFile* currentDownloadFile = nullptr; - int totalPercent = 0; - int totalDownloadsCount = 0; - QString currentJobTitle; - bool requireAdmin = false; - static RetryFunction retryFunction; - - static QString staticErrorMessage; - static_char* WIN_PRE_FINAL_UPDATE_OPTION_NAME = "--update-pre-final-step"; - static_char* WIN_POST_FINAL_UPDATE_OPTION_NAME = "--update-post-final-step"; - static_char* WIN_UPDATER_BINARY = "UpdateSQLiteStudio.exe"; - static_char* updateServiceUrl = "http://sqlitestudio.pl/updates3.rvt"; - static_char* manualUpdatesHelpUrl = "http://wiki.sqlitestudio.pl/index.php/User_Manual#Manual"; - - private slots: - void finished(QNetworkReply* reply); - void downloadProgress(qint64 bytesReceived, qint64 totalBytes); - void readDownload(); + void checkForUpdatesAsync(); + bool waitForProcess(QProcess& proc); + void processCheckResults(const QByteArray& results); signals: void updatesAvailable(const QList& updates); void noUpdatesAvailable(); - void updatingProgress(const QString& jobTitle, int jobPercent, int totalPercent); - void updatingFinished(); void updatingError(const QString& errorMessage); }; +Q_DECLARE_METATYPE(QList) + #define UPDATES SQLITESTUDIO->getUpdateManager() #endif // PORTABLE_CONFIG diff --git a/SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp b/SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp index 201dc8b..26e2d41 100644 --- a/SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/sqlhistorymodel.cpp @@ -5,7 +5,7 @@ SqlHistoryModel::SqlHistoryModel(Db* db, QObject *parent) : QueryModel(db, parent) { - static_char* query = "SELECT dbname, datetime(date, 'unixepoch'), (time_spent / 1000.0)||'s', rows, sql " + static_char* query = "SELECT id, dbname, datetime(date, 'unixepoch', 'localtime'), (time_spent / 1000.0)||'s', rows, sql " "FROM sqleditor_history ORDER BY date DESC"; setQuery(query); @@ -16,6 +16,8 @@ QVariant SqlHistoryModel::data(const QModelIndex& index, int role) const if (role == Qt::TextAlignmentRole && (index.column() == 2 || index.column() == 3)) return (int)(Qt::AlignRight|Qt::AlignVCenter); + QVariant d = QueryModel::data(index, role); + return QueryModel::data(index, role); } @@ -27,14 +29,16 @@ QVariant SqlHistoryModel::headerData(int section, Qt::Orientation orientation, i switch (section) { case 0: - return tr("Database", "sql history header"); + return ""; case 1: - return tr("Execution date", "sql history header"); + return tr("Database", "sql history header"); case 2: - return tr("Time spent", "sql history header"); + return tr("Execution date", "sql history header"); case 3: - return tr("Rows affected", "sql history header"); + return tr("Time spent", "sql history header"); case 4: + return tr("Rows affected", "sql history header"); + case 5: return tr("SQL", "sql history header"); } diff --git a/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp b/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp index 1e7863b..136ba03 100644 --- a/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp @@ -22,6 +22,7 @@ #include "services/impl/functionmanagerimpl.h" #include "services/impl/collationmanagerimpl.h" #include "services/impl/pluginmanagerimpl.h" +#include "services/impl/sqliteextensionmanagerimpl.h" #include "services/updatemanager.h" #include "impl/dbattacherimpl.h" #include "services/exportmanager.h" @@ -30,8 +31,8 @@ #include "plugins/scriptingsql.h" #include "plugins/importplugin.h" #include "plugins/populateplugin.h" -#include "services/bugreporter.h" #include "services/extralicensemanager.h" +#include "services/sqliteextensionmanager.h" #include "translations.h" #include #include @@ -39,7 +40,7 @@ DEFINE_SINGLETON(SQLiteStudio) -static const int sqlitestudioVersion = 30101; +static const int sqlitestudioVersion = 30201; SQLiteStudio::SQLiteStudio() { @@ -99,16 +100,6 @@ void SQLiteStudio::setUpdateManager(UpdateManager* value) } #endif -BugReporter* SQLiteStudio::getBugReporter() const -{ - return bugReporter; -} - -void SQLiteStudio::setBugReporter(BugReporter* value) -{ - bugReporter = value; -} - PopulateManager* SQLiteStudio::getPopulateManager() const { return populateManager; @@ -131,25 +122,37 @@ void SQLiteStudio::setCodeFormatter(CodeFormatter* codeFormatter) QString SQLiteStudio::getHomePage() const { - static const QString url = QStringLiteral("http://sqlitestudio.pl"); + static_qstring(url, "https://sqlitestudio.pl"); return url; } QString SQLiteStudio::getForumPage() const { - static const QString url = QStringLiteral("http://forum.sqlitestudio.pl"); + static_qstring(url, "https://forum.sqlitestudio.pl"); return url; } QString SQLiteStudio::getUserManualPage() const { - static const QString url = QStringLiteral("http://wiki.sqlitestudio.pl/index.php/User_Manual"); + static_qstring(url, "https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual"); return url; } QString SQLiteStudio::getSqliteDocsPage() const { - static const QString url = QStringLiteral("http://sqlite.org/lang.html"); + static_qstring(url, "http://sqlite.org/lang.html"); + return url; +} + +QString SQLiteStudio::getIssuesPage() const +{ + static_qstring(url, "https://github.com/pawelsalawa/sqlitestudio/issues"); + return url; +} + +QString SQLiteStudio::getNewIssuePage() const +{ + static_qstring(url, "https://github.com/pawelsalawa/sqlitestudio/issues/new"); return url; } @@ -198,6 +201,17 @@ void SQLiteStudio::setCollationManager(CollationManager* value) collationManager = value; } +SqliteExtensionManager* SQLiteStudio::getSqliteExtensionManager() const +{ + return extensionManager; +} + +void SQLiteStudio::setSqliteExtensionManager(SqliteExtensionManager* value) +{ + safe_delete(extensionManager); + extensionManager = value; +} + DbAttacherFactory* SQLiteStudio::getDbAttacherFactory() const { return dbAttacherFactory; @@ -305,6 +319,7 @@ void SQLiteStudio::init(const QStringList& cmdListArguments, bool guiAvailable) functionManager = new FunctionManagerImpl(); collationManager = new CollationManagerImpl(); + extensionManager = new SqliteExtensionManagerImpl(); cmdLineArgs = cmdListArguments; @@ -320,7 +335,6 @@ void SQLiteStudio::init(const QStringList& cmdListArguments, bool guiAvailable) exportManager = new ExportManager(); importManager = new ImportManager(); populateManager = new PopulateManager(); - bugReporter = new BugReporter(); #ifdef PORTABLE_CONFIG updateManager = new UpdateManager(); #endif @@ -331,7 +345,7 @@ void SQLiteStudio::init(const QStringList& cmdListArguments, bool guiAvailable) extraLicenseManager->addLicense("Qt, QHexEdit (LGPL v2.1)", ":/docs/licenses/lgpl.txt"); extraLicenseManager->addLicense("diff_match (Apache License v2.0)", ":/docs/licenses/diff_match.txt"); extraLicenseManager->addLicense("RSA library (GPL v3)", ":/docs/licenses/gpl.txt"); - + extraLicenseManager->addLicense("SingleApplication (The MIT License)", ":/docs/licenses/mit.txt"); } void SQLiteStudio::initPlugins() @@ -345,6 +359,7 @@ void SQLiteStudio::initPlugins() void SQLiteStudio::cleanUp() { + emit aboutToQuit(); disconnect(pluginManager, SIGNAL(aboutToUnload(Plugin*,PluginType*)), this, SLOT(pluginToBeUnloaded(Plugin*,PluginType*))); disconnect(pluginManager, SIGNAL(unloaded(QString,PluginType*)), this, SLOT(pluginUnloaded(QString,PluginType*))); if (!immediateQuit) @@ -356,7 +371,6 @@ void SQLiteStudio::cleanUp() #ifdef PORTABLE_CONFIG safe_delete(updateManager); #endif - safe_delete(bugReporter); safe_delete(populateManager); safe_delete(importManager); safe_delete(exportManager); diff --git a/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h b/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h index 0b58b17..5cd3118 100644 --- a/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h +++ b/SQLiteStudio3/coreSQLiteStudio/sqlitestudio.h @@ -24,11 +24,11 @@ class ExportManager; class ImportManager; class PopulateManager; class PluginLoadingHandler; -class BugReporter; #ifdef PORTABLE_CONFIG class UpdateManager; #endif class ExtraLicenseManager; +class SqliteExtensionManager; /** @file */ @@ -117,6 +117,9 @@ class API_EXPORT SQLiteStudio : public QObject CollationManager* getCollationManager() const; void setCollationManager(CollationManager* value); + SqliteExtensionManager* getSqliteExtensionManager() const; + void setSqliteExtensionManager(SqliteExtensionManager* value); + ExportManager* getExportManager() const; void setExportManager(ExportManager* value); @@ -132,13 +135,12 @@ class API_EXPORT SQLiteStudio : public QObject CodeFormatter* getCodeFormatter() const; void setCodeFormatter(CodeFormatter* codeFormatter); - BugReporter* getBugReporter() const; - void setBugReporter(BugReporter* value); - QString getHomePage() const; QString getForumPage() const; QString getUserManualPage() const; QString getSqliteDocsPage() const; + QString getIssuesPage() const; + QString getNewIssuePage() const; #ifdef PORTABLE_CONFIG UpdateManager* getUpdateManager() const; @@ -200,10 +202,10 @@ class API_EXPORT SQLiteStudio : public QObject PluginManager* pluginManager = nullptr; DbAttacherFactory* dbAttacherFactory = nullptr; CollationManager* collationManager = nullptr; + SqliteExtensionManager* extensionManager = nullptr; ExportManager* exportManager = nullptr; ImportManager* importManager = nullptr; PopulateManager* populateManager = nullptr; - BugReporter* bugReporter = nullptr; #ifdef PORTABLE_CONFIG UpdateManager* updateManager = nullptr; #endif @@ -238,6 +240,9 @@ class API_EXPORT SQLiteStudio : public QObject * Doesn't change list of available formatters, but reads new selected formatters from config. */ void updateCurrentCodeFormatter(); + + signals: + void aboutToQuit(); }; /** @@ -259,7 +264,7 @@ class API_EXPORT SQLiteStudio : public QObject void someFunction() { QList dblist = SQLITESTUDIO->getDbManager()->getDbList(); - foreach (Db* db, dblist) + for (Db* db : dblist) { qOut << db->getName(); } diff --git a/SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp b/SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp index 9c14f63..3558ec1 100644 --- a/SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/tablemodifier.cpp @@ -89,7 +89,7 @@ void TableModifier::copyDataTo(const QString& targetTable) SchemaResolver resolver(db); QStringList targetColumns = resolver.getTableColumns(targetTable); QStringList colsToCopy; - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) if (targetColumns.contains(column->name, Qt::CaseInsensitive)) colsToCopy << wrapObjIfNeeded(column->name, dialect); @@ -299,30 +299,79 @@ bool TableModifier::handleUpdateColumns(SqliteUpdate* update) { bool modified = false; QString lowerName; + QVariant colName; + QString newName; + QStringList newNames; QMutableListIterator it(update->keyValueMap); while (it.hasNext()) { it.next(); - // If column was modified, assign new name - lowerName = it.value().first.toLower(); - if (tableColMap.contains(lowerName)) + colName = it.value().first; + if (colName.type() == QVariant::StringList) { - it.value().first = tableColMap[lowerName]; - modified = true; + // List of columns set to a single value + newNames = handleUpdateColumns(colName.toStringList(), modified); + if (!modified) + continue; + + if (newNames.isEmpty()) + { + it.remove(); + continue; + } + + // If any column was modified, assign new list + it.value().first = newNames; continue; } - // It wasn't modified, but it's not on existing columns list? Remove it. - if (indexOf(existingColumns, it.value().first, Qt::CaseInsensitive) == -1) + // Single column case + newName = handleUpdateColumn(colName.toString(), modified); + if (!modified) + continue; + + if (newName.isNull()) { it.remove(); - modified = true; + continue; } + + // If column was modified, assign new name + it.value().first = newName; } return modified; } +QStringList TableModifier::handleUpdateColumns(const QStringList& colNames, bool& modified) +{ + QStringList newNames; + for (const QString& colName : colNames) + newNames << handleUpdateColumn(colName, modified); + + return newNames; +} + +QString TableModifier::handleUpdateColumn(const QString& colName, bool& modified) +{ + // If column was modified, assign new name + QString lowerName = colName.toLower(); + if (tableColMap.contains(lowerName)) + { + modified = true; + return tableColMap[lowerName]; + } + + // It wasn't modified, but it's not on existing columns list? Remove it. + if (indexOf(existingColumns, colName, Qt::CaseInsensitive) == -1) + { + modified = true; + return QString(); + } + + return colName; +} + QStringList TableModifier::getModifiedViews() const { return modifiedViews; @@ -354,7 +403,7 @@ void TableModifier::copyDataTo(SqliteCreateTablePtr newCreateTable) QStringList srcCols; QStringList dstCols; - foreach (SqliteCreateTable::Column* column, newCreateTable->columns) + for (SqliteCreateTable::Column* column : newCreateTable->columns) { if (!existingColumns.contains(column->originalName)) continue; // not copying columns that didn't exist before @@ -370,7 +419,7 @@ void TableModifier::handleIndexes() { SchemaResolver resolver(db); QList parsedIndexesForTable = resolver.getParsedIndexesForTable(originalTable); - foreach (SqliteCreateIndexPtr index, parsedIndexesForTable) + for (SqliteCreateIndexPtr index : parsedIndexesForTable) handleIndex(index); } @@ -396,14 +445,18 @@ void TableModifier::handleTriggers() { SchemaResolver resolver(db); QList parsedTriggersForTable = resolver.getParsedTriggersForTable(originalTable, true); - foreach (SqliteCreateTriggerPtr trig, parsedTriggersForTable) + for (SqliteCreateTriggerPtr trig : parsedTriggersForTable) handleTrigger(trig); } void TableModifier::handleTrigger(SqliteCreateTriggerPtr trigger) { - trigger->rebuildTokens(); - QString originalQueryString = trigger->detokenize(); + // Cloning trigger (to avoid overwritting tokensMap when rebuilding tokens) + // and determining query string before it's modified by this method. + SqliteCreateTrigger* triggerClone = dynamic_cast(trigger->clone()); + triggerClone->rebuildTokens(); + QString originalQueryString = triggerClone->detokenize(); + delete triggerClone; bool forThisTable = (originalTable.compare(trigger->table, Qt::CaseInsensitive) == 0); bool alreadyProcessedOnce = modifiedTriggers.contains(trigger->trigger, Qt::CaseInsensitive); @@ -465,7 +518,7 @@ void TableModifier::handleTriggerQueries(SqliteCreateTriggerPtr trigger) { SqliteQuery* newQuery = nullptr; QList newQueries; - foreach (SqliteQuery* query, trigger->queries) + for (SqliteQuery* query : trigger->queries) { // The handleTriggerQuery() may delete the input query object. Don't refer to it later. newQuery = handleTriggerQuery(query, trigger->trigger, trigger->table); @@ -481,7 +534,7 @@ void TableModifier::handleViews() { SchemaResolver resolver(db); QList parsedViewsForTable = resolver.getParsedViewsForTable(originalTable); - foreach (SqliteCreateViewPtr view, parsedViewsForTable) + for (SqliteCreateViewPtr view : parsedViewsForTable) handleView(view); } @@ -550,7 +603,7 @@ SqliteSelect* TableModifier::handleSelect(SqliteSelect* select, const QString& t resolvedTables = tablesAsNameHash(selectResolver.resolveTables(core)); tableTokens = core->getContextTableTokens(false); - foreach (TokenPtr token, tableTokens) + for (TokenPtr token : tableTokens) { if (token->value.compare(originalTable, Qt::CaseInsensitive) != 0) continue; @@ -623,7 +676,7 @@ bool TableModifier::isTableAliasUsedForColumn(const TokenPtr &token, const StrHa if (table.tableAlias.isNull()) return false; - if (table.tableAlias.compare(token->value), Qt::CaseInsensitive != 0) + if (table.tableAlias.compare(token->value, Qt::CaseInsensitive) != 0) return false; // If the table token is mentioned in FROM clause, it's not a subject for aliased usage, cuase it defines alias, not uses it. @@ -708,7 +761,7 @@ bool TableModifier::handleSubSelects(SqliteStatement* stmt, const QString& trigT bool embedSelectsOk = true; QList selects = stmt->getAllTypedStatements(); SqliteExpr* expr = nullptr; - foreach (SqliteSelect* select, selects) + for (SqliteSelect* select : selects) { if (select->coreSelects.size() >= 1 && select->coreSelects.first()->valuesMode) { @@ -842,7 +895,7 @@ void TableModifier::simpleHandleIndexes() { SchemaResolver resolver(db); QList parsedIndexesForTable = resolver.getParsedIndexesForTable(originalTable); - foreach (SqliteCreateIndexPtr index, parsedIndexesForTable) + for (SqliteCreateIndexPtr index : parsedIndexesForTable) sqls << index->detokenize(); } @@ -855,7 +908,7 @@ void TableModifier::simpleHandleTriggers(const QString& view) else parsedTriggers = resolver.getParsedTriggersForTable(originalTable); - foreach (SqliteCreateTriggerPtr trig, parsedTriggers) + for (SqliteCreateTriggerPtr trig : parsedTriggers) sqls << trig->detokenize(); } diff --git a/SQLiteStudio3/coreSQLiteStudio/tablemodifier.h b/SQLiteStudio3/coreSQLiteStudio/tablemodifier.h index cba27ed..7be5a2a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/tablemodifier.h +++ b/SQLiteStudio3/coreSQLiteStudio/tablemodifier.h @@ -82,6 +82,8 @@ class API_EXPORT TableModifier bool handleColumnNames(QStringList& columnsToUpdate); bool handleColumnTokens(TokenList& columnsToUpdate); bool handleUpdateColumns(SqliteUpdate* update); + QStringList handleUpdateColumns(const QStringList& colNames, bool& modified); + QString handleUpdateColumn(const QString& colName, bool& modified); template diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.qm index 2c10fb5..29cc169 100644 Binary files a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.qm and b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.qm differ diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.ts index 7467fa1..803f815 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_de.ts @@ -4,13 +4,13 @@ AbstractDb - - + + Cannot execute query on closed database. Die Abfrage kann nicht auf einer ungeöffneten Datenbank ausgeführt werden. - + Error attaching database %1: %2 Fehler beim Anhängen der Datenbank %1: %2 @@ -18,9 +18,8 @@ BugReporter - Invalid login or password - Ungültiger Nutzername oder Passwort + Ungültiger Nutzername oder Passwort @@ -146,38 +145,51 @@ Datenbank für temporäre Objekte + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + DbManagerImpl - + Could not add database %1: %2 Die Datenbank %1 kann nicht hinzugefügt werden: %2 - + Database %1 could not be updated, because of an error: %2 Die Datenbank %1 kann nicht aktualisiert werden. Grund: %2 - - + + Database file doesn't exist. Die Datenbankdatei existiert nicht. - - - + + + No supporting plugin loaded. Es wurde kein passendes plugin geladen. - + Database could not be initialized. Die Datenbank kann nicht initialisiert werden. - + No suitable database driver plugin found. Es wurde kein passender Datenbanktreiber (plugin) gefunden. @@ -245,17 +257,17 @@ Tabellen, Indizes, Trigger und Views die in Datenbank %3 kopiert wurden, werden DbVersionConverter - + Target file exists, but could not be overwritten. Die Zieldatei existiert zwar, konnte aber nicht überschrieben werden. - + Could not find proper database plugin to create target database. Es konnte kein geeignetes Datenbankplugin gefunden werden, um die Zieldatenbank zu erzeugen. - + Error while converting database: %1 Fehler beim Konvertieren der Datenbank: %1 @@ -459,20 +471,20 @@ Tabellen, Indizes, Trigger und Views die in Datenbank %3 kopiert wurden, werden - - + + Error while importing data: %1 Fehler beim Import der Daten: %1 - + Interrupted. import process status update Abgebrochen. - + Could not import data row number %1. The row was ignored. Problem details: %2 Datenzeile %1 konnte nicht importiert werden. Die Zeile wurde ignoriert. Problembeschreibung: %2 @@ -768,12 +780,12 @@ Tabellen, Indizes, Trigger und Views die in Datenbank %3 kopiert wurden, werden Es kann keine Transaktion zum Füllen der Tabelle gestartet werden. Problembeschreibung: %1 - + Error while populating table: %1 Fehler beim Füllen der Tabelle: %1 - + Could not commit transaction after table populating. Error details: %1 Die Transaktion zum Füllen der Tabelle kann nicht 'committet' werden. Problembeschreibung: %1 @@ -781,72 +793,78 @@ Tabellen, Indizes, Trigger und Views die in Datenbank %3 kopiert wurden, werden QObject - - + + Could not open database: %1 Die Datenbank %1 kann nicht geöffnet werden. - - + + Result set expired or no row available. Das Abfrageergebniss ist ungültig oder es ist keine Datenzeile verfügbar. - + + + Could not load extension %1: %2 + + + + Could not close database: %1 Die Datenbank %1 kann nicht geschlossen werden. - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. SQLite %1 unterstützt keine '%2' Abfrage. - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. SQLite %1 unterstützt keine '%2' Abfrage, aber die normale Tabelle kann stattdessen erzeugt werden, wenn Sie fortfahren. - + Could not parse statement: %1 Error details: %2 Die Abfrage kann nicht verarbeitet werden: %1 Problembeschreibung: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. SQLite %1 unterstützt keine '%2' Klausel. Die %3 Abfrage kann mit dieser Klausel nicht konvertiert werden. - + SQLite %1 does not support the '%2' clause in the '%3' statement. SQLite %1 unterstützt keine '%2' Klausel in der %3 Abfrage. - + SQLite %1 does not support current date or time clauses in expressions. SQLite %1 unterstützt keine current date' oder 'time' Klauseln in Ausdrücken. - + SQLite %1 does not support row value clauses in expressions. - - - + + + SQLite %1 does not support '%2' clause in expressions. SQLite %1 unterstützt keine '%2' Klausel Ausdrücken. @@ -864,13 +882,13 @@ Problembeschreibung: %2 - + Parser stack overflow Stacküberlauf bei Verarbeitung - + Syntax error Syntaxfehler @@ -925,59 +943,59 @@ Problembeschreibung: %2 Der Implementationscode darf nicht leer sein. - + Could not resolve data source for column: %1 Die Datenquelle für Spalte %1 kann nicht aufgelöst werden. - + Could not resolve table for column '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. Ich hoffe, dass ich "to initialize" hier richtig mit "erstellt" übersetzt habe. Die Konfigurationsdatei kann nicht erstellt werden. Alle Änderungen an der Konfiguration sowie die Abfragehistorie sind nach einem Programmneustart verloren. Es wurde versucht die Konfigurationsdatei in folgendem Verzeichnis zu erstellen: %1 - + General purpose plugin category name Allgemeine Verwendung - + Database support plugin category name Datenbankunterstützung - + Code formatter plugin category name Codeformatierer - + Scripting languages plugin category name Skriptsprachen - + Exporting plugin category name Exportieren - + Importing plugin category name Importieren - + Table populating plugin category name Tabellen füllen @@ -988,34 +1006,34 @@ Problembeschreibung: %2 Tabelle %1 referenziert Tabelle %2, jedoch wird die 'foreign key'-Definition für die neue Tabellendefinition nicht aktualisiert, da es Probleme bei der DDL-Analyse von Tabelle %3 gibt. - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. Alle Spalten, die von Index %1 indiziert wurden, sind verloren. Der Index wird nach der Tabellenmodifikation nicht neu erstellt. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. Es ist ein Problem bei der korrekten Verarbeitung des Triggers %1 aufgetreten. Er wird möglicherweise nicht vollständig aktualisert werden und sollte geprüft werden. - + Cannot not update trigger %1 according to table %2 modification. Die Aktualisierung des Triggers %1, resultierend aus der Änderung der Tabelle %2, kann nicht ausgeführt werden. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. Es ist ein Problem beim Aktualisieren einer %1 Abfrage innerhalb eines %2 Triggers aufgetreten. Eine der %1 Unterabfragen, welche möglicherweise die Tabelle %3 referenziert, kann nicht geändert werden. Eine manuelle Anpassung des Triggers wird nötig sein. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. Alle Spalten, die durch den Trigger %1 abgedeckt wurden, sind verloren. Der Trigger wird nach der Änderung nicht wiederhergestellt. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. Die Aktualisierung des Views %1, resultierend aus der Änderung der Tabelle %2, kann nicht ausgeführt werden. Der View wird daher nicht geändert. @@ -1035,33 +1053,38 @@ The view will remain as it is. SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. SQLiteStudio konnte die vom View zurückgegebenen Spalten nicht auflösen, daher kann nicht ermittelt werden, welcher Trigger beim Wiederherstelllungsprozess einen Fehler verusracht haben könnte. + + + Could not open file '%1' for reading: %2 + + QueryExecutor - + Execution interrupted. Ausführung abgebrochen. - + Database is not open. Die Datenbank ist nicht geöffnet. - + Only one query can be executed simultaneously. Es kann nur eine Abfrage gleichzeitig ausgeführt werden. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 Hier muss ggf. noch das 'data paging' korrekt übersetzt werden. Beim Ausführen der count(*) Abfrage ist ein Fehler aufgetreten, daher wird das data paging abgeschaltet. Problemdetails der Datenbank: %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. SQLiteStudio konnte keine Metadaten aus der Abfrage extrahieren. Die Ergebnismenge kann daher nicht editiert werden. @@ -1082,31 +1105,31 @@ The view will remain as it is. SqlHistoryModel - + Database sql history header Datenbank - + Execution date sql history header Ausführungsdatum - + Time spent sql history header Dauer - + Rows affected sql history header Anzahl Zeilen - + SQL sql history header SQL @@ -1115,204 +1138,183 @@ The view will remain as it is. UpdateManager - An error occurred while checking for updates: %1. - Beim Prüfen auf Updates trat folgender Fehler auf: %1. + Beim Prüfen auf Updates trat folgender Fehler auf: %1. - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - Es konnte nicht auf neue Updates geprüft werden, da der Updateserver in einem ungültigen Nachrichtenformat antwortet. Diese Meldung kann gefahrlos ignoriert werden. + Es konnte nicht auf neue Updates geprüft werden, da der Updateserver in einem ungültigen Nachrichtenformat antwortet. Diese Meldung kann gefahrlos ignoriert werden. - An error occurred while reading updates metadata: %1. - Beim Lesen der Update-Metadaten ist ein Fehler aufgetreten: %1. + Beim Lesen der Update-Metadaten ist ein Fehler aufgetreten: %1. - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - Das Update konnte nicht heruntergeladen werden, da der Updateserver in einem ungültigen Nachrichtenformat antwortet. Sie können es später noch einmal versuchen oder das Update und die Installation manuell ausführen. Weitere Infoamtionen hierzu finden Sie in der <a href="%1">Programmdokumentation</a>. + Das Update konnte nicht heruntergeladen werden, da der Updateserver in einem ungültigen Nachrichtenformat antwortet. Sie können es später noch einmal versuchen oder das Update und die Installation manuell ausführen. Weitere Infoamtionen hierzu finden Sie in der <a href="%1">Programmdokumentation</a>. - Could not create temporary directory for downloading the update. Updating aborted. - Das temporäre Verzeichnis zum Herunterladen des Updates konnte nicht erstellt werden. Der Updatevorgang wird abgebrochen. + Das temporäre Verzeichnis zum Herunterladen des Updates konnte nicht erstellt werden. Der Updatevorgang wird abgebrochen. - There was no updates to download. Updating aborted. - Keine neuen Updates vorhanden. Der Updatevorgang wird beendet. + Keine neuen Updates vorhanden. Der Updatevorgang wird beendet. - Downloading: %1 - Herunterladen von: %1 + Herunterladen von: %1 - Could not determinate file name from update URL: %1. Updating aborted. - Der Dateiname der Update-URL %1 konnte nicht ermittelt werden. Der Updatevorgang wird abgebrochen. + Der Dateiname der Update-URL %1 konnte nicht ermittelt werden. Der Updatevorgang wird abgebrochen. - Failed to open file '%1' for writting: %2. Updating aborted. - Beim Schreiben in die Datei '%1' trat folgender Fehler auf: %2. Der Updatevorgang wird abgebrochen. + Beim Schreiben in die Datei '%1' trat folgender Fehler auf: %2. Der Updatevorgang wird abgebrochen. - Installing updates. - Update wird installiert. + Update wird installiert. - Could not copy current application directory into %1 directory. - Das aktuelle Programmverzeichnis konnte nicht in das Verzeichnis %1 kopiert werden. + Das aktuelle Programmverzeichnis konnte nicht in das Verzeichnis %1 kopiert werden. - Could not create directory %1. - Das Verzeichnis %1 konnte nicht erstellt werden. + Das Verzeichnis %1 konnte nicht erstellt werden. - Could not rename directory %1 to %2. Details: %3 - Das Verzeichnis %1 konnte nicht in %2 umbenannt werden. + Das Verzeichnis %1 konnte nicht in %2 umbenannt werden. Details: %3 - Cannot not rename directory %1 to %2. Details: %3 - Das Verzeichnis %1 kann nicht in %2 umbenannt werden. + Das Verzeichnis %1 kann nicht in %2 umbenannt werden. Details: %3 - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - Das Verzeichnis %1 konnte nicht nach %2 verschoben werden. Ebenso schlug das Wiederherstellen des originalen Verzeichnissses fehlt, daher befindet sich das SQLiteStudio Verzeichnis nun hier: %3 + Das Verzeichnis %1 konnte nicht nach %2 verschoben werden. Ebenso schlug das Wiederherstellen des originalen Verzeichnissses fehlt, daher befindet sich das SQLiteStudio Verzeichnis nun hier: %3 - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - Das Das Verzeichnis %1 konnte nicht nach %2 umbenannt werden.SQLiteStudio wird auf den Ursprungszustand zurückgesetzt. + Das Das Verzeichnis %1 konnte nicht nach %2 umbenannt werden.SQLiteStudio wird auf den Ursprungszustand zurückgesetzt. - Could not unpack component %1 into %2 directory. - Die Komponente %1 konnte nicht in das Verzeichnis %2 extrahiert werden. + Die Komponente %1 konnte nicht in das Verzeichnis %2 extrahiert werden. - Could not find permissions elevator application to run update as a root. Looked for: %1 - Die Rechteerweiterung zum Ausführen des Updates als 'root' konnte nicht gefunden werden. Es wurde gesucht nach: %1 + Die Rechteerweiterung zum Ausführen des Updates als 'root' konnte nicht gefunden werden. Es wurde gesucht nach: %1 - Could not execute final updating steps as root: %1 - Die abschließenden Aktualisierungsschritte konnten nicht als 'root' ausgeführt werden: %1 + Die abschließenden Aktualisierungsschritte konnten nicht als 'root' ausgeführt werden: %1 - - - - Could not execute final updating steps as admin: %1 - Die abschließenden Aktualisierungsschritte konnten nicht als 'admin' ausgeführt werden: %1 + Die abschließenden Aktualisierungsschritte konnten nicht als 'admin' ausgeführt werden: %1 - Cannot create temporary directory for updater. - Das temporäre Verzeichnis für den Updater konnte nicht erstellt werden. + Das temporäre Verzeichnis für den Updater konnte nicht erstellt werden. - Cannot create updater script file. - Die Skriptdatei für den Updater konnte nicht erstellt werden. + Die Skriptdatei für den Updater konnte nicht erstellt werden. - Updating canceled. - Updatevorgang abgebrochen. + Updatevorgang abgebrochen. - Could not execute final updating steps as administrator. - Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. + Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. - Could not execute final updating steps as administrator. Updater startup timed out. - Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. Die Updatevorbereitungen liefen auf Zeitüberschreitung. + Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. Die Updatevorbereitungen liefen auf Zeitüberschreitung. - Could not execute final updating steps as administrator. Updater operation timed out. - Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. Der Updatevorgang lief auf Zeitüberschreitung. + Die abschließenden Aktualisierungsschritte konnten nicht als 'administrator' ausgeführt werden. Der Updatevorgang lief auf Zeitüberschreitung. - Could not clean up temporary directory %1. You can delete it manually at any time. - Das temporäre Verzeichnis %1 konnte nicht aufgeräumt werden. Sie können es später manuell löschen. + Das temporäre Verzeichnis %1 konnte nicht aufgeräumt werden. Sie können es später manuell löschen. - Could not run new version for continuing update. - Die neue Version zum Fortführen des Updates kann nicht gestartet werden. + Die neue Version zum Fortführen des Updates kann nicht gestartet werden. - Package not in tar.gz format, cannot install: %1 - Das Paket liegt nicht im tar.gz Format vor. %1 kann nicht installiert werden. + Das Paket liegt nicht im tar.gz Format vor. %1 kann nicht installiert werden. - Package %1 cannot be installed, because cannot move it to directory: %2 - Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2 verschoben werden kann. + Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2 verschoben werden kann. - Package %1 cannot be installed, because cannot unpack it: %2 - Das Paket %1 kann nicht installiert werden, weil es nicht extrahiert werden kann: %2 + Das Paket %1 kann nicht installiert werden, weil es nicht extrahiert werden kann: %2 - Package not in zip format, cannot install: %1 - Das Paket liegt nicht im zip Format vor. %1 kann nicht installiert werden. + Das Paket liegt nicht im zip Format vor. %1 kann nicht installiert werden. - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 - Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2: %3 extrahiert werden kann. + Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2: %3 extrahiert werden kann. - Package %1 cannot be installed, because cannot unzip it to directory: %2 - Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2 entzippt werden kann. + Das Paket %1 kann nicht installiert werden, weil es nicht in das Verzeichnis %2 entzippt werden kann. - - Could not rename directory %1 to %2. - Das Verzeichnis %1 konnte nicht in %2 umbenannt werden. + Das Verzeichnis %1 konnte nicht in %2 umbenannt werden. - Could not delete directory %1. - Das Verzeichnis %1 konnte nicht gelöscht werden. + Das Verzeichnis %1 konnte nicht gelöscht werden. - Error executing update command: %1 Error message: %2 - Fehler beim Ausführen des Updatekommandos %1. + Fehler beim Ausführen des Updatekommandos %1. Fehlerbeschreibung: %2 - An error occurred while downloading updates: %1. Updating aborted. - Beim Herunterladen des Updates %1 ist ein fehelr aufgetreten. Der Updatevorgang wurde abgebrochen. + Beim Herunterladen des Updates %1 ist ein fehelr aufgetreten. Der Updatevorgang wurde abgebrochen. + + + + Updates installer executable is missing. + + + + + + Unable to check for updates (%1) + + + + + details are unknown + + + + + Unable to run updater application (%1). Please report this. + diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_es.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_es.ts index 007c39b..f0c170b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_es.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_es.ts @@ -4,25 +4,17 @@ AbstractDb - - + + Cannot execute query on closed database. - + Error attaching database %1: %2 - - BugReporter - - - Invalid login or password - - - ChainExecutor @@ -145,38 +137,51 @@ + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + DbManagerImpl - + Could not add database %1: %2 - + Database %1 could not be updated, because of an error: %2 - - + + Database file doesn't exist. - - - + + + No supporting plugin loaded. - + Database could not be initialized. - + No suitable database driver plugin found. @@ -243,17 +248,17 @@ Tables, indexes, triggers and views copied to database %3 will remain. DbVersionConverter - + Target file exists, but could not be overwritten. - + Could not find proper database plugin to create target database. - + Error while converting database: %1 @@ -456,20 +461,20 @@ Tables, indexes, triggers and views copied to database %3 will remain. - - + + Error while importing data: %1 - + Interrupted. import process status update - + Could not import data row number %1. The row was ignored. Problem details: %2 @@ -763,12 +768,12 @@ Tables, indexes, triggers and views copied to database %3 will remain. - + Error while populating table: %1 - + Could not commit transaction after table populating. Error details: %1 @@ -776,71 +781,77 @@ Tables, indexes, triggers and views copied to database %3 will remain. QObject - - + + Could not open database: %1 - - + + Result set expired or no row available. - + + + Could not load extension %1: %2 + + + + Could not close database: %1 - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. - + Could not parse statement: %1 Error details: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. - + SQLite %1 does not support the '%2' clause in the '%3' statement. - + SQLite %1 does not support current date or time clauses in expressions. - + SQLite %1 does not support row value clauses in expressions. - - - + + + SQLite %1 does not support '%2' clause in expressions. @@ -857,13 +868,13 @@ Error details: %2 - + Parser stack overflow - + Syntax error @@ -918,58 +929,58 @@ Error details: %2 - + Could not resolve data source for column: %1 - + Could not resolve table for column '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. - + General purpose plugin category name - + Database support plugin category name - + Code formatter plugin category name - + Scripting languages plugin category name - + Exporting plugin category name - + Importing plugin category name - + Table populating plugin category name @@ -980,34 +991,34 @@ Error details: %2 - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. - + Cannot not update trigger %1 according to table %2 modification. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. @@ -1027,32 +1038,37 @@ The view will remain as it is. SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. + + + Could not open file '%1' for reading: %2 + + QueryExecutor - + Execution interrupted. - + Database is not open. - + Only one query can be executed simultaneously. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. @@ -1073,31 +1089,31 @@ The view will remain as it is. SqlHistoryModel - + Database sql history header - + Execution date sql history header - + Time spent sql history header - + Rows affected sql history header - + SQL sql history header @@ -1106,200 +1122,24 @@ The view will remain as it is. UpdateManager - - An error occurred while checking for updates: %1. - - - - - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - - - - - An error occurred while reading updates metadata: %1. - - - - - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - - - - - Could not create temporary directory for downloading the update. Updating aborted. - - - - - There was no updates to download. Updating aborted. - - - - - Downloading: %1 - - - - - Could not determinate file name from update URL: %1. Updating aborted. - - - - - Failed to open file '%1' for writting: %2. Updating aborted. - - - - - Installing updates. - - - - - Could not copy current application directory into %1 directory. - - - - - Could not create directory %1. - - - - - Could not rename directory %1 to %2. -Details: %3 - - - - - Cannot not rename directory %1 to %2. -Details: %3 - - - - - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - - - - - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - - - - - Could not unpack component %1 into %2 directory. - - - - - Could not find permissions elevator application to run update as a root. Looked for: %1 - - - - - Could not execute final updating steps as root: %1 - - - - - - - - Could not execute final updating steps as admin: %1 - - - - - Cannot create temporary directory for updater. - - - - - Cannot create updater script file. - - - - - Updating canceled. - - - - - Could not execute final updating steps as administrator. - - - - - Could not execute final updating steps as administrator. Updater startup timed out. - - - - - Could not execute final updating steps as administrator. Updater operation timed out. - - - - - Could not clean up temporary directory %1. You can delete it manually at any time. - - - - - Could not run new version for continuing update. - - - - - Package not in tar.gz format, cannot install: %1 - - - - - Package %1 cannot be installed, because cannot move it to directory: %2 - - - - - Package %1 cannot be installed, because cannot unpack it: %2 - - - - - Package not in zip format, cannot install: %1 - - - - - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 - - - - - Package %1 cannot be installed, because cannot unzip it to directory: %2 - - - - - - Could not rename directory %1 to %2. + + Updates installer executable is missing. - - Could not delete directory %1. + + + Unable to check for updates (%1) - - Error executing update command: %1 -Error message: %2 + + details are unknown - - An error occurred while downloading updates: %1. Updating aborted. + + Unable to run updater application (%1). Please report this. diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.qm index fccc28a..552d0cf 100644 Binary files a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.qm and b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.qm differ diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.ts index bac1096..15f6cf7 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_fr.ts @@ -4,13 +4,13 @@ AbstractDb - - + + Cannot execute query on closed database. Impossible d’exécuter la requête sur une base de données fermée. - + Error attaching database %1: %2 Erreur base de données attachée %1 : %2 @@ -18,9 +18,8 @@ BugReporter - Invalid login or password - Identifiant ou mot de passe incorrect + Identifiant ou mot de passe incorrect @@ -145,38 +144,51 @@ Objets temporaires de base de données + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + DbManagerImpl - + Could not add database %1: %2 Impossible d’ajouter une base de données %1 : %2 - + Database %1 could not be updated, because of an error: %2 La base de données %1 ne peut ëtre mise à jour à cause de l’erreur : %2 - - + + Database file doesn't exist. Le fichier de la base de données n’existe pas. - - - + + + No supporting plugin loaded. Aucun plugin supporté chargé. - + Database could not be initialized. La base de données ne peut être initialisée. - + No suitable database driver plugin found. Aucun pilote de base de données approprié trouvé. @@ -244,17 +256,17 @@ Tables, index, déclencheurs et vues copiés de la base de données %3 seront ma DbVersionConverter - + Target file exists, but could not be overwritten. Le fichier cible existe, mais ne peut être remplacé. - + Could not find proper database plugin to create target database. Impossible de trouver le plugin correct pour créer la base de données cible. - + Error while converting database: %1 Erreur lors de la conversion de la base de données : %1 @@ -457,20 +469,20 @@ Tables, index, déclencheurs et vues copiés de la base de données %3 seront ma - - + + Error while importing data: %1 Erreur lors de l’import des données : %1 - + Interrupted. import process status update Transaction interrompue. - + Could not import data row number %1. The row was ignored. Problem details: %2 @@ -764,12 +776,12 @@ Tables, index, déclencheurs et vues copiés de la base de données %3 seront ma Impossible d’initialiser la transaction pour remplir la table.Détails de l’erreur %1 - + Error while populating table: %1 Erreur lors du remplissage de la table : %1 - + Could not commit transaction after table populating. Error details: %1 Impossible d’enregistrer la transaction après le remplissage de la table. Erreur %1 @@ -777,72 +789,78 @@ Tables, index, déclencheurs et vues copiés de la base de données %3 seront ma QObject - - + + Could not open database: %1 Impossible d’ouvrir la base de données : %1 - - + + Result set expired or no row available. Terminé ou aucune ligne valide. - + + + Could not load extension %1: %2 + + + + Could not close database: %1 Impossible de clore la base de bonnées : %1 - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. SQLite %1 ne supporte pas l’instruction « %2 ». - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. SQLite %1 ne supporte pas l’instruction « %2 », mais la table normale peut être créée à la place si vous confirmez. - + Could not parse statement: %1 Error details: %2 Impossible d’analyser l’instruction : %1 Détails erreur: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. SQLite %1 ne supporte pas la clause « %2 ». Impossible de convertir l’instruction « %3 » avec cette clause. - + SQLite %1 does not support the '%2' clause in the '%3' statement. SQLite %1 ne supporte pas la clause « %2 » de l’instruction « %3 ». - + SQLite %1 does not support current date or time clauses in expressions. SQLite %1 ne supporte pas la clause date ou l’heure actuelle dans l’expression. - + SQLite %1 does not support row value clauses in expressions. - - - + + + SQLite %1 does not support '%2' clause in expressions. SQLite %1 ne supporte pas la clause « %2 » dans l’expression. @@ -859,13 +877,13 @@ Détails erreur: %2 - + Parser stack overflow Analyse dépassement pile - + Syntax error Erreur de syntaxe @@ -920,60 +938,60 @@ Détails erreur: %2 L’application de code ne peut être vide. - + Could not resolve data source for column: %1 Impossible de résoudre la source de données pour la colonnes : %1 - + Could not resolve table for column '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. Impossible d’initialiser le fichier de configuration. Aucune modification et les requêtes seront perdues après redémarrage. Essayez d’initialiser le fichier avec cette localisation : %1. - + General purpose plugin category name Objectif général - + Database support plugin category name Support base de données - + Code formatter plugin category name Format code - + Scripting languages plugin category name Langages script - + Exporting plugin category name Export - + Importing plugin category name Import - + Table populating plugin category name Peuplement de la table @@ -984,34 +1002,34 @@ Détails erreur: %2 La table %1 référence la table %2, mais la clef étrangère ne pourra être mise à jour pour la nouvelle table à cause de problèmes lors de l’analyse DDL de la table %3. - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. Toutes les colonnes indéxées par l’index %1 sont traitées. L’index ne sera pas recréé après la modification de la table. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. - + Cannot not update trigger %1 according to table %2 modification. Impossible de mettre à jour le déclencheur %1 selon la modification de la table %2. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. Toutes les colonnes couvertes par le déclencheur %1 sont faites. Le déclencheur ne sera pas recréé après la modification de la table. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. Impossible de mettre à jour les modifications de la vue %1 issue de la table %2 @@ -1036,32 +1054,37 @@ La vue restera telque. SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. SQLiteStudio ne peut résoudre les colonnes résultant de la nouvelle vue, d’où le déclencheur en cause ne pourra être indiqué pendant le process. + + + Could not open file '%1' for reading: %2 + + QueryExecutor - + Execution interrupted. Exécution interrompue. - + Database is not open. La base de données n’est ouverte. - + Only one query can be executed simultaneously. Une seule requête peut être exécutée à la fois. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 Une erreur s’est produite à l’exécution de la requête count(*), la recherche des données est arrêtée. Erreur de la base de données : %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. SQLiteStudio ne peut extraire des métadonnées d’une requête. Les résultats ne peut être affichés. @@ -1082,31 +1105,31 @@ La vue restera telque. SqlHistoryModel - + Database sql history header Base de données - + Execution date sql history header Date d’exécution - + Time spent sql history header Temps passé - + Rows affected sql history header Lignes affectées - + SQL sql history header SQL @@ -1115,203 +1138,182 @@ La vue restera telque. UpdateManager - An error occurred while checking for updates: %1. - Une erreur est apparue lors du contrôle pour la mise à jour : %1. + Une erreur est apparue lors du contrôle pour la mise à jour : %1. - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - Impossible de vérifier la mise à jour, car le serveur a répondu avec un message invalide. Il est possible d’ignorer le warning. + Impossible de vérifier la mise à jour, car le serveur a répondu avec un message invalide. Il est possible d’ignorer le warning. - An error occurred while reading updates metadata: %1. - Erreur lors de la lecture de mise des méta données : %1. + Erreur lors de la lecture de mise des méta données : %1. - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - Impossibles de télécharger les mises à jour, car le serveur répond avec un format de message invalide. Vous pover essayer plus tard ou télécharger et mettre à jour manuellement. Voir <a href="%1">User Manual</a> for details. + Impossibles de télécharger les mises à jour, car le serveur répond avec un format de message invalide. Vous pover essayer plus tard ou télécharger et mettre à jour manuellement. Voir <a href="%1">User Manual</a> for details. - Could not create temporary directory for downloading the update. Updating aborted. - Impossible de créer un répertoire temporaire pour télécharger la mise à jour. Mise à jour abandonnée. + Impossible de créer un répertoire temporaire pour télécharger la mise à jour. Mise à jour abandonnée. - There was no updates to download. Updating aborted. - Il n’y a aucune mise à jour à télécharger. Mise à jour abandonnée. + Il n’y a aucune mise à jour à télécharger. Mise à jour abandonnée. - Downloading: %1 - Téléchargement : %1 + Téléchargement : %1 - Could not determinate file name from update URL: %1. Updating aborted. - Impossible de déterminer le fichier de mise à jour URL : %1.Mise à jour abandonnée. + Impossible de déterminer le fichier de mise à jour URL : %1.Mise à jour abandonnée. - Failed to open file '%1' for writting: %2. Updating aborted. - Erreur à l’ouverture du fichier « %1 » pour l’écriture : %2. Mise à jour abandonnée. + Erreur à l’ouverture du fichier « %1 » pour l’écriture : %2. Mise à jour abandonnée. - Installing updates. - Installation des mises jour. + Installation des mises jour. - Could not copy current application directory into %1 directory. - Impossible de copier le répertoire de l’application courante dans %1. + Impossible de copier le répertoire de l’application courante dans %1. - Could not create directory %1. - Impossible de créer le répertoire : %1. + Impossible de créer le répertoire : %1. - Could not rename directory %1 to %2. Details: %3 - Impossible de renommer le répertoire %1 en %2. Détails : %3 + Impossible de renommer le répertoire %1 en %2. Détails : %3 - Cannot not rename directory %1 to %2. Details: %3 - Impossible de renommer le répertoire %1 en %2.Détails : %3 + Impossible de renommer le répertoire %1 en %2.Détails : %3 - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - Impossible de déplacer le répertoire %1 vers %2 d’où l’impossibilité de restaurer le répertoire original. SQLiteStudio est maintenant localisé : %3 + Impossible de déplacer le répertoire %1 vers %2 d’où l’impossibilité de restaurer le répertoire original. SQLiteStudio est maintenant localisé : %3 - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - Impossible de renommer le répertoire %1 en %2, retour vers la version originale SQLiteStudio. + Impossible de renommer le répertoire %1 en %2, retour vers la version originale SQLiteStudio. - Could not unpack component %1 into %2 directory. - Impossible d’extraire le composant %1 dans le répertoire %2. + Impossible d’extraire le composant %1 dans le répertoire %2. - Could not find permissions elevator application to run update as a root. Looked for: %1 - Impossible d’élever les autorisations pour lancer la mise à jour en tantque root. Bloqué : %1 + Impossible d’élever les autorisations pour lancer la mise à jour en tantque root. Bloqué : %1 - Could not execute final updating steps as root: %1 - Impossible de finaliser la mis à jour en tant que root : %1 + Impossible de finaliser la mis à jour en tant que root : %1 - - - - Could not execute final updating steps as admin: %1 - Impossible de finaliser la mis à jour en tant que admin : %1 + Impossible de finaliser la mis à jour en tant que admin : %1 - Cannot create temporary directory for updater. - Impossible de créer un répertoire temporaire pour la mise à jour. + Impossible de créer un répertoire temporaire pour la mise à jour. - Cannot create updater script file. - impossible de créer le fichier du scripte de mise à jour. + impossible de créer le fichier du scripte de mise à jour. - Updating canceled. - Mise à jour suspendue. + Mise à jour suspendue. - Could not execute final updating steps as administrator. - Impossible de finaliser la mis à jour en tant qu’administrateur. + Impossible de finaliser la mis à jour en tant qu’administrateur. - Could not execute final updating steps as administrator. Updater startup timed out. - Impossible de finaliser la mis à jour en tant qu’administrateur. Délai d’attente de lancement dépassé. + Impossible de finaliser la mis à jour en tant qu’administrateur. Délai d’attente de lancement dépassé. - Could not execute final updating steps as administrator. Updater operation timed out. - Impossible de finaliser la mis à jour en tant qu’administrateur. Délai d’attente d’opération dépassé. + Impossible de finaliser la mis à jour en tant qu’administrateur. Délai d’attente d’opération dépassé. - Could not clean up temporary directory %1. You can delete it manually at any time. - Impossible de nettoyer le répertoire temporaire %1. Vous pouver le supprimer manuellement plutard. + Impossible de nettoyer le répertoire temporaire %1. Vous pouver le supprimer manuellement plutard. - Could not run new version for continuing update. - Impossible de lancer la nouvelle version afin de continuer la mise à jour. + Impossible de lancer la nouvelle version afin de continuer la mise à jour. - Package not in tar.gz format, cannot install: %1 - Installation impossible un paquet n’est pas au format tar.zg : %1 + Installation impossible un paquet n’est pas au format tar.zg : %1 - Package %1 cannot be installed, because cannot move it to directory: %2 - Le paquet %1 ne peut être installé, celui-ci ne pouvant déplacé dans le répertoire : %2 + Le paquet %1 ne peut être installé, celui-ci ne pouvant déplacé dans le répertoire : %2 - Package %1 cannot be installed, because cannot unpack it: %2 - Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé : %2 + Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé : %2 - Package not in zip format, cannot install: %1 - Installation impossible, un paquet est manquant : %1 + Installation impossible, un paquet est manquant : %1 - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 - Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé dans le répertoire %2 : %3 + Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé dans le répertoire %2 : %3 - Package %1 cannot be installed, because cannot unzip it to directory: %2 - Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé dans le répertoire : %2 + Le paquet %1 ne peut être installé, celui-ci ne pouvant décompressé dans le répertoire : %2 - - Could not rename directory %1 to %2. - Impossible de renommer le répertoire %1 en %2. + Impossible de renommer le répertoire %1 en %2. - Could not delete directory %1. - Impossible de supprimer le répertoire %1. + Impossible de supprimer le répertoire %1. - Error executing update command: %1 Error message: %2 - Erreur d’exécution de la commande de mise à jour : %1 + Erreur d’exécution de la commande de mise à jour : %1 Message d’erreur : %2 - An error occurred while downloading updates: %1. Updating aborted. - Erreur lors du téléchargement de la mise à jour : %1. Mise à jour abandonnée. + Erreur lors du téléchargement de la mise à jour : %1. Mise à jour abandonnée. + + + + Updates installer executable is missing. + + + + + + Unable to check for updates (%1) + + + + + details are unknown + + + + + Unable to run updater application (%1). Please report this. + diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_it.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_it.ts index beed03d..461461f 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_it.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_it.ts @@ -4,25 +4,17 @@ AbstractDb - - + + Cannot execute query on closed database. - + Error attaching database %1: %2 - - BugReporter - - - Invalid login or password - - - ChainExecutor @@ -145,38 +137,51 @@ + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + DbManagerImpl - + Could not add database %1: %2 - + Database %1 could not be updated, because of an error: %2 - - + + Database file doesn't exist. - - - + + + No supporting plugin loaded. - + Database could not be initialized. - + No suitable database driver plugin found. @@ -243,17 +248,17 @@ Tables, indexes, triggers and views copied to database %3 will remain. DbVersionConverter - + Target file exists, but could not be overwritten. - + Could not find proper database plugin to create target database. - + Error while converting database: %1 @@ -456,20 +461,20 @@ Tables, indexes, triggers and views copied to database %3 will remain. - - + + Error while importing data: %1 - + Interrupted. import process status update - + Could not import data row number %1. The row was ignored. Problem details: %2 @@ -763,12 +768,12 @@ Tables, indexes, triggers and views copied to database %3 will remain. - + Error while populating table: %1 - + Could not commit transaction after table populating. Error details: %1 @@ -776,71 +781,77 @@ Tables, indexes, triggers and views copied to database %3 will remain. QObject - - + + Could not open database: %1 - - + + Result set expired or no row available. - + + + Could not load extension %1: %2 + + + + Could not close database: %1 - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. - + Could not parse statement: %1 Error details: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. - + SQLite %1 does not support the '%2' clause in the '%3' statement. - + SQLite %1 does not support current date or time clauses in expressions. - + SQLite %1 does not support row value clauses in expressions. - - - + + + SQLite %1 does not support '%2' clause in expressions. @@ -857,13 +868,13 @@ Error details: %2 - + Parser stack overflow - + Syntax error @@ -918,58 +929,58 @@ Error details: %2 - + Could not resolve data source for column: %1 - + Could not resolve table for column '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. - + General purpose plugin category name - + Database support plugin category name - + Code formatter plugin category name - + Scripting languages plugin category name - + Exporting plugin category name - + Importing plugin category name - + Table populating plugin category name @@ -980,35 +991,35 @@ Error details: %2 - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. - + Cannot not update trigger %1 according to table %2 modification. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. @@ -1027,32 +1038,37 @@ The view will remain as it is. SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. + + + Could not open file '%1' for reading: %2 + + QueryExecutor - + Execution interrupted. - + Database is not open. - + Only one query can be executed simultaneously. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. @@ -1073,31 +1089,31 @@ The view will remain as it is. SqlHistoryModel - + Database sql history header - + Execution date sql history header - + Time spent sql history header - + Rows affected sql history header - + SQL sql history header @@ -1106,200 +1122,24 @@ The view will remain as it is. UpdateManager - - An error occurred while checking for updates: %1. - - - - - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - - - - - An error occurred while reading updates metadata: %1. - - - - - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - - - - - Could not create temporary directory for downloading the update. Updating aborted. - - - - - There was no updates to download. Updating aborted. - - - - - Downloading: %1 - - - - - Could not determinate file name from update URL: %1. Updating aborted. - - - - - Failed to open file '%1' for writting: %2. Updating aborted. - - - - - Installing updates. - - - - - Could not copy current application directory into %1 directory. - - - - - Could not create directory %1. - - - - - Could not rename directory %1 to %2. -Details: %3 - - - - - Cannot not rename directory %1 to %2. -Details: %3 - - - - - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - - - - - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - - - - - Could not unpack component %1 into %2 directory. - - - - - Could not find permissions elevator application to run update as a root. Looked for: %1 - - - - - Could not execute final updating steps as root: %1 - - - - - - - - Could not execute final updating steps as admin: %1 - - - - - Cannot create temporary directory for updater. - - - - - Cannot create updater script file. - - - - - Updating canceled. - - - - - Could not execute final updating steps as administrator. - - - - - Could not execute final updating steps as administrator. Updater startup timed out. - - - - - Could not execute final updating steps as administrator. Updater operation timed out. - - - - - Could not clean up temporary directory %1. You can delete it manually at any time. - - - - - Could not run new version for continuing update. - - - - - Package not in tar.gz format, cannot install: %1 - - - - - Package %1 cannot be installed, because cannot move it to directory: %2 - - - - - Package %1 cannot be installed, because cannot unpack it: %2 - - - - - Package not in zip format, cannot install: %1 - - - - - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 - - - - - Package %1 cannot be installed, because cannot unzip it to directory: %2 - - - - - - Could not rename directory %1 to %2. + + Updates installer executable is missing. - - Could not delete directory %1. + + + Unable to check for updates (%1) - - Error executing update command: %1 -Error message: %2 + + details are unknown - - An error occurred while downloading updates: %1. Updating aborted. + + Unable to run updater application (%1). Please report this. diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.qm index 76565a1..d8a2202 100644 Binary files a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.qm and b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.qm differ diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.ts index 843aebe..6a1e7aa 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pl.ts @@ -4,13 +4,13 @@ AbstractDb - - + + Cannot execute query on closed database. Nie można wykonać zapytania na zamkniętej bazie danych. - + Error attaching database %1: %2 Błąd podczas dołączania bazy danych %1: %2 @@ -18,9 +18,8 @@ BugReporter - Invalid login or password - Niepoprawny login lub hasło + Niepoprawny login lub hasło @@ -145,38 +144,51 @@ Baza danych obiektów tymczasowych + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + Nie można rozpocząć transakcji dla usuwania historii SQL, więc nie można usunąć historii. + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + Nie można zatwierdzić transakcji dla usuwania historii SQL, więc nie można usunąć historii. + + DbManagerImpl - + Could not add database %1: %2 Nie udało się dodać bazę danych %1: %2 - + Database %1 could not be updated, because of an error: %2 Nie udało się zaktualizować baza danych %1 z powodu błędu: %2 - - + + Database file doesn't exist. Plik bazy danych nie istnieje. - - - + + + No supporting plugin loaded. Nie załadowano obsługującej wtyczki. - + Database could not be initialized. Nie udało się zainicjalizować bazy danych. - + No suitable database driver plugin found. Nie znaleziono odpowiedniej wtyczki sterownika. @@ -244,17 +256,17 @@ Tabele, indeksy, wyzwalacze i widoki skopiowane do bazy danych %3 pozostaną na DbVersionConverter - + Target file exists, but could not be overwritten. Plik docelowy istnieje, ale nie może być nadpisany. - + Could not find proper database plugin to create target database. Nie znaleziono odpowiedniej wtyczki bazy danych, aby utworzyć docelową bazę danych. - + Error while converting database: %1 Błąd podczas konwersji bazy danych: %1 @@ -465,20 +477,20 @@ Tabele, indeksy, wyzwalacze i widoki skopiowane do bazy danych %3 pozostaną na - - + + Error while importing data: %1 Błąd podczas importowania danych: %1 - + Interrupted. import process status update Przerwano. - + Could not import data row number %1. The row was ignored. Problem details: %2 Nie udało się zaimportować wiersza danych numer %1. Wiersz ten został zignorowany. Szczegóły problemu: %2 @@ -772,12 +784,12 @@ Tabele, indeksy, wyzwalacze i widoki skopiowane do bazy danych %3 pozostaną na Nie udało się rozpocząć transakcji w celu zaludnienia tabeli. Szczegóły błędu: %1 - + Error while populating table: %1 Błąd podczas zaludniania tabeli: %2 - + Could not commit transaction after table populating. Error details: %1 Nie udało się zatwierdzić transakcji po zaludnieniu tabeli. Szczegóły błędy: %1 @@ -785,38 +797,38 @@ Tabele, indeksy, wyzwalacze i widoki skopiowane do bazy danych %3 pozostaną na QObject - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. SQLite %1 nie obsługuje zapytania '%2'. - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. SQLite %1 nie obsługuje zapytania '%2', ale stworzona zostanie zwykła tabela, jeśli będziesz kontynuować. - + Could not parse statement: %1 Error details: %2 Nie udało się przeanalizować zapytania: %1 Szczegóły błędu: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. SQLite %1 nie obsługuje klauzuli '%2'. Nie można przekonwertować zapytania '%3' z tą klauzulą. - + SQLite %1 does not support the '%2' clause in the '%3' statement. SQLite %1 nie obsługuje klauzuli '%2' w zapytaniu '%3'. @@ -825,19 +837,19 @@ Szczegóły błędu: %2 SQLite %1 nie obsługuje klauzuli '%2'. Nie można przekonwertować zapytania '%3' z tą klauzulą. {1 ?} {2'?} {1'?} - + SQLite %1 does not support current date or time clauses in expressions. SQLite %1 nie obsługuje aktualnej daty lub klauzul czasowu w wyrażeniach. - + SQLite %1 does not support row value clauses in expressions. SQLite %1 nie obsługuje klauzuli wartości wierszowej w wyrażeniach. - - - + + + SQLite %1 does not support '%2' clause in expressions. SQLite %1 nie obsługuje klauzuli '%2' w wyrażeniach. @@ -854,13 +866,13 @@ Szczegóły błędu: %2 - + Parser stack overflow Przeciążenie stosu analizatora. - + Syntax error Błąd składni @@ -915,58 +927,58 @@ Szczegóły błędu: %2 Kod implementacji nie może być pusty. - + Could not resolve data source for column: %1 Nie znaleziono źródła danych dla kolumny: %1 - + Could not resolve table for column '%1'. Nie można ustalić tabeli lub kolumny '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. Nie udało się zainicjalizować pliku konfiguracyjnego. Jakiekolwiek zmiany w konfiguracji i historia zapytań będą utracone po zrestartowaniu aplikacji. Próbowano zainicjalizować plik konfiguracyjny w następujących lokalizacjach: %1. - + General purpose plugin category name Ogólne - + Database support plugin category name Wsparcie baz danych - + Code formatter plugin category name Formatowanie kodu - + Scripting languages plugin category name Języki skryptowe - + Exporting plugin category name Eksportowanie - + Importing plugin category name Importowanie - + Table populating plugin category name Zaludnianie tabel @@ -977,34 +989,34 @@ Szczegóły błędu: %2 Tabela %1 odwołuje się do tabeli %2, ale definicja klucza obcego nie zostanie zaktualizowane dla definicji nowej tabeli w związku z problemami przy analizowaniu DDL tabeli %3. - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. Wszystkie kolumny indeksowane przez indeks %1 już nie istnieją. Indeks ten nie będzie odtworzony po modyfikacji tabeli. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. Wystąpił problem z poprawnym przetworzeniem wyzwalacza %1. Może on zostać zaktualizowany tylko częściowo i będzie wymagał twojej uwagi. - + Cannot not update trigger %1 according to table %2 modification. Nie można zaktualizować wyzwalacza %1 zgodnie z modyfikacjami tabeli %2. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. Jest problem ze zaktualizowaniem zapytania %1 w wyzwalaczu %2. Jedeno z podzapytań %1, które może odwoływać się do tabeli %3 nie może być poprawnie zmodyfikowane. Ręczna aktualizacja tego wyzwalacza może być niezbędna. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. Wszystkie kolumny obsługiwane przez wyzwalacz %1 już nie istnieją. Wyzwalacz ten nie będzie odtworzony po modyfikacji tabeli. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. Nie można zaktualizować widoku %1 w związku z modyfikacjami tabeli %2. @@ -1030,22 +1042,33 @@ Widok pozostanie nienaruszony. SQLiteStudio nie było w stanie określić kolumn zwracanych przez nowy widok, w związku z czym nie może określić które wyzwalacze mogą się nie powieść podczas procesu odtwarzania. - - + + Could not open database: %1 Nie udało się otworzyć bazy danych: %1 - + + + Could not load extension %1: %2 + Nie udało się załadować rozszerzenia %1: %2 + + + Could not close database: %1 Nie udało się zamknąć bazy danych: %1 - - + + Result set expired or no row available. Wyniki zapytania są nieaktualne, lub nie ma dostępnych wierszy. + + + Could not open file '%1' for reading: %2 + Nie można otworzyż pliku '%1' do odczytu: %2 + Query @@ -1057,28 +1080,28 @@ Widok pozostanie nienaruszony. QueryExecutor - + Execution interrupted. Wykonywanie przerwane. - + Database is not open. Baza danych nie jest otwarta. - + Only one query can be executed simultaneously. Tylko jedno zapytanie może być wykonywane w danym momencie. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 Wystąpił błąd podczas wykonywania zapytania count(*), przez co stronicowanie danych będzie wyłączone. Szczegóły błędy z bazy danych: %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. SQLiteStudio nie mogło uzyskać metadanych z zapytania. Nie będzie można edytować wyników zapytania. @@ -1099,31 +1122,31 @@ Widok pozostanie nienaruszony. SqlHistoryModel - + Database sql history header Baza danych - + Execution date sql history header Data wykonania - + Time spent sql history header Czas trwania - + Rows affected sql history header Liczba wierszy - + SQL sql history header SQL @@ -1132,204 +1155,183 @@ Widok pozostanie nienaruszony. UpdateManager - An error occurred while checking for updates: %1. - Wystąpił błąd podczas sprawdzania aktualizacji: %1 + Wystąpił błąd podczas sprawdzania aktualizacji: %1 - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - Nie udało się sprawdzić aktualizacji, ponieważ serwer odpowiedział wiadomością w niepoprawnym formacie. Możesz spokojnie zignorować tą informację. + Nie udało się sprawdzić aktualizacji, ponieważ serwer odpowiedział wiadomością w niepoprawnym formacie. Możesz spokojnie zignorować tą informację. - An error occurred while reading updates metadata: %1. - Wystąpił błąd podczas odczytu metadanych aktualizacji: %1 + Wystąpił błąd podczas odczytu metadanych aktualizacji: %1 - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - Nie udało się ściągnąć aktualizacji, ponieważ serwer odpowiedział wiadomością w niepoprawnym formacie. Możesz spróbować jeszcze raz później, lub ściągnąć i stainstalować aktualizację ręcznie. Szczegóły: <a href="%1">Podręcznik użytkownika</a>. + Nie udało się ściągnąć aktualizacji, ponieważ serwer odpowiedział wiadomością w niepoprawnym formacie. Możesz spróbować jeszcze raz później, lub ściągnąć i stainstalować aktualizację ręcznie. Szczegóły: <a href="%1">Podręcznik użytkownika</a>. - Could not create temporary directory for downloading the update. Updating aborted. - Nie udało się stworzyć katalogu tymczasowego w celu pobrania aktualizacji. Aktualizacja została przerwana. + Nie udało się stworzyć katalogu tymczasowego w celu pobrania aktualizacji. Aktualizacja została przerwana. - There was no updates to download. Updating aborted. - Nie znaleziono aktualizacji do pobrania. Aktualizacja przerwana. + Nie znaleziono aktualizacji do pobrania. Aktualizacja przerwana. - Downloading: %1 - Pobieranie: %1 + Pobieranie: %1 - Could not determinate file name from update URL: %1. Updating aborted. - Nie udało się określić nazwy pliku z URL aktualizacji: %1. Aktualizacja przerwana. + Nie udało się określić nazwy pliku z URL aktualizacji: %1. Aktualizacja przerwana. - Failed to open file '%1' for writting: %2. Updating aborted. - Nie udało się otworzyć pliku '%1' do zapisu: %2. Aktualizacja przerwana. + Nie udało się otworzyć pliku '%1' do zapisu: %2. Aktualizacja przerwana. - Installing updates. - Instalowanie aktualizacji. + Instalowanie aktualizacji. - Could not copy current application directory into %1 directory. - Nie udało się skopiować bieżącego katalogu aplikacji do katalogu %1. + Nie udało się skopiować bieżącego katalogu aplikacji do katalogu %1. - Could not create directory %1. - Nie udało się stworzyć katalogu %1. + Nie udało się stworzyć katalogu %1. - Could not rename directory %1 to %2. Details: %3 - Nie udało się zmienić nazwy katalogu %1 na %2. + Nie udało się zmienić nazwy katalogu %1 na %2. Szczegóły: %3 - Cannot not rename directory %1 to %2. Details: %3 - Nie można zmienić nazwy katalogu %1 na %2. + Nie można zmienić nazwy katalogu %1 na %2. Szczegóły: %3 - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - Nie udało się przenieść katalogu %1 do %2, oraz nie udało się przywrócić originalnego katalog, więc originalny katalog SQLiteStudio jest mieści się teraz w: %3 + Nie udało się przenieść katalogu %1 do %2, oraz nie udało się przywrócić originalnego katalog, więc originalny katalog SQLiteStudio jest mieści się teraz w: %3 - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - Nie udało się zmienić nazwy katalogu %1 na %2. Przywrócono originalną wersję SQLiteStudio. + Nie udało się zmienić nazwy katalogu %1 na %2. Przywrócono originalną wersję SQLiteStudio. - Could not unpack component %1 into %2 directory. - Nie udało się rozpakować komponentu %1 do katalogu %2. + Nie udało się rozpakować komponentu %1 do katalogu %2. - Could not find permissions elevator application to run update as a root. Looked for: %1 - Nie udało się znaleźć narzędzia do podnoszenia uprawnień aplikacji, aby uruchomić aktualizację jako administrator. Szukano następujących: %1 + Nie udało się znaleźć narzędzia do podnoszenia uprawnień aplikacji, aby uruchomić aktualizację jako administrator. Szukano następujących: %1 - Could not execute final updating steps as root: %1 - Nie udało się wykonać ostatnich kroków jako administrator: %1 + Nie udało się wykonać ostatnich kroków jako administrator: %1 - - - - Could not execute final updating steps as admin: %1 - Nie udało się wykonać ostatnich kroków jako administrator: %1 + Nie udało się wykonać ostatnich kroków jako administrator: %1 - Cannot create temporary directory for updater. - Nie można stworzyć tymczasowego katalogu dla aktualizacji. + Nie można stworzyć tymczasowego katalogu dla aktualizacji. - Cannot create updater script file. - Nie można utworzyć skryptu aktualizacji. + Nie można utworzyć skryptu aktualizacji. - Updating canceled. - Aktualizacja wycofana. + Aktualizacja wycofana. - Could not execute final updating steps as administrator. - Nie udało się wykonać ostatich kroków aktualizacji jako administrator. + Nie udało się wykonać ostatich kroków aktualizacji jako administrator. - Could not execute final updating steps as administrator. Updater startup timed out. - Nie udało się wykonać ostatich kroków aktualizacji jako administrator. Przekroczono limit czasu oczekiwania. + Nie udało się wykonać ostatich kroków aktualizacji jako administrator. Przekroczono limit czasu oczekiwania. - Could not execute final updating steps as administrator. Updater operation timed out. - Nie udało się wykonać ostatich kroków aktualizacji jako administrator. Przekroczono limit czasu oczekiwania. + Nie udało się wykonać ostatich kroków aktualizacji jako administrator. Przekroczono limit czasu oczekiwania. - Could not clean up temporary directory %1. You can delete it manually at any time. - Nie udało się wyczyścić katalogu tymczasowego %1. Możesz go usunąć ręcznie w dowolnym momencie. + Nie udało się wyczyścić katalogu tymczasowego %1. Możesz go usunąć ręcznie w dowolnym momencie. - Could not run new version for continuing update. - Nie udało się uruchomić nowej wersji w celu kontynuowania aktualizacji. + Nie udało się uruchomić nowej wersji w celu kontynuowania aktualizacji. - Package not in tar.gz format, cannot install: %1 - Paczka nie jest w formacie tar.gz, nie można zainstalować: %1 + Paczka nie jest w formacie tar.gz, nie można zainstalować: %1 - Package %1 cannot be installed, because cannot move it to directory: %2 - Paczka %1 nie może być zainstalowana, ponieważ nie można przenieść jej do katalogu: %2 + Paczka %1 nie może być zainstalowana, ponieważ nie można przenieść jej do katalogu: %2 - Package %1 cannot be installed, because cannot unpack it: %2 - Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować: %2 + Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować: %2 - Package not in zip format, cannot install: %1 - Paczka nie jest w formacie zip, nie można zainstalować: %1 + Paczka nie jest w formacie zip, nie można zainstalować: %1 - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 - Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować do katalogu %2: %3 + Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować do katalogu %2: %3 - Package %1 cannot be installed, because cannot unzip it to directory: %2 - Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować do katalogu %2 + Paczka %1 nie może być zainstalowana, ponieważ nie można jej rozpakować do katalogu %2 - - Could not rename directory %1 to %2. - Nie udało się zmienić nazwy katalogu %1 na %2. + Nie udało się zmienić nazwy katalogu %1 na %2. - Could not delete directory %1. - Nie udało się skasować katalogu %1. + Nie udało się skasować katalogu %1. - Error executing update command: %1 Error message: %2 - Błąd podczas wykonywania polecenia aktualizacji: %1 + Błąd podczas wykonywania polecenia aktualizacji: %1 Treść błędu: %2 - An error occurred while downloading updates: %1. Updating aborted. - Wystąpił błąd podczas pobierania aktualizacji: %1. Aktualizacja przerwana. + Wystąpił błąd podczas pobierania aktualizacji: %1. Aktualizacja przerwana. + + + + Updates installer executable is missing. + Nie można znaleźć pliku wykonywalnego instalatora aktualizacji. + + + + + Unable to check for updates (%1) + Nie można sprawdzić dostępnych aktualizacji (%1) + + + + details are unknown + szczegóły nieznane + + + + Unable to run updater application (%1). Please report this. + Nie można uruchomić aplikacji aktualizującej (%1). Proszę to zgłosić. diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.qm index 8d72a0b..95d8136 100644 Binary files a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.qm and b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.qm differ diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.ts index 82a5283..8f3404e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_pt_BR.ts @@ -4,13 +4,13 @@ AbstractDb - - + + Cannot execute query on closed database. Não é possível executar query em banco de dados fechado. - + Error attaching database %1: %2 @@ -18,9 +18,8 @@ BugReporter - Invalid login or password - login ou senha inválido + login ou senha inválido @@ -145,38 +144,51 @@ + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + DbManagerImpl - + Could not add database %1: %2 - + Database %1 could not be updated, because of an error: %2 - - + + Database file doesn't exist. - - - + + + No supporting plugin loaded. - + Database could not be initialized. - + No suitable database driver plugin found. @@ -243,17 +255,17 @@ Tables, indexes, triggers and views copied to database %3 will remain. DbVersionConverter - + Target file exists, but could not be overwritten. - + Could not find proper database plugin to create target database. - + Error while converting database: %1 @@ -456,20 +468,20 @@ Tables, indexes, triggers and views copied to database %3 will remain. - - + + Error while importing data: %1 - + Interrupted. import process status update - + Could not import data row number %1. The row was ignored. Problem details: %2 @@ -763,12 +775,12 @@ Tables, indexes, triggers and views copied to database %3 will remain. - + Error while populating table: %1 - + Could not commit transaction after table populating. Error details: %1 @@ -776,71 +788,77 @@ Tables, indexes, triggers and views copied to database %3 will remain. QObject - - + + Could not open database: %1 - - + + Result set expired or no row available. - + + + Could not load extension %1: %2 + + + + Could not close database: %1 - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. - + Could not parse statement: %1 Error details: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. - + SQLite %1 does not support the '%2' clause in the '%3' statement. - + SQLite %1 does not support current date or time clauses in expressions. - + SQLite %1 does not support row value clauses in expressions. - - - + + + SQLite %1 does not support '%2' clause in expressions. @@ -857,13 +875,13 @@ Error details: %2 - + Parser stack overflow - + Syntax error @@ -918,58 +936,58 @@ Error details: %2 - + Could not resolve data source for column: %1 - + Could not resolve table for column '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. - + General purpose plugin category name - + Database support plugin category name - + Code formatter plugin category name - + Scripting languages plugin category name - + Exporting plugin category name - + Importing plugin category name - + Table populating plugin category name @@ -980,34 +998,34 @@ Error details: %2 - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. - + Cannot not update trigger %1 according to table %2 modification. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. @@ -1027,32 +1045,37 @@ The view will remain as it is. SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. + + + Could not open file '%1' for reading: %2 + + QueryExecutor - + Execution interrupted. - + Database is not open. - + Only one query can be executed simultaneously. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. @@ -1073,31 +1096,31 @@ The view will remain as it is. SqlHistoryModel - + Database sql history header - + Execution date sql history header - + Time spent sql history header - + Rows affected sql history header - + SQL sql history header @@ -1106,200 +1129,24 @@ The view will remain as it is. UpdateManager - - An error occurred while checking for updates: %1. - - - - - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - - - - - An error occurred while reading updates metadata: %1. - - - - - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - - - - - Could not create temporary directory for downloading the update. Updating aborted. - - - - - There was no updates to download. Updating aborted. - - - - - Downloading: %1 - - - - - Could not determinate file name from update URL: %1. Updating aborted. - - - - - Failed to open file '%1' for writting: %2. Updating aborted. - - - - - Installing updates. - - - - - Could not copy current application directory into %1 directory. - - - - - Could not create directory %1. - - - - - Could not rename directory %1 to %2. -Details: %3 - - - - - Cannot not rename directory %1 to %2. -Details: %3 - - - - - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - - - - - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - - - - - Could not unpack component %1 into %2 directory. - - - - - Could not find permissions elevator application to run update as a root. Looked for: %1 - - - - - Could not execute final updating steps as root: %1 - - - - - - - - Could not execute final updating steps as admin: %1 - - - - - Cannot create temporary directory for updater. - - - - - Cannot create updater script file. - - - - - Updating canceled. - - - - - Could not execute final updating steps as administrator. - - - - - Could not execute final updating steps as administrator. Updater startup timed out. - - - - - Could not execute final updating steps as administrator. Updater operation timed out. - - - - - Could not clean up temporary directory %1. You can delete it manually at any time. - - - - - Could not run new version for continuing update. - - - - - Package not in tar.gz format, cannot install: %1 - - - - - Package %1 cannot be installed, because cannot move it to directory: %2 - - - - - Package %1 cannot be installed, because cannot unpack it: %2 - - - - - Package not in zip format, cannot install: %1 - - - - - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 - - - - - Package %1 cannot be installed, because cannot unzip it to directory: %2 - - - - - - Could not rename directory %1 to %2. + + Updates installer executable is missing. - - Could not delete directory %1. + + + Unable to check for updates (%1) - - Error executing update command: %1 -Error message: %2 + + details are unknown - - An error occurred while downloading updates: %1. Updating aborted. + + Unable to run updater application (%1). Please report this. diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.qm new file mode 100644 index 0000000..2856eb9 Binary files /dev/null and b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.qm differ diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.ts new file mode 100644 index 0000000..744cb0c --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ro_RO.ts @@ -0,0 +1,1146 @@ + + + + + AbstractDb + + + + Cannot execute query on closed database. + + + + + Error attaching database %1: %2 + + + + + ChainExecutor + + + The database for executing queries was not defined. + chain executor + + + + + The database for executing queries was not open. + chain executor + + + + + Could not disable foreign keys in the database. Details: %1 + chain executor + + + + + Could not start a database transaction. Details: %1 + chain executor + + + + + Interrupted + chain executor + + + + + Could not commit a database transaction. Details: %1 + chain executor + + + + + CompletionHelper + + + New row reference + + + + + Old row reference + + + + + New table name + + + + + New index name + + + + + New view name + + + + + New trigger name + + + + + Table or column alias + + + + + transaction name + + + + + New column name + + + + + Column data type + + + + + Constraint name + + + + + Error message + + + + + Collation name + + + + + Any word + + + + + Default database + + + + + Temporary objects database + + + + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + + + DbManagerImpl + + + Could not add database %1: %2 + + + + + Database %1 could not be updated, because of an error: %2 + + + + + + Database file doesn't exist. + + + + + + + No supporting plugin loaded. + + + + + Database could not be initialized. + + + + + No suitable database driver plugin found. + + + + + DbObjectOrganizer + + + + Error while creating table in target database: %1 + + + + + Could not parse table. + + + + + Database %1 could not be attached to database %2, so the data of table %3 will be copied with SQLiteStudio as a mediator. This method can be slow for huge tables, so please be patient. + + + + + Error while copying data for table %1: %2 + + + + + + + Error while copying data to table %1: %2 + + + + + Error while dropping source view %1: %2 +Tables, indexes, triggers and views copied to database %3 will remain. + + + + + Error while creating view in target database: %1 + + + + + Error while creating index in target database: %1 + + + + + Error while creating trigger in target database: %1 + + + + + + + Could not parse object '%1' in order to move or copy it. + + + + + DbVersionConverter + + + Target file exists, but could not be overwritten. + + + + + Could not find proper database plugin to create target database. + + + + + Error while converting database: %1 + + + + + DdlHistoryModel + + + Database name + ddl history header + + + + + Database file + ddl history header + + + + + Date of execution + ddl history header + + + + + Changes + ddl history header + + + + + ExportManager + + + Export plugin %1 doesn't support exporing query results. + + + + + Export plugin %1 doesn't support exporing tables. + + + + + Export plugin %1 doesn't support exporing databases. + + + + + Export format '%1' is not supported. Supported formats are: %2. + + + + + Export to the clipboard was successful. + + + + + Export to the file '%1' was successful. + + + + + Export was successful. + + + + + Could not export to file %1. File cannot be open for writting. + + + + + ExportWorker + + + Error while exporting query results: %1 + + + + + Error while counting data column width to export from query results: %1 + + + + + + Could not parse %1 in order to export it. It will be excluded from the export output. + + + + + Error while reading data to export from table %1: %2 + + + + + Error while counting data to export from table %1: %2 + + + + + Error while counting data column width to export from table %1: %2 + + + + + FunctionManagerImpl + + + Invalid number of arguments to function '%1'. Expected %2, but got %3. + + + + + No such function registered in SQLiteStudio: %1(%2) + + + + + Function %1(%2) was registered with language %3, but the plugin supporting that language is not currently loaded. + + + + + Invalid regular expression pattern: %1 + + + + + + Could not open file %1 for reading: %2 + + + + + Could not open file %1 for writting: %2 + + + + + Error while writting to file %1: %2 + + + + + Unsupported scripting language: %1 + + + + + GenericExportPlugin + + + Could not initialize text codec for exporting. Using default codec: %1 + + + + + ImportManager + + + Imported data to the table '%1' successfully. + + + + + ImportWorker + + + No columns provided by the import plugin. + + + + + Could not start transaction in order to import a data: %1 + + + + + Could not commit transaction for imported data: %1 + + + + + Table '%1' has less columns than there are columns in the data to be imported. Excessive data columns will be ignored. + + + + + Table '%1' has more columns than there are columns in the data to be imported. Some columns in the table will be left empty. + + + + + Could not create table to import to: %1 + + + + + + + Error while importing data: %1 + + + + + + Interrupted. + import process status update + + + + + Could not import data row number %1. The row was ignored. Problem details: %2 + + + + + PluginManagerImpl + + + Cannot load plugin %1, because it's in conflict with plugin %2. + + + + + Cannot load plugin %1, because its dependency was not loaded: %2. + + + + + Cannot load plugin %1. Error details: %2 + + + + + Cannot load plugin %1 (error while initializing plugin). + + + + + min: %1 + plugin dependency version + + + + + max: %1 + plugin dependency version + + + + + PopulateConstant + + + Constant + populate constant plugin name + + + + + PopulateConstantConfig + + + Constant value: + + + + + PopulateDictionary + + + Dictionary + dictionary populating plugin name + + + + + PopulateDictionaryConfig + + + Dictionary file + + + + + Pick dictionary file + + + + + Word separator + + + + + Whitespace + + + + + Line break + + + + + Method of using words + + + + + Ordered + + + + + Randomly + + + + + PopulateManager + + + Table '%1' populated successfully. + + + + + PopulateRandom + + + Random number + + + + + PopulateRandomConfig + + + Constant prefix + + + + + No prefix + + + + + Minimum value + + + + + Maximum value + + + + + Constant suffix + + + + + No suffix + + + + + PopulateRandomText + + + Random text + + + + + PopulateRandomTextConfig + + + Use characters from common sets: + + + + + Minimum length + + + + + Letters from a to z. + + + + + Alpha + + + + + Numbers from 0 to 9. + + + + + Numeric + + + + + A whitespace, a tab and a new line character. + + + + + Whitespace + + + + + Includes all above and all others. + + + + + Binary + + + + + Use characters from my custom set: + + + + + Maximum length + + + + + If you type some character multiple times, it's more likely to be used. + + + + + PopulateScript + + + Script + + + + + PopulateScriptConfig + + + Initialization code (optional) + + + + + Per step code + + + + + Language + + + + + Help + + + + + PopulateSequence + + + Sequence + + + + + PopulateSequenceConfig + + + Start value: + + + + + Step: + + + + + PopulateWorker + + + Could not start transaction in order to perform table populating. Error details: %1 + + + + + Error while populating table: %1 + + + + + Could not commit transaction after table populating. Error details: %1 + + + + + QObject + + + + Could not open database: %1 + + + + + + Result set expired or no row available. + + + + + + Could not load extension %1: %2 + + + + + Could not close database: %1 + + + + + + + + + + + SQLite %1 does not support '%2' statement. + + + + + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. + + + + + Could not parse statement: %1 +Error details: %2 + + + + + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. + + + + + SQLite %1 does not support the '%2' clause in the '%3' statement. + + + + + SQLite %1 does not support current date or time clauses in expressions. + + + + + SQLite %1 does not support row value clauses in expressions. + + + + + + + SQLite %1 does not support '%2' clause in expressions. + + + + + Could not attach database %1: %2 + + + + + + Incomplete query. + + + + + + Parser stack overflow + + + + + + Syntax error + + + + + Could not open dictionary file %1 for reading. + + + + + Dictionary file must exist and be readable. + + + + + Maximum value cannot be less than minimum value. + + + + + Maximum length cannot be less than minimum length. + + + + + Custom character set cannot be empty. + + + + + Could not find plugin to support scripting language: %1 + + + + + Error while executing populating initial code: %1 + + + + + Error while executing populating code: %1 + + + + + Select implementation language. + + + + + Implementation code cannot be empty. + + + + + Could not resolve data source for column: %1 + + + + + Could not resolve table for column '%1'. + + + + + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. + + + + + General purpose + plugin category name + + + + + Database support + plugin category name + + + + + Code formatter + plugin category name + + + + + Scripting languages + plugin category name + + + + + Exporting + plugin category name + + + + + Importing + plugin category name + + + + + Table populating + plugin category name + + + + + Table %1 is referencing table %2, but the foreign key definition will not be updated for new table definition due to problems while parsing DDL of the table %3. + + + + + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. + + + + + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. + + + + + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. + + + + + Cannot not update trigger %1 according to table %2 modification. + + + + + Cannot not update view %1 according to table %2 modifications. +The view will remain as it is. + + + + + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. + + + + + Could not parse DDL of the view to be created. Details: %1 + + + + + Parsed query is not CREATE VIEW. It's: %1 + + + + + SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. + + + + + Could not open file '%1' for reading: %2 + + + + + QueryExecutor + + + Execution interrupted. + + + + + Database is not open. + + + + + Only one query can be executed simultaneously. + + + + + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 + + + + + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. + + + + + ScriptingQtDbProxy + + + No database available in current context, while called QtScript's %1 command. + + + + + Error from %1: %2 + + + + + SqlHistoryModel + + + Database + sql history header + + + + + Execution date + sql history header + + + + + Time spent + sql history header + + + + + Rows affected + sql history header + + + + + SQL + sql history header + + + + + UpdateManager + + + Updates installer executable is missing. + + + + + + Unable to check for updates (%1) + + + + + details are unknown + + + + + Unable to run updater application (%1). Please report this. + + + + diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.qm index c638942..55d59ab 100644 Binary files a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.qm and b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.qm differ diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.ts index 4716a1d..702c2f2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_ru.ts @@ -4,13 +4,13 @@ AbstractDb - - + + Cannot execute query on closed database. Невозможно выполнить запрос при закрытой базе данных. - + Error attaching database %1: %2 Ошибка во время присоединения базы данных %1: %2 @@ -18,9 +18,8 @@ BugReporter - Invalid login or password - Неправильный логин или пароль + Неправильный логин или пароль @@ -145,39 +144,52 @@ База данных временных объектов + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + DbManagerImpl - + Could not add database %1: %2 Не удалось добавить базу данных %1: %2 - + Database %1 could not be updated, because of an error: %2 Невозможно обновить базу данных %1 из-за ошибки: %2 - - + + Database file doesn't exist. Файл базы данных не существует. - - - + + + No supporting plugin loaded. Unclear error string. Checking the source didn't help. Модуль поддержки не загружен. - + Database could not be initialized. Невозможно инициализировать базу данных. - + No suitable database driver plugin found. Не найден подходящий драйвер базы данных. @@ -245,17 +257,17 @@ Tables, indexes, triggers and views copied to database %3 will remain. DbVersionConverter - + Target file exists, but could not be overwritten. Целевой файл существует, но не может быть перезаписан. - + Could not find proper database plugin to create target database. Невозможно найти подходящий модуль для создания целевой базы данных. - + Error while converting database: %1 Ошибка при конвертации базы данных: %1 @@ -458,20 +470,20 @@ Tables, indexes, triggers and views copied to database %3 will remain. - - + + Error while importing data: %1 Ошибка при импорте данных: %1 - + Interrupted. import process status update Прервано. - + Could not import data row number %1. The row was ignored. Problem details: %2 Невозможно импортировать строку данных № %1. Строка пропущена. Подробности проблемы: %2 @@ -765,12 +777,12 @@ Tables, indexes, triggers and views copied to database %3 will remain. Невозможно начать транзакцию для заполнения таблицы. Подробности ошибки: %1 - + Error while populating table: %1 Ошибка при заполнении таблицы: %1 - + Could not commit transaction after table populating. Error details: %1 Невозможно завершить транзакцию после заполнения таблицы. Подробности ошибки: %1 @@ -778,71 +790,77 @@ Tables, indexes, triggers and views copied to database %3 will remain. QObject - - + + Could not open database: %1 Невозможно открыть базу данных: %1 - - + + Result set expired or no row available. Результирующая выборка устарела или ни одна строка не доступна. - + + + Could not load extension %1: %2 + + + + Could not close database: %1 Невозможно закрыть базу данных: %1 - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. SQLite %1 не поддерживает конструкцию '%2'. - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. SQLite %1 не поддерживает конструкцию '%2', однако можно создать обычную таблицу, если вы продолжите. - + Could not parse statement: %1 Error details: %2 Невозможно проанализировать структуру конструкции: %1 Подробности ошибки: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. SQLite %1 не поддерживает оператор '%2'. Невозможно сконвертировать конструкцию '%3' с этим оператором. - + SQLite %1 does not support the '%2' clause in the '%3' statement. SQLite %1 не поддерживает оператор '%2' в конструкции '%3'. - + SQLite %1 does not support current date or time clauses in expressions. SQLite %1 не поддерживает операторы текущей даты и текущего времени в выражениях. - + SQLite %1 does not support row value clauses in expressions. - + SQLite %1 не поддерживает операции со значениями строк в выражениях. - - - + + + SQLite %1 does not support '%2' clause in expressions. SQLite %1 не поддерживает оператор '%2' в выражениях. @@ -859,13 +877,13 @@ Error details: %2 - + Parser stack overflow Переполнение стека анализатора - + Syntax error Синтаксическая ошибка @@ -920,58 +938,58 @@ Error details: %2 Заполняющий код не может быть пустым. - + Could not resolve data source for column: %1 Невозможно определить источник данных для столбца: %1 - + Could not resolve table for column '%1'. Невозможно определить таблицу для столбца '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. Невозможно инициализировать файл конфигурации. Любые изменения конфигурации и история запросов будут утеряны после перезапуска приложения. Попытки инициализации файла предпринимались в следующих местах: %1. - + General purpose plugin category name Общего назначения - + Database support plugin category name Поддержка баз данных - + Code formatter plugin category name Форматирование кода - + Scripting languages plugin category name Скриптовые языки - + Exporting plugin category name Экспорт - + Importing plugin category name Импорт - + Table populating plugin category name Заполнение таблиц @@ -982,34 +1000,34 @@ Error details: %2 Таблица %1 ссылается на таблицу %2, но описание внешнего ключа не будет обновлено для описания новой таблицы из-за проблем с анализом DDL таблицы %3. - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. Все столбцы, проиндексированные индексом %1, удалены. Индекс не будет воссоздан после модификации таблицы. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. Возникла проблема при обработке триггера %1. Впоследствии он не будет полностью обновлён и потребует вашего внимания. - + Cannot not update trigger %1 according to table %2 modification. Невозможно обновить триггер %1 в соответствии с модификацией таблицы %2. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. Возникла проблема при обновлении конструкции %1 внутри триггера %2. Одна из вложенных конструкций %1, которая возможно ссылается на таблицу %3, не может быть корректно модифицирована. Возможно необходима ручная правка триггера. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. Все столбцы, затронутые в триггере %1, удалены. Триггер не будет воссоздан после модификации таблицы. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. Невозможно обновить представление %1 в соответствии с модификациями таблицы %2. @@ -1034,32 +1052,37 @@ The view will remain as it is. SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. SQLiteStudio не удалось определить столбцы, возвращаемые новым представлением, поэтому невозможно указать, какие триггеры могут сломаться в процессе воссоздания. + + + Could not open file '%1' for reading: %2 + + QueryExecutor - + Execution interrupted. Выполнение прервано. - + Database is not open. База данных не открыта. - + Only one query can be executed simultaneously. Одновременно может быть выполнен только один запрос. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 Возникла ошибка при выполнении запроса count(*), поэтому разбивка данных по страницам отключена. Детали ошибки из базы данных: %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. SQLiteStudio не удалось извлечь метаданные из запроса. Результаты нельзя будет редактировать. @@ -1080,31 +1103,31 @@ The view will remain as it is. SqlHistoryModel - + Database sql history header База данных - + Execution date sql history header Дата выполнения - + Time spent sql history header Затраченное время - + Rows affected sql history header Затронуто строк - + SQL sql history header SQL @@ -1113,204 +1136,183 @@ The view will remain as it is. UpdateManager - An error occurred while checking for updates: %1. - При проверке обновлений возникла ошибка: %1 + При проверке обновлений возникла ошибка: %1 - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - Невозможно проверить наличие обновлений, так как ответ сервера имеет некорректный формат. Это предупреждение можно проигнорировать. + Невозможно проверить наличие обновлений, так как ответ сервера имеет некорректный формат. Это предупреждение можно проигнорировать. - An error occurred while reading updates metadata: %1. - При чтении метаданных об обновлениях возникла ошибка: %1 + При чтении метаданных об обновлениях возникла ошибка: %1 - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - Невозможно загрузить обновления, так как ответ сервера имеет некорректный формат. Вы можете попробовать снова позже или скачать и установить обновления вручную. Подробности смотрите в <a href="%1">Руководстве пользователя</a>. + Невозможно загрузить обновления, так как ответ сервера имеет некорректный формат. Вы можете попробовать снова позже или скачать и установить обновления вручную. Подробности смотрите в <a href="%1">Руководстве пользователя</a>. - Could not create temporary directory for downloading the update. Updating aborted. - Невозможно создать временный каталог для загрузки обновления. Обновление прервано. + Невозможно создать временный каталог для загрузки обновления. Обновление прервано. - There was no updates to download. Updating aborted. - Нет обновлений для загрузки. Обновление прервано. + Нет обновлений для загрузки. Обновление прервано. - Downloading: %1 - Загрузка: %1 + Загрузка: %1 - Could not determinate file name from update URL: %1. Updating aborted. - Невозможно определить имя файла из URL обновления. Обновление прервано. + Невозможно определить имя файла из URL обновления. Обновление прервано. - Failed to open file '%1' for writting: %2. Updating aborted. - Не удалось открыть файл %1 для записи: %2. Обновление прервано. + Не удалось открыть файл %1 для записи: %2. Обновление прервано. - Installing updates. - Установка обновлений. + Установка обновлений. - Could not copy current application directory into %1 directory. - Невозможно скопировать текущий каталог приложения в каталог %1. + Невозможно скопировать текущий каталог приложения в каталог %1. - Could not create directory %1. - Невозможно создать каталог %1. + Невозможно создать каталог %1. - Could not rename directory %1 to %2. Details: %3 - Невозможно переименовать каталог %1 в %2. + Невозможно переименовать каталог %1 в %2. Подробности: %3 - Cannot not rename directory %1 to %2. Details: %3 - Невозможно переименовать каталог %1 в %2. + Невозможно переименовать каталог %1 в %2. Подробности: %3 - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - Невозможно переместить каталог %1 в %2, а также не удалось восстановить оригинальный каталог, поэтому оригинальный каталог SQLiteStudio теперь расположен в: %3 + Невозможно переместить каталог %1 в %2, а также не удалось восстановить оригинальный каталог, поэтому оригинальный каталог SQLiteStudio теперь расположен в: %3 - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - Невозможно переименовать каталог %1 в %2. Восстановлена изначальная версия SQLiteStudio. + Невозможно переименовать каталог %1 в %2. Восстановлена изначальная версия SQLiteStudio. - Could not unpack component %1 into %2 directory. - Невозможно распаковать компонент %1 в каталог %2. + Невозможно распаковать компонент %1 в каталог %2. - Could not find permissions elevator application to run update as a root. Looked for: %1 - Невозможно найти приложение повышения привилегий для запуска обновления с правами root. Были испробованы: %1 + Невозможно найти приложение повышения привилегий для запуска обновления с правами root. Были испробованы: %1 - Could not execute final updating steps as root: %1 - Невозможно выполнить финальные шаги обновления с правами root: %1 + Невозможно выполнить финальные шаги обновления с правами root: %1 - - - - Could not execute final updating steps as admin: %1 - Невозможно выполнить финальные шаги обновления с правами администратора: %1 + Невозможно выполнить финальные шаги обновления с правами администратора: %1 - Cannot create temporary directory for updater. - Невозможно создать временный каталог для установщика обновлений. + Невозможно создать временный каталог для установщика обновлений. - Cannot create updater script file. - Невозможно создать файл скрипта обновления. + Невозможно создать файл скрипта обновления. - Updating canceled. - Обновление отменено. + Обновление отменено. - Could not execute final updating steps as administrator. - Невозможно выполнить финальные шаги обновления с правами администратора. + Невозможно выполнить финальные шаги обновления с правами администратора. - Could not execute final updating steps as administrator. Updater startup timed out. - Невозможно выполнить финальные шаги обновления с правами администратора. Превышен тайм-аут запуска программы обновления. + Невозможно выполнить финальные шаги обновления с правами администратора. Превышен тайм-аут запуска программы обновления. - Could not execute final updating steps as administrator. Updater operation timed out. - Невозможно выполнить финальные шаги обновления с правами администратора. Превышен тайм-аут операции программы обновления. + Невозможно выполнить финальные шаги обновления с правами администратора. Превышен тайм-аут операции программы обновления. - Could not clean up temporary directory %1. You can delete it manually at any time. - Невозможно очистить временный каталог %1. Вы можете удалить его вручную в любое время. + Невозможно очистить временный каталог %1. Вы можете удалить его вручную в любое время. - Could not run new version for continuing update. - Невозможно запустить новую версию приложения для продолжения обновления. + Невозможно запустить новую версию приложения для продолжения обновления. - Package not in tar.gz format, cannot install: %1 - Пакет не в формате tar.gz, установка невозможна: %1 + Пакет не в формате tar.gz, установка невозможна: %1 - Package %1 cannot be installed, because cannot move it to directory: %2 - Пакет %1 не может быть установлен, так как невозможно перенести его в каталог: %2 + Пакет %1 не может быть установлен, так как невозможно перенести его в каталог: %2 - Package %1 cannot be installed, because cannot unpack it: %2 - Пакет %1 не может быть установлен, так как его невозможно распаковать: %2 + Пакет %1 не может быть установлен, так как его невозможно распаковать: %2 - Package not in zip format, cannot install: %1 - Пакет не в формате zip, установка невозможна: %1 + Пакет не в формате zip, установка невозможна: %1 - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 - Пакет %1 не может быть установлен, так как его невозможно распаковать в каталог %2: %3 + Пакет %1 не может быть установлен, так как его невозможно распаковать в каталог %2: %3 - Package %1 cannot be installed, because cannot unzip it to directory: %2 - Пакет %1 не может быть установлен, так как его невозможно распаковать в каталог: %2 + Пакет %1 не может быть установлен, так как его невозможно распаковать в каталог: %2 - - Could not rename directory %1 to %2. - Невозможно переименовать каталог %1 в %2. + Невозможно переименовать каталог %1 в %2. - Could not delete directory %1. - Невозможно удалить каталог %1. + Невозможно удалить каталог %1. - Error executing update command: %1 Error message: %2 - Ошибка при выполнении команды обновления: %1 + Ошибка при выполнении команды обновления: %1 Сообщение об ошибке: %2 - An error occurred while downloading updates: %1. Updating aborted. - При загрузке обновлений произошла ошибка: %1. Обновление прервано. + При загрузке обновлений произошла ошибка: %1. Обновление прервано. + + + + Updates installer executable is missing. + + + + + + Unable to check for updates (%1) + + + + + details are unknown + + + + + Unable to run updater application (%1). Please report this. + diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.qm index eb79951..de604e9 100644 Binary files a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.qm and b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.qm differ diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.ts index 3298d89..8db8efb 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_sk.ts @@ -4,13 +4,13 @@ AbstractDb - - + + Cannot execute query on closed database. Nemôžem spustiť dotaz na uzatvorenej databáze. - + Error attaching database %1: %2 Chyba pri pripájaní databázy %1: %2 @@ -18,9 +18,8 @@ BugReporter - Invalid login or password - Neplatné meno alebo heslo + Neplatné meno alebo heslo @@ -145,38 +144,51 @@ + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + DbManagerImpl - + Could not add database %1: %2 Nemôžem pridať databázu %1: %2 - + Database %1 could not be updated, because of an error: %2 Databáza %1 nemôže byť aktualizovaná kvôli chybe: %2 - - + + Database file doesn't exist. Databázový súbor neexistuje. - - - + + + No supporting plugin loaded. - + Database could not be initialized. - + No suitable database driver plugin found. @@ -243,17 +255,17 @@ Tables, indexes, triggers and views copied to database %3 will remain. DbVersionConverter - + Target file exists, but could not be overwritten. Cieľový súbor existuje ale nemôže byť prepísaný. - + Could not find proper database plugin to create target database. Nieje možné nájsť správny databázový plugin pre vytvorenie cieľovej databázy. - + Error while converting database: %1 Vyskytla sa chyba počas konvertovania databázy: %1 @@ -456,20 +468,20 @@ Tables, indexes, triggers and views copied to database %3 will remain. - - + + Error while importing data: %1 Vyskytla sa chyba počas importu dát: %1 - + Interrupted. import process status update - + Could not import data row number %1. The row was ignored. Problem details: %2 @@ -763,12 +775,12 @@ Tables, indexes, triggers and views copied to database %3 will remain. - + Error while populating table: %1 Vyskytla sa chyba počas napĺňania tabuľky: %1 - + Could not commit transaction after table populating. Error details: %1 @@ -776,71 +788,77 @@ Tables, indexes, triggers and views copied to database %3 will remain. QObject - - + + Could not open database: %1 - - + + Result set expired or no row available. - + + + Could not load extension %1: %2 + + + + Could not close database: %1 - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. - + Could not parse statement: %1 Error details: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. - + SQLite %1 does not support the '%2' clause in the '%3' statement. - + SQLite %1 does not support current date or time clauses in expressions. - + SQLite %1 does not support row value clauses in expressions. - - - + + + SQLite %1 does not support '%2' clause in expressions. @@ -857,13 +875,13 @@ Error details: %2 - + Parser stack overflow - + Syntax error Chyba syntaxe @@ -918,58 +936,58 @@ Error details: %2 - + Could not resolve data source for column: %1 - + Could not resolve table for column '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. - + General purpose plugin category name - + Database support plugin category name - + Code formatter plugin category name - + Scripting languages plugin category name Skriptovacie jazyky - + Exporting plugin category name - + Importing plugin category name - + Table populating plugin category name @@ -980,34 +998,34 @@ Error details: %2 - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. - + Cannot not update trigger %1 according to table %2 modification. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. @@ -1027,32 +1045,37 @@ The view will remain as it is. SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. + + + Could not open file '%1' for reading: %2 + + QueryExecutor - + Execution interrupted. - + Database is not open. - + Only one query can be executed simultaneously. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 Vyskytla sa chyba počas vykonávania dotazu count(*), dôsledkom čoho bolo zablokované stránkovanie. Detail chyby: %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. @@ -1073,32 +1096,32 @@ The view will remain as it is. SqlHistoryModel - + Database sql history header Dátum spustenia Databáza - + Execution date sql history header Dátum spustenia - + Time spent sql history header Trvanie dotazu - + Rows affected sql history header Počet riadkov - + SQL sql history header SQL @@ -1107,201 +1130,49 @@ The view will remain as it is. UpdateManager - An error occurred while checking for updates: %1. - Vyskytla sa chyba počas kontroly aktualizácii: %1. - - - - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - + Vyskytla sa chyba počas kontroly aktualizácii: %1. - - An error occurred while reading updates metadata: %1. - - - - - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - - - - - Could not create temporary directory for downloading the update. Updating aborted. - - - - - There was no updates to download. Updating aborted. - - - - Downloading: %1 - Sťahujem: %1 + Sťahujem: %1 - - Could not determinate file name from update URL: %1. Updating aborted. - - - - - Failed to open file '%1' for writting: %2. Updating aborted. - - - - Installing updates. - Inštalujem aktualizácie. - - - - Could not copy current application directory into %1 directory. - - - - - Could not create directory %1. - - - - - Could not rename directory %1 to %2. -Details: %3 - - - - - Cannot not rename directory %1 to %2. -Details: %3 - - - - - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - - - - - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - - - - - Could not unpack component %1 into %2 directory. - - - - - Could not find permissions elevator application to run update as a root. Looked for: %1 - - - - - Could not execute final updating steps as root: %1 - - - - - - - - Could not execute final updating steps as admin: %1 - - - - - Cannot create temporary directory for updater. - - - - - Cannot create updater script file. - - - - - Updating canceled. - - - - - Could not execute final updating steps as administrator. - + Inštalujem aktualizácie. - - Could not execute final updating steps as administrator. Updater startup timed out. - - - - - Could not execute final updating steps as administrator. Updater operation timed out. - - - - - Could not clean up temporary directory %1. You can delete it manually at any time. - - - - - Could not run new version for continuing update. - - - - - Package not in tar.gz format, cannot install: %1 - + Could not rename directory %1 to %2. + Nemôžem premenovať adresár %1na %2. - - Package %1 cannot be installed, because cannot move it to directory: %2 - + Could not delete directory %1. + Nemôžem vymazať adresár %1. - - Package %1 cannot be installed, because cannot unpack it: %2 - + An error occurred while downloading updates: %1. Updating aborted. + Vyskytla sa chyba počas sťahovani aktualizácií:%1. Aktualizácia zrušená. - - Package not in zip format, cannot install: %1 + + Updates installer executable is missing. - - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 + + + Unable to check for updates (%1) - - Package %1 cannot be installed, because cannot unzip it to directory: %2 + + details are unknown - - - Could not rename directory %1 to %2. - Nemôžem premenovať adresár %1na %2. - - - - Could not delete directory %1. - Nemôžem vymazať adresár %1. - - - - Error executing update command: %1 -Error message: %2 + + Unable to run updater application (%1). Please report this. - - - An error occurred while downloading updates: %1. Updating aborted. - Vyskytla sa chyba počas sťahovani aktualizácií:%1. Aktualizácia zrušená. - diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.qm b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.qm index 3c6eeb3..be651ee 100644 Binary files a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.qm and b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.qm differ diff --git a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.ts b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.ts index b9c43f2..2d84208 100644 --- a/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.ts +++ b/SQLiteStudio3/coreSQLiteStudio/translations/coreSQLiteStudio_zh_CN.ts @@ -4,13 +4,13 @@ AbstractDb - - + + Cannot execute query on closed database. - + Error attaching database %1: %2 @@ -18,9 +18,8 @@ BugReporter - Invalid login or password - 用户名或密码错误 + 用户名或密码错误 @@ -145,38 +144,51 @@ + + ConfigImpl + + + Could not start database transaction for deleting SQL history, therefore it's not deleted. + + + + + Could not commit database transaction for deleting SQL history, therefore it's not deleted. + + + DbManagerImpl - + Could not add database %1: %2 - + Database %1 could not be updated, because of an error: %2 - - + + Database file doesn't exist. - - - + + + No supporting plugin loaded. - + Database could not be initialized. - + No suitable database driver plugin found. @@ -243,17 +255,17 @@ Tables, indexes, triggers and views copied to database %3 will remain. DbVersionConverter - + Target file exists, but could not be overwritten. - + Could not find proper database plugin to create target database. - + Error while converting database: %1 @@ -456,20 +468,20 @@ Tables, indexes, triggers and views copied to database %3 will remain. - - + + Error while importing data: %1 - + Interrupted. import process status update - + Could not import data row number %1. The row was ignored. Problem details: %2 @@ -763,12 +775,12 @@ Tables, indexes, triggers and views copied to database %3 will remain. - + Error while populating table: %1 - + Could not commit transaction after table populating. Error details: %1 @@ -776,71 +788,77 @@ Tables, indexes, triggers and views copied to database %3 will remain. QObject - - + + Could not open database: %1 - - + + Result set expired or no row available. - + + + Could not load extension %1: %2 + + + + Could not close database: %1 - - - - - - - + + + + + + + SQLite %1 does not support '%2' statement. - + SQLite %1 does not support '%2' statement, but the regular table can be created instead if you proceed. - + Could not parse statement: %1 Error details: %2 - - - - + + + + SQLite %1 does not support the '%2' clause. Cannot convert '%3' statement with that clause. - + SQLite %1 does not support the '%2' clause in the '%3' statement. - + SQLite %1 does not support current date or time clauses in expressions. - + SQLite %1 does not support row value clauses in expressions. - - - + + + SQLite %1 does not support '%2' clause in expressions. @@ -857,13 +875,13 @@ Error details: %2 - + Parser stack overflow - + Syntax error @@ -918,58 +936,58 @@ Error details: %2 - + Could not resolve data source for column: %1 - + Could not resolve table for column '%1'. - + Could not initialize configuration file. Any configuration changes and queries history will be lost after application restart. Tried to initialize the file at following localizations: %1. - + General purpose plugin category name - + Database support plugin category name - + Code formatter plugin category name - + Scripting languages plugin category name - + Exporting plugin category name - + Importing plugin category name - + Table populating plugin category name @@ -980,34 +998,34 @@ Error details: %2 - + All columns indexed by the index %1 are gone. The index will not be recreated after table modification. - + There is problem with proper processing trigger %1. It may be not fully updated afterwards and will need your attention. - + Cannot not update trigger %1 according to table %2 modification. - - - + + + There is a problem with updating an %1 statement within %2 trigger. One of the %1 substatements which might be referring to table %3 cannot be properly modified. Manual update of the trigger may be necessary. - + All columns covered by the trigger %1 are gone. The trigger will not be recreated after table modification. - + Cannot not update view %1 according to table %2 modifications. The view will remain as it is. @@ -1027,32 +1045,37 @@ The view will remain as it is. SQLiteStudio was unable to resolve columns returned by the new view, therefore it won't be able to tell which triggers might fail during the recreation process. + + + Could not open file '%1' for reading: %2 + + QueryExecutor - + Execution interrupted. - + Database is not open. - + Only one query can be executed simultaneously. - - + + An error occured while executing the count(*) query, thus data paging will be disabled. Error details from the database: %1 - + SQLiteStudio was unable to extract metadata from the query. Results won't be editable. @@ -1073,31 +1096,31 @@ The view will remain as it is. SqlHistoryModel - + Database sql history header - + Execution date sql history header - + Time spent sql history header - + Rows affected sql history header - + SQL sql history header @@ -1106,200 +1129,24 @@ The view will remain as it is. UpdateManager - - An error occurred while checking for updates: %1. - - - - - Could not check available updates, because server responded with invalid message format. It is safe to ignore this warning. - - - - - An error occurred while reading updates metadata: %1. - - - - - Could not download updates, because server responded with invalid message format. You can try again later or download and install updates manually. See <a href="%1">User Manual</a> for details. - - - - - Could not create temporary directory for downloading the update. Updating aborted. - - - - - There was no updates to download. Updating aborted. - - - - - Downloading: %1 - - - - - Could not determinate file name from update URL: %1. Updating aborted. - - - - - Failed to open file '%1' for writting: %2. Updating aborted. - - - - - Installing updates. - - - - - Could not copy current application directory into %1 directory. - - - - - Could not create directory %1. - - - - - Could not rename directory %1 to %2. -Details: %3 - - - - - Cannot not rename directory %1 to %2. -Details: %3 - - - - - Could not move directory %1 to %2 and also failed to restore original directory, so the original SQLiteStudio directory is now located at: %3 - - - - - Could not rename directory %1 to %2. Rolled back to the original SQLiteStudio version. - - - - - Could not unpack component %1 into %2 directory. - - - - - Could not find permissions elevator application to run update as a root. Looked for: %1 - - - - - Could not execute final updating steps as root: %1 - - - - - - - - Could not execute final updating steps as admin: %1 - - - - - Cannot create temporary directory for updater. - - - - - Cannot create updater script file. - - - - - Updating canceled. - - - - - Could not execute final updating steps as administrator. - - - - - Could not execute final updating steps as administrator. Updater startup timed out. - - - - - Could not execute final updating steps as administrator. Updater operation timed out. - - - - - Could not clean up temporary directory %1. You can delete it manually at any time. - - - - - Could not run new version for continuing update. - - - - - Package not in tar.gz format, cannot install: %1 - - - - - Package %1 cannot be installed, because cannot move it to directory: %2 - - - - - Package %1 cannot be installed, because cannot unpack it: %2 - - - - - Package not in zip format, cannot install: %1 - - - - - Package %1 cannot be installed, because cannot unzip it to directory %2: %3 - - - - - Package %1 cannot be installed, because cannot unzip it to directory: %2 - - - - - - Could not rename directory %1 to %2. + + Updates installer executable is missing. - - Could not delete directory %1. + + + Unable to check for updates (%1) - - Error executing update command: %1 -Error message: %2 + + details are unknown - - An error occurred while downloading updates: %1. Updating aborted. + + Unable to run updater application (%1). Please report this. diff --git a/SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp b/SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp index a42c76d..62f6201 100644 --- a/SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/tsvserializer.cpp @@ -11,7 +11,7 @@ QString TsvSerializer::serialize(const QList& data) { QStringList outputRows; - foreach (const QStringList& dataRow, data) + for (const QStringList& dataRow : data) outputRows << serialize(dataRow); return outputRows.join(rowSeparator); @@ -22,7 +22,7 @@ QString TsvSerializer::serialize(const QStringList& data) QString value; bool hasQuote; QStringList outputCells; - foreach (const QString& rowValue, data) + for (const QString& rowValue : data) { value = rowValue; diff --git a/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp b/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp index 36ab457..1c03770 100644 --- a/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp @@ -55,7 +55,7 @@ void ViewModifier::handleTriggers() { SchemaResolver resolver(db); QList triggers = resolver.getParsedTriggersForView(view, true); - foreach (SqliteCreateTriggerPtr trigger, triggers) + for (SqliteCreateTriggerPtr trigger : triggers) { addOptionalSql(QString("DROP TRIGGER %1").arg(wrapObjIfNeeded(trigger->trigger, dialect))); @@ -84,7 +84,7 @@ void ViewModifier::collectNewColumns() return; } - foreach (const SelectResolver::Column& col, multiColumns.first()) + for (const SelectResolver::Column& col : multiColumns.first()) newColumns << col.column; } diff --git a/SQLiteStudio3/create_source_dist.sh b/SQLiteStudio3/create_source_dist.sh index 7c56e94..8fb9d4b 100755 --- a/SQLiteStudio3/create_source_dist.sh +++ b/SQLiteStudio3/create_source_dist.sh @@ -10,10 +10,11 @@ OLDDIR=`pwd` TEMP=`mktemp -d` cd $TEMP -svn co svn://sqlitestudio.pl/sqlitestudio3/$path sqlitestudio +#svn co svn://sqlitestudio.pl/sqlitestudio3/$path sqlitestudio +git clone https://github.com/pawelsalawa/sqlitestudio.git sqlitestudio cd sqlitestudio -rm -rf .svn +rm -rf .git .gitignore VERSION_INT=`cat SQLiteStudio3/coreSQLiteStudio/sqlitestudio.cpp | grep static | grep sqlitestudioVersion | sed 's/\;//'` VERSION=`echo $VERSION_INT | awk '{print int($6/10000) "." int($6/100%100) "." int($6%100)}'` diff --git a/SQLiteStudio3/guiSQLiteStudio/.DS_Store b/SQLiteStudio3/guiSQLiteStudio/.DS_Store new file mode 100644 index 0000000..74fa124 Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/.DS_Store differ diff --git a/SQLiteStudio3/guiSQLiteStudio/common/bindparam.h b/SQLiteStudio3/guiSQLiteStudio/common/bindparam.h new file mode 100644 index 0000000..76cdac1 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/common/bindparam.h @@ -0,0 +1,15 @@ +#ifndef BINDPARAM_H +#define BINDPARAM_H + +#include +#include + +struct BindParam +{ + int position = 0; + QString originalName; + QString newName; + QVariant value; +}; + +#endif // BINDPARAM_H diff --git a/SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp b/SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp index 655a9aa..35e99c8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp @@ -1,6 +1,7 @@ #include "datawidgetmapper.h" #include #include +#include DataWidgetMapper::DataWidgetMapper(QObject *parent) : QObject(parent) @@ -121,6 +122,7 @@ void DataWidgetMapper::submit() idx = model->index(currentIndex, entry->columnIndex); value = entry->widget->property(entry->propertyName.toLatin1().constData()); + qDebug() << "copying from form view for idx" << idx << "value:" << value; model->setData(idx, value, Qt::EditRole); } } diff --git a/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp b/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp index 8aaeefd..c67cc73 100644 --- a/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp @@ -80,7 +80,7 @@ void ExtActionContainer::defShortcut(int action, CfgStringEntry *cfgEntry) void ExtActionContainer::setShortcutContext(const QList actions, Qt::ShortcutContext context) { - foreach (qint32 act, actions) + for (qint32 act : actions) actionMap[act]->setShortcutContext(context); } @@ -100,6 +100,11 @@ void ExtActionContainer::attachActionInMenu(QAction* parentAction, QAction* chil menu->addAction(childAction); } +void ExtActionContainer::addSeparatorInMenu(int parentAction, QToolBar* toolbar) +{ + addSeparatorInMenu(actionMap[parentAction], toolbar); +} + void ExtActionContainer::addSeparatorInMenu(QAction *parentAction, QToolBar* toolbar) { QMenu* menu = getMenuForAction(parentAction, toolbar); @@ -125,7 +130,7 @@ void ExtActionContainer::createAction(int action, QAction* qAction, const QObjec void ExtActionContainer::deleteActions() { - foreach (QAction* action, actionMap.values()) + for (QAction* action : actionMap.values()) delete action; actionMap.clear(); @@ -133,7 +138,7 @@ void ExtActionContainer::deleteActions() void ExtActionContainer::refreshShortcuts() { - foreach (int action, actionMap.keys()) + for (int action : actionMap.keys()) { if (!shortcuts.contains(action)) continue; diff --git a/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.h b/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.h index 0c860f7..159d4e5 100644 --- a/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.h +++ b/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.h @@ -135,6 +135,7 @@ class GUI_API_EXPORT ExtActionContainer void attachActionInMenu(int parentAction, int childAction, QToolBar* toolbar); void attachActionInMenu(int parentAction, QAction* childAction, QToolBar* toolbar); void attachActionInMenu(QAction* parentAction, QAction* childAction, QToolBar* toolbar); + void addSeparatorInMenu(int parentAction, QToolBar* toolbar); void addSeparatorInMenu(QAction* parentAction, QToolBar *toolbar); void updateShortcutTips(); diff --git a/SQLiteStudio3/guiSQLiteStudio/common/userinputfilter.cpp b/SQLiteStudio3/guiSQLiteStudio/common/userinputfilter.cpp index 48ea46e..f3539d5 100644 --- a/SQLiteStudio3/guiSQLiteStudio/common/userinputfilter.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/common/userinputfilter.cpp @@ -1,5 +1,6 @@ #include "userinputfilter.h" #include "common/unused.h" +#include "common/lazytrigger.h" #include #include @@ -7,27 +8,23 @@ UserInputFilter::UserInputFilter(QLineEdit* lineEdit, QObject* filterHandler, co QObject(lineEdit), lineEdit(lineEdit) { - timer = new QTimer(this); - timer->setSingleShot(false); - timer->setInterval(200); - connect(lineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterModified(QString))); - connect(timer, SIGNAL(timeout()), this, SLOT(applyFilter())); + trigger = new LazyTrigger(200, this); + connect(lineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterModified())); + connect(trigger, SIGNAL(triggered()), this, SLOT(applyFilter())); connect(this, SIGNAL(applyFilter(QString)), filterHandler, handlerSlot); } void UserInputFilter::setDelay(int msecs) { - timer->setInterval(msecs); + trigger->setDelay(msecs); } -void UserInputFilter::filterModified(const QString& newValue) +void UserInputFilter::filterModified() { - UNUSED(newValue); - timer->start(); + trigger->schedule(); } void UserInputFilter::applyFilter() { - timer->stop(); emit applyFilter(lineEdit->text()); } diff --git a/SQLiteStudio3/guiSQLiteStudio/common/userinputfilter.h b/SQLiteStudio3/guiSQLiteStudio/common/userinputfilter.h index 1b6f7ee..36d54ed 100644 --- a/SQLiteStudio3/guiSQLiteStudio/common/userinputfilter.h +++ b/SQLiteStudio3/guiSQLiteStudio/common/userinputfilter.h @@ -4,8 +4,8 @@ #include "guiSQLiteStudio_global.h" #include -class QTimer; class QLineEdit; +class LazyTrigger; class GUI_API_EXPORT UserInputFilter : public QObject { @@ -17,11 +17,11 @@ class GUI_API_EXPORT UserInputFilter : public QObject void setDelay(int msecs); private: - QTimer* timer = nullptr; + LazyTrigger* trigger = nullptr; QLineEdit* lineEdit = nullptr; private slots: - void filterModified(const QString& newValue); + void filterModified(); void applyFilter(); signals: diff --git a/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp b/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp index 8543d37..f4098bc 100644 --- a/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp @@ -195,12 +195,11 @@ QVariant ConfigMapper::getCommonConfigValueFromWidget(QWidget* widget, CfgEntry* QVariant ConfigMapper::getCustomConfigValueFromWidget(QWidget* widget, CfgEntry* key, bool& ok) { - CustomConfigWidgetPlugin* plugin = nullptr; QList handlers; handlers += internalCustomConfigWidgets; handlers += PLUGINS->getLoadedPlugins(); - foreach (plugin, handlers) + for (CustomConfigWidgetPlugin* plugin : handlers) { if (plugin->isConfigForWidget(key, widget)) return plugin->getWidgetConfigValue(widget, ok); @@ -275,7 +274,7 @@ void ConfigMapper::saveFromWidget(QWidget *widget, bool noTransaction) if (!noTransaction && isPersistant()) CFG->beginMassSave(); - foreach (QWidget* w, allConfigWidgets) + for (QWidget* w : allConfigWidgets) saveWidget(w, allConfigEntries); if (!noTransaction && isPersistant()) @@ -369,12 +368,11 @@ void ConfigMapper::handleConfigComboBox(QWidget* widget, const QHash handlers; handlers += internalCustomConfigWidgets; handlers += PLUGINS->getLoadedPlugins(); - foreach (handler, handlers) + for (CustomConfigWidgetPlugin* handler : handlers) { if (handler->isConfigForWidget(key, widget)) { @@ -387,12 +385,11 @@ bool ConfigMapper::applyCustomConfigToWidget(CfgEntry* key, QWidget* widget, con bool ConfigMapper::connectCustomNotifierToWidget(QWidget* widget, CfgEntry* cfgEntry) { - CustomConfigWidgetPlugin* handler = nullptr; QList handlers; handlers += internalCustomConfigWidgets; handlers += PLUGINS->getLoadedPlugins(); - foreach (handler, handlers) + for (CustomConfigWidgetPlugin* handler : handlers) { if (handler->isConfigForWidget(cfgEntry, widget)) { @@ -429,12 +426,11 @@ void ConfigMapper::saveFromWidget(QWidget* widget, CfgEntry* cfgEntry) bool ConfigMapper::saveCustomConfigFromWidget(QWidget* widget, CfgEntry* key) { - CustomConfigWidgetPlugin* plugin = nullptr; QList handlers; handlers += internalCustomConfigWidgets; handlers += PLUGINS->getLoadedPlugins(); - foreach (plugin, handlers) + for (CustomConfigWidgetPlugin* plugin : handlers) { if (plugin->isConfigForWidget(key, widget)) { @@ -503,7 +499,7 @@ QList ConfigMapper::getAllConfigWidgets(QWidget *parent) { QList results; QWidget* widget = nullptr; - foreach (QObject* obj, parent->children()) + for (QObject* obj : parent->children()) { widget = qobject_cast(obj); if (!widget || widgetsToIgnore.contains(widget)) diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp index 9322117..5759f76 100644 --- a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp @@ -61,9 +61,9 @@ bool ColumnDefaultPanel::validate() if (exprOk) { // Everything looks fine, so lets do the final check - if the value is considered constant by SQLite. - static QString tempDdlLiteralTpl = QStringLiteral("CREATE TABLE temp.%1 (col DEFAULT %2);"); - static QString tempDdlExprTpl = QStringLiteral("CREATE TABLE temp.%1 (col DEFAULT (%2));"); - static QString dropTempDdl = QStringLiteral("DROP TABLE IF EXISTS temp.%1;"); + static QString tempDdlLiteralTpl = QStringLiteral("CREATE TEMP TABLE %1 (col DEFAULT %2);"); + static QString tempDdlExprTpl = QStringLiteral("CREATE TEMP TABLE %1 (col DEFAULT (%2));"); + static QString dropTempDdl = QStringLiteral("DROP TABLE %1;"); QString tableName = getTempTable(); QString tempDdl = tempDdlExprTpl.arg(tableName, ui->exprEdit->toPlainText()); @@ -75,7 +75,8 @@ bool ColumnDefaultPanel::validate() if (res->isError()) { exprOk = false; - exprError = tr("Invalid default value expression: %1").arg(res->getErrorText()); + exprError = tr("Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters.") + .arg(res->getErrorText()); } else currentMode = Mode::LITERAL; @@ -84,7 +85,8 @@ bool ColumnDefaultPanel::validate() currentMode = Mode::EXPR; db->exec(dropTempDdl.arg(tableName)); - } + } else + exprError = tr("Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters."); setValidState(ui->exprEdit, exprOk, exprError); setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint.")); @@ -269,7 +271,7 @@ void ColumnDefaultPanel::updateVirtualSql() QString ColumnDefaultPanel::getTempTable() { SchemaResolver resolver(db); - return resolver.getUniqueName("temp", "sqlitestudio_temp_table"); + return resolver.getUniqueName("sqlitestudio_temp_table"); } void ColumnDefaultPanel::updateState() diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp index f4eb3eb..af79331 100644 --- a/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp @@ -138,7 +138,7 @@ void ColumnForeignKeyPanel::readConstraint() ui->fkTableCombo->setCurrentText(constr->foreignKey->foreignTable); // Conditions - foreach (SqliteForeignKey::Condition* condition, constr->foreignKey->conditions) + for (SqliteForeignKey::Condition* condition : constr->foreignKey->conditions) readCondition(condition); // Initially, Deferrable diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp index d10b223..f8975d8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp @@ -94,13 +94,7 @@ void ColumnPrimaryKeyPanel::constraintAvailable() if (constraint.isNull()) return; - SqliteCreateTable::Column* column = dynamic_cast(constraint->parent()); ui->autoIncrCheck->setVisible(constraint->dialect == Dialect::Sqlite3); - ui->autoIncrCheck->setEnabled(column->type && - DataType::fromString(column->type->detokenize().trimmed(), Qt::CaseInsensitive) == DataType::INTEGER); - - if (!ui->autoIncrCheck->isEnabled()) - ui->autoIncrCheck->setText(tr("Autoincrement (only for %1 type columns)", "column primary key").arg("INTEGER")); readConstraint(); } diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp index f8390a1..8bc7926 100644 --- a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp @@ -156,7 +156,7 @@ void TableForeignKeyPanel::updateColumnState(int rowIdx, bool tableSelected) if (!wasEnabled && check->isEnabled()) { // Automatically set matching column - int idx = fkColumnsModel.stringList().indexOf(check->text()); + int idx = fkColumnsModel.stringList().indexOf(check->property(UI_PROP_COLUMN).toString()); if (idx > -1) combo->setCurrentIndex(idx); } @@ -191,7 +191,7 @@ void TableForeignKeyPanel::buildColumns() SqliteCreateTable* createTable = dynamic_cast(constraint->parentStatement()); int row = 0; - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) buildColumn(column, row++); } @@ -200,6 +200,7 @@ void TableForeignKeyPanel::buildColumn(SqliteCreateTable::Column* column, int ro int col = 0; QCheckBox* check = new QCheckBox(column->name); + check->setProperty(UI_PROP_COLUMN, column->name); columnsLayout->addWidget(check, row, col++); columnSignalMapping->setMapping(check, row); connect(check, SIGNAL(toggled(bool)), columnSignalMapping, SLOT(map())); @@ -228,7 +229,7 @@ void TableForeignKeyPanel::readConstraint() if (!constr->foreignKey->foreignTable.isNull()) ui->fkTableCombo->setCurrentText(constr->foreignKey->foreignTable); - foreach (SqliteForeignKey::Condition* condition, constr->foreignKey->conditions) + for (SqliteForeignKey::Condition* condition : constr->foreignKey->conditions) readCondition(condition); ui->deferrableCombo->setCurrentText(sqliteDeferrable(constr->foreignKey->deferrable)); @@ -245,10 +246,9 @@ void TableForeignKeyPanel::readConstraint() int idx; QCheckBox* check = nullptr; QComboBox* combo = nullptr; - SqliteIndexedColumn* localCol = nullptr; SqliteIndexedColumn* foreignCol = nullptr; int i = 0; - foreach (localCol, constr->indexedColumns) + for (SqliteIndexedColumn* localCol : constr->indexedColumns) { // Foreign col if (i < constr->foreignKey->indexedColumns.size()) @@ -312,7 +312,7 @@ void TableForeignKeyPanel::storeConfiguration() if (constr->foreignKey) delete constr->foreignKey; - foreach (SqliteIndexedColumn* idxCol, constr->indexedColumns) + for (SqliteIndexedColumn* idxCol : constr->indexedColumns) delete idxCol; constr->indexedColumns.clear(); @@ -334,7 +334,7 @@ void TableForeignKeyPanel::storeConfiguration() if (!check->isChecked()) continue; - idxCol = new SqliteIndexedColumn(check->text()); + idxCol = new SqliteIndexedColumn(check->property(UI_PROP_COLUMN).toString()); idxCol->setParent(constr); constr->indexedColumns << idxCol; @@ -407,7 +407,7 @@ int TableForeignKeyPanel::getColumnIndex(const QString& colName) { item = columnsLayout->itemAtPosition(i, 0)->widget(); cb = qobject_cast(item); - if (cb->text().compare(colName, Qt::CaseInsensitive) == 0) + if (cb->property(UI_PROP_COLUMN).toString().compare(colName, Qt::CaseInsensitive) == 0) return i; } return -1; diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp index f2a0ada..7c1c359 100644 --- a/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp @@ -71,6 +71,7 @@ void TablePrimaryKeyAndUniquePanel::buildColumn(SqliteCreateTable::Column* colum int col = 0; QCheckBox* check = new QCheckBox(column->name); + check->setProperty(UI_PROP_COLUMN, column->name); columnsLayout->addWidget(check, row, col++); columnSignalMapping->setMapping(check, row); connect(check, SIGNAL(toggled(bool)), columnSignalMapping, SLOT(map())); @@ -109,7 +110,7 @@ int TablePrimaryKeyAndUniquePanel::getColumnIndex(const QString& colName) { item = columnsLayout->itemAtPosition(i, 0)->widget(); cb = qobject_cast(item); - if (cb->text().compare(colName, Qt::CaseInsensitive) == 0) + if (cb->property(UI_PROP_COLUMN).toString().compare(colName, Qt::CaseInsensitive) == 0) return i; } return -1; @@ -190,7 +191,7 @@ void TablePrimaryKeyAndUniquePanel::storeConfiguration() constr->onConflict = sqliteConflictAlgo(ui->conflictComboBox->currentText()); // Columns - foreach (SqliteIndexedColumn* idxCol, constr->indexedColumns) + for (SqliteIndexedColumn* idxCol : constr->indexedColumns) delete idxCol; constr->indexedColumns.clear(); @@ -207,7 +208,7 @@ void TablePrimaryKeyAndUniquePanel::storeConfiguration() if (!check->isChecked()) continue; - name = check->text(); + name = check->property(UI_PROP_COLUMN).toString(); if (constr->dialect == Dialect::Sqlite3) { @@ -256,7 +257,7 @@ void TablePrimaryKeyAndUniquePanel::readConstraint() int idx; QCheckBox* check = nullptr; QComboBox* combo = nullptr; - foreach (SqliteIndexedColumn* idxCol, constr->indexedColumns) + for (SqliteIndexedColumn* idxCol : constr->indexedColumns) { idx = getColumnIndex(idxCol->name); if (idx < 0) @@ -294,6 +295,6 @@ void TablePrimaryKeyAndUniquePanel::buildColumns() SqliteCreateTable* createTable = dynamic_cast(constraint->parentStatement()); int row = 0; - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) buildColumn(column, row++); } diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.cpp index c538990..bad4910 100644 --- a/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableprimarykeypanel.cpp @@ -1,5 +1,6 @@ #include "tableprimarykeypanel.h" #include "ui_tablepkanduniquepanel.h" +#include "uiutils.h" #include TablePrimaryKeyPanel::TablePrimaryKeyPanel(QWidget *parent) : @@ -50,7 +51,7 @@ void TablePrimaryKeyPanel::updateState() item = columnsLayout->itemAtPosition(i, 0)->widget(); cb = qobject_cast(item); if (cb->isChecked()) - columns << cb->text(); + columns << cb->property(UI_PROP_COLUMN).toString(); } if (columns.size() != 1) diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp index 4a04736..b8ebf45 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp @@ -284,7 +284,7 @@ QString SqlQueryItem::getToolTip() const { rows << emptyRow; rows << hdrRowTmp.arg(ICONS.COLUMN_CONSTRAINT.getPath()).arg(tr("Constraints:", "data view tooltip")).arg(""); - foreach (SqlQueryModelColumn::Constraint* constr, col->constraints) + for (SqlQueryModelColumn::Constraint* constr : col->constraints) rows << constrRowTmp.arg(constr->getIcon()->toUrl()).arg(constr->getTypeString()).arg(constr->getDetails()); } @@ -447,7 +447,7 @@ QString SqlQueryItem::loadFullData() // ROWID RowIdConditionBuilder rowIdBuilder; - rowIdBuilder.setRowId(getRowId()); + rowIdBuilder.setRowId(getRowId(), dialect); QString rowId = rowIdBuilder.build(); queryArgs = rowIdBuilder.getQueryArgs(); diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp index 74a82ca..64d37e4 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp @@ -85,7 +85,6 @@ QString SqlQueryItemDelegate::displayText(const QVariant& value, const QLocale& void SqlQueryItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { // No need to check or load full data, it is already preloaded if necessary in createEditor(). - QComboBox* cb = dynamic_cast(editor); QLineEdit* le = dynamic_cast(editor); if (cb) { @@ -102,17 +101,29 @@ void SqlQueryItemDelegate::setEditorDataForFk(QComboBox* cb, const QModelIndex& const SqlQueryModel* queryModel = dynamic_cast(index.model()); SqlQueryItem* item = queryModel->itemFromIndex(index); QVariant modelData = item->getValue(); - int idx = cb->findData(modelData, Qt::UserRole); - if (idx == -1 ) + + SqlQueryModel* cbModel = dynamic_cast(cb->model()); + SqlQueryItem* foundItem = cbModel->findAnyInColumn(0, SqlQueryItem::DataRole::VALUE, modelData); + int idx = -1; + if (foundItem) + idx = foundItem->index().row(); + + if (idx == -1 && modelData.isValid()) { - cb->addItem(modelData.toString(), modelData); - idx = cb->count() - 1; + idx = 0; + QList values; + values << modelData; + for (int i = 1; i < cbModel->columnCount(); i++) + values << QVariant(); + + cbModel->insertCustomRow(values, idx); SqlQueryView* view = dynamic_cast(cb->view()); view->resizeColumnsToContents(); view->setMinimumWidth(view->horizontalHeader()->length()); } cb->setCurrentIndex(idx); + cb->lineEdit()->selectAll(); } void SqlQueryItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const @@ -171,21 +182,26 @@ void SqlQueryItemDelegate::setModelDataForLineEdit(QLineEdit* editor, QAbstractI if (CFG_UI.General.KeepNullWhenEmptyValue.get() && model->data(index, Qt::EditRole).isNull() && value.isEmpty()) return; - bool ok; - QVariant variant = value.toLongLong(&ok); - if (ok) - { - model->setData(index, variant, Qt::EditRole); - return; - } + const SqlQueryModel* queryModel = dynamic_cast(model); + SqlQueryItem* item = queryModel->itemFromIndex(index); - variant = value.toDouble(&ok); - if (ok) + if (item->getColumn()->dataType.isNumeric()) { - model->setData(index, variant, Qt::EditRole); - return; - } + bool ok; + QVariant variant = value.toLongLong(&ok); + if (ok) + { + model->setData(index, variant, Qt::EditRole); + return; + } + variant = value.toDouble(&ok); + if (ok) + { + model->setData(index, variant, Qt::EditRole); + return; + } + } model->setData(index, value, Qt::EditRole); } @@ -262,7 +278,7 @@ QString SqlQueryItemDelegate::getSqlForFkEditor(SqlQueryItem* item) const if (fk->foreignColumn.compare(srcCol, Qt::CaseInsensitive) == 0) continue; // Exclude matching column. We don't want the same column several times. - fullSrcCol = src + "." + srcCol; + fullSrcCol = src + "." + wrapObjIfNeeded(srcCol, dialect); selectedCols << srcColTpl.arg(cellLimitTpl.arg(CELL_LENGTH_LIMIT).arg(fullSrcCol), wrapObjName(fullSrcCol, dialect)); } @@ -318,22 +334,21 @@ void SqlQueryItemDelegate::fkDataReady() // Set selected combo value to initial value from the cell QComboBox* cb = modelToFkCombo[model]; - QVariant value = modelToFkInitialValue[model]; + QVariant valueFromQueryModel = modelToFkInitialValue[model]; + if (model->rowCount() > 0) { QModelIndex startIdx = model->index(0, 0); QModelIndex endIdx = model->index(model->rowCount() - 1, 0); - QModelIndexList idxList = model->findIndexes(startIdx, endIdx, SqlQueryItem::DataRole::VALUE, value, 1); + QModelIndexList idxList = model->findIndexes(startIdx, endIdx, SqlQueryItem::DataRole::VALUE, valueFromQueryModel, 1); if (idxList.size() > 0) cb->setCurrentIndex(idxList.first().row()); else - cb->setCurrentText(value.toString()); + cb->setCurrentText(valueFromQueryModel.toString()); } else - { - cb->setCurrentText(value.toString()); - } + cb->setCurrentText(valueFromQueryModel.toString()); } void SqlQueryItemDelegate::fkDataFailed(const QString &errorText) @@ -401,6 +416,7 @@ QWidget* SqlQueryItemDelegate::getFkEditor(SqlQueryItem* item, QWidget* parent, queryModel->setHardRowLimit(MAX_ROWS_FOR_FK); queryModel->setDb(db); queryModel->setQuery(sql); + queryModel->setAsyncMode(false); queryModel->executeQuery(); queryView->verticalHeader()->setVisible(false); diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp index 009b05a..ff025df 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp @@ -68,6 +68,16 @@ void SqlQueryModel::setExplainMode(bool explain) this->explain = explain; } +void SqlQueryModel::setParams(const QHash& params) +{ + queryParams = params; +} + +void SqlQueryModel::setAsyncMode(bool enabled) +{ + queryExecutor->setAsyncMode(enabled); +} + void SqlQueryModel::executeQuery() { if (queryExecutor->isExecutionInProgress()) @@ -121,6 +131,7 @@ void SqlQueryModel::executeQueryInternal() emit executionStarted(); queryExecutor->setQuery(query); + queryExecutor->setParams(queryParams); queryExecutor->setResultsPerPage(getRowsPerPage()); queryExecutor->setExplainMode(explain); queryExecutor->setPreloadResults(true); @@ -224,6 +235,15 @@ QList SqlQueryModel::findItems(const QModelIndex& start, const QM return toItemList(findIndexes(start, end, role, value, hits)); } +SqlQueryItem* SqlQueryModel::findAnyInColumn(int column, int role, const QVariant &value) const +{ + QList itemList = toItemList(findIndexes(index(0, column), index(rowCount() - 1, column), role, value, 1)); + if (itemList.isEmpty()) + return nullptr; + + return itemList[0]; +} + QList SqlQueryModel::getUncommittedItems() const { return findItems(SqlQueryItem::DataRole::UNCOMMITTED, true); @@ -242,7 +262,7 @@ QHash > SqlQueryModel::groupItemsByTable(cons { QHash> itemsByTable; AliasedTable table; - foreach (SqlQueryItem* item, items) + for (SqlQueryItem* item : items) { if (item->getColumn()) { @@ -264,7 +284,7 @@ QList SqlQueryModel::filterOutCommittedItems(const QList newList; - foreach (SqlQueryItem* item, items) + for (SqlQueryItem* item : items) if (item->isUncommitted()) newList << item; @@ -288,7 +308,7 @@ SqlQueryModel::Features SqlQueryModel::features() const QList SqlQueryModel::toItemList(const QModelIndexList& indexes) const { QList list; - foreach (const QModelIndex& idx, indexes) + for (const QModelIndex& idx : indexes) list << itemFromIndex(idx); return list; @@ -452,7 +472,7 @@ void SqlQueryModel::commitInternal(const QList& items) void SqlQueryModel::rollbackInternal(const QList& items) { QList > groupedItems = groupItemsByRows(items); - foreach (const QList& itemsInRow, groupedItems) + for (const QList& itemsInRow : groupedItems) rollbackRow(itemsInRow); emit commitStatusChanged(getUncommittedItems().size() > 0); @@ -611,7 +631,7 @@ bool SqlQueryModel::commitEditedRow(const QList& itemsInRow) // RowId queryBuilder.clear(); rowId = items.first()->getRowId(); - queryBuilder.setRowId(rowId); + queryBuilder.setRowId(rowId, dialect); newRowId = getNewRowId(rowId, items); // if any of item updates any of rowid columns, then this will be different than initial rowid // Database and table @@ -692,13 +712,13 @@ void SqlQueryModel::rollbackAddedRow(const QList& itemsInRow) void SqlQueryModel::rollbackEditedRow(const QList& itemsInRow) { - foreach (SqlQueryItem* item, itemsInRow) + for (SqlQueryItem* item : itemsInRow) item->rollback(); } void SqlQueryModel::rollbackDeletedRow(const QList& itemsInRow) { - foreach (SqlQueryItem* item, itemsInRow) + for (SqlQueryItem* item : itemsInRow) item->rollback(); } @@ -719,7 +739,7 @@ SqlQueryModelColumnPtr SqlQueryModel::getColumnModel(const QString& table, const QList SqlQueryModel::getTableColumnModels(const QString& database, const QString& table) { QList results; - foreach (SqlQueryModelColumnPtr modelColumn, columns) + for (SqlQueryModelColumnPtr modelColumn : columns) { if (modelColumn->database.compare(database, Qt::CaseInsensitive) != 0) continue; @@ -788,7 +808,7 @@ QList SqlQueryModel::loadRow(SqlResultsRowPtr row) SqlQueryItem* item = nullptr; RowId rowId; int colIdx = 0; - foreach (const QVariant& value, row->valueList().mid(0, resultColumnCount)) + for (const QVariant& value : row->valueList().mid(0, resultColumnCount)) { item = new SqlQueryItem(); rowId = getRowIdValue(row, colIdx); @@ -931,7 +951,7 @@ void SqlQueryModel::readColumns() int totalRowIdCols = 0; AliasedTable aliasedTable; DbAndTable dbAndTable; - foreach (const QueryExecutor::ResultRowIdColumnPtr& resCol, queryExecutor->getRowIdResultColumns()) + for (const QueryExecutor::ResultRowIdColumnPtr& resCol : queryExecutor->getRowIdResultColumns()) { if (resCol->dbName.isEmpty() || resCol->dbName.toLower() == "main" || resCol->dbName.toLower() == "temp") dbAndTable.setDb(db); @@ -957,6 +977,16 @@ void SqlQueryModel::readColumns() tablesForColumns = getTablesForColumns(); columnEditionStatus = getColumnEditionEnabledList(); + // Rows limit to avoid out of memory problems + columnRatioBasedRowLimit = -1; + int rowsPerPage = getRowsPerPage(); + if (!columns.isEmpty()) + columnRatioBasedRowLimit = 150000 / columns.size(); + + if (columnRatioBasedRowLimit > -1 && columnRatioBasedRowLimit < rowsPerPage) + NOTIFY_MANAGER->info(tr("Number of rows per page was decreased to %1 due to number of columns (%2) in the data view.") + .arg(columnRatioBasedRowLimit).arg(columns.size())); + // We have fresh info about columns structureOutOfDate = false; } @@ -965,7 +995,7 @@ void SqlQueryModel::readColumnDetails() { // Preparing global (table oriented) edition forbidden reasons QSet editionForbiddenGlobalReasons; - foreach (QueryExecutor::EditionForbiddenReason reason, queryExecutor->getEditionForbiddenGlobalReasons()) + for (QueryExecutor::EditionForbiddenReason reason : queryExecutor->getEditionForbiddenGlobalReasons()) editionForbiddenGlobalReasons << SqlQueryModelColumn::convert(reason); // Reading all the details from query executor source tables @@ -981,7 +1011,7 @@ void SqlQueryModel::readColumnDetails() SqliteColumnTypePtr modelColumnType; SqlQueryModelColumn::Constraint* modelConstraint = nullptr; - foreach (const QueryExecutor::ResultColumnPtr& resCol, queryExecutor->getResultColumns()) + for (const QueryExecutor::ResultColumnPtr& resCol : queryExecutor->getResultColumns()) { // Creating new column for the model (this includes column oriented forbidden reasons) modelColumn = SqlQueryModelColumnPtr::create(resCol); @@ -1002,7 +1032,7 @@ void SqlQueryModel::readColumnDetails() modelColumn->dataType = DataType(modelColumnType->name, modelColumnType->precision, modelColumnType->scale); // Column constraints - foreach (SqliteCreateTable::Column::ConstraintPtr constrPtr, colDetails.constraints) + for (SqliteCreateTable::Column::ConstraintPtr constrPtr : colDetails.constraints) { modelConstraint = SqlQueryModelColumn::Constraint::create(constrPtr); if (modelConstraint) @@ -1010,7 +1040,7 @@ void SqlQueryModel::readColumnDetails() } // Table constraints - foreach (SqliteCreateTable::ConstraintPtr constrPtr, details.constraints) + for (SqliteCreateTable::ConstraintPtr constrPtr : details.constraints) { modelConstraint = SqlQueryModelColumn::Constraint::create(modelColumn->column, constrPtr); if (modelConstraint) @@ -1036,7 +1066,7 @@ QHash SqlQueryModel::readTableDetails AliasedTable table; QString columnName; - foreach (const QueryExecutor::SourceTablePtr& srcTable, queryExecutor->getSourceTables()) + for (const QueryExecutor::SourceTablePtr& srcTable : queryExecutor->getSourceTables()) { database = srcTable->database.isEmpty() ? "main" : srcTable->database; @@ -1054,11 +1084,11 @@ QHash SqlQueryModel::readTableDetails table = {database, srcTable->table, srcTable->alias}; // Table constraints - foreach (SqliteCreateTable::Constraint* tableConstr, createTable->constraints) + for (SqliteCreateTable::Constraint* tableConstr : createTable->constraints) tableDetails.constraints << tableConstr->detach(); // Table columns - foreach (SqliteCreateTable::Column* columnStmt, createTable->columns) + for (SqliteCreateTable::Column* columnStmt : createTable->columns) { // Column details TableDetails::ColumnDetails columnDetails; @@ -1071,7 +1101,7 @@ QHash SqlQueryModel::readTableDetails columnDetails.type = SqliteColumnTypePtr(); // Column constraints - foreach (SqliteCreateTable::Column::Constraint* columnConstr, columnStmt->constraints) + for (SqliteCreateTable::Column::Constraint* columnConstr : columnStmt->constraints) columnDetails.constraints << columnConstr->detach(); tableDetails.columns[columnName] = columnDetails; @@ -1088,7 +1118,7 @@ QList SqlQueryModel::getTablesForColumns() { QList columnTables; AliasedTable table; - foreach (SqlQueryModelColumnPtr column, columns) + for (SqlQueryModelColumnPtr column : columns) { if (column->editionForbiddenReason.size() > 0) { @@ -1104,7 +1134,7 @@ QList SqlQueryModel::getTablesForColumns() QList SqlQueryModel::getColumnEditionEnabledList() { QList columnEditionEnabled; - foreach (SqlQueryModelColumnPtr column, columns) + for (SqlQueryModelColumnPtr column : columns) columnEditionEnabled << (column->editionForbiddenReason.size() == 0); return columnEditionEnabled; @@ -1120,7 +1150,7 @@ void SqlQueryModel::updateColumnsHeader() void SqlQueryModel::updateColumnHeaderLabels() { headerColumns.clear(); - foreach (SqlQueryModelColumnPtr column, columns) + for (SqlQueryModelColumnPtr column : columns) { headerColumns << column->displayName; } @@ -1399,7 +1429,7 @@ void SqlQueryModel::updateSelectiveCommitRollbackActions(const QItemSelection& s bool result = false; if (selectedItems.size() > 0) { - foreach (SqlQueryItem* item, selectedItems) + for (SqlQueryItem* item : selectedItems) { if (item->isUncommitted()) { @@ -1542,6 +1572,9 @@ int SqlQueryModel::getRowsPerPage() const if (hardRowLimit > -1) rowsPerPage = hardRowLimit; + if (columnRatioBasedRowLimit > -1 && columnRatioBasedRowLimit < rowsPerPage) + rowsPerPage = columnRatioBasedRowLimit; + return rowsPerPage; } @@ -1555,6 +1588,46 @@ void SqlQueryModel::setQueryCountLimitForSmartMode(int value) queryExecutor->setQueryCountLimitForSmartMode(value); } +void SqlQueryModel::insertCustomRow(const QList &values, int insertionIndex) +{ + SqlQueryItem* cellItem = nullptr; + int colIdx = 0; + QList row; + for (const QVariant& value : values) + { + cellItem = new SqlQueryItem(); + updateItem(cellItem, value, colIdx++, RowId()); + row << cellItem; + } + insertRow(insertionIndex, row); +} + +void SqlQueryModel::setDesiredColumnWidth(int colIdx, int width) +{ + SqlQueryModelColumnPtr columnModel = columns[colIdx]; + if (!columnModel) + { + qWarning() << "Missing column model for column with index" << colIdx << "while resizing column."; + return; + } + + Column column(columnModel->database, columnModel->table, columnModel->column); + columnWidths[column] = width; +} + +int SqlQueryModel::getDesiredColumnWidth(int colIdx) +{ + SqlQueryModelColumnPtr columnModel = columns[colIdx]; + if (!columnModel) + return -1; + + Column column(columnModel->database, columnModel->table, columnModel->column); + if (!columnWidths.contains(column)) + return -1; + + return columnWidths[column]; +} + bool SqlQueryModel::isStructureOutOfDate() const { return structureOutOfDate; @@ -1610,7 +1683,7 @@ void SqlQueryModel::deleteSelectedRows() { QList selectedItems = view->getSelectedItems(); QSet rows; - foreach (SqlQueryItem* item, selectedItems) + for (SqlQueryItem* item : selectedItems) rows << item->index().row(); QList rowList = rows.toList(); @@ -1618,7 +1691,7 @@ void SqlQueryModel::deleteSelectedRows() QList newItemsToDelete; int cols = columnCount(); - foreach (int row, rowList) + for (int row : rowList) { for (int colIdx = 0; colIdx < cols; colIdx++) { @@ -1634,7 +1707,7 @@ void SqlQueryModel::deleteSelectedRows() } } - foreach (SqlQueryItem* item, newItemsToDelete) + for (SqlQueryItem* item : newItemsToDelete) removeRow(item->index().row()); emit commitStatusChanged(getUncommittedItems().size() > 0); @@ -1675,6 +1748,18 @@ void SqlQueryModel::applyRegExpFilter(const QString& value) // For custom query this is not supported. } +void SqlQueryModel::applyStringFilter(const QStringList& values) +{ + UNUSED(values); + // For custom query this is not supported. +} + +void SqlQueryModel::applyRegExpFilter(const QStringList& values) +{ + UNUSED(values); + // For custom query this is not supported. +} + void SqlQueryModel::resetFilter() { // For custom query this is not supported. @@ -1719,6 +1804,9 @@ QVariant SqlQueryModel::headerData(int section, Qt::Orientation orientation, int if (role == Qt::FontRole) return CFG_UI.Fonts.DataView.get(); + if (role == Qt::TextAlignmentRole && orientation == Qt::Horizontal) + return Qt::AlignLeft; + return QAbstractItemModel::headerData(section, orientation, role); } diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h index 7a4c282..6c17740 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h @@ -42,6 +42,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel QString getQuery() const; void setQuery(const QString &value); void setExplainMode(bool explain); + void setParams(const QHash& params); Db* getDb() const; void setDb(Db* value); qint64 getExecutionTime(); @@ -55,6 +56,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel QModelIndexList findIndexes(const QModelIndex &start, const QModelIndex& end, int role, const QVariant &value, int hits = -1) const; QList findItems(int role, const QVariant &value, int hits = -1) const; QList findItems(const QModelIndex &start, const QModelIndex& end, int role, const QVariant &value, int hits = -1) const; + SqlQueryItem* findAnyInColumn(int column, int role, const QVariant &value) const; QList getUncommittedItems() const; QList getRow(int row); int columnCount(const QModelIndex& parent = QModelIndex()) const; @@ -63,6 +65,16 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel void loadFullDataForEntireRow(int row); StrHash attachDependencyTables(); void detachDependencyTables(); + + /** + * @brief Disables or re-enables async query execution + * @param enabled True to set async mode enabled, false to set synchronous mode. + * + * This option is forwarded directly to the query executor. + * + * By default mode is asynchronous, but in some cases synchronous mode may be useful (like in FK combobox). + */ + void setAsyncMode(bool enabled); virtual QString generateSelectQueryForItems(const QList& items); virtual QString generateInsertQueryForItems(const QList& items); virtual QString generateUpdateQueryForItems(const QList& items); @@ -71,7 +83,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel virtual Features features() const; /** - * @brief applySqlFilter + * @brief Request for applying SQL expression filtering on a dataset. * @param value Filter expression. * Default implementation does nothing. Working implementation (i.e. for a table) * should set the query to temporary value which respects given filter and reload the data. @@ -80,7 +92,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel virtual void applySqlFilter(const QString& value); /** - * @brief applyStringFilter + * @brief Request for applying "LIKE" filtering on a dataset. * @param value Filter expression. * Default implementation does nothing. Working implementation (i.e. for a table) * should set the query to temporary value which respects given filter and reload the data. @@ -89,7 +101,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel virtual void applyStringFilter(const QString& value); /** - * @brief applyStringFilter + * @brief Request for applying Regular Expression filtering on a dataset. * @param value Filter expression. * Default implementation does nothing. Working implementation (i.e. for a table) * should set the query to temporary value which respects given filter and reload the data. @@ -97,6 +109,22 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel */ virtual void applyRegExpFilter(const QString& value); + /** + * @brief Request for applying "LIKE" filtering on a dataset. + * @param values Filter expressions per column. + * This is the same as applyStringFilter(const QString&), but is used for per-column filtering, + * when user enters filtering expressions for each column sparately. + */ + virtual void applyStringFilter(const QStringList& values); + + /** + * @brief Request for applying Regular Expression filtering on a dataset. + * @param values Filter expressions per column. + * This is the same as applyRegExpFilter(const QString&), but is used for per-column filtering, + * when user enters filtering expressions for each column sparately. + */ + virtual void applyRegExpFilter(const QStringList& values); + /** * @brief resetFilter * Default implementation does nothing. Working implementation (i.e. for a table) @@ -145,10 +173,15 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel int getQueryCountLimitForSmartMode() const; void setQueryCountLimitForSmartMode(int value); + void insertCustomRow(const QList& values, int insertionIndex); + + void setDesiredColumnWidth(int colIdx, int width); + int getDesiredColumnWidth(int colIdx); + protected: class CommitUpdateQueryBuilder : public RowIdConditionBuilder { - public: + public: void clear(); void setDatabase(const QString& database); @@ -302,6 +335,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel int getRowsPerPage() const; QString query; + QHash queryParams; bool explain = false; bool simpleExecutionMode = false; @@ -366,6 +400,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel QueryExecutor::SortList sortOrder; QHash columnMap; + QHash columnWidths; QHash> tableToRowIdColumn; QStringList headerColumns; int rowNumBase = 0; @@ -382,6 +417,16 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel */ int hardRowLimit = -1; + /** + * @brief Limit for rows in case there is many columns. + * + * -1 to not apply the limit. This is set during reading columns. If there is many columns, + * we need to keep maximum limit of rows at pace, so we don't overuse the RAM. + * This limit is soft, meaning it applies only if it's smaller than configured limit or hardRowLimit. + * If any of two limits mentioned above are smaller, this limit will not come to the play. + */ + int columnRatioBasedRowLimit = -1; + int resultColumnCount = 0; /** diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp index 3a2457c..688e05a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp @@ -9,13 +9,13 @@ SqlQueryModelColumn::SqlQueryModelColumn(const QueryExecutor::ResultColumnPtr& r table = resultColumn->table; tableAlias = resultColumn->tableAlias; database = resultColumn->database.isEmpty() ? "main": resultColumn->database; - foreach (QueryExecutor::ColumnEditionForbiddenReason reason, resultColumn->editionForbiddenReasons) + for (QueryExecutor::ColumnEditionForbiddenReason reason : resultColumn->editionForbiddenReasons) editionForbiddenReason << SqlQueryModelColumn::convert(reason); } SqlQueryModelColumn::~SqlQueryModelColumn() { - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) delete constr; constraints.clear(); @@ -116,7 +116,7 @@ bool SqlQueryModelColumn::isRowIdPk() const if (dataType.getType() != DataType::INTEGER) return false; - foreach (ConstraintPk* pk, getConstraints()) + for (ConstraintPk* pk : getConstraints()) if (pk->scope == Constraint::Scope::COLUMN) return true; @@ -125,7 +125,7 @@ bool SqlQueryModelColumn::isRowIdPk() const bool SqlQueryModelColumn::isAutoIncr() const { - foreach (ConstraintPk* pk, getConstraints()) + for (ConstraintPk* pk : getConstraints()) if (pk->autoIncrement) return true; @@ -334,7 +334,7 @@ template QList SqlQueryModelColumn::getConstraints() const { QList results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (dynamic_cast(constr)) results << dynamic_cast(constr); diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp index 9f58fd2..4364986 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp @@ -17,7 +17,6 @@ #include "common/utils_sql.h" #include "querygenerator.h" #include "services/codeformatter.h" -#include #include #include #include @@ -29,6 +28,8 @@ #include #include #include +#include +#include CFG_KEYS_DEFINE(SqlQueryView) @@ -55,9 +56,18 @@ void SqlQueryView::init() contextMenu = new QMenu(this); referencedTablesMenu = new QMenu(tr("Go to referenced row in..."), contextMenu); + setHorizontalHeader(new Header(this)); + connect(this, &QWidget::customContextMenuRequested, this, &SqlQueryView::customContextMenuRequested); connect(CFG_UI.Fonts.DataView, SIGNAL(changed(QVariant)), this, SLOT(updateFont())); connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(itemActivated(QModelIndex))); + connect(horizontalHeader(), &QHeaderView::sectionResized, [this](int section, int, int newSize) + { + if (ignoreColumnWidthChanges) + return; + + getModel()->setDesiredColumnWidth(section, newSize); + }); horizontalHeader()->setSortIndicatorShown(false); horizontalHeader()->setSectionsClickable(true); @@ -77,12 +87,13 @@ void SqlQueryView::setupWidgetCover() void SqlQueryView::createActions() { createAction(COPY, ICONS.ACT_COPY, tr("Copy"), this, SLOT(copy()), this); + createAction(COPY_WITH_HEADER, ICONS.ACT_COPY, tr("Copy with headers"), this, SLOT(copyWithHeader()), this); createAction(COPY_AS, ICONS.ACT_COPY, tr("Copy as..."), this, SLOT(copyAs()), this); createAction(PASTE, ICONS.ACT_PASTE, tr("Paste"), this, SLOT(paste()), this); createAction(PASTE_AS, ICONS.ACT_PASTE, tr("Paste as..."), this, SLOT(pasteAs()), this); createAction(SET_NULL, ICONS.SET_NULL, tr("Set NULL values"), this, SLOT(setNull()), this); createAction(ERASE, ICONS.ERASE, tr("Erase values"), this, SLOT(erase()), this); - createAction(OPEN_VALUE_EDITOR, ICONS.OPEN_VALUE_EDITOR, tr("Edit value in editor"), this, SLOT(openValueEditor()), this); + createAction(OPEN_VALUE_EDITOR, ICONS.OPEN_VALUE_EDITOR, "", this, SLOT(openValueEditor()), this); // actual label is set dynamically in setupActionsForMenu() createAction(COMMIT, ICONS.COMMIT, tr("Commit"), this, SLOT(commit()), this); createAction(ROLLBACK, ICONS.ROLLBACK, tr("Rollback"), this, SLOT(rollback()), this); createAction(SELECTIVE_COMMIT, ICONS.COMMIT, tr("Commit selected cells"), this, SLOT(selectiveCommit()), this); @@ -119,9 +130,17 @@ void SqlQueryView::setupActionsForMenu(SqlQueryItem* currentItem, const QList uncommittedItems = getModel()->getUncommittedItems(); int uncommittedCount = uncommittedItems.size(); + // How many of selected items is editable + int editableSelCount = selCount; + for (SqlQueryItem* selItem : getSelectedItems()) + if (selItem->getColumn()->editionForbiddenReason.size() > 0) + editableSelCount--; + + bool currentItemEditable = (getCurrentItem()->getColumn()->editionForbiddenReason.size() == 0); + // Uncommitted & selected items count int uncommittedSelCount = 0; - foreach (SqlQueryItem* item, uncommittedItems) + for (SqlQueryItem* item : uncommittedItems) if (selectedItems.contains(item)) uncommittedSelCount++; @@ -140,10 +159,16 @@ void SqlQueryView::setupActionsForMenu(SqlQueryItem* currentItem, const QList 0 && selCount > 0) contextMenu->addSeparator(); + // Edit/show label for "open in editor" action + actionMap[OPEN_VALUE_EDITOR]->setText(currentItemEditable ? tr("Edit value in editor") : tr("Show value in a viewer")); + if (selCount > 0) { - contextMenu->addAction(actionMap[ERASE]); - contextMenu->addAction(actionMap[SET_NULL]); + if (editableSelCount > 0) + { + contextMenu->addAction(actionMap[ERASE]); + contextMenu->addAction(actionMap[SET_NULL]); + } contextMenu->addAction(actionMap[OPEN_VALUE_EDITOR]); contextMenu->addSeparator(); } @@ -165,6 +190,7 @@ void SqlQueryView::setupActionsForMenu(SqlQueryItem* currentItem, const QListaddSeparator(); contextMenu->addAction(actionMap[COPY]); + contextMenu->addAction(actionMap[COPY_WITH_HEADER]); //contextMenu->addAction(actionMap[COPY_AS]); // TODO uncomment when implemented contextMenu->addAction(actionMap[PASTE]); //contextMenu->addAction(actionMap[PASTE_AS]); // TODO uncomment when implemented @@ -172,7 +198,7 @@ void SqlQueryView::setupActionsForMenu(SqlQueryItem* currentItem, const QList 0) { contextMenu->addSeparator(); - foreach (QAction* action, additionalActions) + for (QAction* action : additionalActions) contextMenu->addAction(action); } } @@ -199,7 +225,7 @@ QList SqlQueryView::getSelectedItems() qSort(idxList); const SqlQueryModel* model = dynamic_cast(idxList.first().model()); - foreach (const QModelIndex& idx, idxList) + for (const QModelIndex& idx : idxList) items << model->itemFromIndex(idx); return items; @@ -314,7 +340,15 @@ void SqlQueryView::paste(const QList >& data) return; } - qSort(selectedItems); + if (data.size() == 1 && data[0].size() == 1) + { + QVariant theValue = data[0][0]; + for (SqlQueryItem* item : selectedItems) + item->setValue(theValue, false, false); + + return; + } + SqlQueryItem* topLeft = selectedItems.first(); int columnCount = getModel()->columnCount(); @@ -324,7 +358,7 @@ void SqlQueryView::paste(const QList >& data) SqlQueryItem* item = nullptr; - foreach (const QList& cells, data) + for (const QList& cells : data) { // Check if we're out of rows range if (rowIdx >= rowCount) @@ -334,7 +368,7 @@ void SqlQueryView::paste(const QList >& data) break; } - foreach (const QVariant& cell, cells) + for (const QVariant& cell : cells) { // Get current cell if (colIdx >= columnCount) @@ -408,6 +442,78 @@ void SqlQueryView::goToReferencedRow(const QString& table, const QString& column win->execute(); } +void SqlQueryView::copy(bool withHeader) +{ + if (simpleBrowserMode) + return; + + QList selectedItems = getSelectedItems(); + QList > groupedItems = SqlQueryModel::groupItemsByRows(selectedItems); + + if (selectedItems.isEmpty()) + return; + + QVariant itemValue; + QStringList cells; + QList rows; + + QPair>> theDataPair; + QList> theData; + QList theDataRow; + + // Header + if (withHeader) + { + for (SqlQueryModelColumnPtr col : getModel()->getColumns().mid(0, groupedItems.first().size())) + { + theDataRow << col->displayName; + cells << col->displayName; + } + + rows << cells; + cells.clear(); + + theData << theDataRow; + theDataRow.clear(); + } + + // Data + for (const QList& itemsInRows : groupedItems) + { + for (SqlQueryItem* item : itemsInRows) + { + itemValue = item->getFullValue(); + if (itemValue.userType() == QVariant::Double) + cells << doubleToString(itemValue); + else + cells << itemValue.toString(); + + theDataRow << itemValue; + } + + rows << cells; + cells.clear(); + + theData << theDataRow; + theDataRow.clear(); + } + + QMimeData* mimeData = new QMimeData(); + QString tsv = TsvSerializer::serialize(rows); + mimeData->setText(tsv); + + QString md5 = QCryptographicHash::hash(tsv.toUtf8(), QCryptographicHash::Md5); + theDataPair.first = md5; + theDataPair.second = theData; + + QByteArray serializedData; + QDataStream stream(&serializedData, QIODevice::WriteOnly); + stream << theDataPair; + mimeData->setData(mimeDataId, serializedData); + + qApp->clipboard()->setMimeData(mimeData); +} + bool SqlQueryView::getSimpleBrowserMode() const { return simpleBrowserMode; @@ -418,6 +524,22 @@ void SqlQueryView::setSimpleBrowserMode(bool value) simpleBrowserMode = value; } +void SqlQueryView::setIgnoreColumnWidthChanges(bool ignore) +{ + ignoreColumnWidthChanges = ignore; +} + +QMenu* SqlQueryView::getHeaderContextMenu() const +{ + return headerContextMenu; +} + +void SqlQueryView::scrollContentsBy(int dx, int dy) +{ + QTableView::scrollContentsBy(dx, dy); + emit scrolledBy(dx, dy); +} + void SqlQueryView::updateCommitRollbackActions(bool enabled) { actionMap[COMMIT]->setEnabled(enabled); @@ -485,11 +607,18 @@ void SqlQueryView::updateFont() void SqlQueryView::executionStarted() { + beforeExecutionHorizontalPosition = horizontalScrollBar()->sliderPosition(); widgetCover->show(); } void SqlQueryView::executionEnded() { + if (beforeExecutionHorizontalPosition > -1) + { + horizontalScrollBar()->setSliderPosition(beforeExecutionHorizontalPosition); + emit scrolledBy(beforeExecutionHorizontalPosition, 0); + } + widgetCover->hide(); } @@ -500,54 +629,12 @@ void SqlQueryView::setCurrentRow(int row) void SqlQueryView::copy() { - if (simpleBrowserMode) - return; - - QList selectedItems = getSelectedItems(); - QList > groupedItems = SqlQueryModel::groupItemsByRows(selectedItems); - - QVariant itemValue; - QStringList cells; - QList rows; - - QPair>> theDataPair; - QList> theData; - QList theDataRow; - - foreach (const QList& itemsInRows, groupedItems) - { - foreach (SqlQueryItem* item, itemsInRows) - { - itemValue = item->getFullValue(); - if (itemValue.userType() == QVariant::Double) - cells << doubleToString(itemValue); - else - cells << itemValue.toString(); - - theDataRow << itemValue; - } - - rows << cells; - cells.clear(); - - theData << theDataRow; - theDataRow.clear(); - } - - QMimeData* mimeData = new QMimeData(); - QString tsv = TsvSerializer::serialize(rows); - mimeData->setText(tsv); - - QString md5 = QCryptographicHash::hash(tsv.toUtf8(), QCryptographicHash::Md5); - theDataPair.first = md5; - theDataPair.second = theData; - - QByteArray serializedData; - QDataStream stream(&serializedData, QIODevice::WriteOnly); - stream << theDataPair; - mimeData->setData(mimeDataId, serializedData); + copy(false); +} - qApp->clipboard()->setMimeData(mimeData); +void SqlQueryView::copyWithHeader() +{ + copy(true); } void SqlQueryView::paste() @@ -574,13 +661,30 @@ void SqlQueryView::paste() } QList deserializedRows = TsvSerializer::deserialize(mimeData->text()); + bool trimOnPaste = false; + bool trimOnPasteAsked = false; QList dataRow; QList> dataToPaste; for (const QStringList& cells : deserializedRows) { for (const QString& cell : cells) - dataRow << cell; + { +#if QT_VERSION >= 0x050A00 + if ((cell.front().isSpace() || cell.back().isSpace()) && !trimOnPasteAsked) +#else + if ((cell.at(0).isSpace() || cell.at(cell.size() - 1).isSpace()) && !trimOnPasteAsked) +#endif + { + QMessageBox::StandardButton choice; + choice = QMessageBox::question(this, tr("Trim pasted text?"), + tr("The pasted text contains leading or trailing white space. Trim it automatically?")); + trimOnPasteAsked = true; + trimOnPaste = (choice == QMessageBox::Yes); + } + + dataRow << (trimOnPaste ? cell.trimmed() : cell); + } dataToPaste << dataRow; dataRow.clear(); @@ -689,3 +793,20 @@ int qHash(SqlQueryView::Action action) { return static_cast(action); } + +SqlQueryView::Header::Header(SqlQueryView* parent) : + QHeaderView(Qt::Horizontal, parent) +{ +} + +QSize SqlQueryView::Header::sectionSizeFromContents(int section) const +{ + QSize originalSize = QHeaderView::sectionSizeFromContents(section); + int colCount = dynamic_cast(parent())->getModel()->columnCount(); + if (colCount <= 5) + return originalSize; + + int wd = minHeaderWidth; + wd = qMin((wd + wd * 20 / colCount), originalSize.width()); + return QSize(wd, originalSize.height()); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h index b0df4d7..98e2783 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h @@ -7,6 +7,7 @@ #include "guiSQLiteStudio_global.h" #include "common/table.h" #include +#include class SqlQueryItemDelegate; class SqlQueryItem; @@ -19,9 +20,10 @@ class QMenu; CFG_KEY_LIST(SqlQueryView, QObject::tr("Data grid view"), CFG_KEY_ENTRY(COPY, Qt::CTRL + Qt::Key_C, QObject::tr("Copy cell(s) contents to clipboard")) -// CFG_KEY_ENTRY(COPY_AS, Qt::CTRL + Qt::SHIFT + Qt::Key_C, QObject::tr("")) + CFG_KEY_ENTRY(COPY_WITH_HEADER, Qt::CTRL + Qt::SHIFT + Qt::Key_C, QObject::tr("Copy cell(s) contents together with header to clipboard")) +// CFG_KEY_ENTRY(COPY_AS, Qt::CTRL + Qt::ALT + Qt::Key_C, QObject::tr("")) CFG_KEY_ENTRY(PASTE, Qt::CTRL + Qt::Key_V, QObject::tr("Paste cell(s) contents from clipboard")) -// CFG_KEY_ENTRY(PASTE_AS, Qt::CTRL + Qt::SHIFT + Qt::Key_V, QObject::tr("")) +// CFG_KEY_ENTRY(PASTE_AS, Qt::CTRL + Qt::ALT + Qt::Key_V, QObject::tr("")) CFG_KEY_ENTRY(ERASE, Qt::ALT + Qt::Key_Backspace, QObject::tr("Set empty value to selected cell(s)")) CFG_KEY_ENTRY(SET_NULL, Qt::Key_Backspace, QObject::tr("Set NULL value to selected cell(s)")) CFG_KEY_ENTRY(COMMIT, Qt::CTRL + Qt::Key_Return, QObject::tr("Commit changes to cell(s) contents")) @@ -40,6 +42,7 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer enum Action { COPY, + COPY_WITH_HEADER, COPY_AS, PASTE, PASTE_AS, @@ -77,8 +80,21 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer QModelIndex getCurrentIndex() const; bool getSimpleBrowserMode() const; void setSimpleBrowserMode(bool value); + void setIgnoreColumnWidthChanges(bool ignore); + QMenu* getHeaderContextMenu() const; + + protected: + void scrollContentsBy(int dx, int dy); private: + class Header : public QHeaderView + { + public: + explicit Header(SqlQueryView* parent); + + QSize sectionSizeFromContents(int section) const; + }; + void init(); void setupWidgetCover(); void createActions(); @@ -90,8 +106,10 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer void paste(const QList>& data); void addFkActionsToContextMenu(SqlQueryItem* currentItem); void goToReferencedRow(const QString& table, const QString& column, const QVariant& value); + void copy(bool withHeaders); constexpr static const char* mimeDataId = "application/x-sqlitestudio-data-view-data"; + constexpr static const int minHeaderWidth = 15; SqlQueryItemDelegate* itemDelegate = nullptr; QMenu* contextMenu = nullptr; @@ -102,6 +120,8 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer QProgressBar* busyBar = nullptr; QList additionalActions; bool simpleBrowserMode = false; + bool ignoreColumnWidthChanges = false; + int beforeExecutionHorizontalPosition = -1; private slots: void updateCommitRollbackActions(bool enabled); @@ -122,6 +142,7 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer void executionEnded(); void setCurrentRow(int row); void copy(); + void copyWithHeader(); void paste(); void copyAs(); void pasteAs(); @@ -139,6 +160,7 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer void requestForRowInsert(); void requestForMultipleRowInsert(); void requestForRowDelete(); + void scrolledBy(int dx, int dy); }; GUI_API_EXPORT int qHash(SqlQueryView::Action action); diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp index 3a9f0b0..ed9a3a4 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp @@ -76,7 +76,7 @@ bool SqlTableModel::commitAddedRow(const QList& itemsInRow) // Handle error if (result->isError()) { - foreach (SqlQueryItem* item, itemsInRow) + for (SqlQueryItem* item : itemsInRow) item->setCommittingError(true); notifyError(tr("Error while committing new row: %1").arg(result->getErrorText())); @@ -129,7 +129,7 @@ bool SqlTableModel::commitDeletedRow(const QList& itemsInRow) CommitDeleteQueryBuilder queryBuilder; queryBuilder.setTable(wrapObjIfNeeded(table, dialect)); - queryBuilder.setRowId(rowId); + queryBuilder.setRowId(rowId, dialect); QString sql = queryBuilder.build(); QHash args = queryBuilder.getQueryArgs(); @@ -147,41 +147,73 @@ bool SqlTableModel::commitDeletedRow(const QList& itemsInRow) return true; } -bool SqlTableModel::supportsModifyingQueriesInMenu() const +void SqlTableModel::applyFilter(const QString& value, FilterValueProcessor valueProc) { - return true; -} + static_qstring(sql, "SELECT * FROM %1 WHERE %2"); -void SqlTableModel::applySqlFilter(const QString& value) -{ if (value.isEmpty()) { resetFilter(); return; } - setQuery("SELECT * FROM "+getDataSource()+" WHERE "+value); + Dialect dialect = db->getDialect(); + QStringList conditions; + for (SqlQueryModelColumnPtr column : columns) + conditions << wrapObjIfNeeded(column->column, dialect)+" "+valueProc(value); + + setQuery(sql.arg(getDataSource(), conditions.join(" OR "))); executeQuery(); } -void SqlTableModel::applyStringFilter(const QString& value) +void SqlTableModel::applyFilter(const QStringList& values, FilterValueProcessor valueProc) { - if (value.isEmpty()) + static_qstring(sql, "SELECT * FROM %1 WHERE %2"); + if (values.isEmpty()) { resetFilter(); return; } + if (values.size() != columns.size()) + { + qCritical() << "Asked to per-column filter, but number columns" + << columns.size() << "is different than number of values" << values.size(); + return; + } + Dialect dialect = db->getDialect(); QStringList conditions; - foreach (SqlQueryModelColumnPtr column, columns) - conditions << wrapObjIfNeeded(column->column, dialect)+" LIKE '%"+escapeString(value)+"%'"; + for (int i = 0, total = columns.size(); i < total; ++i) + { + if (values[i].isEmpty()) + continue; - setQuery("SELECT * FROM "+getDataSource()+" WHERE "+conditions.join(" OR ")); + conditions << wrapObjIfNeeded(columns[i]->column, dialect)+" "+valueProc(values[i]); + } + + setQuery(sql.arg(getDataSource(), conditions.join(" AND "))); executeQuery(); } -void SqlTableModel::applyRegExpFilter(const QString& value) +QString SqlTableModel::stringFilterValueProcessor(const QString& value) +{ + static_qstring(pattern, "LIKE '%%1%'"); + return pattern.arg(escapeString(value)); +} + +QString SqlTableModel::regExpFilterValueProcessor(const QString& value) +{ + static_qstring(pattern, "REGEXP '%1'"); + return pattern.arg(escapeString(value)); +} + +bool SqlTableModel::supportsModifyingQueriesInMenu() const +{ + return true; +} + +void SqlTableModel::applySqlFilter(const QString& value) { if (value.isEmpty()) { @@ -189,15 +221,30 @@ void SqlTableModel::applyRegExpFilter(const QString& value) return; } - Dialect dialect = db->getDialect(); - QStringList conditions; - foreach (SqlQueryModelColumnPtr column, columns) - conditions << wrapObjIfNeeded(column->column, dialect)+" REGEXP '"+escapeString(value)+"'"; - - setQuery("SELECT * FROM "+getDataSource()+" WHERE "+conditions.join(" OR ")); + setQuery("SELECT * FROM "+getDataSource()+" WHERE "+value); executeQuery(); } +void SqlTableModel::applyStringFilter(const QString& value) +{ + applyFilter(value, &stringFilterValueProcessor); +} + +void SqlTableModel::applyStringFilter(const QStringList& values) +{ + applyFilter(values, &stringFilterValueProcessor); +} + +void SqlTableModel::applyRegExpFilter(const QString& value) +{ + applyFilter(value, ®ExpFilterValueProcessor); +} + +void SqlTableModel::applyRegExpFilter(const QStringList& values) +{ + applyFilter(values, ®ExpFilterValueProcessor); +} + void SqlTableModel::resetFilter() { setQuery("SELECT * FROM "+getDataSource()); @@ -296,7 +343,7 @@ void SqlTableModel::updateRowAfterInsert(const QList& itemsInRow, static_qstring(limitedColTpl, "substr(%1, 1, %2)"); SelectColumnsQueryBuilder queryBuilder; queryBuilder.setTable(wrapObjIfNeeded(table, dialect)); - queryBuilder.setRowId(rowId); + queryBuilder.setRowId(rowId, dialect); QList columnKeys = columnsToReadFromDb.keys(); for (const SqlQueryModelColumnPtr& modelColumn : columnKeys) queryBuilder.addColumn(limitedColTpl.arg(wrapObjIfNeeded(modelColumn->column, dialect), QString::number(cellDataLengthLimit))); @@ -394,7 +441,7 @@ void SqlTableModel::updateColumnsAndValues(const QList& itemsInRo SqlQueryItem* item = nullptr; int i = 0; - foreach (SqlQueryModelColumnPtr modelColumn, modelColumns) + for (SqlQueryModelColumnPtr modelColumn : modelColumns) { item = itemsInRow[i++]; if (item->getValue().isNull()) @@ -421,7 +468,7 @@ void SqlTableModel::updateColumnsAndValuesWithDefaultValues(const QListgetDialect(); // First try to find the one with DEFAULT value - foreach (SqlQueryModelColumnPtr modelColumn, modelColumns) + for (SqlQueryModelColumnPtr modelColumn : modelColumns) { if (modelColumn->isDefault()) { @@ -433,7 +480,7 @@ void SqlTableModel::updateColumnsAndValuesWithDefaultValues(const QListisPk() && modelColumn->isAutoIncr()) { diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h index da43b03..b904343 100644 --- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h +++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h @@ -17,7 +17,9 @@ class GUI_API_EXPORT SqlTableModel : public SqlQueryModel Features features() const; void applySqlFilter(const QString& value); void applyStringFilter(const QString& value); + void applyStringFilter(const QStringList& values); void applyRegExpFilter(const QString& value); + void applyRegExpFilter(const QStringList& values); void resetFilter(); QString generateSelectQueryForItems(const QList& items); QString generateInsertQueryForItems(const QList& items); @@ -43,7 +45,13 @@ class GUI_API_EXPORT SqlTableModel : public SqlQueryModel void addColumn(const QString& col); }; + typedef std::function FilterValueProcessor; + static QString stringFilterValueProcessor(const QString& value); + static QString regExpFilterValueProcessor(const QString& value); + + void applyFilter(const QString& value, FilterValueProcessor valueProc); + void applyFilter(const QStringList& values, FilterValueProcessor valueProc); void updateColumnsAndValuesWithDefaultValues(const QList& modelColumns, QStringList& colNameList, QStringList& sqlValues, QList& args); void updateColumnsAndValues(const QList& itemsInRow, const QList& modelColumns, diff --git a/SQLiteStudio3/guiSQLiteStudio/dataview.cpp b/SQLiteStudio3/guiSQLiteStudio/dataview.cpp index 6666834..9012c1c 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dataview.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dataview.cpp @@ -13,6 +13,7 @@ #include "uiconfig.h" #include "datagrid/sqlqueryitem.h" #include "common/widgetcover.h" +#include "common/unused.h" #include #include #include @@ -21,12 +22,15 @@ #include #include #include +#include +#include +#include CFG_KEYS_DEFINE(DataView) -DataView::FilterMode DataView::filterMode; DataView::TabsPosition DataView::tabsPosition; QHash DataView::staticActions; QHash DataView::staticActionGroups; +static const char* DATA_VIEW_FILTER_PROP = "filter"; DataView::DataView(QWidget *parent) : QTabWidget(parent) @@ -76,6 +80,8 @@ void DataView::initSlots() connect(gridView->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(columnsHeaderClicked(int))); connect(this, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int))); connect(model, SIGNAL(itemEditionEnded(SqlQueryItem*)), this, SLOT(adjustColumnWidth(SqlQueryItem*))); + connect(gridView, SIGNAL(scrolledBy(int, int)), this, SLOT(syncFilterScrollPosition())); + connect(gridView->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), this, SLOT(resizeFilter(int, int, int))); } void DataView::initFormView() @@ -119,6 +125,9 @@ void DataView::createContents() gridWidget->layout()->addWidget(gridToolBar); formWidget->layout()->addWidget(formToolBar); + createFilterPanel(); + gridWidget->layout()->addWidget(perColumnAreaParent); + THEME_TUNER->manageCompactLayout({ gridWidget, formWidget @@ -136,6 +145,37 @@ void DataView::createContents() gridWidget->layout()->addWidget(gridView); } +void DataView::createFilterPanel() +{ + perColumnAreaParent = new QWidget(); + perColumnAreaParent->setVisible(false); + perColumnAreaParent->setLayout(new QHBoxLayout()); + perColumnAreaParent->layout()->setSpacing(0); + perColumnAreaParent->layout()->setMargin(0); + perColumnAreaParent->setFixedHeight(0); + + filterLeftSpacer = new QWidget(); + perColumnAreaParent->layout()->addWidget(filterLeftSpacer); + + perColumnFilterArea = new QScrollArea(); + perColumnFilterArea->setFixedHeight(0); + perColumnFilterArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + perColumnFilterArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + perColumnFilterArea->setFrameShape(QFrame::NoFrame); + perColumnWidget = new QWidget(); + perColumnWidget->setLayout(new QHBoxLayout()); + perColumnWidget->layout()->setSizeConstraint(QLayout::SetFixedSize); + perColumnWidget->layout()->setSpacing(0); + perColumnWidget->layout()->setMargin(0); + perColumnWidget->setAutoFillBackground(true); + perColumnWidget->setBackgroundRole(QPalette::Window); + perColumnFilterArea->setWidget(perColumnWidget); + perColumnAreaParent->layout()->addWidget(perColumnFilterArea); + + filterRightSpacer = new QWidget(); + perColumnAreaParent->layout()->addWidget(filterRightSpacer); +} + void DataView::initPageEdit() { pageEdit = new ExtLineEdit(); @@ -187,19 +227,8 @@ void DataView::createActions() createAction(LAST_PAGE, ICONS.PAGE_LAST, tr("Last page", "data view"), this, SLOT(lastPage()), gridToolBar); gridToolBar->addSeparator(); if (model->features().testFlag(SqlQueryModel::FILTERING)) - { - actionMap[FILTER_VALUE] = gridToolBar->addWidget(filterEdit); - createAction(FILTER, tr("Apply filter", "data view"), this, SLOT(applyFilter()), gridToolBar); - attachActionInMenu(FILTER, staticActions[FILTER_STRING], gridToolBar); - attachActionInMenu(FILTER, staticActions[FILTER_REGEXP], gridToolBar); - attachActionInMenu(FILTER, staticActions[FILTER_SQL], gridToolBar); - gridToolBar->addSeparator(); - updateFilterIcon(); - - connect(staticActions[FILTER_STRING], SIGNAL(triggered()), this, SLOT(filterModeSelected())); - connect(staticActions[FILTER_REGEXP], SIGNAL(triggered()), this, SLOT(filterModeSelected())); - connect(staticActions[FILTER_SQL], SIGNAL(triggered()), this, SLOT(filterModeSelected())); - } + createFilteringActions(); + actionMap[GRID_TOTAL_ROWS] = gridToolBar->addWidget(rowCountLabel); noConfigShortcutActions << GRID_TOTAL_ROWS << FILTER_VALUE; @@ -264,55 +293,33 @@ void DataView::setupDefShortcuts() void DataView::resizeColumnsInitiallyToContents() { - int cols = gridView->model()->columnCount(); + SqlQueryModel *model = gridView->getModel(); + int cols = model->columnCount(); + gridView->setIgnoreColumnWidthChanges(true); gridView->resizeColumnsToContents(); int wd; + int desiredWidth = -1; for (int i = 0; i < cols ; i++) { + desiredWidth = model->getDesiredColumnWidth(i); wd = gridView->columnWidth(i); + + if (desiredWidth > -1 && wd != desiredWidth) + { + gridView->setColumnWidth(i, desiredWidth); + continue; + } + if (wd > CFG_UI.General.MaxInitialColumnWith.get()) gridView->setColumnWidth(i, CFG_UI.General.MaxInitialColumnWith.get()); else if (wd < 60) gridView->setColumnWidth(i, 60); - } + gridView->setIgnoreColumnWidthChanges(false); } void DataView::createStaticActions() { - // Filtering actions - staticActions[FILTER_STRING] = new ExtAction(ICONS.APPLY_FILTER_TXT, tr("Filter by text", "data view"), MainWindow::getInstance()); - staticActions[FILTER_REGEXP] = new ExtAction(ICONS.APPLY_FILTER_RE, tr("Filter by the Regular Expression", "data view"), MainWindow::getInstance()); - staticActions[FILTER_SQL] = new ExtAction(ICONS.APPLY_FILTER_SQL, tr("Filter by SQL expression", "data view"), MainWindow::getInstance()); - - staticActionGroups[ActionGroup::FILTER_MODE] = new QActionGroup(MainWindow::getInstance()); - staticActionGroups[ActionGroup::FILTER_MODE]->addAction(staticActions[FILTER_STRING]); - staticActionGroups[ActionGroup::FILTER_MODE]->addAction(staticActions[FILTER_SQL]); - staticActionGroups[ActionGroup::FILTER_MODE]->addAction(staticActions[FILTER_REGEXP]); - - connect(staticActions[FILTER_STRING], &QAction::triggered, [=]() - { - filterMode = FilterMode::STRING; - }); - connect(staticActions[FILTER_SQL], &QAction::triggered, [=]() - { - filterMode = FilterMode::SQL; - }); - connect(staticActions[FILTER_REGEXP], &QAction::triggered, [=]() - { - filterMode = FilterMode::REGEXP; - }); - - staticActions[FILTER_STRING]->setCheckable(true); - staticActions[FILTER_REGEXP]->setCheckable(true); - staticActions[FILTER_SQL]->setCheckable(true); - if (filterMode == FilterMode::STRING) - staticActions[FILTER_STRING]->setChecked(true); - else if (filterMode == FilterMode::REGEXP) - staticActions[FILTER_REGEXP]->setChecked(true); - else - staticActions[FILTER_SQL]->setChecked(true); - // Tabs position actions staticActions[TABS_ON_TOP] = new ExtAction(ICONS.TABS_ON_TOP, tr("Tabs on top", "data view"), MainWindow::getInstance()); staticActions[TABS_AT_BOTTOM] = new ExtAction(ICONS.TABS_AT_BOTTOM, tr("Tabs at bottom", "data view"), MainWindow::getInstance()); @@ -499,6 +506,7 @@ void DataView::updateTabsMode() void DataView::filterModeSelected() { QAction* modeAction = dynamic_cast(sender()); + filterMode = static_cast(modeAction->property(DATA_VIEW_FILTER_PROP).toInt()); actionMap[FILTER]->setIcon(modeAction->icon()); } @@ -541,6 +549,41 @@ void DataView::adjustColumnWidth(SqlQueryItem* item) gridView->setColumnWidth(col, CFG_UI.General.MaxInitialColumnWith.get()); } +void DataView::syncFilterScrollPosition() +{ + perColumnFilterArea->horizontalScrollBar()->setValue(gridView->horizontalScrollBar()->value()); +} + +void DataView::resizeFilter(int section, int oldSize, int newSize) +{ + UNUSED(oldSize); + if (filterInputs.isEmpty()) + return; + + if (filterInputs.size() <= section) + { + qCritical() << "Tried to adjust per-column filter input edit according to resized value, but section index is out of bounds:" + << section << ", while edit widgets count is:" << filterInputs.size(); + return; + } + + filterInputs[section]->setFixedWidth(newSize); +} + +void DataView::togglePerColumnFiltering() +{ + bool enable = actionMap[FILTER_PER_COLUMN]->isChecked(); + + filterEdit->setEnabled(!enable); + if (actionMap[FILTER_SQL]->isChecked()) + actionMap[FILTER_STRING]->setChecked(true); + + actionMap[FILTER_SQL]->setEnabled(!enable); + perColumnAreaParent->setVisible(enable); + + recreateFilterInputs(); +} + void DataView::updateCommitRollbackActions(bool enabled) { gridView->getAction(SqlQueryView::COMMIT)->setEnabled(enabled); @@ -638,18 +681,6 @@ void DataView::readData() model->executeQuery(); } -void DataView::updateFilterIcon() -{ - for (Action act : {FILTER_STRING, FILTER_SQL, FILTER_REGEXP}) - { - if (staticActions[act]->isChecked()) - { - actionMap[FILTER]->setIcon(staticActions[act]->icon()); - break; - } - } -} - bool DataView::isUncommitted() const { return uncommittedGrid || uncommittedForm; @@ -661,6 +692,7 @@ void DataView::dataLoadingEnded(bool successful) { updatePageEdit(); resizeColumnsInitiallyToContents(); + recreateFilterInputs(); } setNavigationState(true); @@ -778,18 +810,47 @@ void DataView::applyFilter() return; } - QString value = filterEdit->text(); - switch (filterMode) + if (actionMap[FILTER_PER_COLUMN]->isChecked()) { - case DataView::FilterMode::STRING: - model->applyStringFilter(value); - break; - case DataView::FilterMode::SQL: - model->applySqlFilter(value); - break; - case DataView::FilterMode::REGEXP: - model->applyRegExpFilter(value); - break; + filterValues.clear(); + for (QLineEdit* edit : filterInputs) + filterValues << edit->text(); + + if (filterValues.join("").isEmpty()) + { + model->resetFilter(); + return; + } + + switch (filterMode) + { + case DataView::FilterMode::STRING: + model->applyStringFilter(filterValues); + break; + case DataView::FilterMode::SQL: + // Should never happen. + qWarning() << "Requested to filter by SQL for filtering per-column. This should not be possible."; + break; + case DataView::FilterMode::REGEXP: + model->applyRegExpFilter(filterValues); + break; + } + } + else + { + QString value = filterEdit->text(); + switch (filterMode) + { + case DataView::FilterMode::STRING: + model->applyStringFilter(value); + break; + case DataView::FilterMode::SQL: + model->applySqlFilter(value); + break; + case DataView::FilterMode::REGEXP: + model->applyRegExpFilter(value); + break; + } } } @@ -854,7 +915,12 @@ void DataView::initFormViewForNewRow() int row = gridView->getCurrentIndex().row(); for (SqlQueryItem* item : getModel()->getRow(row)) + { + if (item->getColumn()->isAutoIncr()) + continue; + item->setValue(""); + } } void DataView::formViewFocusFirstEditor() @@ -863,6 +929,87 @@ void DataView::formViewFocusFirstEditor() formView->focusFirstEditor(); } +void DataView::recreateFilterInputs() +{ + qApp->processEvents(); + + for (QLineEdit* edit : filterInputs) + delete edit; + + filterInputs.clear(); + + filterLeftSpacer->setFixedSize(gridView->verticalHeader()->width() + 1, 1); + + QLineEdit* edit = nullptr; + for (int i = 0, total = gridView->horizontalHeader()->count(); i < total; ++i) + { + edit = new QLineEdit(perColumnWidget); + edit->setPlaceholderText(tr("Filter")); + edit->setClearButtonEnabled(true); + edit->setFixedWidth(gridView->columnWidth(i)); + edit->setToolTip(tr("Hit Enter key or press \"Apply filter\" button on toolbar to apply new value.")); + if (filterValues.size() > i) + edit->setText(filterValues[i]); + + connect(edit, SIGNAL(returnPressed()), this, SLOT(applyFilter())); + perColumnWidget->layout()->addWidget(edit); + filterInputs << edit; + } + + int rightSpacerWd = gridView->verticalScrollBar()->isVisible() ? gridView->verticalScrollBar()->width() : 0; + filterRightSpacer->setFixedSize(rightSpacerWd + 1, 1); + + perColumnAreaParent->setFixedWidth(gridView->width()); + + if (edit) + { + int hg = edit->sizeHint().height(); + perColumnFilterArea->setFixedHeight(hg); + perColumnAreaParent->setFixedHeight(hg); + } + + qApp->processEvents(); + + syncFilterScrollPosition(); +} + +void DataView::createFilteringActions() +{ + createAction(FILTER_STRING, ICONS.APPLY_FILTER_TXT, tr("Filter by text", "data view"), this, SLOT(filterModeSelected()), this); + createAction(FILTER_REGEXP, ICONS.APPLY_FILTER_RE, tr("Filter by the Regular Expression", "data view"), this, SLOT(filterModeSelected()), this); + createAction(FILTER_SQL, ICONS.APPLY_FILTER_SQL, tr("Filter by SQL expression", "data view"), this, SLOT(filterModeSelected()), this); + + actionMap[FILTER_STRING]->setProperty(DATA_VIEW_FILTER_PROP, static_cast(FilterMode::STRING)); + actionMap[FILTER_REGEXP]->setProperty(DATA_VIEW_FILTER_PROP, static_cast(FilterMode::REGEXP)); + actionMap[FILTER_SQL]->setProperty(DATA_VIEW_FILTER_PROP, static_cast(FilterMode::SQL)); + + QActionGroup* filterGroup = new QActionGroup(gridToolBar); + filterGroup->addAction(actionMap[FILTER_STRING]); + filterGroup->addAction(actionMap[FILTER_SQL]); + filterGroup->addAction(actionMap[FILTER_REGEXP]); + + actionMap[FILTER_STRING]->setCheckable(true); + actionMap[FILTER_REGEXP]->setCheckable(true); + actionMap[FILTER_SQL]->setCheckable(true); + actionMap[FILTER_STRING]->setChecked(true); + + createAction(FILTER_PER_COLUMN, tr("Show filter inputs per column", "data view"), this, SLOT(togglePerColumnFiltering()), this); + actionMap[FILTER_PER_COLUMN]->setCheckable(true); + + actionMap[FILTER_VALUE] = gridToolBar->addWidget(filterEdit); + createAction(FILTER, tr("Apply filter", "data view"), this, SLOT(applyFilter()), gridToolBar); + attachActionInMenu(FILTER, actionMap[FILTER_STRING], gridToolBar); + attachActionInMenu(FILTER, actionMap[FILTER_REGEXP], gridToolBar); + attachActionInMenu(FILTER, actionMap[FILTER_SQL], gridToolBar); + addSeparatorInMenu(FILTER, gridToolBar); + attachActionInMenu(FILTER, actionMap[FILTER_PER_COLUMN], gridToolBar); + gridToolBar->addSeparator(); + + actionMap[FILTER]->setIcon(actionMap[FILTER_STRING]->icon()); + + gridView->getHeaderContextMenu()->addAction(actionMap[FILTER_PER_COLUMN]); +} + void DataView::columnsHeaderClicked(int columnIdx) { model->changeSorting(columnIdx); @@ -916,7 +1063,6 @@ QToolBar* DataView::getToolBar(int toolbar) const void DataView::staticInit() { - filterMode = FilterMode::STRING; tabsPosition = TabsPosition::TOP; loadTabsMode(); createStaticActions(); diff --git a/SQLiteStudio3/guiSQLiteStudio/dataview.h b/SQLiteStudio3/guiSQLiteStudio/dataview.h index 73ccfe7..55c7895 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dataview.h +++ b/SQLiteStudio3/guiSQLiteStudio/dataview.h @@ -15,6 +15,8 @@ class ExtLineEdit; class QLabel; class IntValidator; class WidgetCover; +class QScrollArea; +class QLineEdit; CFG_KEY_LIST(DataView, QObject::tr("Data view (both grid and form)"), CFG_KEY_ENTRY(REFRESH_DATA, Qt::Key_F5, QObject::tr("Refresh data")) @@ -46,6 +48,7 @@ class GUI_API_EXPORT DataView : public QTabWidget, public ExtActionContainer FILTER_STRING, FILTER_SQL, FILTER_REGEXP, + FILTER_PER_COLUMN, GRID_TOTAL_ROWS, SELECTIVE_COMMIT, SELECTIVE_ROLLBACK, @@ -123,6 +126,7 @@ class GUI_API_EXPORT DataView : public QTabWidget, public ExtActionContainer void initPageEdit(); void initWidgetCover(); void createContents(); + void createFilterPanel(); void goToFormRow(IndexModifier idxMod); void setNavigationState(bool enabled); void updateNavigationState(); @@ -133,15 +137,16 @@ class GUI_API_EXPORT DataView : public QTabWidget, public ExtActionContainer void updateCurrentFormViewRow(); void setFormViewEnabled(bool enabled); void readData(); - void updateFilterIcon(); void initFormViewForNewRow(); void formViewFocusFirstEditor(); + void recreateFilterInputs(); + void createFilteringActions(); - static FilterMode filterMode; static TabsPosition tabsPosition; static QHash staticActions; static QHash staticActionGroups; + FilterMode filterMode = FilterMode::STRING; QToolBar* gridToolBar = nullptr; QToolBar* formToolBar = nullptr; SqlQueryView* gridView = nullptr; @@ -149,6 +154,9 @@ class GUI_API_EXPORT DataView : public QTabWidget, public ExtActionContainer FormView* formView = nullptr; QWidget* gridWidget = nullptr; QWidget* formWidget = nullptr; + QScrollArea* perColumnFilterArea = nullptr; + QWidget* perColumnWidget = nullptr; + QWidget* perColumnAreaParent = nullptr; ExtLineEdit* filterEdit = nullptr; QLabel* rowCountLabel = nullptr; QLabel* formViewRowCountLabel = nullptr; @@ -161,6 +169,10 @@ class GUI_API_EXPORT DataView : public QTabWidget, public ExtActionContainer bool uncommittedGrid = false; bool uncommittedForm = false; WidgetCover* widgetCover = nullptr; + QList filterInputs; + QStringList filterValues; + QWidget* filterLeftSpacer = nullptr; + QWidget* filterRightSpacer = nullptr; signals: @@ -205,6 +217,9 @@ class GUI_API_EXPORT DataView : public QTabWidget, public ExtActionContainer void updateGridCommitCover(int value); void hideGridCommitCover(); void adjustColumnWidth(SqlQueryItem* item); + void syncFilterScrollPosition(); + void resizeFilter(int section, int oldSize, int newSize); + void togglePerColumnFiltering(); }; int qHash(DataView::ActionGroup action); diff --git a/SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp index 8153fed..b6203da 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp @@ -179,7 +179,7 @@ DbListModel::DbTreeComparer::DbTreeComparer() // TODO when sorting or D&D databases in the tree, this should be updated QList allItems = DBTREE->getModel()->getAllItemsAsFlatList(); dbTreeOrder.clear(); - foreach (DbTreeItem* item, allItems) + for (DbTreeItem* item : allItems) { if (item->getType() != DbTreeItem::Type::DB) continue; diff --git a/SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp b/SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp index 43af10e..7dd45fd 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp @@ -97,7 +97,7 @@ ViewWindow* DbObjectDialogs::addView(const QString &initialSelect) ViewWindow* DbObjectDialogs::editView(const QString& database, const QString& view) { ViewWindow* win = nullptr; - foreach (MdiWindow* mdiWin, mdiArea->getWindows()) + for (MdiWindow* mdiWin : mdiArea->getWindows()) { win = dynamic_cast(mdiWin->getMdiChild()); if (!win) @@ -376,7 +376,7 @@ void DbObjectDialogs::setNoConfirmation(bool value) TableWindow* DbObjectDialogs::editTable(const QString& database, const QString& table) { TableWindow* win = nullptr; - foreach (MdiWindow* mdiWin, mdiArea->getWindows()) + for (MdiWindow* mdiWin : mdiArea->getWindows()) { win = dynamic_cast(mdiWin->getMdiChild()); if (!win) diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp index 018eeb6..ba8ccc1 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp @@ -3,6 +3,7 @@ #include "ui_dbtree.h" #include "actionentry.h" #include "common/utils_sql.h" +#include "common/utils.h" #include "dbtreemodel.h" #include "dialogs/dbdialog.h" #include "services/dbmanager.h" @@ -27,6 +28,8 @@ #include "themetuner.h" #include "dialogs/dbconverterdialog.h" #include "querygenerator.h" +#include "dialogs/execfromfiledialog.h" +#include "dialogs/fileexecerrorsdialog.h" #include #include #include @@ -38,6 +41,10 @@ #include #include #include +#include +#include +#include +#include CFG_KEYS_DEFINE(DbTree) QHash> DbTree::allowedTypesInside; @@ -70,10 +77,33 @@ void DbTree::init() ui->nameFilter->setClearButtonEnabled(true); - widgetCover = new WidgetCover(this); - widgetCover->initWithInterruptContainer(); - widgetCover->hide(); - connect(widgetCover, SIGNAL(cancelClicked()), this, SLOT(interrupt())); + treeRefreshWidgetCover = new WidgetCover(this); + treeRefreshWidgetCover->initWithInterruptContainer(); + treeRefreshWidgetCover->hide(); + connect(treeRefreshWidgetCover, SIGNAL(cancelClicked()), this, SLOT(interrupt())); + + fileExecWidgetCover = new WidgetCover(this); + fileExecWidgetCover->initWithInterruptContainer(); + fileExecWidgetCover->displayProgress(100); + fileExecWidgetCover->hide(); + connect(fileExecWidgetCover, &WidgetCover::cancelClicked, [this]() + { + if (!this->executingQueriesFromFile) + return; + + this->executingQueriesFromFile = 0; + + if (this->executingQueriesFromFileDb) // should always be there, but just in case + { + this->executingQueriesFromFileDb->interrupt(); + this->executingQueriesFromFileDb->rollback(); + this->executingQueriesFromFileDb = nullptr; + notifyWarn(tr("Execution from file cancelled. Any queries executed so far have been rolled back.")); + } + }); + connect(this, &DbTree::updateFileExecProgress, this, &DbTree::setFileExecProgress, Qt::QueuedConnection); + connect(this, &DbTree::fileExecCoverToBeClosed, this, &DbTree::hideFileExecCover, Qt::QueuedConnection); + connect(this, &DbTree::fileExecErrors, this, &DbTree::showFileExecErrors, Qt::QueuedConnection); treeModel = new DbTreeModel(); treeModel->setTreeView(ui->treeView); @@ -107,45 +137,47 @@ void DbTree::createActions() createAction(CREATE_GROUP, ICONS.DIRECTORY_ADD, tr("Create a group"), this, SLOT(createGroup()), this); createAction(DELETE_GROUP, ICONS.DIRECTORY_DEL, tr("Delete the group"), this, SLOT(deleteGroup()), this); createAction(RENAME_GROUP, ICONS.DIRECTORY_EDIT, tr("Rename the group"), this, SLOT(renameGroup()), this); - createAction(ADD_DB, ICONS.DATABASE_ADD, tr("Add a database"), this, SLOT(addDb()), this); - createAction(EDIT_DB, ICONS.DATABASE_EDIT, tr("Edit the database"), this, SLOT(editDb()), this); - createAction(DELETE_DB, ICONS.DATABASE_DEL, tr("Remove the database"), this, SLOT(removeDb()), this); - createAction(CONNECT_TO_DB, ICONS.DATABASE_CONNECT, tr("Connect to the database"), this, SLOT(connectToDb()), this); - createAction(DISCONNECT_FROM_DB, ICONS.DATABASE_DISCONNECT, tr("Disconnect from the database"), this, SLOT(disconnectFromDb()), this); + createAction(ADD_DB, ICONS.DATABASE_ADD, tr("&Add a database"), this, SLOT(addDb()), this); + createAction(EDIT_DB, ICONS.DATABASE_EDIT, tr("&Edit the database"), this, SLOT(editDb()), this); + createAction(DELETE_DB, ICONS.DATABASE_DEL, tr("&Remove the database"), this, SLOT(removeDb()), this); + createAction(CONNECT_TO_DB, ICONS.DATABASE_CONNECT, tr("&Connect to the database"), this, SLOT(connectToDb()), this); + createAction(DISCONNECT_FROM_DB, ICONS.DATABASE_DISCONNECT, tr("&Disconnect from the database"), this, SLOT(disconnectFromDb()), this); createAction(IMPORT_INTO_DB, ICONS.IMPORT, tr("Import"), this, SLOT(import()), this); - createAction(EXPORT_DB, ICONS.DATABASE_EXPORT, tr("Export the database"), this, SLOT(exportDb()), this); - createAction(CONVERT_DB, ICONS.CONVERT_DB, tr("Convert database type"), this, SLOT(convertDb()), this); - createAction(VACUUM_DB, ICONS.VACUUM_DB, tr("Vacuum"), this, SLOT(vacuumDb()), this); - createAction(INTEGRITY_CHECK, ICONS.INTEGRITY_CHECK, tr("Integrity check"), this, SLOT(integrityCheck()), this); - createAction(ADD_TABLE, ICONS.TABLE_ADD, tr("Create a table"), this, SLOT(addTable()), this); - createAction(EDIT_TABLE, ICONS.TABLE_EDIT, tr("Edit the table"), this, SLOT(editTable()), this); - createAction(DEL_TABLE, ICONS.TABLE_DEL, tr("Delete the table"), this, SLOT(delTable()), this); + createAction(EXPORT_DB, ICONS.DATABASE_EXPORT, tr("&Export the database"), this, SLOT(exportDb()), this); + createAction(CONVERT_DB, ICONS.CONVERT_DB, tr("Con&vert database type"), this, SLOT(convertDb()), this); + createAction(VACUUM_DB, ICONS.VACUUM_DB, tr("Vac&uum"), this, SLOT(vacuumDb()), this); + createAction(INTEGRITY_CHECK, ICONS.INTEGRITY_CHECK, tr("&Integrity check"), this, SLOT(integrityCheck()), this); + createAction(ADD_TABLE, ICONS.TABLE_ADD, tr("Create a &table"), this, SLOT(addTable()), this); + createAction(EDIT_TABLE, ICONS.TABLE_EDIT, tr("Edit the t&able"), this, SLOT(editTable()), this); + createAction(DEL_TABLE, ICONS.TABLE_DEL, tr("Delete the ta&ble"), this, SLOT(delTable()), this); createAction(EXPORT_TABLE, ICONS.TABLE_EXPORT, tr("Export the table"), this, SLOT(exportTable()), this); createAction(IMPORT_TABLE, ICONS.TABLE_IMPORT, tr("Import into the table"), this, SLOT(importTable()), this); createAction(POPULATE_TABLE, ICONS.TABLE_POPULATE, tr("Populate table"), this, SLOT(populateTable()), this); createAction(CREATE_SIMILAR_TABLE, ICONS.TABLE_CREATE_SIMILAR, tr("Create similar table"), this, SLOT(createSimilarTable()), this); createAction(RESET_AUTOINCREMENT, ICONS.RESET_AUTOINCREMENT, tr("Reset autoincrement sequence"), this, SLOT(resetAutoincrement()), this); - createAction(ADD_INDEX, ICONS.INDEX_ADD, tr("Create an index"), this, SLOT(addIndex()), this); - createAction(EDIT_INDEX, ICONS.INDEX_EDIT, tr("Edit the index"), this, SLOT(editIndex()), this); - createAction(DEL_INDEX, ICONS.INDEX_DEL, tr("Delete the index"), this, SLOT(delIndex()), this); - createAction(ADD_TRIGGER, ICONS.TRIGGER_ADD, tr("Create a trigger"), this, SLOT(addTrigger()), this); - createAction(EDIT_TRIGGER, ICONS.TRIGGER_EDIT, tr("Edit the trigger"), this, SLOT(editTrigger()), this); - createAction(DEL_TRIGGER, ICONS.TRIGGER_DEL, tr("Delete the trigger"), this, SLOT(delTrigger()), this); - createAction(ADD_VIEW, ICONS.VIEW_ADD, tr("Create a view"), this, SLOT(addView()), this); - createAction(EDIT_VIEW, ICONS.VIEW_EDIT, tr("Edit the view"), this, SLOT(editView()), this); - createAction(DEL_VIEW, ICONS.VIEW_DEL, tr("Delete the view"), this, SLOT(delView()), this); + createAction(ADD_INDEX, ICONS.INDEX_ADD, tr("Create an &index"), this, SLOT(addIndex()), this); + createAction(EDIT_INDEX, ICONS.INDEX_EDIT, tr("Edit the i&ndex"), this, SLOT(editIndex()), this); + createAction(DEL_INDEX, ICONS.INDEX_DEL, tr("Delete the in&dex"), this, SLOT(delIndex()), this); + createAction(ADD_TRIGGER, ICONS.TRIGGER_ADD, tr("Create a trig&ger"), this, SLOT(addTrigger()), this); + createAction(EDIT_TRIGGER, ICONS.TRIGGER_EDIT, tr("Edit the trigg&er"), this, SLOT(editTrigger()), this); + createAction(DEL_TRIGGER, ICONS.TRIGGER_DEL, tr("Delete the trigge&r"), this, SLOT(delTrigger()), this); + createAction(ADD_VIEW, ICONS.VIEW_ADD, tr("Create a &view"), this, SLOT(addView()), this); + createAction(EDIT_VIEW, ICONS.VIEW_EDIT, tr("Edit the v&iew"), this, SLOT(editView()), this); + createAction(DEL_VIEW, ICONS.VIEW_DEL, tr("Delete the vi&ew"), this, SLOT(delView()), this); createAction(ADD_COLUMN, ICONS.TABLE_COLUMN_ADD, tr("Add a column"), this, SLOT(addColumn()), this); createAction(EDIT_COLUMN, ICONS.TABLE_COLUMN_EDIT, tr("Edit the column"), this, SLOT(editColumn()), this); createAction(DEL_COLUMN, ICONS.TABLE_COLUMN_DELETE, tr("Delete the column"), this, SLOT(delColumn()), this); createAction(DEL_SELECTED, ICONS.DELETE_SELECTED, tr("Delete selected items"), this, SLOT(deleteSelected()), this); createAction(CLEAR_FILTER, tr("Clear filter"), ui->nameFilter, SLOT(clear()), this); - createAction(REFRESH_SCHEMAS, ICONS.DATABASE_RELOAD, tr("Refresh all database schemas"), this, SLOT(refreshSchemas()), this); - createAction(REFRESH_SCHEMA, ICONS.DATABASE_RELOAD, tr("Refresh selected database schema"), this, SLOT(refreshSchema()), this); + createAction(REFRESH_SCHEMAS, ICONS.DATABASE_RELOAD, tr("&Refresh all database schemas"), this, SLOT(refreshSchemas()), this); + createAction(REFRESH_SCHEMA, ICONS.DATABASE_RELOAD, tr("Re&fresh selected database schema"), this, SLOT(refreshSchema()), this); createAction(ERASE_TABLE_DATA, ICONS.ERASE_TABLE_DATA, tr("Erase table data"), this, SLOT(eraseTableData()), this); createAction(GENERATE_SELECT, "SELECT", this, SLOT(generateSelectForTable()), this); createAction(GENERATE_INSERT, "INSERT", this, SLOT(generateInsertForTable()), this); createAction(GENERATE_UPDATE, "UPDATE", this, SLOT(generateUpdateForTable()), this); createAction(GENERATE_DELETE, "DELETE", this, SLOT(generateDeleteForTable()), this); + createAction(OPEN_DB_DIRECTORY, ICONS.DIRECTORY_OPEN_WITH_DB, tr("Open file's directory"), this, SLOT(openDbDirectory()), this); + createAction(EXEC_SQL_FROM_FILE, ICONS.EXEC_SQL_FROM_FILE, tr("Execute SQL from file"), this, SLOT(execSqlFromFile()), this); } void DbTree::updateActionStates(const QStandardItem *item) @@ -161,7 +193,7 @@ void DbTree::updateActionStates(const QStandardItem *item) // Add database should always be available, as well as a copy of an item enabled << ADD_DB << COPY; - if (isMimeDataValidForItem(QApplication::clipboard()->mimeData(), dbTreeItem)) + if (isMimeDataValidForItem(QApplication::clipboard()->mimeData(), dbTreeItem, true)) enabled << PASTE; enabled << CLEAR_FILTER; @@ -181,6 +213,10 @@ void DbTree::updateActionStates(const QStandardItem *item) } else enabled << CONNECT_TO_DB; + + QUrl url = QUrl::fromLocalFile(dbTreeItem->getDb()->getPath()); + if (url.isValid()) + enabled << OPEN_DB_DIRECTORY; } if (isDbOpen) @@ -193,7 +229,7 @@ void DbTree::updateActionStates(const QStandardItem *item) // It's handled outside of "item with db", above break; case DbTreeItem::Type::DB: - enabled << CREATE_GROUP << DELETE_DB << EDIT_DB; + enabled << CREATE_GROUP << DELETE_DB << EDIT_DB << EXEC_SQL_FROM_FILE; break; case DbTreeItem::Type::TABLES: break; @@ -308,7 +344,7 @@ void DbTree::updateActionStates(const QStandardItem *item) enabled << REFRESH_SCHEMAS; - foreach (int action, actionMap.keys()) + for (int action : actionMap.keys()) setActionEnabled(action, enabled.contains(action)); } @@ -380,6 +416,8 @@ void DbTree::setupActionsForMenu(DbTreeItem* currItem, QMenu* contextMenu) actions += ActionEntry(CONVERT_DB); actions += ActionEntry(VACUUM_DB); actions += ActionEntry(INTEGRITY_CHECK); + actions += ActionEntry(EXEC_SQL_FROM_FILE); + actions += ActionEntry(OPEN_DB_DIRECTORY); actions += ActionEntry(_separator); } else @@ -559,7 +597,7 @@ void DbTree::setupActionsForMenu(DbTreeItem* currItem, QMenu* contextMenu) actions += ActionEntry(REFRESH_SCHEMAS); QMenu* subMenu = nullptr; - foreach (ActionEntry actionEntry, actions) + for (ActionEntry actionEntry : actions) { switch (actionEntry.type) { @@ -576,7 +614,7 @@ void DbTree::setupActionsForMenu(DbTreeItem* currItem, QMenu* contextMenu) case ActionEntry::Type::SUB_MENU: { subMenu = contextMenu->addMenu(actionEntry.subMenuIcon, actionEntry.subMenuLabel); - foreach (Action action, actionEntry.actions) + for (Action action : actionEntry.actions) { if (action == DbTree::_separator) { @@ -624,10 +662,10 @@ DbTreeView*DbTree::getView() const return ui->treeView; } -bool DbTree::isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item) +bool DbTree::isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item, bool forPasting) { if (mimeData->formats().contains(DbTreeModel::MIMETYPE)) - return areDbTreeItemsValidForItem(getModel()->getDragItems(mimeData), item); + return areDbTreeItemsValidForItem(getModel()->getDragItems(mimeData), item, forPasting); else if (mimeData->hasUrls()) return areUrlsValidForItem(mimeData->urls(), item); @@ -639,7 +677,7 @@ bool DbTree::isItemDraggable(const DbTreeItem* item) return item && draggableTypes.contains(item->getType()); } -bool DbTree::areDbTreeItemsValidForItem(QList srcItems, const DbTreeItem* dstItem) +bool DbTree::areDbTreeItemsValidForItem(QList srcItems, const DbTreeItem* dstItem, bool forPasting) { QSet srcDbs; QList srcTypes; @@ -647,6 +685,9 @@ bool DbTree::areDbTreeItemsValidForItem(QList srcItems, const DbTre if (dstItem) dstType = dstItem->getType(); + if (dstType == DbTreeItem::Type::DB && !dstItem->getDb()->isOpen()) + return false; + for (DbTreeItem* srcItem : srcItems) { if (!srcItem) @@ -664,9 +705,6 @@ bool DbTree::areDbTreeItemsValidForItem(QList srcItems, const DbTre { if (!allowedTypesInside[dstType].contains(srcType)) return false; - - if (dstType == DbTreeItem::Type::DB && !dstItem->getDb()->isOpen()) - return false; } // Support for d&d reordering of db objects @@ -677,7 +715,8 @@ bool DbTree::areDbTreeItemsValidForItem(QList srcItems, const DbTre {DbTreeItem::Type::INDEX, DbTreeItem::Type::INDEXES} }; - if (srcTypes.toSet().size() == 1 && srcDbs.size() == 1 && dstItem && *(srcDbs.begin()) == dstItem->getDb() && reorderingTypeToParent[srcTypes.first()] == dstType) + if (!forPasting && srcTypes.toSet().size() == 1 && srcDbs.size() == 1 && dstItem && + *(srcDbs.begin()) == dstItem->getDb() && reorderingTypeToParent[srcTypes.first()] == dstType) return true; // No other d&d within same db @@ -698,14 +737,14 @@ bool DbTree::areUrlsValidForItem(const QList& srcUrls, const DbTreeItem* d return true; } -void DbTree::showWidgetCover() +void DbTree::showRefreshWidgetCover() { - widgetCover->show(); + treeRefreshWidgetCover->show(); } -void DbTree::hideWidgetCover() +void DbTree::hideRefreshWidgetCover() { - widgetCover->hide(); + treeRefreshWidgetCover->hide(); } void DbTree::setSelectedItem(DbTreeItem *item) @@ -861,11 +900,10 @@ void DbTree::filterItemsWithParentInList(QList& items) { QMutableListIterator it(items); DbTreeItem* item = nullptr; - DbTreeItem* pathItem = nullptr; while (it.hasNext()) { item = it.next(); - foreach (pathItem, item->getPathToRoot().mid(1)) + for (DbTreeItem* pathItem : item->getPathToRoot().mid(1)) { if (items.contains(pathItem) && pathItem->getType() != DbTreeItem::Type::DIR) { @@ -1627,7 +1665,6 @@ QList DbTree::getSelectedItems(DbTree::ItemFilterFunc filterFunc) return items; } - void DbTree::deleteItems(const QList& itemsToDelete) { QList items = itemsToDelete; @@ -1642,7 +1679,7 @@ void DbTree::deleteItems(const QList& itemsToDelete) QStringList databasesToRemove; QString itemStr; int groupItems = 0; - foreach (DbTreeItem* item, items) + for (DbTreeItem* item : items) { itemStr = itemTmp.arg(item->getIcon()->toUrl()).arg(item->text().left(ITEM_TEXT_LIMIT)); @@ -1694,7 +1731,7 @@ void DbTree::deleteItems(const QList& itemsToDelete) void DbTree::refreshSchemas() { - foreach (Db* db, DBLIST->getDbList()) + for (Db* db : DBLIST->getDbList()) treeModel->refreshSchema(db); updateActionsForCurrent(); @@ -1716,6 +1753,22 @@ void DbTree::updateActionsForCurrent() updateActionStates(ui->treeView->currentItem()); } +void DbTree::setFileExecProgress(int newValue) +{ + fileExecWidgetCover->setProgress(newValue); +} + +void DbTree::hideFileExecCover() +{ + fileExecWidgetCover->hide(); +} + +void DbTree::showFileExecErrors(const QList >& errors, bool rolledBack) +{ + FileExecErrorsDialog dialog(errors, rolledBack, MAINWINDOW); + dialog.exec(); +} + void DbTree::dbConnected(Db* db) { updateActionsForCurrent(); @@ -1780,6 +1833,166 @@ void DbTree::generateDeleteForTable() MAINWINDOW->openSqlEditor(db, sql); } +void DbTree::openDbDirectory() +{ + Db* db = getSelectedDb(); + if (!db) + return; + + QFileInfo fi(db->getPath()); + if (!fi.exists()) + return; + + QUrl url = QUrl::fromLocalFile(fi.dir().path()); + if (url.isValid()) + QDesktopServices::openUrl(url); +} + +void DbTree::execSqlFromFile() +{ + Db* db = getSelectedDb(); + if (!db || !db->isOpen()) + return; + + ExecFromFileDialog dialog(MAINWINDOW); + int res = dialog.exec(); + if (res != QDialog::Accepted) + return; + + if (executingQueriesFromFile) + return; + + // Exec file + executingQueriesFromFile = 1; + executingQueriesFromFileDb = db; + fileExecWidgetCover->setProgress(0); + fileExecWidgetCover->show(); + if (!db->begin()) + { + notifyError(tr("Could not execute SQL, because application has failed to start transaction: %1").arg(db->getErrorText())); + fileExecWidgetCover->hide(); + return; + } + + QtConcurrent::run(this, &DbTree::execFromFileAsync, dialog.filePath(), db, dialog.ignoreErrors(), dialog.codec()); +} + +void DbTree::execFromFileAsync(const QString& path, Db* db, bool ignoreErrors, const QString& codec) +{ + // Open file + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + notifyError(tr("Could not open file '%1' for reading: %2").arg(path).arg(file.errorString())); + executingQueriesFromFile = 0; + emit fileExecCoverToBeClosed(); + return; + } + + + QTextStream stream(&file); + stream.setCodec(codec.toLatin1().constData()); + + qint64 fileSize = file.size(); + int attemptedExecutions = 0; + int executed = 0; + bool ok = true; + + QTime timer; + timer.start(); + QList> errors = executeFileQueries(db, stream, executed, attemptedExecutions, ok, ignoreErrors, fileSize); + int millis = timer.elapsed(); + if (executingQueriesFromFile.loadAcquire()) + { + handleFileQueryExecution(db, executed, attemptedExecutions, ok, ignoreErrors, millis); + if (!errors.isEmpty()) + emit fileExecErrors(errors, !ok && !ignoreErrors); + } + + file.close(); + emit fileExecCoverToBeClosed(); + executingQueriesFromFile = 0; +} + +QList> DbTree::executeFileQueries(Db* db, QTextStream& stream, int& executed, int& attemptedExecutions, bool& ok, bool ignoreErrors, qint64 fileSize) +{ + QList> errors; + qint64 pos = 0; + QChar c; + QString sql; + sql.reserve(10000); + SqlQueryPtr results; + while (!stream.atEnd() && executingQueriesFromFile.loadAcquire()) + { + while (!db->isComplete(sql) && !stream.atEnd()) + { + stream >> c; + sql.append(c); + while (c != ';' && !stream.atEnd()) + { + stream >> c; + sql.append(c); + } + } + + if (sql.trimmed().isEmpty()) + continue; + + results = db->exec(sql); + attemptedExecutions++; + if (results->isError()) + { + ok = false; + errors << QPair(sql, results->getErrorText()); + + if (!ignoreErrors) + break; + } + else + executed++; + + sql.clear(); + if (attemptedExecutions % 100 == 0) + { + pos = stream.device()->pos(); + emit updateFileExecProgress(static_cast(100 * pos / fileSize)); + } + } + return errors; +} + +void DbTree::handleFileQueryExecution(Db* db, int executed, int attemptedExecutions, bool ok, bool ignoreErrors, int millis) +{ + bool doCommit = ok ? true : ignoreErrors; + if (doCommit) + { + if (!db->commit()) + { + db->rollback(); + notifyError(tr("Could not execute SQL, because application has failed to commit the transaction: %1").arg(db->getErrorText())); + } + else if (!ok) // committed with errors + { + notifyInfo(tr("Finished executing %1 queries in %2 seconds. %3 were not executed due to errors.") + .arg(executed).arg(millis / 1000.0).arg(attemptedExecutions - executed)); + } + else + { + notifyInfo(tr("Finished executing %1 queries in %2 seconds.").arg(executed).arg(millis / 1000.0)); + } + } + else + { + db->rollback(); + notifyError(tr("Could not execute SQL due to error.")); + } +} + +bool DbTree::execQueryFromFile(Db* db, const QString& sql) +{ + return !db->exec(sql)->isError(); +} + void DbTree::setupDefShortcuts() { setShortcutContext({ diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h index f97e5eb..f72ebda 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h +++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h @@ -8,6 +8,7 @@ #include "guiSQLiteStudio_global.h" #include #include +#include class WidgetCover; class QAction; @@ -90,6 +91,8 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer GENERATE_UPDATE, GENERATE_INSERT, GENERATE_DELETE, + OPEN_DB_DIRECTORY, + EXEC_SQL_FROM_FILE, _separator // Never use it directly, it's just for menu setup }; @@ -109,10 +112,10 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer void restoreSession(const QVariant& sessionValue); DbTreeModel* getModel() const; DbTreeView* getView() const; - void showWidgetCover(); - void hideWidgetCover(); + void showRefreshWidgetCover(); + void hideRefreshWidgetCover(); void setSelectedItem(DbTreeItem* item); - bool isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item); + bool isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item, bool forPasting = false); QToolBar* getToolBar(int toolbar) const; Db* getSelectedDb(); Db* getSelectedOpenDb(); @@ -149,14 +152,21 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer QString getSelectedViewName() const; QList getSelectedItems(DbTreeItem::Type itemType); QList getSelectedItems(ItemFilterFunc filterFunc = nullptr); + void execFromFileAsync(const QString& path, Db* db, bool ignoreErrors, const QString& codec); + bool execQueryFromFile(Db* db, const QString& sql); + void handleFileQueryExecution(Db* db, int executed, int attemptedExecutions, bool ok, bool ignoreErrors, int millis); + QList> executeFileQueries(Db* db, QTextStream& stream, int& executed, int& attemptedExecutions, bool& ok, bool ignoreErrors, qint64 fileSize); - static bool areDbTreeItemsValidForItem(QList srcItems, const DbTreeItem* dstItem); + static bool areDbTreeItemsValidForItem(QList srcItems, const DbTreeItem* dstItem, bool forPasting = false); static bool areUrlsValidForItem(const QList& srcUrls, const DbTreeItem* dstItem); static void initDndTypes(); Ui::DbTree *ui = nullptr; DbTreeModel* treeModel = nullptr; - WidgetCover* widgetCover = nullptr; + WidgetCover* treeRefreshWidgetCover = nullptr; + WidgetCover* fileExecWidgetCover = nullptr; + QAtomicInt executingQueriesFromFile = 0; + Db* executingQueriesFromFileDb = nullptr; static QHash> allowedTypesInside; static QSet draggableTypes; @@ -221,6 +231,16 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer void generateInsertForTable(); void generateUpdateForTable(); void generateDeleteForTable(); + void openDbDirectory(); + void execSqlFromFile(); + void setFileExecProgress(int newValue); + void hideFileExecCover(); + void showFileExecErrors(const QList>& errors, bool rolledBack); + + signals: + void updateFileExecProgress(int value); + void fileExecCoverToBeClosed(); + void fileExecErrors(const QList>& errors, bool rolledBack); }; int qHash(DbTree::Action action); diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp index 9fe88c2..123c4df 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp @@ -99,7 +99,7 @@ void DbTreeModel::deleteGroup(QStandardItem *groupItem) if (!parentItem) parentItem = root(); - foreach (QStandardItem* child, dynamic_cast(groupItem)->childs()) + for (QStandardItem* child : dynamic_cast(groupItem)->childs()) move(child, parentItem); parentItem->removeRow(groupItem->row()); @@ -163,12 +163,12 @@ void DbTreeModel::storeGroups() void DbTreeModel::readGroups(QList dbList) { QList groups = CFG->getGroups(); - foreach (const Config::DbGroupPtr& group, groups) + for (const Config::DbGroupPtr& group : groups) restoreGroup(group, &dbList); // Add rest of databases, not mentioned in groups Config::DbGroupPtr group; - foreach (Db* db, dbList) + for (Db* db : dbList) { group = Config::DbGroupPtr::create(); group->referencedDbName = db->getName(); @@ -243,7 +243,7 @@ void DbTreeModel::restoreGroup(const Config::DbGroupPtr& group, QList* dbLi if (item->getType() == DbTreeItem::Type::DIR) { - foreach (const Config::DbGroupPtr& childGroup, group->childs) + for (const Config::DbGroupPtr& childGroup : group->childs) restoreGroup(childGroup, dbList, item); } @@ -538,7 +538,7 @@ QList DbTreeModel::refreshSchemaTables(const QStringList &table sortedTables.sort(Qt::CaseInsensitive); QList items; - foreach (const QString& table, sortedTables) + for (const QString& table : sortedTables) { if (virtualTables.contains(table)) items += DbTreeItemFactory::createVirtualTable(table, this); @@ -605,7 +605,7 @@ QList DbTreeModel::refreshSchemaViews(const QStringList &views, sortedViews.sort(Qt::CaseInsensitive); QList items; - foreach (const QString& view, sortedViews) + for (const QString& view : sortedViews) items += DbTreeItemFactory::createView(view, this); return items; @@ -638,7 +638,7 @@ void DbTreeModel::refreshSchemaBuild(QStandardItem *dbItem, DbTreeItem* columnsItem = nullptr; DbTreeItem* indexesItem = nullptr; DbTreeItem* triggersItem = nullptr; - foreach (QStandardItem* tableItem, tables) + for (QStandardItem* tableItem : tables) { tablesItem->appendRow(tableItem); @@ -650,22 +650,22 @@ void DbTreeModel::refreshSchemaBuild(QStandardItem *dbItem, tableItem->appendRow(indexesItem); tableItem->appendRow(triggersItem); - foreach (QStandardItem* columnItem, allTableColumns[tableItem->text()]) + for (QStandardItem* columnItem : allTableColumns[tableItem->text()]) columnsItem->appendRow(columnItem); - foreach (QStandardItem* indexItem, indexes[tableItem->text()]) + for (QStandardItem* indexItem : indexes[tableItem->text()]) indexesItem->appendRow(indexItem); - foreach (QStandardItem* triggerItem, triggers[tableItem->text()]) + for (QStandardItem* triggerItem : triggers[tableItem->text()]) triggersItem->appendRow(triggerItem); } - foreach (QStandardItem* viewItem, views) + for (QStandardItem* viewItem : views) { viewsItem->appendRow(viewItem); triggersItem = DbTreeItemFactory::createTriggers(this); viewItem->appendRow(triggersItem); - foreach (QStandardItem* triggerItem, triggers[viewItem->text()]) + for (QStandardItem* triggerItem : triggers[viewItem->text()]) triggersItem->appendRow(triggerItem); } } @@ -677,7 +677,7 @@ void DbTreeModel::restoreExpandedState(const QHash& expandedState if (expandedState.contains(sig) && expandedState[sig]) treeView->expand(parentItem->index()); - foreach (QStandardItem* child, parentDbTreeItem->childs()) + for (QStandardItem* child : parentDbTreeItem->childs()) restoreExpandedState(expandedState, child); } @@ -965,7 +965,7 @@ bool DbTreeModel::pasteData(const QMimeData* data, int row, int column, const QM } if (data->formats().contains(MIMETYPE)) - return dropDbTreeItem(getDragItems(data), dstItem, defaultAction, *invokeStdAction); + return dropDbTreeItem(getDragItems(data), dstItem, defaultAction, invokeStdAction); else if (data->hasUrls()) return dropUrls(data->urls()); else @@ -975,7 +975,7 @@ bool DbTreeModel::pasteData(const QMimeData* data, int row, int column, const QM void DbTreeModel::interruptableStarted(Interruptable* obj) { if (interruptables.size() == 0) - treeView->getDbTree()->showWidgetCover(); + treeView->getDbTree()->showRefreshWidgetCover(); interruptables << obj; } @@ -984,7 +984,7 @@ void DbTreeModel::interruptableFinished(Interruptable* obj) { interruptables.removeOne(obj); if (interruptables.size() == 0) - treeView->getDbTree()->hideWidgetCover(); + treeView->getDbTree()->hideRefreshWidgetCover(); } QList DbTreeModel::getDragItems(const QMimeData* data) @@ -1025,7 +1025,7 @@ void DbTreeModel::staticInit() { } -bool DbTreeModel::dropDbTreeItem(const QList& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction, bool& invokeStdDropAction) +bool DbTreeModel::dropDbTreeItem(const QList& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction, bool *invokeStdDropAction) { // The result means: do we want the old item to be removed from the tree? if (srcItems.size() == 0) @@ -1040,9 +1040,9 @@ bool DbTreeModel::dropDbTreeItem(const QList& srcItems, DbTreeItem* if (!dstItem) return false; - if (srcItem->getDb() == dstItem->getDb()) + if (srcItem->getDb() == dstItem->getDb() && invokeStdDropAction) { - invokeStdDropAction = true; + *invokeStdDropAction = true; return true; } @@ -1050,8 +1050,12 @@ bool DbTreeModel::dropDbTreeItem(const QList& srcItems, DbTreeItem* } case DbTreeItem::Type::DB: case DbTreeItem::Type::DIR: - invokeStdDropAction = true; + { + if (invokeStdDropAction) + *invokeStdDropAction = true; + break; + } case DbTreeItem::Type::COLUMN: case DbTreeItem::Type::TABLES: case DbTreeItem::Type::INDEXES: diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h index 50b080d..9ba0d82 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h +++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h @@ -81,7 +81,7 @@ class GUI_API_EXPORT DbTreeModel : public QStandardItemModel QString getDbToolTip(DbTreeItem *item) const; QString getTableToolTip(DbTreeItem *item) const; QList getChildsAsFlatList(QStandardItem* item) const; - bool dropDbTreeItem(const QList& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction, bool &invokeStdDropAction); + bool dropDbTreeItem(const QList& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction, bool* invokeStdDropAction); bool dropDbObjectItem(const QList& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction); QCheckBox* createCopyOrMoveMenuCheckBox(QMenu* menu, const QString& label); bool dropUrls(const QList& urls); diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp index 7785b8f..9382d7c 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp @@ -54,7 +54,7 @@ QList DbTreeView::selectionItems() { QList items; QModelIndexList selectedIndexes = selectionModel()->selectedIndexes(); - foreach (QModelIndex modIdx, selectedIndexes) + for (QModelIndex modIdx : selectedIndexes) items += dynamic_cast(model()->itemFromIndex(modIdx)); return items; diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.ui index 179ee3b..16a6e1f 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.ui +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.ui @@ -17,7 +17,7 @@ - 2 + 0 @@ -27,7 +27,7 @@ - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> true diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.cpp new file mode 100644 index 0000000..1d7ba66 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.cpp @@ -0,0 +1,133 @@ +#include "bindparamsdialog.h" +#include "ui_bindparamsdialog.h" +#include "common/bindparam.h" +#include "multieditor/multieditor.h" +#include "widgetresizer.h" +#include "services/pluginmanager.h" +#include "multieditor/multieditorwidgetplugin.h" +#include "multieditor/multieditorwidget.h" +#include + +BindParamsDialog::BindParamsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::BindParamsDialog) +{ + init(); +} + +BindParamsDialog::~BindParamsDialog() +{ + delete ui; +} + +void BindParamsDialog::setBindParams(const QVector& params) +{ + bindParams = params; + initEditors(); +} + +void BindParamsDialog::init() +{ + ui->setupUi(this); + + contents = new QWidget(); + QVBoxLayout *contentsLayout = new QVBoxLayout(); + contentsLayout->setSpacing(spacing); + contentsLayout->setMargin(margins); + contentsLayout->setAlignment(Qt::AlignTop); + contents->setLayout(contentsLayout); + + ui->scrollArea->setWidget(contents); + ui->scrollArea->setAlignment(Qt::AlignTop); +} + +void BindParamsDialog::initEditors() +{ + QStringList paramNames; + for (BindParam* param : bindParams) + paramNames << param->originalName; + + MultiEditor* firstEditor = nullptr; + MultiEditor* multiEditor = nullptr; + QVector> paramHistory = CFG->getBindParamHistory(paramNames); + for (BindParam* param : bindParams) + { + multiEditor = initEditor(param, paramHistory.size() > param->position ? paramHistory[param->position].second : QVariant()); + if (firstEditor == nullptr) + firstEditor = multiEditor; + } + + firstEditor->focusThisEditor(); +} + +MultiEditor* BindParamsDialog::initEditor(BindParam* param, const QVariant& cachedValue) +{ + // Label + static_qstring(nameTpl, "[%1] %2"); + QString label = nameTpl.arg(param->position + 1).arg(param->originalName); + + // MultiEditor + MultiEditor* multiEditor = new MultiEditor(this, MultiEditor::DYNAMIC); + multiEditor->setReadOnly(false); + multiEditor->setCornerLabel(label); + contents->layout()->addWidget(multiEditor); + contents->layout()->setAlignment(multiEditor, Qt::AlignTop); + editors[param] = multiEditor; + + // MultiEditor editors + MultiEditorWidgetPlugin* plugin = dynamic_cast(PLUGINS->getLoadedPlugin("MultiEditorNumericPlugin")); + MultiEditorWidget* editor = plugin->getInstance(); + editor->setTabLabel(plugin->getTabLabel()); + multiEditor->addEditor(editor); + + plugin = dynamic_cast(PLUGINS->getLoadedPlugin("MultiEditorTextPlugin")); + editor = plugin->getInstance(); + editor->setTabLabel(plugin->getTabLabel()); + multiEditor->addEditor(editor); + + // Resizer + WidgetResizer* resizer = new WidgetResizer(Qt::Vertical); + resizer->setWidget(multiEditor); + resizer->setWidgetMinimumSize(0, minimumFieldHeight); + contents->layout()->addWidget(resizer); + resizer->minimizeHeight(); + + if (cachedValue.isValid()) + { + switch (cachedValue.type()) + { + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Int: + case QVariant::UInt: + case QVariant::Double: + multiEditor->showTab(0); + break; + default: + multiEditor->showTab(1); + break; + } + + multiEditor->setValue(cachedValue); + } + + return multiEditor; +} + +void BindParamsDialog::accept() +{ + QVector> paramHistory; + paramHistory.reserve(bindParams.size()); + bool rememberValue = false; + QVariant emptyValue; + for (BindParam* param : bindParams) + { + param->value = editors[param]->getValue(); + rememberValue = (param->value.type() != QVariant::ByteArray || param->value.toByteArray().size() <= 102400); + paramHistory << QPair(param->originalName, rememberValue ? param->value : emptyValue); + } + + CFG->addBindParamHistory(paramHistory); + + QDialog::accept(); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.h new file mode 100644 index 0000000..666ffc4 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.h @@ -0,0 +1,41 @@ +#ifndef BINDPARAMSDIALOG_H +#define BINDPARAMSDIALOG_H + +#include + +namespace Ui { + class BindParamsDialog; +} + +struct BindParam; +class MultiEditor; + +class BindParamsDialog : public QDialog +{ + Q_OBJECT + + public: + explicit BindParamsDialog(QWidget *parent = nullptr); + ~BindParamsDialog(); + + void setBindParams(const QVector& params); + + private: + void init(); + void initEditors(); + MultiEditor* initEditor(BindParam* param, const QVariant& cachedValue); + + static const int margins = 2; + static const int spacing = 2; + static const int minimumFieldHeight = 80; + + Ui::BindParamsDialog *ui; + QVector bindParams; + QHash editors; + QWidget* contents = nullptr; + + public slots: + void accept(); +}; + +#endif // BINDPARAMSDIALOG_H diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.ui new file mode 100644 index 0000000..b6af05a --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/bindparamsdialog.ui @@ -0,0 +1,97 @@ + + + BindParamsDialog + + + Qt::WindowModal + + + + 0 + 0 + 576 + 420 + + + + Query parameters + + + true + + + + + + Please provide values for query parameters + + + Qt::AlignCenter + + + + + + + true + + + + + 0 + 0 + 556 + 352 + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Abort|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + BindParamsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + BindParamsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.cpp deleted file mode 100644 index 59a2ec6..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "bugdialog.h" -#include "ui_bugdialog.h" -#include "iconmanager.h" -#include "uiutils.h" -#include "common/utils.h" -#include "sqlitestudio.h" -#include "mainwindow.h" -#include "bugreportlogindialog.h" -#include "services/pluginmanager.h" -#include "services/bugreporter.h" -#include "services/notifymanager.h" -#include -#include -#include - -BugDialog::BugDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::BugDialog) -{ - init(); -} - -BugDialog::~BugDialog() -{ - delete ui; -} - -void BugDialog::setFeatureRequestMode(bool feature) -{ - bugMode = !feature; - updateState(); -} - -void BugDialog::init() -{ - ui->setupUi(this); - resize(width(), height() - 50); - - ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Send")); - - connect(ui->moreDetailsGroup, SIGNAL(toggled(bool)), this, SLOT(updateState())); - connect(ui->shortDescriptionEdit, SIGNAL(textChanged(QString)), this, SLOT(validate())); - connect(ui->longDescriptionEdit, SIGNAL(textChanged()), this, SLOT(validate())); - connect(ui->emailEdit, SIGNAL(textChanged(QString)), this, SLOT(validate())); - connect(ui->helpButton, SIGNAL(clicked()), this, SLOT(help())); - connect(ui->loginButton, SIGNAL(clicked()), this, SLOT(logIn())); - - ui->versionEdit->setText(SQLITESTUDIO->getVersionString()); - ui->osEdit->setText(getOsString()); - ui->pluginsEdit->setText(PLUGINS->getLoadedPluginNames().join(", ")); - - user = CFG_CORE.Internal.BugReportUser.get(); - - if (CFG_CORE.Internal.BugReportRecentError.get()) - { - ui->shortDescriptionEdit->setText(CFG_CORE.Internal.BugReportRecentTitle.get()); - ui->longDescriptionEdit->setPlainText(CFG_CORE.Internal.BugReportRecentContents.get()); - } - - updateState(); - validate(); -} - -QString BugDialog::getMessageAboutReportHistory() -{ - return tr("You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'.").arg(MAINWINDOW->getSQLiteStudioMenu()->title()) - .arg(MAINWINDOW->getAction(MainWindow::BUG_REPORT_HISTORY)->text()); -} - -void BugDialog::finishedBugReport(bool success, const QString& errorMsg) -{ - if (success) - { - notifyInfo(tr("A bug report sent successfully.") + " " + getMessageAboutReportHistory()); - } - else - { - CFG_CORE.Internal.BugReportRecentError.set(true); - notifyError(tr("An error occurred while sending a bug report: %1\n%2").arg(errorMsg, - tr("You can retry sending. The contents will be restored when you open a report dialog after an error like this."))); - } -} - -void BugDialog::finishedFeatureRequest(bool success, const QString& errorMsg) -{ - if (success) - { - notifyInfo(tr("An idea proposal sent successfully.") + " " + getMessageAboutReportHistory()); - } - else - { - CFG_CORE.Internal.BugReportRecentError.set(true); - notifyError(tr("An error occurred while sending an idea proposal: %1\n%2").arg(errorMsg, - tr("You can retry sending. The contents will be restored when you open a report dialog after an error like this."))); - } -} - -void BugDialog::updateState() -{ - ui->scrollArea->setVisible(ui->moreDetailsGroup->isChecked()); - - ui->moreDetailsGroup->setVisible(bugMode); - if (bugMode) - { - setWindowTitle(tr("A bug report")); - ui->shortDescriptionEdit->setPlaceholderText(tr("Describe problem in few words")); - ui->longDescriptionEdit->setPlaceholderText(tr("Describe problem and how to reproduce it")); - } - else - { - setWindowTitle(tr("A new feature idea")); - ui->shortDescriptionEdit->setPlaceholderText(tr("A title for your idea")); - ui->longDescriptionEdit->setPlaceholderText(tr("Describe your idea in more details")); - } - - if (user.isNull()) - { - ui->currentLoginLabel->setToolTip(tr("Reporting as an unregistered user, using e-mail address.")); - ui->currentLoginLabel->setPixmap(ICONS.USER_UNKNOWN); - ui->emailEdit->setEnabled(true); - ui->loginButton->setText(tr("Log in")); - ui->loginButton->setIcon(ICONS.USER); - validate(); - } - else - { - ui->currentLoginLabel->setToolTip(tr("Reporting as a registered user.")); - ui->currentLoginLabel->setPixmap(ICONS.USER); - ui->emailEdit->setText(user); - ui->emailEdit->setEnabled(false); - ui->loginButton->setText(tr("Log out")); - ui->loginButton->setIcon(ICONS.USER_UNKNOWN); - } -} - -void BugDialog::validate() -{ - bool emailOk = !user.isNull() || validateEmail(ui->emailEdit->text()); - int shortSize = ui->shortDescriptionEdit->text().trimmed().size(); - int longSize = ui->longDescriptionEdit->toPlainText().trimmed().size(); - bool shortOk = shortSize >= 10 && shortSize <= 100; - bool longOk = longSize >= 30; - - setValidStateWihtTooltip(ui->emailEdit, tr("Providing true email address will make it possible to contact you regarding your report. " - "To learn more, press 'help' button on the right side."), - emailOk, tr("Enter vaild e-mail address, or log in.")); - - setValidState(ui->shortDescriptionEdit, shortOk, tr("Short description requires at least 10 characters, but not more than 100. " - "Longer description can be entered in the field below.")); - - setValidState(ui->longDescriptionEdit, longOk, tr("Long description requires at least 30 characters.")); - - bool valid = shortOk && longOk && emailOk; - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); -} - -void BugDialog::help() -{ - if (user.isNull()) - QDesktopServices::openUrl(QUrl(BUGS->getReporterEmailHelpUrl())); - else - QDesktopServices::openUrl(QUrl(BUGS->getReporterUserAndPasswordHelpUrl())); -} - -void BugDialog::logIn() -{ - if (!user.isNull()) - { - // Log out - user = QString(); - updateState(); - BUGS->clearBugReportCredentials(); - return; - } - - BugReportLoginDialog dialog(this); - if (dialog.exec() != QDialog::Accepted) - return; - - if (!dialog.isValid()) - return; - - BUGS->useBugReportCredentials(dialog.getLogin(), dialog.getPassword()); - user = dialog.getLogin(); - updateState(); -} - -void BugDialog::accept() -{ - CFG_CORE.Internal.BugReportRecentError.set(false); - CFG_CORE.Internal.BugReportRecentTitle.set(ui->shortDescriptionEdit->text()); - CFG_CORE.Internal.BugReportRecentContents.set(ui->longDescriptionEdit->toPlainText()); - - if (bugMode) - { - if (user.isNull()) - { - BUGS->reportBug(ui->emailEdit->text(), ui->shortDescriptionEdit->text(), ui->longDescriptionEdit->toPlainText(), ui->versionEdit->text(), - ui->osEdit->text(), ui->pluginsEdit->text(), BugDialog::finishedBugReport); - } - else - { - BUGS->reportBug(ui->shortDescriptionEdit->text(), ui->longDescriptionEdit->toPlainText(), ui->versionEdit->text(), ui->osEdit->text(), ui->pluginsEdit->text(), - BugDialog::finishedFeatureRequest); - } - } - else - { - if (user.isNull()) - { - BUGS->requestFeature(ui->emailEdit->text(), ui->shortDescriptionEdit->text(), ui->longDescriptionEdit->toPlainText(), BugDialog::finishedFeatureRequest); - } - else - { - BUGS->requestFeature(ui->shortDescriptionEdit->text(), ui->longDescriptionEdit->toPlainText(), BugDialog::finishedFeatureRequest); - } - } - QDialog::accept(); -} diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.h deleted file mode 100644 index bf60104..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef BUGDIALOG_H -#define BUGDIALOG_H - -#include "guiSQLiteStudio_global.h" -#include - -namespace Ui { - class BugDialog; -} - -class GUI_API_EXPORT BugDialog : public QDialog -{ - Q_OBJECT - - public: - explicit BugDialog(QWidget *parent = 0); - ~BugDialog(); - - void setFeatureRequestMode(bool feature); - - private: - void init(); - - static QString getMessageAboutReportHistory(); - static void finishedBugReport(bool success, const QString& errorMsg); - static void finishedFeatureRequest(bool success, const QString& errorMsg); - - Ui::BugDialog *ui = nullptr; - bool bugMode = true; - QString user; - - private slots: - void updateState(); - void validate(); - void help(); - void logIn(); - - public slots: - void accept(); -}; - -#endif // BUGDIALOG_H diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.ui deleted file mode 100644 index 3871436..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugdialog.ui +++ /dev/null @@ -1,208 +0,0 @@ - - - BugDialog - - - - 0 - 0 - 516 - 421 - - - - Bugs and ideas - - - - - - Reporter - - - - - - - - - :/icons/img/user_unknown.png - - - - - - - E-mail address - - - - - - - Log in - - - - :/icons/img/user.png:/icons/img/user.png - - - - - - - ... - - - - :/icons/img/help.png:/icons/img/help.png - - - - - - - - - - Short description - - - - - - - - - - - - Detailed description - - - - - - - - - - - - Show more details - - - true - - - false - - - - - - true - - - - - 0 - 0 - 462 - 209 - - - - - - - SQLiteStudio version - - - - - - - - - - - - Operating system - - - - - - - - - - - - Loaded plugins - - - - - - - - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - BugDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - BugDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.cpp deleted file mode 100644 index 19727fe..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "bugreportlogindialog.h" -#include "ui_bugreportlogindialog.h" -#include "uiutils.h" -#include "services/bugreporter.h" -#include "iconmanager.h" -#include "common/widgetcover.h" -#include - -BugReportLoginDialog::BugReportLoginDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::BugReportLoginDialog) -{ - init(); -} - -BugReportLoginDialog::~BugReportLoginDialog() -{ - delete ui; -} - -bool BugReportLoginDialog::isValid() const -{ - return validCredentials; -} - -QString BugReportLoginDialog::getLogin() const -{ - return ui->loginEdit->text(); -} - -QString BugReportLoginDialog::getPassword() const -{ - return ui->passwordEdit->text(); -} - -void BugReportLoginDialog::init() -{ - ui->setupUi(this); - connect(ui->loginEdit, SIGNAL(textChanged(QString)), this, SLOT(credentialsChanged())); - connect(ui->passwordEdit, SIGNAL(textChanged(QString)), this, SLOT(credentialsChanged())); - connect(ui->validationButton, SIGNAL(clicked()), this, SLOT(remoteValidation())); - connect(BUGS, SIGNAL(credentialsValidationResult(bool,QString)), this, SLOT(remoteValidationResult(bool,QString))); - - widgetCover = new WidgetCover(this); - widgetCover->initWithInterruptContainer(tr("Abort")); - connect(widgetCover, SIGNAL(cancelClicked()), this, SLOT(abortRemoteValidation())); - - validate(); -} - -void BugReportLoginDialog::credentialsChanged() -{ - validCredentials = false; - validate(); -} - -void BugReportLoginDialog::validate() -{ - QString login = ui->loginEdit->text(); - QString pass = ui->passwordEdit->text(); - - bool loginOk = login.size() >= 2; - bool passOk = pass.size() >= 5; - - setValidState(ui->loginEdit, loginOk, tr("A login must be at least 2 characters long.")); - setValidState(ui->passwordEdit, passOk, tr("A password must be at least 5 characters long.")); - - bool credentialsOk = loginOk && passOk; - ui->validationButton->setEnabled(credentialsOk); - ui->validationLabel->setEnabled(credentialsOk); - - bool valid = credentialsOk && validCredentials; - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); -} - -void BugReportLoginDialog::abortRemoteValidation() -{ - BUGS->abortCredentialsValidation(); -} - -void BugReportLoginDialog::remoteValidation() -{ - widgetCover->show(); - BUGS->validateBugReportCredentials(ui->loginEdit->text(), ui->passwordEdit->text()); -} - -void BugReportLoginDialog::remoteValidationResult(bool success, const QString& errorMessage) -{ - validCredentials = success; - ui->validationButton->setIcon(success ? ICONS.TEST_CONN_OK : ICONS.TEST_CONN_ERROR); - ui->validationLabel->setText(success ? tr("Valid") : errorMessage); - validate(); - widgetCover->hide(); -} diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.h deleted file mode 100644 index 131ba3d..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef BUGREPORTLOGINDIALOG_H -#define BUGREPORTLOGINDIALOG_H - -#include "guiSQLiteStudio_global.h" -#include - -namespace Ui { - class BugReportLoginDialog; -} - -class WidgetCover; - -class GUI_API_EXPORT BugReportLoginDialog : public QDialog -{ - Q_OBJECT - - public: - explicit BugReportLoginDialog(QWidget *parent = 0); - ~BugReportLoginDialog(); - - bool isValid() const; - QString getLogin() const; - QString getPassword() const; - - private: - void init(); - - Ui::BugReportLoginDialog *ui = nullptr; - bool validCredentials = false; - WidgetCover* widgetCover = nullptr; - - private slots: - void credentialsChanged(); - void validate(); - void abortRemoteValidation(); - void remoteValidation(); - void remoteValidationResult(bool success, const QString& errorMessage); -}; - -#endif // BUGREPORTLOGINDIALOG_H diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.ui deleted file mode 100644 index d1d26e6..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/bugreportlogindialog.ui +++ /dev/null @@ -1,132 +0,0 @@ - - - BugReportLoginDialog - - - - 0 - 0 - 343 - 197 - - - - Log in - - - - - - Credentials - - - - - - Login: - - - - - - - - - - Password: - - - - - - - QLineEdit::Password - - - - - - - - - - Validation - - - - - - Validate - - - - :/icons/img/test_conn_error.png:/icons/img/test_conn_error.png - - - Qt::ToolButtonTextBesideIcon - - - - - - - Validation result message - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - BugReportLoginDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - BugReportLoginDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp index 14cb06b..8bf1698 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp @@ -37,7 +37,7 @@ void ColumnDialog::init() ui->precision->setStrict(true, true); ui->typeCombo->addItem(""); - foreach (DataType::Enum type, DataType::getAllTypes()) + for (DataType::Enum type : DataType::getAllTypes()) ui->typeCombo->addItem(DataType::toString(type)); connect(ui->typeCombo, SIGNAL(currentTextChanged(QString)), this, SLOT(updateDataType())); @@ -149,6 +149,7 @@ void ColumnDialog::addConstraint(ConstraintDialog::Constraint mode) constraintsModel->appendConstraint(constr); ui->constraintsView->resizeColumnToContents(0); ui->constraintsView->resizeColumnToContents(1); + updateTypeForAutoIncr(); } void ColumnDialog::setupConstraintCheckBoxes() @@ -218,6 +219,7 @@ void ColumnDialog::editConstraint(SqliteCreateTable::Column::Constraint* constra ui->constraintsView->resizeColumnToContents(0); ui->constraintsView->resizeColumnToContents(1); updateValidations(); + updateTypeForAutoIncr(); } void ColumnDialog::delConstraint(const QModelIndex& idx) @@ -384,6 +386,8 @@ void ColumnDialog::updateTypeValidations() { QString scaleErrorMsg = tr("Scale is not allowed for INTEGER PRIMARY KEY columns."); QString precisionErrorMsg = tr("Precision cannot be defined without the scale."); + QString typeErrorMsg = tr("Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY."); + QString integerEnforcedMsg = tr("INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY."); QVariant scale = ui->scale->getValue(); QVariant precision = ui->precision->getValue(); @@ -393,6 +397,7 @@ void ColumnDialog::updateTypeValidations() bool precisionOk = !(precisionDefined && !scaleDefined); bool scaleOk = true; + bool typeOk = true; bool hasPk = column->getConstraint(SqliteCreateTable::Column::Constraint::PRIMARY_KEY) != nullptr; bool isInteger = ui->typeCombo->currentText().toUpper() == "INTEGER"; @@ -408,16 +413,48 @@ void ColumnDialog::updateTypeValidations() } } + if (!isInteger && hasAutoIncr()) + typeOk = false; + setValidState(ui->scale, scaleOk, scaleErrorMsg); setValidState(ui->precision, precisionOk, precisionErrorMsg); + setValidState(ui->typeCombo, typeOk, typeErrorMsg); + + if (typeOk && integerTypeEnforced) + setValidStateTooltip(ui->typeCombo, integerEnforcedMsg); - if (!scaleOk || !precisionOk) + if (!scaleOk || !precisionOk || !typeOk) { QPushButton* btn = ui->buttonBox->button(QDialogButtonBox::Ok); btn->setEnabled(false); } } +void ColumnDialog::updateTypeForAutoIncr() +{ + bool hasAuto = hasAutoIncr(); + if (hasAuto && ui->typeCombo->currentText().toUpper() != "INTEGER") + { + ui->typeCombo->setCurrentText("INTEGER"); + integerTypeEnforced = true; + } + else if (!hasAuto) + integerTypeEnforced = false; + + updateTypeValidations(); +} + +bool ColumnDialog::hasAutoIncr() const +{ + for (SqliteCreateTable::Column::Constraint* constr : column->getConstraints(SqliteCreateTable::Column::Constraint::PRIMARY_KEY)) + { + if (constr->autoincrKw) + return true; + } + + return false; +} + void ColumnDialog::moveConstraintUp() { QModelIndex idx = ui->constraintsView->currentIndex(); @@ -509,6 +546,7 @@ void ColumnDialog::configureDefault() void ColumnDialog::pkToggled(bool enabled) { constraintToggled(SqliteCreateTable::Column::Constraint::PRIMARY_KEY, enabled); + updateTypeForAutoIncr(); } void ColumnDialog::fkToggled(bool enabled) @@ -630,6 +668,7 @@ void ColumnDialog::updateDataType() if (!column) return; + integerTypeEnforced = false; QString typeTxt = ui->typeCombo->currentText(); QString scaleTxt = ui->scale->getValue().toString(); QString precisionTxt = ui->precision->getValue().toString(); diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h index 596441c..47615e8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h @@ -68,12 +68,15 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer QToolButton* getToolButtonForConstraint(SqliteCreateTable::Column::Constraint* constraint); bool isUnofficialSqlite2Constraint(SqliteCreateTable::Column::Constraint* constraint); void updateTypeValidations(); + void updateTypeForAutoIncr(); + bool hasAutoIncr() const; Ui::ColumnDialog *ui = nullptr; SqliteCreateTable::ColumnPtr column; ColumnDialogConstraintsModel* constraintsModel = nullptr; QCheckBox* modeCheckBox = nullptr; Db* db = nullptr; + bool integerTypeEnforced = false; private slots: void updateConstraintsToolbarState(); diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp index 85ae12d..63af58a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp @@ -63,7 +63,7 @@ ConfigDialog::~ConfigDialog() // Notify plugins about dialog being closed UiConfiguredPlugin* cfgPlugin = nullptr; - foreach (Plugin* plugin, PLUGINS->getLoadedPlugins()) + for (Plugin* plugin : PLUGINS->getLoadedPlugins()) { cfgPlugin = dynamic_cast(plugin); if (!cfgPlugin) @@ -133,7 +133,7 @@ QString ConfigDialog::getFilterString(QTreeWidget *widget) { QList items = widget->findItems("*", Qt::MatchWildcard|Qt::MatchRecursive); QStringList strList; - foreach (QTreeWidgetItem* item, items) + for (QTreeWidgetItem* item : items) for (int i = 0; i < widget->columnCount(); i++) strList << item->text(i) + " " + item->toolTip(0); @@ -144,7 +144,7 @@ QString ConfigDialog::getFilterString(QListWidget *widget) { QList items = widget->findItems("*", Qt::MatchWildcard|Qt::MatchRecursive); QStringList strList; - foreach (QListWidgetItem* item, items) + for (QListWidgetItem* item : items) strList << item->text() + " " + item->toolTip(); return strList.join(" "); @@ -154,7 +154,7 @@ QString ConfigDialog::getFilterString(QTableWidget *widget) { QList items = widget->findItems("*", Qt::MatchWildcard|Qt::MatchRecursive); QStringList strList; - foreach (QTableWidgetItem* item, items) + for (QTableWidgetItem* item : items) strList << item->text() + " " + item->toolTip(); return strList.join(" "); @@ -299,7 +299,7 @@ void ConfigDialog::applyFilter(const QString &filter) QColor disabledColor = ui->categoriesTree->palette().color(QPalette::Disabled, QPalette::WindowText); if (filter.isEmpty()) { - foreach (QTreeWidgetItem* item, getAllCategoryItems()) + for (QTreeWidgetItem* item : getAllCategoryItems()) item->setForeground(0, normalColor); return; @@ -307,7 +307,7 @@ void ConfigDialog::applyFilter(const QString &filter) QList widgets = ui->stackedWidget->findChildren(); QList matchedWidgets; - foreach (QWidget* widget, widgets) + for (QWidget* widget : widgets) { if (getFilterString(widget).contains(filter, Qt::CaseInsensitive)) matchedWidgets << widget; @@ -315,9 +315,9 @@ void ConfigDialog::applyFilter(const QString &filter) QHash pageToCategoryItem = buildPageToCategoryItemMap(); QSet matchedCategories; - foreach (QWidget* page, pageToCategoryItem.keys()) + for (QWidget* page : pageToCategoryItem.keys()) { - foreach (QWidget* matched, matchedWidgets) + for (QWidget* matched : matchedWidgets) { if (page->isAncestorOf(matched)) { @@ -333,10 +333,10 @@ void ConfigDialog::applyFilter(const QString &filter) } } - foreach (QTreeWidgetItem* item, getAllCategoryItems()) + for (QTreeWidgetItem* item : getAllCategoryItems()) item->setForeground(0, disabledColor); - foreach (QTreeWidgetItem* item, matchedCategories) + for (QTreeWidgetItem* item : matchedCategories) { item->setForeground(0, normalColor); while ((item = item->parent()) != nullptr) @@ -347,7 +347,7 @@ void ConfigDialog::applyFilter(const QString &filter) QHash ConfigDialog::buildPageToCategoryItemMap() const { QHash pageNameToCategoryItem; - foreach (QTreeWidgetItem* item, getAllCategoryItems()) + for (QTreeWidgetItem* item : getAllCategoryItems()) pageNameToCategoryItem[item->statusTip(0)] = item; QWidget* page = nullptr; @@ -486,7 +486,14 @@ void ConfigDialog::addDataTypeEditor(const QString& pluginName) void ConfigDialog::addDataTypeEditor(MultiEditorWidgetPlugin* plugin) { MultiEditorWidget* editor = plugin->getInstance(); + editor->setTabLabel(plugin->getTabLabel()); ui->dataEditorsSelectedTabs->addTab(editor, editor->getTabLabel().replace("&", "&&")); + + connect(editor, &MultiEditorWidget::aboutToBeDeleted, [this, editor]() + { + int idx = ui->dataEditorsSelectedTabs->indexOf(editor); + ui->dataEditorsSelectedTabs->removeTab(idx); + }); } void ConfigDialog::removeDataTypeEditor(QListWidgetItem* item, const QString& pluginName) @@ -704,7 +711,7 @@ void ConfigDialog::delDataType() void ConfigDialog::dataTypesHelp() { - static const QString url = QStringLiteral("http://wiki.sqlitestudio.pl/index.php/User_Manual#Customizing_data_type_editors"); + static const QString url = QStringLiteral("https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#customizing-data-type-editors"); QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode)); } @@ -1085,7 +1092,7 @@ void ConfigDialog::refreshFormattersPage() void ConfigDialog::applyStyle(QWidget *widget, QStyle *style) { widget->setStyle(style); - foreach (QObject* child, widget->children()) + for (QObject* child : widget->children()) { if (!qobject_cast(child)) continue; @@ -1184,7 +1191,7 @@ void ConfigDialog::initPlugins() // Recreate QTreeWidgetItem *typeItem = nullptr; - foreach (PluginType* pluginType, PLUGINS->getPluginTypes()) + for (PluginType* pluginType : PLUGINS->getPluginTypes()) { typeItem = createPluginsTypeItem(pluginType->getConfigUiForm(), pluginType->getTitle()); if (!typeItem) @@ -1193,7 +1200,7 @@ void ConfigDialog::initPlugins() item->addChild(typeItem); pluginTypeToItemMap[pluginType] = typeItem; - foreach (Plugin* plugin, pluginType->getLoadedPlugins()) + for (Plugin* plugin : pluginType->getLoadedPlugins()) pluginLoaded(plugin, pluginType, true); } @@ -1244,7 +1251,7 @@ void ConfigDialog::initPluginsPage() categoryRow = 0; QList pluginTypes = PLUGINS->getPluginTypes(); qSort(pluginTypes.begin(), pluginTypes.end(), PluginType::nameLessThan); - foreach (PluginType* pluginType, pluginTypes) + for (PluginType* pluginType : pluginTypes) { category = new QTreeWidgetItem({pluginType->getTitle()}); font.setItalic(false); @@ -1264,7 +1271,7 @@ void ConfigDialog::initPluginsPage() itemRow = 0; pluginNames = pluginType->getAllPluginNames(); qSort(pluginNames); - foreach (const QString& pluginName, pluginNames) + for (const QString& pluginName : pluginNames) { builtIn = PLUGINS->isBuiltIn(pluginName); title = PLUGINS->getTitle(pluginName); @@ -1497,7 +1504,7 @@ void ConfigDialog::initShortcuts(CfgCategory *cfgCategory) int itemRow = 0; QStringList entryNames = cfgCategory->getEntries().keys(); qSort(entryNames); - foreach (const QString& entryName, entryNames) + for (const QString& entryName : entryNames) { // Title title = cfgCategory->getEntries()[entryName]->getTitle(); diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui index 6bedd25..fe0b772 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui @@ -229,7 +229,7 @@ - 1 + 3 @@ -407,8 +407,8 @@ 0 0 - 564 - 580 + 577 + 472 @@ -418,17 +418,30 @@ Data browsing and editing - - + + - <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> - Limit initial data column width to (in pixels): + Number of memorized table populating configurations - + + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + + + 999999 + + + General.PopulateHistorySize + + + + @@ -447,7 +460,7 @@ - + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> @@ -466,27 +479,37 @@ - - + + - <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> - Show column and row details tooltip in data view - - - General.ShowDataViewTooltips + Limit initial data column width to (in pixels): - + Number of data rows per page: - + + + + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> + + + Show column and row details tooltip in data view + + + General.ShowDataViewTooltips + + + + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> @@ -499,7 +522,7 @@ - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> @@ -837,8 +860,21 @@ - - + + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + 999999 + + + General.BindParamsCacheSize + + + + + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> @@ -850,6 +886,16 @@ + + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + Number of memorized query parameters + + + @@ -1027,8 +1073,8 @@ 0 0 - 447 - 307 + 335 + 237 @@ -1448,8 +1494,8 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Abcdefgh</span></p></body></html> +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Abcdefgh</span></p></body></html> @@ -1539,8 +1585,8 @@ p, li { white-space: pre-wrap; } 0 0 - 268 - 328 + 196 + 263 @@ -1661,8 +1707,8 @@ p, li { white-space: pre-wrap; } 0 0 - 331 - 829 + 247 + 701 @@ -2237,7 +2283,7 @@ p, li { white-space: pre-wrap; } ddlHistorySizeSpin dontShowDdlPreview queryHistorySizeSpin - checkBox + execQueryUnderCursorCheck expandTablesCheck activeStyleCombo previewTabs diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp index 781e25e..183f8dd 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp @@ -144,7 +144,7 @@ void DbDialog::updateOptions() setUpdatesEnabled(false); // Remove olds - foreach (QWidget* w, optionWidgets) + for (QWidget* w : optionWidgets) { ui->optionsGrid->removeWidget(w); delete w; @@ -481,7 +481,7 @@ bool DbDialog::validate() if (nameState) { if (nameManuallyEdited) - setValidStateInfo(ui->nameEdit, tr("

    Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.

    ")); + setValidStateInfo(ui->nameEdit, tr("

    Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.

    ")); else setValidState(ui->nameEdit, true); } @@ -560,14 +560,13 @@ void DbDialog::valueForNameGenerationChanged() return; QString generatedName; - if (dbPlugins.count() > 0) - { - DbPlugin* plugin = dbPlugins[ui->typeCombo->currentText()]; + DbPlugin* plugin = dbPlugins.count() > 0 ? dbPlugins[ui->typeCombo->currentText()] : nullptr; + if (plugin) generatedName = DBLIST->generateUniqueDbName(plugin, ui->fileEdit->text()); - } else generatedName = DBLIST->generateUniqueDbName(ui->fileEdit->text()); + ui->nameEdit->setText(generatedName); } diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp index e86f9cd..3af221f 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp @@ -28,7 +28,7 @@ void DdlPreviewDialog::setDdl(const QStringList& ddlList) { QStringList fixedList; QString newDdl; - foreach (const QString& ddl, ddlList) + for (const QString& ddl : ddlList) { newDdl = ddl.trimmed(); if (!newDdl.endsWith(";")) diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.cpp new file mode 100644 index 0000000..3ecae39 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.cpp @@ -0,0 +1,76 @@ +#include "execfromfiledialog.h" +#include "ui_execfromfiledialog.h" +#include "common/utils.h" +#include "uiconfig.h" +#include "uiutils.h" +#include + +ExecFromFileDialog::ExecFromFileDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ExecFromFileDialog) +{ + init(); +} + +ExecFromFileDialog::~ExecFromFileDialog() +{ + delete ui; +} + +bool ExecFromFileDialog::ignoreErrors() const +{ + return ui->skipErrorsCheck->isChecked(); +} + +QString ExecFromFileDialog::filePath() const +{ + return ui->fileEdit->text(); +} + +QString ExecFromFileDialog::codec() const +{ + return ui->encodingCombo->currentText(); +} + +void ExecFromFileDialog::init() +{ + ui->setupUi(this); + + connect(ui->fileBrowse, SIGNAL(clicked()), this, SLOT(browseForInputFile())); + connect(ui->fileEdit, SIGNAL(textChanged(const QString&)), this, SLOT(updateState())); + + ui->encodingCombo->addItems(textCodecNames()); + ui->encodingCombo->setCurrentText(defaultCodecName()); +} + +void ExecFromFileDialog::browseForInputFile() +{ + QString dir = getFileDialogInitPath(); + QString filters = tr("SQL scripts (*.sql);;All files (*)"); + QString path = QFileDialog::getOpenFileName(nullptr, tr("Execute SQL file"), dir, filters); + if (path.isNull()) + return; + + setFileDialogInitPathByFile(path); + ui->fileEdit->setText(path); + updateState(); +} + +void ExecFromFileDialog::updateState() +{ + QString path = ui->fileEdit->text(); + if (path.isEmpty()) + { + setValidState(ui->fileEdit, false, tr("Please provide file to be executed.")); + return; + } + + QFileInfo fi(path); + if (!fi.exists() || !fi.isReadable()) + { + setValidState(ui->fileEdit, false, tr("Provided file does not exist or cannot be read.")); + return; + } + + setValidState(ui->fileEdit, true); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.h new file mode 100644 index 0000000..27751d4 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.h @@ -0,0 +1,32 @@ +#ifndef EXECFROMFILEDIALOG_H +#define EXECFROMFILEDIALOG_H + +#include + +namespace Ui { + class ExecFromFileDialog; +} + +class ExecFromFileDialog : public QDialog +{ + Q_OBJECT + + public: + explicit ExecFromFileDialog(QWidget *parent = nullptr); + ~ExecFromFileDialog(); + + bool ignoreErrors() const; + QString filePath() const; + QString codec() const; + + private: + void init(); + + Ui::ExecFromFileDialog *ui; + + private slots: + void browseForInputFile(); + void updateState(); +}; + +#endif // EXECFROMFILEDIALOG_H diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.ui new file mode 100644 index 0000000..6a24e51 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/execfromfiledialog.ui @@ -0,0 +1,125 @@ + + + ExecFromFileDialog + + + + 0 + 0 + 400 + 203 + + + + Execute SQL from file + + + true + + + + + + Input file + + + + + + Path to file + + + + + + + Browse for file + + + + + + + :/icons/img/directory_open.png:/icons/img/directory_open.png + + + + + + + + + + Options + + + + + + File encoding + + + + + + + + + + Skip failing SQL statements + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + ExecFromFileDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ExecFromFileDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp index 91b4087..7b6a4d0 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp @@ -23,6 +23,15 @@ #include #include +static const QString EXPORT_DIALOG_CFG_GROUP = "ExportDialog"; +static const QString EXPORT_DIALOG_CFG_CODEC = "codec"; +static const QString EXPORT_DIALOG_CFG_FILE = "outputFileName"; +static const QString EXPORT_DIALOG_CFG_CLIP = "intoClipboard"; +static const QString EXPORT_DIALOG_CFG_DATA = "exportData"; +static const QString EXPORT_DIALOG_CFG_IDX = "exportTableIndexes"; +static const QString EXPORT_DIALOG_CFG_TRIG = "exportTableTriggers"; +static const QString EXPORT_DIALOG_CFG_FORMAT = "format"; + ExportDialog::ExportDialog(QWidget *parent) : QWizard(parent), ui(new Ui::ExportDialog) @@ -362,7 +371,10 @@ void ExportDialog::formatPageDisplayed() formatPageVisited = true; } + readStdConfigForLastPage(); pluginSelected(); + + emit formatPageCompleteChanged(); } ExportPlugin* ExportDialog::getSelectedPlugin() const @@ -443,9 +455,6 @@ void ExportDialog::pluginSelected() updateExportOutputOptions(); updateOptions(); - - if (currentPlugin->getConfig() && !currentPlugin->getConfig()->isPersistable()) - currentPlugin->getConfig()->reset(); } void ExportDialog::updateExportOutputOptions() @@ -470,8 +479,18 @@ void ExportDialog::updateExportOutputOptions() ui->encodingLabel->setVisible(displayCodec); if (displayCodec) { - QString codec = currentPlugin->getDefaultEncoding(); + QString codec = CFG->get(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_CODEC).toString(); + QString defaultCodec = currentPlugin->getDefaultEncoding(); + if (codec.isNull()) + codec = defaultCodec; + int idx = ui->encodingCombo->findText(codec); + if (idx == -1 && codec != defaultCodec) + { + codec = defaultCodec; + idx = ui->encodingCombo->findText(codec); + } + if (idx > -1) ui->encodingCombo->setCurrentIndex(idx); } @@ -555,6 +574,12 @@ void ExportDialog::accept() doExport(); } +int ExportDialog::exec() +{ + readStdConfigForFirstPage(); + return QDialog::exec(); +} + void ExportDialog::updatePluginOptions(ExportPlugin* plugin, int& optionsRow) { safe_delete(pluginOptionsWidget); @@ -596,6 +621,46 @@ void ExportDialog::updatePluginOptions(ExportPlugin* plugin, int& optionsRow) plugin->validateOptions(); } +void ExportDialog::storeStdConfig(const ExportManager::StandardExportConfig &stdConfig) +{ + CFG->begin(); + CFG->set(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_CODEC, stdConfig.codec); + CFG->set(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_FILE, stdConfig.outputFileName); + CFG->set(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_CLIP, stdConfig.intoClipboard); + CFG->set(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_DATA, stdConfig.exportData); + CFG->set(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_IDX, stdConfig.exportTableIndexes); + CFG->set(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_TRIG, stdConfig.exportTableTriggers); + CFG->set(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_FORMAT, currentPlugin->getFormatName()); + CFG->commit(); +} + +void ExportDialog::readStdConfigForFirstPage() +{ + bool exportData = CFG->get(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_DATA, true).toBool(); + if (exportMode == ExportManager::DATABASE) + ui->exportDbDataCheck->setChecked(exportData); + else if (exportMode == ExportManager::TABLE) + ui->exportTableDataCheck->setChecked(exportData); + + ui->exportTableIndexesCheck->setChecked(CFG->get(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_IDX, true).toBool()); + ui->exportTableTriggersCheck->setChecked(CFG->get(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_TRIG, true).toBool()); +} + +void ExportDialog::readStdConfigForLastPage() +{ + QString format = CFG->get(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_FORMAT).toString(); + int idx = ui->formatCombo->findText(format); + if (idx > -1) + ui->formatCombo->setCurrentIndex(idx); + + bool useClipboard = CFG->get(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_CLIP, false).toBool(); + ui->exportFileRadio->setChecked(!useClipboard); + ui->exportClipboardRadio->setChecked(useClipboard); + ui->exportFileEdit->setText(CFG->get(EXPORT_DIALOG_CFG_GROUP, EXPORT_DIALOG_CFG_FILE, QString()).toString()); + + // Codec is read within updateExportOutputOptions() +} + void ExportDialog::updateValidation() { if (!currentPlugin) @@ -610,6 +675,9 @@ void ExportDialog::doExport() widgetCover->show(); ExportManager::StandardExportConfig stdConfig = getExportConfig(); + storeStdConfig(stdConfig); + configMapper->saveFromWidget(pluginOptionsWidget); + QString format = ui->formatCombo->currentText(); switch (exportMode) { @@ -684,6 +752,9 @@ ExportManager::StandardExportConfig ExportDialog::getExportConfig() const else stdConfig.exportData = false; + stdConfig.exportTableIndexes = ui->exportTableIndexesCheck->isChecked(); + stdConfig.exportTableTriggers = ui->exportTableTriggersCheck->isChecked(); + if (ui->encodingCombo->isVisible() && ui->encodingCombo->currentIndex() > -1) stdConfig.codec = ui->encodingCombo->currentText(); else diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.h index 0471172..c2f6d7e 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.h +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.h @@ -45,6 +45,9 @@ class GUI_API_EXPORT ExportDialog : public QWizard void formatPageDisplayed(); ExportPlugin* getSelectedPlugin() const; void updatePluginOptions(ExportPlugin* plugin, int& optionsRow); + void storeStdConfig(const ExportManager::StandardExportConfig& stdConfig); + void readStdConfigForFirstPage(); + void readStdConfigForLastPage(); void doExport(); void exportDatabase(const ExportManager::StandardExportConfig& stdConfig, const QString& format); void exportTable(const ExportManager::StandardExportConfig& stdConfig, const QString& format); @@ -96,6 +99,7 @@ class GUI_API_EXPORT ExportDialog : public QWizard public slots: void accept(); + int exec(); signals: void formatPageCompleteChanged(); diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.cpp new file mode 100644 index 0000000..916c8af --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.cpp @@ -0,0 +1,35 @@ +#include "fileexecerrorsdialog.h" +#include "ui_fileexecerrorsdialog.h" + +FileExecErrorsDialog::FileExecErrorsDialog(const QList>& errors, bool rolledBack, QWidget *parent) : + QDialog(parent), + ui(new Ui::FileExecErrorsDialog) +{ + ui->setupUi(this); + + ui->committedLabel->setVisible(!rolledBack); + ui->rolledBackLabel->setVisible(rolledBack); + + ui->tableWidget->setRowCount(errors.size()); + int row = 0; + for (const QPair& err : errors) + { + ui->tableWidget->setItem(row, 0, item(err.first)); + ui->tableWidget->setItem(row, 1, item(err.second)); + row++; + } + ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + ui->tableWidget->resizeRowsToContents(); +} + +FileExecErrorsDialog::~FileExecErrorsDialog() +{ + delete ui; +} + +QTableWidgetItem* FileExecErrorsDialog::item(const QString& text) +{ + QTableWidgetItem* item = new QTableWidgetItem(text); + item->setFlags(Qt::ItemIsEnabled); + return item; +} diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.h new file mode 100644 index 0000000..2b474ce --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.h @@ -0,0 +1,26 @@ +#ifndef FILEEXECERRORSDIALOG_H +#define FILEEXECERRORSDIALOG_H + +#include + +namespace Ui { + class FileExecErrorsDialog; +} + +class QTableWidgetItem; + +class FileExecErrorsDialog : public QDialog +{ + Q_OBJECT + + public: + explicit FileExecErrorsDialog(const QList >& errors, bool rolledBack, QWidget *parent = nullptr); + ~FileExecErrorsDialog(); + + private: + QTableWidgetItem* item(const QString& text); + + Ui::FileExecErrorsDialog *ui; +}; + +#endif // FILEEXECERRORSDIALOG_H diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.ui new file mode 100644 index 0000000..4ad6d6c --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/fileexecerrorsdialog.ui @@ -0,0 +1,132 @@ + + + FileExecErrorsDialog + + + + 0 + 0 + 720 + 436 + + + + Execution errors + + + + + + + 75 + true + + + + Following errors were encountered during execution of SQL statements from the file: + + + true + + + + + + + false + + + false + + + QAbstractItemView::NoSelection + + + 100 + + + + SQL + + + + + Error + + + + + + + + + 75 + true + + + + Statements that were executed successfully were commited. + + + + + + + + 75 + true + + + + Statements that were executed successfully were rolled back. + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + FileExecErrorsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FileExecErrorsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp index 2f52396..ddb443d 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp @@ -6,7 +6,6 @@ #include "common/widgetcover.h" #include "services/dbmanager.h" #include "services/pluginmanager.h" -#include "services/importmanager.h" #include "sqlitestudio.h" #include "plugins/importplugin.h" #include "ui_importdialog.h" @@ -19,6 +18,12 @@ #include #include +static const QString IMPORT_DIALOG_CFG_GROUP = "ImportDialog"; +static const QString IMPORT_DIALOG_CFG_CODEC = "codec"; +static const QString IMPORT_DIALOG_CFG_FILE = "inputFileName"; +static const QString IMPORT_DIALOG_CFG_IGNORE_ERR = "ignoreErrors"; +static const QString IMPORT_DIALOG_CFG_FORMAT = "format"; + ImportDialog::ImportDialog(QWidget *parent) : QWizard(parent), ui(new Ui::ImportDialog) @@ -55,6 +60,43 @@ bool ImportDialog::isPluginConfigValid() const return pluginConfigOk.size() == 0; } +void ImportDialog::storeStdConfig(ImportManager::StandardImportConfig &stdConfig) +{ + CFG->begin(); + CFG->set(IMPORT_DIALOG_CFG_GROUP, IMPORT_DIALOG_CFG_CODEC, stdConfig.codec); + CFG->set(IMPORT_DIALOG_CFG_GROUP, IMPORT_DIALOG_CFG_FILE, stdConfig.inputFileName); + CFG->set(IMPORT_DIALOG_CFG_GROUP, IMPORT_DIALOG_CFG_IGNORE_ERR, stdConfig.ignoreErrors); + CFG->set(IMPORT_DIALOG_CFG_GROUP, IMPORT_DIALOG_CFG_FORMAT, currentPlugin->getDataSourceTypeName()); + CFG->commit(); +} + +void ImportDialog::readStdConfig() +{ + QString format = CFG->get(IMPORT_DIALOG_CFG_GROUP, IMPORT_DIALOG_CFG_FORMAT).toString(); + int idx = ui->dsTypeCombo->findText(format); + if (idx > -1) + ui->dsTypeCombo->setCurrentIndex(idx); + + ui->inputFileEdit->setText(CFG->get(IMPORT_DIALOG_CFG_GROUP, IMPORT_DIALOG_CFG_FILE, QString()).toString()); + ui->ignoreErrorsCheck->setChecked(CFG->get(IMPORT_DIALOG_CFG_GROUP, IMPORT_DIALOG_CFG_IGNORE_ERR, false).toBool()); + + // Encoding + QString codec = CFG->get(IMPORT_DIALOG_CFG_GROUP, IMPORT_DIALOG_CFG_CODEC).toString(); + QString defaultCodec = defaultCodecName(); + if (codec.isNull()) + codec = defaultCodec; + + int codecIdx = ui->codecCombo->findText(codec); + if (codecIdx == -1 && codec != defaultCodec) + { + codec = defaultCodec; + codecIdx = ui->codecCombo->findText(codec); + } + + if (codecIdx > -1) + ui->codecCombo->setCurrentIndex(codecIdx); +} + void ImportDialog::init() { ui->setupUi(this); @@ -303,7 +345,10 @@ void ImportDialog::updateValidation() void ImportDialog::pageChanged() { if (currentPage() == ui->dsPage) + { + readStdConfig(); updateValidation(); + } } void ImportDialog::browseForInputFile() @@ -351,6 +396,9 @@ void ImportDialog::accept() stdConfig.ignoreErrors = ui->ignoreErrorsCheck->isChecked(); + storeStdConfig(stdConfig); + configMapper->saveFromWidget(pluginOptionsWidget); + Db* db = DBLIST->getByName(ui->dbNameCombo->currentText());; if (!db) { diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.h index b4c2883..48402ae 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.h +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.h @@ -2,6 +2,7 @@ #define IMPORTDIALOG_H #include "guiSQLiteStudio_global.h" +#include "services/importmanager.h" #include namespace Ui { @@ -39,6 +40,8 @@ class GUI_API_EXPORT ImportDialog : public QWizard void updateStandardOptions(); void updatePluginOptions(int& rows); bool isPluginConfigValid() const; + void storeStdConfig(ImportManager::StandardImportConfig& stdConfig); + void readStdConfig(); Ui::ImportDialog *ui = nullptr; DbListModel* dbListModel = nullptr; diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp index c5da317..e3e7701 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp @@ -106,13 +106,13 @@ void IndexDialog::init() connect(ui->partialIndexEdit, SIGNAL(textChanged()), this, SLOT(updateValidation())); ui->partialIndexEdit->setVirtualSqlExpression("SELECT %1"); updatePartialConditionState(); - ui->columnsTable->setColumnHidden(1, false); + ui->columnsTable->setColumnHidden(2, false); } else { ui->partialIndexCheck->setVisible(false); ui->partialIndexEdit->setVisible(false); - ui->columnsTable->setColumnHidden(1, true); + ui->columnsTable->setColumnHidden(2, true); ui->addExprColumnButton->setVisible(false); ui->editExprColumnButton->setVisible(false); ui->delExprColumnButton->setVisible(false); diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.ui index 36066c5..5b07d45 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.ui +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.ui @@ -72,12 +72,12 @@
    - Collation + Sort - Sort + Collation diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp index d0976a3..020cfef 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp @@ -22,24 +22,15 @@ NewVersionDialog::~NewVersionDialog() void NewVersionDialog::setUpdates(const QList& updates) { QTableWidgetItem* item = nullptr; - QString currVersion; int row = 0; ui->updateList->setRowCount(updates.size()); for (const UpdateManager::UpdateEntry& entry : updates) { - if (entry.compontent == "SQLiteStudio") - currVersion = SQLITESTUDIO->getVersionString(); - else - currVersion = PLUGINS->getPrintableVersion(entry.compontent); - item = new QTableWidgetItem(entry.compontent); ui->updateList->setItem(row, 0, item); - item = new QTableWidgetItem(currVersion); - ui->updateList->setItem(row, 1, item); - item = new QTableWidgetItem(entry.version); - ui->updateList->setItem(row, 2, item); + ui->updateList->setItem(row, 1, item); row++; } diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui index 6f50e7f..d5468b3 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui @@ -70,11 +70,6 @@ Component
    - - - Current version - - Update version @@ -111,7 +106,7 @@ - The update will be automatically downloaded and installed. This will also restart application at the end. + This application will be closed and the update installer will start to download and install all the updates. diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp index 7861ff0..7f4ec20 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp @@ -48,7 +48,10 @@ void PopulateDialog::init() }); for (PopulatePlugin* plugin : plugins) + { + pluginByName[plugin->getName()] = plugin; pluginTitles << plugin->getTitle(); + } widgetCover = new WidgetCover(this); widgetCover->initWithInterruptContainer(tr("Abort")); @@ -94,12 +97,29 @@ void PopulateDialog::deleteEngines(const QList& engines) delete engine; } -void PopulateDialog::rebuildEngines() +void PopulateDialog::rebuildEngines(const QHash>& columnConfig) { int row = 0; + QVariant config; + QString pluginName; for (const ColumnEntry& entry : columnEntries) { - pluginSelected(entry.combo, entry.combo->currentIndex()); + pluginName.clear(); + if (columnConfig.contains(entry.column)) + pluginName = columnConfig[entry.column].first; + + if (pluginName.isNull()) + { + pluginName = plugins[entry.combo->currentIndex()]->getName(); + config = CFG->getPopulateHistory(pluginName); + } + else + { + entry.combo->setCurrentIndex(plugins.indexOf(pluginByName[pluginName])); + config = columnConfig[entry.column].second; + } + + pluginSelected(entry.combo, entry.combo->currentIndex(), config); updateColumnState(row++, false); } } @@ -135,6 +155,8 @@ void PopulateDialog::refreshColumns() return; } + QString table = ui->tableCombo->currentText(); + buttonMapper = new QSignalMapper(this); connect(buttonMapper, SIGNAL(mapped(int)), this, SLOT(configurePlugin(int))); @@ -142,14 +164,23 @@ void PopulateDialog::refreshColumns() connect(checkMapper, SIGNAL(mapped(int)), this, SLOT(updateColumnState(int))); SchemaResolver resolver(db); - QStringList columns = resolver.getTableColumns(ui->tableCombo->currentText()); + QStringList columns = resolver.getTableColumns(table); QCheckBox* check = nullptr; QComboBox* combo = nullptr; QToolButton* btn = nullptr; + + int rows = -1; + QHash> columnConfig = CFG->getPopulateHistory(db->getName(), table, rows); + if (rows > -1) + ui->rowsSpin->setValue(rows); + int row = 0; for (const QString& column : columns) { check = new QCheckBox(column); + if (columnConfig.contains(column)) + check->setChecked(true); + connect(check, SIGNAL(toggled(bool)), checkMapper, SLOT(map())); checkMapper->setMapping(check, row); @@ -165,11 +196,11 @@ void PopulateDialog::refreshColumns() ui->columnsLayout->addWidget(check, row, 0); ui->columnsLayout->addWidget(combo, row, 1); ui->columnsLayout->addWidget(btn, row, 2); - columnEntries << ColumnEntry(check, combo, btn); + columnEntries << ColumnEntry(column, check, combo, btn); row++; } - rebuildEngines(); + rebuildEngines(columnConfig); QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); ui->columnsLayout->addItem(spacer, row, 0, 1, 3); @@ -179,11 +210,15 @@ void PopulateDialog::refreshColumns() void PopulateDialog::pluginSelected(int index) { + QVariant config; + if (index >= 0 && index < plugins.size()) + config = CFG->getPopulateHistory(plugins[index]->getName()); + QComboBox* cb = dynamic_cast(sender()); - pluginSelected(cb, index); + pluginSelected(cb, index, config); } -void PopulateDialog::pluginSelected(QComboBox* combo, int index) +void PopulateDialog::pluginSelected(QComboBox* combo, int index, const QVariant& config) { if (!combo) return; @@ -209,7 +244,11 @@ void PopulateDialog::pluginSelected(QComboBox* combo, int index) if (index < 0 || index >= plugins.size()) return; - entry->engine = plugins[index]->createEngine(); + entry->plugin = plugins[index]; + entry->engine = entry->plugin->createEngine(); + if (config.isValid()) + entry->engine->getConfig()->setValuesFromQVariant(config); + updateColumnState(columnIndex); } @@ -230,7 +269,8 @@ void PopulateDialog::configurePlugin(int index) engine->getConfig()->savepoint(); - PopulateConfigDialog dialog(engine, columnEntries[index].check->text(), columnEntries[index].combo->currentText(), this); + QString colName = columnEntries[index].column; + PopulateConfigDialog dialog(engine, colName, columnEntries[index].combo->currentText(), this); if (dialog.exec() != QDialog::Accepted) engine->getConfig()->restore(); @@ -304,6 +344,7 @@ void PopulateDialog::accept() if (!db) return; + QHash> configForHistory; QHash engines; for (ColumnEntry& entry : columnEntries) { @@ -313,16 +354,19 @@ void PopulateDialog::accept() if (!entry.engine) return; - engines[entry.check->text()] = entry.engine; -// entry.engine = nullptr; // to avoid deleting it in the entry's destructor - worker will delete it after it's done + engines[entry.column] = entry.engine; + // entry.engine = nullptr; // to avoid deleting it in the entry's destructor - worker will delete it after it's done + + configForHistory[entry.column] = QPair(entry.plugin->getName(), entry.engine->getConfig()->toQVariant()); } QString table = ui->tableCombo->currentText(); - qint64 rows = ui->rowsSpin->value(); + int rows = ui->rowsSpin->value(); started = true; widgetCover->displayProgress(rows, "%v / %m"); widgetCover->show(); + CFG->addPopulateHistory(db->getName(), table, rows, configForHistory); POPULATE_MANAGER->populate(db, table, engines, rows); } @@ -334,8 +378,8 @@ void PopulateDialog::reject() QDialog::reject(); } -PopulateDialog::ColumnEntry::ColumnEntry(QCheckBox* check, QComboBox* combo, QToolButton* button) : - check(check), combo(combo), button(button) +PopulateDialog::ColumnEntry::ColumnEntry(const QString& column, QCheckBox* check, QComboBox* combo, QToolButton* button) : + column(column), check(check), combo(combo), button(button) { } diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.h index 948d6ce..404b9e2 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.h +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.h @@ -3,6 +3,7 @@ #include "guiSQLiteStudio_global.h" #include +#include namespace Ui { class PopulateDialog; @@ -32,19 +33,21 @@ class GUI_API_EXPORT PopulateDialog : public QDialog private: struct GUI_API_EXPORT ColumnEntry { - ColumnEntry(QCheckBox* check, QComboBox* combo, QToolButton* button); + ColumnEntry(const QString& column, QCheckBox* check, QComboBox* combo, QToolButton* button); ~ColumnEntry(); + QString column; QCheckBox* check = nullptr; QComboBox* combo = nullptr; QToolButton* button = nullptr; PopulateEngine* engine = nullptr; + PopulatePlugin* plugin = nullptr; }; void init(); PopulateEngine* getEngine(int selectedPluginIndex); void deleteEngines(const QList& engines); - void rebuildEngines(); + void rebuildEngines(const QHash >& columnConfig); Ui::PopulateDialog *ui = nullptr; QGridLayout* columnsGrid = nullptr; @@ -53,6 +56,7 @@ class GUI_API_EXPORT PopulateDialog : public QDialog Db* db = nullptr; QStringList pluginTitles; QList plugins; + QHash pluginByName; QList columnEntries; QSignalMapper* checkMapper = nullptr; QSignalMapper* buttonMapper = nullptr; @@ -64,7 +68,7 @@ class GUI_API_EXPORT PopulateDialog : public QDialog void refreshTables(); void refreshColumns(); void pluginSelected(int index); - void pluginSelected(QComboBox* combo, int index); + void pluginSelected(QComboBox* combo, int index, const QVariant& config); void configurePlugin(int index); void updateColumnState(int index, bool updateGlobalState = true); void updateState(); diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp index 3254f26..255694c 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp @@ -214,7 +214,7 @@ void TriggerDialog::readTrigger() if (createTrigger->queries.size() > 0) { QStringList sqls; - foreach (SqliteQuery* query, createTrigger->queries) + for (SqliteQuery* query : createTrigger->queries) sqls << query->detokenize(); ui->codeEdit->setPlainText(sqls.join(";\n")+";"); @@ -307,7 +307,7 @@ void TriggerDialog::rebuildTrigger() if (actionType == SqliteCreateTrigger::Event::UPDATE_OF) { QStringList colNames; - foreach (const QString& colName, selectedColumns) + for (const QString& colName : selectedColumns) colNames << wrapObjIfNeeded(colName, dialect); columns = " "+colNames.join(", "); @@ -363,7 +363,7 @@ void TriggerDialog::showColumnsDialog() QPoint topRight = ui->actionColumns->mapToGlobal(ui->actionColumns->rect().topRight()); TriggerColumnsDialog dialog(this, topRight.x(), topRight.y()); - foreach (const QString& colName, targetColumns) + for (const QString& colName : targetColumns) dialog.addColumn(colName, selectedColumns.contains(colName, Qt::CaseInsensitive)); if (dialog.exec() != QDialog::Accepted) diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.ui index 723f903..d25b2c0 100644 --- a/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.ui +++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.ui @@ -110,6 +110,9 @@ Trigger statements to be executed. + + QPlainTextEdit::NoWrap + @@ -123,6 +126,9 @@ <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> + + QPlainTextEdit::NoWrap + diff --git a/SQLiteStudio3/guiSQLiteStudio/formmanager.cpp b/SQLiteStudio3/guiSQLiteStudio/formmanager.cpp index 0ee7d43..735fb5d 100644 --- a/SQLiteStudio3/guiSQLiteStudio/formmanager.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/formmanager.cpp @@ -123,7 +123,7 @@ void FormManager::load() formDirs += STRINGIFY(FORMS_DIR); #endif - foreach (QString dirPath, formDirs) + for (QString dirPath : formDirs) loadRecurently(dirPath, ""); } @@ -134,7 +134,7 @@ void FormManager::loadRecurently(const QString& path, const QString& prefix) QDir dir(path); QString fullPath; QString widgetName; - foreach (QFileInfo entry, dir.entryInfoList(fileExtensions, QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot|QDir::Readable)) + for (const QFileInfo& entry : dir.entryInfoList(fileExtensions, QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot|QDir::Readable)) { fullPath = entry.absoluteFilePath(); if (entry.isDir()) diff --git a/SQLiteStudio3/guiSQLiteStudio/formview.cpp b/SQLiteStudio3/guiSQLiteStudio/formview.cpp index 0ebb9aa..575c2de 100644 --- a/SQLiteStudio3/guiSQLiteStudio/formview.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/formview.cpp @@ -85,7 +85,7 @@ void FormView::reloadInternal() { // Cleanup dataMapper->clearMapping(); - foreach (QWidget* widget, widgets) + for (QWidget* widget : widgets) { contents->layout()->removeWidget(widget); delete widget; @@ -97,7 +97,7 @@ void FormView::reloadInternal() // Recreate dataMapper->setModel(model.data()); int i = 0; - foreach (SqlQueryModelColumnPtr column, model->getColumns()) + for (SqlQueryModelColumnPtr column : model->getColumns()) addColumn(i++, column->displayName, column->dataType, (column->editionForbiddenReason.size() > 0)); } @@ -150,12 +150,18 @@ void FormView::updateDeletedState() { SqlQueryItem* item = model->itemFromIndex(dataMapper->getCurrentIndex(), 0); if (!item) + { + for (MultiEditor* editor : editors) + editor->setEnabled(false); + return; + } bool deleted = item->isDeletedRow(); int i = 0; - foreach (MultiEditor* editor, editors) + for (MultiEditor* editor : editors) { + editor->setEnabled(true); editor->setDeletedRow(deleted); editor->setReadOnly(readOnly[i++] || deleted); } diff --git a/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro b/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro index 60a85ff..d603f87 100644 --- a/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro +++ b/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro @@ -31,7 +31,8 @@ QMAKE_CXXFLAGS += -pedantic DEFINES += GUISQLITESTUDIO_LIBRARY -TRANSLATIONS += translations/guiSQLiteStudio_de.ts \ +TRANSLATIONS += translations/guiSQLiteStudio_ro_RO.ts \ + translations/guiSQLiteStudio_de.ts \ translations/guiSQLiteStudio_it.ts \ translations/guiSQLiteStudio_zh_CN.ts \ translations/guiSQLiteStudio_sk.ts \ @@ -172,10 +173,7 @@ SOURCES +=\ uidebug.cpp \ debugconsole.cpp \ common/extactionprototype.cpp \ - dialogs/bugdialog.cpp \ dialogs/aboutdialog.cpp \ - dialogs/bugreportlogindialog.cpp \ - windows/bugreporthistorywindow.cpp \ dialogs/newversiondialog.cpp \ dialogs/quitconfirmdialog.cpp \ common/datawidgetmapper.cpp \ @@ -187,7 +185,12 @@ SOURCES +=\ common/centerediconitemdelegate.cpp \ datagrid/sqlviewmodel.cpp \ common/exttableview.cpp \ - common/exttablewidget.cpp + common/exttablewidget.cpp \ + windows/sqliteextensioneditor.cpp \ + windows/sqliteextensioneditormodel.cpp \ + dialogs/bindparamsdialog.cpp \ + dialogs/execfromfiledialog.cpp \ + dialogs/fileexecerrorsdialog.cpp HEADERS += mainwindow.h \ iconmanager.h \ @@ -323,10 +326,7 @@ HEADERS += mainwindow.h \ uidebug.h \ debugconsole.h \ common/extactionprototype.h \ - dialogs/bugdialog.h \ dialogs/aboutdialog.h \ - dialogs/bugreportlogindialog.h \ - windows/bugreporthistorywindow.h \ dialogs/newversiondialog.h \ guiSQLiteStudio_global.h \ dialogs/quitconfirmdialog.h \ @@ -339,7 +339,13 @@ HEADERS += mainwindow.h \ common/centerediconitemdelegate.h \ datagrid/sqlviewmodel.h \ common/exttableview.h \ - common/exttablewidget.h + common/exttablewidget.h \ + windows/sqliteextensioneditor.h \ + windows/sqliteextensioneditormodel.h \ + dialogs/bindparamsdialog.h \ + common/bindparam.h \ + dialogs/execfromfiledialog.h \ + dialogs/fileexecerrorsdialog.h FORMS += mainwindow.ui \ dbtree/dbtree.ui \ @@ -381,15 +387,16 @@ FORMS += mainwindow.ui \ dialogs/dbconverterdialog.ui \ dialogs/dbdialog.ui \ debugconsole.ui \ - dialogs/bugdialog.ui \ dialogs/aboutdialog.ui \ - dialogs/bugreportlogindialog.ui \ - windows/bugreporthistorywindow.ui \ dialogs/newversiondialog.ui \ dialogs/quitconfirmdialog.ui \ dialogs/languagedialog.ui \ dialogs/cssdebugdialog.ui \ - dialogs/indexexprcolumndialog.ui + dialogs/indexexprcolumndialog.ui \ + windows/sqliteextensioneditor.ui \ + dialogs/bindparamsdialog.ui \ + dialogs/execfromfiledialog.ui \ + dialogs/fileexecerrorsdialog.ui RESOURCES += \ icons.qrc \ @@ -420,3 +427,4 @@ DISTFILES += \ + diff --git a/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.qrc b/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.qrc index 0970b86..56db5ac 100644 --- a/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.qrc +++ b/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.qrc @@ -1,5 +1,6 @@ + translations/guiSQLiteStudio_ro_RO.qm translations/guiSQLiteStudio_pl.qm translations/guiSQLiteStudio_ru.qm translations/guiSQLiteStudio_fr.qm @@ -14,3 +15,4 @@ + diff --git a/SQLiteStudio3/guiSQLiteStudio/iconmanager.cpp b/SQLiteStudio3/guiSQLiteStudio/iconmanager.cpp index 3d6c5f2..8610dbf 100644 --- a/SQLiteStudio3/guiSQLiteStudio/iconmanager.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/iconmanager.cpp @@ -48,7 +48,7 @@ void IconManager::init() iconFileExtensions << "*.png" << "*.PNG" << "*.jpg" << "*.JPG" << "*.svg" << "*.SVG"; movieFileExtensions << "*.gif" << "*.GIF" << "*.mng" << "*.MNG"; - foreach (QString dirPath, iconDirs) + for (QString dirPath : iconDirs) { loadRecurently(dirPath, "", false); loadRecurently(dirPath, "", true); @@ -115,7 +115,7 @@ void IconManager::loadRecurently(QString dirPath, const QString& prefix, bool mo QString path; QString name; QDir dir(dirPath); - foreach (QFileInfo entry, dir.entryInfoList(extensions, QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot|QDir::Readable)) + for (QFileInfo entry : dir.entryInfoList(extensions, QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot|QDir::Readable)) { if (entry.isDir()) { diff --git a/SQLiteStudio3/guiSQLiteStudio/iconmanager.h b/SQLiteStudio3/guiSQLiteStudio/iconmanager.h index 2bc63a2..6034de1 100644 --- a/SQLiteStudio3/guiSQLiteStudio/iconmanager.h +++ b/SQLiteStudio3/guiSQLiteStudio/iconmanager.h @@ -109,9 +109,15 @@ class GUI_API_EXPORT IconManager : public QObject DEF_ICON(ERASE, "erase") DEF_ICON(ERASE_TABLE_DATA, "erase_table_data") DEF_ICON(EXEC_QUERY, "exec_query") + DEF_ICON(EXEC_SQL_FROM_FILE, "execute_sql_from_file") DEF_ICON(EXPLAIN_QUERY, "explain_query") DEF_ICON(EXPORT, "export") DEF_ICON(EXPORT_FILE_BROWSE, "export_file_browse") + DEF_ICON(EXTENSION, "brick") + DEF_ICON(EXTENSION_ADD, "brick_add") + DEF_ICON(EXTENSION_DELETE, "brick_delete") + DEF_ICON(EXTENSION_EDITOR, "brick_folder") + DEF_ICON(EXTENSION_ERROR, "brick_error") DEF_ICON(FEATURE_REQUEST, "feature_request") DEF_ICON(FONT_BROWSE, "font_browse") DEF_ICON(FORMAT_SQL, "format_sql") @@ -167,6 +173,7 @@ class GUI_API_EXPORT IconManager : public QObject DEF_ICON(RESULTS_BELOW, "results_below") DEF_ICON(RESULTS_IN_TAB, "results_in_tab") DEF_ICON(ROLLBACK, "rollback") + DEF_ICON(SAVE_FILE, "save_file") DEF_ICON(SAVE_SQL_FILE, "save_sql_file") DEF_ICON(SEARCH, "search") DEF_ICON(SEARCH_AND_REPLACE, "search_and_replace") @@ -248,6 +255,9 @@ class GUI_API_EXPORT IconManager : public QObject DEF_ICON(WIN_CLOSE_OTHER, "window_close_other") DEF_ICON(WIN_RESTORE, "window_restore") DEF_ICON(WIN_RENAME, "window_rename") + DEF_ICON(ZOOM_RESET, "zoom") + DEF_ICON(ZOOM_IN, "zoom_in") + DEF_ICON(ZOOM_OUT, "zoom_out") ) static IconManager* getInstance(); diff --git a/SQLiteStudio3/guiSQLiteStudio/icons.qrc b/SQLiteStudio3/guiSQLiteStudio/icons.qrc index 8819276..b656f25 100644 --- a/SQLiteStudio3/guiSQLiteStudio/icons.qrc +++ b/SQLiteStudio3/guiSQLiteStudio/icons.qrc @@ -201,5 +201,15 @@ img/wand.png img/search_and_replace.png img/search.png + img/zoom.png + img/zoom_in.png + img/zoom_out.png + img/save_file.png + img/brick.png + img/brick_add.png + img/brick_delete.png + img/brick_error.png + img/brick_folder.png + img/execute_sql_from_file.png diff --git a/SQLiteStudio3/guiSQLiteStudio/img/brick.png b/SQLiteStudio3/guiSQLiteStudio/img/brick.png new file mode 100644 index 0000000..7851cf3 Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/brick.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/brick_add.png b/SQLiteStudio3/guiSQLiteStudio/img/brick_add.png new file mode 100644 index 0000000..fac186b Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/brick_add.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/brick_delete.png b/SQLiteStudio3/guiSQLiteStudio/img/brick_delete.png new file mode 100644 index 0000000..3a8c373 Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/brick_delete.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/brick_error.png b/SQLiteStudio3/guiSQLiteStudio/img/brick_error.png new file mode 100644 index 0000000..18ab01e Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/brick_error.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/brick_folder.png b/SQLiteStudio3/guiSQLiteStudio/img/brick_folder.png new file mode 100644 index 0000000..5dea976 Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/brick_folder.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/execute_sql_from_file.png b/SQLiteStudio3/guiSQLiteStudio/img/execute_sql_from_file.png new file mode 100644 index 0000000..806d7e6 Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/execute_sql_from_file.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/save_file.png b/SQLiteStudio3/guiSQLiteStudio/img/save_file.png new file mode 100644 index 0000000..c619461 Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/save_file.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/zoom.png b/SQLiteStudio3/guiSQLiteStudio/img/zoom.png new file mode 100644 index 0000000..908612e Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/zoom.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/zoom_in.png b/SQLiteStudio3/guiSQLiteStudio/img/zoom_in.png new file mode 100644 index 0000000..cdf0a52 Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/zoom_in.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/img/zoom_out.png b/SQLiteStudio3/guiSQLiteStudio/img/zoom_out.png new file mode 100644 index 0000000..07bf98a Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/img/zoom_out.png differ diff --git a/SQLiteStudio3/guiSQLiteStudio/license.txt b/SQLiteStudio3/guiSQLiteStudio/license.txt deleted file mode 100644 index f166cc5..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! \ No newline at end of file diff --git a/SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp index f7bcb83..2b6463a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp @@ -9,6 +9,7 @@ #include "windows/functionseditor.h" #include "windows/collationseditor.h" #include "windows/ddlhistorywindow.h" +#include "windows/sqliteextensioneditor.h" #include "mdiarea.h" #include "statusfield.h" #include "uiconfig.h" @@ -32,8 +33,6 @@ #include "services/dbmanager.h" #include "services/updatemanager.h" #include "dialogs/aboutdialog.h" -#include "dialogs/bugdialog.h" -#include "windows/bugreporthistorywindow.h" #include "dialogs/newversiondialog.h" #include "dialogs/quitconfirmdialog.h" #include "common/widgetcover.h" @@ -47,6 +46,8 @@ #include #include #include +#include +#include CFG_KEYS_DEFINE(MainWindow) MainWindow* MainWindow::instance = nullptr; @@ -65,7 +66,7 @@ MainWindow::~MainWindow() void MainWindow::init() { ui->setupUi(this); - connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(cleanUp())); + connect(SQLITESTUDIO, SIGNAL(aboutToQuit()), this, SLOT(cleanUp())); #ifdef Q_OS_WIN setWindowIcon(ICONS.SQLITESTUDIO_APP.toQIcon().pixmap(256, 256)); @@ -130,32 +131,6 @@ void MainWindow::init() #endif connect(statusField, SIGNAL(linkActivated(QString)), this, SLOT(statusFieldLinkClicked(QString))); - // Widget cover - widgetCover = new WidgetCover(this); - widgetCover->setVisible(false); - - updatingBusyBar = new QProgressBar(); - updatingBusyBar->setRange(0, 100); - updatingBusyBar->setTextVisible(true); - updatingBusyBar->setValue(0); - updatingBusyBar->setFixedWidth(300); - - updatingSubBar = new QProgressBar(); - updatingSubBar->setRange(0, 100); - updatingSubBar->setTextVisible(true); - updatingSubBar->setValue(0); - updatingSubBar->setFixedWidth(300); - - updatingLabel = new QLabel(); - - widgetCover->getContainerLayout()->addWidget(updatingLabel, 0, 0); - widgetCover->getContainerLayout()->addWidget(updatingBusyBar, 1, 0); - widgetCover->getContainerLayout()->addWidget(updatingSubBar, 2, 0); -#ifdef PORTABLE_CONFIG - connect(UPDATES, SIGNAL(updatingProgress(QString,int,int)), this, SLOT(handleUpdatingProgress(QString,int,int))); - connect(UPDATES, SIGNAL(updatingError(QString)), this, SLOT(handleUpdatingError())); -#endif - connect(CFG_CORE.General.Language, SIGNAL(changed(QVariant)), this, SLOT(notifyAboutLanguageChange())); fixFonts(); @@ -166,6 +141,7 @@ void MainWindow::cleanUp() if (SQLITESTUDIO->getImmediateQuit()) return; +// qDebug() << "MainWindow::cleanUp()"; for (MdiWindow* win : getMdiArea()->getWindows()) delete win; @@ -254,42 +230,43 @@ void MainWindow::closeEvent(QCloseEvent* event) void MainWindow::createActions() { - createAction(OPEN_SQL_EDITOR, ICONS.OPEN_SQL_EDITOR, tr("Open SQL editor"), this, SLOT(openSqlEditorSlot()), ui->mainToolBar); - createAction(OPEN_DDL_HISTORY, ICONS.DDL_HISTORY, tr("Open DDL history"), this, SLOT(openDdlHistorySlot()), ui->mainToolBar); - createAction(OPEN_FUNCTION_EDITOR, ICONS.FUNCTION, tr("Open SQL functions editor"), this, SLOT(openFunctionEditorSlot()), ui->mainToolBar); - createAction(OPEN_COLLATION_EDITOR, ICONS.CONSTRAINT_COLLATION, tr("Open collations editor"), this, SLOT(openCollationEditorSlot()), ui->mainToolBar); - createAction(IMPORT, ICONS.IMPORT, tr("Import"), this, SLOT(importAnything()), ui->mainToolBar); - createAction(EXPORT, ICONS.EXPORT, tr("Export"), this, SLOT(exportAnything()), ui->mainToolBar); + createAction(OPEN_SQL_EDITOR, ICONS.OPEN_SQL_EDITOR, tr("Open SQL &editor"), this, SLOT(openSqlEditorSlot()), ui->mainToolBar); + createAction(OPEN_DDL_HISTORY, ICONS.DDL_HISTORY, tr("Open DDL &history"), this, SLOT(openDdlHistorySlot()), ui->mainToolBar); + createAction(OPEN_FUNCTION_EDITOR, ICONS.FUNCTION, tr("Open SQL &functions editor"), this, SLOT(openFunctionEditorSlot()), ui->mainToolBar); + createAction(OPEN_COLLATION_EDITOR, ICONS.CONSTRAINT_COLLATION, tr("Open &collations editor"), this, SLOT(openCollationEditorSlot()), ui->mainToolBar); + createAction(OPEN_EXTENSION_MANAGER, ICONS.EXTENSION, tr("Open ex&tension manager"), this, SLOT(openExtensionManagerSlot()), ui->mainToolBar); + createAction(IMPORT, ICONS.IMPORT, tr("&Import"), this, SLOT(importAnything()), ui->mainToolBar); + createAction(EXPORT, ICONS.EXPORT, tr("E&xport"), this, SLOT(exportAnything()), ui->mainToolBar); ui->mainToolBar->addSeparator(); - createAction(OPEN_CONFIG, ICONS.CONFIGURE, tr("Open configuration dialog"), this, SLOT(openConfig()), ui->mainToolBar); + createAction(OPEN_CONFIG, ICONS.CONFIGURE, tr("Open confi&guration dialog"), this, SLOT(openConfig()), ui->mainToolBar); - createAction(MDI_TILE, ICONS.WIN_TILE, tr("Tile windows"), ui->mdiArea, SLOT(tileSubWindows()), ui->viewToolbar); - createAction(MDI_TILE_HORIZONTAL, ICONS.WIN_TILE_HORIZONTAL, tr("Tile windows horizontally"), ui->mdiArea, SLOT(tileHorizontally()), ui->viewToolbar); - createAction(MDI_TILE_VERTICAL, ICONS.WIN_TILE_VERTICAL, tr("Tile windows vertically"), ui->mdiArea, SLOT(tileVertically()), ui->viewToolbar); - createAction(MDI_CASCADE, ICONS.WIN_CASCADE, tr("Cascade windows"), ui->mdiArea, SLOT(cascadeSubWindows()), ui->viewToolbar); + createAction(MDI_TILE, ICONS.WIN_TILE, tr("&Tile windows"), ui->mdiArea, SLOT(tileSubWindows()), ui->viewToolbar); + createAction(MDI_TILE_HORIZONTAL, ICONS.WIN_TILE_HORIZONTAL, tr("Tile windows &horizontally"), ui->mdiArea, SLOT(tileHorizontally()), ui->viewToolbar); + createAction(MDI_TILE_VERTICAL, ICONS.WIN_TILE_VERTICAL, tr("Tile windows &vertically"), ui->mdiArea, SLOT(tileVertically()), ui->viewToolbar); + createAction(MDI_CASCADE, ICONS.WIN_CASCADE, tr("&Cascade windows"), ui->mdiArea, SLOT(cascadeSubWindows()), ui->viewToolbar); createAction(NEXT_TASK, tr("Next window"), ui->taskBar, SLOT(nextTask()), this); createAction(PREV_TASK, tr("Previous window"), ui->taskBar, SLOT(prevTask()), this); createAction(HIDE_STATUS_FIELD, tr("Hide status field"), this, SLOT(hideStatusField()), this); - createAction(CLOSE_WINDOW, ICONS.WIN_CLOSE, tr("Close selected window"), this, SLOT(closeSelectedWindow()), this); - createAction(CLOSE_OTHER_WINDOWS, ICONS.WIN_CLOSE_OTHER, tr("Close all windows but selected"), this, SLOT(closeAllWindowsButSelected()), this); - createAction(CLOSE_ALL_WINDOWS, ICONS.WIN_CLOSE_ALL, tr("Close all windows"), this, SLOT(closeAllWindows()), this); - createAction(RESTORE_WINDOW, ICONS.WIN_RESTORE, tr("Restore recently closed window"), this, SLOT(restoreLastClosedWindow()), this); - createAction(RENAME_WINDOW, ICONS.WIN_RENAME, tr("Rename selected window"), this, SLOT(renameWindow()), this); + createAction(CLOSE_WINDOW, ICONS.WIN_CLOSE, tr("Close selected &window"), this, SLOT(closeSelectedWindow()), this); + createAction(CLOSE_OTHER_WINDOWS, ICONS.WIN_CLOSE_OTHER, tr("Close all windows &but selected"), this, SLOT(closeAllWindowsButSelected()), this); + createAction(CLOSE_ALL_WINDOWS, ICONS.WIN_CLOSE_ALL, tr("Close &all windows"), this, SLOT(closeAllWindows()), this); + createAction(RESTORE_WINDOW, ICONS.WIN_RESTORE, tr("Re&store recently closed window"), this, SLOT(restoreLastClosedWindow()), this); + createAction(RENAME_WINDOW, ICONS.WIN_RENAME, tr("&Rename selected window"), this, SLOT(renameWindow()), this); createAction(OPEN_DEBUG_CONSOLE, tr("Open Debug Console"), this, SLOT(openDebugConsole()), this); createAction(OPEN_CSS_CONSOLE, tr("Open CSS Console"), this, SLOT(openCssConsole()), this); - createAction(REPORT_BUG, ICONS.BUG, tr("Report a bug"), this, SLOT(reportBug()), this); - createAction(FEATURE_REQUEST, ICONS.FEATURE_REQUEST, tr("Propose a new feature"), this, SLOT(requestFeature()), this); - createAction(ABOUT, ICONS.SQLITESTUDIO_APP16, tr("About"), this, SLOT(aboutSqlitestudio()), this); - createAction(LICENSES, ICONS.LICENSES, tr("Licenses"), this, SLOT(licenses()), this); - createAction(HOMEPAGE, ICONS.HOMEPAGE, tr("Open home page"), this, SLOT(homepage()), this); - createAction(FORUM, ICONS.OPEN_FORUM, tr("Open forum page"), this, SLOT(forum()), this); - createAction(USER_MANUAL, ICONS.USER_MANUAL, tr("User Manual"), this, SLOT(userManual()), this); - createAction(SQLITE_DOCS, ICONS.SQLITE_DOCS, tr("SQLite documentation"), this, SLOT(sqliteDocs()), this); - createAction(BUG_REPORT_HISTORY, ICONS.BUG_LIST, tr("Report history"), this, SLOT(reportHistory()), this); + createAction(REPORT_BUG, ICONS.BUG, tr("Report a &bug"), this, SLOT(reportBug()), this); + createAction(FEATURE_REQUEST, ICONS.FEATURE_REQUEST, tr("Propose a new &feature"), this, SLOT(requestFeature()), this); + createAction(ABOUT, ICONS.SQLITESTUDIO_APP16, tr("&About"), this, SLOT(aboutSqlitestudio()), this); + createAction(LICENSES, ICONS.LICENSES, tr("&Licenses"), this, SLOT(licenses()), this); + createAction(HOMEPAGE, ICONS.HOMEPAGE, tr("Open home &page"), this, SLOT(homepage()), this); + createAction(FORUM, ICONS.OPEN_FORUM, tr("Open fo&rum page"), this, SLOT(forum()), this); + createAction(USER_MANUAL, ICONS.USER_MANUAL, tr("User &Manual"), this, SLOT(userManual()), this); + createAction(SQLITE_DOCS, ICONS.SQLITE_DOCS, tr("SQLite &documentation"), this, SLOT(sqliteDocs()), this); + createAction(BUG_REPORT_HISTORY, ICONS.BUG_LIST, tr("Bugs and feature &requests"), this, SLOT(reportHistory()), this); #ifdef PORTABLE_CONFIG - createAction(CHECK_FOR_UPDATES, ICONS.GET_UPDATE, tr("Check for updates"), this, SLOT(checkForUpdates()), this); + createAction(CHECK_FOR_UPDATES, ICONS.GET_UPDATE, tr("Check for &updates"), this, SLOT(checkForUpdates()), this); #endif actionMap[ABOUT]->setMenuRole(QAction::AboutRole); @@ -327,7 +304,7 @@ void MainWindow::initMenuBar() { // Database menu dbMenu = new QMenu(this); - dbMenu->setTitle(tr("Database", "menubar")); + dbMenu->setTitle(tr("&Database", "menubar")); menuBar()->addMenu(dbMenu); dbMenu->addAction(dbTree->getAction(DbTree::CONNECT_TO_DB)); @@ -347,7 +324,7 @@ void MainWindow::initMenuBar() // Structure menu structMenu = new QMenu(this); - structMenu->setTitle(tr("Structure", "menubar")); + structMenu->setTitle(tr("&Structure", "menubar")); menuBar()->addMenu(structMenu); structMenu->addAction(dbTree->getAction(DbTree::ADD_TABLE)); @@ -368,7 +345,7 @@ void MainWindow::initMenuBar() // View menu viewMenu = createPopupMenu(); - viewMenu->setTitle(tr("View", "menubar")); + viewMenu->setTitle(tr("&View", "menubar")); menuBar()->addMenu(viewMenu); mdiMenu = new QMenu(viewMenu); @@ -393,13 +370,14 @@ void MainWindow::initMenuBar() // Tools menu toolsMenu = new QMenu(this); - toolsMenu->setTitle(tr("Tools", "menubar")); + toolsMenu->setTitle(tr("&Tools", "menubar")); menuBar()->addMenu(toolsMenu); toolsMenu->addAction(actionMap[OPEN_SQL_EDITOR]); toolsMenu->addAction(actionMap[OPEN_DDL_HISTORY]); toolsMenu->addAction(actionMap[OPEN_FUNCTION_EDITOR]); toolsMenu->addAction(actionMap[OPEN_COLLATION_EDITOR]); + toolsMenu->addAction(actionMap[OPEN_EXTENSION_MANAGER]); toolsMenu->addAction(actionMap[IMPORT]); toolsMenu->addAction(actionMap[EXPORT]); toolsMenu->addSeparator(); @@ -407,7 +385,7 @@ void MainWindow::initMenuBar() // Help menu sqlitestudioMenu = new QMenu(this); - sqlitestudioMenu->setTitle(tr("Help")); + sqlitestudioMenu->setTitle(tr("&Help")); menuBar()->addMenu(sqlitestudioMenu); if (isDebugEnabled() && isDebugConsoleEnabled()) { @@ -447,7 +425,7 @@ void MainWindow::saveSession(MdiWindow* currWindow) if (CFG_UI.General.RestoreSession.get()) { QList windowSessions; - foreach (MdiWindow* window, ui->mdiArea->getWindows()) + for (MdiWindow* window : ui->mdiArea->getWindows()) if (window->restoreSessionNextTime()) windowSessions << window->saveSession(); @@ -515,7 +493,7 @@ void MainWindow::restoreWindowSessions(const QList& windowSessions) if (windowSessions.size() == 0) return; - foreach (const QVariant& winSession, windowSessions) + for (const QVariant& winSession : windowSessions) restoreWindowSession(winSession); } @@ -597,7 +575,7 @@ EditorWindow* MainWindow::openSqlEditor(Db* dbToSet, const QString& sql) void MainWindow::closeNonSessionWindows() { - foreach (MdiWindow* window, ui->mdiArea->getWindows()) + for (MdiWindow* window : ui->mdiArea->getWindows()) if (!window->restoreSessionNextTime()) window->close(); } @@ -662,6 +640,11 @@ void MainWindow::openCollationEditorSlot() openCollationEditor(); } +void MainWindow::openExtensionManagerSlot() +{ + openExtensionManager(); +} + void MainWindow::exportAnything() { if (!ExportManager::isAnyPluginAvailable()) @@ -736,15 +719,12 @@ void MainWindow::openCssConsole() void MainWindow::reportBug() { - BugDialog dialog(this); - dialog.exec(); + QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getNewIssuePage())); } void MainWindow::requestFeature() { - BugDialog dialog(this); - dialog.setFeatureRequestMode(true); - dialog.exec(); + QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getNewIssuePage())); } void MainWindow::aboutSqlitestudio() @@ -781,7 +761,7 @@ void MainWindow::sqliteDocs() void MainWindow::reportHistory() { - openReportHistory(); + QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getIssuesPage())); } void MainWindow::statusFieldLinkClicked(const QString& link) @@ -816,23 +796,9 @@ void MainWindow::noUpdatesAvailable() void MainWindow::checkForUpdates() { manualUpdatesChecking = true; - UPDATES->checkForUpdates(true); -} - -void MainWindow::handleUpdatingProgress(const QString& jobTitle, int jobPercent, int totalPercent) -{ - if (!widgetCover->isVisible()) - widgetCover->show(); - - updatingLabel->setText(jobTitle); - updatingBusyBar->setValue(totalPercent); - updatingSubBar->setValue(jobPercent); + UPDATES->checkForUpdates(); } -void MainWindow::handleUpdatingError() -{ - widgetCover->hide(); -} #endif void MainWindow::updateCornerDocking() @@ -850,6 +816,16 @@ void MainWindow::updateCornerDocking() } } +void MainWindow::messageFromSecondaryInstance(quint32 instanceId, QByteArray message) +{ + UNUSED(instanceId); + QApplication::setActiveWindow(this); + raise(); + QString dbToOpen = deserializeFromBytes(message).toString(); + if (!dbToOpen.isNull()) + openDb(dbToOpen); +} + DdlHistoryWindow* MainWindow::openDdlHistory() { return openMdiWindow(); @@ -865,9 +841,9 @@ CollationsEditor* MainWindow::openCollationEditor() return openMdiWindow(); } -BugReportHistoryWindow* MainWindow::openReportHistory() +SqliteExtensionEditor* MainWindow::openExtensionManager() { - return openMdiWindow(); + return openMdiWindow(); } void MainWindow::fixFonts() diff --git a/SQLiteStudio3/guiSQLiteStudio/mainwindow.h b/SQLiteStudio3/guiSQLiteStudio/mainwindow.h index be96af1..fbc3317 100644 --- a/SQLiteStudio3/guiSQLiteStudio/mainwindow.h +++ b/SQLiteStudio3/guiSQLiteStudio/mainwindow.h @@ -31,6 +31,7 @@ class WidgetCover; class QProgressBar; class QLabel; class ThemeTuner; +class SqliteExtensionEditor; #ifdef Q_OS_MACX #define PREV_TASK_KEY_SEQ Qt::CTRL + Qt::ALT + Qt::Key_Left @@ -70,6 +71,7 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer OPEN_DDL_HISTORY, OPEN_FUNCTION_EDITOR, OPEN_COLLATION_EDITOR, + OPEN_EXTENSION_MANAGER, EXPORT, IMPORT, CLOSE_WINDOW, @@ -140,7 +142,7 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer DdlHistoryWindow* openDdlHistory(); FunctionsEditor* openFunctionEditor(); CollationsEditor* openCollationEditor(); - BugReportHistoryWindow* openReportHistory(); + SqliteExtensionEditor* openExtensionManager(); void fixFonts(); template @@ -168,15 +170,13 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer QPointer newVersionDialog; #endif WidgetCover* widgetCover = nullptr; - QLabel* updatingLabel = nullptr; - QProgressBar* updatingBusyBar = nullptr; - QProgressBar* updatingSubBar = nullptr; bool manualUpdatesChecking = false; public slots: EditorWindow* openSqlEditor(); void updateWindowActions(); void updateCornerDocking(); + void messageFromSecondaryInstance(quint32 instanceId, QByteArray message); private slots: void notifyAboutLanguageChange(); @@ -188,6 +188,7 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer void openDdlHistorySlot(); void openFunctionEditorSlot(); void openCollationEditorSlot(); + void openExtensionManagerSlot(); void exportAnything(); void importAnything(); void closeAllWindows(); @@ -210,8 +211,6 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer void updatesAvailable(const QList& updates); void noUpdatesAvailable(); void checkForUpdates(); - void handleUpdatingProgress(const QString& jobTitle, int jobPercent, int totalPercent); - void handleUpdatingError(); #endif void statusFieldLinkClicked(const QString& link); }; @@ -220,7 +219,7 @@ template T* MainWindow::openMdiWindow() { T* win = nullptr; - foreach (MdiWindow* mdiWin, ui->mdiArea->getWindows()) + for (MdiWindow* mdiWin : ui->mdiArea->getWindows()) { win = dynamic_cast(mdiWin->getMdiChild()); if (win) diff --git a/SQLiteStudio3/guiSQLiteStudio/mdiarea.cpp b/SQLiteStudio3/guiSQLiteStudio/mdiarea.cpp index 0d07bcb..8f8521d 100644 --- a/SQLiteStudio3/guiSQLiteStudio/mdiarea.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/mdiarea.cpp @@ -72,7 +72,7 @@ QAction* MdiArea::getTaskByWindow(MdiWindow* window) QList MdiArea::getWindows() const { QList windowList; - foreach(QAction* action, taskBar->getTasks()) + for (QAction* action : taskBar->getTasks()) windowList << actionToWinMap[action]; return windowList; @@ -90,7 +90,7 @@ QList MdiArea::getMdiChilds() const QList MdiArea::getWindowsToTile() const { QList list; - foreach (MdiWindow *window, getWindows()) + for (MdiWindow *window : getWindows()) { if (window->isMinimized()) continue; @@ -162,7 +162,7 @@ void MdiArea::tileHorizontally() QPoint position(0, 0); QList windowsToTile = getWindowsToTile(); int winCnt = windowsToTile.count(); - foreach (MdiWindow *window, windowsToTile) + for (MdiWindow *window : windowsToTile) { if (window->isMaximized()) window->showNormal(); @@ -189,7 +189,7 @@ void MdiArea::tileVertically() QPoint position(0, 0); QList windowsToTile = getWindowsToTile(); int winCnt = windowsToTile.count(); - foreach (MdiWindow *window, windowsToTile) + for (MdiWindow *window : windowsToTile) { if (window->isMaximized()) window->showNormal(); @@ -212,7 +212,7 @@ void MdiArea::closeAllButActive() QList allButActive = subWindowList(); allButActive.removeOne(activeSubWindow()); - foreach (QMdiSubWindow *window, allButActive) + for (QMdiSubWindow *window : allButActive) window->close(); } @@ -221,7 +221,7 @@ MdiWindow* MdiArea::getWindowByChild(MdiChild *child) if (!child) return nullptr; - foreach (QMdiSubWindow *window, subWindowList()) + for (QMdiSubWindow *window : subWindowList()) if (window->widget() == child) return dynamic_cast(window); @@ -261,7 +261,7 @@ bool MdiArea::isActiveSubWindow(MdiChild *child) QStringList MdiArea::getWindowTitles() { QStringList titles; - foreach (QMdiSubWindow *subWin, subWindowList()) + for (QMdiSubWindow *subWin : subWindowList()) titles << subWin->windowTitle(); return titles; @@ -269,7 +269,7 @@ QStringList MdiArea::getWindowTitles() MdiWindow *MdiArea::getWindowByTitle(const QString &title) { - foreach (QMdiSubWindow *subWin, subWindowList()) + for (QMdiSubWindow *subWin : subWindowList()) { QString t = subWin->windowTitle(); if (subWin->windowTitle() == title) diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp index c99b774..d766738 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp @@ -30,13 +30,13 @@ static QHash missingEditorPluginsAlreadyWarned; -MultiEditor::MultiEditor(QWidget *parent) : +MultiEditor::MultiEditor(QWidget *parent, TabsMode tabsMode) : QWidget(parent) { - init(); + init(tabsMode); } -void MultiEditor::init() +void MultiEditor::init(TabsMode tabsMode) { QVBoxLayout* vbox = new QVBoxLayout(); vbox->setMargin(margins); @@ -73,14 +73,39 @@ void MultiEditor::init() layout()->addWidget(tabs); tabs->tabBar()->installEventFilter(this); - configBtn = new QToolButton(); - configBtn->setToolTip(tr("Configure editors for this data type")); - configBtn->setIcon(ICONS.CONFIGURE); - configBtn->setFocusPolicy(Qt::NoFocus); - configBtn->setAutoRaise(true); - configBtn->setEnabled(false); - connect(configBtn, SIGNAL(clicked()), this, SLOT(configClicked())); - tabs->setCornerWidget(configBtn); + switch (tabsMode) + { + case CONFIGURABLE: + { + configBtn = new QToolButton(); + configBtn->setToolTip(tr("Configure editors for this data type")); + configBtn->setIcon(ICONS.CONFIGURE); + configBtn->setFocusPolicy(Qt::NoFocus); + configBtn->setAutoRaise(true); + configBtn->setEnabled(false); + connect(configBtn, SIGNAL(clicked()), this, SLOT(configClicked())); + tabs->setCornerWidget(configBtn); + break; + } + case DYNAMIC: + { + initAddTabMenu(); + addTabBtn = new QToolButton(); + addTabBtn->setToolTip(tr("Open another tab")); + addTabBtn->setIcon(ICONS.PLUS); + addTabBtn->setFocusPolicy(Qt::NoFocus); + addTabBtn->setAutoRaise(true); + addTabBtn->setEnabled(true); + addTabBtn->setPopupMode(QToolButton::InstantPopup); + addTabBtn->setMenu(addTabMenu); + tabs->setCornerWidget(addTabBtn); + tabs->setTabsClosable(true); + connect(tabs, &QTabWidget::tabCloseRequested, this, &MultiEditor::removeTab); + break; + } + case PRECONFIGURED: + break; + } QGraphicsColorizeEffect* effect = new QGraphicsColorizeEffect(); effect->setColor(Qt::black); @@ -167,6 +192,25 @@ void MultiEditor::addEditor(MultiEditorWidget* editorWidget) tabs->addTab(editorWidget, editorWidget->getTabLabel().replace("&", "&&")); THEME_TUNER->manageCompactLayout(editorWidget); editorWidget->installEventFilter(this); + + connect(editorWidget, &MultiEditorWidget::aboutToBeDeleted, [this, editorWidget]() + { + int idx = tabs->indexOf(editorWidget); + tabs->removeTab(idx); + }); + + if (addTabMenu) + { + QAction* addTabAction = findFirst(addTabMenu->actions(), [editorWidget](QAction* a) + { + return a->data().toString() == editorWidget->getTabLabel(); + }); + + if (addTabAction) + addTabMenu->removeAction(addTabAction); + else + qWarning() << "Could not find action associated with added MultiEditorWidget:" << editorWidget->getTabLabel(); + } } void MultiEditor::showTab(int idx) @@ -235,11 +279,12 @@ void MultiEditor::setDataType(const DataType& dataType) { this->dataType = dataType; - foreach (MultiEditorWidget* editorWidget, getEditorTypes(dataType)) + for (MultiEditorWidget* editorWidget : getEditorTypes(dataType)) addEditor(editorWidget); showTab(0); - configBtn->setEnabled(true); + if (configBtn) + configBtn->setEnabled(true); } void MultiEditor::focusThisEditor() @@ -271,6 +316,7 @@ void MultiEditor::loadBuiltInEditors() QList MultiEditor::getEditorTypes(const DataType& dataType) { QList editors; + MultiEditorWidget* editor = nullptr; QString typeStr = dataType.toString().trimmed().toUpper(); QHash editorsOrder = CFG_UI.General.DataEditorsOrder.get(); @@ -290,7 +336,9 @@ QList MultiEditor::getEditorTypes(const DataType& dataType) continue; } - editors << plugin->getInstance(); + editor = plugin->getInstance(); + editor->setTabLabel(plugin->getTabLabel()); + editors << editor; } } @@ -313,6 +361,7 @@ QList MultiEditor::getEditorTypes(const DataType& dataType) editorWithPrio.first = plugin->getPriority(dataType); editorWithPrio.second = plugin->getInstance(); + editorWithPrio.second->setTabLabel(plugin->getTabLabel()); sortedEditors << editorWithPrio; } @@ -360,12 +409,17 @@ void MultiEditor::updateValue(const QVariant& newValue) for (int i = 0; i < tabs->count(); i++) { editorWidget = dynamic_cast(tabs->widget(i)); - editorWidget->setValue(newValue); - editorWidget->setUpToDate(true); + setValueToWidget(editorWidget, newValue); } invalidatingDisabled = false; } +void MultiEditor::setValueToWidget(MultiEditorWidget* editorWidget, const QVariant& newValue) +{ + editorWidget->setValue(newValue); + editorWidget->setUpToDate(true); +} + void MultiEditor::updateLabel() { if (deleted) @@ -380,3 +434,62 @@ QVariant MultiEditor::getValueOmmitNull() const { return dynamic_cast(tabs->currentWidget())->getValue(); } + +void MultiEditor::initAddTabMenu() +{ + addTabMenu = new QMenu(addTabBtn); + for (MultiEditorWidgetPlugin* plugin : PLUGINS->getLoadedPlugins()) + addPluginToMenu(plugin); + + sortAddTabMenu(); +} + +void MultiEditor::addPluginToMenu(MultiEditorWidgetPlugin* plugin) +{ + QAction* addTabAction = addTabMenu->addAction(plugin->getTabLabel()); + addTabAction->setData(plugin->getTabLabel()); // for display-independent identification of action to avoid ampersand issue + connect(addTabAction, &QAction::triggered, [plugin, this]() + { + MultiEditorWidget* editor = plugin->getInstance(); + editor->setTabLabel(plugin->getTabLabel()); + addEditor(editor); + setValueToWidget(editor, valueBeforeNull); + showTab(tabs->count() - 1); + }); +} + +void MultiEditor::sortAddTabMenu() +{ + QList editorActions = addTabMenu->actions(); + std::sort(editorActions.begin(), editorActions.end(), [](QAction* a1, QAction* a2) + { + return a1->data().toString().compare(a2->data().toString(), Qt::CaseInsensitive) < 0; + }); + + for (QAction* action : editorActions) + addTabMenu->removeAction(action); + + addTabMenu->insertActions(nullptr, editorActions); +} + +void MultiEditor::removeTab(int idx) +{ + MultiEditorWidget* editor = dynamic_cast(tabs->widget(idx)); + QString label = editor->getTabLabel(); + tabs->removeTab(idx); + + // Re-add it to menu + MultiEditorWidgetPlugin* plugin = findFirst( + PLUGINS->getLoadedPlugins(), + [label](MultiEditorWidgetPlugin* p) {return p->getTabLabel() == label;} + ); + + if (!plugin) + { + qWarning() << "Missing MultiEditorWidgetPlugin after removing its tab for label:" << label; + return; + } + + addPluginToMenu(plugin); + sortAddTabMenu(); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.h index 04b9af7..55d7f2e 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.h @@ -12,6 +12,7 @@ class MultiEditorWidget; class QLabel; class MultiEditorWidgetPlugin; class QToolButton; +class QMenu; class GUI_API_EXPORT MultiEditor : public QWidget { @@ -31,7 +32,13 @@ class GUI_API_EXPORT MultiEditor : public QWidget HEX }; - explicit MultiEditor(QWidget *parent = 0); + enum TabsMode { + CONFIGURABLE, /**< Tabs are loaded from datatype and also have configure button visible. */ + PRECONFIGURED, /**< Tabs are loaded from datatype. No config button is present. */ + DYNAMIC /**< No tabs are loaded, but user has button to add new tabs, can close them and reorder them. */ + }; + + explicit MultiEditor(QWidget *parent = nullptr, TabsMode tabsMode = CONFIGURABLE); void addEditor(MultiEditorWidget* editorWidget); void showTab(int idx); @@ -50,12 +57,16 @@ class GUI_API_EXPORT MultiEditor : public QWidget static void loadBuiltInEditors(); private: - void init(); + void init(TabsMode tabsMode); void updateVisibility(); void updateNullEffect(); void updateValue(const QVariant& newValue); + void setValueToWidget(MultiEditorWidget* editorWidget, const QVariant& newValue); void updateLabel(); QVariant getValueOmmitNull() const; + void initAddTabMenu(); + void addPluginToMenu(MultiEditorWidgetPlugin* plugin); + void sortAddTabMenu(); static QList getEditorTypes(const DataType& dataType); @@ -74,6 +85,8 @@ class GUI_API_EXPORT MultiEditor : public QWidget bool valueModified = false; QVariant valueBeforeNull; QToolButton* configBtn = nullptr; + QToolButton* addTabBtn = nullptr; + QMenu* addTabMenu = nullptr; DataType dataType; /** @@ -90,6 +103,7 @@ class GUI_API_EXPORT MultiEditor : public QWidget void nullStateChanged(int state); void invalidateValue(); void setModified(); + void removeTab(int idx); signals: void modified(); diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorbool.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorbool.cpp index ed7c260..1882335 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorbool.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorbool.cpp @@ -125,11 +125,6 @@ QList MultiEditorBool::getNoScrollWidgets() return list; } -QString MultiEditorBool::getTabLabel() -{ - return tr("Boolean"); -} - void MultiEditorBool::focusThisWidget() { checkBox->setFocus(); @@ -213,3 +208,8 @@ int MultiEditorBoolPlugin::getPriority(const DataType& dataType) } return 100; } + +QString MultiEditorBoolPlugin::getTabLabel() +{ + return tr("Boolean"); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorbool.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorbool.h index f328cf0..6aa11d5 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorbool.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorbool.h @@ -22,7 +22,6 @@ class GUI_API_EXPORT MultiEditorBool : public MultiEditorWidget QVariant getValue(); void setReadOnly(bool boolValue); QList getNoScrollWidgets(); - QString getTabLabel(); void focusThisWidget(); private: @@ -63,6 +62,7 @@ class GUI_API_EXPORT MultiEditorBoolPlugin : public BuiltInPlugin, public MultiE MultiEditorWidget* getInstance(); bool validFor(const DataType& dataType); int getPriority(const DataType& dataType); + QString getTabLabel(); }; #endif // MULTIEDITORBOOL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordate.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordate.cpp index 44178f8..4059f96 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordate.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordate.cpp @@ -9,11 +9,6 @@ MultiEditorDate::MultiEditorDate(QWidget* parent) setDisplayFormat(formats.first()); } -QString MultiEditorDate::getTabLabel() -{ - return tr("Date"); -} - void MultiEditorDate::staticInit() { formats << "yyyy-MM-dd"; @@ -85,3 +80,8 @@ int MultiEditorDatePlugin::getPriority(const DataType& dataType) } return 10; } + +QString MultiEditorDatePlugin::getTabLabel() +{ + return tr("Date"); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordate.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordate.h index d51150b..3b53c32 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordate.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordate.h @@ -10,8 +10,6 @@ class GUI_API_EXPORT MultiEditorDate : public MultiEditorDateTime public: explicit MultiEditorDate(QWidget *parent = 0); - QString getTabLabel(); - static void staticInit(); protected: @@ -34,6 +32,7 @@ class GUI_API_EXPORT MultiEditorDatePlugin : public BuiltInPlugin, public MultiE MultiEditorWidget* getInstance(); bool validFor(const DataType& dataType); int getPriority(const DataType& dataType); + QString getTabLabel(); }; #endif // MULTIEDITORDATE_H diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordatetime.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordatetime.cpp index bd1e244..99053b0 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordatetime.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordatetime.cpp @@ -106,7 +106,7 @@ QList MultiEditorDateTime::getNoScrollWidgets() QDateTime MultiEditorDateTime::fromString(const QString& value) { QDateTime dateTime; - foreach (const QString& format, getParsingFormats()) + for (const QString& format : getParsingFormats()) { dateTime = QDateTime::fromString(value, format); if (dateTime.isValid()) @@ -176,11 +176,6 @@ void MultiEditorDateTime::setReadOnly(bool value) updateReadOnlyDisplay(); } -QString MultiEditorDateTime::getTabLabel() -{ - return tr("Date & time"); -} - void MultiEditorDateTime::focusThisWidget() { dateTimeEdit->setFocus(); @@ -273,3 +268,8 @@ int MultiEditorDateTimePlugin::getPriority(const DataType& dataType) } return 10; } + +QString MultiEditorDateTimePlugin::getTabLabel() +{ + return tr("Date & time"); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordatetime.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordatetime.h index 59bd111..9038ede 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordatetime.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditordatetime.h @@ -27,7 +27,6 @@ class GUI_API_EXPORT MultiEditorDateTime : public MultiEditorWidget bool getReadOnly() const; void setReadOnly(bool value); - QString getTabLabel(); void focusThisWidget(); protected: @@ -79,6 +78,7 @@ class GUI_API_EXPORT MultiEditorDateTimePlugin : public BuiltInPlugin, public Mu MultiEditorWidget* getInstance(); bool validFor(const DataType& dataType); int getPriority(const DataType& dataType); + QString getTabLabel(); }; #endif // MULTIEDITORDATETIME_H diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorhex.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorhex.cpp index 5a3cd28..a959e53 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorhex.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorhex.cpp @@ -9,8 +9,6 @@ MultiEditorHex::MultiEditorHex() hexEdit = new QHexEdit(); layout()->addWidget(hexEdit); - //hexEdit->setTabChangesFocus(true); - connect(hexEdit, SIGNAL(dataChanged()), this, SLOT(modificationChanged())); setFocusProxy(hexEdit); } @@ -34,11 +32,6 @@ void MultiEditorHex::setReadOnly(bool value) hexEdit->setReadOnly(value); } -QString MultiEditorHex::getTabLabel() -{ - return tr("Hex"); -} - void MultiEditorHex::focusThisWidget() { hexEdit->setFocus(); @@ -92,3 +85,8 @@ int MultiEditorHexPlugin::getPriority(const DataType& dataType) } return 100; } + +QString MultiEditorHexPlugin::getTabLabel() +{ + return tr("Hex"); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorhex.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorhex.h index 5fd32a0..e647f12 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorhex.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorhex.h @@ -20,7 +20,6 @@ class GUI_API_EXPORT MultiEditorHex : public MultiEditorWidget void setValue(const QVariant& value); QVariant getValue(); void setReadOnly(bool value); - QString getTabLabel(); void focusThisWidget(); QList getNoScrollWidgets(); @@ -45,6 +44,7 @@ class GUI_API_EXPORT MultiEditorHexPlugin : public BuiltInPlugin, public MultiEd MultiEditorWidget* getInstance(); bool validFor(const DataType& dataType); int getPriority(const DataType& dataType); + QString getTabLabel(); }; #endif // MULTIEDITORHEX_H diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditornumeric.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditornumeric.cpp index 526f5c4..6b1dd09 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditornumeric.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditornumeric.cpp @@ -18,7 +18,7 @@ MultiEditorNumeric::MultiEditorNumeric(QWidget* parent) void MultiEditorNumeric::setValue(const QVariant& value) { - spinBox->setValue(value); + spinBox->setValue(value, false); } QVariant MultiEditorNumeric::getValue() @@ -31,11 +31,6 @@ void MultiEditorNumeric::setReadOnly(bool value) spinBox->setReadOnly(value); } -QString MultiEditorNumeric::getTabLabel() -{ - return tr("Number", "numeric multi editor tab name"); -} - void MultiEditorNumeric::focusThisWidget() { spinBox->setFocus(); @@ -108,3 +103,8 @@ int MultiEditorNumericPlugin::getPriority(const DataType& dataType) } return 10; } + +QString MultiEditorNumericPlugin::getTabLabel() +{ + return tr("Number", "numeric multi editor tab name"); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditornumeric.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditornumeric.h index c74d27a..224c6d4 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditornumeric.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditornumeric.h @@ -17,7 +17,6 @@ class GUI_API_EXPORT MultiEditorNumeric : public MultiEditorWidget void setValue(const QVariant& value); QVariant getValue(); void setReadOnly(bool value); - QString getTabLabel(); void focusThisWidget(); QList getNoScrollWidgets(); @@ -39,6 +38,7 @@ class GUI_API_EXPORT MultiEditorNumericPlugin : public BuiltInPlugin, public Mul MultiEditorWidget* getInstance(); bool validFor(const DataType& dataType); int getPriority(const DataType& dataType); + QString getTabLabel(); }; #endif // MULTIEDITORNUMERIC_H diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortext.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortext.cpp index 05db8e0..0d963a5 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortext.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortext.cpp @@ -5,6 +5,7 @@ #include #include #include +#include CFG_KEYS_DEFINE(MultiEditorText) @@ -40,11 +41,6 @@ void MultiEditorText::setReadOnly(bool value) textEdit->setReadOnly(value); } -QString MultiEditorText::getTabLabel() -{ - return tr("Text"); -} - QToolBar* MultiEditorText::getToolBar(int toolbar) const { UNUSED(toolbar); @@ -182,3 +178,8 @@ int MultiEditorTextPlugin::getPriority(const DataType& dataType) } return 1; } + +QString MultiEditorTextPlugin::getTabLabel() +{ + return tr("Text"); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortext.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortext.h index bd814ce..59d2a44 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortext.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortext.h @@ -44,7 +44,6 @@ class GUI_API_EXPORT MultiEditorText : public MultiEditorWidget, public ExtActio void setValue(const QVariant& value); QVariant getValue(); void setReadOnly(bool value); - QString getTabLabel(); QToolBar* getToolBar(int toolbar) const; void focusThisWidget(); QList getNoScrollWidgets(); @@ -82,6 +81,7 @@ class GUI_API_EXPORT MultiEditorTextPlugin : public BuiltInPlugin, public MultiE MultiEditorWidget* getInstance(); bool validFor(const DataType& dataType); int getPriority(const DataType& dataType); + QString getTabLabel(); }; #endif // MULTIEDITORTEXT_H diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortime.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortime.cpp index 8b49715..35800ce 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortime.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortime.cpp @@ -11,11 +11,6 @@ MultiEditorTime::MultiEditorTime(QWidget *parent) setDisplayFormat(formats.first()); } -QString MultiEditorTime::getTabLabel() -{ - return tr("Time"); -} - void MultiEditorTime::staticInit() { formats << "hh:mm:ss" @@ -88,3 +83,8 @@ int MultiEditorTimePlugin::getPriority(const DataType& dataType) } return 10; } + +QString MultiEditorTimePlugin::getTabLabel() +{ + return tr("Time"); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortime.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortime.h index 1fb05f3..e5b64a8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortime.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditortime.h @@ -11,8 +11,6 @@ class GUI_API_EXPORT MultiEditorTime : public MultiEditorDateTime public: explicit MultiEditorTime(QWidget *parent = 0); - QString getTabLabel(); - static void staticInit(); protected: @@ -35,6 +33,7 @@ class GUI_API_EXPORT MultiEditorTimePlugin : public BuiltInPlugin, public MultiE MultiEditorWidget* getInstance(); bool validFor(const DataType& dataType); int getPriority(const DataType& dataType); + QString getTabLabel(); }; #endif // MULTIEDITORTIME_H diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidget.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidget.cpp index caea9a5..826728a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidget.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidget.cpp @@ -8,10 +8,20 @@ MultiEditorWidget::MultiEditorWidget(QWidget *parent) : void MultiEditorWidget::installEventFilter(QObject* filterObj) { QObject::installEventFilter(filterObj); - foreach (QWidget* w, getNoScrollWidgets()) + for (QWidget* w : getNoScrollWidgets()) w->installEventFilter(filterObj); } +void MultiEditorWidget::setTabLabel(const QString& value) +{ + tabLabel = value; +} + +QString MultiEditorWidget::getTabLabel() +{ + return tabLabel; +} + bool MultiEditorWidget::isUpToDate() const { return upToDate; diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidget.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidget.h index 14bac26..dc98b1a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidget.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidget.h @@ -9,25 +9,28 @@ class GUI_API_EXPORT MultiEditorWidget : public QWidget Q_OBJECT public: - explicit MultiEditorWidget(QWidget *parent = 0); + explicit MultiEditorWidget(QWidget *parent = nullptr); virtual void setValue(const QVariant& value) = 0; virtual QVariant getValue() = 0; virtual void setReadOnly(bool value) = 0; virtual QList getNoScrollWidgets() = 0; - virtual QString getTabLabel() = 0; virtual void focusThisWidget() = 0; void installEventFilter(QObject* filterObj); + void setTabLabel(const QString& value); + QString getTabLabel(); bool isUpToDate() const; void setUpToDate(bool value); private: bool upToDate = true; + QString tabLabel; signals: void valueModified(); + void aboutToBeDeleted(); }; #endif // MULTIEDITORWIDGET_H diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidgetplugin.h b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidgetplugin.h index 011bde5..7426006 100644 --- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidgetplugin.h +++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditorwidgetplugin.h @@ -12,6 +12,7 @@ class GUI_API_EXPORT MultiEditorWidgetPlugin : public virtual Plugin virtual MultiEditorWidget* getInstance() = 0; virtual bool validFor(const DataType& dataType) = 0; virtual int getPriority(const DataType& dataType) = 0; + virtual QString getTabLabel() = 0; }; #endif // MULTIEDITORWIDGETPLUGIN_H diff --git a/SQLiteStudio3/guiSQLiteStudio/selectabledbmodel.h b/SQLiteStudio3/guiSQLiteStudio/selectabledbmodel.h index bbae582..f33e413 100644 --- a/SQLiteStudio3/guiSQLiteStudio/selectabledbmodel.h +++ b/SQLiteStudio3/guiSQLiteStudio/selectabledbmodel.h @@ -11,7 +11,7 @@ class DbTreeItem; class GUI_API_EXPORT SelectableDbModel : public QSortFilterProxyModel { public: - explicit SelectableDbModel(QObject *parent = 0); + explicit SelectableDbModel(QObject *parent = nullptr); QVariant data(const QModelIndex& index, int role) const; bool setData(const QModelIndex& index, const QVariant& value, int role); diff --git a/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp b/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp index c3fd257..b3656a6 100644 --- a/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp @@ -20,6 +20,7 @@ #include "dbtree/dbtreeitem.h" #include "dbtree/dbtree.h" #include "dbtree/dbtreemodel.h" +#include "common/lazytrigger.h" #include #include #include @@ -66,8 +67,9 @@ void SqlEditor::init() connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth())); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); - connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); + connect(this, SIGNAL(textChanged()), this, SLOT(checkContentSize())); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(cursorMoved())); + connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); updateLineNumberAreaWidth(); highlightCurrentLine(); @@ -79,15 +81,14 @@ void SqlEditor::init() connect(completer, SIGNAL(leftPressed()), this, SLOT(completerLeftPressed())); connect(completer, SIGNAL(rightPressed()), this, SLOT(completerRightPressed())); - autoCompleteTimer = new QTimer(this); - autoCompleteTimer->setSingleShot(true); - autoCompleteTimer->setInterval(autoCompleterDelay); - connect(autoCompleteTimer, SIGNAL(timeout()), this, SLOT(checkForAutoCompletion())); + autoCompleteTrigger = new LazyTrigger(autoCompleterDelay, + [this]() -> bool {return autoCompletion && !deletionKeyPressed;}, + this); + connect(autoCompleteTrigger, SIGNAL(triggered()), this, SLOT(checkForAutoCompletion())); + + queryParserTrigger = new LazyTrigger(queryParserDelay, this); + connect(autoCompleteTrigger, SIGNAL(triggered()), this, SLOT(parseContents())); - queryParserTimer = new QTimer(this); - queryParserTimer->setSingleShot(true); - queryParserTimer->setInterval(queryParserDelay); - connect(queryParserTimer, SIGNAL(timeout()), this, SLOT(parseContents())); connect(this, SIGNAL(textChanged()), this, SLOT(scheduleQueryParser())); queryParser = new Parser(Dialect::Sqlite3); @@ -502,17 +503,9 @@ void SqlEditor::completeSelected() insertPlainText(value); } -void SqlEditor::scheduleAutoCompletion() -{ - autoCompleteTimer->stop(); - - if (autoCompletion && !deletionKeyPressed) - autoCompleteTimer->start(); -} - void SqlEditor::checkForAutoCompletion() { - if (!db || !autoCompletion || deletionKeyPressed) + if (!db || !autoCompletion || deletionKeyPressed || !richFeaturesEnabled) return; Lexer lexer(getDialect()); @@ -545,7 +538,7 @@ void SqlEditor::refreshValidObjects() QSet databases = resolver.getDatabases(); databases << "main"; QStringList objects; - foreach (const QString& dbName, databases) + for (const QString& dbName : databases) { objects = resolver.getAllObjects(dbName); objectsInNamedDb[dbName] << objects; @@ -623,6 +616,9 @@ int SqlEditor::lineNumberAreaWidth() void SqlEditor::highlightParenthesis() { + if (!richFeaturesEnabled) + return; + // Clear extra selections QList selections = extraSelections(); @@ -703,6 +699,14 @@ void SqlEditor::indentSelected(bool shiftPressed) QTextDocument* doc = document(); QTextBlock startBlock = doc->findBlock(cursor.selectionStart()); QTextBlock endBlock = doc->findBlock(cursor.selectionEnd()); + + if (cursor.selectionEnd() > endBlock.position()) + { + QTextBlock afterEndBlock = endBlock.next(); + if (afterEndBlock.isValid()) + endBlock = afterEndBlock; + } + for (QTextBlock it = startBlock; it != endBlock; it = it.next()) { if (shiftPressed) @@ -834,18 +838,8 @@ void SqlEditor::completerRightPressed() void SqlEditor::parseContents() { - if (document()->characterCount() > SqliteSyntaxHighlighter::MAX_QUERY_LENGTH) - { - if (richFeaturesEnabled) - notifyWarn(tr("Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled.")); - - richFeaturesEnabled = false; + if (!richFeaturesEnabled) return; - } - else if (!richFeaturesEnabled) - { - richFeaturesEnabled = true; - } // Updating dialect according to current database (if any) Dialect dialect = Dialect::Sqlite3; @@ -880,9 +874,9 @@ void SqlEditor::checkForSyntaxErrors() // Marking invalid tokens, like in "SELECT * from test] t" - the "]" token is invalid. // Such tokens don't cause parser to fail. - foreach (SqliteQueryPtr query, queryParser->getQueries()) + for (SqliteQueryPtr query : queryParser->getQueries()) { - foreach (TokenPtr token, query->tokens) + for (TokenPtr token : query->tokens) { if (token->type == Token::INVALID) markErrorAt(token->start, token->end, true); @@ -896,7 +890,7 @@ void SqlEditor::checkForSyntaxErrors() } // Setting new markers when errors were detected - foreach (ParserError* error, queryParser->getErrors()) + for (ParserError* error : queryParser->getErrors()) markErrorAt(sqlIndex(error->getFrom()), sqlIndex(error->getTo())); emit errorsChecked(true); @@ -912,10 +906,10 @@ void SqlEditor::checkForValidObjects() Dialect dialect = db->getDialect(); QList fullObjects; QString dbName; - foreach (SqliteQueryPtr query, queryParser->getQueries()) + for (SqliteQueryPtr query : queryParser->getQueries()) { fullObjects = query->getContextFullObjects(); - foreach (const SqliteStatement::FullObject& fullObj, fullObjects) + for (const SqliteStatement::FullObject& fullObj : fullObjects) { dbName = fullObj.database ? stripObjName(fullObj.database->value, dialect) : "main"; if (!objectsInNamedDb.contains(dbName)) @@ -945,10 +939,8 @@ void SqlEditor::scheduleQueryParser(bool force) syntaxValidated = false; document()->setModified(false); - queryParserTimer->stop(); - queryParserTimer->start(); - - scheduleAutoCompletion(); + queryParserTrigger->schedule(); + autoCompleteTrigger->schedule(); } int SqlEditor::sqlIndex(int idx) @@ -1053,6 +1045,21 @@ void SqlEditor::cursorMoved() } } +void SqlEditor::checkContentSize() +{ + if (document()->characterCount() > SqliteSyntaxHighlighter::MAX_QUERY_LENGTH) + { + if (richFeaturesEnabled) + notifyWarn(tr("Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled.")); + + richFeaturesEnabled = false; + } + else if (!richFeaturesEnabled) + { + richFeaturesEnabled = true; + } +} + void SqlEditor::formatSql() { QString sql = hasSelection() ? getSelectedText() : toPlainText(); @@ -1094,17 +1101,14 @@ void SqlEditor::loadFromFile() setFileDialogInitPathByFile(fName); - QFile file(fName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + QString err; + QString sql = readFileContents(fName, &err); + if (sql.isNull() && !err.isNull()) { - notifyError(tr("Could not open file '%1' for reading: %2").arg(fName).arg(file.errorString())); + notifyError(tr("Could not open file '%1' for reading: %2").arg(fName).arg(err)); return; } - QTextStream stream(&file); - stream.setCodec("UTF-8"); - QString sql = stream.readAll(); - file.close(); setPlainText(sql); loadedFile = fName; @@ -1556,7 +1560,7 @@ void SqlEditor::setShowLineNumbers(bool value) void SqlEditor::checkSyntaxNow() { - queryParserTimer->stop(); + queryParserTrigger->cancel(); parseContents(); } @@ -1617,7 +1621,7 @@ const SqlEditor::DbObject* SqlEditor::getValidObjectForPosition(const QPoint& po const SqlEditor::DbObject* SqlEditor::getValidObjectForPosition(int position, bool movedLeft) { - foreach (const DbObject& obj, validDbObjects) + for (const DbObject& obj : validDbObjects) { if ((!movedLeft && position > obj.from && position-1 <= obj.to) || (movedLeft && position >= obj.from && position <= obj.to)) diff --git a/SQLiteStudio3/guiSQLiteStudio/sqleditor.h b/SQLiteStudio3/guiSQLiteStudio/sqleditor.h index 1c98682..c56492c 100644 --- a/SQLiteStudio3/guiSQLiteStudio/sqleditor.h +++ b/SQLiteStudio3/guiSQLiteStudio/sqleditor.h @@ -13,11 +13,17 @@ #include class CompleterWindow; -class QTimer; class Parser; class SqlEditor; class SearchTextDialog; class SearchTextLocator; +class LazyTrigger; + +#ifdef Q_OS_OSX +# define COMPLETE_REQ_KEY Qt::META +#else +# define COMPLETE_REQ_KEY Qt::CTRL +#endif CFG_KEY_LIST(SqlEditor, QObject::tr("SQL editor input field"), CFG_KEY_ENTRY(CUT, QKeySequence::Cut, QObject::tr("Cut selected text")) @@ -34,7 +40,7 @@ CFG_KEY_LIST(SqlEditor, QObject::tr("SQL editor input field"), CFG_KEY_ENTRY(FIND_PREV, QKeySequence::FindPrevious, QObject::tr("Find previous")) CFG_KEY_ENTRY(REPLACE, QKeySequence::Replace, QObject::tr("Replace in text")) CFG_KEY_ENTRY(DELETE_LINE, Qt::CTRL + Qt::Key_D, QObject::tr("Delete current line")) - CFG_KEY_ENTRY(COMPLETE, Qt::CTRL + Qt::Key_Space, QObject::tr("Request code assistant")) + CFG_KEY_ENTRY(COMPLETE, COMPLETE_REQ_KEY + Qt::Key_Space, QObject::tr("Request code assistant")) CFG_KEY_ENTRY(FORMAT_SQL, Qt::CTRL + Qt::Key_T, QObject::tr("Format contents")) CFG_KEY_ENTRY(MOVE_BLOCK_DOWN, Qt::ALT + Qt::Key_Down, QObject::tr("Move selected block of text one line down")) CFG_KEY_ENTRY(MOVE_BLOCK_UP, Qt::ALT + Qt::Key_Up, QObject::tr("Move selected block of text one line up")) @@ -199,10 +205,10 @@ class GUI_API_EXPORT SqlEditor : public QPlainTextEdit, public ExtActionContaine QMenu* validObjContextMenu = nullptr; Db* db = nullptr; CompleterWindow* completer = nullptr; - QTimer* autoCompleteTimer = nullptr; + LazyTrigger* autoCompleteTrigger = nullptr; bool autoCompletion = true; bool deletionKeyPressed = false; - QTimer* queryParserTimer = nullptr; + LazyTrigger* queryParserTrigger = nullptr; Parser* queryParser = nullptr; QHash objectsInNamedDb; QMutex objectsInNamedDbMutex; @@ -254,7 +260,7 @@ class GUI_API_EXPORT SqlEditor : public QPlainTextEdit, public ExtActionContaine void backspacePressed(); void complete(); void completeSelected(); - void scheduleAutoCompletion(); +// void scheduleAutoCompletion(); void checkForAutoCompletion(); void completerTypedText(const QString& text); void completerBackspacePressed(); @@ -266,6 +272,7 @@ class GUI_API_EXPORT SqlEditor : public QPlainTextEdit, public ExtActionContaine void highlightCurrentLine(); void updateLineNumberArea(const QRect&rect, int dy); void cursorMoved(); + void checkContentSize(); void formatSql(); void saveToFile(); void saveAsToFile(); diff --git a/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp b/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp index ac8d6cf..55ccc08 100644 --- a/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp @@ -279,7 +279,7 @@ bool SqliteSyntaxHighlighter::isError(int start, int lgt, bool* limitedDamage) { start += currentBlock().position(); int end = start + lgt - 1; - foreach (const Error& error, errors) + for (const Error& error : errors) { if (error.from <= start && error.to >= end) { @@ -294,7 +294,7 @@ bool SqliteSyntaxHighlighter::isValid(int start, int lgt) { start += currentBlock().position(); int end = start + lgt - 1; - foreach (const DbObject& obj, dbObjects) + for (const DbObject& obj : dbObjects) { if (obj.from <= start && obj.to >= end) return true; @@ -379,7 +379,7 @@ SqliteSyntaxHighlighter::DbObject::DbObject(int from, int to) : QList TextBlockData::parentheses() { QList list; - foreach (const TextBlockData::Parenthesis& par, parData) + for (const TextBlockData::Parenthesis& par : parData) list << ∥ return list; @@ -395,7 +395,7 @@ void TextBlockData::insertParenthesis(int pos, char c) const TextBlockData::Parenthesis* TextBlockData::parenthesisForPosision(int pos) { - foreach (const Parenthesis& par, parData) + for (const Parenthesis& par : parData) { if (par.position == pos) return ∥ diff --git a/SQLiteStudio3/guiSQLiteStudio/statusfield.cpp b/SQLiteStudio3/guiSQLiteStudio/statusfield.cpp index 4acd1a6..571fcba 100644 --- a/SQLiteStudio3/guiSQLiteStudio/statusfield.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/statusfield.cpp @@ -178,13 +178,13 @@ void StatusField::setupMenu() void StatusField::readRecentMessages() { noFlashing = true; - foreach (const QString& msg, NotifyManager::getInstance()->getRecentInfos()) + for (const QString& msg : NotifyManager::getInstance()->getRecentInfos()) info(msg); - foreach (const QString& msg, NotifyManager::getInstance()->getRecentWarnings()) + for (const QString& msg : NotifyManager::getInstance()->getRecentWarnings()) warn(msg); - foreach (const QString& msg, NotifyManager::getInstance()->getRecentErrors()) + for (const QString& msg : NotifyManager::getInstance()->getRecentErrors()) error(msg); noFlashing = false; diff --git a/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp b/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp index b63c58d..fd0c338 100644 --- a/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp @@ -158,7 +158,7 @@ QAction* TaskBar::getNextClosestAction(const QPoint& position) QToolButton* btn = nullptr; if (orientation() == Qt::Horizontal) { - foreach (QAction* action, tasks) + for (QAction* action : tasks) { btn = getToolButton(action); if (btn && btn->x() >= position.x()) @@ -167,7 +167,7 @@ QAction* TaskBar::getNextClosestAction(const QPoint& position) } else { - foreach (QAction* action, tasks) + for (QAction* action : tasks) { btn = getToolButton(action); if (btn && btn->y() >= position.y()) @@ -260,15 +260,33 @@ void TaskBar::dragTaskTo(QAction* task, int positionIndex) if (positionIndex < 0) return; + dragCurrentIndex = positionIndex; + removeAction(task); if (positionIndex >= tasks.size()) + { addAction(task); + tasks.removeOne(task); + tasks << task; + } else + { + int oldIdx = tasks.indexOf(task); + + // If we move from left to right, the positionIndex actually points to 1 position after, + // so insertAction() can expect its "before action" first argument. + // Although at this step we want precise position index to move the task on the list, + // so if this is movement from left to right, we deduct 1 from the index. + int newTaskIdx = (positionIndex > oldIdx) ? (positionIndex - 1) : positionIndex; + if (oldIdx == newTaskIdx) + return; + insertAction(tasks.at(positionIndex), task); + tasks.move(oldIdx, newTaskIdx); + } connect(getToolButton(task), SIGNAL(pressed()), this, SLOT(mousePressed())); - dragCurrentIndex = positionIndex; } QMimeData* TaskBar::generateMimeData() diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de.qm b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de.qm index f1dac43..3f118d1 100644 Binary files a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de.qm and b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de.qm differ diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de.ts index c597ce1..0047f6c 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de.ts @@ -14,9 +14,8 @@ Über SQLiteStudio - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Freier, open-source, multiplattformfähiger SQLite Datenbankmanager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Autor und aktiver Verantwortlicher:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Freier, open-source, multiplattformfähiger SQLite Datenbankmanager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Autor und aktiver Verantwortlicher:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> @@ -58,6 +57,11 @@ Configuration directory Konfigurationsverzeichnis + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + + Qt version: @@ -91,261 +95,221 @@ <h3>Inhaltsverzeichnis:</h3><ol>%2</ol> + + BindParamsDialog + + + Query parameters + + + + + Please provide values for query parameters + + + BugDialog - Bugs and ideas - Fehler und Anregungen + Fehler und Anregungen - Reporter - Gemeldet von + Gemeldet von - E-mail address - Ihre E-mail Adresse oder Ihr 'bugtracker' Login + Ihre E-mail Adresse oder Ihr 'bugtracker' Login - - Log in - Anmelden + Anmelden - Short description - Kurzbeschreibung + Kurzbeschreibung - Detailed description - Ausführliche Fehlerbeschreibung + Ausführliche Fehlerbeschreibung - Show more details - Mehr Details + Mehr Details - SQLiteStudio version - SQLiteStudio Version + SQLiteStudio Version - Operating system - Betriebssystem + Betriebssystem - Loaded plugins - Geladene Plugins + Geladene Plugins - Send - Absenden + Absenden - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - Sie können Ihre gemeldeten Fehler und Anregungen sehen, wenn Sie im Menü '%1' den Eintrag '%2' auswählen. + Sie können Ihre gemeldeten Fehler und Anregungen sehen, wenn Sie im Menü '%1' den Eintrag '%2' auswählen. - A bug report sent successfully. - Ihr Fehlerbericht wurde erfolgreich versendet. + Ihr Fehlerbericht wurde erfolgreich versendet. - An error occurred while sending a bug report: %1 %2 - Beim Absenden des Fehlerberichts ist ein Fehler aufgetreten: %1 %2 + Beim Absenden des Fehlerberichts ist ein Fehler aufgetreten: %1 %2 - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - Sie können versuchen den Bericht erneut abzusenden. Ihr eingegebener Text wird nach einem Fehler wie diesem wieder hergestellt. + Sie können versuchen den Bericht erneut abzusenden. Ihr eingegebener Text wird nach einem Fehler wie diesem wieder hergestellt. - An idea proposal sent successfully. - Ihre Anregung wurde erfolgreich versendet. + Ihre Anregung wurde erfolgreich versendet. - An error occurred while sending an idea proposal: %1 %2 - Beim Absenden der Anregung ist ein Fehler aufgetreten: %1 %2 + Beim Absenden der Anregung ist ein Fehler aufgetreten: %1 %2 - A bug report - Fehlerbericht erfassen + Fehlerbericht erfassen - Describe problem in few words - Beschreiben Sie das Problem mit wenigen Worten + Beschreiben Sie das Problem mit wenigen Worten - Describe problem and how to reproduce it - Beschreiben Sie das Problem hier genauer und die Schritte, um es zu reproduzieren + Beschreiben Sie das Problem hier genauer und die Schritte, um es zu reproduzieren - A new feature idea - Anregung zu einer neuen Funktion erfassen + Anregung zu einer neuen Funktion erfassen - A title for your idea - Ein kurzer Titel für ihre Anregung + Ein kurzer Titel für ihre Anregung - Describe your idea in more details - Beschreiben Sie hier Ihre Anregung ausführlich + Beschreiben Sie hier Ihre Anregung ausführlich - Reporting as an unregistered user, using e-mail address. - Versenden als nicht registrierter Benutzer mittels E-mail Adresse. + Versenden als nicht registrierter Benutzer mittels E-mail Adresse. - Reporting as a registered user. - Versenden als registrierter Benutzer. + Versenden als registrierter Benutzer. - Log out - Abmelden + Abmelden - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - Die Angabe Ihrer echten E-mail Adresse ermöglicht es uns Sie bzgl. Ihres Berichts zu kontaktieren. Erfahren Sie mehr dazu und klicken Sie den 'Hilfe' Knopf auf der rechtehn Seite. + Die Angabe Ihrer echten E-mail Adresse ermöglicht es uns Sie bzgl. Ihres Berichts zu kontaktieren. Erfahren Sie mehr dazu und klicken Sie den 'Hilfe' Knopf auf der rechtehn Seite. - Enter vaild e-mail address, or log in. - Geben Sie Ihre gültige E-mail Adresse oder Ihre Anmeldedaten an. + Geben Sie Ihre gültige E-mail Adresse oder Ihre Anmeldedaten an. - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - Eine Kurzbeschreibung benötigt mindestens 10 Zeichen, maximal jedoch 100 Zeichen. Eine ausführlichere Beschreibung kann in dem Feld unten erfasst werden. + Eine Kurzbeschreibung benötigt mindestens 10 Zeichen, maximal jedoch 100 Zeichen. Eine ausführlichere Beschreibung kann in dem Feld unten erfasst werden. - Long description requires at least 30 characters. - Eine ausführliche Beschreibung benötigt mindestens 30 Zeichen. + Eine ausführliche Beschreibung benötigt mindestens 30 Zeichen. BugReportHistoryWindow - - Title - Titel + Titel - - Reported at - Gemeldet am + Gemeldet am - - URL - URL + URL - Reports history - Berichtsverlauf + Berichtsverlauf - Clear reports history - Lösche Berichtsverlauf + Lösche Berichtsverlauf - Delete selected entry - Gewählten Eintrag löschen + Gewählten Eintrag löschen - Invalid response from server. - Ungültige Antwort vom Server. + Ungültige Antwort vom Server. BugReportLoginDialog - Log in - Anmelden + Anmelden - Credentials Hier fehlt mir der Kontext!!! - Überprüfung + Überprüfung - Login: - Login: + Login: - Password: - Passwort: + Passwort: - Validation - Überprüfung + Überprüfung - Validate - Überprüfe + Überprüfe - Validation result message - Ergebnis der Überprüfung + Ergebnis der Überprüfung - Abort - Abbrechen + Abbrechen - A login must be at least 2 characters long. - Ein Login Kürzel muss mindestens 2 Zeichen lang sein. + Ein Login Kürzel muss mindestens 2 Zeichen lang sein. - A password must be at least 5 characters long. - Ein Passwort muss mindestens 5 Zeichen lang sein. + Ein Passwort muss mindestens 5 Zeichen lang sein. - Valid - Gültig + Gültig @@ -356,12 +320,12 @@ Kollationen filtern - + Collation name: Kollationsname: - + Implementation language: Sprache: @@ -490,11 +454,20 @@ + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. + + + Invalid default value expression: %1 - Ungültiger Standardwert für Ausdruck: %1 + Ungültiger Standardwert für Ausdruck: %1 - + Enter a name of the constraint. Geben Sie einen Namen für die Bedingung ein. @@ -606,7 +579,7 @@ - + Delete constraint column dialog Bedingung löschen @@ -666,34 +639,44 @@ Standardbedingung hinzufügen - + Are you sure you want to delete constraint '%1'? column dialog Sind Sie sicher, dass Sie die folgende Bedingung löschen wollen: '%1'? - + Correct the constraint's configuration. Korrigiert die Konfiguration der Bedingung. - + This constraint is not officially supported by SQLite 2, but it's okay to use it. Diese Bedingung wird von SQLite 2 offiziell nicht unterstützt, aber sie kann dennoch benutzt werden. - + Scale is not allowed for INTEGER PRIMARY KEY columns. Für INTEGER PRIMARY KEY ist eine Skalierung nicht erlaubt. - + Precision cannot be defined without the scale. Die Präzision kann ohne Skalierung nicht definiert werden. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. Für INTEGER PRIMARY KEY ist eine Präzision nicht erlaubt. @@ -795,10 +778,9 @@ but it's okay to use it. Geben Sie einen Namen für die Bedingung ein. - Autoincrement (only for %1 type columns) column primary key - Automatische Zählung (nur für %1 Spaltentypen) + Automatische Zählung (nur für %1 Spaltentypen) @@ -910,7 +892,7 @@ but it's okay to use it. ConfigDialog - + Configuration Konfiguration @@ -1001,128 +983,139 @@ but it's okay to use it. Datenbearbeitung - + Number of data rows per page: Anzahl an Datenzeilen pro Seite: - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> <p>Wenn Daten in das Ergebnisfenster eingelesen werden, dann wird die Breite der Spalten dabei automatisch angepasst. Dieser Wert begrenzt maximale Breite für die automatische Breitenanpassung. Der Anwender kann die Spaltenbreite jedoch manuell über dieses Limit verbreitern.</p> - + Limit initial data column width to (in pixels): Begrenze die initiale Spaltenbreite im Ergebnisfenster auf (Pixel): - + Keep NULL value when entering empty value - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> - + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + + + + + Number of memorized table populating configurations + + + + Show column and row details tooltip in data view - + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> - + Use DEFAULT value (if defined), when committing NULL value - + Inserting new row in data grid Neue Zeile im Gitternetz des Datenfensters hinzufügen - + Before currently selected row Vor der derzeitig ausgewählten Zeile - + After currently selected row Nach der derzeitig ausgewählten Zeile - + At the end of data view Am Ende der Datenfensters - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> <p>Wenn aktiviert, wird der Reiter "Daten" anstelle des Reiters "Struktur" angezeigt beim öffnen eines Tabellenfensters angezeigt.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> <p>Wenn aktiviert, wird der Reiter "Daten" als erster Reiter angezeigt für jedes Tabellenfenster, anstelle an zweiter Stelle.</p> - + Place data tab as first tab in a Table Window Den Reiter Daten als ersten Reiter im Tabellenfenster anzeigen - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> - + Place data tab as first tab in a View Window Den Reiter Daten als ersten Reiter im View-Fenster anzeigen - + Data types Datentypen - + Available editors: Verfügbare Editoren: - + Editors selected for this data type: Für diesen Datentyp ausgewählte Editoren: - + Schema editing Schema - + Number of DDL changes kept in history. Maximale Anzahl an DDL Änderungen im Verlauf. - + DDL history size: DDL Verlaufsgröße: @@ -1131,104 +1124,104 @@ but it's okay to use it. Zeige keine DDL Vorschau, wenn Schemaänderungen committed werden - + SQL queries SQL Abfragen - - + + Number of queries kept in the history. Maximale Anzahl an SQL Abfragen im Verlauf. - + History size: Verlaufsgröße: - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> <p>Wenn diese Option aktiviert ist und sich mehrere SQL Abfragen im Editorfenster befinden, dann wird nur die SQL Abfrage ausgeführt, in der sich der Cursor befindet. Ist diese Option nicht gesetzt, dann werden alle SQL Abfragen ausgeführt. Sie können die auszuführenden SQL Abfragen selbst bestimmen, indem Sie diese vor der Ausführung mit der Maus oder Tastatur markieren.</p> - + Execute only the query under the cursor Führt nur die Abfrage unter dem Cursor aus - + Updates Updates - + Automatically check for updates at startup Prüfe vor dem Start automatisch auf Updates - + Session Sitzung - + Restore last session (active MDI windows) after startup Stelle letzte Sitzung nach dem Start wieder her (aktive MDI Fenster) - + Status Field Statusfeld - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> - + Always open Status panel when new message is printed Den Panel Status immer öffnen, wenn eine neue Meldung ausgegeben wird - + Filter shortcuts by name or key combination Filtere Tastaturkürzel nach Name oder Tastenkombination - + Action Aktion - + Key combination Tastenkombination - - + + Language Sprache - + Changing language requires application restart to take effect. Die Änderung der Sprache erfordert einen Neustart des Programms. - + Compact layout Kompaktes Layout - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> <p>Das kompakte Layout reduziert alle Lücken und Abstände der Oberfläche auf ein Minimum, um mehr Platz für die Darstellung der Daten zu schaffen. Die Oberfläche sieht dann zwar nicht mehr sehr ästhetisch aus, aber man hat mehr Daten im Überblick.</p> - + Use compact layout Benutze kompaktes Layout @@ -1308,7 +1301,7 @@ but it's okay to use it. Zeige Systemtabellen und Indizes in der Liste an - + Table windows Tabellenfenster @@ -1317,12 +1310,12 @@ but it's okay to use it. Wenn die Option aktiviert ist, dann wird im Tabellenfenster der Reiter "Daten" angezeigt statt "Strukturen". - + Open Table Windows with the data tab for start Öffnet das Tabellenfenster mit dem Reiter "Daten" im Vordergrund - + View windows Viewfenster @@ -1331,182 +1324,193 @@ but it's okay to use it. Wenn die Option aktiviert ist, dann wird im Viewfenster der Reiter "Daten" angezeigt statt "Strukturen". - + Open View Windows with the data tab for start Öffnet das Viewfenster mit dem Reiter "Daten" im Vordergrund - + Don't show DDL preview dialog when committing schema changes - + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + Number of memorized query parameters + + + + Main window dock areas Dockingbereiche des Hauptfensters - + Left and right areas occupy corners Linke und rechte Bereiche belegen die Ecken - + Top and bottom areas occupy corners Obere und untere Bereiche belegen die Ecken - + Hide built-in plugins Verberge eingebaute Plugins - + Current style: Aktueller Stil: - + Preview Vorschau - + Enabled Aktiviert - + Disabled Deaktiviert - + Active formatter plugin Aktives Formatierungsplugin - + SQL editor font Schriftart des SQL Editors - + Database list font Schriftart der Datenbankliste - + Database list additional label font Zusätzliche Bezeichnungen in der Datenbankliste - + Data view font Schriftart der Ergebnisansicht - + Status field font Schriftart des Statusfelds - + SQL editor colors Farben des SQL Editors - + Current line background Hintergrundfarbe der aktuellen Zeile - + <p>SQL strings are enclosed with single quote characters.</p> <p>SQL Zeichenketten sind mit einfachen Anführungszeichen umschlossen.</p> - + String foreground Vordergrundfarbe von Zeichenketten - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> <p>Bind Parameter sind Platzhalter für Werte, die der Anwender eingibt. Sie haben dabei eine der folgenden Formen:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> - + Bind parameter foreground Vordergrundfarbe von Bind Parametern - + Highlighted parenthesis background Hintergrundfarbe von hervorgehobener Klammern - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> <p>BLOB Werte sind hexadezimale Werte wie z.B.:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground Vordergrundfarbe von BLOB Werten - + Regular foreground Reguläre Vordergrundfarbe - + Line numbers area background Hintergrundfarbe der Zeilennummernleiste - + Keyword foreground Vordergrundfarbe von Schlüsselwörtern - + Number foreground Vordergrundfarbe von Ziffern - + Comment foreground Vordergrundfarbe von Kommentaren - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> <p>Gültige Objekte sind Namen von Tabellen, Indizes, Triggern oder Views die in der SQLite Datenbank existieren.</p> - + Valid objects foreground Vordergrundfarbe von gültigen Objekten - + Data view colors Farben der Ergebnisansicht - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> - + Uncommitted data outline color - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> @@ -1523,140 +1527,140 @@ but it's okay to use it. <p>Tritt beim Speichern einer Änderung ein Problem auf, dann wird die problematische Zelle mit dieser Farbe markiert.</p> - + Commit error outline color Rahmenfarbe für fehlerhafte Daten - + NULL value foreground Vordergrundfarbe für NULL Werte - + Deleted row background Hintergrundfarbe von gelöschten Zeilen - + Database list colors Farben der Datenbankliste - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> <p>Zusätzliche Bezeichnungen sind solche, die z.B. die SQLite Version oder die Anzahl an Einträgen in einer Baumliste usw. anzeigen.</p> - + Additional labels foreground Vordergrundfarbe für zusätzliche Bezeichnungen - + Status field colors Farben des Statusfelds - + Information message foreground Vordergrundfarbe für Infomeldungen - + Warning message foreground Vordergrundfarbe für Warnmeldungen - + Error message foreground Vordergrundfarbe für Fehlermeldungen - + Description: plugin details Bezeichnung: - + Category: plugin details Kategorie: - + Version: plugin details Version: - + Author: plugin details Autor: - + Internal name: plugin details Interner Name: - + Dependencies: plugin details Abhängigkeiten: - + Conflicts: plugin details Konflikte: - + Plugin details Plugin Details - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. Plugins werden direkt beim Aktivieren/Deaktivieren geladen bzw. entfernt, die modifizierte Pluginliste wird jedoch erst beim Bestätigen und Schließen des Konfigurationsfensters gespeichert. - + %1 (built-in) plugins manager in configuration dialog %1 (eingebaut) - + Details Details - + No plugins in this category. Keine Plugins in dieser Kategorie. - + Add new data type Neuen Datentypen zufügen - + Rename selected data type Markierten Datentypen umbenennen - + Delete selected data type Markierten Datentypen löschen - + Help for configuring data type editors Hilfe zur Konfiguration des Datentypen Editors @@ -1808,138 +1812,154 @@ but it's okay to use it. DataView - + Filter data data view Daten filtern - + Grid view Gitteransicht - + Form view Formularansicht - + Refresh table data data view Aktualisiere Tabellendaten - + First page data view Erste Seite - + Previous page data view Vorherige Seite - + Next page data view Nächste Seite - + Last page data view Letzte Seite - + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + Apply filter data view Filter anwenden - + Commit changes for selected cells data view Änderungen für die selektierten Zellen speichern - + Rollback changes for selected cells data view Änderungen für die selektierten Zellen zurücknehmen - + Show grid view of results sql editor Zeige Ergebnismenge in der Gitteransicht - + Show form view of results sql editor Zeige Ergebnismenge in der Formularansicht - + Filter by text data view Nach Text filtern - + Filter by the Regular Expression data view Nach regulärem Ausdruck filtern - + Filter by SQL expression data view Nach einem SQL Ausdruck filtern - + Tabs on top data view Reiterleiste oben - + Tabs at bottom data view Reiterleiste unten - + Place new rows above selected row data view Neue Zeilen über der ausgewählten Zeile einfügen - + Place new rows below selected row data view Neue Zeilen nach der ausgewählten Zeile einfügen - + Place new rows at the end of the data view data view Neue Zeilen am Ende des Datenfensters einfügen - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. Gesamtanzahl der Zeilen wird ermittelt. Das Aufrufen anderer Seiten ist erst nach Abschluss der Zählung möglich. - + Row: %1 Zeile: %1 @@ -2126,7 +2146,7 @@ Das Aufrufen anderer Seiten ist erst nach Abschluss der Zählung möglich. - <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> @@ -2237,288 +2257,425 @@ Das Aufrufen anderer Seiten ist erst nach Abschluss der Zählung möglich.Nach Name filtern - + Copy Kopieren - + Paste Einfügen - + Select all Alles auswählen - + Create a group Gruppe erstellen - + Delete the group Diese Gruppe löschen - + Rename the group Gruppe umbenennen - Add a database - Datenbank hinzufügen + Datenbank hinzufügen - Edit the database - Datenbank editieren + Datenbank editieren - Remove the database - Datenbank entfernen + Datenbank entfernen - Connect to the database - Mit der Datenbank verbinden + Mit der Datenbank verbinden - Disconnect from the database - Verbindung zur Datenbank trennen + Verbindung zur Datenbank trennen - + Import Import - Export the database - Datenbank exportieren + Datenbank exportieren - Convert database type - Datenbanktyp konvertieren + Datenbanktyp konvertieren - Vacuum ??? - Vakuum + Vakuum - Integrity check - Integritätsprüfung + Integritätsprüfung - Create a table - Tabelle erstellen + Tabelle erstellen - Edit the table - Tabelle editieren + Tabelle editieren - Delete the table - Tabelle löschen + Tabelle löschen - + Export the table Tabelle exportieren - + Import into the table In die Tabelle importieren - + Populate table Tabelle füllen - + Create similar table Erzeuge identische Tabelle - + Reset autoincrement sequence Automatischen Zähler zurücksetzen - Create an index - Index erstellen + Index erstellen - Edit the index - Index editieren + Index editieren - Delete the index - Index löschen + Index löschen - Create a trigger - Trigger erstellen + Trigger erstellen - Edit the trigger - Trigger editieren + Trigger editieren - Delete the trigger - Trigger löschen + Trigger löschen - Create a view - View erstellen + View erstellen - Edit the view - View editieren + View editieren - Delete the view - View löschen + View löschen - + Add a column Spalte zufügen - + Edit the column Spalte editieren - + Delete the column Spalte löschen - + Delete selected items Gewählte Einträge löschen - + Clear filter Filter zurücksetzen - Refresh all database schemas - Alle Datenbankschemen aktualisieren + Alle Datenbankschemen aktualisieren - Refresh selected database schema - Alle markierten Datenbankschemen aktualisieren + Alle markierten Datenbankschemen aktualisieren + + + + Execution from file cancelled. Any queries executed so far have been rolled back. + + + + + &Add a database + + + + + &Edit the database + + + + + &Remove the database + + + + + &Connect to the database + - + &Disconnect from the database + + + + + &Export the database + + + + + Con&vert database type + + + + + Vac&uum + + + + + &Integrity check + + + + + Create a &table + + + + + Edit the t&able + + + + + Delete the ta&ble + + + + + Create an &index + + + + + Edit the i&ndex + + + + + Delete the in&dex + + + + + Create a trig&ger + + + + + Edit the trigg&er + + + + + Delete the trigge&r + + + + + Create a &view + + + + + Edit the v&iew + + + + + Delete the vi&ew + + + + + &Refresh all database schemas + + + + + Re&fresh selected database schema + + + + + Erase table data Tabellendaten löschen - - + + Open file's directory + + + + + Execute SQL from file + + + + + Database Datenbank - + Grouping Gruppieren - + Generate query for table Abfrage für Tabelle generieren - - + + Create group Gruppe erstellen - + Group name Gruppenname - + Entry with name %1 already exists in group %2. Der Eintrag mit Namen %1 existiert bereits in der Gruppe %2. - + Delete group Gruppe löschen - + Are you sure you want to delete group %1? All objects from this group will be moved to parent group. Sind Sie sicher, dass Sie die Gruppe %1 löschen möchten? Alle Objekte in dieser Gruppe werden in die übergeordnete Gruppe verschoben. - + Are you sure you want to remove database '%1' from the list? Sind Sie sicher, dass Sie die Datenbank '%1' aus der Liste entfernen möchten? - + Are you sure you want to remove following databases from the list: %1 Sind Sie sicher, dass Sie folgende Datenbanken aus der Liste entfernen möchten: %1 - + Remove database Datenbank entfernen - + Vacuum (%1) Vacuum (%1) - + Autoincrement value for table '%1' has been reset successfully. - + Are you sure you want to delete all data from table(s): %1? + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + Die Datei '%1' kann nicht für Lesezugriffe geöffnet werden: %2 + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. + + Delete database Datenbank löschen @@ -2529,14 +2686,14 @@ Alle Objekte in dieser Gruppe werden in die übergeordnete Gruppe verschoben.Sind Sie sicher, dass Sie die Datenbank '%1' entfernen möchten? - - + + Cannot import, because no import plugin is loaded. Der Import kann nicht durchgeführt werden, da kein Import Plugin geladen ist. - - + + Cannot export, because no export plugin is loaded. Export fehlgeschlagen, da kein Export Plugins geladen sind. @@ -2549,22 +2706,22 @@ Alle Objekte in dieser Gruppe werden in die übergeordnete Gruppe verschoben.VACUUM erfolgreich abgeschlossen. - + Integrity check (%1) Integritätsprüfung (%1) - + Reset autoincrement Autoincrement zurücksetzen - + Are you sure you want to reset autoincrement value for table '%1'? Sind Sie sicher, dass Sie den Autoincrement Wert für die Tabelle '%1' zurücksetzen möchten? - + An error occurred while trying to reset autoincrement value for table '%1': %2 Ein Fehler ist aufgetreten beim Zurücksetzen des Autoincrementwertes für die Tabelle '%1': %2 @@ -2577,37 +2734,37 @@ Alle Objekte in dieser Gruppe werden in die übergeordnete Gruppe verschoben.Sind Sie sicher, dass Sie alle Daten der Tabelle '%1' löschen möchten? - + An error occurred while trying to delete data from table '%1': %2 Beim Löschen der Daten aus Tabelle '%1' ist folgender Fehler aufgetreten: %2 - + All data has been deleted for table '%1'. Es wurden alle Daten aus Tabelle '%1' gelöscht. - + Following objects will be deleted: %1. Folgende Objekte werden gelöscht: %1. - + Following databases will be removed from list: %1. Folgende Datenbanken werden aus der Liste entfernt: %1. - + Remainig objects from deleted group will be moved in place where the group used to be. Die aus der gelöschten Gruppe verbleibenden Objekte werden an die Position der gelöschten Gruppe verschoben. - + %1<br><br>Are you sure you want to continue? %1<br><br>Sind Sie sicher, dass Sie fortfahren möchten? - + Delete objects Objekte löschen @@ -2696,75 +2853,75 @@ Alle Objekte in dieser Gruppe werden in die übergeordnete Gruppe verschoben.Trigger (%1): - + Copy Kopieren - + Move Verschieben - + Include data Inklusive Daten - + Include indexes Inklusive Indizes - + Include triggers Inklusive Trigger - + Abort Abbrechen - + Could not add dropped database file '%1' automatically. Manual setup is necessary. - + Referenced tables Referenzierte Tabellen - + Do you want to include following referenced tables as well: %1 Möchten Sie die folgenden referenzierten Tabellen mit einbeziehen? %1 - + Name conflict Namenskonflikt - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: Folgende Objekte existieren bereits in der Datenbank. Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den Vorgang abzubrechen: - + SQL statements conversion SQL Statement Konvertierung - + Following error occurred while converting SQL statements to the target SQLite version: Folgender Fehler trat auf bei der Konvertierung von SQL Statements in die SQLite Zielversion: - + Would you like to ignore those errors and proceed? Möchten Sie diese Fehler ignorieren und fortfahren? @@ -2820,130 +2977,136 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Abfrage - + History Verlauf - + Results in the separate tab Ergebnisse in separatem Reiter - + Results below the query Ergebnisse unter der Abfrage - - + + SQL editor %1 SQL Editor %1 - + Results Ergebnisse - + Execute query Abfrage ausführen - + Explain query Abfrage ausführen (explain) - + Clear execution history sql editor Ausführungsverlauf löschen - + Export results sql editor Ergebnisse exportieren - + Create view from query sql editor View aus der Abfrage erstellen - + Previous database Vorherige Datenbank - + Next database Nächste Datenbank - + Show next tab sql editor Nächsten Reiter zeigen - + Show previous tab sql editor Vorherigen Reiter zeigen - + Focus results below sql editor Fokus auf die Ergebnisse unten - + Focus SQL editor above sql editor Fokus auf den SQL Editor oben - + + Delete selected SQL history entries + sql editor + + + + Active database (%1/%2) Aktive Datenbank (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 Abfrage in %1 Sekunde(n) abgeschlossen. %2 Zeile(n) betroffen - + Query finished in %1 second(s). Abfrage in %1 Sekunde(n) abgeschlossen. - + Clear execution history Lösche Ausführungsverlauf - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. Sind Sie sicher, dass Sie den gesamten SQL Ausführungsverlauf löschen möchten? Dieser Vorgang kann nicht rückgängig gemacht werden. - + Cannot export, because no export plugin is loaded. Es kann nicht exportiert werden, da kein Export Plugin geladen ist. - + No database selected in the SQL editor. Cannot create a view for unknown database. Es ist keine Datenbank im SQL Editor selektiert. Für eine unbekannte Datenbank kann kein View erzeugt werden. - + Editor window "%1" has uncommitted data. @@ -2970,6 +3133,64 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Möchten Sie fortsetzen? + + ExecFromFileDialog + + + Execute SQL from file + + + + + Input file + + + + + Path to file + + + + + Browse for file + + + + + Options + Optionen + + + + File encoding + + + + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + SQL Skripte (*.sql);;Alle Dateien (*) + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + ExportDialog @@ -3121,79 +3342,112 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Optionen des Exportformats - + Cancel Abbrechen - - - + + + Select database to export. Wählen Sie die zu exportierenden Datebank aus. - + Select table to export. Wählen Sie die zu exportierenden Tabellen aus. - + Enter valid query to export. ??? Geben Sie eine gültige Abfrage für den Export an. - + Select at least one object to export. Wählen Sie ein zu exportierendes Datebankobjekt aus. - + You must provide a file name to export to. Sie müssen einen Namen für die Exportdatei angeben. - + Path you provided is an existing directory. You cannot overwrite it. Das von Ihnen angegebene Verzeichnis existiert bereits. Es kann nicht überschrieben werden. - + The directory '%1' does not exist. Das Verzeichnis '%1' existiert nicht. - + The file '%1' exists and will be overwritten. Die Datei '%1' existiert bereits und wird überschrieben werden. - + All files (*) Alle Dateien (*) - + Pick file to export to Wählen Sie eine Datei aus in die exportiert werden soll - + Internal error during export. This is a bug. Please report it. Es trat ein interner Fehler während des Exportvorgangs auf. Dies ist ein Fehler, bitte melden Sie ihn dem Programmautor. - FontEdit + FileExecErrorsDialog - - Choose font - font configuration - Schriftart auswählen + + Execution errors + - - + + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + Fehler + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + + + FontEdit + + + Choose font + font configuration + Schriftart auswählen + + + Form @@ -3204,49 +3458,49 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V FormView - + Commit row form view Zeile speichern (Commit) - + Rollback row form view Zeile rückgängig (Rollback) - + First row form view Erste Zeile - + Previous row form view Vorherige Zeile - + Next row form view Nächste Zeile - + Last row form view Letzte Zeile - + Insert new row form view Neue Zeile einfügen - + Delete current row form view Aktuelle Zeile löschen @@ -3305,13 +3559,13 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Initialisierungsanweisungen: - + Function implementation code: Funktionsanweisungen: - + Final step implementation code: Abschlussanweisungen: @@ -3480,42 +3734,42 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Datenquellenoptionen - + Cancel Abbrechen - + If you type table name that doesn't exist, it will be created. Wenn Sie einen Tabellenname eingeben, der noch nicht existiert, dann wird diese neue Tabelle erzeugt werden. - + Enter the table name Datenbankname eingeben - + Select import plugin. Importplugin auswählen - + You must provide a file to import from. Sie müssen den Namen der Importdatei angeben. - + The file '%1' does not exist. Die Datei '%1' existiert nicht. - + Path you provided is a directory. A regular file is required. Der von Ihnen angegebene Pfad ist ein Verzeichnis. Es wird jedoch eine Datei benötigt. - + Pick file to import from Wählen Sie eine Datei aus von der importiert werden soll. @@ -3554,12 +3808,12 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Spalte - + Collation Kollation - + Sort Sortierung @@ -3739,273 +3993,402 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Ansichtenleiste - + Configuration widgets Konfigurationshelfer - + Syntax highlighting engines Syntaxhervorhebungen - + Data editors Dateneditoren - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. Ablauf im Debugmodus. Zum Öffnen der Debugkonsole drücken Sie %1 oder wählen Menü 'Hilfe' den Eintrag 'Debugkonsole öffnen' aus. - + Running in debug mode. Debug messages are printed to the standard output. Ablauf im Debugmodus. Debugmeldungen werden in der Standardausgabe angezeigt.. - + You need to restart application to make the language change take effect. Das Programm muss neu gestartet werden, damit die Änderung der Sprache wirksam wird. - Open SQL editor - SQL Editor öffnen + SQL Editor öffnen - Open DDL history - DDL Verlauf öffnen - - - - Open SQL functions editor - + DDL Verlauf öffnen - Open collations editor - Editor für Kollationen öffnen + Editor für Kollationen öffnen - Import - Importieren + Importieren - Export - Exportieren + Exportieren - Open configuration dialog - Einstellungen + Einstellungen - Tile windows - Alle Fenster aufteilen + Alle Fenster aufteilen - Tile windows horizontally - Alle Fenster horizontal aufteilen + Alle Fenster horizontal aufteilen - Tile windows vertically - Alle Fenster vertikal aufteilen + Alle Fenster vertikal aufteilen - Cascade windows - Alle Fenster kaskadiert aufteilen + Alle Fenster kaskadiert aufteilen - + Next window Nächstes Fenster - + Previous window Vorheriges Fenster - + Hide status field Statusfeld verbergen - Close selected window - Ausgewähltes Fenster schließen + Ausgewähltes Fenster schließen - Close all windows but selected - Alle anderen Fenster schließen + Alle anderen Fenster schließen - Close all windows - Alle Fenster schließen + Alle Fenster schließen - Restore recently closed window - Zuletzt geöffnetes Fenster wiederherstellen + Zuletzt geöffnetes Fenster wiederherstellen - Rename selected window - Ausgewähltes Fenster umbenennen + Ausgewähltes Fenster umbenennen - + Open Debug Console Debug Konsole öffnen - + Open CSS Console CSS Konsole öffnen - Report a bug - Fehler melden + Fehler melden - Propose a new feature - Eine neue Programmfunktion vorschlagen + Eine neue Programmfunktion vorschlagen - About - Über SQLiteStudio + Über SQLiteStudio - Licenses - Lizenzen + Lizenzen - Open home page - Homepage aufrufen + Homepage aufrufen - Open forum page - Forum aufrufen + Forum aufrufen - User Manual - Bedienungsanleitung + Bedienungsanleitung - SQLite documentation - SQLite Dokumentation + SQLite Dokumentation - Report history - Verlauf gemeldeter Fehler + Verlauf gemeldeter Fehler - Check for updates - Auf Updates prüfen + Auf Updates prüfen - Database menubar - Datenbank + Datenbank - Structure menubar - Struktur + Struktur - View menubar - Ansicht + Ansicht - + Window list menubar view menu Fensterliste - Tools menubar - Werkzeuge + Werkzeuge - Help - Hilfe + Hilfe + + + + Open SQL &editor + + + + + Open DDL &history + + + + + Open SQL &functions editor + + + + + Open &collations editor + + + + + Open ex&tension manager + + + + + &Import + + + + + E&xport + + + + + Open confi&guration dialog + + + + + &Tile windows + + + + + Tile windows &horizontally + + + + + Tile windows &vertically + + + + + &Cascade windows + + + + + Close selected &window + + + + + Close all windows &but selected + + + + + Close &all windows + + + + + Re&store recently closed window + + + + + &Rename selected window + + + + + Report a &bug + + + + + Propose a new &feature + - + + &About + + + + + &Licenses + + + + + Open home &page + + + + + Open fo&rum page + + + + + User &Manual + + + + + SQLite &documentation + + + + + Bugs and feature &requests + + + + + Check for &updates + + + + + &Database + menubar + + + + + &Structure + menubar + + + + + &View + menubar + + + + + &Tools + menubar + + + + + &Help + + + + Could not set style: %1 main window Der folgende Stil kann nicht gesetzt werden: %1 - + Cannot export, because no export plugin is loaded. Es kann nicht exportiert werden, da kein Export Plugin geladen ist. - + Cannot import, because no import plugin is loaded. Es kann nicht importiert werden, da kein Import Plugin geladen ist. - + Rename window Fenster umbenennen - + Enter new name for the window: Neuen Namen für das Fenster eingeben: - + New updates are available. <a href="%1">Click here for details</a>. Neues Update verfügbar. <a href="%1">Weitere Details</a>. - + You're running the most recent version. No updates are available. Sie haben bereits die aktuellste Version. Keine Update verfügbar. - + Database passed in command line parameters (%1) was already on the list under name: %2 Die Datenbank, die mittels Programmparameter übergeben wurde (%1), war bereits in der Liste unter dem Namen %2 vorhanden. - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 Die Datenbank, die mittels Programmparameter übergeben wurde (%1), wurde in der Liste termporär unter dem Namen %2 zugefügt. - + Could not add database %1 to list. Die Datenbank %1 konnte nicht hinzugefügt werden. @@ -4041,23 +4424,28 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V NULL Wert - + Configure editors for this data type Konfigurationseditoren für diesen Datentyp - + + Open another tab + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. Das Dateneditor Plugin '%1' ist nicht geladen, obwohl es für den '%1' Datentypen als Editor definiert ist. - + Deleted multieditor Gelöscht - + Read only multieditor Nur lesend @@ -4066,94 +4454,144 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V MultiEditorBool - Boolean - Boolean + Boolean + + + + MultiEditorBoolPlugin + + + Boolean + Boolean MultiEditorDate - Date - Datum + Datum + + + + MultiEditorDatePlugin + + + Date + Datum MultiEditorDateTime - Date & time - Datum & Zeit + Datum & Zeit + + + + MultiEditorDateTimePlugin + + + Date & time + Datum & Zeit MultiEditorHex - Hex - Hexadezimal + Hexadezimal + + + + MultiEditorHexPlugin + + + Hex + Hexadezimal MultiEditorNumeric - Number numeric multi editor tab name - Nummer + Nummer + + + + MultiEditorNumericPlugin + + + Number + numeric multi editor tab name + Nummer MultiEditorText - Text - Text + Text - + Tab changes focus Hier fehlt mir der Kontext... Nacharbeiten nötig. Reiter Änderungen Fokus - + Cut Ausschneiden - + Copy Kopieren - + Paste Einfügen - + Delete Löschen - + Undo Rückgängig - + Redo Wiederholen + + MultiEditorTextPlugin + + + Text + Text + + MultiEditorTime - Time - Zeit + Zeit + + + + MultiEditorTimePlugin + + + Time + Zeit @@ -4228,37 +4666,40 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Komponente - + + This application will be closed and the update installer will start to download and install all the updates. + + + Current version - Derzeitige Version + Derzeitige Version - + Update version Neue Version - + Check for updates on startup Beim Programmstart auf Updates prüfen - + Update to new version! Auf neue Version aktualisieren! - The update will be automatically downloaded and installed. This will also restart application at the end. - Das Update wird automatisch heruntergeladen und installiert. Die Anwendung wird daraufhin neugestartet. + Das Update wird automatisch heruntergeladen und installiert. Die Anwendung wird daraufhin neugestartet. - + Not now. Nicht jetzt. - + Don't install the update and close this window. Update nicht installieren und Fenster schließen. @@ -4310,32 +4751,32 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Füllen - + Abort Abbrechen - + Configure Konfigurieren - + Populating configuration for this column is invalid or incomplete. Die Konfigurationsauffüllung für diese Spalte ist ungültig oder unvollständig. - + Select database with table to populate Wählen Sie die Datebank und Tabelle zum Auffüllen aus - + Select table to populate Wählen Sie die Tabelle zum Auffüllen aus - + You have to select at least one column. Sie müssen mindestens eine Spalte auswählen. @@ -4410,129 +4851,134 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Name der Kollation: %1 - + Data grid view Ergebnisansicht - + Copy cell(s) contents to clipboard Kopiert Zelleninhalt(e) in die Zwischenablage + Copy cell(s) contents together with header to clipboard + + + + Paste cell(s) contents from clipboard Fügt Zelleninhalt(e) von der Zwischenablage ein - + Set empty value to selected cell(s) Fügt einen leeren Wert in die selektierte(n) Zelle(n) ein - + Set NULL value to selected cell(s) Fügt den NULL Wert in die selektierte(n) Zelle(n) ein - + Commit changes to cell(s) contents Änderungen der Zellenninhalte speichern - + Rollback changes to cell(s) contents Änderungen der Zelleninhalte zurücknehmen - + Delete selected data row Markierte Datenzeile löschen - + Insert new data row Neue Datenzeile einfügen - + Open contents of selected cell in a separate editor Inhalt der markierten Zelle im separaten Editor öffnen - + Total pages available: %1 Verfügbare Gesamtseiten: %1 - + Total rows loaded: %1 Insgesamt geladene Zeilen: %1 - + Data view (both grid and form) Ergebnisansicht (tabellarisch und Formular) - + Refresh data Daten aktualisieren - + Switch to grid view of the data Zur tabellarischen Ergebnisansicht wechseln - + Switch to form view of the data Zur Formularansicht wechseln - + Database list Liste der Datenbanken - + Delete selected item Gewählten Eintrag löschen - + Clear filter contents Filter zurücksetzen - + Refresh schema Schema aktualisieren - + Refresh all schemas Alle Schemas aktualisieren - + Add database Datenbank hinzufügen - + Select all items Alles auswählen - + Copy selected item(s) Gewählte Einträge kopieren - + - + Paste from clipboard Von der Zwischenablage einfügen @@ -4607,42 +5053,42 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Derzeitige Zeile löschen - + Main window Hauptfenster - + Open SQL editor SQL Editor öffnen - + Previous window Vorheriges Fenster - + Next window Nächstes Fenster - + Hide status area Statusfeld verbergen - + Open configuration dialog Konfigurationsdialog öffnen - + Open Debug Console Debug Konsole öffnen - + Open CSS Console CSS Konsole öffnen @@ -4653,111 +5099,111 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V - + Cut selected text Gewählten Text ausschneiden - + Copy selected text Gewählten Text kopieren - + Delete selected text Gewählten Text löschen - + Undo Rückgängig - + Redo Wiederholen - + SQL editor input field SQL Editor Eingabefeld - + Select whole editor contents Gesamten Editorinhalt auswählen - + Save contents into a file Inhalte in eine Datei speichern - + Load contents from a file Inhalte aus einer Datei laden - + Find in text Suche im Text - + Find next Nächster Fund - + Find previous Vorheriger Fund - + Replace in text Ersetze im Text - + Delete current line Aktuelle Zeile löschen - + Request code assistant Code-Assistenten anfordern - + Format contents Format-Inhalte - + Move selected block of text one line down Selektierten Textblock eine Zeile nach unten verschieben - + Move selected block of text one line up Selektierten Textblock eine Zeile nach oben verschieben - + Copy selected block of text and paste it a line below Selektierten Textblock kopieren und unterhalb einfügen - + Copy selected block of text and paste it a line above Selektierten Textblock kopieren und oberhalb einfügen - + Toggle comment Kommentar umschalten @@ -4778,15 +5224,13 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Datenbankdatei - Reports history window Diese Übersetzung muss noch einmal geprüft werden, wenn ich den Kontext dazu kenne. - Report-Verlaufsfenster + Report-Verlaufsfenster - Delete selected entry - Gewählten Eintrag löschen + Gewählten Eintrag löschen @@ -4833,6 +5277,11 @@ Bitte geben Sie einen neuen, eindeutigen Namen an oder drücken Sie %1, um den V Move keyboard input focus to the SQL editor above Tastatureingabe-Fokus in das obere SQL Editorfenster setzen + + + Delete selected SQL history entries + + Table window @@ -5059,180 +5508,180 @@ find next SqlEditor - + Cut sql editor Ausschneiden - + Copy sql editor Kopieren - + Paste sql editor Einfügen - + Delete sql editor Löschen - + Select all sql editor Alles auswählen - + Undo sql editor Rückgängig - + Redo sql editor Wiederholen - + Complete sql editor Komplett - + Format SQL sql editor SQL formatieren - + Save SQL to file sql editor SQL in Datei speichern - + Select file to save SQL sql editor SQL aus Datei laden - + Load SQL from file sql editor Zeile löschen - + Delete line sql editor Zeile löschen - + Move block down sql editor Block nach unten verschieben - + Move block up sql editor Block nach oben verschieben - + Copy block down sql editor Block nach unten kopieren - + Copy up down sql editor "up down" ??? Muss geklärt werden! Kopiere auf ab - + Find sql editor Finden - + Find next sql editor Nächster Fund - + Find previous sql editor Vorheriger Fund - + Replace sql editor Ersetzen - + Toggle comment sql editor Kommentar umschalten - + Saved SQL contents to file: %1 SQL Inhalte in Datei speichern: %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. Die Funktion Autovervollständigung kann nur genutzt werden, wenn eine gültige Datenbank für den SQL Editor gewählt wurde. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. Der Text im SQL Editor ist sehr groß, daher wurde die Syntaxkontrolle und die farbliche Hervorhebung von Objekten vorübergehend deaktiviert. - + Save to file In Datei speichern - + Could not open file '%1' for writing: %2 Die Datei '%1' kann nicht für Schreibzugriffe geöffnet werden: %2 - + SQL scripts (*.sql);;All files (*) SQL Skripte (*.sql);;Alle Dateien (*) - + Open file Datei öffnen - + Could not open file '%1' for reading: %2 Die Datei '%1' kann nicht für Lesezugriffe geöffnet werden: %2 - + Reached the end of document. Hit the find again to restart the search. Das Dokumentenende wurde erreicht. Drücken Sie 'Nächster Fund', um die Suche am Dokumentenanfang fortzusetzen. @@ -5288,24 +5737,24 @@ find next - - + + Cannot edit this cell. Details: %1 Die Zelle kann nicht editiert. Details: %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. @@ -5313,8 +5762,8 @@ find next SqlQueryModel - - + + Only one query can be executed simultaneously. Es kann nur eine Abfrage gleichzeitig ausgeführt werden. @@ -5327,12 +5776,12 @@ find next Es gibt ungespeicherte Änderungen. Möchten Sie wirklich fortfahren? Alle Änderungen werden dann verloren gehen. - + Cannot commit the data for a cell that refers to the already closed database. Es können keine Daten für eine Zelle gespeichert werden, die eine bereits geschlossene Datenbank referenziert. - + Could not begin transaction on the database. Details: %1 Es kann keine Transaktion auf der Datenbank gestartet werden. Details: %1 @@ -5341,12 +5790,12 @@ find next Fehler beim Committen der Transaktion: %1 - + An error occurred while rolling back the transaction: %1 Fehler beim Rollback der Transaktion: %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. Es wurde versucht eine nicht editierbare Zelle zu committen (derzeit modifiziert und auf das Commit wartend)! Dies ist ein Fehler den Sie melden sollten. @@ -5355,43 +5804,48 @@ find next Fehler beim Committen der Daten: %1 - + Uncommitted data - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. - + An error occurred while committing the transaction: %1 - + An error occurred while committing the data: %1 - - + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + + + + + Error while executing SQL query on database '%1': %2 Fehler beim Ausführen der SQL-Abfrage auf der Datenbank '%1': %2 - + Error while loading query results: %1 Fehler beim Laden der Abfrageergebnisse: %1 - + Insert multiple rows Mehrere Zeilen einfügen - + Number of rows to insert: Anzahl an Zeilen zum Einfügen: @@ -5399,117 +5853,137 @@ find next SqlQueryView - + Go to referenced row in... - + Copy Kopieren - + Copy as... Kopieren als... - + Paste Einfügen - + Paste as... Einfügen als... - + Set NULL values NULL Wert setzen - + Erase values Werte löschen - + Edit value in editor Wert im Editor bearbeiten - + Commit Commit - + + Copy with headers + + + + Rollback Rollback - + Commit selected cells Gewählte Zellen speichern - + Rollback selected cells Gewählte Zellen wiederherstellen - + Define columns to sort by Sortierspalten definieren - + Remove custom sorting Benutzerdefinierte Sortierung entfernen - + Insert row Zeile einfügen - + Insert multiple rows Mehrere Zeilen einfügen - + Delete selected row Gewählte Zeile löschen - + + Show value in a viewer + + + + Generate query for selected cells - + No items selected to paste clipboard contents to. Es sind keine Elemente selektiert in die der Inhalt der Zwischenablage eingefügt werden könnte. - + Go to referenced row in table '%1' - + table '%1' - + Referenced row (%1) - + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + Edit value Werte editieren @@ -5531,6 +6005,119 @@ find next Fehler beim Löschen der Zeile aus Tabelle %1: %2 + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + Datenbanken + + + + Register in all databases + In allen Datenbanken registrieren + + + + Register in following databases: + In den folgenden Datenbanken registrieren: + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + Alle Dateien (*) + + + + Open file + Datei öffnen + + StatusField @@ -5639,7 +6226,7 @@ but it's okay to use them anyway. Geben Sie einen Namen für die Bedingung ein. - + Foreign column table constraints @@ -5693,24 +6280,24 @@ but it's okay to use them anyway. Bei Konflikt - + Collate table constraints - + Sort order table constraints Sortierung - + Select at least one column. Mindestens eine Spalte auswählen. - + Enter a name of the constraint. Geben Sie einen Namen für die Bedingung ein. @@ -6269,7 +6856,7 @@ Are you sure you want to create a table with blank name? - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> @@ -6314,7 +6901,7 @@ Are you sure you want to create a table with blank name? - + DDL DDL @@ -6393,18 +6980,18 @@ Are you sure you want to create a table with blank name? - - + + Data - + Triggers Trigger - + DDL DDL @@ -6436,125 +7023,125 @@ Are you sure you want to create a table with blank name? - + Refresh the view view window - + Commit the view changes view window - + Rollback the view changes view window - + Explicit column names - + Generate output column names automatically basing on result columns of the view. - + Add column view window - + Edit column view window - + Delete column view window - + Move column up view window Spalte nach oben verschieben - + Move column down view window Spalte nach unten verschieben - + Refresh trigger list view window Trigger Liste aktualisieren - + Create new trigger view window Trigger erstellen - + Edit selected trigger view window Trigger editieren - + Delete selected trigger view window Trigger löschen - + View window "%1" has uncommitted structure modifications and data. - + View window "%1" has uncommitted data. - + View window "%1" has uncommitted structure modifications. - + Uncommitted changes - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Committed changes for view '%1' successfully. - + Committed changes for view '%1' (named before '%2') successfully. - + Could not load data for view %1. Error details: %2 @@ -6563,101 +7150,101 @@ Do you want to commit the structure, or do you want to go back to the structure Nicht gespeicherte Änderungen - + Go back to structure tab - + Commit modifications and browse data. - + Could not commit view changes. Error message: %1 view window - + Override columns - + Currently defined columns will be overriden. Do you want to continue? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. - + Name view window triggers Name - + Instead of view window triggers - + Condition view window triggers - + Details table window triggers Details - + Could not process the %1 view correctly. Unable to open a view window. - + Empty name - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. - + Following problems will take place while modifying the view. Would you like to proceed? view window - + View modification view window diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_es.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_es.ts index 2771e77..fc3f218 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_es.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_es.ts @@ -13,11 +13,6 @@ About - - - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> - - Licenses @@ -58,6 +53,11 @@ Configuration directory + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + + Qt version: @@ -90,258 +90,15 @@ - BugDialog - - - Bugs and ideas - - - - - Reporter - - - - - E-mail address - - - - - - Log in - - - - - Short description - - - - - Detailed description - - - - - Show more details - - - - - SQLiteStudio version - - - - - Operating system - - - - - Loaded plugins - - - - - Send - - - - - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - - - - - A bug report sent successfully. - - - - - An error occurred while sending a bug report: %1 -%2 - - - - - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - - - - - An idea proposal sent successfully. - - - - - An error occurred while sending an idea proposal: %1 -%2 - - - - - A bug report - - - - - Describe problem in few words - - - - - Describe problem and how to reproduce it - - - - - A new feature idea - - - - - A title for your idea - - - - - Describe your idea in more details - - - - - Reporting as an unregistered user, using e-mail address. - - - - - Reporting as a registered user. - - - - - Log out - - - - - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - - - - - Enter vaild e-mail address, or log in. - - - - - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - - - - - Long description requires at least 30 characters. - - - - - BugReportHistoryWindow + BindParamsDialog - - - Title + + Query parameters - - - Reported at - - - - - - URL - - - - - Reports history - - - - - Clear reports history - - - - - Delete selected entry - - - - - Invalid response from server. - - - - - BugReportLoginDialog - - - Log in - - - - - Credentials - - - - - Login: - - - - - Password: - - - - - Validation - - - - - Validate - - - - - Validation result message - - - - - Abort - - - - - A login must be at least 2 characters long. - - - - - A password must be at least 5 characters long. - - - - - Valid + + Please provide values for query parameters @@ -353,12 +110,12 @@ - + Collation name: - + Implementation language: @@ -483,11 +240,16 @@ - Invalid default value expression: %1 + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. - + Enter a name of the constraint. @@ -599,7 +361,7 @@ - + Delete constraint column dialog @@ -659,34 +421,44 @@ - + Are you sure you want to delete constraint '%1'? column dialog - + Correct the constraint's configuration. - + This constraint is not officially supported by SQLite 2, but it's okay to use it. - + Scale is not allowed for INTEGER PRIMARY KEY columns. - + Precision cannot be defined without the scale. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. @@ -787,12 +559,6 @@ but it's okay to use it. Enter a name of the constraint. - - - Autoincrement (only for %1 type columns) - column primary key - - ColumnUniqueAndNotNullPanel @@ -903,7 +669,7 @@ but it's okay to use it. ConfigDialog - + Configuration @@ -993,215 +759,215 @@ but it's okay to use it. - + Number of data rows per page: - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> - + Limit initial data column width to (in pixels): - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> - + Show column and row details tooltip in data view - + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> - + Inserting new row in data grid - + Before currently selected row - + After currently selected row - + At the end of data view - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> - + Place data tab as first tab in a Table Window - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> - + Place data tab as first tab in a View Window - + Data types - + Available editors: - + Editors selected for this data type: - + Schema editing - + Number of DDL changes kept in history. - + DDL history size: - + SQL queries - - + + Number of queries kept in the history. - + History size: - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> - + Execute only the query under the cursor - + Updates - + Automatically check for updates at startup - + Session - + Restore last session (active MDI windows) after startup - + Status Field - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> - + Always open Status panel when new message is printed - + Filter shortcuts by name or key combination - + Action - + Key combination - - + + Language - + Changing language requires application restart to take effect. - + Compact layout - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> - + Use compact layout @@ -1277,350 +1043,372 @@ but it's okay to use it. - + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + + + + + Number of memorized table populating configurations + + + + Keep NULL value when entering empty value - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> - + Use DEFAULT value (if defined), when committing NULL value - + Table windows - + Open Table Windows with the data tab for start - + View windows - + Open View Windows with the data tab for start - + Don't show DDL preview dialog when committing schema changes - + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + Number of memorized query parameters + + + + Main window dock areas - + Left and right areas occupy corners - + Top and bottom areas occupy corners - + Hide built-in plugins - + Current style: - + Preview - + Enabled - + Disabled - + Active formatter plugin - + SQL editor font - + Database list font - + Database list additional label font - + Data view font - + Status field font - + SQL editor colors - + Current line background - + <p>SQL strings are enclosed with single quote characters.</p> - + String foreground - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> - + Bind parameter foreground - + Highlighted parenthesis background - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground - + Regular foreground - + Line numbers area background - + Keyword foreground - + Number foreground - + Comment foreground - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> - + Valid objects foreground - + Data view colors - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> - + Uncommitted data outline color - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> - + Commit error outline color - + NULL value foreground - + Deleted row background - + Database list colors - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> - + Additional labels foreground - + Status field colors - + Information message foreground - + Warning message foreground - + Error message foreground - + Description: plugin details - + Category: plugin details - + Version: plugin details - + Author: plugin details - + Internal name: plugin details - + Dependencies: plugin details - + Conflicts: plugin details - + Plugin details - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. - + %1 (built-in) plugins manager in configuration dialog - + Details - + No plugins in this category. - + Add new data type - + Rename selected data type - + Delete selected data type - + Help for configuring data type editors @@ -1772,137 +1560,153 @@ but it's okay to use it. DataView - + Filter data data view - + Grid view - + Form view - + Refresh table data data view - + First page data view - + Previous page data view - + Next page data view - + Last page data view - + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + Apply filter data view - + Commit changes for selected cells data view - + Rollback changes for selected cells data view - + Show grid view of results sql editor - + Show form view of results sql editor - + Filter by text data view - + Filter by the Regular Expression data view - + Filter by SQL expression data view - + Tabs on top data view - + Tabs at bottom data view - + Place new rows above selected row data view - + Place new rows below selected row data view - + Place new rows at the end of the data view data view - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. - + Row: %1 @@ -2081,7 +1885,7 @@ Browsing other pages will be possible after the row counting is done. - <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> @@ -2183,352 +1987,397 @@ Browsing other pages will be possible after the row counting is done. - + Copy - + Paste - + Select all - + Create a group - + Delete the group - + Rename the group - - Add a database + + Import - - Edit the database + + Export the table - - Remove the database + + Import into the table - - Connect to the database + + Populate table - - Disconnect from the database + + Create similar table - - Import + + Reset autoincrement sequence - - Export the database + + Add a column - - Convert database type + + Edit the column - - Vacuum + + Delete the column - - Integrity check + + Delete selected items - - Create a table + + Clear filter - - Edit the table + + + Erase table data - - Delete the table + + + Database - - Export the table + + Grouping - - Import into the table + + Generate query for table - - Populate table + + + Create group - - Create similar table + + Group name - - Reset autoincrement sequence + + Entry with name %1 already exists in group %2. - - Create an index + + Delete group - - Edit the index + + Are you sure you want to delete group %1? +All objects from this group will be moved to parent group. - - Delete the index + + Are you sure you want to remove database '%1' from the list? - - Create a trigger + + Are you sure you want to remove following databases from the list: +%1 - - Edit the trigger + + Remove database - - Delete the trigger + + Vacuum (%1) - - Create a view + + Autoincrement value for table '%1' has been reset successfully. - - Edit the view + + Are you sure you want to delete all data from table(s): %1? - - Delete the view + + + Cannot import, because no import plugin is loaded. - - Add a column + + Execution from file cancelled. Any queries executed so far have been rolled back. - - Edit the column + + &Add a database - - Delete the column + + &Edit the database - - Delete selected items + + &Remove the database - - Clear filter + + &Connect to the database - - Refresh all database schemas + + &Disconnect from the database - - Refresh selected database schema + + &Export the database - - - Erase table data + + Con&vert database type - - - Database + + Vac&uum - - Grouping + + &Integrity check - - Generate query for table + + Create a &table - - - Create group + + Edit the t&able - - Group name + + Delete the ta&ble - - Entry with name %1 already exists in group %2. + + Create an &index - - Delete group + + Edit the i&ndex - - Are you sure you want to delete group %1? -All objects from this group will be moved to parent group. + + Delete the in&dex - - Are you sure you want to remove database '%1' from the list? + + Create a trig&ger - - Are you sure you want to remove following databases from the list: -%1 + + Edit the trigg&er - - Remove database + + Delete the trigge&r - - Vacuum (%1) + + Create a &view - - Autoincrement value for table '%1' has been reset successfully. + + Edit the v&iew - - Are you sure you want to delete all data from table(s): %1? + + Delete the vi&ew - - - Cannot import, because no import plugin is loaded. + + &Refresh all database schemas + + + + + Re&fresh selected database schema - - + + Open file's directory + + + + + Execute SQL from file + + + + + Cannot export, because no export plugin is loaded. - + Integrity check (%1) - + Reset autoincrement - + Are you sure you want to reset autoincrement value for table '%1'? - + An error occurred while trying to reset autoincrement value for table '%1': %2 - + An error occurred while trying to delete data from table '%1': %2 - + All data has been deleted for table '%1'. - + Following objects will be deleted: %1. - + Following databases will be removed from list: %1. - + Remainig objects from deleted group will be moved in place where the group used to be. - + %1<br><br>Are you sure you want to continue? - + Delete objects + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. + + DbTreeItemDelegate @@ -2614,74 +2463,74 @@ All objects from this group will be moved to parent group. - + Copy - + Move - + Include data - + Include indexes - + Include triggers - + Abort - + Could not add dropped database file '%1' automatically. Manual setup is necessary. - + Referenced tables - + Do you want to include following referenced tables as well: %1 - + Name conflict - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: - + SQL statements conversion - + Following error occurred while converting SQL statements to the target SQLite version: - + Would you like to ignore those errors and proceed? @@ -2735,130 +2584,136 @@ Please enter new, unique name, or press '%1' to abort the operation: - + History - + Results in the separate tab - + Results below the query - - + + SQL editor %1 - + Results - + Execute query - + Explain query - + Clear execution history sql editor - + Export results sql editor - + Create view from query sql editor - + Previous database - + Next database - + Show next tab sql editor - + Show previous tab sql editor - + Focus results below sql editor - + Focus SQL editor above sql editor - + + Delete selected SQL history entries + sql editor + + + + Active database (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 - + Query finished in %1 second(s). - + Clear execution history - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. - + Cannot export, because no export plugin is loaded. - + No database selected in the SQL editor. Cannot create a view for unknown database. - + Editor window "%1" has uncommitted data. @@ -2881,6 +2736,64 @@ Please enter new, unique name, or press '%1' to abort the operation: + + ExecFromFileDialog + + + Execute SQL from file + + + + + Input file + + + + + Path to file + + + + + Browse for file + + + + + Options + + + + + File encoding + + + + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + ExportDialog @@ -3030,68 +2943,101 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cancel - - - + + + Select database to export. - + Select table to export. - + Enter valid query to export. - + Select at least one object to export. - + You must provide a file name to export to. - + Path you provided is an existing directory. You cannot overwrite it. - + The directory '%1' does not exist. - + The file '%1' exists and will be overwritten. - + All files (*) - + Pick file to export to - + Internal error during export. This is a bug. Please report it. + + FileExecErrorsDialog + + + Execution errors + + + + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + FontEdit @@ -3112,49 +3058,49 @@ Please enter new, unique name, or press '%1' to abort the operation: FormView - + Commit row form view - + Rollback row form view - + First row form view - + Previous row form view - + Next row form view - + Last row form view - + Insert new row form view - + Delete current row form view @@ -3213,13 +3159,13 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Function implementation code: - + Final step implementation code: @@ -3383,42 +3329,42 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cancel - + If you type table name that doesn't exist, it will be created. - + Enter the table name - + Select import plugin. - + You must provide a file to import from. - + The file '%1' does not exist. - + Path you provided is a directory. A regular file is required. - + Pick file to import from @@ -3457,12 +3403,12 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Collation - + Sort @@ -3641,273 +3587,278 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Configuration widgets - + Syntax highlighting engines - + Data editors - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. - + Running in debug mode. Debug messages are printed to the standard output. - + You need to restart application to make the language change take effect. - - Open SQL editor + + Next window - - Open DDL history + + Previous window - - Open SQL functions editor + + Hide status field - - Open collations editor + + Open Debug Console - - Import + + Open CSS Console - - Export + + Bugs and feature &requests - - Open configuration dialog + + Window list + menubar view menu - - Tile windows + + Open SQL &editor - - Tile windows horizontally + + Open DDL &history - - Tile windows vertically + + Open SQL &functions editor - - Cascade windows + + Open &collations editor - - Next window + + Open ex&tension manager - - Previous window + + &Import - - Hide status field + + E&xport - - Close selected window + + Open confi&guration dialog - - Close all windows but selected + + &Tile windows - - Close all windows + + Tile windows &horizontally - - Restore recently closed window + + Tile windows &vertically - - Rename selected window + + &Cascade windows - - Open Debug Console + + Close selected &window - - Open CSS Console + + Close all windows &but selected - - Report a bug + + Close &all windows - - Propose a new feature + + Re&store recently closed window - - About + + &Rename selected window - - Licenses + + Report a &bug + + + + + Propose a new &feature - - Open home page + + &About - - Open forum page + + &Licenses - - User Manual + + Open home &page - - SQLite documentation + + Open fo&rum page - - Report history + + User &Manual - - Check for updates + + SQLite &documentation - - Database - menubar + + Check for &updates - - Structure + + &Database menubar - - View + + &Structure menubar - - Window list - menubar view menu + + &View + menubar - - Tools + + &Tools menubar - - Help + + &Help - + Could not set style: %1 main window - + Cannot export, because no export plugin is loaded. - + Cannot import, because no import plugin is loaded. - + Rename window - + Enter new name for the window: - + New updates are available. <a href="%1">Click here for details</a>. - + You're running the most recent version. No updates are available. - + Database passed in command line parameters (%1) was already on the list under name: %2 - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 - + Could not add database %1 to list. @@ -3939,64 +3890,69 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Configure editors for this data type - + + Open another tab + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. - + Deleted multieditor - + Read only multieditor - MultiEditorBool + MultiEditorBoolPlugin - + Boolean - MultiEditorDate + MultiEditorDatePlugin - + Date - MultiEditorDateTime + MultiEditorDateTimePlugin - + Date & time - MultiEditorHex + MultiEditorHexPlugin - + Hex - MultiEditorNumeric + MultiEditorNumericPlugin - + Number numeric multi editor tab name @@ -4005,50 +3961,53 @@ Please enter new, unique name, or press '%1' to abort the operation: MultiEditorText - - Text - - - - + Tab changes focus - + Cut - + Copy - + Paste - + Delete - - Undo + + Undo + + + + + Redo + + + MultiEditorTextPlugin - - Redo + + Text - MultiEditorTime + MultiEditorTimePlugin - + Time @@ -4125,37 +4084,32 @@ Please enter new, unique name, or press '%1' to abort the operation: - - Current version + + This application will be closed and the update installer will start to download and install all the updates. - + Update version - + Check for updates on startup - + Update to new version! - - The update will be automatically downloaded and installed. This will also restart application at the end. - - - - + Not now. - + Don't install the update and close this window. @@ -4207,32 +4161,32 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Abort - + Configure - + Populating configuration for this column is invalid or incomplete. - + Select database with table to populate - + Select table to populate - + You have to select at least one column. @@ -4307,129 +4261,134 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Data grid view - + Copy cell(s) contents to clipboard - Paste cell(s) contents from clipboard + Copy cell(s) contents together with header to clipboard + Paste cell(s) contents from clipboard + + + + Set empty value to selected cell(s) - + Set NULL value to selected cell(s) - + Commit changes to cell(s) contents - + Rollback changes to cell(s) contents - + Delete selected data row - + Insert new data row - + Open contents of selected cell in a separate editor - + Total pages available: %1 - + Total rows loaded: %1 - + Data view (both grid and form) - + Refresh data - + Switch to grid view of the data - + Switch to form view of the data - + Database list - + Delete selected item - + Clear filter contents - + Refresh schema - + Refresh all schemas - + Add database - + Select all items - + Copy selected item(s) - + - + Paste from clipboard @@ -4504,42 +4463,42 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Main window - + Open SQL editor - + Previous window - + Next window - + Hide status area - + Open configuration dialog - + Open Debug Console - + Open CSS Console @@ -4550,111 +4509,111 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cut selected text - + Copy selected text - + Delete selected text - + Undo - + Redo - + SQL editor input field - + Select whole editor contents - + Save contents into a file - + Load contents from a file - + Find in text - + Find next - + Find previous - + Replace in text - + Delete current line - + Request code assistant - + Format contents - + Move selected block of text one line down - + Move selected block of text one line up - + Copy selected block of text and paste it a line below - + Copy selected block of text and paste it a line above - + Toggle comment @@ -4674,16 +4633,6 @@ Please enter new, unique name, or press '%1' to abort the operation:Database file - - - Reports history window - - - - - Delete selected entry - - SQL editor window @@ -4729,6 +4678,11 @@ Please enter new, unique name, or press '%1' to abort the operation:Move keyboard input focus to the SQL editor above + + + Delete selected SQL history entries + + Table window @@ -4947,179 +4901,179 @@ find next SqlEditor - + Cut sql editor - + Copy sql editor - + Paste sql editor - + Delete sql editor - + Select all sql editor - + Undo sql editor - + Redo sql editor - + Complete sql editor - + Format SQL sql editor - + Save SQL to file sql editor - + Select file to save SQL sql editor - + Load SQL from file sql editor - + Delete line sql editor - + Move block down sql editor - + Move block up sql editor - + Copy block down sql editor - + Copy up down sql editor - + Find sql editor - + Find next sql editor - + Find previous sql editor - + Replace sql editor - + Toggle comment sql editor - + Saved SQL contents to file: %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. - + Save to file - + Could not open file '%1' for writing: %2 - + SQL scripts (*.sql);;All files (*) - + Open file - + Could not open file '%1' for reading: %2 - + Reached the end of document. Hit the find again to restart the search. @@ -5167,24 +5121,24 @@ find next - - + + Cannot edit this cell. Details: %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. @@ -5192,69 +5146,74 @@ find next SqlQueryModel - - + + Only one query can be executed simultaneously. - + Cannot commit the data for a cell that refers to the already closed database. - + Could not begin transaction on the database. Details: %1 - + An error occurred while rolling back the transaction: %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. - + Uncommitted data - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. - + An error occurred while committing the transaction: %1 - + An error occurred while committing the data: %1 - - + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + + + + + Error while executing SQL query on database '%1': %2 - + Error while loading query results: %1 - + Insert multiple rows - + Number of rows to insert: @@ -5262,117 +5221,137 @@ find next SqlQueryView - + Go to referenced row in... - + Copy - + Copy as... - + Paste - + Paste as... - + Set NULL values - + Erase values - + Edit value in editor - + Commit - + + Copy with headers + + + + Rollback - + Commit selected cells - + Rollback selected cells - + Define columns to sort by - + Remove custom sorting - + Insert row - + Insert multiple rows - + Delete selected row - + + Show value in a viewer + + + + Generate query for selected cells - + No items selected to paste clipboard contents to. - + Go to referenced row in table '%1' - + table '%1' - + Referenced row (%1) - + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + Edit value @@ -5390,6 +5369,119 @@ find next + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + + + + + Register in all databases + + + + + Register in following databases: + + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + + + + + Open file + + + StatusField @@ -5498,7 +5590,7 @@ but it's okay to use them anyway. - + Foreign column table constraints @@ -5552,24 +5644,24 @@ but it's okay to use them anyway. - + Collate table constraints - + Sort order table constraints - + Select at least one column. - + Enter a name of the constraint. @@ -6120,7 +6212,7 @@ Are you sure you want to create a table with blank name? - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> @@ -6165,7 +6257,7 @@ Are you sure you want to create a table with blank name? - + DDL @@ -6243,18 +6335,18 @@ Are you sure you want to create a table with blank name? - - + + Data - + Triggers - + DDL @@ -6286,224 +6378,224 @@ Are you sure you want to create a table with blank name? - + Refresh the view view window - + Commit the view changes view window - + Rollback the view changes view window - + Explicit column names - + Generate output column names automatically basing on result columns of the view. - + Add column view window - + Edit column view window - + Delete column view window - + Move column up view window - + Move column down view window - + Refresh trigger list view window - + Create new trigger view window - + Edit selected trigger view window - + Delete selected trigger view window - + View window "%1" has uncommitted structure modifications and data. - + View window "%1" has uncommitted data. - + View window "%1" has uncommitted structure modifications. - + Uncommitted changes - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Committed changes for view '%1' successfully. - + Committed changes for view '%1' (named before '%2') successfully. - + Could not load data for view %1. Error details: %2 - + Go back to structure tab - + Commit modifications and browse data. - + Could not commit view changes. Error message: %1 view window - + Override columns - + Currently defined columns will be overriden. Do you want to continue? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. - + Name view window triggers - + Instead of view window triggers - + Condition view window triggers - + Details table window triggers - + Could not process the %1 view correctly. Unable to open a view window. - + Empty name - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. - + Following problems will take place while modifying the view. Would you like to proceed? view window - + View modification view window diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_fr.qm b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_fr.qm index 71a632e..0f02e29 100644 Binary files a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_fr.qm and b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_fr.qm differ diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_fr.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_fr.ts index 8a46630..aec2cac 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_fr.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_fr.ts @@ -6,7 +6,7 @@ About SQLiteStudio and licenses - À propos de SQLiteStudio et ses licences + À propos de SQLiteStudio et des licences @@ -14,9 +14,13 @@ À propos de… - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Libre, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Auteur et maintenance:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Libre, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Auteur et maintenance:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + @@ -51,7 +55,7 @@ SQLite 3 version: - + Version de SQLite 3 : SQLite 3 version : @@ -70,7 +74,7 @@ Portable distribution. - Version portable + Version portable. @@ -80,7 +84,7 @@ Operating system managed distribution. - Operating system managed distribution + Distribution gérée par le système d'exploitation. @@ -93,261 +97,221 @@ <h3>Table des matières : </h3><ol>%2</ol> + + BindParamsDialog + + + Query parameters + + + + + Please provide values for query parameters + + + BugDialog - Bugs and ideas - Bugs et idées + Bugs et idées - Reporter - Rapport + Rapport - E-mail address - Adresse électronique + Adresse électronique - - Log in - S’identifier + S’identifier - Short description - Description brève + Description brève - Detailed description - Description détaillée + Description détaillée - Show more details - Montrer plus de détails + Montrer plus de détails - SQLiteStudio version - Version SQLiteStudio + Version de SQLiteStudio - Operating system - Système d’exploitation + Système d’exploitation - Loaded plugins - Plugins chargés + Plugins chargés - Send - Envoyez + Envoyer - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - Vous pouvez voir tous bugs et idées que vous avez rapportées en sélectionnant le menu « %1 » puis « %2 ». + Vous pouvez voir tous bugs et idées que vous avez rapportées en sélectionnant le menu « %1 » puis « %2 ». - A bug report sent successfully. - Rapport de bogue envoyé avec succès + Rapport de bogue envoyé avec succès - An error occurred while sending a bug report: %1 %2 - Une erreur est survenue lors de l’envoi du rapport de bogue : %1 + Une erreur est survenue lors de l’envoi du rapport de bogue : %1 %2 - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - Vous pouvez réexpédier. Le contenu sera restoré lorsque vous ouvrirez le dialogue du rapport après une telle erreur. + Vous pouvez essayer à nouveau. Le contenu sera restauré lorsque vous ouvrirez le dialogue du rapport après une telle erreur. - An idea proposal sent successfully. - L’idée proposée à été envoyée avec succès. + L’idée proposée à été envoyée avec succès. - An error occurred while sending an idea proposal: %1 %2 - Une erreeur est survenu lors de l’envoi de l’idée proposée : %1 %2 + Une erreeur est survenu lors de l’envoi de l’idée proposée : %1 %2 - A bug report - Rapport de bug + Rapport de bug - Describe problem in few words - Décrivez le problème en queques mots + Décrivez le problème en queques mots - Describe problem and how to reproduce it - Décriver le problem et comment le reproduire + Décrivez le problème et comment le reproduire - A new feature idea - Une nouvelle idée de fonctionalité + Une nouvelle idée de fonctionalité - A title for your idea - Un titre pour votre idée + Un titre pour votre idée - Describe your idea in more details - Décrivez votre idée avec plus de détails + Décrivez votre idée avec plus de détails - Reporting as an unregistered user, using e-mail address. - Rapport comme nouvel utilisateur, avec une adresse mail. + Envoyer le rapport comme nouvel utilisateur, avec une adresse mail. - Reporting as a registered user. - Rapport comme utilisateur enregistré. + Envoyer le rapport comme utilisateur enregistré. - Log out - Déconnexion + Déconnexion - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - En fournissant un mail existant il sera possible de vous contacterau sujet du rapport. Pour en savoir plus, clic sur le bouton « help » sur le coté droit. + En fournissant un mail existant il sera possible de vous contacter au sujet du rapport. Pour en savoir plus, clic sur le bouton « help » sur le coté droit. - Enter vaild e-mail address, or log in. - Entrez un email valide ou connectez-vous. + Entrez un email valide ou connectez-vous. - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - Une description courte nécessite au moins 10 caractères, mais pas plus de 100. La longueur de la description ne peut être contenue dans ce champ. + Une description courte nécessite au moins 10 caractères, mais pas plus de 100. La longueur de la description ne peut être contenue dans ce champ. - Long description requires at least 30 characters. - Une descption longue require au moins 30 caractères. + Une descption longue requiert au moins 30 caractères. BugReportHistoryWindow - - Title - Titre + Titre - - Reported at - Reporté à + Rapport envoyé à - - URL - URL + URL - Reports history - Historique de rapports + Historique de rapports - Clear reports history - Vider l’historique de rapports + Vider l’historique des rapports - Delete selected entry - Supprimer l’entrée sélectionnée + Supprimer l’entrée sélectionnée - Invalid response from server. - Réponse invalide du serveur. + Réponse invalide du serveur. BugReportLoginDialog - Log in - Connexion + Connexion - Credentials - Certifications + Identités - Login: - Identification : + Identification : - Password: - Mot de passe : + Mot de passe : - Validation - Validation + Validation - Validate - Valider + Valider - Validation result message - Message de validation + Message de validation - Abort - Abandonner + Abandonner - A login must be at least 2 characters long. - Un identifiant dois avoir au moins 2 caractères. + Un identifiant doit avoir au moins 2 caractères. - A password must be at least 5 characters long. - Un mot de passe doit avoir au moins 5 caractères. + Un mot de passe doit avoir au moins 5 caractères. - Valid - Valide + Valide @@ -355,15 +319,15 @@ Filter collations - Filtre de regroupements + Filtre de collation - + Collation name: - Nom de regroupements : + Nom de collation : - + Implementation language: Language d’implémentation : @@ -375,7 +339,7 @@ Register in all databases - Inscrire daans toutes les bases de données + Inscrire dans toutes les bases de données @@ -385,61 +349,57 @@ Implementation code: - Code d’inplémentation : + Code d’implémentation : Collations editor - Éditeur de regroupement + Éditeur de collation Commit all collation changes - Enregistrer les motifications de regroupement + Enregistrer les motifications de collation Rollback all collation changes - Annuler toutes les modifications de regroupement + Annuler toutes les modifications de collation Create new collation - Création de regroupement + Création de collation Delete selected collation - Supprimer le regroupement sélectionné + Supprimer la collation sélectionnée Editing collations manual - Modification manuelle de regroupement + Manuel pour l'édition de collations Enter a non-empty, unique name of the collation. - Saississez un nom unique, non vide, de regroupement. + Saisissez un nom unique, non vide, de regroupement. Pick the implementation language. - Prendre le language d’inplémentation. + Choisir le language d’implémentation. Enter a non-empty implementation code. - Saississez un nom, non vide, de language d’implémentation. + Saisissez un nom, non vide, de language d’implémentation. Collations editor window has uncommitted modifications. - - - - Collations editor window has uncommited modifications. - L’éditeur de regroupement n’as pas enregistré les modifications. + L’éditeur de collations a des modifications non enregistrées. @@ -447,7 +407,7 @@ Pick a color - Coisir une couleur + Choisir une couleur @@ -455,12 +415,12 @@ Collation name: - Nom de la jointure : + Nom de la collation : Named constraint: - Constante nommée : + Contrainte nommée : @@ -470,7 +430,7 @@ Enter a collation name. - Saisir le nom de la jointure. + Saisir le nom de la collation. @@ -488,17 +448,26 @@ Enter a default value expression. - Saississez l’expression d’une valeur par défaut. + Saisissez l’expression d’une valeur par défaut. + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. + + + Invalid default value expression: %1 - Invalide expression d’une valeur par défaut : %1 + Expression invalide pour une valeur par défaut : %1 - + Enter a name of the constraint. - Saississez un nom de contrainte. + Saisir un nom de contrainte. @@ -567,7 +536,7 @@ Collate - Jointure + Collation @@ -577,7 +546,7 @@ Check condition - Vérifiez la contition + Vérifier la condition @@ -608,7 +577,7 @@ - + Delete constraint column dialog Supprimer la contrainte @@ -641,13 +610,13 @@ Add an unique constraint column dialog - Ajouter une contrainte unique + Ajouter une contrainte d'unicité Add a check constraint column dialog - Ajouter un contrôle de la contrainte + Ajouter une contrainte de contrôle @@ -668,35 +637,45 @@ Ajouter une contrainte par défaut - + Are you sure you want to delete constraint '%1'? column dialog Êtes-vous sûr de vouloir supprimer la contrainte « %1 » ? - + Correct the constraint's configuration. Corrigez la configuration de la contrainte. - + This constraint is not officially supported by SQLite 2, but it's okay to use it. Cette contrainte n’est pas supportée officiellement par SQLite 2, mais c’est OK pour l’utiliser. - + Scale is not allowed for INTEGER PRIMARY KEY columns. - + Precision cannot be defined without the scale. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. @@ -719,7 +698,7 @@ mais c’est OK pour l’utiliser. Details column dialog constraints - Details + Détails @@ -757,17 +736,17 @@ mais c’est OK pour l’utiliser. Pick the foreign table. - Sélectionner une table étrangère. + Sélectionner la table étrangère. Pick the foreign column. - Séléctionner une colonne étrangère. + Sélectionner la colonne étrangère. Enter a name of the constraint. - Saississez un nom de contraite. + Saisir un nom de contraite. @@ -790,18 +769,17 @@ mais c’est OK pour l’utiliser. On conflict: - Sur conflit : + En cas de conflit : Enter a name of the constraint. - Saississez le nom d’une contrainte. + Saisissez le nom d’une contrainte. - Autoincrement (only for %1 type columns) column primary key - Auto-incrémentation (seulement pour %1 colonne type) + Auto-incrémentation (seulement pour %1 colonne type) @@ -814,12 +792,12 @@ mais c’est OK pour l’utiliser. On conflict: - Sur conflit : + En cas de conflit : Enter a name of the constraint. - Saississez un nom de contrainte. + Saisissez un nom de contrainte. @@ -852,7 +830,7 @@ mais c’est OK pour l’utiliser. View: %1 completer statusbar - Vue %1 + Vue : %1 @@ -894,13 +872,13 @@ mais c’est OK pour l’utiliser. Binary data completer statusbar - Données binaire + Données binaires Collation: %1 completer statusbar - Regroupement : %1 + Collation : %1 @@ -913,7 +891,7 @@ mais c’est OK pour l’utiliser. ConfigDialog - + Configuration Configuration @@ -935,7 +913,7 @@ mais c’est OK pour l’utiliser. Look & feel - Aspet + Apparence @@ -960,17 +938,17 @@ mais c’est OK pour l’utiliser. Code formatters - Formatage code + Formateurs de code Data browsing - Navigation données + Navigation de données Data editors - Éditeur de données + Éditeurs de données @@ -978,201 +956,193 @@ mais c’est OK pour l’utiliser. Navigateur et éditeur de données - + Number of data rows per page: Nombre de lignes de données par page : - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> <p>Lorsque les données sont lues dans le tableau, la largeur est automatiquement ajustée. Cette valeur limite la largeur initiale pour l’ajustement, mais l’utilisateur peut recadrer les colonnes manuellement au-dessus de cette limite.</p> - + Limit initial data column width to (in pixels): Limite initiale de la largeur de la colonne de données (en pixel) : - + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> - + Use DEFAULT value (if defined), when committing NULL value - + Inserting new row in data grid - + Insertion d'une nouvelle ligne dans la grille de données - + Before currently selected row - + Avant la ligne courante - + After currently selected row - + Après la ligne courante - + At the end of data view - + À la fin de la vue de données - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> - + Place data tab as first tab in a Table Window - + Placer l'onglet Données en premier dans les fenêtres de tables - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> - + Data types Types de données - + Available editors: Éditeurs disponibles : - + Editors selected for this data type: Éditeur sélectionné pour ce type de données : - + Schema editing Edition de schéma - + Number of DDL changes kept in history. Nombre de DDL modifiés gardés dans l’historique. - + DDL history size: Dimension de l’historique DDL : - Don't show DDL preview dialog when commiting schema changes - Ne pas montrer la présualisation DDL pendant l’enregistrement du schéma modifié - - - + SQL queries Requêtes SQL - - + + Number of queries kept in the history. Nombre de requêtes gardées dans l’historique. - + History size: Dimension de l’historique : - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> <p>S’il y a plus d’une requête dans l’éditeur SQL, alors (si cette option est permise) seulement une seule requête sera exécutée -cellesous le curseur d’insertion. Autrement toutes les requêtes seront exécutées. Vous pouvez limiter le nombre de requêtes devant être exécutées en sélectionnant ces requêtes avant leur exécution.</p> - + Execute only the query under the cursor Exécuter seulement la requête sous le curseur - + Updates Mises à jour - + Automatically check for updates at startup Contrôle automatique des mises à jour au lancement - + Session Session - + Restore last session (active MDI windows) after startup Restaurer la dernière session (Fenêtre MDI active) après lancement - + Filter shortcuts by name or key combination Filtre par nom raccourci ou combinaison de touches - + Action Action - + Key combination Combinaison de touches - - + + Language Langage - + Changing language requires application restart to take effect. - Le changement de langage requiére le redemarrage de l’application pour prendre effet. + Le changement de langage requiert le redémarrage de l’application pour prendre effet. - + Compact layout Présentation compacte - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> - + Use compact layout Utiliser la présentation compacte - - General.CompactLayout - Général.PrésentationCompacte - @@ -1192,7 +1162,7 @@ mais c’est OK pour l’utiliser. Expand tables node when connected to a database - Déployez le noeud des tables lors de la connexion de la base de données + Développer le nœud des tables lors de la connexion de la base de données @@ -1202,7 +1172,7 @@ mais c’est OK pour l’utiliser. Display additional labels on the list - Afficher des labels supplémentaires à la liste + Afficher des labels supplémentaires dans la liste @@ -1227,12 +1197,12 @@ mais c’est OK pour l’utiliser. Expand views node when connected to a database - Etendre le noeud des vues lorsque la base de données est connectée + Développer le nœud des vues lorsque la base de données est connectée If this option is switched off, then objects will be sorted in order they appear in sqlite_master table (which is in order they were created) - Si cette option est déactivée, les objets seront triés pour qu’ ils apparaissent dans la table sqlite_master (dans l’ordre de création) + Si cette option est désactivée, les objets seront triés pour qu’ ils apparaissent dans la table sqlite_master (dans l’ordre de création) @@ -1270,395 +1240,397 @@ mais c’est OK pour l’utiliser. - + Keep NULL value when entering empty value - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> - - Show column and row details tooltip in data view + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> - - Table windows - Fenêtre de ta table + + Number of memorized table populating configurations + + + + + Show column and row details tooltip in data view + - When enabled, Table Windows will show up with the data tab, instead of the structure tab. - Lorsque c’est permis, la fenêtre des tables sera affichée avec l’onglet des données, à la place de l’onglet structure. + + Table windows + Fenêtres de tables - + Open Table Windows with the data tab for start - Ourerture la fenêtre de table avec l’onglet des données au départ + Sélectionner l'onglet de données lors de l'ouverture d'une fenêtre de table - + View windows Fenêtre de vue - When enabled, View Windows will show up with the data tab, instead of the structure tab. - Lorsque c’est permis, la fenêtre des vues sera affichée avec l’onglet des données, à la place de l’onglet structure. - - - + Open View Windows with the data tab for start - Ourerture la fenêtre de vue avec l’onglet des données au départ + Sélectionner l'onglet de données lors de l'ouverture d'une fenêtre de vue - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> - + Place data tab as first tab in a View Window - + Don't show DDL preview dialog when committing schema changes - + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + Number of memorized query parameters + + + + Status Field - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> - + Always open Status panel when new message is printed - + Main window dock areas - + Left and right areas occupy corners - + Top and bottom areas occupy corners - + Hide built-in plugins Cacher des plugins incorporés - + Current style: Style actuel : - + Preview Aperçu - + Enabled En service - + Disabled Hors service - + Active formatter plugin Plugin de formattage actif - + SQL editor font Police de caractères de l’éditeur SQL - + Database list font Liste des polices de caractères de base de données - + Database list additional label font Police de caractères additionelle de la liste des bases de données - + Data view font Police de caractères des données de vue - + Status field font Police de caractères du champ d’état - + SQL editor colors Couleurs de l’éditeur SQL - + Current line background - Fond actuel de la ligne + Arrière plan pour la ligne courante - + <p>SQL strings are enclosed with single quote characters.</p> <p>Les chaines SQL sont encadrées avec de caractères simple quote.</p> - + String foreground Avant plan chaine - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> <p>Les paramètres fournis par l’utilisateur sont passés par valeur. Ils ont l’une de ces formes : </p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> - + Bind parameter foreground - Premier plan de paramètre de lien + Premier plan pour les paramètres de lien - + Highlighted parenthesis background Parenthèses surlignées - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> <p>les valeurs BLOB sont binaire représentés comme nombres hexadécimaux, comme : </p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground - Premier plan de valeur BLOB + Premier plan pour les valeurs BLOB - + Regular foreground - Avant plan courant + Avant plan par défaut - + Line numbers area background - Zone des numéros de ligne en arrière plan + Arrière plan pour la zone des numéros de ligne - + Keyword foreground - Mot-clef en avant plan + Premier plan pour les mots-cléfs - + Number foreground - Nombre en avant plan + Premier plan pour les nombres - + Comment foreground - Commentaire en avant plan + Premier plan pour les commentaires - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> <p>Les objets valides sont les nom de tables, index, déclencheurs, ou vues qui existent dans la base de données SQLite.</p> - + Valid objects foreground - Objets valides en avant plan + Premier plan pour les objets valides - + Data view colors Couleurs de vue de données - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> - + Uncommitted data outline color - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> - <p>Any data changes will be outlined with this color, until they're commited to the database.</p> - <p>Toutes les modifications de données seront écrits avec cette couleur, à l’enregistrement de la base de données.</p> - - - Uncommited data outline color - Annulation de la couleur des données - - - <p>In case of error while commiting data changes, the problematic cell will be outlined with this color.</p> - <p>En cas de l’erreur à l’enregistrement des modifications de données, la cellule problématique sera indiquée avec cette couleur.</p> - - - + Commit error outline color - Erreur d’enregistrement du surlignage + Surlignage pour les erreurs de commit - + NULL value foreground - Valeur NULL au premier plan + Premier plan pour la valeur NULL - + Deleted row background - Ligne supprimée en arrier plan + Arrière-plan pour une ligne supprimée - + Database list colors - Liste de couleurs des bases de données + Couleurs pour la liste des bases de données - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> <p>Des labels supplémentaires indique la version SQLITE, le nombre d’objets au nievau inférieur, etc.</p> - + Additional labels foreground - Labels additionels en avant plan + Premier plan pour les labels additionnels - + Status field colors Couleurs du champ d’état - + Information message foreground - Message d’information devant + Premier plan pour les messages d’information - + Warning message foreground - Warning devant + Premier plan pour les avertissements - + Error message foreground - Message d’erreur devant + Premier plan pour les erreurs - + Description: plugin details Description : - + Category: plugin details - Catégories : + Catégorie : - + Version: plugin details Version : - + Author: plugin details Auteur : - + Internal name: plugin details Nom interne : - + Dependencies: plugin details Dépendances : - + Conflicts: plugin details - Conflicts : + Conflits : - + Plugin details - Détails plugins + Détails du plugin - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. Les plugins sont chargés/déchargés immédiatement avec vérifié/non vérifié, mais les modifications de la liste de plugins à charger au lancement ne sont pas enregistrées avant l’enregistrement de la configuration entière. - + %1 (built-in) plugins manager in configuration dialog %1 (intégré) - + Details Détails - + No plugins in this category. Pas de plugins dans cette catégorie. - + Add new data type Ajouter un nouveau type de données - + Rename selected data type Renommer le type de données sélectionné - + Delete selected data type - Supprimez le type de données sélectionnées + Supprimer le type de données sélectionnées - + Help for configuring data type editors Aide à la configuration des éditeurs de type de données @@ -1810,137 +1782,153 @@ mais c’est OK pour l’utiliser. DataView - + Filter data data view Filtre de données - + Grid view Table - + Form view Formulaire - + Refresh table data data view Actualiser les données de la table - + First page data view Première page - + Previous page data view Page précédente - + Next page data view Page suivante - + Last page data view Dernière page - + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + Apply filter data view Appliquer le filtre - + Commit changes for selected cells data view Enregistrer les modifications des cellules sélectionnées - + Rollback changes for selected cells data view Annuler les modifications des celulles sélectionnées - + Show grid view of results sql editor Affichage des résultats en tableau - + Show form view of results sql editor Affichage des résultat en formulaire - + Filter by text data view Filtrer par texte - + Filter by the Regular Expression data view Filtrer par une expression standard - + Filter by SQL expression data view Filtrer par une expression SQL - + Tabs on top data view Onglets en haut - + Tabs at bottom data view Onglet en bas - + Place new rows above selected row data view - + Place new rows below selected row data view - + Place new rows at the end of the data view data view - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. Le total des lignes en cours de comptage. La navigation d’autres pages à la fin du comptage. - + Row: %1 Lignes : %1 @@ -2060,10 +2048,6 @@ Browsing other pages will be possible after the row counting is done. Database driver Pilote de base de données - - Generate automatically - Générer automatiquement - Options @@ -2079,14 +2063,6 @@ Browsing other pages will be possible after the row counting is done. Test connection Tester la connexion - - Name - Nom - - - Type - Type - Browse for database file on local computer Navigation de la base de données en local @@ -2107,24 +2083,12 @@ Browsing other pages will be possible after the row counting is done. Name (on the list) Nom (dans la liste) - - Generate name basing on file path - Génération du nom basé sur le chemin du fichier - - - Permanent - Permanent - <p>Enable this if you want the database to be stored in configuration file and restored every time SQLiteStudio is started.</p> aasfd <p>Autorisez-ceci si vous voulez que la base de données soit stockée dans le fichier de configuration et restauré chaque fois SQLiteStudio est lancé.</p> - - Test database connection - Test de connexion - Browse for existing database file on local computer @@ -2147,7 +2111,7 @@ Browsing other pages will be possible after the row counting is done. - <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> @@ -2165,14 +2129,6 @@ Browsing other pages will be possible after the row counting is done. Select a database type. - - The name will be auto-generated - Le non sera généré automatiquement - - - Type the name - Saississez le nom - DbObjectDialogs @@ -2257,373 +2213,490 @@ Browsing other pages will be possible after the row counting is done. Filtre par nom - + Copy Copier - + Paste Coller - + Select all Tout sélectionner - + Create a group Créer un groupe - + Delete the group Supprimer le groupe - + Rename the group Renommer le groupe - Add a database - Attacher une base de données + Attacher une base de données - Edit the database - Modifier la base de données + Modifier la base de données - Remove the database - Déatcher la base de données + Déatcher la base de données - Connect to the database - Connecter une base de données + Connecter une base de données - Disconnect from the database - Déconnecter la base de données + Déconnecter la base de données - + Import Importer - Export the database - Exporter la base de données + Exporter la base de données - Convert database type - Type de base de données à convertir + Convertir le format de base de données - Vacuum - Vaccum + Vaccum - Integrity check - Contrôle d’intégrité + Contrôler l’intégrité - Create a table - Créer une table + Créer une table - Edit the table - Modifier la table + Modifier la table - Delete the table - Supprimer la table + Supprimer la table - + Export the table Exporter la table - + Import into the table Importer dans la table - + Populate table Peupler une table - + Create similar table Créer une table identique - + Reset autoincrement sequence Réinitialise l’auto-incrémentation - Create an index - Créer un index + Créer un index - Edit the index - Modifier l’index + Modifier l’index - Delete the index - Supprimer l’index + Supprimer l’index - Create a trigger - Créer un déclencheur + Créer un déclencheur - Edit the trigger - Modifier le déclencheur + Modifier le déclencheur - Delete the trigger - Supprimer le déclencheur + Supprimer le déclencheur - Create a view - Créer une vue + Créer une vue - Edit the view - Modier la vue + Modier la vue - Delete the view - Supprimer la vue + Supprimer la vue - + Add a column Ajouter une colonne - + Edit the column Modifier la colonne - + Delete the column Supprimer la colonne - + Delete selected items Supprimer les objets sélectionnés - + Clear filter Vider le filtre - Refresh all database schemas - Actualiser tous les schémas de la base de données + Actualiser tous les schémas de base de données - Refresh selected database schema - Actualiser les schémas sélectionné de la base de données + Actualiser le schéma de base de données sélectionné - - + + Erase table data - - + + Database Base de données - + Grouping Groupement - + Generate query for table - - + + Create group Créer un groupe - + Group name Nom du groupe - + Entry with name %1 already exists in group %2. L’entrée nommée %1 existe déjà dans le groupe %2. - + Delete group Supprimer le groupe - + Are you sure you want to delete group %1? All objects from this group will be moved to parent group. Êtes-vous certain de supprimer le groupe %1 ? Tous les objets de ce groupe seront déplacés dans le groupe parent. - + Are you sure you want to remove database '%1' from the list? - + Are you sure you want to remove following databases from the list: %1 - + Remove database - + Vacuum (%1) - + Autoincrement value for table '%1' has been reset successfully. - + Are you sure you want to delete all data from table(s): %1? - Delete database - Suppression de la base de données + + + Cannot import, because no import plugin is loaded. + Import impossible, car aucun plugin d’import n’est chargé. - Are you sure you want to delete database '%1'? - Êtes-vous certain de vouloir supprimer la base de données : « %1 » ? + + Execution from file cancelled. Any queries executed so far have been rolled back. + - - - Cannot import, because no import plugin is loaded. - Import impossible, car aucun plugin d’import n’est chargé. + + &Add a database + - - - Cannot export, because no export plugin is loaded. - Export impossible, car aucun plugin d’import n’est chargé. + + &Edit the database + + + + + &Remove the database + + + + + &Connect to the database + + + + + &Disconnect from the database + + + + + &Export the database + + + + + Con&vert database type + + + + + Vac&uum + + + + + &Integrity check + + + + + Create a &table + + + + + Edit the t&able + + + + + Delete the ta&ble + + + + + Create an &index + + + + + Edit the i&ndex + + + + + Delete the in&dex + + + + + Create a trig&ger + + + + + Edit the trigg&er + + + + + Delete the trigge&r + + + + + Create a &view + + + + + Edit the v&iew + - Error while executing VACUUM on the database %1: %2 - Erreur pendant l’exécution de VACCUM sur la base de données %1 : %2 + + Delete the vi&ew + + + + + &Refresh all database schemas + + + + + Re&fresh selected database schema + + + + + Open file's directory + + + + + Execute SQL from file + - VACUUM execution finished successfully. - Exécution de VACCUM terminé avec succès. + + + Cannot export, because no export plugin is loaded. + Export impossible, car aucun plugin d’import n’est chargé. - + Integrity check (%1) Contrôle d’intégrité (%1) - + Reset autoincrement Remise à zéro de l’auto-incrément - + Are you sure you want to reset autoincrement value for table '%1'? Êtes-vous certain de vouloir réinitialiser l’auto-incrémentation de la table « %1 » ? - + An error occurred while trying to reset autoincrement value for table '%1': %2 Une erreur est survenue pendant la réinitialisation de la valeur de l’auto-incrémentation de la table « %1 » : %2 - Autoincrement value for table '%1' has been reset successfly. - La valeur de l’auto-incrémentation de la table %1 a été réinitialisé avec succès. - - - + An error occurred while trying to delete data from table '%1': %2 - + All data has been deleted for table '%1'. - + Following objects will be deleted: %1. Les objets suivant vont être supprimés : %1. - + Following databases will be removed from list: %1. Les bases de données suivantes seront enlevées de la liste : %1. - + Remainig objects from deleted group will be moved in place where the group used to be. Les objets restants du groupe supprimé seront déplacés où le groupe a eu l’habitude d’être. - + %1<br><br>Are you sure you want to continue? %1<br><br>Êtes-vous certain de vouloir continuer ? - + Delete objects Objets supprimés + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + Impossible d’ouvrir en lecture le fichier « %1 » : %2 + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. + + DbTreeItemDelegate @@ -2678,11 +2751,6 @@ Tous les objets de ce groupe seront déplacés dans le groupe parent.dbtree tooltip Codage : - - Error details: - dbtree tooltip - Détails de l’erreur : - Error: @@ -2714,76 +2782,76 @@ Tous les objets de ce groupe seront déplacés dans le groupe parent.Déclencheurs (%1) : - + Copy Copier - + Move Déplacer - + Include data Données incluses - + Include indexes Index inclus - + Include triggers Déclencheurs inclus - + Abort Abandonner - + Could not add dropped database file '%1' automatically. Manual setup is necessary. - + Referenced tables Tables référencées - + Do you want to include following referenced tables as well: %1 Vous voulez inclure des tables référencées suivantes aussi : %1 - + Name conflict Conflit de nom - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: L’objet suivant existe déjà dans la base de données cible. Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’opération : - + SQL statements conversion Conversion des déclarations SQL - + Following error occurred while converting SQL statements to the target SQLite version: L’erreur suivante est survenue en convertissant des déclarations de SQL de la version cible SQLite : - + Would you like to ignore those errors and proceed? Voulez-vous ignorer ces erreurs et procéder ? @@ -2839,137 +2907,139 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Requête - + History Historique - + Results in the separate tab Résultats dans un onglet séparé - + Results below the query Résultats après la requête - - + + SQL editor %1 Éditeur SQL %1 - + Results Résultats - + Execute query Exécuter la requête - + Explain query Explication de la requête - + Clear execution history sql editor Vider l’historique d’exécution - + Export results sql editor Exporter résultats - + Create view from query sql editor Créer une vue à partir d’une requête - + Previous database Base de données précédente - + Next database Base de données suivante - + Show next tab sql editor Afficher l’onglet suivant - + Show previous tab sql editor Afficher l’onget précédent - + Focus results below sql editor - + Focus SQL editor above sql editor Focus sur l’éditeur SQL ci-dessus - + + Delete selected SQL history entries + sql editor + + + + Active database (%1/%2) Base de données active (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 Requête terminée en %1 secondes. Nombre de lignes : %2 - + Query finished in %1 second(s). Requête terminée en %1 seconde(s). - + Clear execution history Supprimer l’historique d’exécution - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. Êtes vous certain de vouloir supprimer la totalité de l’historique d’exécution SQL ? Aucun retour possible. - + Cannot export, because no export plugin is loaded. Impossible d’exporter, car aucun plugin d’expertation n’est chargés. - + No database selected in the SQL editor. Cannot create a view for unknown database. Aucune base de données den sélectionnée dans l’éditeur SQL. Impossible de créer une vue sur une base de données inconnue. - + Editor window "%1" has uncommitted data. - - Editor window "%1" has uncommited data. - Fenêtre d’éditeur "%1" n’a pas enregistrer les données. - ErrorsConfirmDialog @@ -2989,6 +3059,64 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Désirez-vous traiter ? + + ExecFromFileDialog + + + Execute SQL from file + + + + + Input file + + + + + Path to file + + + + + Browse for file + + + + + Options + Options + + + + File encoding + + + + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + Scripts SQL (*.sql);;Tous les fichiers (*) + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + ExportDialog @@ -3138,68 +3266,101 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Exporter options de format - + Cancel Annuler - - - + + + Select database to export. Sélecctionnez la base de données à exporter. - + Select table to export. Sélectionnez la table à exporter. - + Enter valid query to export. Saississez une requête valide à exporter. - + Select at least one object to export. Sélectionnez au moins un objet à exporter. - + You must provide a file name to export to. Vous devez fournir le nom d’un fichier à exporter. - + Path you provided is an existing directory. You cannot overwrite it. Le chemin fourni est un répertoire existant. Vous ne pouvez pas l’écraser. - + The directory '%1' does not exist. Le répertoire « %1 » n’existe pas. - + The file '%1' exists and will be overwritten. Le fichier « %1 » existe et sera écrasé. - + All files (*) Tous les fichiers(*) - + Pick file to export to Sélectionnez un fichier à exporter - + Internal error during export. This is a bug. Please report it. Erreur interne pendant l’exportation. c’est un bug. SVP veuillez le reporter. + + FileExecErrorsDialog + + + Execution errors + + + + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + Erreur + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + FontEdit @@ -3220,49 +3381,49 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ FormView - + Commit row form view Enregistrer ligne - + Rollback row form view Annuler ligne - + First row form view Première ligne - + Previous row form view Ligne précédente - + Next row form view Ligne suivante - + Last row form view Dernière ligne - + Insert new row form view Insérer une nouvelle ligne - + Delete current row form view Supprimer la ligne courante @@ -3321,13 +3482,13 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Code d’initialisation : - + Function implementation code: Fonction de code d’implémentation : - + Final step implementation code: Etape finale de code d’implémentaion : @@ -3427,10 +3588,6 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Functions editor window has uncommitted modifications. - - Functions editor window has uncommited modifications. - L’éditeur de fonction n’a pas enregistré les modifications. - ImportDialog @@ -3495,42 +3652,42 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Optrions de source de données - + Cancel Annuler - + If you type table name that doesn't exist, it will be created. Si vous saississez un nom de table inexistant, celle-ci sera créée. - + Enter the table name Saississez un nom de table - + Select import plugin. Sélectionnez un plugin d’importation. - + You must provide a file to import from. Vous devez fournir un fichier à importer. - + The file '%1' does not exist. Le fichier « %1 » n’existe pas. - + Path you provided is a directory. A regular file is required. Le chemin indiqué est un répertoire. Un fichier est requis. - + Pick file to import from Sélectionnez le fichier d’importation @@ -3569,12 +3726,12 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Colonne - + Collation Regroupement - + Sort Tri @@ -3754,283 +3911,412 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Barre d’outils de fenêtrage - + Configuration widgets Configuration widgets - + Syntax highlighting engines Syntaxe surlignée des moteurs - + Data editors Éditeurs de données - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. Passage en mode débogue. Cliquez %1 ou utilisez l’entrée du menu « l’Aide / Ouvrir la console de débogage ». - + Running in debug mode. Debug messages are printed to the standard output. Passage en mode débogue. Les messages de débogage sont imprimés dans la sortie standard. - + You need to restart application to make the language change take effect. Vous devez relancer l’application pour que le langage prenne effet. - Open SQL editor - Ouvrir l’éditeur SQL + Ouvrir l’éditeur SQL - Open DDL history - Ouvrir l’historique DDL + Ouvrir l’historique DDL - Open SQL functions editor - Éditeur de fonctions SQL + Éditeur de fonctions SQL - Open collations editor - Ouvrir l’éditeur de collections + Ouvrir l’éditeur de collections - Import - Importer + Importer - Export - Exporter + Exporter - Open configuration dialog - Préférences + Préférences - Tile windows - Organisation des fenêtres en grille + Organisation des fenêtres en grille - Tile windows horizontally - Organisation horizontale des fenêtres + Organisation horizontale des fenêtres - Tile windows vertically - Organisation verticale des fenêtres + Organisation verticale des fenêtres - Cascade windows - Organisation des fenêtres en cascade + Organisation des fenêtres en cascade - + Next window Fenêtre suivante - + Previous window Fenêtre précédante - + Hide status field Cacher le champ d’état - Close selected window - Fermer la fenêtre sélectionnée + Fermer la fenêtre sélectionnée - Close all windows but selected - Fermer toutes les fenêtres sélectionnées + Fermer toutes les fenêtres sélectionnées - Close all windows - Fermer toutes les fenêtres + Fermer toutes les fenêtres - Restore recently closed window - Restaurer la dernière fenêtre fermée + Restaurer la dernière fenêtre fermée - Rename selected window - Renommer la fenêtre sélectionnée + Renommer la fenêtre sélectionnée - + Open Debug Console Ouvrir la console de debogage - + Open CSS Console Ouvrir la console CSS - Report a bug - Rapporter un bogue + Rapporter un bogue - Propose a new feature - Proposer une fonctionnalité + Proposer une fonctionnalité - About - À propos de… + À propos de… - Licenses - Licences + Licences - Open home page - Page d’accueil web + Site web de l’application - Open forum page - Forum d’aide + Forum d’aide - User Manual - Manuel utilisateurs en ligne + Manuel utilisateur en ligne - SQLite documentation - Documentation en ligne de SQLite + Documentation en ligne de SQLite - Report history - Historique + Historique - Check for updates - Vérifier les mises à jour + Vérifier les mises à jour - Database menubar - Base de données + Base de données - Structure menubar - Structure + Structure - View menubar - Vue + Vue - + Window list menubar view menu Liste des fenêtres - Tools menubar - Outils + Outils - Help - Aide + Aide + + + + Open SQL &editor + + + + + Open DDL &history + + + + + Open SQL &functions editor + + + + + Open &collations editor + + + + + Open ex&tension manager + + + + + &Import + + + + + E&xport + + + + + Open confi&guration dialog + + + + + &Tile windows + + + + + Tile windows &horizontally + + + + + Tile windows &vertically + + + + + &Cascade windows + + + + + Close selected &window + + + + + Close all windows &but selected + + + + + Close &all windows + + + + + Re&store recently closed window + + + + + &Rename selected window + - + + Report a &bug + + + + + Propose a new &feature + + + + + &About + + + + + &Licenses + + + + + Open home &page + + + + + Open fo&rum page + + + + + User &Manual + + + + + SQLite &documentation + + + + + Bugs and feature &requests + + + + + Check for &updates + + + + + &Database + menubar + + + + + &Structure + menubar + + + + + &View + menubar + + + + + &Tools + menubar + + + + + &Help + + + + Could not set style: %1 main window Impossible de positionner le style : %1 - + Cannot export, because no export plugin is loaded. Exportation impossible, aucun plugin d’exportation n’est chargé. - + Cannot import, because no import plugin is loaded. Importation impossible, aucun plugin d’importation n’est chargé. - + Rename window Renommer la fenêtre - + Enter new name for the window: Saississez un nouveau nom de fenêtre : - + New updates are available. <a href="%1">Click here for details</a>. Une nouvelle mise à jour est disponible. <a href="%1"> cliquez ici pour détails</a>. - + You're running the most recent version. No updates are available. Vous utilisez la dernière version. Aucune mise à jour de disponible. - + Database passed in command line parameters (%1) was already on the list under name: %2 - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 La base de données passée en paramètre dans la ligne de commande (%1)a été temporaire ajoutée à la liste sous le nom : %2 - + Could not add database %1 to list. Impossible d’ajouter la base de données %1 à la liste. MdiWindow - - Uncommited changes - Modification non enregistrées - Uncommitted changes @@ -4056,23 +4342,28 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Valeur NULL - + Configure editors for this data type Configurer l’éditeur pour ce type de données - + + Open another tab + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. Plugin d"éditeur de données « %1 » non chargé, ausii il n’ai pas défini pour le type de données « %1 ». - + Deleted multieditor Suppression - + Read only multieditor Lecture seule @@ -4081,93 +4372,143 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ MultiEditorBool - Boolean - booleen + booleen + + + + MultiEditorBoolPlugin + + + Boolean + booleen MultiEditorDate - Date - Date + Date + + + + MultiEditorDatePlugin + + + Date + Date MultiEditorDateTime - Date & time - date & heure + date & heure + + + + MultiEditorDateTimePlugin + + + Date & time + date & heure MultiEditorHex - Hex - Hex + Hex + + + + MultiEditorHexPlugin + + + Hex + Hex MultiEditorNumeric - Number numeric multi editor tab name - Nombre + Nombre + + + + MultiEditorNumericPlugin + + + Number + numeric multi editor tab name + Nombre MultiEditorText - Text - Texte + Texte - + Tab changes focus Tab modifie le focus - + Cut Couper - + Copy Copier - + Paste Coller - + Delete Supprimer - + Undo Annuler - + Redo Rétablir + + MultiEditorTextPlugin + + + Text + Texte + + MultiEditorTime - Time - Heure + Heure + + + + MultiEditorTimePlugin + + + Time + Heure @@ -4242,37 +4583,40 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Composant - + + This application will be closed and the update installer will start to download and install all the updates. + + + Current version - Version courante + Version courante - + Update version Version de mise à jour - + Check for updates on startup Contrôle de nouvelles version au lancement - + Update to new version! Mettre à jour la nouvelle version ! - The update will be automatically downloaded and installed. This will also restart application at the end. - La mise à jour sera automatiquement téléchargée et installée. Un redémarrage de l’application sera aussi effectué à la fin. + La mise à jour sera automatiquement téléchargée et installée. Un redémarrage de l’application sera aussi effectué à la fin. - + Not now. Paas maintenant. - + Don't install the update and close this window. Ne pas installer la mise à jour maintenant et fermer cette fenêtre. @@ -4324,32 +4668,32 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Peupler - + Abort Abandonner - + Configure Configurer - + Populating configuration for this column is invalid or incomplete. La configuration du peuplement pour cette colonne est invalide ou incomplète. - + Select database with table to populate Sélectionner la base de données avec la table à peupler - + Select table to populate Sélectionner la table à peupler - + You have to select at least one column. Vous devez sélectionner au moins une colonne. @@ -4424,129 +4768,134 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Nom de collation : %1 - + Data grid view Vue de tableau de données - + Copy cell(s) contents to clipboard Copie le contenu de cellule(s) dans le presse-papier + Copy cell(s) contents together with header to clipboard + + + + Paste cell(s) contents from clipboard Colle - + Set empty value to selected cell(s) Efface le contenu de cellule(s) - + Set NULL value to selected cell(s) Met à NULL les cellules séléctionnées - + Commit changes to cell(s) contents Enregistre les modifications de cellule(s) - + Rollback changes to cell(s) contents Annule les modifications de cellule(s) - + Delete selected data row Supprime les données de la ligne sélectionnée - + Insert new data row Insére une nouvelle ligne de données - + Open contents of selected cell in a separate editor Contenu ouvert de cellule choisie dans un éditeur séparé - + Total pages available: %1 Nombre de pages disponibles : %1 - + Total rows loaded: %1 Nombre de lignes chargées : %1 - + Data view (both grid and form) Vue des données (tableau et formulaire) - + Refresh data Actualisation des données - + Switch to grid view of the data Basculer sur la vue des données en table - + Switch to form view of the data Basculer sur la vue des données en formulaire - + Database list Liste de bases de données - + Delete selected item Suppression de l’item sélectionné - + Clear filter contents Effacer le contenu du filtre - + Refresh schema Actualiser le schéma - + Refresh all schemas Actualiser tous les schémas - + Add database Ajouter une base de données - + Select all items Séléctionner tous les éléments - + Copy selected item(s) Copie d’item(s) sélectionné(s) - + - + Paste from clipboard Collé dans le presse-papier @@ -4621,42 +4970,42 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Supprimer la ligne courante - + Main window Fenêtre principale - + Open SQL editor Ouvrir l’éditeur SQL - + Previous window Fenêtre précédente - + Next window Fenêtre suivante - + Hide status area Cacher la barre d’état - + Open configuration dialog Préférences - + Open Debug Console Ouvrir la console de débogage - + Open CSS Console Ouvrir la console CSS @@ -4667,111 +5016,111 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ - + Cut selected text Couper le texte sélectionné - + Copy selected text Copie du texte sélectionné - + Delete selected text Suppression du texte sélectionné - + Undo Annuler - + Redo Rétablir - + SQL editor input field Éditeur SQL saisie de champ - + Select whole editor contents Sélectionnez le contenu entier de l’éditeur - + Save contents into a file Sauver le contenu dans un fichier - + Load contents from a file Charger le contenu d’un fichier - + Find in text Rechercher un texte - + Find next Occurence suivante - + Find previous Occurence précédente - + Replace in text Remplacer dans le texte - + Delete current line Supprimer la ligne courante - + Request code assistant Assistant de code nécessaire - + Format contents Format de contenu - + Move selected block of text one line down Déplacer le bloc de texte sélectionné à la ligne inférieure - + Move selected block of text one line up Déplacer le bloc de texte sélectionné à la ligne supérieure - + Copy selected block of text and paste it a line below Copier le bloc de texte sélectionné à la ligne au-dessus - + Copy selected block of text and paste it a line above Copier le bloc de texte sélectionné à la ligne au-dessous - + Toggle comment @@ -4792,14 +5141,12 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Fichier base de données - Reports history window - Fenêtre d’historique + Fenêtre d’historique - Delete selected entry - Effacer l’entrée sélectionnée + Effacer l’entrée sélectionnée @@ -4846,6 +5193,11 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ Move keyboard input focus to the SQL editor above Déplacement au-dessous du focus des résultats de vue par les touches + + + Delete selected SQL history entries + + Table window @@ -4964,10 +5316,6 @@ Entrez SVP un nouveau nom, unique, ou cliquez « %1 » pour d’interrompre l’ QuitConfirmDialog - - Uncommited changes - modifications non enregistrées - Uncommitted changes @@ -5069,179 +5417,179 @@ recherche suivant SqlEditor - + Cut sql editor Couper - + Copy sql editor Copier - + Paste sql editor Coller - + Delete sql editor Supprimer - + Select all sql editor Tout sélectionner - + Undo sql editor Annuler - + Redo sql editor Rétablir - + Complete sql editor Complet - + Format SQL sql editor Format SQL - + Save SQL to file sql editor Enregistrer le SQL - + Select file to save SQL sql editor - + Load SQL from file sql editor Charger le SQL - + Delete line sql editor Ligne suppimée - + Move block down sql editor Descendre le bloc - + Move block up sql editor Monter le bloc - + Copy block down sql editor Copier bloc au-dessus - + Copy up down sql editor Copier bloc au-dessous - + Find sql editor Chercher - + Find next sql editor Chercher suivant - + Find previous sql editor Chercher précédent - + Replace sql editor Remplacer - + Toggle comment sql editor - + Saved SQL contents to file: %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. L’achèvement de syntaxe peut être utilisé seulement quand une base de données valable est utilisée dans l’éditeur SQL. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. Le contenu l’éditeur SQL est important, aussi la détectiond’objets en erreur est temporairement mise hors de service. - + Save to file Sauvegarder - + Could not open file '%1' for writing: %2 Impossible d’ouvrir en écriture le fichier « %1 » : %2 - + SQL scripts (*.sql);;All files (*) Scripts SQL (*.sql);;Tous les fichiers (*) - + Open file Fichier ouvert - + Could not open file '%1' for reading: %2 Impossible d’ouvrir en lecture le fichier « %1 » : %2 - + Reached the end of document. Hit the find again to restart the search. Fin de document atteint. Saississez de nouveau la recherche pour relancer la recherche. @@ -5272,10 +5620,6 @@ recherche suivant data view tooltip Contrainte : - - This cell is not editable, because: %1 - Cette cellule n’est pas modifiable : %1 - Cannot load the data for a cell that refers to the already closed database. @@ -5284,10 +5628,6 @@ recherche suivant SqlQueryItemDelegate - - Cannot edit this cell. Details: %2 - Impossible de modifier cette cellule. Détails : %2 - The row is marked for deletion. @@ -5297,24 +5637,24 @@ recherche suivant - - + + Cannot edit this cell. Details: %1 Impossible de modifier cette cellule. Détails : %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. @@ -5322,81 +5662,74 @@ recherche suivant SqlQueryModel - - + + Only one query can be executed simultaneously. Uniquement une seule requête peut être exécutée à la fois. - Uncommited data - Données non enregistrées - - - + Cannot commit the data for a cell that refers to the already closed database. Impossible d’enregistrer les données pour la celle qui référe à une base de données déjà fermée. - + Could not begin transaction on the database. Details: %1 Impossible de lancer la transaction sur la base de données. Détails : %1 - An error occurred while commiting the transaction: %1 - Une erreur est survenuelors de l’enregistrement de la transaction : %1 - - - + An error occurred while rolling back the transaction: %1 Une erreur est survenuelors de l’annulation de la transaction : %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. Tentative d’enregistrement d’une une cellule qui n’est pas modifiable ! Ceci est un bogue. Rapportez-le SVP. - An error occurred while commiting the data: %1 - Une erreur est survenuelors de l’enregistrement des données : %1 - - - + Uncommitted data - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. - + An error occurred while committing the transaction: %1 - + An error occurred while committing the data: %1 - - + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + + + + + Error while executing SQL query on database '%1': %2 Erreur pendant l’exécution de la requête sur la base de données « %1 » : %2 - + Error while loading query results: %1 Erreur lors du chargement des résultats de la requête : %1 - + Insert multiple rows Insérer plusieurs lignes - + Number of rows to insert: Nombre de lignes à inserer : @@ -5404,127 +5737,143 @@ recherche suivant SqlQueryView - + Go to referenced row in... - + Copy Copier - + Copy as... Copier comme… - + Paste Coller - + Paste as... Coller comme… - + Set NULL values Valeurs NULL positionnées - + Erase values valeurs écrasées - + Edit value in editor Valeur modifiée par l’éditeur - + Commit Enregistrer - + + Copy with headers + + + + Rollback Annuler - + Commit selected cells Enregistrer les cellules sélectionnées - + Rollback selected cells Annuler les modifications des cellules sélectionnées - + Define columns to sort by Définit les colonnes triées par - + Remove custom sorting Enléve le tri personnalisé - + Insert row Insérer une ligne - + Insert multiple rows Insérer plusieurs lignes - + Delete selected row Supprimer les lignes sélectionnées - + + Show value in a viewer + + + + Generate query for selected cells - + No items selected to paste clipboard contents to. - + Go to referenced row in table '%1' - + table '%1' - + Referenced row (%1) - + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + Edit value Modifier la valeur SqlTableModel - - Error while commiting new row: %1 - Erreur à l’enregistrement d’une nouvelle ligne : %1 - Error while committing new row: %1 @@ -5536,6 +5885,119 @@ recherche suivant Erreur à la suppression d’une ligne de la table %1 : %2 + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + + + + + Register in all databases + + + + + Register in following databases: + + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + Tous les fichiers(*) + + + + Open file + Fichier ouvert + + StatusField @@ -5644,7 +6106,7 @@ but it's okay to use them anyway. Saisissez un nom de contrainte. - + Foreign column table constraints Colonne étrangère @@ -5698,24 +6160,24 @@ but it's okay to use them anyway. Sur conflit - + Collate table constraints Collationne - + Sort order table constraints Ordre de tri - + Select at least one column. Sélectionnez au moins une colonne. - + Enter a name of the constraint. Saisissez le nom de la contrainte. @@ -6090,14 +6552,6 @@ Do you want to commit the structure, or do you want to go back to the structure Table window "%1" has uncommitted structure modifications. - - Could not restore window, because database %1 could not be resolved. - Impossible de restaurer la fenêtre, car la base de données %1 ne peut ëtre résolue. - - - Could not restore window, because the table %1 doesn't exist in the database %2. - Impossible de restaurer la fenêtre, car la vue %1 n’existe pas dans la base de données %2.. - @@ -6125,10 +6579,6 @@ Do you want to commit the structure, or do you want to go back to the structure An error occurred while trying to reset autoincrement value for table '%1': %2 Une erreur est survenue pendant la réinitialisation de la valeur de l’auto-incrémentation de la table « %1 » : %2 - - Autoincrement value for table '%1' has been reset successfly. - La valeur de l’auto-incrémentaion de la table %1 a été réinitialisé avec succès. - Empty name @@ -6178,16 +6628,6 @@ Are you sure you want to create a table with blank name? Cannot import, because no import plugin is loaded. Import impossible, car aucun plugin d’import n’est chargé. - - Uncommited changes - Modification non enregistrées - - - There are uncommited structure modifications. You cannot browse or edit data until you have table structure settled. -Do you want to commit the structure, or do you want to go back to the structure tab? - Il ya des modifications de structure non enregistrées. Vous ne pouvez pas naviguer ou modifier des données jusqu’à ce que vous ailliez installer la structure de table. -Voulez-vous enregistrer la structure, ou voulez-vous retourner à l’onglet de structure ? - Go back to structure tab @@ -6246,18 +6686,6 @@ Voulez-vous enregistrer la structure, ou voulez-vous retourner à l’onglet de table window triggers Details - - Table window "%1" has uncommited structure modifications and data. - La fenêtre de table "%1" n’a pas enregistré les modifications de structure et de données. - - - Table window "%1" has uncommited data. - La fenêtre de table "%1" n’a pas enregistrer les données. - - - Table window "%1" has uncommited structure modifications. - La fenêtre de table "%1" n’a pas enregistré les modifications de structure. - TriggerColumnsDialog @@ -6302,7 +6730,7 @@ Voulez-vous enregistrer la structure, ou voulez-vous retourner à l’onglet de - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> <p> La condition SQL sera évaluée avant le code du déclencheur réel. Dans le cas où le retour de condition est faux, le déclencheur ne sera pas utilisé pour cette ligne.</p > @@ -6347,7 +6775,7 @@ Voulez-vous enregistrer la structure, ou voulez-vous retourner à l’onglet de Déclaration du déclencheur devant être exécutée. - + DDL DDL @@ -6425,33 +6853,21 @@ Voulez-vous enregistrer la structure, ou voulez-vous retourner à l’onglet de - - + + Data Données - + Triggers Déclencheur - + DDL DDL - - Could not restore window, because database %1 could not be resolved. - Impossible de restaurer la fenêtre, car la base de données %1 ne peut ëtre résolue. - - - Could not restore window, because database %1 could not be open. - Impossible de restaurer la fenêtre, car la base de données %1 ne peut ëtre ouverte. - - - Could not restore window, because the view %1 doesn't exist in the database %2. - Impossible de restaurer la fenêtre, car la vue %1 n’existe pas dans la base de données %2.. - @@ -6480,246 +6896,219 @@ Voulez-vous enregistrer la structure, ou voulez-vous retourner à l’onglet de Nouvelle vue %1 - + Refresh the view view window Actualisation de la vue - + Commit the view changes view window Enregistrement des changements dans la vue - + Rollback the view changes view window Annulation des changements dans la vue - + Explicit column names - + Generate output column names automatically basing on result columns of the view. - + Add column view window Ajouter une colonne - + Edit column view window Modifier une colonne - + Delete column view window Supprimer une colonne - + Move column up view window - + Move column down view window - + Refresh trigger list view window Actualisation de la liste des déclencheurs - + Create new trigger view window Création d’un nouveau déclencheur - + Edit selected trigger view window Modification du déclencheur sélectionné - + Delete selected trigger view window Suppression du déclencheur sélectionné - + View window "%1" has uncommitted structure modifications and data. - + View window "%1" has uncommitted data. - + View window "%1" has uncommitted structure modifications. - + Uncommitted changes - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Committed changes for view '%1' successfully. - + Committed changes for view '%1' (named before '%2') successfully. - View window "%1" has uncommited structure modifications and data. - La fenêtre de la vue "%1" n’a pas enregistré les modifications de structure et de données. - - - View window "%1" has uncommited data. - La fenêtre de la vue "%1" n’a pas enregistré les modifications de données. - - - View window "%1" has uncommited structure modifications. - La fenêtre de la vue "%1" n’a pas enregistré les modifications de structure. - - - + Could not load data for view %1. Error details: %2 Impossible de charher les données de vue %1. Détails d’ erreur : %2 - Uncommited changes - Modifications non enregistrées - - - There are uncommited structure modifications. You cannot browse or edit data until you have the view structure settled. -Do you want to commit the structure, or do you want to go back to the structure tab? - Des modifications de structure n’ont pa été enregistrées. - Vous ne pouvez pas naviguer ou éditer des données jusqu’à ce que vous installliez la structure de vue. -Voulez-vous enregistrer la structure, ou voulez-vous retourner à l’onglet de structure ? - - - + Go back to structure tab Retour à l’onlet de structure - + Commit modifications and browse data. Enregistrement des modifications et navigation des données. - + Could not commit view changes. Error message: %1 view window Impossible d’enregistrer les modifications de vue. Message d’erreur : %1 - + Override columns - + Currently defined columns will be overriden. Do you want to continue? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. - + Name view window triggers Nom - + Instead of view window triggers À la place de - + Condition view window triggers Condition - + Details table window triggers Détails - + Could not process the %1 view correctly. Unable to open a view window. Impossible de lancer correctement la vue %1. Impossible d’ouvrir la fenêtre de vue. - + Empty name Nom absent - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? Un nom vide pour la vue dans SQLITE est admis, mais on ne le recommande pas. Êtes-vous sûrs que vous voulez créer une vue avec le nom vide ? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 La déclaration SELECT ne peut être analysé. Veuillez corriger la requête et réessayer. Details : %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! La vue ne peut être modifiée a cause d’une erreur interne de SQLiteStudio. SVP repportez l’erreur ! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. - The view code could not be parsed properly for execution. This is a SQLiteStudio’s bug. Please report it. - La vue ne peut être correctement analysée avant exécution. Cest un bug SQLiteStudio. Veuillez le signaler. - - - + Following problems will take place while modifying the view. Would you like to proceed? view window @@ -6727,7 +7116,7 @@ Would you like to proceed? Veulez-vous continuer ? - + View modification view window Fenêtre vue diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_it.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_it.ts index aaac2b6..e1651a8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_it.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_it.ts @@ -15,7 +15,7 @@ - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> @@ -90,258 +90,15 @@ - BugDialog + BindParamsDialog - - Bugs and ideas + + Query parameters - - Reporter - - - - - E-mail address - - - - - - Log in - - - - - Short description - - - - - Detailed description - - - - - Show more details - - - - - SQLiteStudio version - - - - - Operating system - - - - - Loaded plugins - - - - - Send - - - - - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - - - - - A bug report sent successfully. - - - - - An error occurred while sending a bug report: %1 -%2 - - - - - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - - - - - An idea proposal sent successfully. - - - - - An error occurred while sending an idea proposal: %1 -%2 - - - - - A bug report - - - - - Describe problem in few words - - - - - Describe problem and how to reproduce it - - - - - A new feature idea - - - - - A title for your idea - - - - - Describe your idea in more details - - - - - Reporting as an unregistered user, using e-mail address. - - - - - Reporting as a registered user. - - - - - Log out - - - - - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - - - - - Enter vaild e-mail address, or log in. - - - - - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - - - - - Long description requires at least 30 characters. - - - - - BugReportHistoryWindow - - - - Title - - - - - - Reported at - - - - - - URL - - - - - Reports history - - - - - Clear reports history - - - - - Delete selected entry - - - - - Invalid response from server. - - - - - BugReportLoginDialog - - - Log in - - - - - Credentials - - - - - Login: - - - - - Password: - - - - - Validation - - - - - Validate - - - - - Validation result message - - - - - Abort - - - - - A login must be at least 2 characters long. - - - - - A password must be at least 5 characters long. - - - - - Valid + + Please provide values for query parameters @@ -373,12 +130,12 @@ - + Collation name: - + Implementation language: @@ -483,11 +240,16 @@ - Invalid default value expression: %1 + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. - + Enter a name of the constraint. @@ -599,7 +361,7 @@ - + Delete constraint column dialog @@ -659,34 +421,44 @@ - + Are you sure you want to delete constraint '%1'? column dialog - + Correct the constraint's configuration. - + This constraint is not officially supported by SQLite 2, but it's okay to use it. - + Scale is not allowed for INTEGER PRIMARY KEY columns. - + Precision cannot be defined without the scale. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. @@ -787,12 +559,6 @@ but it's okay to use it. Enter a name of the constraint. - - - Autoincrement (only for %1 type columns) - column primary key - - ColumnUniqueAndNotNullPanel @@ -903,7 +669,7 @@ but it's okay to use it. ConfigDialog - + Configuration @@ -993,215 +759,215 @@ but it's okay to use it. - + Number of data rows per page: - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> - + Limit initial data column width to (in pixels): - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> - + Show column and row details tooltip in data view - + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> - + Inserting new row in data grid - + Before currently selected row - + After currently selected row - + At the end of data view - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> - + Place data tab as first tab in a Table Window - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> - + Place data tab as first tab in a View Window - + Data types - + Available editors: - + Editors selected for this data type: - + Schema editing - + Number of DDL changes kept in history. - + DDL history size: - + SQL queries - - + + Number of queries kept in the history. - + History size: - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> - + Execute only the query under the cursor - + Updates - + Automatically check for updates at startup - + Session - + Restore last session (active MDI windows) after startup - + Status Field - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> - + Always open Status panel when new message is printed - + Filter shortcuts by name or key combination - + Action - + Key combination - - + + Language - + Changing language requires application restart to take effect. - + Compact layout - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> - + Use compact layout @@ -1277,350 +1043,372 @@ but it's okay to use it. - + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + + + + + Number of memorized table populating configurations + + + + Keep NULL value when entering empty value - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> - + Use DEFAULT value (if defined), when committing NULL value - + Table windows - + Open Table Windows with the data tab for start - + View windows - + Open View Windows with the data tab for start - + Don't show DDL preview dialog when committing schema changes - + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + Number of memorized query parameters + + + + Main window dock areas - + Left and right areas occupy corners - + Top and bottom areas occupy corners - + Hide built-in plugins - + Current style: - + Preview - + Enabled - + Disabled - + Active formatter plugin - + SQL editor font - + Database list font - + Database list additional label font - + Data view font - + Status field font - + SQL editor colors - + Current line background - + <p>SQL strings are enclosed with single quote characters.</p> - + String foreground - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> - + Bind parameter foreground - + Highlighted parenthesis background - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground - + Regular foreground - + Line numbers area background - + Keyword foreground - + Number foreground - + Comment foreground - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> - + Valid objects foreground - + Data view colors - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> - + Uncommitted data outline color - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> - + Commit error outline color - + NULL value foreground - + Deleted row background - + Database list colors - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> - + Additional labels foreground - + Status field colors - + Information message foreground - + Warning message foreground - + Error message foreground - + Description: plugin details - + Category: plugin details - + Version: plugin details - + Author: plugin details - + Internal name: plugin details - + Dependencies: plugin details - + Conflicts: plugin details - + Plugin details - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. - + %1 (built-in) plugins manager in configuration dialog - + Details - + No plugins in this category. - + Add new data type - + Rename selected data type - + Delete selected data type - + Help for configuring data type editors @@ -1772,137 +1560,153 @@ but it's okay to use it. DataView - + Filter data data view - + Grid view - + Form view - + Refresh table data data view - + First page data view - + Previous page data view - + Next page data view - + Last page data view - + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + Apply filter data view - + Commit changes for selected cells data view - + Rollback changes for selected cells data view - + Show grid view of results sql editor - + Show form view of results sql editor - + Filter by text data view - + Filter by the Regular Expression data view - + Filter by SQL expression data view - + Tabs on top data view - + Tabs at bottom data view - + Place new rows above selected row data view - + Place new rows below selected row data view - + Place new rows at the end of the data view data view - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. - + Row: %1 @@ -2081,7 +1885,7 @@ Browsing other pages will be possible after the row counting is done. - <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> @@ -2183,352 +1987,397 @@ Browsing other pages will be possible after the row counting is done. - + Copy - + Paste - + Select all - + Create a group - + Delete the group - + Rename the group - - Add a database + + Import - - Edit the database + + Export the table - - Remove the database + + Import into the table - - Connect to the database + + Populate table - - Disconnect from the database + + Create similar table - - Import + + Reset autoincrement sequence - - Export the database + + Add a column - - Convert database type + + Edit the column - - Vacuum + + Delete the column - - Integrity check + + Delete selected items - - Create a table + + Clear filter - - Edit the table + + + Erase table data - - Delete the table + + + Database - - Export the table + + Grouping - - Import into the table + + Generate query for table - - Populate table + + + Create group - - Create similar table + + Group name - - Reset autoincrement sequence + + Entry with name %1 already exists in group %2. - - Create an index + + Delete group - - Edit the index + + Are you sure you want to delete group %1? +All objects from this group will be moved to parent group. - - Delete the index + + Are you sure you want to remove database '%1' from the list? - - Create a trigger + + Are you sure you want to remove following databases from the list: +%1 - - Edit the trigger + + Remove database - - Delete the trigger + + Vacuum (%1) - - Create a view + + Autoincrement value for table '%1' has been reset successfully. - - Edit the view + + Are you sure you want to delete all data from table(s): %1? - - Delete the view + + + Cannot import, because no import plugin is loaded. - - Add a column + + Execution from file cancelled. Any queries executed so far have been rolled back. - - Edit the column + + &Add a database - - Delete the column + + &Edit the database - - Delete selected items + + &Remove the database - - Clear filter + + &Connect to the database - - Refresh all database schemas + + &Disconnect from the database - - Refresh selected database schema + + &Export the database - - - Erase table data + + Con&vert database type - - - Database + + Vac&uum - - Grouping + + &Integrity check - - Generate query for table + + Create a &table - - - Create group + + Edit the t&able - - Group name + + Delete the ta&ble - - Entry with name %1 already exists in group %2. + + Create an &index - - Delete group + + Edit the i&ndex - - Are you sure you want to delete group %1? -All objects from this group will be moved to parent group. + + Delete the in&dex - - Are you sure you want to remove database '%1' from the list? + + Create a trig&ger - - Are you sure you want to remove following databases from the list: -%1 + + Edit the trigg&er - - Remove database + + Delete the trigge&r - - Vacuum (%1) + + Create a &view - - Autoincrement value for table '%1' has been reset successfully. + + Edit the v&iew - - Are you sure you want to delete all data from table(s): %1? + + Delete the vi&ew - - - Cannot import, because no import plugin is loaded. + + &Refresh all database schemas + + + + + Re&fresh selected database schema + + + + + Open file's directory - - + + Execute SQL from file + + + + + Cannot export, because no export plugin is loaded. - + Integrity check (%1) - + Reset autoincrement - + Are you sure you want to reset autoincrement value for table '%1'? - + An error occurred while trying to reset autoincrement value for table '%1': %2 - + An error occurred while trying to delete data from table '%1': %2 - + All data has been deleted for table '%1'. - + Following objects will be deleted: %1. - + Following databases will be removed from list: %1. - + Remainig objects from deleted group will be moved in place where the group used to be. - + %1<br><br>Are you sure you want to continue? - + Delete objects + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. + + DbTreeItemDelegate @@ -2614,74 +2463,74 @@ All objects from this group will be moved to parent group. - + Copy - + Move - + Include data - + Include indexes - + Include triggers - + Abort - + Could not add dropped database file '%1' automatically. Manual setup is necessary. - + Referenced tables - + Do you want to include following referenced tables as well: %1 - + Name conflict - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: - + SQL statements conversion - + Following error occurred while converting SQL statements to the target SQLite version: - + Would you like to ignore those errors and proceed? @@ -2735,130 +2584,136 @@ Please enter new, unique name, or press '%1' to abort the operation: - + History - + Results in the separate tab - + Results below the query - - + + SQL editor %1 - + Results - + Execute query - + Explain query - + Clear execution history sql editor - + Export results sql editor - + Create view from query sql editor - + Previous database - + Next database - + Show next tab sql editor - + Show previous tab sql editor - + Focus results below sql editor - + Focus SQL editor above sql editor - + + Delete selected SQL history entries + sql editor + + + + Active database (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 - + Query finished in %1 second(s). - + Clear execution history - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. - + Cannot export, because no export plugin is loaded. - + No database selected in the SQL editor. Cannot create a view for unknown database. - + Editor window "%1" has uncommitted data. @@ -2881,6 +2736,64 @@ Please enter new, unique name, or press '%1' to abort the operation: + + ExecFromFileDialog + + + Execute SQL from file + + + + + Input file + + + + + Path to file + + + + + Browse for file + + + + + Options + + + + + File encoding + + + + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + ExportDialog @@ -3030,68 +2943,101 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cancel - - - + + + Select database to export. - + Select table to export. - + Enter valid query to export. - + Select at least one object to export. - + You must provide a file name to export to. - + Path you provided is an existing directory. You cannot overwrite it. - + The directory '%1' does not exist. - + The file '%1' exists and will be overwritten. - + All files (*) - + Pick file to export to - + Internal error during export. This is a bug. Please report it. + + FileExecErrorsDialog + + + Execution errors + + + + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + FontEdit @@ -3112,49 +3058,49 @@ Please enter new, unique name, or press '%1' to abort the operation: FormView - + Commit row form view - + Rollback row form view - + First row form view - + Previous row form view - + Next row form view - + Last row form view - + Insert new row form view - + Delete current row form view @@ -3213,13 +3159,13 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Function implementation code: - + Final step implementation code: @@ -3383,42 +3329,42 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cancel - + If you type table name that doesn't exist, it will be created. - + Enter the table name - + Select import plugin. - + You must provide a file to import from. - + The file '%1' does not exist. - + Path you provided is a directory. A regular file is required. - + Pick file to import from @@ -3457,12 +3403,12 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Collation - + Sort @@ -3641,273 +3587,278 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Configuration widgets - + Syntax highlighting engines - + Data editors - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. - + Running in debug mode. Debug messages are printed to the standard output. - + You need to restart application to make the language change take effect. - - Open SQL editor + + Next window - - Open DDL history + + Previous window - - Open SQL functions editor + + Hide status field - - Open collations editor + + Open Debug Console - - Import + + Open CSS Console - - Export + + Bugs and feature &requests - - Open configuration dialog + + Window list + menubar view menu - - Tile windows + + Open SQL &editor - - Tile windows horizontally + + Open DDL &history - - Tile windows vertically + + Open SQL &functions editor - - Cascade windows + + Open &collations editor - - Next window + + Open ex&tension manager - - Previous window + + &Import - - Hide status field + + E&xport - - Close selected window + + Open confi&guration dialog - - Close all windows but selected + + &Tile windows - - Close all windows + + Tile windows &horizontally - - Restore recently closed window + + Tile windows &vertically - - Rename selected window + + &Cascade windows - - Open Debug Console + + Close selected &window - - Open CSS Console + + Close all windows &but selected - - Report a bug + + Close &all windows - - Propose a new feature + + Re&store recently closed window - - About + + &Rename selected window - - Licenses + + Report a &bug - - Open home page + + Propose a new &feature - - Open forum page + + &About - - User Manual + + &Licenses - - SQLite documentation + + Open home &page - - Report history + + Open fo&rum page - - Check for updates + + User &Manual - - Database - menubar + + SQLite &documentation - - Structure + + Check for &updates + + + + + &Database menubar - - View + + &Structure menubar - - Window list - menubar view menu + + &View + menubar - - Tools + + &Tools menubar - - Help + + &Help - + Could not set style: %1 main window - + Cannot export, because no export plugin is loaded. - + Cannot import, because no import plugin is loaded. - + Rename window - + Enter new name for the window: - + New updates are available. <a href="%1">Click here for details</a>. - + You're running the most recent version. No updates are available. - + Database passed in command line parameters (%1) was already on the list under name: %2 - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 - + Could not add database %1 to list. @@ -3939,64 +3890,69 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Configure editors for this data type - + + Open another tab + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. - + Deleted multieditor - + Read only multieditor - MultiEditorBool + MultiEditorBoolPlugin - + Boolean - MultiEditorDate + MultiEditorDatePlugin - + Date - MultiEditorDateTime + MultiEditorDateTimePlugin - + Date & time - MultiEditorHex + MultiEditorHexPlugin - + Hex - MultiEditorNumeric + MultiEditorNumericPlugin - + Number numeric multi editor tab name @@ -4005,50 +3961,53 @@ Please enter new, unique name, or press '%1' to abort the operation: MultiEditorText - - Text - - - - + Tab changes focus - + Cut - + Copy - + Paste - + Delete - - Undo + + Undo + + + + + Redo + + + MultiEditorTextPlugin - - Redo + + Text - MultiEditorTime + MultiEditorTimePlugin - + Time @@ -4125,37 +4084,32 @@ Please enter new, unique name, or press '%1' to abort the operation: - - Current version + + This application will be closed and the update installer will start to download and install all the updates. - + Update version - + Check for updates on startup - + Update to new version! - - The update will be automatically downloaded and installed. This will also restart application at the end. - - - - + Not now. - + Don't install the update and close this window. @@ -4207,32 +4161,32 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Abort - + Configure - + Populating configuration for this column is invalid or incomplete. - + Select database with table to populate - + Select table to populate - + You have to select at least one column. @@ -4307,129 +4261,134 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Data grid view - + Copy cell(s) contents to clipboard - Paste cell(s) contents from clipboard + Copy cell(s) contents together with header to clipboard + Paste cell(s) contents from clipboard + + + + Set empty value to selected cell(s) - + Set NULL value to selected cell(s) - + Commit changes to cell(s) contents - + Rollback changes to cell(s) contents - + Delete selected data row - + Insert new data row - + Open contents of selected cell in a separate editor - + Total pages available: %1 - + Total rows loaded: %1 - + Data view (both grid and form) - + Refresh data - + Switch to grid view of the data - + Switch to form view of the data - + Database list - + Delete selected item - + Clear filter contents - + Refresh schema - + Refresh all schemas - + Add database - + Select all items - + Copy selected item(s) - + - + Paste from clipboard @@ -4504,42 +4463,42 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Main window - + Open SQL editor - + Previous window - + Next window - + Hide status area - + Open configuration dialog - + Open Debug Console - + Open CSS Console @@ -4550,111 +4509,111 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cut selected text - + Copy selected text - + Delete selected text - + Undo - + Redo - + SQL editor input field - + Select whole editor contents - + Save contents into a file - + Load contents from a file - + Find in text - + Find next - + Find previous - + Replace in text - + Delete current line - + Request code assistant - + Format contents - + Move selected block of text one line down - + Move selected block of text one line up - + Copy selected block of text and paste it a line below - + Copy selected block of text and paste it a line above - + Toggle comment @@ -4674,16 +4633,6 @@ Please enter new, unique name, or press '%1' to abort the operation:Database file - - - Reports history window - - - - - Delete selected entry - - SQL editor window @@ -4729,6 +4678,11 @@ Please enter new, unique name, or press '%1' to abort the operation:Move keyboard input focus to the SQL editor above + + + Delete selected SQL history entries + + Table window @@ -4947,179 +4901,179 @@ find next SqlEditor - + Cut sql editor - + Copy sql editor - + Paste sql editor - + Delete sql editor - + Select all sql editor - + Undo sql editor - + Redo sql editor - + Complete sql editor - + Format SQL sql editor - + Save SQL to file sql editor - + Select file to save SQL sql editor - + Load SQL from file sql editor - + Delete line sql editor - + Move block down sql editor - + Move block up sql editor - + Copy block down sql editor - + Copy up down sql editor - + Find sql editor - + Find next sql editor - + Find previous sql editor - + Replace sql editor - + Toggle comment sql editor - + Could not open file '%1' for writing: %2 - + Saved SQL contents to file: %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. - + Save to file - + SQL scripts (*.sql);;All files (*) - + Open file - + Could not open file '%1' for reading: %2 - + Reached the end of document. Hit the find again to restart the search. @@ -5167,24 +5121,24 @@ find next - - + + Cannot edit this cell. Details: %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. @@ -5192,69 +5146,74 @@ find next SqlQueryModel - - + + Only one query can be executed simultaneously. - + Cannot commit the data for a cell that refers to the already closed database. - + Could not begin transaction on the database. Details: %1 - + An error occurred while rolling back the transaction: %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. - + Uncommitted data - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. - + An error occurred while committing the transaction: %1 - + An error occurred while committing the data: %1 - - + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + + + + + Error while executing SQL query on database '%1': %2 - + Error while loading query results: %1 - + Insert multiple rows - + Number of rows to insert: @@ -5262,117 +5221,137 @@ find next SqlQueryView - + Go to referenced row in... - + Copy - + Copy as... - + Paste - + Paste as... - + Set NULL values - + Erase values - + Edit value in editor - + Commit - + + Copy with headers + + + + Rollback - + Commit selected cells - + Rollback selected cells - + Define columns to sort by - + Remove custom sorting - + Insert row - + Insert multiple rows - + Delete selected row - + + Show value in a viewer + + + + Generate query for selected cells - + No items selected to paste clipboard contents to. - + Go to referenced row in table '%1' - + table '%1' - + Referenced row (%1) - + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + Edit value @@ -5390,6 +5369,119 @@ find next + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + + + + + Register in all databases + + + + + Register in following databases: + + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + + + + + Open file + + + StatusField @@ -5498,7 +5590,7 @@ but it's okay to use them anyway. - + Foreign column table constraints @@ -5552,24 +5644,24 @@ but it's okay to use them anyway. - + Collate table constraints - + Sort order table constraints - + Select at least one column. - + Enter a name of the constraint. @@ -6120,7 +6212,7 @@ Are you sure you want to create a table with blank name? - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> @@ -6165,7 +6257,7 @@ Are you sure you want to create a table with blank name? - + DDL @@ -6243,18 +6335,18 @@ Are you sure you want to create a table with blank name? - - + + Data - + Triggers - + DDL @@ -6286,224 +6378,224 @@ Are you sure you want to create a table with blank name? - + Refresh the view view window - + Commit the view changes view window - + Rollback the view changes view window - + Explicit column names - + Generate output column names automatically basing on result columns of the view. - + Add column view window - + Edit column view window - + Delete column view window - + Move column up view window - + Move column down view window - + Refresh trigger list view window - + Create new trigger view window - + Edit selected trigger view window - + Delete selected trigger view window - + View window "%1" has uncommitted structure modifications and data. - + View window "%1" has uncommitted data. - + View window "%1" has uncommitted structure modifications. - + Uncommitted changes - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Committed changes for view '%1' successfully. - + Committed changes for view '%1' (named before '%2') successfully. - + Could not load data for view %1. Error details: %2 - + Go back to structure tab - + Commit modifications and browse data. - + Could not commit view changes. Error message: %1 view window - + Override columns - + Currently defined columns will be overriden. Do you want to continue? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. - + Name view window triggers - + Instead of view window triggers - + Condition view window triggers - + Details table window triggers - + Could not process the %1 view correctly. Unable to open a view window. - + Empty name - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. - + Following problems will take place while modifying the view. Would you like to proceed? view window - + View modification view window diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pl.qm b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pl.qm index 0adb64a..5740bcd 100644 Binary files a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pl.qm and b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pl.qm differ diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pl.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pl.ts index ad6aaf3..e144d8b 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pl.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pl.ts @@ -14,9 +14,8 @@ O programie - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Darmowy, otwartoźródłowy, wieloplatformowy menadżer baz danych SQLite.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Autor i aktywny opiekun:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Darmowy, otwartoźródłowy, wieloplatformowy menadżer baz danych SQLite.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Autor i aktywny opiekun:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> @@ -58,6 +57,11 @@ Configuration directory Katalog konfiguracji + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Darmowy, otwartoźródłowy, wieloplatformowy menadżer baz danych SQLite.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Autor i aktywny opiekun:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + Qt version: @@ -89,262 +93,222 @@ <h3>Zawartość:</h3><ol>%2</ol> + + BindParamsDialog + + + Query parameters + Parametry zapytania + + + + Please provide values for query parameters + Proszę podać wartości dla parametrów zapytania + + BugDialog - Bugs and ideas - Błędy i pomysły + Błędy i pomysły - Reporter - Zgłaszający + Zgłaszający - E-mail address - Adres e-mail + Adres e-mail - - Log in - Zaloguj + Zaloguj - Short description - Krótki opis + Krótki opis - Detailed description - Opis szczegółowy + Opis szczegółowy - Show more details - Pokaż więcej szczegółów + Pokaż więcej szczegółów - SQLiteStudio version - Wersja SQLiteStudio + Wersja SQLiteStudio - Operating system - System operacyjny + System operacyjny - Loaded plugins - Załadowane wtyczki + Załadowane wtyczki - Send - Wyślij + Wyślij - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - Możesz zobaczyć wszystkie błędy i pomysły zgłoszone przez ciebie wybierając menu '%1' i dalej '%2'. + Możesz zobaczyć wszystkie błędy i pomysły zgłoszone przez ciebie wybierając menu '%1' i dalej '%2'. - A bug report sent successfully. - Błąd został zgłoszony pomyślnie. + Błąd został zgłoszony pomyślnie. - An error occurred while sending a bug report: %1 %2 - Wystąpił błąd podczas zgłaszania błędu: %1 + Wystąpił błąd podczas zgłaszania błędu: %1 %2 - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - Możesz spróbować powtórzyć wysyłkę. Zawartość będzie przywrócona, kiedy otworzysz okno zgłaszania po błędzie takim jak ten. + Możesz spróbować powtórzyć wysyłkę. Zawartość będzie przywrócona, kiedy otworzysz okno zgłaszania po błędzie takim jak ten. - An idea proposal sent successfully. - Pomysł został zgłoszony pomyślnie. + Pomysł został zgłoszony pomyślnie. - An error occurred while sending an idea proposal: %1 %2 - Wystąpił błąd podczas zgłaszania pomysłu: %1 + Wystąpił błąd podczas zgłaszania pomysłu: %1 %2 - A bug report - Zgłoś błąd + Zgłoś błąd - Describe problem in few words - Opisz problem w kilku słowach + Opisz problem w kilku słowach - Describe problem and how to reproduce it - Opisz problem, oraz jak go powtórzyć + Opisz problem, oraz jak go powtórzyć - A new feature idea - Zgłoś pomysł + Zgłoś pomysł - A title for your idea - Tytuł twojego pomysłu + Tytuł twojego pomysłu - Describe your idea in more details - Opisz twój pomysł szerzej + Opisz twój pomysł szerzej - Reporting as an unregistered user, using e-mail address. - Zgłaszanie jako niezarejestrowany użytkownik, używając adresu e-mail. + Zgłaszanie jako niezarejestrowany użytkownik, używając adresu e-mail. - Reporting as a registered user. - Zgłaszanie jako zarejestrowany użytkownik. + Zgłaszanie jako zarejestrowany użytkownik. - Log out - Wyloguj + Wyloguj - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - Podanie prawdziwego adresu e-mail pozwoli na skontaktowanie się z tobą w związku z twoim zgłoszeniem. Aby dowiedzieć się więcej, kliknij przycisk 'pomoc' po prawej stronie. + Podanie prawdziwego adresu e-mail pozwoli na skontaktowanie się z tobą w związku z twoim zgłoszeniem. Aby dowiedzieć się więcej, kliknij przycisk 'pomoc' po prawej stronie. - Enter vaild e-mail address, or log in. - Wpisz poprawny adres e-mail, lub zaloguj się. + Wpisz poprawny adres e-mail, lub zaloguj się. - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - Krótki opis wymaga przynajmniej 10 znaków, ale nie więcej niż 100. Dłuższy opis może być wpisany w polu poniżej. + Krótki opis wymaga przynajmniej 10 znaków, ale nie więcej niż 100. Dłuższy opis może być wpisany w polu poniżej. - Long description requires at least 30 characters. - Długi opis wymaga przynajmniej 30 znaków. + Długi opis wymaga przynajmniej 30 znaków. BugReportHistoryWindow - - Title - Tytuł + Tytuł - - Reported at - Zgłoszony dnia + Zgłoszony dnia - - URL - URL + URL - Reports history - Historia zgłoszeń + Historia zgłoszeń - Clear reports history - Wyczyść historię zgłoszeń + Wyczyść historię zgłoszeń - Delete selected entry - Usuń wybraną pozycję + Usuń wybraną pozycję - Invalid response from server. - Niepoprawna odpowiedź z serwera. + Niepoprawna odpowiedź z serwera. BugReportLoginDialog - Log in - Zaloguj + Zaloguj - Credentials - Dane do logowania + Dane do logowania - Login: - Login: + Login: - Password: - Hasło: + Hasło: - Validation - Walidacja + Walidacja - Validate - Sprawdź + Sprawdź - Validation result message - Treść wyniku walidacji + Treść wyniku walidacji - Abort - Przerwij + Przerwij - A login must be at least 2 characters long. - Login musi mieć przynajmniej 2 znaki. + Login musi mieć przynajmniej 2 znaki. - A password must be at least 5 characters long. - Hasło musi mieć przynajmniej 5 znaków. + Hasło musi mieć przynajmniej 5 znaków. - Valid - Poprawne + Poprawne @@ -355,12 +319,12 @@ Filtruj zestawienia - + Collation name: Nazwa zestawienia: - + Implementation language: Język implementacji: @@ -489,11 +453,20 @@ + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + Niepoprawne wyrażenie wartości domyślnej: %1. Jeśli chcesz użyć zwykłego tekstu jako wartość, pamiętaj o zamknięciu go w znakach apostrofu. + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. + Niepoprawne wyrażenie wartości domyślnej. Jeśli chcesz użyć zwykłego tekstu jako wartość, pamiętaj o zamknięciu go w znakach apostrofu. + + Invalid default value expression: %1 - Niepoprawna wartość wyrażenia domyślnego: %1 + Niepoprawna wartość wyrażenia domyślnego: %1 - + Enter a name of the constraint. Wprowadź nazwę ograniczenia. @@ -605,7 +578,7 @@ - + Delete constraint column dialog Usuń ograniczenie @@ -665,35 +638,45 @@ Dodaj ograniczenie wartości domyślnej - + Are you sure you want to delete constraint '%1'? column dialog Czy na pewno chcesz usunąć ograniczenie '%1'? - + Correct the constraint's configuration. Popraw konfigurację ograniczenia. - + This constraint is not officially supported by SQLite 2, but it's okay to use it. To ograniczenie nie jest oficjalnie wspireane przez SQLite 2, ale można go używać. - + Scale is not allowed for INTEGER PRIMARY KEY columns. Skala nie jest dozwolona dla kolumn INTEGER PRIMARY KEY. - + Precision cannot be defined without the scale. Precyzja nie może być zdefiniowana bez skali. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + Nie można użyć innego typu niż INTEGER, jeśli opcja AUTOINCREMENT jest wybrana w PRIMARY KEY. + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + Typ INTEGER został wymuszony w związku z wybraną opcją AUTOINCREMENT w PRIMARY KEY. + + + Precision is not allowed for INTEGER PRIMARY KEY columns. Precyzja nie jest dozwolona dla kolumn INTEGER PRIMARY KEY. @@ -795,10 +778,9 @@ ale można go używać. Wprowadź nazwę ograniczenia. - Autoincrement (only for %1 type columns) column primary key - Autoinkrementacja (tylko dla kolumn o typie %1) + Autoinkrementacja (tylko dla kolumn o typie %1) @@ -910,7 +892,7 @@ ale można go używać. ConfigDialog - + Configuration Konfiguracja @@ -975,68 +957,68 @@ ale można go używać. Przeglądanie i edycja danych - + Number of data rows per page: Liczba wierszy danych na stronie: - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> <p>Kiedy dane są wczytane do widoku siatki, szerokość kolumn jest automatycznie dostosowywana. Ta wartość ogranicza początkową szerokość tego dostosowywania, ale użytkownik nadal może rozszerzać kolumnę ręcznie poza ten limit.</p> - + Limit initial data column width to (in pixels): Ogranicz początkową szerokość kolumn danych (w pikselach): - + Inserting new row in data grid Wstawianie nowego wiersza w widoku siatki danych. - + Before currently selected row Przed aktualnie wybranym wierszem - + After currently selected row Po aktualnie wybranym wierszu. - + At the end of data view Na końcu widoku siatki danych - + Data types Type danych - + Available editors: Dostępne edytory: - + Editors selected for this data type: Edytory wybrane dla tego typu danych: - + Schema editing Edycja schematu - + Number of DDL changes kept in history. Liczba zmian DDL trzymanych w historii. - + DDL history size: Rozmiar historii DDL: @@ -1045,83 +1027,83 @@ ale można go używać. Nie pokazuj okna podglądu DDL podczas zatwierdzania zmian schematu - + SQL queries Zapytania SQL - - + + Number of queries kept in the history. Liczba zapytań trzymana w historii. - + History size: Rozmiar historii: - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> <p>Jeśli w oknie edytora SQL jest więcej niż jedno zapytanie, to (jeśli ta opcja jest włączona) tylko jedno zapytanie będzie wykonana - to, które znajduje się pod kursorem pisania. W przeciwnym wypadku wszystkie zapytania będą wykonywane. Zawsze możesz ograniczyć zapytania do wywołania przez zaznaczenie tych zapytań, które chcesz wywołać.</p> - + Execute only the query under the cursor Wykonuj tylko zapytania będące pod kursorem - + Updates Aktualizacje - + Automatically check for updates at startup Sprawdzaj aktualizacje automatycznie przy starcie - + Session Sesje - + Restore last session (active MDI windows) after startup Przywróć ostatnią sesję (aktywne okna MDI) po starcie - + Filter shortcuts by name or key combination Filtruj skróty po nazwie, lub kombinacji klawiszy - + Action Akcja - + Key combination Kombinacja klawiszy - + Changing language requires application restart to take effect. Zmiana języka wymaga restartu aplikacji, aby zadziałać. - + Compact layout Układ kompaktowy - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> <p>Układ kompaktowy zmniejsza wszystkie marginesy i odstępy na interfejsie do minimum, robiąc więcej miejsca na wyświetlanie danych. Powoduje to, że interfejs jest nieco mniej estetyczny, ale pozwala to na prezentację większej ilości danych naraz.</p> - + Use compact layout Użyj układu kompaktowego @@ -1197,7 +1179,7 @@ ale można go używać. Wyświetlaj tabele i indeksy systemowe na liście - + Table windows Okna tabel @@ -1206,12 +1188,12 @@ ale można go używać. Gdy włączone, Okna Tabel będą się pokazywać z zakładką danych, zamiast z zakładką struktury. - + Open Table Windows with the data tab for start Otwieraj Okna Tabeli z zakładką danych na początek - + View windows Okna Widoków @@ -1220,42 +1202,42 @@ ale można go używać. Gdy włączone, Okna Widoków będą się pokazywać z zakładką danych, zamiast z zakładką struktury. - + Open View Windows with the data tab for start Otwieraj Okna Widoku z zakładką danych na początek - + Main window dock areas Strefy dokowania głównego okna - + Left and right areas occupy corners Lewa i prawa strefa zajmują rogi - + Top and bottom areas occupy corners Górna i dolna strefa zajmują rogi - + Hide built-in plugins Ukryj wtyczki wbudowane - + Current style: Aktualny styl: - + Preview Podgląd - + Enabled Włączone @@ -1264,13 +1246,13 @@ ale można go używać. Kolumna - + Disabled Wyłączone - - + + Language Język @@ -1300,212 +1282,234 @@ ale można go używać. Próbuj całkowicie pomijać dialog podczas upuszczania pliku bazy na listę - + Keep NULL value when entering empty value Zachowaj wartość NULL gdy wstawiania jest pusta wartość - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> <p>Gdy to jest włączone i użytkownik zatrzyma kursor myszy nad komórką w widoku siatki danych (wyniki zapytania, dane tabeli, dane widoku), to pojawi się podpowiedź ze szczegółami odnośnie komórki - zawiera ona szczegóły , jak typ danych kolumny, ograniczenia, ROWID i inne.</p> - + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + <p>Maksymalna liczba konfiguracji w oknie dialogowym zaludniania tabeli, która ma być trzymana w konfiguracji. Wartość 100 powinna być wystarczająca.</p> + + + + Number of memorized table populating configurations + Liczba zapamiętanych konfiguracji zaludniania tabeli + + + Show column and row details tooltip in data view Pokazuj podpowiedź ze szczegółami o kolumnie i wierszu w widoku siatki danych - + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> <p>Kiedy edytowana jest komórka, która miała wartość NULL, a nowa wartość wprowadzona jest pusta, to ta opcja decyduje o tym, czy wartość powinna pozostać NULL (gdy ta opcja jest włączona), czy powinna być nadpisana pustym łańcuchem znaków (gdy ta opcja wyłączona).</p> - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> <html><head/><body><p>Włącz to, aby wymusić wartość DEFAULT podczas zatwierdzania wartości NULL dla kolumn, które mają zdefiniowaną wartość DEFAULT, nawet jeśli kolumna dopuszcza wartości NULL.</p><p>Wyłącz tą opcję aby używać wartości DEFAULT tylko i wyłącznie, gdy wartość NULL jest zatwierdzana dla kolumny z ograniczeniem NOT NULL.</p></body></html> - + Use DEFAULT value (if defined), when committing NULL value Używaj wartości DEFAULT (jeśli zdefiniowana), gdy zatwierdzana jest wartość NULL - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> <p>Gdy włączone, Okna Tabeli będą się otwierać na zakładce danych, zamiast na zakładce struktury.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> <p>Gdy włączone, to zakładka "Dane" będzie umieszczona jako pierwsza w każdym Oknie Tabeli, zamiast jako druga.</p> - + Place data tab as first tab in a Table Window Ustaw zakładkę danych jako pierwszą w Oknie Tabeli - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> <p>Gdy włączone, Okna Widoku będą się otwierać na zakładce danych, zamiast na zakładce struktury.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> <p>Gdy włączone, to zakładka "Dane" będzie umieszczona jako pierwsza w każdym Oknie Widoku, zamiast jako druga.</p> - + Place data tab as first tab in a View Window Ustaw zakładkę danych jako pierwszą w Oknie Widoku - + Don't show DDL preview dialog when committing schema changes Nie pokazuj okna podglądu DDL podczas zatwierdzania zmian struktury - + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + <p>Maksymalna liczba parametrów zapytania (:param, @param, $param, ?) trzymanych w historii. Kiedy ponownie użyjesz parametru o tej samej nazwie/pozycji, SQLiteStudio wstępnie uzupełni go używając ostatniej zapamiętanej wartości (nadal będzie można ją zmienić). Wartość 100 powinna być wystarczająca.</p> + + + + Number of memorized query parameters + Liczba zapamiętanych parametrów zapytania + + + Status Field Pole Statusu - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> <p>Kiedy użytkownik ręcznie zamyka panel Statusu, ta opcja zapewnia, że zostanie ono otwarte ponownie, gdy jest wyświetlona nowa wiadomość. Jeśli jest ona wyłączona, to panel Statusu może być otwarte tylko ręcznie z menu "Widok".</p> - + Always open Status panel when new message is printed Zawsze otwieraj panel Statusu, gdy wyświetlona jest nowa wiadomość - + Active formatter plugin Aktywna wtyczka formatera - + SQL editor font Czcionka edytora SQL - + Database list font Czcionka listy baz danych - + Database list additional label font Czcionka dodatkowych etykiety listy baz danych - + Data view font Czcionka widoku danych - + Status field font Czcionka pola statusu - + SQL editor colors Kolory edytora SQL - + Current line background Tło bieżącej linii - + <p>SQL strings are enclosed with single quote characters.</p> <p>Łańcuchy znaków SQL są zamknięte pomiędzy znakami apostrofu.</p> - + String foreground Czcionka łańcucha znaków - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> <b>Parametry wiążące to wyrażenia zastępcze dla wartości, które mają być dopiero dostarczone przez użytkownika. Mają one jedną z form: </p><ul><li>:nazwa_parametru</li><li>$nazwa_parametru</li><li>@nazwa_parametru</li><li>?</li></ul> - + Bind parameter foreground Czcionka parametru wiążącego - + Highlighted parenthesis background Tło podświetlonych nawiasów - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> <p>Wartości BLOB są wartościami binarnymi, reprezentowanymi jako liczby heksadecymalne, jak np:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground - + Regular foreground Standardowa czcionka - + Line numbers area background Tło obszaru numerów linii - + Keyword foreground Czcionka słowa kluczowego - + Number foreground Czcionka liczby - + Comment foreground Czcionka komentarza - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> <p>Poprawne obiekty to nazwy tabel, indekstów, wyzwalaczy i widoków, które istnieją w basie SQLite.</p> - + Valid objects foreground Czcionka poprawnych obiektów - + Data view colors Kolory widoku danych - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> <p>Jakiekolwiek zmiany danych będą otoczone ramką w tym kolorze, dopóki nie zostaną zatwierdzone do bazy.</p> - + Uncommitted data outline color Kolor obramowania niezatwierdzonych danych - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> <p>W razie błędu podczas zatwierdzania zmian w danych, komórki sprawiające problem będą obramowane tym kolorem.</p> @@ -1522,140 +1526,140 @@ ale można go używać. <p>W przypadku błędu podczas zatwierdzania zmian danych, komórka będąca przyczyną problemu zostanie obrysowana tym kolorem.</p> - + Commit error outline color Kolor obrysu błędu zatwierdzania - + NULL value foreground Kolor czcionki wartości NULL - + Deleted row background Tło wiersza usuniętego - + Database list colors Kolory listy baz danych - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> <p>Dodatkowe etykiety to te, które mówią o wersji SQLite, liczbie obiektów w głębszych częściach drzewa, itp.</p> - + Additional labels foreground Czcionka dodatkowych etykiet - + Status field colors Kolory pola statusu - + Information message foreground Czcionka wiadomości informującej - + Warning message foreground Czcionka wiadomości ostrzegającej - + Error message foreground Czcionka wiadomości błędu - + Description: plugin details Opis: - + Category: plugin details Kategoria: - + Version: plugin details Wersja: - + Author: plugin details Autor: - + Internal name: plugin details Nazwa wewnętrzna: - + Dependencies: plugin details Zależności: - + Conflicts: plugin details Konflikty: - + Plugin details Szczegóły wtyczki - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. Wtyczki są ładowane/wyładowywane natychmiast po zaznaczeniu/odznaczeniu, ale zmodyfikowana lista wtyczek, które należy załadować przy starcie nie jest zapisana, dopóki nie zatwierdzisz całego okna configuracji. - + %1 (built-in) plugins manager in configuration dialog %1 (wbudowany) - + Details Szczegóły - + No plugins in this category. Brak wtyczek w tej kategorii. - + Add new data type Dodaj nowy typ danych - + Rename selected data type Zmień nazwę wybranego typu danych - + Delete selected data type Usuń wybrany typ danych - + Help for configuring data type editors Pomoc w konfiguracji edytorów typów danych @@ -1807,138 +1811,154 @@ ale można go używać. DataView - + Filter data data view Filtruj dane - + Grid view Widok siatki - + Form view Widok formularza - + Refresh table data data view Odśwież dane tabeli - + First page data view Pierwsza strona - + Previous page data view Poprzednia strona - + Next page data view Następna strona - + Last page data view Ostatnia strona - + + Filter + Filtruj + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + Wciśnij Enter lub naciśnij przycisk "Zastosuj filtr", aby zastosować nową wartość. + + + + Show filter inputs per column + data view + Pokaż filtr dla każdej kolumny + + + Apply filter data view Zastosuj filtr - + Commit changes for selected cells data view Zatwierdź zmiany dla wybranych komórek - + Rollback changes for selected cells data view Wycofaj zmiany dla wybranych komórek - + Show grid view of results sql editor Pokaż widok siatki dla wyników - + Show form view of results sql editor Pokaż widok formularza dla wyników - + Filter by text data view Filtruj po tekście - + Filter by the Regular Expression data view Filtruj używając Wyrażeń Regularnych - + Filter by SQL expression data view Filtruj używając wyrażenia SQL - + Tabs on top data view Karty na górze - + Tabs at bottom data view Karty na dole - + Place new rows above selected row data view Wstawiaj nowe wiersze nad aktualnie wybranym wierszem - + Place new rows below selected row data view Wstawiaj nowe wiersze pod aktualnie wybranym wierszem - + Place new rows at the end of the data view data view Wstawiaj nowe wiersze na końcu widoku siatki danych - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. Całkowita liczba wierszy jest liczona. Przeglądanie pozostałych stron będzie możliwe kiedy liczenie wierszy zostanie zakończone. - + Row: %1 Wiersz: %1 @@ -2145,9 +2165,13 @@ Przeglądanie pozostałych stron będzie możliwe kiedy liczenie wierszy zostani - <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> <p>Automatyczne generowanie nazwy zostało wyłączone, ponieważ nazwa była edytowana ręcznie. Aby przywrócić automatyczne generowanie, proszę wyczyścić pole nazwy.</p> + + <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatyczne generowanie nazwy zostało wyłączone, ponieważ nazwa była edytowana ręcznie. Aby przywrócić automatyczne generowanie, proszę wyczyścić pole nazwy.</p> + Enter a database file path. @@ -2260,298 +2284,435 @@ Przeglądanie pozostałych stron będzie możliwe kiedy liczenie wierszy zostani Filtruj po nazwie - + Copy Kopiuj - + Paste Wklej - + Select all Zaznacz wszystko - + Create a group Utwórz grupę - + Delete the group Usuń grupę - + Rename the group Zmień nazwę grupy - Add a database - Dodaj bazę danych + Dodaj bazę danych - Edit the database - Edytuj bazę danych + Edytuj bazę danych - Remove the database - Usuń bazę danych + Usuń bazę danych - Connect to the database - Połącz z bazą danych + Połącz z bazą danych - Disconnect from the database - Rozłącz się z bazą danych + Rozłącz się z bazą danych - + Import Importuj - Export the database - Eksportuj bazę danych + Eksportuj bazę danych - Convert database type - Konwertuj typ bazy danych + Konwertuj typ bazy danych - Vacuum - Odkurz + Odkurz - Integrity check - Sprawdź spójność + Sprawdź spójność - Create a table - Utwórz tabelę + Utwórz tabelę - Edit the table - Edytuj tabelę + Edytuj tabelę + + + + Execution from file cancelled. Any queries executed so far have been rolled back. + Wykonywanie z pliku przerwane. Jakiekolwiek wykonane zapytania zostały wycofane. + + + + &Add a database + Dod&aj bazę danych + + + + &Edit the database + &Edytuj bazę danych + + + + &Remove the database + U&suń bazę danych + + + + &Connect to the database + &Połącz z bazą danych + + + + &Disconnect from the database + &Rozłącz się z bazą danych + + + + &Export the database + &Eksportuj bazę danych + + + + Con&vert database type + Kon&wertuj typ bazy danych + + + + Vac&uum + Odk&urz + + + + &Integrity check + Sprawdź spó&jność + + + + Create a &table + Utwórz &tabelę + + + + Edit the t&able + Edytuj t&abelę + + + + Delete the ta&ble + Usuń ta&belę + + + + Create an &index + Utwórz &indeks + + + + Edit the i&ndex + Edytuj i&ndeks + + + + Delete the in&dex + Usuń in&deks + + + + Create a trig&ger + Utwórz wyz&walacz + + + + Edit the trigg&er + Edytuj wyzw&alacz + + + + Delete the trigge&r + Usuń wyzwa&lacz + + + + Create a &view + Utwórz &widok + + + + Edit the v&iew + Edytuj w&idok + + + + Delete the vi&ew + Usuń wi&dok + + + + &Refresh all database schemas + &Odśwież schematy wszystkich baz danych + + + + Re&fresh selected database schema + Odśwież schemat wy&branej bazy danych + + + + Open file's directory + Otwórz katalog pliku + + + + Execute SQL from file + Wykonaj SQL z pliku - + Generate query for table Generuj zapytanie dla tabeli - + Entry with name %1 already exists in group %2. Pozycja o nazwie %1 istnieje już w grupie %2. - + Are you sure you want to remove database '%1' from the list? Czy napewno chcesz wycofać bazę '%1' z listy? - + Are you sure you want to remove following databases from the list: %1 Czy na pewno chcesz wycofać następujące bazy z listy: %1 - + Remove database Wycofaj bazę - + Vacuum (%1) Odkurz (%1) - + Autoincrement value for table '%1' has been reset successfully. Wartość automatycznej inkrementacji dla tabeli '%1' została zresetowana. - + Are you sure you want to delete all data from table(s): %1? Czy na pewno chcesz usunąć wszystkie dane z tabel(i): %1? + + + Could not execute SQL, because application has failed to start transaction: %1 + Nie można wykonać SQLa, ponieważ aplikacja nie mogła rozpocząć transakcji: %1 + + + + Could not open file '%1' for reading: %2 + Nie udało się otworzyć pliku '%1' do odczytu: %2 + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + Nie można wykonać SQLa, ponieważ aplikacja nie mogła zatwierdzić transakcji: %1 + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + Zakończono wykonywanie %1 zapytań w %2 sekund(y). %3 nie zostały wykonane w zwiążku z błędami. + + + + Finished executing %1 queries in %2 seconds. + Zakończono wykonywanie %1 zapytań w %2 sekund(y). + + + + Could not execute SQL due to error. + Nie można wykonać SQL w związku z błędem. + Drop the table Porzuć tabelę - + Export the table Eksportuj tabelę - + Import into the table Importuj do tabeli - + Populate table Zaludnij tabelę - + Create similar table Utwórz podobną tabelę - Create an index - Utwórz indeks + Utwórz indeks - Edit the index - Edytuj indeks + Edytuj indeks Drop the index Porzuć indeks - Create a trigger - Utwórz wyzwalacz + Utwórz wyzwalacz - Edit the trigger - Edytuj wyzwalacz + Edytuj wyzwalacz Drop the trigger Porzuć wyzwalacz - Create a view - Utwórz widok + Utwórz widok - Edit the view - Edytuj widok + Edytuj widok Drop the view Porzuć widok - + Add a column Dodaj kolumnę - + Edit the column Edytuj kolumnę - + Delete the column Usuń kolumnę - + Delete selected items Usuń wybrane elementy - + Clear filter Wyczyść filtr - Refresh all database schemas - Odśwież schematy wszystkich baz danych + Odśwież schematy wszystkich baz danych - Refresh selected database schema - Odśwież schemat wybranej bazy danych + Odśwież schemat wybranej bazy danych - Delete the table - Usuń tabelę + Usuń tabelę - + Reset autoincrement sequence Wyzeruj sekwencję autoinkrementacji - Delete the index - Usuń indeks + Usuń indeks - Delete the trigger - Usuń wyzwalacz + Usuń wyzwalacz - Delete the view - Usuń widok + Usuń widok - - + + Erase table data Wymaż dane tabeli - - + + Database Baza danych - + Grouping Grupowanie - - + + Create group Utwórz grupę - + Group name Nazwa grupy - + Delete group Usuń grupę - + Are you sure you want to delete group %1? All objects from this group will be moved to parent group. Czy na pewno chcesz usunąć grupę %1? @@ -2566,14 +2727,14 @@ Wszystkie obiekty z tej grupy zostaną przeniesione do nadrzędnej grupy.Czy na pewno chcesz usunąć bazę danych '%1'? - - + + Cannot import, because no import plugin is loaded. Nie można zaimportować, ponieważ żadna wtyczka importu nie została załadowana. - - + + Cannot export, because no export plugin is loaded. Nie można wyeksportować, ponieważ żadna wtyczka eksportu nie została załadowana. @@ -2586,22 +2747,22 @@ Wszystkie obiekty z tej grupy zostaną przeniesione do nadrzędnej grupy.Wykonanie VACUUM przebiegło pomyślnie. - + Integrity check (%1) Sprawdzanie spójności (%1) - + Reset autoincrement Wyzeruj autoinkrementację - + Are you sure you want to reset autoincrement value for table '%1'? Czy na pewno chcesz wyzerować wartość autoinkrementacji dla tabeli '%1'? - + An error occurred while trying to reset autoincrement value for table '%1': %2 Wystąpił błąd podczas próby wyzerowania wartości autoinkrementacji dla tabeli '%1': %2 @@ -2614,37 +2775,37 @@ Wszystkie obiekty z tej grupy zostaną przeniesione do nadrzędnej grupy.Czy na pewno chcesz usunąć wszystkie dane z tabeli '%1'? - + An error occurred while trying to delete data from table '%1': %2 Wystąpił błąd podczas próby usunięcia danych z tabeli '%1': %2 - + All data has been deleted for table '%1'. Wszystkie dane z tabeli '%1' zostały usunięte. - + Following objects will be deleted: %1. Następujące obiekty zostaną usunięte: %1 - + Following databases will be removed from list: %1. Następujące bazy danych zostaną usunięte z listy: %1 - + Remainig objects from deleted group will be moved in place where the group used to be. Pozostałe obiekty z usuniętej grupy będą przeniesione w miejsce, gdzie dotychczas była ta grupa. - + %1<br><br>Are you sure you want to continue? %1<br><br>Czy na pewno chcesz kontynuować? - + Delete objects Usuń obiekty @@ -2738,76 +2899,76 @@ Wszystkie obiekty z tej grupy zostaną przeniesione do nadrzędnej grupy.Wyzwalacze (%1): - + Copy Kopiuj - + Move Przenieś - + Include data Również dane - + Include indexes Również indeksy - + Include triggers Również wyzwalacze - + Abort Przerwij - + Could not add dropped database file '%1' automatically. Manual setup is necessary. Nie udało się automatycznie dodać upuszczonego pliku bazy '%1'. Niezbędna ręczna ingerencja. - + Referenced tables Tabele powiązane - + Do you want to include following referenced tables as well: %1 Czy chcesz zawrzeć również powiązane tabele: %1 - + Name conflict Konflikt nazwy - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: Następująy obiekt istnieje już w docelowej bazie danych. Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przerwać operację. - + SQL statements conversion Konwersja zapytań SQL - + Following error occurred while converting SQL statements to the target SQLite version: Następujące błędy wystąpiły podczas konwersji zapytań SQL do docelowej wersji SQLite: - + Would you like to ignore those errors and proceed? Czy chcesz zignorować te błędy i kontynuować? @@ -2863,110 +3024,116 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Zapytanie - + History Historia - + Results in the separate tab Wyniki w osobnej karcie - + Results below the query Wyniki pod zapytaniem - - + + SQL editor %1 Edytor SQL %1 - + Results Wyniki - + Execute query Wykonaj zapytanie - + Explain query Wytłumacz zapytanie - + Clear execution history sql editor Wymaż historię zapytań - + Export results sql editor Wyeksportuj wyniki - + Create view from query sql editor Utwórz widok z zapytania - + Previous database Poprzednia baza danych - + Next database Następna baza danych - + Show next tab sql editor Pokaż następną kartę - + Show previous tab sql editor Pokaż poprzednią kartę - + Focus results below sql editor Aktywuj wyniki poniżej - + Focus SQL editor above sql editor Aktywuj edytor SQL powyżej - + + Delete selected SQL history entries + sql editor + Usuń wybrane wpisy z historii SQL + + + Active database (%1/%2) Aktywna baza danych (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 Zapytanie ukończone w %1 sekund(y). Liczba przetworzonych wierszy: %2 - + Query finished in %1 second(s). Zapytanie ukończone w %1 sekund(y). - + Editor window "%1" has uncommitted data. Okno edytora "%1" ma niezatwierdzone dane. @@ -2975,22 +3142,22 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Zapytanie ukończone w %2 sekund(y). - + Clear execution history Wymaż historię zapytań - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. Czy na pewno chcesz wymazać całą historię zapytań SQL? Tego nie można odwrócić. - + Cannot export, because no export plugin is loaded. Nie można wyeksportować, ponieważ żadna wtyczka eksportu nie została załadowana. - + No database selected in the SQL editor. Cannot create a view for unknown database. Nie wybrano bazdy danych w edytorze SQL. Nie można utworzyć widoku dla nieznanej bazy. @@ -3017,6 +3184,64 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Czy chcesz kontynuować? + + ExecFromFileDialog + + + Execute SQL from file + Wykonaj SQL z pliku + + + + Input file + Plik wejściowy + + + + Path to file + Ścieżka do pliku + + + + Browse for file + Przeglądaj pliki + + + + Options + Opcje + + + + File encoding + Kodowanie pliku + + + + Skip failing SQL statements + Pomiń zapytania z błędami + + + + SQL scripts (*.sql);;All files (*) + Skrypty SQL (*.sql);;Wszystkie pliki (*) + + + + Execute SQL file + Wykonaj plik SQL + + + + Please provide file to be executed. + Proszę podać plik do wykonania + + + + Provided file does not exist or cannot be read. + Podany plik nie istnieje, lub nie można go odczytać. + + ExportDialog @@ -3166,68 +3391,101 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Opcje formatu eksportowania - + Cancel Anuluj - - - + + + Select database to export. Wybierz bazę do eksportu. - + Select table to export. Wybierz tabelę do eksportu. - + Enter valid query to export. Wprowadź poprawne zapytanie do eksportu. - + Select at least one object to export. Wybierz przynajmniej jeden obiekt do eksportu. - + You must provide a file name to export to. Musisz podać nazwę pliku do którego należy wyeksportować. - + Path you provided is an existing directory. You cannot overwrite it. Ścieżka którą podałeś jest istniejącym katalogiem. Nie można go nadpisać. - + The directory '%1' does not exist. Katalog '%1' nie istnieje. - + The file '%1' exists and will be overwritten. Plik '%1' istnieje i zostanie nadpisany. - + All files (*) Wszystkie pliki (*) - + Pick file to export to Wybierz plik do eksportu - + Internal error during export. This is a bug. Please report it. Wystąpił wewnętrzny błąd podczas eksportu. To jest błąd programu. Proszę to zgłosić. + + FileExecErrorsDialog + + + Execution errors + Błędy wykonywania + + + + Following errors were encountered during execution of SQL statements from the file: + Następujące błędy wystąpiły podczas wykonywania zapytań SQL z pliku: + + + + SQL + SQL + + + + Error + Błąd + + + + Statements that were executed successfully were commited. + Wyniki zapytań, które zostały wykonane, zostały zatwierdzone. + + + + Statements that were executed successfully were rolled back. + Wyniki zapytań, które zostały wykonane zostały wycofane. + + FontEdit @@ -3248,49 +3506,49 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer FormView - + Commit row form view Zatwierdź wiersz - + Rollback row form view Wycofaj wiersz - + First row form view Pierwszy wiersz - + Previous row form view Poprzedni wiersz - + Next row form view Następny wiersz - + Last row form view Ostatni wiersz - + Insert new row form view Wstaw nowy wiersz - + Delete current row form view Usuń bieżący wiersz @@ -3349,13 +3607,13 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Kod inicjalizacji: - + Function implementation code: Kod implementacji funkcji: - + Final step implementation code: Kod implementacji ostatniego kroku: @@ -3495,7 +3753,7 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Options - OOpcje + Opcje @@ -3523,42 +3781,42 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Opcje źródła danych - + Cancel Anuluj - + If you type table name that doesn't exist, it will be created. Jeśli wpiszesz nazwę tabeli, która nie istnieje, to zostanie ona stworzona. - + Enter the table name Wprowadź nazwę tabeli - + Select import plugin. Wybierz wtyczkę importu - + You must provide a file to import from. Musisz podać plik z którego należy zaimportować. - + The file '%1' does not exist. Plik '%1' nie istnieje. - + Path you provided is a directory. A regular file is required. Ścieżka którą podałeś jest katalogiem. Wymagany jest zwykły plik. - + Pick file to import from Wybierz plik do importu @@ -3597,12 +3855,12 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Kolumna - + Collation Zestawienie - + Sort Sortowanie @@ -3782,273 +4040,406 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Pasek narzędzi widoku - + Configuration widgets Kontrolki konfiguracji - + Syntax highlighting engines Silniki podświetlania składni - + Data editors Edytory danych - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. Uruchomiono tryb debugowania. Wciśnij %1 lub wybierz menu 'Pomoc / Otwórz konsolę debugowania' aby otworzyć konsolę debugowania. - + Running in debug mode. Debug messages are printed to the standard output. Uruchomiono tryb debugowania. Wiadomości debugujące są wyświetlane na standardowym wyjściu. - + You need to restart application to make the language change take effect. Należy zrestartować aplikację, aby nastąpiła zmiana języka. - Open SQL editor - Otwórz edytor SQL + Otwórz edytor SQL - Open DDL history - Otwórz historię DDL + Otwórz historię DDL - Open SQL functions editor - Otwórz edytor funkcji SQL + Otwórz edytor funkcji SQL - Open collations editor - Otwórz edytor zestawień + Otwórz edytor zestawień - Import - Importuj + Importuj - Export - Eksportuj + Eksportuj - Open configuration dialog - Otwórz okno konfiguracji + Otwórz okno konfiguracji - Tile windows - Ustaw okna w płytki + Ustaw okna w płytki - Tile windows horizontally - Ustaw okno poziomo + Ustaw okno poziomo - Tile windows vertically - Ustaw okna pionowo + Ustaw okna pionowo - Cascade windows - Ustaw okna caskadowo + Ustaw okna kaskadowo - + Next window Następne okno - + Previous window Poprzednie okno - + Hide status field Ukryj pole statusu - Close selected window - Zamknij wybrane okno + Zamknij wybrane okno - Close all windows but selected - Zamknij wszystkie okna, oprócz wybranego + Zamknij wszystkie okna, oprócz wybranego - Close all windows - Zamknij wszystkie okna + Zamknij wszystkie okna - Restore recently closed window - Przywróć ostatnio zamknięte okno + Przywróć ostatnio zamknięte okno - Rename selected window - Zmień nazwę wybranego okna + Zmień nazwę wybranego okna - + Open Debug Console Otwórz Konsolę Debugowania - + Open CSS Console Otwórz konsolę CSS - Report a bug - Zgłoś błąd + Zgłoś błąd - Propose a new feature - Zgłoś pomysł + Zgłoś pomysł - About - O programie + O programie - Licenses - Licencje + Licencje - Open home page - Otwórz stronę domową + Otwórz stronę domową - Open forum page - Otwórz stronę forum + Otwórz stronę forum - User Manual - Podręcznik Użytkownika + Podręcznik Użytkownika - SQLite documentation - Dokumentacja SQLite + Dokumentacja SQLite - Report history - Historia zgłoszeń + Historia zgłoszeń - Check for updates - Sprawdź aktualizacje + Sprawdź aktualizacje - Database menubar - Baza danych + Baza danych - Structure menubar - Struktura + Struktura - View menubar - Widok + Widok - + Window list menubar view menu Lista okien - Tools menubar - Narzędzia + Narzędzia - Help - Pomoc + Pomoc - - Could not set style: %1 - main window + + Open SQL &editor + Otwórz &edytor SQL + + + + Open DDL &history + Otwórz &historię DDL + + + + Open SQL &functions editor + Otwórz edytor &funkcji SQL + + + + Open &collations editor + Otwórz edytor &zestawień + + + + Open ex&tension manager + O&twórzy menadżera rozszerzeń + + + + &Import + &Importuj + + + + E&xport + E&ksportuj + + + + Open confi&guration dialog + Otwórz okno konfi&guracji + + + + &Tile windows + Ustaw okna w pły&tki + + + + Tile windows &horizontally + Ustaw okno po&ziomo + + + + Tile windows &vertically + Ustaw okna pio&nowo + + + + &Cascade windows + Ustaw okna &kaskadowo + + + + Close selected &window + Zamknij &wybrane okno + + + + Close all windows &but selected + Zamknij wszystkie okna, &oprócz wybranego + + + + Close &all windows + Z&amknij wszystkie okna + + + + Re&store recently closed window + Przywróć o&statnio zamknięte okno + + + + &Rename selected window + Zmień nazwę wyb&ranego okna + + + + Report a &bug + Zgłoś &błąd + + + + Propose a new &feature + Zgłoś &pomysł + + + + &About + O progra&mie + + + + &Licenses + &Licencje + + + + Open home &page + Otwórz stronę &domową + + + + Open fo&rum page + Otwórz stronę &forum + + + + User &Manual + &Podręcznik Użytkownika + + + + SQLite &documentation + &Dokumentacja SQLite + + + + Bugs and feature &requests + Błęd&y i pomysły + + + + Check for &updates + Sprawdź akt&ualizacje + + + + &Database + menubar + Bazy &danych + + + + &Structure + menubar + &Struktura + + + + &View + menubar + &Widoki + + + + &Tools + menubar + &Narzędzia + + + + &Help + &Pomoc + + + + Could not set style: %1 + main window Nie udało się ustawić stylu: %1 - + Cannot export, because no export plugin is loaded. Nie można wyeksportować, ponieważ żadna wtyczka eksportu nie została załadowana. - + Cannot import, because no import plugin is loaded. Nie można zaimportować, ponieważ żadna wtyczka importu nie została załadowana. - + Rename window Zmień nazwę okna - + Enter new name for the window: Wprowadź nową nazwę dla okna: - + New updates are available. <a href="%1">Click here for details</a>. Nowe aktualizacje są dostępne: <a href="%1">Kliknij aby poznać szczegóły</a>. - + You're running the most recent version. No updates are available. Uruchomiona jest najnowsza wersja. Nie ma dostępnych aktualizacji. - + Database passed in command line parameters (%1) was already on the list under name: %2 Baza danych podana w parametrach linii poleceń (%1) była już na liście pod nazwą: %2 - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 Baza danych podana w linii poleceń (%1) jest tymczasowo dodana do listy pod nazwą: %2 - + Could not add database %1 to list. Nie udało się dodać bazy danych %1 do listy. @@ -4084,23 +4475,28 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Wartość null - + Configure editors for this data type Skonfiguruj edytory dla tego typu danych - + + Open another tab + Otwórz kolejną zakładkę + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. Wtyczka edytora danych '%1' nie jest załadowana, podczas gdy jest ona zdefiniowana do edycji typu danych '%1'. - + Deleted multieditor Usunięto - + Read only multieditor Tylko do odczytu @@ -4109,7 +4505,14 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer MultiEditorBool - + Boolean + Logiczna + + + + MultiEditorBoolPlugin + + Boolean Logiczna @@ -4117,7 +4520,14 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer MultiEditorDate - + Date + Data + + + + MultiEditorDatePlugin + + Date Data @@ -4125,7 +4535,14 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer MultiEditorDateTime - + Date & time + Data i czas + + + + MultiEditorDateTimePlugin + + Date & time Data i czas @@ -4133,7 +4550,14 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer MultiEditorHex - + Hex + Heks + + + + MultiEditorHexPlugin + + Hex Heks @@ -4145,7 +4569,15 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Liczba - + Number + numeric multi editor tab name + Liczba + + + + MultiEditorNumericPlugin + + Number numeric multi editor tab name Liczba @@ -4154,50 +4586,64 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer MultiEditorText - Text - Tekst + Tekst - + Tab changes focus Tabulator zmienia aktywność - + Cut Wytnij - + Copy Kopiuj - + Paste Wklej - + Delete Usuń - + Undo Cofnij - + Redo Przywróć + + MultiEditorTextPlugin + + + Text + Tekst + + MultiEditorTime - + Time + Czas + + + + MultiEditorTimePlugin + + Time Czas @@ -4274,37 +4720,40 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Komponent - + + This application will be closed and the update installer will start to download and install all the updates. + Aplikacja zostanie zamknięta i uruchomiony zostanie instalator aktualizacji, który ściągnie i zainstaluje wszystkie aktualizacje. + + Current version - Obecna wersja + Obecna wersja - + Update version Wersja aktualizacji - + Check for updates on startup Sprawdzaj aktualizacje na starcie - + Update to new version! Aktualizuj do nowej wersji! - The update will be automatically downloaded and installed. This will also restart application at the end. - Aktualizacja będzie pobrana i zainstalowana automatycznie. Spowoduje to również na końcu restart aplikacji. + Aktualizacja będzie pobrana i zainstalowana automatycznie. Spowoduje to również na końcu restart aplikacji. - + Not now. Nie teraz. - + Don't install the update and close this window. Nie instaluj aktualizacji i zamknij to okno. @@ -4356,32 +4805,32 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Zaludnij - + Abort Przerwij - + Configure Konfiguruj - + Populating configuration for this column is invalid or incomplete. Konfiguracja zaludniania dla tej kolumny jest niepoprawna lub niekompletna. - + Select database with table to populate Wybierz bazę danych z tabelą do zaludnienia - + Select table to populate Wybierz tabelę do zaludnienia - + You have to select at least one column. Musisz zaznaczyć przynajmniej jedną kolumnę. @@ -4456,129 +4905,134 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer nazwa zestawienia: %1 - + Data grid view Widok siatki danych - + Copy cell(s) contents to clipboard Skopiuj zawartość komórek do schowka. + Copy cell(s) contents together with header to clipboard + Skopiuj zawartość komórek z z nagłówkiem do schowka + + + Paste cell(s) contents from clipboard Wklej zawartość komórkek ze schowka. - + Set empty value to selected cell(s) Ustaw pustą wartość dla wybranych komórek - + Set NULL value to selected cell(s) Ustaw wartość NULL dla wybranych komórek - + Commit changes to cell(s) contents Zatwierdź zmiany dla zawartości komórek - + Rollback changes to cell(s) contents Wycofaj zmiany dla zawartości komórek - + Delete selected data row Usuń wybrane wiersze danych - + Insert new data row Wstaw nowy wiersz danych - + Open contents of selected cell in a separate editor Otwórz zawartość wybranej komórki w osobnym edytorze - + Total pages available: %1 Liczba dostępnych stron: %1 - + Total rows loaded: %1 Liczba załadowanych wierszy: %1 - + Data view (both grid and form) Widok danych (zarówno siatki i formularza) - + Refresh data Odśwież dane - + Switch to grid view of the data Przełącz do widoku siatki danych - + Switch to form view of the data Przełącz do widoku formularza danych - + Database list Lista baz - + Delete selected item Usuń zaznaczony element - + Clear filter contents Wyczyść zawartość filtra - + Refresh schema Odśwież schemat - + Refresh all schemas Odśwież wszystkie schematy - + Add database Dodaj bazę danych - + Select all items Zaznacz wszystkie elementy - + Copy selected item(s) Kopiuj zaznaczone elementy - + - + Paste from clipboard Wklej ze schowka @@ -4653,42 +5107,42 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Usuń bieżący wiersz - + Main window Okno główne - + Open SQL editor Otwórz edytor SQL - + Previous window Poprzednie okno - + Next window Następne okno - + Hide status area Ukryj pole statusu - + Open configuration dialog Otwórz okno konfiguracji - + Open Debug Console Otwórz Konsolę Debugowania - + Open CSS Console Otwórz konsolę CSS @@ -4699,111 +5153,111 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer - + Cut selected text Wytnij wybrany tekst - + Copy selected text Skopiuj wybrany tekst - + Delete selected text Usuń wybrany tekst - + Undo Cofnij - + Redo Przywróć - + SQL editor input field Pole wprowadzania edytora SQL - + Select whole editor contents Zaznacz całą zawartość edytora - + Save contents into a file Zapisz zawartość do pliku - + Load contents from a file Wczytaj zawartość z pliku - + Find in text Znajdź w tekście - + Find next Znajdź następny - + Find previous Znajdź poprzedni - + Replace in text Zmień w tekście - + Delete current line Usuń bieżącą linię - + Request code assistant Wywołaj asystenta kodu - + Format contents Formatuj zawartość - + Move selected block of text one line down Przenieś wybrany blok tekstu o jedną linię w dół - + Move selected block of text one line up Przenieś wybrany blok tekstu o jedną linię w górę - + Copy selected block of text and paste it a line below Skopiuj wybrany blok tekstu i wklej go poniżej - + Copy selected block of text and paste it a line above Skopiuj wybrany blok tekstu i wklej go powyżej - + Toggle comment Przełącz komentarz @@ -4824,14 +5278,12 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Plik bazy danych - Reports history window - Okno history zgłoszeń + Okno history zgłoszeń - Delete selected entry - Usuń wybraną pozycję + Usuń wybraną pozycję @@ -4878,6 +5330,11 @@ Proszę podać nową, unikalną nazwę, lub nacisnąć '%1', aby przer Move keyboard input focus to the SQL editor above Przenieś aktywność klawiatury do edytora SQL powyżej + + + Delete selected SQL history entries + Usuń wybrane wpisy z historii SQL + Table window @@ -5103,179 +5560,179 @@ znajdź następny SqlEditor - + Cut sql editor Wytnij - + Copy sql editor Kopiuj - + Paste sql editor Wklej - + Delete sql editor Usuń - + Select all sql editor Zaznacz wszystko - + Undo sql editor Cofnij - + Redo sql editor Przywróć - + Complete sql editor Dopełnij - + Format SQL sql editor Formatuj SQL - + Save SQL to file sql editor Zapisz SQL do pliku - + Select file to save SQL sql editor Wybierz plik do zapisu SQL - + Load SQL from file sql editor Wczytaj SQL z pliku - + Delete line sql editor Usuń linię - + Move block down sql editor Przesuń blok w dół - + Move block up sql editor Przesuń blok w górę - + Copy block down sql editor Skopiuj blok w dół - + Copy up down sql editor Skopiuj blok w górę - + Find sql editor Znajdź - + Find next sql editor Znajdź następny - + Find previous sql editor Znajdź poprzedni - + Replace sql editor Zastąp - + Toggle comment sql editor Przełącz komentarz - + Saved SQL contents to file: %1 Zapisano zawartość SQL do pliku: %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. Dopełnianie składni może być użyte tylko wtedy, gdy poprawna baza danych jest ustawiona w edytorze SQL. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. Zawartość edytora SQL jest ogromna, więc sprawdzanie błędów i podświetlanie istniejących obiektów zostało tymczasowo wyłączone. - + Save to file Zapisz do pliku - + Could not open file '%1' for writing: %2 Nie udało się otworzyć pliku '%1' do zapisu: %2 - + SQL scripts (*.sql);;All files (*) Skrypty SQL (*.sql);;Wszystkie pliki (*) - + Open file Otwórz plik - + Could not open file '%1' for reading: %2 Nie udało się otworzyć pliku '%1' do odczytu: %2 - + Reached the end of document. Hit the find again to restart the search. Osiągnięto koniec dokumentu. Wciśnij szukanie ponownie, aby zrestartować szukanie. @@ -5331,24 +5788,24 @@ znajdź następny - - + + Cannot edit this cell. Details: %1 Nie można edytować tej komórki. Szczegóły: %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. Struktura tej tabeli zmieniła się od ostatniego ładowania danych. Przeładuj dane, aby kontynuować. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). Edytowanie ogromnych ilości danych w podręcznym edytorze nie jest dobrym pomysłem. Może być on powolny i nieporęczny. Lepiej edytować takie duże ilości danych w Widoku Formularza, lub w osobnym oknie edytora (dostępnym w menu prawego kliknięcia myszy). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. Klucz obcy dla kolumny %2 ma więcej niż %1 możliwych wartości. To zbyt wiele, by wyświetlić w liście rozwijanej. Musisz edytować wartość ręcznie. @@ -5356,8 +5813,8 @@ znajdź następny SqlQueryModel - - + + Only one query can be executed simultaneously. Tylko jedno zapytanie może być wykonywane w danym momencie. @@ -5370,12 +5827,12 @@ znajdź następny Niektóre zmiany w danych nie zostały zatwierdzone. Czy na pewno chcesz kontynuować? Wszystkie niezatwierdzone zmiany zostaną utracone. - + Cannot commit the data for a cell that refers to the already closed database. Nie można zatwierdzić danych dla komórki, która odnosi się do zamkniętej już bazy danych. - + Could not begin transaction on the database. Details: %1 Nie udało się rozpocząć transakcji na bazie danych. Szczegóły: %1 @@ -5384,12 +5841,12 @@ znajdź następny Wystąpił błąd podczas zatwierdzania transakcji: %1 - + An error occurred while rolling back the transaction: %1 Wystąpił błąd podczas wycofywania transakcji: %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. Próbowano zatwierdzić komórkę, której nie można edytować (a mimo to została zmodyfikowana i czeka na zatwierdzenie)! To jest błąd. Proszę to zgłosić. @@ -5398,8 +5855,8 @@ znajdź następny Wystąpił błąd podczas zatwierdzania danych: %1 - - + + Error while executing SQL query on database '%1': %2 Błąd podczas wykonywania zapytania SQL na bazie '%1': %2 @@ -5408,37 +5865,42 @@ znajdź następny Błąd podczas wykonywania zapytania SQL: %1 - + Uncommitted data Niezatwierdzone dane - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. Niektóre zmiany w danych nie zostały zatwierdzone. Czy na pewno chcesz kontynuować? Wszystkie niezatwierdzone zmiany zostaną utracone. - + An error occurred while committing the transaction: %1 Wystąpił błąd podczas zatwierdzania transakcji: %1 - + An error occurred while committing the data: %1 Wystąpił błąd podczas zatwierdzania danych: %1 - + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + Liczba wierszy na stronę została zmniejszona do %1, w związku z liczbą kolumn (%2) w widoku danych. + + + Error while loading query results: %1 Błąd podczas wczytywania wyników zapytania: %1 - + Insert multiple rows Wstaw wiele wierszy - + Number of rows to insert: Liczba wierszy do wstawienia: @@ -5446,117 +5908,137 @@ znajdź następny SqlQueryView - + Go to referenced row in... Idź do powiązanego wiersza w... - + Copy Kopiuj - + Copy as... Kopiuj jako... - + Paste Wklej - + Paste as... Wklej jako... - + Set NULL values Ustaw wartości NULL - + Erase values Wymaż wartości - + Edit value in editor Edytuj wartość w edytorze - + Commit Zatwierdź - + + Copy with headers + Kopiuj z nagłówkami + + + Rollback Wycofaj - + Commit selected cells Zatwierdź zaznaczone komórki - + Rollback selected cells Wycofaj zaznaczone komórki - + Define columns to sort by Zdefiniuj kolumny po których sortować - + Remove custom sorting Wycofaj własne sortowanie - + Insert row Wstaw wiersz - + Insert multiple rows Wstaw wiele wierszy - + Delete selected row Usuń zaznaczony wiersz - + + Show value in a viewer + Pokaż wartość w przeglądarce + + + Generate query for selected cells Generuj zapytanie dla wybranych komórek - + No items selected to paste clipboard contents to. Nie wybrano elementów do których należy wkleić zawartość schowka. - + Go to referenced row in table '%1' Idź do powiązanego wiersza w tabeli '%1' - + table '%1' tabela '%1' - + Referenced row (%1) Powiązany wiersz (%1) - + + Trim pasted text? + Przyciąć wklejany tekst? + + + + The pasted text contains leading or trailing white space. Trim it automatically? + Wklejany tekst zawiera spacje na początku lub końcu. Czy przyciąć go automatycznie? + + + Edit value Edytuj wartość @@ -5578,6 +6060,119 @@ znajdź następny Błąd podczas usuwania wiersza z tabeli %1: %2 + + SqliteExtensionEditor + + + Filter extensions + Filtruj rozszerzenia + + + + Leave empty to use default function + Pozostaw puste, aby użyć domyślnej funkcji + + + + Extension file + Plik rozszerzenia + + + + Initialization function + Funkcja inicjalizująca + + + + Databases + Bazy danych + + + + Register in all databases + Zarejestruj we wszystkich bazach danych + + + + Register in following databases: + Zarejestruj w następujących bazach danych: + + + + Extension manager window has uncommitted modifications. + Okno menadżera rozszerzeń ma niezatwierdzone modyfikacje. + + + + Extension manager + Menadżer rozszerzeń + + + + Commit all extension changes + Zatwierdź wszystkie zmiany w rozszerzeniach + + + + Rollback all extension changes + Wycofaj wszystkie zmiany w rozszerzeniach + + + + Add new extension + Dodaj nowe rozszerzenie + + + + Remove selected extension + Usuń wybrane rozszerzenie + + + + Editing extensions manual + Podręcznik edytowania rozszerzeń + + + + File with given path does not exist or is not readable. + Plik o podanej ścieżce nie istnieje lub nie można go odczytać. + + + + Unable to load extension: %1 + Nie można załadować rozszerzenia: %1 + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + Niepoprawna nazwa funkcji inicjalizującej. Nazwa funkcji może zawierać jedynie znaki alfanumeryczne i znak podkreślenia. + + + + Dynamic link libraries (*.dll);;All files (*) + Biblioteki linkowania dynamicznego (*.dll);;Wszystkie pliki (*) + + + + Shared objects (*.so);;All files (*) + Obiekty wspóldzielone (*.so);;Wszystkie pliki (*) + + + + Dynamic libraries (*.dylib);;All files (*) + Biblioteki dynamiczne (*.dylib);;Wszystkie pliki (*) + + + + All files (*) + Wszystkie pliki (*) + + + + Open file + Otwórz plik + + StatusField @@ -5687,7 +6282,7 @@ ale można ich używać. Wprowadź nazwę ograniczenia. - + Foreign column table constraints Kolumna obca @@ -5741,24 +6336,24 @@ ale można ich używać. W razie konfliktu - + Collate table constraints Zestawienie - + Sort order table constraints Kierunek sortowania - + Select at least one column. Zaznacz przynajmniej jedną kolumnę. - + Enter a name of the constraint. Wprowadź nazwę ograniczenia. @@ -6357,7 +6952,7 @@ Czy chcesz zatwierdzić strukturę, czy jednak chcesz wrócić do karty struktur - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> <p>Warunek SQL, który będzie wykonany przed właściwym kodem wyzwalacza. W przypadku gdy warunek zwróci fałsz, wyzwalacz nie zostanie uruchomiony dla tego wiersza.</p> @@ -6402,7 +6997,7 @@ Czy chcesz zatwierdzić strukturę, czy jednak chcesz wrócić do karty struktur Zapytania wyzwalacz do wykonania. - + DDL DDL @@ -6481,18 +7076,18 @@ Czy chcesz zatwierdzić strukturę, czy jednak chcesz wrócić do karty struktur Nazwy kolumn wyjściowych - - + + Data Dane - + Triggers Wyzwalacze - + DDL DDL @@ -6536,121 +7131,121 @@ Czy chcesz zatwierdzić strukturę, czy jednak chcesz wrócić do karty struktur Nowy widok %1 - + Refresh the view view window Odśwież widok - + Commit the view changes view window Zatwierdź zmiany w widoku - + Rollback the view changes view window Wycofaj zmiany w widoku - + Explicit column names Jawne nazwy kolumn - + Generate output column names automatically basing on result columns of the view. Generuj automatycznie nazwy kolumn wyjściowych bazując na kolumnach wynikowych widoku. - + Add column view window Dodaj kolumnę - + Edit column view window Edytuj kolumnę - + Delete column view window Usuń kolumnę - + Move column up view window Przesuń kolumnę w górę - + Move column down view window Przesuń kolumnę w dół - + Refresh trigger list view window Odśwież listę wyzwalaczy - + Create new trigger view window Utwórz nowy wyzwalacz - + Edit selected trigger view window Edytuj wybrany wyzwalacz - + Delete selected trigger view window Usuń wybrany wyzwalacz - + View window "%1" has uncommitted structure modifications and data. Okno widoku "%1" ma niezatwierdzone modyfikacje struktury i danych. - + View window "%1" has uncommitted data. Okno widoku "%1" ma niezatwierdzone dane. - + View window "%1" has uncommitted structure modifications. Okno widoku "%1" ma niezatwierdzone modyfikacje struktury. - + Uncommitted changes Niezatwierdzone zmiany - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? Zmiany w strukturze nie zostały zatwierdzone. Nie można przeglądać, ani edytować danych, dopóki struktura widoku nie zostanie ustalona. Czy chcesz zatwierdzić strukturę, czy jednak chcesz wrócić do karty struktury? - + Committed changes for view '%1' successfully. Pomyślnie zatwierdzono zmiany dla widoku '%1'. - + Committed changes for view '%1' (named before '%2') successfully. Pomyślnie zatwierdzono zmiany dla tabeli '%1' (nazwanej wcześniej '%2'). @@ -6667,7 +7262,7 @@ Czy chcesz zatwierdzić strukturę, czy jednak chcesz wrócić do karty struktur Okno widoku "%1" ma niezatwierdzone modyfikacje struktury. - + Could not load data for view %1. Error details: %2 Nie udało się załadować danych dla widoku %1. Szczegóły błędu: %2 @@ -6682,12 +7277,12 @@ Do you want to commit the structure, or do you want to go back to the structure Czy chcesz zatwierdzić strukturę, czy jednak chcesz wrócić do karty struktury? - + Go back to structure tab Wróć do karty struktury - + Commit modifications and browse data. Zatwierdź modyfikacje i przeglądaj dane. @@ -6700,86 +7295,86 @@ Czy chcesz zatwierdzić strukturę, czy jednak chcesz wrócić do karty struktur Pomyślnie zatwierdzono zmiany dla widoku '%1' (nazwanego wcześniej '%2'). - + Could not commit view changes. Error message: %1 view window Nie udało się zatwierdzić widoku. Treść błędu: %1 - + Override columns Nadpisz kolumny - + Currently defined columns will be overriden. Do you want to continue? Aktualnie zdefiniowane kolumny zostaną nadpisane. Czy chcesz kontynuować? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. Nie udało się ustalić kolumn zwracanych z widoku. Zapytanie jest prawdopodobnie niekompletne lub zawiera błędy. - + Name view window triggers Nazwa - + Instead of view window triggers Zamiast - + Condition view window triggers Warunek - + Details table window triggers Szczegóły - + Could not process the %1 view correctly. Unable to open a view window. Nie udało się przetworzyć poprawnie widoku %1. Nie można otworzyć okna widoku. - + Empty name Pusta nazwa - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? Pusta nazwa dla widoku jest dozwolona w SQLite, ale nie jest zalecana. Czy na pewno chcesz utworzyć widok o pustej nazwie? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 Zapytanie SELECT nie mogło być poprawnie przeanalizowane. Proszę poprawić zapytanie i spróbować ponownie. Szczegóły: %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! Widok nie mógł być zmodyfikowany w związku z wewnętrznym błędem SQLiteStudio. Proszę to zgłosić! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. Kod widok nie mógł być poprawnie przeanalizowany. To jest błąd SQLiteStudio Proszę to zgłosić! - + Following problems will take place while modifying the view. Would you like to proceed? view window @@ -6787,7 +7382,7 @@ Would you like to proceed? Czy chcesz kontynuować? - + View modification view window Modyfikacja widoku diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pt_BR.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pt_BR.ts index 4d51bcb..0d15aa6 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pt_BR.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_pt_BR.ts @@ -13,11 +13,6 @@ About - - - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> - - Licenses @@ -58,6 +53,11 @@ Configuration directory + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + + Qt version: @@ -90,258 +90,15 @@ - BugDialog - - - Bugs and ideas - - - - - Reporter - - - - - E-mail address - - - - - - Log in - - - - - Short description - - - - - Detailed description - - - - - Show more details - - - - - SQLiteStudio version - - - - - Operating system - - - - - Loaded plugins - - - - - Send - - - - - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - - - - - A bug report sent successfully. - - - - - An error occurred while sending a bug report: %1 -%2 - - - - - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - - - - - An idea proposal sent successfully. - - - - - An error occurred while sending an idea proposal: %1 -%2 - - - - - A bug report - - - - - Describe problem in few words - - - - - Describe problem and how to reproduce it - - - - - A new feature idea - - - - - A title for your idea - - - - - Describe your idea in more details - - - - - Reporting as an unregistered user, using e-mail address. - - - - - Reporting as a registered user. - - - - - Log out - - - - - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - - - - - Enter vaild e-mail address, or log in. - - - - - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - - - - - Long description requires at least 30 characters. - - - - - BugReportHistoryWindow + BindParamsDialog - - - Title + + Query parameters - - - Reported at - - - - - - URL - - - - - Reports history - - - - - Clear reports history - - - - - Delete selected entry - - - - - Invalid response from server. - - - - - BugReportLoginDialog - - - Log in - - - - - Credentials - - - - - Login: - - - - - Password: - - - - - Validation - - - - - Validate - - - - - Validation result message - - - - - Abort - - - - - A login must be at least 2 characters long. - - - - - A password must be at least 5 characters long. - - - - - Valid + + Please provide values for query parameters @@ -353,12 +110,12 @@ - + Collation name: - + Implementation language: @@ -483,11 +240,16 @@ - Invalid default value expression: %1 + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. - + Enter a name of the constraint. @@ -599,7 +361,7 @@ - + Delete constraint column dialog @@ -659,34 +421,44 @@ - + Are you sure you want to delete constraint '%1'? column dialog - + Correct the constraint's configuration. - + This constraint is not officially supported by SQLite 2, but it's okay to use it. - + Scale is not allowed for INTEGER PRIMARY KEY columns. - + Precision cannot be defined without the scale. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. @@ -787,12 +559,6 @@ but it's okay to use it. Enter a name of the constraint. - - - Autoincrement (only for %1 type columns) - column primary key - - ColumnUniqueAndNotNullPanel @@ -903,7 +669,7 @@ but it's okay to use it. ConfigDialog - + Configuration @@ -993,215 +759,215 @@ but it's okay to use it. - + Number of data rows per page: - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> - + Limit initial data column width to (in pixels): - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> - + Show column and row details tooltip in data view - + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> - + Inserting new row in data grid - + Before currently selected row - + After currently selected row - + At the end of data view - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> - + Place data tab as first tab in a Table Window - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> - + Place data tab as first tab in a View Window - + Data types - + Available editors: - + Editors selected for this data type: - + Schema editing - + Number of DDL changes kept in history. - + DDL history size: - + SQL queries - - + + Number of queries kept in the history. - + History size: - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> - + Execute only the query under the cursor - + Updates - + Automatically check for updates at startup - + Session - + Restore last session (active MDI windows) after startup - + Status Field - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> - + Always open Status panel when new message is printed - + Filter shortcuts by name or key combination - + Action - + Key combination - - + + Language - + Changing language requires application restart to take effect. - + Compact layout - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> - + Use compact layout @@ -1277,350 +1043,372 @@ but it's okay to use it. - + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + + + + + Number of memorized table populating configurations + + + + Keep NULL value when entering empty value - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> - + Use DEFAULT value (if defined), when committing NULL value - + Table windows - + Open Table Windows with the data tab for start - + View windows - + Open View Windows with the data tab for start - + Don't show DDL preview dialog when committing schema changes - + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + Number of memorized query parameters + + + + Main window dock areas - + Left and right areas occupy corners - + Top and bottom areas occupy corners - + Hide built-in plugins - + Current style: - + Preview - + Enabled - + Disabled - + Active formatter plugin - + SQL editor font - + Database list font - + Database list additional label font - + Data view font - + Status field font - + SQL editor colors - + Current line background - + <p>SQL strings are enclosed with single quote characters.</p> - + String foreground - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> - + Bind parameter foreground - + Highlighted parenthesis background - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground - + Regular foreground - + Line numbers area background - + Keyword foreground - + Number foreground - + Comment foreground - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> - + Valid objects foreground - + Data view colors - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> - + Uncommitted data outline color - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> - + Commit error outline color - + NULL value foreground - + Deleted row background - + Database list colors - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> - + Additional labels foreground - + Status field colors - + Information message foreground - + Warning message foreground - + Error message foreground - + Description: plugin details - + Category: plugin details - + Version: plugin details - + Author: plugin details - + Internal name: plugin details - + Dependencies: plugin details - + Conflicts: plugin details - + Plugin details - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. - + %1 (built-in) plugins manager in configuration dialog - + Details - + No plugins in this category. - + Add new data type - + Rename selected data type - + Delete selected data type - + Help for configuring data type editors @@ -1772,137 +1560,153 @@ but it's okay to use it. DataView - + Filter data data view - + Grid view - + Form view - + Refresh table data data view - + First page data view - + Previous page data view - + Next page data view - + Last page data view - + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + Apply filter data view - + Commit changes for selected cells data view - + Rollback changes for selected cells data view - + Show grid view of results sql editor - + Show form view of results sql editor - + Filter by text data view - + Filter by the Regular Expression data view - + Filter by SQL expression data view - + Tabs on top data view - + Tabs at bottom data view - + Place new rows above selected row data view - + Place new rows below selected row data view - + Place new rows at the end of the data view data view - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. - + Row: %1 @@ -2081,7 +1885,7 @@ Browsing other pages will be possible after the row counting is done. - <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> @@ -2183,352 +1987,397 @@ Browsing other pages will be possible after the row counting is done. - + Copy - + Paste - + Select all - + Create a group - + Delete the group - + Rename the group - - Add a database + + Import - - Edit the database + + Export the table - - Remove the database + + Import into the table - - Connect to the database + + Populate table - - Disconnect from the database + + Create similar table - - Import + + Reset autoincrement sequence - - Export the database + + Add a column - - Convert database type + + Edit the column - - Vacuum + + Delete the column - - Integrity check + + Delete selected items - - Create a table + + Clear filter - - Edit the table + + + Erase table data - - Delete the table + + + Database - - Export the table + + Grouping - - Import into the table + + Generate query for table - - Populate table + + + Create group - - Create similar table + + Group name - - Reset autoincrement sequence + + Entry with name %1 already exists in group %2. - - Create an index + + Delete group - - Edit the index + + Are you sure you want to delete group %1? +All objects from this group will be moved to parent group. - - Delete the index + + Are you sure you want to remove database '%1' from the list? - - Create a trigger + + Are you sure you want to remove following databases from the list: +%1 - - Edit the trigger + + Remove database - - Delete the trigger + + Vacuum (%1) - - Create a view + + Autoincrement value for table '%1' has been reset successfully. - - Edit the view + + Are you sure you want to delete all data from table(s): %1? - - Delete the view + + + Cannot import, because no import plugin is loaded. - - Add a column + + Execution from file cancelled. Any queries executed so far have been rolled back. - - Edit the column + + &Add a database - - Delete the column + + &Edit the database - - Delete selected items + + &Remove the database - - Clear filter + + &Connect to the database - - Refresh all database schemas + + &Disconnect from the database - - Refresh selected database schema + + &Export the database - - - Erase table data + + Con&vert database type - - - Database + + Vac&uum - - Grouping + + &Integrity check - - Generate query for table + + Create a &table - - - Create group + + Edit the t&able - - Group name + + Delete the ta&ble - - Entry with name %1 already exists in group %2. + + Create an &index - - Delete group + + Edit the i&ndex - - Are you sure you want to delete group %1? -All objects from this group will be moved to parent group. + + Delete the in&dex - - Are you sure you want to remove database '%1' from the list? + + Create a trig&ger - - Are you sure you want to remove following databases from the list: -%1 + + Edit the trigg&er - - Remove database + + Delete the trigge&r - - Vacuum (%1) + + Create a &view - - Autoincrement value for table '%1' has been reset successfully. + + Edit the v&iew - - Are you sure you want to delete all data from table(s): %1? + + Delete the vi&ew - - - Cannot import, because no import plugin is loaded. + + &Refresh all database schemas + + + + + Re&fresh selected database schema - - + + Open file's directory + + + + + Execute SQL from file + + + + + Cannot export, because no export plugin is loaded. - + Integrity check (%1) - + Reset autoincrement - + Are you sure you want to reset autoincrement value for table '%1'? - + An error occurred while trying to reset autoincrement value for table '%1': %2 - + An error occurred while trying to delete data from table '%1': %2 - + All data has been deleted for table '%1'. - + Following objects will be deleted: %1. - + Following databases will be removed from list: %1. - + Remainig objects from deleted group will be moved in place where the group used to be. - + %1<br><br>Are you sure you want to continue? - + Delete objects + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. + + DbTreeItemDelegate @@ -2614,74 +2463,74 @@ All objects from this group will be moved to parent group. - + Copy - + Move - + Include data - + Include indexes - + Include triggers - + Abort - + Could not add dropped database file '%1' automatically. Manual setup is necessary. - + Referenced tables - + Do you want to include following referenced tables as well: %1 - + Name conflict - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: - + SQL statements conversion - + Following error occurred while converting SQL statements to the target SQLite version: - + Would you like to ignore those errors and proceed? @@ -2735,130 +2584,136 @@ Please enter new, unique name, or press '%1' to abort the operation: - + History - + Results in the separate tab - + Results below the query - - + + SQL editor %1 - + Results - + Execute query - + Explain query - + Clear execution history sql editor - + Export results sql editor - + Create view from query sql editor - + Previous database - + Next database - + Show next tab sql editor - + Show previous tab sql editor - + Focus results below sql editor - + Focus SQL editor above sql editor - + + Delete selected SQL history entries + sql editor + + + + Active database (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 - + Query finished in %1 second(s). - + Clear execution history - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. - + Cannot export, because no export plugin is loaded. - + No database selected in the SQL editor. Cannot create a view for unknown database. - + Editor window "%1" has uncommitted data. @@ -2881,6 +2736,64 @@ Please enter new, unique name, or press '%1' to abort the operation: + + ExecFromFileDialog + + + Execute SQL from file + + + + + Input file + + + + + Path to file + + + + + Browse for file + + + + + Options + + + + + File encoding + + + + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + ExportDialog @@ -3030,68 +2943,101 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cancel - - - + + + Select database to export. - + Select table to export. - + Enter valid query to export. - + Select at least one object to export. - + You must provide a file name to export to. - + Path you provided is an existing directory. You cannot overwrite it. - + The directory '%1' does not exist. - + The file '%1' exists and will be overwritten. - + All files (*) - + Pick file to export to - + Internal error during export. This is a bug. Please report it. + + FileExecErrorsDialog + + + Execution errors + + + + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + FontEdit @@ -3112,49 +3058,49 @@ Please enter new, unique name, or press '%1' to abort the operation: FormView - + Commit row form view - + Rollback row form view - + First row form view - + Previous row form view - + Next row form view - + Last row form view - + Insert new row form view - + Delete current row form view @@ -3213,13 +3159,13 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Function implementation code: - + Final step implementation code: @@ -3383,42 +3329,42 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cancel - + If you type table name that doesn't exist, it will be created. - + Enter the table name - + Select import plugin. - + You must provide a file to import from. - + The file '%1' does not exist. - + Path you provided is a directory. A regular file is required. - + Pick file to import from @@ -3457,12 +3403,12 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Collation - + Sort @@ -3641,273 +3587,278 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Configuration widgets - + Syntax highlighting engines - + Data editors - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. - + Running in debug mode. Debug messages are printed to the standard output. - + You need to restart application to make the language change take effect. - - Open SQL editor + + Next window - - Open DDL history + + Previous window - - Open SQL functions editor + + Hide status field - - Open collations editor + + Open Debug Console - - Import + + Open CSS Console - - Export + + Bugs and feature &requests - - Open configuration dialog + + Window list + menubar view menu - - Tile windows + + Open SQL &editor - - Tile windows horizontally + + Open DDL &history - - Tile windows vertically + + Open SQL &functions editor - - Cascade windows + + Open &collations editor - - Next window + + Open ex&tension manager - - Previous window + + &Import - - Hide status field + + E&xport - - Close selected window + + Open confi&guration dialog - - Close all windows but selected + + &Tile windows - - Close all windows + + Tile windows &horizontally - - Restore recently closed window + + Tile windows &vertically - - Rename selected window + + &Cascade windows - - Open Debug Console + + Close selected &window - - Open CSS Console + + Close all windows &but selected - - Report a bug + + Close &all windows - - Propose a new feature + + Re&store recently closed window - - About + + &Rename selected window - - Licenses + + Report a &bug + + + + + Propose a new &feature - - Open home page + + &About - - Open forum page + + &Licenses - - User Manual + + Open home &page - - SQLite documentation + + Open fo&rum page - - Report history + + User &Manual - - Check for updates + + SQLite &documentation - - Database - menubar + + Check for &updates - - Structure + + &Database menubar - - View + + &Structure menubar - - Window list - menubar view menu + + &View + menubar - - Tools + + &Tools menubar - - Help + + &Help - + Could not set style: %1 main window - + Cannot export, because no export plugin is loaded. - + Cannot import, because no import plugin is loaded. - + Rename window - + Enter new name for the window: - + New updates are available. <a href="%1">Click here for details</a>. - + You're running the most recent version. No updates are available. - + Database passed in command line parameters (%1) was already on the list under name: %2 - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 - + Could not add database %1 to list. @@ -3939,64 +3890,69 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Configure editors for this data type - + + Open another tab + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. - + Deleted multieditor - + Read only multieditor - MultiEditorBool + MultiEditorBoolPlugin - + Boolean - MultiEditorDate + MultiEditorDatePlugin - + Date - MultiEditorDateTime + MultiEditorDateTimePlugin - + Date & time - MultiEditorHex + MultiEditorHexPlugin - + Hex - MultiEditorNumeric + MultiEditorNumericPlugin - + Number numeric multi editor tab name @@ -4005,50 +3961,53 @@ Please enter new, unique name, or press '%1' to abort the operation: MultiEditorText - - Text - - - - + Tab changes focus - + Cut - + Copy - + Paste - + Delete - - Undo + + Undo + + + + + Redo + + + MultiEditorTextPlugin - - Redo + + Text - MultiEditorTime + MultiEditorTimePlugin - + Time @@ -4125,37 +4084,32 @@ Please enter new, unique name, or press '%1' to abort the operation: - - Current version + + This application will be closed and the update installer will start to download and install all the updates. - + Update version - + Check for updates on startup - + Update to new version! - - The update will be automatically downloaded and installed. This will also restart application at the end. - - - - + Not now. - + Don't install the update and close this window. @@ -4207,32 +4161,32 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Abort - + Configure - + Populating configuration for this column is invalid or incomplete. - + Select database with table to populate - + Select table to populate - + You have to select at least one column. @@ -4307,129 +4261,134 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Data grid view - + Copy cell(s) contents to clipboard - Paste cell(s) contents from clipboard + Copy cell(s) contents together with header to clipboard + Paste cell(s) contents from clipboard + + + + Set empty value to selected cell(s) - + Set NULL value to selected cell(s) - + Commit changes to cell(s) contents - + Rollback changes to cell(s) contents - + Delete selected data row - + Insert new data row - + Open contents of selected cell in a separate editor - + Total pages available: %1 - + Total rows loaded: %1 - + Data view (both grid and form) - + Refresh data - + Switch to grid view of the data - + Switch to form view of the data - + Database list - + Delete selected item - + Clear filter contents - + Refresh schema - + Refresh all schemas - + Add database - + Select all items - + Copy selected item(s) - + - + Paste from clipboard @@ -4504,42 +4463,42 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Main window - + Open SQL editor - + Previous window - + Next window - + Hide status area - + Open configuration dialog - + Open Debug Console - + Open CSS Console @@ -4550,111 +4509,111 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cut selected text - + Copy selected text - + Delete selected text - + Undo - + Redo - + SQL editor input field - + Select whole editor contents - + Save contents into a file - + Load contents from a file - + Find in text - + Find next - + Find previous - + Replace in text - + Delete current line - + Request code assistant - + Format contents - + Move selected block of text one line down - + Move selected block of text one line up - + Copy selected block of text and paste it a line below - + Copy selected block of text and paste it a line above - + Toggle comment @@ -4674,16 +4633,6 @@ Please enter new, unique name, or press '%1' to abort the operation:Database file - - - Reports history window - - - - - Delete selected entry - - SQL editor window @@ -4729,6 +4678,11 @@ Please enter new, unique name, or press '%1' to abort the operation:Move keyboard input focus to the SQL editor above + + + Delete selected SQL history entries + + Table window @@ -4947,179 +4901,179 @@ find next SqlEditor - + Cut sql editor - + Copy sql editor - + Paste sql editor - + Delete sql editor - + Select all sql editor - + Undo sql editor - + Redo sql editor - + Complete sql editor - + Format SQL sql editor - + Save SQL to file sql editor - + Select file to save SQL sql editor - + Load SQL from file sql editor - + Delete line sql editor - + Move block down sql editor - + Move block up sql editor - + Copy block down sql editor - + Copy up down sql editor - + Find sql editor - + Find next sql editor - + Find previous sql editor - + Replace sql editor - + Toggle comment sql editor - + Saved SQL contents to file: %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. - + Save to file - + Could not open file '%1' for writing: %2 - + SQL scripts (*.sql);;All files (*) - + Open file - + Could not open file '%1' for reading: %2 - + Reached the end of document. Hit the find again to restart the search. @@ -5167,24 +5121,24 @@ find next - - + + Cannot edit this cell. Details: %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. @@ -5192,69 +5146,74 @@ find next SqlQueryModel - - + + Only one query can be executed simultaneously. - + Cannot commit the data for a cell that refers to the already closed database. - + Could not begin transaction on the database. Details: %1 - + An error occurred while rolling back the transaction: %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. - + Uncommitted data - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. - + An error occurred while committing the transaction: %1 - + An error occurred while committing the data: %1 - - + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + + + + + Error while executing SQL query on database '%1': %2 - + Error while loading query results: %1 - + Insert multiple rows - + Number of rows to insert: @@ -5262,117 +5221,137 @@ find next SqlQueryView - + Go to referenced row in... - + Copy - + Copy as... - + Paste - + Paste as... - + Set NULL values - + Erase values - + Edit value in editor - + Commit - + + Copy with headers + + + + Rollback - + Commit selected cells - + Rollback selected cells - + Define columns to sort by - + Remove custom sorting - + Insert row - + Insert multiple rows - + Delete selected row - + + Show value in a viewer + + + + Generate query for selected cells - + No items selected to paste clipboard contents to. - + Go to referenced row in table '%1' - + table '%1' - + Referenced row (%1) - + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + Edit value @@ -5390,6 +5369,119 @@ find next + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + + + + + Register in all databases + + + + + Register in following databases: + + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + + + + + Open file + + + StatusField @@ -5498,7 +5590,7 @@ but it's okay to use them anyway. - + Foreign column table constraints @@ -5552,24 +5644,24 @@ but it's okay to use them anyway. - + Collate table constraints - + Sort order table constraints - + Select at least one column. - + Enter a name of the constraint. @@ -6120,7 +6212,7 @@ Are you sure you want to create a table with blank name? - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> @@ -6165,7 +6257,7 @@ Are you sure you want to create a table with blank name? - + DDL @@ -6243,18 +6335,18 @@ Are you sure you want to create a table with blank name? - - + + Data - + Triggers - + DDL @@ -6286,224 +6378,224 @@ Are you sure you want to create a table with blank name? - + Refresh the view view window - + Commit the view changes view window - + Rollback the view changes view window - + Explicit column names - + Generate output column names automatically basing on result columns of the view. - + Add column view window - + Edit column view window - + Delete column view window - + Move column up view window - + Move column down view window - + Refresh trigger list view window - + Create new trigger view window - + Edit selected trigger view window - + Delete selected trigger view window - + View window "%1" has uncommitted structure modifications and data. - + View window "%1" has uncommitted data. - + View window "%1" has uncommitted structure modifications. - + Uncommitted changes - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Committed changes for view '%1' successfully. - + Committed changes for view '%1' (named before '%2') successfully. - + Could not load data for view %1. Error details: %2 - + Go back to structure tab - + Commit modifications and browse data. - + Could not commit view changes. Error message: %1 view window - + Override columns - + Currently defined columns will be overriden. Do you want to continue? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. - + Name view window triggers - + Instead of view window triggers - + Condition view window triggers - + Details table window triggers - + Could not process the %1 view correctly. Unable to open a view window. - + Empty name - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. - + Following problems will take place while modifying the view. Would you like to proceed? view window - + View modification view window diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ro_RO.qm b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ro_RO.qm new file mode 100644 index 0000000..2856eb9 Binary files /dev/null and b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ro_RO.qm differ diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ro_RO.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ro_RO.ts new file mode 100644 index 0000000..5df742d --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ro_RO.ts @@ -0,0 +1,6612 @@ + + + + + AboutDialog + + + About SQLiteStudio and licenses + + + + + About + + + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + + + + + Licenses + + + + + Environment + + + + + Icon directories + + + + + Form directories + + + + + Plugin directories + + + + + Configuration directory + + + + + Application directory + + + + + Qt version: + + + + + SQLite 3 version: + + + + + Portable distribution. + + + + + MacOS X application boundle distribution. + + + + + Operating system managed distribution. + + + + + Copy + + + + + <h3>Table of contents:</h3><ol>%2</ol> + + + + + BindParamsDialog + + + Query parameters + + + + + Please provide values for query parameters + + + + + CollationsEditor + + + Filter collations + + + + + Databases + + + + + Register in all databases + + + + + Register in following databases: + + + + + Implementation code: + + + + + Collation name: + + + + + Implementation language: + + + + + Collations editor + + + + + Commit all collation changes + + + + + Rollback all collation changes + + + + + Create new collation + + + + + Delete selected collation + + + + + Editing collations manual + + + + + Enter a non-empty, unique name of the collation. + + + + + Pick the implementation language. + + + + + Enter a non-empty implementation code. + + + + + Collations editor window has uncommitted modifications. + + + + + ColorButton + + + Pick a color + + + + + ColumnCollatePanel + + + Collation name: + + + + + Named constraint: + + + + + Enter a name of the constraint. + + + + + Enter a collation name. + + + + + ColumnDefaultPanel + + + Default value: + + + + + Named constraint: + + + + + Enter a default value expression. + + + + + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Enter a name of the constraint. + + + + + ColumnDialog + + + Column + + + + + Name and type + + + + + Scale + + + + + Precision + + + + + Data type: + + + + + Column name: + + + + + Size: + + + + + Constraints + + + + + Unique + + + + + + + + + + + Configure + + + + + Foreign Key + + + + + Collate + + + + + Not NULL + + + + + Check condition + + + + + Primary Key + + + + + Default + + + + + Advanced mode + + + + + Add constraint + column dialog + + + + + Edit constraint + column dialog + + + + + + Delete constraint + column dialog + + + + + Move constraint up + column dialog + + + + + Move constraint down + column dialog + + + + + Add a primary key + column dialog + + + + + Add a foreign key + column dialog + + + + + Add an unique constraint + column dialog + + + + + Add a check constraint + column dialog + + + + + Add a not null constraint + column dialog + + + + + Add a collate constraint + column dialog + + + + + Add a default constraint + column dialog + + + + + Are you sure you want to delete constraint '%1'? + column dialog + + + + + Correct the constraint's configuration. + + + + + This constraint is not officially supported by SQLite 2, +but it's okay to use it. + + + + + Scale is not allowed for INTEGER PRIMARY KEY columns. + + + + + Precision cannot be defined without the scale. + + + + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. + + + + + ColumnDialogConstraintsModel + + + Type + column dialog constraints + + + + + Name + column dialog constraints + + + + + Details + column dialog constraints + + + + + ColumnForeignKeyPanel + + + Foreign table: + + + + + Foreign column: + + + + + Reactions + + + + + Deferred foreign key + + + + + Named constraint + + + + + Constraint name + + + + + Pick the foreign table. + + + + + Pick the foreign column. + + + + + Enter a name of the constraint. + + + + + ColumnPrimaryKeyPanel + + + Autoincrement + + + + + Sort order: + + + + + Named constraint: + + + + + On conflict: + + + + + Enter a name of the constraint. + + + + + ColumnUniqueAndNotNullPanel + + + Named constraint: + + + + + On conflict: + + + + + Enter a name of the constraint. + + + + + CompleterWindow + + + Column: %1 + completer statusbar + + + + + Table: %1 + completer statusbar + + + + + Index: %1 + completer statusbar + + + + + Trigger: %1 + completer statusbar + + + + + View: %1 + completer statusbar + + + + + Database: %1 + completer statusbar + + + + + Keyword: %1 + completer statusbar + + + + + Function: %1 + completer statusbar + + + + + Operator: %1 + completer statusbar + + + + + String + completer statusbar + + + + + Number + completer statusbar + + + + + Binary data + completer statusbar + + + + + Collation: %1 + completer statusbar + + + + + Pragma function: %1 + completer statusbar + + + + + ConfigDialog + + + + Configuration + + + + + Search + + + + + General + + + + + Keyboard shortcuts + + + + + Look & feel + + + + + Style + + + + + Fonts + + + + + Colors + + + + + + Database list + + + + + Data browsing + + + + + Data editors + + + + + Plugins + + + + + Code formatters + + + + + If switched off, then columns will be sorted in the order they are typed in CREATE TABLE statement. + + + + + Sort table columns alphabetically + + + + + Expand tables node when connected to a database + + + + + <p>Additional labels are those displayed next to the names on the databases list (they are blue, unless configured otherwise). Enabling this option will result in labels for databases, invalid databases and aggregated nodes (column group, index group, trigger group). For more labels see options below.<p> + + + + + Display additional labels on the list + + + + + For regular tables labels will show number of columns, indexes and triggers for each of tables. + + + + + Display labels for regular tables + + + + + Virtual tables will be marked with a 'virtual' label. + + + + + Display labels for virtual tables + + + + + Expand views node when connected to a database + + + + + If this option is switched off, then objects will be sorted in order they appear in sqlite_master table (which is in order they were created) + + + + + Sort objects (tables, indexes, triggers and views) alphabetically + + + + + Display system tables and indexes on the list + + + + + Database dialog window + + + + + <p>When adding new database it is marked to be "permanent" (stored in configuration) by default. Checking this option makes every new database to NOT be "permanent" by default.</p> + + + + + Do not mark database to be "permanent" by default + + + + + <p>When this option is enabled, then files dropped from file manager onto database list will be automatically added to the list, bypassing standard database dialog. If for various reasons automatic process fails, then standard dialog will be presented to the user.</p> + + + + + Try to bypass dialog completly when dropping database file onto the list + + + + + Data browsing and editing + + + + + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> + + + + + Limit initial data column width to (in pixels): + + + + + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> + + + + + Show column and row details tooltip in data view + + + + + Number of data rows per page: + + + + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + + + + + Number of memorized table populating configurations + + + + + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> + + + + + Keep NULL value when entering empty value + + + + + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> + + + + + Use DEFAULT value (if defined), when committing NULL value + + + + + Inserting new row in data grid + + + + + Before currently selected row + + + + + After currently selected row + + + + + At the end of data view + + + + + Table windows + + + + + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> + + + + + Open Table Windows with the data tab for start + + + + + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> + + + + + Place data tab as first tab in a Table Window + + + + + View windows + + + + + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> + + + + + Open View Windows with the data tab for start + + + + + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> + + + + + Place data tab as first tab in a View Window + + + + + Data types + + + + + Available editors: + + + + + Editors selected for this data type: + + + + + Schema editing + + + + + Number of DDL changes kept in history. + + + + + DDL history size: + + + + + Don't show DDL preview dialog when committing schema changes + + + + + SQL queries + + + + + + Number of queries kept in the history. + + + + + History size: + + + + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> + + + + + Execute only the query under the cursor + + + + + Number of memorized query parameters + + + + + Updates + + + + + Automatically check for updates at startup + + + + + Session + + + + + Restore last session (active MDI windows) after startup + + + + + Status Field + + + + + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> + + + + + Always open Status panel when new message is printed + + + + + Filter shortcuts by name or key combination + + + + + Action + + + + + Key combination + + + + + + Language + + + + + Changing language requires application restart to take effect. + + + + + Compact layout + + + + + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> + + + + + Use compact layout + + + + + Main window dock areas + + + + + Left and right areas occupy corners + + + + + Top and bottom areas occupy corners + + + + + Hide built-in plugins + + + + + Current style: + + + + + Preview + + + + + Enabled + + + + + Disabled + + + + + Active formatter plugin + + + + + SQL editor font + + + + + Database list font + + + + + Database list additional label font + + + + + Data view font + + + + + Status field font + + + + + SQL editor colors + + + + + Current line background + + + + + <p>SQL strings are enclosed with single quote characters.</p> + + + + + String foreground + + + + + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> + + + + + Bind parameter foreground + + + + + Highlighted parenthesis background + + + + + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> + + + + + BLOB value foreground + + + + + Regular foreground + + + + + Line numbers area background + + + + + Keyword foreground + + + + + Number foreground + + + + + Comment foreground + + + + + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> + + + + + Valid objects foreground + + + + + Data view colors + + + + + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> + + + + + Uncommitted data outline color + + + + + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> + + + + + Commit error outline color + + + + + NULL value foreground + + + + + Deleted row background + + + + + Database list colors + + + + + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> + + + + + Additional labels foreground + + + + + Status field colors + + + + + Information message foreground + + + + + Warning message foreground + + + + + Error message foreground + + + + + Description: + plugin details + + + + + Category: + plugin details + + + + + Version: + plugin details + + + + + Author: + plugin details + + + + + Internal name: + plugin details + + + + + Dependencies: + plugin details + + + + + Conflicts: + plugin details + + + + + Plugin details + + + + + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. + + + + + %1 (built-in) + plugins manager in configuration dialog + + + + + Details + + + + + No plugins in this category. + + + + + Add new data type + + + + + Rename selected data type + + + + + Delete selected data type + + + + + Help for configuring data type editors + + + + + ConstraintCheckPanel + + + The condition + + + + + Named constraint: + + + + + On conflict + + + + + Enter a valid condition. + + + + + Enter a name of the constraint. + + + + + ConstraintDialog + + + New constraint + constraint dialog + + + + + Create + constraint dialog + + + + + Edit constraint + dialog window + + + + + Apply + constraint dialog + + + + + Primary key + table constraints + + + + + Foreign key + table constraints + + + + + Unique + table constraints + + + + + Not NULL + table constraints + + + + + Check + table constraints + + + + + Collate + table constraints + + + + + Default + table constraints + + + + + ConstraintTabModel + + + Table + table constraints + + + + + Column (%1) + table constraints + + + + + Scope + table constraints + + + + + Type + table constraints + + + + + Details + table constraints + + + + + Name + table constraints + + + + + CssDebugDialog + + + SQLiteStudio CSS console + + + + + DataView + + + Filter data + data view + + + + + Grid view + + + + + Form view + + + + + Refresh table data + data view + + + + + First page + data view + + + + + Previous page + data view + + + + + Next page + data view + + + + + Last page + data view + + + + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + + Apply filter + data view + + + + + Commit changes for selected cells + data view + + + + + Rollback changes for selected cells + data view + + + + + Show grid view of results + sql editor + + + + + Show form view of results + sql editor + + + + + Filter by text + data view + + + + + Filter by the Regular Expression + data view + + + + + Filter by SQL expression + data view + + + + + Tabs on top + data view + + + + + Tabs at bottom + data view + + + + + Place new rows above selected row + data view + + + + + Place new rows below selected row + data view + + + + + Place new rows at the end of the data view + data view + + + + + Total number of rows is being counted. +Browsing other pages will be possible after the row counting is done. + + + + + Row: %1 + + + + + DbConverterDialog + + + Convert database + + + + + Source database + + + + + Source database version: + + + + + Target database + + + + + Target version: + + + + + This is the file that will be created as a result of the conversion. + + + + + Target file: + + + + + Name of the new database: + + + + + This is the name that the converted database will be added to SQLiteStudio with. + + + + + Select source database + + + + + Enter valid and writable file path. + + + + + Entered file exists and will be overwritten. + + + + + Enter a not empty, unique name (as in the list of databases on the left). + + + + + No valid target dialect available. Conversion not possible. + + + + + Select valid target dialect. + + + + + Database %1 has been successfully converted and now is available under new name: %2 + + + + + SQL statements conversion + + + + + Following error occurred while converting SQL statements to the target SQLite version: + + + + + Would you like to ignore those errors and proceed? + + + + + DbDialog + + + Database + + + + + Database type + + + + + Database driver + + + + + + File + + + + + Create new database file + + + + + Name (on the list) + + + + + Options + + + + + <p>Enable this if you want the database to be stored in configuration file and restored every time SQLiteStudio is started.</p> + aasfd + + + + + Permanent (keep it in configuration) + + + + + Test connection + + + + + Browse for existing database file on local computer + + + + + Browse + + + + + Enter an unique database name. + + + + + This name is already in use. Please enter unique name. + + + + + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + + + + + Enter a database file path. + + + + + This database is already on the list under name: %1 + + + + + Select a database type. + + + + + DbObjectDialogs + + + Delete table + + + + + Are you sure you want to delete table %1? + + + + + Delete index + + + + + Are you sure you want to delete index %1? + + + + + Delete trigger + + + + + Are you sure you want to delete trigger %1? + + + + + Delete view + + + + + Are you sure you want to delete view %1? + + + + + + Error while dropping %1: %2 + + + + + Delete objects + + + + + Are you sure you want to delete following objects: +%1 + + + + + Cannot start transaction. Details: %1 + + + + + Cannot commit transaction. Details: %1 + + + + + DbTree + + + Databases + + + + + Filter by name + + + + + Copy + + + + + Paste + + + + + Select all + + + + + Create a group + + + + + Delete the group + + + + + Rename the group + + + + + Import + + + + + Export the table + + + + + Import into the table + + + + + Populate table + + + + + Create similar table + + + + + Reset autoincrement sequence + + + + + Add a column + + + + + Edit the column + + + + + Delete the column + + + + + Delete selected items + + + + + Clear filter + + + + + &Add a database + + + + + Execution from file cancelled. Any queries executed so far have been rolled back. + + + + + &Edit the database + + + + + &Remove the database + + + + + &Connect to the database + + + + + &Disconnect from the database + + + + + &Export the database + + + + + Con&vert database type + + + + + Vac&uum + + + + + &Integrity check + + + + + Create a &table + + + + + Edit the t&able + + + + + Delete the ta&ble + + + + + Create an &index + + + + + Edit the i&ndex + + + + + Delete the in&dex + + + + + Create a trig&ger + + + + + Edit the trigg&er + + + + + Delete the trigge&r + + + + + Create a &view + + + + + Edit the v&iew + + + + + Delete the vi&ew + + + + + &Refresh all database schemas + + + + + Re&fresh selected database schema + + + + + + Erase table data + + + + + Open file's directory + + + + + Execute SQL from file + + + + + + Database + + + + + Grouping + + + + + Generate query for table + + + + + + Create group + + + + + Group name + + + + + Entry with name %1 already exists in group %2. + + + + + Delete group + + + + + Are you sure you want to delete group %1? +All objects from this group will be moved to parent group. + + + + + Are you sure you want to remove database '%1' from the list? + + + + + Are you sure you want to remove following databases from the list: +%1 + + + + + Remove database + + + + + + Cannot import, because no import plugin is loaded. + + + + + + Cannot export, because no export plugin is loaded. + + + + + Vacuum (%1) + + + + + Integrity check (%1) + + + + + Reset autoincrement + + + + + Are you sure you want to reset autoincrement value for table '%1'? + + + + + An error occurred while trying to reset autoincrement value for table '%1': %2 + + + + + Autoincrement value for table '%1' has been reset successfully. + + + + + Are you sure you want to delete all data from table(s): %1? + + + + + An error occurred while trying to delete data from table '%1': %2 + + + + + All data has been deleted for table '%1'. + + + + + Following objects will be deleted: %1. + + + + + Following databases will be removed from list: %1. + + + + + Remainig objects from deleted group will be moved in place where the group used to be. + + + + + %1<br><br>Are you sure you want to continue? + + + + + Delete objects + + + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. + + + + + DbTreeItemDelegate + + + error + dbtree labels + + + + + (system table) + database tree label + + + + + (virtual) + virtual table label + + + + + (system index) + database tree label + + + + + DbTreeModel + + + Database: %1 + dbtree tooltip + + + + + Version: + dbtree tooltip + + + + + File size: + dbtree tooltip + + + + + Encoding: + dbtree tooltip + + + + + Error: + dbtree tooltip + + + + + Table : %1 + dbtree tooltip + + + + + Columns (%1): + dbtree tooltip + + + + + Indexes (%1): + dbtree tooltip + + + + + Triggers (%1): + dbtree tooltip + + + + + Copy + + + + + Move + + + + + Include data + + + + + Include indexes + + + + + Include triggers + + + + + Abort + + + + + Could not add dropped database file '%1' automatically. Manual setup is necessary. + + + + + Referenced tables + + + + + Do you want to include following referenced tables as well: +%1 + + + + + Name conflict + + + + + Following object already exists in the target database. +Please enter new, unique name, or press '%1' to abort the operation: + + + + + SQL statements conversion + + + + + Following error occurred while converting SQL statements to the target SQLite version: + + + + + Would you like to ignore those errors and proceed? + + + + + DdlHistoryWindow + + + Filter by database: + + + + + -- Queries executed on database %1 (%2) +-- Date and time of execution: %3 +%4 + + + + + DDL history + + + + + DdlPreviewDialog + + + Queries to be executed + + + + + Don't show again + + + + + DebugConsole + + + SQLiteStudio Debug Console + + + + + EditorWindow + + + Query + + + + + History + + + + + Results in the separate tab + + + + + Results below the query + + + + + + SQL editor %1 + + + + + Results + + + + + Execute query + + + + + Explain query + + + + + Clear execution history + sql editor + + + + + Export results + sql editor + + + + + Create view from query + sql editor + + + + + Previous database + + + + + Next database + + + + + Show next tab + sql editor + + + + + Show previous tab + sql editor + + + + + Focus results below + sql editor + + + + + Focus SQL editor above + sql editor + + + + + Delete selected SQL history entries + sql editor + + + + + Active database (%1/%2) + + + + + Query finished in %1 second(s). Rows affected: %2 + + + + + Query finished in %1 second(s). + + + + + Clear execution history + + + + + Are you sure you want to erase the entire SQL execution history? This cannot be undone. + + + + + Cannot export, because no export plugin is loaded. + + + + + No database selected in the SQL editor. Cannot create a view for unknown database. + + + + + Editor window "%1" has uncommitted data. + + + + + ErrorsConfirmDialog + + + Errors + + + + + Following errors occured: + + + + + Would you like to proceed? + + + + + ExecFromFileDialog + + + Execute SQL from file + + + + + Input file + + + + + Path to file + + + + + Browse for file + + + + + Options + + + + + File encoding + + + + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + + + ExportDialog + + + Export + + + + + What do you want to export? + + + + + A database + + + + + A single table + + + + + Query results + + + + + Table to export + + + + + Database + + + + + Table + + + + + Options + + + + + When this option is unchecked, then only table DDL (CREATE TABLE statement) is exported. + + + + + Export table data + + + + + Export table indexes + + + + + Export table triggers + + + + + Note, that exporting table indexes and triggers may be unsupported by some output formats. + + + + + Select database objects to export + + + + + Export data from tables + + + + + Select all + + + + + Deselect all + + + + + + Database: + + + + + Query to export results for + + + + + Query to be executed for results: + + + + + Export format and options + + + + + Export format + + + + + Output + + + + + Exported file path + + + + + Clipboard + + + + + File + + + + + Exported text encoding: + + + + + Export format options + + + + + Cancel + + + + + + + Select database to export. + + + + + Select table to export. + + + + + Enter valid query to export. + + + + + Select at least one object to export. + + + + + You must provide a file name to export to. + + + + + Path you provided is an existing directory. You cannot overwrite it. + + + + + The directory '%1' does not exist. + + + + + The file '%1' exists and will be overwritten. + + + + + All files (*) + + + + + Pick file to export to + + + + + Internal error during export. This is a bug. Please report it. + + + + + FileExecErrorsDialog + + + Execution errors + + + + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + + + FontEdit + + + Choose font + font configuration + + + + + Form + + + Active SQL formatter plugin + + + + + FormView + + + Commit row + form view + + + + + Rollback row + form view + + + + + First row + form view + + + + + Previous row + form view + + + + + Next row + form view + + + + + Last row + form view + + + + + Insert new row + form view + + + + + Delete current row + form view + + + + + FunctionsEditor + + + Filter funtions + + + + + Input arguments + + + + + Undefined + + + + + Databases + + + + + Register in all databases + + + + + Register in following databases: + + + + + Type: + + + + + Function name: + + + + + Implementation language: + + + + + Initialization code: + + + + + + Function implementation code: + + + + + Final step implementation code: + + + + + SQL function editor + + + + + Commit all function changes + + + + + Rollback all function changes + + + + + Create new function + + + + + Delete selected function + + + + + Custom SQL functions manual + + + + + Add function argument + + + + + Rename function argument + + + + + Delete function argument + + + + + Move function argument up + + + + + Move function argument down + + + + + Scalar + + + + + Aggregate + + + + + Enter a non-empty, unique name of the function. + + + + + Pick the implementation language. + + + + + Per step code: + + + + + Enter a non-empty implementation code. + + + + + argument + new function argument name in function editor window + + + + + Functions editor window has uncommitted modifications. + + + + + ImportDialog + + + Import data + + + + + Table to import to + + + + + Table + + + + + Database + + + + + Data source to import from + + + + + Data source type + + + + + Options + + + + + Text encoding: + + + + + Input file: + + + + + <p>If enabled, any constraint violation, or invalid data format (wrong column count), or any other problem encountered during import will be ignored and the importing will be continued.</p> + + + + + Ignore errors + + + + + Data source options + + + + + Cancel + + + + + If you type table name that doesn't exist, it will be created. + + + + + Enter the table name + + + + + Select import plugin. + + + + + You must provide a file to import from. + + + + + The file '%1' does not exist. + + + + + Path you provided is a directory. A regular file is required. + + + + + Pick file to import from + + + + + IndexDialog + + + + Index + + + + + Column + + + + + Collation + + + + + Sort + + + + + On table: + + + + + Delete selected indexed expression + + + + + Moves selected index column up in the order, making it more significant in the index. + + + + + Moves selected index column down in the order, making it less significant in the index. + + + + + Partial index condition + + + + + Unique index + + + + + Index name: + + + + + Edit selected indexed expression + + + + + Add indexed expression + + + + + DDL + + + + + Tried to open index dialog for closed or inexisting database. + + + + + Could not process index %1 correctly. Unable to open an index dialog. + + + + + Unique index cannot have indexed expressions. Either remove expressions from list below, or uncheck this option. + + + + + Pick the table for the index. + + + + + Select at least one column. + + + + + Enter a valid condition. + + + + + default + index dialog + + + + + Sort order + table constraints + + + + + + Error + index dialog + + + + + Cannot create unique index, because values in selected columns are not unique. Would you like to execute SELECT query to see problematic values? + + + + + An error occurred while executing SQL statements: +%1 + + + + + IndexExprColumnDialog + + + Indexed expression + + + + + Expression to index + + + + + This expression is already indexed by the index. + + + + + Column should be indexed directly, not by expression. Either extend this expression to contain something more than just column name, or abort and select this column in index dialog directly. + + + + + Column '%1' does not belong to the table covered by this index. Indexed expressions can refer only to columns from the indexed table. + + + + + It's forbidden to use 'SELECT' statements in indexed expressions. + + + + + Enter an indexed expression. + + + + + Invalid expression. + + + + + LanguageDialog + + + Language + + + + + Please choose language: + + + + + MainWindow + + + Database toolbar + + + + + Structure toolbar + + + + + Tools + + + + + Window list + + + + + View toolbar + + + + + Configuration widgets + + + + + Syntax highlighting engines + + + + + Data editors + + + + + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. + + + + + Running in debug mode. Debug messages are printed to the standard output. + + + + + You need to restart application to make the language change take effect. + + + + + Next window + + + + + Previous window + + + + + Hide status field + + + + + Open Debug Console + + + + + Open CSS Console + + + + + Bugs and feature &requests + + + + + Window list + menubar view menu + + + + + Open SQL &editor + + + + + Open DDL &history + + + + + Open SQL &functions editor + + + + + Open &collations editor + + + + + Open ex&tension manager + + + + + &Import + + + + + E&xport + + + + + Open confi&guration dialog + + + + + &Tile windows + + + + + Tile windows &horizontally + + + + + Tile windows &vertically + + + + + &Cascade windows + + + + + Close selected &window + + + + + Close all windows &but selected + + + + + Close &all windows + + + + + Re&store recently closed window + + + + + &Rename selected window + + + + + Report a &bug + + + + + Propose a new &feature + + + + + &About + + + + + &Licenses + + + + + Open home &page + + + + + Open fo&rum page + + + + + User &Manual + + + + + SQLite &documentation + + + + + Check for &updates + + + + + &Database + menubar + + + + + &Structure + menubar + + + + + &View + menubar + + + + + &Tools + menubar + + + + + &Help + + + + + Could not set style: %1 + main window + + + + + Cannot export, because no export plugin is loaded. + + + + + Cannot import, because no import plugin is loaded. + + + + + Rename window + + + + + Enter new name for the window: + + + + + New updates are available. <a href="%1">Click here for details</a>. + + + + + You're running the most recent version. No updates are available. + + + + + Database passed in command line parameters (%1) was already on the list under name: %2 + + + + + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 + + + + + Could not add database %1 to list. + + + + + MdiWindow + + + Uncommitted changes + + + + + Close anyway + + + + + Don't close + + + + + MultiEditor + + + Null value + multieditor + + + + + Configure editors for this data type + + + + + Open another tab + + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. + + + + + Deleted + multieditor + + + + + Read only + multieditor + + + + + MultiEditorBoolPlugin + + + Boolean + + + + + MultiEditorDatePlugin + + + Date + + + + + MultiEditorDateTimePlugin + + + Date & time + + + + + MultiEditorHexPlugin + + + Hex + + + + + MultiEditorNumericPlugin + + + Number + numeric multi editor tab name + + + + + MultiEditorText + + + Tab changes focus + + + + + Cut + + + + + Copy + + + + + Paste + + + + + Delete + + + + + Undo + + + + + Redo + + + + + MultiEditorTextPlugin + + + Text + + + + + MultiEditorTimePlugin + + + Time + + + + + NewConstraintDialog + + + New constraint + + + + + + Primary Key + new constraint dialog + + + + + + Foreign Key + new constraint dialog + + + + + + Unique + new constraint dialog + + + + + + Check + new constraint dialog + + + + + Not NULL + new constraint dialog + + + + + Collate + new constraint dialog + + + + + Default + new constraint dialog + + + + + NewVersionDialog + + + SQLiteStudio updates + + + + + New updates are available! + + + + + Component + + + + + This application will be closed and the update installer will start to download and install all the updates. + + + + + Update version + + + + + Check for updates on startup + + + + + Update to new version! + + + + + Not now. + + + + + Don't install the update and close this window. + + + + + PopulateConfigDialog + + + Populating configuration + + + + + Configuring <b>%1</b> for column <b>%2</b> + + + + + PopulateDialog + + + Populate table + + + + + Database + + + + + Table + + + + + Columns + + + + + Number of rows to populate: + + + + + Populate + populate dialog button + + + + + Abort + + + + + Configure + + + + + Populating configuration for this column is invalid or incomplete. + + + + + Select database with table to populate + + + + + Select table to populate + + + + + You have to select at least one column. + + + + + QObject + + + Cannot edit columns that are result of compound %1 statements (one that includes %2, %3 or %4 keywords). + + + + + The query execution mechanism had problems with extracting ROWID's properly. This might be a bug in the application. You may want to report this. + + + + + Requested column is a result of SQL expression, instead of a simple column selection. Such columns cannot be edited. + + + + + Requested column belongs to restricted SQLite table. Those tables cannot be edited directly. + + + + + Cannot edit results of query other than %1. + + + + + Cannot edit columns that are result of aggregated %1 statements. + + + + + Cannot edit columns that are result of %1 statement. + + + + + Cannot edit columns that are result of common table expression statement (%1). + + + + + + + + on conflict: %1 + data view tooltip + + + + + references table %1, column %2 + data view tooltip + + + + + condition: %1 + data view tooltip + + + + + collation name: %1 + data view tooltip + + + + + Data grid view + + + + + Copy cell(s) contents to clipboard + + + + + Copy cell(s) contents together with header to clipboard + + + + + Paste cell(s) contents from clipboard + + + + + Set empty value to selected cell(s) + + + + + Set NULL value to selected cell(s) + + + + + Commit changes to cell(s) contents + + + + + Rollback changes to cell(s) contents + + + + + Delete selected data row + + + + + Insert new data row + + + + + Open contents of selected cell in a separate editor + + + + + Total pages available: %1 + + + + + Total rows loaded: %1 + + + + + Data view (both grid and form) + + + + + Refresh data + + + + + Switch to grid view of the data + + + + + Switch to form view of the data + + + + + Database list + + + + + Delete selected item + + + + + Clear filter contents + + + + + Refresh schema + + + + + Refresh all schemas + + + + + Add database + + + + + Select all items + + + + + Copy selected item(s) + + + + + + + Paste from clipboard + + + + + Tables + + + + + Indexes + + + + + Triggers + + + + + Views + + + + + Columns + + + + + Data form view + + + + + Commit changes for current row + + + + + Rollback changes for current row + + + + + Go to first row on current page + + + + + Go to next row + + + + + Go to previous row + + + + + Go to last row on current page + + + + + Insert new row + + + + + Delete current row + + + + + Main window + + + + + Open SQL editor + + + + + Previous window + + + + + Next window + + + + + Hide status area + + + + + Open configuration dialog + + + + + Open Debug Console + + + + + Open CSS Console + + + + + Cell text value editor + + + + + + Cut selected text + + + + + + Copy selected text + + + + + + Delete selected text + + + + + + Undo + + + + + + Redo + + + + + SQL editor input field + + + + + Select whole editor contents + + + + + Save contents into a file + + + + + Load contents from a file + + + + + Find in text + + + + + Find next + + + + + Find previous + + + + + Replace in text + + + + + Delete current line + + + + + Request code assistant + + + + + Format contents + + + + + Move selected block of text one line down + + + + + Move selected block of text one line up + + + + + Copy selected block of text and paste it a line below + + + + + Copy selected block of text and paste it a line above + + + + + Toggle comment + + + + + All SQLite databases + + + + + All files + + + + + + Database file + + + + + SQL editor window + + + + + Execute query + + + + + Execute "%1" query + + + + + Switch current working database to previous on the list + + + + + Switch current working database to next on the list + + + + + Go to next editor tab + + + + + Go to previous editor tab + + + + + Move keyboard input focus to the results view below + + + + + Move keyboard input focus to the SQL editor above + + + + + Delete selected SQL history entries + + + + + Table window + + + + + Refresh table structure + + + + + Add new column + + + + + Edit selected column + + + + + Delete selected column + + + + + Export table data + + + + + Import data to the table + + + + + Add new table constraint + + + + + Edit selected table constraint + + + + + Delete selected table constraint + + + + + Refresh table index list + + + + + Add new index + + + + + Edit selected index + + + + + Delete selected index + + + + + Refresh table trigger list + + + + + + Add new trigger + + + + + + Edit selected trigger + + + + + + Delete selected trigger + + + + + + Go to next tab + + + + + + Go to previous tab + + + + + A view window + + + + + Refresh view trigger list + + + + + QuitConfirmDialog + + + Uncommitted changes + + + + + Are you sure you want to quit the application? + +Following items are pending: + + + + + SearchTextDialog + + + Find or replace + + + + + Find: + + + + + Case sensitive + + + + + Search backwards + + + + + Regular expression matching + + + + + Replace && +find next + + + + + Replace with: + + + + + Replace all + + + + + Find + + + + + SortDialog + + + Sort by columns + + + + + + Column + + + + + + Order + + + + + Sort by: %1 + + + + + Move column up + + + + + Move column down + + + + + SqlEditor + + + Cut + sql editor + + + + + Copy + sql editor + + + + + Paste + sql editor + + + + + Delete + sql editor + + + + + Select all + sql editor + + + + + Undo + sql editor + + + + + Redo + sql editor + + + + + Complete + sql editor + + + + + Format SQL + sql editor + + + + + Save SQL to file + sql editor + + + + + Select file to save SQL + sql editor + + + + + Load SQL from file + sql editor + + + + + Delete line + sql editor + + + + + Move block down + sql editor + + + + + Move block up + sql editor + + + + + Copy block down + sql editor + + + + + Copy up down + sql editor + + + + + Find + sql editor + + + + + Find next + sql editor + + + + + Find previous + sql editor + + + + + Replace + sql editor + + + + + Toggle comment + sql editor + + + + + Could not open file '%1' for writing: %2 + + + + + Saved SQL contents to file: %1 + + + + + Syntax completion can be used only when a valid database is set for the SQL editor. + + + + + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. + + + + + Save to file + + + + + SQL scripts (*.sql);;All files (*) + + + + + Open file + + + + + Could not open file '%1' for reading: %2 + + + + + Reached the end of document. Hit the find again to restart the search. + + + + + SqlQueryItem + + + Column: + data view tooltip + + + + + Data type: + data view + + + + + Table: + data view tooltip + + + + + Constraints: + data view tooltip + + + + + Cannot load the data for a cell that refers to the already closed database. + + + + + SqlQueryItemDelegate + + + + + + + Cannot edit this cell. Details: %1 + + + + + The row is marked for deletion. + + + + + + Structure of this table has changed since last data was loaded. Reload the data to proceed. + + + + + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). + + + + + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. + + + + + SqlQueryModel + + + + Only one query can be executed simultaneously. + + + + + Uncommitted data + + + + + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. + + + + + Cannot commit the data for a cell that refers to the already closed database. + + + + + Could not begin transaction on the database. Details: %1 + + + + + An error occurred while committing the transaction: %1 + + + + + An error occurred while rolling back the transaction: %1 + + + + + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. + + + + + An error occurred while committing the data: %1 + + + + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + + + + + + Error while executing SQL query on database '%1': %2 + + + + + Error while loading query results: %1 + + + + + Insert multiple rows + + + + + Number of rows to insert: + + + + + SqlQueryView + + + Go to referenced row in... + + + + + Copy + + + + + Copy as... + + + + + Paste + + + + + Paste as... + + + + + Set NULL values + + + + + Erase values + + + + + Edit value in editor + + + + + Commit + + + + + Copy with headers + + + + + Rollback + + + + + Commit selected cells + + + + + Rollback selected cells + + + + + Define columns to sort by + + + + + Remove custom sorting + + + + + Insert row + + + + + Insert multiple rows + + + + + Delete selected row + + + + + Show value in a viewer + + + + + Generate query for selected cells + + + + + No items selected to paste clipboard contents to. + + + + + Go to referenced row in table '%1' + + + + + table '%1' + + + + + Referenced row (%1) + + + + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + + Edit value + + + + + SqlTableModel + + + Error while committing new row: %1 + + + + + Error while deleting row from table %1: %2 + + + + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + + + + + Register in all databases + + + + + Register in following databases: + + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + + + + + Open file + + + + + StatusField + + + Status + + + + + Copy + + + + + Clear + + + + + TableConstraintsModel + + + Type + table constraints + + + + + Details + table constraints + + + + + Name + table constraints + + + + + TableForeignKeyPanel + + + Foreign table: + + + + + SQLite 2 does not support foreign keys officially, +but it's okay to use them anyway. + + + + + Columns + + + + + Local column + + + + + Foreign column + + + + + Reactions + + + + + Deferred foreign key + + + + + Named constraint + + + + + Constraint name + + + + + Pick the foreign column. + + + + + Pick the foreign table. + + + + + Select at least one foreign column. + + + + + Enter a name of the constraint. + + + + + Foreign column + table constraints + + + + + TablePrimaryKeyAndUniquePanel + + + Columns + + + + + Column + + + + + Collation + + + + + Sort + + + + + Valid only for a single column with INTEGER data type + + + + + Autoincrement + + + + + Named constraint + + + + + Constraint name + + + + + On conflict + + + + + Collate + table constraints + + + + + Sort order + table constraints + + + + + Select at least one column. + + + + + Enter a name of the constraint. + + + + + TableStructureModel + + + Name + table structure columns + + + + + Data type + table structure columns + + + + + Primary +Key + table structure columns + + + + + Foreign +Key + table structure columns + + + + + Unique + table structure columns + + + + + Check + table structure columns + + + + + Not +NULL + table structure columns + + + + + Collate + table structure columns + + + + + Default value + table structure columns + + + + + TableWindow + + + Structure + + + + + Table name: + + + + + + Data + + + + + Constraints + + + + + Indexes + + + + + Triggers + + + + + DDL + + + + + Export table + table window + + + + + Import data to table + table window + + + + + Populate table + table window + + + + + Refresh structure + table window + + + + + Commit structure changes + table window + + + + + Rollback structure changes + table window + + + + + Add column + table window + + + + + Edit column + table window + + + + + + Delete column + table window + + + + + Move column up + table window + + + + + Move column down + table window + + + + + Create similar table + table window + + + + + Reset autoincrement value + table window + + + + + Add table constraint + table window + + + + + Edit table constraint + table window + + + + + Delete table constraint + table window + + + + + Move table constraint up + table window + + + + + Move table constraint down + table window + + + + + Add table primary key + table window + + + + + Add table foreign key + table window + + + + + Add table unique constraint + table window + + + + + Add table check constraint + table window + + + + + Refresh index list + table window + + + + + Create index + table window + + + + + Edit index + table window + + + + + Delete index + table window + + + + + Refresh trigger list + table window + + + + + Create trigger + table window + + + + + Edit trigger + table window + + + + + Delete trigger + table window + + + + + Are you sure you want to delete column '%1'? + table window + + + + + Following problems will take place while modifying the table. +Would you like to proceed? + table window + + + + + Table modification + table window + + + + + Could not load data for table %1. Error details: %2 + + + + + Could not process the %1 table correctly. Unable to open a table window. + + + + + Could not restore window %1, because no database or table was stored in session for this window. + + + + + Could not restore window '%1', because no database or table was stored in session for this window. + + + + + Could not restore window '%1', because database %2 could not be resolved. + + + + + Could not restore window '%1'', because the table %2 doesn't exist in the database %3. + + + + + + New table %1 + + + + + Committed changes for table '%1' successfully. + + + + + Committed changes for table '%1' (named before '%2') successfully. + + + + + Could not commit table structure. Error message: %1 + table window + + + + + Reset autoincrement + + + + + Are you sure you want to reset autoincrement value for table '%1'? + + + + + An error occurred while trying to reset autoincrement value for table '%1': %2 + + + + + Autoincrement value for table '%1' has been reset successfully. + + + + + Empty name + + + + + A blank name for the table is allowed in SQLite, but it is not recommended. +Are you sure you want to create a table with blank name? + + + + + Cannot create a table without at least one column. + + + + + Cannot create table %1, if it has no primary key defined. Either uncheck the %2, or define a primary key. + + + + + Cannot use autoincrement for primary key when %1 clause is used. Either uncheck the %2, or the autoincrement in a primary key. + + + + + Are you sure you want to delete table constraint '%1'? + table window + + + + + Delete constraint + table window + + + + + Cannot export, because no export plugin is loaded. + + + + + Cannot import, because no import plugin is loaded. + + + + + Uncommitted changes + + + + + There are uncommitted structure modifications. You cannot browse or edit data until you have table structure settled. +Do you want to commit the structure, or do you want to go back to the structure tab? + + + + + Go back to structure tab + + + + + Commit modifications and browse data. + + + + + Name + table window indexes + + + + + Unique + table window indexes + + + + + Columns + table window indexes + + + + + Partial index condition + table window indexes + + + + + Name + table window triggers + + + + + Event + table window triggers + + + + + Condition + table window triggers + + + + + Details + table window triggers + + + + + Table window "%1" has uncommitted structure modifications and data. + + + + + Table window "%1" has uncommitted data. + + + + + Table window "%1" has uncommitted structure modifications. + + + + + TriggerColumnsDialog + + + Trigger columns + + + + + Triggering columns: + + + + + Select all + + + + + Deselect all + + + + + TriggerDialog + + + + Trigger + + + + + On table: + + + + + Action: + + + + + + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> + + + + + Pre-condition: + + + + + The scope is still not fully supported by the SQLite database. + + + + + Trigger name: + + + + + When: + + + + + List of columns for UPDATE OF action. + + + + + Scope: + + + + + Code: + + + + + Trigger statements to be executed. + + + + + DDL + + + + + On view: + + + + + Could not process trigger %1 correctly. Unable to open a trigger dialog. + + + + + Enter a valid condition. + + + + + Enter a valid trigger code. + + + + + Error + trigger dialog + + + + + An error occurred while executing SQL statements: +%1 + + + + + VersionConvertSummaryDialog + + + Database version convert + + + + + Following changes to the SQL statements will be made: + + + + + Before + + + + + After + + + + + ViewWindow + + + Query + + + + + View name: + + + + + Output column names + + + + + + Data + + + + + Triggers + + + + + DDL + + + + + + Could not restore window '%1', because no database or view was stored in session for this window. + + + + + Could not restore window '%1', because database %2 could not be resolved. + + + + + Could not restore window '%1', because database %2 could not be open. + + + + + Could not restore window '%1', because the view %2 doesn't exist in the database %3. + + + + + + New view %1 + + + + + Refresh the view + view window + + + + + Commit the view changes + view window + + + + + Rollback the view changes + view window + + + + + Explicit column names + + + + + Generate output column names automatically basing on result columns of the view. + + + + + Add column + view window + + + + + Edit column + view window + + + + + Delete column + view window + + + + + Move column up + view window + + + + + Move column down + view window + + + + + Refresh trigger list + view window + + + + + Create new trigger + view window + + + + + Edit selected trigger + view window + + + + + Delete selected trigger + view window + + + + + View window "%1" has uncommitted structure modifications and data. + + + + + View window "%1" has uncommitted data. + + + + + View window "%1" has uncommitted structure modifications. + + + + + Could not load data for view %1. Error details: %2 + + + + + Uncommitted changes + + + + + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. +Do you want to commit the structure, or do you want to go back to the structure tab? + + + + + Go back to structure tab + + + + + Commit modifications and browse data. + + + + + Committed changes for view '%1' successfully. + + + + + Committed changes for view '%1' (named before '%2') successfully. + + + + + Could not commit view changes. Error message: %1 + view window + + + + + Override columns + + + + + Currently defined columns will be overriden. Do you want to continue? + + + + + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. + + + + + Name + view window triggers + + + + + Instead of + view window triggers + + + + + Condition + view window triggers + + + + + Details + table window triggers + + + + + Could not process the %1 view correctly. Unable to open a view window. + + + + + Empty name + + + + + A blank name for the view is allowed in SQLite, but it is not recommended. +Are you sure you want to create a view with blank name? + + + + + The SELECT statement could not be parsed. Please correct the query and retry. +Details: %1 + + + + + The view could not be modified due to internal SQLiteStudio error. Please report this! + + + + + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. + + + + + Following problems will take place while modifying the view. +Would you like to proceed? + view window + + + + + View modification + view window + + + + + WidgetCover + + + Interrupt + + + + diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.qm b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.qm index 7a4d27a..4a142a7 100644 Binary files a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.qm and b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.qm differ diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts index 4b135af..ebd49cf 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts @@ -14,9 +14,8 @@ О программе - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Бесплатный кроссплатформенный менеджер баз данных SQLite с открытым исходным кодом.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Автор и активный разработчик:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Бесплатный кроссплатформенный менеджер баз данных SQLite с открытым исходным кодом.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Автор и активный разработчик:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> @@ -58,6 +57,11 @@ Configuration directory Каталог конфигурации + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + + Qt version: @@ -89,262 +93,222 @@ <h3>Содержание:</h3><ol>%2</ol> + + BindParamsDialog + + + Query parameters + + + + + Please provide values for query parameters + + + BugDialog - Bugs and ideas - Ошибки и предложения + Ошибки и предложения - Reporter - Отправитель + Отправитель - E-mail address - Адрес e-mail + Адрес e-mail - - Log in - Вход + Вход - Short description - Краткое описание + Краткое описание - Detailed description - Подробное описание + Подробное описание - Show more details - Показать дополнительную информацию + Показать дополнительную информацию - SQLiteStudio version - Версия SQLiteStudio + Версия SQLiteStudio - Operating system - Операционная система + Операционная система - Loaded plugins - Загруженные модули + Загруженные модули - Send - Отправить + Отправить - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - Вы можете просмотреть все отправленные вами отчёты об ошибках и предложения, выбрав в меню '%1' пункт '%2'. + Вы можете просмотреть все отправленные вами отчёты об ошибках и предложения, выбрав в меню '%1' пункт '%2'. - A bug report sent successfully. - Отчёт об ошибке успешно отправлен. + Отчёт об ошибке успешно отправлен. - An error occurred while sending a bug report: %1 %2 - При отправке отчёта об ошибке возникла проблема: %1 + При отправке отчёта об ошибке возникла проблема: %1 %2 - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - Вы можете повторить отправку. После такой ошибки содержимое полей окна отправки отчёта будет восстановлено при повторном открытии. + Вы можете повторить отправку. После такой ошибки содержимое полей окна отправки отчёта будет восстановлено при повторном открытии. - An idea proposal sent successfully. - Предложение по улучшению было успешно отправлено. + Предложение по улучшению было успешно отправлено. - An error occurred while sending an idea proposal: %1 %2 - При отправке предложения по улучшению возникла проблема: %1 + При отправке предложения по улучшению возникла проблема: %1 %2 - A bug report - Отчёт об ошибке + Отчёт об ошибке - Describe problem in few words - Опишите проблему в нескольких словах + Опишите проблему в нескольких словах - Describe problem and how to reproduce it - Опишите проблему и шаги для её воспроизведения + Опишите проблему и шаги для её воспроизведения - A new feature idea - Предложение по улучшению функционала + Предложение по улучшению функционала - A title for your idea - Название для вашего предложения + Название для вашего предложения - Describe your idea in more details - Опишите ваше предложение более подробно + Опишите ваше предложение более подробно - Reporting as an unregistered user, using e-mail address. - Отправка от незарегистрированного пользователя, используя адрес e-mail + Отправка от незарегистрированного пользователя, используя адрес e-mail - Reporting as a registered user. - Отправка от зарегистрированного пользователя + Отправка от зарегистрированного пользователя - Log out - Выход + Выход - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - Указание действительного адреса e-mail поможет связаться с вами касательно вашего отчёта. Для подробной информации нажмите кнопку Помощь справа. + Указание действительного адреса e-mail поможет связаться с вами касательно вашего отчёта. Для подробной информации нажмите кнопку Помощь справа. - Enter vaild e-mail address, or log in. - Введите действительный адрес e-mail либо выполните вход. + Введите действительный адрес e-mail либо выполните вход. - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - Краткое описание должно содержать от 10 до 100 символов. Более подробное описание можно ввести в поле ниже. + Краткое описание должно содержать от 10 до 100 символов. Более подробное описание можно ввести в поле ниже. - Long description requires at least 30 characters. - Детальное описание должно содержать как минимум 30 символов. + Детальное описание должно содержать как минимум 30 символов. BugReportHistoryWindow - - Title - Заголовок + Заголовок - - Reported at - Дата отправки + Дата отправки - - URL - URL + URL - Reports history - История отчётов + История отчётов - Clear reports history - Очистить историю отчётов + Очистить историю отчётов - Delete selected entry - Удалить выбранную запись + Удалить выбранную запись - Invalid response from server. - Некорректный ответ сервера. + Некорректный ответ сервера. BugReportLoginDialog - Log in - Вход + Вход - Credentials - Данные для входа + Данные для входа - Login: - Имя пользователя: + Имя пользователя: - Password: - Пароль: + Пароль: - Validation - Проверка + Проверка - Validate - Проверить + Проверить - Validation result message - Статус проверки + Статус проверки - Abort - Прервать + Прервать - A login must be at least 2 characters long. - Имя пользователя должно состоять как минимум из двух символов. + Имя пользователя должно состоять как минимум из двух символов. - A password must be at least 5 characters long. - Пароль должен состоять как минимум из пяти символов. + Пароль должен состоять как минимум из пяти символов. - Valid - Верно + Верно @@ -355,12 +319,12 @@ Отфильтровать сравнения - + Collation name: Имя сравнения: - + Implementation language: Язык реализации: @@ -432,7 +396,7 @@ Collations editor window has uncommitted modifications. - + В редакторе сравнений имеются неподтверждённые изменения. Collations editor window has uncommited modifications. @@ -489,11 +453,20 @@ + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. + + + Invalid default value expression: %1 - Некорректное выражение для значения по умолчанию: %1 + Некорректное выражение для значения по умолчанию: %1 - + Enter a name of the constraint. Введите имя ограничения. @@ -605,7 +578,7 @@ - + Delete constraint column dialog @@ -665,34 +638,44 @@ Добавить ограничение на значение по умочанию - + Are you sure you want to delete constraint '%1'? column dialog Вы действительно хотите удалить ограничение '%1'? - + Correct the constraint's configuration. Исправьте конфигурацию ограничения. - + This constraint is not officially supported by SQLite 2, but it's okay to use it. Это ограничение официально не поддерживается SQLite 2, но его использование допустимо. - + Scale is not allowed for INTEGER PRIMARY KEY columns. Указание размера данных недопустимо для столбцов с типом INTEGER PRIMARY KEY. - + Precision cannot be defined without the scale. Точность не может быть задана без указания размера данных. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. Указание точности недопустимо для столбцов с типом INTEGER PRIMARY KEY. @@ -794,10 +777,9 @@ but it's okay to use it. Введите имя ограничения. - Autoincrement (only for %1 type columns) column primary key - Автоинкремент (только для столбцов типа %1) + Автоинкремент (только для столбцов типа %1) @@ -909,7 +891,7 @@ but it's okay to use it. ConfigDialog - + Configuration Конфигурация @@ -999,18 +981,18 @@ but it's okay to use it. Просмотр и редактирование данных - + Number of data rows per page: Количество строк данных на странице: - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> <p>При загрузке даных в табличный вид ширина столбцов автоматически подстраивается. Этот параметр ограничивает начальную ширину для подстройки, при этом пользователь может вручную изменить ширину столбца сверх данного лимита.</p> - + Limit initial data column width to (in pixels): Ограничить начальную ширину столбца данных (в пикселях): @@ -1019,7 +1001,7 @@ but it's okay to use it. <html><head/><body><p>&lt;p&gt;Если редактируется ячейка, содержащая NULL, и вводится пустая строка в качестве значения, то эта опция определяет, останется ли в качестве значения ячейки NULL (если опция активирована), или значение будет заменено на пустую строку (если эта опция деактивирована).&lt;/p&gt;</p></body></html> - + Keep NULL value when entering empty value Сохранять значение NULL при вводе пустой тсроки @@ -1028,22 +1010,22 @@ but it's okay to use it. General.KeepNullWhenEmptyValue - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> <p>Если данная опция активирована и пользователь наводит указатель мыши на ячейку в любом режиме просмотра данных (результаты запроса, данные таблицы, данные представления), то будет отображена всплывающая подсказка с информацией о ячейке, в том числе информация о типе данных столбца, ограничениях, значение ROWID и прочее.</p> - + Show column and row details tooltip in data view Показывать всплывающую подсказку с информацией о столбце и строке при просмотре данных - + Inserting new row in data grid Вставка новой строки в таблице данных - + Before currently selected row Перед текущей выделенной строкой @@ -1052,72 +1034,72 @@ but it's okay to use it. General.InsertRowPlacement - + After currently selected row После текущей выделенной строки - + At the end of data view В конец области просмотра данных - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> <p>Если опция активирована, окна таблиц будут открываться на вкладке данных вместо вкладки со структурой.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> <p>Если опция активирована, вкладка "Данные" в окнах таблиц будет первой, а не второй по порядку.</p> - + Place data tab as first tab in a Table Window Помещать вкладку данных в окнах таблиц первой - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> <p>Если опция активирована, окна представлений будут открываться на вкладке данных вместо вкладки со структурой.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> <p>Если опция активирована, вкладка "Данные" в окнах представлений будет первой, а не второй по порядку.</p> - + Place data tab as first tab in a View Window Помещать вкладку данных в окнах представлений первой - + Data types Типы данных - + Available editors: Доступные редакторы: - + Editors selected for this data type: Выбранные редакторы для этого типа данных: - + Schema editing Редактирование схемы - + Number of DDL changes kept in history. Количество сохраняемых в истории изменений DDL. - + DDL history size: Размер истории DDL: @@ -1126,104 +1108,104 @@ but it's okay to use it. Не показывать диалог предпросмотра DDL при подтверждении изменений схемы - + SQL queries SQL запросы - - + + Number of queries kept in the history. Количество сохраняемых в истории запросов. - + History size: Размер истории: - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> <p>Если в окне редактора SQL введено более одного запроса, то (если данная опция активирована) будет выполнен лишь один запрос - тот, который находится под текстовым курсором. В противном случае будут исполнены все запросы. Вы можете ограничить выполняемые запросы, выделив их перед вызовом выполнения.</p> - + Execute only the query under the cursor Выполнять только запрос под курсором - + Updates Обновления - + Automatically check for updates at startup Автоматически проверять обновления при запуске - + Session Сессия - + Restore last session (active MDI windows) after startup Восстановить предыдущую сессию (активные MDI окна) после запуска - + Status Field Окно статуса - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> <p>Если пользователь вручную закрыл окно статуса, включение данной опции гарантирует, что при появлении новых сообщений окно статуса будет автоматически открыто. Если опция отключена, окно статуса может быть заново открыто только пользователем вручную через меню "Вид".</p> - + Always open Status panel when new message is printed Всегда открывать окно статуса при появлении нового сообщения - + Filter shortcuts by name or key combination Фильтруйте горячие клавиши по имени или комбинации клавиш - + Action Действие - + Key combination Комбинация клавиш - - + + Language Язык - + Changing language requires application restart to take effect. Для смены языка потребуется перезапустить приложение. - + Compact layout Компактный режим - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> <p>В компактном режиме все поля и отступы в интерфейсе минимизированы для отображения большего количества данных. Интерфейс станет чуть менее эстетичным, однако это позволит уместить больше данных на экране.</p> - + Use compact layout Включить компактный режим @@ -1303,22 +1285,33 @@ but it's okay to use it. Отображать в списке системные таблицы и индексы - - <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> - - <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> + + Number of memorized table populating configurations - + + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> + <p>Если редактируется ячейка, содержащая NULL, и вводится пустая строка в качестве значения, то эта опция определяет, останется ли в качестве значения ячейки NULL (если опция активирована), или значение будет заменено на пустую строку (если эта опция деактивирована).</p> + + + + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> + <html><head/><body><p>Активируйте эту опцию, чтобы всегда подставлять значение DEFAULT (значение по умолчанию) при записи NULL в столбец, у которого определено значение DEFAULT, даже если столбец может содержать NULL.</p><p>Отключите эту опцию для подстановки значения DEFAULT только в случае записи NULL в столбец с ограничением NOT NULL.</p></body></html> + + + Use DEFAULT value (if defined), when committing NULL value - + Использовать значение DEFAULT (если оно определено) при записи NULL - + Table windows Окна таблиц @@ -1327,12 +1320,12 @@ but it's okay to use it. Если опция активирована, окно таблицы будет открыто на вкладке данных вместо вкладки структуры. - + Open Table Windows with the data tab for start Открывать окна таблиц на вкладке данных - + View windows Окна представлений @@ -1341,184 +1334,195 @@ but it's okay to use it. Если опция активирована, окно представления будет открыто на вкладке данных вместо вкладки структуры. - + Open View Windows with the data tab for start Открывать окна представлений на вкладке данных - + Don't show DDL preview dialog when committing schema changes + Не показывать диалог предпросмотра DDL при подтверждении изменений схемы + + + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + Number of memorized query parameters - + Main window dock areas Области прикрепления вокруг главного окна - + Left and right areas occupy corners Углы занимают правая и левая области - + Top and bottom areas occupy corners Углы занимают верхняя и нижняя области - + Hide built-in plugins Скрыть встроенные модули - + Current style: Текущий стиль: - + Preview Предпросмотр - + Enabled Активно - + Disabled Неактивно - + Active formatter plugin Активный модуль форматирования - + SQL editor font Шрифт редактора SQL - + Database list font Шрифт списка баз данных - + Database list additional label font Шрифт дополнительных меток в списке баз данных - + Data view font Шрифт просмотра данных - + Status field font Шрифт окна статуса - + SQL editor colors Цвета редактора SQL - + Current line background Фон текущей строки - + <p>SQL strings are enclosed with single quote characters.</p> <p>Строки SQL обрамляются в одинарные кавычки.</p> - + String foreground Цвет строки - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> <p>Подстановочные параметры предназначены для значений, которые будут в дальнейшем указаны пользователем. Они определяются одним из следующих способов:</p><ul><li>:имя_параметра</li><li>$имя_параметра</li><li>@имя_параметра</li><li>?</li></ul> - + Bind parameter foreground Цвет подстановочных параметров - + Highlighted parenthesis background Фон подсвечиваемых скобок - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> <p>Данные типа BLOB — это бинарные данные, представляемые в виде шестнадцатеричных чисел, например:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground Цвет данных типа BLOB - + Regular foreground Стандартный цвет - + Line numbers area background Фон области нумерации строк - + Keyword foreground Цвет ключевого слова - + Number foreground Цвет числа - + Comment foreground Цвет комментария - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> <p>Распознаваемыми объектами являются имена талиц, индексов, триггеров и представлений, существующих в базе данных SQLite.</p> - + Valid objects foreground Цвет распознанных объектов - + Data view colors Цвета в окне просмотра данных - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> - + <p>Все изменения данных будут обрамлены этим цветом, пока не будут записаны в базу данных.</p> - + Uncommitted data outline color - + Цвет обрамления неподтверждённых изменений - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> - + <p>В случае ошибки при подтверждении изменений данных, этим цветом будут обрамлены проблемные ячейки.</p> <p>Any data changes will be outlined with this color, until they're commited to the database.</p> @@ -1533,140 +1537,140 @@ but it's okay to use it. <p>В случае ошибки при подтверждении изменений данных, этим цветом будут обрамлены проблемные ячейки.</p> - + Commit error outline color Цвет обрамления ошибочных ячеек - + NULL value foreground Цвет значений NULL - + Deleted row background Фон удалённых строк - + Database list colors Цвета списка баз данных - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> <p>Дополнительные метки содержат информацию о версии SQLite, о количестве объектов в глубине дерева и т.д.</p> - + Additional labels foreground Цвет дополнительных меток - + Status field colors Цвета в окне Статуса - + Information message foreground Цвет информационного сообщения - + Warning message foreground Цвет предупреждения - + Error message foreground Цвет ошибки - + Description: plugin details Описание: - + Category: plugin details Категория: - + Version: plugin details Версия: - + Author: plugin details Автор: - + Internal name: plugin details Внутреннее имя: - + Dependencies: plugin details Зависимости: - + Conflicts: plugin details Конфликты: - + Plugin details Сведения о модуле - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. Модули загружаются и выгружаются сразу после активации/деактивации, однако изменения в списке загружаемых при старте модулей не будут сохранены пока вы не примените изменения в окне конфигурации. - + %1 (built-in) plugins manager in configuration dialog %1 (встроенный) - + Details Сведения - + No plugins in this category. В этой категории модулей нет. - + Add new data type Добавить новый тип данных - + Rename selected data type Переименовать выбранный тип данных - + Delete selected data type Удалить выбранный тип данных - + Help for configuring data type editors Справка по настройке редакторов типов данных @@ -1818,138 +1822,154 @@ but it's okay to use it. DataView - + Filter data data view Отфильтровать данные - + Grid view Табличный вид - + Form view Форма - + Refresh table data data view Обновить данные таблицы - + First page data view Первая страница - + Previous page data view Предыдущая страница - + Next page data view Следующая страница - + Last page data view Последняя страница - + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + Apply filter data view Применить фильтр - + Commit changes for selected cells data view Подтвердить изменения для выбранных ячеек - + Rollback changes for selected cells data view Откатить изменения для выбранных ячеек - + Show grid view of results sql editor Показать результаты в виде таблицы - + Show form view of results sql editor Показать результаты в виде формы - + Filter by text data view Текстовый фильтр - + Filter by the Regular Expression data view Фильтр по регулярному выражению - + Filter by SQL expression data view Фильтр по выражению SQL - + Tabs on top data view Вкладки сверху - + Tabs at bottom data view Вкладки снизу - + Place new rows above selected row data view Поместить новые строки перед выделенной строкой - + Place new rows below selected row data view Поместить новые строки после выделенной строки - + Place new rows at the end of the data view data view Поместить новые строки в конец области просмотра данных - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. Идёт подсчёт общего числа строк. Переключение на другие страницы станет возможным после окончания подсчёта. - + Row: %1 Строка: %1 @@ -2156,8 +2176,12 @@ Browsing other pages will be possible after the row counting is done. + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + + + <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> - <p>Автоматическая генерация имени отключена, так как имя было задано вручную. Для автоматической генерации необходимо удалить содержимое из поля имени.</p> + <p>Автоматическая генерация имени отключена, так как имя было задано вручную. Для автоматической генерации необходимо удалить содержимое из поля имени.</p> @@ -2271,283 +2295,420 @@ Browsing other pages will be possible after the row counting is done. Фильтр по имени - + Copy Копировать - + Paste Вставить - + Select all Выделить всё - + Create a group Создать группу - + Delete the group Удалить группу - + Rename the group Переименовать группу - Add a database - Добавить базу данных + Добавить базу данных - Edit the database - Редактировать базу данных + Редактировать базу данных - Remove the database - Удалить базу данных + Удалить базу данных - Connect to the database - Подключиться к базе данных + Подключиться к базе данных - Disconnect from the database - Отключиться от базы данных + Отключиться от базы данных - + Import Импорт - Export the database - Экспортировать базу данных + Экспортировать базу данных - Convert database type - Сконвертировать тип базы данных + Сконвертировать тип базы данных - Vacuum - Выполнить VACUUM + Выполнить VACUUM - Integrity check - Проверить целостность + Проверить целостность - Create a table - Создать таблицу + Создать таблицу - Edit the table - Редактировать таблицу + Редактировать таблицу - Delete the table - Удалить таблицу + Удалить таблицу - + Export the table Экспортировать таблицу - + Import into the table Импортировать данные в таблицу - + Populate table Заполнить таблицу - + Create similar table Создать подобную таблицу - + Reset autoincrement sequence Сбросить счётчик автоинкремента - Create an index - Создать индекс + Создать индекс - Edit the index - Редактировать индекс + Редактировать индекс - Delete the index - Удалить индекс + Удалить индекс - Create a trigger - Создать триггер + Создать триггер - Edit the trigger - Редактировать триггер + Редактировать триггер - Delete the trigger - Удалить триггер + Удалить триггер - Create a view - Создать представление + Создать представление - Edit the view - Редактировать представление + Редактировать представление - Delete the view - Удалить представление + Удалить представление - + Add a column Добавить столбец - + Edit the column Редактировать столбец - + Delete the column Удалить столбец - + Delete selected items Удалить выбранные элементы - + Clear filter Сбросить фильтр - Refresh all database schemas - Обновить структуры всех баз данных + Обновить структуры всех баз данных - Refresh selected database schema - Обновить структуру выбранной базы данных + Обновить структуру выбранной базы данных + + + + Execution from file cancelled. Any queries executed so far have been rolled back. + + + + + &Add a database + + + + + &Edit the database + + + + + &Remove the database + + + + + &Connect to the database + - + &Disconnect from the database + + + + + &Export the database + + + + + Con&vert database type + + + + + Vac&uum + + + + + &Integrity check + + + + + Create a &table + + + + + Edit the t&able + + + + + Delete the ta&ble + + + + + Create an &index + + + + + Edit the i&ndex + + + + + Delete the in&dex + + + + + Create a trig&ger + + + + + Edit the trigg&er + + + + + Delete the trigge&r + + + + + Create a &view + + + + + Edit the v&iew + + + + + Delete the vi&ew + + + + + &Refresh all database schemas + + + + + Re&fresh selected database schema + + + + + Erase table data Удалить данные из таблицы - - + + Open file's directory + + + + + Execute SQL from file + + + + + Database База данных - + Grouping Группировка - + Generate query for table Сгенерировать запрос для этой таблицы - - + + Create group Создать группу - + Group name Имя группы - + Entry with name %1 already exists in group %2. Элемент с именем %1 уже входит в группу %2. - + Delete group Удалить группу - + Are you sure you want to delete group %1? All objects from this group will be moved to parent group. Вы действительно хотите удалить группу %1? Все объекты из данной группы будут перемещены в родительскую группу. - + Are you sure you want to remove database '%1' from the list? Вы действительно хотите удалить базу данных '%1' из списка? - + Are you sure you want to remove following databases from the list: %1 Вы действительно хотите удалить следующие базы данных из списка: %1 - + Remove database Удалить базу данных - + Vacuum (%1) Операция VACUUM (%1) - + Autoincrement value for table '%1' has been reset successfully. - + Сброс счётчика автоинкремента у таблицы '%1' успешно выполнен. - + Are you sure you want to delete all data from table(s): %1? + Вы действительно хотите удалить все данные из таблицы (таблиц): '%1'? + + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + Невозможно открыть файл '%1' для чтения: %2 + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. @@ -2559,14 +2720,14 @@ All objects from this group will be moved to parent group. Вы действительно хотите удалить базу данных '%1'? - - + + Cannot import, because no import plugin is loaded. Невозможно произвести импорт, т.к. не загружено ни одного модуля импорта. - - + + Cannot export, because no export plugin is loaded. Невозможно произвести экспорт, т.к. не загружено ни одного модуля экспорта. @@ -2579,22 +2740,22 @@ All objects from this group will be moved to parent group. Выполнение команды VACUUM успешно завершено. - + Integrity check (%1) Проверка целостности (%1) - + Reset autoincrement Сброс счётчика автоинкремента - + Are you sure you want to reset autoincrement value for table '%1'? Вы действительно хотите сбросить счётчик автоинкремента у таблицы '%1'? - + An error occurred while trying to reset autoincrement value for table '%1': %2 При попытке сброса счётчика автоинкремента у таблицы '%1' произошла ошибка: %2 @@ -2607,37 +2768,37 @@ All objects from this group will be moved to parent group. Вы действительно хотите удалить все данные из таблицы '%1'? - + An error occurred while trying to delete data from table '%1': %2 При попытке удаления данных из таблицы '%1' произошла ошибка: %2 - + All data has been deleted for table '%1'. Из таблицы '%1' были удалены все данные. - + Following objects will be deleted: %1. Будут удалены следующие объекты: %1. - + Following databases will be removed from list: %1. Из списка будут удалены следующие базы данных: %1. - + Remainig objects from deleted group will be moved in place where the group used to be. Оставшиеся после удаления группы объекты будут перемещены туда, где ранее располагалась группа. - + %1<br><br>Are you sure you want to continue? %11<br><br>Вы действительно хотите продолжить? - + Delete objects Удалить объекты @@ -2731,76 +2892,76 @@ All objects from this group will be moved to parent group. Триггеры (%1): - + Copy Копировать - + Move Переместить - + Include data Включая данные - + Include indexes Включая индексы - + Include triggers Включая триггеры - + Abort Прервать - + Could not add dropped database file '%1' automatically. Manual setup is necessary. Невозможно автоматически добавить перетянутый файл базы данных '%1'. Необходима ручная настройка. - + Referenced tables Связанные таблицы - + Do you want to include following referenced tables as well: %1 Вы хотите также включить следующие связанные таблицы: %1 - + Name conflict Конфликт имён - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: Данный объект уже существует в целевой базе данных. Пожалуйста введите новое уникальное имя или нажмите %1 для прерывания операции: - + SQL statements conversion Конвертация конструкций SQL - + Following error occurred while converting SQL statements to the target SQLite version: При конвертации конструкций SQL в новую версию SQLite произошла ошибка: - + Would you like to ignore those errors and proceed? Вы хотите проигнорировать эти ошибки и продолжить? @@ -2856,132 +3017,138 @@ Please enter new, unique name, or press '%1' to abort the operation:Запрос - + History История - + Results in the separate tab Результаты в отдельной вкладке - + Results below the query Результаты под запросом - - + + SQL editor %1 Редактор SQL %1 - + Results Результаты - + Execute query Выполнить запрос - + Explain query План запроса - + Clear execution history sql editor Очистить историю запросов - + Export results sql editor Экспортировать результаты - + Create view from query sql editor Создать представление из запроса - + Previous database Предыдущая база данных - + Next database Следующая база данных - + Show next tab sql editor Открыть следующую вкладку - + Show previous tab sql editor Открыть предыдущую вкладку - + Focus results below sql editor Фокус на результатах внизу - + Focus SQL editor above sql editor Фокус на редакторе SQL сверху - + + Delete selected SQL history entries + sql editor + + + + Active database (%1/%2) Текущая база данных (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 Запрос выполнен за %1 секунд. Затронуто строк: %2 - + Query finished in %1 second(s). Запрос выполнен за %1 секунд. - + Clear execution history Очистка истории запросов - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. Вы действительно хотите удалить всю историю выполнения SQL запросов? Операцию невозможно отменить. - + Cannot export, because no export plugin is loaded. Невозможно произвести экспорт, т.к. не загружено ни одного модуля экспорта. - + No database selected in the SQL editor. Cannot create a view for unknown database. В редакторе SQL не выбрана база данных. Невозможно создать представление в неизвестной базе данных. - + Editor window "%1" has uncommitted data. - + В окне редактора "%1" имеются неподтверждённые данные. Editor window "%1" has uncommited data. @@ -3007,41 +3174,99 @@ Please enter new, unique name, or press '%1' to abort the operation: - ExportDialog + ExecFromFileDialog - - Export - Экспорт + + Execute SQL from file + - - What do you want to export? - Что вы хотите экспортировать? + + Input file + - - A database - Базу данных + + Path to file + - - A single table - Одну таблицу + + Browse for file + - - Query results - Результаты запроса + + Options + Опции - - Table to export - Экспортируемая таблица + + File encoding + - - Database - База данных + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + Скрипты SQL (*.sql);;Все файлы (*) + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + + + ExportDialog + + + Export + Экспорт + + + + What do you want to export? + Что вы хотите экспортировать? + + + + A database + Базу данных + + + + A single table + Одну таблицу + + + + Query results + Результаты запроса + + + + Table to export + Экспортируемая таблица + + + + Database + База данных @@ -3155,68 +3380,101 @@ Please enter new, unique name, or press '%1' to abort the operation:Опции формата экспорта - + Cancel Отмена - - - + + + Select database to export. Выберите базу данных для экспорта. - + Select table to export. Выберите таблицу для экспорта. - + Enter valid query to export. Введи корректный запрос для экспорта. - + Select at least one object to export. Выберите хотя бы один объект для экспорта. - + You must provide a file name to export to. Необходимо указать имя файла, в который будет произведён экспорт. - + Path you provided is an existing directory. You cannot overwrite it. Указанный путь является существующим каталогом. Его невозможно перезаписать. - + The directory '%1' does not exist. Каталог '%1' не существует. - + The file '%1' exists and will be overwritten. Файл '%1' существует и будет перезаписан. - + All files (*) Все файлы (*) - + Pick file to export to Выберите файл для экспорта - + Internal error during export. This is a bug. Please report it. Внутренняя ошибка во время экспорта. Пожалуйста, вышлите отчёт об этой ошибке. + + FileExecErrorsDialog + + + Execution errors + + + + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + Ошибка + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + FontEdit @@ -3237,49 +3495,49 @@ Please enter new, unique name, or press '%1' to abort the operation: FormView - + Commit row form view Подтвердить строку - + Rollback row form view Откатить строку - + First row form view Первая строка - + Previous row form view Предыдущая строка - + Next row form view Следующая строка - + Last row form view Последняя строка - + Insert new row form view Вставить новую строку - + Delete current row form view Удалить текущую строку @@ -3338,13 +3596,13 @@ Please enter new, unique name, or press '%1' to abort the operation:Код инициализации: - + Function implementation code: Код реализации функции: - + Final step implementation code: Код реализации последнего шага: @@ -3442,7 +3700,7 @@ Please enter new, unique name, or press '%1' to abort the operation: Functions editor window has uncommitted modifications. - + В окне редактора функций имеются неподтверждённые изменения. Functions editor window has uncommited modifications. @@ -3512,42 +3770,42 @@ Please enter new, unique name, or press '%1' to abort the operation:Опции источника данных - + Cancel Отмена - + If you type table name that doesn't exist, it will be created. Если вы введёте несуществующее имя таблицы, она будет создана. - + Enter the table name Введите имя таблицы - + Select import plugin. Выберите модуль импорта. - + You must provide a file to import from. Необходимо указать файл, из которого осуществляется импорт. - + The file '%1' does not exist. Файл '%1' не существует. - + Path you provided is a directory. A regular file is required. Указанный путь является каталогом. Необходимо указать файл. - + Pick file to import from Выберите файл для импорта @@ -3586,12 +3844,12 @@ Please enter new, unique name, or press '%1' to abort the operation:Столбец - + Collation Сравнение - + Sort Сортировка @@ -3771,273 +4029,406 @@ Please enter new, unique name, or press '%1' to abort the operation:Панель отображения - + Configuration widgets Виджеты конфигурации - + Syntax highlighting engines Движки синтаксической подсветки - + Data editors Редакторы данных - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. Отладочный режим. Нажмите %1 или воспользуйтесь пунктом меню 'Справка / Открыть отладочную консоль' для открытия отладочной консоли. - + Running in debug mode. Debug messages are printed to the standard output. Отладочный режим. Отладочные сообщения выводятся в стандартный выходной поток. - + You need to restart application to make the language change take effect. Для смены языка необходимо перезапустить приложение. - Open SQL editor - Открыть редактор SQL + Открыть редактор SQL - Open DDL history - Открыть историю DDL + Открыть историю DDL - Open SQL functions editor - Открыть редактор функций SQL + Открыть редактор функций SQL - Open collations editor - Открыть редактор сравнений + Открыть редактор сравнений - Import - Импорт + Импорт - Export - Экспорт + Экспорт - Open configuration dialog - Открыть диалог конфигурации + Открыть диалог конфигурации - Tile windows - Расположить окна плиткой + Расположить окна плиткой - Tile windows horizontally - Расположить окна по горизонтали + Расположить окна по горизонтали - Tile windows vertically - Расположить окна по вертикали + Расположить окна по вертикали - Cascade windows - Расположить окна каскадом + Расположить окна каскадом - + Next window Следующее окно - + Previous window Предыдущее окно - + Hide status field Скрыть окно статуса - Close selected window - Закрыть выбранное окно + Закрыть выбранное окно - Close all windows but selected - Закрыть все окна, кроме выбранного + Закрыть все окна, кроме выбранного - Close all windows - Закрыть все окна + Закрыть все окна - Restore recently closed window - Восстановить недавно закрытые окна + Восстановить недавно закрытые окна - Rename selected window - Переименовать выбранное окно + Переименовать выбранное окно - + Open Debug Console Открыть отладочную консоль - + Open CSS Console Открыть консоль CSS - Report a bug - Сообщить об ошибке + Сообщить об ошибке - Propose a new feature - Предложить новый функционал + Предложить новый функционал - About - О программе + О программе - Licenses - Лицензии + Лицензии - Open home page - Открыть домашнюю страницу + Открыть домашнюю страницу - Open forum page - Открыть страницу форума + Открыть страницу форума - User Manual - Руководство пользователя + Руководство пользователя - SQLite documentation - Документация по SQLite + Документация по SQLite - Report history - История отчётов + История отчётов - Check for updates - Проверить обновления + Проверить обновления - Database menubar - База данных + База данных - Structure menubar - Структура + Структура - View menubar - Вид + Вид - + Window list menubar view menu Окна - Tools menubar - Инструменты + Инструменты - Help - Справка + Справка + + + + Open SQL &editor + + + + + Open DDL &history + + + + + Open SQL &functions editor + + + + + Open &collations editor + + + + + Open ex&tension manager + + + + + &Import + + + + + E&xport + + + + + Open confi&guration dialog + + + + + &Tile windows + + + + + Tile windows &horizontally + - + + Tile windows &vertically + + + + + &Cascade windows + + + + + Close selected &window + + + + + Close all windows &but selected + + + + + Close &all windows + + + + + Re&store recently closed window + + + + + &Rename selected window + + + + + Report a &bug + + + + + Propose a new &feature + + + + + &About + + + + + &Licenses + + + + + Open home &page + + + + + Open fo&rum page + + + + + User &Manual + + + + + SQLite &documentation + + + + + Bugs and feature &requests + + + + + Check for &updates + + + + + &Database + menubar + + + + + &Structure + menubar + + + + + &View + menubar + + + + + &Tools + menubar + + + + + &Help + + + + Could not set style: %1 main window Невозможно применить стиль: %1 - + Cannot export, because no export plugin is loaded. Невозможно произвести экспорт, т.к. не загружено ни одного модуля экспорта. - + Cannot import, because no import plugin is loaded. Невозможно произвести импорт, т.к. не загружено ни одного модуля импорта. - + Rename window Переименовать окно - + Enter new name for the window: Введите новое имя для окна: - + New updates are available. <a href="%1">Click here for details</a>. Доступны обновления. <a href="%1">Нажмите здесь для подробностей</a>. - + You're running the most recent version. No updates are available. Установлена последняя версия. Обновлений нет. - + Database passed in command line parameters (%1) was already on the list under name: %2 База данных, переданная через аргументы командной строки (%1), уже находится в списке под именем %2 - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 База данных, переданная через аргументы командной строки (%1), была временно добавлена в список под именем %2 - + Could not add database %1 to list. Невозможно добавить базу данных %1 в список. @@ -4051,7 +4442,7 @@ Please enter new, unique name, or press '%1' to abort the operation: Uncommitted changes - + Неподтверждённые изменения @@ -4073,23 +4464,28 @@ Please enter new, unique name, or press '%1' to abort the operation:Значение Null - + Configure editors for this data type Настройте редакторы для этого типа данных - + + Open another tab + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. Модуль редактора данных '%1' не загружен, хотя указан для редактирования типа данных '%1' - + Deleted multieditor Удалено - + Read only multieditor Только для чтения @@ -4098,93 +4494,143 @@ Please enter new, unique name, or press '%1' to abort the operation: MultiEditorBool - Boolean - Логическое + Логическое + + + + MultiEditorBoolPlugin + + + Boolean + Логическое MultiEditorDate - Date - Дата + Дата + + + + MultiEditorDatePlugin + + + Date + Дата MultiEditorDateTime - Date & time - Дата и время + Дата и время + + + + MultiEditorDateTimePlugin + + + Date & time + Дата и время MultiEditorHex - Hex - Шестнадцатеричное + Шестнадцатеричное + + + + MultiEditorHexPlugin + + + Hex + Шестнадцатеричное MultiEditorNumeric - Number numeric multi editor tab name - Число + Число + + + + MultiEditorNumericPlugin + + + Number + numeric multi editor tab name + Число MultiEditorText - Text - Текст + Текст - + Tab changes focus Tab перемещает фокус - + Cut Вырезать - + Copy Копировать - + Paste Вставить - + Delete Удалить - + Undo Отменить - + Redo Повторить + + MultiEditorTextPlugin + + + Text + Текст + + MultiEditorTime - Time - Время + Время + + + + MultiEditorTimePlugin + + + Time + Время @@ -4259,37 +4705,40 @@ Please enter new, unique name, or press '%1' to abort the operation:Компонент - + + This application will be closed and the update installer will start to download and install all the updates. + + + Current version - Текущая версия + Текущая версия - + Update version Новая версия - + Check for updates on startup Проверять обновления при запуске - + Update to new version! Обновить до новой версии! - The update will be automatically downloaded and installed. This will also restart application at the end. - Обновление будет автоматически загружено и установлено. В конце процесса приложение будет перезапущено. + Обновление будет автоматически загружено и установлено. В конце процесса приложение будет перезапущено. - + Not now. Не сейчас. - + Don't install the update and close this window. Не устанавливать обновление и закрыть данное окно. @@ -4341,32 +4790,32 @@ Please enter new, unique name, or press '%1' to abort the operation:Заполнить - + Abort Прервать - + Configure Настроить - + Populating configuration for this column is invalid or incomplete. Настройка заполнения для данного столбца некорректна или незавершена. - + Select database with table to populate Выберите базу данных с таблицей для заполнения - + Select table to populate Выберите таблицу для заполнения - + You have to select at least one column. Необходимо выбрать хотя бы один столбец. @@ -4441,129 +4890,134 @@ Please enter new, unique name, or press '%1' to abort the operation:имя сравнения: %1 - + Data grid view Табличный вид данных - + Copy cell(s) contents to clipboard Копировать содержимое ячеек в буфер обмена - + + Copy cell(s) contents together with header to clipboard + + + + Paste cell(s) contents from clipboard Вставить содержимое ячеек из буфера обмена - + Set empty value to selected cell(s) Установить пустое значение для выбранных ячеек - + Set NULL value to selected cell(s) Установить для выбранных ячеек значение NULL - + Commit changes to cell(s) contents Подтвердить изменение содержимого ячеек - + Rollback changes to cell(s) contents Откатить изменения содержимого ячеек - + Delete selected data row Удалить выбранную строку данных - + Insert new data row Вставить новую строку данных - + Open contents of selected cell in a separate editor Открыть содержимое выбранной ячейки в отдельном редакторе - + Total pages available: %1 Всего доступно страниц: %1 - + Total rows loaded: %1 Всего загружено строк: %1 - + Data view (both grid and form) Окно данных (и табличный вид, и форма) - + Refresh data Обновить данные - + Switch to grid view of the data Переключиться с табличного вида на форму - + Switch to form view of the data Переключиться из формы на табличный вид - + Database list Список баз данных - + Delete selected item Удалить выбранный элемент - + Clear filter contents Сбросить содержимое фильтра - + Refresh schema Обновить структуру - + Refresh all schemas Обновить структуры всех баз данных - + Add database Добавить базу данных - + Select all items Выделить все элементы - + Copy selected item(s) Копировать выбранные элементы - + - + Paste from clipboard Вставить из буфера обмена @@ -4638,42 +5092,42 @@ Please enter new, unique name, or press '%1' to abort the operation:Удалить текущую строку - + Main window Главное окно - + Open SQL editor Открыть редактор SQL - + Previous window Предыдущее окно - + Next window Следующее окно - + Hide status area Скрыть область статуса - + Open configuration dialog Открыть диалог конфигурации - + Open Debug Console Открыть отладочную консоль - + Open CSS Console Открыть консоль CSS @@ -4684,111 +5138,111 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cut selected text Вырезать выбранный текст - + Copy selected text Копировать выбранный текст - + Delete selected text Удалить выбранный текст - + Undo Отменить - + Redo Повторить - + SQL editor input field Поле ввода редактора SQL - + Select whole editor contents Выбрать всё содержимое редактора - + Save contents into a file Сохранить содержимое в файл - + Load contents from a file Загрузить содержимое из файла - + Find in text Найти в тексте - + Find next Найти далее - + Find previous Найти предыдущее - + Replace in text Замена в тексте - + Delete current line Удалить текущую строчку - + Request code assistant Вызвать автодополнение - + Format contents Форматировать содержимое - + Move selected block of text one line down Переместить выбранный блок текста на строчку вниз - + Move selected block of text one line up Переместить выбранный блок текста на строчку вверх - + Copy selected block of text and paste it a line below Скопировать блок текста и вставить его строчкой ниже - + Copy selected block of text and paste it a line above Скопировать блок текста и вставить его строчкой выше - + Toggle comment Комментировать/раскомментировать @@ -4809,14 +5263,12 @@ Please enter new, unique name, or press '%1' to abort the operation:Файл баз данных - Reports history window - Окно истории отчётов + Окно истории отчётов - Delete selected entry - Удалить выбранную запись + Удалить выбранную запись @@ -4863,6 +5315,11 @@ Please enter new, unique name, or press '%1' to abort the operation:Move keyboard input focus to the SQL editor above Переместить фокус ввода в окно редактора SQL вверху + + + Delete selected SQL history entries + + Table window @@ -4988,7 +5445,7 @@ Please enter new, unique name, or press '%1' to abort the operation: Uncommitted changes - + Неподтверждённые изменения @@ -5087,179 +5544,179 @@ find next SqlEditor - + Cut sql editor Вырезать - + Copy sql editor Копировать - + Paste sql editor Вставить - + Delete sql editor Удалить - + Select all sql editor Выделить всё - + Undo sql editor Отменить - + Redo sql editor Повторить - + Complete sql editor Завершить - + Format SQL sql editor Форматировать SQL - + Save SQL to file sql editor Сохранить SQL в файл - + Select file to save SQL sql editor Выбрать файл для сохранения SQL - + Load SQL from file sql editor Загрузить SQL из файла - + Delete line sql editor Удалить строчку - + Move block down sql editor Переместить блок вниз - + Move block up sql editor Переместить блок вверх - + Copy block down sql editor Копировать блок вниз - + Copy up down sql editor Копировать блок вверх - + Find sql editor Найти - + Find next sql editor Найти далее - + Find previous sql editor Найти предыдущее - + Replace sql editor Заменить - + Toggle comment sql editor Комментировать/раскомментировать - + Saved SQL contents to file: %1 SQL-код сохранён в файле %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. Дополнение синтаксиса может быть использовано только после назначения корректной базы данных редактору SQL. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. Размер содержимого редактора SQL слишком велико, поэтому обнаружение ошибок и подсветка существующих объектов временно отключена. - + Save to file Сохранить в файл - + Could not open file '%1' for writing: %2 Невозможно открыть файл '%1' для записи: %2 - + SQL scripts (*.sql);;All files (*) Скрипты SQL (*.sql);;Все файлы (*) - + Open file Открыть файл - + Could not open file '%1' for reading: %2 Невозможно открыть файл '%1' для чтения: %2 - + Reached the end of document. Hit the find again to restart the search. Достигнут конец документа. Нажмите Найти снова для перезапуска поиска. @@ -5315,24 +5772,24 @@ find next - - + + Cannot edit this cell. Details: %1 - Невозможно редактировать данную ячейку. Подробности: %1 + Невозможно редактировать данную ячейку. Подробности: %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. - + Структура этой таблицы изменилась с момента последней загрузки данных. Перезагрузите данные для продолжения. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). - + Редактирование значений большой длины непосредственно в табличном режиме не рекомендуется. Возможны проблемы с производительностью и удобством работы. Для работы с такими большими значениями рекомендуется использовать режим формы либо отдельное окно редактирования значения (доступно в контекстном меню по щелчку правой кнопкой мыши). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. Внешний ключ для столбца %2 имеет более чем %1 возможных значений. Это слишком много для отображения в выпадающем списке. Вам необходимо ввести значение вручную. @@ -5340,8 +5797,8 @@ find next SqlQueryModel - - + + Only one query can be executed simultaneously. Одновременно может быть выполнен только один запрос. @@ -5354,12 +5811,12 @@ find next Имеются неподтверждённые изменения данных. Вы действительно хотите продолжить? Все неподтверждённые изменения будут утеряны. - + Cannot commit the data for a cell that refers to the already closed database. Невозможно подтвердить данные для ячейки, которая ссылается на уже закрытую базу данных. - + Could not begin transaction on the database. Details: %1 Невозможно начать транзакцию в базе данных. Подробности: %1 @@ -5368,12 +5825,12 @@ find next При завершении транзакции возникла ошибка: %1 - + An error occurred while rolling back the transaction: %1 При отмене транзакции возникла ошибка: %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. Попытка подтверждения данных для нередактируемой ячейки (которая тем не менее была изменена и ожидает подтверждения). Это программная ошибка. Пожалуйста, отправьте о ней отчёт. @@ -5382,43 +5839,48 @@ find next При подтверждении данных произошла ошибка: %1 - + Uncommitted data - + Неподтверждённые данные - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. - + Имеются неподтверждённые изменения данных. Вы действительно хотите продолжить? Все неподтверждённые изменения будут утеряны. - + An error occurred while committing the transaction: %1 - + При завершении транзакции возникла ошибка: %1 - + An error occurred while committing the data: %1 + При подтверждении данных произошла ошибка: %1 + + + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. - - + + Error while executing SQL query on database '%1': %2 Ошибка при выполнении SQL запроса к базе данных '%1': %2 - + Error while loading query results: %1 Ошибка при загрузке результатов запроса: %1 - + Insert multiple rows Вставить несколько строк - + Number of rows to insert: Количество вставляемых строк: @@ -5426,117 +5888,137 @@ find next SqlQueryView - + Go to referenced row in... Перейти к связанной строке в... - + Copy Копировать - + Copy as... Копировать как... - + Paste Вставить - + Paste as... Вставить как... - + Set NULL values Установить значения на NULL - + Erase values Стереть содержимое - + Edit value in editor Править содержимое в редакторе - + Commit Подтвердить - + + Copy with headers + + + + Rollback Откатить - + Commit selected cells Подтвердить выбранные ячейки - + Rollback selected cells Откатить выбранные ячейки - + Define columns to sort by Определить столбцы для сортировки - + Remove custom sorting Сбросить указанную сортировку - + Insert row Вставить строку - + Insert multiple rows Вставить несколько строк - + Delete selected row Удалить выбранную строку - + + Show value in a viewer + + + + Generate query for selected cells Сгенерировать запрос для выбранных ячеек - + No items selected to paste clipboard contents to. Не выбраны элементы для вставки в них содержимого буфера обмена. - + Go to referenced row in table '%1' Перейти к связанной строке в таблице '%1' - + table '%1' таблица '%1' - + Referenced row (%1) Связанная строка (%1) - + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + Edit value Править содержимое @@ -5550,7 +6032,7 @@ find next Error while committing new row: %1 - + Ошибка при подтверждении новой строки: %1 @@ -5558,6 +6040,119 @@ find next Ошибка при удалении строки из таблицы %1: %2 + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + Базы данных + + + + Register in all databases + Зарегистрировать во всех базах данных + + + + Register in following databases: + Зарегистрировать в следующих базах данных: + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + Все файлы (*) + + + + Open file + Открыть файл + + StatusField @@ -5667,7 +6262,7 @@ but it's okay to use them anyway. Введите имя ограничения. - + Foreign column table constraints Внешний столбец @@ -5721,24 +6316,24 @@ but it's okay to use them anyway. При конфликте - + Collate table constraints Сравнение - + Sort order table constraints Порядок сортировки - + Select at least one column. Выберите хотя бы один столбец. - + Enter a name of the constraint. Введите имя ограничения. @@ -6078,43 +6673,44 @@ Would you like to proceed? Committed changes for table '%1' successfully. - + Изменения в таблицу '%1' внесены успешно. Committed changes for table '%1' (named before '%2') successfully. - + Изменения в таблицу '%1' (предыдущее название '%2') внесены успешно. Autoincrement value for table '%1' has been reset successfully. - + Сброс счётчика автоинкремента у таблицы '%1' успешно выполнен. Uncommitted changes - + Неподтверждённые изменения There are uncommitted structure modifications. You cannot browse or edit data until you have table structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Имеются неподтверждённые изменения структуры. Невозможно просматривать или редактировать данные, пока структура таблицы не подтверждена. +Подтвердить структуру таблицы или вернуться на вкладку структуры? Table window "%1" has uncommitted structure modifications and data. - + В окне таблицы "%1" имеются неподтверждённые изменения структуры и данных. Table window "%1" has uncommitted data. - + В окне таблицы "%1" имеются неподтверждённые изменения данных. Table window "%1" has uncommitted structure modifications. - + В окне таблицы "%1" имеются неподтверждённые изменения структуры. Could not restore window, because database %1 could not be resolved. @@ -6308,12 +6904,12 @@ Do you want to commit the structure, or do you want to go back to the structure Select all - + Выделить всё Deselect all - Снять выделение + Снять выделение @@ -6336,7 +6932,7 @@ Do you want to commit the structure, or do you want to go back to the structure - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> <p>SQL-условие для проверки перед запуском кода триггера. Если условие не выполнено, для текущей строки триггер вызван не будет.</p> @@ -6381,7 +6977,7 @@ Do you want to commit the structure, or do you want to go back to the structure Выполняемые конструкции триггера. - + DDL DDL @@ -6460,18 +7056,18 @@ Do you want to commit the structure, or do you want to go back to the structure Отображаемые имена столбцов - - + + Data Данные - + Triggers Триггеры - + DDL DDL @@ -6515,122 +7111,123 @@ Do you want to commit the structure, or do you want to go back to the structure Новое представление %1 - + Refresh the view view window Обновить представление - + Commit the view changes view window Подтвердить изменения представления - + Rollback the view changes view window Откатить изменения представления - + Explicit column names Явные имена столбцов - + Generate output column names automatically basing on result columns of the view. Сгенерировать отображаемые имена столбцов на основе результирующих столбцов представления. - + Add column view window Добавить столбец - + Edit column view window Редактировать столбец - + Delete column view window Удалить столбец - + Move column up view window Переместить столбец вверх - + Move column down view window Переместить столбец вниз - + Refresh trigger list view window Обновить список триггеров - + Create new trigger view window Создать новый триггер - + Edit selected trigger view window Редактировать выбранный триггер - + Delete selected trigger view window Удалить выбранный триггер - + View window "%1" has uncommitted structure modifications and data. - + В окне представления "%1" имеются неподтверждённые изменения структуры и данных. - + View window "%1" has uncommitted data. - + В окне представления "%1" имеются неподтверждённые изменения данных. - + View window "%1" has uncommitted structure modifications. - + В окне представления "%1" имеются неподтверждённые изменения структуры. - + Uncommitted changes - + Неподтверждённые изменения - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Имеются неподтверждённые изменения структуры. Невозможно просматривать или редактировать данные, пока структура представления не подтверждена. +Подтвердить структуру представления или вернуться на вкладку структуры? - + Committed changes for view '%1' successfully. - + Изменения в представление '%1' внесены успешно. - + Committed changes for view '%1' (named before '%2') successfully. - + Изменения в таблицу '%1' (предыдущее название '%2') внесены успешно. View window "%1" has uncommited structure modifications and data. @@ -6645,7 +7242,7 @@ Do you want to commit the structure, or do you want to go back to the structure В окне представления "%1" имеются неподтверждённые изменения структуры. - + Could not load data for view %1. Error details: %2 Невозможно загрузить данные представления %1. Подробности ошибки: %2 @@ -6660,12 +7257,12 @@ Do you want to commit the structure, or do you want to go back to the structure Подтвердить структуру представления или вернуться на вкладку структуры? - + Go back to structure tab Вернуться на вкладку структуры - + Commit modifications and browse data. Подтвердить изменения и перейти к данным. @@ -6678,86 +7275,86 @@ Do you want to commit the structure, or do you want to go back to the structure Изменения в представление '%1' (предыдущее название '%2') внесены успешно. - + Could not commit view changes. Error message: %1 view window Невозможно подтвердить изменения представления. Сообщение об ошибке: %1 - + Override columns Перезапись столбцов - + Currently defined columns will be overriden. Do you want to continue? Заданные столбцы будут перезаписаны. Вы хотите продолжить? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. Невозможно определить столбцы, возвращаемые представлением. Вероятно запрос неполон или содержит ошибки. - + Name view window triggers Имя - + Instead of view window triggers Вместо - + Condition view window triggers Условие - + Details table window triggers Подробности - + Could not process the %1 view correctly. Unable to open a view window. Не удалось корректно обработать представление %1. Невозможно открыть окно представления. - + Empty name Пустое имя - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? SQLite позволяет представлению иметь пустое имя, хотя это не рекомендуется. Вы действительно хотите создать представление с пустым именем? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 Невозможно проанализировать структуру конструкции SELECT. Пожалуйста, исправьте запрос и повторите попытку. Подробности: %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! Невозможно изменить представление из-за внутренней ошибки SQLiteStudio. Пожалуйста, сообщите о ней! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. Невозможно корректно проанализировать структуру представления для выполнения. Это ошибка SQLiteStudio. Пожалуйста, сообщите о ней. - + Following problems will take place while modifying the view. Would you like to proceed? view window @@ -6765,7 +7362,7 @@ Would you like to proceed? Вы хотите продолжить? - + View modification view window Изменение представления diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_sk.qm b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_sk.qm index 6490cf2..c3c6d5f 100644 Binary files a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_sk.qm and b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_sk.qm differ diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_sk.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_sk.ts index 8703dc7..aeb372d 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_sk.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_sk.ts @@ -14,9 +14,8 @@ O programe - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Slobodný, open-source, multi-platformový SQLite databázový manažér.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Autor a aktívny správca:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Slobodný, open-source, multi-platformový SQLite databázový manažér.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Autor a aktívny správca:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> @@ -58,6 +57,11 @@ Configuration directory Adresár s konfiguráciou + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + + Qt version: @@ -89,262 +93,222 @@ <h3>Tabuľka obsahu:</h3><ol>%2</ol> + + BindParamsDialog + + + Query parameters + + + + + Please provide values for query parameters + + + BugDialog - Bugs and ideas - Chyby a nápady + Chyby a nápady - Reporter - Reportér + Reportér - E-mail address - emailová adresa + emailová adresa - - Log in - Prihlásenie + Prihlásenie - Short description - Krátky popis + Krátky popis - Detailed description - Detailný popis + Detailný popis - Show more details - Zobraziť viacej detailov + Zobraziť viacej detailov - SQLiteStudio version - Verzia SQLiteStudio + Verzia SQLiteStudio - Operating system - Operačný systém + Operačný systém - Loaded plugins - Načítané pluginy + Načítané pluginy - Send - Odoslať + Odoslať - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - Všetky svoje nahlásené chyby a nápady môžte vidieť výberom '%1' a následne '%2'. + Všetky svoje nahlásené chyby a nápady môžte vidieť výberom '%1' a následne '%2'. - A bug report sent successfully. - Správa o chybe bola úspešne odoslaná. + Správa o chybe bola úspešne odoslaná. - An error occurred while sending a bug report: %1 %2 - Vyskytol sa problém pri posielaní správy o chybe: %1 + Vyskytol sa problém pri posielaní správy o chybe: %1 %2 - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - Môžte zopakovať odoslanie. Keď otvoríte nahlasovacie okno po takejto chybe, obsah bude obnovený. + Môžte zopakovať odoslanie. Keď otvoríte nahlasovacie okno po takejto chybe, obsah bude obnovený. - An idea proposal sent successfully. - Nahlásenie prebehlo úspešne. + Nahlásenie prebehlo úspešne. - An error occurred while sending an idea proposal: %1 %2 - Vyskytla sa chyba pri odoslieaní: %1 + Vyskytla sa chyba pri odoslieaní: %1 %2 - A bug report - Nahlásenie chyby + Nahlásenie chyby - Describe problem in few words - Popíšte problém niekoľkými slovami + Popíšte problém niekoľkými slovami - Describe problem and how to reproduce it - Popíšte problém a spôsob ako ho reprodukovať + Popíšte problém a spôsob ako ho reprodukovať - A new feature idea - Nová funkcia + Nová funkcia - A title for your idea - Titulok novej funkcie + Titulok novej funkcie - Describe your idea in more details - Detailnejšie popíšte svoj návrh na funkciu + Detailnejšie popíšte svoj návrh na funkciu - Reporting as an unregistered user, using e-mail address. - Nahlásenie ako neregistrovaný používateľ pomocou emailovej adresy. + Nahlásenie ako neregistrovaný používateľ pomocou emailovej adresy. - Reporting as a registered user. - Nahlásenie ako registrovaný používateľ. + Nahlásenie ako registrovaný používateľ. - Log out - Odhlásiť sa + Odhlásiť sa - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - Zadaním reálnej emailovej adresy umožníte kontaktovať vás ohľadom vášho nahlásenia. Pre zistenie bližších detailov, kliknite na tlačitko 'i' na pravej strane okna. + Zadaním reálnej emailovej adresy umožníte kontaktovať vás ohľadom vášho nahlásenia. Pre zistenie bližších detailov, kliknite na tlačitko 'i' na pravej strane okna. - Enter vaild e-mail address, or log in. - Zadajte platný email alebo sa prihláste. + Zadajte platný email alebo sa prihláste. - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - Krátky popis by mal obsahovať minimálne 10 znakov ale nie viacej ako 100. Dlhší popis môžte zadať v poli nižšie. + Krátky popis by mal obsahovať minimálne 10 znakov ale nie viacej ako 100. Dlhší popis môžte zadať v poli nižšie. - Long description requires at least 30 characters. - Dlhší popis by mal obsahovať minimálne 30 znakov. + Dlhší popis by mal obsahovať minimálne 30 znakov. BugReportHistoryWindow - - Title - Titulok + Titulok - - Reported at - Nahlásené + Nahlásené - - URL - URL + URL - Reports history - História hlásení + História hlásení - Clear reports history - Vymazať históriu hlásení + Vymazať históriu hlásení - Delete selected entry - Vymazať vybranú položku + Vymazať vybranú položku - Invalid response from server. - Neplatná odpoveď zo servera. + Neplatná odpoveď zo servera. BugReportLoginDialog - Log in - Prihlásenie + Prihlásenie - Credentials - Prihlasovacie údaje + Prihlasovacie údaje - Login: - Meno: + Meno: - Password: - Heslo: + Heslo: - Validation - Overenie + Overenie - Validate - Overiť + Overiť - Validation result message - Výsledok overenia + Výsledok overenia - Abort - Zrušiť + Zrušiť - A login must be at least 2 characters long. - meno musí mať dĺžku minimálne 2 znaky. + meno musí mať dĺžku minimálne 2 znaky. - A password must be at least 5 characters long. - Heslo musí mať dĺžku minimálne 5 znakov. + Heslo musí mať dĺžku minimálne 5 znakov. - Valid - Úspešné overenie + Úspešné overenie @@ -355,12 +319,12 @@ Filtrovať porovnávania - + Collation name: Názov porovnánavania: - + Implementation language: Implementačný jazyk: @@ -489,11 +453,16 @@ - Invalid default value expression: %1 + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. - + Enter a name of the constraint. Zadajte názov obmedzenia. @@ -605,7 +574,7 @@ - + Delete constraint column dialog Vymazať obmedzenie @@ -665,34 +634,44 @@ - + Are you sure you want to delete constraint '%1'? column dialog Ste si istý, že chcete vymazať obmedzenie '%1'? - + Correct the constraint's configuration. - + This constraint is not officially supported by SQLite 2, but it's okay to use it. - + Scale is not allowed for INTEGER PRIMARY KEY columns. - + Precision cannot be defined without the scale. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. @@ -794,10 +773,9 @@ but it's okay to use it. Zadajte názov obmedzenia. - Autoincrement (only for %1 type columns) column primary key - Autoinkrement (iba pre stĺpec typu %1) + Autoinkrement (iba pre stĺpec typu %1) @@ -909,7 +887,7 @@ but it's okay to use it. ConfigDialog - + Configuration Konfigurácia @@ -999,128 +977,139 @@ but it's okay to use it. Prezeranie a úprava dát - + Number of data rows per page: Počet data riadkov na stranu: - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> - + Limit initial data column width to (in pixels): - + Keep NULL value when entering empty value - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> - + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + + + + + Number of memorized table populating configurations + + + + Show column and row details tooltip in data view - + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> - + Use DEFAULT value (if defined), when committing NULL value - + Inserting new row in data grid - + Before currently selected row - + After currently selected row - + At the end of data view - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> - + Place data tab as first tab in a Table Window - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> - + Place data tab as first tab in a View Window - + Data types Datové typy - + Available editors: Dostupné editory: - + Editors selected for this data type: - + Schema editing Úprava schémy - + Number of DDL changes kept in history. Počet DDL zmien uchovávaných v histórii. - + DDL history size: Veľkosť DDL histórie: @@ -1129,104 +1118,104 @@ but it's okay to use it. Nezobrazovať náhľad DDL pri potvrdzovaní zmien v schéme - + SQL queries SQL dotazy - - + + Number of queries kept in the history. Počet dotazov uchovávaných v histórii. - + History size: Veľkosť SQL histórie: - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> <p>Ak je v SQL editore viacej ako jeden dotaz, potom(ak je táto voľba zapnutá) bude vykonaný iba jeden dotaz - ten, na ktorom je kurzor. Ináč budú vykonané všetky dotazy. Vždy si viete vybrať ktoré dotazy budú vykonané a to ich výberom\označením.</p> - + Execute only the query under the cursor Vykonať len dotaz, na ktorom stojí kurzor - + Updates Aktualizácie - + Automatically check for updates at startup Kontrolovať aktualizácie pri štarte - + Session Sedenie - + Restore last session (active MDI windows) after startup Obnoviť posledné sedenie (aktívne okná) pri štarte - + Status Field - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> - + Always open Status panel when new message is printed - + Filter shortcuts by name or key combination Filtrovať podľa názvu alebo klávesovej skratky - + Action Akcia - + Key combination Klávesová skratka - - + + Language Jazyk - + Changing language requires application restart to take effect. Je potrebné reštartovať aplikáciu aby sa zmena jazyka prejavila. - + Compact layout - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> - + Use compact layout @@ -1302,7 +1291,7 @@ but it's okay to use it. Zobraziť systémové tabuľky a indexy v zozname - + Table windows Okná tabuľky @@ -1311,12 +1300,12 @@ but it's okay to use it. Ak je táto možnosť zaškrtnutá, tak sa v okne zobrazia dáta a nie štruktúra tabuľky. - + Open Table Windows with the data tab for start Zobraziť dáta po otvorení tabuľky - + View windows Okná pohľadov @@ -1325,182 +1314,193 @@ but it's okay to use it. Ak je táto možnosť zaškrtnutá, tak sa v okne zobrazia dáta a nie SQL dotaz. - + Open View Windows with the data tab for start Zobraziť dáta po otvorení pohľadu - + Don't show DDL preview dialog when committing schema changes - + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + Number of memorized query parameters + + + + Main window dock areas - + Left and right areas occupy corners - + Top and bottom areas occupy corners - + Hide built-in plugins Nezobrazovať interné pluginy - + Current style: Aktuálny štýl: - + Preview Náhľad - + Enabled Zapnutý - + Disabled Vypnutý - + Active formatter plugin Aktívny formátovací plugin - + SQL editor font Písmo SQL editora - + Database list font Font zoznamu databáz - + Database list additional label font Font doplnkového popisku - + Data view font Font dát - + Status field font Font status okna - + SQL editor colors Farby SQL editora - + Current line background - + <p>SQL strings are enclosed with single quote characters.</p> - + String foreground - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> - + Bind parameter foreground - + Highlighted parenthesis background - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground Farba BLOB hodnoty - + Regular foreground - + Line numbers area background - + Keyword foreground - + Number foreground - + Comment foreground - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> - + Valid objects foreground - + Data view colors Farby dát - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> - + Uncommitted data outline color - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> @@ -1517,140 +1517,140 @@ but it's okay to use it. <p>V prípade chyby pri potvrdzovaní zmien dát, budú problematické bunky ohraničené touto farbou.</p> - + Commit error outline color Farba rámčeka s chybou potvrdenia dát - + NULL value foreground Farba NULL hodnoty - + Deleted row background Pozadie vymazaného riadka - + Database list colors Farby zoznamu databáz - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> - + Additional labels foreground Farba doplnkového popisku - + Status field colors Farby status okna - + Information message foreground Farba informačnej správy - + Warning message foreground Farba upozornenia - + Error message foreground Farba chybovej správy - + Description: plugin details Popis: - + Category: plugin details Kategória: - + Version: plugin details Verzia: - + Author: plugin details Autor: - + Internal name: plugin details Interný názov: - + Dependencies: plugin details Závislosti: - + Conflicts: plugin details Konflikty: - + Plugin details Detaily pluginu - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. Pluginy sú načítané/uvoľnené okamžite pri zaškrtnutí/odškrtnutí ale midifikovaný zoznam pluginov načítaných pri štarte nieje uložený až kým nepotvrdíte celý konfiguračný dialóg. - + %1 (built-in) plugins manager in configuration dialog %1 (interný) - + Details Detaily - + No plugins in this category. - + Add new data type Pridať nový datový typ - + Rename selected data type Premenovať vybraný datový typ - + Delete selected data type Vymazať vybraný datový typ - + Help for configuring data type editors @@ -1802,138 +1802,154 @@ but it's okay to use it. DataView - + Filter data data view Filtrovať - + Grid view Tabuľkové zobrazenie - + Form view Formulárové zobrazenie - + Refresh table data data view Obnoviť dáta v tabuľke - + First page data view Prvá strana - + Previous page data view Predchádzajúca strana - + Next page data view Nasledujúca strana - + Last page data view Posledná strana - + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + Apply filter data view Aplikovať filter - + Commit changes for selected cells data view Potvrdiť zmeny pre vybrané bunky - + Rollback changes for selected cells data view Vrátiť späť zmeny pre vybrané bunky - + Show grid view of results sql editor Výsledky zobraziť v tabuľke - + Show form view of results sql editor Výsledky zobraziť vo formulári - + Filter by text data view Filtrovať pomocou textu - + Filter by the Regular Expression data view Filtrovať pomocou regulárneho výrazu - + Filter by SQL expression data view Filtrovať pomocou SQL výrazu - + Tabs on top data view Záložky hore - + Tabs at bottom data view Záložky dole - + Place new rows above selected row data view - + Place new rows below selected row data view - + Place new rows at the end of the data view data view - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. Spočítava sa celkový počet riadkov. Prezeranie ďalších strán bude možné až po dokončení spočítavania. - + Row: %1 Riadok:%1 @@ -2140,7 +2156,7 @@ Prezeranie ďalších strán bude možné až po dokončení spočítavania. - <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> @@ -2255,286 +2271,423 @@ Prezeranie ďalších strán bude možné až po dokončení spočítavania.Filtrovať podľa názvu - + Copy Kopírovať - + Paste Vložiť - + Select all Vybrať všetko - + Create a group Vytvoriť skupinu - + Delete the group Vymazať skupinu - + Rename the group Premenovať skupinu - Add a database - Pridať databázu + Pridať databázu - Edit the database - Upraviť databázu + Upraviť databázu - Remove the database - Odstrániť databázu + Odstrániť databázu - Connect to the database - Pripojiť sa k databáze + Pripojiť sa k databáze - Disconnect from the database - Odpojiť sa od databázy + Odpojiť sa od databázy - + Import Importovať - Export the database - Exportovať databázu + Exportovať databázu - Convert database type - Konvertovať databázu + Konvertovať databázu - Vacuum - Vacuum + Vacuum - Integrity check - Kontrola integrity + Kontrola integrity - Create a table - Vytvoriť tabuľku + Vytvoriť tabuľku - Edit the table - Upraviť tabuľku + Upraviť tabuľku - Delete the table - Vymazať tabuľku + Vymazať tabuľku - + Export the table Exportovať tabuľku - + Import into the table Importovať do tabuľky - + Populate table Naplniť tabuľku - + Create similar table Vytvoriť rovnakú tabuľku - + Reset autoincrement sequence Resetovať sekvenciu autoinkrementu - Create an index - Vytvoriť index + Vytvoriť index - Edit the index - Upraviť index + Upraviť index - Delete the index - Vymazať index + Vymazať index - Create a trigger - Vytvoriť spúšťač + Vytvoriť spúšťač - Edit the trigger - Upraviť spúšťač + Upraviť spúšťač - Delete the trigger - Vymazať spúšťač + Vymazať spúšťač - Create a view - Vytvoriť pohľad + Vytvoriť pohľad - Edit the view - Upraviť pohľad + Upraviť pohľad - Delete the view - Vymazať pohľad + Vymazať pohľad - + Add a column Pridať stĺpec - + Edit the column Upraviť stĺpec - + Delete the column Vymazať stĺpec - + Delete selected items Vymazať vybrané položky - + Clear filter Zrušiť filter - Refresh all database schemas - Obnoviť všetky databázové schémy + Obnoviť všetky databázové schémy - Refresh selected database schema - Obnoviť vybranú databázovú schému + Obnoviť vybranú databázovú schému + + + + Execution from file cancelled. Any queries executed so far have been rolled back. + + + + + &Add a database + + + + + &Edit the database + + + + + &Remove the database + + + + + &Connect to the database + - + &Disconnect from the database + + + + + &Export the database + + + + + Con&vert database type + + + + + Vac&uum + + + + + &Integrity check + + + + + Create a &table + + + + + Edit the t&able + + + + + Delete the ta&ble + + + + + Create an &index + + + + + Edit the i&ndex + + + + + Delete the in&dex + + + + + Create a trig&ger + + + + + Edit the trigg&er + + + + + Delete the trigge&r + + + + + Create a &view + + + + + Edit the v&iew + + + + + Delete the vi&ew + + + + + &Refresh all database schemas + + + + + Re&fresh selected database schema + + + + + Erase table data Vymazať dáta z tabuľky - - + + Open file's directory + + + + + Execute SQL from file + + + + + Database Databáza - + Grouping Zoskupovanie - + Generate query for table - - + + Create group Vytvoriť skupinu - + Group name Názov skupiny - + Entry with name %1 already exists in group %2. Položka s názvom %1 už existuje v skupine %2. - + Delete group Vymazať skupinu - + Are you sure you want to delete group %1? All objects from this group will be moved to parent group. Ste si istý, že chcete vymazať skupinu %1? Všetky objekty z tejto skupiny budú presunuté do nadradenej skupiny. - + Are you sure you want to remove database '%1' from the list? - + Are you sure you want to remove following databases from the list: %1 - + Remove database - + Vacuum (%1) - + Autoincrement value for table '%1' has been reset successfully. - + Are you sure you want to delete all data from table(s): %1? + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + Nemôžem otvoriť súbor '%1' na čítanie: %2 + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. + + Delete database Odstrániť databázu @@ -2544,14 +2697,14 @@ Všetky objekty z tejto skupiny budú presunuté do nadradenej skupiny.Ste si istý, že chcete odstrániť databázu '%1'? - - + + Cannot import, because no import plugin is loaded. Nemôžem importovať, lebo nebol načítaný žiaden plugin na import. - - + + Cannot export, because no export plugin is loaded. Nemôžem exportovať, lebo nebol načítaný žiaden plugin na export. @@ -2564,22 +2717,22 @@ Všetky objekty z tejto skupiny budú presunuté do nadradenej skupiny.VACUUM úspešne skončilo. - + Integrity check (%1) Kontrola integrity (%1) - + Reset autoincrement Resetovať autoinkrement - + Are you sure you want to reset autoincrement value for table '%1'? Ste si istý, že chcete zresetovať hodnotu autoinkrementu pre tabuľku %1 ? - + An error occurred while trying to reset autoincrement value for table '%1': %2 Vyskytla sa chyba pri pokuse o zresetovanie hodnoty autoinkrementu pre tebuľku '%1': %2 @@ -2588,37 +2741,37 @@ Všetky objekty z tejto skupiny budú presunuté do nadradenej skupiny.Ste si istý, že chcete vymazať všetky dáta z tabuľky '%1'? - + An error occurred while trying to delete data from table '%1': %2 Vyskytla sa chyba pri pokuse vymazať dáta z tabuľky '%1': %2 - + All data has been deleted for table '%1'. Všetky dáta z tabuľky '%1' boli vymazané. - + Following objects will be deleted: %1. Nasledujúce objekty budú odstránené: %1. - + Following databases will be removed from list: %1. Nasledujúce databázy budú odstránené zo zoznamu: %1. - + Remainig objects from deleted group will be moved in place where the group used to be. - + %1<br><br>Are you sure you want to continue? %1<br><br>Ste si istý, že chcete pokračovať? - + Delete objects Odstránenie objektov @@ -2712,74 +2865,74 @@ Všetky objekty z tejto skupiny budú presunuté do nadradenej skupiny.Spúšťače (%1): - + Copy Kopírovať - + Move - + Include data - + Include indexes - + Include triggers - + Abort Zrušiť - + Could not add dropped database file '%1' automatically. Manual setup is necessary. - + Referenced tables - + Do you want to include following referenced tables as well: %1 - + Name conflict - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: - + SQL statements conversion - + Following error occurred while converting SQL statements to the target SQLite version: - + Would you like to ignore those errors and proceed? @@ -2833,130 +2986,136 @@ Please enter new, unique name, or press '%1' to abort the operation:Dotaz - + History História - + Results in the separate tab Výsledky zobraziť v samostatnej záložke - + Results below the query Výsledky zobraziť pod dotaz - - + + SQL editor %1 SQL editor %1 - + Results Výsledky - + Execute query Vykonať dotaz - + Explain query Vysvetliť dotaz - + Clear execution history sql editor Vymazať históriu dotazov - + Export results sql editor Vyexportovať výsledky - + Create view from query sql editor Vytvoriť pohľad z dotazu - + Previous database Predchádzajúca databáza - + Next database Nasledujúca databáza - + Show next tab sql editor Zobraziť nasledujúcu záložku - + Show previous tab sql editor Zobraziť predchádzajúcu záložku - + Focus results below sql editor - + Focus SQL editor above sql editor - + + Delete selected SQL history entries + sql editor + + + + Active database (%1/%2) Aktívna databáza (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 Dotaz trval %1 sekúnd. Počet dotknutých riadkov: %2 - + Query finished in %1 second(s). Dotaz trval %1 sekúnd. - + Clear execution history Vymazať históriu dotazov - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. Ste si istý, že chete vymazať celú históriu SQL dotazov? Túto operáciu nieje možné vrátiť späť. - + Cannot export, because no export plugin is loaded. Nemôžem exportovať, lebo nebol načítaný žiaden plugin na export. - + No database selected in the SQL editor. Cannot create a view for unknown database. Nebola vybraná žiadna databáza v SQL editore. Nemôžem vytvoriť view pre neznámu databázu. - + Editor window "%1" has uncommitted data. @@ -2983,6 +3142,64 @@ Please enter new, unique name, or press '%1' to abort the operation: + + ExecFromFileDialog + + + Execute SQL from file + + + + + Input file + + + + + Path to file + + + + + Browse for file + + + + + Options + Voľby + + + + File encoding + + + + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + ExportDialog @@ -3132,78 +3349,111 @@ Please enter new, unique name, or press '%1' to abort the operation:Možnosti formátu exportu - + Cancel Zrušiť - - - + + + Select database to export. Vyberte databázu, ktorú chcete exportovať. - + Select table to export. Vyberte tabuľku, ktorú chcete exportovať. - + Enter valid query to export. Zadajte platný dotaz pre export. - + Select at least one object to export. Vyberte aspoň jeden objekt pre export. - + You must provide a file name to export to. Musíte zadať názov súboru, do ktorého sa budú exportovať dáta. - + Path you provided is an existing directory. You cannot overwrite it. Cesta, ktorú ste zadali je existujúci adresár. Nemôžte ho prepísať. - + The directory '%1' does not exist. Adresár %1 neexistuje. - + The file '%1' exists and will be overwritten. Súbor %1 už existuje a bude prepísaný. - + All files (*) Všetky súbory (*) - + Pick file to export to Výber súboru do ktorého sa budú exportovať dáta - + Internal error during export. This is a bug. Please report it. Počas exportu sa vyskytla interná chyba. Toto je chyba v programe. Prosím nahláste ju. - FontEdit + FileExecErrorsDialog - - Choose font - font configuration + + Execution errors - - + + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + Chyba + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + + + FontEdit + + + Choose font + font configuration + + + + Form @@ -3214,49 +3464,49 @@ Please enter new, unique name, or press '%1' to abort the operation: FormView - + Commit row form view Potvrdiť riadok - + Rollback row form view Vrátiť späť riadok - + First row form view Prvý riadok - + Previous row form view Predchádzajúci riadok - + Next row form view Nasledujúci riadok - + Last row form view Posledný riadok - + Insert new row form view Vložiť nový riadok - + Delete current row form view Vymazať aktuálny riadok @@ -3315,13 +3565,13 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Function implementation code: - + Final step implementation code: @@ -3485,42 +3735,42 @@ Please enter new, unique name, or press '%1' to abort the operation:Nastavenia dátového zdroja - + Cancel Zrušiť - + If you type table name that doesn't exist, it will be created. Ak zadáte názov neexistujúcej tabuľky, tak bude vytvorená. - + Enter the table name Zadajte názov tabuľky - + Select import plugin. Vyberte importný plugin. - + You must provide a file to import from. Musíte zadať súbor, z ktorého sa budú importovať dáta. - + The file '%1' does not exist. Súbor %1 neexistuje. - + Path you provided is a directory. A regular file is required. Cesta, ktorú ste zadali je adresár. Prosím zadajte celú cestu. - + Pick file to import from Výber súboru, z ktorého sa budú importovať dáta @@ -3559,12 +3809,12 @@ Please enter new, unique name, or press '%1' to abort the operation:Stĺpec - + Collation Porovnávanie - + Sort Zoradiť @@ -3743,273 +3993,406 @@ Please enter new, unique name, or press '%1' to abort the operation:Lišta pohľadov - + Configuration widgets - + Syntax highlighting engines - + Data editors Editory dát - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. - + Running in debug mode. Debug messages are printed to the standard output. Beží v ladiacom móde. Ladiace správy sú vypisované na štandardný výstup. - + You need to restart application to make the language change take effect. Je potrebné reštartovať aplikáciu aby sa zmena jazyka prejavila. - Open SQL editor - Otvoriť SQL editor + Otvoriť SQL editor - Open DDL history - Otvoriť DDL históriu + Otvoriť DDL históriu - Open SQL functions editor - Otvoriť editor SQL funkcií + Otvoriť editor SQL funkcií - Open collations editor - Otvoriť editor porovnávaní + Otvoriť editor porovnávaní - Import - Import + Import - Export - Export + Export - Open configuration dialog - Konfigurácia + Konfigurácia - Tile windows - Oddeliť okná + Oddeliť okná - Tile windows horizontally - Oddeliť okná horizontálne + Oddeliť okná horizontálne - Tile windows vertically - Oddeliť okná vertikálne + Oddeliť okná vertikálne - Cascade windows - Okná kaskádovito + Okná kaskádovito - + Next window Nasledujúce okno - + Previous window Predchádzajúce okno - + Hide status field - Close selected window - Zatvoriť vybrané okno + Zatvoriť vybrané okno - Close all windows but selected - Zatvoriť všetky okná okrem vybraného + Zatvoriť všetky okná okrem vybraného - Close all windows - Zatvoriť všetky okná + Zatvoriť všetky okná - Restore recently closed window - Obnoviť posledné zatvorené okno + Obnoviť posledné zatvorené okno - Rename selected window - Premenovať vybrané okno + Premenovať vybrané okno - + Open Debug Console Otvoriť ladiacu konzolu - + Open CSS Console Otvoriť CSS konzolu - Report a bug - Nahlásiť chybu + Nahlásiť chybu - Propose a new feature - Navrhnúť novú funkciu + Navrhnúť novú funkciu - About - O programe + O programe - Licenses - Licencie + Licencie - Open home page - Otvoriť domovskú stránku + Otvoriť domovskú stránku - Open forum page - Otvoriť fórum + Otvoriť fórum - User Manual - Používateľský manuál + Používateľský manuál - SQLite documentation - Dokumentácia SQLite + Dokumentácia SQLite - Report history - História hlásení + História hlásení - Check for updates - Skontrolovať akutalizácie + Skontrolovať akutalizácie - Database menubar - Databázy + Databázy - Structure menubar - Štruktúry + Štruktúry - View menubar - Zobrazenie + Zobrazenie - + Window list menubar view menu Lišta okien - Tools menubar - Nástroje + Nástroje - Help - Pomoc + Pomoc + + + + Open SQL &editor + + + + + Open DDL &history + + + + + Open SQL &functions editor + + + + + Open &collations editor + - + + Open ex&tension manager + + + + + &Import + + + + + E&xport + + + + + Open confi&guration dialog + + + + + &Tile windows + + + + + Tile windows &horizontally + + + + + Tile windows &vertically + + + + + &Cascade windows + + + + + Close selected &window + + + + + Close all windows &but selected + + + + + Close &all windows + + + + + Re&store recently closed window + + + + + &Rename selected window + + + + + Report a &bug + + + + + Propose a new &feature + + + + + &About + + + + + &Licenses + + + + + Open home &page + + + + + Open fo&rum page + + + + + User &Manual + + + + + SQLite &documentation + + + + + Bugs and feature &requests + + + + + Check for &updates + + + + + &Database + menubar + + + + + &Structure + menubar + + + + + &View + menubar + + + + + &Tools + menubar + + + + + &Help + + + + Could not set style: %1 main window Nemôžem nastaviť štýl: %1 - + Cannot export, because no export plugin is loaded. Nemôžem exportovať, lebo nebol načítaný žiaden plugin na export. - + Cannot import, because no import plugin is loaded. Nemôžem importovať, lebo nebol načítaný žiaden plugin na import. - + Rename window Premenovať okno - + Enter new name for the window: Zadajte nový názov pre okno: - + New updates are available. <a href="%1">Click here for details</a>. Nové aktualizácie sú dostupné. <a href="%1">Kliknite sem pre zobrazenie detailov</a>. - + You're running the most recent version. No updates are available. Niesú dostupné žiadne aktualizácie. Používate aktuálnu verziu. - + Database passed in command line parameters (%1) was already on the list under name: %2 Databáza prebratá z príkazového riadka (%1) už je v zozname pod názvom: %2 - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 Databáza prebratá z príkazového riadka (%1) bola dočasne pridaná do zoznamu pod názvom: %2 - + Could not add database %1 to list. Nemôžem pridať databázu %1 do zoznamu. @@ -4045,32 +4428,37 @@ Please enter new, unique name, or press '%1' to abort the operation:Hodnota null - + Configure editors for this data type - + + Open another tab + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. - + Deleted multieditor - + Read only multieditor Iba na čítanie - MultiEditorBool + MultiEditorBoolPlugin - + Boolean @@ -4078,23 +4466,37 @@ Please enter new, unique name, or press '%1' to abort the operation: MultiEditorDate - Date - Dátum + Dátum + + + + MultiEditorDatePlugin + + + Date + Dátum MultiEditorDateTime - Date & time - Dátum a čas + Dátum a čas - MultiEditorHex + MultiEditorDateTimePlugin - + + Date & time + Dátum a čas + + + + MultiEditorHexPlugin + + Hex @@ -4102,59 +4504,70 @@ Please enter new, unique name, or press '%1' to abort the operation: MultiEditorNumeric - Number numeric multi editor tab name - Číslo + Číslo - MultiEditorText + MultiEditorNumericPlugin - - Text - + + Number + numeric multi editor tab name + Číslo + + + MultiEditorText - + Tab changes focus - + Cut Vystrihnúť - + Copy Kopírovať - + Paste Vložiť - + Delete Vymazať - + Undo - + Redo - MultiEditorTime + MultiEditorTextPlugin - + + Text + + + + + MultiEditorTimePlugin + + Time @@ -4231,37 +4644,40 @@ Please enter new, unique name, or press '%1' to abort the operation:Komponenta - + + This application will be closed and the update installer will start to download and install all the updates. + + + Current version - Nainštalovaná verzia + Nainštalovaná verzia - + Update version Dostupná verzia - + Check for updates on startup Kontrolovať aktualizácie pri štarte - + Update to new version! Aktualizovať na novú verziu! - The update will be automatically downloaded and installed. This will also restart application at the end. - Aktualizácie budú automaticky stiahnuté a nainštalované. Na konci sa aplikácia reštartuje. + Aktualizácie budú automaticky stiahnuté a nainštalované. Na konci sa aplikácia reštartuje. - + Not now. Nie teraz. - + Don't install the update and close this window. Neinštalovať aktializácie a zatvoriť toto okno. @@ -4313,32 +4729,32 @@ Please enter new, unique name, or press '%1' to abort the operation:Naplniť - + Abort Zrušiť - + Configure Konfigurovať - + Populating configuration for this column is invalid or incomplete. - + Select database with table to populate Vyberte databázu s tabuľkou na naplnenie - + Select table to populate Vyberte tabuľku na naplnenie - + You have to select at least one column. Musíte vybrať minimálne jeden stĺpec. @@ -4413,129 +4829,134 @@ Please enter new, unique name, or press '%1' to abort the operation:Názov porovnánavania: %1 - + Data grid view Tabuľkové zobrazenie dát - + Copy cell(s) contents to clipboard Kopírovať obsah buniek do schránky + Copy cell(s) contents together with header to clipboard + + + + Paste cell(s) contents from clipboard Vložiť obsah buniek zo schránky - + Set empty value to selected cell(s) Vymazať hodnoty z vybraných buniek - + Set NULL value to selected cell(s) Nastaviť NULL hodnotu vo vybraných bunkách - + Commit changes to cell(s) contents Potvrdiť zmeny v bunkách - + Rollback changes to cell(s) contents Vrátiť späť zmeny v bunkách - + Delete selected data row Vymazať vybraný riadok - + Insert new data row Vložiť nový riadok - + Open contents of selected cell in a separate editor Otvoriť obsah vybranej bunky v samostatnom editore - + Total pages available: %1 Celkový počet strán: %1 - + Total rows loaded: %1 Celkový počet riadkov: %1 - + Data view (both grid and form) Zobrazenie dát (tabuľka a formulár) - + Refresh data Obnoviť dáta - + Switch to grid view of the data Prepnúť na tabuľkové zobrazenie dát - + Switch to form view of the data Prepnúť na formulárové zobrazenie dát - + Database list Zoznam databáz - + Delete selected item Vymazať vybranú položku - + Clear filter contents Vymazať filter - + Refresh schema Obnoviť schému - + Refresh all schemas Obnoviť všetky schémy - + Add database Pridať databázu - + Select all items Vybrať všetky položky - + Copy selected item(s) Kopírovať vybrané položky - + - + Paste from clipboard Vložiť zo schránky @@ -4610,42 +5031,42 @@ Please enter new, unique name, or press '%1' to abort the operation:Vymazať aktuálny riadok - + Main window Hlavné okno - + Open SQL editor Otvoriť SQL editor - + Previous window Predchádzajúce okno - + Next window Nasledujúce okno - + Hide status area Skryť status okno - + Open configuration dialog Otvoriť konfiguračné okno - + Open Debug Console Otvoriť ladiacu konzolu - + Open CSS Console Otvoriť CSS konzolu @@ -4656,111 +5077,111 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cut selected text Vystrihnúť vybraný text - + Copy selected text Kopírovať vybraný text - + Delete selected text Vymazať vybraný text - + Undo - + Redo - + SQL editor input field - + Select whole editor contents Označiť všetko - + Save contents into a file Uložiť SQL do súboru - + Load contents from a file Načítať SQL zo súboru - + Find in text Nájsť v SQL - + Find next Nájsť ďalší - + Find previous Nájsť predchádzajúci - + Replace in text Nahradiť v SQL - + Delete current line Vymazať aktuálny riadok - + Request code assistant Otvoriť SQL pomocníka - + Format contents Formátovať SQL - + Move selected block of text one line down Presunúť blok kódu o riadok nižšie - + Move selected block of text one line up Presunúť blok kódu o riadok vyššie - + Copy selected block of text and paste it a line below Kopírovať blok kódu a vložiť ho na riadok nižšie - + Copy selected block of text and paste it a line above Kopírovať blok kódu a vložiť ho na riadok vyššie - + Toggle comment @@ -4781,14 +5202,12 @@ Please enter new, unique name, or press '%1' to abort the operation:Databázový súbor - Reports history window - Okno histórie hlásení + Okno histórie hlásení - Delete selected entry - Vymazať vybranú položku + Vymazať vybranú položku @@ -4835,6 +5254,11 @@ Please enter new, unique name, or press '%1' to abort the operation:Move keyboard input focus to the SQL editor above Prepnúť kurzor do editora + + + Delete selected SQL history entries + + Table window @@ -5058,179 +5482,179 @@ nájsť ďalší SqlEditor - + Cut sql editor Vystrihnúť - + Copy sql editor Kopírovať - + Paste sql editor Vložiť - + Delete sql editor Vymazať - + Select all sql editor Vybrať všetko - + Undo sql editor - + Redo sql editor - + Complete sql editor - + Format SQL sql editor Formátovať SQL - + Save SQL to file sql editor Uložiť SQL do súboru - + Select file to save SQL sql editor - + Load SQL from file sql editor Načítať SQL zo súboru - + Delete line sql editor Vymazať riadok - + Move block down sql editor - + Move block up sql editor - + Copy block down sql editor - + Copy up down sql editor - + Find sql editor Nájsť - + Find next sql editor Nájsť ďalší - + Find previous sql editor Nájsť predchádzajúci - + Replace sql editor Nahradiť - + Toggle comment sql editor - + Saved SQL contents to file: %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. - + Save to file Uložiť do súboru - + Could not open file '%1' for writing: %2 Nemôžem otvoriť súbor '%1' pre zápis: %2 - + SQL scripts (*.sql);;All files (*) - + Open file Otvoriť súbor - + Could not open file '%1' for reading: %2 Nemôžem otvoriť súbor '%1' na čítanie: %2 - + Reached the end of document. Hit the find again to restart the search. Dosiahnutý koniec súboru. Kliknite na tlačidlo Nájsť pre hľadanie od začiatku súboru. @@ -5282,24 +5706,24 @@ nájsť ďalší - - + + Cannot edit this cell. Details: %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. @@ -5307,8 +5731,8 @@ nájsť ďalší SqlQueryModel - - + + Only one query can be executed simultaneously. Nemôže byť spustených viacero dotazov súčasne. @@ -5321,12 +5745,12 @@ nájsť ďalší Sú tu nepotvrdené zmeny. Chcete aj napriek tomu pokračovať? Všetky nepotvrdené zmeny budú stratené. - + Cannot commit the data for a cell that refers to the already closed database. Nemôžem potrdiť dáta bunky, ktorá odkazuje na už uzatvorenú databázu. - + Could not begin transaction on the database. Details: %1 Nemôžem začať tranzakciu na databáze. Detaily: %1 @@ -5335,12 +5759,12 @@ nájsť ďalší Vyskytla sa chyba počas potvrdzovania tranzakcie: %1 - + An error occurred while rolling back the transaction: %1 Vyskytla sa chyba počas vracania späť tranzakcie: %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. Nastal pokus o potvrdenie zmien v bunke, ktorú nieje možné upravovať (napriek tomu bola upravená a čaká na potvrdenie)! Toto je chyba. Prosím nahláste ju. @@ -5349,43 +5773,48 @@ nájsť ďalší Vyskytla sa chyba počas potvrdzovania dát: %1 - + Uncommitted data - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. - + An error occurred while committing the transaction: %1 - + An error occurred while committing the data: %1 - - + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + + + + + Error while executing SQL query on database '%1': %2 Vyskytla sa chyba počas vykonávania SQL dotazu na databáze '%1': %2 - + Error while loading query results: %1 Vyskytla sa chyba počas načítavania výsledkov dotazu: %1 - + Insert multiple rows Vložiť viacero riadkov - + Number of rows to insert: Počet vkládaných riadkov: @@ -5393,117 +5822,137 @@ nájsť ďalší SqlQueryView - + Go to referenced row in... - + Copy Kopírovať - + Copy as... Kopírovať ako... - + Paste Vložiť - + Paste as... Vložiť ako... - + Set NULL values Nastaviť null hodnoty - + Erase values Vymazať hodnoty - + Edit value in editor Upraviť hodnotu v editory - + Commit Potvrdiť - + + Copy with headers + + + + Rollback Vrátiť späť - + Commit selected cells Potvrdiť vybrané bunky - + Rollback selected cells Vrátiť späť vybrané bunky - + Define columns to sort by Vybrať stĺpce na zoradenie podľa - + Remove custom sorting Odstrániť užívateľské triedenie - + Insert row Vložiť riadok - + Insert multiple rows Vložiť viacero riadkov - + Delete selected row Vymazať viacero riadkov - + + Show value in a viewer + + + + Generate query for selected cells - + No items selected to paste clipboard contents to. Neboli vybrané žiadne položky na vloženie obsahu schránky. - + Go to referenced row in table '%1' - + table '%1' - + Referenced row (%1) - + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + Edit value Upraviť hodnotu @@ -5525,6 +5974,119 @@ nájsť ďalší Vyskytla sa chyba počas mazania riadka z tabuľky %1: %2 + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + Databázy + + + + Register in all databases + Registrovať vo všetkých databázach + + + + Register in following databases: + Registrovať v nasledujúcich databázach: + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + Všetky súbory (*) + + + + Open file + Otvoriť súbor + + StatusField @@ -5633,7 +6195,7 @@ but it's okay to use them anyway. Zadajte názov obmedzenia. - + Foreign column table constraints Cudzí stĺpec @@ -5687,24 +6249,24 @@ but it's okay to use them anyway. Pri konflikte - + Collate table constraints Porovnať - + Sort order table constraints Zoradiť - + Select at least one column. Vyberte minimálne jeden stĺpec. - + Enter a name of the constraint. Zadajte názov obmedzenia. @@ -6277,7 +6839,7 @@ Chcete potvrdiť štruktúru alebo sa chcete vrátiť do záložky štruktúr? - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> @@ -6322,7 +6884,7 @@ Chcete potvrdiť štruktúru alebo sa chcete vrátiť do záložky štruktúr? - + DDL DDL @@ -6400,18 +6962,18 @@ Chcete potvrdiť štruktúru alebo sa chcete vrátiť do záložky štruktúr? - - + + Data Dáta - + Triggers Spúšťače - + DDL DDL @@ -6443,120 +7005,120 @@ Chcete potvrdiť štruktúru alebo sa chcete vrátiť do záložky štruktúr?Nový pohľad %1 - + Refresh the view view window Obnoviť pohľad - + Commit the view changes view window Potvrdiť zmeny v pohľade - + Rollback the view changes view window Vrátiť späť zmeny v pohľade - + Explicit column names - + Generate output column names automatically basing on result columns of the view. - + Add column view window Pridať stĺpec - + Edit column view window Upraviť stĺpec - + Delete column view window Vymazať stĺpec - + Move column up view window Posunúť stĺpec hore - + Move column down view window Posunúť stĺpec dole - + Refresh trigger list view window Obnoviť zoznam spúšťačov - + Create new trigger view window Vytvoriť nový spúšťač - + Edit selected trigger view window Upraviť vybraný spúšťač - + Delete selected trigger view window Vymazať vybraný spúšťač - + View window "%1" has uncommitted structure modifications and data. - + View window "%1" has uncommitted data. - + View window "%1" has uncommitted structure modifications. - + Uncommitted changes - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Committed changes for view '%1' successfully. - + Committed changes for view '%1' (named before '%2') successfully. @@ -6573,7 +7135,7 @@ Do you want to commit the structure, or do you want to go back to the structure Okno pohľadu "%1" obsahuje nepotrdené zmeny štruktúr. - + Could not load data for view %1. Error details: %2 Nemôžem načítať dáta z pohľadu %1. Detaily chyby: %2 @@ -6588,102 +7150,102 @@ Do you want to commit the structure, or do you want to go back to the structure Chcete potvrdiť štruktúru alebo sa chcete vrátiť do záložky štruktúr? - + Go back to structure tab Choď späť na záložku štruktúr - + Commit modifications and browse data. Potvrdiť zmeny a prezerať dáta. - + Could not commit view changes. Error message: %1 view window Nemôžem potvrdiť zmeny v pohľade. Chyba: %1 - + Override columns - + Currently defined columns will be overriden. Do you want to continue? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. - + Name view window triggers Názov - + Instead of view window triggers - + Condition view window triggers Podmienka - + Details table window triggers Detaily - + Could not process the %1 view correctly. Unable to open a view window. - + Empty name - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 SELECT nemôže byť analyzovaný. Prosím opravte dotaz a skúste to znovu. Detaily: %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. - + Following problems will take place while modifying the view. Would you like to proceed? view window - + View modification view window diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.qm b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.qm index 3201eff..98db9d2 100644 Binary files a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.qm and b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.qm differ diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts index 53cd968..cbfc48e 100644 --- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts +++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts @@ -14,9 +14,8 @@ 关于 - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">自由,开源,跨平台的 SQLite 数据库管理工具。<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">作者和活跃维护人:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">自由,开源,跨平台的 SQLite 数据库管理工具。<br/><a href="http://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">作者和活跃维护人:<br/>SalSoft (<a href="http://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">http://salsoft.com.pl</span></a>)<br/></p></body></html> @@ -58,6 +57,11 @@ Configuration directory 配置文件目录 + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">SQLiteStudio v%1</span></p><p align="center">Free, open-source, cross-platform SQLite database manager.<br/><a href="https://sqlitestudio.pl"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitestudio.pl</span></a><br/></p><p align="center">%2<br/></p><p align="center">Author and active maintainer:<br/>SalSoft (<a href="https://salsoft.com.pl"><span style=" text-decoration: underline; color:#0000ff;">https://salsoft.com.pl</span></a>)<br/></p></body></html> + + Qt version: @@ -89,264 +93,224 @@ <h3>目录:</h3><ol>%2</ol> + + BindParamsDialog + + + Query parameters + + + + + Please provide values for query parameters + + + BugDialog - Bugs and ideas - Bugs 和想法 + Bugs 和想法 - Reporter - 报告者 + 报告者 - E-mail address - E-mail 地址 + E-mail 地址 - - Log in - 登录 + 登录 - Short description - 简要描述 + 简要描述 - Detailed description - 详细描述 + 详细描述 - Show more details - 更多详细信息 + 更多详细信息 - SQLiteStudio version - SQLiteStudio 版本 + SQLiteStudio 版本 - Operating system - 操作系统 + 操作系统 - Loaded plugins - 已加载插件 + 已加载插件 - Send - 发送 + 发送 - You can see all your reported bugs and ideas by selecting menu '%1' and then '%2'. - 您可以通过选择菜单 “1%”下的“%2”来查看全部您报告的bugs和想法。 + 您可以通过选择菜单 “1%”下的“%2”来查看全部您报告的bugs和想法。 - A bug report sent successfully. - Bug报告提交成功。 + Bug报告提交成功。 - An error occurred while sending a bug report: %1 %2 - 提交bug报告时发生了错误:%1 + 提交bug报告时发生了错误:%1 %2 - - You can retry sending. The contents will be restored when you open a report dialog after an error like this. - 您可以重新发送试试。当你在发生错误后重新打开上报对话框时,你之前输入的内容将会恢复。 + 您可以重新发送试试。当你在发生错误后重新打开上报对话框时,你之前输入的内容将会恢复。 - An idea proposal sent successfully. - 提交建议成功。 + 提交建议成功。 - An error occurred while sending an idea proposal: %1 %2 - 在提交建议时发生错误:%1 + 在提交建议时发生错误:%1 %2 - A bug report - Bug报告 + Bug报告 - Describe problem in few words - 简要描述一下问题 + 简要描述一下问题 - Describe problem and how to reproduce it - 描述一下问题,怎么复现问题 + 描述一下问题,怎么复现问题 - A new feature idea - 新功能建议 + 新功能建议 - A title for your idea - 您的建议题目 + 您的建议题目 - Describe your idea in more details - 仔细描述一下您的想法 + 仔细描述一下您的想法 - Reporting as an unregistered user, using e-mail address. - 使用e-mail地址以未注册用户身份上报。 + 使用e-mail地址以未注册用户身份上报。 - Reporting as a registered user. - 作为已注册用户报告。 + 作为已注册用户报告。 - Log out - 退出 + 退出 - Providing true email address will make it possible to contact you regarding your report. To learn more, press 'help' button on the right side. - 使用真实email地址有助于您上报后联系到您。如果想了解更多,请点击右方的“帮助”按钮。 + 使用真实email地址有助于您上报后联系到您。如果想了解更多,请点击右方的“帮助”按钮。 - Enter vaild e-mail address, or log in. - 输入正确的e-mail地址,或者登录。 + 输入正确的e-mail地址,或者登录。 - Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below. - 简要描述至少10个字符,但不超过100个字符。更详细的描述内容请在下面的区域填写。 + 简要描述至少10个字符,但不超过100个字符。更详细的描述内容请在下面的区域填写。 - Long description requires at least 30 characters. - 详细描述内容至少30个字符。 + 详细描述内容至少30个字符。 BugReportHistoryWindow - - Title - 标题 + 标题 - - Reported at - 报告时间 + 报告时间 - - URL - URL + URL - Reports history - 报告历史 + 报告历史 - Clear reports history - 清空报告历史 + 清空报告历史 - Delete selected entry - 删除选中项 + 删除选中项 - Invalid response from server. - 无效的服务器回应。 + 无效的服务器回应。 BugReportLoginDialog - Log in - 登录 + 登录 - Credentials - 认证信息 + 认证信息 - Login: - 登录名: + 登录名: - Password: - 密码: + 密码: - Validation 这里不是很确认。Not sure about this translation. - 确认 + 确认 - Validate not sure about this translation - 确认 + 确认 - Validation result message - 验证信息 + 验证信息 - Abort - 中止 + 中止 - A login must be at least 2 characters long. - 登录名至少2个字符。 + 登录名至少2个字符。 - A password must be at least 5 characters long. - 密码至少5个字符。 + 密码至少5个字符。 - Valid - 已验证 + 已验证 @@ -357,12 +321,12 @@ 过滤器排序规则 - + Collation name: 排序规则名称: - + Implementation language: 实现语言: @@ -491,11 +455,20 @@ + Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters. + + + + + Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters. + + + Invalid default value expression: %1 - 无效的默认值表达式:%1 + 无效的默认值表达式:%1 - + Enter a name of the constraint. 输入约束名: @@ -607,7 +580,7 @@ - + Delete constraint column dialog 删除约束 @@ -667,34 +640,44 @@ 添加默认约束 - + Are you sure you want to delete constraint '%1'? column dialog 您确定要删除约束“%1”吗? - + Correct the constraint's configuration. 修正约束配置。 - + This constraint is not officially supported by SQLite 2, but it's okay to use it. SQLite2没有官方支持该约束,但是可以使用。 - + Scale is not allowed for INTEGER PRIMARY KEY columns. - + Precision cannot be defined without the scale. - + + Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY. + + + + + INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY. + + + + Precision is not allowed for INTEGER PRIMARY KEY columns. @@ -796,10 +779,9 @@ but it's okay to use it. - Autoincrement (only for %1 type columns) column primary key - Autoincrement (只能%1类型的字段才能有该属性) + Autoincrement (只能%1类型的字段才能有该属性) @@ -911,7 +893,7 @@ but it's okay to use it. ConfigDialog - + Configuration 配置 @@ -1001,113 +983,113 @@ but it's okay to use it. 流量和编辑数据 - + Number of data rows per page: 每页的行数: - - + + <p>When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.</p> <p>在以列表方式显示数据时,列宽度会自动调整。该值控制初始列宽度,之后您可以手动调整列宽度,不受此限制。</p> - + Limit initial data column width to (in pixels): 限制宽度(单位:像素): - + <p>When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.</p> - + Show column and row details tooltip in data view - + <p>When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).</p> - + Inserting new row in data grid - + Before currently selected row 在已选列之前 - + After currently selected row 在已选列之后 - + At the end of data view 在数据显示区域的末尾 - + <p>When enabled, Table Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every Table Window, instead of being at second place.</p> - + Place data tab as first tab in a Table Window - + <p>When enabled, View Windows will show up with the data tab, instead of the structure tab.</p> - + <p>When enabled the "Data" tab will be placed as first tab in every View Window, instead of being at second place.</p> - + Place data tab as first tab in a View Window - + Data types 数据类型 - + Available editors: 可用的编辑器: - + Editors selected for this data type: 已选的该数据类型编辑器: - + Schema editing 架构编辑 - + Number of DDL changes kept in history. 数据库定义(DDL)的更改历史记录数量。 - + DDL history size: 数据库定义(DDL)历史大小: @@ -1116,104 +1098,104 @@ but it's okay to use it. 当提交schema变动时不显示数据库定义(DDL)预览对话框 - + SQL queries SQL查询 - - + + Number of queries kept in the history. 查询历史记录数量。 - + History size: 历史大小: - + <p>If there is more than one query in the SQL editor window, then (if this option is enabled) only a single query will be executed - the one under the keyboard insertion cursor. Otherwise all queries will be executed. You can always limit queries to be executed by selecting those queries before calling to execute.</p> <p>如果SQL编辑器中有多个语句,如果启用该选项,只执行光标下的语句;反之则执行全部语句。另外您可以选择需要执行的语句来执行</p> - + Execute only the query under the cursor 只执行光标下的语句 - + Updates 更新 - + Automatically check for updates at startup 在启动时自己检查更新 - + Session 会话 - + Restore last session (active MDI windows) after startup 启动后恢复上一次会话。 - + Status Field - + <p>When user manually closes the Status panel, this option makes sure that if any new message is printed in the Status panel it will be reopened. If it's disabled, then Status panel can only be open manually by the user from the "View" menu.</p> - + Always open Status panel when new message is printed - + Filter shortcuts by name or key combination - + Action - + Key combination 按键编定 - - + + Language 语言 - + Changing language requires application restart to take effect. 更改语言后,重启程序生效。 - + Compact layout - + <p>Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.</p> - + Use compact layout @@ -1289,350 +1271,372 @@ but it's okay to use it. - + + + <p>Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.</p> + + + + + Number of memorized table populating configurations + + + + Keep NULL value when entering empty value - + <html><head/><body><p>Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.</p><p>Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.</p></body></html> - + Use DEFAULT value (if defined), when committing NULL value - + Table windows - + Open Table Windows with the data tab for start - + View windows - + Open View Windows with the data tab for start - + Don't show DDL preview dialog when committing schema changes - + + + <p>Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.</p> + + + + + Number of memorized query parameters + + + + Main window dock areas - + Left and right areas occupy corners - + Top and bottom areas occupy corners - + Hide built-in plugins - + Current style: 当前风格: - + Preview 预览 - + Enabled 已启用 - + Disabled 已禁用 - + Active formatter plugin 启用格式化插件 - + SQL editor font SQL编辑器字体 - + Database list font 数据库字体 - + Database list additional label font 数据库额外标签字体 - + Data view font 数据浏览字体 - + Status field font 状态栏字体 - + SQL editor colors SQL编辑器颜色 - + Current line background 当前行的背景色 - + <p>SQL strings are enclosed with single quote characters.</p> <p>单引号内的SQL字符串</p> - + String foreground 字符串颜色 - + <p>Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:</p><ul><li>:param_name</li><li>$param_name</li><li>@param_name</li><li>?</li></ul> - + Bind parameter foreground - + Highlighted parenthesis background - + <p>BLOB values are binary values represented as hexadecimal numbers, like:</p><ul><li>X'12B4'</li><li>x'46A2F4'</li></ul> - + BLOB value foreground BLOB值的颜色 - + Regular foreground 背景色 - + Line numbers area background 行号的背景色 - + Keyword foreground 关键字的颜色 - + Number foreground 数字颜色 - + Comment foreground 注释颜色 - + <p>Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.</p> - + Valid objects foreground - + Data view colors - + <p>Any data changes will be outlined with this color, until they're committed to the database.</p> - + Uncommitted data outline color - + <p>In case of error while committing data changes, the problematic cell will be outlined with this color.</p> - + Commit error outline color - + NULL value foreground NULL值的颜色 - + Deleted row background 已删除行的背景色 - + Database list colors 数据库列表颜色 - + <p>Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.</p> - + Additional labels foreground - + Status field colors - + Information message foreground 信息颜色 - + Warning message foreground 警告信息颜色 - + Error message foreground 错误信息颜色 - + Description: plugin details 描述: - + Category: plugin details 分类: - + Version: plugin details 版本: - + Author: plugin details 作者: - + Internal name: plugin details 内部名字: - + Dependencies: plugin details 依赖: - + Conflicts: plugin details - + Plugin details 插件详情 - + Plugins are loaded/unloaded immediately when checked/unchecked, but modified list of plugins to load at startup is not saved until you commit the whole configuration dialog. - + %1 (built-in) plugins manager in configuration dialog %1 (内建) - + Details 详情 - + No plugins in this category. 该分类下没有插件。 - + Add new data type 添加新的数据类型 - + Rename selected data type 重命名选择的数据类型 - + Delete selected data type 删除已选数据类型 - + Help for configuring data type editors @@ -1784,137 +1788,153 @@ but it's okay to use it. DataView - + Filter data data view - + Grid view - + Form view - + Refresh table data data view - + First page data view 首页 - + Previous page data view 上一页 - + Next page data view 下一页 - + Last page data view 末页 - + + Filter + + + + + Hit Enter key or press "Apply filter" button on toolbar to apply new value. + + + + + Show filter inputs per column + data view + + + + Apply filter data view - + Commit changes for selected cells data view - + Rollback changes for selected cells data view - + Show grid view of results sql editor - + Show form view of results sql editor - + Filter by text data view - + Filter by the Regular Expression data view - + Filter by SQL expression data view - + Tabs on top data view - + Tabs at bottom data view - + Place new rows above selected row data view - + Place new rows below selected row data view - + Place new rows at the end of the data view data view - + Total number of rows is being counted. Browsing other pages will be possible after the row counting is done. - + Row: %1 行:%1 @@ -2101,7 +2121,7 @@ Browsing other pages will be possible after the row counting is done. - <p>Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.</p> + <p>Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.</p> @@ -2211,286 +2231,423 @@ Browsing other pages will be possible after the row counting is done. 过滤名 - + Copy 复制 - + Paste 粘贴 - + Select all 全选 - + Create a group 创建分组 - + Delete the group 删除分组 - + Rename the group 重命名分组 - Add a database - 添加数据库 + 添加数据库 - Edit the database - 编辑数据库 + 编辑数据库 - Remove the database - 移除数据库 + 移除数据库 - Connect to the database - 连接到数据库 + 连接到数据库 - Disconnect from the database - 断开数据库连接 + 断开数据库连接 - + Import 导入 - Export the database - 导数该数据库 + 导数该数据库 - Convert database type - 转换数据库类型 + 转换数据库类型 - Vacuum - 清理 + 清理 - Integrity check - 检查完整性 + 检查完整性 - Create a table - 新建表 + 新建表 - Edit the table - 编辑该表 + 编辑该表 - Delete the table - 删除该表 + 删除该表 - + Export the table 导出该表 - + Import into the table 导入到该表 - + Populate table 填充表 - + Create similar table 创建一个相似的表 - + Reset autoincrement sequence 重设 autoincrement - Create an index - 创建索引 + 创建索引 - Edit the index - 编辑该索引 + 编辑该索引 - Delete the index - 删除该索引 + 删除该索引 - Create a trigger - 创建触发器 + 创建触发器 - Edit the trigger - 编辑该触发器 + 编辑该触发器 - Delete the trigger - 删除该触发器 + 删除该触发器 - Create a view - 创建视图 + 创建视图 - Edit the view - 编辑该视图 + 编辑该视图 - Delete the view - 删除该视图 + 删除该视图 - + Add a column 添加字段 - + Edit the column 编辑该字段 - + Delete the column 删除该字段 - + Delete selected items 删除已选项目 - + Clear filter 清除过滤器 - Refresh all database schemas - 刷新全部数据库的结构 + 刷新全部数据库的结构 - Refresh selected database schema - 刷新已选数据库的结构 + 刷新已选数据库的结构 + + + + Execution from file cancelled. Any queries executed so far have been rolled back. + + + + + &Add a database + + + + + &Edit the database + + + + + &Remove the database + + + + + &Connect to the database + - + &Disconnect from the database + + + + + &Export the database + + + + + Con&vert database type + + + + + Vac&uum + + + + + &Integrity check + + + + + Create a &table + + + + + Edit the t&able + + + + + Delete the ta&ble + + + + + Create an &index + + + + + Edit the i&ndex + + + + + Delete the in&dex + + + + + Create a trig&ger + + + + + Edit the trigg&er + + + + + Delete the trigge&r + + + + + Create a &view + + + + + Edit the v&iew + + + + + Delete the vi&ew + + + + + &Refresh all database schemas + + + + + Re&fresh selected database schema + + + + + Erase table data 擦除该表的数据 - - + + Open file's directory + + + + + Execute SQL from file + + + + + Database 数据库 - + Grouping 分组 - + Generate query for table - - + + Create group 创建分组 - + Group name 分组名 - + Entry with name %1 already exists in group %2. - + Delete group 删除分组 - + Are you sure you want to delete group %1? All objects from this group will be moved to parent group. 确认删除组 %1 吗? 删除后该组下的全部内容将被移动到其所属的父分组中。 - + Are you sure you want to remove database '%1' from the list? - + Are you sure you want to remove following databases from the list: %1 - + Remove database - + Vacuum (%1) - + Autoincrement value for table '%1' has been reset successfully. - + Are you sure you want to delete all data from table(s): %1? + + + Could not execute SQL, because application has failed to start transaction: %1 + + + + + Could not open file '%1' for reading: %2 + + + + + Could not execute SQL, because application has failed to commit the transaction: %1 + + + + + Finished executing %1 queries in %2 seconds. %3 were not executed due to errors. + + + + + Finished executing %1 queries in %2 seconds. + + + + + Could not execute SQL due to error. + + Delete database 删除数据库 @@ -2500,14 +2657,14 @@ All objects from this group will be moved to parent group. 您确定要删除数据库“%1”吗? - - + + Cannot import, because no import plugin is loaded. 未能导入,因为没有导入插件被加载。 - - + + Cannot export, because no export plugin is loaded. 未能导出,因为没有导出插件被加载。 @@ -2520,22 +2677,22 @@ All objects from this group will be moved to parent group. VACUUM 命令执行完成。 - + Integrity check (%1) 完整性检查(%1) - + Reset autoincrement 重置autoincrement - + Are you sure you want to reset autoincrement value for table '%1'? 您确定要重设“%1”的autoincrement吗? - + An error occurred while trying to reset autoincrement value for table '%1': %2 在重设表“%1”的autoincrement时出现错误:%2 @@ -2548,37 +2705,37 @@ All objects from this group will be moved to parent group. 您确定要删除表“%1”中的全部数据吗? - + An error occurred while trying to delete data from table '%1': %2 删除表“%1”中的数据时出错:%2 - + All data has been deleted for table '%1'. 表“%1”中的数据全部被删除。 - + Following objects will be deleted: %1. 以下内容将被删除:%1。 - + Following databases will be removed from list: %1. 以下数据库将从列表中移除:%1。 - + Remainig objects from deleted group will be moved in place where the group used to be. - + %1<br><br>Are you sure you want to continue? %1<br><br>继续? - + Delete objects 删除对象 @@ -2667,74 +2824,74 @@ All objects from this group will be moved to parent group. 触发器(%1) - + Copy 复制 - + Move 移动 - + Include data 包含数据 - + Include indexes 包含索引 - + Include triggers 包含触发器 - + Abort 中止 - + Could not add dropped database file '%1' automatically. Manual setup is necessary. - + Referenced tables 参照表 - + Do you want to include following referenced tables as well: %1 - + Name conflict 名字冲突 - + Following object already exists in the target database. Please enter new, unique name, or press '%1' to abort the operation: - + SQL statements conversion - + Following error occurred while converting SQL statements to the target SQLite version: - + Would you like to ignore those errors and proceed? 忽略错误并继续? @@ -2788,130 +2945,136 @@ Please enter new, unique name, or press '%1' to abort the operation: - + History 历史 - + Results in the separate tab 结果在新标签中打开 - + Results below the query 结果在当前页打开 - - + + SQL editor %1 SQL编辑器 %1 - + Results 结果 - + Execute query 执行语句 - + Explain query - + Clear execution history sql editor 清除执行历史 - + Export results sql editor 导出结果 - + Create view from query sql editor 从query中创建视图 - + Previous database 前一个数据库 - + Next database 下一个数据库 - + Show next tab sql editor 显示下一个标签 - + Show previous tab sql editor 显示上一个标签 - + Focus results below sql editor - + Focus SQL editor above sql editor - + + Delete selected SQL history entries + sql editor + + + + Active database (%1/%2) - + Query finished in %1 second(s). Rows affected: %2 - + Query finished in %1 second(s). - + Clear execution history 清除执行历史 - + Are you sure you want to erase the entire SQL execution history? This cannot be undone. 确定要删除全部的SQL执行历史吗?删除后不能恢复。 - + Cannot export, because no export plugin is loaded. 未能导出,因为没有导出插件被加载。 - + No database selected in the SQL editor. Cannot create a view for unknown database. - + Editor window "%1" has uncommitted data. @@ -2938,6 +3101,64 @@ Please enter new, unique name, or press '%1' to abort the operation:仍然继续吗? + + ExecFromFileDialog + + + Execute SQL from file + + + + + Input file + + + + + Path to file + + + + + Browse for file + + + + + Options + 选项 + + + + File encoding + + + + + Skip failing SQL statements + + + + + SQL scripts (*.sql);;All files (*) + SQL文件 (*.sql);;所有文件 (*) + + + + Execute SQL file + + + + + Please provide file to be executed. + + + + + Provided file does not exist or cannot be read. + + + ExportDialog @@ -3087,131 +3308,164 @@ Please enter new, unique name, or press '%1' to abort the operation:导出格式选项 - + Cancel 取消 - - - + + + Select database to export. 选择要导出的数据库。 - + Select table to export. 选择要导出的表。 - + Enter valid query to export. - + Select at least one object to export. - + You must provide a file name to export to. - + Path you provided is an existing directory. You cannot overwrite it. - + The directory '%1' does not exist. - + The file '%1' exists and will be overwritten. - + All files (*) 所有文件 (*) - + Pick file to export to - + Internal error during export. This is a bug. Please report it. - FontEdit + FileExecErrorsDialog - - Choose font - font configuration - 字体选择 + + Execution errors + - - - Form - - Active SQL formatter plugin - 激活SQL语句格式化插件 + + Following errors were encountered during execution of SQL statements from the file: + + + + + SQL + + + + + Error + 错误 + + + + Statements that were executed successfully were commited. + + + + + Statements that were executed successfully were rolled back. + + + + + FontEdit + + + Choose font + font configuration + 字体选择 + + + + Form + + + Active SQL formatter plugin + 激活SQL语句格式化插件 FormView - + Commit row form view 提交 - + Rollback row form view 回滚 - + First row form view 首行 - + Previous row form view 前一行 - + Next row form view 下一行 - + Last row form view 末行 - + Insert new row form view 新插入行 - + Delete current row form view 删除当前行 @@ -3270,13 +3524,13 @@ Please enter new, unique name, or press '%1' to abort the operation:初始化代码: - + Function implementation code: - + Final step implementation code: @@ -3440,42 +3694,42 @@ Please enter new, unique name, or press '%1' to abort the operation:数据源选项 - + Cancel 取消 - + If you type table name that doesn't exist, it will be created. 如果输入的表不存在,则新建该表。 - + Enter the table name 输入表名 - + Select import plugin. 选择导入插件。 - + You must provide a file to import from. 必须提供一个导入文件。 - + The file '%1' does not exist. 文件“%1”不存在。 - + Path you provided is a directory. A regular file is required. 你提供的是一个目录。我们需要的是文件。 - + Pick file to import from 选择要导入的文件 @@ -3514,12 +3768,12 @@ Please enter new, unique name, or press '%1' to abort the operation:字段 - + Collation - + Sort 排序 @@ -3698,273 +3952,402 @@ Please enter new, unique name, or press '%1' to abort the operation:查看工具栏 - + Configuration widgets 配置部件 - + Syntax highlighting engines 语法高亮引擎 - + Data editors 数据编辑器 - + Running in debug mode. Press %1 or use 'Help / Open debug console' menu entry to open the debug console. - + Running in debug mode. Debug messages are printed to the standard output. - + You need to restart application to make the language change take effect. 更改语言后重启程序生效。 - Open SQL editor - 打开SQL编辑器 + 打开SQL编辑器 - Open DDL history - 打开数据库定义(DDL)历史 + 打开数据库定义(DDL)历史 - Open SQL functions editor - 打开SQL函数编辑器 + 打开SQL函数编辑器 - - Open collations editor - - - - Import - 导入 + 导入 - Export - 导出 + 导出 - Open configuration dialog - 打开配置对话框 + 打开配置对话框 - Tile windows - 平铺窗口 + 平铺窗口 - Tile windows horizontally - 水平排列窗口 + 水平排列窗口 - Tile windows vertically - 垂直排列窗口 + 垂直排列窗口 - Cascade windows - 层叠窗口 + 层叠窗口 - + Next window 下一个窗口 - + Previous window 上一个窗口 - + Hide status field 隐藏状态栏 - Close selected window - 关闭当前窗口 + 关闭当前窗口 - Close all windows but selected - 关闭其它窗口 + 关闭其它窗口 - Close all windows - 关闭全部窗口 + 关闭全部窗口 - Restore recently closed window - 恢复最近关闭的窗口 + 恢复最近关闭的窗口 - Rename selected window - 重命名当前窗口 + 重命名当前窗口 - + Open Debug Console 打开调试终端 - + Open CSS Console 打开CSS控制台 - Report a bug - 提交Bug + 提交Bug - Propose a new feature - 提交新功能建议 + 提交新功能建议 - About - 关于 + 关于 - Licenses - 许可 + 许可 - Open home page - 访问主页 + 访问主页 - Open forum page - 访问论坛 + 访问论坛 - User Manual - 用户手册 + 用户手册 - SQLite documentation - SQLite文档 + SQLite文档 - Report history - 报告历史 + 报告历史 - Check for updates - 检查更新 + 检查更新 - Database menubar - 数据库 + 数据库 - Structure menubar - 结构 + 结构 - View menubar - 查看 + 查看 - + Window list menubar view menu 窗口列表 - Tools menubar - 工具 + 工具 - Help - 帮助 + 帮助 + + + + Open SQL &editor + + + + + Open DDL &history + + + + + Open SQL &functions editor + + + + + Open &collations editor + + + + + Open ex&tension manager + + + + + &Import + + + + + E&xport + + + + + Open confi&guration dialog + + + + + &Tile windows + + + + + Tile windows &horizontally + + + + + Tile windows &vertically + + + + + &Cascade windows + + + + + Close selected &window + + + + + Close all windows &but selected + + + + + Close &all windows + + + + + Re&store recently closed window + + + + + &Rename selected window + + + + + Report a &bug + + + + + Propose a new &feature + + + + + &About + + + + + &Licenses + + + + + Open home &page + + + + + Open fo&rum page + + + + + User &Manual + + + + + SQLite &documentation + + + + + Bugs and feature &requests + + + + + Check for &updates + + + + + &Database + menubar + + + + + &Structure + menubar + - + + &View + menubar + + + + + &Tools + menubar + + + + + &Help + + + + Could not set style: %1 main window 未能设置风格:%1 - + Cannot export, because no export plugin is loaded. 未能导出,因为没有导出插件被加载。 - + Cannot import, because no import plugin is loaded. 未能导入,因为没有导入插件被加载。 - + Rename window 重命名窗口 - + Enter new name for the window: 窗口的新名称: - + New updates are available. <a href="%1">Click here for details</a>. 有新更新 <a href="%1">点此查看更新详情</a>. - + You're running the most recent version. No updates are available. 您使用的是最新版,不需要更新。 - + Database passed in command line parameters (%1) was already on the list under name: %2 - + Database passed in command line parameters (%1) has been temporarily added to the list under name: %2 - + Could not add database %1 to list. 未能将数据%1添加到列表 @@ -4000,23 +4383,28 @@ Please enter new, unique name, or press '%1' to abort the operation:Null 值 - + Configure editors for this data type - + + Open another tab + + + + Data editor plugin '%1' not loaded, while it is defined for editing '%1' data type. - + Deleted multieditor 已删除 - + Read only multieditor 只读 @@ -4025,93 +4413,143 @@ Please enter new, unique name, or press '%1' to abort the operation: MultiEditorBool - Boolean - 布尔 + 布尔 + + + + MultiEditorBoolPlugin + + + Boolean + 布尔 MultiEditorDate - Date - 日期 + 日期 + + + + MultiEditorDatePlugin + + + Date + 日期 MultiEditorDateTime - Date & time - 日期和时间 + 日期和时间 + + + + MultiEditorDateTimePlugin + + + Date & time + 日期和时间 MultiEditorHex - Hex - 十六进制 + 十六进制 + + + + MultiEditorHexPlugin + + + Hex + 十六进制 MultiEditorNumeric - Number numeric multi editor tab name - 数值 + 数值 + + + + MultiEditorNumericPlugin + + + Number + numeric multi editor tab name + 数值 MultiEditorText - Text - 文本 + 文本 - + Tab changes focus - + Cut 剪切 - + Copy 复制 - + Paste 粘贴 - + Delete 删除 - + Undo 撤销 - + Redo 恢复 + + MultiEditorTextPlugin + + + Text + 文本 + + MultiEditorTime - Time - 时间 + 时间 + + + + MultiEditorTimePlugin + + + Time + 时间 @@ -4186,37 +4624,40 @@ Please enter new, unique name, or press '%1' to abort the operation:组件 - + + This application will be closed and the update installer will start to download and install all the updates. + + + Current version - 当年版本 + 当年版本 - + Update version 可更新版本 - + Check for updates on startup 在启动时检查更新 - + Update to new version! 更新到新版本! - The update will be automatically downloaded and installed. This will also restart application at the end. - 本次更新将会自动下载和安装。在更新后会重启程序。 + 本次更新将会自动下载和安装。在更新后会重启程序。 - + Not now. 现在不更新。 - + Don't install the update and close this window. 不安装更新并关闭本窗口。 @@ -4268,32 +4709,32 @@ Please enter new, unique name, or press '%1' to abort the operation:填充 - + Abort 中止 - + Configure 配置 - + Populating configuration for this column is invalid or incomplete. - + Select database with table to populate - + Select table to populate 选择要填充的表 - + You have to select at least one column. 您至少得选择一个字段。 @@ -4368,129 +4809,134 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Data grid view - + Copy cell(s) contents to clipboard - Paste cell(s) contents from clipboard + Copy cell(s) contents together with header to clipboard + Paste cell(s) contents from clipboard + + + + Set empty value to selected cell(s) - + Set NULL value to selected cell(s) - + Commit changes to cell(s) contents - + Rollback changes to cell(s) contents - + Delete selected data row - + Insert new data row - + Open contents of selected cell in a separate editor - + Total pages available: %1 - + Total rows loaded: %1 - + Data view (both grid and form) - + Refresh data - + Switch to grid view of the data - + Switch to form view of the data - + Database list 数据库列表 - + Delete selected item - + Clear filter contents - + Refresh schema - + Refresh all schemas - + Add database - + Select all items - + Copy selected item(s) - + - + Paste from clipboard @@ -4565,42 +5011,42 @@ Please enter new, unique name, or press '%1' to abort the operation:删除当前行 - + Main window - + Open SQL editor 打开SQL编辑器 - + Previous window 上一个窗口 - + Next window 下一个窗口 - + Hide status area - + Open configuration dialog 打开配置对话框 - + Open Debug Console 打开调试终端 - + Open CSS Console 打开CSS控制台 @@ -4611,111 +5057,111 @@ Please enter new, unique name, or press '%1' to abort the operation: - + Cut selected text - + Copy selected text - + Delete selected text - + Undo 撤销 - + Redo 恢复 - + SQL editor input field - + Select whole editor contents - + Save contents into a file - + Load contents from a file - + Find in text - + Find next 查找下一个 - + Find previous 查找上一个 - + Replace in text - + Delete current line - + Request code assistant - + Format contents - + Move selected block of text one line down - + Move selected block of text one line up - + Copy selected block of text and paste it a line below - + Copy selected block of text and paste it a line above - + Toggle comment @@ -4736,14 +5182,8 @@ Please enter new, unique name, or press '%1' to abort the operation: - - Reports history window - - - - Delete selected entry - 删除选中项 + 删除选中项 @@ -4790,6 +5230,11 @@ Please enter new, unique name, or press '%1' to abort the operation:Move keyboard input focus to the SQL editor above + + + Delete selected SQL history entries + + Table window @@ -5012,179 +5457,179 @@ find next SqlEditor - + Cut sql editor 剪切 - + Copy sql editor 复制 - + Paste sql editor 粘贴 - + Delete sql editor 删除 - + Select all sql editor 全选 - + Undo sql editor 撤销 - + Redo sql editor 恢复 - + Complete sql editor 完成 - + Format SQL sql editor 格式化SQL - + Save SQL to file sql editor 保存SQL到文件 - + Select file to save SQL sql editor - + Load SQL from file sql editor 从文件加载SQL - + Delete line sql editor 删除行 - + Move block down sql editor 整块下移 - + Move block up sql editor 整块上移 - + Copy block down sql editor - + Copy up down sql editor - + Find sql editor 查找 - + Find next sql editor 查找下一个 - + Find previous sql editor 查找上一个 - + Replace sql editor 替换 - + Toggle comment sql editor - + Saved SQL contents to file: %1 - + Syntax completion can be used only when a valid database is set for the SQL editor. - + Contents of the SQL editor are huge, so errors detecting and existing objects highlighting are temporarily disabled. - + Save to file 保存到文件 - + Could not open file '%1' for writing: %2 - + SQL scripts (*.sql);;All files (*) SQL文件 (*.sql);;所有文件 (*) - + Open file 打开文件 - + Could not open file '%1' for reading: %2 - + Reached the end of document. Hit the find again to restart the search. 已搜索到文档底部。点击查找从头程序开始搜索。 @@ -5232,24 +5677,24 @@ find next - - + + Cannot edit this cell. Details: %1 - + Structure of this table has changed since last data was loaded. Reload the data to proceed. - + Editing a huge contents in an inline cell editor is not a good idea. It can become slow and inconvenient. It's better to edit such big contents in a Form View, or in popup editor (available under rick-click menu). - + Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually. @@ -5257,69 +5702,74 @@ find next SqlQueryModel - - + + Only one query can be executed simultaneously. - + Cannot commit the data for a cell that refers to the already closed database. - + Could not begin transaction on the database. Details: %1 - + An error occurred while rolling back the transaction: %1 - + Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it. - + Uncommitted data - + There are uncommitted data changes. Do you want to proceed anyway? All uncommitted changes will be lost. - + An error occurred while committing the transaction: %1 - + An error occurred while committing the data: %1 - - + + Number of rows per page was decreased to %1 due to number of columns (%2) in the data view. + + + + + Error while executing SQL query on database '%1': %2 - + Error while loading query results: %1 - + Insert multiple rows 插入多行 - + Number of rows to insert: @@ -5327,117 +5777,137 @@ find next SqlQueryView - + Go to referenced row in... - + Copy 复制 - + Copy as... 复制为... - + Paste 粘贴 - + Paste as... 粘贴为... - + Set NULL values 设置为NULL - + Erase values 擦除 - + Edit value in editor - + Commit 提交 - + + Copy with headers + + + + Rollback 回滚 - + Commit selected cells - + Rollback selected cells - + Define columns to sort by - + Remove custom sorting - + Insert row 插入行 - + Insert multiple rows 插入多行 - + Delete selected row 删除已选行 - + + Show value in a viewer + + + + Generate query for selected cells - + No items selected to paste clipboard contents to. - + Go to referenced row in table '%1' - + table '%1' - + Referenced row (%1) - + + Trim pasted text? + + + + + The pasted text contains leading or trailing white space. Trim it automatically? + + + + Edit value 编辑值 @@ -5459,6 +5929,119 @@ find next 删除行时发生了错误 %1:%2 + + SqliteExtensionEditor + + + Filter extensions + + + + + Leave empty to use default function + + + + + Extension file + + + + + Initialization function + + + + + Databases + 数据库 + + + + Register in all databases + 在所有数据库中注册 + + + + Register in following databases: + 在下列数据库中注册: + + + + Extension manager window has uncommitted modifications. + + + + + Extension manager + + + + + Commit all extension changes + + + + + Rollback all extension changes + + + + + Add new extension + + + + + Remove selected extension + + + + + Editing extensions manual + + + + + File with given path does not exist or is not readable. + + + + + Unable to load extension: %1 + + + + + Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore. + + + + + Dynamic link libraries (*.dll);;All files (*) + + + + + Shared objects (*.so);;All files (*) + + + + + Dynamic libraries (*.dylib);;All files (*) + + + + + All files (*) + 所有文件 (*) + + + + Open file + 打开文件 + + StatusField @@ -5567,7 +6150,7 @@ but it's okay to use them anyway. - + Foreign column table constraints @@ -5621,24 +6204,24 @@ but it's okay to use them anyway. - + Collate table constraints 排序规则 - + Sort order table constraints 排序 - + Select at least one column. 至少选择一列。 - + Enter a name of the constraint. @@ -6197,7 +6780,7 @@ Are you sure you want to create a table with blank name? - + <p>SQL condition that will be evaluated before the actual trigger code. In case the condition returns false, the trigger will not be fired for that row.</p> @@ -6242,7 +6825,7 @@ Are you sure you want to create a table with blank name? - + DDL DDL @@ -6320,18 +6903,18 @@ Are you sure you want to create a table with blank name? - - + + Data 数据 - + Triggers 触发器 - + DDL DDL @@ -6363,125 +6946,125 @@ Are you sure you want to create a table with blank name? - + Refresh the view view window - + Commit the view changes view window - + Rollback the view changes view window - + Explicit column names - + Generate output column names automatically basing on result columns of the view. - + Add column view window - + Edit column view window - + Delete column view window - + Move column up view window - + Move column down view window - + Refresh trigger list view window - + Create new trigger view window - + Edit selected trigger view window - + Delete selected trigger view window - + View window "%1" has uncommitted structure modifications and data. - + View window "%1" has uncommitted data. - + View window "%1" has uncommitted structure modifications. - + Uncommitted changes - + There are uncommitted structure modifications. You cannot browse or edit data until you have the view structure settled. Do you want to commit the structure, or do you want to go back to the structure tab? - + Committed changes for view '%1' successfully. - + Committed changes for view '%1' (named before '%2') successfully. - + Could not load data for view %1. Error details: %2 @@ -6490,101 +7073,101 @@ Do you want to commit the structure, or do you want to go back to the structure 未提交的更改 - + Go back to structure tab - + Commit modifications and browse data. - + Could not commit view changes. Error message: %1 view window - + Override columns - + Currently defined columns will be overriden. Do you want to continue? - + Could not determinate columns returned from the view. The query is problably incomplete or contains errors. - + Name view window triggers 名称 - + Instead of view window triggers - + Condition view window triggers - + Details table window triggers 详情 - + Could not process the %1 view correctly. Unable to open a view window. - + Empty name - + A blank name for the view is allowed in SQLite, but it is not recommended. Are you sure you want to create a view with blank name? - + The SELECT statement could not be parsed. Please correct the query and retry. Details: %1 - + The view could not be modified due to internal SQLiteStudio error. Please report this! - + The view code could not be parsed properly for execution. This is a SQLiteStudio's bug. Please report it. - + Following problems will take place while modifying the view. Would you like to proceed? view window - + View modification view window diff --git a/SQLiteStudio3/guiSQLiteStudio/uidebug.cpp b/SQLiteStudio3/guiSQLiteStudio/uidebug.cpp index 6448259..9473ab5 100644 --- a/SQLiteStudio3/guiSQLiteStudio/uidebug.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/uidebug.cpp @@ -40,9 +40,9 @@ void uiMessageHandler(QtMsgType type, const QMessageLogContext &context, const Q case QtFatalMsg: msgHandlerThreadProxy->fatal(fatMsg.arg(time, msg)); abort(); -#if QT_VERSION >= 0x050300 +#if QT_VERSION >= 0x050500 case QtInfoMsg: - msgHandlerThreadProxy->fatal(fatMsg.arg(time, msg)); + msgHandlerThreadProxy->debug(fatMsg.arg(time, msg)); break; #endif } diff --git a/SQLiteStudio3/guiSQLiteStudio/uiutils.h b/SQLiteStudio3/guiSQLiteStudio/uiutils.h index 01652b7..455d97c 100644 --- a/SQLiteStudio3/guiSQLiteStudio/uiutils.h +++ b/SQLiteStudio3/guiSQLiteStudio/uiutils.h @@ -20,4 +20,6 @@ GUI_API_EXPORT QPixmap addOpacity(const QPixmap& input, float opacity); GUI_API_EXPORT void limitDialogWidth(QDialog* dialog); GUI_API_EXPORT void fixTextCursorSelectedText(QString& text); +#define UI_PROP_COLUMN "column_name" + #endif // UIUTILS_H diff --git a/SQLiteStudio3/guiSQLiteStudio/widgetresizer.cpp b/SQLiteStudio3/guiSQLiteStudio/widgetresizer.cpp index 4602050..180eb16 100644 --- a/SQLiteStudio3/guiSQLiteStudio/widgetresizer.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/widgetresizer.cpp @@ -135,3 +135,8 @@ void WidgetResizer::setWidgetMinimumSize(int width, int height) { widgetMinimumSize = QSize(width, height); } + +void WidgetResizer::minimizeHeight() +{ + widget->setFixedHeight(widgetMinimumSize.height()); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/widgetresizer.h b/SQLiteStudio3/guiSQLiteStudio/widgetresizer.h index 29e380b..40d1502 100644 --- a/SQLiteStudio3/guiSQLiteStudio/widgetresizer.h +++ b/SQLiteStudio3/guiSQLiteStudio/widgetresizer.h @@ -24,6 +24,7 @@ class GUI_API_EXPORT WidgetResizer : public QWidget QSize getWidgetMinimumSize() const; void setWidgetMinimumSize(const QSize& value); void setWidgetMinimumSize(int width, int height); + void minimizeHeight(); protected: void mouseMoveEvent(QMouseEvent* event); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.cpp deleted file mode 100644 index 7632c8f..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "bugreporthistorywindow.h" -#include "ui_bugreporthistorywindow.h" -#include "common/unused.h" -#include "services/config.h" -#include -#include - -CFG_KEYS_DEFINE(BugReportHistoryWindow) - -BugReportHistoryWindow::BugReportHistoryWindow(QWidget *parent) : - MdiChild(parent), - ui(new Ui::BugReportHistoryWindow) -{ - init(); -} - -BugReportHistoryWindow::~BugReportHistoryWindow() -{ - delete ui; -} - -bool BugReportHistoryWindow::restoreSessionNextTime() -{ - return false; -} - -QVariant BugReportHistoryWindow::saveSession() -{ - return QVariant(); -} - -bool BugReportHistoryWindow::restoreSession(const QVariant& sessionValue) -{ - UNUSED(sessionValue); - return false; -} - -Icon* BugReportHistoryWindow::getIconNameForMdiWindow() -{ - return ICONS.BUG_LIST; -} - -QString BugReportHistoryWindow::getTitleForMdiWindow() -{ - return tr("Reports history"); -} - -void BugReportHistoryWindow::createActions() -{ - createAction(CLEAR_HISTORY, ICONS.CLEAR_HISTORY, tr("Clear reports history"), this, SLOT(clearHistory()), ui->toolBar); - createAction(DELETE_SELECTED, ICONS.DELETE_ROW, tr("Delete selected entry"), this, SLOT(deleteSelected()), ui->toolBar); -} - -void BugReportHistoryWindow::setupDefShortcuts() -{ - setShortcutContext({ - DELETE_SELECTED - }, - Qt::WidgetWithChildrenShortcut); - - BIND_SHORTCUTS(BugReportHistoryWindow, Action); -} - -QToolBar* BugReportHistoryWindow::getToolBar(int toolbar) const -{ - UNUSED(toolbar); - return ui->toolBar; -} - -void BugReportHistoryWindow::init() -{ - ui->setupUi(this); - initActions(); - - reload(); - connect(ui->reportsList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateState())); - connect(CFG, SIGNAL(reportsHistoryRefreshNeeded()), this, SLOT(reload())); - - updateState(); -} - -void BugReportHistoryWindow::updateState() -{ - actionMap[DELETE_SELECTED]->setEnabled(ui->reportsList->selectedItems().size() > 0); -} - -void BugReportHistoryWindow::reload() -{ - static_qstring(urlTpl, "%2"); - QString invalidUrlTpl = tr("Invalid response from server."); - - QList entries = CFG->getReportHistory(); - ui->reportsList->clear(); - ui->reportsList->setRowCount(entries.size()); - - QTableWidgetItem* item = nullptr; - QLabel* urlLabel = nullptr; - int row = 0; - for (const Config::ReportHistoryEntryPtr& entry : entries) - { - item = new QTableWidgetItem((entry->isFeatureRequest ? ICONS.FEATURE_REQUEST : ICONS.BUG), entry->title); - item->setData(ENTRY_ID, entry->id); - ui->reportsList->setItem(row, 0, item); - - item = new QTableWidgetItem(QDateTime::fromTime_t(entry->timestamp).toString("yyyy-MM-dd HH:mm:ss")); - ui->reportsList->setItem(row, 1, item); - - if (entry->url.startsWith("http://")) - urlLabel = new QLabel(urlTpl.arg(entry->url, entry->url)); - else - urlLabel = new QLabel(invalidUrlTpl); - - urlLabel->setOpenExternalLinks(true); - ui->reportsList->setCellWidget(row, 2, urlLabel); - - row++; - } - - ui->reportsList->setHorizontalHeaderLabels({tr("Title"), tr("Reported at"), tr("URL")}); - ui->reportsList->resizeColumnsToContents(); -} - -void BugReportHistoryWindow::clearHistory() -{ - CFG->clearReportHistory(); -} - -void BugReportHistoryWindow::deleteSelected() -{ - QList items = ui->reportsList->selectedItems(); - if (items.size() == 0) - { - qDebug() << "Called BugReportHistoryWindow::deleteSelected(), but there's no row selected."; - return; - } - - int id = items.first()->data(ENTRY_ID).toInt(); - if (id == 0) - { - qDebug() << "Called BugReportHistoryWindow::deleteSelected(), but there's no ID in selected row."; - return; - } - - CFG->deleteReport(id); -} - -bool BugReportHistoryWindow::isUncommitted() const -{ - return false; -} - -QString BugReportHistoryWindow::getQuitUncommittedConfirmMessage() const -{ - return QString(); -} diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.h deleted file mode 100644 index 42e518a..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef BUGREPORTHISTORYWINDOW_H -#define BUGREPORTHISTORYWINDOW_H - -#include "mdichild.h" -#include - -namespace Ui { - class BugReportHistoryWindow; -} - -CFG_KEY_LIST(BugReportHistoryWindow, QObject::tr("Reports history window"), - CFG_KEY_ENTRY(DELETE_SELECTED, Qt::Key_Delete, QObject::tr("Delete selected entry")) -) - -class GUI_API_EXPORT BugReportHistoryWindow : public MdiChild -{ - Q_OBJECT - Q_ENUMS(Action) - - public: - enum Action - { - DELETE_SELECTED, - CLEAR_HISTORY - }; - - enum ToolBar - { - TOOLBAR - }; - - explicit BugReportHistoryWindow(QWidget *parent = 0); - ~BugReportHistoryWindow(); - - bool restoreSessionNextTime(); - bool isUncommitted() const; - QString getQuitUncommittedConfirmMessage() const; - - protected: - QVariant saveSession(); - bool restoreSession(const QVariant &sessionValue); - Icon* getIconNameForMdiWindow(); - QString getTitleForMdiWindow(); - void createActions(); - void setupDefShortcuts(); - QToolBar* getToolBar(int toolbar) const; - - private: - enum UserRole - { - ENTRY_ID = Qt::UserRole + 1 - }; - - void init(); - - Ui::BugReportHistoryWindow *ui = nullptr; - - private slots: - void updateState(); - void reload(); - void clearHistory(); - void deleteSelected(); -}; - -#endif // BUGREPORTHISTORYWINDOW_H diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.ui deleted file mode 100644 index 2211ec2..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.ui +++ /dev/null @@ -1,55 +0,0 @@ - - - BugReportHistoryWindow - - - - 0 - 0 - 400 - 300 - - - - Form - - - - - - - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - QAbstractItemView::ScrollPerPixel - - - true - - - - Title - - - - - Reported at - - - - - URL - - - - - - - - - diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp index 286924b..5d36683 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp @@ -106,11 +106,11 @@ void CollationsEditor::init() connect(CFG_UI.Fonts.SqlEditor, SIGNAL(changed(QVariant)), this, SLOT(changeFont(QVariant))); // Language plugins - foreach (ScriptingPlugin* plugin, PLUGINS->getLoadedPlugins()) + for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins()) ui->langCombo->addItem(plugin->getLanguage()); // Syntax highlighting plugins - foreach (SyntaxHighlighterPlugin* plugin, PLUGINS->getLoadedPlugins()) + for (SyntaxHighlighterPlugin* plugin : PLUGINS->getLoadedPlugins()) highlighterPlugins[plugin->getLanguageName()] = plugin; updateState(); @@ -156,7 +156,7 @@ void CollationsEditor::collationSelected(int row) ui->selectedDatabasesRadio->setChecked(true); updatesForSelection = false; - currentModified = false; + currentModified = model->isModified(row); updateCurrentCollationState(); } @@ -190,7 +190,7 @@ void CollationsEditor::setFont(const QFont& font) void CollationsEditor::help() { - static const QString url = QStringLiteral("http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_collations"); + static const QString url = QStringLiteral("https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-collations"); QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode)); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h index a75e66b..7b2e469 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h @@ -36,7 +36,7 @@ class GUI_API_EXPORT CollationsEditor : public MdiChild TOOLBAR }; - explicit CollationsEditor(QWidget *parent = 0); + explicit CollationsEditor(QWidget *parent = nullptr); ~CollationsEditor(); bool restoreSessionNextTime(); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui index 97c4e0a..454c12a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui @@ -167,7 +167,11 @@ - + + + QPlainTextEdit::NoWrap + + diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp index 05ca4e1..f04e023 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp @@ -27,7 +27,7 @@ CollationsEditorModel::CollationsEditorModel(QObject *parent) : void CollationsEditorModel::clearModified() { beginResetModel(); - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) coll->modified = false; listModified = false; @@ -41,7 +41,7 @@ bool CollationsEditorModel::isModified() const if (collationList != originalCollationList) return true; - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) { if (coll->modified) return true; @@ -121,7 +121,7 @@ void CollationsEditorModel::setValid(int row, bool valid) bool CollationsEditorModel::isValid() const { - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) { if (!coll->valid) return false; @@ -133,13 +133,12 @@ void CollationsEditorModel::setData(const QList& { beginResetModel(); - Collation* collationPtr = nullptr; - foreach (collationPtr, collationList) + for (Collation* collationPtr : collationList) delete collationPtr; collationList.clear(); - foreach (const CollationManager::CollationPtr& coll, collations) + for (const CollationManager::CollationPtr& coll : collations) collationList << new Collation(coll); listModified = false; @@ -178,8 +177,7 @@ void CollationsEditorModel::deleteCollation(int row) QList CollationsEditorModel::getCollations() const { QList results; - - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) results << coll->data; return results; @@ -188,7 +186,7 @@ QList CollationsEditorModel::getCollations() con QStringList CollationsEditorModel::getCollationNames() const { QStringList names; - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) names << coll->data->name; return names; @@ -199,7 +197,7 @@ void CollationsEditorModel::validateNames() StrHash> counter; int row = 0; - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) { coll->valid &= true; counter[coll->data->name] << row++; @@ -211,7 +209,7 @@ void CollationsEditorModel::validateNames() cntIt.next(); if (cntIt.value().size() > 1) { - foreach (int cntRow, cntIt.value()) + for (int cntRow : cntIt.value()) setValid(cntRow, false); } } @@ -265,7 +263,7 @@ QVariant CollationsEditorModel::data(const QModelIndex& index, int role) const void CollationsEditorModel::init() { - foreach (ScriptingPlugin* plugin, PLUGINS->getLoadedPlugins()) + for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins()) langToIcon[plugin->getLanguage()] = QIcon(plugin->getIconPath()); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h index 0c17c5b..46f7ab5 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h @@ -13,7 +13,7 @@ class GUI_API_EXPORT CollationsEditorModel : public QAbstractListModel public: using QAbstractItemModel::setData; - explicit CollationsEditorModel(QObject *parent = 0); + explicit CollationsEditorModel(QObject *parent = nullptr); void clearModified(); bool isModified() const; diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp index 2d8897b..1144fda 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp @@ -16,7 +16,7 @@ int ConstraintTabModel::rowCount(const QModelIndex& parent) const return 0; int cnt = 0; - foreach (SqliteCreateTable::Column* col, createTable->columns) + for (SqliteCreateTable::Column* col : createTable->columns) cnt += col->constraints.size(); cnt += createTable->constraints.size(); @@ -36,9 +36,9 @@ QVariant ConstraintTabModel::data(const QModelIndex& index, int role) const int constrIdx = index.row(); int currIdx = -1; - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) { - foreach (SqliteCreateTable::Column::Constraint* constr, column->constraints) + for (SqliteCreateTable::Column::Constraint* constr : column->constraints) { currIdx++; @@ -47,7 +47,7 @@ QVariant ConstraintTabModel::data(const QModelIndex& index, int role) const } } - foreach (SqliteCreateTable::Constraint* constr, createTable->constraints) + for (SqliteCreateTable::Constraint* constr : createTable->constraints) { currIdx++; diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/ddlhistorywindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/ddlhistorywindow.cpp index 15b49e5..795158a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/ddlhistorywindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/ddlhistorywindow.cpp @@ -76,7 +76,7 @@ void DdlHistoryWindow::activated(const QModelIndex& current, const QModelIndex& QStringList contentEntries; QList entries = CFG->getDdlHistoryFor(dbName, dbFile, date); - foreach (Config::DdlHistoryEntryPtr entry, entries) + for (Config::DdlHistoryEntryPtr entry : entries) { contentEntries << templ.arg(entry->dbName).arg(entry->dbFile) .arg(entry->timestamp.toString("yyyy-MM-dd HH:mm:ss")) diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp index 56ab6fe..cd3e135 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp @@ -19,12 +19,14 @@ #include "parser/parser.h" #include "dbobjectdialogs.h" #include "dialogs/exportdialog.h" +#include "themetuner.h" +#include "dialogs/bindparamsdialog.h" +#include "common/bindparam.h" #include #include #include #include #include -#include CFG_KEYS_DEFINE(EditorWindow) EditorWindow::ResultsDisplayMode EditorWindow::resultsDisplayMode; @@ -100,6 +102,7 @@ void EditorWindow::init() createDbCombo(); initActions(); updateShortcutTips(); + setupSqlHistoryMenu(); Db* treeSelectedDb = DBTREE->getSelectedOpenDb(); if (treeSelectedDb) @@ -115,10 +118,12 @@ void EditorWindow::init() // SQL history list ui->historyList->setModel(CFG->getSqlHistoryModel()); + ui->historyList->hideColumn(0); ui->historyList->resizeColumnToContents(1); connect(ui->historyList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(historyEntrySelected(QModelIndex,QModelIndex))); connect(ui->historyList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(historyEntryActivated(QModelIndex))); + connect(ui->historyList, &QWidget::customContextMenuRequested, this, &EditorWindow::sqlHistoryContextMenuRequested); updateState(); } @@ -390,6 +395,7 @@ void EditorWindow::createActions() createAction(SHOW_PREV_TAB, tr("Show previous tab", "sql editor"), this, SLOT(showPrevTab()), this); createAction(FOCUS_RESULTS_BELOW, tr("Focus results below", "sql editor"), this, SLOT(focusResultsBelow()), this); createAction(FOCUS_EDITOR_ABOVE, tr("Focus SQL editor above", "sql editor"), this, SLOT(focusEditorAbove()), this); + createAction(DELETE_SINGLE_HISTORY_SQL, tr("Delete selected SQL history entries", "sql editor"), this, SLOT(deleteSelectedSqlHistory()), ui->historyList); // Static action triggers connect(staticActions[RESULTS_IN_TAB], SIGNAL(triggered()), this, SLOT(updateResultsDisplayMode())); @@ -470,9 +476,15 @@ void EditorWindow::updateShortcutTips() void EditorWindow::execQuery(bool explain) { QString sql = getQueryToExecute(true); + QHash bindParams; + bool proceed = processBindParams(sql, bindParams); + if (!proceed) + return; + resultsModel->setDb(getCurrentDb()); resultsModel->setExplainMode(explain); resultsModel->setQuery(sql); + resultsModel->setParams(bindParams); resultsModel->setQueryCountLimitForSmartMode(queryLimitForSmartExecution); ui->dataView->refreshData(); updateState(); @@ -490,6 +502,61 @@ void EditorWindow::explainQuery() execQuery(true); } +bool EditorWindow::processBindParams(QString& sql, QHash& queryParams) +{ + // Determin dialect + Dialect dialect = Dialect::Sqlite3; + Db* db = getCurrentDb(); + if (db && db->isValid()) + dialect = db->getDialect(); + + // Get all bind parameters from the query + TokenList tokens = Lexer::tokenize(sql, dialect); + TokenList bindTokens = tokens.filter(Token::BIND_PARAM); + + // No bind tokens? Return fast. + if (bindTokens.isEmpty()) + return true; + + // Process bind tokens, prepare list for a dialog. + static_qstring(paramTpl, ":arg%1"); + QString arg; + QVector bindParams; + BindParam* bindParam = nullptr; + int i = 0; + for (const TokenPtr& token : bindTokens) + { + bindParam = new BindParam(); + bindParam->position = i; + bindParam->originalName = token->value; + bindParam->newName = paramTpl.arg(i); + bindParams << bindParam; + i++; + + token->value = bindParam->newName; + } + + // Show dialog to query user for values + BindParamsDialog dialog(MAINWINDOW); + dialog.setBindParams(bindParams); + bool accepted = (dialog.exec() == QDialog::Accepted); + + // Transfer values from dialog to arguments for query + if (accepted) + { + for (BindParam* bindParam : bindParams) + queryParams[bindParam->newName] = bindParam->value; + + sql = tokens.detokenize(); + } + + // Cleanup + for (BindParam* bindParam : bindParams) + delete bindParam; + + return accepted; +} + void EditorWindow::dbChanged() { Db* currentDb = getCurrentDb(); @@ -597,17 +664,29 @@ void EditorWindow::focusEditorAbove() void EditorWindow::historyEntrySelected(const QModelIndex& current, const QModelIndex& previous) { UNUSED(previous); - QString sql = ui->historyList->model()->index(current.row(), 4).data().toString(); + QString sql = ui->historyList->model()->index(current.row(), 5).data().toString(); ui->historyContents->setPlainText(sql); } void EditorWindow::historyEntryActivated(const QModelIndex& current) { - QString sql = ui->historyList->model()->index(current.row(), 4).data().toString(); + QString sql = ui->historyList->model()->index(current.row(), 5).data().toString(); ui->sqlEdit->setPlainText(sql); ui->tabWidget->setCurrentIndex(0); } +void EditorWindow::deleteSelectedSqlHistory() +{ + if (ui->historyList->selectionModel()->selectedIndexes().isEmpty()) + return; + + QList ids; + for (const QModelIndex& idx : ui->historyList->selectionModel()->selectedRows(0)) + ids += idx.data().toLongLong(); + + CFG->deleteSqlHistory(ids); +} + void EditorWindow::clearHistory() { QMessageBox::StandardButton res = QMessageBox::question(this, tr("Clear execution history"), tr("Are you sure you want to erase the entire SQL execution history? " @@ -618,6 +697,19 @@ void EditorWindow::clearHistory() CFG->clearSqlHistory(); } +void EditorWindow::sqlHistoryContextMenuRequested(const QPoint &pos) +{ + actionMap[DELETE_SINGLE_HISTORY_SQL]->setEnabled(!ui->historyList->selectionModel()->selectedIndexes().isEmpty()); + + sqlHistoryMenu->popup(ui->historyList->mapToGlobal(pos)); +} + +void EditorWindow::setupSqlHistoryMenu() +{ + sqlHistoryMenu = new QMenu(this); + sqlHistoryMenu->addAction(actionMap[DELETE_SINGLE_HISTORY_SQL]); +} + void EditorWindow::exportResults() { if (!ExportManager::isAnyPluginAvailable()) diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h index 12486a8..296a9e2 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h +++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h @@ -24,14 +24,15 @@ class SqlQueryItem; class SqlEditor; CFG_KEY_LIST(EditorWindow, QObject::tr("SQL editor window"), - CFG_KEY_ENTRY(EXEC_QUERY, Qt::Key_F9, QObject::tr("Execute query")) - CFG_KEY_ENTRY(EXPLAIN_QUERY, Qt::Key_F8, QObject::tr("Execute \"%1\" query").arg("EXPLAIN")) - CFG_KEY_ENTRY(PREV_DB, Qt::CTRL + Qt::Key_Up, QObject::tr("Switch current working database to previous on the list")) - CFG_KEY_ENTRY(NEXT_DB, Qt::CTRL + Qt::Key_Down, QObject::tr("Switch current working database to next on the list")) - CFG_KEY_ENTRY(SHOW_NEXT_TAB, Qt::ALT + Qt::Key_Right, QObject::tr("Go to next editor tab")) - CFG_KEY_ENTRY(SHOW_PREV_TAB, Qt::ALT + Qt::Key_Left, QObject::tr("Go to previous editor tab")) - CFG_KEY_ENTRY(FOCUS_RESULTS_BELOW, Qt::ALT + Qt::Key_PageDown, QObject::tr("Move keyboard input focus to the results view below")) - CFG_KEY_ENTRY(FOCUS_EDITOR_ABOVE, Qt::ALT + Qt::Key_PageUp, QObject::tr("Move keyboard input focus to the SQL editor above")) + CFG_KEY_ENTRY(EXEC_QUERY, Qt::Key_F9, QObject::tr("Execute query")) + CFG_KEY_ENTRY(EXPLAIN_QUERY, Qt::Key_F8, QObject::tr("Execute \"%1\" query").arg("EXPLAIN")) + CFG_KEY_ENTRY(PREV_DB, Qt::CTRL + Qt::Key_Up, QObject::tr("Switch current working database to previous on the list")) + CFG_KEY_ENTRY(NEXT_DB, Qt::CTRL + Qt::Key_Down, QObject::tr("Switch current working database to next on the list")) + CFG_KEY_ENTRY(SHOW_NEXT_TAB, Qt::ALT + Qt::Key_Right, QObject::tr("Go to next editor tab")) + CFG_KEY_ENTRY(SHOW_PREV_TAB, Qt::ALT + Qt::Key_Left, QObject::tr("Go to previous editor tab")) + CFG_KEY_ENTRY(FOCUS_RESULTS_BELOW, Qt::ALT + Qt::Key_PageDown, QObject::tr("Move keyboard input focus to the results view below")) + CFG_KEY_ENTRY(FOCUS_EDITOR_ABOVE, Qt::ALT + Qt::Key_PageUp, QObject::tr("Move keyboard input focus to the SQL editor above")) + CFG_KEY_ENTRY(DELETE_SINGLE_HISTORY_SQL, QKeySequence::Delete, QObject::tr("Delete selected SQL history entries")) ) class GUI_API_EXPORT EditorWindow : public MdiChild @@ -61,7 +62,8 @@ class GUI_API_EXPORT EditorWindow : public MdiChild FOCUS_EDITOR_ABOVE, CLEAR_HISTORY, EXPORT_RESULTS, - CREATE_VIEW_FROM_QUERY + CREATE_VIEW_FROM_QUERY, + DELETE_SINGLE_HISTORY_SQL }; enum ToolBar @@ -114,6 +116,8 @@ class GUI_API_EXPORT EditorWindow : public MdiChild void setupDefShortcuts(); void selectCurrentQuery(bool fallBackToPreviousIfNecessary = false); void updateShortcutTips(); + void setupSqlHistoryMenu(); + bool processBindParams(QString& sql, QHash& queryParams); static const int queryLimitForSmartExecution = 100; @@ -129,6 +133,7 @@ class GUI_API_EXPORT EditorWindow : public MdiChild int sqlEditorNum = 1; qint64 lastQueryHistoryId = 0; QString lastSuccessfulQuery; + QMenu* sqlHistoryMenu = nullptr; private slots: void execQuery(bool explain = false); @@ -146,7 +151,9 @@ class GUI_API_EXPORT EditorWindow : public MdiChild void focusEditorAbove(); void historyEntrySelected(const QModelIndex& current, const QModelIndex& previous); void historyEntryActivated(const QModelIndex& current); + void deleteSelectedSqlHistory(); void clearHistory(); + void sqlHistoryContextMenuRequested(const QPoint &pos); void exportResults(); void createViewFromQuery(); void updateState(); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.ui index 924f895..f3f44e3 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.ui +++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.ui @@ -51,6 +51,9 @@ Qt::CustomContextMenu + + QPlainTextEdit::NoWrap + @@ -118,11 +121,14 @@ Qt::Vertical + + Qt::CustomContextMenu + true - QAbstractItemView::SingleSelection + QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp index 1bfd1f7..9894098 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp @@ -140,13 +140,13 @@ void FunctionsEditor::init() model->setData(FUNCTIONS->getAllScriptFunctions()); // Language plugins - foreach (ScriptingPlugin* plugin, PLUGINS->getLoadedPlugins()) + for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins()) scriptingPlugins[plugin->getLanguage()] = plugin; ui->langCombo->addItems(scriptingPlugins.keys()); // Syntax highlighting plugins - foreach (SyntaxHighlighterPlugin* plugin, PLUGINS->getLoadedPlugins()) + for (SyntaxHighlighterPlugin* plugin : PLUGINS->getLoadedPlugins()) highlighterPlugins[plugin->getLanguageName()] = plugin; updateState(); @@ -204,7 +204,7 @@ void FunctionsEditor::functionSelected(int row) // Arguments ui->argsList->clear(); QListWidgetItem* item = nullptr; - foreach (const QString& arg, model->getArguments(row)) + for (const QString& arg : model->getArguments(row)) { item = new QListWidgetItem(arg); item->setFlags(item->flags() | Qt::ItemIsEditable); @@ -232,7 +232,7 @@ void FunctionsEditor::functionSelected(int row) } updatesForSelection = false; - currentModified = false; + currentModified = model->isModified(row); updateCurrentFunctionState(); } @@ -606,7 +606,7 @@ void FunctionsEditor::applyFilter(const QString& value) void FunctionsEditor::help() { - static const QString url = QStringLiteral("http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_SQL_functions"); + static const QString url = QStringLiteral("https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-sql-functions"); QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode)); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.ui b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.ui index b99efe1..17c3859 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.ui +++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.ui @@ -294,7 +294,11 @@ - + + + QPlainTextEdit::NoWrap + + @@ -310,7 +314,11 @@ - + + + QPlainTextEdit::NoWrap + + @@ -326,7 +334,11 @@ - + + + QPlainTextEdit::NoWrap + + diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp index cf7efdf..623ebd8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp @@ -28,7 +28,7 @@ FunctionsEditorModel::FunctionsEditorModel(QObject *parent) : void FunctionsEditorModel::clearModified() { beginResetModel(); - foreach (Function* func, functionList) + for (Function* func : functionList) func->modified = false; listModified = false; @@ -42,7 +42,7 @@ bool FunctionsEditorModel::isModified() const if (functionList != originalFunctionList) return true; - foreach (Function* func, functionList) + for (Function* func : functionList) { if (func->modified) return true; @@ -62,7 +62,7 @@ void FunctionsEditorModel::setModified(int row, bool modified) bool FunctionsEditorModel::isValid() const { - foreach (Function* func, functionList) + for (Function* func : functionList) { if (!func->valid) return false; @@ -199,7 +199,7 @@ void FunctionsEditorModel::setData(const QList functionList.clear(); - foreach (FunctionManager::ScriptFunction* func, functions) + for (FunctionManager::ScriptFunction* func : functions) functionList << new Function(func); listModified = false; @@ -239,7 +239,7 @@ QList FunctionsEditorModel::generateFunctions( { QList results; - foreach (Function* func, functionList) + for (Function* func : functionList) results << new FunctionManager::ScriptFunction(func->data); return results; @@ -248,7 +248,7 @@ QList FunctionsEditorModel::generateFunctions( QStringList FunctionsEditorModel::getFunctionNames() const { QStringList names; - foreach (Function* func, functionList) + for (Function* func : functionList) names << func->data.name; return names; @@ -259,7 +259,7 @@ void FunctionsEditorModel::validateNames() StrHash> counter; int row = 0; - foreach (Function* func, functionList) + for (Function* func : functionList) { func->valid &= true; counter[func->data.name] << row++; @@ -271,7 +271,7 @@ void FunctionsEditorModel::validateNames() cntIt.next(); if (cntIt.value().size() > 1) { - foreach (int cntRow, cntIt.value()) + for (int cntRow : cntIt.value()) setValid(cntRow, false); } } @@ -322,7 +322,7 @@ QVariant FunctionsEditorModel::data(const QModelIndex& index, int role) const void FunctionsEditorModel::init() { - foreach (ScriptingPlugin* plugin, PLUGINS->getLoadedPlugins()) + for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins()) langToIcon[plugin->getLanguage()] = QIcon(plugin->getIconPath()); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp new file mode 100644 index 0000000..ca45eff --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp @@ -0,0 +1,439 @@ +#include "sqliteextensioneditor.h" +#include "sqliteextensioneditormodel.h" +#include "ui_sqliteextensioneditor.h" +#include "selectabledbmodel.h" +#include "dbtree/dbtree.h" +#include "dbtree/dbtreemodel.h" +#include "common/unused.h" +#include "uiutils.h" +#include "uiconfig.h" +#include "db/db.h" +#include "services/dbmanager.h" +#include "services/notifymanager.h" +#include "common/lazytrigger.h" +#include +#include +#include + +SqliteExtensionEditor::SqliteExtensionEditor(QWidget *parent) : + MdiChild(parent), + ui(new Ui::SqliteExtensionEditor) +{ + init(); +} + +SqliteExtensionEditor::~SqliteExtensionEditor() +{ + delete ui; + probingDb->closeQuiet(); +} + +bool SqliteExtensionEditor::restoreSessionNextTime() +{ + return false; +} + +bool SqliteExtensionEditor::isUncommitted() const +{ + return model->isModified(); +} + +QString SqliteExtensionEditor::getQuitUncommittedConfirmMessage() const +{ + return tr("Extension manager window has uncommitted modifications."); +} + +QVariant SqliteExtensionEditor::saveSession() +{ + return QVariant(); +} + +bool SqliteExtensionEditor::restoreSession(const QVariant& sessionValue) +{ + UNUSED(sessionValue); + return true; +} + +Icon*SqliteExtensionEditor::getIconNameForMdiWindow() +{ + return ICONS.EXTENSION; +} + +QString SqliteExtensionEditor::getTitleForMdiWindow() +{ + return tr("Extension manager"); +} + +void SqliteExtensionEditor::createActions() +{ + createAction(COMMIT, ICONS.COMMIT, tr("Commit all extension changes"), this, SLOT(commit()), ui->toolbar); + createAction(ROLLBACK, ICONS.ROLLBACK, tr("Rollback all extension changes"), this, SLOT(rollback()), ui->toolbar); + ui->toolbar->addSeparator(); + createAction(ADD, ICONS.EXTENSION_ADD, tr("Add new extension"), this, SLOT(newExtension()), ui->toolbar); + createAction(DELETE, ICONS.EXTENSION_DELETE, tr("Remove selected extension"), this, SLOT(deleteExtension()), ui->toolbar); + ui->toolbar->addSeparator(); + createAction(HELP, ICONS.HELP, tr("Editing extensions manual"), this, SLOT(help()), ui->toolbar); +} + +void SqliteExtensionEditor::setupDefShortcuts() +{ +} + +QToolBar* SqliteExtensionEditor::getToolBar(int toolbar) const +{ + UNUSED(toolbar); + return ui->toolbar; +} + +void SqliteExtensionEditor::init() +{ + ui->setupUi(this); + initActions(); + + statusUpdateTrigger = new LazyTrigger(500, this, SLOT(updateCurrentExtensionState())); + + model = new SqliteExtensionEditorModel(this); + extensionFilterModel = new QSortFilterProxyModel(this); + extensionFilterModel->setSourceModel(model); + ui->extensionList->setModel(extensionFilterModel); + + dbListModel = new SelectableDbModel(this); + dbListModel->setDisabledVersion(2); + dbListModel->setSourceModel(DBTREE->getModel()); + ui->databaseList->setModel(dbListModel); + ui->databaseList->expandAll(); + + model->setData(SQLITE_EXTENSIONS->getAllExtensions()); + + connect(ui->extensionList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(extensionSelected(QItemSelection,QItemSelection))); + connect(ui->extensionList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateState())); + connect(ui->fileEdit, SIGNAL(textChanged(QString)), this, SLOT(updateModified())); + connect(ui->initEdit, SIGNAL(textChanged(QString)), this, SLOT(updateModified())); + connect(ui->allDatabasesRadio, SIGNAL(clicked()), this, SLOT(updateModified())); + connect(ui->selectedDatabasesRadio, SIGNAL(clicked()), this, SLOT(updateModified())); + connect(ui->fileBrowse, SIGNAL(clicked()), this, SLOT(browseForFile())); + connect(ui->fileEdit, SIGNAL(textChanged(QString)), statusUpdateTrigger, SLOT(schedule())); + connect(ui->fileEdit, SIGNAL(textChanged(QString)), this, SLOT(generateName())); + connect(ui->initEdit, SIGNAL(textChanged(QString)), statusUpdateTrigger, SLOT(schedule())); + connect(dbListModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateModified())); + + probingDb = DBLIST->createInMemDb(true); + if (!probingDb->openQuiet()) + qWarning() << "Could not open in-memory dtabase for Extension manager window. Probing files will be impossible."; + + initStateForAll(); + updateState(); + updateCurrentExtensionState(); +} + +int SqliteExtensionEditor::getCurrentExtensionRow() const +{ + QModelIndexList idxList = ui->extensionList->selectionModel()->selectedIndexes(); + if (idxList.size() == 0) + return -1; + + return idxList.first().row(); +} + +void SqliteExtensionEditor::extensionDeselected(int row) +{ + statusUpdateTrigger->cancel(); + + model->setFilePath(row, ui->fileEdit->text()); + model->setInitFunction(row, ui->initEdit->text()); + model->setAllDatabases(row, ui->allDatabasesRadio->isChecked()); + model->setModified(row, currentModified); + + if (ui->selectedDatabasesRadio->isChecked()) + model->setDatabases(row, getCurrentDatabases()); + + model->setValid(row, validateExtension(row)); +} + +void SqliteExtensionEditor::extensionSelected(int row) +{ + updatesForSelection = true; + ui->fileEdit->setText(model->getFilePath(row)); + ui->initEdit->setText(model->getInitFunction(row)); + + // Databases + dbListModel->setDatabases(model->getDatabases(row)); + ui->databaseList->expandAll(); + + if (model->getAllDatabases(row)) + ui->allDatabasesRadio->setChecked(true); + else + ui->selectedDatabasesRadio->setChecked(true); + + updatesForSelection = false; + currentModified = model->isModified(row); + + updateCurrentExtensionState(); +} + +void SqliteExtensionEditor::clearEdits() +{ + ui->fileEdit->setText(QString::null); + ui->initEdit->setText(QString::null); + ui->allDatabasesRadio->setChecked(true); +} + +void SqliteExtensionEditor::selectExtension(int row) +{ + if (!model->isValidRowIndex(row)) + return; + + ui->extensionList->selectionModel()->setCurrentIndex(model->index(row), QItemSelectionModel::Clear|QItemSelectionModel::SelectCurrent); +} + +QStringList SqliteExtensionEditor::getCurrentDatabases() const +{ + return dbListModel->getDatabases(); +} + +bool SqliteExtensionEditor::tryToLoad(const QString& filePath, const QString& initFunc, QString* resultError) +{ + if (!probingDb->isOpen()) + { + qWarning() << "Probing database is closed. Cannot evaluate if file" << filePath << "is loadable."; + return true; + } + + bool loadedOk = probingDb->loadExtension(filePath, initFunc.isEmpty() ? QString() : initFunc); + if (!loadedOk && resultError) + *resultError = probingDb->getErrorText(); + + probingDb->closeQuiet(); + probingDb->openQuiet(); + + return loadedOk; +} + +bool SqliteExtensionEditor::validateExtension(bool* fileOk, bool* initOk, QString* fileError) +{ + QString filePath = ui->fileEdit->text(); + QString initFunc = ui->initEdit->text(); + return validateExtension(filePath, initFunc, fileOk, initOk, fileError); +} + +bool SqliteExtensionEditor::validateExtension(int row) +{ + QString filePath = model->getFilePath(row); + QString initFunc = model->getInitFunction(row); + return validateExtension(filePath, initFunc); +} + +bool SqliteExtensionEditor::validateExtension(const QString& filePath, const QString& initFunc, bool* fileOk, bool* initOk, QString* fileError) +{ + bool localFileOk = true; + bool localInitOk = true; + + QFileInfo fileInfo(filePath); + if (!fileInfo.exists() || !fileInfo.isReadable()) + { + localFileOk = false; + *fileError = tr("File with given path does not exist or is not readable."); + } + else + localFileOk = tryToLoad(filePath, initFunc, fileError); + + if (!localFileOk && fileError && fileError->isEmpty()) + *fileError = tr("Unable to load extension: %1").arg(filePath); + + static const QRegularExpression initFuncRegExp("^[a-zA-Z0-9_]*$"); + localInitOk = initFuncRegExp.match(initFunc).hasMatch(); + + if (fileOk) + *fileOk = localFileOk; + + if (initOk) + *initOk = localInitOk; + + return localFileOk && localInitOk; +} + +void SqliteExtensionEditor::initStateForAll() +{ + for (int i = 0, total = model->rowCount(); i < total; ++i) + { + model->setName(i, QFileInfo(model->getFilePath(i)).baseName()); + model->setValid(i, validateExtension(i)); + } +} + +void SqliteExtensionEditor::help() +{ + static const QString url = QStringLiteral("https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#sqlite-extensions"); + QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode)); +} + +void SqliteExtensionEditor::commit() +{ + int row = getCurrentExtensionRow(); + if (model->isValidRowIndex(row)) + extensionDeselected(row); + + QList extensions = model->getExtensions(); + + SQLITE_EXTENSIONS->setExtensions(extensions); + model->clearModified(); + currentModified = false; + + if (model->isValidRowIndex(row)) + selectExtension(row); + + updateState(); +} + +void SqliteExtensionEditor::rollback() +{ + int selectedBefore = getCurrentExtensionRow(); + + model->setData(SQLITE_EXTENSIONS->getAllExtensions()); + currentModified = false; + clearEdits(); + + if (model->isValidRowIndex(selectedBefore)) + selectExtension(selectedBefore); + + updateState(); +} + +void SqliteExtensionEditor::newExtension() +{ + model->addExtension(SqliteExtensionManager::ExtensionPtr::create()); + selectExtension(model->rowCount() - 1); +} + +void SqliteExtensionEditor::deleteExtension() +{ + nameGenerationActive = false; + int row = getCurrentExtensionRow(); + model->deleteExtension(row); + clearEdits(); + + row = getCurrentExtensionRow(); + if (model->isValidRowIndex(row)) + extensionSelected(row); + else + updateCurrentExtensionState(); + + nameGenerationActive = true; + updateState(); +} + +void SqliteExtensionEditor::updateState() +{ + bool modified = model->isModified() || currentModified; + bool valid = model->isValid(); + + actionMap[COMMIT]->setEnabled(modified && valid); + actionMap[ROLLBACK]->setEnabled(modified); + actionMap[DELETE]->setEnabled(ui->extensionList->selectionModel()->selectedIndexes().size() > 0); + ui->databaseList->setEnabled(ui->selectedDatabasesRadio->isChecked()); +} + +void SqliteExtensionEditor::updateCurrentExtensionState() +{ + int row = getCurrentExtensionRow(); + bool validRow = model->isValidRowIndex(row); + ui->rightWidget->setEnabled(validRow); + if (!validRow) + { + setValidState(ui->fileEdit, true); + setValidState(ui->initEdit, true); + return; + } + + bool fileOk = true; + bool initOk = true; + QString fileError; + bool allOk = validateExtension(&fileOk, &initOk, &fileError); + + // Display results + setValidState(ui->fileEdit, fileOk, fileError); + setValidState(ui->initEdit, initOk, tr("Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore.")); + ui->databasesGroup->setEnabled(allOk); + model->setValid(row, allOk); + + updateState(); +} + +void SqliteExtensionEditor::extensionSelected(const QItemSelection& selected, const QItemSelection& deselected) +{ + int deselCnt = deselected.indexes().size(); + int selCnt = selected.indexes().size(); + + if (deselCnt > 0) + extensionDeselected(deselected.indexes().first().row()); + + if (selCnt > 0) + extensionSelected(selected.indexes().first().row()); + + if (deselCnt > 0 && selCnt == 0) + { + currentModified = false; + clearEdits(); + } +} + +void SqliteExtensionEditor::updateModified() +{ + if (updatesForSelection) + return; + + int row = getCurrentExtensionRow(); + if (model->isValidRowIndex(row)) + { + bool fileDiff = model->getFilePath(row) != ui->fileEdit->text(); + bool initDiff = model->getInitFunction(row) != ui->initEdit->text(); + bool allDatabasesDiff = model->getAllDatabases(row) != ui->allDatabasesRadio->isChecked(); + bool dbDiff = getCurrentDatabases().toSet() != model->getDatabases(row).toSet(); // QSet to ignore order + + currentModified = (fileDiff || initDiff || allDatabasesDiff || dbDiff); + } + + statusUpdateTrigger->schedule(); +} + +void SqliteExtensionEditor::generateName() +{ + if (!nameGenerationActive) + return; + + int row = getCurrentExtensionRow(); + if (model->isValidRowIndex(row)) + model->setName(row, QFileInfo(ui->fileEdit->text()).baseName()); +} + +void SqliteExtensionEditor::applyFilter(const QString& value) +{ + int row = getCurrentExtensionRow(); + ui->extensionList->selectionModel()->clearSelection(); + + extensionFilterModel->setFilterFixedString(value); + + selectExtension(row); +} + +void SqliteExtensionEditor::browseForFile() +{ + QString dir = getFileDialogInitPath(); + QString filter = +#if defined(Q_OS_WIN) + tr("Dynamic link libraries (*.dll);;All files (*)"); +#elif defined(Q_OS_LINUX) + tr("Shared objects (*.so);;All files (*)"); +#elif defined(Q_OS_OSX) + tr("Dynamic libraries (*.dylib);;All files (*)"); +#else + tr("All files (*)"); +#endif + QString filePath = QFileDialog::getOpenFileName(this, tr("Open file"), dir, filter); + if (filePath.isNull()) + return; + + setFileDialogInitPathByFile(filePath); + + ui->fileEdit->setText(filePath); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h new file mode 100644 index 0000000..c8ea3d0 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h @@ -0,0 +1,94 @@ +#ifndef SQLITEEXTENSIONEDITOR_H +#define SQLITEEXTENSIONEDITOR_H + +#include "icon.h" +#include "mdichild.h" +#include +#include + +namespace Ui { + class SqliteExtensionEditor; +} + +class QToolBar; +class SqliteExtensionEditorModel; +class QSortFilterProxyModel; +class SelectableDbModel; +class Db; +class LazyTrigger; + +class SqliteExtensionEditor : public MdiChild +{ + Q_OBJECT + + public: + enum Action + { + COMMIT, + ROLLBACK, + ADD, + DELETE, + HELP + }; + + enum ToolBar + { + TOOLBAR + }; + + explicit SqliteExtensionEditor(QWidget *parent = nullptr); + ~SqliteExtensionEditor(); + + bool restoreSessionNextTime(); + bool isUncommitted() const; + QString getQuitUncommittedConfirmMessage() const; + + protected: + QVariant saveSession(); + bool restoreSession(const QVariant &sessionValue); + Icon* getIconNameForMdiWindow(); + QString getTitleForMdiWindow(); + void createActions(); + void setupDefShortcuts(); + QToolBar* getToolBar(int toolbar) const; + + private: + void init(); + int getCurrentExtensionRow() const; + void extensionDeselected(int row); + void extensionSelected(int row); + void clearEdits(); + void selectExtension(int row); + QStringList getCurrentDatabases() const; + bool tryToLoad(const QString& filePath, const QString& initFunc, QString* resultError); + bool validateExtension(bool* fileOk = nullptr, bool* initOk = nullptr, QString* fileError = nullptr); + bool validateExtension(int row); + bool validateExtension(const QString& filePath, const QString& initFunc, bool* fileOk = nullptr, bool* initOk = nullptr, QString* fileError = nullptr); + void initStateForAll(); + + Ui::SqliteExtensionEditor *ui; + SqliteExtensionEditorModel* model = nullptr; + QSortFilterProxyModel* extensionFilterModel = nullptr; + SelectableDbModel* dbListModel = nullptr; + bool currentModified = false; + bool updatesForSelection = false; + Db* probingDb = nullptr; + LazyTrigger* statusUpdateTrigger = nullptr; + bool nameGenerationActive = true; + + private slots: + void help(); + void commit(); + void rollback(); + void newExtension(); + void deleteExtension(); + void updateState(); + void updateCurrentExtensionState(); + void extensionSelected(const QItemSelection& selected, const QItemSelection& deselected); + void updateModified(); + void generateName(); + void applyFilter(const QString& value); + void browseForFile(); +}; + +#endif // SQLITEEXTENSIONEDITOR_H diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.ui b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.ui new file mode 100644 index 0000000..747aa7f --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.ui @@ -0,0 +1,191 @@ + + + SqliteExtensionEditor + + + + 0 + 0 + 980 + 659 + + + + Form + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Filter extensions + + + + + + + + + + + + 4 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + + + Leave empty to use default function + + + + + + + + + + + + + + :/icons/img/directory_open.png:/icons/img/directory_open.png + + + + + + + Extension file + + + + + + + Initialization function + + + + + + + + + + + 0 + 1 + + + + Databases + + + + + + Register in all databases + + + + + + + Register in following databases: + + + + + + + false + + + + + + + + + + + + + + + + + + + + diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.cpp new file mode 100644 index 0000000..6e94a64 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.cpp @@ -0,0 +1,234 @@ +#include "sqliteextensioneditormodel.h" +#include "iconmanager.h" +#include "common/unused.h" + +#include + +#define SETTER(X, Y) \ + if (!isValidRowIndex(row) || X == Y) \ + return; \ + \ + X = Y; \ + emitDataChanged(row); + +#define GETTER(X, Y) \ + if (!isValidRowIndex(row)) \ + return Y; \ + \ + return X; + +SqliteExtensionEditorModel::SqliteExtensionEditorModel(QObject* parent) : + QAbstractListModel(parent) +{ +} + +void SqliteExtensionEditorModel::clearModified() +{ + beginResetModel(); + for (Extension* ext : extensionList) + ext->modified = false; + + listModified = false; + originalExtensionList = extensionList; + endResetModel(); +} + +bool SqliteExtensionEditorModel::isModified() const +{ + if (extensionList != originalExtensionList) + return true; + + for (Extension* ext : extensionList) + { + if (ext->modified) + return true; + } + return false; +} + +bool SqliteExtensionEditorModel::isModified(int row) const +{ + GETTER(extensionList[row]->modified, false); +} + +void SqliteExtensionEditorModel::setModified(int row, bool modified) +{ + SETTER(extensionList[row]->modified, modified); +} + +QString SqliteExtensionEditorModel::getName(int row) const +{ + GETTER(extensionList[row]->name, QString()); +} + +void SqliteExtensionEditorModel::setName(int row, const QString& name) +{ + SETTER(extensionList[row]->name, name); + + QModelIndex idx = index(0); + emit dataChanged(idx, idx, {Qt::DisplayRole}); +} + +void SqliteExtensionEditorModel::setFilePath(int row, const QString& filePath) +{ + SETTER(extensionList[row]->data->filePath, filePath); +} + +QString SqliteExtensionEditorModel::getFilePath(int row) const +{ + GETTER(extensionList[row]->data->filePath, QString()); +} + +void SqliteExtensionEditorModel::setInitFunction(int row, const QString& initFunc) +{ + SETTER(extensionList[row]->data->initFunc, initFunc); +} + +QString SqliteExtensionEditorModel::getInitFunction(int row) const +{ + GETTER(extensionList[row]->data->initFunc, QString()); +} + +void SqliteExtensionEditorModel::setAllDatabases(int row, bool allDatabases) +{ + SETTER(extensionList[row]->data->allDatabases, allDatabases); +} + +bool SqliteExtensionEditorModel::getAllDatabases(int row) const +{ + GETTER(extensionList[row]->data->allDatabases, true); +} + +void SqliteExtensionEditorModel::setDatabases(int row, const QStringList& databases) +{ + SETTER(extensionList[row]->data->databases, databases); +} + +QStringList SqliteExtensionEditorModel::getDatabases(int row) +{ + GETTER(extensionList[row]->data->databases, QStringList()); +} + +bool SqliteExtensionEditorModel::isValid(int row) const +{ + GETTER(extensionList[row]->valid, true); +} + +void SqliteExtensionEditorModel::setValid(int row, bool valid) +{ + SETTER(extensionList[row]->valid, valid); + + QModelIndex idx = index(0); + emit dataChanged(idx, idx, {Qt::DecorationRole}); +} + +bool SqliteExtensionEditorModel::isValid() const +{ + for (Extension* ext : extensionList) + { + if (!ext->valid) + return false; + } + return true; +} + +void SqliteExtensionEditorModel::setData(const QList& extensions) +{ + beginResetModel(); + + for (Extension* extPtr : extensionList) + delete extPtr; + + extensionList.clear(); + + for (const SqliteExtensionManager::ExtensionPtr& ext : extensions) + extensionList << new Extension(ext); + + listModified = false; + originalExtensionList = extensionList; + + endResetModel(); +} + +void SqliteExtensionEditorModel::addExtension(const SqliteExtensionManager::ExtensionPtr& extension) +{ + int row = extensionList.size(); + + beginInsertRows(QModelIndex(), row, row); + + extensionList << new Extension(extension); + listModified = true; + + endInsertRows(); +} + +void SqliteExtensionEditorModel::deleteExtension(int row) +{ + if (!isValidRowIndex(row)) + return; + + beginRemoveRows(QModelIndex(), row, row); + + delete extensionList[row]; + extensionList.removeAt(row); + + listModified = true; + + endRemoveRows(); +} + +QList SqliteExtensionEditorModel::getExtensions() const +{ + QList results; + for (Extension* ext : extensionList) + results << ext->data; + + return results; +} + +bool SqliteExtensionEditorModel::isValidRowIndex(int row) const +{ + return (row >= 0 && row < extensionList.size()); +} + +int SqliteExtensionEditorModel::rowCount(const QModelIndex& parent) const +{ + UNUSED(parent); + return extensionList.size(); +} + +QVariant SqliteExtensionEditorModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid() || !isValidRowIndex(index.row())) + return QVariant(); + + if (role == Qt::DisplayRole) + return getName(index.row()); + + if (role == Qt::DecorationRole) + { + QIcon icon = ICONS.EXTENSION; + if (!isValid(index.row())) + icon = Icon::merge(icon, Icon::ERROR); + + return icon; + } + + return QVariant(); +} + +void SqliteExtensionEditorModel::emitDataChanged(int row) +{ + QModelIndex idx = index(row); + emit dataChanged(idx, idx); +} + +SqliteExtensionEditorModel::Extension::Extension() +{ + data = SqliteExtensionManager::ExtensionPtr::create(); +} + +SqliteExtensionEditorModel::Extension::Extension(const SqliteExtensionManager::ExtensionPtr& other) +{ + data = SqliteExtensionManager::ExtensionPtr::create(*other); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.h b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.h new file mode 100644 index 0000000..085edd9 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.h @@ -0,0 +1,65 @@ +#ifndef SQLITEEXTENSIONEDITORMODEL_H +#define SQLITEEXTENSIONEDITORMODEL_H + +#include "guiSQLiteStudio_global.h" +#include "services/sqliteextensionmanager.h" +#include +#include +#include + +class GUI_API_EXPORT SqliteExtensionEditorModel : public QAbstractListModel +{ + Q_OBJECT + + public: + using QAbstractItemModel::setData; + + explicit SqliteExtensionEditorModel(QObject* parent = nullptr); + + void clearModified(); + bool isModified() const; + bool isModified(int row) const; + void setModified(int row, bool modified); + QString getName(int row) const; + void setName(int row, const QString& name); + void setFilePath(int row, const QString& filePath); + QString getFilePath(int row) const; + void setInitFunction(int row, const QString& initFunc); + QString getInitFunction(int row) const; + void setAllDatabases(int row, bool allDatabases); + bool getAllDatabases(int row) const; + void setDatabases(int row, const QStringList& databases); + QStringList getDatabases(int row); + bool isValid(int row) const; + void setValid(int row, bool valid); + bool isValid() const; + void setData(const QList& extensions); + void addExtension(const SqliteExtensionManager::ExtensionPtr& extension); + void deleteExtension(int row); + QList getExtensions() const; + bool isValidRowIndex(int row) const; + + int rowCount(const QModelIndex& parent = QModelIndex()) const; + QVariant data(const QModelIndex& index, int role) const; + + private: + struct Extension + { + Extension(); + Extension(const SqliteExtensionManager::ExtensionPtr& other); + + SqliteExtensionManager::ExtensionPtr data; + QString name; + bool modified = false; + bool valid = true; + }; + + void emitDataChanged(int row); + + QList extensionList; + QList originalExtensionList; + QHash langToIcon; + bool listModified = false; +}; + +#endif // SQLITEEXTENSIONEDITORMODEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp index 850d8a7..0f95a98 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp @@ -395,7 +395,7 @@ QString TableConstraintsModel::getConstrDetails(SqliteCreateTable::Constraint* c void TableConstraintsModel::columnRenamed(SqliteCreateTable::Constraint* constr, const QString& oldColumn, const QString& newColumn) { - foreach (SqliteIndexedColumn* idxCol, constr->indexedColumns) + for (SqliteIndexedColumn* idxCol : constr->indexedColumns) { if (idxCol->name.compare(oldColumn, Qt::CaseInsensitive) == 0) { @@ -444,7 +444,7 @@ void TableConstraintsModel::columnModified(const QString& oldColumn, SqliteCreat return; int idx = 0; - foreach (SqliteCreateTable::Constraint* constr, createTable->constraints) + for (SqliteCreateTable::Constraint* constr : createTable->constraints) { if (constr->doesAffectColumn(oldColumn)) { @@ -461,7 +461,7 @@ void TableConstraintsModel::columnDeleted(const QString& column) { QList toDelete; int idx = 0; - foreach (SqliteCreateTable::Constraint* constr, createTable->constraints) + for (SqliteCreateTable::Constraint* constr : createTable->constraints) { if (constr->doesAffectColumn(column)) { @@ -477,6 +477,6 @@ void TableConstraintsModel::columnDeleted(const QString& column) idx++; } - foreach (int idx, toDelete) + for (int idx : toDelete) delConstraint(idx); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp index 1c817de..62b6613 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp @@ -283,7 +283,7 @@ void TableStructureModel::moveColumnTo(int colIdx, int newIdx) QModelIndex TableStructureModel::findColumn(const QString& columnName, Qt::CaseSensitivity cs) const { int row = 0; - foreach (SqliteCreateTable::Column* col, createTable->columns) + for (SqliteCreateTable::Column* col : createTable->columns) { if (col->name.compare(columnName, cs) == 0) return createIndex(row, 0); @@ -432,7 +432,7 @@ bool TableStructureModel::isColumnPk(SqliteCreateTable::Column* column) const return true; QList constraints = createTable->getConstraints(SqliteCreateTable::Constraint::PRIMARY_KEY); - foreach (SqliteCreateTable::Constraint* constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) if (constr->doesAffectColumn(column->name)) return true; @@ -445,7 +445,7 @@ bool TableStructureModel::isColumnFk(SqliteCreateTable::Column* column) const return true; QList constraints = createTable->getConstraints(SqliteCreateTable::Constraint::FOREIGN_KEY); - foreach (SqliteCreateTable::Constraint* constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) if (constr->doesAffectColumn(column->name)) return true; @@ -458,7 +458,7 @@ bool TableStructureModel::isColumnUnique(SqliteCreateTable::Column* column) cons return true; QList constraints = createTable->getConstraints(SqliteCreateTable::Constraint::UNIQUE); - foreach (SqliteCreateTable::Constraint* constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) if (constr->doesAffectColumn(column->name)) return true; @@ -471,7 +471,7 @@ bool TableStructureModel::isColumnCheck(SqliteCreateTable::Column* column) const return true; QList constraints = createTable->getConstraints(SqliteCreateTable::Constraint::CHECK); - foreach (SqliteCreateTable::Constraint* constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) if (constr->expr->getContextColumns(false).contains(column->name, Qt::CaseInsensitive)) return true; diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp index 286aad7..526ae1b 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp @@ -338,10 +338,10 @@ void TableWindow::executeStructureChanges() MessageListDialog dialog(tr("Following problems will take place while modifying the table.\n" "Would you like to proceed?", "table window")); dialog.setWindowTitle(tr("Table modification", "table window")); - foreach (const QString& error, tableModifier->getErrors()) + for (const QString& error : tableModifier->getErrors()) dialog.addError(error); - foreach (const QString& warn, tableModifier->getWarnings()) + for (const QString& warn : tableModifier->getWarnings()) dialog.addWarning(warn); if (dialog.exec() != QDialog::Accepted) @@ -844,9 +844,9 @@ void TableWindow::changesSuccessfullyCommitted() tableModifier->getModifiedTriggers(), tableModifier->getModifiedViews() }; - foreach (const QStringList& objList, modifiedObjects) + for (const QStringList& objList : modifiedObjects) { - foreach (const QString& obj, objList) + for (const QString& obj : objList) { if (obj.compare(oldTable, Qt::CaseInsensitive) == 0) continue; @@ -996,7 +996,7 @@ bool TableWindow::validate(bool skipWarning) hasPk = true; SqliteCreateTable::Column::Constraint* colConstraint = nullptr; - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) { colConstraint = column->getConstraint(SqliteCreateTable::Column::Constraint::PRIMARY_KEY); if (colConstraint) @@ -1112,8 +1112,8 @@ void TableWindow::updateDdlTab() void TableWindow::updateNewTableState() { - for (int i = 1; i < 5; i++) - ui->tabWidget->setTabEnabled(i, existingTable); + for (QWidget* tab : {ui->dataTab, ui->constraintsTab, ui->indexesTab, ui->triggersTab}) + ui->tabWidget->setTabEnabled(ui->tabWidget->indexOf(tab), existingTable); actionMap[EXPORT]->setEnabled(existingTable); actionMap[IMPORT]->setEnabled(existingTable); @@ -1466,7 +1466,7 @@ void TableWindow::updateIndexes() QTableWidgetItem* item = nullptr; int row = 0; - foreach (SqliteCreateIndexPtr index, indexes) + for (SqliteCreateIndexPtr index : indexes) { item = new QTableWidgetItem(index->index); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); @@ -1518,7 +1518,7 @@ void TableWindow::updateTriggers() QTableWidgetItem* item = nullptr; QString timeAndEvent; int row = 0; - foreach (SqliteCreateTriggerPtr trig, triggers) + for (SqliteCreateTriggerPtr trig : triggers) { item = new QTableWidgetItem(trig->trigger); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp index be805af..c7ec7d8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp @@ -259,6 +259,13 @@ void ViewWindow::init() updateQueryToolbarStatus(); updateTriggersState(); updateColumnButtons(); + updateAfterInit(); +} + +void ViewWindow::updateAfterInit() +{ + for (QWidget* tab : {ui->dataTab, ui->triggersTab}) + ui->tabWidget->setTabEnabled(ui->tabWidget->indexOf(tab), existingView); } void ViewWindow::newView() @@ -624,6 +631,7 @@ void ViewWindow::changesSuccessfullyCommitted() initView(); updateQueryToolbarStatus(); updateWindowTitle(); + updateAfterInit(); if (oldView.compare(view, Qt::CaseInsensitive) == 0) notifyInfo(tr("Committed changes for view '%1' successfully.").arg(view)); @@ -874,7 +882,7 @@ void ViewWindow::refreshTriggers() QTableWidgetItem* item = nullptr; QString event; int row = 0; - foreach (SqliteCreateTriggerPtr trig, triggers) + for (SqliteCreateTriggerPtr trig : triggers) { item = new QTableWidgetItem(trig->trigger); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); @@ -1017,10 +1025,10 @@ void ViewWindow::executeStructureChanges() MessageListDialog dialog(tr("Following problems will take place while modifying the view.\n" "Would you like to proceed?", "view window")); dialog.setWindowTitle(tr("View modification", "view window")); - foreach (const QString& error, viewModifier->getErrors()) + for (const QString& error : viewModifier->getErrors()) dialog.addError(error); - foreach (const QString& warn, viewModifier->getWarnings()) + for (const QString& warn : viewModifier->getWarnings()) dialog.addWarning(warn); if (dialog.exec() != QDialog::Accepted) diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h index 6144ad8..1a8b5b3 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h +++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h @@ -96,6 +96,7 @@ class GUI_API_EXPORT ViewWindow : public MdiChild private: void init(); + void updateAfterInit(); void newView(); void initView(); void setupCoverWidget(); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui index 9112280..8c17205 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui +++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui @@ -29,7 +29,7 @@ - 2 + 0 @@ -143,7 +143,11 @@ - + + + QPlainTextEdit::NoWrap + + diff --git a/SQLiteStudio3/lang.tcl b/SQLiteStudio3/lang.tcl index d169450..52661f3 100755 --- a/SQLiteStudio3/lang.tcl +++ b/SQLiteStudio3/lang.tcl @@ -14,6 +14,21 @@ if {$::tcl_platform(platform) == "windows"} { set ERR_NULL "2>/dev/null" } +proc find {dir mask} { + set results [list] + foreach f [glob -nocomplain -directory $dir *] { + if {[file isdirectory $f]} { + lappend results {*}[find $f $mask] + continue; + } + + if {[string match $mask [lindex [file split $f] end]]} { + lappend results $f + } + } + return $results +} + proc countstrings {data search} { set l [string length $search] set count 0 @@ -27,7 +42,7 @@ proc countstrings {data search} { proc scanLangs {} { set langs [dict create] - foreach f [exec find .. -name "*.ts"] { + foreach f [find .. "*.ts"] { set lang [lindex [regexp -inline {[^_]*_(\w+(\w+)?).ts$} $f] 1] if {[dict exists $langs $lang]} { set langDict [dict get $langs $lang] diff --git a/SQLiteStudio3/plugins.pri b/SQLiteStudio3/plugins.pri index 326e3e7..10c0660 100644 --- a/SQLiteStudio3/plugins.pri +++ b/SQLiteStudio3/plugins.pri @@ -2,6 +2,8 @@ include($$PWD/dirs.pri) CONFIG += c++11 plugin +QMAKE_CFLAGS += -std=c11 + DESTDIR = $$PWD/../$$OUTPUT_DIR_NAME/SQLiteStudio/plugins OBJECTS_DIR = $$PWD/../$$OUTPUT_DIR_NAME/build MOC_DIR = $$PWD/../$$OUTPUT_DIR_NAME/build diff --git a/SQLiteStudio3/qt_package.xml b/SQLiteStudio3/qt_package.xml new file mode 100644 index 0000000..d7f9358 --- /dev/null +++ b/SQLiteStudio3/qt_package.xml @@ -0,0 +1,10 @@ + + + Qt + Qt framework + %VERSION% + %DATE% + io.qt + false + true + \ No newline at end of file diff --git a/SQLiteStudio3/sqlitestudio/installscript.qs b/SQLiteStudio3/sqlitestudio/installscript.qs new file mode 100644 index 0000000..8e6b84b --- /dev/null +++ b/SQLiteStudio3/sqlitestudio/installscript.qs @@ -0,0 +1,64 @@ +function Component() +{ + if (installer.value("os") === "win") { + component.loaded.connect(this, addOptionsCheckBoxForm); + component.fileTypes = ['db', 'db3', 'sqlite', 'sqlite3', 'sdb', 's3db']; + } +} + +addOptionsCheckBoxForm = function() +{ + // don't show when updating or uninstalling + if (installer.isInstaller()) { + installer.addWizardPageItem(component, "OptionsCheckBoxForm", QInstaller.TargetDirectory); + var form = component.userInterface("OptionsCheckBoxForm"); + + var assocCheckBox = form.RegisterFileCheckBox; + assocCheckBox.text = assocCheckBox.text + component.fileTypes.join(', '); + + var startMenuCheckbox = form.CreateStartMenuEntry; + startMenuCheckbox.stateChanged.connect(this, function() { + installer.setDefaultPageVisible(QInstaller.StartMenuSelection, startMenuCheckbox.checked); + }); + } +} + +Component.prototype.createOperations = function() +{ + // call default implementation to actually install the app + component.createOperations(); + + if (installer.value("os") === "win") { + var form = component.userInterface("OptionsCheckBoxForm"); + var isRegisterFileChecked = form.RegisterFileCheckBox.checked; + var isStartMenuEntryChecked = form.CreateStartMenuEntry.checked; + var forAllUsersChecked = form.CreateStartMenuEntry.ForAllUsers.checked; + + var executable = "@TargetDir@/SQLiteStudio.exe"; + + var linkPrefix = "@UserStartMenuProgramsPath@"; + if (forAllUsersChecked) { + linkPrefix = "@AllUsersStartMenuProgramsPath@"; + } + + if (isRegisterFileChecked) { + component.addOperation("CreateShortcut", executable, linkPrefix + "/@StartMenuDir@/SQLiteStudio.lnk", + "workingDirectory=@TargetDir@", "iconPath=@TargetDir@/SQLiteStudio.exe", + "iconId=0", "description=SQLiteStudio"); + } + + if (isRegisterFileChecked) { + component.fileTypes.forEach(function(fileType) { + component.addOperation( + "RegisterFileType", + fileType, + executable + " '%1'", + "SQLite database", + "application/octet-stream", + executable + ",0", + "ProgId=SQLiteStudio." + fileType + ); + }); + } + } +} diff --git a/SQLiteStudio3/sqlitestudio/main.cpp b/SQLiteStudio3/sqlitestudio/main.cpp index 829d657..443006b 100644 --- a/SQLiteStudio3/sqlitestudio/main.cpp +++ b/SQLiteStudio3/sqlitestudio/main.cpp @@ -26,6 +26,7 @@ #include "dialogs/languagedialog.h" #include "dialogs/triggerdialog.h" #include "services/pluginmanager.h" +#include "singleapplication/singleapplication.h" #include #include #include @@ -35,10 +36,14 @@ #include #include #include +#ifdef Q_OS_WIN +# include +# include +#endif static bool listPlugins = false; -QString uiHandleCmdLineArgs() +QString uiHandleCmdLineArgs(bool applyOptions = true) { QCommandLineParser parser; parser.setApplicationDescription(QObject::tr("GUI interface to SQLiteStudio, a SQLite manager.")); @@ -68,19 +73,22 @@ QString uiHandleCmdLineArgs() parser.process(qApp->arguments()); - bool enableDebug = parser.isSet(debugOption) || parser.isSet(debugStdOutOption) || parser.isSet(sqlDebugOption) || parser.isSet(debugFileOption); - setUiDebug(enableDebug, !parser.isSet(debugStdOutOption), parser.value(debugFileOption)); - CompletionHelper::enableLemonDebug = parser.isSet(lemonDebugOption); - setSqlLoggingEnabled(parser.isSet(sqlDebugOption)); - setExecutorLoggingEnabled(parser.isSet(executorDebugOption)); - if (parser.isSet(sqlDebugDbNameOption)) - setSqlLoggingFilter(parser.value(sqlDebugDbNameOption)); - - if (parser.isSet(listPluginsOption)) - listPlugins = true; - - if (parser.isSet(masterConfigOption)) - Config::setMasterConfigFile(parser.value(masterConfigOption)); + if (applyOptions) + { + bool enableDebug = parser.isSet(debugOption) || parser.isSet(debugStdOutOption) || parser.isSet(sqlDebugOption) || parser.isSet(debugFileOption); + setUiDebug(enableDebug, !parser.isSet(debugStdOutOption), parser.value(debugFileOption)); + CompletionHelper::enableLemonDebug = parser.isSet(lemonDebugOption); + setSqlLoggingEnabled(parser.isSet(sqlDebugOption)); + setExecutorLoggingEnabled(parser.isSet(executorDebugOption)); + if (parser.isSet(sqlDebugDbNameOption)) + setSqlLoggingFilter(parser.value(sqlDebugDbNameOption)); + + if (parser.isSet(listPluginsOption)) + listPlugins = true; + + if (parser.isSet(masterConfigOption)) + Config::setMasterConfigFile(parser.value(masterConfigOption)); + } QStringList args = parser.positionalArguments(); if (args.size() > 0) @@ -89,29 +97,18 @@ QString uiHandleCmdLineArgs() return QString::null; } -bool updateRetryFunction(const QString& msg) -{ - QMessageBox mb(QMessageBox::Critical, QObject::tr("Error"), msg); - mb.addButton(QMessageBox::Retry); - mb.addButton(QMessageBox::Abort); - return (mb.exec() == QMessageBox::Retry); -} - int main(int argc, char *argv[]) { - QApplication a(argc, argv); + SingleApplication a(argc, argv, true, SingleApplication::ExcludeAppPath|SingleApplication::ExcludeAppVersion); -#ifdef PORTABLE_CONFIG - int retCode = 1; - UpdateManager::setRetryFunction(updateRetryFunction); - if (UpdateManager::handleUpdateOptions(a.arguments(), retCode)) - { - if (retCode) - QMessageBox::critical(nullptr, QObject::tr("Error"), UpdateManager::getStaticErrorMessage()); - - return retCode; - } + if (a.isSecondary()) { +#ifdef Q_OS_WIN + AllowSetForegroundWindow(DWORD( a.primaryPid())); #endif + QString dbToOpen = uiHandleCmdLineArgs(); + a.sendMessage(serializeToBytes(dbToOpen)); + return 0; + } qInstallMessageHandler(uiMessageHandler); @@ -135,7 +132,9 @@ int main(int argc, char *argv[]) MultiEditorBool::staticInit(); TriggerDialog::staticInit(); - MainWindow::getInstance(); + MainWindow* mainWin = MAINWINDOW; + + QObject::connect(&a, &SingleApplication::receivedMessage, mainWin, &MainWindow::messageFromSecondaryInstance); SQLITESTUDIO->initPlugins(); diff --git a/SQLiteStudio3/sqlitestudio/package.xml b/SQLiteStudio3/sqlitestudio/package.xml new file mode 100644 index 0000000..1ac4203 --- /dev/null +++ b/SQLiteStudio3/sqlitestudio/package.xml @@ -0,0 +1,17 @@ + + + SQLiteStudio + SQLiteStudio core application + %VERSION% + %DATE% + pl.com.salsoft.sqlitestudio + io.qt + + + true + true + + + register_file_types.ui + + \ No newline at end of file diff --git a/SQLiteStudio3/sqlitestudio/register_file_types.ui b/SQLiteStudio3/sqlitestudio/register_file_types.ui new file mode 100644 index 0000000..24d896d --- /dev/null +++ b/SQLiteStudio3/sqlitestudio/register_file_types.ui @@ -0,0 +1,64 @@ + + + OptionsCheckBoxForm + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 20 + + + + + Register following file extensions with SQLiteStudio: + + + + true + + + + + + + Create Start menu entry + + + true + + + + + + Create for current user only + + + true + + + + + + + Create for all users in the system + + + + + + + + + + + diff --git a/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication.cpp b/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication.cpp new file mode 100644 index 0000000..55d6853 --- /dev/null +++ b/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication.cpp @@ -0,0 +1,472 @@ +// The MIT License (MIT) +// +// Copyright (c) Itay Grudev 2015 - 2016 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SINGLE_APP_STREAM_VERSION QDataStream::Qt_5_3 + +#ifdef Q_OS_UNIX + #include + #include +#endif + +#ifdef Q_OS_WIN + #include + #include +#endif + +#include "singleapplication.h" +#include "singleapplication_p.h" + + +SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr ) : q_ptr( q_ptr ) { + server = nullptr; + socket = nullptr; +} + +SingleApplicationPrivate::~SingleApplicationPrivate() +{ + if( socket != nullptr ) { + socket->close(); + delete socket; + } + + memory->lock(); + InstancesInfo* inst = static_cast(memory->data()); + if( server != nullptr ) { + server->close(); + delete server; + inst->primary = false; + inst->primaryPid = -1; + } + memory->unlock(); + + delete memory; +} + +void SingleApplicationPrivate::genBlockServerName( int timeout ) +{ + QCryptographicHash appData( QCryptographicHash::Sha256 ); + appData.addData( "SingleApplication", 17 ); + appData.addData( SingleApplication::app_t::applicationName().toUtf8() ); + appData.addData( SingleApplication::app_t::organizationName().toUtf8() ); + appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() ); + + if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ) { + appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() ); + } + + if( ! (options & SingleApplication::Mode::ExcludeAppPath) ) { +#ifdef Q_OS_WIN + appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() ); +#else + appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() ); +#endif + } + + // User level block requires a user specific data in the hash + if( options & SingleApplication::Mode::User ) { +#ifdef Q_OS_WIN + Q_UNUSED(timeout); + wchar_t username [ UNLEN + 1 ]; + // Specifies size of the buffer on input + DWORD usernameLength = UNLEN + 1; + if( GetUserNameW( username, &usernameLength ) ) { + appData.addData( QString::fromWCharArray(username).toUtf8() ); + } else { + appData.addData( QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).join("").toUtf8() ); + } +#endif +#ifdef Q_OS_UNIX + QProcess process; + process.start( "whoami" ); + if( process.waitForFinished( timeout ) && + process.exitCode() == QProcess::NormalExit) { + appData.addData( process.readLine() ); + } else { + appData.addData( + QDir( + QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).first() + ).absolutePath().toUtf8() + ); + } +#endif + } + + // Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with + // server naming requirements. + blockServerName = appData.result().toBase64().replace("/", "_"); +} + +void SingleApplicationPrivate::startPrimary( bool resetMemory ) +{ + Q_Q(SingleApplication); + +#ifdef Q_OS_UNIX + // Handle any further termination signals to ensure the + // QSharedMemory block is deleted even if the process crashes + crashHandler(); +#endif + // Successful creation means that no main process exists + // So we start a QLocalServer to listen for connections + QLocalServer::removeServer( blockServerName ); + server = new QLocalServer(); + + // Restrict access to the socket according to the + // SingleApplication::Mode::User flag on User level or no restrictions + if( options & SingleApplication::Mode::User ) { + server->setSocketOptions( QLocalServer::UserAccessOption ); + } else { + server->setSocketOptions( QLocalServer::WorldAccessOption ); + } + + server->listen( blockServerName ); + QObject::connect( + server, + &QLocalServer::newConnection, + this, + &SingleApplicationPrivate::slotConnectionEstablished + ); + + // Reset the number of connections + memory->lock(); + InstancesInfo* inst = static_cast(memory->data()); + + if( resetMemory ) { + inst->secondary = 0; + } + + inst->primary = true; + inst->primaryPid = q->applicationPid(); + + memory->unlock(); + + instanceNumber = 0; +} + +void SingleApplicationPrivate::startSecondary() +{ +#ifdef Q_OS_UNIX + // Handle any further termination signals to ensure the + // QSharedMemory block is deleted even if the process crashes + crashHandler(); +#endif +} + +void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType ) +{ + // Connect to the Local Server of the Primary Instance if not already + // connected. + if( socket == nullptr ) { + socket = new QLocalSocket(); + } + + // If already connected - we are done; + if( socket->state() == QLocalSocket::ConnectedState ) + return; + + // If not connect + if( socket->state() == QLocalSocket::UnconnectedState || + socket->state() == QLocalSocket::ClosingState ) { + socket->connectToServer( blockServerName ); + } + + // Wait for being connected + if( socket->state() == QLocalSocket::ConnectingState ) { + socket->waitForConnected( msecs ); + } + + // Initialisation message according to the SingleApplication protocol + if( socket->state() == QLocalSocket::ConnectedState ) { + // Notify the parent that a new instance had been started; + QByteArray initMsg; + QDataStream writeStream(&initMsg, QIODevice::WriteOnly); + writeStream.setVersion(SINGLE_APP_STREAM_VERSION); + writeStream << blockServerName.toLatin1(); + writeStream << static_cast(connectionType); + writeStream << instanceNumber; + quint16 checksum = qChecksum(initMsg.constData(), static_cast(initMsg.length())); + writeStream << checksum; + + socket->write( initMsg ); + socket->flush(); + socket->waitForBytesWritten( msecs ); + } +} + +qint64 SingleApplicationPrivate::primaryPid() +{ + qint64 pid; + + memory->lock(); + InstancesInfo* inst = static_cast(memory->data()); + pid = inst->primaryPid; + memory->unlock(); + + return pid; +} + +#ifdef Q_OS_UNIX + void SingleApplicationPrivate::crashHandler() + { + // Handle any further termination signals to ensure the + // QSharedMemory block is deleted even if the process crashes + signal( SIGHUP, SingleApplicationPrivate::terminate ); // 1 + signal( SIGINT, SingleApplicationPrivate::terminate ); // 2 + signal( SIGQUIT, SingleApplicationPrivate::terminate ); // 3 + signal( SIGILL, SingleApplicationPrivate::terminate ); // 4 + signal( SIGABRT, SingleApplicationPrivate::terminate ); // 6 + signal( SIGFPE, SingleApplicationPrivate::terminate ); // 8 + signal( SIGBUS, SingleApplicationPrivate::terminate ); // 10 + signal( SIGSEGV, SingleApplicationPrivate::terminate ); // 11 + signal( SIGSYS, SingleApplicationPrivate::terminate ); // 12 + signal( SIGPIPE, SingleApplicationPrivate::terminate ); // 13 + signal( SIGALRM, SingleApplicationPrivate::terminate ); // 14 + signal( SIGTERM, SingleApplicationPrivate::terminate ); // 15 + signal( SIGXCPU, SingleApplicationPrivate::terminate ); // 24 + signal( SIGXFSZ, SingleApplicationPrivate::terminate ); // 25 + } + + void SingleApplicationPrivate::terminate( int signum ) + { + delete ((SingleApplication*)QCoreApplication::instance())->d_ptr; + ::exit( 128 + signum ); + } +#endif + +/** + * @brief Executed when a connection has been made to the LocalServer + */ +void SingleApplicationPrivate::slotConnectionEstablished() +{ + Q_Q(SingleApplication); + + QLocalSocket *nextConnSocket = server->nextPendingConnection(); + + quint32 instanceId = 0; + ConnectionType connectionType = InvalidConnection; + if( nextConnSocket->waitForReadyRead( 100 ) ) { + // read all data from message in same order/format as written + QByteArray msgBytes = nextConnSocket->read(nextConnSocket->bytesAvailable() - static_cast(sizeof(quint16))); + QByteArray checksumBytes = nextConnSocket->read(sizeof(quint16)); + QDataStream readStream(msgBytes); + readStream.setVersion(SINGLE_APP_STREAM_VERSION); + + // server name + QByteArray latin1Name; + readStream >> latin1Name; + // connectioon type + quint8 connType = InvalidConnection; + readStream >> connType; + connectionType = static_cast(connType); + // instance id + readStream >> instanceId; + // checksum + quint16 msgChecksum = 0; + QDataStream checksumStream(checksumBytes); + checksumStream.setVersion(SINGLE_APP_STREAM_VERSION); + checksumStream >> msgChecksum; + + const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast(msgBytes.length())); + + if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) { + connectionType = InvalidConnection; + } + } + + if( connectionType == InvalidConnection ) { + nextConnSocket->close(); + delete nextConnSocket; + return; + } + + QObject::connect( + nextConnSocket, + &QLocalSocket::aboutToClose, + this, + [nextConnSocket, instanceId, this]() { + Q_EMIT this->slotClientConnectionClosed( nextConnSocket, instanceId ); + } + ); + + QObject::connect( + nextConnSocket, + &QLocalSocket::readyRead, + this, + [nextConnSocket, instanceId, this]() { + Q_EMIT this->slotDataAvailable( nextConnSocket, instanceId ); + } + ); + + if( connectionType == NewInstance || ( + connectionType == SecondaryInstance && + options & SingleApplication::Mode::SecondaryNotification + ) + ) { + Q_EMIT q->instanceStarted(); + } + + if( nextConnSocket->bytesAvailable() > 0 ) { + Q_EMIT this->slotDataAvailable( nextConnSocket, instanceId ); + } +} + +void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId ) +{ + Q_Q(SingleApplication); + Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() ); +} + +void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId ) +{ + if( closedSocket->bytesAvailable() > 0 ) + Q_EMIT slotDataAvailable( closedSocket, instanceId ); + closedSocket->deleteLater(); +} + +/** + * @brief Constructor. Checks and fires up LocalServer or closes the program + * if another instance already exists + * @param argc + * @param argv + * @param {bool} allowSecondaryInstances + */ +SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout ) + : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) ) +{ + Q_D(SingleApplication); + + // Store the current mode of the program + d->options = options; + + // Generating an application ID used for identifying the shared memory + // block and QLocalServer + d->genBlockServerName( timeout ); + + // Guarantee thread safe behaviour with a shared memory block. Also by + // explicitly attaching it and then deleting it we make sure that the + // memory is deleted even if the process had crashed on Unix. +#ifdef Q_OS_UNIX + d->memory = new QSharedMemory( d->blockServerName ); + d->memory->attach(); + delete d->memory; +#endif + d->memory = new QSharedMemory( d->blockServerName ); + + // Create a shared memory block + if( d->memory->create( sizeof( InstancesInfo ) ) ) { + d->startPrimary( true ); + return; + } else { + // Attempt to attach to the memory segment + if( d->memory->attach() ) { + d->memory->lock(); + InstancesInfo* inst = static_cast(d->memory->data()); + + if( ! inst->primary ) { + d->startPrimary( false ); + d->memory->unlock(); + return; + } + + // Check if another instance can be started + if( allowSecondary ) { + inst->secondary += 1; + d->instanceNumber = inst->secondary; + d->startSecondary(); + if( d->options & Mode::SecondaryNotification ) { + d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance ); + } + d->memory->unlock(); + return; + } + + d->memory->unlock(); + } + } + + d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance ); + delete d; + ::exit( EXIT_SUCCESS ); +} + +/** + * @brief Destructor + */ +SingleApplication::~SingleApplication() +{ + Q_D(SingleApplication); + delete d; +} + +bool SingleApplication::isPrimary() +{ + Q_D(SingleApplication); + return d->server != nullptr; +} + +bool SingleApplication::isSecondary() +{ + Q_D(SingleApplication); + return d->server == nullptr; +} + +quint32 SingleApplication::instanceId() +{ + Q_D(SingleApplication); + return d->instanceNumber; +} + +qint64 SingleApplication::primaryPid() +{ + Q_D(SingleApplication); + return d->primaryPid(); +} + +bool SingleApplication::sendMessage( QByteArray message, int timeout ) +{ + Q_D(SingleApplication); + + // Nobody to connect to + if( isPrimary() ) return false; + + // Make sure the socket is connected + d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect ); + QThread::msleep(100); + + d->socket->write( message ); + bool dataWritten = d->socket->flush(); + d->socket->waitForBytesWritten( timeout ); + return dataWritten; +} diff --git a/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication.h b/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication.h new file mode 100644 index 0000000..33a9898 --- /dev/null +++ b/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication.h @@ -0,0 +1,135 @@ +// The MIT License (MIT) +// +// Copyright (c) Itay Grudev 2015 - 2016 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef SINGLE_APPLICATION_H +#define SINGLE_APPLICATION_H + +#include +#include + +#ifndef QAPPLICATION_CLASS + #define QAPPLICATION_CLASS QCoreApplication +#endif + +#include QT_STRINGIFY(QAPPLICATION_CLASS) + +class SingleApplicationPrivate; + +/** + * @brief The SingleApplication class handles multipe instances of the same + * Application + * @see QCoreApplication + */ +class SingleApplication : public QAPPLICATION_CLASS +{ + Q_OBJECT + + typedef QAPPLICATION_CLASS app_t; + +public: + /** + * @brief Mode of operation of SingleApplication. + * Whether the block should be user-wide or system-wide and whether the + * primary instance should be notified when a secondary instance had been + * started. + * @note Operating system can restrict the shared memory blocks to the same + * user, in which case the User/System modes will have no effect and the + * block will be user wide. + * @enum + */ + enum Mode { + User = 1 << 0, + System = 1 << 1, + SecondaryNotification = 1 << 2, + ExcludeAppVersion = 1 << 3, + ExcludeAppPath = 1 << 4 + }; + Q_DECLARE_FLAGS(Options, Mode) + + /** + * @brief Intitializes a SingleApplication instance with argc command line + * arguments in argv + * @arg {int &} argc - Number of arguments in argv + * @arg {const char *[]} argv - Supplied command line arguments + * @arg {bool} allowSecondary - Whether to start the instance as secondary + * if there is already a primary instance. + * @arg {Mode} mode - Whether for the SingleApplication block to be applied + * User wide or System wide. + * @arg {int} timeout - Timeout to wait in miliseconds. + * @note argc and argv may be changed as Qt removes arguments that it + * recognizes + * @note Mode::SecondaryNotification only works if set on both the primary + * instance and the secondary instance. + * @note The timeout is just a hint for the maximum time of blocking + * operations. It does not guarantee that the SingleApplication + * initialisation will be completed in given time, though is a good hint. + * Usually 4*timeout would be the worst case (fail) scenario. + * @see See the corresponding QAPPLICATION_CLASS constructor for reference + */ + explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 ); + ~SingleApplication(); + + /** + * @brief Returns if the instance is the primary instance + * @returns {bool} + */ + bool isPrimary(); + + /** + * @brief Returns if the instance is a secondary instance + * @returns {bool} + */ + bool isSecondary(); + + /** + * @brief Returns a unique identifier for the current instance + * @returns {qint32} + */ + quint32 instanceId(); + + /** + * @brief Returns the process ID (PID) of the primary instance + * @returns {qint64} + */ + qint64 primaryPid(); + + /** + * @brief Sends a message to the primary instance. Returns true on success. + * @param {int} timeout - Timeout for connecting + * @returns {bool} + * @note sendMessage() will return false if invoked from the primary + * instance. + */ + bool sendMessage( QByteArray message, int timeout = 100 ); + +Q_SIGNALS: + void instanceStarted(); + void receivedMessage( quint32 instanceId, QByteArray message ); + +private: + SingleApplicationPrivate *d_ptr; + Q_DECLARE_PRIVATE(SingleApplication) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options) + +#endif // SINGLE_APPLICATION_H diff --git a/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication_p.h b/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication_p.h new file mode 100644 index 0000000..a990a53 --- /dev/null +++ b/SQLiteStudio3/sqlitestudio/singleapplication/singleapplication_p.h @@ -0,0 +1,85 @@ +// The MIT License (MIT) +// +// Copyright (c) Itay Grudev 2015 - 2016 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// +// W A R N I N G !!! +// ----------------- +// +// This file is not part of the SingleApplication API. It is used purely as an +// implementation detail. This header file may change from version to +// version without notice, or may even be removed. +// + +#ifndef SINGLEAPPLICATION_P_H +#define SINGLEAPPLICATION_P_H + +#include +#include +#include +#include "singleapplication.h" + +struct InstancesInfo { + bool primary; + quint32 secondary; + qint64 primaryPid; +}; + +class SingleApplicationPrivate : public QObject { +Q_OBJECT +public: + enum ConnectionType : quint8 { + InvalidConnection = 0, + NewInstance = 1, + SecondaryInstance = 2, + Reconnect = 3 + }; + Q_DECLARE_PUBLIC(SingleApplication) + + SingleApplicationPrivate( SingleApplication *q_ptr ); + ~SingleApplicationPrivate(); + + void genBlockServerName( int msecs ); + void startPrimary( bool resetMemory ); + void startSecondary(); + void connectToPrimary(int msecs, ConnectionType connectionType ); + qint64 primaryPid(); + +#ifdef Q_OS_UNIX + void crashHandler(); + static void terminate( int signum ); +#endif + + QSharedMemory *memory; + SingleApplication *q_ptr; + QLocalSocket *socket; + QLocalServer *server; + quint32 instanceNumber; + QString blockServerName; + SingleApplication::Options options; + +public Q_SLOTS: + void slotConnectionEstablished(); + void slotDataAvailable( QLocalSocket*, quint32 ); + void slotClientConnectionClosed( QLocalSocket*, quint32 ); +}; + +#endif // SINGLEAPPLICATION_P_H diff --git a/SQLiteStudio3/sqlitestudio/sqlitestudio.pro b/SQLiteStudio3/sqlitestudio/sqlitestudio.pro index 42aa7dc..96d9f0d 100644 --- a/SQLiteStudio3/sqlitestudio/sqlitestudio.pro +++ b/SQLiteStudio3/sqlitestudio/sqlitestudio.pro @@ -4,9 +4,7 @@ # #------------------------------------------------- -QT += core gui - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +QT += core gui widgets network include($$PWD/../dirs.pri) include($$PWD/../utils.pri) @@ -15,25 +13,37 @@ OBJECTS_DIR = $$OBJECTS_DIR/sqlitestudio MOC_DIR = $$MOC_DIR/sqlitestudio UI_DIR = $$UI_DIR/sqlitestudio -linux: { +linux { TARGET = sqlitestudio -} -!linux: { +} else { TARGET = SQLiteStudio } TEMPLATE = app CONFIG += c++11 QMAKE_CXXFLAGS += -pedantic -linux|portable { - QMAKE_LFLAGS += -Wl,-rpath,./lib + +DEFINES += QAPPLICATION_CLASS=QApplication + +win32 { + msvc:LIBS += Advapi32.lib + gcc:LIBS += -lAdvapi32 +} + +portable { + DEFINES += PORTABLE_CONFIG + linux { + QMAKE_LFLAGS += -Wl,-rpath,./lib + } } LIBS += -lcoreSQLiteStudio -lguiSQLiteStudio -SOURCES += main.cpp +SOURCES += main.cpp \ + singleapplication/singleapplication.cpp -TRANSLATIONS += translations/sqlitestudio_de.ts \ +TRANSLATIONS += translations/sqlitestudio_ro_RO.ts \ + translations/sqlitestudio_de.ts \ translations/sqlitestudio_it.ts \ translations/sqlitestudio_zh_CN.ts \ translations/sqlitestudio_sk.ts \ @@ -43,11 +53,13 @@ TRANSLATIONS += translations/sqlitestudio_de.ts \ translations/sqlitestudio_es.ts \ translations/sqlitestudio_pl.ts -win32: { +win32 { RC_FILE = windows.rc + msvc:LIBS += User32.lib + gcc:LIBS += -lUser32 } -macx: { +macx { ICON = ../guiSQLiteStudio/img/sqlitestudio.icns } @@ -55,7 +67,7 @@ OTHER_FILES += \ windows.rc \ SQLiteStudio.exe.manifest -unix: { +unix { target.path = $$BINDIR INSTALLS += target } @@ -63,6 +75,11 @@ unix: { RESOURCES += \ sqlitestudio.qrc +HEADERS += \ + singleapplication/singleapplication.h \ + singleapplication/singleapplication_p.h + + diff --git a/SQLiteStudio3/sqlitestudio/sqlitestudio.qrc b/SQLiteStudio3/sqlitestudio/sqlitestudio.qrc index 9942536..6431227 100644 --- a/SQLiteStudio3/sqlitestudio/sqlitestudio.qrc +++ b/SQLiteStudio3/sqlitestudio/sqlitestudio.qrc @@ -1,5 +1,6 @@ + translations/sqlitestudio_ro_RO.qm translations/sqlitestudio_de.qm translations/sqlitestudio_pl.qm translations/sqlitestudio_ru.qm @@ -11,3 +12,4 @@ + diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_de.qm b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_de.qm index 6007538..b319573 100644 Binary files a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_de.qm and b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_de.qm differ diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_de.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_de.ts index fb20723..a65829c 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_de.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_de.ts @@ -4,87 +4,85 @@ QObject - + GUI interface to SQLiteStudio, a SQLite manager. GUI Schnittstelle zu SQLiteStudio, ein SQLite Manager. - + Enables debug messages in console (accessible with F12). Aktiviert Debug-Meldungen in der Konsole (erreichbar über F12). - + Redirects debug messages into standard output (forces debug mode). Leitet Debug-Meldungen in den Standardausgabekanal um (erzwingt den Debugmodus). - + Redirects debug messages into given file (forces debug mode). Leitet Debug-Meldungen in die angegebene Datei um (erzwingt den Debugmodus). - + log file Logdatei - + Enables Lemon parser debug messages for SQL code assistant. Aktiviert Lemon Parser Debug-Meldungen für den SQL Codeassistenten. - + Enables debugging of every single SQL query being sent to any database. Aktiviert das Debugging für jede SQL Abfrage, die an eine beliebige Datenbank gesendet wurde. - + Limits SQL query messages to only the given <database>. Wird <database> bei Ausgabe der Meldung in die aktuelle Datenbankbezeichnung umgewandelt? Begrenzt SQL Abfragemeldungen auf folgende Datenbank: <database>. - + database Datenbank - + Enables debugging of SQLiteStudio's query executor. - + Lists plugins installed in the SQLiteStudio and quits. Was wird hier beendet? Listet die in SQLiteStudio installierten Plugins auf und beendet. - + Points to the master configuration file. Read manual at wiki page for more details. - + SQLiteStudio settings file - + file Datei - + Database file to open Zu öffnende Datenbankdatei - - Error - Fehler + Fehler diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_es.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_es.ts index d58025f..ff56801 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_es.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_es.ts @@ -4,85 +4,79 @@ QObject - + GUI interface to SQLiteStudio, a SQLite manager. - + Enables debug messages in console (accessible with F12). - + Redirects debug messages into standard output (forces debug mode). - + Redirects debug messages into given file (forces debug mode). - + log file - + Enables Lemon parser debug messages for SQL code assistant. - + Enables debugging of every single SQL query being sent to any database. - + Limits SQL query messages to only the given <database>. - + database - + Enables debugging of SQLiteStudio's query executor. - + Lists plugins installed in the SQLiteStudio and quits. - + Points to the master configuration file. Read manual at wiki page for more details. - + SQLiteStudio settings file - + file - + Database file to open - - - - Error - - diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_fr.qm b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_fr.qm index 9d59c25..de3c6d6 100644 Binary files a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_fr.qm and b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_fr.qm differ diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_fr.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_fr.ts index fc7e350..087d5b8 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_fr.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_fr.ts @@ -4,86 +4,83 @@ QObject - + GUI interface to SQLiteStudio, a SQLite manager. - Interface GUI de SQLiteStudio un outil pour SQLite - + Interface GUI de SQLiteStudio, un outil pour SQLite. - + Enables debug messages in console (accessible with F12). - Messages de déboguage avec la console(accessible avec F12). + Messages de déboguage dans la console (accessible avec F12). - + Redirects debug messages into standard output (forces debug mode). - Messages de déboguage redirigés vers sortie standard(mode déboguage forcé). + Messages de déboguage redirigés vers sortie standard (mode déboguage forcé). - + Redirects debug messages into given file (forces debug mode). - + Messages de déboguage redirigés vers un fichier (mode déboguage forcé). - + log file - + fichier log - + Enables Lemon parser debug messages for SQL code assistant. Message de déboguage avec l’analyseur Lemon pour un assistant code SQL. - + Enables debugging of every single SQL query being sent to any database. - Déboguage pour toutes requêtes SQL simple utilisé pour la plupart des bases de données. + Déboguage pour chaque requête SQL envoyée à toute base de données. - + Limits SQL query messages to only the given <database>. - Limites des meesages de la requête SQL pour la <database>. + Limite les messages de la requête SQL à la <database>. - + database Base de données - + Enables debugging of SQLiteStudio's query executor. - + Déboguage de l'exécuteur de requêtes de SQLiteStudio. - + Lists plugins installed in the SQLiteStudio and quits. - Listes des plugins installés dans SQLiteStudio et quitter. + Liste les plugins installés dans SQLiteStudio et quitte. - + Points to the master configuration file. Read manual at wiki page for more details. - + SQLiteStudio settings file - + file Fichier - + Database file to open Fichier de la base de données à ouvrir - - Error - Erreur + Erreur diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_it.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_it.ts index 88ce9ce..ef01351 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_it.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_it.ts @@ -4,85 +4,79 @@ QObject - + GUI interface to SQLiteStudio, a SQLite manager. - + Enables debug messages in console (accessible with F12). - + Redirects debug messages into standard output (forces debug mode). - + Redirects debug messages into given file (forces debug mode). - + log file - + Enables Lemon parser debug messages for SQL code assistant. - + Enables debugging of every single SQL query being sent to any database. - + Limits SQL query messages to only the given <database>. - + database - + Enables debugging of SQLiteStudio's query executor. - + Lists plugins installed in the SQLiteStudio and quits. - + Points to the master configuration file. Read manual at wiki page for more details. - + SQLiteStudio settings file - + file - + Database file to open - - - - Error - - diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pl.qm b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pl.qm index df5348b..b444825 100644 Binary files a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pl.qm and b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pl.qm differ diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pl.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pl.ts index 365a823..0add178 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pl.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pl.ts @@ -41,7 +41,7 @@ Error - Błąd + Błąd Lists plugins installed in the SQLiteStudio and quits. @@ -61,11 +61,11 @@ Points to the master configuration file. Read manual at wiki page for more details. - + Wskazuje na główny plik konfiguracyjny. Więcej szczegółów w podręczniku na stronie wiki. SQLiteStudio settings file - + Plik ustawień SQLiteStudio diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pt_BR.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pt_BR.ts index 95025b4..23c60cc 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pt_BR.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_pt_BR.ts @@ -4,85 +4,79 @@ QObject - + GUI interface to SQLiteStudio, a SQLite manager. - + Enables debug messages in console (accessible with F12). - + Redirects debug messages into standard output (forces debug mode). - + Redirects debug messages into given file (forces debug mode). - + log file - + Enables Lemon parser debug messages for SQL code assistant. - + Enables debugging of every single SQL query being sent to any database. - + Limits SQL query messages to only the given <database>. - + database - + Enables debugging of SQLiteStudio's query executor. - + Lists plugins installed in the SQLiteStudio and quits. - + Points to the master configuration file. Read manual at wiki page for more details. - + SQLiteStudio settings file - + file - + Database file to open - - - - Error - - diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ro_RO.qm b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ro_RO.qm new file mode 100644 index 0000000..2856eb9 Binary files /dev/null and b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ro_RO.qm differ diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ro_RO.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ro_RO.ts new file mode 100644 index 0000000..b4b3802 --- /dev/null +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ro_RO.ts @@ -0,0 +1,82 @@ + + + + + QObject + + + GUI interface to SQLiteStudio, a SQLite manager. + + + + + Enables debug messages in console (accessible with F12). + + + + + Redirects debug messages into standard output (forces debug mode). + + + + + Redirects debug messages into given file (forces debug mode). + + + + + log file + + + + + Enables Lemon parser debug messages for SQL code assistant. + + + + + Enables debugging of every single SQL query being sent to any database. + + + + + Limits SQL query messages to only the given <database>. + + + + + database + + + + + Enables debugging of SQLiteStudio's query executor. + + + + + Lists plugins installed in the SQLiteStudio and quits. + + + + + Points to the master configuration file. Read manual at wiki page for more details. + + + + + SQLiteStudio settings file + + + + + file + + + + + Database file to open + + + + diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ru.qm b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ru.qm index b5a73d2..5541fe4 100644 Binary files a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ru.qm and b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ru.qm differ diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ru.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ru.ts index 65f0cf4..f9d2eae 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ru.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_ru.ts @@ -4,85 +4,83 @@ QObject - + GUI interface to SQLiteStudio, a SQLite manager. Графический интерфейс для SQLiteStudio, менеджера баз данных SQLite. - + Enables debug messages in console (accessible with F12). Включает вывод отладочных сообщений в консоль (доступную по нажатию F12). - + Redirects debug messages into standard output (forces debug mode). Перенаправляет отладочные сообщения в стандартный поток (принудительный отладочный режим). - + Redirects debug messages into given file (forces debug mode). Перенаправляет отладочные сообщения в указанный файл (принудительный отладочный режим). - + log file файл журнала - + Enables Lemon parser debug messages for SQL code assistant. Включает вывод отладочных сообщений анализатора Lemon для автодополнения SQL кода. - + Enables debugging of every single SQL query being sent to any database. Включает отладку каждого запроса SQL, посылаемого к любой базе данных. - + Limits SQL query messages to only the given <database>. Ограничивает сообщения запросов SQL только для указанной <базы данных>. - + database база данных - + Enables debugging of SQLiteStudio's query executor. Включает отладку обработчика запросов SQLiteStudio. - + Lists plugins installed in the SQLiteStudio and quits. Выводит список установленных в SQLiteStudio модулей и осуществляет выход. - + Points to the master configuration file. Read manual at wiki page for more details. Указывает основной файл конфигурации. Детальная информация содержится в инструкции на wiki-странице. - + SQLiteStudio settings file Файл настроек SQLiteStudio - + file файл - + Database file to open Файл базы данных для открытия - - Error - Ошибка + Ошибка diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_sk.qm b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_sk.qm index 526751e..01f60b5 100644 Binary files a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_sk.qm and b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_sk.qm differ diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_sk.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_sk.ts index 6c08225..d1ec165 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_sk.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_sk.ts @@ -4,85 +4,83 @@ QObject - + GUI interface to SQLiteStudio, a SQLite manager. GUI rozhranie pre SQLiteStudio, SQLite manažér. - + Enables debug messages in console (accessible with F12). Aktivuje ladiace správy v konzole (dostupné pomocou F12). - + Redirects debug messages into standard output (forces debug mode). Presmerovať ladiace informácie na štandardný výstup (vynútený ladiaci mód). - + Redirects debug messages into given file (forces debug mode). - + log file - + Enables Lemon parser debug messages for SQL code assistant. - + Enables debugging of every single SQL query being sent to any database. - + Limits SQL query messages to only the given <database>. - + database databáza - + Enables debugging of SQLiteStudio's query executor. - + Lists plugins installed in the SQLiteStudio and quits. - + Points to the master configuration file. Read manual at wiki page for more details. - + SQLiteStudio settings file - + file Súbor - + Database file to open - - Error - Chyba + Chyba diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_zh_CN.qm b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_zh_CN.qm index 83692c1..83024d2 100644 Binary files a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_zh_CN.qm and b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_zh_CN.qm differ diff --git a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_zh_CN.ts b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_zh_CN.ts index 0417421..b84ae66 100644 --- a/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_zh_CN.ts +++ b/SQLiteStudio3/sqlitestudio/translations/sqlitestudio_zh_CN.ts @@ -4,85 +4,83 @@ QObject - + GUI interface to SQLiteStudio, a SQLite manager. - + Enables debug messages in console (accessible with F12). - + Redirects debug messages into standard output (forces debug mode). - + Redirects debug messages into given file (forces debug mode). - + log file 日志文件 - + Enables Lemon parser debug messages for SQL code assistant. - + Enables debugging of every single SQL query being sent to any database. - + Limits SQL query messages to only the given <database>. - + database 数据库 - + Enables debugging of SQLiteStudio's query executor. - + Lists plugins installed in the SQLiteStudio and quits. 列出已安装的插件并退出。 - + Points to the master configuration file. Read manual at wiki page for more details. - + SQLiteStudio settings file - + file 文件 - + Database file to open 要打开的数据库文件 - - Error - 错误 + 错误 diff --git a/SQLiteStudio3/sqlitestudiocli/cli.cpp b/SQLiteStudio3/sqlitestudiocli/cli.cpp index df7e7cd..90c8d5e 100644 --- a/SQLiteStudio3/sqlitestudiocli/cli.cpp +++ b/SQLiteStudio3/sqlitestudiocli/cli.cpp @@ -208,7 +208,7 @@ bool CLI::isComplete(const QString& contents) const void CLI::loadHistory() { - foreach (const QString& line, CFG->getCliHistory()) + for (const QString& line : CFG->getCliHistory()) { if (!line.isEmpty()) add_history(line.toLocal8Bit().data()); diff --git a/SQLiteStudio3/sqlitestudiocli/clicommandsyntax.cpp b/SQLiteStudio3/sqlitestudiocli/clicommandsyntax.cpp index 732b0f0..a473c5d 100644 --- a/SQLiteStudio3/sqlitestudiocli/clicommandsyntax.cpp +++ b/SQLiteStudio3/sqlitestudiocli/clicommandsyntax.cpp @@ -10,13 +10,13 @@ CliCommandSyntax::CliCommandSyntax() CliCommandSyntax::~CliCommandSyntax() { - foreach (Argument* arg, arguments) + for (Argument* arg : arguments) delete arg; arguments.clear(); argumentMap.clear(); - foreach (Option* opt, options) + for (Option* opt : options) delete opt; optionMap.clear(); @@ -172,7 +172,7 @@ QStringList CliCommandSyntax::getStrictArgumentCandidates() if (lastParsedOption && !lastParsedOption->argName.isEmpty()) return results; // this case is covered by getRegularArgumentCandidates() - foreach (Option* opt, options) + for (Option* opt : options) { if (opt->requested) continue; @@ -248,7 +248,7 @@ QString CliCommandSyntax::getSyntaxDefinition(const QString& usedName) const QString optName; QStringList optNameParts; - foreach (Option* opt, options) + for (Option* opt : options) { optNameParts.clear();; if (!opt->shortName.isEmpty()) @@ -264,7 +264,7 @@ QString CliCommandSyntax::getSyntaxDefinition(const QString& usedName) const QString templ; QString argName; - foreach (Argument* arg, arguments) + for (Argument* arg : arguments) { templ = (arg->mandatory ? mandatoryArgTempl : optionalArgTempl); switch (arg->type) @@ -404,7 +404,7 @@ bool CliCommandSyntax::parseOpt(const QString& arg, const QStringList& args, int int CliCommandSyntax::requiredArguments() const { int cnt = 0; - foreach (Argument* arg, arguments) + for (Argument* arg : arguments) { if (arg->mandatory) cnt++; diff --git a/SQLiteStudio3/sqlitestudiocli/clicompleter.cpp b/SQLiteStudio3/sqlitestudiocli/clicompleter.cpp index 1c3c99c..3d6dcb0 100644 --- a/SQLiteStudio3/sqlitestudiocli/clicompleter.cpp +++ b/SQLiteStudio3/sqlitestudiocli/clicompleter.cpp @@ -106,7 +106,7 @@ QStringList CliCompleter::completeCommand(const QString& str, int curPos) { QStringList cmdNames = CliCommandFactory::getCommandNames().filter(QRegExp("^"+cmdStr+".*")); cmdNames.sort(Qt::CaseInsensitive); - foreach (const QString& cmdName, cmdNames) + for (const QString& cmdName : cmdNames) results << CFG_CLI.Console.CommandPrefixChar.get() + cmdName; } @@ -124,7 +124,7 @@ QStringList CliCompleter::completeQuery(const QString& toBeReplaced, const QStri CompletionHelper completer(str, curPos, cli->getCurrentDb()); QList expectedTokens = completer.getExpectedTokens().filtered(); - foreach (const ExpectedTokenPtr& token, expectedTokens) + for (const ExpectedTokenPtr& token : expectedTokens) list << token->value; list.removeAll(""); @@ -162,7 +162,7 @@ char** CliCompleter::toCharArray(const QStringList& list) array[list.size()] = nullptr; int i = 0; - foreach (const QString& str, list) + for (const QString& str : list) #if defined(Q_OS_WIN) array[i++] = _strdup(str.toLocal8Bit().data()); #elif defined(Q_OS_UNIX) diff --git a/SQLiteStudio3/sqlitestudiocli/climsghandler.cpp b/SQLiteStudio3/sqlitestudiocli/climsghandler.cpp index f9dbc76..c9f2f2c 100644 --- a/SQLiteStudio3/sqlitestudiocli/climsghandler.cpp +++ b/SQLiteStudio3/sqlitestudiocli/climsghandler.cpp @@ -14,9 +14,11 @@ void cliMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString txt; switch (type) { +#if QT_VERSION >= 0x050500 case QtInfoMsg: txt = QString("Info: %1").arg(msg); break; +#endif case QtDebugMsg: txt = QString("Debug: %1").arg(msg); break; diff --git a/SQLiteStudio3/sqlitestudiocli/cliutils.cpp b/SQLiteStudio3/sqlitestudiocli/cliutils.cpp index 2b5c44d..d78509b 100644 --- a/SQLiteStudio3/sqlitestudiocli/cliutils.cpp +++ b/SQLiteStudio3/sqlitestudiocli/cliutils.cpp @@ -55,7 +55,7 @@ QStringList toAsciiTree(const AsciiTree& tree, const QList& indents, bool if (!topLevel) { // Draw indent before this node - foreach (bool indent, indents) + for (bool indent : indents) line += (indent ? indentStr : indentStrEmpty); // Draw node prefix @@ -77,7 +77,7 @@ QStringList toAsciiTree(const AsciiTree& tree, const QList& indents, bool if (!topLevel) subIndents << (lastNode ? false : true); - foreach (const AsciiTree& subTree, tree.childs) + for (const AsciiTree& subTree : tree.childs) { lines += toAsciiTree(subTree, subIndents, false, i == lastIdx); i++; diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommand.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommand.cpp index 3002ee5..20f180e 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommand.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommand.cpp @@ -64,7 +64,7 @@ QStringList CliCommand::complete(const QStringList& args) QStringList results; results += syntax.getStrictArgumentCandidates(); - foreach (int id, syntax.getRegularArgumentCandidates()) + for (int id : syntax.getRegularArgumentCandidates()) results += getCompletionValuesFor(id, args.last()); return results; @@ -93,9 +93,9 @@ void CliCommand::printBox(const QString& str) QStringList lines = str.split("\n"); println(".---------------------------"); - foreach (const QString& line, lines) + for (const QString& line : lines) { - foreach (const QString& lineWithMargin, applyMargin(line, cols - 3)) // 2 for "| " and 1 for final new line character + for (const QString& lineWithMargin : applyMargin(line, cols - 3)) // 2 for "| " and 1 for final new line character println("| " + lineWithMargin); } @@ -153,7 +153,7 @@ QStringList CliCommand::getCompletionTables() resolver.setIgnoreSystemObjects(true); results += wrapObjNamesIfNeeded(resolver.getTables(), dialect); results += prefixEach("temp.", wrapObjNamesIfNeeded(resolver.getTables("temp"), dialect)); - foreach (const QString& database, resolver.getDatabases()) + for (const QString& database : resolver.getDatabases()) results += prefixEach(wrapObjIfNeeded(database, Dialect::Sqlite3)+".", wrapObjNamesIfNeeded(resolver.getTables(database), dialect)); return results; @@ -171,7 +171,7 @@ QStringList CliCommand::getCompletionIndexes() resolver.setIgnoreSystemObjects(true); results += wrapObjNamesIfNeeded(resolver.getIndexes(), dialect); results += prefixEach("temp.", wrapObjNamesIfNeeded(resolver.getIndexes("temp"), dialect)); - foreach (const QString& database, resolver.getDatabases()) + for (const QString& database : resolver.getDatabases()) results += prefixEach(wrapObjIfNeeded(database, Dialect::Sqlite3)+".", wrapObjNamesIfNeeded(resolver.getIndexes(database), dialect)); return results; @@ -189,7 +189,7 @@ QStringList CliCommand::getCompletionTriggers() resolver.setIgnoreSystemObjects(true); results += wrapObjNamesIfNeeded(resolver.getTriggers(), dialect); results += prefixEach("temp.", wrapObjNamesIfNeeded(resolver.getTriggers("temp"), dialect)); - foreach (const QString& database, resolver.getDatabases()) + for (const QString& database : resolver.getDatabases()) results += prefixEach(wrapObjIfNeeded(database, Dialect::Sqlite3)+".", wrapObjNamesIfNeeded(resolver.getTriggers(database), dialect)); return results; @@ -207,7 +207,7 @@ QStringList CliCommand::getCompletionViews() resolver.setIgnoreSystemObjects(true); results += wrapObjNamesIfNeeded(resolver.getViews(), dialect); results += prefixEach("temp.", wrapObjNamesIfNeeded(resolver.getViews("temp"), dialect)); - foreach (const QString& database, resolver.getDatabases()) + for (const QString& database : resolver.getDatabases()) results += prefixEach(wrapObjIfNeeded(database, Dialect::Sqlite3)+".", wrapObjNamesIfNeeded(resolver.getViews(database), dialect)); return results; @@ -228,7 +228,7 @@ QStringList CliCommand::getCompletionFiles(const QString& partialValue) QStringList results; QString name; - foreach (const QFileInfo& entry, entries) + for (const QFileInfo& entry : entries) { name = entry.fileName(); if (dir != QDir::current()) @@ -248,7 +248,7 @@ QStringList CliCommand::getCompletionDirs(const QString& partialValue) QStringList results; QString name; - foreach (const QFileInfo& entry, entries) + for (const QFileInfo& entry : entries) { name = entry.fileName(); if (dir != QDir::current()) diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommanddblist.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommanddblist.cpp index 35f9c47..271a44f 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommanddblist.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommanddblist.cpp @@ -22,7 +22,7 @@ void CliCommandDbList::execute() int maxNameLength = tr("Name", "CLI db name column").length(); int lgt = 0; - foreach (Db* db, dbList) + for (Db* db : dbList) { lgt = db->getName().length() + 1; maxNameLength = qMax(maxNameLength, lgt); @@ -46,7 +46,7 @@ void CliCommandDbList::execute() println(msg); QString name; - foreach (Db* db, dbList) + for (Db* db : dbList) { bool open = db->isOpen(); path = db->getPath(); diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommanddir.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommanddir.cpp index c61f503..8410cba 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommanddir.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommanddir.cpp @@ -15,7 +15,7 @@ void CliCommandDir::execute() entries = dir.entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot, QDir::DirsFirst|QDir::LocaleAware|QDir::Name); QString name; - foreach (const QFileInfo& entry, entries) + for (const QFileInfo& entry : entries) { name = entry.fileName(); if (entry.isDir()) diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommandfactory.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommandfactory.cpp index 742709b..32f972f 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommandfactory.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommandfactory.cpp @@ -78,7 +78,7 @@ void CliCommandFactory::registerCommand(CliCommandCreatorFunc func) cmd->defineSyntax(); mapping[cmd->getName()] = func; - foreach (const QString& alias, cmd->aliases()) + for (const QString& alias : cmd->aliases()) mapping[alias] = func; delete cmd; diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommandhelp.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommandhelp.cpp index 7a957c3..5f92fd4 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommandhelp.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommandhelp.cpp @@ -77,7 +77,7 @@ void CliCommandHelp::printHelp() names.sort(); QStringList msgList; - foreach (const QString& cmd, names) + for (const QString& cmd : names) { msgList << (CFG_CLI.Console.CommandPrefixChar.get() + pad(cmd, width, ' ') + " - " + allCommands[cmd]->shortHelp()); delete allCommands[cmd]; diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommandhistory.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommandhistory.cpp index 7d08846..c7b16f8 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommandhistory.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommandhistory.cpp @@ -26,7 +26,7 @@ void CliCommandHistory::execute() int cols = getCliColumns(); QString hline = pad("", cols, '-'); - foreach (const QString& line, cli->getHistory()) + for (const QString& line : cli->getHistory()) { print(hline); println(line); diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommandsql.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommandsql.cpp index 7ae78e5..4b66592 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommandsql.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommandsql.cpp @@ -91,7 +91,7 @@ void CliCommandSql::printResultsClassic(QueryExecutor* executor, SqlQueryPtr res int resultColumnCount = executor->getResultColumns().size(); // Columns - foreach (const QueryExecutor::ResultColumnPtr& resCol, executor->getResultColumns()) + for (const QueryExecutor::ResultColumnPtr& resCol : executor->getResultColumns()) qOut << resCol->displayName << "|"; qOut << "\n"; @@ -105,7 +105,7 @@ void CliCommandSql::printResultsClassic(QueryExecutor* executor, SqlQueryPtr res row = results->next(); i = 0; values = row->valueList().mid(0, resultColumnCount); - foreach (QVariant value, values) + for (QVariant value : values) { qOut << getValueString(value); if ((i + 1) < resultColumnCount) @@ -148,7 +148,7 @@ void CliCommandSql::printResultsFixed(QueryExecutor* executor, SqlQueryPtr resul // Columns QStringList columns; - foreach (const QueryExecutor::ResultColumnPtr& resCol, executor->getResultColumns()) + for (const QueryExecutor::ResultColumnPtr& resCol : executor->getResultColumns()) columns << resCol->displayName; printColumnHeader(widths, columns); @@ -183,7 +183,7 @@ void CliCommandSql::printResultsColumns(QueryExecutor* executor, SqlQueryPtr res // Get widths of each column in every data row, remember the longest ones QList columnWidths; SortedColumnWidth* colWidth = nullptr; - foreach (const QueryExecutor::ResultColumnPtr& resCol, resultColumns) + for (const QueryExecutor::ResultColumnPtr& resCol : resultColumns) { colWidth = new SortedColumnWidth(); colWidth->setHeaderWidth(resCol->displayName.length()); @@ -192,7 +192,7 @@ void CliCommandSql::printResultsColumns(QueryExecutor* executor, SqlQueryPtr res } int dataLength; - foreach (const SqlResultsRowPtr& row, allRows) + for (const SqlResultsRowPtr& row : allRows) { for (int i = 0; i < resultColumnsCount; i++) { @@ -203,8 +203,8 @@ void CliCommandSql::printResultsColumns(QueryExecutor* executor, SqlQueryPtr res // Calculate width as it would be required to display entire rows int totalWidth = 0; - foreach (colWidth, columnWidths) - totalWidth += colWidth->getWidth(); + for (SortedColumnWidth* colWd : columnWidths) + totalWidth += colWd->getWidth(); totalWidth += (resultColumnsCount - 1); // column separators @@ -223,12 +223,12 @@ void CliCommandSql::printResultsColumns(QueryExecutor* executor, SqlQueryPtr res // Printing QList finalWidths; - foreach (colWidth, columnWidths) - finalWidths << colWidth->getWidth(); + for (SortedColumnWidth* colWd : columnWidths) + finalWidths << colWd->getWidth(); printColumnHeader(finalWidths, headerNames); - foreach (SqlResultsRowPtr row, allRows) + for (SqlResultsRowPtr row : allRows) printColumnDataRow(finalWidths, row, resultColumnsCount); qOut.flush(); @@ -239,14 +239,14 @@ void CliCommandSql::printResultsRowByRow(QueryExecutor* executor, SqlQueryPtr re // Columns int resultColumnCount = executor->getResultColumns().size(); int colWidth = 0; - foreach (const QueryExecutor::ResultColumnPtr& resCol, executor->getResultColumns()) + for (const QueryExecutor::ResultColumnPtr& resCol : executor->getResultColumns()) { if (resCol->displayName.length() > colWidth) colWidth = resCol->displayName.length(); } QStringList columns; - foreach (const QueryExecutor::ResultColumnPtr& resCol, executor->getResultColumns()) + for (const QueryExecutor::ResultColumnPtr& resCol : executor->getResultColumns()) columns << pad(resCol->displayName, -colWidth, ' '); // Data @@ -262,7 +262,7 @@ void CliCommandSql::printResultsRowByRow(QueryExecutor* executor, SqlQueryPtr re i = 0; rowCntString = " " + rowCntTemplate.arg(rowCnt) + " "; qOut << center(rowCntString, termWidth - 1, '-') << "\n"; - foreach (QVariant value, row->valueList().mid(0, resultColumnCount)) + for (QVariant value : row->valueList().mid(0, resultColumnCount)) { qOut << columns[i] + ": " + getValueString(value) << "\n"; i++; @@ -293,7 +293,7 @@ void CliCommandSql::shrinkColumns(QList& colu qSort(columnWidths); // See if we can shrink headers only, or we already need to shrink the data - foreach (SortedColumnWidth* colWidth, columnWidths) + for (SortedColumnWidth* colWidth : columnWidths) { if (colWidth->isHeaderLonger()) { @@ -360,7 +360,7 @@ void CliCommandSql::printColumnHeader(const QList& widths, const QStringLis { QStringList line; int i = 0; - foreach (const QString& col, columns) + for (const QString& col : columns) { line << pad(col.left(widths[i]), widths[i], ' '); i++; @@ -380,7 +380,7 @@ void CliCommandSql::printColumnDataRow(const QList& widths, const SqlResult { int i = 0; QStringList line; - foreach (const QVariant& value, row->valueList().mid(0, resultColumnCount)) + for (const QVariant& value : row->valueList().mid(0, resultColumnCount)) { line << pad(getValueString(value).left(widths[i]), widths[i], ' '); i++; diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommandtables.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommandtables.cpp index f5a9708..8a8f5dc 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommandtables.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommandtables.cpp @@ -47,9 +47,9 @@ void CliCommandTables::execute() println(pad(tr("Database"), width, ' ') + " " + tr("Table")); println(pad("", width, '-') + "-------------------"); - foreach (const QString& dbName, dbList) + for (const QString& dbName : dbList) { - foreach (const QString& table, resolver.getTables(dbName)) + for (const QString& table : resolver.getTables(dbName)) println(pad(dbName, width, ' ') + " " + table); } diff --git a/SQLiteStudio3/sqlitestudiocli/commands/clicommandtree.cpp b/SQLiteStudio3/sqlitestudiocli/commands/clicommandtree.cpp index cbd57c6..c99fe66 100644 --- a/SQLiteStudio3/sqlitestudiocli/commands/clicommandtree.cpp +++ b/SQLiteStudio3/sqlitestudiocli/commands/clicommandtree.cpp @@ -32,7 +32,7 @@ void CliCommandTree::execute() AsciiTree tree; tree.label = cli->getCurrentDb()->getName(); - foreach (const QString& database, databases) + for (const QString& database : databases) { tree.childs << getDatabaseTree(database, resolver, printColumns); } @@ -52,11 +52,11 @@ AsciiTree CliCommandTree::getDatabaseTree(const QString& database, SchemaResolve AsciiTree viewsTree; tablesTree.label = metaNodeNameTemplate.arg(tr("Tables")); - foreach (const QString& table, tables) + for (const QString& table : tables) tablesTree.childs << getTableTree(database, table, resolver, printColumns); viewsTree.label = metaNodeNameTemplate.arg(tr("Views")); - foreach (const QString& view, views) + for (const QString& view : views) viewsTree.childs << getViewTree(database, view, resolver); tree.label = database; @@ -81,16 +81,16 @@ AsciiTree CliCommandTree::getTableTree(const QString& database, const QString& t if (printColumns) { columnsTree.label = metaNodeNameTemplate.arg(tr("Columns")); - foreach (const QString& column, columns) + for (const QString& column : columns) columnsTree.childs << getTreeLeaf(column); } indexesTree.label = metaNodeNameTemplate.arg(tr("Indexes")); - foreach (const QString& index, indexes) + for (const QString& index : indexes) indexesTree.childs << getTreeLeaf(index); triggersTree.label = metaNodeNameTemplate.arg(tr("Triggers")); - foreach (const QString& trig, triggers) + for (const QString& trig : triggers) triggersTree.childs << getTreeLeaf(trig); if (printColumns) @@ -111,7 +111,7 @@ AsciiTree CliCommandTree::getViewTree(const QString& database, const QString& vi AsciiTree triggersTree; triggersTree.label = metaNodeNameTemplate.arg(tr("Triggers")); - foreach (const QString& trig, triggers) + for (const QString& trig : triggers) triggersTree.childs << getTreeLeaf(trig); tree.label = view; diff --git a/SQLiteStudio3/sqlitestudiocli/main.cpp b/SQLiteStudio3/sqlitestudiocli/main.cpp index eb7a46e..7a126e3 100644 --- a/SQLiteStudio3/sqlitestudiocli/main.cpp +++ b/SQLiteStudio3/sqlitestudiocli/main.cpp @@ -52,13 +52,6 @@ QString cliHandleCmdLineArgs() int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); - -#ifdef PORTABLE_CONFIG - int retCode = 1; - if (UpdateManager::handleUpdateOptions(a.arguments(), retCode)) - return retCode; -#endif - QCoreApplication::setApplicationName("SQLiteStudio"); QCoreApplication::setApplicationVersion(SQLITESTUDIO->getVersionString()); diff --git a/SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.pro b/SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.pro index 9e402d5..6583172 100644 --- a/SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.pro +++ b/SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.pro @@ -27,7 +27,12 @@ linux { } } -TRANSLATIONS += translations/sqlitestudiocli_de.ts \ +portable { + DEFINES += PORTABLE_CONFIG +} + +TRANSLATIONS += translations/sqlitestudiocli_ro_RO.ts \ + translations/sqlitestudiocli_de.ts \ translations/sqlitestudiocli_it.ts \ translations/sqlitestudiocli_zh_CN.ts \ translations/sqlitestudiocli_sk.ts \ @@ -128,3 +133,4 @@ RESOURCES += \ + diff --git a/SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.qrc b/SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.qrc index 025053f..613e5bf 100644 --- a/SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.qrc +++ b/SQLiteStudio3/sqlitestudiocli/sqlitestudiocli.qrc @@ -1,5 +1,6 @@ + translations/sqlitestudiocli_ro_RO.qm translations/sqlitestudiocli_de.qm @@ -15,3 +16,4 @@ + diff --git a/SQLiteStudio3/sqlitestudiocli/translations/sqlitestudiocli_ro_RO.qm b/SQLiteStudio3/sqlitestudiocli/translations/sqlitestudiocli_ro_RO.qm new file mode 100644 index 0000000..2856eb9 Binary files /dev/null and b/SQLiteStudio3/sqlitestudiocli/translations/sqlitestudiocli_ro_RO.qm differ diff --git a/SQLiteStudio3/sqlitestudiocli/translations/sqlitestudiocli_ro_RO.ts b/SQLiteStudio3/sqlitestudiocli/translations/sqlitestudiocli_ro_RO.ts new file mode 100644 index 0000000..e4821ef --- /dev/null +++ b/SQLiteStudio3/sqlitestudiocli/translations/sqlitestudiocli_ro_RO.ts @@ -0,0 +1,788 @@ + + + + + CLI + + + Current database: %1 + + + + + No current working database is set. + + + + + Type %1 for help + + + + + Database passed in command line parameters (%1) was already on the list under name: %2 + + + + + Could not add database %1 to list. + + + + + closed + + + + + CliCommand + + + Usage: %1%2 + + + + + CliCommandAdd + + + Could not add database %1 to list. + + + + + Database added: %1 + + + + + adds new database to the list + + + + + Adds given database pointed by <path> with given <name> to list the databases list. The <name> is just a symbolic name that you can later refer to. Just pick any unique name. For list of databases already on the list use %1 command. + + + + + name + CLI command syntax + + + + + path + CLI command syntax + + + + + CliCommandCd + + + Changed directory to: %1 + + + + + Could not change directory to: %1 + + + + + changes current working directory + + + + + Very similar command to 'cd' known from Unix systems and Windows. It requires a <path> argument to be passed, therefore calling %1 will always cause a change of the directory. To learn what's the current working directory use %2 command and to list contents of the current working directory use %3 command. + + + + + path + CLI command syntax + + + + + CliCommandClose + + + Cannot call %1 when no database is set to be current. Specify current database with %2 command or pass database name to %3. + + + + + + Connection to database %1 closed. + + + + + No such database: %1. Use %2 to see list of known databases. + + + + + closes given (or current) database + + + + + Closes database connection. If the database was already closed, nothing happens. If <name> is provided, it should be name of the database to close (as printed by %1 command). The the <name> is not provided, then current working database is closed (see help for %2 for details). + + + + + name + CLI command syntax + + + + + CliCommandDbList + + + No current working database defined. + + + + + Databases: + + + + + + Name + CLI db name column + + + + + + Open + CLI connection state column + + + + + + Closed + CLI connection state column + + + + + + Connection + CLI connection state column + + + + + + Database file path + + + + + prints list of registered databases + + + + + Prints list of databases registered in the SQLiteStudio. Each database on the list can be in open or closed state and %1 tells you that. The current working database (aka default database) is also marked on the list with '*' at the start of its name. See help for %2 command to learn about the default database. + + + + + CliCommandDesc + + + No working database is set. +Call %1 command to set working database. +Call %2 to see list of all databases. + + + + + Database is not open. + + + + + Cannot find table named: %1 + + + + + shows details about the table + + + + + table + + + + + Table: %1 + + + + + Column name + + + + + Data type + + + + + Constraints + + + + + Virtual table: %1 + + + + + Construction arguments: + + + + + No construction arguments were passed for this virtual table. + + + + + CliCommandDir + + + lists directories and files in current working directory + + + + + This is very similar to 'dir' command known from Windows and 'ls' command from Unix systems. + +You can pass <pattern> with wildcard characters to filter output. + + + + + pattern + + + + + CliCommandExit + + + quits the application + + + + + Quits the application. Settings are stored in configuration file and will be restored on next startup. + + + + + CliCommandHelp + + + shows this help message + + + + + Use %1 to learn about certain commands supported by the command line interface (CLI) of the SQLiteStudio. +To see list of supported commands, type %2 without any arguments. + +When passing <command> name, you can skip special prefix character ('%3'). + +You can always execute any command with exactly single '--help' option to see help for that command. It's an alternative for typing: %1 <command>. + + + + + command + CLI command syntax + + + + + No such command: %1 + + + + + Type '%1' for list of available commands. + + + + + Usage: %1%2 + + + + + Aliases: %1 + + + + + CliCommandHistory + + + Current history limit is set to: %1 + + + + + prints history or erases it + + + + + When no argument was passed, this command prints command line history. Every history entry is separated with a horizontal line, so multiline entries are easier to read. + +When the -c or --clear option is passed, then the history gets erased. +When the -l or --limit option is passed, it sets the new history entries limit. It requires an additional argument saying how many entries do you want the history to be limited to. +Use -ql or --querylimit option to see the current limit value. + + + + + number + + + + + Console history erased. + + + + + Invalid number: %1 + + + + + History limit set to %1 + + + + + CliCommandMode + + + Current results printing mode: %1 + + + + + Invalid results printing mode: %1 + + + + + New results printing mode: %1 + + + + + tells or changes the query results format + + + + + When called without argument, tells the current output format for a query results. When the <mode> is passed, the mode is changed to the given one. Supported modes are: +- CLASSIC - columns are separated by a comma, not aligned, +- FIXED - columns have equal and fixed width, they always fit into terminal window width, but the data in columns can be cut off, +- COLUMNS - like FIXED, but smarter (do not use with huge result sets, see details below), +- ROW - each column from the row is displayed in new line, so the full data is displayed. + +The CLASSIC mode is recommended if you want to see all the data, but you don't want to waste lines for each column. Each row will display full data for every column, but this also means, that columns will not be aligned to each other in next rows. The CLASSIC mode also doesn't respect the width of your terminal (console) window, so if values in columns are wider than the window, the row will be continued in next lines. + +The FIXED mode is recommended if you want a readable output and you don't care about long data values. Columns will be aligned, making the output a nice table. The width of columns is calculated from width of the console window and a number of columns. + +The COLUMNS mode is similar to FIXED mode, except it tries to be smart and make columns with shorter values more thin, while columns with longer values get more space. First to shrink are columns with longest headers (so the header names are to be cut off as first), then columns with the longest values are shrinked, up to the moment when all columns fit into terminal window. +ATTENTION! The COLUMNS mode reads all the results from the query at once in order to evaluate column widhts, therefore it is dangerous to use this mode when working with huge result sets. Keep in mind that this mode will load entire result set into memory. + +The ROW mode is recommended if you need to see whole values and you don't expect many rows to be displayed, because this mode displays a line of output per each column, so you'll get 10 lines for single row with 10 columns, then if you have 10 of such rows, you will get 100 lines of output (+1 extra line per each row, to separate rows from each other). + + + + + CliCommandNullValue + + + Current NULL representation string: %1 + + + + + tells or changes the NULL representation string + + + + + If no argument was passed, it tells what's the current NULL value representation (that is - what is printed in place of NULL values in query results). If the argument is given, then it's used as a new string to be used for NULL representation. + + + + + CliCommandOpen + + + Cannot call %1 when no database is set to be current. Specify current database with %2 command or pass database name to %3. + + + + + Could not add database %1 to list. + + + + + File %1 doesn't exist in %2. Cannot open inexisting database with %3 command. To create a new database, use %4 command. + + + + + Database %1 has been open and set as the current working database. + + + + + opens database connection + + + + + Opens connection to the database. If no additional argument was passed, then the connection is open to the current default database (see help for %1 for details). However if an argument was passed, it can be either <name> of the registered database to open, or it can be <path> to the database file to open. In the second case, the <path> gets registered on the list with a generated name, but only for the period of current application session. After restarting application such database is not restored on the list. + + + + + name + CLI command syntax + + + + + path + CLI command syntax + + + + + CliCommandPwd + + + prints the current working directory + + + + + This is the same as 'pwd' command on Unix systems and 'cd' command without arguments on Windows. It prints current working directory. You can change the current working directory with %1 command and you can also list contents of the current working directory with %2 command. + + + + + CliCommandRemove + + + No such database: %1 + + + + + Database removed: %1 + + + + + New current database set: + + + + + removes database from the list + + + + + Removes <name> database from the list of registered databases. If the database was not on the list (see %1 command), then error message is printed and nothing more happens. + + + + + name + CLI command syntax + + + + + CliCommandSql + + + No working database is set. +Call %1 command to set working database. +Call %2 to see list of all databases. + + + + + Database is not open. + + + + + executes SQL query + + + + + This command is executed every time you enter SQL query in command prompt. It executes the query on the current working database (see help for %1 for details). There's no sense in executing this command explicitly. Instead just type the SQL query in the command prompt, without any command prefixed. + + + + + sql + CLI command syntax + + + + + + Too many columns to display in %1 mode. + + + + + Row %1 + + + + + Query execution error: %1 + + + + + CliCommandTables + + + No such database: %1. Use %2 to see list of known databases. + + + + + Cannot call %1 when no database is set to be current. Specify current database with %2 command or pass database name to %3. + + + + + Database %1 is closed. + + + + + + Database + + + + + Table + + + + + prints list of tables in the database + + + + + Prints list of tables in given <database> or in the current working database. Note, that the <database> should be the name of the registered database (see %1). The output list includes all tables from any other databases attached to the queried database. +When the -s option is given, then system tables are also listed. + + + + + database + CLI command syntax + + + + + CliCommandTree + + + No current working database is selected. Use %1 to define one and then run %2. + + + + + Tables + + + + + Views + + + + + Columns + + + + + Indexes + + + + + + Triggers + + + + + prints all objects in the database as a tree + + + + + Prints all objects (tables, indexes, triggers and views) that are in the database as a tree. The tree is very similar to the one that you can see in GUI client of the SQLiteStudio. +When -c option is given, then also columns will be listed under each table. +When -s option is given, then also system objects will be printed (sqlite_* tables, autoincrement indexes, etc). +The database argument is optional and if provided, then only given database will be printed. This is not a registered database name, but instead it's an internal SQLite database name, like 'main', 'temp', or any attached database name. To print tree for other registered database, call %1 first to switch the working database, and then use %2 command. + + + + + CliCommandUse + + + No current database selected. + + + + + + Current database: %1 + + + + + No such database: %1 + + + + + changes default working database + + + + + Changes current working database to <name>. If the <name> database is not registered in the application, then the error message is printed and no change is made. + +What is current working database? +When you type a SQL query to be executed, it is executed on the default database, which is also known as the current working database. Most of database-related commands can also work using default database, if no database was provided in their arguments. The current database is always identified by command line prompt. The default database is always defined (unless there is no database on the list at all). + +The default database can be selected in various ways: +- using %1 command, +- by passing database file name to the application startup parameters, +- by passing registered database name to the application startup parameters, +- by restoring previously selected default database from saved configuration, +- or when default database was not selected by any of the above, then first database from the registered databases list becomes the default one. + + + + + name + CLI command syntax + + + + + QObject + + + Insufficient number of arguments. + + + + + Too many arguments. + + + + + Invalid argument value: %1. +Expected one of: %2 + + + + + Unknown option: %1 + CLI command syntax + + + + + Option %1 requires an argument. + CLI command syntax + + + + + string + CLI command syntax + + + + + Command line interface to SQLiteStudio, a SQLite manager. + + + + + Enables debug messages on standard error output. + + + + + Enables Lemon parser debug messages for SQL code assistant. + + + + + Lists plugins installed in the SQLiteStudio and quits. + + + + + file + + + + + Database file to open + + + + -- cgit v1.2.3