YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/tablet/composite-pushdown-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include <algorithm>
34
#include <limits>
35
#include <string>
36
#include <unordered_set>
37
#include <vector>
38
39
#include <glog/logging.h>
40
#include <gtest/gtest.h>
41
42
#include "yb/common/partial_row.h"
43
#include "yb/common/ql_protocol_util.h"
44
#include "yb/common/ql_rowblock.h"
45
#include "yb/common/schema.h"
46
47
#include "yb/gutil/strings/numbers.h"
48
#include "yb/gutil/strings/substitute.h"
49
50
#include "yb/tablet/local_tablet_writer.h"
51
#include "yb/tablet/read_result.h"
52
#include "yb/tablet/tablet-test-util.h"
53
#include "yb/tablet/tablet.h"
54
55
#include "yb/util/env.h"
56
#include "yb/util/test_macros.h"
57
#include "yb/util/test_util.h"
58
59
namespace yb {
60
namespace tablet {
61
62
const char* const kTestHostnames[] = { "foo", "foobar", "baz", nullptr };
63
64
class CompositePushdownTest : public YBTabletTest {
65
 public:
66
  CompositePushdownTest()
67
      : YBTabletTest(Schema({ ColumnSchema("year", INT16, false, true),
68
                              ColumnSchema("month", INT8, false, true),
69
                              ColumnSchema("day", INT8, false, true),
70
                              ColumnSchema("hostname", STRING, false, true),
71
                              ColumnSchema("data", STRING) },
72
6
                            4)) {
73
6
  }
74
75
6
  void SetUp() override {
76
6
    YBTabletTest::SetUp();
77
78
6
    FillTestTablet();
79
6
  }
80
81
6
  void FillTestTablet() {
82
6
    int nrows = 10 * 12 * 28;
83
6
    int i = 0;
84
85
6
    LocalTabletWriter writer(tablet().get());
86
72
    for (int16_t year = 2000; year <= 2010; year++) {
87
858
      for (int8_t month = 1; month <= 12; month++) {
88
22.9k
        for (int8_t day = 1; day <= 28; day++) {
89
88.7k
          for (int host_idx = 0; kTestHostnames[host_idx] != nullptr; host_idx++) {
90
66.5k
            QLWriteRequestPB req;
91
66.5k
            QLAddInt16HashValue(&req, year);
92
66.5k
            QLAddInt8HashValue(&req, month);
93
66.5k
            QLAddInt8HashValue(&req, day);
94
66.5k
            QLAddStringHashValue(&req, kTestHostnames[host_idx]);
95
66.5k
            QLAddStringColumnValue(&req, kFirstColumnId + 4,
96
66.5k
                StringPrintf("%d/%02d/%02d-%s", year, month, day, kTestHostnames[host_idx]));
97
66.5k
            ASSERT_OK_FAST(writer.Write(&req));
98
99
66.5k
            if (i == nrows * 9 / 10) {
100
6
              ASSERT_OK(tablet()->Flush(tablet::FlushMode::kSync));
101
6
            }
102
66.5k
            ++i;
103
66.5k
          }
104
22.1k
        }
105
792
      }
106
66
    }
107
6
  }
108
109
  // Helper function for sorting returned results by the 'data' field.
110
  // This is needed as "2" is lexicographically greater than "12" which means
111
  // that, e.g., comparing "(int16 year=2001, int8 month=2, int8 day=7, string
112
  // data=2001/02/07)" to "(int16 year=2001, int8 month=12, int8
113
  // day=7, string data=2001/12/07)" would be semantically incorrect if
114
  // the comparison was on the whole string vs the last portion of the
115
  // string ("2001/02/01" vs. "2001/12/01")
116
  struct SuffixComparator {
117
258k
    bool operator()(const string &a, const string &b) {
118
258k
      string s_a = a.substr(a.find("\", string:"));
119
258k
      string s_b = b.substr(b.find("\", string:"));
120
258k
      return s_a < s_b;
121
258k
    }
122
  };
123
124
13
  void ScanTablet(QLReadRequestPB* req, vector<string> *results) {
125
13
    ReadHybridTime read_time = ReadHybridTime::SingleTime(ASSERT_RESULT(tablet()->SafeTime()));
126
13
    QLReadRequestResult result;
127
13
    TransactionMetadataPB transaction;
128
13
    QLAddColumns(schema_, {}, req);
129
13
    EXPECT_OK(tablet()->HandleQLReadRequest(
130
13
        CoarseTimePoint::max() /* deadline */, read_time, *req, transaction, &result));
131
132
26
    ASSERT_EQ(QLResponsePB::YQL_STATUS_OK, result.response.status())
133
26
        << "Error: " << result.response.error_message();
134
135
13
    auto row_block = CreateRowBlock(QLClient::YQL_CLIENT_CQL, schema_, result.rows_data);
136
19.4k
    for (const auto& row : row_block->rows()) {
137
19.4k
      results->push_back(row.ToString());
138
19.4k
    }
139
13
    std::sort(results->begin(), results->end(), SuffixComparator());
140
19.4k
    for (const string &str : *results) {
141
0
      VLOG(1) << str;
142
19.4k
    }
143
13
  }
144
};
145
146
1
TEST_F(CompositePushdownTest, TestPushDownExactEquality) {
147
1
  int16_t year = 2001;
148
1
  int8_t month = 9;
149
1
  int8_t day = 7;
150
151
1
  QLReadRequestPB req;
152
1
  auto cond = req.mutable_where_expr()->mutable_condition();
153
1
  cond->set_op(QLOperator::QL_OP_AND);
154
1
  QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
155
1
  cond = cond->add_operands()->mutable_condition();
156
1
  cond->set_op(QLOperator::QL_OP_AND);
157
1
  QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_EQUAL, month);
158
1
  cond = cond->add_operands()->mutable_condition();
159
1
  cond->set_op(QLOperator::QL_OP_AND);
160
1
  QLAddInt8Condition(cond, kFirstColumnId + 2, QL_OP_EQUAL, day);
161
1
  QLAddStringCondition(cond, kFirstColumnId + 3, QL_OP_EQUAL, kTestHostnames[0]);
162
163
1
  vector<string> results;
164
1
  ASSERT_NO_FATALS(ScanTablet(&req, &results));
165
1
  ASSERT_EQ(1, results.size());
166
1
  EXPECT_EQ("{ int16:2001, int8:9, int8:7, string:\"foo\", string:\"2001/09/07-foo\" }",
167
1
            results.front());
168
1
}
169
170
171
// Test for "host <= 'foo'" which should reject 'foobaz'.
172
// Regression test for a bug in an earlier implementation of predicate pushdown.
173
1
TEST_F(CompositePushdownTest, TestPushDownStringInequality) {
174
1
  int16_t year = 2001;
175
1
  int8_t month = 9;
176
1
  int8_t day = 7;
177
178
1
  QLReadRequestPB req;
179
1
  auto cond = req.mutable_where_expr()->mutable_condition();
180
1
  cond->set_op(QLOperator::QL_OP_AND);
181
1
  QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
182
1
  cond = cond->add_operands()->mutable_condition();
183
1
  cond->set_op(QLOperator::QL_OP_AND);
184
1
  QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_EQUAL, month);
185
1
  cond = cond->add_operands()->mutable_condition();
186
1
  cond->set_op(QLOperator::QL_OP_AND);
187
1
  QLAddInt8Condition(cond, kFirstColumnId + 2, QL_OP_EQUAL, day);
188
1
  QLAddStringCondition(cond, kFirstColumnId + 3, QL_OP_LESS_THAN_EQUAL, kTestHostnames[0]);
189
190
1
  vector<string> results;
191
1
  ASSERT_NO_FATALS(ScanTablet(&req, &results));
192
1
  ASSERT_EQ(2, results.size());
193
1
  EXPECT_EQ("{ int16:2001, int8:9, int8:7, string:\"baz\", string:\"2001/09/07-baz\" }",
194
1
            results.front());
195
1
  EXPECT_EQ("{ int16:2001, int8:9, int8:7, string:\"foo\", string:\"2001/09/07-foo\" }",
196
1
            results.back());
197
1
}
198
199
1
TEST_F(CompositePushdownTest, TestPushDownDateEquality) {
200
1
  int16_t year = 2001;
201
1
  int8_t month = 9;
202
1
  int8_t day = 7;
203
204
1
  QLReadRequestPB req;
205
1
  auto cond = req.mutable_where_expr()->mutable_condition();
206
1
  cond->set_op(QLOperator::QL_OP_AND);
207
1
  QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
208
1
  cond = cond->add_operands()->mutable_condition();
209
1
  cond->set_op(QLOperator::QL_OP_AND);
210
1
  QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_EQUAL, month);
211
1
  QLAddInt8Condition(cond, kFirstColumnId + 2, QL_OP_EQUAL, day);
212
213
1
  vector<string> results;
214
1
  ASSERT_NO_FATALS(ScanTablet(&req, &results));
215
1
  ASSERT_EQ(3, results.size());
216
1
  EXPECT_EQ("{ int16:2001, int8:9, int8:7, string:\"baz\", string:\"2001/09/07-baz\" }",
217
1
            results[0]);
218
1
  EXPECT_EQ("{ int16:2001, int8:9, int8:7, string:\"foo\", string:\"2001/09/07-foo\" }",
219
1
            results[1]);
220
1
  EXPECT_EQ("{ int16:2001, int8:9, int8:7, string:\"foobar\", string:\"2001/09/07-foobar\" }",
221
1
            results[2]);
222
1
}
223
224
1
TEST_F(CompositePushdownTest, TestPushDownPrefixEquality) {
225
1
  int16_t year = 2001;
226
1
  int8_t month = 9;
227
228
1
  {
229
1
    QLReadRequestPB req;
230
1
    auto cond = req.mutable_where_expr()->mutable_condition();
231
1
    cond->set_op(QLOperator::QL_OP_AND);
232
1
    QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
233
1
    QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_EQUAL, month);
234
235
1
    vector<string> results;
236
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
237
1
    ASSERT_EQ(28 * 3, results.size());
238
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:1, string:\"baz\", string:\"2001/09/01-baz\" }",
239
1
              results.front());
240
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:28, string:\"foobar\", string:\"2001/09/28-foobar\" }",
241
1
              results.back());
242
1
  }
243
244
1
  {
245
1
    QLReadRequestPB req;
246
1
    auto cond = req.mutable_where_expr()->mutable_condition();
247
1
    QLSetInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
248
249
1
    vector<string> results;
250
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
251
1
    ASSERT_EQ(28 * 12 * 3, results.size());
252
1
    EXPECT_EQ("{ int16:2001, int8:1, int8:1, string:\"baz\", string:\"2001/01/01-baz\" }",
253
1
              results.front());
254
1
    EXPECT_EQ("{ int16:2001, int8:2, int8:1, string:\"baz\", string:\"2001/02/01-baz\" }",
255
1
              results[28 * 3]);
256
1
    EXPECT_EQ("{ int16:2001, int8:12, int8:28, string:\"foobar\", string:\"2001/12/28-foobar\" }",
257
1
              results.back());
258
1
  }
259
1
}
260
261
1
TEST_F(CompositePushdownTest, TestPushDownPrefixEqualitySuffixInequality) {
262
1
  int16_t year = 2001;
263
1
  int8_t month_l = 9;
264
1
  int8_t month_u = 11;
265
1
  int8_t day_l = 1;
266
1
  int8_t day_u = 15;
267
268
1
  {
269
    // year=2001, month=9, day >= 1 && day <= 15
270
1
    QLReadRequestPB req;
271
1
    auto cond = req.mutable_where_expr()->mutable_condition();
272
1
    cond->set_op(QLOperator::QL_OP_AND);
273
1
    QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
274
1
    cond = cond->add_operands()->mutable_condition();
275
1
    cond->set_op(QLOperator::QL_OP_AND);
276
1
    QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_EQUAL, month_l);
277
1
    cond = cond->add_operands()->mutable_condition();
278
1
    cond->set_op(QLOperator::QL_OP_AND);
279
1
    QLAddInt8Condition(cond, kFirstColumnId + 2, QL_OP_GREATER_THAN_EQUAL, day_l);
280
1
    QLAddInt8Condition(cond, kFirstColumnId + 2, QL_OP_LESS_THAN_EQUAL, day_u);
281
282
1
    vector<string> results;
283
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
284
1
    ASSERT_EQ(15 * 3, results.size());
285
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:1, string:\"baz\", string:\"2001/09/01-baz\" }",
286
1
              results.front());
287
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:15, string:\"foobar\", string:\"2001/09/15-foobar\" }",
288
1
              results.back());
289
1
  }
290
291
1
  {
292
    // year=2001, month=9, day >= 1
293
1
    QLReadRequestPB req;
294
1
    auto cond = req.mutable_where_expr()->mutable_condition();
295
1
    cond->set_op(QLOperator::QL_OP_AND);
296
1
    QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
297
1
    cond = cond->add_operands()->mutable_condition();
298
1
    cond->set_op(QLOperator::QL_OP_AND);
299
1
    QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_EQUAL, month_l);
300
1
    QLAddInt8Condition(cond, kFirstColumnId + 2, QL_OP_GREATER_THAN_EQUAL, day_l);
301
302
1
    vector<string> results;
303
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
304
1
    ASSERT_EQ(28 * 3, results.size());
305
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:1, string:\"baz\", string:\"2001/09/01-baz\" }",
306
1
              results.front());
307
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:28, string:\"foobar\", string:\"2001/09/28-foobar\" }",
308
1
              results.back());
309
1
  }
310
311
1
  {
312
    // year=2001, month=9, day <= 15
313
1
    QLReadRequestPB req;
314
1
    auto cond = req.mutable_where_expr()->mutable_condition();
315
1
    cond->set_op(QLOperator::QL_OP_AND);
316
1
    QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
317
1
    cond = cond->add_operands()->mutable_condition();
318
1
    cond->set_op(QLOperator::QL_OP_AND);
319
1
    QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_EQUAL, month_l);
320
1
    QLAddInt8Condition(cond, kFirstColumnId + 2, QL_OP_LESS_THAN_EQUAL, day_u);
321
322
1
    vector<string> results;
323
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
324
1
    ASSERT_EQ(15 * 3, results.size());
325
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:1, string:\"baz\", string:\"2001/09/01-baz\" }",
326
1
              results.front());
327
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:15, string:\"foobar\", string:\"2001/09/15-foobar\" }",
328
1
              results.back());
329
1
  }
330
331
1
  {
332
    // year=2001, month >= 9 && month <= 11
333
1
    QLReadRequestPB req;
334
1
    auto cond = req.mutable_where_expr()->mutable_condition();
335
1
    cond->set_op(QLOperator::QL_OP_AND);
336
1
    QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
337
1
    cond = cond->add_operands()->mutable_condition();
338
1
    cond->set_op(QLOperator::QL_OP_AND);
339
1
    QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_GREATER_THAN_EQUAL, month_l);
340
1
    QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_LESS_THAN_EQUAL, month_u);
341
342
1
    vector<string> results;
343
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
344
1
    ASSERT_EQ(3 * 28 * 3, results.size());
345
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:1, string:\"baz\", string:\"2001/09/01-baz\" }",
346
1
              results.front());
347
1
    EXPECT_EQ( "{ int16:2001, int8:11, int8:28, string:\"foobar\", string:\"2001/11/28-foobar\" }",
348
1
              results.back());
349
1
  }
350
351
1
  {
352
    // year=2001, month <= 9
353
1
    QLReadRequestPB req;
354
1
    auto cond = req.mutable_where_expr()->mutable_condition();
355
1
    cond->set_op(QLOperator::QL_OP_AND);
356
1
    QLAddInt16Condition(cond, kFirstColumnId, QL_OP_EQUAL, year);
357
1
    QLAddInt8Condition(cond, kFirstColumnId + 1, QL_OP_LESS_THAN_EQUAL, month_l);
358
359
1
    vector<string> results;
360
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
361
1
    ASSERT_EQ(9 * 28 * 3, results.size());
362
1
    EXPECT_EQ("{ int16:2001, int8:1, int8:1, string:\"baz\", string:\"2001/01/01-baz\" }",
363
1
               results.front());
364
1
    EXPECT_EQ("{ int16:2001, int8:9, int8:28, string:\"foobar\", string:\"2001/09/28-foobar\" }",
365
1
              results.back());
366
1
  }
367
1
}
368
369
1
TEST_F(CompositePushdownTest, TestPushdownPrefixInequality) {
370
1
  int16_t year_2001 = 2001;
371
1
  int16_t year_2003 = 2003;
372
1
  {
373
    // year >= 2001 && year <= 2003
374
1
    QLReadRequestPB req;
375
1
    auto cond = req.mutable_where_expr()->mutable_condition();
376
1
    cond->set_op(QLOperator::QL_OP_AND);
377
1
    QLAddInt16Condition(cond, kFirstColumnId, QL_OP_GREATER_THAN_EQUAL, year_2001);
378
1
    QLAddInt16Condition(cond, kFirstColumnId, QL_OP_LESS_THAN_EQUAL, year_2003);
379
380
1
    vector<string> results;
381
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
382
1
    ASSERT_EQ(3 * 12 * 28 * 3, results.size());
383
1
    EXPECT_EQ("{ int16:2001, int8:1, int8:1, string:\"baz\", string:\"2001/01/01-baz\" }",
384
1
              results.front());
385
1
    EXPECT_EQ("{ int16:2003, int8:12, int8:28, string:\"foobar\", string:\"2003/12/28-foobar\" }",
386
1
              results.back());
387
1
  }
388
389
1
  {
390
    // year >= 2001
391
1
    QLReadRequestPB req;
392
1
    auto cond = req.mutable_where_expr()->mutable_condition();
393
1
    QLSetInt16Condition(cond, kFirstColumnId, QL_OP_GREATER_THAN_EQUAL, year_2001);
394
395
1
    vector<string> results;
396
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
397
1
    ASSERT_EQ(10 * 12 * 28 * 3, results.size());
398
1
    EXPECT_EQ("{ int16:2001, int8:1, int8:1, string:\"baz\", string:\"2001/01/01-baz\" }",
399
1
              results.front());
400
1
    EXPECT_EQ("{ int16:2010, int8:12, int8:28, string:\"foobar\", string:\"2010/12/28-foobar\" }",
401
1
              results.back());
402
1
  }
403
404
1
  {
405
    // year <= 2003
406
1
    QLReadRequestPB req;
407
1
    auto cond = req.mutable_where_expr()->mutable_condition();
408
1
    QLSetInt16Condition(cond, kFirstColumnId, QL_OP_LESS_THAN_EQUAL, year_2003);
409
410
1
    vector<string> results;
411
1
    ASSERT_NO_FATALS(ScanTablet(&req, &results));
412
1
    ASSERT_EQ(4 * 12 * 28 * 3, results.size());
413
1
    EXPECT_EQ("{ int16:2000, int8:1, int8:1, string:\"baz\", string:\"2000/01/01-baz\" }",
414
1
              results.front());
415
1
    EXPECT_EQ("{ int16:2003, int8:12, int8:28, string:\"foobar\", string:\"2003/12/28-foobar\" }",
416
1
              results.back());
417
1
  }
418
1
}
419
420
} // namespace tablet
421
} // namespace yb