should be it

This commit is contained in:
2025-10-24 19:21:19 -05:00
parent a4b23fc57c
commit f09560c7b1
14047 changed files with 3161551 additions and 1 deletions

View File

@@ -0,0 +1,47 @@
# name: test/sql/catalog/function/attached_macro.test
# description: Call a table function living in a different catalog.
# group: [function]
statement ok
ATTACH ':memory:' AS checksum_macro;
statement ok
CREATE MACRO checksum_macro.checksum(table_name) AS TABLE
SELECT bit_xor(md5_number(COLUMNS(*)::VARCHAR))
FROM query_table(table_name);
# Use 'query_table' with a schema-qualified table name.
statement ok
BEGIN
statement ok
CREATE TABLE tbl AS SELECT UNNEST([42, 43]) AS x;
statement ok
USE checksum_macro;
query I
SELECT * FROM checksum('memory.tbl');
----
60609334165039584609948387465088153270
statement ok
ABORT
# Call a table function that lives in a different catalog
statement ok
BEGIN
statement ok
USE memory;
statement ok
CREATE TABLE tbl AS SELECT UNNEST([42, 43]) AS x;
statement ok
SELECT * FROM checksum_macro.checksum('tbl');
statement ok
ABORT

View File

@@ -0,0 +1,12 @@
# name: test/sql/catalog/function/information_schema_macro.test
# description: Issue #3690: Creating a MACRO in pg_catalog or information_schema causes duckdb to crash
# group: [function]
statement ok
PRAGMA enable_verification
# not allowed
statement error
create macro information_schema.foo(a) as a;
----
<REGEX>:.*Binder Error: Cannot create entry.*

View File

@@ -0,0 +1,35 @@
# name: test/sql/catalog/function/macro_query_table.test
# description: Test using a scalar macro with the query_table function
# group: [function]
statement ok
PRAGMA enable_verification
statement ok
create macro min_from_tbl(tbl, col) as (select min(col) from query_table(tbl::VARCHAR));
statement ok
create table integers as from range(100) t(i)
query I
SELECT min_from_tbl(integers, i)
----
0
# column does not exist
statement error
SELECT min_from_tbl(integers, k)
----
not found in FROM clause
# table does not exist
statement error
SELECT min_from_tbl(integers2, i)
----
Table with name integers2 does not exist
# using a non-scalar parameter is not supported
statement error
SELECT min_from_tbl(tbl_name, i) from (values ('integers')) t(tbl_name);
----
tbl_name

View File

@@ -0,0 +1,159 @@
# name: test/sql/catalog/function/python_style_macro_parameters.test
# description: Test Python-style macro parameters
# group: [function]
statement ok
create or replace macro m(a := 'a', b := 'b') as a || b
query I
select m()
----
ab
# we can supply arguments in any order as long as they are named
query I
select m(b := 'a', a := 'b')
----
ba
query I
select m(a := 'b', b := 'a')
----
ba
query I
select m('c')
----
cb
query I
select m('c', 'd')
----
cd
query I
select m('c', b := 'd')
----
cd
# 'a' is already supplied as positional, so cannot be used as named
statement error
select m('c', a:= 'd')
----
does not support the supplied arguments
statement error
select m('c', 'd', b := 'e')
----
does not support the supplied arguments
# now without default arguments
statement ok
create or replace macro m(a, b) as a || b
statement error
select m()
----
does not support the supplied arguments
query I
select m(b := 'a', a := 'b')
----
ba
query I
select m(a := 'b', b := 'a')
----
ba
statement error
select m('c')
----
does not support the supplied arguments
query I
select m('c', 'd')
----
cd
query I
select m('c', b := 'd')
----
cd
# replicate tests above but with a table macro
statement ok
create or replace macro m(a := 'a', b := 'b') as table (select a || b)
query I
select * from m()
----
ab
query I
select * from m(b := 'a', a := 'b')
----
ba
query I
select * from m(a := 'b', b := 'a')
----
ba
query I
select * from m('c')
----
cb
query I
select * from m('c', 'd')
----
cd
query I
select * from m('c', b := 'd')
----
cd
statement error
select * from m('c', a:= 'd')
----
does not support the supplied arguments
statement error
select * from m('c', 'd', b := 'e')
----
does not support the supplied arguments
statement ok
create or replace macro m(a, b) as table (select a || b)
statement error
select * from m()
----
does not support the supplied arguments
query I
select * from m(b := 'a', a := 'b')
----
ba
query I
select * from m(a := 'b', b := 'a')
----
ba
statement error
select * from m('c')
----
does not support the supplied arguments
query I
select * from m('c', 'd')
----
cd
query I
select * from m('c', b := 'd')
----
cd

View File

@@ -0,0 +1,304 @@
# name: test/sql/catalog/function/query_function.test
# description: test query() function
# group: [function]
statement ok
PRAGMA enable_verification
query I
SELECT * FROM query('SELECT 42');
----
42
query I
FROM query('SELECT 42 AS a');
----
42
query I
FROM query('SELECT 10 + 32;');
----
42
query I
FROM query('SELECT abs(-42)');
----
42
query I
SELECT * FROM query('SELECT * FROM (SELECT 1 + 2)');
----
3
query III
FROM query('SELECT 1, 2, 3');
----
1 2 3
query I
FROM query('SELECT 42;;;--- hello;');
----
42
# query text
query I
SELECT * FROM query('SELECT ''hello''');
----
hello
# query a table
statement ok
CREATE TABLE tbl (a INT, b INT, c INT);
statement ok
FROM query('SELECT *, 1 + 2 FROM tbl');
statement ok
INSERT INTO tbl VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9);
query III
SELECT * FROM query('FROM tbl');
----
1 2 3
4 5 6
7 8 9
query I
SELECT * FROM query('SELECT a + b + c FROM tbl');
----
6
15
24
# query multiple nested type tags
query II
SELECT * FROM query('WITH a(i) AS (SELECT 1) SELECT a1.i AS i1, a2.i AS i2 FROM a AS a1, a AS a2');
----
1 1
# test incorrect usage
statement error
SELECT * FROM query(NULL);
----
<REGEX>:Parser Error.*NULL.*
statement error
SELECT * FROM query(' ');
----
Parser Error: Expected a single SELECT statement
statement error
SELECT * FROM query('');
----
Parser Error: Expected a single SELECT statement
statement error
SELECT * FROM query('FROM query(FROM)');
----
Parser Error: syntax error at or near "FROM"
# multiple statements are not supported
statement error
SELECT * FROM query('SELECT 1; SELECT 2');
----
Parser Error: Expected a single SELECT statement
# invalid input
statement error
SELECT query(SELECT 1);
----
Parser Error: syntax error at or near "SELECT"
statement error
SELECT * FROM query('CREATE TABLE tbl (a INT)');
----
Parser Error: Expected a single SELECT statement
# test PIVOT statements in query() function
query I
SELECT * FROM query('SELECT * FROM (PIVOT (SELECT 1 AS col) ON col IN (1) using first(col))');
----
1
# PIVOT without explicit IN clause should give helpful error message
statement error
SELECT * FROM query('SELECT * FROM (PIVOT (SELECT 1 AS col) ON col using first(col))');
----
Parser Error: PIVOT statements without explicit IN clauses are not supported in query() function. Please specify the pivot values explicitly, e.g.: PIVOT ... ON col IN (val1, val2, ...)
# test query_table()
statement ok
CREATE TABLE tbl_int AS SELECT 42;
statement ok
CREATE TABLE tbl_varchar AS SELECT 'duckdb';
statement ok
CREATE TABLE tbl2_varchar AS SELECT '1?ch@racter$';
statement ok
CREATE TABLE tbl_empty AS SELECT '';
query I
FROM query_table('tbl_int');
----
42
query I
FROM query_table(['tbl_int']);
----
42
query III
FROM query_table(tbl);
----
1 2 3
4 5 6
7 8 9
statement ok
CREATE TABLE tbl2 (a INT, b INT, c INT);
statement ok
INSERT INTO tbl2 VALUES (9, 8, 7), (6, 5, 4), (3, 2, 1);
query III
FROM query_table([tbl, tbl2]);
----
1 2 3
4 5 6
7 8 9
9 8 7
6 5 4
3 2 1
# test incorrect usage
statement error
FROM query_table();
----
No function matches the given name and argument types 'query_table()'.
statement error
FROM query_table(NULL);
----
<REGEX>:.*Cannot use NULL.*
statement error
FROM query_table([]);
----
Binder Error: No function matches the given name and argument types 'query_table(INTEGER[])'.
statement error
FROM query_table(['']);
----
Parser Error: syntax error at end of input
statement error
FROM query_table('tbl_int', 'tbl_varchar', tbl2_varchar);
----
Binder Error: No function matches the given name and argument types 'query_table(VARCHAR, VARCHAR, VARCHAR)'.
statement error
FROM query_table([tbl_int, tbl2]);
----
Binder Error: Set operations can only apply to expressions with the same number of result columns
statement error
FROM query_table(not_defined_tbl);
----
Catalog Error: Table with name not_defined_tbl does not exist!
statement error
FROM query_table('FROM query(''select 1 + 2;'')');
----
Catalog Error: Table with name FROM query('select 1 + 2;') does not exist!
statement error
FROM query_table('FROM query("select 1 + 2;")');
----
Catalog Error: Table with name FROM query(select 1 + 2;) does not exist!
statement error
FROM query_table('(SELECT 17 + 25)');
----
Catalog Error: Table with name (SELECT 17 + 25) does not exist!
# tables with special table names
statement ok
CREATE TABLE "(SELECT 17 + 25)"(i int);
statement ok
insert into "(SELECT 17 + 25)" values (100);
query I
SELECT * FROM "(SELECT 17 + 25)";
----
100
query I
FROM query_table("(SELECT 17 + 25)");
----
100
query I
FROM query_table('(SELECT 17 + 25)');
----
100
statement error
FROM query_table(SELECT 17 + 25);
----
Parser Error: syntax error at or near "SELECT"
statement error
FROM query_table("SELECT 4 + 2");
----
Catalog Error: Table with name SELECT 4 + 2 does not exist!
statement error
FROM query_table('SELECT 4 + 2');
----
Catalog Error: Table with name SELECT 4 + 2 does not exist!
query I
SELECT f.* FROM query_table('tbl_int') as f;
----
42
query I
SELECT f.x FROM query_table('tbl_int') as f(x);
----
42
# test by_name argument
query I
FROM query_table(['tbl_int', 'tbl_varchar', 'tbl_empty', 'tbl2_varchar'], false);
----
42
duckdb
(empty)
1?ch@racter$
query IIII
from query_table([tbl_int, tbl_varchar, tbl_empty, tbl2_varchar], true);
----
42 NULL NULL NULL
NULL duckdb NULL NULL
NULL NULL (empty) NULL
NULL NULL NULL 1?ch@racter$
# test incorrect usage
statement error
FROM query_table(true);
----
Binder Error: No function matches the given name and argument types 'query_table(BOOLEAN)'.
statement error
FROM query_table(tbl2, true);
----
Binder Error: No function matches the given name and argument types 'query_table(VARCHAR, BOOLEAN)'.
statement error
FROM query_table(['tbl_int', 'tbl_varchar', 'tbl_empty', '(select ''I am a subquery'')'], false);
----
Catalog Error: Table with name (select 'I am a subquery') does not exist!

View File

@@ -0,0 +1,28 @@
# name: test/sql/catalog/function/struct_extract_macro.test
# description: Test struct extract on a macro
# group: [function]
statement ok
PRAGMA enable_verification
statement ok
CREATE MACRO my_extract(x) AS x.a.b
query I
SELECT my_extract({'a': {'b': 42}})
----
42
mode skip
# FIXME: this does not work yet due to the way in which macro functions are bound
# as it is not trivial to fix, for now we leave it as is
statement ok
CREATE MACRO my_subquery_extract(x) AS (SELECT x.a.b);
query I
SELECT my_subquery_extract({'a': {'b': 42}})
----
42
mode unskip

View File

@@ -0,0 +1,330 @@
# name: test/sql/catalog/function/test_complex_macro.test
# description: Test Complex Macro
# group: [function]
statement ok
PRAGMA enable_verification
statement ok
CREATE TABLE integers (a INT)
statement ok
INSERT INTO integers VALUES (1)
# cte and subquery
statement ok
CREATE MACRO cte_sq(a,b) AS (WITH cte AS (SELECT a * 2 AS c) SELECT cte.c + sq.d FROM cte, (SELECT b * 3 AS d) AS sq)
query T
SELECT cte_sq(3,4)
----
18
statement ok
CREATE MACRO nested_cte(needle, haystack) AS needle IN (
SELECT i FROM (
WITH ints AS (
SELECT CAST(UNNEST(string_split(haystack,',')) AS INT) AS i
)
SELECT i FROM ints
) AS sq
)
query T
SELECT nested_cte(2, '2,2,2,2')
----
1
statement ok
CREATE MACRO IFELSE(a,b,c) AS CASE WHEN a THEN b ELSE c END
query T
SELECT IFELSE(1, IFELSE(1,'a','b'), 'c')
----
a
query T
SELECT IFELSE(1, IFELSE(0,'a','b'), 'c')
----
b
query T
SELECT IFELSE(0, IFELSE(1,'a','b'), 'c')
----
c
query T
SELECT IFELSE(1, IFELSE(1,a,'b'), 'c') FROM integers
----
1
statement error
SELECT IFELSE(1,IFELSE(1,b,1),a) FROM integers
----
statement ok
CREATE MACRO f1(x) AS (SELECT MIN(a) + x FROM integers)
query I
select f1(42) from integers;
----
43
# macro in GROUP BY
statement ok
CREATE MACRO mod_two(k) AS k%2
query II
SELECT mod_two(a), SUM(a) FROM integers GROUP BY mod_two(a)
----
1 1
# more nested stuff
statement ok
CREATE MACRO add_mac(a, b) AS a + b
statement ok
CREATE MACRO double_add(a, b, c) AS add_mac(add_mac(a, b), c)
query T
SELECT double_add(1, 2, 3)
----
6
statement ok
CREATE MACRO triple_add1(a, b, c, d) AS add_mac(add_mac(a, b), add_mac(c, d))
query T
SELECT triple_add1(1, 2, 3, 4)
----
10
statement ok
CREATE MACRO triple_add2(a, b, c, d) as add_mac(add_mac(add_mac(a, b), c), d)
query T
SELECT triple_add2(1, 2, 3, 4)
----
10
# subquery within macro parameters
statement ok
INSERT INTO integers VALUES (41)
query T
SELECT add((SELECT MIN(a) FROM integers), (SELECT MAX(a) FROM integers))
----
42
# macros within a correlated subquery
query T
SELECT (SELECT MAX(add(i1.a, a)) FROM integers) FROM integers i1
----
42
82
# parameter expression
statement error
CREATE MACRO prep(x) AS ?+1
----
# prepared statements
statement ok
CREATE MACRO add_one(a) AS a + 1
statement ok
PREPARE v1 AS SELECT add_one(?::INTEGER)
query T
EXECUTE v1(1)
----
2
statement ok
CREATE MACRO my_square(a) AS a * a
statement ok
PREPARE v2 AS SELECT my_square(?::INTEGER)
query T
EXECUTE v2(3)
----
9
# test FTS extension use case
statement ok
CREATE TABLE documents(id VARCHAR, body VARCHAR)
statement ok
INSERT INTO documents VALUES ('doc1', ' QUÁCK+QUÁCK+QUÁCK'), ('doc2', ' BÁRK+BÁRK+BÁRK+BÁRK'), ('doc3', ' MÉOW+MÉOW+MÉOW+MÉOW+MÉOW')
statement ok
CREATE SCHEMA fts_main_documents
statement ok
CREATE TABLE fts_main_documents.docs AS (
SELECT
row_number() OVER () AS docid,
id AS name
FROM
main.documents
)
statement ok
CREATE TABLE fts_main_documents.terms AS (
SELECT
term,
docid,
row_number() OVER (PARTITION BY docid) AS pos
FROM (
SELECT
unnest(string_split_regex(regexp_replace(lower(strip_accents(body)), '[^a-z]', ' ', 'g'), '\s+')) AS term,
row_number() OVER () AS docid
FROM main.documents
) AS sq
WHERE
term != ''
)
statement ok
ALTER TABLE fts_main_documents.docs ADD len INT
statement ok
UPDATE fts_main_documents.docs d
SET len = (
SELECT count(term)
FROM fts_main_documents.terms t
WHERE t.docid = d.docid
)
statement ok
CREATE TABLE fts_main_documents.dict AS
WITH distinct_terms AS (
SELECT DISTINCT term, docid
FROM fts_main_documents.terms
ORDER BY docid
)
SELECT
row_number() OVER () AS termid,
term
FROM
distinct_terms
statement ok
ALTER TABLE fts_main_documents.terms ADD termid INT
statement ok
UPDATE fts_main_documents.terms t
SET termid = (
SELECT termid
FROM fts_main_documents.dict d
WHERE t.term = d.term
)
statement ok
ALTER TABLE fts_main_documents.terms DROP term
statement ok
ALTER TABLE fts_main_documents.dict ADD df INT
statement ok
UPDATE fts_main_documents.dict d
SET df = (
SELECT count(distinct docid)
FROM fts_main_documents.terms t
WHERE d.termid = t.termid
GROUP BY termid
)
query II
WITH ppterms AS (
SELECT unnest(string_split_regex(regexp_replace(lower(strip_accents('QUÁCK BÁRK')), '[^a-z]', ' ', 'g'), '\s+')) AS term
), qtermids AS (
SELECT termid
FROM fts_main_documents.dict AS dict
JOIN ppterms
USING (term)
), qterms AS (
SELECT termid,
docid
FROM fts_main_documents.terms AS terms
WHERE termid IN (
SELECT qtermids.termid FROM qtermids
)
), subscores AS (
SELECT docs.docid,
len,
term_tf.termid,
tf,
df,
(log((3 - df + 0.5) / (df + 0.5))* ((tf * (1.2 + 1)/(tf + 1.2 * (1 - 0.75 + 0.75 * (len / 4)))))) AS subscore
FROM (
SELECT termid,
docid,
COUNT(*) AS tf
FROM qterms
GROUP BY docid,
termid
) AS term_tf
JOIN (
SELECT DISTINCT docid
FROM qterms
) AS cdocs
ON term_tf.docid = cdocs.docid
JOIN fts_main_documents.docs AS docs
ON term_tf.docid = docs.docid
JOIN fts_main_documents.dict AS dict
ON term_tf.termid = dict.termid
)
SELECT name,
score
FROM (
SELECT docid,
sum(subscore) AS score
FROM subscores
GROUP BY docid
) AS scores
JOIN fts_main_documents.docs AS docs
ON scores.docid = docs.docid
ORDER BY score DESC
LIMIT 1000
----
doc2 0.37543634550460314
doc1 0.3683526408724408
statement ok
CREATE MACRO fts_match(docname, query_string) AS docname IN (
WITH ppterms AS (SELECT unnest(string_split_regex(regexp_replace(lower(strip_accents(query_string)), '[^a-z]', ' ', 'g'), '\s+')) AS term),
qtermids AS (SELECT termid FROM fts_main_documents.dict AS dict, ppterms WHERE dict.term = ppterms.term),
qterms AS (SELECT termid, docid FROM fts_main_documents.terms AS terms WHERE termid IN (SELECT qtermids.termid FROM qtermids)),
subscores AS (
SELECT docs.docid, len, term_tf.termid,
tf, df, (log((3 - df + 0.5) / (df + 0.5))* ((tf * (1.2 + 1)/(tf + 1.2 * (1 - 0.75 + 0.75 * (len / 4)))))) AS subscore
FROM (SELECT termid, docid, COUNT(*) AS tf FROM qterms
GROUP BY docid, termid) AS term_tf
JOIN (SELECT docid FROM qterms
GROUP BY docid) -- HAVING COUNT(DISTINCT termid) = 3)
AS cdocs ON term_tf.docid = cdocs.docid
JOIN fts_main_documents.docs AS docs ON term_tf.docid = docs.docid
JOIN fts_main_documents.dict AS dict ON term_tf.termid = dict.termid)
SELECT name FROM (SELECT docid, sum(subscore) AS score
FROM subscores GROUP BY docid) AS scores JOIN fts_main_documents.docs AS docs ON
scores.docid = docs.docid ORDER BY score DESC LIMIT 1000)
query II
SELECT * FROM documents WHERE fts_match(id, 'QUÁCK BÁRK')
----
doc1 QUÁCK+QUÁCK+QUÁCK
doc2 BÁRK+BÁRK+BÁRK+BÁRK
# macro with window function
statement ok
CREATE MACRO mywindow(k,v) AS SUM(v) OVER (PARTITION BY k)
query II rowsort
WITH grouped AS (SELECT mod(range, 3) AS grp, range AS val FROM RANGE(500))
SELECT DISTINCT grp, mywindow(grp, val) FROM grouped ORDER BY grp
----
0 41583
1 41750
2 41417

View File

@@ -0,0 +1,14 @@
# name: test/sql/catalog/function/test_cross_catalog_macros.test
# description: Test cross-catalog dependencies in macros
# group: [function]
statement ok
CREATE MACRO my_first_macro() AS (84)
statement ok
CREATE TEMPORARY MACRO my_second_macro() AS my_first_macro() + 42;
query I
SELECT my_second_macro()
----
126

View File

@@ -0,0 +1,92 @@
# name: test/sql/catalog/function/test_cte_macro.test
# description: Test Macro with CTE
# group: [function]
statement ok
PRAGMA enable_verification
statement ok
CREATE TABLE integers (a INT)
statement ok
INSERT INTO integers VALUES (1)
statement ok
CREATE MACRO parameterized_cte(a) AS (WITH cte AS (SELECT a AS answer) SELECT answer FROM cte)
query T
SELECT parameterized_cte(42)
----
42
statement ok
CREATE MACRO in_with_cte(i) AS i IN (WITH cte AS (SELECT a AS answer FROM integers) SELECT answer FROM cte)
query T
SELECT in_with_cte(1)
----
1
query T
SELECT in_with_cte(2)
----
0
statement ok
CREATE MACRO plus42(a) AS (WITH cte AS (SELECT 42 AS answer) SELECT answer + a FROM cte)
query T
SELECT plus42(42)
----
84
query T
SELECT plus42(a) FROM integers
----
43
# macro parameters should be contained within the function call (so 42 + 3 + 1)
query T
SELECT plus42(3) + a FROM integers
----
46
# we should not be able to query the CTE from outside the function call
statement error
SELECT plus42(42) + answer FROM cte;
----
statement ok
CREATE MACRO plus1(a) AS (WITH tbl AS (SELECT 1 AS one) SELECT one + a FROM tbl)
query T
SELECT plus1(3)
----
4
query T
SELECT plus42(a) + plus1(a) FROM integers;
----
45
statement ok
CREATE MACRO deep_cte(param) AS (
WITH cte1 AS (
WITH cte2 AS (
WITH cte3 AS (
WITH cte4 AS (
SELECT param AS d
)
SELECT d AS c FROM cte4
)
SELECT c AS b FROM cte3
)
SELECT b AS a FROM cte2
)
SELECT a FROM cte1
)
query T
SELECT deep_cte(42)
----
42

View File

@@ -0,0 +1,36 @@
# name: test/sql/catalog/function/test_drop_macro.test
# description: Test dropping scalar/table macros
# group: [function]
# create scalar and table macro with same name
statement ok
create macro m() as 42;
statement ok
create macro m() as table (select 42 i);
# table macros are explicitly dropped with "drop macro table"
# however, we also want to support dropping them with drop macro
# we disambiguate by first trying to drop the scalar macro, then the table macro
statement ok
drop macro m;
# scalar macros are dropped first so this fails
statement error
select m();
----
is a table function but it was used as a scalar function
# table macro is still available
query I
from m();
----
42
statement ok
drop macro m;
statement error
from m();
----
with name m does not exist

View File

@@ -0,0 +1,88 @@
# name: test/sql/catalog/function/test_macro_default_arg.test
# group: [function]
statement ok
set storage_compatibility_version='v0.10.2'
statement ok
pragma enable_verification;
statement ok
CREATE MACRO f(x := NULL) AS x+1;
query I
SELECT f();
----
NULL
query I
SELECT f(x := 41)
----
42
query I
SELECT f(x := (SELECT 41));
----
42
query I
select f(x:=(select 1 a));
----
2
query I
select f(x:=a) from (select 41) t(a);
----
42
statement ok
create table t as select 41 a;
query I
select f(x:=a) from t;
----
42
statement error
create macro my_macro1(a, b := a) as a + b;
----
Invalid default value
statement ok
create table integers (a integer);
# this used to be allowed but is no longer (and for good reason)
statement error
create macro my_macro2(a := i) as (
select min(a) from integers
)
----
Invalid default value
statement ok
drop table integers;
statement ok
Create table t1 (a int, b int);
statement ok
Create table t2 (c int, d int);
statement ok
CREATE OR REPLACE MACRO eq(x := NULL, y := NULL) AS x = y
statement ok
INSERT INTO t1 VALUES (1, 1), (1, 2), (2, 2), (3, 4);
statement ok
INSERT INTO t2 VALUES (4, 1), (2, 10), (6, 2), (2, 6);
statement ok
SELECT * FROM t1 as t1_alias inner join (select * from t2) as t2_alias ON (eq(x := t1_alias.a, y := t2_alias.c))
# no default parameters with incorrect names
statement error
SELECT * FROM t1 as t1_alias inner join (select * from t2) as t2_alias ON (eq(a := t1_alias.a, c := t2_alias.c))
----
Binder Error

View File

@@ -0,0 +1,60 @@
# name: test/sql/catalog/function/test_macro_default_arg.test_slow
# group: [function]
statement ok
pragma enable_verification;
# The following tests do not test any behavior related to default arguments,
# other than what expressions can be passed to a parameter with a default argument
statement ok
CREATE MACRO f(x := NULL) AS (
x
)
# Empty
statement ok
select f(
)
# constant
statement ok
select f(
x := 42
)
# column reference
statement ok
create table tbl as select 42 i;
# existing column reference
statement ok
select f(
x := i
) from tbl;
# non-existing column reference
statement error
select f(
x := j
) from tbl;
----
# cast
statement ok
select f(
x := cast('42' as INT)
);
# is null
statement ok
select f(
x := 42 IS NULL
)
# is not null
statement ok
select f(
x := 42 IS NOT NULL
)

View File

@@ -0,0 +1,119 @@
# name: test/sql/catalog/function/test_macro_default_arg_with_dependencies.test
# group: [function]
statement ok
ATTACH '__TEST_DIR__/macro_default_arg.db' (STORAGE_VERSION 'v1.0.0');
statement ok
USE macro_default_arg
statement ok
set enable_macro_dependencies=true
statement ok
pragma enable_verification;
statement ok
CREATE MACRO f(x := NULL) AS x+1;
query I
SELECT f();
----
NULL
query I
SELECT f(x := 41)
----
42
query I
SELECT f(x := (SELECT 41));
----
42
query I
select f(x:=(select 1 a));
----
2
query I
select f(x:=a) from (select 41) t(a);
----
42
statement ok
create table t as select 41 a;
query I
select f(x:=a) from t;
----
42
statement error
create macro my_macro1(a, b := a) as a + b;
----
Invalid default value
statement ok
create table integers (a integer);
# this used to be allowed but is no longer (and for good reason)
statement error
create macro my_macro2(a := i) as (
select min(a) from integers
);
----
Invalid default value
# to test the dependencies we create this macro instead
statement ok
create macro my_macro2(i := 42) as (
select min(a) + i from integers
);
statement ok
insert into integers values (5), (10), (13)
query I
select my_macro2(84)
----
89
statement error
drop table integers;
----
macro function "my_macro2" depends on table "integers".
statement ok
drop table integers cascade;
# The macro was dropped by the CASCADE
statement error
select my_macro2(5);
----
Catalog Error: Scalar Function with name my_macro2 does not exist!
statement ok
Create table t1 (a int, b int);
statement ok
Create table t2 (c int, d int);
statement ok
CREATE OR REPLACE MACRO eq(x := NULL, y := NULL) AS x = y
statement ok
INSERT INTO t1 VALUES (1, 1), (1, 2), (2, 2), (3, 4);
statement ok
INSERT INTO t2 VALUES (4, 1), (2, 10), (6, 2), (2, 6);
statement ok
SELECT * FROM t1 as t1_alias inner join (select * from t2) as t2_alias ON (eq(x := t1_alias.a, y := t2_alias.c))
# no default parameters with incorrect names
statement error
SELECT * FROM t1 as t1_alias inner join (select * from t2) as t2_alias ON (eq(a := t1_alias.a, c := t2_alias.c))
----
Binder Error

View File

@@ -0,0 +1,36 @@
# name: test/sql/catalog/function/test_macro_issue_13104.test
# description: Test Issue 13104 - Macro default variable that is a boolean type fails
# group: [function]
statement ok
create or replace macro my_macro(a:=true) as a;
query I
select my_macro()
----
true
statement ok
create or replace macro my_macro(a:=false) as a;
query I
select my_macro()
----
false
# bonus: we can also use struct/list as default parameters now
statement ok
create or replace macro my_macro(a:={duck:42}) as a;
query I
select my_macro()
----
{'duck': 42}
statement ok
create or replace macro my_macro(a:=[42]) as a;
query I
select my_macro()
----
[42]

View File

@@ -0,0 +1,11 @@
# name: test/sql/catalog/function/test_macro_issue_18927.test
# description: Test Issue 18927 - Dot operator (function chaining) fails with macros
# group: [function]
statement ok
CREATE OR REPLACE MACRO my(s) AS s.lower().split('').aggregate('count');
query I
SELECT my('AA');
----
2

View File

@@ -0,0 +1,12 @@
# name: test/sql/catalog/function/test_macro_issue_19119.test
# description: Test Issue 19119 - Regression: combination of window functions and RAISE_EVEN raises "Not implemented Error: Unimplemented expression class"
# group: [function]
statement ok
CREATE TABLE t (x INT);
statement ok
INSERT INTO t (x) VALUES (1), (2);
statement ok
SELECT ROUND_EVEN(SUM(x) OVER (), 0) AS y FROM t;

View File

@@ -0,0 +1,97 @@
# name: test/sql/catalog/function/test_macro_overloads.test
# description: Test macro overloads
# group: [function]
statement ok
PRAGMA enable_verification
# simple overloaded macro
statement ok
CREATE MACRO multi_add
() AS 0,
(a) AS a,
(a, b) AS a + b,
(a, b, c) AS a + b + c,
(a, b, c, d) AS a + b + c + d,
(a, b, c, d, e) AS a + b + c + d + e
query IIIIII
SELECT multi_add(),
multi_add(42),
multi_add(42, 1),
multi_add(42, 1, 1),
multi_add(42, 1, 1, 1),
multi_add(42, 1, 1, 1, 1)
----
0 42 43 44 45 46
# overload not found
statement error
SELECT multi_add(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
----
does not support the supplied arguments
# named parameters
statement ok
CREATE MACRO arithmetic
(a, b, mult := 1) AS (a + b) * mult,
(a, b, c, division := 1) AS (a + b + c) / division
statement error
select arithmetic(100, 200, 300)
----
multiple overloads that match the supplied arguments
# disambiguate arithmetic(100, 200, 300) using c := 300
query IIII
SELECT arithmetic(42, 84), arithmetic(42, 84, mult := 10), arithmetic(100, 200, c := 300), arithmetic(100, 200, 300, division := 10)
----
126 1260 600 60
# table macro overloads
statement ok
CREATE MACRO generate_numbers
(a, b) AS TABLE (SELECT * FROM range(a + b) t(i)),
(a, b, c, mult := 1) AS TABLE (SELECT * FROM range((a + b + c) * mult) t(i))
query I
SELECT COUNT(*) FROM generate_numbers(20, 10);
----
30
query I
SELECT COUNT(*) FROM generate_numbers(1, 2, 2, mult := 5);
----
25
# view overloads in duckdb_functions
query II
SELECT function_name, parameters FROM duckdb_functions() WHERE function_name IN ('arithmetic', 'multi_add', 'generate_numbers') ORDER BY function_name, len(parameters)
----
arithmetic [a, b, mult]
arithmetic [a, b, c, division]
generate_numbers [a, b]
generate_numbers [a, b, c, mult]
multi_add []
multi_add [a]
multi_add [a, b]
multi_add [a, b, c]
multi_add [a, b, c, d]
multi_add [a, b, c, d, e]
# ambiguity conflict between macros
statement error
CREATE MACRO ambiguous_macro
(a) AS a,
(a) AS a + 1
----
Ambiguity in macro overloads
# error in macro overload definition
statement error
CREATE MACRO error_in_definition
(a) AS a,
(a, b) AS a + y
----
Referenced column "y" not found in FROM clause

View File

@@ -0,0 +1,73 @@
# name: test/sql/catalog/function/test_macro_relpersistence_conflict.test
# description: Test Macro temporary/if exists/or replace
# group: [function]
load __TEST_DIR__/my_macro_database.db
statement ok
PRAGMA disable_checkpoint_on_shutdown
statement ok
PRAGMA wal_autocheckpoint='1TB';
statement ok
create macro test(a, b) as a + b
query T
select test(4, 2)
----
6
statement ok
create or replace macro test(a, b) as a + a
# should be different now
query T
select test(4, 2)
----
8
# should be ignored
statement ok
create macro if not exists test(a, b) as a + b
query T
select test(4, 2)
----
8
statement ok
drop macro test
# now let's do the same stuff with a temporary macro
statement ok
create temporary macro test(a, b) as a + b
query T
select test(4, 2)
----
6
statement ok
create or replace temporary macro test(a, b) as a + a
query T
select test(4, 2)
----
8
statement ok
create temporary macro if not exists test(a, b) as a + b
query T
select test(4, 2)
----
8
restart
# macro should be gone
statement error
select test(4, 2)
----
<REGEX>:.*Catalog Error.*does not exist.*

View File

@@ -0,0 +1,352 @@
# name: test/sql/catalog/function/test_macro_type_overloads.test
# description: Test macro TYPE overloads
# group: [function]
# always works for in-memory dbs
statement ok
attach ':memory:' AS inmemorydb
statement ok
use inmemorydb
statement ok
create or replace macro m(s varchar) as s || 'c'
statement ok
drop macro m;
statement ok
attach '__TEST_DIR__/test_macro_type_overloads_olderdb.db' AS olderdb (storage_version 'v1.3.0')
statement ok
use olderdb
# does not work for older versions
statement error
create or replace macro m(s varchar) as s || 'c'
----
Typed macro parameters are only supported for
# we can also always create temporary typed macros
statement ok
create or replace temporary macro m(s varchar) as s || 'c'
statement ok
drop macro m;
# rest of the tests proceed with a db version that works
statement ok
attach '__TEST_DIR__/test_macro_type_overloads_newerdb.db' AS newerdb (storage_version 'v1.4.0')
statement ok
use newerdb
statement ok
create view v as select 42
# create macro with type varchar
statement ok
create or replace macro m(s varchar) as s || 'c'
# this works
query I
select m('ab')
----
abc
query I
select m(s := 'ab')
----
abc
# list cannot be implicitly cast to varchar, so this fails
statement error
select m([42])
----
does not support the supplied arguments
statement error
select m(s := [42])
----
does not support the supplied arguments
# test the same behavior with an arg with a default
statement ok
create or replace macro m(s varchar := 'cc') as s || 'c'
query I
select m('ab')
----
abc
query I
select m(s := 'ab')
----
abc
statement error
select m([42])
----
does not support the supplied arguments
statement error
select m(s := [42])
----
does not support the supplied arguments
statement ok
create or replace macro m
(a tinyint) as a + 1,
(a smallint) as a + 2,
(a integer) as a + 3,
(a bigint) as a + 4,
(a hugeint) as a + 5,
(a) as a + 10
# to support the sliding window of forwards compatibility, we don't yet serialize parameter types to storage
# therefore, this test has is skipped in the force_storage_restart.json test config
query I
select parameter_types[1]
from duckdb_functions()
where function_name = 'm'
and function_type = 'macro'
order by all
----
BIGINT
HUGEINT
INTEGER
SMALLINT
TINYINT
NULL
query IIIIII
select
m(0::tinyint),
m(0::smallint),
m(0::integer),
m(0::bigint),
m(0::hugeint),
m(0::double)
----
1 2 3 4 5 10
# not sure if I agree with this but this is how our implicit cast cost rules select the lowest cost function
# i also doubt that people will create this many integer type overloads with different behaviors
query IIIIII
select
m(0::utinyint),
m(0::usmallint),
m(0::uinteger),
m(0::ubigint),
m(0::uhugeint),
m(0::float)
----
4 4 4 5 10 10
statement ok
create or replace macro m
(i int, j) as i + j,
(i, j int) as i - j;
# exact same cost, can't disambiguate with these arguments
statement error
select m(0, 42)
----
has multiple overloads
# this resolves to the first one because the first arg is int
query I
select m(0, 42::float)
----
42
# this resolves to the second one because the second arg is int
query I
select m(0::float, 42)
----
-42
# user types should at least bind properly (instead of defaulting to LogicalTypeId::USER)
statement ok
create or replace type cool_string as varchar;
statement ok
create or replace macro m(s cool_string) as s;
statement ok
select m('duck')
# this fails on creation because we won't implicitly cast
statement error
create or replace macro m(s varchar := 42) as s
----
cannot be implicitly cast
# can fix with an explicit type cast
statement ok
create or replace macro m(s varchar := 42::varchar) as s
# this can be implicitly cast so it succeeds
statement ok
create or replace macro m(i bigint := 42::integer) as i
# test that the supplied arg is cast to a bigint
query I
select typeof(m(42::integer))
----
BIGINT
# replicate tests above with table macro
statement ok
create or replace macro m(s varchar) as table (select s || 'c')
query I
from m('ab')
----
abc
query I
from m(s := 'ab')
----
abc
statement error
from m([42])
----
does not support the supplied arguments
statement error
from m(s := [42])
----
does not support the supplied arguments
statement ok
create or replace macro m(s varchar := 'cc') as table (select s || 'c')
query I
from m('ab')
----
abc
query I
from m(s := 'ab')
----
abc
statement error
from m([42])
----
does not support the supplied arguments
statement error
from m(s := [42])
----
does not support the supplied arguments
statement ok
create or replace macro m
(a tinyint) as table (select a + 1),
(a smallint) as table (select a + 2),
(a integer) as table (select a + 3),
(a bigint) as table (select a + 4),
(a hugeint) as table (select a + 5),
(a) as table (select a + 10)
query I
select parameter_types[1]
from duckdb_functions()
where function_name = 'm'
and function_type = 'table_macro'
order by all
----
BIGINT
HUGEINT
INTEGER
SMALLINT
TINYINT
NULL
query I
from m(0::tinyint)
union all
from m(0::smallint)
union all
from m(0::integer)
union all
from m(0::bigint)
union all
from m(0::hugeint)
union all
from m(0::double)
----
1
2
3
4
5
10
query I
from m(0::utinyint)
union all
from m(0::usmallint)
union all
from m(0::uinteger)
union all
from m(0::ubigint)
union all
from m(0::uhugeint)
union all
from m(0::float)
----
4
4
4
5
10
10
statement ok
create or replace macro m
(i int, j) as table (select i + j),
(i, j int) as table (select i - j);
statement error
from m(0, 42)
----
has multiple overloads
query I
from m(0, 42::float)
----
42
query I
from m(0::float, 42)
----
-42
statement ok
create or replace type cool_string as varchar;
statement ok
create or replace macro m(s cool_string) as table (select s);
statement ok
from m('duck')
statement error
create or replace macro m(s varchar := 42) as table (select s)
----
cannot be implicitly cast
statement ok
create or replace macro m(s varchar := 42::varchar) as table (select s)
statement ok
create or replace macro m(i bigint := 42::integer) as table (select i as i)
query I
select typeof(i) from m(42::integer)
----
BIGINT

View File

@@ -0,0 +1,16 @@
# name: test/sql/catalog/function/test_macro_with_unknown_types.test
# description: Test MACRO binding with unknown parameter types.
# group: [function]
statement ok
PRAGMA enable_verification;
statement ok
CREATE TEMP MACRO m1(x, y) AS (
SELECT list_has_all(x, y) AND list_has_all(y, x)
);
query I
SELECT m1([1, 2], [1, 2]);
----
true

View File

@@ -0,0 +1,60 @@
# name: test/sql/catalog/function/test_recursive_macro.test
# description: Test recursive macros
# group: [function]
statement ok
set enable_macro_dependencies=true
statement ok
CREATE MACRO "sum"(x) AS (CASE WHEN sum(x) IS NULL THEN 0 ELSE sum(x) END);
statement error
SELECT sum(1);
----
Max expression depth limit
statement error
SELECT sum(1) WHERE 42=0
----
Max expression depth limit
statement ok
DROP MACRO sum
# recursive macro with explicit qualification
statement ok
CREATE MACRO "sum"(x) AS (CASE WHEN system.main.sum(x) IS NULL THEN 0 ELSE system.main.sum(x) END);
query I
SELECT sum(1);
----
1
query I
SELECT sum(1) WHERE 42=0
----
0
# evil test case by Mark
statement ok
create macro m1(a) as a+1;
statement ok
create macro m2(a) as m1(a)+1;
statement error
create or replace macro m1(a) as m2(a)+1;
----
Catalog Error: CREATE OR REPLACE is not allowed to depend on itself
# also table macros
statement ok
create macro m3(a) as a+1;
statement ok
create macro m4(a) as table select m3(a);
statement error
create or replace macro m3(a) as (from m4(42));
----
Catalog Error: CREATE OR REPLACE is not allowed to depend on itself

View File

@@ -0,0 +1,53 @@
# name: test/sql/catalog/function/test_recursive_macro_no_dependency.test
# description: Test recursive macros
# group: [function]
statement ok
CREATE MACRO "sum"(x) AS (CASE WHEN sum(x) IS NULL THEN 0 ELSE sum(x) END);
statement error
SELECT sum(1);
----
Max expression depth limit
statement error
SELECT sum(1) WHERE 42=0
----
Max expression depth limit
statement ok
DROP MACRO sum
# recursive macro with explicit qualification
statement ok
CREATE MACRO "sum"(x) AS (CASE WHEN system.main.sum(x) IS NULL THEN 0 ELSE system.main.sum(x) END);
query I
SELECT sum(1);
----
1
query I
SELECT sum(1) WHERE 42=0
----
0
# evil test case by Mark
statement ok
create macro m1(a) as a+1;
statement ok
create macro m2(a) as m1(a)+1;
statement ok
create or replace macro m1(a) as m2(a)+1;
# also table macros
statement ok
create macro m3(a) as a+1;
statement ok
create macro m4(a) as table select m3(a);
statement ok
create or replace macro m3(a) as (from m4(42));

View File

@@ -0,0 +1,98 @@
# name: test/sql/catalog/function/test_sequence_macro.test
# description: Test Sequence Macro
# group: [function]
statement ok
CREATE TABLE integers (i INT)
statement ok
INSERT INTO integers VALUES (42), (42)
statement ok
CREATE SEQUENCE seq
# recursive CTE with sequences
statement ok
CREATE MACRO in_next_n(x, s, n) AS x IN (
WITH RECURSIVE cte AS (
SELECT nextval(s) AS nxt, 1 AS iter
UNION ALL
SELECT nextval(s), iter + 1
FROM cte
WHERE iter < n
)
SELECT nxt
FROM cte
)
query T
SELECT in_next_n(3, 'seq', 5);
----
1
query T
SELECT in_next_n(3, 'seq', 5);
----
0
query T
SELECT in_next_n(12, 'seq', 5);
----
1
# overlapping param/column names can be disambiguated
statement ok
CREATE MACRO in_next_n2(x, s, n) AS x IN (
WITH RECURSIVE cte AS (
SELECT nextval(s) AS nxt, n AS n
UNION ALL
SELECT nextval(s), cte.n - 1
FROM cte
WHERE cte.n > 1
)
SELECT nxt
FROM cte
)
query T
SELECT in_next_n2(17, 'seq', 5);
----
1
statement ok
DROP SEQUENCE seq
statement ok
CREATE SEQUENCE seq1
statement ok
CREATE SEQUENCE seq2 INCREMENT BY 2 START WITH 2
statement ok
CREATE MACRO test(s1, s2, x) AS nextval(s1) + nextval(s2) + x
query T
SELECT test('seq1', 'seq2', i) FROM integers
----
45
48
statement ok
DROP SEQUENCE seq1
statement ok
DROP SEQUENCE seq2
# argument with side-effects not allowed
statement ok
CREATE MACRO add_macro(a, b) AS a + b
statement ok
CREATE SEQUENCE seqq
# TODO: uncomment when macro parameters are pushed as a projection
#query T
#SELECT add_macro(i + nextval('seqq'), 5) FROM integers
#----
#48
#48

View File

@@ -0,0 +1,379 @@
# name: test/sql/catalog/function/test_simple_macro.test
# description: Test Simple Macro
# group: [function]
statement ok
PRAGMA enable_verification
statement ok
CREATE TABLE integers (a INT)
statement ok
INSERT INTO integers VALUES (1)
statement ok
CREATE MACRO one() AS (SELECT 1);
query T
SELECT one()
----
1
statement error
SELECT one(1)
----
does not support the supplied arguments
statement error
SELECT one(NULL)
----
does not support the supplied arguments
statement ok
DROP MACRO one;
# HAVING in a macro
statement ok
CREATE MACRO having_macro(x) AS (SELECT * FROM integers GROUP BY a HAVING a = x)
query T
SELECT having_macro(1)
----
1
query T
SELECT having_macro(6)
----
NULL
# UNION in a macro
statement ok
CREATE MACRO union_macro(x, y, z) AS (SELECT x IN (SELECT y UNION ALL SELECT z))
query T
SELECT union_macro(1, 2, 3)
----
false
query T
SELECT union_macro(1, 2, 1)
----
true
query T
SELECT union_macro(1, 1, 2)
----
true
# expression list
statement ok
CREATE MACRO in_expression_list(x, y, z) AS (SELECT x IN (VALUES (y), (z)))
query T
SELECT in_expression_list(1, 2, 3)
----
false
query T
SELECT in_expression_list(1, 2, 1)
----
true
query T
SELECT in_expression_list(1, 1, 2)
----
true
# FUNCTION alias
statement ok
CREATE FUNCTION two() AS (SELECT 2);
query T
SELECT two()
----
2
statement ok
DROP FUNCTION two;
# b cannot be found
statement error
CREATE MACRO add_macro(a) AS a + b
----
column "b" not found
statement ok
CREATE MACRO add_macro(a, b) AS a + b
query T
SELECT add_macro(a,a) FROM integers
----
2
statement ok
CREATE TABLE floats (b FLOAT)
statement ok
INSERT INTO floats VALUES (0.5)
query T
SELECT add_macro(a,2) + add_macro(3,b) FROM integers, floats
----
6.5
# can create function with same name as a ScalarFunction
statement ok
CREATE MACRO string_split(a,b) AS a + b
query I
SELECT string_split(1, 2)
----
3
statement ok
CREATE MACRO IFELSE(a,b,c) AS CASE WHEN a THEN b ELSE c END
query T
SELECT IFELSE(1,'true','false')
----
true
query T
SELECT ifelse(1,'true','false')
----
true
query T
SELECT IFELSE(0,'true','false')
----
false
query T
SELECT IFELSE(a = 1, 'true', 'false') FROM integers
----
true
query T
SELECT IFELSE(a = 0, 'true', 'false') FROM integers
----
false
# incorrect number of arguments
statement error
SELECT IFELSE();
----
does not support the supplied arguments
statement error
SELECT IFELSE(1);
----
does not support the supplied arguments
statement error
SELECT IFELSE(1, 2);
----
does not support the supplied arguments
statement error
SELECT IFELSE(1, 2, 3, 4);
----
does not support the supplied arguments
# no duplicate macro function names
statement error
CREATE MACRO IFELSE(a,b) AS a+b
----
already exists
statement error
CREATE MACRO ifelse(a,b) AS a+b
----
already exists
query T
SELECT IFELSE('1', 'random', RANDOM()::VARCHAR)
----
random
# macro in a different schema
statement ok
CREATE SCHEMA macros
statement ok
CREATE MACRO macros.add_macro(a, b) AS a + b
query T
SELECT macros.add_macro(40,2)
----
42
# conflicting parameter names in macro definition
statement error
CREATE MACRO conflict(i, i) AS i + 1
----
# aggregation macro's
statement ok
CREATE MACRO myavg(x) AS SUM(x) / COUNT(x)
statement ok
INSERT INTO integers VALUES (21), (41);
query T
SELECT myavg(a) FROM integers
----
21
statement ok
CREATE MACRO weird_avg(x) AS (MIN(x) + MAX(x)) / COUNT(x)
query T
SELECT weird_avg(a) FROM integers
----
14
statement error
CREATE MACRO star() AS *
----
# macro's with default arguments
statement error
CREATE MACRO conflict(a, a := 1) AS a + a
----
statement ok
CREATE MACRO add_default5(a, b := 5) AS a + b
query I
SELECT add_default5(3, 6)
----
9
query T
SELECT add_default5(3)
----
8
query T
SELECT add_default5(3, b := 6)
----
9
statement error
SELECT add_default5(b := 6, 3)
----
positional argument following named argument
statement error
CREATE MACRO wrong_order(a, b := 3, c) AS a + b + c
----
Parameter without a default follows parameter with a default
statement error
CREATE MACRO wrong_order(a := 3, b) AS a + b
----
Parameter without a default follows parameter with a default
# only constant default values are allowed
statement error
CREATE MACRO select_plus_floats(a, f := b) AS (SELECT a + f FROM floats)
----
Invalid default value
# +(FLOAT, VARCHAR) does not work - but types are only checked once the macro is called
statement ok
CREATE MACRO wrong_type(s := 'not a float') AS (SELECT b + s FROM floats)
# this should fail
statement error
select wrong_type()
----
Could not convert
# but succeed if we pass the correct type
query I
select wrong_type(42)
----
42.5
statement error
CREATE MACRO two_default_params(a := 4, a := 2) AS a + a
----
Duplicate parameter
statement ok
CREATE MACRO two_default_params(a := 4, b := 2) AS a + b
query T
SELECT two_default_params()
----
6
query T
SELECT two_default_params(a := 5)
----
7
query T
SELECT two_default_params(b := 3)
----
7
statement error
SELECT two_default_params(a := 5, a := 3)
----
has named argument repeated
statement error
SELECT two_default_params(b := 5, b := 3)
----
has named argument repeated
statement error
CREATE MACRO macros.add_macro(a, b) AS a + b
----
already exists
statement error
CREATE MACRO my_macro(a.b) AS 42;
----
syntax error
statement error
CREATE MACRO my_macro(a.b.c) AS 42;
----
syntax error
statement ok
CREATE MACRO my_macro(a) AS 42;
statement error
SELECT my_macro(x := 42);
----
does not support the supplied arguments
statement error
SELECT my_macro(a := 42, a := 42);
----
has named argument repeated
# internal issue 1044
statement ok
create macro zz1(x) as (select 10+x);
statement ok
create macro zz2(x) as 20+x;
query II
select zz1(1),zz2(2);
----
11 22
# should not return any results (because we shouldn't display "macro_parameters"
query III
select function_name, parameters, macro_definition
from duckdb_functions()
where function_name like 'zz%'
and macro_definition like '%macro_parameters%';
----

View File

@@ -0,0 +1,66 @@
# name: test/sql/catalog/function/test_subquery_macro.test
# description: Test Macro with subquery
# group: [function]
statement ok
PRAGMA enable_verification
statement ok
CREATE TABLE integers (a INT)
statement ok
INSERT INTO integers VALUES (1)
statement ok
CREATE MACRO subquery(a) AS (SELECT a)
query T
SELECT subquery(1)
----
1
query T
SELECT subquery(NULL)
----
NULL
query T
SELECT subquery(3) + a FROM integers
----
4
query T
SELECT subquery(a) FROM integers
----
1
# macro parameters and column names should not conflict
statement error
CREATE MACRO a1(a) AS (SELECT a + a FROM integers)
----
statement ok
CREATE MACRO a1(b) AS (SELECT a + a FROM integers)
query T
SELECT a1(3)
----
2
query T
SELECT a1(3) + a FROM integers
----
3
# never allow columns with the same name as parameters
statement error
CREATE MACRO a2(a) AS (SELECT i.a + a FROM integers i)
----
statement ok
CREATE MACRO a2(b) AS (SELECT i.a + b FROM integers i)
query T
SELECT a2(3)
----
4

View File

@@ -0,0 +1,128 @@
# name: test/sql/catalog/function/test_table_macro.test
# description: Test SELECTMacro
# group: [function]
statement ok
PRAGMA enable_verification
statement ok
CREATE TABLE test_tbl (id INT, name string);
statement ok
CREATE TABLE test2_tbl (id INT, name string);
statement ok
CREATE TABLE greek_tbl (id INT, name string);
statement ok
INSERT INTO test_tbl VALUES (1,'tom'), (2,'dick'),(3,'harry'), (4,'mary'), (5,'mungo'), (6,'midge');
statement ok
INSERT INTO test_tbl VALUES (20,'andrew'), (21,'boris'),(22,'Caleb'), (23,'david'), (24,'evan');
statement ok
INSERT INTO greek_tbl VALUES (1, 'alpha'), (2, 'beta'), (3, 'gamma'), (4, 'delta'), (5, 'epsilon'),(6, 'zeta'), (7, 'eta') , (8, 'theta'), (9, 'iota') , (10, 'kappa');
statement ok
CREATE MACRO xt(a,_name) as TABLE SELECT * FROM test_tbl WHERE(id>=a or name=_name);
statement ok
CREATE MACRO xt2(a,_name) as TABLE SELECT * FROM test_tbl WHERE(id>=a or name like _name);
statement ok
CREATE MACRO sgreek(a,b,c) as TABLE SELECT a,b FROM greek_tbl WHERE(id >= c);
query II
( SELECT* FROM xt(1, 'tom') UNION SELECT* FROM xt2(1, '%%%') ) INTERSECT SELECT* FROM xt(100,'midge');
----
6 midge
query II
(SELECT* FROM xt(1, 'tom') EXCEPT SELECT* FROM xt(20,'tom' )) INTERSECT SELECT* FROM xt(100,'harry');
----
3 harry
query II
SELECT * FROM xt(200,'andrew');
----
20 andrew
query II
SELECT * FROM xt2(100,'m%');
----
4 mary
5 mungo
6 midge
# check similar to
statement ok
CREATE MACRO xtm(cmp_str) as TABLE SELECT id, name FROM test_tbl WHERE( name similar to cmp_str);
statement ok
SELECT * FROM xtm('m.*');
# check regexp_matches
statement ok
CREATE MACRO xt_reg(cmp) as TABLE SELECT * FROM test_tbl WHERE regexp_matches(name ,cmp );
statement ok
SELECT * FROM xt_reg('^m');
# use regular macro for comparison
statement ok
CREATE MACRO cmp(a,m) as regexp_matches(a,m) or a similar to m;
statement ok
CREATE MACRO gm(m) as TABLE SELECT * FROM greek_tbl WHERE cmp(name,m);
statement ok
SELECT * FROM gm('^m');
# create a scalar macro with same name as table macro
statement ok
CREATE MACRO xt(a,b) as a+b;
# drop table macro
statement ok
DROP MACRO TABLE xt;
# use column identifer as a macro parameter
statement ok
CREATE MACRO xt(id, imax) as TABLE SELECT id,name FROM test_tbl WHERE id<=imax;
query II
SELECT * FROM xt(id,1);
----
1 tom
# try to create table macro with pre-existing table name "range"
statement ok
CREATE MACRO range(a,b) as TABLE select a,b from test_tbl;
# use table macro as a scalar macro
query II
SELECT * FROM test_tbl where id>=(SELECT max(id) FROM xt(id,30));
----
24 evan
# use table macro as a scalar macro
query II
SELECT * FROM greek_tbl where id<=(SELECT min(id) FROM xt(id,30));
----
1 alpha
# check that table macros are present in duckdb_functions() -
# nb they have the function_type 'table_macro'
query IIIIIIIII
SELECT schema_name, function_name, function_type, description, return_type, parameters, parameter_types, varargs, macro_definition FROM duckdb_functions() WHERE function_type = 'table_macro' AND
( function_name = 'sgreek' or function_name = 'xt') order by function_name;
----
main sgreek table_macro NULL NULL [a, b, c] [NULL, NULL, NULL] NULL SELECT a, b FROM greek_tbl WHERE (id >= c)
main xt table_macro NULL NULL [id, imax] [NULL, NULL] NULL SELECT id, "name" FROM test_tbl WHERE (id <= imax)

View File

@@ -0,0 +1,157 @@
# name: test/sql/catalog/function/test_table_macro_args.test
# description: Test table macros with default args
# group: [function]
statement ok
CREATE TABLE cards_tbl (val int, name string, suit string);
statement ok
INSERT INTO cards_tbl values (1, 'ace', 'clubs'), (11,'jack', 'clubs' ),
(12, 'queen', 'clubs' ), (13, 'king', 'clubs');
statement ok
INSERT INTO cards_tbl values (1, 'ace', 'diamonds'), (11,'jack', 'diamonds' ),
(12, 'queen', 'diamonds' ), (13, 'king', 'diamonds');
statement ok
INSERT INTO cards_tbl values (1, 'ace', 'hearts'), (11,'jack', 'hearts' ),
(12, 'queen', 'hearts' ), (13, 'king', 'hearts');
statement ok
INSERT INTO cards_tbl values (1, 'ace', 'spades'), (11,'jack', 'spades' ),
(12, 'queen', 'spades' ), (13, 'king', 'spades');
statement ok
CREATE MACRO card_select(_val_min:=1, _val_max:=1, _name:='%', _suit:='%')
as TABLE SELECT * FROM cards_tbl WHERE val>=_val_min AND val<=_val_max AND name like _name AND suit like _suit;
# try out macro with default args
query I
SELECT DISTINCT val from card_select();
----
1
# a single args
query III
SELECT * FROM card_select(_suit:='clubs');
----
1 ace clubs
# args in wrong order
query III
SELECT * FROM card_select(_name:='king', _val_max:=13) ORDER BY suit;
----
13 king clubs
13 king diamonds
13 king hearts
13 king spades
query I
SELECT count(suit) FROM card_select() GROUP BY ALL;
----
4
# use every arg
query III
SELECT * FROM card_select(_name:='king', _val_max:=13, _suit:='hearts', _val_min:=10);
----
13 king hearts
# try a macro again with regular args and default args
statement ok
CREATE MACRO card_select_args(_val_min, _val_max, _name:='%', _suit:='%')
as TABLE SELECT * FROM cards_tbl WHERE val>=_val_min AND val<=_val_max AND name like _name AND suit like _suit;
# default args before positional args
statement error
SELECT * FROM card_select_args(_name:='king',1, 13);
----
# correct arg order
query I
SELECT suit FROM card_select_args(1, 13, _name:='king' ) ORDER BY suit;
----
clubs
diamonds
hearts
spades
# create macro without any args
statement ok
CREATE MACRO card_dfl() as TABLE SELECT DISTINCT suit FROM cards_tbl where suit='hearts';
query I
SELECT * FROM card_dfl();
----
hearts
# check order by , limit with expressions
statement ok
CREATE MACRO sc(aorder, border, nlimit) AS TABLE SELECT * FROM cards_tbl ORDER BY aorder,border LIMIT nlimit;
query III
SELECT * FROM sc(name, suit, 4);
----
1 ace clubs
1 ace diamonds
1 ace hearts
1 ace spades
# check limit PERCENT and offset
statement ok
CREATE MACRO sc2(dlimit, noffset) AS TABLE SELECT DISTINCT suit from cards_tbl order by all limit dlimit% offset noffset;
query I
SELECT * FROM sc2(50.0, 2);
----
hearts
spades
statement ok
CREATE MACRO sc3(col) AS TABLE SELECT DISTINCT ON (col) col FROM cards_tbl ORDER BY col;
query I
SELECT * FROM sc3(name);
----
ace
jack
king
queen
query I
SELECT * FROM sc3(suit);
----
clubs
diamonds
hearts
spades
# create macro with non existing table
statement error
CREATE MACRO card_no_tbl() as TABLE SELECT * FROM suit_tbl;
----
Catalog Error
# wrong arg order
statement error
CREATE MACRO card_select_args(_val_min, _name:='%', _suit:='%', _val_max)
as TABLE SELECT * FROM cards_tbl WHERE val>=_val_min AND val<=_val_max AND name like _name AND suit like _suit;
----
# positional parameter repeated
statement error
CREATE MACRO card_select_val(_val_min, _val_min) as TABLE SELECT * FROM cards_tbl WHERE val>=_val_min AND val<=_val_max;
----
Parser Error: Duplicate parameter

View File

@@ -0,0 +1,68 @@
# name: test/sql/catalog/function/test_table_macro_complex.test
# description: Test SELECT Macro
# group: [function]
statement ok
CREATE MACRO my_values(m,s) as TABLE select * from (values (1.0*m+s,'adam'), (2.0*m+s,'ben'),
(3.0*m+s,'cris'), (4.0*m+s,'desmond'),(5.0*m+s, 'eric'));
query I
SELECT sum(col0) from my_values(10.0,5.0);
----
175.00
# recursive union select macro
statement ok
CREATE MACRO my_values_union(m1,s1,m2,s2) as TABLE select * from my_values(m1,s1) UNION select * from my_values(m2,s2);
query I
select max(col0) from my_values_union(1.0,2.0,3.0,20.0);
----
35.00
# ranges
statement ok
CREATE MACRO dates_between(date_min, date_max, ilimit:=100) AS TABLE WITH dates(date) AS
(SELECT * FROM range(date '0000-01-01', date '3000-01-01', interval '1' month))
SELECT * FROM dates WHERE date between date_min AND date_max;
query T
select * from dates_between('2021-01-01', '2021-02-04');
----
2021-01-01 00:00:00
2021-02-01 00:00:00
# alternative verify turns this CTE into a materialized CTE,
# which then does not terminate anymore.
require no_alternative_verify
statement ok
CREATE MACRO fibonacci(n0, n1, nlimit, noffset) AS TABLE
WITH RECURSIVE fib AS (
SELECT 1 AS n,
n0::bigint AS "fibₙ",
n1::bigint AS "fibₙ₊₁"
UNION ALL
SELECT n+1,
"fibₙ₊₁",
"fibₙ" + "fibₙ₊₁"
FROM fib
)
SELECT n, "fibₙ" FROM fib
LIMIT nlimit OFFSET noffset;
query II
SELECT * FROM fibonacci(1, 2, 5, 10);
----
11 144
12 233
13 377
14 610
15 987

View File

@@ -0,0 +1,143 @@
# name: test/sql/catalog/function/test_table_macro_copy.test
# description: Test SELECTMacro
# group: [function]
statement ok
PRAGMA enable_verification
load __TEST_DIR__/table_macro.db
statement ok
CREATE TABLE test_tbl (id INT, name string);
statement ok
CREATE TABLE test2_tbl (id INT, name string);
statement ok
CREATE TABLE greek_tbl (id INT, name string);
statement ok
INSERT INTO test_tbl VALUES (1,'tom'), (2,'dick'),(3,'harry'), (4,'mary'), (5,'mungo'), (6,'midge');
statement ok
INSERT INTO test_tbl VALUES (20,'andrew'), (21,'boris'),(22,'Caleb'), (23,'david'), (24,'evan');
statement ok
INSERT INTO greek_tbl VALUES (1, 'alpha'), (2, 'beta'), (3, 'gamma'), (4, 'delta'), (5, 'epsilon'),(6, 'zeta'), (7, 'eta') , (8, 'theta'), (9, 'iota') , (10, 'kappa');
statement ok
CREATE MACRO xt(a,_name) as TABLE SELECT * FROM test_tbl WHERE(id>=a or name=_name);
statement ok
CREATE MACRO xt2(a,_name) as TABLE SELECT * FROM test_tbl WHERE(id>=a or name like _name);
statement ok
CREATE MACRO sgreek(a,b,c) as TABLE SELECT a,b FROM greek_tbl WHERE(id >= c);
query II
( SELECT* FROM xt(1, 'tom') UNION SELECT* FROM xt2(1, '%%%') ) INTERSECT SELECT* FROM xt(100,'midge');
----
6 midge
query II
(SELECT* FROM xt(1, 'tom') EXCEPT SELECT* FROM xt(20,'tom' )) INTERSECT SELECT* FROM xt(100,'harry');
----
3 harry
query II
SELECT * FROM xt(200,'andrew');
----
20 andrew
query II
SELECT * FROM xt2(100,'m%');
----
4 mary
5 mungo
6 midge
# check similar to
statement ok
CREATE MACRO xtm(cmp_str) as TABLE SELECT id, name FROM test_tbl WHERE( name similar to cmp_str);
statement ok
SELECT * FROM xtm('m.*');
# check regexp_matches
statement ok
CREATE MACRO xt_reg(cmp) as TABLE SELECT * FROM test_tbl WHERE regexp_matches(name ,cmp );
statement ok
SELECT * FROM xt_reg('^m');
# use regular macro for comparison
statement ok
CREATE MACRO cmp(a,m) as regexp_matches(a,m) or a similar to m;
statement ok
CREATE MACRO gm(m) as TABLE SELECT * FROM greek_tbl WHERE cmp(name,m);
statement ok
SELECT * FROM gm('^m');
# create a scalar macro with same name as table macro
statement ok
CREATE MACRO xt(a,b) as a+b;
# drop table macro
statement ok
DROP MACRO TABLE xt;
# use column identifer as a macro parameter
statement ok
CREATE MACRO xt(id, imax) as TABLE SELECT id,name FROM test_tbl WHERE id<=imax;
query II
SELECT * FROM xt(id,1);
----
1 tom
# try to create table macro with pre-existing table name "range"
statement ok
CREATE MACRO range(a,b) as TABLE select a,b from test_tbl;
# use table macro as a scalar macro
query II
SELECT * FROM test_tbl where id>=(SELECT max(id) FROM xt(id,30));
----
24 evan
# use table macro as a scalar macro
query II
SELECT * FROM greek_tbl where id<=(SELECT min(id) FROM xt(id,30));
----
1 alpha
# check that table macros are present in duckdb_functions() -
# nb they have the function_type 'table_macro'
query IIIIIIIII
SELECT schema_name, function_name, function_type, description, return_type, parameters, parameter_types, varargs, macro_definition FROM duckdb_functions() WHERE function_type = 'table_macro' AND
( function_name = 'sgreek' or function_name = 'xt') order by function_name;
----
main sgreek table_macro NULL NULL [a, b, c] [NULL, NULL, NULL] NULL SELECT a, b FROM greek_tbl WHERE (id >= c)
main xt table_macro NULL NULL [id, imax] [NULL, NULL] NULL SELECT id, "name" FROM test_tbl WHERE (id <= imax)
statement ok
ATTACH '__TEST_DIR__/table_macro2.db'
statement ok
COPY FROM DATABASE table_macro TO table_macro2
# check that table macros are present in duckdb_functions() -
# nb they have the function_type 'table_macro'
query IIIIIIIIII
SELECT database_name, schema_name, function_name, function_type, description, return_type, parameters, parameter_types, varargs, macro_definition FROM duckdb_functions() WHERE function_type = 'table_macro' AND
( function_name = 'sgreek' or function_name = 'xt') order by database_name, function_name;
----
table_macro main sgreek table_macro NULL NULL [a, b, c] [NULL, NULL, NULL] NULL SELECT a, b FROM greek_tbl WHERE (id >= c)
table_macro main xt table_macro NULL NULL [id, imax] [NULL, NULL] NULL SELECT id, "name" FROM test_tbl WHERE (id <= imax)
table_macro2 main sgreek table_macro NULL NULL [a, b, c] [NULL, NULL, NULL] NULL SELECT a, b FROM greek_tbl WHERE (id >= c)
table_macro2 main xt table_macro NULL NULL [id, imax] [NULL, NULL] NULL SELECT id, "name" FROM test_tbl WHERE (id <= imax)

View File

@@ -0,0 +1,105 @@
# name: test/sql/catalog/function/test_table_macro_groups.test
# description: Test table macros with GROUP BY, HAVING
# group: [function]
statement ok
SET default_null_order='nulls_first';
statement ok
CREATE TABLE car_pool (
-- define columns (name / type / default value / nullable)
id DECIMAL ,
producer VARCHAR(50) ,
model VARCHAR(50) ,
yyyy DECIMAL CHECK (yyyy BETWEEN 1970 AND 2020),
counter DECIMAL CHECK (counter >= 0),
CONSTRAINT car_pool_pk PRIMARY KEY (id)
);
statement ok
INSERT INTO car_pool VALUES
( 1, 'VW', 'Golf', 2005, 5),
( 2, 'VW', 'Golf', 2006, 2),
( 3, 'VW', 'Golf', 2007, 3),
( 4, 'VW', 'Golf', 2008, 3),
( 5, 'VW', 'Passat', 2005, 5),
( 6, 'VW', 'Passat', 2006, 1),
( 7, 'VW', 'Beetle', 2005, 1),
( 8, 'VW', 'Beetle', 2006, 2),
( 9, 'VW', 'Beetle', 2008, 4),
(10, 'Toyota', 'Corolla', 2005, 4),
(11, 'Toyota', 'Corolla', 2006, 3),
(12, 'Toyota', 'Corolla', 2007, 2),
(13, 'Toyota', 'Corolla', 2008, 4),
(14, 'Toyota', 'Prius', 2005, 1),
(15, 'Toyota', 'Prius', 2006, 1),
(16, 'Toyota', 'Hilux', 2005, 1),
(17, 'Toyota', 'Hilux', 2006, 1),
(18, 'Toyota', 'Hilux', 2008, 1);
statement ok
CREATE MACRO car_pool_cube(g1, g2, hcnt:=1) AS
TABLE SELECT g1, g2, sum(counter) AS cnt FROM car_pool
GROUP BY CUBE(g1, g2) HAVING cnt >= hcnt order by g1 NULLS LAST, g2 NULLS LAST;
query III
SELECT * FROM car_pool_cube(producer, model, hcnt:=4.0);
----
Toyota Corolla 13.000
Toyota NULL 18.000
VW Beetle 7.000
VW Golf 13.000
VW Passat 6.000
VW NULL 26.000
NULL Beetle 7.000
NULL Corolla 13.000
NULL Golf 13.000
NULL Passat 6.000
NULL NULL 44.000
statement ok
CREATE MACRO car_pool_rollup(g1, g2, hcnt:=1) AS
TABLE SELECT g1, g2, sum(counter) AS cnt FROM car_pool
GROUP BY ROLLUP(g1, g2) HAVING cnt >= hcnt order by g1, g2;
query III
SELECT * FROM car_pool_rollup(model, yyyy, hcnt:=4);
----
NULL NULL 44.000
Beetle NULL 7.000
Beetle 2008.000 4.000
Corolla NULL 13.000
Corolla 2005.000 4.000
Corolla 2008.000 4.000
Golf NULL 13.000
Golf 2005.000 5.000
Passat NULL 6.000
Passat 2005.000 5.000
statement ok
CREATE MACRO car_pool_groups(g1, g2, hcnt:=1) AS
TABLE SELECT g1, g2, sum(counter) AS cnt FROM car_pool
GROUP BY (g1, g2) HAVING cnt >= hcnt order by g1, g2;
query III
SELECT * FROM car_pool_groups(model, yyyy, hcnt:=2);
----
Beetle 2006.000 2.000
Beetle 2008.000 4.000
Corolla 2005.000 4.000
Corolla 2006.000 3.000
Corolla 2007.000 2.000
Corolla 2008.000 4.000
Golf 2005.000 5.000
Golf 2006.000 2.000
Golf 2007.000 3.000
Golf 2008.000 3.000
Passat 2005.000 5.000

View File

@@ -0,0 +1,46 @@
# name: test/sql/catalog/function/test_window_macro.test
# description: Test macro expansion for window functions
# group: [function]
statement ok
PRAGMA enable_verification
# Windowed aggregate macro
statement ok
CREATE OR REPLACE MACRO my_agg(x) AS SUM(CASE WHEN x THEN 1 END);
statement ok
select my_agg(range)
from range(2);
statement ok
select my_agg(range) OVER ()
from range(2);
# Windowed non-aggregate function macro
statement ok
CREATE OR REPLACE MACRO my_func(x) AS mod(x, 2);
statement ok
select my_func(range)
from range(2);
statement error
select my_func(range) OVER ()
from range(2);
----
mod is not an aggregate function
# Windowed non-aggregate expression macro
statement ok
CREATE OR REPLACE MACRO my_case(x) AS (CASE WHEN x THEN 1 END);
statement ok
select my_case(range)
from range(2);
statement error
select my_case(range) OVER ()
from range(2);
----
Window function macros must be functions