| 1 | #include "catch.hpp" |
| 2 | #include "test_helpers.hpp" |
| 3 | |
| 4 | using namespace duckdb; |
| 5 | using namespace std; |
| 6 | |
| 7 | TEST_CASE("Test Row IDs" , "[rowid]" ) { |
| 8 | unique_ptr<QueryResult> result; |
| 9 | DuckDB db(nullptr); |
| 10 | Connection con(db); |
| 11 | con.EnableQueryVerification(); |
| 12 | |
| 13 | REQUIRE_NO_FAIL(con.Query("create table a(i integer);" )); |
| 14 | REQUIRE_NO_FAIL(con.Query("insert into a values (42), (44);" )); |
| 15 | |
| 16 | // we can query row ids |
| 17 | result = con.Query("SELECT rowid, * FROM a" ); |
| 18 | REQUIRE(CHECK_COLUMN(result, 0, {0, 1})); |
| 19 | REQUIRE(CHECK_COLUMN(result, 1, {42, 44})); |
| 20 | REQUIRE(result->types.size() == 2); |
| 21 | |
| 22 | result = con.Query("SELECT rowid+1 FROM a WHERE CASE WHEN i=42 THEN rowid=0 ELSE rowid=1 END;" ); |
| 23 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2})); |
| 24 | |
| 25 | // rowid isn't expanded in * |
| 26 | result = con.Query("SELECT * FROM a" ); |
| 27 | REQUIRE(CHECK_COLUMN(result, 0, {42, 44})); |
| 28 | REQUIRE(result->types.size() == 1); |
| 29 | |
| 30 | // we can't update rowids |
| 31 | REQUIRE_FAIL(con.Query("UPDATE a SET rowid=5" )); |
| 32 | // we also can't insert with explicit row ids |
| 33 | REQUIRE_FAIL(con.Query("INSERT INTO a (rowid, i) VALUES (5, 6)" )); |
| 34 | |
| 35 | // we can use rowid as column name |
| 36 | REQUIRE_NO_FAIL(con.Query("create table b(rowid integer);" )); |
| 37 | REQUIRE_NO_FAIL(con.Query("insert into b values (42), (22);" )); |
| 38 | |
| 39 | // this rowid is expanded |
| 40 | result = con.Query("SELECT * FROM b ORDER BY 1" ); |
| 41 | REQUIRE(CHECK_COLUMN(result, 0, {22, 42})); |
| 42 | REQUIRE(result->types.size() == 1); |
| 43 | |
| 44 | // selecting rowid just selects the column |
| 45 | result = con.Query("SELECT rowid FROM b ORDER BY 1" ); |
| 46 | REQUIRE(CHECK_COLUMN(result, 0, {22, 42})); |
| 47 | REQUIRE(result->types.size() == 1); |
| 48 | // now we can update |
| 49 | REQUIRE_NO_FAIL(con.Query("UPDATE b SET rowid=5" )); |
| 50 | // and insert |
| 51 | REQUIRE_NO_FAIL(con.Query("INSERT INTO b (rowid) VALUES (5)" )); |
| 52 | |
| 53 | result = con.Query("SELECT * FROM b" ); |
| 54 | REQUIRE(CHECK_COLUMN(result, 0, {5, 5, 5})); |
| 55 | } |
| 56 | |
| 57 | TEST_CASE("Test Row IDs used in different types of operations" , "[rowid]" ) { |
| 58 | unique_ptr<QueryResult> result; |
| 59 | DuckDB db(nullptr); |
| 60 | Connection con(db); |
| 61 | con.EnableQueryVerification(); |
| 62 | |
| 63 | // test row ids on different operations |
| 64 | // this is interesting because rowids are emitted as compressed vectors |
| 65 | // hence this is really a test of correct handling of compressed vectors in the execution engine |
| 66 | REQUIRE_NO_FAIL(con.Query("create table a(i integer);" )); |
| 67 | REQUIRE_NO_FAIL(con.Query("insert into a values (42);" )); |
| 68 | |
| 69 | // arithmetic |
| 70 | result = con.Query("SELECT rowid + 1, rowid - 1, rowid + rowid, i + rowid FROM a" ); |
| 71 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 72 | REQUIRE(CHECK_COLUMN(result, 1, {-1})); |
| 73 | REQUIRE(CHECK_COLUMN(result, 2, {0})); |
| 74 | REQUIRE(CHECK_COLUMN(result, 3, {42})); |
| 75 | |
| 76 | // unary ops |
| 77 | result = con.Query("SELECT -rowid, +rowid, abs(rowid) FROM a" ); |
| 78 | REQUIRE(CHECK_COLUMN(result, 0, {0})); |
| 79 | REQUIRE(CHECK_COLUMN(result, 1, {0})); |
| 80 | REQUIRE(CHECK_COLUMN(result, 2, {0})); |
| 81 | |
| 82 | // ternary ops |
| 83 | result = con.Query("SELECT rowid BETWEEN -1 AND 1, 0 BETWEEN rowid AND 1, 1 BETWEEN -3 AND rowid FROM a" ); |
| 84 | REQUIRE(CHECK_COLUMN(result, 0, {true})); |
| 85 | REQUIRE(CHECK_COLUMN(result, 1, {true})); |
| 86 | REQUIRE(CHECK_COLUMN(result, 2, {false})); |
| 87 | |
| 88 | // comparisons |
| 89 | result = con.Query("SELECT rowid < i, rowid = NULL, rowid = i, rowid <> 0 FROM a" ); |
| 90 | REQUIRE(CHECK_COLUMN(result, 0, {true})); |
| 91 | REQUIRE(CHECK_COLUMN(result, 1, {Value()})); |
| 92 | REQUIRE(CHECK_COLUMN(result, 2, {false})); |
| 93 | REQUIRE(CHECK_COLUMN(result, 3, {false})); |
| 94 | |
| 95 | // simple (ungrouped) aggregates |
| 96 | result = con.Query("SELECT SUM(rowid), MIN(rowid), MAX(rowid), COUNT(rowid), FIRST(rowid) FROM a" ); |
| 97 | REQUIRE(CHECK_COLUMN(result, 0, {0})); |
| 98 | REQUIRE(CHECK_COLUMN(result, 1, {0})); |
| 99 | REQUIRE(CHECK_COLUMN(result, 2, {0})); |
| 100 | REQUIRE(CHECK_COLUMN(result, 3, {1})); |
| 101 | REQUIRE(CHECK_COLUMN(result, 4, {0})); |
| 102 | |
| 103 | result = con.Query("SELECT COUNT(*) FROM a" ); |
| 104 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 105 | |
| 106 | // grouped aggregates |
| 107 | result = con.Query("SELECT SUM(rowid), MIN(rowid), MAX(rowid), COUNT(rowid), FIRST(rowid) FROM a GROUP BY i" ); |
| 108 | REQUIRE(CHECK_COLUMN(result, 0, {0})); |
| 109 | REQUIRE(CHECK_COLUMN(result, 1, {0})); |
| 110 | REQUIRE(CHECK_COLUMN(result, 2, {0})); |
| 111 | REQUIRE(CHECK_COLUMN(result, 3, {1})); |
| 112 | REQUIRE(CHECK_COLUMN(result, 4, {0})); |
| 113 | |
| 114 | // group by rowid |
| 115 | result = con.Query("SELECT SUM(i) FROM a GROUP BY rowid" ); |
| 116 | REQUIRE(CHECK_COLUMN(result, 0, {42})); |
| 117 | |
| 118 | // joins |
| 119 | // equality |
| 120 | result = con.Query("SELECT * FROM a, a a2 WHERE a.rowid=a2.rowid" ); |
| 121 | REQUIRE(CHECK_COLUMN(result, 0, {42})); |
| 122 | // inequality |
| 123 | result = con.Query("SELECT * FROM a, a a2 WHERE a.rowid<>a2.rowid" ); |
| 124 | REQUIRE(CHECK_COLUMN(result, 0, {})); |
| 125 | // range |
| 126 | result = con.Query("SELECT * FROM a, a a2 WHERE a.rowid>=a2.rowid" ); |
| 127 | REQUIRE(CHECK_COLUMN(result, 0, {42})); |
| 128 | |
| 129 | // order by |
| 130 | result = con.Query("SELECT * FROM a ORDER BY rowid" ); |
| 131 | REQUIRE(CHECK_COLUMN(result, 0, {42})); |
| 132 | |
| 133 | // insert into table |
| 134 | REQUIRE_NO_FAIL(con.Query("INSERT INTO a SELECT rowid FROM a" )); |
| 135 | result = con.Query("SELECT * FROM a ORDER BY 1" ); |
| 136 | REQUIRE(CHECK_COLUMN(result, 0, {0, 42})); |
| 137 | |
| 138 | // update value |
| 139 | REQUIRE_NO_FAIL(con.Query("UPDATE a SET i=rowid" )); |
| 140 | result = con.Query("SELECT * FROM a ORDER BY 1" ); |
| 141 | REQUIRE(CHECK_COLUMN(result, 0, {0, 1})); |
| 142 | |
| 143 | // use rowid in filter |
| 144 | result = con.Query("SELECT * FROM a WHERE rowid=0" ); |
| 145 | REQUIRE(CHECK_COLUMN(result, 0, {0})); |
| 146 | result = con.Query("SELECT * FROM a WHERE rowid BETWEEN -100 AND 100 ORDER BY 1" ); |
| 147 | REQUIRE(CHECK_COLUMN(result, 0, {0, 1})); |
| 148 | result = con.Query("SELECT * FROM a WHERE rowid=0 OR rowid=1" ); |
| 149 | REQUIRE(CHECK_COLUMN(result, 0, {0, 1})); |
| 150 | |
| 151 | // window expressions |
| 152 | result = con.Query("SELECT row_number() OVER (PARTITION BY rowid) FROM a ORDER BY rowid" ); |
| 153 | REQUIRE(CHECK_COLUMN(result, 0, {1, 1})); |
| 154 | result = con.Query("SELECT row_number() OVER (ORDER BY rowid) FROM a ORDER BY rowid" ); |
| 155 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2})); |
| 156 | result = con.Query("SELECT row_number() OVER (ORDER BY rowid DESC) FROM a ORDER BY rowid" ); |
| 157 | REQUIRE(CHECK_COLUMN(result, 0, {2, 1})); |
| 158 | |
| 159 | // uncorrelated subqueries |
| 160 | result = con.Query("SELECT (SELECT rowid FROM a LIMIT 1)" ); |
| 161 | REQUIRE(CHECK_COLUMN(result, 0, {0})); |
| 162 | result = con.Query("SELECT 0 IN (SELECT rowid FROM a)" ); |
| 163 | REQUIRE(CHECK_COLUMN(result, 0, {true})); |
| 164 | result = con.Query("SELECT EXISTS(SELECT rowid FROM a)" ); |
| 165 | REQUIRE(CHECK_COLUMN(result, 0, {true})); |
| 166 | |
| 167 | // correlated subqueries |
| 168 | result = con.Query("SELECT (SELECT a2.rowid FROM a a2 WHERE a.rowid=a2.rowid) FROM a" ); |
| 169 | REQUIRE(CHECK_COLUMN(result, 0, {0, 1})); |
| 170 | result = con.Query("SELECT a.rowid IN (SELECT a2.rowid FROM a a2 WHERE a.rowid>=a2.rowid) FROM a" ); |
| 171 | REQUIRE(CHECK_COLUMN(result, 0, {true, true})); |
| 172 | result = con.Query("SELECT EXISTS(SELECT a2.rowid FROM a a2 WHERE a.rowid>=a2.rowid) FROM a" ); |
| 173 | REQUIRE(CHECK_COLUMN(result, 0, {true, true})); |
| 174 | } |
| 175 | |