Skip to content

Commit 4f4e170

Browse files
committed
Implement minimal SQL support
1 parent 66a2233 commit 4f4e170

39 files changed

Lines changed: 1445 additions & 238 deletions

hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5716,6 +5716,77 @@ cpsession_generatethreadid_encode(const cp::raft_group_id& group_id)
57165716
return msg;
57175717
}
57185718

5719+
ClientMessage
5720+
sql_close_encode(const sql::impl::query_id& query_id)
5721+
{
5722+
size_t initial_frame_size = ClientMessage::REQUEST_HEADER_LEN;
5723+
ClientMessage msg(initial_frame_size);
5724+
msg.set_retryable(false);
5725+
msg.set_operation_name("sql.close");
5726+
5727+
msg.set_message_type(static_cast<int32_t>(2163456));
5728+
msg.set_partition_id(-1);
5729+
5730+
msg.set(query_id, true);
5731+
5732+
return msg;
5733+
}
5734+
5735+
ClientMessage
5736+
sql_execute_encode(const std::string& sql,
5737+
const std::vector<serialization::pimpl::data>& parameters,
5738+
int64_t timeout_millis,
5739+
int32_t cursor_buffer_size,
5740+
const std::string* schema,
5741+
byte expected_result_type,
5742+
const sql::impl::query_id& query_id,
5743+
bool skip_update_statistics)
5744+
{
5745+
size_t initial_frame_size =
5746+
ClientMessage::REQUEST_HEADER_LEN + ClientMessage::INT64_SIZE +
5747+
ClientMessage::INT32_SIZE + ClientMessage::UINT8_SIZE +
5748+
ClientMessage::UINT8_SIZE;
5749+
ClientMessage msg(initial_frame_size);
5750+
msg.set_retryable(false);
5751+
msg.set_operation_name("sql.execute");
5752+
5753+
msg.set_message_type(static_cast<int32_t>(2163712));
5754+
msg.set_partition_id(-1);
5755+
5756+
msg.set(timeout_millis);
5757+
msg.set(cursor_buffer_size);
5758+
msg.set(expected_result_type);
5759+
msg.set(skip_update_statistics);
5760+
msg.set(sql);
5761+
5762+
msg.set(parameters);
5763+
5764+
msg.set_nullable(schema);
5765+
5766+
msg.set(query_id, true);
5767+
5768+
return msg;
5769+
}
5770+
5771+
ClientMessage
5772+
sql_fetch_encode(const sql::impl::query_id& query_id,
5773+
int32_t cursor_buffer_size)
5774+
{
5775+
size_t initial_frame_size =
5776+
ClientMessage::REQUEST_HEADER_LEN + ClientMessage::INT32_SIZE;
5777+
ClientMessage msg(initial_frame_size);
5778+
msg.set_retryable(false);
5779+
msg.set_operation_name("sql.fetch");
5780+
5781+
msg.set_message_type(static_cast<int32_t>(2163968));
5782+
msg.set_partition_id(-1);
5783+
5784+
msg.set(cursor_buffer_size);
5785+
msg.set(query_id, true);
5786+
5787+
return msg;
5788+
}
5789+
57195790
} // namespace codec
57205791
} // namespace protocol
57215792
} // namespace client

hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,6 +3053,32 @@ cpsession_heartbeatsession_encode(const cp::raft_group_id& group_id,
30533053
ClientMessage HAZELCAST_API
30543054
cpsession_generatethreadid_encode(const cp::raft_group_id& group_id);
30553055

3056+
/**
3057+
* Closes server-side query cursor.
3058+
*/
3059+
ClientMessage HAZELCAST_API
3060+
sql_close_encode(const sql::impl::query_id& query_id);
3061+
3062+
/**
3063+
* Starts execution of an SQL query (as of 4.2).
3064+
*/
3065+
ClientMessage HAZELCAST_API
3066+
sql_execute_encode(const std::string& sql,
3067+
const std::vector<serialization::pimpl::data>& parameters,
3068+
int64_t timeout_millis,
3069+
int32_t cursor_buffer_size,
3070+
const std::string* schema,
3071+
byte expected_result_type,
3072+
const sql::impl::query_id& query_id,
3073+
bool skip_update_statistics);
3074+
3075+
/**
3076+
* Fetches the next row page.
3077+
*/
3078+
ClientMessage HAZELCAST_API
3079+
sql_fetch_encode(const sql::impl::query_id& query_id,
3080+
int32_t cursor_buffer_size);
3081+
30563082
} // namespace codec
30573083
} // namespace protocol
30583084
} // namespace client

hazelcast/include/hazelcast/client/hazelcast_client.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,18 @@ class HAZELCAST_API hazelcast_client
345345
*/
346346
cp::cp_subsystem& get_cp_subsystem();
347347

348+
boost::future<sql::result> execute_sql(const sql::statement& statement);
349+
350+
template<typename... Params>
351+
boost::future<sql::result> execute_sql(const std::string& query,
352+
const Params&... params)
353+
{
354+
sql::statement s{ *this, query };
355+
int _[] = { (s.add_parameter(params), 0)... };
356+
(void)_;
357+
return execute_sql(s);
358+
}
359+
348360
private:
349361
hazelcast_client();
350362

hazelcast/include/hazelcast/client/impl/hazelcast_client_instance_impl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include <atomic>
1919
#include <memory>
20-
#include <stdint.h>
20+
#include <cstdint>
2121
#include <vector>
2222
#include <random>
2323
#include <boost/uuid/uuid.hpp>
@@ -55,6 +55,8 @@
5555
#include "hazelcast/cp/cp.h"
5656
#include "hazelcast/cp/cp_impl.h"
5757
#include "hazelcast/logger.h"
58+
#include "hazelcast/client/sql/result.h"
59+
#include "hazelcast/client/sql/statement.h"
5860

5961
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
6062
#pragma warning(push)
@@ -216,6 +218,8 @@ class HAZELCAST_API hazelcast_client_instance_impl
216218

217219
cp::cp_subsystem& get_cp_subsystem();
218220

221+
boost::future<sql::result> execute_sql(const sql::statement& statement);
222+
219223
private:
220224
client_config client_config_;
221225
client_properties client_properties_;

hazelcast/include/hazelcast/client/protocol/ClientMessage.h

Lines changed: 155 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,32 @@
2121
#pragma warning(disable : 4251) // for dll export
2222
#endif
2323

24-
#include <string>
24+
#include <cassert>
2525
#include <memory>
26-
#include <vector>
27-
#include <assert.h>
28-
#include <unordered_map>
2926
#include <ostream>
30-
#include <boost/uuid/uuid.hpp>
27+
#include <string>
28+
#include <unordered_map>
29+
#include <vector>
30+
3131
#include <boost/endian/arithmetic.hpp>
3232
#include <boost/endian/conversion.hpp>
3333
#include <boost/optional.hpp>
3434
#include <boost/uuid/nil_generator.hpp>
35+
#include <boost/uuid/uuid.hpp>
3536

36-
#include <hazelcast/client/query/paging_predicate.h>
3737
#include "hazelcast/client/address.h"
38-
#include "hazelcast/client/member.h"
39-
#include "hazelcast/client/serialization/pimpl/data.h"
40-
#include "hazelcast/client/map/data_entry_view.h"
41-
#include "hazelcast/client/exception/protocol_exceptions.h"
4238
#include "hazelcast/client/config/index_config.h"
39+
#include "hazelcast/client/exception/protocol_exceptions.h"
40+
#include "hazelcast/client/map/data_entry_view.h"
41+
#include "hazelcast/client/member.h"
4342
#include "hazelcast/client/protocol/codec/ErrorCodec.h"
43+
#include "hazelcast/client/query/paging_predicate.h"
44+
#include "hazelcast/client/serialization/pimpl/data.h"
45+
#include "hazelcast/client/sql/impl/query_id.h"
46+
#include "hazelcast/client/sql/column_metadata.h"
47+
#include "hazelcast/client/sql/impl/page.h"
48+
#include "hazelcast/client/sql/impl/error.h"
49+
#include "hazelcast/client/sql/column_type.h"
4450

4551
namespace hazelcast {
4652
namespace util {
@@ -795,6 +801,121 @@ class HAZELCAST_API ClientMessage
795801
return h;
796802
}
797803

804+
/**
805+
* Reads the header of the current frame.
806+
* The cursor must be at a frame's beginning.
807+
*/
808+
frame_header_t read_frame_header()
809+
{
810+
frame_header_t header{};
811+
auto pos = rd_ptr(SIZE_OF_FRAME_LENGTH_AND_FLAGS);
812+
std::memcpy(&header.frame_len, pos, sizeof(header.frame_len));
813+
pos += sizeof(header.frame_len);
814+
std::memcpy(&header.flags, pos, sizeof(header.flags));
815+
return header;
816+
}
817+
818+
template<typename T>
819+
typename std::enable_if<std::is_same<T, sql::column_metadata>::value,
820+
T>::type
821+
get()
822+
{
823+
// skip begin frame
824+
skip_frame();
825+
826+
const frame_header_t header = read_frame_header();
827+
828+
auto type = static_cast<sql::column_type>(get<int32_t>());
829+
830+
bool nullable = true;
831+
int nullable_size = 0;
832+
if (header.frame_len - SIZE_OF_FRAME_LENGTH_AND_FLAGS >=
833+
INT32_SIZE + INT8_SIZE) {
834+
nullable = get<bool>();
835+
nullable_size = INT8_SIZE;
836+
}
837+
838+
// skip bytes in initial frame
839+
rd_ptr(static_cast<int32_t>(header.frame_len) -
840+
SIZE_OF_FRAME_LENGTH_AND_FLAGS - INT32_SIZE - nullable_size);
841+
842+
std::string name = get<std::string>();
843+
844+
fast_forward_to_end_frame();
845+
846+
return sql::column_metadata(std::move(name), type, nullable);
847+
}
848+
849+
template<typename T>
850+
typename std::enable_if<std::is_same<T, sql::impl::page>::value, T>::type
851+
get()
852+
{
853+
// begin frame
854+
skip_frame();
855+
856+
bool last = peek(SIZE_OF_FRAME_LENGTH_AND_FLAGS +
857+
1)[SIZE_OF_FRAME_LENGTH_AND_FLAGS] == 1;
858+
skip_frame();
859+
860+
auto column_type_ids = get<std::vector<int32_t>>();
861+
862+
using column = std::vector<boost::optional<std::string>>;
863+
864+
std::vector<column> columns;
865+
std::vector<sql::column_type> column_types;
866+
867+
for (auto column_type_id : column_type_ids) {
868+
auto column_type = static_cast<sql::column_type>(column_type_id);
869+
column_types.push_back(column_type);
870+
871+
switch (column_type) {
872+
case sql::column_type::varchar:
873+
columns.push_back(
874+
get<std::vector<boost::optional<std::string>>>());
875+
break;
876+
default:
877+
assert(false);
878+
879+
// TODO add others
880+
}
881+
}
882+
883+
fast_forward_to_end_frame();
884+
885+
return sql::impl::page{ column_types, columns, last };
886+
}
887+
888+
template<typename T>
889+
typename std::enable_if<std::is_same<T, sql::impl::error>::value, T>::type
890+
get()
891+
{
892+
// begin frame
893+
skip_frame();
894+
895+
const auto header = read_frame_header();
896+
897+
auto code = get<int>();
898+
auto originating_member_id = get<boost::uuids::uuid>();
899+
900+
// skip bytes in initial frame
901+
rd_ptr(static_cast<int32_t>(header.frame_len) -
902+
SIZE_OF_FRAME_LENGTH_AND_FLAGS - INT32_SIZE - UUID_SIZE);
903+
904+
auto message = get_nullable<std::string>();
905+
906+
boost::optional<std::string> suggestion;
907+
if (!next_frame_is_data_structure_end_frame()) {
908+
suggestion = get_nullable<std::string>();
909+
}
910+
911+
fast_forward_to_end_frame();
912+
913+
return sql::impl::error{ code,
914+
std::move(message),
915+
originating_member_id,
916+
std::move(suggestion) };
917+
}
918+
798919
template<typename T>
799920
boost::optional<T> get_nullable()
800921
{
@@ -1075,6 +1196,30 @@ class HAZELCAST_API ClientMessage
10751196
h->flags |= IS_FINAL_FLAG;
10761197
}
10771198
}
1199+
1200+
void set(const frame_header_t& header)
1201+
{
1202+
auto pos = wr_ptr(SIZE_OF_FRAME_LENGTH_AND_FLAGS);
1203+
std::memcpy(pos, &header.frame_len, sizeof(header.frame_len));
1204+
pos += sizeof(header.frame_len);
1205+
std::memcpy(pos, &header.flags, sizeof(header.flags));
1206+
}
1207+
1208+
void set(const sql::impl::query_id& query_id, bool is_final = false)
1209+
{
1210+
add_begin_frame();
1211+
1212+
set(frame_header_t{ SIZE_OF_FRAME_LENGTH_AND_FLAGS + 4 * INT64_SIZE,
1213+
DEFAULT_FLAGS });
1214+
1215+
set(query_id.member_id_high());
1216+
set(query_id.member_id_low());
1217+
set(query_id.local_id_high());
1218+
set(query_id.local_id_low());
1219+
1220+
add_end_frame(is_final);
1221+
}
1222+
10781223
//----- Setter methods end ---------------------
10791224

10801225
//----- utility methods -------------------
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved.
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+
#pragma once
17+
18+
#include <string>
19+
20+
#include "hazelcast/util/export.h"
21+
#include "hazelcast/client/sql/column_type.h"
22+
23+
namespace hazelcast {
24+
namespace client {
25+
namespace sql {
26+
27+
class HAZELCAST_API column_metadata
28+
{
29+
public:
30+
column_metadata(std::string name, column_type type, bool nullable);
31+
32+
const std::string& name() const;
33+
column_type type() const;
34+
bool nullable() const;
35+
36+
private:
37+
std::string name_;
38+
column_type type_;
39+
bool nullable_;
40+
};
41+
42+
} // namespace sql
43+
} // namespace client
44+
} // namespace hazelcast

0 commit comments

Comments
 (0)