/Users/deen/code/yugabyte-db/src/yb/yql/pggate/test/pggate_test_select_multi_tablets.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/ybc-internal.h" |
17 | | |
18 | | #include "yb/util/status_log.h" |
19 | | |
20 | | #include "yb/yql/pggate/test/pggate_test.h" |
21 | | #include "yb/yql/pggate/ybc_pggate.h" |
22 | | |
23 | | namespace yb { |
24 | | namespace pggate { |
25 | | |
26 | | class PggateTestSelectMultiTablets : public PggateTest { |
27 | | }; |
28 | | |
29 | 0 | TEST_F(PggateTestSelectMultiTablets, TestSelectMultiTablets) { |
30 | 0 | CHECK_OK(Init("TestSelectMultiTablet")); |
31 | |
|
32 | 0 | const char *tabname = "basic_table"; |
33 | 0 | const YBCPgOid tab_oid = 3; |
34 | 0 | YBCPgStatement pg_stmt; |
35 | | |
36 | | // Create table in the connected database. |
37 | 0 | int col_count = 0; |
38 | 0 | CHECK_YBC_STATUS(YBCPgNewCreateTable(kDefaultDatabase, kDefaultSchema, tabname, |
39 | 0 | kDefaultDatabaseOid, tab_oid, |
40 | 0 | false /* is_shared_table */, true /* if_not_exist */, |
41 | 0 | false /* add_primary_key */, true /* colocated */, |
42 | 0 | kInvalidOid /* tablegroup_id */, |
43 | 0 | kInvalidOid /* tablespace_id */, |
44 | 0 | kInvalidOid /* matview_pg_table_id */, |
45 | 0 | &pg_stmt)); |
46 | 0 | CHECK_YBC_STATUS(YBCTestCreateTableAddColumn(pg_stmt, "hash_key", ++col_count, |
47 | 0 | DataType::INT64, true, true)); |
48 | 0 | CHECK_YBC_STATUS(YBCTestCreateTableAddColumn(pg_stmt, "id", ++col_count, |
49 | 0 | DataType::INT32, false, true)); |
50 | 0 | CHECK_YBC_STATUS(YBCTestCreateTableAddColumn(pg_stmt, "dependent_count", ++col_count, |
51 | 0 | DataType::INT16, false, false)); |
52 | 0 | CHECK_YBC_STATUS(YBCTestCreateTableAddColumn(pg_stmt, "project_count", ++col_count, |
53 | 0 | DataType::INT32, false, false)); |
54 | 0 | CHECK_YBC_STATUS(YBCTestCreateTableAddColumn(pg_stmt, "salary", ++col_count, |
55 | 0 | DataType::FLOAT, false, false)); |
56 | 0 | CHECK_YBC_STATUS(YBCTestCreateTableAddColumn(pg_stmt, "job", ++col_count, |
57 | 0 | DataType::STRING, false, false)); |
58 | 0 | CHECK_YBC_STATUS(YBCPgExecCreateTable(pg_stmt)); |
59 | 0 | pg_stmt = nullptr; |
60 | | |
61 | | // SELECT: Empty Table --------------------------------------------------------------------------- |
62 | 0 | LOG(INFO) << "Test SELECTing from empty table"; |
63 | 0 | CHECK_YBC_STATUS(YBCPgNewSelect(kDefaultDatabaseOid, tab_oid, |
64 | 0 | NULL /* prepare_params */, &pg_stmt)); |
65 | | |
66 | | // Specify the selected expressions. |
67 | 0 | YBCPgExpr colref; |
68 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 1, DataType::INT64, &colref)); |
69 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
70 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 2, DataType::INT32, &colref)); |
71 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
72 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 3, DataType::INT16, &colref)); |
73 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
74 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 4, DataType::INT32, &colref)); |
75 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
76 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 5, DataType::FLOAT, &colref)); |
77 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
78 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 6, DataType::STRING, &colref)); |
79 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
80 | | |
81 | | // Execute select statement. |
82 | 0 | BeginTransaction(); |
83 | 0 | CHECK_YBC_STATUS(YBCPgExecSelect(pg_stmt, nullptr /* exec_params */)); |
84 | | |
85 | | // Fetching rows and check their contents. |
86 | 0 | uint64_t *values = static_cast<uint64_t*>(YBCPAlloc(col_count * sizeof(uint64_t))); |
87 | 0 | bool *isnulls = static_cast<bool*>(YBCPAlloc(col_count * sizeof(bool))); |
88 | 0 | bool has_data = true; |
89 | 0 | while (has_data) { |
90 | 0 | CHECK_YBC_STATUS(YBCPgDmlFetch(pg_stmt, col_count, values, isnulls, nullptr, &has_data)); |
91 | 0 | CHECK(!has_data) << "Corrupted DB. Table is expected to be empty"; |
92 | 0 | } |
93 | 0 | CommitTransaction(); |
94 | | |
95 | | // Deallocate statement. |
96 | 0 | pg_stmt = nullptr; |
97 | | |
98 | | // INSERT ---------------------------------------------------------------------------------------- |
99 | | // Allocate new insert. |
100 | 0 | CHECK_YBC_STATUS(YBCPgNewInsert(kDefaultDatabaseOid, tab_oid, |
101 | 0 | false /* is_single_row_txn */, &pg_stmt)); |
102 | | |
103 | | // Allocate constant expressions. |
104 | | // TODO(neil) We can also allocate expression with bind. |
105 | 0 | int seed = 1; |
106 | 0 | YBCPgExpr expr_hash; |
107 | 0 | CHECK_YBC_STATUS(YBCTestNewConstantInt8(pg_stmt, seed, false, &expr_hash)); |
108 | 0 | YBCPgExpr expr_id; |
109 | 0 | CHECK_YBC_STATUS(YBCTestNewConstantInt4(pg_stmt, seed, false, &expr_id)); |
110 | 0 | YBCPgExpr expr_depcnt; |
111 | 0 | CHECK_YBC_STATUS(YBCTestNewConstantInt2(pg_stmt, seed, false, &expr_depcnt)); |
112 | 0 | YBCPgExpr expr_projcnt; |
113 | 0 | CHECK_YBC_STATUS(YBCTestNewConstantInt4(pg_stmt, 100 + seed, false, &expr_projcnt)); |
114 | 0 | YBCPgExpr expr_salary; |
115 | 0 | CHECK_YBC_STATUS(YBCTestNewConstantFloat4(pg_stmt, seed + 1.0*seed/10.0, false, &expr_salary)); |
116 | 0 | YBCPgExpr expr_job; |
117 | 0 | string job = strings::Substitute("Job_title_$0", seed); |
118 | 0 | CHECK_YBC_STATUS(YBCTestNewConstantText(pg_stmt, job.c_str(), false, &expr_job)); |
119 | | |
120 | | // Set column value to be inserted. |
121 | 0 | int attr_num = 0; |
122 | 0 | CHECK_YBC_STATUS(YBCPgDmlBindColumn(pg_stmt, ++attr_num, expr_hash)); |
123 | 0 | CHECK_YBC_STATUS(YBCPgDmlBindColumn(pg_stmt, ++attr_num, expr_id)); |
124 | 0 | CHECK_YBC_STATUS(YBCPgDmlBindColumn(pg_stmt, ++attr_num, expr_depcnt)); |
125 | 0 | CHECK_YBC_STATUS(YBCPgDmlBindColumn(pg_stmt, ++attr_num, expr_projcnt)); |
126 | 0 | CHECK_YBC_STATUS(YBCPgDmlBindColumn(pg_stmt, ++attr_num, expr_salary)); |
127 | 0 | CHECK_YBC_STATUS(YBCPgDmlBindColumn(pg_stmt, ++attr_num, expr_job)); |
128 | 0 | CHECK_EQ(attr_num, col_count); |
129 | |
|
130 | 0 | const int insert_row_count = 7; |
131 | 0 | for (int i = 0; i < insert_row_count; i++) { |
132 | | // Insert the row with the original seed. |
133 | 0 | BeginTransaction(); |
134 | 0 | CHECK_YBC_STATUS(YBCPgExecInsert(pg_stmt)); |
135 | 0 | CommitTransaction(); |
136 | | |
137 | | // Update the constant expresions to insert the next row. |
138 | | // TODO(neil) When we support binds, we can also call UpdateBind here. |
139 | 0 | seed++; |
140 | 0 | CHECK_YBC_STATUS(YBCPgUpdateConstInt8(expr_hash, seed, false)); |
141 | 0 | CHECK_YBC_STATUS(YBCPgUpdateConstInt4(expr_id, seed, false)); |
142 | 0 | CHECK_YBC_STATUS(YBCPgUpdateConstInt2(expr_depcnt, seed, false)); |
143 | 0 | CHECK_YBC_STATUS(YBCPgUpdateConstInt4(expr_projcnt, 100 + seed, false)); |
144 | 0 | CHECK_YBC_STATUS(YBCPgUpdateConstFloat4(expr_salary, seed + 1.0*seed/10.0, false)); |
145 | 0 | job = strings::Substitute("Job_title_$0", seed); |
146 | 0 | CHECK_YBC_STATUS(YBCPgUpdateConstChar(expr_job, job.c_str(), job.size(), false)); |
147 | 0 | } |
148 | |
|
149 | 0 | pg_stmt = nullptr; |
150 | | |
151 | | // SELECT ---------------------------------------------------------------------------------------- |
152 | 0 | LOG(INFO) << "Test SELECTing from partitioned table WITH specifying RANGE column"; |
153 | 0 | CHECK_YBC_STATUS(YBCPgNewSelect(kDefaultDatabaseOid, tab_oid, |
154 | 0 | NULL /* prepare_params */, &pg_stmt)); |
155 | | |
156 | | // Specify the selected expressions. |
157 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 1, DataType::INT64, &colref)); |
158 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
159 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 2, DataType::INT32, &colref)); |
160 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
161 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 3, DataType::INT16, &colref)); |
162 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
163 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 4, DataType::INT32, &colref)); |
164 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
165 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 5, DataType::FLOAT, &colref)); |
166 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
167 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 6, DataType::STRING, &colref)); |
168 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
169 | | |
170 | | // Set partition and range columns for SELECT to select a specific row. |
171 | | // SELECT ... WHERE hash = seed AND id = seed. |
172 | 0 | seed = 3; |
173 | 0 | attr_num = 0; |
174 | 0 | CHECK_YBC_STATUS(YBCTestNewConstantInt8(pg_stmt, seed, false, &expr_hash)); |
175 | 0 | CHECK_YBC_STATUS(YBCPgDmlBindColumn(pg_stmt, ++attr_num, expr_hash)); |
176 | 0 | CHECK_YBC_STATUS(YBCTestNewConstantInt4(pg_stmt, seed, false, &expr_id)); |
177 | 0 | CHECK_YBC_STATUS(YBCPgDmlBindColumn(pg_stmt, ++attr_num, expr_id)); |
178 | | |
179 | | // Execute select statement. |
180 | 0 | BeginTransaction(); |
181 | 0 | CHECK_YBC_STATUS(YBCPgExecSelect(pg_stmt, nullptr /* exec_params */)); |
182 | | |
183 | | // Fetching rows and check their contents. |
184 | 0 | values = static_cast<uint64_t*>(YBCPAlloc(col_count * sizeof(uint64_t))); |
185 | 0 | isnulls = static_cast<bool*>(YBCPAlloc(col_count * sizeof(bool))); |
186 | 0 | int select_row_count = 0; |
187 | 0 | for (int i = 0; i < insert_row_count; i++) { |
188 | 0 | has_data = false; |
189 | 0 | CHECK_YBC_STATUS(YBCPgDmlFetch(pg_stmt, col_count, values, isnulls, nullptr, &has_data)); |
190 | 0 | if (!has_data) { |
191 | 0 | break; |
192 | 0 | } |
193 | 0 | select_row_count++; |
194 | | |
195 | | // Print result |
196 | 0 | LOG(INFO) << "ROW " << i << ": " |
197 | 0 | << "hash_key = " << values[0] |
198 | 0 | << ", id = " << values[1] |
199 | 0 | << ", dependent count = " << values[2] |
200 | 0 | << ", project count = " << values[3] |
201 | 0 | << ", salary = " << *reinterpret_cast<float*>(&values[4]) |
202 | 0 | << ", job = (" << values[5] << ")"; |
203 | | |
204 | | // Check result. |
205 | 0 | int col_index = 0; |
206 | 0 | int64_t id = values[col_index++]; // hash_key : int64 |
207 | 0 | CHECK_EQ(id, seed) << "Unexpected result for hash column"; |
208 | 0 | CHECK_EQ(values[col_index++], id); // id : int32 |
209 | 0 | CHECK_EQ(values[col_index++], id); // dependent_count : int16 |
210 | 0 | CHECK_EQ(values[col_index++], 100 + id); // project_count : int32 |
211 | |
|
212 | 0 | float salary = *reinterpret_cast<float*>(&values[col_index++]); // salary : float |
213 | 0 | CHECK_LE(salary, id + 1.0*id/10.0 + 0.01); |
214 | 0 | CHECK_GE(salary, id + 1.0*id/10.0 - 0.01); |
215 | |
|
216 | 0 | string selected_job_name = reinterpret_cast<char*>(values[col_index++]); |
217 | 0 | string expected_job_name = strings::Substitute("Job_title_$0", id); |
218 | 0 | CHECK_EQ(selected_job_name, expected_job_name); |
219 | 0 | } |
220 | 0 | CHECK_EQ(select_row_count, 1) << "Unexpected row count"; |
221 | 0 | CommitTransaction(); |
222 | |
|
223 | 0 | pg_stmt = nullptr; |
224 | | |
225 | | // SELECT ---------------------------------------------------------------------------------------- |
226 | 0 | LOG(INFO) << "Test SELECTing from partitioned table WITHOUT specifying RANGE column"; |
227 | 0 | CHECK_YBC_STATUS(YBCPgNewSelect(kDefaultDatabaseOid, tab_oid, |
228 | 0 | NULL /* prepare_params */, &pg_stmt)); |
229 | | |
230 | | // Specify the selected expressions. |
231 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 1, DataType::INT64, &colref)); |
232 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
233 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 2, DataType::INT32, &colref)); |
234 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
235 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 3, DataType::INT16, &colref)); |
236 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
237 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 4, DataType::INT32, &colref)); |
238 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
239 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 5, DataType::FLOAT, &colref)); |
240 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
241 | 0 | CHECK_YBC_STATUS(YBCTestNewColumnRef(pg_stmt, 6, DataType::STRING, &colref)); |
242 | 0 | CHECK_YBC_STATUS(YBCPgDmlAppendTarget(pg_stmt, colref)); |
243 | | |
244 | | // Execute select statement. |
245 | 0 | BeginTransaction(); |
246 | 0 | CHECK_YBC_STATUS(YBCPgExecSelect(pg_stmt, nullptr /* exec_params */)); |
247 | | |
248 | | // Fetching rows and check their contents. |
249 | 0 | values = static_cast<uint64_t*>(YBCPAlloc(col_count * sizeof(uint64_t))); |
250 | 0 | isnulls = static_cast<bool*>(YBCPAlloc(col_count * sizeof(bool))); |
251 | 0 | for (int i = 0; i < insert_row_count; i++) { |
252 | 0 | has_data = false; |
253 | 0 | CHECK_YBC_STATUS(YBCPgDmlFetch(pg_stmt, col_count, values, isnulls, nullptr, &has_data)); |
254 | 0 | CHECK(has_data) << "Not all inserted rows are fetch"; |
255 | | |
256 | | // Print result |
257 | 0 | LOG(INFO) << "ROW " << i << ": " |
258 | 0 | << "hash_key = " << values[0] |
259 | 0 | << ", id = " << values[1] |
260 | 0 | << ", dependent count = " << values[2] |
261 | 0 | << ", project count = " << values[3] |
262 | 0 | << ", salary = " << *reinterpret_cast<float*>(&values[4]) |
263 | 0 | << ", job = (" << values[5] << ")"; |
264 | | |
265 | | // Check result. |
266 | 0 | int col_index = 0; |
267 | 0 | int64_t id = values[col_index++]; // hash_key : int64 |
268 | 0 | CHECK_EQ(values[col_index++], id); // id : int32 |
269 | 0 | CHECK_EQ(values[col_index++], id); // dependent_count : int16 |
270 | 0 | CHECK_EQ(values[col_index++], 100 + id); // project_count : int32 |
271 | |
|
272 | 0 | float salary = *reinterpret_cast<float*>(&values[col_index++]); // salary : float |
273 | 0 | CHECK_LE(salary, id + 1.0*id/10.0 + 0.01); // salary |
274 | 0 | CHECK_GE(salary, id + 1.0*id/10.0 - 0.01); // float |
275 | |
|
276 | 0 | string selected_job_name = reinterpret_cast<char*>(values[col_index++]); |
277 | 0 | string expected_job_name = strings::Substitute("Job_title_$0", id); |
278 | 0 | CHECK_EQ(selected_job_name, expected_job_name); |
279 | 0 | } |
280 | 0 | CommitTransaction(); |
281 | |
|
282 | 0 | pg_stmt = nullptr; |
283 | 0 | } |
284 | | |
285 | | } // namespace pggate |
286 | | } // namespace yb |