diff --git a/doc/sql.extensions/README.isc_info_xxx b/doc/sql.extensions/README.isc_info_xxx index 959488849e..9a487be8b8 100644 --- a/doc/sql.extensions/README.isc_info_xxx +++ b/doc/sql.extensions/README.isc_info_xxx @@ -45,9 +45,9 @@ New items for isc_database_info isc_dpb_addr_flag_conn_encrypted - connection is encrypted; fb_info_wire_crypt - name of connection encryption plugin. -6. fb_info_provider_features: +6. fb_info_features: return list of features supported by current connection's provider. - Each byte in returned array shall be one of following info_provider_features: + Each byte in returned array shall be one of following info_features: fb_feature_multi_statements - multiple prepared statements in single attachment fb_feature_multi_transactions - multiple concurrent transactions in single attachment @@ -55,6 +55,7 @@ New items for isc_database_info fb_feature_session_reset - ALTER SESSION RESET is supported fb_feature_read_consistency - read consistency TIL is supported fb_feature_statement_timeout - statement timeout is supported + fb_feature_statement_long_life - prepared statements are not dropped on transaction end New items for isc_transaction_info: diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 9754866e85..a978771ce2 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -6535,47 +6535,36 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb) } */ - // posting the required privilege access to the current relation and field + // Unless this is a validation expression, post the required privilege access + // to the current relation and field - // If this is in a "validate_subtree" then we must not - // post access checks to the table and the fields in the table. - // If any node of the parse tree is a nod_validate type node, - // the nodes in the subtree are involved in a validation - // clause only, the subtree is a validate_subtree in our notation. - - const SLONG ssRelationId = tail->csb_view ? - tail->csb_view->rel_id : (csb->csb_view ? csb->csb_view->rel_id : 0); - - if (tail->csb_flags & csb_modify) + if (!csb->csb_validate_expr) { - if (!csb->csb_validate_expr) + SecurityClass::flags_t privilege = SCL_select; + + if (!csb->csb_returning_expr) { - SecurityClass::flags_t priv = csb->csb_returning_expr ? - SCL_select : SCL_update; - CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId, - priv, SCL_object_table, relation->rel_name); - CMP_post_access(tdbb, csb, field->fld_security_name, ssRelationId, - priv, SCL_object_column, field->fld_name, relation->rel_name); + if (tail->csb_flags & csb_store) + privilege = SCL_insert; + else if (tail->csb_flags & csb_modify) + privilege = SCL_update; + else if (tail->csb_flags & csb_erase) + privilege = SCL_delete; } - } - else if (tail->csb_flags & csb_erase) - { + + const SLONG ssRelationId = tail->csb_view ? + tail->csb_view->rel_id : (csb->csb_view ? csb->csb_view->rel_id : 0); + CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId, - SCL_delete, SCL_object_table, relation->rel_name); - } - else if (tail->csb_flags & csb_store) - { - CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId, - SCL_insert, SCL_object_table, relation->rel_name); - CMP_post_access(tdbb, csb, field->fld_security_name, ssRelationId, - SCL_insert, SCL_object_column, field->fld_name, relation->rel_name); - } - else - { - CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId, - SCL_select, SCL_object_table, relation->rel_name); - CMP_post_access(tdbb, csb, field->fld_security_name, ssRelationId, - SCL_select, SCL_object_column, field->fld_name, relation->rel_name); + privilege, SCL_object_table, relation->rel_name); + + // Field-level privilege access is posted for every operation except DELETE + + if (privilege != SCL_delete) + { + CMP_post_access(tdbb, csb, field->fld_security_name, ssRelationId, + privilege, SCL_object_column, field->fld_name, relation->rel_name); + } } ValueExprNode* sub; diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 32763a911c..0f714d6e64 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -7241,7 +7241,12 @@ StoreNode* StoreNode::pass1(thread_db* tdbb, CompilerScratch* csb) makeDefaults(tdbb, csb); doPass1(tdbb, csb, statement.getAddress()); - doPass1(tdbb, csb, statement2.getAddress()); + + { // scope + AutoSetRestore autoReturningExpr(&csb->csb_returning_expr, true); + doPass1(tdbb, csb, statement2.getAddress()); + } + doPass1(tdbb, csb, subStore.getAddress()); pass1Validations(tdbb, csb, validations); diff --git a/src/include/firebird/impl/inf_pub.h b/src/include/firebird/impl/inf_pub.h index 45e270bf69..97ee92d385 100644 --- a/src/include/firebird/impl/inf_pub.h +++ b/src/include/firebird/impl/inf_pub.h @@ -163,7 +163,7 @@ enum db_info_types fb_info_wire_crypt = 140, // Return list of features supported by provider of current connection - fb_info_provider_features = 141, + fb_info_features = 141, isc_info_db_last_value /* Leave this LAST! */ }; @@ -174,7 +174,7 @@ enum db_info_crypt /* flags set in fb_info_crypt_state */ fb_info_crypt_process = 0x02 }; -enum info_provider_features // response to fb_info_provider_features +enum info_features // response to fb_info_features { fb_feature_multi_statements = 1, // Multiple prepared statements in single attachment fb_feature_multi_transactions = 2, // Multiple concurrent transaction in single attachment @@ -182,7 +182,7 @@ enum info_provider_features // response to fb_info_provider_features fb_feature_session_reset = 4, // ALTER SESSION RESET is supported fb_feature_read_consistency = 5, // Read consistency TIL is supported fb_feature_statement_timeout = 6, // Statement timeout is supported - fb_feature_statement_long_life = 7, // Prepared statement can survive transaction end + fb_feature_statement_long_life = 7, // Prepared statements are not dropped on transaction end info_provider_features_max // Not really a feature. Keep this last. }; diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 8ec43c2d43..2c6e63091f 100644 --- a/src/jrd/build_no.h +++ b/src/jrd/build_no.h @@ -3,16 +3,16 @@ *** DO NOT EDIT *** TO CHANGE ANY INFORMATION IN HERE PLEASE EDIT src/misc/writeBuildNum.sh - FORMAL BUILD NUMBER:2048 + FORMAL BUILD NUMBER:2049 */ -#define PRODUCT_VER_STRING "4.0.0.2048" -#define FILE_VER_STRING "WI-V4.0.0.2048" -#define LICENSE_VER_STRING "WI-V4.0.0.2048" -#define FILE_VER_NUMBER 4, 0, 0, 2048 +#define PRODUCT_VER_STRING "4.0.0.2049" +#define FILE_VER_STRING "WI-V4.0.0.2049" +#define LICENSE_VER_STRING "WI-V4.0.0.2049" +#define FILE_VER_NUMBER 4, 0, 0, 2049 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "2048" +#define FB_BUILD_NO "2049" #define FB_BUILD_TYPE "V" #define FB_BUILD_SUFFIX "Firebird 4.0 Release Candidate 1" diff --git a/src/jrd/constants.h b/src/jrd/constants.h index da352e96f1..97e6900214 100644 --- a/src/jrd/constants.h +++ b/src/jrd/constants.h @@ -466,7 +466,7 @@ const int OPT_STATIC_ITEMS = 64; #define CURRENT_ENGINE "Engine13" #define EMBEDDED_PROVIDERS "Providers=" CURRENT_ENGINE -// Feature mask for current version of engine provider +// Features set for current version of engine provider #define ENGINE_FEATURES {fb_feature_multi_statements, \ fb_feature_multi_transactions, \ fb_feature_session_reset, \ diff --git a/src/jrd/extds/ExtDS.h b/src/jrd/extds/ExtDS.h index 21e0a33478..61b1583a54 100644 --- a/src/jrd/extds/ExtDS.h +++ b/src/jrd/extds/ExtDS.h @@ -492,11 +492,11 @@ public: virtual Blob* createBlob() = 0; // Test specified feature flag - bool testFeature(info_provider_features value) const { return m_features[value]; } + bool testFeature(info_features value) const { return m_features[value]; } // Set specified flag - void setFeature(info_provider_features value) { m_features[value] = true; } + void setFeature(info_features value) { m_features[value] = true; } // Clear specified flag - void clearFeature(info_provider_features value) { m_features[value] = false; } + void clearFeature(info_features value) { m_features[value] = false; } protected: virtual Transaction* doCreateTransaction() = 0; diff --git a/src/jrd/extds/InternalDS.cpp b/src/jrd/extds/InternalDS.cpp index 1ec3952770..ec9f8503a8 100644 --- a/src/jrd/extds/InternalDS.cpp +++ b/src/jrd/extds/InternalDS.cpp @@ -189,8 +189,8 @@ void InternalConnection::attach(thread_db* tdbb) SQL_DIALECT_V6 : SQL_DIALECT_V5; memset(m_features, false, sizeof(m_features)); - static const info_provider_features features[] = ENGINE_FEATURES; - for (int i = 0; i < sizeof(features); i++) + static const info_features features[] = ENGINE_FEATURES; + for (int i = 0; i < FB_NELEM(features); i++) setFeature(features[i]); } @@ -450,50 +450,51 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql) fb_assert(!m_allocated); } + CallerName save_caller_name(tran->getHandle()->tra_caller_name); + + if (m_callerPrivileges) + { + jrd_req* request = tdbb->getRequest(); + JrdStatement* statement = request ? request->getStatement() : NULL; + CallerName callerName; + const Routine* routine; + + if (statement && statement->parentStatement) + statement = statement->parentStatement; + + if (statement && statement->triggerInvoker) + tran->getHandle()->tra_caller_name = CallerName(obj_trigger, + statement->triggerName, + statement->triggerInvoker->getUserName()); + else if (statement && (routine = statement->getRoutine()) && + routine->getName().identifier.hasData()) + { + const MetaString& userName = routine->invoker ? routine->invoker->getUserName() : ""; + if (routine->getName().package.isEmpty()) + { + tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(), + routine->getName().identifier, userName); + } + else + { + tran->getHandle()->tra_caller_name = CallerName(obj_package_header, + routine->getName().package, userName); + } + } + else + tran->getHandle()->tra_caller_name = CallerName(); + } + { EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); - CallerName save_caller_name(tran->getHandle()->tra_caller_name); - - if (m_callerPrivileges) - { - jrd_req* request = tdbb->getRequest(); - JrdStatement* statement = request ? request->getStatement() : NULL; - CallerName callerName; - const Routine* routine; - - if (statement && statement->parentStatement) - statement = statement->parentStatement; - - if (statement && statement->triggerInvoker) - tran->getHandle()->tra_caller_name = CallerName(obj_trigger, - statement->triggerName, - statement->triggerInvoker->getUserName()); - else if (statement && (routine = statement->getRoutine()) && - routine->getName().identifier.hasData()) - { - const MetaString& userName = routine->invoker ? routine->invoker->getUserName() : ""; - if (routine->getName().package.isEmpty()) - { - tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(), - routine->getName().identifier, userName); - } - else - { - tran->getHandle()->tra_caller_name = CallerName(obj_package_header, - routine->getName().package, userName); - } - } - else - tran->getHandle()->tra_caller_name = CallerName(); - } - m_request.assignRefNoIncr(att->prepare(&status, tran, sql.length(), sql.c_str(), m_connection.getSqlDialect(), 0)); - m_allocated = (m_request != NULL); - - tran->getHandle()->tra_caller_name = save_caller_name; } + m_allocated = (m_request != NULL); + + if (tran->getHandle()) + tran->getHandle()->tra_caller_name = save_caller_name; if (status->getState() & IStatus::STATE_ERRORS) raise(&status, tdbb, "JAttachment::prepare", &sql); diff --git a/src/jrd/extds/IscDS.cpp b/src/jrd/extds/IscDS.cpp index 33c7c515d5..5ded99d713 100644 --- a/src/jrd/extds/IscDS.cpp +++ b/src/jrd/extds/IscDS.cpp @@ -148,7 +148,7 @@ void IscConnection::attach(thread_db* tdbb) { EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); - const unsigned char info[] = {isc_info_db_sql_dialect, fb_info_provider_features, isc_info_end}; + const unsigned char info[] = {isc_info_db_sql_dialect, fb_info_features, isc_info_end}; m_iscProvider.isc_database_info(&status, &m_handle, sizeof(info), info, sizeof(buff), buff); } if (status->getState() & IStatus::STATE_ERRORS) { @@ -171,7 +171,7 @@ void IscConnection::attach(thread_db* tdbb) m_sqlDialect = m_iscProvider.isc_vax_integer(p, len); break; - case fb_info_provider_features: + case fb_info_features: for (int i = 0; i < len; i++) { if (p[i] == 0) @@ -181,7 +181,7 @@ void IscConnection::attach(thread_db* tdbb) if (p[i] < info_provider_features_max) { - setFeature(static_cast(p[i])); + setFeature(static_cast(p[i])); } // else this provider supports unknown feature, ignore it. } @@ -192,7 +192,7 @@ void IscConnection::attach(thread_db* tdbb) const ULONG err = m_iscProvider.isc_vax_integer(p + 1, len - 1); if (err == isc_infunk) { - if (*p == fb_info_provider_features) + if (*p == fb_info_features) { // Used provider follow Firebird error reporting conventions but is not aware of // this info item. Assume Firebird 3 or earlier. diff --git a/src/jrd/inf.cpp b/src/jrd/inf.cpp index b3bb49bd4b..b367bf9811 100644 --- a/src/jrd/inf.cpp +++ b/src/jrd/inf.cpp @@ -227,7 +227,7 @@ void INF_database_info(thread_db* tdbb, CHECK_INPUT("INF_database_info"); CountsBuffer counts_buffer; - UCHAR* buffer = counts_buffer.getBuffer(BUFFER_SMALL); + UCHAR* buffer = counts_buffer.getBuffer(BUFFER_SMALL, false); USHORT length; ULONG err_val; bool header_refreshed = false; @@ -458,31 +458,24 @@ void INF_database_info(thread_db* tdbb, case isc_info_db_id: { - counts_buffer.resize(BUFFER_SMALL); - const UCHAR* const end_buf = counts_buffer.end(); - // May be simpler to code using a server-side version of isql's Extender class. + counts_buffer.clear(); + const PathName& str_fn = dbb->dbb_database_name; - STUFF(p, 2); - USHORT len = str_fn.length(); - if (p + len + 1 >= end_buf) - len = end_buf - p - 1; + counts_buffer.push(2); + PathName::size_type len = str_fn.length(); if (len > 255) len = 255; // Cannot put more in one byte, will truncate instead. - *p++ = len; - memcpy(p, str_fn.c_str(), len); - p += len; - if (p + 2 < end_buf) - { - SCHAR site[256]; - ISC_get_host(site, sizeof(site)); - len = static_cast(strlen(site)); - if (p + len + 1 >= end_buf) - len = end_buf - p - 1; - *p++ = len; - memcpy(p, site, len); - p += len; - } - length = p - buffer; + counts_buffer.push(static_cast(len)); + counts_buffer.push(reinterpret_cast(str_fn.c_str()), len); + + TEXT site[256]; + ISC_get_host(site, sizeof(site)); + UCHAR siteLen = static_cast(strlen(site)); + counts_buffer.push(siteLen); + counts_buffer.push(reinterpret_cast(site), siteLen); + + buffer = counts_buffer.begin(); + length = counts_buffer.getCount(); } break; @@ -855,13 +848,14 @@ void INF_database_info(thread_db* tdbb, length = INF_convert(att->getActualIdleTimeout(), buffer); break; - case fb_info_provider_features: - { - static const unsigned char features[] = ENGINE_FEATURES; - length = sizeof(features); - memcpy(buffer, features, length); - break; - } + case fb_info_features: + { + static const unsigned char features[] = ENGINE_FEATURES; + length = sizeof(features); + counts_buffer.assign(features, length); + buffer = counts_buffer.begin(); + break; + } default: buffer[0] = item; diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index 51fdddc75f..09d721f2ef 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -1789,7 +1789,7 @@ USHORT SCL_convert_privilege(thread_db* tdbb, jrd_tra* transaction, const Firebi { static GlobalPtr privCacheMutex; static bool cacheFlag = false; - typedef NonPooled CachedPriv; + typedef NonPooled CachedPriv; static GlobalPtr > privCache; if (!cacheFlag) diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 87b1115bd1..ffb33c0b69 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=V MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=2048 +BuildNum=2049 NowAt=`pwd` cd `dirname $0`