8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 20:43:03 +01:00

1) Make a new kind of Node (TransactionNode).

2) Make main parser statement return requests instead of nodes.
3) Some related cleanup (ddlData, ddlScratch).
4) Added dsqlPass to dsql_req and children, to get rid of ugly logic in prepareStatement.
This commit is contained in:
asfernandes 2012-02-25 19:56:37 +00:00
parent 1198014fcf
commit 8f46d9300e
9 changed files with 359 additions and 354 deletions

View File

@ -46,17 +46,19 @@ class VariableNode;
class DsqlCompilerScratch : public BlrWriter class DsqlCompilerScratch : public BlrWriter
{ {
public: public:
static const unsigned FLAG_IN_AUTO_TRANS_BLOCK = 0x001; static const unsigned FLAG_IN_AUTO_TRANS_BLOCK = 0x0001;
static const unsigned FLAG_RETURNING_INTO = 0x002; static const unsigned FLAG_RETURNING_INTO = 0x0002;
static const unsigned FLAG_METADATA_SAVED = 0x004; static const unsigned FLAG_METADATA_SAVED = 0x0004;
static const unsigned FLAG_PROCEDURE = 0x008; static const unsigned FLAG_PROCEDURE = 0x0008;
static const unsigned FLAG_TRIGGER = 0x010; static const unsigned FLAG_TRIGGER = 0x0010;
static const unsigned FLAG_BLOCK = 0x020; static const unsigned FLAG_BLOCK = 0x0020;
static const unsigned FLAG_RECURSIVE_CTE = 0x040; static const unsigned FLAG_RECURSIVE_CTE = 0x0040;
static const unsigned FLAG_UPDATE_OR_INSERT = 0x080; static const unsigned FLAG_UPDATE_OR_INSERT = 0x0080;
static const unsigned FLAG_MERGE = 0x100; static const unsigned FLAG_MERGE = 0x0100;
static const unsigned FLAG_FUNCTION = 0x200; static const unsigned FLAG_FUNCTION = 0x0200;
static const unsigned FLAG_SUB_ROUTINE = 0x400; static const unsigned FLAG_SUB_ROUTINE = 0x0400;
static const unsigned FLAG_INTERNAL_REQUEST = 0x0800;
static const unsigned FLAG_AMBIGUOUS_STMT = 0x1000;
public: public:
DsqlCompilerScratch(MemoryPool& p, dsql_dbb* aDbb, jrd_tra* aTransaction, DsqlCompilerScratch(MemoryPool& p, dsql_dbb* aDbb, jrd_tra* aTransaction,

View File

@ -225,6 +225,25 @@ public:
}; };
class TransactionNode : public Node
{
public:
explicit TransactionNode(MemoryPool& pool)
: Node(pool)
{
}
public:
virtual TransactionNode* dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
Node::dsqlPass(dsqlScratch);
return this;
}
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const = 0;
};
class DmlNode : public Node class DmlNode : public Node
{ {
public: public:
@ -851,7 +870,6 @@ public:
{ {
TYPE_ASSIGNMENT, TYPE_ASSIGNMENT,
TYPE_BLOCK, TYPE_BLOCK,
TYPE_COMMIT_ROLLBACK,
TYPE_COMPOUND_STMT, TYPE_COMPOUND_STMT,
TYPE_CONTINUE_LEAVE, TYPE_CONTINUE_LEAVE,
TYPE_CURSOR_STMT, TYPE_CURSOR_STMT,
@ -885,7 +903,6 @@ public:
TYPE_SAVEPOINT_ENCLOSE, TYPE_SAVEPOINT_ENCLOSE,
TYPE_SELECT, TYPE_SELECT,
TYPE_SET_GENERATOR, TYPE_SET_GENERATOR,
TYPE_SET_TRANSACTION,
TYPE_STALL, TYPE_STALL,
TYPE_STORE, TYPE_STORE,
TYPE_SUSPEND, TYPE_SUSPEND,

View File

@ -91,10 +91,13 @@ Parser::~Parser()
} }
Node* Parser::parse() dsql_req* Parser::parse()
{ {
if (parseAux() != 0) if (parseAux() != 0)
{
fb_assert(false);
return NULL; return NULL;
}
transformString(lex.start, lex.end - lex.start, transformedString); transformString(lex.start, lex.end - lex.start, transformedString);

View File

@ -128,7 +128,7 @@ public:
~Parser(); ~Parser();
public: public:
Node* parse(); dsql_req* parse();
const Firebird::string& getTransformedString() const const Firebird::string& getTransformedString() const
{ {
@ -283,7 +283,7 @@ private:
Firebird::string transformedString; Firebird::string transformedString;
Firebird::GenericMap<Firebird::NonPooled<dsql_str*, StrMark> > strMarks; Firebird::GenericMap<Firebird::NonPooled<dsql_str*, StrMark> > strMarks;
bool stmt_ambiguous; bool stmt_ambiguous;
Node* DSQL_parse; dsql_req* DSQL_parse;
// These value/posn are taken from the lexer // These value/posn are taken from the lexer
YYSTYPE yylval; YYSTYPE yylval;

View File

@ -6776,42 +6776,8 @@ DmlNode* UserSavepointNode::parse(thread_db* /*tdbb*/, MemoryPool& pool, Compile
UserSavepointNode* UserSavepointNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) UserSavepointNode* UserSavepointNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{ {
DsqlCompiledStatement* statement = dsqlScratch->getStatement(); fb_assert(!(dsqlScratch->flags & DsqlCompilerScratch::FLAG_BLOCK));
dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_SAVEPOINT);
// ASF: It should never enter in this IF, because the grammar does not allow it.
if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_BLOCK) // blocks, procedures and triggers
{
const char* cmd = NULL;
switch (command)
{
//case CMD_NOTHING:
case CMD_SET:
cmd = "SAVEPOINT";
break;
case CMD_RELEASE:
cmd = "RELEASE";
break;
case CMD_RELEASE_ONLY:
cmd = "RELEASE ONLY";
break;
case CMD_ROLLBACK:
cmd = "ROLLBACK";
break;
default:
cmd = "UNKNOWN";
fb_assert(false);
}
ERRD_post(
Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
// Token unknown
Arg::Gds(isc_token_err) <<
Arg::Gds(isc_random) << Arg::Str(cmd));
}
statement->setType(DsqlCompiledStatement::TYPE_SAVEPOINT);
return this; return this;
} }
@ -7616,14 +7582,18 @@ SetTransactionNode* SetTransactionNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
} }
if (dsqlScratch->getBlrData().getCount() > 1) // 1 -> isc_tpb_version1 if (dsqlScratch->getBlrData().getCount() > 1) // 1 -> isc_tpb_version1
{ tpb.add(dsqlScratch->getBlrData().begin(), dsqlScratch->getBlrData().getCount());
// Store DYN data in the statement.
dsqlScratch->getStatement()->setDdlData(dsqlScratch->getBlrData());
}
return this; return this;
} }
void SetTransactionNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const
{
JRD_start_transaction(tdbb, &request->req_transaction, request->req_dbb->dbb_attachment,
tpb.getCount(), tpb.begin());
*transaction = request->req_transaction;
}
// Generate tpb for table lock. // Generate tpb for table lock.
// If lock level is specified, it overrrides the transaction lock level. // If lock level is specified, it overrrides the transaction lock level.
void SetTransactionNode::genTableLock(DsqlCompilerScratch* dsqlScratch, const dsql_nod* tblLock, void SetTransactionNode::genTableLock(DsqlCompilerScratch* dsqlScratch, const dsql_nod* tblLock,

View File

@ -159,7 +159,7 @@ public:
}; };
class CommitRollbackNode : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_COMMIT_ROLLBACK> class CommitRollbackNode : public TransactionNode
{ {
public: public:
enum Command enum Command
@ -170,7 +170,7 @@ public:
public: public:
explicit CommitRollbackNode(MemoryPool& pool, Command aCommand, bool aRetain) explicit CommitRollbackNode(MemoryPool& pool, Command aCommand, bool aRetain)
: TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_COMMIT_ROLLBACK>(pool), : TransactionNode(pool),
command(aCommand), command(aCommand),
retain(aRetain) retain(aRetain)
{ {
@ -200,8 +200,36 @@ public:
return this; return this;
} }
virtual void genBlr(DsqlCompilerScratch* dsqlScratch) virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const
{ {
if (retain)
{
switch (command)
{
case CMD_COMMIT:
JRD_commit_retaining(tdbb, request->req_transaction);
break;
case CMD_ROLLBACK:
JRD_rollback_retaining(tdbb, request->req_transaction);
break;
}
}
else
{
switch (command)
{
case CMD_COMMIT:
JRD_commit_transaction(tdbb, request->req_transaction);
break;
case CMD_ROLLBACK:
JRD_rollback_transaction(tdbb, request->req_transaction);
break;
}
*transaction = NULL;
}
} }
private: private:
@ -1432,7 +1460,7 @@ public:
}; };
class SetTransactionNode : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_SET_TRANSACTION> class SetTransactionNode : public TransactionNode
{ {
public: public:
enum enum
@ -1445,7 +1473,8 @@ public:
public: public:
explicit SetTransactionNode(MemoryPool& pool) explicit SetTransactionNode(MemoryPool& pool)
: TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_SET_TRANSACTION>(pool) : TransactionNode(pool),
tpb(pool)
{ {
} }
@ -1457,9 +1486,7 @@ public:
virtual SetTransactionNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); virtual SetTransactionNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch) virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const;
{
}
private: private:
void genTableLock(DsqlCompilerScratch* dsqlScratch, const dsql_nod* tblLock, USHORT lockLevel); void genTableLock(DsqlCompilerScratch* dsqlScratch, const dsql_nod* tblLock, USHORT lockLevel);
@ -1473,6 +1500,7 @@ public:
Nullable<bool> restartRequests; Nullable<bool> restartRequests;
Nullable<USHORT> lockTimeout; Nullable<USHORT> lockTimeout;
Nullable<dsql_nod*> reserveList; Nullable<dsql_nod*> reserveList;
Firebird::UCharBuffer tpb;
}; };

View File

@ -115,57 +115,6 @@ namespace
isc_info_req_update_count, isc_info_req_delete_count, isc_info_req_update_count, isc_info_req_delete_count,
isc_info_req_select_count, isc_info_req_insert_count isc_info_req_select_count, isc_info_req_insert_count
}; };
class DsqlDmlRequest : public dsql_req
{
public:
explicit DsqlDmlRequest(DsqlCompilerScratch* scratch)
: dsql_req(scratch)
{
}
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
bool singleton);
virtual void setCursor(thread_db* tdbb, const TEXT* name);
virtual ISC_STATUS fetch(thread_db* tdbb, ULONG blrLength, const UCHAR* blr,
ULONG msgLength, UCHAR* msgBuffer);
};
class DsqlDdlRequest : public dsql_req
{
public:
explicit DsqlDdlRequest(DsqlCompilerScratch* scratch, DdlNode* aNode)
: dsql_req(scratch),
node(aNode)
{
}
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
bool singleton);
private:
DdlNode* node;
};
class DsqlTransactionRequest : public dsql_req
{
public:
explicit DsqlTransactionRequest(DsqlCompilerScratch* scratch)
: dsql_req(scratch)
{
}
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
bool singleton);
};
} // namespace } // namespace
@ -204,8 +153,10 @@ dsql_req* DSQL_allocate_statement(thread_db* tdbb, Jrd::Attachment* attachment)
DsqlCompilerScratch* scratch = FB_NEW(pool) DsqlCompilerScratch(pool, database, DsqlCompilerScratch* scratch = FB_NEW(pool) DsqlCompilerScratch(pool, database,
NULL, statement); NULL, statement);
dsql_req* const request = FB_NEW(pool) DsqlDmlRequest(scratch); dsql_req* const request = FB_NEW(pool) DsqlDmlRequest(pool, NULL);
request->req_dbb = database; request->req_dbb = database;
request->req_transaction = scratch->getTransaction();
request->statement = scratch->getStatement();
return request; return request;
} }
@ -754,14 +705,108 @@ void DSQL_execute_immediate(thread_db* tdbb, Jrd::Attachment* attachment, jrd_tr
} }
void DsqlDmlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
ntrace_result_t* traceResult)
{
node = Node::doDsqlPass(scratch, node);
if (scratch->clientDialect > SQL_DIALECT_V5)
scratch->getStatement()->addFlags(DsqlCompiledStatement::FLAG_BLR_VERSION5);
else
scratch->getStatement()->addFlags(DsqlCompiledStatement::FLAG_BLR_VERSION4);
GEN_request(scratch, node);
// Create the messages buffers
for (size_t i = 0; i < scratch->ports.getCount(); ++i)
{
dsql_msg* message = scratch->ports[i];
// Allocate buffer for message
const ULONG newLen = message->msg_length + FB_DOUBLE_ALIGN - 1;
message->msg_buffer_number = req_msg_buffers.getCount();
req_msg_buffers.grow(message->msg_buffer_number + 1);
UCHAR*& msgBuffer = req_msg_buffers[message->msg_buffer_number];
fb_assert(!msgBuffer);
msgBuffer = FB_NEW(*tdbb->getDefaultPool()) UCHAR[newLen];
msgBuffer = (UCHAR*) FB_ALIGN((U_IPTR) msgBuffer, FB_DOUBLE_ALIGN);
}
// have the access method compile the statement
#ifdef DSQL_DEBUG
if (DSQL_debug & 64)
{
dsql_trace("Resulting BLR code for DSQL:");
gds__trace_raw("Statement:\n");
gds__trace_raw(statement->getSqlText()->c_str(), statement->getSqlText()->length());
gds__trace_raw("\nBLR:\n");
fb_print_blr(scratch->getBlrData().begin(),
(ULONG) scratch->getBlrData().getCount(),
gds__trace_printer, 0, 0);
}
#endif
ISC_STATUS_ARRAY localStatus;
MOVE_CLEAR(localStatus, sizeof(localStatus));
// check for warnings
if (tdbb->tdbb_status_vector[2] == isc_arg_warning)
{
// save a status vector
memcpy(localStatus, tdbb->tdbb_status_vector, sizeof(ISC_STATUS_ARRAY));
}
ISC_STATUS status = FB_SUCCESS;
try
{
JRD_compile(tdbb, scratch->getAttachment()->dbb_attachment, &req_request,
scratch->getBlrData().getCount(), scratch->getBlrData().begin(),
statement->getSqlText(),
scratch->getDebugData().getCount(), scratch->getDebugData().begin(),
(scratch->flags & DsqlCompilerScratch::FLAG_INTERNAL_REQUEST));
}
catch (const Exception&)
{
status = tdbb->tdbb_status_vector[1];
*traceResult = (status == isc_no_priv ? res_unauthorized : res_failed);
}
// restore warnings (if there are any)
if (localStatus[2] == isc_arg_warning)
{
size_t indx, len, warning;
// find end of a status vector
PARSE_STATUS(tdbb->tdbb_status_vector, indx, warning);
if (indx)
--indx;
// calculate length of saved warnings
PARSE_STATUS(localStatus, len, warning);
len -= 2;
if ((len + indx - 1) < ISC_STATUS_LENGTH)
memcpy(&tdbb->tdbb_status_vector[indx], &localStatus[2], sizeof(ISC_STATUS) * len);
}
// free blr memory
scratch->getBlrData().free();
if (status)
status_exception::raise(tdbb->tdbb_status_vector);
}
// Execute a dynamic SQL statement. // Execute a dynamic SQL statement.
void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle, void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg, ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg, ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
bool singleton) bool singleton)
{ {
const DsqlCompiledStatement* statement = getStatement();
// If there is no data required, just start the request // If there is no data required, just start the request
const dsql_msg* message = statement->getSendMsg(); const dsql_msg* message = statement->getSendMsg();
@ -894,6 +939,30 @@ void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
trace.finish(have_cursor, res_successful); trace.finish(have_cursor, res_successful);
} }
void DsqlDdlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
ntrace_result_t* traceResult)
{
this->scratch = scratch;
node = Node::doDsqlPass(scratch, node);
if (scratch->getAttachment()->dbb_read_only)
ERRD_post(Arg::Gds(isc_read_only_database));
if ((scratch->flags & DsqlCompilerScratch::FLAG_AMBIGUOUS_STMT) &&
scratch->getAttachment()->dbb_db_SQL_dialect != scratch->clientDialect)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-817) <<
Arg::Gds(isc_ddl_not_allowed_by_db_sql_dial) <<
Arg::Num(scratch->getAttachment()->dbb_db_SQL_dialect));
}
if (scratch->clientDialect > SQL_DIALECT_V5)
scratch->getStatement()->addFlags(DsqlCompiledStatement::FLAG_BLR_VERSION5);
else
scratch->getStatement()->addFlags(DsqlCompiledStatement::FLAG_BLR_VERSION4);
}
// Execute a dynamic SQL statement. // Execute a dynamic SQL statement.
void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle, void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg, ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
@ -902,14 +971,12 @@ void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
{ {
TraceDSQLExecute trace(req_dbb->dbb_attachment, this); TraceDSQLExecute trace(req_dbb->dbb_attachment, this);
const DsqlCompiledStatement* statement = getStatement();
fb_utils::init_status(tdbb->tdbb_status_vector); fb_utils::init_status(tdbb->tdbb_status_vector);
// run all statements under savepoint control // run all statements under savepoint control
{ // scope { // scope
AutoSavePoint savePoint(tdbb, req_transaction); AutoSavePoint savePoint(tdbb, req_transaction);
node->executeDdl(tdbb, statement->getDdlScratch(), req_transaction); node->executeDdl(tdbb, scratch, req_transaction);
savePoint.release(); // everything is ok savePoint.release(); // everything is ok
} }
@ -918,43 +985,20 @@ void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
trace.finish(false, res_successful); trace.finish(false, res_successful);
} }
void DsqlTransactionRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
ntrace_result_t* /*traceResult*/)
{
node = Node::doDsqlPass(scratch, node);
}
// Execute a dynamic SQL statement. // Execute a dynamic SQL statement.
void DsqlTransactionRequest::execute(thread_db* tdbb, jrd_tra** traHandle, void DsqlTransactionRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg, ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg, ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
bool singleton) bool singleton)
{ {
const DsqlCompiledStatement* statement = getStatement(); node->execute(tdbb, this, traHandle);
switch (statement->getType())
{
case DsqlCompiledStatement::TYPE_START_TRANS:
JRD_start_transaction(tdbb, &req_transaction, req_dbb->dbb_attachment,
statement->getDdlData().getCount(), statement->getDdlData().begin());
*traHandle = req_transaction;
break;
case DsqlCompiledStatement::TYPE_COMMIT:
JRD_commit_transaction(tdbb, req_transaction);
*traHandle = NULL;
break;
case DsqlCompiledStatement::TYPE_COMMIT_RETAIN:
JRD_commit_retaining(tdbb, req_transaction);
break;
case DsqlCompiledStatement::TYPE_ROLLBACK:
JRD_rollback_transaction(tdbb, req_transaction);
*traHandle = NULL;
break;
case DsqlCompiledStatement::TYPE_ROLLBACK_RETAIN:
JRD_rollback_retaining(tdbb, req_transaction);
break;
default:
fb_assert(false);
}
} }
@ -1535,6 +1579,9 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra*
transaction, statement); transaction, statement);
scratch->clientDialect = clientDialect; scratch->clientDialect = clientDialect;
if (isInternalRequest)
scratch->flags |= DsqlCompilerScratch::FLAG_INTERNAL_REQUEST;
dsql_req* request = NULL; dsql_req* request = NULL;
try try
@ -1545,17 +1592,10 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra*
scratch->getAttachment()->dbb_db_SQL_dialect, parserVersion, text, textLength, scratch->getAttachment()->dbb_db_SQL_dialect, parserVersion, text, textLength,
tdbb->getAttachment()->att_charset); tdbb->getAttachment()->att_charset);
Node* node = parser.parse(); request = parser.parse();
if (!node) if (parser.isStmtAmbiguous())
{ scratch->flags |= DsqlCompilerScratch::FLAG_AMBIGUOUS_STMT;
// CVC: Apparently, Parser::parse won't return if the command is incomplete,
// because yyerror() will call ERRD_post().
// This may be a special case, but we don't know about positions here.
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
// Unexpected end of command
Arg::Gds(isc_command_end_err));
}
string transformedText = parser.getTransformedString(); string transformedText = parser.getTransformedString();
SSHORT charSetId = database->dbb_attachment->att_charset; SSHORT charSetId = database->dbb_attachment->att_charset;
@ -1602,161 +1642,24 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra*
statement->setType(DsqlCompiledStatement::TYPE_SELECT); statement->setType(DsqlCompiledStatement::TYPE_SELECT);
node = Node::doDsqlPass(scratch, node); if (request->req_traced)
fb_assert(node);
const DsqlCompiledStatement::Type statementType = statement->getType();
switch (statementType)
{
case DsqlCompiledStatement::TYPE_COMMIT:
case DsqlCompiledStatement::TYPE_COMMIT_RETAIN:
case DsqlCompiledStatement::TYPE_ROLLBACK:
case DsqlCompiledStatement::TYPE_ROLLBACK_RETAIN:
case DsqlCompiledStatement::TYPE_START_TRANS:
request = FB_NEW(statement->getPool()) DsqlTransactionRequest(scratch);
request->req_traced = false;
trace.setStatement(request);
return request; // Stop here for statements not requiring code generation.
case DsqlCompiledStatement::TYPE_CREATE_DB:
case DsqlCompiledStatement::TYPE_DDL:
if (scratch->getAttachment()->dbb_read_only)
ERRD_post(Arg::Gds(isc_read_only_database));
request = FB_NEW(statement->getPool()) DsqlDdlRequest(scratch,
static_cast<DdlNode*>(node));
break;
default:
request = FB_NEW(statement->getPool()) DsqlDmlRequest(scratch);
break;
}
request->req_traced = true;
trace.setStatement(request); trace.setStatement(request);
if (statementType == DsqlCompiledStatement::TYPE_DDL) ntrace_result_t traceResult = res_successful;
{
if (parser.isStmtAmbiguous() &&
scratch->getAttachment()->dbb_db_SQL_dialect != clientDialect)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-817) <<
Arg::Gds(isc_ddl_not_allowed_by_db_sql_dial) <<
Arg::Num(scratch->getAttachment()->dbb_db_SQL_dialect));
}
statement->setDdlScratch(scratch);
}
if (clientDialect > SQL_DIALECT_V5)
statement->addFlags(DsqlCompiledStatement::FLAG_BLR_VERSION5);
else
statement->addFlags(DsqlCompiledStatement::FLAG_BLR_VERSION4);
if (!statement->isDdl())
GEN_request(scratch, static_cast<DmlNode*>(node));
// Create the messages buffers
for (size_t i = 0; i < scratch->ports.getCount(); ++i)
{
dsql_msg* message = scratch->ports[i];
// Allocate buffer for message
const ULONG newLen = message->msg_length + FB_DOUBLE_ALIGN - 1;
message->msg_buffer_number = request->req_msg_buffers.getCount();
request->req_msg_buffers.grow(message->msg_buffer_number + 1);
UCHAR*& msgBuffer = request->req_msg_buffers[message->msg_buffer_number];
fb_assert(!msgBuffer);
msgBuffer = FB_NEW(*tdbb->getDefaultPool()) UCHAR[newLen];
msgBuffer = (UCHAR*) FB_ALIGN((U_IPTR) msgBuffer, FB_DOUBLE_ALIGN);
}
// stop here for ddl statements
if (statementType == DsqlCompiledStatement::TYPE_CREATE_DB ||
statementType == DsqlCompiledStatement::TYPE_DDL)
{
// Notify Trace API manager about new DDL request cooked.
trace.prepare(res_successful);
return request;
}
// have the access method compile the statement
#ifdef DSQL_DEBUG
if (DSQL_debug & 64)
{
dsql_trace("Resulting BLR code for DSQL:");
gds__trace_raw("Statement:\n");
gds__trace_raw(text, textLength);
gds__trace_raw("\nBLR:\n");
fb_print_blr(scratch->getBlrData().begin(),
(ULONG) scratch->getBlrData().getCount(),
gds__trace_printer, 0, 0);
}
#endif
ISC_STATUS_ARRAY localStatus;
MOVE_CLEAR(localStatus, sizeof(localStatus));
// check for warnings
if (tdbb->tdbb_status_vector[2] == isc_arg_warning)
{
// save a status vector
memcpy(localStatus, tdbb->tdbb_status_vector, sizeof(ISC_STATUS_ARRAY));
}
ISC_STATUS status = FB_SUCCESS;
try try
{ {
JRD_compile(tdbb, request->req_dbb = scratch->getAttachment();
scratch->getAttachment()->dbb_attachment, request->req_transaction = scratch->getTransaction();
&request->req_request, request->statement = scratch->getStatement();
scratch->getBlrData().getCount(),
scratch->getBlrData().begin(), request->dsqlPass(tdbb, scratch, &traceResult);
statement->getSqlText(),
scratch->getDebugData().getCount(),
scratch->getDebugData().begin(),
isInternalRequest);
} }
catch (const Firebird::Exception&) catch (const Exception&)
{ {
status = tdbb->tdbb_status_vector[1]; trace.prepare(traceResult);
trace.prepare(status == isc_no_priv ? res_unauthorized : res_failed); throw;
} }
trace.prepare(traceResult);
// restore warnings (if there are any)
if (localStatus[2] == isc_arg_warning)
{
size_t indx, len, warning;
// find end of a status vector
PARSE_STATUS(tdbb->tdbb_status_vector, indx, warning);
if (indx)
--indx;
// calculate length of saved warnings
PARSE_STATUS(localStatus, len, warning);
len -= 2;
if ((len + indx - 1) < ISC_STATUS_LENGTH)
memcpy(&tdbb->tdbb_status_vector[indx], &localStatus[2], sizeof(ISC_STATUS) * len);
}
// free blr memory
scratch->getBlrData().free();
if (status)
Firebird::status_exception::raise(tdbb->tdbb_status_vector);
// Notify Trace API manager about new request cooked.
trace.prepare(res_successful);
return request; return request;
} }
@ -1830,16 +1733,15 @@ static void release_statement(DsqlCompiledStatement* statement)
} }
statement->setSqlText(NULL); statement->setSqlText(NULL);
statement->getDdlData().free(); // free blr memory
} }
dsql_req::dsql_req(DsqlCompilerScratch* scratch) dsql_req::dsql_req(MemoryPool& pool)
: req_pool(scratch->getStatement()->getPool()), : req_pool(pool),
statement(scratch->getStatement()), statement(NULL),
cursors(req_pool), cursors(req_pool),
req_dbb(scratch->getAttachment()), req_dbb(NULL),
req_transaction(scratch->getTransaction()), req_transaction(NULL),
req_msg_buffers(req_pool), req_msg_buffers(req_pool),
req_cursor(req_pool), req_cursor(req_pool),
req_user_descs(req_pool), req_user_descs(req_pool),

View File

@ -71,6 +71,9 @@ namespace Jrd
class Attachment; class Attachment;
class Database; class Database;
class DsqlCompilerScratch; class DsqlCompilerScratch;
class DdlNode;
class StmtNode;
class TransactionNode;
class jrd_tra; class jrd_tra;
class jrd_req; class jrd_req;
class blb; class blb;
@ -427,7 +430,6 @@ public:
: PermanentStorage(p), : PermanentStorage(p),
type(TYPE_SELECT), type(TYPE_SELECT),
flags(0), flags(0),
ddlData(p),
sendMsg(NULL), sendMsg(NULL),
receiveMsg(NULL), receiveMsg(NULL),
eof(NULL), eof(NULL),
@ -435,8 +437,7 @@ public:
recVersion(NULL), recVersion(NULL),
parentRecVersion(NULL), parentRecVersion(NULL),
parentDbKey(NULL), parentDbKey(NULL),
parentRequest(NULL), parentRequest(NULL)
ddlScratch(NULL)
{ {
} }
@ -454,10 +455,6 @@ public:
const Firebird::RefStrPtr& getSqlText() const { return sqlText; } const Firebird::RefStrPtr& getSqlText() const { return sqlText; }
void setSqlText(Firebird::RefString* value) { sqlText = value; } void setSqlText(Firebird::RefString* value) { sqlText = value; }
Firebird::HalfStaticArray<UCHAR, 1024>& getDdlData() { return ddlData; }
const Firebird::HalfStaticArray<UCHAR, 1024>& getDdlData() const { return ddlData; }
void setDdlData(Firebird::HalfStaticArray<UCHAR, 1024>& value) { ddlData = value; }
bool isDdl() const bool isDdl() const
{ {
return type == TYPE_DDL || type == TYPE_CREATE_DB; return type == TYPE_DDL || type == TYPE_CREATE_DB;
@ -494,14 +491,10 @@ public:
dsql_req* getParentRequest() const { return parentRequest; } dsql_req* getParentRequest() const { return parentRequest; }
void setParentRequest(dsql_req* value) { parentRequest = value; } void setParentRequest(dsql_req* value) { parentRequest = value; }
DsqlCompilerScratch* getDdlScratch() const { return ddlScratch; }
void setDdlScratch(DsqlCompilerScratch* value) { ddlScratch = value; }
private: private:
Type type; // Type of statement Type type; // Type of statement
ULONG flags; // generic flag ULONG flags; // generic flag
Firebird::RefStrPtr sqlText; Firebird::RefStrPtr sqlText;
Firebird::HalfStaticArray<UCHAR, 1024> ddlData;
dsql_msg* sendMsg; // Message to be sent to start request dsql_msg* sendMsg; // Message to be sent to start request
dsql_msg* receiveMsg; // Per record message to be received dsql_msg* receiveMsg; // Per record message to be received
dsql_par* eof; // End of file parameter dsql_par* eof; // End of file parameter
@ -510,7 +503,6 @@ private:
dsql_par* parentRecVersion; // parent record version dsql_par* parentRecVersion; // parent record version
dsql_par* parentDbKey; // Parent database key for current of dsql_par* parentDbKey; // Parent database key for current of
dsql_req* parentRequest; // Source request, if cursor update dsql_req* parentRequest; // Source request, if cursor update
DsqlCompilerScratch* ddlScratch; // DSQL scratch for DDL statements
}; };
class dsql_req : public pool_alloc<dsql_type_req> class dsql_req : public pool_alloc<dsql_type_req>
@ -520,7 +512,7 @@ public:
static const unsigned FLAG_EMBEDDED = 0x02; static const unsigned FLAG_EMBEDDED = 0x02;
public: public:
explicit dsql_req(DsqlCompilerScratch* scratch); explicit dsql_req(MemoryPool& pool);
public: public:
MemoryPool& getPool() MemoryPool& getPool()
@ -538,6 +530,9 @@ public:
return statement; return statement;
} }
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
ntrace_result_t* traceResult) = 0;
virtual void execute(thread_db* tdbb, jrd_tra** traHandle, virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg, ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg, ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
@ -552,9 +547,9 @@ public:
private: private:
MemoryPool& req_pool; MemoryPool& req_pool;
const DsqlCompiledStatement* statement;
public: public:
const DsqlCompiledStatement* statement;
Firebird::Array<DsqlCompiledStatement*> cursors; // Cursor update statements Firebird::Array<DsqlCompiledStatement*> cursors; // Cursor update statements
dsql_dbb* req_dbb; // DSQL attachment dsql_dbb* req_dbb; // DSQL attachment
@ -584,6 +579,79 @@ protected:
friend class Firebird::MemoryPool; friend class Firebird::MemoryPool;
}; };
class DsqlDmlRequest : public dsql_req
{
public:
explicit DsqlDmlRequest(MemoryPool& pool, StmtNode* aNode)
: dsql_req(pool),
node(aNode)
{
req_traced = true;
}
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
ntrace_result_t* traceResult);
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
bool singleton);
virtual void setCursor(thread_db* tdbb, const TEXT* name);
virtual ISC_STATUS fetch(thread_db* tdbb, ULONG blrLength, const UCHAR* blr,
ULONG msgLength, UCHAR* msgBuffer);
private:
StmtNode* node;
};
class DsqlDdlRequest : public dsql_req
{
public:
explicit DsqlDdlRequest(MemoryPool& pool, DdlNode* aNode)
: dsql_req(pool),
node(aNode),
scratch(NULL)
{
req_traced = true;
}
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
ntrace_result_t* traceResult);
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
bool singleton);
private:
DdlNode* node;
DsqlCompilerScratch* scratch;
};
class DsqlTransactionRequest : public dsql_req
{
public:
explicit DsqlTransactionRequest(MemoryPool& pool, TransactionNode* aNode)
: dsql_req(pool),
node(aNode)
{
req_traced = false;
}
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
ntrace_result_t* traceResult);
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
ULONG inBlrLength, const UCHAR* inBlr, ULONG inMsgLength, const UCHAR* inMsg,
ULONG outBlrLength, const UCHAR* const outBlr, ULONG outMsgLength, UCHAR* outMsg,
bool singleton);
private:
TransactionNode* node;
};
//! Implicit (NATURAL and USING) joins //! Implicit (NATURAL and USING) joins
class ImplicitJoin : public pool_alloc<dsql_type_imp_join> class ImplicitJoin : public pool_alloc<dsql_type_imp_join>
{ {

View File

@ -645,6 +645,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
Jrd::BoolExprNode* boolExprNode; Jrd::BoolExprNode* boolExprNode;
Jrd::StmtNode* stmtNode; Jrd::StmtNode* stmtNode;
Jrd::DdlNode* ddlNode; Jrd::DdlNode* ddlNode;
Jrd::TransactionNode* traNode;
Jrd::CreateCollationNode* createCollationNode; Jrd::CreateCollationNode* createCollationNode;
Jrd::CreateDomainNode* createDomainNode; Jrd::CreateDomainNode* createDomainNode;
Jrd::AlterDomainNode* alterDomainNode; Jrd::AlterDomainNode* alterDomainNode;
@ -676,6 +677,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
Jrd::SetTransactionNode* setTransactionNode; Jrd::SetTransactionNode* setTransactionNode;
Jrd::DeclareSubProcNode* declareSubProcNode; Jrd::DeclareSubProcNode* declareSubProcNode;
Jrd::DeclareSubFuncNode* declareSubFuncNode; Jrd::DeclareSubFuncNode* declareSubFuncNode;
Jrd::dsql_req* dsqlReq;
} }
%type <legacyNode> access_type alias_list %type <legacyNode> access_type alias_list
@ -712,10 +714,10 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type <legacyNode> column_constraint column_constraint_clause %type <legacyNode> column_constraint column_constraint_clause
%type <legacyNode> column_constraint_def column_constraint_list column_def %type <legacyNode> column_constraint_def column_constraint_list column_def
%type <boolVal> check_opt %type <boolVal> check_opt
%type <legacyNode> column_list column_name column_parens column_parens_opt column_select %type <legacyNode> column_list column_name column_parens column_parens_opt column_select
%type <legacyNode> column_singleton %type <legacyNode> column_singleton
%type <stmtNode> commit complex_proc_statement %type <traNode> commit
%type <stmtNode> complex_proc_statement
%type <legacyNode> computed_by computed_clause constant constraint_index_opt %type <legacyNode> computed_by computed_clause constant constraint_index_opt
%type <boolVal> conditional %type <boolVal> conditional
%type <legacyNode> constraint_name_opt correlation_name %type <legacyNode> constraint_name_opt correlation_name
@ -744,6 +746,8 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type <ddlNode> declare declare_clause drop drop_clause %type <ddlNode> declare declare_clause drop drop_clause
%type <legacyStr> db_name ddl_desc %type <legacyStr> db_name ddl_desc
%type db_alter_clause(<alterDatabaseNode>) %type db_alter_clause(<alterDatabaseNode>)
%type <ddlNode> ddl_statement
%type <stmtNode> dml_statement
%type <legacyNode> event_argument_opt %type <legacyNode> event_argument_opt
%type <ddlNode> exception_clause %type <ddlNode> exception_clause
@ -851,7 +855,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type <ddlNode> revoke rexception_clause %type <ddlNode> revoke rexception_clause
%type <legacyNode> role_admin_option role_grantee role_grantee_list %type <legacyNode> role_admin_option role_grantee role_grantee_list
%type <legacyNode> role_name role_name_list rows_clause %type <legacyNode> role_name role_name_list rows_clause
%type <stmtNode> rollback %type <traNode> rollback
%type <ddlNode> role_clause rtable_clause %type <ddlNode> role_clause rtable_clause
%type <ddlNode> rview_clause %type <ddlNode> rview_clause
%type <nullableIntVal> revoke_admin %type <nullableIntVal> revoke_admin
@ -871,7 +875,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type <ddlNode> set_statistics %type <ddlNode> set_statistics
%type <legacyNode> simple_type simple_when_clause skip_clause %type <legacyNode> simple_type simple_when_clause skip_clause
%type <uintVal> snap_shot %type <uintVal> snap_shot
%type <node> statement %type <dsqlReq> statement
%type <legacyNode> string_length_opt %type <legacyNode> string_length_opt
%type <legacyNode> symbol_UDF_call_name symbol_UDF_name symbol_blob_subtype_name symbol_character_set_name %type <legacyNode> symbol_UDF_call_name symbol_UDF_name symbol_blob_subtype_name symbol_character_set_name
%type <legacyNode> symbol_collation_name symbol_column_name symbol_constraint_name symbol_cursor_name %type <legacyNode> symbol_collation_name symbol_column_name symbol_constraint_name symbol_cursor_name
@ -897,6 +901,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type tran_option(<setTransactionNode>) tran_option_list(<setTransactionNode>) %type tran_option(<setTransactionNode>) tran_option_list(<setTransactionNode>)
%type tran_option_list_opt(<setTransactionNode>) %type tran_option_list_opt(<setTransactionNode>)
%type <uintVal> time_precision_opt timestamp_precision_opt %type <uintVal> time_precision_opt timestamp_precision_opt
%type <traNode> tra_statement
%type <legacyNode> u_constant u_numeric_constant udf_data_type %type <legacyNode> u_constant u_numeric_constant udf_data_type
%type <createAlterFunctionNode> udf_decl_clause %type <createAlterFunctionNode> udf_decl_clause
@ -998,40 +1003,50 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
// list of possible statements // list of possible statements
top top
: statement : statement { DSQL_parse = $1; }
{ DSQL_parse = $1; } | statement ';' { DSQL_parse = $1; }
| statement ';'
{ DSQL_parse = $1; }
; ;
statement statement
: alter { $$ = $1; } : dml_statement { $$ = newNode<DsqlDmlRequest>($1); }
| ddl_statement { $$ = newNode<DsqlDdlRequest>($1); }
| tra_statement { $$ = newNode<DsqlTransactionRequest>($1); }
;
dml_statement
// ASF: ALTER SEQUENCE is defined here cause it's treated as DML. // ASF: ALTER SEQUENCE is defined here cause it's treated as DML.
| ALTER SEQUENCE alter_sequence_clause { $$ = $3; } : ALTER SEQUENCE alter_sequence_clause { $$ = $3; }
| comment { $$ = $1; }
| commit { $$ = $1; }
| create { $$ = $1; }
| create_or_alter { $$ = $1; }
| declare { $$ = $1; }
| delete { $$ = $1; } | delete { $$ = $1; }
| drop { $$ = $1; }
| grant { $$ = $1; }
| insert { $$ = $1; } | insert { $$ = $1; }
| merge { $$ = $1; } | merge { $$ = $1; }
| exec_procedure { $$ = $1; } | exec_procedure { $$ = $1; }
| exec_block { $$ = $1; } | exec_block { $$ = $1; }
| recreate { $$ = $1; }
| revoke { $$ = $1; }
| rollback { $$ = $1; }
| savepoint { $$ = $1; } | savepoint { $$ = $1; }
| select { $$ = $1; } | select { $$ = $1; }
| set_transaction { $$ = $1; }
| set_generator { $$ = $1; } | set_generator { $$ = $1; }
| set_statistics { $$ = $1; }
| update { $$ = $1; } | update { $$ = $1; }
| update_or_insert { $$ = $1; } | update_or_insert { $$ = $1; }
; ;
ddl_statement
: alter { $$ = $1; }
| comment { $$ = $1; }
| create { $$ = $1; }
| create_or_alter { $$ = $1; }
| declare { $$ = $1; }
| drop { $$ = $1; }
| grant { $$ = $1; }
| recreate { $$ = $1; }
| revoke { $$ = $1; }
| set_statistics { $$ = $1; }
;
tra_statement
: set_transaction { $$ = $1; }
| commit { $$ = $1; }
| rollback { $$ = $1; }
;
// GRANT statement // GRANT statement