Support column references in table-valued function arguments

This change extends table-valued function support by allowing arguments
to be column references, not only literals.

Virtual tables can now reject a plan by returning an error from
best_index (e.g., when a TVF argument references a table that appears
later in the join order). The planner using this information excludes
invalid plans during join order search.
This commit is contained in:
Piotr Rzysko
2025-08-03 09:46:02 +02:00
parent 82491ceb6a
commit 99f87c07c1
10 changed files with 172 additions and 59 deletions

View File

@@ -381,6 +381,56 @@ def _test_series(limbo: TestTursoShell):
"SELECT * FROM target;",
lambda res: res == "1\n2\n3\n4\n5",
)
limbo.run_test_fn(
"SELECT t.id, series.value FROM target t, generate_series(t.id, 3) series;",
lambda res: res == "1|1\n1|2\n1|3\n2|2\n2|3\n3|3",
"Column reference from table on the left used as generate_series argument"
)
limbo.run_test_fn(
"SELECT t.id, series.value FROM generate_series(t.id, 3) series, target t;",
lambda res: res == "1|1\n1|2\n1|3\n2|2\n2|3\n3|3",
"Column reference from table on the right used as generate_series argument"
)
limbo.run_test_fn(
"SELECT one.value, series.value FROM (SELECT 1 AS value) one, generate_series(one.value, 3) series;",
lambda res: res == "1|1\n1|2\n1|3",
"Column reference from scalar subquery (left side)"
)
limbo.run_test_fn(
"SELECT one.value, series.value FROM generate_series(one.value, 3) series, (SELECT 1 AS value) one;",
lambda res: res == "1|1\n1|2\n1|3",
"Column reference from scalar subquery (right side)"
)
limbo.run_test_fn(
"SELECT "
" * "
"FROM "
" generate_series(a.start, a.stop) series "
"NATURAL JOIN "
" (SELECT 1 AS start, 3 AS stop, 2 AS value) a;",
lambda res: res == "2|1|3",
"Natural join where TVF arguments come from column references"
)
limbo.run_test_fn(
"SELECT * FROM generate_series(a.start, a.stop) JOIN (SELECT 1 AS start, 3 AS stop) a USING (start, stop);",
lambda res: res == "1\n2\n3",
"Join USING where TVF arguments come from column references"
)
limbo.run_test_fn(
"SELECT a.value, b.value FROM generate_series(b.value, b.value+1) a JOIN generate_series(1, 2) b;",
lambda res: res == "1|1\n2|1\n2|2\n3|2",
"TVF arguments come from another TVF"
)
limbo.run_test_fn(
"SELECT * FROM generate_series(a.start, a.stop) b, generate_series(b.start, b.stop) a;",
lambda res: "No valid query plan found" in res or "no query solution" in res,
"circular column references between two generate_series"
)
limbo.run_test_fn(
"SELECT * FROM generate_series(b.start, b.stop) b;",
lambda res: "Invalid Argument" in res or 'first argument to "generate_series()" missing or unusable' in res,
"self-reference in generate_series arguments"
)
limbo.quit()