8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 09:20:39 +01:00

Improvement CORE-5658 : Execute statement with excess parameters

This commit is contained in:
hvlad 2019-03-06 12:05:46 +02:00
parent 906e474541
commit ee3a13d5f6
18 changed files with 113 additions and 44 deletions

View File

@ -1916,6 +1916,8 @@ C --
PARAMETER (GDS__bad_repl_handle = 335545251)
INTEGER*4 GDS__tra_snapshot_does_not_exist
PARAMETER (GDS__tra_snapshot_does_not_exist = 335545252)
INTEGER*4 GDS__eds_input_prm_not_used
PARAMETER (GDS__eds_input_prm_not_used = 335545253)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1911,6 +1911,8 @@ const
gds_bad_repl_handle = 335545251;
isc_tra_snapshot_does_not_exist = 335545252;
gds_tra_snapshot_does_not_exist = 335545252;
isc_eds_input_prm_not_used = 335545253;
gds_eds_input_prm_not_used = 335545253;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;

View File

@ -3367,6 +3367,19 @@ DmlNode* ExecStatementNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr
node->outputs = PAR_args(tdbb, csb, outputs, outputs);
break;
case blr_exec_stmt_in_excess:
{
MemoryPool& pool = csb->csb_pool;
node->excessInputs = FB_NEW_POOL(pool) EDS::ParamNumbers(pool);
const USHORT count = csb->csb_blr_reader.getWord();
for (FB_SIZE_T i = 0; i < count; i++)
{
const USHORT n = csb->csb_blr_reader.getWord();
node->excessInputs->add(n);
}
break;
}
case blr_end:
break;
@ -3395,6 +3408,7 @@ StmtNode* ExecStatementNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
node->sql = doDsqlPass(dsqlScratch, sql);
node->inputs = doDsqlPass(dsqlScratch, inputs);
node->inputNames = inputNames;
node->excessInputs = excessInputs;
// Check params names uniqueness, if present.
@ -3563,7 +3577,7 @@ void ExecStatementNode::genBlr(DsqlCompilerScratch* dsqlScratch)
dsqlScratch->appendUChar(blr_exec_stmt_in_params);
NestConst<ValueExprNode>* ptr = inputs->items.begin();
MetaName* const* name = inputNames ? inputNames->begin() : NULL;
const MetaName* const* name = inputNames ? inputNames->begin() : NULL;
for (const NestConst<ValueExprNode>* end = inputs->items.end(); ptr != end; ++ptr, ++name)
{
@ -3572,6 +3586,15 @@ void ExecStatementNode::genBlr(DsqlCompilerScratch* dsqlScratch)
GEN_expr(dsqlScratch, *ptr);
}
if (excessInputs)
{
dsqlScratch->appendUChar(blr_exec_stmt_in_excess);
dsqlScratch->appendUShort(excessInputs->getCount());
for (FB_SIZE_T i = 0; i < excessInputs->getCount(); i++)
dsqlScratch->appendUShort((*excessInputs)[i]);
}
}
// Outputs.
@ -3676,9 +3699,9 @@ const StmtNode* ExecStatementNode::execute(thread_db* tdbb, jrd_req* request, Ex
stmt->setTimeout(tdbb, timer->timeToExpire());
if (stmt->isSelectable())
stmt->open(tdbb, tran, inpNames, inputs, !innerStmt);
stmt->open(tdbb, tran, inpNames, inputs, excessInputs, !innerStmt);
else
stmt->execute(tdbb, tran, inpNames, inputs, outputs);
stmt->execute(tdbb, tran, inpNames, inputs, excessInputs, outputs);
request->req_operation = jrd_req::req_return;
} // jrd_req::req_evaluate

View File

@ -687,7 +687,8 @@ public:
outputs(NULL),
useCallerPrivs(false),
traScope(EDS::traNotSet), // not defined
inputNames(NULL)
inputNames(NULL),
excessInputs(NULL)
{
}
@ -721,6 +722,7 @@ public:
bool useCallerPrivs;
EDS::TraScope traScope;
EDS::ParamNames* inputNames;
EDS::ParamNumbers* excessInputs;
};

View File

@ -1 +1 @@
58 shift/reduce conflicts, 17 reduce/reduce conflicts.
60 shift/reduce conflicts, 17 reduce/reduce conflicts.

View File

@ -606,6 +606,7 @@ using namespace Firebird;
%token <metaNamePtr> CUME_DIST
%token <metaNamePtr> DECFLOAT
%token <metaNamePtr> DEFINER
%token <metaNamePtr> EXCESS
%token <metaNamePtr> EXCLUDE
%token <metaNamePtr> FIRST_DAY
%token <metaNamePtr> FOLLOWING
@ -623,6 +624,7 @@ using namespace Firebird;
%token <metaNamePtr> NATIVE
%token <metaNamePtr> NORMALIZE_DECFLOAT
%token <metaNamePtr> NTILE
%token <metaNamePtr> NUMBER
%token <metaNamePtr> OTHERS
%token <metaNamePtr> OVERRIDING
%token <metaNamePtr> PERCENT_RANK
@ -3319,6 +3321,23 @@ named_param($execStatementNode)
else
$execStatementNode->inputs->add($3);
}
| EXCESS symbol_variable_name BIND_PARAM value
{
if (!$execStatementNode->inputNames)
$execStatementNode->inputNames = FB_NEW_POOL(getPool()) EDS::ParamNames(getPool());
if (!$execStatementNode->excessInputs)
$execStatementNode->excessInputs = FB_NEW_POOL(getPool()) EDS::ParamNumbers(getPool());
$execStatementNode->excessInputs->add($execStatementNode->inputNames->getCount());
$execStatementNode->inputNames->add($2);
if (!$execStatementNode->inputs)
$execStatementNode->inputs = newNode<ValueListNode>($4);
else
$execStatementNode->inputs->add($4);
}
;
%type not_named_params_list(<execStatementNode>)
@ -8795,6 +8814,7 @@ non_reserved_word
| CTR_LITTLE_ENDIAN
| CUME_DIST
| DEFINER
| EXCESS
| EXCLUDE
| FIRST_DAY
| FOLLOWING

View File

@ -954,6 +954,7 @@ static const struct {
{"tom_chacha_key", 335545250},
{"bad_repl_handle", 335545251},
{"tra_snapshot_does_not_exist", 335545252},
{"eds_input_prm_not_used", 335545253},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -988,6 +988,7 @@ const ISC_STATUS isc_tom_rsa_verify = 335545249L;
const ISC_STATUS isc_tom_chacha_key = 335545250L;
const ISC_STATUS isc_bad_repl_handle = 335545251L;
const ISC_STATUS isc_tra_snapshot_does_not_exist = 335545252L;
const ISC_STATUS isc_eds_input_prm_not_used = 335545253L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1462,7 +1463,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1406;
const ISC_STATUS isc_err_max = 1407;
#else /* c definitions */
@ -2420,6 +2421,7 @@ const ISC_STATUS isc_err_max = 1406;
#define isc_tom_chacha_key 335545250L
#define isc_bad_repl_handle 335545251L
#define isc_tra_snapshot_does_not_exist 335545252L
#define isc_eds_input_prm_not_used 335545253L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2894,7 +2896,7 @@ const ISC_STATUS isc_err_max = 1406;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1406
#define isc_err_max 1407
#endif

View File

@ -957,6 +957,7 @@ Data source : @4"}, /* eds_statement */
{335545250, "Invalid key length @1, need 16 or 32"}, /* tom_chacha_key */
{335545251, "invalid replicator handle"}, /* bad_repl_handle */
{335545252, "Transaction's base snapshot number does not exist"}, /* tra_snapshot_does_not_exist */
{335545253, "Input parameter '@1' is not used in SQL query text"}, /* eds_input_prm_not_used */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -953,6 +953,7 @@ static const struct {
{335545250, -901}, /* 930 tom_chacha_key */
{335545251, -901}, /* 931 bad_repl_handle */
{335545252, -901}, /* 932 tra_snapshot_does_not_exist */
{335545253, -901}, /* 933 eds_input_prm_not_used */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -953,6 +953,7 @@ static const struct {
{335545250, "22023"}, // 930 tom_chacha_key
{335545251, "08003"}, // 931 bad_repl_handle
{335545252, "0B000"}, // 932 tra_snapshot_does_not_exist
{335545253, "42000"}, // 933 eds_input_prm_not_used
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -389,6 +389,7 @@
#define blr_exec_stmt_in_params2 (unsigned char) 12 // named input parameters
#define blr_exec_stmt_out_params (unsigned char) 13 // output parameters
#define blr_exec_stmt_role (unsigned char) 14
#define blr_exec_stmt_in_excess (unsigned char) 15 // excess input params numbers
#define blr_stmt_expr (unsigned char) 190
#define blr_derived_expr (unsigned char) 191

View File

@ -1772,7 +1772,7 @@ void Statement::setTimeout(thread_db* tdbb, unsigned int timeout)
}
void Statement::execute(thread_db* tdbb, Transaction* tran,
const MetaName* const* in_names, const ValueListNode* in_params,
const MetaName* const* in_names, const ValueListNode* in_params, const ParamNumbers* in_excess,
const ValueListNode* out_params)
{
fb_assert(isAllocated() && !m_stmt_selectable);
@ -1781,13 +1781,14 @@ void Statement::execute(thread_db* tdbb, Transaction* tran,
m_transaction = tran;
setInParams(tdbb, in_names, in_params);
setInParams(tdbb, in_names, in_params, in_excess);
doExecute(tdbb);
getOutParams(tdbb, out_params);
}
void Statement::open(thread_db* tdbb, Transaction* tran,
const MetaName* const* in_names, const ValueListNode* in_params, bool singleton)
const MetaName* const* in_names, const ValueListNode* in_params, const ParamNumbers* in_excess,
bool singleton)
{
fb_assert(isAllocated() && m_stmt_selectable);
fb_assert(!m_error);
@ -1796,7 +1797,7 @@ void Statement::open(thread_db* tdbb, Transaction* tran,
m_singleton = singleton;
m_transaction = tran;
setInParams(tdbb, in_names, in_params);
setInParams(tdbb, in_names, in_params, in_excess);
doOpen(tdbb);
m_active = true;
@ -2105,18 +2106,13 @@ void Statement::preprocess(const string& sql, string& ret)
ident.upper();
FB_SIZE_T n = 0;
for (; n < m_sqlParamNames.getCount(); n++)
if (!m_sqlParamNames.find(ident.c_str(), n))
{
if ((*m_sqlParamNames[n]) == ident)
break;
MetaName* pName = FB_NEW_POOL(getPool()) MetaName(getPool(), ident);
n = m_sqlParamNames.add(*pName);
}
if (n >= m_sqlParamNames.getCount())
{
n = m_sqlParamNames.getCount();
m_sqlParamNames.add(FB_NEW_POOL(getPool()) MetaName(getPool(), ident));
}
m_sqlParamsMap.add(m_sqlParamNames[n]);
m_sqlParamsMap.add(&m_sqlParamNames[n]);
}
else
{
@ -2169,27 +2165,44 @@ void Statement::preprocess(const string& sql, string& ret)
}
void Statement::setInParams(thread_db* tdbb, const MetaName* const* names,
const ValueListNode* params)
const ValueListNode* params, const ParamNumbers* in_excess)
{
const FB_SIZE_T count = params ? params->items.getCount() : 0;
const FB_SIZE_T excCount = in_excess ? in_excess->getCount() : 0;
const FB_SIZE_T sqlCount = m_sqlParamNames.getCount();
m_error = (names && (m_sqlParamNames.getCount() != count || count == 0)) ||
(!names && m_sqlParamNames.getCount());
// OK : count - excCount <= sqlCount <= count
if (m_error)
// Check if all passed named parameters, not marked as excess, are present in query text
if (names && count > 0 && excCount != count)
{
// Input parameters mismatch
status_exception::raise(Arg::Gds(isc_eds_input_prm_mismatch));
for (unsigned n = 0, e = 0; n < count; n++)
{
// values in in_excess array are ordered
if (e < excCount && (*in_excess)[e] == n)
{
e++;
continue;
}
const MetaName* name = names[n];
if (!m_sqlParamNames.exist(*name))
{
m_error = true;
// Input parameter ''@1'' is not used in SQL query text
status_exception::raise(Arg::Gds(isc_eds_input_prm_not_used) << Arg::Str(*name));
}
}
}
if (m_sqlParamNames.getCount())
if (sqlCount || names && count > 0)
{
const unsigned int sqlCount = m_sqlParamsMap.getCount();
const unsigned int mapCount = m_sqlParamsMap.getCount();
// Here NestConst plays against its objective. It temporary unconstifies the values.
Array<NestConst<ValueExprNode> > sqlParamsArray(getPool(), 16);
NestConst<ValueExprNode>* sqlParams = sqlParamsArray.getBuffer(sqlCount);
NestConst<ValueExprNode>* sqlParams = sqlParamsArray.getBuffer(mapCount);
for (unsigned int sqlNum = 0; sqlNum < sqlCount; sqlNum++)
for (unsigned int sqlNum = 0; sqlNum < mapCount; sqlNum++)
{
const MetaName* sqlName = m_sqlParamsMap[sqlNum];
@ -2202,6 +2215,7 @@ void Statement::setInParams(thread_db* tdbb, const MetaName* const* names,
if (num == count)
{
m_error = true;
// Input parameter ''@1'' have no value set
status_exception::raise(Arg::Gds(isc_eds_input_prm_not_set) << Arg::Str(*sqlName));
}
@ -2209,7 +2223,7 @@ void Statement::setInParams(thread_db* tdbb, const MetaName* const* names,
sqlParams[sqlNum] = params->items[num];
}
doSetInParams(tdbb, sqlCount, m_sqlParamsMap.begin(), sqlParams);
doSetInParams(tdbb, mapCount, m_sqlParamsMap.begin(), sqlParams);
}
else
doSetInParams(tdbb, count, names, (params ? params->items.begin() : NULL));
@ -2426,13 +2440,6 @@ void Statement::putExtBlob(thread_db* tdbb, dsc& src, dsc& dst)
void Statement::clearNames()
{
MetaName** s = m_sqlParamNames.begin(), **end = m_sqlParamNames.end();
for (; s < end; s++)
{
delete *s;
*s = NULL;
}
m_sqlParamNames.clear();
m_sqlParamsMap.clear();
}

View File

@ -25,6 +25,7 @@
#include "../../common/classes/fb_string.h"
#include "../../common/classes/array.h"
#include "../../common/classes/objects_array.h"
#include "../../common/classes/ClumpletWriter.h"
#include "../../common/classes/locks.h"
#include "../../common/utils_proto.h"
@ -573,7 +574,8 @@ protected:
};
typedef Firebird::Array<Firebird::MetaName*> ParamNames;
typedef Firebird::Array<const Firebird::MetaName*> ParamNames;
typedef Firebird::Array<USHORT> ParamNumbers;
class Statement : public Firebird::PermanentStorage
{
@ -597,9 +599,10 @@ public:
void setTimeout(Jrd::thread_db* tdbb, unsigned int timeout);
void execute(Jrd::thread_db* tdbb, Transaction* tran,
const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params,
const Jrd::ValueListNode* out_params);
const ParamNumbers* in_excess, const Jrd::ValueListNode* out_params);
void open(Jrd::thread_db* tdbb, Transaction* tran,
const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params, bool singleton);
const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params,
const ParamNumbers* in_excess, bool singleton);
bool fetch(Jrd::thread_db* tdbb, const Jrd::ValueListNode* out_params);
void close(Jrd::thread_db* tdbb, bool invalidTran = false);
void deallocate(Jrd::thread_db* tdbb);
@ -636,7 +639,7 @@ protected:
virtual void doClose(Jrd::thread_db* tdbb, bool drop) = 0;
void setInParams(Jrd::thread_db* tdbb, const Firebird::MetaName* const* names,
const Jrd::ValueListNode* params);
const Jrd::ValueListNode* params, const ParamNumbers* in_excess);
virtual void getOutParams(Jrd::thread_db* tdbb, const Jrd::ValueListNode* params);
virtual void doSetInParams(Jrd::thread_db* tdbb, unsigned int count,
@ -689,7 +692,7 @@ protected:
Jrd::jrd_req* m_preparedByReq;
// set in preprocess
ParamNames m_sqlParamNames;
Firebird::SortedObjectsArray<const Firebird::MetaName> m_sqlParamNames;
ParamNames m_sqlParamsMap;
// set in prepare()

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
--
('2019-03-01 12:35:00', 'JRD', 0, 933)
('2019-03-04 19:40:00', 'JRD', 0, 934)
('2015-03-17 18:33:00', 'QLI', 1, 533)
('2018-03-17 12:00:00', 'GFIX', 3, 136)
('1996-11-07 13:39:40', 'GPRE', 4, 1)

View File

@ -1040,6 +1040,7 @@ Data source : @4', NULL, NULL)
('tom_chacha_key', NULL, 'SysFunction.cpp', NULL, 0, 930, NULL, 'Invalid key length @1, need 16 or 32', NULL, NULL);
('bad_repl_handle', NULL, 'jrd.cpp', NULL, 0, 931, NULL, 'invalid replicator handle', NULL, NULL);
('tra_snapshot_does_not_exist', NULL, 'tpc.cpp', NULL, 0, 932, NULL, 'Transaction''s base snapshot number does not exist', NULL, NULL);
('eds_input_prm_not_used', NULL, 'ExtDS.cpp', NULL, 0, 933, NULL, 'Input parameter ''@1'' is not used in SQL query text', NULL, NULL)
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);

View File

@ -939,6 +939,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-901, '22', '023', 0, 930, 'tom_chacha_key', NULL, NULL)
(-901, '08', '003', 0, 931, 'bad_repl_handle', NULL, NULL)
(-901, '0B', '000', 0, 932, 'tra_snapshot_does_not_exist', NULL, NULL)
(-901, '42', '000', 0, 933, 'eds_input_prm_not_used', NULL, NULL)
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)

View File

@ -198,6 +198,7 @@ static const TOK tokens[] =
{TOK_ENTRY_POINT, "ENTRY_POINT", true},
{TOK_ESCAPE, "ESCAPE", false},
{TOK_EXCEPTION, "EXCEPTION", true},
{TOK_EXCESS, "EXCESS", true },
{TOK_EXCLUDE, "EXCLUDE", true},
{TOK_EXECUTE, "EXECUTE", false},
{TOK_EXISTS, "EXISTS", false},