File method_callback.cpp¶
File List > cubrid > src > method > method_callback.cpp
Go to the documentation of this file
/*
*
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "method_callback.hpp"
#include "dbi.h"
#include "ddl_log.h"
#include "pl_struct_compile.hpp"
#include "method_query_util.hpp"
#include "method_struct_oid_info.hpp"
#include "method_schema_info.hpp"
#include "parser.h"
#include "db_session.h"
#include "db.h"
#include "object_primitive.h"
#include "oid.h"
#include "transaction_cl.h"
#include "jsp_cl.h"
#include "authenticate.h"
#include "set_object.h"
#include "transform.h"
#include "execute_statement.h"
#include "schema_manager.h"
#include "network_callback_cl.hpp"
extern int ux_create_srv_handle_with_method_query_result (DB_QUERY_RESULT *result, int stmt_type, int num_column,
DB_QUERY_TYPE *column_info, bool is_holdable);
using namespace cubpl;
namespace cubmethod
{
callback_handler::callback_handler (int max_query_handler)
{
m_query_handlers.resize (max_query_handler, nullptr);
m_oid_handler = nullptr;
}
callback_handler::~callback_handler ()
{
if (m_oid_handler)
{
delete m_oid_handler;
}
}
int
callback_handler::callback_dispatch (packing_unpacker &unpacker)
{
m_error_ctx.clear ();
int code;
unpacker.unpack_int (code);
int error = NO_ERROR;
switch (code)
{
case METHOD_CALLBACK_END_TRANSACTION:
error = end_transaction (unpacker);
break;
case METHOD_CALLBACK_QUERY_PREPARE:
error = prepare (unpacker);
break;
case METHOD_CALLBACK_QUERY_EXECUTE:
error = execute (unpacker);
break;
case METHOD_CALLBACK_OID_GET:
error = oid_get (unpacker);
break;
case METHOD_CALLBACK_OID_PUT:
error = oid_put (unpacker);
break;
case METHOD_CALLBACK_OID_CMD:
error = oid_cmd (unpacker);
break;
case METHOD_CALLBACK_COLLECTION:
error = collection_cmd (unpacker);
break;
case METHOD_CALLBACK_MAKE_OUT_RS:
error = make_out_resultset (unpacker);
break;
case METHOD_CALLBACK_GET_GENERATED_KEYS:
error = generated_keys (unpacker);
break;
/* schema info */
case METHOD_CALLBACK_GET_SCHEMA_INFO:
// error = get_schema_info (unpacker);
assert (false);
break;
/* compilation */
case METHOD_CALLBACK_GET_SQL_SEMANTICS:
error = get_sql_semantics (unpacker);
break;
case METHOD_CALLBACK_GET_GLOBAL_SEMANTICS:
error = get_global_semantics (unpacker);
break;
case METHOD_CALLBACK_CHANGE_RIGHTS:
error = change_rights (unpacker);
break;
default:
assert (false);
error = ER_FAILED;
break;
}
#if defined (CS_MODE)
xs_queue_send ();
#else
/* do nothing for SA_MODE */
#endif
return error;
}
int
callback_handler::end_transaction (packing_unpacker &unpacker)
{
int error_code = NO_ERROR;
int command; // commit : 1, abort : 2
unpacker.unpack_all (command);
if (command == 1)
{
error_code = db_commit_transaction ();
}
else if (command == 2)
{
error_code = db_abort_transaction ();
}
else
{
assert (false);
error_code = ER_FAILED;
}
if (error_code != NO_ERROR)
{
m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
}
if (m_error_ctx.has_error())
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, 1);
}
}
int
callback_handler::prepare (packing_unpacker &unpacker)
{
std::string sql;
int flag;
TRANID tid;
unpacker.unpack_all (sql, flag, tid);
/* find in m_sql_handler_map */
query_handler *handler = get_query_handler_by_sql (sql, [&] (query_handler *h)
{
return h->get_is_occupied() == false && (h->get_tran_id () == NULL_TRANID || h->get_tran_id() == tid)
&& h->get_user_name ().compare (au_get_current_user_name ()) == 0;
});
if (handler == nullptr)
{
/* not found in statement handler cache */
handler = new_query_handler ();
if (handler == nullptr)
{
// TODO: proper error code
m_error_ctx.set_error (METHOD_CALLBACK_ER_NO_MORE_MEMORY, NULL, __FILE__, __LINE__);
}
else
{
int error = handler->prepare (sql, flag);
if (error == NO_ERROR)
{
// add to statement handler cache
m_sql_handler_map.emplace (sql, handler->get_id ());
handler->set_tran_id (tid);
}
else
{
m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
}
}
}
if (handler != nullptr)
{
handler->set_is_occupied (true);
/* DDL audit */
DB_SESSION *hdl_session = handler->get_db_session();
logddl_set_callback_stmt (handler->get_statement_type(), (char *) sql.c_str (), sql.size (), m_error_ctx.get_error (),
((hdl_session && hdl_session->parser) ? & (hdl_session->parser->hide_pwd_info) : NULL));
}
if (m_error_ctx.has_error())
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, handler->get_prepare_info ());
}
}
int
callback_handler::execute (packing_unpacker &unpacker)
{
execute_request request;
request.unpack (unpacker);
query_handler *handler = get_query_handler_by_id (request.handler_id);
if (handler == nullptr)
{
// CUATION: do not change the error message below because
// it is used in PL server to identify this error.
m_error_ctx.set_error (METHOD_CALLBACK_ER_NO_QUERY_HANDLER, "no query handler", __FILE__, __LINE__);
}
else
{
int error = handler->execute (request);
if (error == NO_ERROR)
{
/* register query_id for out resultset */
const cubmethod::query_result &qresult = handler->get_result();
if (qresult.stmt_type == CUBRID_STMT_SELECT)
{
uint64_t qid = (uint64_t) handler->get_query_id ();
m_qid_handler_map[qid] = request.handler_id;
}
}
else
{
/* XASL cache is not found */
if (error == ER_QPROC_INVALID_XASLNODE)
{
m_error_ctx.clear ();
handler->prepare_retry ();
error = handler->execute (request);
}
if (error != NO_ERROR)
{
m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
}
}
/* DDL audit */
logddl_write_end ();
}
if (m_error_ctx.has_error())
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, handler->get_execute_info ());
}
}
int
callback_handler::make_out_resultset (packing_unpacker &unpacker)
{
uint64_t query_id;
unpacker.unpack_all (query_id);
cubmethod::query_handler *query_handler = get_query_handler_by_query_id (query_id);
if (query_handler)
{
const query_result &qresult = query_handler->get_result();
make_outresult_info info;
query_handler->set_prepare_column_list_info (info.column_infos);
query_handler->set_qresult_info (info.qresult_info);
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, info);
}
/* unexpected error, should not be here */
m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
int
callback_handler::generated_keys (packing_unpacker &unpacker)
{
int handler_id = -1;
unpacker.unpack_all (handler_id);
query_handler *handler = get_query_handler_by_id (handler_id);
if (handler == nullptr)
{
// TODO: proper error code
m_error_ctx.set_error (METHOD_CALLBACK_ER_NO_MORE_MEMORY, NULL, __FILE__, __LINE__);
return ER_FAILED;
}
get_generated_keys_info info = handler->generated_keys ();
if (m_error_ctx.has_error())
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, info);
}
}
// OID
oid_handler *
callback_handler::get_oid_handler ()
{
if (m_oid_handler == nullptr)
{
m_oid_handler = new (std::nothrow) oid_handler (m_error_ctx);
if (m_oid_handler == nullptr)
{
assert (false);
m_error_ctx.set_error (METHOD_CALLBACK_ER_NO_MORE_MEMORY, NULL, __FILE__, __LINE__);
}
}
return m_oid_handler;
}
int
callback_handler::oid_get (packing_unpacker &unpacker)
{
int error = NO_ERROR;
oid_get_request request;
request.unpack (unpacker);
oid_get_info info = get_oid_handler()->oid_get (request.oid, request.attr_names);
if (m_error_ctx.has_error())
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, info);
}
}
int
callback_handler::oid_put (packing_unpacker &unpacker)
{
oid_put_request request;
request.unpack (unpacker);
int result = get_oid_handler()->oid_put (request.oid, request.attr_names, request.db_values);
if (m_error_ctx.has_error())
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, result);
}
}
int
callback_handler::oid_cmd (packing_unpacker &unpacker)
{
int cmd = OID_CMD_FIRST;
unpacker.unpack_int (cmd);
OID oid = OID_INITIALIZER;
unpacker.unpack_oid (oid);
std::string res; // result for OID_CLASS_NAME
int res_code = get_oid_handler()->oid_cmd (oid, cmd, res);
if (m_error_ctx.has_error())
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, res_code, res);
}
}
// Collection
int
callback_handler::collection_cmd (packing_unpacker &unpacker)
{
// args
collection_cmd_request request;
request.unpack (unpacker);
int result = m_oid_handler->collection_cmd (request.oid, request.command, request.index, request.attr_name,
request.value);
if (m_error_ctx.has_error())
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, result);
}
}
// Schema Info
/*
int
callback_handler::get_schema_info (packing_unpacker &unpacker)
{
int error = NO_ERROR;
schema_info_handler sch_handler (m_error_ctx);
return error;
}
*/
// Compile
static bool
is_supported_dbtype (const DB_TYPE type)
{
bool res = false;
switch (type)
{
case DB_TYPE_INTEGER:
case DB_TYPE_SHORT:
case DB_TYPE_BIGINT:
case DB_TYPE_FLOAT:
case DB_TYPE_DOUBLE:
case DB_TYPE_MONETARY:
case DB_TYPE_NUMERIC:
case DB_TYPE_CHAR:
case DB_TYPE_STRING:
case DB_TYPE_DATE:
case DB_TYPE_TIME:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_DATETIME:
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
case DB_TYPE_OID:
case DB_TYPE_OBJECT:
case DB_TYPE_RESULTSET:
case DB_TYPE_NULL:
res = true;
break;
// unsupported types
case DB_TYPE_BIT:
case DB_TYPE_VARBIT:
case DB_TYPE_TABLE:
case DB_TYPE_BLOB:
case DB_TYPE_CLOB:
case DB_TYPE_TIMESTAMPTZ:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_DATETIMETZ:
case DB_TYPE_DATETIMELTZ:
case DB_TYPE_JSON:
case DB_TYPE_ENUMERATION:
res = false;
break;
// obsolete, internal, unused type
case DB_TYPE_ELO:
case DB_TYPE_VARIABLE:
case DB_TYPE_SUB:
case DB_TYPE_POINTER:
case DB_TYPE_ERROR:
case DB_TYPE_VOBJ:
case DB_TYPE_DB_VALUE:
case DB_TYPE_MIDXKEY:
default:
assert (false);
break;
}
return res;
}
int
callback_handler::get_sql_semantics (packing_unpacker &unpacker)
{
sql_semantics_request request;
unpacker.unpack_all (request);
int i = -1;
int error = NO_ERROR;
std::vector<sql_semantics> semantics_vec;
for (const std::string &s : request.sqls)
{
i++;
query_handler *handler = new_query_handler ();
if (handler == nullptr)
{
break;
}
sql_semantics semantics;
semantics.idx = i;
er_clear ();
m_error_ctx.clear ();
error = handler->prepare_compile (s);
if (error == NO_ERROR && m_error_ctx.has_error () == false)
{
DB_SESSION *db_session = handler->get_db_session ();
const prepare_info &info = handler->get_prepare_info ();
semantics.sql_type = info.stmt_type;
PARSER_CONTEXT *parser = db_get_parser (db_session);
PT_NODE *stmt = db_get_statement (db_session, 0);
parser->custom_print |= PT_CONVERT_RANGE;
semantics.rewritten_query = parser_print_tree (parser, stmt);
const std::vector<column_info> &column_infos = info.column_infos;
for (const column_info &c_info : column_infos)
{
semantics.columns.emplace_back (c_info);
}
// into variable
char **external_into_label = db_session->parser->external_into_label;
if (external_into_label)
{
for (int i = 0; i < db_session->parser->external_into_label_cnt; i++)
{
semantics.into_vars.push_back (external_into_label[i]);
free (external_into_label[i]);
}
free (external_into_label);
}
db_session->parser->external_into_label = NULL;
db_session->parser->external_into_label_cnt = 0;
// host/automatic variables
DB_MARKER *marker = db_get_input_markers (db_session, 1);
if (marker)
{
/* The following way of getting markers_cnt is unreliable:
* it does not match the actual number of markers sometimes (CBRD-25606)
* TODO: figure out why.
int markers_cnt = parser->host_var_count + parser->auto_param_count;
* Instead, we count the actual number of markers as follows.
*/
int markers_cnt = 0;
DB_MARKER *marker_save = marker;
do
{
markers_cnt++;
marker = db_marker_next (marker);
}
while (marker);
marker = marker_save;
semantics.hvs.resize (markers_cnt);
do
{
int idx = marker->info.host_var.index;
if (idx >= markers_cnt)
{
error = ER_FAILED;
semantics.sql_type = error;
semantics.rewritten_query = "internal error: a host variable marker index is out of valid range";
break;
}
if (semantics.hvs[idx].mode != 0)
{
error = ER_FAILED;
semantics.sql_type = error;
semantics.rewritten_query = "internal error: two different host variable markers have the same index";
break;
}
semantics.hvs[idx].mode = 1;
if (marker->info.host_var.label)
{
semantics.hvs[idx].name.assign ((char *) marker->info.host_var.label);
}
TP_DOMAIN *hv_expected_domain = NULL;
if (idx >= parser->host_var_count)
{
// auto parameterized
hv_expected_domain = marker->expected_domain;
}
else
{
hv_expected_domain = db_session->parser->host_var_expected_domains[idx];
}
// safe guard
if (hv_expected_domain == NULL)
{
hv_expected_domain = pt_node_to_db_domain (parser, marker, NULL);
}
semantics.hvs[idx].type = TP_DOMAIN_TYPE (hv_expected_domain);
semantics.hvs[idx].precision = db_domain_precision (hv_expected_domain);
semantics.hvs[idx].scale = (short) db_domain_scale (hv_expected_domain);
semantics.hvs[idx].charset = db_domain_codeset (hv_expected_domain);
if (semantics.hvs[idx].type != DB_TYPE_NULL)
{
db_value_clone (& (db_session->parser->host_variables[idx]), & (semantics.hvs[idx].value));
}
else
{
db_make_null (& (semantics.hvs[idx].value));
}
marker = db_marker_next (marker);
}
while (marker);
}
}
else
{
error = ER_FAILED;
semantics.sql_type = m_error_ctx.get_error ();
semantics.rewritten_query = m_error_ctx.get_error_msg ();
}
semantics_vec.push_back (semantics);
free_query_handle (handler->get_id (), true);
if (error != NO_ERROR)
{
break;
}
}
for (sql_semantics &s : semantics_vec)
{
for (const cubpl::pl_parameter_info &hv : s.hvs)
{
if (is_supported_dbtype ((DB_TYPE) hv.type) == false)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_ARG_TYPE, 1, pr_type_name ((DB_TYPE) hv.type));
}
}
if (er_errid () != NO_ERROR)
{
s.columns.clear ();
s.hvs.clear ();
s.into_vars.clear ();
error = s.sql_type = er_errid ();
s.rewritten_query = er_msg ();
}
}
sql_semantics_response response;
response.semantics = std::move (semantics_vec);
if (error == NO_ERROR)
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, response);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, response);
}
}
// TODO: move it to proper place
static int
get_user_defined_procedure_function_info (global_semantics_question &question, global_semantics_response_udpf &res)
{
DB_OBJECT *mop_p;
DB_VALUE return_type;
int err = NO_ERROR;
int save;
const char *name = question.name.c_str ();
AU_DISABLE (save);
{
// TODO
mop_p = jsp_find_stored_procedure (name, DB_AUTH_NONE);
if (mop_p == NULL)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto exit;
}
DB_VALUE temp;
int num_args = -1;
err = db_get (mop_p, SP_ATTR_ARG_COUNT, &temp);
if (err == NO_ERROR)
{
num_args = db_get_int (&temp);
}
pr_clear_value (&temp);
if (num_args == -1)
{
goto exit;
}
res.args.resize (num_args);
DB_VALUE args;
/* arg_mode, arg_type */
err = db_get (mop_p, SP_ATTR_ARGS, &args);
if (err == NO_ERROR)
{
DB_SET *param_set = db_get_set (&args);
DB_VALUE mode, arg_type, has_default;
int i;
for (i = 0; i < num_args; i++)
{
pl_parameter_info ¶m_info = res.args[i];
set_get_element (param_set, i, &temp);
DB_OBJECT *arg_mop_p = db_get_object (&temp);
if (arg_mop_p)
{
if (db_get (arg_mop_p, SP_ARG_ATTR_MODE, &mode) == NO_ERROR)
{
param_info.mode = db_get_int (&mode);
}
if (db_get (arg_mop_p, SP_ARG_ATTR_DATA_TYPE, &arg_type) == NO_ERROR)
{
param_info.type = db_get_int (&arg_type);
}
if (db_get (arg_mop_p, SP_ARG_ATTR_DEFAULT_VALUE, &has_default) == NO_ERROR)
{
param_info.has_default = DB_IS_NULL (&has_default) ? 0 : 1;
}
pr_clear_value (&mode);
pr_clear_value (&arg_type);
pr_clear_value (&has_default);
pr_clear_value (&temp);
}
else
{
// error
break;
}
}
pr_clear_value (&args);
}
if (db_get (mop_p, SP_ATTR_RETURN_TYPE, &return_type) == NO_ERROR)
{
res.ret.type = db_get_int (&return_type);
pr_clear_value (&return_type);
}
}
exit:
AU_ENABLE (save);
res.err_id = err;
if (err != NO_ERROR)
{
res.err_msg = er_msg ();
}
er_clear ();
return err;
}
static int
get_serial_info (global_semantics_question &question, global_semantics_response_serial &res)
{
int result = NO_ERROR;
MOP serial_class_mop, serial_mop;
DB_IDENTIFIER serial_obj_id;
const char *serial_name = question.name.c_str ();
serial_class_mop = sm_find_class (CT_SERIAL_NAME);
char realname[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
sm_user_specified_name (serial_name, realname, DB_MAX_IDENTIFIER_LENGTH);
serial_mop = do_get_serial_obj_id (&serial_obj_id, serial_class_mop, realname);
if (serial_mop == NULL)
{
result = ER_QPROC_SERIAL_NOT_FOUND;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_SERIAL_NOT_FOUND, 1, realname);
}
res.err_id = result;
if (result != NO_ERROR)
{
res.err_msg = er_msg ();
}
er_clear();
return result;
}
static int
get_column_info (global_semantics_question &question, global_semantics_response_column &res)
{
int err = NO_ERROR;
const std::string &name = question.name;
if (name.empty () == true)
{
err = res.err_id = ER_FAILED;
res.err_msg = "Invalid parameter";
}
std::string owner_name;
std::string class_name;
std::string attr_name;
auto split_str = [] (const std::string& name, size_t &prev, size_t &cur, std::string& out_name)
{
cur = name.find ('.', prev);
if (cur != std::string::npos)
{
out_name = name.substr (prev, cur - prev);
prev = cur + 1;
}
else
{
out_name = name.substr (prev);
}
};
size_t prev = 0, cur = 0;
int dot_cnt = std::count (name.begin (), name.end(), '.');
if (dot_cnt == 2) // with owner name
{
split_str (name, prev, cur, owner_name);
owner_name += ".";
}
split_str (name, prev, cur, class_name);
split_str (name, prev, cur, attr_name);
std::string class_name_with_owner = owner_name + class_name;
char realname[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
sm_user_specified_name (class_name_with_owner.c_str (), realname, DB_MAX_IDENTIFIER_LENGTH);
transform (attr_name.begin(), attr_name.end(), attr_name.begin(), ::tolower);
DB_ATTRIBUTE *attr = db_get_attribute_by_name (realname, attr_name.c_str ());
if (attr == NULL)
{
err = res.err_id = ER_FAILED;
res.err_msg = "Failed to get attribute information";
}
else
{
DB_DOMAIN *domain = db_attribute_domain (attr);
int precision = db_domain_precision (domain);
short scale = db_domain_scale (domain);
char charset = db_domain_codeset (domain);
int db_type = TP_DOMAIN_TYPE (domain);
int set_type = DB_TYPE_NULL;
if (TP_IS_SET_TYPE (db_type))
{
set_type = get_set_domain (domain, precision, scale, charset);
}
char auto_increment = db_attribute_is_auto_increment (attr);
char unique_key = db_attribute_is_unique (attr);
char primary_key = db_attribute_is_primary_key (attr);
char reverse_index = db_attribute_is_reverse_indexed (attr);
char reverse_unique = db_attribute_is_reverse_unique (attr);
char foreign_key = db_attribute_is_foreign_key (attr);
char shared = db_attribute_is_shared (attr);
const char *c_attr_name = db_attribute_name (attr);
std::string attr_name_string (c_attr_name? c_attr_name : "");
std::string class_name_string (realname? realname : "");
std::string default_value_string = get_column_default_as_string (attr);
column_info info (db_type, set_type, scale, precision, charset,
attr_name_string, default_value_string,
auto_increment, unique_key, primary_key, reverse_index, reverse_unique, foreign_key, shared,
attr_name_string, class_name_string, false);
res.c_info = std::move (info);
}
return err;
}
int
callback_handler::get_global_semantics (packing_unpacker &unpacker)
{
int error = NO_ERROR;
global_semantics_request request;
unpacker.unpack_all (request);
global_semantics_response response;
int i = 0;
for (global_semantics_question &question : request.qsqs)
{
switch (question.type)
{
case 1: // PROCEDURE
case 2: // FUNCTION
{
auto res_ptr = std::make_unique <global_semantics_response_udpf> ();
res_ptr->idx = i++;
error = get_user_defined_procedure_function_info (question, *res_ptr);
response.qs.push_back (std::move (res_ptr));
break;
}
case 3: // SERIAL
{
auto res_ptr = std::make_unique <global_semantics_response_serial> ();
res_ptr->idx = i++;
error = get_serial_info (question, *res_ptr);
response.qs.push_back (std::move (res_ptr));
break;
}
case 4: // COLUMN
{
auto res_ptr = std::make_unique <global_semantics_response_column> ();
res_ptr->idx = i++;
error = get_column_info (question, *res_ptr);
response.qs.push_back (std::move (res_ptr));
break;
}
default:
{
assert (false);
global_semantics_response_common error_response;
error = error_response.err_id = ER_FAILED;
error_response.err_msg = "Invalid request type";
error_response.idx = request.qsqs.size ();
auto res_ptr = std::make_unique <global_semantics_response_common> (error_response);
res_ptr->idx = i++;
response.qs.push_back (std::move (res_ptr));
break;
}
}
if (error != NO_ERROR)
{
break;
}
}
if (error == NO_ERROR)
{
return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, response);
}
else
{
return xs_pack_and_queue (METHOD_RESPONSE_ERROR, response);
}
}
int
callback_handler::change_rights (packing_unpacker &unpacker)
{
int error = NO_ERROR;
int command;
std::string auth_user_name;
unpacker.unpack_int (command);
if (command == 0) // PUSH
{
unpacker.unpack_string (auth_user_name);
MOP user = au_find_user (auth_user_name.c_str ());
if (user == NULL)
{
error = ER_FAILED;
}
else
{
au_perform_push_user (user);
}
}
else // POP
{
au_perform_pop_user ();
}
// no response
return error;
}
// Managing Query Handler Table
query_handler *
callback_handler::new_query_handler ()
{
int idx = 0;
int handler_size = m_query_handlers.size();
for (; idx < handler_size; idx++)
{
if (m_query_handlers[idx] == nullptr)
{
/* found */
break;
}
}
query_handler *handler = new (std::nothrow) query_handler (m_error_ctx, idx);
if (handler == nullptr)
{
assert (false);
return handler;
}
if (idx < handler_size)
{
m_query_handlers[idx] = handler;
}
else
{
m_query_handlers.push_back (handler);
}
return handler;
}
query_handler *
callback_handler::get_query_handler_by_id (const int id)
{
if (id < 0 || id >= (int) m_query_handlers.size())
{
return nullptr;
}
return m_query_handlers[id];
}
void
callback_handler::free_query_handle (int id, bool is_free)
{
if (id < 0 || id >= (int) m_query_handlers.size())
{
return;
}
if (m_query_handlers[id] != nullptr)
{
// clear <query ID -> handler ID>
if (m_query_handlers[id]->get_query_id () != (uint64_t) (-1))
{
m_qid_handler_map.erase (m_query_handlers[id]->get_query_id ());
}
if (is_free)
{
// clear <SQL string -> handler ID>
m_sql_handler_map.erase (m_query_handlers[id]->get_sql_stmt());
m_deferred_query_free_handler.push_back (m_query_handlers[id]);
m_query_handlers[id] = nullptr;
}
else
{
m_query_handlers[id]->reset ();
}
}
}
void
callback_handler::free_query_handle_all (bool is_free)
{
for (int i = 0; i < (int) m_query_handlers.size(); i++)
{
free_query_handle (i, is_free);
}
}
void
callback_handler::free_deferred_query_handler ()
{
for (auto it = m_deferred_query_free_handler.begin(); it != m_deferred_query_free_handler.end(); it++)
{
delete *it;
}
m_deferred_query_free_handler.clear();
}
void
callback_handler::clear_all_query_handlers ()
{
/* must run before ws_final(); query_handler dtor walks ws_heap-allocated host_variables */
for (auto it = m_deferred_query_free_handler.begin (); it != m_deferred_query_free_handler.end (); it++)
{
delete *it;
}
m_deferred_query_free_handler.clear ();
for (size_t i = 0; i < m_query_handlers.size (); i++)
{
if (m_query_handlers[i] != nullptr)
{
delete m_query_handlers[i];
m_query_handlers[i] = nullptr;
}
}
m_query_handlers.clear ();
m_sql_handler_map.clear ();
m_qid_handler_map.clear ();
}
query_handler *
callback_handler::get_query_handler_by_query_id (const uint64_t qid)
{
const auto &iter = m_qid_handler_map.find (qid);
if (iter == m_qid_handler_map.end() )
{
return nullptr;
}
else
{
return get_query_handler_by_id (iter->second);
}
}
query_handler *
callback_handler::get_query_handler_by_sql (const std::string &sql, std::function<bool (query_handler *)> cond)
{
for (auto it = m_sql_handler_map.lower_bound (sql); it != m_sql_handler_map.upper_bound (sql); it++)
{
query_handler *handler = get_query_handler_by_id (it->second);
if (handler != nullptr && cond (handler))
{
/* found */
return handler;
}
}
return nullptr;
}
std::queue <cubmem::extensible_block> &
callback_handler::get_data_queue ()
{
return m_data_queue;
}
// Global method callback handler interface
static callback_handler handler (100);
callback_handler *
get_callback_handler (void)
{
return &handler;
}
}
/* called from boot_client_all_finalize() before ws_final() */
void
method_callback_final (void)
{
cubmethod::callback_handler *h = cubmethod::get_callback_handler ();
if (h != NULL)
{
h->clear_all_query_handlers ();
}
}