Quellcode durchsuchen

LibSQL: Gracefully react to unimplemented valid SQL

Fixes a crash that was caused by a syntax error which is difficult to
catch by the parser: usually identifiers are accepted in column lists,
but they are not in a list of column values to be inserted in an INSERT.

Fixed this by putting in a heuristic check; we probably need a better
way to do this.

Included tests for this case.

Also introduced a new SQL Error code, `NotYetImplemented`, and return
that instead of crashing when encountering unimplemented SQL.
Jan de Visser vor 3 Jahren
Ursprung
Commit
c369626ac1

+ 22 - 0
Tests/LibSQL/TestSqlStatementExecution.cpp

@@ -137,6 +137,28 @@ TEST_CASE(insert_wrong_number_of_values)
     EXPECT(result->inserted() == 0);
 }
 
+TEST_CASE(insert_identifier_as_value)
+{
+    ScopeGuard guard([]() { unlink(db_name); });
+    auto database = SQL::Database::construct(db_name);
+    EXPECT(!database->open().is_error());
+    create_table(database);
+    auto result = execute(database, "INSERT INTO TestSchema.TestTable VALUES ( identifier, 42 );");
+    EXPECT(result->error().code == SQL::SQLErrorCode::SyntaxError);
+    EXPECT(result->inserted() == 0);
+}
+
+TEST_CASE(insert_quoted_identifier_as_value)
+{
+    ScopeGuard guard([]() { unlink(db_name); });
+    auto database = SQL::Database::construct(db_name);
+    EXPECT(!database->open().is_error());
+    create_table(database);
+    auto result = execute(database, "INSERT INTO TestSchema.TestTable VALUES ( \"QuotedIdentifier\", 42 );");
+    EXPECT(result->error().code == SQL::SQLErrorCode::SyntaxError);
+    EXPECT(result->inserted() == 0);
+}
+
 TEST_CASE(insert_without_column_names)
 {
     ScopeGuard guard([]() { unlink(db_name); });

+ 4 - 0
Userland/Libraries/LibSQL/AST/Expression.cpp

@@ -169,6 +169,10 @@ Value UnaryOperatorExpression::evaluate(ExecutionContext& context) const
 
 Value ColumnNameExpression::evaluate(ExecutionContext& context) const
 {
+    if (!context.current_row) {
+        context.result->set_error(SQLErrorCode::SyntaxError, column_name());
+        return Value::null();
+    }
     auto& descriptor = *context.current_row->descriptor();
     VERIFY(context.current_row->size() == descriptor.size());
     Optional<size_t> index_in_row;