aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2015-01-30 17:00:24 -0500
committerLibravatarUnit 193 <unit193@ubuntu.com>2015-01-30 17:00:24 -0500
commite4767514ed04e6a0bddf3f4a47f5f0b09e65e0ee (patch)
tree86cadc2137831d44fa29fd40a2964f7fb1326de4 /SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
parent26ddfe11c2b7fac52e5f57dcd9f5223a50b2a9a7 (diff)
parent016003905ca0e8e459e3dc33e786beda8ec92f45 (diff)
Merge tag 'upstream/3.0.2'
Upstream version 3.0.2 # gpg: Signature made Fri 30 Jan 2015 05:00:11 PM EST using RSA key ID EBE9BD91 # gpg: Good signature from "Unit 193 <unit193@gmail.com>" # gpg: aka "Unit 193 <unit193@ninthfloor.org>" # gpg: aka "Unit 193 <unit193@ubuntu.com>"
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp')
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp245
1 files changed, 159 insertions, 86 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
index 3d7090a..4f402b2 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
@@ -1,9 +1,9 @@
#include "columndefaultpanel.h"
#include "ui_columndefaultpanel.h"
-#include "parser/ast/sqlitecreatetable.h"
#include "parser/parser.h"
#include "parser/keywords.h"
#include "uiutils.h"
+#include "schemaresolver.h"
#include <QDebug>
ColumnDefaultPanel::ColumnDefaultPanel(QWidget *parent) :
@@ -34,6 +34,22 @@ void ColumnDefaultPanel::changeEvent(QEvent *e)
bool ColumnDefaultPanel::validate()
{
+ if (!ui->exprEdit->isSyntaxChecked())
+ {
+ setValidState(ui->exprEdit, false, tr("Enter a default value expression."));
+ currentMode = Mode::ERROR;
+ return false;
+ }
+
+ // First check if we already validated this text.
+ // This method is called twice, by both errors checking and syntax highlighting,
+ // because signal for textChange() is connected with call to updateValidation().
+ QString text = ui->exprEdit->toPlainText();
+ if (!lastValidatedText.isNull() && lastValidatedText == text)
+ return lastValidationResult;
+
+ lastValidatedText = text;
+
bool nameOk = true;
if (ui->namedCheck->isChecked() && ui->namedEdit->text().isEmpty())
nameOk = false;
@@ -41,12 +57,40 @@ bool ColumnDefaultPanel::validate()
bool exprOk = !ui->exprEdit->toPlainText().trimmed().isEmpty() &&
!ui->exprEdit->haveErrors();
- bool exprCheckedOk = exprOk && ui->exprEdit->isSyntaxChecked();
+ QString exprError;
+ 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;");
+
+ QString tableName = getTempTable();
+ QString tempDdl = tempDdlExprTpl.arg(tableName, ui->exprEdit->toPlainText());
+ SqlQueryPtr res = db->exec(tempDdl);
+ if (res->isError())
+ {
+ tempDdl = tempDdlLiteralTpl.arg(tableName, ui->exprEdit->toPlainText());
+ res = db->exec(tempDdl);
+ if (res->isError())
+ {
+ exprOk = false;
+ exprError = tr("Invalid default value expression: %1").arg(res->getErrorText());
+ }
+ else
+ currentMode = Mode::LITERAL;
+ }
+ else
+ currentMode = Mode::EXPR;
+
+ db->exec(dropTempDdl.arg(tableName));
+ }
- setValidState(ui->exprEdit, exprOk, tr("Enter a default value expression."));
+ setValidState(ui->exprEdit, exprOk, exprError);
setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint."));
- return exprCheckedOk && nameOk;
+ lastValidationResult = (exprOk && nameOk);
+ return lastValidationResult;
}
bool ColumnDefaultPanel::validateOnly()
@@ -69,18 +113,99 @@ void ColumnDefaultPanel::storeConfiguration()
if (constraint.isNull())
return;
+ if (currentMode == Mode::ERROR)
+ {
+ qCritical() << "Call to ColumnDefaultPanel::storeConfiguration() while its mode is in ERROR state.";
+ return;
+ }
+
SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data());
constr->type = SqliteCreateTable::Column::Constraint::DEFAULT;
- SqliteExprPtr expr = parseExpression(ui->exprEdit->toPlainText());
- SqliteExpr* newExpr = new SqliteExpr(*expr.data());
- newExpr->setParent(constraint.data());
- constr->expr = newExpr;
+ switch (currentMode)
+ {
+ case Mode::EXPR:
+ storeExpr(constr);
+ break;
+ case Mode::LITERAL:
+ storeLiteral(constr);
+ break;
+ case Mode::ERROR:
+ return;
+ }
if (ui->namedCheck->isChecked())
constr->name = ui->namedEdit->text();
}
+void ColumnDefaultPanel::storeExpr(SqliteCreateTable::Column::Constraint* constr)
+{
+ QString text = ui->exprEdit->toPlainText();
+ clearDefault(constr);
+ if (text.toUpper() == "NULL")
+ {
+ // We will just use literal null, no need to create expression with null.
+ constr->literalNull = true;
+ return;
+ }
+
+ Parser parser(db->getDialect());
+ SqliteExpr* newExpr = parser.parseExpr(text);
+ newExpr->setParent(constraint.data());
+ constr->expr = newExpr;
+}
+
+void ColumnDefaultPanel::storeLiteral(SqliteCreateTable::Column::Constraint* constr)
+{
+ QString text = ui->exprEdit->toPlainText();
+
+ Parser parser(db->getDialect());
+ SqliteCreateTablePtr createTable = parser.parse<SqliteCreateTable>("CREATE TABLE tab (col DEFAULT "+text+");");
+ if (!createTable || createTable->columns.size() == 0 || createTable->columns.first()->constraints.size() == 0)
+ {
+ qCritical() << "ColumnDefaultPanel::storeLiteral(): create table not parsed! Cannot store literal. Expression was:" << text;
+ return;
+ }
+
+ SqliteCreateTable::Column::Constraint* parsedConstr = createTable->columns.first()->constraints.first();
+ if (parsedConstr->type != SqliteCreateTable::Column::Constraint::Type::DEFAULT)
+ {
+ qCritical() << "ColumnDefaultPanel::storeLiteral(): parsed constraint not a DEFAULT! Cannot store literal. Expression was:" << text;
+ return;
+ }
+
+ clearDefault(constr);
+ if (!parsedConstr->id.isNull())
+ constr->id = parsedConstr->id;
+ else if (!parsedConstr->ctime.isNull())
+ constr->ctime = parsedConstr->ctime.toUpper();
+ else if (parsedConstr->expr)
+ {
+ qWarning() << "ColumnDefaultPanel::storeLiteral(): parsed constraint turned out to be an expression. This should be handled by ColumnDefaultPanel::storeExpr."
+ << "Expression was:" << text;
+ constr->expr = parsedConstr->expr;
+ parsedConstr->expr = nullptr;
+ constr->expr->setParent(constr);
+ }
+ else if (parsedConstr->literalNull)
+ constr->literalNull = true;
+ else
+ constr->literalValue = parsedConstr->literalValue;
+}
+
+void ColumnDefaultPanel::clearDefault(SqliteCreateTable::Column::Constraint* constr)
+{
+ if (constr->expr)
+ {
+ delete constr->expr;
+ constr->expr = nullptr;
+ }
+ constr->literalNull = false;
+ constr->literalValue = QVariant();
+ constr->id = QString();
+ constr->ctime = QString();
+}
+
void ColumnDefaultPanel::init()
{
setFocusProxy(ui->exprEdit);
@@ -101,101 +226,49 @@ void ColumnDefaultPanel::readConstraint()
SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data());
if (constr->expr)
+ {
ui->exprEdit->setPlainText(constr->expr->detokenize());
+ currentMode = Mode::EXPR;
+ }
else if (!constr->literalValue.isNull())
- ui->exprEdit->setPlainText(constr->literalValue.toString());
-
- if (!constr->name.isNull())
{
- ui->namedCheck->setChecked(true);
- ui->namedEdit->setText(constr->name);
+ ui->exprEdit->setPlainText(constr->literalValue.toString());
+ currentMode = Mode::LITERAL;
}
-}
-
-void ColumnDefaultPanel::updateVirtualSql()
-{
- ui->exprEdit->setDb(db);
-
- SqliteCreateTable::Column* column = dynamic_cast<SqliteCreateTable::Column*>(constraint->parentStatement());
- SqliteCreateTable* createTable = dynamic_cast<SqliteCreateTable*>(column->parentStatement());
-
- createTable->rebuildTokens();
- TokenList tokens = createTable->tokens;
- TokenList colTokens = column->tokens;
- if (createTable->columns.indexOf(column) == -1)
+ else if (!constr->id.isNull())
{
- if (createTable->columns.size() == 0)
- {
- // No columns. Cannot get any context info.
- return;
- }
-
- colTokens = createTable->columns.last()->tokens;
+ ui->exprEdit->setPlainText(constr->id);
+ currentMode = Mode::LITERAL;
}
-
- if (colTokens.size() == 0)
+ else if (!constr->ctime.isNull())
{
- qWarning() << "CREATE TABLE tokens are invalid (0) while call to ColumnDefaultPanel::updateVirtualSql().";
- return;
+ ui->exprEdit->setPlainText(constr->ctime);
+ currentMode = Mode::LITERAL;
}
-
- int idx = tokens.lastIndexOf(colTokens.last());
- if (idx == -1)
+ else if (constr->literalNull)
{
- qWarning() << "CREATE TABLE tokens are invalid while call to ColumnDefaultPanel::updateVirtualSql().";
- return;
+ ui->exprEdit->setPlainText("NULL");
+ currentMode = Mode::LITERAL;
}
- idx++;
-
- TokenList newTokens;
- newTokens << TokenPtr::create(Token::SPACE, " ")
- << TokenPtr::create(Token::KEYWORD, "DEFAULT")
- << TokenPtr::create(Token::SPACE, " ");
- if (constraint->dialect == Dialect::Sqlite3)
- {
- newTokens << TokenPtr::create(Token::PAR_LEFT, "(")
- << TokenPtr::create(Token::OTHER, "%1")
- << TokenPtr::create(Token::PAR_RIGHT, ")");
- }
- else
+ if (!constr->name.isNull())
{
- newTokens << TokenPtr::create(Token::OTHER, "%1");
+ ui->namedCheck->setChecked(true);
+ ui->namedEdit->setText(constr->name);
}
-
- tokens.insert(idx, newTokens);
- QString sql = tokens.detokenize();
-
- ui->exprEdit->setVirtualSqlExpression(sql);
}
-SqliteExprPtr ColumnDefaultPanel::parseExpression(const QString& sql)
+void ColumnDefaultPanel::updateVirtualSql()
{
- Parser parser(db->getDialect());
- if (!parser.parse("SELECT "+sql))
- return SqliteExprPtr();
-
- QList<SqliteQueryPtr> queries = parser.getQueries();
- if (queries.size() == 0)
- return SqliteExprPtr();
-
- SqliteQueryPtr first = queries.first();
- if (first->queryType != SqliteQueryType::Select)
- return SqliteExprPtr();
-
- SqliteSelectPtr select = first.dynamicCast<SqliteSelect>();
- if (select->coreSelects.size() < 1)
- return SqliteExprPtr();
-
- SqliteSelect::Core* core = select->coreSelects.first();
- if (core->resultColumns.size() < 1)
- return SqliteExprPtr();
-
- SqliteSelect::Core::ResultColumn* resCol = core->resultColumns.first();
- if (!resCol->expr)
- return SqliteExprPtr();
+ static QString sql = QStringLiteral("CREATE TABLE tab (col DEFAULT %1)");
+ ui->exprEdit->setDb(db);
+ ui->exprEdit->setVirtualSqlExpression(sql.arg(db->getDialect() == Dialect::Sqlite3 ? "(%1)" : "%1"));
+}
- return resCol->expr->detach().dynamicCast<SqliteExpr>();
+QString ColumnDefaultPanel::getTempTable()
+{
+ SchemaResolver resolver(db);
+ return resolver.getUniqueName("temp", "sqlitestudio_temp_table");
}
void ColumnDefaultPanel::updateState()