146 lines
4.9 KiB
C++
146 lines
4.9 KiB
C++
/*
|
|
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License, version 2.0,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is also distributed with certain software (including
|
|
* but not limited to OpenSSL) that is licensed under separate terms,
|
|
* as designated in a particular file or component or in included license
|
|
* documentation. The authors of MySQL hereby grant you an additional
|
|
* permission to link the program and your derivative works with the
|
|
* separately licensed software that they have included with MySQL.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License, version 2.0, for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "my_sys.h" // escape_string_for_mysql
|
|
|
|
#include "../utility/error.h"
|
|
|
|
#include "getter_any.h"
|
|
#include "query_string_builder.h"
|
|
#include "sql_statement_builder.h"
|
|
|
|
namespace polarx_rpc {
|
|
|
|
const std::string HINT_RETURNING_FIELD = "fields";
|
|
const std::string RETURNING_CLAUSE = "call dbms_trans.returning('?', '?')";
|
|
|
|
#define HINT_RETURNING "returning"
|
|
#define FIRST_PLACEHOLDER_OF_RETURNING_CLAUSE 27
|
|
#define SECOND_PLACEHOLDER_OF_RETURNING_CLAUSE 32
|
|
|
|
namespace {
|
|
|
|
class Arg_inserter {
|
|
public:
|
|
explicit Arg_inserter(Query_string_builder *qb) : m_qb(qb) {}
|
|
|
|
void operator()() {
|
|
static const char *const k_value_null = "NULL";
|
|
m_qb->format() % Query_formatter::No_escape<const char *>(k_value_null);
|
|
}
|
|
|
|
template <typename Value_type> void operator()(const Value_type &value) {
|
|
m_qb->format() % value;
|
|
}
|
|
|
|
void operator()(const std::string &value, const uint32_t) {
|
|
m_qb->format() % value;
|
|
}
|
|
|
|
private:
|
|
Query_string_builder *m_qb;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
std::string get_returning_field(const std::string &hint, size_t pos) {
|
|
std::string fields = "*";
|
|
if ((hint.length() <= pos + HINT_RETURNING_FIELD.length()) ||
|
|
(hint[pos + HINT_RETURNING_FIELD.length()] != '('))
|
|
throw err_t(ER_POLARX_RPC_ERROR_MSG,
|
|
"Invalid hint format, expecting /* +sql field() */");
|
|
size_t end_pos = 0;
|
|
if ((end_pos = hint.find(')', pos)) != std::string::npos) {
|
|
if (end_pos - pos > 1)
|
|
fields = hint.substr(pos + HINT_RETURNING_FIELD.length() + 1,
|
|
end_pos - (pos + HINT_RETURNING_FIELD.length()) - 1);
|
|
} else
|
|
throw err_t(ER_POLARX_RPC_ERROR_MSG,
|
|
"Invalid hint format, expecting /* +sql field() */");
|
|
return fields;
|
|
}
|
|
|
|
std::string trans_returning(const std::string &query,
|
|
const std::string &fields) {
|
|
std::string returning;
|
|
returning.reserve(FIRST_PLACEHOLDER_OF_RETURNING_CLAUSE + fields.length() +
|
|
(SECOND_PLACEHOLDER_OF_RETURNING_CLAUSE -
|
|
FIRST_PLACEHOLDER_OF_RETURNING_CLAUSE - 1) +
|
|
query.length() + 3);
|
|
returning +=
|
|
RETURNING_CLAUSE.substr(0, FIRST_PLACEHOLDER_OF_RETURNING_CLAUSE);
|
|
returning += fields;
|
|
returning +=
|
|
RETURNING_CLAUSE.substr(FIRST_PLACEHOLDER_OF_RETURNING_CLAUSE + 1,
|
|
SECOND_PLACEHOLDER_OF_RETURNING_CLAUSE -
|
|
FIRST_PLACEHOLDER_OF_RETURNING_CLAUSE - 1);
|
|
returning += query;
|
|
returning +=
|
|
RETURNING_CLAUSE.substr(SECOND_PLACEHOLDER_OF_RETURNING_CLAUSE + 1);
|
|
return returning;
|
|
}
|
|
|
|
void Sql_statement_builder::build(const std::string &query,
|
|
const Arg_list &args,
|
|
const std::string &hint) const {
|
|
/// build original sql
|
|
build(query, args);
|
|
|
|
std::string out_query;
|
|
if (hint.find(HINT_RETURNING) != std::string::npos) {
|
|
/// escape inner sql string
|
|
auto sql_str(m_qb->get());
|
|
m_qb->clear();
|
|
m_qb->escape_string(sql_str.data(), sql_str.length());
|
|
|
|
/// build returning
|
|
std::string::size_type pos;
|
|
if ((pos = hint.find(HINT_RETURNING_FIELD)) != std::string::npos)
|
|
out_query = trans_returning(m_qb->get(), get_returning_field(hint, pos));
|
|
else
|
|
out_query = trans_returning(m_qb->get(), "*");
|
|
} else
|
|
out_query = m_qb->get();
|
|
|
|
m_qb->clear();
|
|
std::string hint_query;
|
|
hint_query.reserve(hint.length() + out_query.length() + 1);
|
|
hint_query += hint;
|
|
hint_query += out_query;
|
|
m_qb->put(hint_query);
|
|
}
|
|
|
|
void Sql_statement_builder::build(const std::string &query,
|
|
const Arg_list &args) const {
|
|
m_qb->put(query);
|
|
|
|
Arg_inserter inserter(m_qb);
|
|
for (int i = 0; i < args.size(); ++i) {
|
|
Getter_any::put_scalar_value_to_functor(args.Get(i), inserter);
|
|
}
|
|
m_qb->format_finalize();
|
|
}
|
|
|
|
} // namespace polarx_rpc
|