/Users/deen/code/yugabyte-db/src/yb/yql/cql/ql/test/ql-insert-table-test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //-------------------------------------------------------------------------------------------------- |
2 | | // Copyright (c) YugaByte, Inc. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
5 | | // in compliance with the License. You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
10 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
11 | | // or implied. See the License for the specific language governing permissions and limitations |
12 | | // under the License. |
13 | | // |
14 | | //-------------------------------------------------------------------------------------------------- |
15 | | |
16 | | #include "yb/common/jsonb.h" |
17 | | #include "yb/common/ql_value.h" |
18 | | #include "yb/common/table_properties_constants.h" |
19 | | |
20 | | #include "yb/util/status_log.h" |
21 | | |
22 | | #include "yb/yql/cql/ql/test/ql-test-base.h" |
23 | | |
24 | | namespace yb { |
25 | | namespace ql { |
26 | | |
27 | | class TestQLInsertTable : public QLTestBase { |
28 | | public: |
29 | 0 | TestQLInsertTable() : QLTestBase() { |
30 | 0 | } |
31 | | |
32 | 0 | std::string InsertStmtWithTTL(std::string ttl_seconds) { |
33 | 0 | return strings::Substitute( |
34 | 0 | "INSERT INTO human_resource(id, name, salary) VALUES(1, 'Scott Tiger', 100) USING TTL $0;", |
35 | 0 | ttl_seconds); |
36 | 0 | } |
37 | | }; |
38 | | |
39 | 0 | TEST_F(TestQLInsertTable, TestQLInsertTableSimple) { |
40 | | // Init the simulated cluster. |
41 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
42 | | |
43 | | // Get a processor. |
44 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
45 | | |
46 | | // Create the table 1. |
47 | 0 | EXEC_VALID_STMT( |
48 | 0 | "CREATE TABLE human_resource(id int, name varchar, salary int, primary key(id, name));"); |
49 | | |
50 | | // INSERT: Valid statement with column list. |
51 | 0 | EXEC_VALID_STMT("INSERT INTO human_resource(id, name, salary) VALUES(1, 'Scott Tiger', 100);"); |
52 | 0 | EXEC_VALID_STMT("INSERT INTO human_resource(id, name, salary) VALUES(-1, 'Scott Tiger', -100);"); |
53 | | |
54 | | // INSERT: Valid statement with column list and ttl. |
55 | 0 | EXEC_VALID_STMT(InsertStmtWithTTL(std::to_string(1))); |
56 | | |
57 | | // INSERT: Valid statement with ttl at the lower limit. |
58 | 0 | EXEC_VALID_STMT(InsertStmtWithTTL(std::to_string(yb::common::kCassandraMinTtlSeconds))); |
59 | | |
60 | | // INSERT: Valid statement with ttl at the upper limit. |
61 | 0 | EXEC_VALID_STMT(InsertStmtWithTTL(std::to_string(yb::common::kCassandraMaxTtlSeconds))); |
62 | | |
63 | | // INSERT: Invalid statement with ttl just over limit. |
64 | 0 | EXEC_INVALID_STMT(InsertStmtWithTTL(std::to_string(yb::common::kCassandraMaxTtlSeconds + 1))); |
65 | | |
66 | | // INSERT: Invalid statement with ttl just below lower limit. |
67 | 0 | EXEC_INVALID_STMT(InsertStmtWithTTL(std::to_string(yb::common::kCassandraMinTtlSeconds - 1))); |
68 | | |
69 | | // INSERT: Invalid statement with ttl too high. |
70 | 0 | EXEC_INVALID_STMT(InsertStmtWithTTL(std::to_string(std::numeric_limits<int64_t>::max()))); |
71 | | |
72 | | // INSERT: Invalid statement with float ttl. |
73 | 0 | EXEC_INVALID_STMT(InsertStmtWithTTL("1.1")); |
74 | | |
75 | | // INSERT: Invalid statement with negative ttl. |
76 | 0 | EXEC_INVALID_STMT(InsertStmtWithTTL(std::to_string(-1))); |
77 | | |
78 | | // INSERT: Invalid statement with hex ttl. |
79 | 0 | EXEC_INVALID_STMT(InsertStmtWithTTL("0x100")); |
80 | | |
81 | | // INSERT: Statement with invalid TTL syntax. |
82 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource(id, name, salary) VALUES(1, 'Scott Tiger', 100) " |
83 | 0 | "TTL 1000;"); |
84 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource(id, name, salary) VALUES(-1, 'Scott Tiger', -100) " |
85 | 0 | "TTL 1000;"); |
86 | | |
87 | | // INSERT: Statement with invalid TTL value. |
88 | 0 | EXEC_INVALID_STMT(InsertStmtWithTTL("abcxyz")); |
89 | | |
90 | | // INSERT: Invalid CQL statement though it's a valid SQL statement without column list. |
91 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource VALUES(2, 'Scott Tiger', 100);"); |
92 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource VALUES(-2, 'Scott Tiger', -100);"); |
93 | | |
94 | | // INSERT: Invalid statement - Duplicate key. |
95 | | // IF NOT EXISTS is not implemented yet, so we ignore this test case for now. |
96 | 0 | EXEC_VALID_STMT("INSERT INTO human_resource(id, name, salary) VALUES(1, 'Scott Tiger', 100) " |
97 | 0 | "IF NOT EXISTS;"); |
98 | 0 | EXEC_VALID_STMT("INSERT INTO human_resource(id, name, salary) VALUES(-1, 'Scott Tiger', -100) " |
99 | 0 | "IF NOT EXISTS;"); |
100 | | |
101 | | // INSERT: Invalid statement - "--" is not yet supported. |
102 | | // TODO(neil) Parser needs to handle this error more elegantly. |
103 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource_wrong(id, name, salary)" |
104 | 0 | " VALUES(--1, 'Scott Tiger', 100);"); |
105 | | |
106 | | // INSERT: Invalid statement - Wrong table name. |
107 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource_wrong(id, name, salary)" |
108 | 0 | " VALUES(1, 'Scott Tiger', 100);"); |
109 | | |
110 | | // INSERT: Invalid statement - Mismatch column and argument count. |
111 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource(id, name, salary) VALUES(1, 'Scott Tiger');"); |
112 | | |
113 | | // INSERT: Invalid statement - Mismatch column and argument count. |
114 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource(id, name, salary)" |
115 | 0 | " VALUES(1, 'Scott Tiger', 100, 200);"); |
116 | | |
117 | | // INSERT: Invalid statement - Mismatch column and argument count. |
118 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource(id, name, salary) VALUES(1);"); |
119 | | |
120 | | // INSERT: Invalid statement - Mismatch column and argument count. |
121 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource(id, name) VALUES(1, 'Scott Tiger', 100);"); |
122 | | |
123 | | // INSERT: Invalid statement - Missing primary key (id). |
124 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource(name, salary) VALUES('Scott Tiger', 100);"); |
125 | | |
126 | | // INSERT: Invalid statement - Missing primary key (name). |
127 | 0 | EXEC_INVALID_STMT("INSERT INTO human_resource(id, salary) VALUES(2, 100);"); |
128 | | |
129 | | // Because string and numeric datatypes are implicitly compatible, we cannot test datatype |
130 | | // mismatch yet. Once timestamp, boolean, ... types are introduced, type incompability should be |
131 | | // tested here also. |
132 | 0 | } |
133 | | |
134 | 0 | TEST_F(TestQLInsertTable, TestQLInsertCast) { |
135 | | // Init the simulated cluster. |
136 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
137 | | |
138 | | // Get a processor. |
139 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
140 | 0 | std::shared_ptr<QLRowBlock> row_block; |
141 | 0 | LOG(INFO) << "Test inserting with cast(... as text) built-in."; |
142 | | |
143 | | // Create table. |
144 | 0 | CHECK_VALID_STMT("CREATE TABLE test_cast (h int PRIMARY KEY, t text)"); |
145 | | |
146 | | // Test simple insert. |
147 | 0 | CHECK_VALID_STMT("INSERT INTO test_cast (h, t) values (1, 'a')"); |
148 | 0 | CHECK_VALID_STMT("SELECT * FROM test_cast"); |
149 | 0 | row_block = processor->row_block(); |
150 | 0 | CHECK_EQ(row_block->row_count(), 1); |
151 | 0 | EXPECT_EQ(1, row_block->row(0).column(0).int32_value()); |
152 | 0 | EXPECT_EQ("a", row_block->row(0).column(1).string_value()); |
153 | | |
154 | | // Test various insert vi cast() built-in. |
155 | | // cast(FLOAT as TEXT) |
156 | 0 | CHECK_VALID_STMT("INSERT INTO test_cast (h, t) values (3, cast(1234.5 as text))"); |
157 | 0 | CHECK_VALID_STMT("SELECT * FROM test_cast where h = 3"); |
158 | 0 | row_block = processor->row_block(); |
159 | 0 | CHECK_EQ(row_block->row_count(), 1); |
160 | 0 | EXPECT_EQ(3, row_block->row(0).column(0).int32_value()); |
161 | 0 | EXPECT_EQ("1234.5", row_block->row(0).column(1).string_value()); |
162 | | // cast(TEXT as TEXT) |
163 | 0 | CHECK_VALID_STMT("INSERT INTO test_cast (h, t) values (4, cast('ABC' as text))"); |
164 | 0 | CHECK_VALID_STMT("SELECT * FROM test_cast where h = 4"); |
165 | 0 | row_block = processor->row_block(); |
166 | 0 | CHECK_EQ(row_block->row_count(), 1); |
167 | 0 | EXPECT_EQ(4, row_block->row(0).column(0).int32_value()); |
168 | 0 | EXPECT_EQ("ABC", row_block->row(0).column(1).string_value()); |
169 | | // cast(TEXT as TEXT) where the string is a list in string. |
170 | 0 | CHECK_VALID_STMT("INSERT INTO test_cast (h, t) values (5, cast('[1, 2]' as text))"); |
171 | 0 | CHECK_VALID_STMT("SELECT * FROM test_cast where h = 5"); |
172 | 0 | row_block = processor->row_block(); |
173 | 0 | CHECK_EQ(row_block->row_count(), 1); |
174 | 0 | EXPECT_EQ(5, row_block->row(0).column(0).int32_value()); |
175 | 0 | EXPECT_EQ("[1, 2]", row_block->row(0).column(1).string_value()); |
176 | | |
177 | | // cast(INT as TEXT) |
178 | 0 | EXEC_INVALID_STMT_WITH_ERROR("INSERT INTO test_cast (h, t) values (2, cast(22 as text))", |
179 | 0 | "Execution Error. Cannot convert varint to text"); |
180 | | // cast(LIST as TEXT) |
181 | 0 | EXEC_INVALID_STMT_WITH_ERROR("INSERT INTO test_cast (h, t) values (7, cast([1, 2] as text))", |
182 | 0 | "Invalid Arguments. Input argument must be of primitive type"); |
183 | | // cast(SET as TEXT) |
184 | 0 | EXEC_INVALID_STMT_WITH_ERROR("INSERT INTO test_cast (h, t) values (7, cast({1, 2} as text))", |
185 | 0 | "Invalid Arguments. Input argument must be of primitive type"); |
186 | | // cast(MAP as TEXT) |
187 | 0 | EXEC_INVALID_STMT_WITH_ERROR( |
188 | 0 | "INSERT INTO test_cast (h, t) values (7, cast({'a':11, 'b':22} as text))", |
189 | 0 | "Invalid Arguments. Input argument must be of primitive type"); |
190 | 0 | } |
191 | | |
192 | 0 | TEST_F(TestQLInsertTable, TestQLInsertToJson) { |
193 | | // Init the simulated cluster. |
194 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
195 | | |
196 | | // Get a processor. |
197 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
198 | 0 | std::shared_ptr<QLRowBlock> row_block; |
199 | 0 | LOG(INFO) << "Test inserting with ToJson() built-in."; |
200 | |
|
201 | 0 | auto to_json_str = [](const QLValue& value) -> string { |
202 | 0 | common::Jsonb jsonb(value.jsonb_value()); |
203 | 0 | string str; |
204 | 0 | CHECK_OK(jsonb.ToJsonString(&str)); |
205 | 0 | return str; |
206 | 0 | }; |
207 | | |
208 | | // Create table with JSONB. |
209 | 0 | CHECK_VALID_STMT("CREATE TABLE test_json (h int PRIMARY KEY, j jsonb)"); |
210 | | |
211 | | // Test simple JSON insert. |
212 | 0 | CHECK_VALID_STMT("INSERT INTO test_json (h, j) values (1, '{\"a\":123}')"); |
213 | 0 | CHECK_VALID_STMT("SELECT * FROM test_json"); |
214 | 0 | row_block = processor->row_block(); |
215 | 0 | CHECK_EQ(row_block->row_count(), 1); |
216 | 0 | EXPECT_EQ(1, row_block->row(0).column(0).int32_value()); |
217 | 0 | EXPECT_EQ("{\"a\":123}", to_json_str(row_block->row(0).column(1))); |
218 | | |
219 | | // Test various insert vi ToJson() built-in. |
220 | | // ToJson(INT) |
221 | 0 | CHECK_VALID_STMT("INSERT INTO test_json (h, j) values (2, ToJson(22))"); |
222 | 0 | CHECK_VALID_STMT("SELECT * FROM test_json where h = 2"); |
223 | 0 | row_block = processor->row_block(); |
224 | 0 | CHECK_EQ(row_block->row_count(), 1); |
225 | 0 | EXPECT_EQ(2, row_block->row(0).column(0).int32_value()); |
226 | 0 | EXPECT_EQ("22", to_json_str(row_block->row(0).column(1))); |
227 | | // ToJson(FLOAT) |
228 | 0 | CHECK_VALID_STMT("INSERT INTO test_json (h, j) values (3, ToJson(1234.5))"); |
229 | 0 | CHECK_VALID_STMT("SELECT * FROM test_json where h = 3"); |
230 | 0 | row_block = processor->row_block(); |
231 | 0 | CHECK_EQ(row_block->row_count(), 1); |
232 | 0 | EXPECT_EQ(3, row_block->row(0).column(0).int32_value()); |
233 | 0 | EXPECT_EQ("1234.5", to_json_str(row_block->row(0).column(1))); |
234 | | // ToJson(TEXT) |
235 | 0 | CHECK_VALID_STMT("INSERT INTO test_json (h, j) values (4, ToJson('ABC'))"); |
236 | 0 | CHECK_VALID_STMT("SELECT * FROM test_json where h = 4"); |
237 | 0 | row_block = processor->row_block(); |
238 | 0 | CHECK_EQ(row_block->row_count(), 1); |
239 | 0 | EXPECT_EQ(4, row_block->row(0).column(0).int32_value()); |
240 | 0 | EXPECT_EQ("\"ABC\"", to_json_str(row_block->row(0).column(1))); |
241 | | // ToJson(TEXT) where the string is a list in string. |
242 | 0 | CHECK_VALID_STMT("INSERT INTO test_json (h, j) values (5, ToJson('[1, 2]'))"); |
243 | 0 | CHECK_VALID_STMT("SELECT * FROM test_json where h = 5"); |
244 | 0 | row_block = processor->row_block(); |
245 | 0 | CHECK_EQ(row_block->row_count(), 1); |
246 | 0 | EXPECT_EQ(5, row_block->row(0).column(0).int32_value()); |
247 | 0 | EXPECT_EQ("\"[1, 2]\"", to_json_str(row_block->row(0).column(1))); |
248 | | // ToJson(TEXT) where the string is a set in string. |
249 | 0 | CHECK_VALID_STMT("INSERT INTO test_json (h, j) values (6, ToJson('{1, 2}'))"); |
250 | 0 | CHECK_VALID_STMT("SELECT * FROM test_json where h = 6"); |
251 | 0 | row_block = processor->row_block(); |
252 | 0 | CHECK_EQ(row_block->row_count(), 1); |
253 | 0 | EXPECT_EQ(6, row_block->row(0).column(0).int32_value()); |
254 | 0 | EXPECT_EQ("\"{1, 2}\"", to_json_str(row_block->row(0).column(1))); |
255 | | |
256 | | // ToJson(LIST) |
257 | 0 | EXEC_INVALID_STMT_WITH_ERROR("INSERT INTO test_json (h, j) values (7, ToJson([1, 2]))", |
258 | 0 | "Invalid Arguments. Input argument must be of primitive type"); |
259 | | // ToJson(SET) |
260 | 0 | EXEC_INVALID_STMT_WITH_ERROR("INSERT INTO test_json (h, j) values (8, ToJson({3, 4}))", |
261 | 0 | "Invalid Arguments. Input argument must be of primitive type"); |
262 | | // ToJson(MAP) |
263 | 0 | EXEC_INVALID_STMT_WITH_ERROR("INSERT INTO test_json (h, j) values (9, ToJson({5:55, 6:66}))", |
264 | 0 | "Invalid Arguments. Input argument must be of primitive type"); |
265 | 0 | EXEC_INVALID_STMT_WITH_ERROR( |
266 | 0 | "INSERT INTO test_json (h, j) values (10, ToJson({a : 1, b : 'foo'}))", |
267 | 0 | "Invalid Arguments. Input argument must be of primitive type"); |
268 | 0 | } |
269 | | |
270 | | } // namespace ql |
271 | | } // namespace yb |