From ba9413b26a478ece8826883d8f254f1d40b6bb43 Mon Sep 17 00:00:00 2001 From: alexpeshkoff Date: Tue, 19 Feb 2013 11:20:49 +0000 Subject: [PATCH] Add IStatement::getFlags() to help user make a solution what to do with SQL statement --- src/common/StatementMetadata.cpp | 26 ++++++++++++++++++++++++++ src/common/StatementMetadata.h | 3 ++- src/dsql/dsql.cpp | 21 +++++++++++++++++++++ src/include/firebird/Provider.h | 11 +++++++++-- src/jrd/EngineInterface.h | 1 + src/jrd/inf_pub.h | 1 + src/jrd/jrd.cpp | 31 +++++++++++++++++++++++++++++++ src/remote/client/interface.cpp | 27 +++++++++++++++++++++++++++ src/remote/server/server.cpp | 5 ++--- src/yvalve/YObjects.h | 1 + src/yvalve/why.cpp | 21 ++++++++++++++++++--- 11 files changed, 139 insertions(+), 9 deletions(-) diff --git a/src/common/StatementMetadata.cpp b/src/common/StatementMetadata.cpp index ecd08cfbff..f35a27c075 100644 --- a/src/common/StatementMetadata.cpp +++ b/src/common/StatementMetadata.cpp @@ -64,6 +64,9 @@ unsigned StatementMetadata::buildInfoItems(Array& items, unsigned flags) if (flags & IStatement::PREPARE_PREFETCH_TYPE) items.add(isc_info_sql_stmt_type); + if (flags & IStatement::PREPARE_PREFETCH_FLAGS) + items.add(isc_info_sql_stmt_flags); + if (flags & IStatement::PREPARE_PREFETCH_INPUT_PARAMETERS) { items.add(isc_info_sql_bind); @@ -100,6 +103,10 @@ unsigned StatementMetadata::buildInfoFlags(unsigned itemsLength, const UCHAR* it flags |= IStatement::PREPARE_PREFETCH_TYPE; break; + case isc_info_sql_stmt_flags: + flags |= IStatement::PREPARE_PREFETCH_FLAGS; + break; + case isc_info_sql_get_plan: flags |= IStatement::PREPARE_PREFETCH_LEGACY_PLAN; break; @@ -137,6 +144,21 @@ unsigned StatementMetadata::getType() return type.value; } +unsigned StatementMetadata::getFlags() +{ + if (!flags.specified) + { + UCHAR info[] = {isc_info_sql_stmt_flags}; + UCHAR result[16]; + + getAndParse(sizeof(info), info, sizeof(result), result); + + fb_assert(flags.specified); + } + + return flags.value; +} + // Get statement plan. const char* StatementMetadata::getPlan(bool detailed) { @@ -227,6 +249,10 @@ void StatementMetadata::parse(unsigned bufferLength, const UCHAR* buffer) type = getNumericInfo(&buffer); break; + case isc_info_sql_stmt_flags: + flags = getNumericInfo(&buffer); + break; + case isc_info_sql_get_plan: case isc_info_sql_explain_plan: { diff --git a/src/common/StatementMetadata.h b/src/common/StatementMetadata.h index 79fc156424..ac80ee3cd9 100644 --- a/src/common/StatementMetadata.h +++ b/src/common/StatementMetadata.h @@ -66,6 +66,7 @@ public: static unsigned buildInfoFlags(unsigned itemsLength, const UCHAR* items); unsigned getType(); + unsigned getFlags(); const char* getPlan(bool detailed); IMessageMetadata* getInputMetadata(); IMessageMetadata* getOutputMetadata(); @@ -81,7 +82,7 @@ private: private: IStatement* statement; - Nullable type; + Nullable type, flags; string legacyPlan, detailedPlan; RefPtr inputParameters, outputParameters; }; diff --git a/src/dsql/dsql.cpp b/src/dsql/dsql.cpp index 930775707e..b7289080bc 100644 --- a/src/dsql/dsql.cpp +++ b/src/dsql/dsql.cpp @@ -1713,6 +1713,7 @@ static void sql_info(thread_db* tdbb, { ULONG length; USHORT number; + ULONG value; const UCHAR item = *items++; switch (item) @@ -1730,6 +1731,26 @@ static void sql_info(thread_db* tdbb, *info++ = item; break; + case isc_info_sql_stmt_flags: + value = IStatement::STATEMENT_REPEAT_EXECUTE; + switch (statement->getType()) + { + case DsqlCompiledStatement::TYPE_CREATE_DB: + case DsqlCompiledStatement::TYPE_DDL: + value &= ~IStatement::STATEMENT_REPEAT_EXECUTE; + break; + case DsqlCompiledStatement::TYPE_SELECT: + case DsqlCompiledStatement::TYPE_SELECT_UPD: + case DsqlCompiledStatement::TYPE_SELECT_BLOCK: + value |= IStatement::STATEMENT_HAS_CURSOR; + break; + } + length = put_vax_long(buffer, value); + info = put_item(item, length, buffer, info, end_info); + if (!info) + return; + break; + case isc_info_sql_stmt_type: switch (statement->getType()) { diff --git a/src/include/firebird/Provider.h b/src/include/firebird/Provider.h index bdfc7f6180..f6d1a92ac7 100644 --- a/src/include/firebird/Provider.h +++ b/src/include/firebird/Provider.h @@ -151,12 +151,18 @@ public: static const unsigned PREPARE_PREFETCH_LEGACY_PLAN = 0x08; static const unsigned PREPARE_PREFETCH_DETAILED_PLAN = 0x10; static const unsigned PREPARE_PREFETCH_AFFECTED_RECORDS = 0x20; // not used yet + static const unsigned PREPARE_PREFETCH_FLAGS = 0x40; static const unsigned PREPARE_PREFETCH_METADATA = - PREPARE_PREFETCH_TYPE | PREPARE_PREFETCH_INPUT_PARAMETERS | PREPARE_PREFETCH_OUTPUT_PARAMETERS; + PREPARE_PREFETCH_TYPE | PREPARE_PREFETCH_FLAGS | + PREPARE_PREFETCH_INPUT_PARAMETERS | PREPARE_PREFETCH_OUTPUT_PARAMETERS; static const unsigned PREPARE_PREFETCH_ALL = PREPARE_PREFETCH_METADATA | PREPARE_PREFETCH_LEGACY_PLAN | PREPARE_PREFETCH_DETAILED_PLAN | PREPARE_PREFETCH_AFFECTED_RECORDS; + // Statement flags. + static const unsigned STATEMENT_HAS_CURSOR = 0x01; + static const unsigned STATEMENT_REPEAT_EXECUTE = 0x02; + virtual void FB_CARG getInfo(IStatus* status, unsigned int itemsLength, const unsigned char* items, unsigned int bufferLength, unsigned char* buffer) = 0; @@ -171,8 +177,9 @@ public: FbMessage* in, IMessageMetadata* out) = 0; virtual void FB_CARG setCursorName(IStatus* status, const char* name) = 0; virtual void FB_CARG free(IStatus* status) = 0; + virtual unsigned FB_CARG getFlags(IStatus* status) = 0; }; -#define FB_STATEMENT_VERSION (FB_REFCOUNTED_VERSION + 10) +#define FB_STATEMENT_VERSION (FB_REFCOUNTED_VERSION + 11) class IRequest : public IRefCounted { diff --git a/src/jrd/EngineInterface.h b/src/jrd/EngineInterface.h index b9671c74bd..8b14d0b2e8 100644 --- a/src/jrd/EngineInterface.h +++ b/src/jrd/EngineInterface.h @@ -190,6 +190,7 @@ public: virtual JResultSet* FB_CARG openCursor(Firebird::IStatus* status, Firebird::ITransaction* transaction, Firebird::FbMessage* in, Firebird::IMessageMetadata* out); virtual void FB_CARG setCursorName(Firebird::IStatus* status, const char* name); + virtual unsigned FB_CARG getFlags(Firebird::IStatus* status); public: JStatement(dsql_req* handle, JAttachment* ja, Firebird::Array& meta) diff --git a/src/jrd/inf_pub.h b/src/jrd/inf_pub.h index 3f699b1e28..56f6853ee4 100644 --- a/src/jrd/inf_pub.h +++ b/src/jrd/inf_pub.h @@ -390,6 +390,7 @@ enum info_db_provider #define isc_info_sql_batch_fetch 24 #define isc_info_sql_relation_alias 25 #define isc_info_sql_explain_plan 26 +#define isc_info_sql_stmt_flags 27 /*********************************/ /* SQL information return values */ diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 7d2498b911..7bedefc583 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -4573,6 +4573,37 @@ unsigned JStatement::getType(IStatus* userStatus) } +unsigned JStatement::getFlags(IStatus* userStatus) +{ + unsigned ret = 0; + + try + { + EngineContextHolder tdbb(userStatus, this, FB_FUNCTION); + check_database(tdbb); + + try + { + ret = metadata.getFlags(); + } + catch (const Exception& ex) + { + transliterateException(tdbb, ex, userStatus, "JStatement::getFlags"); + return ret; + } + } + catch (const Exception& ex) + { + ex.stuffException(userStatus); + return ret; + } + + successful_completion(userStatus); + + return ret; +} + + const char* JStatement::getPlan(IStatus* userStatus, FB_BOOLEAN detailed) { const char* ret = NULL; diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp index ab8aecf733..bf02a0ae2e 100644 --- a/src/remote/client/interface.cpp +++ b/src/remote/client/interface.cpp @@ -291,6 +291,7 @@ public: FbMessage* inMsgBuffer, IMessageMetadata* outFormat); virtual void FB_CARG setCursorName(IStatus* status, const char* name); virtual void FB_CARG free(IStatus* status); + virtual unsigned FB_CARG getFlags(IStatus* status); public: Statement(Rsr* handle, Attachment* a, unsigned aDialect) @@ -2405,6 +2406,32 @@ unsigned Statement::getType(IStatus* status) } +unsigned Statement::getFlags(IStatus* status) +{ + try + { + reset(status); + + // Check and validate handles, etc. + + CHECK_HANDLE(statement, isc_bad_req_handle); + Rdb* rdb = statement->rsr_rdb; + rem_port* port = rdb->rdb_port; + RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION); + + statement->raiseException(); + + return metadata.getFlags(); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } + + return 0; +} + + const char* Statement::getPlan(IStatus* status, FB_BOOLEAN detailed) { try diff --git a/src/remote/server/server.cpp b/src/remote/server/server.cpp index e6902b5d7b..aa937ac23b 100644 --- a/src/remote/server/server.cpp +++ b/src/remote/server/server.cpp @@ -2921,14 +2921,13 @@ ISC_STATUS rem_port::execute_statement(P_OP op, P_SQLDATA* sqldata, PACKET* send InternalMessageBuffer oMsgBuffer(out_blr_length, out_blr, out_msg_length, out_msg); ITransaction* newTra = tra; - unsigned type = statement->rsr_iface->getType(&status_vector); + unsigned flags = statement->rsr_iface->getFlags(&status_vector); if (!status_vector.isSuccess()) { status_exception::raise(status_vector.get()); } - if ((type == isc_info_sql_stmt_select || type == isc_info_sql_stmt_select_for_upd) && - out_msg_length == 0) + if ((flags & IStatement::STATEMENT_HAS_CURSOR) && (out_msg_length == 0)) { if (out_blr_length) { diff --git a/src/yvalve/YObjects.h b/src/yvalve/YObjects.h index 77f45cd3c8..8b5f9757d2 100644 --- a/src/yvalve/YObjects.h +++ b/src/yvalve/YObjects.h @@ -325,6 +325,7 @@ public: Firebird::FbMessage* in, Firebird::IMessageMetadata* out); virtual void FB_CARG setCursorName(Firebird::IStatus* status, const char* name); virtual void FB_CARG free(Firebird::IStatus* status); + virtual unsigned FB_CARG getFlags(Firebird::IStatus* status); public: Firebird::Mutex cursorMutex; diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index f4d1c672ce..2cb003b27b 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -1961,14 +1961,13 @@ ISC_STATUS API_ROUTINE isc_dsql_execute2_m(ISC_STATUS* userStatus, FB_API_HANDLE Arg::Gds(isc_dsql_cursor_open_err)).raise(); } - unsigned type = statement->statement->getType(&status); + unsigned flags = statement->statement->getFlags(&status); if (!status.isSuccess()) { return status[1]; } - if ((type == isc_info_sql_stmt_select || type == isc_info_sql_stmt_select_for_upd) && - outMsgLength == 0) + if ((flags & IStatement::STATEMENT_HAS_CURSOR) && (outMsgLength == 0)) { if (outBlrLength) { @@ -3852,6 +3851,22 @@ unsigned YStatement::getType(IStatus* status) return 0; } +unsigned YStatement::getFlags(IStatus* status) +{ + try + { + YEntry entry(status, this); + + return entry.next()->getFlags(status); + } + catch (const Exception& e) + { + e.stuffException(status); + } + + return 0; +} + const char* YStatement::getPlan(IStatus* status, FB_BOOLEAN detailed) { try