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