1 /*
2   Copyright (c) DataStax, Inc.
3 
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7 
8   http://www.apache.org/licenses/LICENSE-2.0
9 
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17 #include "integration.hpp"
18 
19 #define TABLE_FORMAT           \
20   "CREATE TABLE %s ("          \
21   "key timeuuid PRIMARY KEY, " \
22   "a int, "                    \
23   "b boolean, "                \
24   "c text, "                   \
25   "abc float, "                \
26   "\"ABC\" float, "            \
27   "\"aBc\" float"              \
28   ")"
29 #define TABLE_BYTES_FORMAT     \
30   "CREATE TABLE %s ("          \
31   "key timeuuid PRIMARY KEY, " \
32   "blobs blob, "               \
33   "varints varint"             \
34   ")"
35 #define INSERT_FORMAT "INSERT INTO %s (key, a, b, c) VALUES (?, ?, ?, ?)"
36 #define INSERT_CASE_SENSITIVE_FORMAT \
37   "INSERT INTO %s "                  \
38   "(key, abc, \"ABC\", \"aBc\") "    \
39   "VALUES (?, ?, ?, ?)"
40 #define INSERT_ALL_FORMAT                  \
41   "INSERT INTO %s "                        \
42   "(key, a, b, c, abc, \"ABC\", \"aBc\") " \
43   "VALUES (?, ?, ?, ?, ?, ?, ?)"
44 #define INSERT_BYTES_FORMAT "INSERT INTO %s (key, blobs, varints) VALUES (?, ?, ?)"
45 
46 /**
47  * By name integration tests
48  */
49 class ByNameTests : public Integration {
50 public:
SetUp()51   virtual void SetUp() {
52     // Call the parent setup function
53     Integration::SetUp();
54 
55     // Create the table for the test
56     session_.execute(format_string(TABLE_FORMAT, table_name_.c_str()));
57   }
58 
59 protected:
60   /**
61    * Insert and validate
62    *
63    * @param statement Insert statement to use (not case sensitive format)
64    */
insert_and_validate(Statement statement)65   void insert_and_validate(Statement statement) {
66     // Insert values into the table by name
67     TimeUuid key = uuid_generator_.generate_timeuuid();
68     statement.bind<TimeUuid>("key", key);
69     statement.bind<Integer>("a", Integer(9042));
70     statement.bind<Boolean>("b", Boolean(true));
71     statement.bind<Text>("c", Text("yyz"));
72     session_.execute(statement);
73 
74     // Validate the inserts into the table
75     Result result = session_.execute(default_select_all());
76     ASSERT_EQ(1u, result.row_count());
77     ASSERT_EQ(7u, result.column_count());
78     Row row = result.first_row();
79     ASSERT_EQ(key, row.column_by_name<TimeUuid>("key"));
80     ASSERT_EQ(Integer(9042), row.column_by_name<Integer>("a"));
81     ASSERT_EQ(Boolean(true), row.column_by_name<Boolean>("b"));
82     ASSERT_EQ(Text("yyz"), row.column_by_name<Text>("c"));
83   }
84 
85   /**
86    * Insert and validate
87    *
88    * @param statement Insert statement to use (case sensitive format)
89    */
insert_and_validate_case_sensitive(Statement statement)90   void insert_and_validate_case_sensitive(Statement statement) {
91     // Insert values into the table by name
92     TimeUuid key = uuid_generator_.generate_timeuuid();
93     statement.bind<TimeUuid>("key", key);
94     statement.bind<Float>("\"abc\"", Float(1.1f));
95     statement.bind<Float>("\"ABC\"", Float(2.2f));
96     statement.bind<Float>("\"aBc\"", Float(3.3f));
97     session_.execute(statement);
98 
99     // Validate the inserts into the table
100     Result result = session_.execute(default_select_all());
101     ASSERT_EQ(1u, result.row_count());
102     ASSERT_EQ(7u, result.column_count());
103     Row row = result.first_row();
104     ASSERT_EQ(key, row.column_by_name<TimeUuid>("key"));
105     ASSERT_EQ(Float(1.1f), row.column_by_name<Float>("\"abc\""));
106     ASSERT_EQ(Float(2.2f), row.column_by_name<Float>("\"ABC\""));
107     ASSERT_EQ(Float(3.3f), row.column_by_name<Float>("\"aBc\""));
108   }
109 
110   /**
111    * Insert all values into the table
112    *
113    * @param statement Insert statement to use (all format)
114    */
insert_and_validate_all(Statement statement)115   void insert_and_validate_all(Statement statement) {
116     // Insert values into the table by name
117     TimeUuid key = uuid_generator_.generate_timeuuid();
118     statement.bind<TimeUuid>("key", key);
119     statement.bind<Integer>("a", Integer(9042));
120     statement.bind<Boolean>("b", Boolean(true));
121     statement.bind<Text>("c", Text("yyz"));
122     statement.bind<Float>("\"abc\"", Float(1.1f));
123     statement.bind<Float>("\"ABC\"", Float(2.2f));
124     statement.bind<Float>("\"aBc\"", Float(3.3f));
125     session_.execute(statement);
126 
127     // Validate the inserts into the table
128     Result result = session_.execute(default_select_all());
129     ASSERT_EQ(1u, result.row_count());
130     ASSERT_EQ(7u, result.column_count());
131     Row row = result.first_row();
132     ASSERT_EQ(key, row.column_by_name<TimeUuid>("key"));
133     ASSERT_EQ(Integer(9042), row.column_by_name<Integer>("a"));
134     ASSERT_EQ(Boolean(true), row.column_by_name<Boolean>("b"));
135     ASSERT_EQ(Text("yyz"), row.column_by_name<Text>("c"));
136     ASSERT_EQ(Float(1.1f), row.column_by_name<Float>("\"abc\""));
137     ASSERT_EQ(Float(2.2f), row.column_by_name<Float>("\"ABC\""));
138     ASSERT_EQ(Float(3.3f), row.column_by_name<Float>("\"aBc\""));
139   }
140 
141   /**
142    * Insert all values into the table
143    *
144    * @param statement Insert statement to use (all format)
145    */
insert_and_validate_all_null(Statement statement)146   void insert_and_validate_all_null(Statement statement) {
147     // Create NULL wrapped objects for easier inserting and validation
148     TimeUuid key = uuid_generator_.generate_timeuuid();
149     Integer a = Integer();
150     Boolean b = Boolean();
151     Text c = Text();
152     Float abc = Float();
153 
154     // Insert values into the table by name
155     statement.bind<TimeUuid>("key", key);
156     statement.bind<Integer>("a", a);
157     statement.bind<Boolean>("b", b);
158     statement.bind<Text>("c", c);
159     statement.bind<Float>("\"abc\"", abc);
160     statement.bind<Float>("\"ABC\"", abc);
161     statement.bind<Float>("\"aBc\"", abc);
162     session_.execute(statement);
163 
164     // Validate the inserts into the table
165     Result result = session_.execute(default_select_all());
166     ASSERT_EQ(1u, result.row_count());
167     ASSERT_EQ(7u, result.column_count());
168     Row row = result.first_row();
169     ASSERT_EQ(key, row.column_by_name<TimeUuid>("key"));
170     ASSERT_TRUE(row.column_by_name<Integer>("a").is_null());
171     ASSERT_TRUE(row.column_by_name<Boolean>("b").is_null());
172     ASSERT_TRUE(row.column_by_name<Text>("c").is_null());
173     ASSERT_TRUE(row.column_by_name<Float>("\"abc\"").is_null());
174     ASSERT_TRUE(row.column_by_name<Float>("\"ABC\"").is_null());
175     ASSERT_TRUE(row.column_by_name<Float>("\"aBc\"").is_null());
176   }
177 };
178 
179 /**
180  * By name (bytes) integration tests
181  */
182 class ByNameBytesTests : public Integration {
SetUp()183   virtual void SetUp() {
184     // Call the parent setup function
185     Integration::SetUp();
186 
187     // Create the table for the test
188     session_.execute(format_string(TABLE_BYTES_FORMAT, table_name_.c_str()));
189   }
190 };
191 
192 /**
193  * Perform `by name` references using a prepared statement and validate
194  *
195  * This test will perform a `by name` insert using a prepared statement and
196  * validate the results a single node cluster.
197  *
198  * @test_category queries:prepared
199  * @since core:1.0.0
200  * @expected_result Cassandra values are inserted and validated by name
201  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,Prepared)202 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, Prepared) {
203   CHECK_FAILURE;
204 
205   // Prepare, create, insert and validate
206   Prepared prepared = session_.prepare(format_string(INSERT_FORMAT, table_name_.c_str()));
207   insert_and_validate(prepared.bind());
208 }
209 
210 /**
211  * Perform `by name` references using a simple (bound) statement and validate
212  *
213  * This test will perform a `by name` insert using a simple statement and
214  * validate the results a single node cluster.
215  *
216  * @test_category queries:basic
217  * @since core:1.0.0
218  * @expected_result Cassandra values are inserted and validated by name
219  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,Simple)220 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, Simple) {
221   CHECK_FAILURE;
222 
223   // Prepare, create, insert and validate
224   Statement statement(format_string(INSERT_FORMAT, table_name_.c_str()), 4);
225   insert_and_validate(statement);
226 }
227 
228 /**
229  * Perform case sensitive `by name` references using a prepared statement and
230  * validate
231  *
232  * This test will perform a case sensitive`by name` insert using a prepared
233  * statement and validate the results a single node cluster.
234  *
235  * @test_category queries:prepared
236  * @since core:1.0.0
237  * @expected_result Cassandra values are inserted and validated by name
238  *                  (case sensitive)
239  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,PreparedCaseSensitive)240 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, PreparedCaseSensitive) {
241   CHECK_FAILURE;
242 
243   // Prepare, create, insert and validate
244   Prepared prepared =
245       session_.prepare(format_string(INSERT_CASE_SENSITIVE_FORMAT, table_name_.c_str()));
246   insert_and_validate_case_sensitive(prepared.bind());
247 }
248 
249 /**
250  * Perform case sensitive `by name` references using a simple (bound) statement
251  * and validate
252  *
253  * This test will perform a case sensitive `by name` insert using a simple
254  * statement and validate the results a single node cluster.
255  *
256  * @test_category queries:basic
257  * @since core:1.0.0
258  * @cassandra_version 2.1.0
259  * @expected_result Cassandra values are inserted and validated by name
260  *                  (case sensitive)
261  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,SimpleCaseSensitive)262 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, SimpleCaseSensitive) {
263   CHECK_FAILURE;
264   CHECK_VERSION(2.1.0);
265 
266   // Prepare, create, insert and validate
267   Statement statement(format_string(INSERT_CASE_SENSITIVE_FORMAT, table_name_.c_str()), 4);
268   insert_and_validate_case_sensitive(statement);
269 }
270 
271 /**
272  * Perform `by name` references using a prepared statement to insert multiple
273  * value and validate
274  *
275  * This test will perform bindings of a value to multiple columns `by name`
276  * insert using a prepared statement and validate the results a single node
277  * cluster.
278  *
279  * @test_category queries:prepared
280  * @since core:1.0.0
281  * @expected_result Cassandra values are inserted and validated by name
282  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,MultipleBinds)283 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, MultipleBinds) {
284   CHECK_FAILURE;
285 
286   // Prepare, bind, and insert the values into the table
287   Prepared prepared =
288       session_.prepare(format_string(INSERT_CASE_SENSITIVE_FORMAT, table_name_.c_str()));
289   Statement statement = prepared.bind();
290   TimeUuid key = uuid_generator_.generate_timeuuid();
291   statement.bind<TimeUuid>("key", key);
292   statement.bind<Float>("abc", Float(1.23f)); // This should bind to columns `abc`, `ABC`, and `aBc`
293   session_.execute(statement);
294 
295   // Validate the inserts to multiple binded columns
296   Result result = session_.execute(default_select_all());
297   ASSERT_EQ(1u, result.row_count());
298   ASSERT_EQ(7u, result.column_count());
299   Row row = result.first_row();
300   ASSERT_EQ(key, row.column_by_name<TimeUuid>("key"));
301   ASSERT_EQ(Float(1.23f), row.column_by_name<Float>("\"abc\""));
302   ASSERT_EQ(Float(1.23f), row.column_by_name<Float>("\"ABC\""));
303   ASSERT_EQ(Float(1.23f), row.column_by_name<Float>("\"aBc\""));
304 }
305 
306 /**
307  * Perform `by name` references using a prepared statement against an invalid
308  * column name
309  *
310  * This test will attempt to bind an invalid column name to a prepared statement
311  * using a single node cluster.
312  *
313  * @test_category queries:prepared
314  * @since core:1.0.0
315  * @expected_result Driver error will occur when binding value to invalid column
316  *                 name
317  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,BindUsingInvalidName)318 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, BindUsingInvalidName) {
319   CHECK_FAILURE;
320 
321   // Prepare and create the insert statement
322   Prepared prepared = session_.prepare(format_string(INSERT_ALL_FORMAT, table_name_.c_str()));
323   Statement statement = prepared.bind();
324 
325   // Bind values to invalid columns name and validate error
326   CassError error_code = cass_statement_bind_int32_by_name(statement.get(), "d", 0);
327   ASSERT_EQ(CASS_ERROR_LIB_NAME_DOES_NOT_EXIST, error_code);
328   error_code = cass_statement_bind_float_by_name(statement.get(), "\"aBC", 0.0f);
329   ASSERT_EQ(CASS_ERROR_LIB_NAME_DOES_NOT_EXIST, error_code);
330   error_code = cass_statement_bind_float_by_name(statement.get(), "\"abC", 0.0f);
331 }
332 
333 /**
334  * Perform `by name` references against an invalid column name lookup
335  *
336  * This test will perform a `by name` insert using a prepared statement and
337  * attempt to retrieve a column using an invalid name against a single node
338  * cluster.
339  *
340  * @test_category queries:basic
341  * @since core:1.0.0
342  * @expected_result Driver error will occur when retrieving value from invalid
343  *                 column name
344  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,RetrieveInvalidName)345 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, RetrieveInvalidName) {
346   CHECK_FAILURE;
347 
348   // Prepare, create, insert and validate (all)
349   Prepared prepared = session_.prepare(format_string(INSERT_ALL_FORMAT, table_name_.c_str()));
350   Statement statement = prepared.bind();
351   insert_and_validate_all(statement);
352 
353   // Retrieve the row and validate error using invalid column name
354   Result result = session_.execute(default_select_all());
355   Row row = result.first_row();
356   ASSERT_TRUE(NULL == cass_row_get_column_by_name(row.get(), "d"));
357   ASSERT_TRUE(NULL == cass_row_get_column_by_name(row.get(), "\"aBC\""));
358   ASSERT_TRUE(NULL == cass_row_get_column_by_name(row.get(), "\"abC\""));
359 }
360 
361 /**
362  * Perform `by name` references using a prepared statement and validate values
363  * are NULL
364  *
365  * This test will perform a `by name` NULL insert using a prepared statement and
366  * validate the results a single node cluster.
367  *
368  * @test_category queries:prepared
369  * @since core:1.0.0
370  * @expected_result Cassandra NULL values are inserted and validated by name
371  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,NullPrepared)372 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, NullPrepared) {
373   CHECK_FAILURE;
374 
375   // Prepare, create, insert and validate
376   Prepared prepared = session_.prepare(format_string(INSERT_ALL_FORMAT, table_name_.c_str()));
377   insert_and_validate_all_null(prepared.bind());
378 }
379 
380 /**
381  * Perform `by name` references using a simple (bound) statement and validate
382  * values are NULL
383  *
384  * This test will perform a `by name` NULL insert using a simple statement and
385  * validate the results a single node cluster.
386  *
387  * @test_category queries:basic
388  * @since core:1.0.0
389  * @cassandra_version 2.1.0
390  * @expected_result Cassandra NULL values are inserted and validated by name
391  */
CASSANDRA_INTEGRATION_TEST_F(ByNameTests,NullSimple)392 CASSANDRA_INTEGRATION_TEST_F(ByNameTests, NullSimple) {
393   CHECK_FAILURE;
394   CHECK_VERSION(2.1.0);
395 
396   // Prepare, create, insert and validate
397   Statement statement(format_string(INSERT_ALL_FORMAT, table_name_.c_str()), 7);
398   insert_and_validate_all_null(statement);
399 }
400 
401 /**
402  * Perform `by name` references using a prepared statement and validate using
403  * bytes
404  *
405  * This test will perform a `by name` bytes insert using a prepared statement
406  * for `blob` and `varint` data types validating  inserts.
407  *
408  * NOTE: This will be using a single node cluster.
409  *
410  * @jira_ticket CPP-272
411  * @test_category queries:basic
412  * @since core:2.1.0-beta
413  * @expected_result Bytes will be bound to `blob` and `varint` valued and will
414  *                  be validated by name
415  */
CASSANDRA_INTEGRATION_TEST_F(ByNameBytesTests,Prepared)416 CASSANDRA_INTEGRATION_TEST_F(ByNameBytesTests, Prepared) {
417   CHECK_FAILURE;
418 
419   // Create values to be inserted in the test
420   TimeUuid key = uuid_generator_.generate_timeuuid();
421   Blob blobs("68971169783116971203269110116101114112114105115101329911211245100114105118101114");
422   Varint varints("1234567890123456789012345678901234567890");
423 
424   // Prepare, bind, and insert the values into the table
425   Prepared prepared = session_.prepare(format_string(INSERT_BYTES_FORMAT, table_name_.c_str()));
426   Statement statement = prepared.bind();
427   statement.bind<TimeUuid>("key", key);
428   statement.bind<Blob>("blobs", blobs);
429   statement.bind<Varint>("varints", varints);
430   session_.execute(statement);
431 
432   // Validate the inserts
433   Result result = session_.execute(default_select_all());
434   ASSERT_EQ(1u, result.row_count());
435   ASSERT_EQ(3u, result.column_count());
436   Row row = result.first_row();
437   ASSERT_EQ(key, row.column_by_name<TimeUuid>("key"));
438   ASSERT_EQ(blobs, row.column_by_name<Blob>("blobs"));
439   ASSERT_EQ(varints, row.column_by_name<Varint>("varints"));
440 }
441