Skip to content

CreateTableTranslator silently drops AS SELECT from CREATE TABLE t (cols) AS SELECT ... #91

Description

@erans

Found while working on #86 / #90. Pre-existing and independent of --hide-internal-tables — it reproduces with the flag off.

Problem

CREATE_TABLE_REGEX (src/translator/create_table_translator.rs:10-13) is

(?is)CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"|(\w+))\s*\((.*)\)

and translate_with_connection rebuilds the statement from capture group 3 alone (:90):

let sqlite_sql = format!("CREATE TABLE {} ({})", table_name_for_output, final_columns);

For a PostgreSQL-style CTAS carrying an explicit column list, group 3 captures only the column definitions and the AS SELECT tail is discarded:

Input Group 3 Rebuilt
CREATE TABLE t (name TEXT) AS SELECT name FROM src name TEXT CREATE TABLE t (name TEXT)
CREATE TABLE t AS SELECT name FROM src no match passed through unchanged (correct)

So the client gets a success response and an empty table. No error, no warning. The plain CTAS form is unaffected because the regex requires ( right after the table name.

CREATE TABLE t (a, b) AS SELECT ... is valid PostgreSQL, so a PostgreSQL client has every reason to send it.

Reproduction

CREATE TABLE src (name TEXT);
INSERT INTO src VALUES ('alice');
CREATE TABLE snap (name TEXT) AS SELECT name FROM src;
SELECT count(*) FROM snap;  -- 0, expected 1

Note for whoever fixes this

tests/sqlite_master_filter_enabled_test.rs has ctas_with_explicit_column_list_never_leaks_internal_prefix, added in #90. Its "no __pgsqlite_ rows" assertion currently passes vacuously in the success branch, because this bug leaves the table empty so there are no rows to inspect. Once this is fixed, that test should be strengthened to assert the expected rows actually land.

Related: #90 works around the interaction by skipping the sqlite_master rewrite when a CTAS carries an explicit column list (src/translator/sqlite_master_filter.rs), because the injected subquery's parens extended the greedy capture into malformed SQL. That guard can be revisited once the regex is fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions