/Users/deen/code/yugabyte-db/src/yb/integration-tests/cql_test_util.h
Line | Count | Source |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #ifndef YB_INTEGRATION_TESTS_CQL_TEST_UTIL_H |
15 | | #define YB_INTEGRATION_TESTS_CQL_TEST_UTIL_H |
16 | | |
17 | | #include <cassandra.h> |
18 | | |
19 | | #include <string> |
20 | | |
21 | | #include "yb/util/monotime.h" |
22 | | #include "yb/util/result.h" |
23 | | #include "yb/util/status_log.h" |
24 | | |
25 | | namespace yb { |
26 | | |
27 | | class CassandraJson; |
28 | | class CassandraStatement; |
29 | | |
30 | | // Cassandra CPP driver has his own functions to release objects, so we should use them for it. |
31 | | template <class T, void (*Func)(T*)> |
32 | | class FuncDeleter { |
33 | | public: |
34 | 427k | void operator()(T* t) const { |
35 | 427k | if (t427k ) { |
36 | 427k | Func(t); |
37 | 427k | } |
38 | 427k | } yb::FuncDeleter<CassIterator_, &(cass_iterator_free)>::operator()(CassIterator_*) const Line | Count | Source | 34 | 3.01k | void operator()(T* t) const { | 35 | 3.01k | if (t) { | 36 | 3.01k | Func(t); | 37 | 3.01k | } | 38 | 3.01k | } |
yb::FuncDeleter<CassResult_ const, &(cass_result_free)>::operator()(CassResult_ const*) const Line | Count | Source | 34 | 148 | void operator()(T* t) const { | 35 | 148 | if (t) { | 36 | 148 | Func(t); | 37 | 148 | } | 38 | 148 | } |
yb::FuncDeleter<CassPrepared_ const, &(cass_prepared_free)>::operator()(CassPrepared_ const*) const Line | Count | Source | 34 | 620 | void operator()(T* t) const { | 35 | 620 | if (t) { | 36 | 620 | Func(t); | 37 | 620 | } | 38 | 620 | } |
yb::FuncDeleter<CassFuture_, &(cass_future_free)>::operator()(CassFuture_*) const Line | Count | Source | 34 | 32.9k | void operator()(T* t) const { | 35 | 32.9k | if (t32.9k ) { | 36 | 32.9k | Func(t); | 37 | 32.9k | } | 38 | 32.9k | } |
yb::FuncDeleter<CassStatement_, &(cass_statement_free)>::operator()(CassStatement_*) const Line | Count | Source | 34 | 391k | void operator()(T* t) const { | 35 | 391k | if (t391k ) { | 36 | 391k | Func(t); | 37 | 391k | } | 38 | 391k | } |
|
39 | | }; |
40 | | |
41 | | template <class Out> |
42 | | struct GetCassandraValue { |
43 | | static CassError Apply(const CassValue* value, Out* out); |
44 | | }; |
45 | | |
46 | | class CassandraValue { |
47 | | public: |
48 | 11.7k | explicit CassandraValue(const CassValue* value) : value_(value) {} |
49 | | |
50 | | template <class Out> |
51 | 10.2k | void Get(Out* out) const { |
52 | 10.2k | CHECK_EQ(CASS_OK, GetCassandraValue<Out>::Apply(value_, out)); |
53 | 10.2k | } void yb::CassandraValue::Get<yb::Slice>(yb::Slice*) const Line | Count | Source | 51 | 2.86k | void Get(Out* out) const { | 52 | 2.86k | CHECK_EQ(CASS_OK, GetCassandraValue<Out>::Apply(value_, out)); | 53 | 2.86k | } |
void yb::CassandraValue::Get<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const Line | Count | Source | 51 | 4.36k | void Get(Out* out) const { | 52 | 4.36k | CHECK_EQ(CASS_OK, GetCassandraValue<Out>::Apply(value_, out)); | 53 | 4.36k | } |
void yb::CassandraValue::Get<long long>(long long*) const Line | Count | Source | 51 | 34 | void Get(Out* out) const { | 52 | 34 | CHECK_EQ(CASS_OK, GetCassandraValue<Out>::Apply(value_, out)); | 53 | 34 | } |
void yb::CassandraValue::Get<int>(int*) const Line | Count | Source | 51 | 79 | void Get(Out* out) const { | 52 | 79 | CHECK_EQ(CASS_OK, GetCassandraValue<Out>::Apply(value_, out)); | 53 | 79 | } |
void yb::CassandraValue::Get<CassUuid_>(CassUuid_*) const Line | Count | Source | 51 | 1.43k | void Get(Out* out) const { | 52 | 1.43k | CHECK_EQ(CASS_OK, GetCassandraValue<Out>::Apply(value_, out)); | 53 | 1.43k | } |
void yb::CassandraValue::Get<CassInet_>(CassInet_*) const Line | Count | Source | 51 | 1.48k | void Get(Out* out) const { | 52 | 1.48k | CHECK_EQ(CASS_OK, GetCassandraValue<Out>::Apply(value_, out)); | 53 | 1.48k | } |
|
54 | | |
55 | | template <class Out> |
56 | 10.2k | Out As() const { |
57 | 10.2k | Out result; |
58 | 10.2k | Get(&result); |
59 | 10.2k | return result; |
60 | 10.2k | } yb::Slice yb::CassandraValue::As<yb::Slice>() const Line | Count | Source | 56 | 2.86k | Out As() const { | 57 | 2.86k | Out result; | 58 | 2.86k | Get(&result); | 59 | 2.86k | return result; | 60 | 2.86k | } |
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > yb::CassandraValue::As<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >() const Line | Count | Source | 56 | 4.34k | Out As() const { | 57 | 4.34k | Out result; | 58 | 4.34k | Get(&result); | 59 | 4.34k | return result; | 60 | 4.34k | } |
long long yb::CassandraValue::As<long long>() const Line | Count | Source | 56 | 31 | Out As() const { | 57 | 31 | Out result; | 58 | 31 | Get(&result); | 59 | 31 | return result; | 60 | 31 | } |
int yb::CassandraValue::As<int>() const Line | Count | Source | 56 | 66 | Out As() const { | 57 | 66 | Out result; | 58 | 66 | Get(&result); | 59 | 66 | return result; | 60 | 66 | } |
CassUuid_ yb::CassandraValue::As<CassUuid_>() const Line | Count | Source | 56 | 1.43k | Out As() const { | 57 | 1.43k | Out result; | 58 | 1.43k | Get(&result); | 59 | 1.43k | return result; | 60 | 1.43k | } |
CassInet_ yb::CassandraValue::As<CassInet_>() const Line | Count | Source | 56 | 1.48k | Out As() const { | 57 | 1.48k | Out result; | 58 | 1.48k | Get(&result); | 59 | 1.48k | return result; | 60 | 1.48k | } |
|
61 | | |
62 | | bool IsNull() const; |
63 | | |
64 | | std::string ToString() const; |
65 | | |
66 | | private: |
67 | | const CassValue* value_; |
68 | | }; |
69 | | |
70 | | typedef std::unique_ptr< |
71 | | CassIterator, FuncDeleter<CassIterator, &cass_iterator_free>> CassIteratorPtr; |
72 | | |
73 | | class CassandraRowIterator { |
74 | | public: |
75 | 1.43k | explicit CassandraRowIterator(CassIterator* iterator) : cass_iterator_(iterator) {} |
76 | | |
77 | | bool Next(); |
78 | | |
79 | | template <class Out> |
80 | | void Get(Out* out) const { |
81 | | Value().Get(out); |
82 | | } |
83 | | |
84 | | CassandraValue Value() const; |
85 | | |
86 | | private: |
87 | | CassIteratorPtr cass_iterator_; |
88 | | }; |
89 | | |
90 | | class CassandraRow { |
91 | | public: |
92 | 1.52k | explicit CassandraRow(const CassRow* row) : cass_row_(row) {} |
93 | | |
94 | | template <class Out> |
95 | | void Get(size_t index, Out* out) const { |
96 | | return Value(index).Get(out); |
97 | | } |
98 | | |
99 | | CassandraValue Value(size_t index) const; |
100 | | |
101 | | CassandraRowIterator CreateIterator() const; |
102 | | |
103 | | std::string RenderToString(const std::string& separator = ","); |
104 | | |
105 | | void TakeIterator(CassIteratorPtr iterator); |
106 | | |
107 | | private: |
108 | | const CassRow* cass_row_; // owned by iterator |
109 | | CassIteratorPtr cass_iterator_; |
110 | | }; |
111 | | |
112 | | class CassandraIterator { |
113 | | public: |
114 | 146 | explicit CassandraIterator(CassIterator* iterator) : cass_iterator_(iterator) {} |
115 | | |
116 | | bool Next(); |
117 | | |
118 | | CassandraRow Row(); |
119 | | |
120 | | void MoveToRow(CassandraRow* row); |
121 | | |
122 | | private: |
123 | | CassIteratorPtr cass_iterator_; |
124 | | }; |
125 | | |
126 | | typedef std::unique_ptr< |
127 | | const CassResult, FuncDeleter<const CassResult, &cass_result_free>> CassResultPtr; |
128 | | |
129 | | class CassandraResult { |
130 | | public: |
131 | 148 | explicit CassandraResult(const CassResult* result) : cass_result_(result) {} |
132 | | |
133 | | CassandraIterator CreateIterator() const; |
134 | | |
135 | | std::string RenderToString(const std::string& line_separator = ";", |
136 | | const std::string& value_separator = ",") const; |
137 | | |
138 | | private: |
139 | | CassResultPtr cass_result_; |
140 | | }; |
141 | | |
142 | | typedef std::unique_ptr< |
143 | | const CassPrepared, FuncDeleter<const CassPrepared, &cass_prepared_free>> CassPreparedPtr; |
144 | | |
145 | | class CassandraPrepared { |
146 | | public: |
147 | | CassandraPrepared() = default; |
148 | 620 | explicit CassandraPrepared(const CassPrepared* prepared) : prepared_(prepared) {} |
149 | | |
150 | | CassandraStatement Bind(); |
151 | | |
152 | | private: |
153 | | CassPreparedPtr prepared_; |
154 | | }; |
155 | | |
156 | | typedef std::unique_ptr< |
157 | | CassFuture, FuncDeleter<CassFuture, &cass_future_free>> CassFuturePtr; |
158 | | |
159 | | class CassandraFuture { |
160 | | public: |
161 | 32.9k | explicit CassandraFuture(CassFuture* future) : future_(future) {} |
162 | | |
163 | | bool Ready() const; |
164 | | |
165 | | CHECKED_STATUS Wait(); |
166 | | |
167 | | CHECKED_STATUS WaitFor(MonoDelta duration); |
168 | | |
169 | | CassandraResult Result(); |
170 | | |
171 | | CassandraPrepared Prepared(); |
172 | | |
173 | | private: |
174 | | CHECKED_STATUS CheckErrorCode(); |
175 | | |
176 | | CassFuturePtr future_; |
177 | | }; |
178 | | |
179 | | typedef std::unique_ptr< |
180 | | CassStatement, FuncDeleter<CassStatement, &cass_statement_free>> CassStatementPtr; |
181 | | |
182 | | class CassandraStatement { |
183 | | public: |
184 | | explicit CassandraStatement(CassStatement* statement) |
185 | 389k | : cass_statement_(statement) {} |
186 | | |
187 | | explicit CassandraStatement(const std::string& query, size_t parameter_count = 0) |
188 | 1.78k | : cass_statement_(cass_statement_new(query.c_str(), parameter_count)) {} |
189 | | |
190 | | void SetKeyspace(const std::string& keyspace); |
191 | | |
192 | | void Bind(size_t index, const std::string& v); |
193 | | void Bind(size_t index, const cass_bool_t& v); |
194 | | void Bind(size_t index, const cass_float_t& v); |
195 | | void Bind(size_t index, const cass_double_t& v); |
196 | | void Bind(size_t index, const cass_int32_t& v); |
197 | | void Bind(size_t index, const cass_int64_t& v); |
198 | | void Bind(size_t index, const CassandraJson& v); |
199 | | |
200 | | CassStatement* get() const; |
201 | | |
202 | | private: |
203 | | friend class CassandraBatch; |
204 | | friend class CassandraSession; |
205 | | |
206 | | CassStatementPtr cass_statement_; |
207 | | }; |
208 | | |
209 | | typedef std::unique_ptr<CassBatch, FuncDeleter<CassBatch, &cass_batch_free>> CassBatchPtr; |
210 | | |
211 | | class CassandraBatch { |
212 | | public: |
213 | | explicit CassandraBatch(CassBatchType type) : cass_batch_(cass_batch_new(type)) {} |
214 | | |
215 | | void Add(CassandraStatement* statement); |
216 | | |
217 | | private: |
218 | | friend class CassandraSession; |
219 | | |
220 | | CassBatchPtr cass_batch_; |
221 | | }; |
222 | | |
223 | | struct DeleteSession { |
224 | | void operator()(CassSession* session) const; |
225 | | }; |
226 | | |
227 | | typedef std::unique_ptr<CassSession, DeleteSession> CassSessionPtr; |
228 | | |
229 | | class CassandraSession { |
230 | | public: |
231 | 197 | CassandraSession() = default; |
232 | | |
233 | | CHECKED_STATUS Connect(CassCluster* cluster); |
234 | | |
235 | | static Result<CassandraSession> Create(CassCluster* cluster); |
236 | | |
237 | | CHECKED_STATUS Execute(const CassandraStatement& statement); |
238 | | |
239 | | Result<CassandraResult> ExecuteWithResult(const CassandraStatement& statement); |
240 | | |
241 | | CassandraFuture ExecuteGetFuture(const CassandraStatement& statement); |
242 | | |
243 | | CassandraFuture ExecuteGetFuture(const std::string& query); |
244 | | |
245 | | CHECKED_STATUS ExecuteQuery(const std::string& query); |
246 | | |
247 | | template <class... Args> |
248 | | CHECKED_STATUS ExecuteQueryFormat(const std::string& query, Args&&... args) { |
249 | | return ExecuteQuery(Format(query, std::forward<Args>(args)...)); |
250 | | } |
251 | | |
252 | | Result<CassandraResult> ExecuteWithResult(const std::string& query); |
253 | | |
254 | | Result<std::string> ExecuteAndRenderToString(const std::string& statement); |
255 | | |
256 | | template <class Action> |
257 | | CHECKED_STATUS ExecuteAndProcessOneRow( |
258 | | const CassandraStatement& statement, const Action& action) { |
259 | | auto result = VERIFY_RESULT(ExecuteWithResult(statement)); |
260 | | auto iterator = result.CreateIterator(); |
261 | | if (!iterator.Next()) { |
262 | | return STATUS(IllegalState, "Row does not exists"); |
263 | | } |
264 | | auto row = iterator.Row(); |
265 | | action(row); |
266 | | if (iterator.Next()) { |
267 | | return STATUS(IllegalState, "Multiple rows returned"); |
268 | | } |
269 | | return Status::OK(); |
270 | | } |
271 | | |
272 | | template <class Action> |
273 | | CHECKED_STATUS ExecuteAndProcessOneRow(const std::string& query, const Action& action) { |
274 | | return ExecuteAndProcessOneRow(CassandraStatement(query), action); |
275 | | } |
276 | | |
277 | | template <class T> |
278 | | Result<T> FetchValue(const std::string& query) { |
279 | | T result = T(); |
280 | | RETURN_NOT_OK(ExecuteAndProcessOneRow(query, [&result](const CassandraRow& row) { |
281 | | result = row.Value(0).As<T>(); |
282 | | })); |
283 | | return result; |
284 | | } |
285 | | |
286 | | CHECKED_STATUS ExecuteBatch(const CassandraBatch& batch); |
287 | | |
288 | | CassandraFuture SubmitBatch(const CassandraBatch& batch); |
289 | | |
290 | | // If 'local_keyspace' is not empty, creating temporary CassStatement and setting keyspace |
291 | | // for this statement only. Result CassPrepared will be based on this temporary statement. |
292 | | Result<CassandraPrepared> Prepare(const std::string& prepare_query, |
293 | | MonoDelta timeout = MonoDelta::kZero, |
294 | | const std::string& local_keyspace = std::string()); |
295 | | |
296 | | void Reset(); |
297 | | |
298 | | private: |
299 | | CassSessionPtr cass_session_; |
300 | | }; |
301 | | |
302 | | YB_STRONGLY_TYPED_BOOL(UsePartitionAwareRouting); |
303 | | |
304 | | class CppCassandraDriver { |
305 | | public: |
306 | | CppCassandraDriver( |
307 | | const std::vector<std::string>& hosts, uint16_t port, |
308 | | UsePartitionAwareRouting use_partition_aware_routing); |
309 | | |
310 | | ~CppCassandraDriver(); |
311 | | |
312 | | Result<CassandraSession> CreateSession(); |
313 | | |
314 | | private: |
315 | | CassCluster* cass_cluster_ = nullptr; |
316 | | }; |
317 | | |
318 | | class CassandraJson { |
319 | | public: |
320 | | CassandraJson() = default; |
321 | | explicit CassandraJson(const std::string& s) : value_(s) {} |
322 | 4 | explicit CassandraJson(std::string&& s) : value_(std::move(s)) {} |
323 | | explicit CassandraJson(const char* s) : value_(s) {} |
324 | | |
325 | 24 | const std::string& value() const { |
326 | 24 | return value_; |
327 | 24 | } |
328 | | |
329 | | private: |
330 | | std::string value_; |
331 | | }; |
332 | | |
333 | | inline std::ostream& operator<<(std::ostream& out, const CassandraJson& value) { |
334 | | return out << value.value(); |
335 | | } |
336 | | |
337 | | inline bool operator==(const CassandraJson& lhs, const CassandraJson& rhs) { |
338 | | return lhs.value() == rhs.value(); |
339 | | } |
340 | | |
341 | | extern const MonoDelta kCassandraTimeOut; |
342 | | extern const std::string kCqlTestKeyspace; |
343 | | |
344 | | Result<CassandraSession> EstablishSession(CppCassandraDriver* driver); |
345 | | |
346 | | } // namespace yb |
347 | | |
348 | | #endif // YB_INTEGRATION_TESTS_CQL_TEST_UTIL_H |