From 54cebb88bdd213b69ea3812e896cd13fa3740c9a Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 11 Nov 2016 00:02:23 +0000 Subject: [PATCH 001/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index b4825a6ee3..9c1e20df6b 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:449 + FORMAL BUILD NUMBER:450 */ -#define PRODUCT_VER_STRING "4.0.0.449" -#define FILE_VER_STRING "WI-T4.0.0.449" -#define LICENSE_VER_STRING "WI-T4.0.0.449" -#define FILE_VER_NUMBER 4, 0, 0, 449 +#define PRODUCT_VER_STRING "4.0.0.450" +#define FILE_VER_STRING "WI-T4.0.0.450" +#define LICENSE_VER_STRING "WI-T4.0.0.450" +#define FILE_VER_NUMBER 4, 0, 0, 450 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "449" +#define FB_BUILD_NO "450" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index dc291f50a7..e127c35675 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=449 +BuildNum=450 NowAt=`pwd` cd `dirname $0` From 1e592de776ea07004cae3b09ae9dc3471696fcf9 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Sun, 13 Nov 2016 09:55:21 -0200 Subject: [PATCH 002/134] Misc. --- examples/dbcrypt/DbCrypt.cpp | 3 ++- src/common/classes/DbImplementation.cpp | 2 +- src/dsql/PackageNodes.epp | 1 - src/dsql/parse.y | 9 ++++++--- src/jrd/blb.cpp | 2 +- src/jrd/met.epp | 2 +- src/jrd/met_proto.h | 1 + src/jrd/tra.cpp | 8 ++++++-- src/yvalve/PluginManager.cpp | 8 ++++++-- 9 files changed, 24 insertions(+), 12 deletions(-) diff --git a/examples/dbcrypt/DbCrypt.cpp b/examples/dbcrypt/DbCrypt.cpp index 898678163f..ae20a28380 100644 --- a/examples/dbcrypt/DbCrypt.cpp +++ b/examples/dbcrypt/DbCrypt.cpp @@ -81,7 +81,8 @@ public: void decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to); void setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolderPlugin** sources, const char* keyName); - // One if free to ignore passed info when not needed + + // One is free to ignore passed info when not needed void setInfo(CheckStatusWrapper* status, IDbCryptInfo* info) { // You may uncomment next line in a case of embedded connection diff --git a/src/common/classes/DbImplementation.cpp b/src/common/classes/DbImplementation.cpp index 9c60caa04d..f948bddbc3 100644 --- a/src/common/classes/DbImplementation.cpp +++ b/src/common/classes/DbImplementation.cpp @@ -131,7 +131,7 @@ const UCHAR backwardTable[FB_NELEM(hardware) * FB_NELEM(operatingSystem)] = const UCHAR backEndianess[FB_NELEM(hardware)] = { // Intel AMD Sparc PPC PPC64 MIPSEL MIPS ARM IA64 s390 s390x SH SHEB HPPA Alpha ARM64 PowerPC64el M68k - 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1 + 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1 }; } // anonymous namespace diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index 329e5123ee..75daf789c6 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -591,7 +591,6 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* PKG.RDB$SQL_SECURITY.NULL = FALSE; PKG.RDB$SQL_SECURITY = ssDefiner.value ? FB_TRUE : FB_FALSE; } - END_MODIFY owner = PKG.RDB$OWNER_NAME; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 3573266a77..d02d6c6137 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2096,9 +2096,12 @@ gtt_ops($createRelationNode) %type gtt_op() gtt_op($createRelationNode) : // nothing by default. Will be set "on commit delete rows" in dsqlPass - | sql_security_clause { $createRelationNode->ssDefiner = $1; } - | ON COMMIT DELETE ROWS { setClause($createRelationNode->relationType, "ON COMMIT DELETE ROWS", rel_global_temp_delete); } - | ON COMMIT PRESERVE ROWS { setClause($createRelationNode->relationType, "ON COMMIT PRESERVE ROWS", rel_global_temp_preserve); } + | sql_security_clause + { $createRelationNode->ssDefiner = $1; } + | ON COMMIT DELETE ROWS + { setClause($createRelationNode->relationType, "ON COMMIT DELETE ROWS", rel_global_temp_delete); } + | ON COMMIT PRESERVE ROWS + { setClause($createRelationNode->relationType, "ON COMMIT PRESERVE ROWS", rel_global_temp_preserve); } ; %type external_file diff --git a/src/jrd/blb.cpp b/src/jrd/blb.cpp index e799016b51..6dbb7221e0 100644 --- a/src/jrd/blb.cpp +++ b/src/jrd/blb.cpp @@ -1423,7 +1423,7 @@ blb* blb::open2(thread_db* tdbb, SecurityClass* s_class = SCL_get_class(tdbb, fld->fld_security_name.c_str()); if (s_class && !s_class->scl_blb_access) { - SCL_check_access(tdbb, s_class, 0, 0, NULL, SCL_select, SCL_object_column, false, + SCL_check_access(tdbb, s_class, 0, 0, NULL, SCL_select, SCL_object_column, false, fld->fld_name, blob->blb_relation->rel_name); s_class->scl_blb_access = true; } diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 4b1164bac4..c42c5790ab 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5393,7 +5393,7 @@ int MET_get_linger(thread_db* tdbb) return rc; } -Nullable MET_get_ss_definer(Jrd::thread_db* tdbb) +Nullable MET_get_ss_definer(Jrd::thread_db* tdbb) { /************************************** * diff --git a/src/jrd/met_proto.h b/src/jrd/met_proto.h index 4c65943c4b..fd8554a76d 100644 --- a/src/jrd/met_proto.h +++ b/src/jrd/met_proto.h @@ -141,4 +141,5 @@ Firebird::MetaName MET_get_relation_field(Jrd::thread_db*, MemoryPool& csbPool, void MET_update_partners(Jrd::thread_db*); int MET_get_linger(Jrd::thread_db*); Nullable MET_get_ss_definer(Jrd::thread_db*); + #endif // JRD_MET_PROTO_H diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index 97fbec108d..cda32fcd11 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -3630,7 +3630,8 @@ void jrd_tra::rollforwardSavepoint(thread_db* tdbb) void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id) { USHORT rel_id = blob_id->bid_internal.bid_relation_id; - if ((tra_attachment->isGbak()) || + + if (tra_attachment->isGbak() || tra_attachment->att_user->locksmith(tdbb, SELECT_ANY_OBJECT_IN_DATABASE) || rel_id == 0) { @@ -3641,14 +3642,17 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id) { vec* vector = tra_attachment->att_relations; jrd_rel* blb_relation; + if (rel_id < vector->count() && (blb_relation = (*vector)[rel_id])) { if (blb_relation->rel_security_name.isEmpty()) MET_scan_relation(tdbb, blb_relation); + SecurityClass* s_class = SCL_get_class(tdbb, blb_relation->rel_security_name.c_str()); + if (s_class && !s_class->scl_blb_access) { - SCL_check_access(tdbb, s_class, 0, 0, NULL, SCL_select, SCL_object_table, false, + SCL_check_access(tdbb, s_class, 0, 0, NULL, SCL_select, SCL_object_table, false, blb_relation->rel_name); s_class->scl_blb_access = true; } diff --git a/src/yvalve/PluginManager.cpp b/src/yvalve/PluginManager.cpp index c1f96d7062..d8b6e8da9d 100644 --- a/src/yvalve/PluginManager.cpp +++ b/src/yvalve/PluginManager.cpp @@ -270,12 +270,15 @@ namespace { LocalStatus ls; CheckStatusWrapper s(&ls); + if (pluginLoaderConfig) { const ConfigFile::Parameter* p = pluginLoaderConfig->findParameter("Config"); + if (p) { RefPtr configSection(findInPluginsConf("Config", p->value.c_str())); + if (configSection.hasData()) { IConfig* rc = FB_NEW ConfigAccess(configSection); @@ -1026,7 +1029,7 @@ void PluginManager::registerPluginFactory(unsigned int interfaceType, const char changeExtension(plugConfigFile, "conf"); ConfiguredPlugin* p = FB_NEW ConfiguredPlugin(RefPtr(builtin), r, - findInPluginsConf("Plugin", defaultName), plugConfigFile, defaultName); + findInPluginsConf("Plugin", defaultName), plugConfigFile, defaultName); p->addRef(); // Will never be unloaded plugins->put(MapKey(interfaceType, defaultName), p); } @@ -1116,7 +1119,8 @@ IConfig* PluginManager::getConfig(CheckStatusWrapper* status, const char* filena try { IConfig* rc = FB_NEW ConfigAccess(RefPtr( - FB_NEW_POOL(*getDefaultMemoryPool()) ConfigFile(*getDefaultMemoryPool(), filename, ConfigFile::HAS_SUB_CONF))); + FB_NEW_POOL(*getDefaultMemoryPool()) ConfigFile(*getDefaultMemoryPool(), + filename, ConfigFile::HAS_SUB_CONF))); rc->addRef(); return rc; } From 58bb87e94bd4b83fbb7cebe2125942fd3f705424 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Mon, 14 Nov 2016 00:02:27 +0000 Subject: [PATCH 003/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 9c1e20df6b..3e12447174 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:450 + FORMAL BUILD NUMBER:451 */ -#define PRODUCT_VER_STRING "4.0.0.450" -#define FILE_VER_STRING "WI-T4.0.0.450" -#define LICENSE_VER_STRING "WI-T4.0.0.450" -#define FILE_VER_NUMBER 4, 0, 0, 450 +#define PRODUCT_VER_STRING "4.0.0.451" +#define FILE_VER_STRING "WI-T4.0.0.451" +#define LICENSE_VER_STRING "WI-T4.0.0.451" +#define FILE_VER_NUMBER 4, 0, 0, 451 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "450" +#define FB_BUILD_NO "451" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index e127c35675..57f643ca38 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=450 +BuildNum=451 NowAt=`pwd` cd `dirname $0` From 01f36be94dc347ae5ebdce50e1b3cc58bd21670f Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Mon, 14 Nov 2016 17:07:09 +0300 Subject: [PATCH 004/134] Fixed a possibility to duplicate SQL SECURITY option for GTT --- src/dsql/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index d02d6c6137..e9dec95e52 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2097,7 +2097,7 @@ gtt_ops($createRelationNode) gtt_op($createRelationNode) : // nothing by default. Will be set "on commit delete rows" in dsqlPass | sql_security_clause - { $createRelationNode->ssDefiner = $1; } + { setClause(static_cast&>($createRelationNode->ssDefiner), "SQL SECURITY", $1); } | ON COMMIT DELETE ROWS { setClause($createRelationNode->relationType, "ON COMMIT DELETE ROWS", rel_global_temp_delete); } | ON COMMIT PRESERVE ROWS From c7cefb9dd9fb9efbbaa74af23d0640e6109c09cd Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Tue, 15 Nov 2016 00:02:22 +0000 Subject: [PATCH 005/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 3e12447174..c9ca93f399 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:451 + FORMAL BUILD NUMBER:452 */ -#define PRODUCT_VER_STRING "4.0.0.451" -#define FILE_VER_STRING "WI-T4.0.0.451" -#define LICENSE_VER_STRING "WI-T4.0.0.451" -#define FILE_VER_NUMBER 4, 0, 0, 451 +#define PRODUCT_VER_STRING "4.0.0.452" +#define FILE_VER_STRING "WI-T4.0.0.452" +#define LICENSE_VER_STRING "WI-T4.0.0.452" +#define FILE_VER_NUMBER 4, 0, 0, 452 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "451" +#define FB_BUILD_NO "452" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 57f643ca38..2b777bd66a 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=451 +BuildNum=452 NowAt=`pwd` cd `dirname $0` From c72cb574d4f59308ace9321c830da8ccd155b8cc Mon Sep 17 00:00:00 2001 From: hvlad Date: Thu, 17 Nov 2016 13:12:40 +0200 Subject: [PATCH 006/134] Fixed bug CORE-5350 : Assert in CachedMasterInterface::set --- src/jrd/Mapping.cpp | 60 +++++++++++++++++++++++++++------------------ src/jrd/Mapping.h | 2 ++ src/jrd/jrd.cpp | 1 + 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index dabaf125d6..5b43a1da21 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -588,36 +588,43 @@ public: { } ~MappingIpc() + { + shutdown(); + } + + void shutdown() { if (!sharedMemory) return; - Guard gShared(this); - - MappingHeader* sMem = sharedMemory->getHeader(); - - startupSemaphore.tryEnter(5); - sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE; - (void) // Ignore errors in cleanup - sharedMemory->eventPost(&sMem->process[process].notifyEvent); - cleanupSemaphore.tryEnter(5); - - // Ignore errors in cleanup - sharedMemory->eventFini(&sMem->process[process].notifyEvent); - sharedMemory->eventFini(&sMem->process[process].callbackEvent); - - bool found = false; - for (unsigned n = 0; n < sMem->processes; ++n) { - if (sMem->process[n].flags & MappingHeader::FLAG_ACTIVE) - { - found = true; - break; - } - } + Guard gShared(this); + MappingHeader* sMem = sharedMemory->getHeader(); - if (!found) - sharedMemory->removeMapFile(); + startupSemaphore.tryEnter(5); + sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE; + (void) // Ignore errors in cleanup + sharedMemory->eventPost(&sMem->process[process].notifyEvent); + cleanupSemaphore.tryEnter(5); + + // Ignore errors in cleanup + sharedMemory->eventFini(&sMem->process[process].notifyEvent); + sharedMemory->eventFini(&sMem->process[process].callbackEvent); + + bool found = false; + for (unsigned n = 0; n < sMem->processes; ++n) + { + if (sMem->process[n].flags & MappingHeader::FLAG_ACTIVE) + { + found = true; + break; + } + } + + if (!found) + sharedMemory->removeMapFile(); + } + sharedMemory = NULL; } void clearCache(const char* dbName, USHORT index) @@ -1659,4 +1666,9 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation) return getData(relation); } +void shutdownMappingIpc() +{ + mappingIpc->shutdown(); +} + } // namespace Jrd diff --git a/src/jrd/Mapping.h b/src/jrd/Mapping.h index 71b48878ee..1838da6ba9 100644 --- a/src/jrd/Mapping.h +++ b/src/jrd/Mapping.h @@ -53,6 +53,8 @@ void clearMappingCache(const char* dbName, USHORT index); const USHORT MAPPING_CACHE = 0; const USHORT SYSTEM_PRIVILEGES_CACHE = 1; +void shutdownMappingIpc(); + class GlobalMappingScan: public VirtualTableScan { public: diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 7a438dab08..4422542ed3 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -4126,6 +4126,7 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const // Do not put it into separate shutdown thread - during shutdown of TraceManager // PluginManager wants to lock a mutex, which is sometimes already locked in current thread TraceManager::shutdown(); + shutdownMappingIpc(); } catch (const Exception& ex) { From 9d03c83c827f403c0307833bb0bf6a22521c8526 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 18 Nov 2016 00:02:26 +0000 Subject: [PATCH 007/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index c9ca93f399..e5cc230567 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:452 + FORMAL BUILD NUMBER:453 */ -#define PRODUCT_VER_STRING "4.0.0.452" -#define FILE_VER_STRING "WI-T4.0.0.452" -#define LICENSE_VER_STRING "WI-T4.0.0.452" -#define FILE_VER_NUMBER 4, 0, 0, 452 +#define PRODUCT_VER_STRING "4.0.0.453" +#define FILE_VER_STRING "WI-T4.0.0.453" +#define LICENSE_VER_STRING "WI-T4.0.0.453" +#define FILE_VER_NUMBER 4, 0, 0, 453 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "452" +#define FB_BUILD_NO "453" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 2b777bd66a..8451d6ebab 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=452 +BuildNum=453 NowAt=`pwd` cd `dirname $0` From 383c511cfc05e08b5cdc00f119aa23193722278b Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Mon, 21 Nov 2016 18:22:44 +0300 Subject: [PATCH 008/134] Postfix for CORE-5204 --- .../install/posix-common/posixLibrary.sh.in | 119 +++++++++++------- 1 file changed, 73 insertions(+), 46 deletions(-) diff --git a/builds/install/posix-common/posixLibrary.sh.in b/builds/install/posix-common/posixLibrary.sh.in index 3f04f4acb7..d436585acd 100644 --- a/builds/install/posix-common/posixLibrary.sh.in +++ b/builds/install/posix-common/posixLibrary.sh.in @@ -546,26 +546,38 @@ buildUninstallFile() { then cp $Manifest $MANIFEST_TXT else - rm -f $MANIFEST_TXT - oldPath=".${default_prefix}" - - for line in `grep "^${oldPath}" $Manifest | colrm 1 ${#oldPath}` - do - echo ".${fb_install_prefix}${line}" >>$MANIFEST_TXT - done - - newPath=`dirname "${fb_install_prefix}"` - while [ ${#newPath} -gt 1 ] - do - echo ".${newPath}" >>$MANIFEST_TXT - newPath=`dirname $newPath` - done + newManifest $Manifest $MANIFEST_TXT fi [ -f @FB_SBINDIR@/$UninstallScript ] && chmod u=rx,go= @FB_SBINDIR@/$UninstallScript } +#------------------------------------------------------------------------ +# newManifest +# Create new manifest replacing default_prefix with fb_install_prefix +# in existing manifest + +newManifest() { + ExistingManifestFile=${1} + CreateManifestFile=${2} + + rm -f $CreateManifestFile + oldPath=".${default_prefix}" + + for line in `grep "^${oldPath}" $ExistingManifestFile | colrm 1 ${#oldPath}` + do + echo ".${fb_install_prefix}${line}" >>$CreateManifestFile + done + + newPath=`dirname "${fb_install_prefix}"` + while [ ${#newPath} -gt 1 ] + do + echo ".${newPath}" >>$CreateManifestFile + newPath=`dirname $newPath` + done +} + #------------------------------------------------------------------------ # Remove if only a link @@ -715,14 +727,25 @@ archivePriorInstallSystemFiles() { fi tarArc=${ArchiveMainFile}.$tarExt - oldPWD=`pwd` + distManifest=${oldPWD}/manifest.txt archiveFileList="" + archiveDelTemp="" + + if [ "${fb_install_prefix}" != "${default_prefix}" ] + then + TmpFile="" + MakeTemp + newManifest $distManifest $TmpFile + distManifest=$TmpFile + archiveDelTemp=$TmpFile + fi + cd / - if [ -f ${oldPWD}/manifest.txt ]; then - manifest=`cat ${oldPWD}/manifest.txt` + if [ -f ${distManifest} ]; then + manifest=`cat ${distManifest}` for i in $manifest; do if [ -f $i ]; then i=${i#/} # strip off leading / @@ -731,6 +754,8 @@ archivePriorInstallSystemFiles() { done fi + rm -f "$archiveDelTemp" + DestFile=@FB_CONFDIR@ if [ -e "$DestFile" ] then @@ -754,38 +779,40 @@ archivePriorInstallSystemFiles() { fi fi - - for i in ibase.h ib_util.h - do - DestFile=usr/include/$i - if [ -e $DestFile ]; then - if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then - archiveFileList="$archiveFileList $DestFile" - fi - fi - done - - for i in libib_util.@SHRLIB_EXT@ libfbclient.@SHRLIB_EXT@* - do - for DestFile in usr/lib/$i - do - if [ -e $DestFile ]; then + if [ "${fb_install_prefix}" = "${default_prefix}" ] + then + for i in ibase.h ib_util.h + do + DestFile=usr/include/$i + if [ -e $DestFile ]; then if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then - archiveFileList="$archiveFileList $DestFile" + archiveFileList="$archiveFileList $DestFile" fi - fi - done - done + fi + done - for i in usr/sbin/rcfirebird etc/init.d/firebird etc/rc.d/init.d/firebird - do - DestFile=./$i - if [ -e $DestFile ]; then - if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then - archiveFileList="$archiveFileList $DestFile" - fi - fi - done + for i in libib_util.@SHRLIB_EXT@ libfbclient.@SHRLIB_EXT@* + do + for DestFile in usr/lib/$i + do + if [ -e $DestFile ]; then + if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then + archiveFileList="$archiveFileList $DestFile" + fi + fi + done + done + + for i in usr/sbin/rcfirebird etc/init.d/firebird etc/rc.d/init.d/firebird + do + DestFile=./$i + if [ -e $DestFile ]; then + if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then + archiveFileList="$archiveFileList $DestFile" + fi + fi + done + fi if [ ! -z "$archiveFileList" ] then From 18dabe30011102028b4985922809aa88a0bdf70d Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Tue, 22 Nov 2016 00:02:26 +0000 Subject: [PATCH 009/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index e5cc230567..c2ce3dd192 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:453 + FORMAL BUILD NUMBER:454 */ -#define PRODUCT_VER_STRING "4.0.0.453" -#define FILE_VER_STRING "WI-T4.0.0.453" -#define LICENSE_VER_STRING "WI-T4.0.0.453" -#define FILE_VER_NUMBER 4, 0, 0, 453 +#define PRODUCT_VER_STRING "4.0.0.454" +#define FILE_VER_STRING "WI-T4.0.0.454" +#define LICENSE_VER_STRING "WI-T4.0.0.454" +#define FILE_VER_NUMBER 4, 0, 0, 454 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "453" +#define FB_BUILD_NO "454" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 8451d6ebab..f43c243866 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=453 +BuildNum=454 NowAt=`pwd` cd `dirname $0` From 0cf8d887a1acb4167ba4a839993b54cf5002764a Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Mon, 21 Nov 2016 22:16:04 -0200 Subject: [PATCH 010/134] Fixed CORE-5404 - Inconsistent column/line references when PSQL definitions return errors. --- src/dsql/Parser.cpp | 24 +++++++++++++----------- src/dsql/Parser.h | 2 +- src/dsql/parse.y | 16 ++++++++-------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/dsql/Parser.cpp b/src/dsql/Parser.cpp index 0f05c6477d..c37c4c3b33 100644 --- a/src/dsql/Parser.cpp +++ b/src/dsql/Parser.cpp @@ -437,7 +437,7 @@ int Parser::yylexAux() check_bound(p, string); if (p > string + maxByteLength || p > string + maxCharLength) - yyabandon(-104, isc_dyn_name_longer); + yyabandon(yyposn, -104, isc_dyn_name_longer); *p = 0; @@ -519,7 +519,7 @@ int Parser::yylexAux() { if (buffer != string) gds__free (buffer); - yyabandon (-104, isc_invalid_string_constant); + yyabandon(yyposn, -104, isc_invalid_string_constant); } else if (client_dialect >= SQL_DIALECT_V6) { @@ -527,19 +527,19 @@ int Parser::yylexAux() { if (buffer != string) gds__free (buffer); - yyabandon(-104, isc_token_too_long); + yyabandon(yyposn, -104, isc_token_too_long); } else if (p > &buffer[MAX_SQL_IDENTIFIER_LEN]) { if (buffer != string) gds__free (buffer); - yyabandon(-104, isc_dyn_name_longer); + yyabandon(yyposn, -104, isc_dyn_name_longer); } else if (p - buffer == 0) { if (buffer != string) gds__free (buffer); - yyabandon(-104, isc_dyn_zero_len_id); + yyabandon(yyposn, -104, isc_dyn_zero_len_id); } Attachment* const attachment = tdbb->getAttachment(); @@ -548,7 +548,7 @@ int Parser::yylexAux() name.length(), (const UCHAR*) name.c_str(), true); if (name.length() > maxByteLength || charLength > maxCharLength) - yyabandon(-104, isc_dyn_name_longer); + yyabandon(yyposn, -104, isc_dyn_name_longer); yylval.metaNamePtr = FB_NEW_POOL(pool) MetaName(pool, name); @@ -1103,7 +1103,7 @@ int Parser::yylexAux() *p = 0; if (p > &string[maxByteLength] || p > &string[maxCharLength]) - yyabandon(-104, isc_dyn_name_longer); + yyabandon(yyposn, -104, isc_dyn_name_longer); const MetaName str(string, p - string); const Keyword* const keyVer = keywordsMap->get(str); @@ -1206,7 +1206,7 @@ void Parser::yyerrorIncompleteCmd() void Parser::check_bound(const char* const to, const char* const string) { if ((to - string) >= Parser::MAX_TOKEN_LEN) - yyabandon(-104, isc_token_too_long); + yyabandon(yyposn, -104, isc_token_too_long); //// FIXME: } void Parser::check_copy_incr(char*& to, const char ch, const char* const string) @@ -1216,7 +1216,7 @@ void Parser::check_copy_incr(char*& to, const char ch, const char* const string) } -void Parser::yyabandon(SLONG sql_code, ISC_STATUS error_symbol) +void Parser::yyabandon(const Position& position, SLONG sql_code, ISC_STATUS error_symbol) { /************************************** * @@ -1229,6 +1229,8 @@ void Parser::yyabandon(SLONG sql_code, ISC_STATUS error_symbol) * **************************************/ - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(sql_code) << - Arg::Gds(error_symbol)); + ERRD_post( + Arg::Gds(isc_sqlerr) << Arg::Num(sql_code) << Arg::Gds(error_symbol) << + Arg::Gds(isc_dsql_line_col_error) << + Arg::Num(position.firstLine) << Arg::Num(position.firstColumn)); } diff --git a/src/dsql/Parser.h b/src/dsql/Parser.h index d59185279f..7d195914e9 100644 --- a/src/dsql/Parser.h +++ b/src/dsql/Parser.h @@ -234,7 +234,7 @@ private: void check_bound(const char* const to, const char* const string); void check_copy_incr(char*& to, const char ch, const char* const string); - void yyabandon(SLONG, ISC_STATUS); + void yyabandon(const Position& position, SLONG, ISC_STATUS); Firebird::MetaName optName(Firebird::MetaName* name) { diff --git a/src/dsql/parse.y b/src/dsql/parse.y index e9dec95e52..0025a7296c 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -4435,7 +4435,7 @@ non_charset_simple_type $$->length = sizeof(GDS_TIMESTAMP); } else if (client_dialect == SQL_DIALECT_V6_TRANSITION) - yyabandon(-104, isc_transitional_date); + yyabandon(YYPOSNARG(1), -104, isc_transitional_date); else { $$->dtype = dtype_sql_date; @@ -4647,7 +4647,7 @@ prec_scale $$ = newNode(); if ($2 < 1 || $2 > 18) - yyabandon(-842, isc_precision_err); // Precision must be between 1 and 18. + yyabandon(YYPOSNARG(2), -842, isc_precision_err); // Precision must be between 1 and 18. if ($2 > 9) { @@ -4697,10 +4697,10 @@ prec_scale $$ = newNode(); if ($2 < 1 || $2 > 18) - yyabandon (-842, isc_precision_err); // Precision should be between 1 and 18 + yyabandon(YYPOSNARG(2), -842, isc_precision_err); // Precision should be between 1 and 18 if ($4 > $2 || $4 < 0) - yyabandon (-842, isc_scale_nogt); // Scale must be between 0 and precision + yyabandon(YYPOSNARG(4), -842, isc_scale_nogt); // Scale must be between 0 and precision if ($2 > 9) { @@ -6991,7 +6991,7 @@ nonneg_short_integer : NUMBER { if ($1 > SHRT_POS_MAX) - yyabandon(-842, isc_expec_short); // Short integer expected + yyabandon(YYPOSNARG(1), -842, isc_expec_short); // Short integer expected $$ = $1; } @@ -7002,7 +7002,7 @@ neg_short_integer : NUMBER { if ($1 > SHRT_NEG_MAX) - yyabandon(-842, isc_expec_short); // Short integer expected + yyabandon(YYPOSNARG(1), -842, isc_expec_short); // Short integer expected $$ = $1; } @@ -7013,7 +7013,7 @@ pos_short_integer : nonneg_short_integer { if ($1 == 0) - yyabandon(-842, isc_expec_positive); // Positive number expected + yyabandon(YYPOSNARG(1), -842, isc_expec_positive); // Positive number expected $$ = $1; } @@ -7024,7 +7024,7 @@ unsigned_short_integer : NUMBER { if ($1 > SHRT_UNSIGNED_MAX) - yyabandon(-842, isc_expec_ushort); // Unsigned short integer expected + yyabandon(YYPOSNARG(1), -842, isc_expec_ushort); // Unsigned short integer expected $$ = $1; } From 2388af42f6526ff35d7650ea55471698fb647703 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Mon, 21 Nov 2016 22:19:49 -0200 Subject: [PATCH 011/134] Misc. --- src/dsql/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsql/Parser.cpp b/src/dsql/Parser.cpp index c37c4c3b33..ceeb0a30db 100644 --- a/src/dsql/Parser.cpp +++ b/src/dsql/Parser.cpp @@ -1206,7 +1206,7 @@ void Parser::yyerrorIncompleteCmd() void Parser::check_bound(const char* const to, const char* const string) { if ((to - string) >= Parser::MAX_TOKEN_LEN) - yyabandon(yyposn, -104, isc_token_too_long); //// FIXME: + yyabandon(yyposn, -104, isc_token_too_long); } void Parser::check_copy_incr(char*& to, const char ch, const char* const string) From dac882c97e2642e260abef475de75c490c5e4bc7 Mon Sep 17 00:00:00 2001 From: hvlad Date: Tue, 22 Nov 2016 13:21:51 +0200 Subject: [PATCH 012/134] Introduced small per-relation cache of physical numbers of data pages. It allows to reduce number of pointer page fetches and improves performance. --- src/jrd/Relation.cpp | 16 +++---- src/jrd/Relation.h | 98 +++++++++++++++++++++++++++++++++---- src/jrd/dpm.epp | 112 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 203 insertions(+), 23 deletions(-) diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp index 1788315c59..31ac6cddc1 100644 --- a/src/jrd/Relation.cpp +++ b/src/jrd/Relation.cpp @@ -73,16 +73,8 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a return 0; RelationPages* newPages = rel_pages_free; - if (!newPages) - { - const size_t BULK_ALLOC = 8; - - RelationPages* allocatedPages = newPages = - FB_NEW_POOL(*rel_pool) RelationPages[BULK_ALLOC]; - - rel_pages_free = ++allocatedPages; - for (size_t i = 1; i < BULK_ALLOC - 1; i++, allocatedPages++) - allocatedPages->rel_next_free = allocatedPages + 1; + if (!newPages) { + newPages = FB_NEW_POOL(*rel_pool) RelationPages(*rel_pool); } else { @@ -527,5 +519,9 @@ void RelationPages::free(RelationPages*& nextFree) rel_index_root = rel_data_pages = 0; rel_slot_space = rel_pri_data_space = rel_sec_data_space = 0; + rel_last_free_pri_dp = 0; rel_instance_id = 0; + + dpMap.clear(); + dpMapMark = 0; } diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index 44cef563ac..e1ef92aaa5 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -70,25 +70,31 @@ class RelationPages { public: typedef SINT64 RP_INSTANCE_ID; + vcl* rel_pages; // vector of pointer page numbers RP_INSTANCE_ID rel_instance_id; // 0 or att_attachment_id or tra_number + // Vlad asked for this compile-time check to make sure we can contain a txn number here typedef int RangeCheck1[sizeof(RP_INSTANCE_ID) >= sizeof(TraNumber)]; typedef int RangeCheck2[sizeof(RP_INSTANCE_ID) >= sizeof(AttNumber)]; - SLONG rel_index_root; // index root page number - SLONG rel_data_pages; // count of relation data pages + ULONG rel_index_root; // index root page number + ULONG rel_data_pages; // count of relation data pages ULONG rel_slot_space; // lowest pointer page with slot space ULONG rel_pri_data_space; // lowest pointer page with primary data page space ULONG rel_sec_data_space; // lowest pointer page with secondary data page space + ULONG rel_last_free_pri_dp; // last primary data page found with space USHORT rel_pg_space_id; - RelationPages() + RelationPages(Firebird::MemoryPool& pool) : rel_pages(NULL), rel_instance_id(0), rel_index_root(0), rel_data_pages(0), rel_slot_space(0), rel_pri_data_space(0), rel_sec_data_space(0), + rel_last_free_pri_dp(0), rel_pg_space_id(DB_PAGE_SPACE), rel_next_free(NULL), - useCount(0) + useCount(0), + dpMap(pool), + dpMapMark(0) {} inline SLONG addRef() @@ -103,10 +109,83 @@ public: return item->rel_instance_id; } + ULONG getDPNumber(ULONG dpSequence) + { + FB_SIZE_T pos; + if (dpMap.find(dpSequence, pos)) + { + if (dpMap[pos].mark != dpMapMark) + dpMap[pos].mark = ++dpMapMark; + return dpMap[pos].physNum; + } + + return 0; + } + + void setDPNumber(ULONG dpSequence, ULONG dpNumber) + { + FB_SIZE_T pos; + if (dpMap.find(dpSequence, pos)) + { + if (dpNumber) + { + dpMap[pos].physNum = dpNumber; + dpMap[pos].mark = ++dpMapMark; + } + else + dpMap.remove(pos); + } + else if (dpNumber) + { + dpMap.insert(pos, {dpSequence, dpNumber, ++dpMapMark}); + + if (dpMap.getCount() == MAX_DPMAP_ITEMS) + freeOldestMapItems(); + } + } + + void freeOldestMapItems() + { + ULONG minMark = MAX_ULONG; + FB_SIZE_T i; + for (i = 0; i < dpMap.getCount(); i++) + if (minMark > dpMap[i].mark) + minMark = dpMap[i].mark; + + minMark = (minMark + dpMapMark) / 2; + + i = 0; + while (i < dpMap.getCount()) + { + if (dpMap[i].mark > minMark) + dpMap[i++].mark -= minMark; + else + dpMap.remove(i); + } + dpMapMark -= minMark; + } + private: RelationPages* rel_next_free; SLONG useCount; + static const ULONG MAX_DPMAP_ITEMS = 64; + + struct DPItem + { + ULONG seqNum; + ULONG physNum; + ULONG mark; + + static ULONG generate(const DPItem& item) + { + return item.seqNum; + } + }; + + Firebird::SortedArray, ULONG, DPItem> dpMap; + ULONG dpMapMark; + friend class jrd_rel; }; @@ -195,12 +274,12 @@ public: return &rel_pages_base; } - bool delPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, RelationPages* aPages = NULL); + bool delPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, RelationPages* aPages = NULL); - void getRelLockKey(thread_db* tdbb, UCHAR* key); - USHORT getRelLockKeyLength() const; + void getRelLockKey(thread_db* tdbb, UCHAR* key); + USHORT getRelLockKeyLength() const; - void cleanUp(); + void cleanUp(); class RelPagesSnapshot : public Firebird::Array { @@ -320,7 +399,8 @@ const ULONG REL_gc_lockneed = 0x80000; // gc lock should be acquired inline jrd_rel::jrd_rel(MemoryPool& p) : rel_pool(&p), rel_flags(REL_gc_lockneed), rel_name(p), rel_owner_name(p), rel_security_name(p), - rel_view_contexts(p), rel_gc_records(p), rel_ss_definer(false) + rel_view_contexts(p), rel_gc_records(p), rel_ss_definer(false), + rel_pages_base(p) { } diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index c894f6057c..9d871f5aaf 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -1390,9 +1390,37 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type) if (rpb->rpb_number.getValue() < 0) return false; - // Find the next pointer page, data page, and record + RelationPages* relPages = rpb->rpb_relation->getPages(tdbb); + + const ULONG dpSequence = rpb->rpb_number.getValue() / dbb->dbb_max_records; + ULONG page_number = relPages->getDPNumber(dpSequence); + + if (page_number) + { + window->win_page = page_number; + data_page* dpage = (data_page*) CCH_FETCH(tdbb, window, lock_type, pag_undefined); + const bool pageOk = + dpage->dpg_header.pag_type == pag_data && + !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && + dpage->dpg_relation == rpb->rpb_relation->rel_id && + dpage->dpg_sequence == dpSequence && + (dpage->dpg_count > 0); + + if (pageOk && get_header(window, line, rpb) && + !(rpb->rpb_flags & (rpb_blob | rpb_chained | rpb_fragment))) + { + return true; + } + + CCH_RELEASE(tdbb, window); + + if (pageOk) + return false; + } + + // Find the pointer page, data page, and record pointer_page* page = get_pointer_page(tdbb, rpb->rpb_relation, - rpb->rpb_relation->getPages(tdbb), window, pp_sequence, LCK_read); + relPages, window, pp_sequence, LCK_read); if (!page) return false; @@ -1401,7 +1429,8 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type) " record %" ULONGFORMAT":%d\n", page->ppg_page[slot], line); #endif - const ULONG page_number = page->ppg_page[slot]; + page_number = page->ppg_page[slot]; + relPages->setDPNumber(dpSequence, page_number); if (page_number) { CCH_HANDOFF(tdbb, window, page_number, lock_type, pag_data); @@ -1614,6 +1643,51 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage rpb->rpb_number = saveRecNo; } + ULONG dpSequence = rpb->rpb_number.getValue() / dbb->dbb_max_records; + ULONG page_number = relPages->getDPNumber(dpSequence); + + if (page_number) + { + fb_assert(window->win_page.getPageSpaceID() == relPages->rel_pg_space_id); + + window->win_page = page_number; + const data_page* dpage = (data_page*) CCH_FETCH(tdbb, window, lock_type, pag_undefined); + const bool pageOk = + dpage->dpg_header.pag_type == pag_data && + !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && + dpage->dpg_relation == rpb->rpb_relation->rel_id && + dpage->dpg_sequence == dpSequence && + (dpage->dpg_count > 0); + + if (pageOk) + { + for (; line < dpage->dpg_count; ++line) + { + if (get_header(window, line, rpb) && + !(rpb->rpb_flags & (rpb_blob | rpb_chained | rpb_fragment))) + { + if (sweeper && !rpb->rpb_b_page && rpb->rpb_transaction_nr <= oldest) + continue; + + rpb->rpb_number.compose(dbb->dbb_max_records, dbb->dbb_dp_per_pp, + line, slot, pp_sequence); + return true; + } + } + } + + if (window->win_flags & WIN_large_scan) + CCH_RELEASE_TAIL(tdbb, window); + else if (window->win_flags & WIN_garbage_collector && + window->win_flags & WIN_garbage_collect) + { + CCH_RELEASE_TAIL(tdbb, window); + window->win_flags &= ~WIN_garbage_collect; + } + else + CCH_RELEASE(tdbb, window); + } + // Find the next pointer page, data page, and record while (true) @@ -1654,6 +1728,8 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage } } #endif + dpSequence = ppage->ppg_sequence * dbb->dbb_dp_per_pp + slot; + relPages->setDPNumber(dpSequence, page_number); const data_page* dpage = (data_page*) CCH_HANDOFF(tdbb, window, page_number, lock_type, pag_data); @@ -3133,6 +3209,29 @@ static rhd* locate_space(thread_db* tdbb, } } + if (type == DPM_primary && relPages->rel_last_free_pri_dp) + { + window->win_page = relPages->rel_last_free_pri_dp; + data_page* dpage = (data_page*) CCH_FETCH(tdbb, window, LCK_write, pag_undefined); + const bool pageOk = + dpage->dpg_header.pag_type == pag_data && + !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && + dpage->dpg_relation == rpb->rpb_relation->rel_id && + //dpage->dpg_sequence == dpSequence && + (dpage->dpg_count > 0); + + if (pageOk) + { + UCHAR* space = find_space(tdbb, rpb, size, stack, record, type); + if (space) + return (rhd*)space; + } + else + CCH_RELEASE(tdbb, window); + + relPages->rel_last_free_pri_dp = 0; + } + // Look for space anywhere // Make few tries to lock consecutive data pages without waiting. In highly @@ -3230,7 +3329,12 @@ static rhd* locate_space(thread_db* tdbb, { UCHAR* space = find_space(tdbb, rpb, size, stack, record, type); if (space) - return (rhd*) space; + { + if (type == DPM_primary) + relPages->rel_last_free_pri_dp = dp_number; + + return (rhd*)space; + } } ppLock = LCK_read; From 66c9416162578a786d5c3acb3eb4ffa196e4523c Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 10 Nov 2016 12:30:22 +0300 Subject: [PATCH 013/134] Revert back old change that's not actual anymore but causing undesired side-effects in CS under concurrent load. --- src/common/isc_s_proto.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/isc_s_proto.h b/src/common/isc_s_proto.h index 7ffb31f7b1..e19a91be9a 100644 --- a/src/common/isc_s_proto.h +++ b/src/common/isc_s_proto.h @@ -47,7 +47,9 @@ #ifdef LINUX // This hack fixes CORE-2896 - embedded connections fail on linux. // Looks like a lot of linux kernels are buggy when working with PRIO_INHERIT mutexes. -//#undef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL +// dimitr (10-11-2016): PRIO_INHERIT also causes undesired short-time sleeps (CPU idle 30-35%) +// during context switches under concurrent load. Proved on linux kernels up to 4.8. +#undef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL #endif From 04c9fbed66fc480e271444977d068d0b2ac68de4 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Wed, 23 Nov 2016 00:02:22 +0000 Subject: [PATCH 014/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index c2ce3dd192..a0ce5a8b3b 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:454 + FORMAL BUILD NUMBER:458 */ -#define PRODUCT_VER_STRING "4.0.0.454" -#define FILE_VER_STRING "WI-T4.0.0.454" -#define LICENSE_VER_STRING "WI-T4.0.0.454" -#define FILE_VER_NUMBER 4, 0, 0, 454 +#define PRODUCT_VER_STRING "4.0.0.458" +#define FILE_VER_STRING "WI-T4.0.0.458" +#define LICENSE_VER_STRING "WI-T4.0.0.458" +#define FILE_VER_NUMBER 4, 0, 0, 458 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "454" +#define FB_BUILD_NO "458" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index f43c243866..26bc85887e 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=454 +BuildNum=458 NowAt=`pwd` cd `dirname $0` From 989a6b90af25a2b5693660e8488d64d299961c93 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 24 Nov 2016 19:22:27 +0300 Subject: [PATCH 015/134] Misc improvement as suggested by Adriano. --- src/jrd/opt.cpp | 58 +++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/jrd/opt.cpp b/src/jrd/opt.cpp index c5f20c0bce..0d08429e5a 100644 --- a/src/jrd/opt.cpp +++ b/src/jrd/opt.cpp @@ -1476,12 +1476,13 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc **************************************/ // dimitr: Dumb protection against too many injected conjuncts (see CORE-5381). + // Don't produce more additional conjuncts than we originally had + // (i.e. this routine should never more than double the number of conjuncts). // Ideally, we need two separate limits here: // 1) number of injected conjuncts (affects required impure size) // 2) number of input conjuncts (affects search time inside this routine) - const ULONG threshold = base_count * 2; - if (threshold > MAX_CONJUNCTS) + if (base_count * 2 > MAX_CONJUNCTS) return 0; ObjectsArray classes; @@ -1491,23 +1492,23 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc // Zip thru stack of booleans looking for field equalities - for (BoolExprNodeStack::iterator stack1(org_stack); stack1.hasData(); ++stack1) + for (BoolExprNodeStack::iterator iter(org_stack); iter.hasData(); ++iter) { - BoolExprNode* boolean = stack1.object(); + BoolExprNode* const boolean = iter.object(); if (boolean->nodFlags & ExprNode::FLAG_DEOPTIMIZE) continue; - ComparativeBoolNode* cmpNode = boolean->as(); + ComparativeBoolNode* const cmpNode = boolean->as(); if (!cmpNode || cmpNode->blrOp != blr_eql) continue; - ValueExprNode* node1 = cmpNode->arg1; + ValueExprNode* const node1 = cmpNode->arg1; if (!node1->is()) continue; - ValueExprNode* node2 = cmpNode->arg2; + ValueExprNode* const node2 = cmpNode->arg2; if (!node2->is()) continue; @@ -1534,7 +1535,7 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc } } - if (classes.getCount() == 0) + if (classes.isEmpty()) return 0; // Make another pass looking for any equality relationships that may have crept @@ -1542,12 +1543,12 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc for (eq_class = classes.begin(); eq_class != classes.end(); ++eq_class) { - for (ValueExprNodeStack::const_iterator stack2(*eq_class); stack2.hasData(); ++stack2) + for (ValueExprNodeStack::const_iterator iter(*eq_class); iter.hasData(); ++iter) { for (ObjectsArray::iterator eq_class2(eq_class); ++eq_class2 != classes.end();) { - if (search_stack(stack2.object(), *eq_class2)) + if (search_stack(iter.object(), *eq_class2)) { while (eq_class2->hasData()) augment_stack(eq_class2->pop(), *eq_class); @@ -1568,15 +1569,19 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc { for (ValueExprNodeStack::iterator inner(outer); (++inner).hasData(); ) { - ComparativeBoolNode* cmpNode = - FB_NEW_POOL(csb->csb_pool) ComparativeBoolNode(csb->csb_pool, blr_eql); - cmpNode->arg1 = outer.object(); - cmpNode->arg2 = inner.object(); + if (count < base_count) + { + AutoPtr cmpNode(FB_NEW_POOL(csb->csb_pool) + ComparativeBoolNode(csb->csb_pool, blr_eql)); + cmpNode->arg1 = outer.object(); + cmpNode->arg2 = inner.object(); - if (count < threshold && augment_stack(cmpNode, org_stack)) - count++; - else - delete cmpNode; + if (augment_stack(cmpNode, org_stack)) + { + count++; + cmpNode.release(); + } + } } } } @@ -1584,10 +1589,10 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc // Now make a second pass looking for non-field equalities - for (BoolExprNodeStack::iterator stack3(org_stack); stack3.hasData(); ++stack3) + for (BoolExprNodeStack::iterator iter(org_stack); iter.hasData(); ++iter) { - BoolExprNode* boolean = stack3.object(); - ComparativeBoolNode* cmpNode = boolean->as(); + BoolExprNode* const boolean = iter.object(); + ComparativeBoolNode* const cmpNode = boolean->as(); ValueExprNode* node1; ValueExprNode* node2; @@ -1625,7 +1630,7 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc { for (ValueExprNodeStack::iterator temp(*eq_class); temp.hasData(); ++temp) { - if (!node_equality(node1, temp.object())) + if (!node_equality(node1, temp.object()) && count < base_count) { ValueExprNode* arg1; ValueExprNode* arg2; @@ -1642,12 +1647,13 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc } // From the conjuncts X(A,B) and A=C, infer the conjunct X(C,B) - BoolExprNode* newNode = make_inference_node(csb, boolean, arg1, arg2); + AutoPtr newNode(make_inference_node(csb, boolean, arg1, arg2)); - if (count < threshold && augment_stack(newNode, org_stack)) + if (augment_stack(newNode, org_stack)) + { ++count; - else - delete newNode; + newNode.release(); + } } } From c020815299f67b33ffeb4368f0f659ce154f7de4 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 25 Nov 2016 00:02:18 +0000 Subject: [PATCH 016/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index a0ce5a8b3b..e9d10ff747 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:458 + FORMAL BUILD NUMBER:459 */ -#define PRODUCT_VER_STRING "4.0.0.458" -#define FILE_VER_STRING "WI-T4.0.0.458" -#define LICENSE_VER_STRING "WI-T4.0.0.458" -#define FILE_VER_NUMBER 4, 0, 0, 458 +#define PRODUCT_VER_STRING "4.0.0.459" +#define FILE_VER_STRING "WI-T4.0.0.459" +#define LICENSE_VER_STRING "WI-T4.0.0.459" +#define FILE_VER_NUMBER 4, 0, 0, 459 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "458" +#define FB_BUILD_NO "459" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 26bc85887e..897f03e1d4 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=458 +BuildNum=459 NowAt=`pwd` cd `dirname $0` From d7e131b5b772486a824219c50747a9187b37401c Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Thu, 1 Dec 2016 12:55:01 -0200 Subject: [PATCH 017/134] Fixed CORE-5410 - Dependencies are not stored when using some type of contructions in subroutines. --- src/dsql/StmtNodes.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index d16627cede..326e2f74df 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -1401,7 +1401,7 @@ DmlNode* DeclareSubFuncNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerSc { // scope CompilerScratch* const subCsb = node->subCsb = FB_NEW_POOL(csb->csb_pool) CompilerScratch(csb->csb_pool); - subCsb->csb_g_flags |= csb_subroutine; + subCsb->csb_g_flags |= csb_subroutine | (csb->csb_g_flags & csb_get_dependencies); subCsb->csb_blr_reader = csb->csb_blr_reader; BlrReader& reader = subCsb->csb_blr_reader; @@ -1676,7 +1676,7 @@ DmlNode* DeclareSubProcNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerSc { // scope CompilerScratch* const subCsb = node->subCsb = FB_NEW_POOL(csb->csb_pool) CompilerScratch(csb->csb_pool); - subCsb->csb_g_flags |= csb_subroutine; + subCsb->csb_g_flags |= csb_subroutine | (csb->csb_g_flags & csb_get_dependencies); subCsb->csb_blr_reader = csb->csb_blr_reader; BlrReader& reader = subCsb->csb_blr_reader; From 246f8a817d2325024481aa8497119b2e3172741e Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 2 Dec 2016 00:02:25 +0000 Subject: [PATCH 018/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index e9d10ff747..32887182d6 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:459 + FORMAL BUILD NUMBER:460 */ -#define PRODUCT_VER_STRING "4.0.0.459" -#define FILE_VER_STRING "WI-T4.0.0.459" -#define LICENSE_VER_STRING "WI-T4.0.0.459" -#define FILE_VER_NUMBER 4, 0, 0, 459 +#define PRODUCT_VER_STRING "4.0.0.460" +#define FILE_VER_STRING "WI-T4.0.0.460" +#define LICENSE_VER_STRING "WI-T4.0.0.460" +#define FILE_VER_NUMBER 4, 0, 0, 460 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "459" +#define FB_BUILD_NO "460" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 897f03e1d4..12fbd03a5c 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=459 +BuildNum=460 NowAt=`pwd` cd `dirname $0` From cd8b6e0a4117a7c42ee75e62dea09177272ee12b Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 1 Dec 2016 15:52:12 +0300 Subject: [PATCH 019/134] Reworked syntax for new error context vars, based on feedback from the other devs. --- doc/sql.extensions/README.context_variables | 55 ++++++--------------- src/dsql/ExprNodes.cpp | 4 +- src/dsql/parse-conflicts.txt | 2 +- src/dsql/parse.y | 27 +++++++--- src/yvalve/keywords.cpp | 3 +- 5 files changed, 43 insertions(+), 48 deletions(-) diff --git a/doc/sql.extensions/README.context_variables b/doc/sql.extensions/README.context_variables index 6ce54c6d09..8eb7f3b149 100644 --- a/doc/sql.extensions/README.context_variables +++ b/doc/sql.extensions/README.context_variables @@ -170,20 +170,30 @@ SQLSTATE (FB 2.5) 1. SQLSTATE always evaluates to NULL outside the exception handling block. -EXCEPTION (FB 4.0) +RDB$ERROR (FB 4.0) ------------------ Function: - Returns name of the active user-defined exception. + Returns specific context of the active exception. Author: Dmitry Yemanov Syntax rules: - EXCEPTION + RDB$ERROR ( context ) + context ::= { GDSCODE | SQLCODE | SQLSTATE | EXCEPTION | MESSAGE } + + GDSCODE, SQLCODE, SQLSTATE - see above + + EXCEPTION : VARCHAR(63) CHARACTER SET UTF8 + Returns name of the active user-defined exception + or NULL if active exception is a system one + + MESSAGE : VARCHAR(1024) CHARACTER SET UTF8 + Returns interpreted text for the active exception Type: - VARCHAR(63) CHARACTER SET UTF8 + Depends on context Scope: PSQL, context of the exception handling block. @@ -192,41 +202,8 @@ EXCEPTION (FB 4.0) BEGIN ... WHEN ANY DO - IF (EXCEPTION IS NOT NULL) - EXECUTE PROCEDURE P_USR_EXCEPTION(EXCEPTION); - ELSE - EXECUTE PROCEDURE P_SYS_EXCEPTION; + EXECUTE PROCEDURE P_LOG_EXCEPTION(RDB$ERROR(MESSAGE)); END Note(s): - 1. EXCEPTION always contains NULL outside the exception handling block. - 2. If system exception is thrown, EXCEPTION also contains NULL. - - -ERROR_MESSAGE (FB 4.0) ----------------------- - - Function: - Returns interpreted text for the active exception. - - Author: - Dmitry Yemanov - - Syntax rules: - ERROR_MESSAGE - - Type: - VARCHAR(1024) CHARACTER SET UTF8 - - Scope: - PSQL, context of the exception handling block. - - Example(s): - BEGIN - ... - WHEN ANY DO - EXECUTE PROCEDURE P_LOG_EXCEPTION(ERROR_MESSAGE); - END - - Note(s): - 1. ERROR_MESSAGE always contains NULL outside the exception handling block. + RDB$ERROR always contains NULL outside the exception handling block. diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index f0d4ec0fe1..bddbfce0fc 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -6125,7 +6125,9 @@ const InternalInfoNode::InfoAttr InternalInfoNode::INFO_TYPE_ATTRIBUTES[MAX_INFO {"SQLCODE", DsqlCompilerScratch::FLAG_BLOCK}, {"ROW_COUNT", DsqlCompilerScratch::FLAG_BLOCK}, {"INSERTING/UPDATING/DELETING", DsqlCompilerScratch::FLAG_TRIGGER}, - {"SQLSTATE", DsqlCompilerScratch::FLAG_BLOCK} + {"SQLSTATE", DsqlCompilerScratch::FLAG_BLOCK}, + {"EXCEPTION", DsqlCompilerScratch::FLAG_BLOCK}, + {"MESSAGE", DsqlCompilerScratch::FLAG_BLOCK} }; InternalInfoNode::InternalInfoNode(MemoryPool& pool, ValueExprNode* aArg) diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 0819e55618..b0587cd258 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -44 shift/reduce conflicts, 583 reduce/reduce conflicts. +44 shift/reduce conflicts, 17 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 0025a7296c..66098b9a17 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -593,7 +593,7 @@ using namespace Firebird; %token CUME_DIST %token DEFINER -%token ERROR_MESSAGE +%token MESSAGE %token EXCLUDE %token FOLLOWING %token INVOKER @@ -603,6 +603,7 @@ using namespace Firebird; %token PRECEDING %token PRIVILEGE %token RANGE +%token RDB_ERROR %token RDB_ROLE_IN_USE %token RDB_SYSTEM_PRIVILEGE %token SECURITY @@ -6952,12 +6953,25 @@ internal_info { $$ = newNode(MAKE_const_slong(INFO_TYPE_SQLSTATE)); } | ROW_COUNT { $$ = newNode(MAKE_const_slong(INFO_TYPE_ROWS_AFFECTED)); } - | EXCEPTION - { $$ = newNode(MAKE_const_slong(INFO_TYPE_EXCEPTION)); } - | ERROR_MESSAGE - { $$ = newNode(MAKE_const_slong(INFO_TYPE_ERROR_MSG)); } + | RDB_ERROR '(' error_context ')' + { $$ = newNode(MAKE_const_slong($3)); } ; +%type error_context +error_context + : GDSCODE + { $$ = INFO_TYPE_GDSCODE; } + | SQLCODE + { $$ = INFO_TYPE_SQLCODE; } + | SQLSTATE + { $$ = INFO_TYPE_SQLSTATE; } + | EXCEPTION + { $$ = INFO_TYPE_EXCEPTION; } + | MESSAGE + { $$ = INFO_TYPE_ERROR_MSG; } + ; + + %type sql_string sql_string : STRING // string in current charset @@ -8088,16 +8102,17 @@ non_reserved_word | TRUSTED | CUME_DIST // added in FB 4.0 | DEFINER - | ERROR_MESSAGE | EXCLUDE | FOLLOWING | INVOKER + | MESSAGE | NTILE | OTHERS | PERCENT_RANK | PRECEDING | PRIVILEGE | RANGE + | RDB_ERROR | RDB_ROLE_IN_USE | RDB_SYSTEM_PRIVILEGE | SECURITY diff --git a/src/yvalve/keywords.cpp b/src/yvalve/keywords.cpp index ebac6911ac..12abc49e17 100644 --- a/src/yvalve/keywords.cpp +++ b/src/yvalve/keywords.cpp @@ -182,7 +182,6 @@ static const TOK tokens[] = {TOK_END, "END", false}, {TOK_ENGINE, "ENGINE", true}, {TOK_ENTRY_POINT, "ENTRY_POINT", false}, - {TOK_ERROR_MESSAGE, "ERROR_MESSAGE", true}, {TOK_ESCAPE, "ESCAPE", false}, {TOK_EXCEPTION, "EXCEPTION", false}, {TOK_EXCLUDE, "EXCLUDE", false}, @@ -269,6 +268,7 @@ static const TOK tokens[] = {TOK_MAXIMUM, "MAX", false}, {TOK_MAXVALUE, "MAXVALUE", false}, {TOK_MERGE, "MERGE", false}, + {TOK_MESSAGE, "MESSAGE", true}, {TOK_MILLISECOND, "MILLISECOND", false}, {TOK_MIDDLENAME, "MIDDLENAME", false}, {TOK_MINIMUM, "MIN", false}, @@ -336,6 +336,7 @@ static const TOK tokens[] = {TOK_RANGE, "RANGE", false}, {TOK_RANK, "RANK", false}, {TOK_DB_KEY, "RDB$DB_KEY", false}, + {TOK_RDB_ERROR, "RDB$ERROR", true}, {TOK_RDB_GET_CONTEXT, "RDB$GET_CONTEXT", true}, {TOK_RDB_RECORD_VERSION, "RDB$RECORD_VERSION", false}, {TOK_RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", true}, From 90b4de2b25591f0f8db5dff357bbb2c1a3a6f640 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Fri, 2 Dec 2016 10:24:18 +0300 Subject: [PATCH 020/134] I see no sense in making RDBhimBHprefixed functions/variables non-reserved. RDB$ is well-known system prefix, people should not use it for user objects. --- src/dsql/parse.y | 7 ------- src/yvalve/keywords.cpp | 10 +++++----- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 66098b9a17..1456652b99 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -4020,7 +4020,6 @@ keyword_or_column | REGR_SXY | REGR_SYY | RETURN - | RDB_RECORD_VERSION | ROW | SCROLL | SQLSTATE @@ -8007,7 +8006,6 @@ non_reserved_word | CONTAINING | CSTRING | DATABASE -// | DB_KEY | DESC | DO | DOMAIN @@ -8082,8 +8080,6 @@ non_reserved_word | PACKAGE | PARTITION | PRIOR - | RDB_GET_CONTEXT - | RDB_SET_CONTEXT | RELATIVE | DENSE_RANK | FIRST_VALUE @@ -8112,9 +8108,6 @@ non_reserved_word | PRECEDING | PRIVILEGE | RANGE - | RDB_ERROR - | RDB_ROLE_IN_USE - | RDB_SYSTEM_PRIVILEGE | SECURITY | SQL | SYSTEM diff --git a/src/yvalve/keywords.cpp b/src/yvalve/keywords.cpp index 12abc49e17..f5e90a59fa 100644 --- a/src/yvalve/keywords.cpp +++ b/src/yvalve/keywords.cpp @@ -336,12 +336,12 @@ static const TOK tokens[] = {TOK_RANGE, "RANGE", false}, {TOK_RANK, "RANK", false}, {TOK_DB_KEY, "RDB$DB_KEY", false}, - {TOK_RDB_ERROR, "RDB$ERROR", true}, - {TOK_RDB_GET_CONTEXT, "RDB$GET_CONTEXT", true}, + {TOK_RDB_ERROR, "RDB$ERROR", false}, + {TOK_RDB_GET_CONTEXT, "RDB$GET_CONTEXT", false}, {TOK_RDB_RECORD_VERSION, "RDB$RECORD_VERSION", false}, - {TOK_RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", true}, - {TOK_RDB_SET_CONTEXT, "RDB$SET_CONTEXT", true}, - {TOK_RDB_SYSTEM_PRIVILEGE, "RDB$SYSTEM_PRIVILEGE", true}, + {TOK_RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", false}, + {TOK_RDB_SET_CONTEXT, "RDB$SET_CONTEXT", false}, + {TOK_RDB_SYSTEM_PRIVILEGE, "RDB$SYSTEM_PRIVILEGE", false}, {TOK_READ, "READ", false}, {TOK_REAL, "REAL", false}, {TOK_VERSION, "RECORD_VERSION", false}, From 5cd2083aedca5511b947f4e417482862de0148a6 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Sat, 3 Dec 2016 00:02:24 +0000 Subject: [PATCH 021/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 32887182d6..b6915c64e9 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:460 + FORMAL BUILD NUMBER:462 */ -#define PRODUCT_VER_STRING "4.0.0.460" -#define FILE_VER_STRING "WI-T4.0.0.460" -#define LICENSE_VER_STRING "WI-T4.0.0.460" -#define FILE_VER_NUMBER 4, 0, 0, 460 +#define PRODUCT_VER_STRING "4.0.0.462" +#define FILE_VER_STRING "WI-T4.0.0.462" +#define LICENSE_VER_STRING "WI-T4.0.0.462" +#define FILE_VER_NUMBER 4, 0, 0, 462 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "460" +#define FB_BUILD_NO "462" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 12fbd03a5c..070de507ab 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=460 +BuildNum=462 NowAt=`pwd` cd `dirname $0` From fedcbbb5345803da6b6191914114a4c87d846fc4 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Mon, 5 Dec 2016 14:48:41 +0300 Subject: [PATCH 022/134] Attempt to fix CORE-5392: BUCHECK 179(decompression overran buffer) or unexpected lock conflict may happen during record version backout. --- src/jrd/dpm.epp | 18 ++++-------------- src/jrd/vio.cpp | 4 +++- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 9d871f5aaf..00d2b88aca 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -88,27 +88,17 @@ static void store_big_record(thread_db*, record_param*, PageStack&, const UCHAR* namespace { - Lock* lock_gc_active(thread_db* tdbb, const jrd_tra* transaction, record_param* rpb) + inline Lock* lockGCActive(thread_db* tdbb, const jrd_tra* transaction, record_param* rpb) { AutoPtr lock(FB_NEW_RPT(*tdbb->getDefaultPool(), 0) Lock(tdbb, sizeof(SINT64), LCK_record_gc)); lock->setKey(((SINT64) rpb->rpb_page << 16) | rpb->rpb_line); lock->lck_data = transaction->tra_number; - ThreadStatusGuard temp_status(tdbb); - - if (LCK_lock(tdbb, lock, LCK_EX, LCK_NO_WAIT)) - return lock.release(); - - if (lock->lck_data != LCK_read_data(tdbb, lock)) - { - fb_assert(false); - CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); - temp_status.copyToOriginal(); + if (!LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT)) ERR_punt(); - } - return NULL; + return lock.release(); } } @@ -2645,7 +2635,7 @@ static void fragment(thread_db* tdbb, header->rhdf_flags |= rhd_gc_active; - AutoLock gcLockGuard(tdbb, lock_gc_active(tdbb, transaction, rpb)); + AutoLock gcLockGuard(tdbb, lockGCActive(tdbb, transaction, rpb)); #ifdef VIO_DEBUG VIO_trace(DEBUG_WRITES_INFO, diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 70b1a5f6ee..4633039c41 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -276,7 +276,7 @@ inline bool checkGCActive(thread_db* tdbb, record_param* rpb, int& state) if (!LCK_lock(tdbb, &temp_lock, LCK_SR, LCK_NO_WAIT)) { rpb->rpb_transaction_nr = LCK_read_data(tdbb, &temp_lock); - state = TRA_pc_active(tdbb, rpb->rpb_transaction_nr) ? tra_precommitted : tra_active; + state = tra_active; return true; } @@ -622,6 +622,8 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction) rpb->rpb_prior = data; } + gcLockGuard.release(); + if (samePage) { DPM_backout(tdbb, rpb); From 9b814610cbbe9dc2236292af2707739333640b42 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Tue, 6 Dec 2016 00:02:24 +0000 Subject: [PATCH 023/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index b6915c64e9..d0290f93e3 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:462 + FORMAL BUILD NUMBER:463 */ -#define PRODUCT_VER_STRING "4.0.0.462" -#define FILE_VER_STRING "WI-T4.0.0.462" -#define LICENSE_VER_STRING "WI-T4.0.0.462" -#define FILE_VER_NUMBER 4, 0, 0, 462 +#define PRODUCT_VER_STRING "4.0.0.463" +#define FILE_VER_STRING "WI-T4.0.0.463" +#define LICENSE_VER_STRING "WI-T4.0.0.463" +#define FILE_VER_NUMBER 4, 0, 0, 463 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "462" +#define FB_BUILD_NO "463" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 070de507ab..83ee5a5274 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=462 +BuildNum=463 NowAt=`pwd` cd `dirname $0` From 0c520b8ea621c96cceedc92d6abbe9609306650f Mon Sep 17 00:00:00 2001 From: hvlad Date: Sun, 11 Dec 2016 22:26:34 +0200 Subject: [PATCH 024/134] Fixed bug CORE-5417 : Engine could hang up if auto-sweep is starting while database is shutting down --- src/jrd/Database.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/jrd/Database.cpp b/src/jrd/Database.cpp index bd575547b5..f01dfb7529 100644 --- a/src/jrd/Database.cpp +++ b/src/jrd/Database.cpp @@ -123,14 +123,19 @@ namespace Jrd int Database::blocking_ast_sweep(void* ast_object) { - Database* dbb = static_cast(ast_object); - AsyncContextHolder tdbb(dbb, FB_FUNCTION); - - if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress)) + try { - dbb->dbb_flags &= ~DBB_sweep_starting; - LCK_release(tdbb, dbb->dbb_sweep_lock); + Database* dbb = static_cast(ast_object); + AsyncContextHolder tdbb(dbb, FB_FUNCTION); + + if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress)) + { + dbb->dbb_flags &= ~DBB_sweep_starting; + LCK_release(tdbb, dbb->dbb_sweep_lock); + } } + catch (const Exception&) + {} // no-op return 0; } From 5fb4a9c6f32f15370e77fc06f14833056c5bfdda Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Sun, 11 Dec 2016 20:53:27 -0200 Subject: [PATCH 025/134] Misc. --- src/dsql/parse.y | 17 ++++++----------- src/jrd/Mapping.cpp | 6 +++++- src/jrd/Relation.h | 6 +++++- src/jrd/dpm.epp | 9 +++++++-- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 1456652b99..3f3aa34bdf 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -593,10 +593,10 @@ using namespace Firebird; %token CUME_DIST %token DEFINER -%token MESSAGE %token EXCLUDE %token FOLLOWING %token INVOKER +%token MESSAGE %token NTILE %token OTHERS %token PERCENT_RANK @@ -6958,16 +6958,11 @@ internal_info %type error_context error_context - : GDSCODE - { $$ = INFO_TYPE_GDSCODE; } - | SQLCODE - { $$ = INFO_TYPE_SQLCODE; } - | SQLSTATE - { $$ = INFO_TYPE_SQLSTATE; } - | EXCEPTION - { $$ = INFO_TYPE_EXCEPTION; } - | MESSAGE - { $$ = INFO_TYPE_ERROR_MSG; } + : GDSCODE { $$ = INFO_TYPE_GDSCODE; } + | SQLCODE { $$ = INFO_TYPE_SQLCODE; } + | SQLSTATE { $$ = INFO_TYPE_SQLSTATE; } + | EXCEPTION { $$ = INFO_TYPE_EXCEPTION; } + | MESSAGE { $$ = INFO_TYPE_ERROR_MSG; } ; diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index 5b43a1da21..a0b957f6d4 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -597,14 +597,16 @@ public: if (!sharedMemory) return; - { + { // scope Guard gShared(this); MappingHeader* sMem = sharedMemory->getHeader(); startupSemaphore.tryEnter(5); sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE; + (void) // Ignore errors in cleanup sharedMemory->eventPost(&sMem->process[process].notifyEvent); + cleanupSemaphore.tryEnter(5); // Ignore errors in cleanup @@ -612,6 +614,7 @@ public: sharedMemory->eventFini(&sMem->process[process].callbackEvent); bool found = false; + for (unsigned n = 0; n < sMem->processes; ++n) { if (sMem->process[n].flags & MappingHeader::FLAG_ACTIVE) @@ -624,6 +627,7 @@ public: if (!found) sharedMemory->removeMapFile(); } + sharedMemory = NULL; } diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index e1ef92aaa5..03a0470d79 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -148,9 +148,12 @@ public: { ULONG minMark = MAX_ULONG; FB_SIZE_T i; + for (i = 0; i < dpMap.getCount(); i++) + { if (minMark > dpMap[i].mark) minMark = dpMap[i].mark; + } minMark = (minMark + dpMapMark) / 2; @@ -162,6 +165,7 @@ public: else dpMap.remove(i); } + dpMapMark -= minMark; } @@ -399,7 +403,7 @@ const ULONG REL_gc_lockneed = 0x80000; // gc lock should be acquired inline jrd_rel::jrd_rel(MemoryPool& p) : rel_pool(&p), rel_flags(REL_gc_lockneed), rel_name(p), rel_owner_name(p), rel_security_name(p), - rel_view_contexts(p), rel_gc_records(p), rel_ss_definer(false), + rel_view_contexts(p), rel_gc_records(p), rel_ss_definer(false), rel_pages_base(p) { } diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 00d2b88aca..540d270ec5 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -1389,6 +1389,7 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type) { window->win_page = page_number; data_page* dpage = (data_page*) CCH_FETCH(tdbb, window, lock_type, pag_undefined); + const bool pageOk = dpage->dpg_header.pag_type == pag_data && !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && @@ -1411,6 +1412,7 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type) // Find the pointer page, data page, and record pointer_page* page = get_pointer_page(tdbb, rpb->rpb_relation, relPages, window, pp_sequence, LCK_read); + if (!page) return false; @@ -1421,6 +1423,7 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type) page_number = page->ppg_page[slot]; relPages->setDPNumber(dpSequence, page_number); + if (page_number) { CCH_HANDOFF(tdbb, window, page_number, lock_type, pag_data); @@ -1642,6 +1645,7 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage window->win_page = page_number; const data_page* dpage = (data_page*) CCH_FETCH(tdbb, window, lock_type, pag_undefined); + const bool pageOk = dpage->dpg_header.pag_type == pag_data && !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && @@ -1668,8 +1672,8 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage if (window->win_flags & WIN_large_scan) CCH_RELEASE_TAIL(tdbb, window); - else if (window->win_flags & WIN_garbage_collector && - window->win_flags & WIN_garbage_collect) + else if ((window->win_flags & WIN_garbage_collector) && + (window->win_flags & WIN_garbage_collect)) { CCH_RELEASE_TAIL(tdbb, window); window->win_flags &= ~WIN_garbage_collect; @@ -3203,6 +3207,7 @@ static rhd* locate_space(thread_db* tdbb, { window->win_page = relPages->rel_last_free_pri_dp; data_page* dpage = (data_page*) CCH_FETCH(tdbb, window, LCK_write, pag_undefined); + const bool pageOk = dpage->dpg_header.pag_type == pag_data && !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && From 3dd3764f13f4aba704351090733b98bee20b1bcd Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Mon, 12 Dec 2016 00:02:24 +0000 Subject: [PATCH 026/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index d0290f93e3..cd786b7e48 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:463 + FORMAL BUILD NUMBER:465 */ -#define PRODUCT_VER_STRING "4.0.0.463" -#define FILE_VER_STRING "WI-T4.0.0.463" -#define LICENSE_VER_STRING "WI-T4.0.0.463" -#define FILE_VER_NUMBER 4, 0, 0, 463 +#define PRODUCT_VER_STRING "4.0.0.465" +#define FILE_VER_STRING "WI-T4.0.0.465" +#define LICENSE_VER_STRING "WI-T4.0.0.465" +#define FILE_VER_NUMBER 4, 0, 0, 465 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "463" +#define FB_BUILD_NO "465" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 83ee5a5274..daf9ae7ecf 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=463 +BuildNum=465 NowAt=`pwd` cd `dirname $0` From 64fa7dce858be27b596c4c37c7d4d2befc7fd1d6 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Tue, 13 Dec 2016 13:11:06 -0200 Subject: [PATCH 027/134] Fixed CORE-5408 - Result of boolean expression can not be concatenated with string literal. --- src/dsql/parse-conflicts.txt | 2 +- src/dsql/parse.y | 31 +++++++++++++------------------ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index b0587cd258..844d1b2bae 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -44 shift/reduce conflicts, 17 reduce/reduce conflicts. +44 shift/reduce conflicts, 21 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 3f3aa34bdf..963ee3a393 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -6285,22 +6285,17 @@ distinct_predicate %type between_predicate between_predicate - : value BETWEEN value_between AND value_between %prec BETWEEN - { $$ = newNode(blr_between, $1, $3, $5); } - | value NOT BETWEEN value_between AND value_between %prec BETWEEN + : value BETWEEN value AND value %prec BETWEEN + { + $$ = newNode(blr_between, $1, $3, $5); + } + | value NOT BETWEEN value AND value %prec BETWEEN { ComparativeBoolNode* node = newNode(blr_between, $1, $4, $6); $$ = newNode(node); } ; -// Special value for BETWEEN, to avoid conflicts with boolean expressions. -%type value_between -value_between - : value_primary - | '(' boolean_value_expression ')' { $$ = newNode($2); } - ; - %type binary_pattern_predicate binary_pattern_predicate : value binary_pattern_operator value %prec CONTAINING @@ -6731,21 +6726,21 @@ nonparenthesized_value { $$ = $1; } | udf { $$ = $1; } - | '-' value_primary %prec UMINUS + | '-' value %prec UMINUS { $$ = newNode($2); } - | '+' value_primary %prec UPLUS + | '+' value %prec UPLUS { $$ = $2; } - | value_primary '+' value_primary + | value '+' value { $$ = newNode(blr_add, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } - | value_primary CONCATENATE value_primary + | value CONCATENATE value { $$ = newNode($1, $3); } - | value_primary COLLATE symbol_collation_name + | value COLLATE symbol_collation_name { $$ = newNode($1, *$3); } - | value_primary '-' value_primary + | value '-' value { $$ = newNode(blr_subtract, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } - | value_primary '*' value_primary + | value '*' value { $$ = newNode(blr_multiply, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } - | value_primary '/' value_primary + | value '/' value { $$ = newNode(blr_divide, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } | '(' column_singleton ')' { $$ = $2; } From 01c11aebf60d592c3f837c0a77bc82a72b08baef Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Wed, 14 Dec 2016 00:02:23 +0000 Subject: [PATCH 028/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index cd786b7e48..45095f37c7 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:465 + FORMAL BUILD NUMBER:466 */ -#define PRODUCT_VER_STRING "4.0.0.465" -#define FILE_VER_STRING "WI-T4.0.0.465" -#define LICENSE_VER_STRING "WI-T4.0.0.465" -#define FILE_VER_NUMBER 4, 0, 0, 465 +#define PRODUCT_VER_STRING "4.0.0.466" +#define FILE_VER_STRING "WI-T4.0.0.466" +#define LICENSE_VER_STRING "WI-T4.0.0.466" +#define FILE_VER_NUMBER 4, 0, 0, 466 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "465" +#define FB_BUILD_NO "466" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index daf9ae7ecf..40a902528e 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=465 +BuildNum=466 NowAt=`pwd` cd `dirname $0` From 59a912923257e5f4070ea23aead52575f62f0408 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Wed, 14 Dec 2016 19:30:25 +0300 Subject: [PATCH 029/134] Temporarily disable the broken code path. --- src/jrd/jrd.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 4422542ed3..7b153a299a 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1512,7 +1512,15 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch // Here we do not let anyone except SYSDBA (like DBO) to change dbb_page_buffers, // cause other flags is UserId can be set only when DB is opened. // No idea how to test for other cases before init is complete. - if ((config->getServerMode() != MODE_SUPER) || userId.locksmith(tdbb, CHANGE_HEADER_SETTINGS)) + // + // ATTN! dimitr 14-DEC-2016 + // We cannot call locksmith() here anymore because it queries the database + // which is not initialized at this point yet. I'd suggest to initialize the cache + // with the default settings and call CCH_expand() later if dpb_set_page_buffers + // is specified. + // + // if ((config->getServerMode() != MODE_SUPER) || userId.locksmith(tdbb, CHANGE_HEADER_SETTINGS)) + if (config->getServerMode() != MODE_SUPER) dbb->dbb_page_buffers = options.dpb_page_buffers; } From d301c85659791c04c20233afdc8bcd81eff31ba6 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Thu, 15 Dec 2016 00:02:29 +0000 Subject: [PATCH 030/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 45095f37c7..12fe58cb1b 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:466 + FORMAL BUILD NUMBER:467 */ -#define PRODUCT_VER_STRING "4.0.0.466" -#define FILE_VER_STRING "WI-T4.0.0.466" -#define LICENSE_VER_STRING "WI-T4.0.0.466" -#define FILE_VER_NUMBER 4, 0, 0, 466 +#define PRODUCT_VER_STRING "4.0.0.467" +#define FILE_VER_STRING "WI-T4.0.0.467" +#define LICENSE_VER_STRING "WI-T4.0.0.467" +#define FILE_VER_NUMBER 4, 0, 0, 467 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "466" +#define FB_BUILD_NO "467" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 40a902528e..fd9e47017b 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=466 +BuildNum=467 NowAt=`pwd` cd `dirname $0` From c3fe90cd8eddb9eb9a74bac5aee0319143c2915a Mon Sep 17 00:00:00 2001 From: Roman Simakov Date: Thu, 15 Dec 2016 10:13:43 +0300 Subject: [PATCH 031/134] Adjusted tokens array to be consistent to non_reserved_word of grammar (#71) * Adjusted tokens array to be consistent to non_reserved_word of grammar * Duplicated WEEK removed from non_reserved_word. tokens array adjusted according to this. * Make WEEK non reserved --- src/dsql/parse.y | 3 +- src/yvalve/keywords.cpp | 312 ++++++++++++++++++++-------------------- 2 files changed, 157 insertions(+), 158 deletions(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 963ee3a393..318e314899 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -7968,7 +7968,6 @@ non_reserved_word | TANH | TEMPORARY | TRUNC - | WEEK | AUTONOMOUS // added in FB 2.5 | CHAR_TO_UUID | FIRSTNAME @@ -8051,7 +8050,7 @@ non_reserved_word // | VARIABLE // | VIEW | WAIT -// | WEEK + | WEEK // | WHILE | WORK | WRITE // end of old keywords, that were reserved pre-Firebird.2.5 diff --git a/src/yvalve/keywords.cpp b/src/yvalve/keywords.cpp index f5e90a59fa..262008280b 100644 --- a/src/yvalve/keywords.cpp +++ b/src/yvalve/keywords.cpp @@ -54,46 +54,46 @@ static const TOK tokens[] = {'>', ">", false}, {TOK_GEQ, ">=", false}, {TOK_BIND_PARAM, ":=", false}, - {TOK_ABS, "ABS", false}, + {TOK_ABS, "ABS", true}, {TOK_ABSOLUTE, "ABSOLUTE", true}, {TOK_ACCENT, "ACCENT", true}, - {TOK_ACOS, "ACOS", false}, - {TOK_ACOSH, "ACOSH", false}, + {TOK_ACOS, "ACOS", true}, + {TOK_ACOSH, "ACOSH", true}, {TOK_ACTION, "ACTION", true}, - {TOK_ACTIVE, "ACTIVE", false}, + {TOK_ACTIVE, "ACTIVE", true}, {TOK_ADD, "ADD", false}, {TOK_ADMIN, "ADMIN", false}, - {TOK_AFTER, "AFTER", false}, + {TOK_AFTER, "AFTER", true}, {TOK_ALL, "ALL", false}, {TOK_ALTER, "ALTER", false}, {TOK_ALWAYS, "ALWAYS", true}, {TOK_AND, "AND", false}, {TOK_ANY, "ANY", false}, {TOK_AS, "AS", false}, - {TOK_ASC, "ASC", false}, // Alias of ASCENDING - {TOK_ASC, "ASCENDING", false}, - {TOK_ASCII_CHAR, "ASCII_CHAR", false}, - {TOK_ASCII_VAL, "ASCII_VAL", false}, - {TOK_ASIN, "ASIN", false}, - {TOK_ASINH, "ASINH", false}, + {TOK_ASC, "ASC", true}, // Alias of ASCENDING + {TOK_ASC, "ASCENDING", true}, + {TOK_ASCII_CHAR, "ASCII_CHAR", true}, + {TOK_ASCII_VAL, "ASCII_VAL", true}, + {TOK_ASIN, "ASIN", true}, + {TOK_ASINH, "ASINH", true}, {TOK_AT, "AT", false}, - {TOK_ATAN, "ATAN", false}, - {TOK_ATAN2, "ATAN2", false}, - {TOK_ATANH, "ATANH", false}, - {TOK_AUTO, "AUTO", false}, - {TOK_AUTONOMOUS, "AUTONOMOUS", false}, + {TOK_ATAN, "ATAN", true}, + {TOK_ATAN2, "ATAN2", true}, + {TOK_ATANH, "ATANH", true}, + {TOK_AUTO, "AUTO", true}, + {TOK_AUTONOMOUS, "AUTONOMOUS", true}, {TOK_AVG, "AVG", false}, {TOK_BACKUP, "BACKUP", true}, - {TOK_BEFORE, "BEFORE", false}, + {TOK_BEFORE, "BEFORE", true}, {TOK_BEGIN, "BEGIN", false}, {TOK_BETWEEN, "BETWEEN", false}, {TOK_BIGINT, "BIGINT", false}, - {TOK_BIN_AND, "BIN_AND", false}, - {TOK_BIN_NOT, "BIN_NOT", false}, - {TOK_BIN_OR, "BIN_OR", false}, - {TOK_BIN_SHL, "BIN_SHL", false}, - {TOK_BIN_SHR, "BIN_SHR", false}, - {TOK_BIN_XOR, "BIN_XOR", false}, + {TOK_BIN_AND, "BIN_AND", true}, + {TOK_BIN_NOT, "BIN_NOT", true}, + {TOK_BIN_OR, "BIN_OR", true}, + {TOK_BIN_SHL, "BIN_SHL", true}, + {TOK_BIN_SHR, "BIN_SHR", true}, + {TOK_BIN_XOR, "BIN_XOR", true}, {TOK_BIT_LENGTH, "BIT_LENGTH", false}, {TOK_BLOB, "BLOB", false}, {TOK_BLOCK, "BLOCK", true}, @@ -106,11 +106,11 @@ static const TOK tokens[] = {TOK_CASCADE, "CASCADE", true}, {TOK_CASE, "CASE", false}, {TOK_CAST, "CAST", false}, - {TOK_CEIL, "CEIL", false}, // alias of CEILING - {TOK_CEIL, "CEILING", false}, + {TOK_CEIL, "CEIL", true}, // Alias of CEILING + {TOK_CEIL, "CEILING", true}, {TOK_CHAR, "CHAR", false}, {TOK_CHAR_LENGTH, "CHAR_LENGTH", false}, - {TOK_CHAR_TO_UUID, "CHAR_TO_UUID", false}, + {TOK_CHAR_TO_UUID, "CHAR_TO_UUID", true}, {TOK_CHARACTER, "CHARACTER", false}, {TOK_CHARACTER_LENGTH, "CHARACTER_LENGTH", false}, {TOK_CHECK, "CHECK", false}, @@ -119,27 +119,27 @@ static const TOK tokens[] = {TOK_COLLATE, "COLLATE", false}, {TOK_COLLATION, "COLLATION", true}, {TOK_COLUMN, "COLUMN", false}, - {TOK_COMMENT, "COMMENT", true}, + {TOK_COMMENT, "COMMENT", false}, {TOK_COMMIT, "COMMIT", false}, - {TOK_COMMITTED, "COMMITTED", false}, + {TOK_COMMITTED, "COMMITTED", true}, {TOK_COMMON, "COMMON", true}, - {TOK_COMPUTED, "COMPUTED", false}, - {TOK_CONDITIONAL, "CONDITIONAL", false}, + {TOK_COMPUTED, "COMPUTED", true}, + {TOK_CONDITIONAL, "CONDITIONAL", true}, {TOK_CONNECT, "CONNECT", false}, {TOK_CONSTRAINT, "CONSTRAINT", false}, - {TOK_CONTAINING, "CONTAINING", false}, + {TOK_CONTAINING, "CONTAINING", true}, {TOK_CONTINUE, "CONTINUE", true}, {TOK_CORR, "CORR", false}, - {TOK_COS, "COS", false}, - {TOK_COSH, "COSH", false}, - {TOK_COT, "COT", false}, + {TOK_COS, "COS", true}, + {TOK_COSH, "COSH", true}, + {TOK_COT, "COT", true}, {TOK_COUNT, "COUNT", false}, {TOK_COVAR_POP, "COVAR_POP", false}, {TOK_COVAR_SAMP, "COVAR_SAMP", false}, {TOK_CREATE, "CREATE", false}, {TOK_CROSS, "CROSS", false}, - {TOK_CSTRING, "CSTRING", false}, - {TOK_CUME_DIST, "CUME_DIST", false}, + {TOK_CSTRING, "CSTRING", true}, + {TOK_CUME_DIST, "CUME_DIST", true}, {TOK_CURRENT, "CURRENT", false}, {TOK_CURRENT_CONNECTION, "CURRENT_CONNECTION", false}, {TOK_CURRENT_DATE, "CURRENT_DATE", false}, @@ -149,58 +149,58 @@ static const TOK tokens[] = {TOK_CURRENT_TRANSACTION, "CURRENT_TRANSACTION", false}, {TOK_CURRENT_USER, "CURRENT_USER", false}, {TOK_CURSOR, "CURSOR", false}, - {TOK_DATABASE, "DATABASE", false}, + {TOK_DATABASE, "DATABASE", true}, {TOK_DATA, "DATA", true}, {TOK_DATE, "DATE", false}, - {TOK_DATEADD, "DATEADD", false}, - {TOK_DATEDIFF, "DATEDIFF", false}, + {TOK_DATEADD, "DATEADD", true}, + {TOK_DATEDIFF, "DATEDIFF", true}, {TOK_DAY, "DAY", false}, - {TOK_DDL, "DDL", false}, + {TOK_DDL, "DDL", true}, {TOK_DEC, "DEC", false}, {TOK_DECIMAL, "DECIMAL", false}, {TOK_DECLARE, "DECLARE", false}, - {TOK_DECODE, "DECODE", false}, + {TOK_DECODE, "DECODE", true}, {TOK_DECRYPT, "DECRYPT", true}, {TOK_DEFAULT, "DEFAULT", false}, {TOK_DEFINER, "DEFINER", true}, {TOK_DELETE, "DELETE", false}, - {TOK_DELETING, "DELETING", true}, - {TOK_DENSE_RANK, "DENSE_RANK", false}, - {TOK_DESC, "DESC", false}, // Alias of DESCENDING - {TOK_DESC, "DESCENDING", false}, + {TOK_DELETING, "DELETING", false}, + {TOK_DENSE_RANK, "DENSE_RANK", true}, + {TOK_DESC, "DESC", true}, // Alias of DESCENDING + {TOK_DESC, "DESCENDING", true}, {TOK_DESCRIPTOR, "DESCRIPTOR", true}, {TOK_DETERMINISTIC, "DETERMINISTIC", false}, {TOK_DIFFERENCE, "DIFFERENCE", true}, {TOK_DISCONNECT, "DISCONNECT", false}, {TOK_DISTINCT, "DISTINCT", false}, - {TOK_DO, "DO", false}, - {TOK_DOMAIN, "DOMAIN", false}, + {TOK_DO, "DO", true}, + {TOK_DOMAIN, "DOMAIN", true}, {TOK_DOUBLE, "DOUBLE", false}, {TOK_DROP, "DROP", false}, {TOK_ELSE, "ELSE", false}, {TOK_ENCRYPT, "ENCRYPT", true}, {TOK_END, "END", false}, {TOK_ENGINE, "ENGINE", true}, - {TOK_ENTRY_POINT, "ENTRY_POINT", false}, + {TOK_ENTRY_POINT, "ENTRY_POINT", true}, {TOK_ESCAPE, "ESCAPE", false}, - {TOK_EXCEPTION, "EXCEPTION", false}, - {TOK_EXCLUDE, "EXCLUDE", false}, + {TOK_EXCEPTION, "EXCEPTION", true}, + {TOK_EXCLUDE, "EXCLUDE", true}, {TOK_EXECUTE, "EXECUTE", false}, {TOK_EXISTS, "EXISTS", false}, - {TOK_EXIT, "EXIT", false}, - {TOK_EXP, "EXP", false}, + {TOK_EXIT, "EXIT", true}, + {TOK_EXP, "EXP", true}, {TOK_EXTERNAL, "EXTERNAL", false}, {TOK_EXTRACT, "EXTRACT", false}, {TOK_FALSE, "FALSE", false}, {TOK_FETCH, "FETCH", false}, - {TOK_FILE, "FILE", false}, + {TOK_FILE, "FILE", true}, {TOK_FILTER, "FILTER", false}, {TOK_FIRST, "FIRST", true}, - {TOK_FIRST_VALUE, "FIRST_VALUE", false}, - {TOK_FIRSTNAME, "FIRSTNAME", false}, + {TOK_FIRST_VALUE, "FIRST_VALUE", true}, + {TOK_FIRSTNAME, "FIRSTNAME", true}, {TOK_FLOAT, "FLOAT", false}, - {TOK_FLOOR, "FLOOR", false}, - {TOK_FOLLOWING, "FOLLOWING", false}, + {TOK_FLOOR, "FLOOR", true}, + {TOK_FOLLOWING, "FOLLOWING", true}, {TOK_FOR, "FOR", false}, {TOK_FOREIGN, "FOREIGN", false}, {TOK_FREE_IT, "FREE_IT", true}, @@ -209,84 +209,84 @@ static const TOK tokens[] = {TOK_FUNCTION, "FUNCTION", false}, {TOK_GDSCODE, "GDSCODE", false}, {TOK_GENERATED, "GENERATED", true}, - {TOK_GENERATOR, "GENERATOR", false}, - {TOK_GEN_ID, "GEN_ID", false}, - {TOK_GEN_UUID, "GEN_UUID", false}, + {TOK_GENERATOR, "GENERATOR", true}, + {TOK_GEN_ID, "GEN_ID", true}, + {TOK_GEN_UUID, "GEN_UUID", true}, {TOK_GLOBAL, "GLOBAL", false}, {TOK_GRANT, "GRANT", false}, - {TOK_GRANTED, "GRANTED", false}, + {TOK_GRANTED, "GRANTED", true}, {TOK_GROUP, "GROUP", false}, - {TOK_HASH, "HASH", false}, + {TOK_HASH, "HASH", true}, {TOK_HAVING, "HAVING", false}, {TOK_HOUR, "HOUR", false}, - {TOK_IDENTITY, "IDENTITY", false}, - {TOK_IF, "IF", false}, + {TOK_IDENTITY, "IDENTITY", true}, + {TOK_IF, "IF", true}, {TOK_IGNORE, "IGNORE", true}, {TOK_IIF, "IIF", true}, {TOK_IN, "IN", false}, - {TOK_INACTIVE, "INACTIVE", false}, - {TOK_INCREMENT, "INCREMENT", false}, + {TOK_INACTIVE, "INACTIVE", true}, + {TOK_INCREMENT, "INCREMENT", true}, {TOK_INDEX, "INDEX", false}, {TOK_INNER, "INNER", false}, - {TOK_INPUT_TYPE, "INPUT_TYPE", false}, + {TOK_INPUT_TYPE, "INPUT_TYPE", true}, {TOK_INSENSITIVE, "INSENSITIVE", false}, {TOK_INSERT, "INSERT", false}, - {TOK_INSERTING, "INSERTING", true}, + {TOK_INSERTING, "INSERTING", false}, {TOK_INT, "INT", false}, {TOK_INTEGER, "INTEGER", false}, {TOK_INTO, "INTO", false}, {TOK_INVOKER, "INVOKER", true}, {TOK_IS, "IS", false}, - {TOK_ISOLATION, "ISOLATION", false}, + {TOK_ISOLATION, "ISOLATION", true}, {TOK_JOIN, "JOIN", false}, - {TOK_KEY, "KEY", false}, - {TOK_LAG, "LAG", false}, + {TOK_KEY, "KEY", true}, + {TOK_LAG, "LAG", true}, {TOK_LAST, "LAST", true}, - {TOK_LAST_VALUE, "LAST_VALUE", false}, - {TOK_LASTNAME, "LASTNAME", false}, - {TOK_LEAD, "LEAD", false}, + {TOK_LAST_VALUE, "LAST_VALUE", true}, + {TOK_LASTNAME, "LASTNAME", true}, + {TOK_LEAD, "LEAD", true}, {TOK_LEADING, "LEADING", false}, {TOK_LEAVE, "LEAVE", true}, {TOK_LEFT, "LEFT", false}, - {TOK_LENGTH, "LENGTH", false}, - {TOK_LEVEL, "LEVEL", false}, + {TOK_LENGTH, "LENGTH", true}, + {TOK_LEVEL, "LEVEL", true}, {TOK_LIKE, "LIKE", false}, {TOK_LIMBO, "LIMBO", true}, {TOK_LINGER, "LINGER", true}, - {TOK_LIST, "LIST", false}, - {TOK_LN, "LN", false}, + {TOK_LIST, "LIST", true}, + {TOK_LN, "LN", true}, {TOK_LOCK, "LOCK", true}, - {TOK_LOG, "LOG", false}, - {TOK_LOG10, "LOG10", false}, + {TOK_LOG, "LOG", true}, + {TOK_LOG10, "LOG10", true}, {TOK_LONG, "LONG", false}, {TOK_LOWER, "LOWER", false}, - {TOK_LPAD, "LPAD", false}, - {TOK_MANUAL, "MANUAL", false}, - {TOK_MAPPING, "MAPPING", false}, - {TOK_MATCHED, "MATCHED", false}, - {TOK_MATCHING, "MATCHING", false}, + {TOK_LPAD, "LPAD", true}, + {TOK_MANUAL, "MANUAL", true}, + {TOK_MAPPING, "MAPPING", true}, + {TOK_MATCHED, "MATCHED", true}, + {TOK_MATCHING, "MATCHING", true}, {TOK_MAXIMUM, "MAX", false}, - {TOK_MAXVALUE, "MAXVALUE", false}, + {TOK_MAXVALUE, "MAXVALUE", true}, {TOK_MERGE, "MERGE", false}, {TOK_MESSAGE, "MESSAGE", true}, - {TOK_MILLISECOND, "MILLISECOND", false}, - {TOK_MIDDLENAME, "MIDDLENAME", false}, + {TOK_MILLISECOND, "MILLISECOND", true}, + {TOK_MIDDLENAME, "MIDDLENAME", true}, {TOK_MINIMUM, "MIN", false}, {TOK_MINUTE, "MINUTE", false}, - {TOK_MINVALUE, "MINVALUE", false}, - {TOK_MOD, "MOD", false}, - {TOK_MODULE_NAME, "MODULE_NAME", false}, + {TOK_MINVALUE, "MINVALUE", true}, + {TOK_MOD, "MOD", true}, + {TOK_MODULE_NAME, "MODULE_NAME", true}, {TOK_MONTH, "MONTH", false}, {TOK_NAME, "NAME", true}, - {TOK_NAMES, "NAMES", false}, + {TOK_NAMES, "NAMES", true}, {TOK_NATIONAL, "NATIONAL", false}, {TOK_NATURAL, "NATURAL", false}, {TOK_NCHAR, "NCHAR", false}, {TOK_NEXT, "NEXT", true}, {TOK_NO, "NO", false}, {TOK_NOT, "NOT", false}, - {TOK_NTH_VALUE, "NTH_VALUE", false}, - {TOK_NTILE, "NTILE", false}, + {TOK_NTH_VALUE, "NTH_VALUE", true}, + {TOK_NTILE, "NTILE", true}, {TOK_NULLIF, "NULLIF", true}, {TOK_NULL, "NULL", false}, {TOK_NULLS, "NULLS", true}, @@ -297,44 +297,44 @@ static const TOK tokens[] = {TOK_ON, "ON", false}, {TOK_ONLY, "ONLY", false}, {TOK_OPEN, "OPEN", false}, - {TOK_OPTION, "OPTION", false}, + {TOK_OPTION, "OPTION", true}, {TOK_OR, "OR", false}, {TOK_ORDER, "ORDER", false}, - {TOK_OS_NAME, "OS_NAME", false}, - {TOK_OTHERS, "OTHERS", false}, + {TOK_OS_NAME, "OS_NAME", true}, + {TOK_OTHERS, "OTHERS", true}, {TOK_OUTER, "OUTER", false}, - {TOK_OUTPUT_TYPE, "OUTPUT_TYPE", false}, + {TOK_OUTPUT_TYPE, "OUTPUT_TYPE", true}, {TOK_OVER, "OVER", false}, - {TOK_OVERFLOW, "OVERFLOW", false}, - {TOK_OVERLAY, "OVERLAY", false}, + {TOK_OVERFLOW, "OVERFLOW", true}, + {TOK_OVERLAY, "OVERLAY", true}, {TOK_PACKAGE, "PACKAGE", true}, {TOK_PAD, "PAD", true}, - {TOK_PAGE, "PAGE", false}, - {TOK_PAGES, "PAGES", false}, - {TOK_PAGE_SIZE, "PAGE_SIZE", false}, + {TOK_PAGE, "PAGE", true}, + {TOK_PAGES, "PAGES", true}, + {TOK_PAGE_SIZE, "PAGE_SIZE", true}, {TOK_PARAMETER, "PARAMETER", false}, - {TOK_PARTITION, "PARTITION", false}, - {TOK_PASSWORD, "PASSWORD", false}, - {TOK_PERCENT_RANK, "PERCENT_RANK", false}, - {TOK_PI, "PI", false}, - {TOK_PLACING, "PLACING", false}, + {TOK_PARTITION, "PARTITION", true}, + {TOK_PASSWORD, "PASSWORD", true}, + {TOK_PERCENT_RANK, "PERCENT_RANK", true}, + {TOK_PI, "PI", true}, + {TOK_PLACING, "PLACING", true}, {TOK_PLAN, "PLAN", false}, {TOK_PLUGIN, "PLUGIN", true}, {TOK_POSITION, "POSITION", false}, {TOK_POST_EVENT, "POST_EVENT", false}, - {TOK_POWER, "POWER", false}, - {TOK_PRECEDING, "PRECEDING", false}, + {TOK_POWER, "POWER", true}, + {TOK_PRECEDING, "PRECEDING", true}, {TOK_PRECISION, "PRECISION", false}, {TOK_PRESERVE, "PRESERVE", true}, {TOK_PRIMARY, "PRIMARY", false}, {TOK_PRIOR, "PRIOR", true}, - {TOK_PRIVILEGE, "PRIVILEGE", false}, - {TOK_PRIVILEGES, "PRIVILEGES", false}, + {TOK_PRIVILEGE, "PRIVILEGE", true}, + {TOK_PRIVILEGES, "PRIVILEGES", true}, {TOK_PROCEDURE, "PROCEDURE", false}, - {TOK_PROTECTED, "PROTECTED", false}, - {TOK_RAND, "RAND", false}, - {TOK_RANGE, "RANGE", false}, - {TOK_RANK, "RANK", false}, + {TOK_PROTECTED, "PROTECTED", true}, + {TOK_RAND, "RAND", true}, + {TOK_RANGE, "RANGE", true}, + {TOK_RANK, "RANK", true}, {TOK_DB_KEY, "RDB$DB_KEY", false}, {TOK_RDB_ERROR, "RDB$ERROR", false}, {TOK_RDB_GET_CONTEXT, "RDB$GET_CONTEXT", false}, @@ -342,7 +342,7 @@ static const TOK tokens[] = {TOK_RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", false}, {TOK_RDB_SET_CONTEXT, "RDB$SET_CONTEXT", false}, {TOK_RDB_SYSTEM_PRIVILEGE, "RDB$SYSTEM_PRIVILEGE", false}, - {TOK_READ, "READ", false}, + {TOK_READ, "READ", true}, {TOK_REAL, "REAL", false}, {TOK_VERSION, "RECORD_VERSION", false}, {TOK_RECREATE, "RECREATE", false}, @@ -359,28 +359,28 @@ static const TOK tokens[] = {TOK_REGR_SYY, "REGR_SYY", false}, {TOK_RELATIVE, "RELATIVE", true}, {TOK_RELEASE, "RELEASE", false}, - {TOK_REPLACE, "REPLACE", false}, + {TOK_REPLACE, "REPLACE", true}, {TOK_REQUESTS, "REQUESTS", true}, - {TOK_RESERVING, "RESERV", false}, // Alias of RESERVING - {TOK_RESERVING, "RESERVING", false}, + {TOK_RESERVING, "RESERV", true}, // Alias of RESERVING + {TOK_RESERVING, "RESERVING", true}, {TOK_RESTART, "RESTART", true}, {TOK_RESTRICT, "RESTRICT", true}, - {TOK_RETAIN, "RETAIN", false}, + {TOK_RETAIN, "RETAIN", true}, {TOK_RETURN, "RETURN", false}, {TOK_RETURNING, "RETURNING", true}, {TOK_RETURNING_VALUES, "RETURNING_VALUES", false}, {TOK_RETURNS, "RETURNS", false}, - {TOK_REVERSE, "REVERSE", false}, + {TOK_REVERSE, "REVERSE", true}, {TOK_REVOKE, "REVOKE", false}, {TOK_RIGHT, "RIGHT", false}, {TOK_ROLE, "ROLE", true}, {TOK_ROLLBACK, "ROLLBACK", false}, - {TOK_ROUND, "ROUND", false}, + {TOK_ROUND, "ROUND", true}, {TOK_ROW, "ROW", false}, {TOK_ROW_COUNT, "ROW_COUNT", false}, - {TOK_ROW_NUMBER, "ROW_NUMBER", false}, + {TOK_ROW_NUMBER, "ROW_NUMBER", true}, {TOK_ROWS, "ROWS", false}, - {TOK_RPAD, "RPAD", false}, + {TOK_RPAD, "RPAD", true}, {TOK_SAVEPOINT, "SAVEPOINT", false}, {TOK_SCALAR_ARRAY, "SCALAR_ARRAY", true}, {TOK_DATABASE, "SCHEMA", false}, // Alias of DATABASE @@ -388,76 +388,76 @@ static const TOK tokens[] = {TOK_SECOND, "SECOND", false}, {TOK_SQL, "SQL", true}, {TOK_SECURITY, "SECURITY", true}, - {TOK_SEGMENT, "SEGMENT", false}, + {TOK_SEGMENT, "SEGMENT", true}, {TOK_SELECT, "SELECT", false}, {TOK_SENSITIVE, "SENSITIVE", false}, {TOK_SEQUENCE, "SEQUENCE", true}, {TOK_SERVERWIDE, "SERVERWIDE", true}, {TOK_SET, "SET", false}, - {TOK_SHADOW, "SHADOW", false}, - {TOK_SHARED, "SHARED", false}, - {TOK_SIGN, "SIGN", false}, + {TOK_SHADOW, "SHADOW", true}, + {TOK_SHARED, "SHARED", true}, + {TOK_SIGN, "SIGN", true}, {TOK_SIMILAR, "SIMILAR", false}, - {TOK_SIN, "SIN", false}, - {TOK_SINGULAR, "SINGULAR", false}, - {TOK_SINH, "SINH", false}, - {TOK_SIZE, "SIZE", false}, + {TOK_SIN, "SIN", true}, + {TOK_SINGULAR, "SINGULAR", true}, + {TOK_SINH, "SINH", true}, + {TOK_SIZE, "SIZE", true}, {TOK_SKIP, "SKIP", true}, {TOK_SMALLINT, "SMALLINT", false}, - {TOK_SNAPSHOT, "SNAPSHOT", false}, + {TOK_SNAPSHOT, "SNAPSHOT", true}, {TOK_SOME, "SOME", false}, - {TOK_SORT, "SORT", false}, + {TOK_SORT, "SORT", true}, {TOK_SOURCE, "SOURCE", true}, {TOK_SPACE, "SPACE", true}, {TOK_SQLCODE, "SQLCODE", false}, {TOK_SQLSTATE, "SQLSTATE", false}, - {TOK_SQRT, "SQRT", false}, - {TOK_STABILITY, "STABILITY", false}, + {TOK_SQRT, "SQRT", true}, + {TOK_STABILITY, "STABILITY", true}, {TOK_START, "START", false}, - {TOK_STARTING, "STARTING", false}, - {TOK_STARTING, "STARTS", false}, // Alias of STARTING + {TOK_STARTING, "STARTING", true}, + {TOK_STARTING, "STARTS", true}, // Alias of STARTING {TOK_STATEMENT, "STATEMENT", true}, - {TOK_STATISTICS, "STATISTICS", false}, + {TOK_STATISTICS, "STATISTICS", true}, {TOK_STDDEV_POP, "STDDEV_POP", false}, {TOK_STDDEV_SAMP, "STDDEV_SAMP", false}, {TOK_SUBSTRING, "SUBSTRING", true}, - {TOK_SUB_TYPE, "SUB_TYPE", false}, + {TOK_SUB_TYPE, "SUB_TYPE", true}, {TOK_SUM, "SUM", false}, - {TOK_SUSPEND, "SUSPEND", false}, - {TOK_SYSTEM, "SYSTEM", false}, + {TOK_SUSPEND, "SUSPEND", true}, + {TOK_SYSTEM, "SYSTEM", true}, {TOK_TABLE, "TABLE", false}, {TOK_TAGS, "TAGS", true}, - {TOK_TAN, "TAN", false}, - {TOK_TANH, "TANH", false}, + {TOK_TAN, "TAN", true}, + {TOK_TANH, "TANH", true}, {TOK_TEMPORARY, "TEMPORARY", true}, {TOK_THEN, "THEN", false}, - {TOK_TIES, "TIES", false}, + {TOK_TIES, "TIES", true}, {TOK_TIME, "TIME", false}, {TOK_TIMESTAMP, "TIMESTAMP", false}, {TOK_TIMEOUT, "TIMEOUT", true}, {TOK_TO, "TO", false}, {TOK_TRAILING, "TRAILING", false}, - {TOK_TRANSACTION, "TRANSACTION", false}, + {TOK_TRANSACTION, "TRANSACTION", true}, {TOK_TRIGGER, "TRIGGER", false}, {TOK_TRIM, "TRIM", false}, {TOK_TRUE, "TRUE", false}, - {TOK_TRUNC, "TRUNC", false}, - {TOK_TRUSTED, "TRUSTED", false}, + {TOK_TRUNC, "TRUNC", true}, + {TOK_TRUSTED, "TRUSTED", true}, {TOK_TWO_PHASE, "TWO_PHASE", true}, {TOK_TYPE, "TYPE", true}, {TOK_UNBOUNDED, "UNBOUNDED", false}, - {TOK_UNCOMMITTED, "UNCOMMITTED", false}, + {TOK_UNCOMMITTED, "UNCOMMITTED", true}, {TOK_UNDO, "UNDO", true}, {TOK_UNION, "UNION", false}, {TOK_UNIQUE, "UNIQUE", false}, {TOK_UNKNOWN, "UNKNOWN", false}, {TOK_UPDATE, "UPDATE", false}, - {TOK_UPDATING, "UPDATING", true}, + {TOK_UPDATING, "UPDATING", false}, {TOK_UPPER, "UPPER", false}, {TOK_USAGE, "USAGE", true}, {TOK_USER, "USER", false}, {TOK_USING, "USING", false}, - {TOK_UUID_TO_CHAR, "UUID_TO_CHAR", false}, + {TOK_UUID_TO_CHAR, "UUID_TO_CHAR", true}, {TOK_VALUE, "VALUE", false}, {TOK_VALUES, "VALUES", false}, {TOK_VAR_POP, "VAR_POP", false}, @@ -466,16 +466,16 @@ static const TOK tokens[] = {TOK_VARIABLE, "VARIABLE", false}, {TOK_VARYING, "VARYING", false}, {TOK_VIEW, "VIEW", false}, - {TOK_WAIT, "WAIT", false}, - {TOK_WEEK, "WEEK", false}, + {TOK_WAIT, "WAIT", true}, + {TOK_WEEK, "WEEK", true}, {TOK_WEEKDAY, "WEEKDAY", true}, {TOK_WHEN, "WHEN", false}, {TOK_WHERE, "WHERE", false}, {TOK_WHILE, "WHILE", false}, {TOK_WINDOW, "WINDOW", false}, {TOK_WITH, "WITH", false}, - {TOK_WORK, "WORK", false}, - {TOK_WRITE, "WRITE", false}, + {TOK_WORK, "WORK", true}, + {TOK_WRITE, "WRITE", true}, {TOK_YEAR, "YEAR", false}, {TOK_YEARDAY, "YEARDAY", true}, {TOK_NOT_LSS, "^<", false}, // Alias of !< From ff0ddf3a11485580ed72e601337dab52ff05ad86 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 16 Dec 2016 00:02:24 +0000 Subject: [PATCH 032/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 12fe58cb1b..efd327b58f 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:467 + FORMAL BUILD NUMBER:468 */ -#define PRODUCT_VER_STRING "4.0.0.467" -#define FILE_VER_STRING "WI-T4.0.0.467" -#define LICENSE_VER_STRING "WI-T4.0.0.467" -#define FILE_VER_NUMBER 4, 0, 0, 467 +#define PRODUCT_VER_STRING "4.0.0.468" +#define FILE_VER_STRING "WI-T4.0.0.468" +#define LICENSE_VER_STRING "WI-T4.0.0.468" +#define FILE_VER_NUMBER 4, 0, 0, 468 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "467" +#define FB_BUILD_NO "468" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index fd9e47017b..ee7ee39ae0 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=467 +BuildNum=468 NowAt=`pwd` cd `dirname $0` From 5f6d20c3fb00a682789b49c492190ec58f997c2b Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Tue, 20 Dec 2016 14:25:23 -0200 Subject: [PATCH 033/134] Rework in the fix for CORE-5408 to fix CORE-5423. CORE-5408 - Result of boolean expression can not be concatenated with string literal CORE-5423 - Regression: "Invalid usage of boolean expression" when use "BETWEEN" and "IS" operators --- src/dsql/parse-conflicts.txt | 2 +- src/dsql/parse.y | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 844d1b2bae..b0587cd258 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -44 shift/reduce conflicts, 21 reduce/reduce conflicts. +44 shift/reduce conflicts, 17 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 318e314899..c3582b3580 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -6285,11 +6285,11 @@ distinct_predicate %type between_predicate between_predicate - : value BETWEEN value AND value %prec BETWEEN + : value BETWEEN value_special AND value_special %prec BETWEEN { $$ = newNode(blr_between, $1, $3, $5); } - | value NOT BETWEEN value AND value %prec BETWEEN + | value NOT BETWEEN value_special AND value_special %prec BETWEEN { ComparativeBoolNode* node = newNode(blr_between, $1, $4, $6); $$ = newNode(node); @@ -6695,6 +6695,13 @@ value { $$ = newNode($1); } ; +// Used in situations that is not possible to use non-parenthesized boolean expressions. +%type value_special +value_special + : value_primary + | '(' boolean_value_expression ')' { $$ = newNode($2); } + ; + %type value_primary value_primary : nonparenthesized_value @@ -6726,21 +6733,21 @@ nonparenthesized_value { $$ = $1; } | udf { $$ = $1; } - | '-' value %prec UMINUS + | '-' value_special %prec UMINUS { $$ = newNode($2); } - | '+' value %prec UPLUS + | '+' value_special %prec UPLUS { $$ = $2; } - | value '+' value + | value_special '+' value_special { $$ = newNode(blr_add, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } - | value CONCATENATE value + | value_special CONCATENATE value_special { $$ = newNode($1, $3); } - | value COLLATE symbol_collation_name + | value_special COLLATE symbol_collation_name { $$ = newNode($1, *$3); } - | value '-' value + | value_special '-' value_special { $$ = newNode(blr_subtract, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } - | value '*' value + | value_special '*' value_special { $$ = newNode(blr_multiply, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } - | value '/' value + | value_special '/' value_special { $$ = newNode(blr_divide, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } | '(' column_singleton ')' { $$ = $2; } From 6089425ee43e1bf23e9b852e216e11acf934bd7a Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Wed, 21 Dec 2016 00:02:25 +0000 Subject: [PATCH 034/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index efd327b58f..a673a5b982 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:468 + FORMAL BUILD NUMBER:469 */ -#define PRODUCT_VER_STRING "4.0.0.468" -#define FILE_VER_STRING "WI-T4.0.0.468" -#define LICENSE_VER_STRING "WI-T4.0.0.468" -#define FILE_VER_NUMBER 4, 0, 0, 468 +#define PRODUCT_VER_STRING "4.0.0.469" +#define FILE_VER_STRING "WI-T4.0.0.469" +#define LICENSE_VER_STRING "WI-T4.0.0.469" +#define FILE_VER_NUMBER 4, 0, 0, 469 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "468" +#define FB_BUILD_NO "469" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index ee7ee39ae0..1e97713c9b 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=468 +BuildNum=469 NowAt=`pwd` cd `dirname $0` From ddfdcc25e960054141c408c6e13156e97b0d434a Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Thu, 22 Dec 2016 12:22:21 -0200 Subject: [PATCH 035/134] Fixed CORE-5427 - Error on field concatenation of System tables. --- src/dsql/ExprNodes.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index bddbfce0fc..c12fcf5d48 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -5873,11 +5873,8 @@ dsc* FieldNode::execute(thread_db* tdbb, jrd_req* request) const MOV_move(tdbb, &desc, &impure->vlu_desc); } - if (!relation || !(relation->rel_flags & REL_system)) - { - if (impure->vlu_desc.dsc_dtype == dtype_text) - INTL_adjust_text_descriptor(tdbb, &impure->vlu_desc); - } + if (impure->vlu_desc.dsc_dtype == dtype_text) + INTL_adjust_text_descriptor(tdbb, &impure->vlu_desc); return &impure->vlu_desc; } From e814cf69cbd97fe9cc7048e2d2ce035055d1b9ec Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 23 Dec 2016 00:02:25 +0000 Subject: [PATCH 036/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index a673a5b982..4c5590d0fc 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:469 + FORMAL BUILD NUMBER:470 */ -#define PRODUCT_VER_STRING "4.0.0.469" -#define FILE_VER_STRING "WI-T4.0.0.469" -#define LICENSE_VER_STRING "WI-T4.0.0.469" -#define FILE_VER_NUMBER 4, 0, 0, 469 +#define PRODUCT_VER_STRING "4.0.0.470" +#define FILE_VER_STRING "WI-T4.0.0.470" +#define LICENSE_VER_STRING "WI-T4.0.0.470" +#define FILE_VER_NUMBER 4, 0, 0, 470 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "469" +#define FB_BUILD_NO "470" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 1e97713c9b..d9a58b9089 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=469 +BuildNum=470 NowAt=`pwd` cd `dirname $0` From cb3a1518f5cb35d22c7c536c26aaba79718db8a5 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Sun, 25 Dec 2016 17:23:03 +0300 Subject: [PATCH 037/134] Warning --- src/jrd/btr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 8283fece3c..75600f4d1b 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -5184,7 +5184,7 @@ static void generate_jump_nodes(thread_db* tdbb, btree_page* page, if (splitIndex && *splitIndex < jumpNodes->getCount()) { splitPageSize += jumpNode.getJumpNodeSize(); - if (*splitIndex + 1 == jumpNodes->getCount()) + if (*splitIndex + 1u == jumpNodes->getCount()) splitPageSize += jumpNode.prefix; } } From f88ddeda497712fb648f838bbf4b81697fb9a513 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Sun, 25 Dec 2016 18:07:57 +0300 Subject: [PATCH 038/134] Fixed CORE-5428: Rare segfault when preparing request working with a table with triggers --- src/dsql/StmtNodes.cpp | 20 +++++++-------- src/jrd/Attachment.cpp | 1 + src/jrd/Attachment.h | 7 +++--- src/jrd/JrdStatement.cpp | 6 ++--- src/jrd/JrdStatement.h | 4 +-- src/jrd/Relation.cpp | 2 +- src/jrd/Relation.h | 12 ++++----- src/jrd/dfw.epp | 18 +++++++------- src/jrd/exe.cpp | 12 ++++----- src/jrd/exe_proto.h | 2 +- src/jrd/jrd.cpp | 30 +++++++++++++++++++++-- src/jrd/jrd.h | 35 ++++++++++++++++++++++++-- src/jrd/met.epp | 53 +++++++++++++++++----------------------- src/jrd/met_proto.h | 6 ++--- 14 files changed, 129 insertions(+), 79 deletions(-) diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 326e2f74df..9d4b05db44 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -87,12 +87,12 @@ static void makeValidation(thread_db* tdbb, CompilerScratch* csb, StreamType str static StmtNode* pass1ExpandView(thread_db* tdbb, CompilerScratch* csb, StreamType orgStream, StreamType newStream, bool remap); static RelationSourceNode* pass1Update(thread_db* tdbb, CompilerScratch* csb, jrd_rel* relation, - const trig_vec* trigger, StreamType stream, StreamType updateStream, SecurityClass::flags_t priv, + const TrigVector* trigger, StreamType stream, StreamType updateStream, SecurityClass::flags_t priv, jrd_rel* view, StreamType viewStream, StreamType viewUpdateStream); static void pass1Validations(thread_db* tdbb, CompilerScratch* csb, Array& validations); static void postTriggerAccess(CompilerScratch* csb, jrd_rel* ownerRelation, ExternalAccess::exa_act operation, jrd_rel* view); -static void preModifyEraseTriggers(thread_db* tdbb, trig_vec** trigs, +static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs, StmtNode::WhichTrigger whichTrig, record_param* rpb, record_param* rec, TriggerAction op); static void validateExpressions(thread_db* tdbb, const Array& validations); @@ -2243,8 +2243,8 @@ void EraseNode::pass1Erase(thread_db* tdbb, CompilerScratch* csb, EraseNode* nod if (parent) priv |= SCL_select; - const trig_vec* trigger = relation->rel_pre_erase ? - relation->rel_pre_erase : relation->rel_post_erase; + RefPtr trigger(relation->rel_pre_erase ? + relation->rel_pre_erase : relation->rel_post_erase); // If we have a view with triggers, let's expand it. @@ -5936,8 +5936,8 @@ void ModifyNode::pass1Modify(thread_db* tdbb, CompilerScratch* csb, ModifyNode* if (parent) priv |= SCL_select; - const trig_vec* trigger = (relation->rel_pre_modify) ? - relation->rel_pre_modify : relation->rel_post_modify; + RefPtr trigger(relation->rel_pre_modify ? + relation->rel_pre_modify : relation->rel_post_modify); // If we have a view with triggers, let's expand it. @@ -6697,8 +6697,8 @@ bool StoreNode::pass1Store(thread_db* tdbb, CompilerScratch* csb, StoreNode* nod postTriggerAccess(csb, relation, ExternalAccess::exa_insert, view); - const trig_vec* trigger = relation->rel_pre_store ? - relation->rel_pre_store : relation->rel_post_store; + RefPtr trigger(relation->rel_pre_store ? + relation->rel_pre_store : relation->rel_post_store); // Check out insert. If this is an insert thru a view, verify the view by checking for read // access on the base table. If field-level select privileges are implemented, this needs @@ -9069,7 +9069,7 @@ static StmtNode* pass1ExpandView(thread_db* tdbb, CompilerScratch* csb, StreamTy // If it's a view update, make sure the view is updatable, and return the view source for redirection. // If it's a simple relation, return NULL. static RelationSourceNode* pass1Update(thread_db* tdbb, CompilerScratch* csb, jrd_rel* relation, - const trig_vec* trigger, StreamType stream, StreamType updateStream, SecurityClass::flags_t priv, + const TrigVector* trigger, StreamType stream, StreamType updateStream, SecurityClass::flags_t priv, jrd_rel* view, StreamType viewStream, StreamType viewUpdateStream) { SET_TDBB(tdbb); @@ -9196,7 +9196,7 @@ static void postTriggerAccess(CompilerScratch* csb, jrd_rel* ownerRelation, } // Perform operation's pre-triggers, storing active rpb in chain. -static void preModifyEraseTriggers(thread_db* tdbb, trig_vec** trigs, +static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs, StmtNode::WhichTrigger whichTrig, record_param* rpb, record_param* rec, TriggerAction op) { if (!tdbb->getTransaction()->tra_rpblist) diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index e4e16c98b1..c97f56704c 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -755,3 +755,4 @@ JAttachment* Attachment::getInterface() throw() { return att_stable->getInterface(); } + diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index 1a398ab004..182fd6d0b0 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -77,7 +77,7 @@ namespace Jrd class jrd_rel; class jrd_prc; class Trigger; - typedef Firebird::ObjectsArray trig_vec; + class TrigVector; class Function; class JrdStatement; class Validation; @@ -295,8 +295,8 @@ public: vec* att_relations; // relation vector Firebird::Array att_procedures; // scanned procedures - trig_vec* att_triggers[DB_TRIGGER_MAX]; - trig_vec* att_ddl_triggers; + TrigVector* att_triggers[DB_TRIGGER_MAX]; + TrigVector* att_ddl_triggers; Firebird::Array att_functions; // User defined functions Firebird::Array att_internal; // internal statements @@ -562,7 +562,6 @@ private: Firebird::RefPtr m_JAttachment; }; - } // namespace Jrd #endif // JRD_ATTACHMENT_H diff --git a/src/jrd/JrdStatement.cpp b/src/jrd/JrdStatement.cpp index 1c459e140a..3c02c0d041 100644 --- a/src/jrd/JrdStatement.cpp +++ b/src/jrd/JrdStatement.cpp @@ -616,7 +616,7 @@ void JrdStatement::release(thread_db* tdbb) // Check that we have enough rights to access all resources this list of triggers touches. void JrdStatement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, - trig_vec* triggers, MetaName userName) + TrigVector* triggers, MetaName userName) { if (!triggers) return; @@ -676,7 +676,7 @@ void JrdStatement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, // Invoke buildExternalAccess for triggers in vector inline void JrdStatement::triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, - trig_vec* tvec) + TrigVector* tvec) { if (!tvec) return; @@ -723,7 +723,7 @@ void JrdStatement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list if (!relation) continue; - trig_vec *vec1, *vec2; + RefPtr vec1, vec2; switch (item->exa_action) { diff --git a/src/jrd/JrdStatement.h b/src/jrd/JrdStatement.h index c0820da985..7f252b5db9 100644 --- a/src/jrd/JrdStatement.h +++ b/src/jrd/JrdStatement.h @@ -57,9 +57,9 @@ public: void release(thread_db* tdbb); private: - static void verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, trig_vec* triggers, + static void verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, TrigVector* triggers, Firebird::MetaName userName); - static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, trig_vec* tvec); + static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, TrigVector* tvec); void buildExternalAccess(thread_db* tdbb, ExternalAccessList& list); diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp index 31ac6cddc1..b1e15061f9 100644 --- a/src/jrd/Relation.cpp +++ b/src/jrd/Relation.cpp @@ -273,7 +273,7 @@ void jrd_rel::RelPagesSnapshot::clear() bool jrd_rel::hasTriggers() const { - typedef const trig_vec* ctv; + typedef const TrigVector* ctv; ctv trigs[6] = // non-const array, don't want optimization tricks by the compiler. { rel_pre_erase, diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index 03a0470d79..6842e63caf 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -253,12 +253,12 @@ public: Lock* rel_gc_lock; // garbage collection lock IndexLock* rel_index_locks; // index existence locks IndexBlock* rel_index_blocks; // index blocks for caching index info - trig_vec* rel_pre_erase; // Pre-operation erase trigger - trig_vec* rel_post_erase; // Post-operation erase trigger - trig_vec* rel_pre_modify; // Pre-operation modify trigger - trig_vec* rel_post_modify; // Post-operation modify trigger - trig_vec* rel_pre_store; // Pre-operation store trigger - trig_vec* rel_post_store; // Post-operation store trigger + TrigVector* rel_pre_erase; // Pre-operation erase trigger + TrigVector* rel_post_erase; // Post-operation erase trigger + TrigVector* rel_pre_modify; // Pre-operation modify trigger + TrigVector* rel_post_modify; // Post-operation modify trigger + TrigVector* rel_pre_store; // Pre-operation store trigger + TrigVector* rel_post_store; // Post-operation store trigger prim rel_primary_dpnds; // foreign dependencies on this relation's primary key frgn rel_foreign_refs; // foreign references to other relations' primary keys Nullable rel_ss_definer; diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 3a8d1cc1a7..89bfee7074 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -499,13 +499,13 @@ static bool formatsAreEqual(const Format*, const Format*); static bool find_depend_in_dfw(thread_db*, TEXT*, USHORT, USHORT, jrd_tra*); static void get_array_desc(thread_db*, const TEXT*, Ods::InternalArrayDesc*); static void get_trigger_dependencies(DeferredWork*, bool, jrd_tra*); -static void load_trigs(thread_db*, jrd_rel*, trig_vec**); +static void load_trigs(thread_db*, jrd_rel*, TrigVector**); static Format* make_format(thread_db*, jrd_rel*, USHORT *, TemporaryField*); static void put_summary_blob(thread_db* tdbb, blb*, enum rsr_t, bid*, jrd_tra*); static void put_summary_record(thread_db* tdbb, blb*, enum rsr_t, const UCHAR*, USHORT); static void setup_array(thread_db*, blb*, const TEXT*, USHORT, TemporaryField*); -static blb* setup_triggers(thread_db*, jrd_rel*, bool, trig_vec**, blb*); -static void setup_trigger_details(thread_db*, jrd_rel*, blb*, trig_vec**, const TEXT*, bool); +static blb* setup_triggers(thread_db*, jrd_rel*, bool, TrigVector**, blb*); +static void setup_trigger_details(thread_db*, jrd_rel*, blb*, TrigVector**, const TEXT*, bool); static bool validate_text_type (thread_db*, const TemporaryField*); static void check_partners(thread_db*, const USHORT); @@ -5327,7 +5327,7 @@ static void get_trigger_dependencies(DeferredWork* work, bool compile, jrd_tra* } -static void load_trigs(thread_db* tdbb, jrd_rel* relation, trig_vec** triggers) +static void load_trigs(thread_db* tdbb, jrd_rel* relation, TrigVector** triggers) { /************************************** * @@ -5341,7 +5341,7 @@ static void load_trigs(thread_db* tdbb, jrd_rel* relation, trig_vec** triggers) * place ie the relation block. * **************************************/ - trig_vec* tmp_vector; + TrigVector* tmp_vector; tmp_vector = relation->rel_pre_store; relation->rel_pre_store = triggers[TRIGGER_PRE_STORE]; @@ -5572,7 +5572,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ int physical_fields = 0; bool external_flag = false; bool computed_field; - trig_vec* triggers[TRIGGER_MAX]; + TrigVector* triggers[TRIGGER_MAX]; SET_TDBB(tdbb); Jrd::Attachment* attachment = tdbb->getAttachment(); @@ -6040,7 +6040,7 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr relation->rel_flags &= ~REL_scanned; MET_scan_relation(tdbb, relation); - trig_vec* triggers[TRIGGER_MAX]; + TrigVector* triggers[TRIGGER_MAX]; for (int i = 0; i < TRIGGER_MAX; ++i) triggers[i] = NULL; @@ -6274,7 +6274,7 @@ static void setup_array(thread_db* tdbb, blb* blob, const TEXT* field_name, USHO static blb* setup_triggers(thread_db* tdbb, jrd_rel* relation, bool null_view, - trig_vec** triggers, blb* blob) + TrigVector** triggers, blb* blob) { /************************************** * @@ -6372,7 +6372,7 @@ static blb* setup_triggers(thread_db* tdbb, jrd_rel* relation, bool null_view, static void setup_trigger_details(thread_db* tdbb, jrd_rel* relation, blb* blob, - trig_vec** triggers, + TrigVector** triggers, const TEXT* trigger_name, bool null_view) { diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index faf09c1fac..8e21a40760 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -567,10 +567,10 @@ void EXE_execute_ddl_triggers(thread_db* tdbb, jrd_tra* transaction, bool preTri try { - trig_vec triggers; - trig_vec* triggersPtr = &triggers; + TrigVector triggers; + TrigVector* triggersPtr = &triggers; - for (trig_vec::iterator i = attachment->att_ddl_triggers->begin(); + for (TrigVector::iterator i = attachment->att_ddl_triggers->begin(); i != attachment->att_ddl_triggers->end(); ++i) { @@ -1033,7 +1033,7 @@ static void execute_looper(thread_db* tdbb, void EXE_execute_triggers(thread_db* tdbb, - trig_vec** triggers, + TrigVector** triggers, record_param* old_rpb, record_param* new_rpb, TriggerAction trigger_action, StmtNode::WhichTrigger which_trig) @@ -1057,7 +1057,7 @@ void EXE_execute_triggers(thread_db* tdbb, jrd_req* const request = tdbb->getRequest(); jrd_tra* const transaction = request ? request->req_transaction : tdbb->getTransaction(); - trig_vec* vector = *triggers; + TrigVector* vector = *triggers; Record* const old_rec = old_rpb ? old_rpb->rpb_record : NULL; Record* const new_rec = new_rpb ? new_rpb->rpb_record : NULL; @@ -1083,7 +1083,7 @@ void EXE_execute_triggers(thread_db* tdbb, try { - for (trig_vec::iterator ptr = vector->begin(); ptr != vector->end(); ++ptr) + for (TrigVector::iterator ptr = vector->begin(); ptr != vector->end(); ++ptr) { ptr->compile(tdbb); diff --git a/src/jrd/exe_proto.h b/src/jrd/exe_proto.h index f7e84ba9e4..2bc4ae301e 100644 --- a/src/jrd/exe_proto.h +++ b/src/jrd/exe_proto.h @@ -43,7 +43,7 @@ void EXE_execute_ddl_triggers(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, const Jrd::StmtNode* EXE_looper(Jrd::thread_db* tdbb, Jrd::jrd_req* request, const Jrd::StmtNode* in_node); -void EXE_execute_triggers(Jrd::thread_db*, Jrd::trig_vec**, Jrd::record_param*, Jrd::record_param*, +void EXE_execute_triggers(Jrd::thread_db*, Jrd::TrigVector**, Jrd::record_param*, Jrd::record_param*, enum TriggerAction, Jrd::StmtNode::WhichTrigger); void EXE_receive(Jrd::thread_db*, Jrd::jrd_req*, USHORT, ULONG, UCHAR*, bool = false); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 7b153a299a..bbb6d04a6b 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1861,7 +1861,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch // load DDL triggers MET_load_ddl_triggers(tdbb); - const trig_vec* trig_connect = attachment->att_triggers[DB_TRIGGER_CONNECT]; + const TrigVector* trig_connect = attachment->att_triggers[DB_TRIGGER_CONNECT]; if (trig_connect && !trig_connect->isEmpty()) { // Start a transaction to execute ON CONNECT triggers. @@ -6913,7 +6913,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign { try { - const trig_vec* const trig_disconnect = + const TrigVector* const trig_disconnect = attachment->att_triggers[DB_TRIGGER_DISCONNECT]; if (!forcedPurge && @@ -8075,3 +8075,29 @@ void JRD_cancel_operation(thread_db* /*tdbb*/, Jrd::Attachment* attachment, int fb_assert(false); } } + + +void TrigVector::release() const +{ + release(JRD_get_thread_data()); +} + + +void TrigVector::release(thread_db* tdbb) const +{ + if (--useCount == 0) + { + const const_iterator e = end(); + for (const_iterator t = begin(); t != e; ++t) + { + JrdStatement* stmt = t->statement; + if (stmt) + stmt->release(tdbb); + + delete t->extTrigger; + } + + delete this; + } +} + diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index ab7a39da2a..ddfcadfa95 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -135,8 +135,6 @@ class PreparedStatement; class TraceManager; class MessageNode; -// The database block, the topmost block in the metadata -// cache for a database // Relation trigger definition @@ -174,6 +172,39 @@ public: }; +// Array of triggers (suppose separate arrays for triggers of different types) + +class TrigVector : public Firebird::ObjectsArray +{ +public: + explicit TrigVector(Firebird::MemoryPool& pool) + : Firebird::ObjectsArray(pool), + useCount(0) + { } + + TrigVector() + : Firebird::ObjectsArray(), + useCount(0) + { } + + void addRef() const + { + ++useCount; + } + + void release() const; + void release(thread_db* tdbb) const; + + ~TrigVector() + { + fb_assert(useCount.value() == 0); + } + +private: + mutable Firebird::AtomicCounter useCount; +}; + + // // Flags to indicate normal internal requests vs. dyn internal requests // diff --git a/src/jrd/met.epp b/src/jrd/met.epp index c42c5790ab..743902f45e 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -113,7 +113,7 @@ static int blocking_ast_relation(void*); static int partners_ast_relation(void*); static int rescan_ast_relation(void*); static ULONG get_rel_flags_from_FLAGS(USHORT); -static void get_trigger(thread_db*, jrd_rel*, bid*, bid*, trig_vec**, const TEXT*, FB_UINT64, bool, +static void get_trigger(thread_db*, jrd_rel*, bid*, bid*, TrigVector**, const TEXT*, FB_UINT64, bool, USHORT, const MetaName&, const string&, const bid*, Nullable ssDefiner); static bool get_type(thread_db*, USHORT*, const UCHAR*, const TEXT*); static void lookup_view_contexts(thread_db*, jrd_rel*); @@ -121,7 +121,7 @@ static void make_relation_scope_name(const TEXT*, const USHORT, string& str); static ValueExprNode* parse_field_default_blr(thread_db* tdbb, bid* blob_id); static BoolExprNode* parse_field_validation_blr(thread_db* tdbb, bid* blob_id, const MetaName name); static bool resolve_charset_and_collation(thread_db*, USHORT*, const UCHAR*, const UCHAR*); -static void save_trigger_data(thread_db*, trig_vec**, jrd_rel*, JrdStatement*, blb*, blb*, +static void save_trigger_data(thread_db*, TrigVector**, jrd_rel*, JrdStatement*, blb*, blb*, const TEXT*, FB_UINT64, bool, USHORT, const MetaName&, const string&, const bid*, Nullable ssDefiner); static void scan_partners(thread_db*, jrd_rel*); @@ -131,7 +131,7 @@ static bool verify_TRG_ignore_perm(thread_db*, const MetaName&); // Decompile all triggers from vector -static void release_cached_triggers(thread_db* tdbb, trig_vec* vector) +static void release_cached_triggers(thread_db* tdbb, TrigVector* vector) { if (!vector) return; @@ -178,7 +178,7 @@ static void inc_int_use_count(JrdStatement* statement) // Increment int_use_count for all procedures used by triggers -static void post_used_procedures(trig_vec* vector) +static void post_used_procedures(TrigVector* vector) { if (!vector) return; @@ -1843,7 +1843,8 @@ void MET_load_db_triggers(thread_db* tdbb, int type) } attachment->att_triggers[type] = FB_NEW_POOL(*attachment->att_pool) - trig_vec(*attachment->att_pool); + TrigVector(*attachment->att_pool); + attachment->att_triggers[type]->addRef(); AutoRequest trigger_request; int encoded_type = type | TRIGGER_TYPE_DB; @@ -1876,7 +1877,7 @@ void MET_load_ddl_triggers(thread_db* tdbb) } attachment->att_ddl_triggers = FB_NEW_POOL(*attachment->att_pool) - trig_vec(*attachment->att_pool); + TrigVector(*attachment->att_pool); AutoRequest trigger_request; @@ -1899,7 +1900,7 @@ void MET_load_ddl_triggers(thread_db* tdbb) void MET_load_trigger(thread_db* tdbb, jrd_rel* relation, const MetaName& trigger_name, - trig_vec** triggers) + TrigVector** triggers) { /************************************** * @@ -3119,7 +3120,7 @@ void MET_parse_sys_trigger(thread_db* tdbb, jrd_rel* relation) const USHORT trig_flags = TRG.RDB$FLAGS; const TEXT* name = TRG.RDB$TRIGGER_NAME; - trig_vec** ptr; + TrigVector** ptr; switch (type) { @@ -3763,7 +3764,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) * **************************************/ SET_TDBB(tdbb); - trig_vec* triggers[TRIGGER_MAX]; + TrigVector* triggers[TRIGGER_MAX]; Attachment* attachment = tdbb->getAttachment(); Database* dbb = tdbb->getDatabase(); Jrd::ContextPoolHolder context(tdbb, attachment->att_pool); @@ -4065,7 +4066,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) // We have just loaded the triggers onto the local vector triggers. // Its now time to place them at their rightful place ie the relation block. - trig_vec* tmp_vector; + TrigVector* tmp_vector; tmp_vector = relation->rel_pre_store; relation->rel_pre_store = triggers[TRIGGER_PRE_STORE]; @@ -4458,7 +4459,7 @@ ULONG MET_get_rel_flags_from_TYPE(USHORT type) static void get_trigger(thread_db* tdbb, jrd_rel* relation, - bid* blob_id, bid* debug_blob_id, trig_vec** ptr, + bid* blob_id, bid* debug_blob_id, TrigVector** ptr, const TEXT* name, FB_UINT64 type, bool sys_trigger, USHORT flags, const MetaName& engine, const string& entryPoint, @@ -4653,7 +4654,7 @@ static BoolExprNode* parse_field_validation_blr(thread_db* tdbb, bid* blob_id, c } -void MET_release_trigger(thread_db* tdbb, trig_vec** vector_ptr, const MetaName& name) +void MET_release_trigger(thread_db* tdbb, TrigVector** vector_ptr, const MetaName& name) { /*********************************************** * @@ -4670,7 +4671,7 @@ void MET_release_trigger(thread_db* tdbb, trig_vec** vector_ptr, const MetaName& if (!*vector_ptr) return; - trig_vec& vector = **vector_ptr; + TrigVector& vector = **vector_ptr; SET_TDBB(tdbb); @@ -4692,7 +4693,7 @@ void MET_release_trigger(thread_db* tdbb, trig_vec** vector_ptr, const MetaName& } -void MET_release_triggers( thread_db* tdbb, trig_vec** vector_ptr) +void MET_release_triggers( thread_db* tdbb, TrigVector** vector_ptr) { /*********************************************** * @@ -4706,7 +4707,7 @@ void MET_release_triggers( thread_db* tdbb, trig_vec** vector_ptr) * else do the work. * **************************************/ - trig_vec* vector = *vector_ptr; + TrigVector* vector = *vector_ptr; if (!vector) return; @@ -4722,16 +4723,7 @@ void MET_release_triggers( thread_db* tdbb, trig_vec** vector_ptr) return; } - for (FB_SIZE_T i = 0; i < vector->getCount(); i++) - { - JrdStatement* stmt = (*vector)[i].statement; - if (stmt) - stmt->release(tdbb); - - delete (*vector)[i].extTrigger; - } - - delete vector; + vector->release(tdbb); } @@ -4848,7 +4840,7 @@ static bool resolve_charset_and_collation(thread_db* tdbb, } -static void save_trigger_data(thread_db* tdbb, trig_vec** ptr, jrd_rel* relation, +static void save_trigger_data(thread_db* tdbb, TrigVector** ptr, jrd_rel* relation, JrdStatement* statement, blb* blrBlob, blb* debugInfoBlob, const TEXT* name, FB_UINT64 type, bool sys_trigger, USHORT flags, @@ -4866,12 +4858,13 @@ static void save_trigger_data(thread_db* tdbb, trig_vec** ptr, jrd_rel* relation * **************************************/ Attachment* attachment = tdbb->getAttachment(); - trig_vec* vector = *ptr; + TrigVector* vector = *ptr; if (!vector) { MemoryPool* pool = relation ? relation->rel_pool : attachment->att_pool; - vector = FB_NEW_POOL(*pool) trig_vec(*pool); + vector = FB_NEW_POOL(*pool) TrigVector(*pool); + vector->addRef(); *ptr = vector; } @@ -4918,11 +4911,11 @@ static void save_trigger_data(thread_db* tdbb, trig_vec** ptr, jrd_rel* relation } -const Trigger* findTrigger(trig_vec* triggers, const MetaName& trig_name) +const Trigger* findTrigger(TrigVector* triggers, const MetaName& trig_name) { if (triggers) { - for (trig_vec::iterator t = triggers->begin(); t != triggers->end(); ++t) + for (TrigVector::iterator t = triggers->begin(); t != triggers->end(); ++t) { if (t->name.compare(trig_name) == 0) return &(*t); diff --git a/src/jrd/met_proto.h b/src/jrd/met_proto.h index fd8554a76d..44f9743565 100644 --- a/src/jrd/met_proto.h +++ b/src/jrd/met_proto.h @@ -94,7 +94,7 @@ void MET_get_shadow_files(Jrd::thread_db*, bool); void MET_load_db_triggers(Jrd::thread_db*, int); void MET_load_ddl_triggers(Jrd::thread_db* tdbb); bool MET_load_exception(Jrd::thread_db*, Jrd::ExceptionItem&); -void MET_load_trigger(Jrd::thread_db*, Jrd::jrd_rel*, const Firebird::MetaName&, Jrd::trig_vec**); +void MET_load_trigger(Jrd::thread_db*, Jrd::jrd_rel*, const Firebird::MetaName&, Jrd::TrigVector**); void MET_lookup_cnstrt_for_index(Jrd::thread_db*, Firebird::MetaName& constraint, const Firebird::MetaName& index_name); void MET_lookup_cnstrt_for_trigger(Jrd::thread_db*, Firebird::MetaName&, Firebird::MetaName&, const Firebird::MetaName&); void MET_lookup_exception(Jrd::thread_db*, SLONG, /* OUT */ Firebird::MetaName&, /* OUT */ Firebird::string*); @@ -120,8 +120,8 @@ void MET_prepare(Jrd::thread_db*, Jrd::jrd_tra*, USHORT, const UCHAR*); Jrd::jrd_prc* MET_procedure(Jrd::thread_db*, USHORT, bool, USHORT); Jrd::jrd_rel* MET_relation(Jrd::thread_db*, USHORT); void MET_release_existence(Jrd::thread_db*, Jrd::jrd_rel*); -void MET_release_trigger(Jrd::thread_db*, Jrd::trig_vec**, const Firebird::MetaName&); -void MET_release_triggers(Jrd::thread_db*, Jrd::trig_vec**); +void MET_release_trigger(Jrd::thread_db*, Jrd::TrigVector**, const Firebird::MetaName&); +void MET_release_triggers(Jrd::thread_db*, Jrd::TrigVector**); #ifdef DEV_BUILD void MET_verify_cache(Jrd::thread_db*); #endif From 239bda87aacfc7bae530a7e01d1130e21f212040 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Mon, 26 Dec 2016 00:02:27 +0000 Subject: [PATCH 039/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 4c5590d0fc..d053cd6fe1 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:470 + FORMAL BUILD NUMBER:472 */ -#define PRODUCT_VER_STRING "4.0.0.470" -#define FILE_VER_STRING "WI-T4.0.0.470" -#define LICENSE_VER_STRING "WI-T4.0.0.470" -#define FILE_VER_NUMBER 4, 0, 0, 470 +#define PRODUCT_VER_STRING "4.0.0.472" +#define FILE_VER_STRING "WI-T4.0.0.472" +#define LICENSE_VER_STRING "WI-T4.0.0.472" +#define FILE_VER_NUMBER 4, 0, 0, 472 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "470" +#define FB_BUILD_NO "472" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index d9a58b9089..653402ce64 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=470 +BuildNum=472 NowAt=`pwd` cd `dirname $0` From 94bdb099b5fb0d8a35e85605cff4c802e17b3378 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Tue, 27 Dec 2016 16:27:35 +0300 Subject: [PATCH 040/134] This should fix bug reported by Gabor: ./install.sh: 1570: [: /opt/firebird: unexpected operator --- builds/install/arch-specific/linux/linuxLibrary.sh.in | 2 +- builds/install/posix-common/posixLibrary.sh.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builds/install/arch-specific/linux/linuxLibrary.sh.in b/builds/install/arch-specific/linux/linuxLibrary.sh.in index c7b30663a1..f6eb020730 100644 --- a/builds/install/arch-specific/linux/linuxLibrary.sh.in +++ b/builds/install/arch-specific/linux/linuxLibrary.sh.in @@ -370,7 +370,7 @@ EOF chown root:root $initScript chmod u=rwx,g=rx,o=r $initScript - if [ "${fb_install_prefix}" == "${default_prefix}" ] + if [ "${fb_install_prefix}" = "${default_prefix}" ] then # RedHat and Mandrake specific if [ -x /sbin/chkconfig ] diff --git a/builds/install/posix-common/posixLibrary.sh.in b/builds/install/posix-common/posixLibrary.sh.in index d436585acd..c19aa79fd5 100644 --- a/builds/install/posix-common/posixLibrary.sh.in +++ b/builds/install/posix-common/posixLibrary.sh.in @@ -1175,7 +1175,7 @@ extractBuildroot() { # depending upon presence of startup script starts super or classic server startFirebird() { - if [ "${fb_install_prefix}" == "${default_prefix}" ] + if [ "${fb_install_prefix}" = "${default_prefix}" ] then if standaloneServerInstalled; then startService From 278c993915a2b6aaa69018212a4c211f0d357ef6 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Tue, 27 Dec 2016 14:51:27 -0200 Subject: [PATCH 041/134] Improvement CORE-5430 - Support for INCREMENT option in identity columns. --- CHANGELOG.md | 3 ++ .../README.identity_columns.txt | 10 ++++- lang_helpers/gds_codes.ftn | 2 + lang_helpers/gds_codes.pas | 2 + src/common/classes/Nullable.h | 5 +++ src/dsql/DdlNodes.epp | 39 +++++++++++++++--- src/dsql/DdlNodes.h | 17 ++++++-- src/dsql/ExprNodes.h | 2 +- src/dsql/StmtNodes.cpp | 12 ++---- src/dsql/parse.y | 41 +++++++++++++++---- src/include/gen/codetext.h | 1 + src/include/gen/iberror.h | 6 ++- src/include/gen/msgs.h | 1 + src/include/gen/sql_code.h | 1 + src/include/gen/sql_state.h | 1 + src/msgs/facilities2.sql | 2 +- src/msgs/messages2.sql | 1 + src/msgs/system_errors2.sql | 1 + 18 files changed, 115 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f983109aef..5a5f09e506 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ ## Improvements +* [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5430): Support for INCREMENT option in identity columns + Contributor(s): Adriano dos Santos Fernandes + * [CORE-5119](http://tracker.firebirdsql.org/browse/CORE-5119): Support autocommit mode in SET TRANSACTION statement Contributor(s): Dmitry Yemanov diff --git a/doc/sql.extensions/README.identity_columns.txt b/doc/sql.extensions/README.identity_columns.txt index 2da196909e..acf47a612b 100644 --- a/doc/sql.extensions/README.identity_columns.txt +++ b/doc/sql.extensions/README.identity_columns.txt @@ -11,10 +11,15 @@ Description: Syntax: ::= - GENERATED BY DEFAULT AS IDENTITY [ (START WITH ) ] + GENERATED BY DEFAULT AS IDENTITY [ ( ... ) ] + + ::= + START WITH | + INCREMENT [ BY ] ::= - RESTART [ WITH ] + RESTART [ WITH ] | + SET INCREMENT [ BY ] Syntax rules: - The type of an identity column must be an exact number type with zero scale. That includes: @@ -25,6 +30,7 @@ Notes: - You cannot alter a identity column to normal column and vice versa. - Identity columns are implicitly NOT NULL. - Identity columns don't enforce uniqueness automatically. Use UNIQUE or PRIMARY key for that. + - Increment value cannot be 0. Implementation: Two columns have been inserted in RDB$RELATION_FIELDS: RDB$GENERATOR_NAME and RDB$IDENTITY_TYPE. diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index 7631637f1d..b7419617f1 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -1948,6 +1948,8 @@ C -- PARAMETER (GDS__dyn_cant_use_in_foreignkey = 336068897) INTEGER*4 GDS__dyn_defvaldecl_package_func PARAMETER (GDS__dyn_defvaldecl_package_func = 336068898) + INTEGER*4 GDS__dyn_cant_use_zero_inc_ident + PARAMETER (GDS__dyn_cant_use_zero_inc_ident = 336068904) INTEGER*4 GDS__gbak_unknown_switch PARAMETER (GDS__gbak_unknown_switch = 336330753) INTEGER*4 GDS__gbak_page_size_missing diff --git a/lang_helpers/gds_codes.pas b/lang_helpers/gds_codes.pas index b480146947..f428092767 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -1943,6 +1943,8 @@ const gds_dyn_cant_use_in_foreignkey = 336068897; isc_dyn_defvaldecl_package_func = 336068898; gds_dyn_defvaldecl_package_func = 336068898; + isc_dyn_cant_use_zero_inc_ident = 336068904; + gds_dyn_cant_use_zero_inc_ident = 336068904; isc_gbak_unknown_switch = 336330753; gds_gbak_unknown_switch = 336330753; isc_gbak_page_size_missing = 336330754; diff --git a/src/common/classes/Nullable.h b/src/common/classes/Nullable.h index 8f8bf42969..54352ec980 100644 --- a/src/common/classes/Nullable.h +++ b/src/common/classes/Nullable.h @@ -60,6 +60,11 @@ public: return nullable; } + T orElse(T elseValue) const + { + return specified ? value : elseValue; + } + bool operator ==(const BaseNullable& o) const { return (!specified && !o.specified) || (specified == o.specified && value == o.value); diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 6a8fdcc6fb..7b1149c077 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -6279,6 +6279,13 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch if (clause->identity) { + if (clause->identity->increment.orElse(1) == 0) + { + status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) << + Arg::Str(field->fld_name) << + Arg::Str(name)); + } + dsc desc; MET_get_domain(tdbb, *tdbb->getDefaultPool(), fieldDefinition.fieldSource, &desc, NULL); @@ -6291,7 +6298,9 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence); CreateAlterSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence, - fb_sysflag_identity_generator, clause->identityStart, 1); + fb_sysflag_identity_generator, + clause->identity->start.orElse(0), + clause->identity->increment.orElse(1)); } BlrDebugWriter::BlrData defaultValue; @@ -7838,7 +7847,7 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc } END_MODIFY } - else if (clause->identityRestart) + else if (clause->identityRestart || clause->identityIncrement.specified) { bool found = false; AutoRequest request2; @@ -7849,11 +7858,29 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc { const SLONG id = GEN.RDB$GENERATOR_ID; const MetaName genName(RFR.RDB$GENERATOR_NAME); - const SINT64 val = clause->identityRestartValue.specified ? - clause->identityRestartValue.value : - (!GEN.RDB$INITIAL_VALUE.NULL ? GEN.RDB$INITIAL_VALUE : 0); - transaction->getGenIdCache()->put(id, val); + if (clause->identityRestart) + { + const SINT64 val = clause->identityRestartValue.specified ? + clause->identityRestartValue.value : + (!GEN.RDB$INITIAL_VALUE.NULL ? GEN.RDB$INITIAL_VALUE : 0); + + transaction->getGenIdCache()->put(id, val); + } + else if (clause->identityIncrement.specified) + { + if (clause->identityIncrement.value == 0) + { + status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) << + Arg::Str(field->fld_name) << + Arg::Str(name)); + } + + MET_update_generator_increment(tdbb, id, clause->identityIncrement.value); + } + else + fb_assert(false); + dsc desc; desc.makeText((USHORT) genName.length(), ttype_metadata, (UCHAR*) genName.c_str()); diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 1af1e4471f..8c688f2e59 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1304,6 +1304,16 @@ public: NestConst check; }; + struct IdentityOptions + { + IdentityOptions(MemoryPool&) + { + } + + Nullable start; + Nullable increment; + }; + struct AddColumnClause : public Clause { explicit AddColumnClause(MemoryPool& p) @@ -1313,8 +1323,7 @@ public: constraints(p), collate(p), computed(NULL), - identity(false), - identityStart(0), + identity(NULL), notNullSpecified(false) { } @@ -1324,8 +1333,7 @@ public: Firebird::ObjectsArray constraints; Firebird::MetaName collate; NestConst computed; - bool identity; - SINT64 identityStart; + NestConst identity; bool notNullSpecified; }; @@ -1385,6 +1393,7 @@ public: bool dropDefault; bool identityRestart; Nullable identityRestartValue; + Nullable identityIncrement; NestConst computed; }; diff --git a/src/dsql/ExprNodes.h b/src/dsql/ExprNodes.h index a557aa54da..a9d475ac96 100644 --- a/src/dsql/ExprNodes.h +++ b/src/dsql/ExprNodes.h @@ -698,9 +698,9 @@ public: const bool dialect1; GeneratorItem generator; NestConst arg; + SLONG step; private: - SLONG step; bool sysGen; const bool implicit; const bool identity; diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 9d4b05db44..168f417e4e 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -6839,17 +6839,13 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb) if (generatorName.hasData()) { - // Make a gen_id(, 1) expression. + // Make a (next value for ) expression. - LiteralNode* literal = FB_NEW_POOL(csb->csb_pool) LiteralNode(csb->csb_pool); - SLONG* increment = FB_NEW_POOL(csb->csb_pool) SLONG(1); - literal->litDesc.makeLong(0, increment); - - GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool) - GenIdNode(csb->csb_pool, (csb->blrVersion == 4), generatorName, literal, false, true); + GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool) GenIdNode( + csb->csb_pool, (csb->blrVersion == 4), generatorName, NULL, true, true); bool sysGen = false; - if (!MET_load_generator(tdbb, genNode->generator, &sysGen)) + if (!MET_load_generator(tdbb, genNode->generator, &sysGen, &genNode->step)) PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(generatorName)); if (sysGen) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index c3582b3580..1bed23b666 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -722,6 +722,7 @@ using namespace Firebird; Jrd::RelationNode::AddColumnClause* addColumnClause; Jrd::RelationNode::RefActionClause* refActionClause; Jrd::RelationNode::IndexConstraintClause* indexConstraintClause; + Jrd::RelationNode::IdentityOptions* identityOptions; Jrd::CreateRelationNode* createRelationNode; Jrd::CreateAlterViewNode* createAlterViewNode; Jrd::CreateIndexNode* createIndexNode; @@ -2148,8 +2149,7 @@ column_def($relationNode) newNode(); clause->field = $2; clause->field->fld_name = *$1; - clause->identity = true; - clause->identityStart = $3; + clause->identity = $3; $relationNode->clauses.add(clause); } column_constraint_clause(NOTRIAL($4)) collate_clause @@ -2177,15 +2177,32 @@ column_def($relationNode) } ; -%type identity_clause +%type identity_clause identity_clause - : GENERATED BY DEFAULT AS IDENTITY identity_clause_options { $$ = $6; } + : GENERATED BY DEFAULT AS IDENTITY + { $$ = newNode(); } + identity_clause_options_opt($6) + { $$ = $6; } ; -%type identity_clause_options -identity_clause_options - : /* nothing */ { $$ = 0; } - | '(' START WITH sequence_value ')' { $$ = $4; } +%type identity_clause_options_opt() +identity_clause_options_opt($identityOptions) + : // nothing + | '(' identity_clause_options($identityOptions) ')' + ; + +%type identity_clause_options() +identity_clause_options($identityOptions) + : identity_clause_options identity_clause_option($identityOptions) + | identity_clause_option($identityOptions) + ; + +%type identity_clause_option() +identity_clause_option($identityOptions) + : START WITH sequence_value + { setClause($identityOptions->start, "START WITH", $3); } + | INCREMENT by_noise signed_long_integer + { setClause($identityOptions->increment, "INCREMENT BY", $3); } ; // value does allow parens around it, but there is a problem getting the source text. @@ -3919,6 +3936,14 @@ alter_op($relationNode) clause->identityRestartValue = $4; $relationNode->clauses.add(clause); } + | col_opt symbol_column_name SET INCREMENT by_noise signed_long_integer + { + RelationNode::AlterColTypeClause* clause = newNode(); + clause->field = newNode(); + clause->field->fld_name = *$2; + clause->identityIncrement = $6; + $relationNode->clauses.add(clause); + } | ALTER SQL SECURITY DEFINER { RelationNode::AlterSqlSecurityClause* clause = diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index e0e29ea127..40409fd74d 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -970,6 +970,7 @@ static const struct { {"dyn_cant_use_zero_increment", 336068896}, {"dyn_cant_use_in_foreignkey", 336068897}, {"dyn_defvaldecl_package_func", 336068898}, + {"dyn_cant_use_zero_inc_ident", 336068904}, {"gbak_unknown_switch", 336330753}, {"gbak_page_size_missing", 336330754}, {"gbak_page_size_toobig", 336330755}, diff --git a/src/include/gen/iberror.h b/src/include/gen/iberror.h index d5bb90172e..6ecd4913a3 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -1004,6 +1004,7 @@ const ISC_STATUS isc_dyn_cant_modify_sysobj = 336068895L; const ISC_STATUS isc_dyn_cant_use_zero_increment = 336068896L; const ISC_STATUS isc_dyn_cant_use_in_foreignkey = 336068897L; const ISC_STATUS isc_dyn_defvaldecl_package_func = 336068898L; +const ISC_STATUS isc_dyn_cant_use_zero_inc_ident = 336068904L; const ISC_STATUS isc_gbak_unknown_switch = 336330753L; const ISC_STATUS isc_gbak_page_size_missing = 336330754L; const ISC_STATUS isc_gbak_page_size_toobig = 336330755L; @@ -1334,7 +1335,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 = 1278; +const ISC_STATUS isc_err_max = 1279; #else /* c definitions */ @@ -2308,6 +2309,7 @@ const ISC_STATUS isc_err_max = 1278; #define isc_dyn_cant_use_zero_increment 336068896L #define isc_dyn_cant_use_in_foreignkey 336068897L #define isc_dyn_defvaldecl_package_func 336068898L +#define isc_dyn_cant_use_zero_inc_ident 336068904L #define isc_gbak_unknown_switch 336330753L #define isc_gbak_page_size_missing 336330754L #define isc_gbak_page_size_toobig 336330755L @@ -2638,7 +2640,7 @@ const ISC_STATUS isc_err_max = 1278; #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 1278 +#define isc_err_max 1279 #endif diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index ceef2f5836..d11466ac8c 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -973,6 +973,7 @@ Data source : @4"}, /* eds_statement */ {336068896, "INCREMENT BY 0 is an illegal option for sequence @1"}, /* dyn_cant_use_zero_increment */ {336068897, "Can't use @1 in FOREIGN KEY constraint"}, /* dyn_cant_use_in_foreignkey */ {336068898, "Default values for parameters are allowed only in declaration of packaged function @1.@2"}, /* dyn_defvaldecl_package_func */ + {336068904, "INCREMENT BY 0 is an illegal option for identity column @1 of table @2"}, /* dyn_cant_use_zero_inc_ident */ {336330753, "found unknown switch"}, /* gbak_unknown_switch */ {336330754, "page size parameter missing"}, /* gbak_page_size_missing */ {336330755, "Page size specified (@1) greater than limit (32768 bytes)"}, /* gbak_page_size_toobig */ diff --git a/src/include/gen/sql_code.h b/src/include/gen/sql_code.h index 0312e0baf9..ba0b149e91 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -969,6 +969,7 @@ static const struct { {336068896, -901}, /* 288 dyn_cant_use_zero_increment */ {336068897, -901}, /* 289 dyn_cant_use_in_foreignkey */ {336068898, -901}, /* 290 dyn_defvaldecl_package_func */ + {336068904, -901}, /* 296 dyn_cant_use_zero_inc_ident */ {336330753, -901}, /* 1 gbak_unknown_switch */ {336330754, -901}, /* 2 gbak_page_size_missing */ {336330755, -901}, /* 3 gbak_page_size_toobig */ diff --git a/src/include/gen/sql_state.h b/src/include/gen/sql_state.h index 43930d4119..4436c83cdf 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -969,6 +969,7 @@ static const struct { {336068896, "42000"}, // 288 dyn_cant_use_zero_increment {336068897, "42000"}, // 289 dyn_cant_use_in_foreignkey {336068898, "42000"}, // 290 dyn_defvaldecl_package_func + {336068904, "42000"}, // 296 dyn_cant_use_zero_inc_ident {336330753, "00000"}, // 1 gbak_unknown_switch {336330754, "00000"}, // 2 gbak_page_size_missing {336330755, "00000"}, // 3 gbak_page_size_toobig diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index 4c324e99bb..45406dd5d2 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -6,7 +6,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM ('2015-01-07 18:01:51', 'GFIX', 3, 134) ('1996-11-07 13:39:40', 'GPRE', 4, 1) ('2016-02-23 00:00:00', 'DSQL', 7, 40) -('2016-05-30 17:56:47', 'DYN', 8, 296) +('2016-12-27 12:30:00', 'DYN', 8, 297) ('1996-11-07 13:39:40', 'INSTALL', 10, 1) ('1996-11-07 13:38:41', 'TEST', 11, 4) ('2015-07-23 14:20:00', 'GBAK', 12, 370) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index 7551bed3fc..e5a6051a1e 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -1992,6 +1992,7 @@ COMMIT WORK; (NULL, 'CreateAlterRoleNode::execute', 'DdlNodes.epp', NULL, 8, 293, NULL, 'DROP SYSTEM PRIVILEGES should not be used in CREATE ROLE operator', NULL, NULL); (NULL, 'CreateAlterRoleNode::execute', 'DdlNodes.epp', NULL, 8, 294, NULL, 'Access to SYSTEM PRIVILEGES in ROLES denied to @1', NULL, NULL); (NULL, 'grant/revoke', 'DdlNode.epp', NULL, 8, 295, NULL, 'Only @1, DB owner @2 or user with privilege USE_GRANTED_BY_CLAUSE can use GRANTED BY clause', NULL, NULL); +('dyn_cant_use_zero_inc_ident', NULL, 'DdlNodes.epp', NULL, 8, 296, NULL, 'INCREMENT BY 0 is an illegal option for identity column @1 of table @2', NULL, NULL); COMMIT WORK; -- TEST (NULL, 'main', 'test.c', NULL, 11, 0, NULL, 'This is a modified text message', NULL, NULL); diff --git a/src/msgs/system_errors2.sql b/src/msgs/system_errors2.sql index 9553c7a4c4..0be14bbbf8 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -958,6 +958,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-901, '42', '000', 8, 288, 'dyn_cant_use_zero_increment', NULL, NULL) (-901, '42', '000', 8, 289, 'dyn_cant_use_in_foreignkey', NULL, NULL) (-901, '42', '000', 8, 290, 'dyn_defvaldecl_package_func', NULL, NULL) +(-901, '42', '000', 8, 296, 'dyn_cant_use_zero_inc_ident', NULL, NULL) -- GBAK (-901, '00', '000', 12, 1, 'gbak_unknown_switch', NULL, NULL) (-901, '00', '000', 12, 2, 'gbak_page_size_missing', NULL, NULL) From 4c5e36f3d731500f72449f7e8c0d17ce90b017c5 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Wed, 28 Dec 2016 00:02:23 +0000 Subject: [PATCH 042/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index d053cd6fe1..2b640fcb1e 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:472 + FORMAL BUILD NUMBER:474 */ -#define PRODUCT_VER_STRING "4.0.0.472" -#define FILE_VER_STRING "WI-T4.0.0.472" -#define LICENSE_VER_STRING "WI-T4.0.0.472" -#define FILE_VER_NUMBER 4, 0, 0, 472 +#define PRODUCT_VER_STRING "4.0.0.474" +#define FILE_VER_STRING "WI-T4.0.0.474" +#define LICENSE_VER_STRING "WI-T4.0.0.474" +#define FILE_VER_NUMBER 4, 0, 0, 474 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "472" +#define FB_BUILD_NO "474" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 653402ce64..1dfaeb92af 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=472 +BuildNum=474 NowAt=`pwd` cd `dirname $0` From 9fd55f7660f846b72588d90121e261dd298f0384 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Wed, 28 Dec 2016 11:14:00 +0300 Subject: [PATCH 043/134] Fixed CORE-5425: Server hangs under load test --- src/yvalve/PluginManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yvalve/PluginManager.cpp b/src/yvalve/PluginManager.cpp index d8b6e8da9d..7cf73764ca 100644 --- a/src/yvalve/PluginManager.cpp +++ b/src/yvalve/PluginManager.cpp @@ -1094,8 +1094,6 @@ IPluginSet* PluginManager::getPlugins(CheckStatusWrapper* status, unsigned int i void PluginManager::releasePlugin(IPluginBase* plugin) { - MutexLockGuard g(plugins->mutex, FB_FUNCTION); - IReferenceCounted* parent = plugin->getOwner(); if (plugin->release() == 0) @@ -1103,6 +1101,8 @@ void PluginManager::releasePlugin(IPluginBase* plugin) ///fb_assert(parent); if (parent) { + MutexLockGuard g(plugins->mutex, FB_FUNCTION); + parent->release(); if (plugins->wakeIt) { From 127dddfe743daaa84242a2a19aa8784a9bc3c11e Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Wed, 28 Dec 2016 12:57:47 -0200 Subject: [PATCH 044/134] Improvement CORE-5431 - Support for DROP IDENTITY clause. --- CHANGELOG.md | 3 +++ doc/sql.extensions/README.identity_columns.txt | 9 ++++++++- src/dsql/DdlNodes.epp | 15 +++++++++++++++ src/dsql/DdlNodes.h | 2 ++ src/dsql/parse.y | 8 ++++++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a5f09e506..ebb5776428 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ ## Improvements +* [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5431): Support for DROP IDENTITY clause + Contributor(s): Adriano dos Santos Fernandes + * [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5430): Support for INCREMENT option in identity columns Contributor(s): Adriano dos Santos Fernandes diff --git a/doc/sql.extensions/README.identity_columns.txt b/doc/sql.extensions/README.identity_columns.txt index acf47a612b..5e97b5d405 100644 --- a/doc/sql.extensions/README.identity_columns.txt +++ b/doc/sql.extensions/README.identity_columns.txt @@ -19,7 +19,8 @@ Syntax: ::= RESTART [ WITH ] | - SET INCREMENT [ BY ] + SET INCREMENT [ BY ] | + DROP IDENTITY Syntax rules: - The type of an identity column must be an exact number type with zero scale. That includes: @@ -74,3 +75,9 @@ select * from objects order by id; 2 Book 10 Computer 15 Pencil + +alter table objects + alter id set increment by 2; + +alter table objects + alter id drop identity; diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 7b1149c077..83740b621b 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -7847,6 +7847,21 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc } END_MODIFY } + else if (clause->dropIdentity) + { + if (RFR.RDB$GENERATOR_NAME.NULL) + { + // msg 285: "Column @1 is not an identity column" + status_exception::raise(Arg::PrivateDyn(285) << field->fld_name); + } + + DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME); + + MODIFY RFR + RFR.RDB$GENERATOR_NAME.NULL = TRUE; + RFR.RDB$IDENTITY_TYPE.NULL = TRUE; + END_MODIFY + } else if (clause->identityRestart || clause->identityIncrement.specified) { bool found = false; diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 8c688f2e59..2604a6765f 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1383,6 +1383,7 @@ public: field(NULL), defaultValue(NULL), dropDefault(false), + dropIdentity(false), identityRestart(false), computed(NULL) { @@ -1391,6 +1392,7 @@ public: dsql_fld* field; NestConst defaultValue; bool dropDefault; + bool dropIdentity; bool identityRestart; Nullable identityRestartValue; Nullable identityIncrement; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 1bed23b666..cc97817454 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -3944,6 +3944,14 @@ alter_op($relationNode) clause->identityIncrement = $6; $relationNode->clauses.add(clause); } + | col_opt symbol_column_name DROP IDENTITY + { + RelationNode::AlterColTypeClause* clause = newNode(); + clause->field = newNode(); + clause->field->fld_name = *$2; + clause->dropIdentity = true; + $relationNode->clauses.add(clause); + } | ALTER SQL SECURITY DEFINER { RelationNode::AlterSqlSecurityClause* clause = From f51791b181460d30a2d83490c61f5bcbabc940ea Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Wed, 28 Dec 2016 12:59:56 -0200 Subject: [PATCH 045/134] Correction. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebb5776428..859af6e7a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ ## Improvements -* [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5431): Support for DROP IDENTITY clause +* [CORE-5431](http://tracker.firebirdsql.org/browse/CORE-5431): Support for DROP IDENTITY clause Contributor(s): Adriano dos Santos Fernandes * [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5430): Support for INCREMENT option in identity columns From 15b17efeaa9130540fdeb6bef807725f71c056d4 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Thu, 29 Dec 2016 00:02:24 +0000 Subject: [PATCH 046/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 2b640fcb1e..9b6373f929 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:474 + FORMAL BUILD NUMBER:477 */ -#define PRODUCT_VER_STRING "4.0.0.474" -#define FILE_VER_STRING "WI-T4.0.0.474" -#define LICENSE_VER_STRING "WI-T4.0.0.474" -#define FILE_VER_NUMBER 4, 0, 0, 474 +#define PRODUCT_VER_STRING "4.0.0.477" +#define FILE_VER_STRING "WI-T4.0.0.477" +#define LICENSE_VER_STRING "WI-T4.0.0.477" +#define FILE_VER_NUMBER 4, 0, 0, 477 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "474" +#define FB_BUILD_NO "477" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 1dfaeb92af..b9086402a6 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=474 +BuildNum=477 NowAt=`pwd` cd `dirname $0` From 34c2b613b863a5268f218d0e973658b0d98fd0e1 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 29 Dec 2016 18:16:17 +0300 Subject: [PATCH 047/134] Update the docs. --- CHANGELOG.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 859af6e7a4..4a65a677ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Bugfixes +* [CORE-5408](http://tracker.firebirdsql.org/browse/CORE-5408): Result of boolean expression can not be concatenated with string literal + Contributor(s): Adriano dos Santos Fernandes + * [CORE-5237](http://tracker.firebirdsql.org/browse/CORE-5237): Invalid handling of dot (.) and asterisk (*) in config file name and path for include clause Contributor(s): Dimitry Sibiryakov @@ -37,23 +40,35 @@ * [CORE-2557](http://tracker.firebirdsql.org/browse/CORE-2557): Grants on MON$ tables Contributor(s): Alex Peshkoff +* [CORE-2216](http://tracker.firebirdsql.org/browse/CORE-2216): NBackup as online dump + Contributor(s): Roman Simakov, Vlad Khorsun + * [CORE-2192](http://tracker.firebirdsql.org/browse/CORE-2192): Extend maximum database page size to 32KB Contributor(s): Dmitry Yemanov +* [CORE-2040](http://tracker.firebirdsql.org/browse/CORE-2040): Allow exception name and possibly exception text to be determined within a "WHEN ANY" error handling block + Contributor(s): Dmitry Yemanov + +* [CORE-1132](http://tracker.firebirdsql.org/browse/CORE-1132): Exception context in PSQL exception handlers + Contributor(s): Dmitry Yemanov + * [CORE-749](http://tracker.firebirdsql.org/browse/CORE-749): Increase maximum length of object names to 63 characters Contributor(s): Adriano dos Santos Fernandes ## New features -* [CORE-5346](http://tracker.firebirdsql.org/browse/CORE-5346): Named windows +* [CORE-5346](http://tracker.firebirdsql.org/browse/CORE-5346): Named windows Contributor(s): Adriano dos Santos Fernandes * [CORE-5343](http://tracker.firebirdsql.org/browse/CORE-5343): Allow particular DBA privileges to be transferred to regular users Contributor(s): Alex Peshkoff -* [CORE-3647](http://tracker.firebirdsql.org/browse/CORE-3647): Frames for window functions +* [CORE-3647](http://tracker.firebirdsql.org/browse/CORE-3647): Frames for window functions Contributor(s): Adriano dos Santos Fernandes +* [CORE-2990](http://tracker.firebirdsql.org/browse/CORE-2990): Physical (page-level) standby replication / page shipping + Contributor(s): Roman Simakov, Vlad Khorsun + * [CORE-2762](http://tracker.firebirdsql.org/browse/CORE-2762): New built-in function to check whether some role is implicitly active Contributor(s): Roman Simakov From 74bfb8f90fc3fafe6c339b7bf90697be5a4b299c Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 30 Dec 2016 00:02:25 +0000 Subject: [PATCH 048/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 9b6373f929..1120671bb1 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:477 + FORMAL BUILD NUMBER:478 */ -#define PRODUCT_VER_STRING "4.0.0.477" -#define FILE_VER_STRING "WI-T4.0.0.477" -#define LICENSE_VER_STRING "WI-T4.0.0.477" -#define FILE_VER_NUMBER 4, 0, 0, 477 +#define PRODUCT_VER_STRING "4.0.0.478" +#define FILE_VER_STRING "WI-T4.0.0.478" +#define LICENSE_VER_STRING "WI-T4.0.0.478" +#define FILE_VER_NUMBER 4, 0, 0, 478 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "477" +#define FB_BUILD_NO "478" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index b9086402a6..2e76ca1268 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=477 +BuildNum=478 NowAt=`pwd` cd `dirname $0` From efc155f4b34cd8412449018d2a8180648ca3b4c4 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Fri, 30 Dec 2016 13:55:34 -0200 Subject: [PATCH 049/134] Allow to set more than one ALTER identity option in the same command - CORE-5430. --- .../README.identity_columns.txt | 7 ++- src/dsql/DdlNodes.epp | 29 ++++++----- src/dsql/DdlNodes.h | 14 +++--- src/dsql/parse-conflicts.txt | 2 +- src/dsql/parse.y | 48 +++++++++++-------- 5 files changed, 56 insertions(+), 44 deletions(-) diff --git a/doc/sql.extensions/README.identity_columns.txt b/doc/sql.extensions/README.identity_columns.txt index 5e97b5d405..5c5970ef8c 100644 --- a/doc/sql.extensions/README.identity_columns.txt +++ b/doc/sql.extensions/README.identity_columns.txt @@ -18,10 +18,13 @@ Syntax: INCREMENT [ BY ] ::= - RESTART [ WITH ] | - SET INCREMENT [ BY ] | + ... | DROP IDENTITY + ::= + RESTART [ WITH ] | + SET INCREMENT [ BY ] + Syntax rules: - The type of an identity column must be an exact number type with zero scale. That includes: smallint, integer, bigint, numeric(x, 0) and decimal(x, 0). diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 83740b621b..a701117574 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -6214,7 +6214,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch ObjectsArray constraints; bool notNullFlag = false; - if (clause->identity) + if (clause->identityOptions) notNullFlag = true; // identity columns are implicitly not null for (ObjectsArray::iterator ptr = clause->constraints.begin(); @@ -6277,9 +6277,9 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch if (clause->collate.hasData()) DDL_resolve_intl_type(dsqlScratch, field, clause->collate); - if (clause->identity) + if (clause->identityOptions) { - if (clause->identity->increment.orElse(1) == 0) + if (clause->identityOptions->increment.orElse(1) == 0) { status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) << Arg::Str(field->fld_name) << @@ -6299,8 +6299,8 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch CreateAlterSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence, fb_sysflag_identity_generator, - clause->identity->start.orElse(0), - clause->identity->increment.orElse(1)); + clause->identityOptions->startValue.orElse(0), + clause->identityOptions->increment.orElse(1)); } BlrDebugWriter::BlrData defaultValue; @@ -7862,7 +7862,7 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc RFR.RDB$IDENTITY_TYPE.NULL = TRUE; END_MODIFY } - else if (clause->identityRestart || clause->identityIncrement.specified) + else if (clause->identityOptions) { bool found = false; AutoRequest request2; @@ -7874,27 +7874,26 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc const SLONG id = GEN.RDB$GENERATOR_ID; const MetaName genName(RFR.RDB$GENERATOR_NAME); - if (clause->identityRestart) + if (clause->identityOptions->restart) { - const SINT64 val = clause->identityRestartValue.specified ? - clause->identityRestartValue.value : - (!GEN.RDB$INITIAL_VALUE.NULL ? GEN.RDB$INITIAL_VALUE : 0); + const SINT64 val = clause->identityOptions->startValue + .orElse(!GEN.RDB$INITIAL_VALUE.NULL ? GEN.RDB$INITIAL_VALUE : 0); transaction->getGenIdCache()->put(id, val); } - else if (clause->identityIncrement.specified) + + if (clause->identityOptions->increment.specified) { - if (clause->identityIncrement.value == 0) + if (clause->identityOptions->increment.value == 0) { status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) << Arg::Str(field->fld_name) << Arg::Str(name)); } - MET_update_generator_increment(tdbb, id, clause->identityIncrement.value); + MET_update_generator_increment(tdbb, id, + clause->identityOptions->increment.value); } - else - fb_assert(false); dsc desc; desc.makeText((USHORT) genName.length(), ttype_metadata, diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 2604a6765f..a46b7b6db7 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1307,11 +1307,13 @@ public: struct IdentityOptions { IdentityOptions(MemoryPool&) + : restart(false) { } - Nullable start; + Nullable startValue; Nullable increment; + bool restart; // used in ALTER }; struct AddColumnClause : public Clause @@ -1323,7 +1325,7 @@ public: constraints(p), collate(p), computed(NULL), - identity(NULL), + identityOptions(NULL), notNullSpecified(false) { } @@ -1333,7 +1335,7 @@ public: Firebird::ObjectsArray constraints; Firebird::MetaName collate; NestConst computed; - NestConst identity; + NestConst identityOptions; bool notNullSpecified; }; @@ -1384,7 +1386,7 @@ public: defaultValue(NULL), dropDefault(false), dropIdentity(false), - identityRestart(false), + identityOptions(NULL), computed(NULL) { } @@ -1393,9 +1395,7 @@ public: NestConst defaultValue; bool dropDefault; bool dropIdentity; - bool identityRestart; - Nullable identityRestartValue; - Nullable identityIncrement; + NestConst identityOptions; NestConst computed; }; diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index b0587cd258..20cc527f2d 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -44 shift/reduce conflicts, 17 reduce/reduce conflicts. +45 shift/reduce conflicts, 17 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index cc97817454..491d0a9805 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2149,7 +2149,7 @@ column_def($relationNode) newNode(); clause->field = $2; clause->field->fld_name = *$1; - clause->identity = $3; + clause->identityOptions = $3; $relationNode->clauses.add(clause); } column_constraint_clause(NOTRIAL($4)) collate_clause @@ -2200,7 +2200,7 @@ identity_clause_options($identityOptions) %type identity_clause_option() identity_clause_option($identityOptions) : START WITH sequence_value - { setClause($identityOptions->start, "START WITH", $3); } + { setClause($identityOptions->startValue, "START WITH", $3); } | INCREMENT by_noise signed_long_integer { setClause($identityOptions->increment, "INCREMENT BY", $3); } ; @@ -3927,23 +3927,16 @@ alter_op($relationNode) clause->dropDefault = true; $relationNode->clauses.add(clause); } - | col_opt symbol_column_name RESTART with_opt - { - RelationNode::AlterColTypeClause* clause = newNode(); - clause->field = newNode(); - clause->field->fld_name = *$2; - clause->identityRestart = true; - clause->identityRestartValue = $4; - $relationNode->clauses.add(clause); - } - | col_opt symbol_column_name SET INCREMENT by_noise signed_long_integer - { - RelationNode::AlterColTypeClause* clause = newNode(); - clause->field = newNode(); - clause->field->fld_name = *$2; - clause->identityIncrement = $6; - $relationNode->clauses.add(clause); - } + | col_opt symbol_column_name + { $$ = newNode(); } + alter_identity_clause_options($3) + { + RelationNode::AlterColTypeClause* clause = newNode(); + clause->field = newNode(); + clause->field->fld_name = *$2; + clause->identityOptions = $3; + $relationNode->clauses.add(clause); + } | col_opt symbol_column_name DROP IDENTITY { RelationNode::AlterColTypeClause* clause = newNode(); @@ -4082,6 +4075,23 @@ alter_data_type_or_domain } ; +%type alter_identity_clause_options() +alter_identity_clause_options($identityOptions) + : alter_identity_clause_options alter_identity_clause_option($identityOptions) + | alter_identity_clause_option($identityOptions) + ; + +%type alter_identity_clause_option() +alter_identity_clause_option($identityOptions) + : RESTART with_opt + { + setClause($identityOptions->restart, "RESTART"); + $identityOptions->startValue = $2; + } + | SET INCREMENT by_noise signed_long_integer + { setClause($identityOptions->increment, "SET INCREMENT BY", $4); } + ; + %type drop_behaviour drop_behaviour : { $$ = false; } From dbc73bff069d44cc3b9dfea63002f57e3d9e3407 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Fri, 30 Dec 2016 19:17:58 +0300 Subject: [PATCH 050/134] Restored security checks related to CHANGE_HEADER_SETTINGS privilege during attachment initialization --- src/jrd/jrd.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index bbb6d04a6b..32082d0a18 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1509,19 +1509,10 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch if (options.dpb_set_page_buffers) { - // Here we do not let anyone except SYSDBA (like DBO) to change dbb_page_buffers, - // cause other flags is UserId can be set only when DB is opened. - // No idea how to test for other cases before init is complete. - // - // ATTN! dimitr 14-DEC-2016 - // We cannot call locksmith() here anymore because it queries the database - // which is not initialized at this point yet. I'd suggest to initialize the cache - // with the default settings and call CCH_expand() later if dpb_set_page_buffers - // is specified. - // - // if ((config->getServerMode() != MODE_SUPER) || userId.locksmith(tdbb, CHANGE_HEADER_SETTINGS)) - if (config->getServerMode() != MODE_SUPER) - dbb->dbb_page_buffers = options.dpb_page_buffers; + // In a case when we need to preset cache size set it first to minimum value. + // We will check access rights and call CCH_expand() later when database is initialized. + + dbb->dbb_page_buffers = MIN_PAGE_BUFFERS; } options.setBuffers(dbb->dbb_config); @@ -1799,6 +1790,8 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch if (dbb->dbb_flags & DBB_shared) validateAccess(tdbb, attachment, CHANGE_HEADER_SETTINGS); + CCH_expand(tdbb, options.dpb_page_buffers); + if (attachment->locksmith(tdbb, CHANGE_HEADER_SETTINGS)) { PAG_set_page_buffers(tdbb, options.dpb_page_buffers); From 5e70385a162e3978ea22fdf83d42850460744357 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Fri, 30 Dec 2016 19:28:37 +0300 Subject: [PATCH 051/134] Fixed CORE-5433: Minor performance optimization - avoid additional database attachment from security objects mapping code --- src/jrd/Attachment.cpp | 17 ++++++--- src/jrd/Attachment.h | 57 +++++++++++++++--------------- src/jrd/ExtEngineManager.cpp | 2 +- src/jrd/Mapping.cpp | 10 ++++++ src/jrd/Monitoring.cpp | 11 +++--- src/jrd/SysFunction.cpp | 7 ++-- src/jrd/UserManagement.cpp | 6 ++-- src/jrd/extds/ExtDS.cpp | 2 +- src/jrd/extds/InternalDS.cpp | 6 ++-- src/jrd/extds/ValidatePassword.cpp | 2 ++ src/jrd/jrd.cpp | 56 ++++++++++++++++++----------- src/jrd/scl.epp | 4 ++- src/jrd/shut.cpp | 6 ++-- src/jrd/tra.cpp | 5 +-- src/jrd/vio.cpp | 29 +++++++++------ 15 files changed, 135 insertions(+), 85 deletions(-) diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index c97f56704c..cde65cd20f 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -724,12 +724,19 @@ void AttachmentsRefHolder::debugHelper(const char* from) RefDeb(DEB_RLS_JATT, from); } -void StableAttachmentPart::manualLock(ULONG& flags) +void StableAttachmentPart::manualLock(ULONG& flags, const ULONG whatLock) { - fb_assert(!(flags & ATT_manual_lock)); - asyncMutex.enter(FB_FUNCTION); - mainMutex.enter(FB_FUNCTION); - flags |= (ATT_manual_lock | ATT_async_manual_lock); + fb_assert(!(flags & whatLock)); + if (whatLock & ATT_async_manual_lock) + { + asyncMutex.enter(FB_FUNCTION); + flags |= ATT_async_manual_lock; + } + if (whatLock & ATT_manual_lock) + { + mainMutex.enter(FB_FUNCTION); + flags |= ATT_manual_lock; + } } void StableAttachmentPart::manualUnlock(ULONG& flags) diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index 182fd6d0b0..3c735eb4dd 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -114,9 +114,35 @@ struct DdlTriggerContext }; -struct bid; +// Attachment flags + +const ULONG ATT_no_cleanup = 0x00001L; // Don't expunge, purge, or garbage collect +const ULONG ATT_shutdown = 0x00002L; // attachment has been shutdown +const ULONG ATT_shutdown_manager = 0x00004L; // attachment requesting shutdown +const ULONG ATT_exclusive = 0x00008L; // attachment wants exclusive database access +const ULONG ATT_attach_pending = 0x00010L; // Indicate attachment is only pending +const ULONG ATT_exclusive_pending = 0x00020L; // Indicate exclusive attachment pending +const ULONG ATT_notify_gc = 0x00040L; // Notify garbage collector to expunge, purge .. +const ULONG ATT_garbage_collector = 0x00080L; // I'm a garbage collector +const ULONG ATT_cancel_raise = 0x00100L; // Cancel currently running operation +const ULONG ATT_cancel_disable = 0x00200L; // Disable cancel operations +const ULONG ATT_no_db_triggers = 0x00400L; // Don't execute database triggers +const ULONG ATT_manual_lock = 0x00800L; // Was locked manually +const ULONG ATT_async_manual_lock = 0x01000L; // Async mutex was locked manually +//const ULONG ATT_purge_started = 0x02000L; // Purge already started - avoid 2 purges at once +const ULONG ATT_overwrite_check = 0x02000L; // Attachment checks is it possible to overwrite DB +const ULONG ATT_system = 0x04000L; // Special system attachment +const ULONG ATT_creator = 0x08000L; // This attachment created the DB +const ULONG ATT_monitor_done = 0x10000L; // Monitoring data is refreshed +const ULONG ATT_security_db = 0x20000L; // Attachment used for security purposes +const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block +const ULONG ATT_crypt_thread = 0x80000L; // Attachment from crypt thread + +const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc); class Attachment; +struct bid; + // // RefCounted part of Attachment object, placed into permanent pool @@ -172,7 +198,7 @@ public: return getInterface()->getTransactionInterface(status, tra); } - void manualLock(ULONG& flags); + void manualLock(ULONG& flags, const ULONG whatLock = ATT_manual_lock | ATT_async_manual_lock); void manualUnlock(ULONG& flags); void manualAsyncUnlock(ULONG& flags); @@ -384,33 +410,6 @@ private: }; -// Attachment flags - -const ULONG ATT_no_cleanup = 0x00001L; // Don't expunge, purge, or garbage collect -const ULONG ATT_shutdown = 0x00002L; // attachment has been shutdown -const ULONG ATT_shutdown_manager = 0x00004L; // attachment requesting shutdown -const ULONG ATT_exclusive = 0x00008L; // attachment wants exclusive database access -const ULONG ATT_attach_pending = 0x00010L; // Indicate attachment is only pending -const ULONG ATT_exclusive_pending = 0x00020L; // Indicate exclusive attachment pending -const ULONG ATT_notify_gc = 0x00040L; // Notify garbage collector to expunge, purge .. -const ULONG ATT_garbage_collector = 0x00080L; // I'm a garbage collector -const ULONG ATT_cancel_raise = 0x00100L; // Cancel currently running operation -const ULONG ATT_cancel_disable = 0x00200L; // Disable cancel operations -const ULONG ATT_no_db_triggers = 0x00400L; // Don't execute database triggers -const ULONG ATT_manual_lock = 0x00800L; // Was locked manually -const ULONG ATT_async_manual_lock = 0x01000L; // Async mutex was locked manually -//const ULONG ATT_purge_started = 0x02000L; // Purge already started - avoid 2 purges at once -const ULONG ATT_overwrite_check = 0x02000L; // Attachment checks is it possible to overwrite DB -const ULONG ATT_system = 0x04000L; // Special system attachment -const ULONG ATT_creator = 0x08000L; // This attachment created the DB -const ULONG ATT_monitor_done = 0x10000L; // Monitoring data is refreshed -const ULONG ATT_security_db = 0x20000L; // Attachment used for security purposes -const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block -const ULONG ATT_crypt_thread = 0x80000L; // Attachment from crypt thread - -const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc); - - inline bool Attachment::locksmith(thread_db* tdbb, SystemPrivilege sp) const { return att_user && att_user->locksmith(tdbb, sp); diff --git a/src/jrd/ExtEngineManager.cpp b/src/jrd/ExtEngineManager.cpp index dc913ca87a..6de86aafbb 100644 --- a/src/jrd/ExtEngineManager.cpp +++ b/src/jrd/ExtEngineManager.cpp @@ -662,7 +662,7 @@ Firebird::ITransaction* ExtEngineManager::ExternalContextImpl::getTransaction( const char* ExtEngineManager::ExternalContextImpl::getUserName() { - return internalAttachment->att_user->getUserName().c_str(); + return internalAttachment->att_user ? internalAttachment->att_user->getUserName().c_str() : ""; } const char* ExtEngineManager::ExternalContextImpl::getDatabaseName() diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index a0b957f6d4..b9cb06abc0 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -903,7 +903,10 @@ public: : AutoPtr(att) { if (att) + { + MAP_DEBUG(fprintf(stderr, "Using existing db handle %p\n", att)); att->addRef(); + } } bool attach(FbLocalStatus& st, const char* aliasDb, ICryptKeyCallback* cryptCb) @@ -911,7 +914,10 @@ public: bool down = false; // true if on attach db is shutdown if (hasData()) + { + MAP_DEBUG(fprintf(stderr, "Already attached %s\n", aliasDb)); return down; + } DispatcherPtr prov; if (cryptCb) @@ -1337,7 +1343,11 @@ ULONG mapUser(const bool throwNotFoundError, } if (cDb) + { + MAP_DEBUG(fprintf(stderr, "Populate cache for main DB %p\n", iDb.get())); cDb->populate(iDb, dbDown); + } + MAP_DEBUG(fprintf(stderr, "Populate cache for sec DB %p\n", iSec.get())); cSec->populate(iSec, secDown); sSec.downgrade(SYNC_SHARED); diff --git a/src/jrd/Monitoring.cpp b/src/jrd/Monitoring.cpp index a00d15e04d..63ca28c029 100644 --- a/src/jrd/Monitoring.cpp +++ b/src/jrd/Monitoring.cpp @@ -391,9 +391,8 @@ MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool) // Enumerate active sessions - const MetaName& user_name = attachment->att_user->getUserName(); const bool locksmith = attachment->locksmith(tdbb, MONITOR_ANY_ATTACHMENT); - const char* user_name_ptr = locksmith ? NULL : user_name.c_str(); + const char* user_name_ptr = locksmith ? NULL : attachment->att_user ? attachment->att_user->getUserName().c_str() : ""; MonitoringData::SessionList sessions(pool); @@ -856,7 +855,9 @@ void Monitoring::putDatabase(thread_db* tdbb, SnapshotData::DumpRecord& record) void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Attachment* attachment) { - fb_assert(attachment && attachment->att_user); + fb_assert(attachment); + if (!attachment->att_user) + return; record.reset(rel_mon_attachments); @@ -1309,10 +1310,10 @@ void Monitoring::publishAttachment(thread_db* tdbb) if (!dbb->dbb_monitoring_data) dbb->dbb_monitoring_data = FB_NEW_POOL(*dbb->dbb_permanent) MonitoringData(dbb); - const MetaName& user_name = attachment->att_user->getUserName(); + const char* user_name = attachment->att_user ? attachment->att_user->getUserName().c_str() : ""; MonitoringData::Guard guard(dbb->dbb_monitoring_data); - dbb->dbb_monitoring_data->setup(attachment->att_attachment_id, user_name.c_str()); + dbb->dbb_monitoring_data->setup(attachment->att_attachment_id, user_name); } void Monitoring::cleanupAttachment(thread_db* tdbb) diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index 4ab8cbd3c1..5757573762 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -3814,8 +3814,8 @@ dsc* evlRoleInUse(thread_db* tdbb, const SysFunction*, const NestValueArray& arg string roleStr(MOV_make_string2(tdbb, value, ttype_none)); roleStr.upper(); - impure->vlu_misc.vlu_uchar = attachment->att_user->roleInUse(tdbb, roleStr.c_str()) ? - FB_TRUE : FB_FALSE; + impure->vlu_misc.vlu_uchar = (attachment->att_user && + attachment->att_user->roleInUse(tdbb, roleStr.c_str())) ? FB_TRUE : FB_FALSE; impure->vlu_desc.makeBoolean(&impure->vlu_misc.vlu_uchar); @@ -3837,7 +3837,8 @@ dsc* evlSystemPrivilege(thread_db* tdbb, const SysFunction*, const NestValueArra USHORT p = *((USHORT*) value->dsc_address); Jrd::Attachment* attachment = tdbb->getAttachment(); - impure->vlu_misc.vlu_uchar = attachment->att_user->locksmith(tdbb, p) ? FB_TRUE : FB_FALSE; + impure->vlu_misc.vlu_uchar = (attachment->att_user && + attachment->att_user->locksmith(tdbb, p)) ? FB_TRUE : FB_FALSE; impure->vlu_desc.makeBoolean(&impure->vlu_misc.vlu_uchar); return &impure->vlu_desc; diff --git a/src/jrd/UserManagement.cpp b/src/jrd/UserManagement.cpp index a5f4a3659f..6f41eeef3e 100644 --- a/src/jrd/UserManagement.cpp +++ b/src/jrd/UserManagement.cpp @@ -47,12 +47,12 @@ namespace // ILogonInfo implementation const char* name() { - return att->att_user->getUserName().c_str(); + return att->att_user ? att->att_user->getUserName().c_str() : ""; } const char* role() { - return att->att_user->getSqlRole().c_str(); + return att->att_user ? att->att_user->getSqlRole().c_str() : ""; } const char* networkProtocol() @@ -67,6 +67,8 @@ namespace const unsigned char* authBlock(unsigned* length) { + if (!att->att_user) + return NULL; const Auth::AuthenticationBlock& aBlock = att->att_user->usr_auth_block; *length = aBlock.getCount(); return aBlock.getCount() ? aBlock.begin() : NULL; diff --git a/src/jrd/extds/ExtDS.cpp b/src/jrd/extds/ExtDS.cpp index 1f8acf126f..81fdbe1fe0 100644 --- a/src/jrd/extds/ExtDS.cpp +++ b/src/jrd/extds/ExtDS.cpp @@ -320,7 +320,7 @@ void Connection::generateDPB(thread_db* tdbb, ClumpletWriter& dpb, dpb.insertInt(isc_dpb_ext_call_depth, attachment->att_ext_call_depth + 1); if ((m_provider.getFlags() & prvTrustedAuth) && - user.isEmpty() && pwd.isEmpty() && role.isEmpty()) + user.isEmpty() && pwd.isEmpty() && role.isEmpty() && attachment->att_user) { attachment->att_user->populateDpb(dpb); } diff --git a/src/jrd/extds/InternalDS.cpp b/src/jrd/extds/InternalDS.cpp index f5a9dbc3b4..7e0e08d35e 100644 --- a/src/jrd/extds/InternalDS.cpp +++ b/src/jrd/extds/InternalDS.cpp @@ -147,7 +147,8 @@ void InternalConnection::attach(thread_db* tdbb, const PathName& dbName, setWrapErrors(false); Jrd::Attachment* attachment = tdbb->getAttachment(); - if ((user.isEmpty() || user == attachment->att_user->getUserName()) && + if (attachment->att_user && + (user.isEmpty() || user == attachment->att_user->getUserName()) && pwd.isEmpty() && (role.isEmpty() || role == attachment->att_user->getSqlRole())) { @@ -249,7 +250,8 @@ bool InternalConnection::isSameDatabase(thread_db* tdbb, const PathName& dbName, if (m_isCurrent) { const UserId* attUser = m_attachment->getHandle()->att_user; - return ((user.isEmpty() || user == attUser->getUserName()) && + return (attUser && + (user.isEmpty() || user == attUser->getUserName()) && pwd.isEmpty() && (role.isEmpty() || role == attUser->getSqlRole())); } diff --git a/src/jrd/extds/ValidatePassword.cpp b/src/jrd/extds/ValidatePassword.cpp index 17f102ef9e..315c11b335 100644 --- a/src/jrd/extds/ValidatePassword.cpp +++ b/src/jrd/extds/ValidatePassword.cpp @@ -172,6 +172,8 @@ void validatePassword(thread_db* tdbb, const PathName& file, ClumpletWriter& dpb if (ISC_check_if_remote(file, false)) // check for remote connection return; UserId* usr = tdbb->getAttachment()->att_user; + if (!usr) + return; if (!usr->usr_auth_block.hasData()) // check for embedded attachment return; diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 32082d0a18..e02198efae 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -745,7 +745,7 @@ namespace UserId* u = attachment->att_user; Arg::Gds err(isc_adm_task_denied); err << Arg::Gds(isc_miss_prvlg) << missPriv; - if (u->testFlag(USR_mapdown)) + if (u && u->testFlag(USR_mapdown)) err << Arg::Gds(isc_map_down); ERR_post(err); @@ -1038,7 +1038,7 @@ static void release_attachment(thread_db*, Jrd::Attachment*); static void rollback(thread_db*, jrd_tra*, const bool); static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0); static void getUserInfo(UserId&, const DatabaseOptions&, const char*, const char*, - const RefPtr*, bool, ICryptKeyCallback*); + const RefPtr*, bool, IAttachment*, ICryptKeyCallback*); static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM); @@ -1051,7 +1051,7 @@ TraceFailedConnection::TraceFailedConnection(const char* filename, const Databas m_filename(filename), m_options(options) { - getUserInfo(m_id, *m_options, m_filename, NULL, NULL, false, NULL); + getUserInfo(m_id, *m_options, m_filename, NULL, NULL, false, NULL, NULL); } @@ -1324,7 +1324,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch { ThreadContextHolder tdbb(user_status); - UserId userId; DatabaseOptions options; RefPtr config; bool invalid_client_SQL_dialect = false; @@ -1368,15 +1367,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch if (ISC_check_if_remote(expanded_name, true)) ERR_post(Arg::Gds(isc_unavailable)); - // Check for correct credentials supplied - if (existingId) - userId = *existingId; - else - { - getUserInfo(userId, options, org_filename.c_str(), expanded_name.c_str(), - &config, false, cryptCallback); - } - #ifdef WIN_NT guardDbInit.enter(); // Required to correctly expand name of just created database @@ -1626,8 +1616,28 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch break; } - userId.makeRoleName(options.dpb_sql_dialect); + // Check for correct credentials supplied + UserId userId; + if (existingId) + userId = *existingId; + else + { + jAtt->getStable()->manualUnlock(attachment->att_flags); + try + { + getUserInfo(userId, options, org_filename.c_str(), expanded_name.c_str(), + &config, false, jAtt, cryptCallback); + } + catch(const Exception&) + { + jAtt->getStable()->manualLock(attachment->att_flags, ATT_manual_lock); + throw; + } + jAtt->getStable()->manualLock(attachment->att_flags, ATT_manual_lock); + } + + userId.makeRoleName(options.dpb_sql_dialect); UserId::sclInit(tdbb, false, userId); // This pair (SHUT_database/SHUT_online) checks itself for valid user name @@ -1695,7 +1705,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch // Note we throw exception here when entering full-shutdown mode Arg::Gds v(isc_shutdown); v << Arg::Str(org_filename); - if (attachment->att_user->testFlag(USR_mapdown)) + if (attachment->att_user && attachment->att_user->testFlag(USR_mapdown)) v << Arg::Gds(isc_map_down); ERR_post(v); } @@ -2441,7 +2451,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch ERR_post(Arg::Gds(isc_unavailable)); // Check for correct credentials supplied - getUserInfo(userId, options, org_filename.c_str(), NULL, &config, true, cryptCallback); + getUserInfo(userId, options, org_filename.c_str(), NULL, &config, true, nullptr, cryptCallback); #ifdef WIN_NT guardDbInit.enter(); // Required to correctly expand name of just created database @@ -2595,7 +2605,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch if (attachment2) { - allow_overwrite = attachment2->getHandle()->att_user->locksmith(tdbb, DROP_DATABASE); + allow_overwrite = attachment2->getHandle()->locksmith(tdbb, DROP_DATABASE); attachment2->detach(user_status); } else @@ -2681,6 +2691,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch if (options.dpb_set_no_reserve) PAG_set_no_reserve(tdbb, options.dpb_no_reserve); + fb_assert(attachment->att_user); // set by UserId::sclInit() INI_format(attachment->att_user->getUserName().c_str(), options.dpb_set_db_charset.c_str()); @@ -7126,12 +7137,17 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status @param user @param options - @param + @param aliasName + @param dbName + @param config + @param creating + @param iAtt + @param cryptCb **/ static void getUserInfo(UserId& user, const DatabaseOptions& options, const char* aliasName, const char* dbName, const RefPtr* config, bool creating, - ICryptKeyCallback* cryptCb) + IAttachment* iAtt, ICryptKeyCallback* cryptCb) { bool wheel = false; int id = -1, group = -1; // CVC: This var contained trash @@ -7159,7 +7175,7 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, { if (mapUser(true, name, trusted_role, &auth_method, &user.usr_auth_block, NULL, options.dpb_auth_block, aliasName, dbName, - (config ? (*config)->getSecurityDatabase() : NULL), "", cryptCb, NULL) & MAPUSER_MAP_DOWN) + (config ? (*config)->getSecurityDatabase() : NULL), "", cryptCb, iAtt) & MAPUSER_MAP_DOWN) { user.setFlag(USR_mapdown); } diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index c0063b01a3..6ef3cb0c92 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -1517,8 +1517,10 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb, if (userName.hasData()) user.setUserName(userName); - else + else if (attachment->att_user) user = *attachment->att_user; + else + user.setUserName(""); SecurityClass::flags_t privilege = 0; const UCHAR* a = acl.begin(); diff --git a/src/jrd/shut.cpp b/src/jrd/shut.cpp index c801e6fc7f..d38a1106d5 100644 --- a/src/jrd/shut.cpp +++ b/src/jrd/shut.cpp @@ -161,7 +161,7 @@ void SHUT_database(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* guard) if (!attachment->locksmith(tdbb, CHANGE_SHUTDOWN_MODE)) { ERR_post_nothrow(Arg::Gds(isc_no_priv) << "shutdown" << "database" << dbb->dbb_filename); - if (attachment->att_user->testFlag(USR_mapdown)) + if (attachment->att_user && attachment->att_user->testFlag(USR_mapdown)) ERR_post_nothrow(Arg::Gds(isc_map_down)); ERR_punt(); } @@ -340,10 +340,10 @@ void SHUT_online(thread_db* tdbb, SSHORT flag, Sync* guard) // Only platform's user locksmith can shutdown or bring online a database - if (!attachment->att_user->locksmith(tdbb, CHANGE_SHUTDOWN_MODE)) + if (!attachment->locksmith(tdbb, CHANGE_SHUTDOWN_MODE)) { ERR_post_nothrow(Arg::Gds(isc_no_priv) << "bring online" << "database" << dbb->dbb_filename); - if (attachment->att_user->testFlag(USR_mapdown)) + if (attachment->att_user && attachment->att_user->testFlag(USR_mapdown)) ERR_post_nothrow(Arg::Gds(isc_map_down)); ERR_punt(); } diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index cda32fcd11..109c3f34cd 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -3632,7 +3632,8 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id) USHORT rel_id = blob_id->bid_internal.bid_relation_id; if (tra_attachment->isGbak() || - tra_attachment->att_user->locksmith(tdbb, SELECT_ANY_OBJECT_IN_DATABASE) || + (tra_attachment->att_user && + tra_attachment->att_user->locksmith(tdbb, SELECT_ANY_OBJECT_IN_DATABASE)) || rel_id == 0) { return; @@ -3677,7 +3678,7 @@ TraceSweepEvent::TraceSweepEvent(thread_db* tdbb) gds__log("Sweep is started by %s\n" "\tDatabase \"%s\" \n" "\tOIT %" SQUADFORMAT", OAT %" SQUADFORMAT", OST %" SQUADFORMAT", Next %" SQUADFORMAT, - att->att_user->getUserName().c_str(), + att->att_user ? att->att_user->getUserName().c_str() : "", att->att_filename.c_str(), m_sweep_info.getOIT(), m_sweep_info.getOAT(), diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 4633039c41..e5e53ad4f5 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -3900,10 +3900,13 @@ static void check_owner(thread_db* tdbb, return; const Jrd::Attachment* const attachment = tdbb->getAttachment(); - const Firebird::MetaName name(attachment->att_user->getUserName()); - desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str()); - if (!MOV_compare(&desc1, &desc2)) - return; + if (attachment->att_user) + { + const Firebird::MetaName name(attachment->att_user->getUserName()); + desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str()); + if (!MOV_compare(&desc1, &desc2)) + return; + } ERR_post(Arg::Gds(isc_protect_ownership)); } @@ -3925,7 +3928,8 @@ static bool check_user(thread_db* tdbb, const dsc* desc) const TEXT* p = (TEXT *) desc->dsc_address; const TEXT* const end = p + desc->dsc_length; - const TEXT* q = tdbb->getAttachment()->att_user->getUserName().c_str(); + const UserId* user = tdbb->getAttachment()->att_user; + const TEXT* q = user ? user->getUserName().c_str() : ""; // It is OK to not internationalize this function for v4.00 as // User names are limited to 7-bit ASCII for v4.00 @@ -5699,12 +5703,15 @@ static void set_owner_name(thread_db* tdbb, Record* record, USHORT field_id) if (!EVL_field(0, record, field_id, &desc1)) { - const Jrd::Attachment* const attachment = tdbb->getAttachment(); - const Firebird::MetaName name(attachment->att_user->getUserName()); - dsc desc2; - desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str()); - MOV_move(tdbb, &desc2, &desc1); - record->clearNull(field_id); + const Jrd::UserId* const user = tdbb->getAttachment()->att_user; + if (user) + { + const Firebird::MetaName name(user->getUserName()); + dsc desc2; + desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str()); + MOV_move(tdbb, &desc2, &desc1); + record->clearNull(field_id); + } } } From 1a103a273bc1240e32726d6752219bee19bf2034 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Sat, 31 Dec 2016 00:02:27 +0000 Subject: [PATCH 052/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 1120671bb1..6b1b83a20f 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:478 + FORMAL BUILD NUMBER:481 */ -#define PRODUCT_VER_STRING "4.0.0.478" -#define FILE_VER_STRING "WI-T4.0.0.478" -#define LICENSE_VER_STRING "WI-T4.0.0.478" -#define FILE_VER_NUMBER 4, 0, 0, 478 +#define PRODUCT_VER_STRING "4.0.0.481" +#define FILE_VER_STRING "WI-T4.0.0.481" +#define LICENSE_VER_STRING "WI-T4.0.0.481" +#define FILE_VER_NUMBER 4, 0, 0, 481 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "478" +#define FB_BUILD_NO "481" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 2e76ca1268..8c1addbb45 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=478 +BuildNum=481 NowAt=`pwd` cd `dirname $0` From 23a55f0b452d280dcf2edc82844a9329da7de5fd Mon Sep 17 00:00:00 2001 From: hvlad Date: Tue, 3 Jan 2017 18:42:32 +0200 Subject: [PATCH 053/134] Improvement CORE-5434 : Read-only transactions in SuperServer could avoid immediate write of Header and TIP pages after change --- src/jrd/tra.cpp | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index 109c3f34cd..ea8fd2359c 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -89,7 +89,7 @@ typedef Firebird::GenericMap > #ifdef SUPERSERVER_V2 static TraNumber bump_transaction_id(thread_db*, WIN*); #else -static header_page* bump_transaction_id(thread_db*, WIN*); +static header_page* bump_transaction_id(thread_db*, WIN*, bool); #endif static void retain_context(thread_db* tdbb, jrd_tra* transaction, bool commit, int state); static void expand_view_lock(thread_db* tdbb, jrd_tra*, jrd_rel*, UCHAR lock_type, @@ -1445,16 +1445,24 @@ void TRA_set_state(thread_db* tdbb, jrd_tra* transaction, TraNumber number, int WIN window(DB_PAGE_SPACE, -1); tx_inv_page* tip = fetch_inventory_page(tdbb, &window, sequence, LCK_write); + UCHAR* address = tip->tip_transactions + byte; + const int old_state = ((*address) >> shift) & TRA_MASK; + #ifdef SUPERSERVER_V2 CCH_MARK(tdbb, &window); const ULONG generation = tip->tip_header.pag_generation; #else - CCH_MARK_MUST_WRITE(tdbb, &window); + if (!(dbb->dbb_flags & DBB_shared) || transaction->tra_flags & TRA_write || + old_state != tra_active || state != tra_committed) + { + CCH_MARK_MUST_WRITE(tdbb, &window); + } + else + CCH_MARK(tdbb, &window); #endif // set the state on the TIP page - UCHAR* address = tip->tip_transactions + byte; *address &= ~(TRA_MASK << shift); *address |= state << shift; @@ -1944,7 +1952,7 @@ static TraNumber bump_transaction_id(thread_db* tdbb, WIN* window) #else -static header_page* bump_transaction_id(thread_db* tdbb, WIN* window) +static header_page* bump_transaction_id(thread_db* tdbb, WIN* window, bool dontWrite) { /************************************** * @@ -1999,7 +2007,11 @@ static header_page* bump_transaction_id(thread_db* tdbb, WIN* window) // Extend, if necessary, has apparently succeeded. Next, update header page - CCH_MARK_MUST_WRITE(tdbb, window); + if (dontWrite && !new_tip) + CCH_MARK(tdbb, window); + else + CCH_MARK_MUST_WRITE(tdbb, window); + dbb->dbb_next_transaction = number; Ods::writeNT(header, number); @@ -2391,7 +2403,10 @@ static void retain_context(thread_db* tdbb, jrd_tra* transaction, bool commit, i new_number = dbb->dbb_next_transaction + dbb->generateTransactionId(tdbb); else { - const header_page* const header = bump_transaction_id(tdbb, &window); + const bool dontWrite = (dbb->dbb_flags & DBB_shared) && + (transaction->tra_flags & TRA_readonly); + + const header_page* const header = bump_transaction_id(tdbb, &window, dontWrite); new_number = Ods::getNT(header); } #endif @@ -3077,7 +3092,10 @@ static void transaction_start(thread_db* tdbb, jrd_tra* trans) } else { - const header_page* header = bump_transaction_id(tdbb, &window); + const bool dontWrite = (dbb->dbb_flags & DBB_shared) && + (trans->tra_flags & TRA_readonly); + + const header_page* header = bump_transaction_id(tdbb, &window, dontWrite); number = Ods::getNT(header); oldest = Ods::getOIT(header); oldest_active = Ods::getOAT(header); From 96af3a363852a0e8b6f41cc28aaf743efb9e3a22 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Wed, 4 Jan 2017 00:02:25 +0000 Subject: [PATCH 054/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 6b1b83a20f..8f9c7c1c5e 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:481 + FORMAL BUILD NUMBER:482 */ -#define PRODUCT_VER_STRING "4.0.0.481" -#define FILE_VER_STRING "WI-T4.0.0.481" -#define LICENSE_VER_STRING "WI-T4.0.0.481" -#define FILE_VER_NUMBER 4, 0, 0, 481 +#define PRODUCT_VER_STRING "4.0.0.482" +#define FILE_VER_STRING "WI-T4.0.0.482" +#define LICENSE_VER_STRING "WI-T4.0.0.482" +#define FILE_VER_NUMBER 4, 0, 0, 482 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "481" +#define FB_BUILD_NO "482" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 8c1addbb45..82e11351d2 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=481 +BuildNum=482 NowAt=`pwd` cd `dirname $0` From 60d20db515e74fbdb38f1d17ad5ed839a2e8c7c8 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Wed, 4 Jan 2017 19:47:36 +0300 Subject: [PATCH 055/134] Fixed CORE-5421: Performance degradation in FB 3.0.2 compared to FB 2.5.7. --- src/jrd/Optimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jrd/Optimizer.h b/src/jrd/Optimizer.h index 91b780f2ed..8b8061a45a 100644 --- a/src/jrd/Optimizer.h +++ b/src/jrd/Optimizer.h @@ -260,7 +260,7 @@ public: bool isFiltered() const { - return (baseSelectivity < MAXIMUM_SELECTIVITY); + return (baseIndexes || baseSelectivity < MAXIMUM_SELECTIVITY); } IndexedRelationships indexedRelationships; From 1cb877591aaddc0498f694dd736c33b9942a4352 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Thu, 5 Jan 2017 00:02:27 +0000 Subject: [PATCH 056/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 8f9c7c1c5e..3ac16bdebb 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:482 + FORMAL BUILD NUMBER:483 */ -#define PRODUCT_VER_STRING "4.0.0.482" -#define FILE_VER_STRING "WI-T4.0.0.482" -#define LICENSE_VER_STRING "WI-T4.0.0.482" -#define FILE_VER_NUMBER 4, 0, 0, 482 +#define PRODUCT_VER_STRING "4.0.0.483" +#define FILE_VER_STRING "WI-T4.0.0.483" +#define LICENSE_VER_STRING "WI-T4.0.0.483" +#define FILE_VER_NUMBER 4, 0, 0, 483 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "482" +#define FB_BUILD_NO "483" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 82e11351d2..1ffaa932a4 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=482 +BuildNum=483 NowAt=`pwd` cd `dirname $0` From e4f7a6d54205662abd8e4523919ef76e1d1b0787 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Wed, 4 Jan 2017 22:32:48 +0300 Subject: [PATCH 057/134] Bugfix CORE-5435: Badly selective index could be used for extra filtering even if selective index is used for sorting --- src/jrd/Optimizer.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/jrd/Optimizer.cpp b/src/jrd/Optimizer.cpp index e265a3e35b..896c18bafa 100644 --- a/src/jrd/Optimizer.cpp +++ b/src/jrd/Optimizer.cpp @@ -1273,6 +1273,16 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in matches.add(segment->matches[j]); } } + + // If the navigational candidate includes any matching segments, + // reset the selectivity/cost prerequisites to account these matches + if (matchedSegments) + { + totalSelectivity = navigationCandidate->selectivity; + totalIndexCost = DEFAULT_INDEX_COST + totalSelectivity * navigationCandidate->cardinality; + previousTotalCost = totalIndexCost + totalSelectivity * streamCardinality; + firstCandidate = false; + } } for (i = 0; i < inversions->getCount(); i++) From b8e9675b75b33eba48d035229c9d5a21f49b0cd7 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Thu, 5 Jan 2017 15:32:15 -0200 Subject: [PATCH 058/134] Restored the line removal which leaves temporary files in Windows. --- builds/win32/parse.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/builds/win32/parse.bat b/builds/win32/parse.bat index a2573ca7f5..fe7f44a5a8 100644 --- a/builds/win32/parse.bat +++ b/builds/win32/parse.bat @@ -27,5 +27,6 @@ @del types.y @del y_tab.h @del y_tab.c +@del sed* :END From 4f7843d5b5359a6d19d53db81629250d55c7880f Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 5 Jan 2017 21:31:02 +0300 Subject: [PATCH 059/134] Bugfix CORE-5414: Error restoring on FB 3.0 from FB 2.5: bugcheck 221 (cannot remap) --- src/dsql/BoolNodes.cpp | 33 +-------------------------------- src/dsql/ExprNodes.cpp | 8 +++----- src/dsql/Nodes.h | 16 ++++++++++++++++ src/dsql/StmtNodes.cpp | 17 +++++++---------- src/jrd/JrdStatement.cpp | 11 +++++------ src/jrd/cmp.cpp | 9 +++++---- 6 files changed, 37 insertions(+), 57 deletions(-) diff --git a/src/dsql/BoolNodes.cpp b/src/dsql/BoolNodes.cpp index e50b7deb56..9f6cefa3ee 100644 --- a/src/dsql/BoolNodes.cpp +++ b/src/dsql/BoolNodes.cpp @@ -58,36 +58,6 @@ static const int TEMP_LENGTH = 128; //-------------------- -namespace -{ - // Copy sub expressions (including subqueries). - class SubExprNodeCopier : public NodeCopier - { - public: - explicit SubExprNodeCopier(thread_db* tdbb, CompilerScratch* aCsb) - //: NodeCopier(aCsb, localMap) - : NodeCopier(aCsb, FB_NEW_POOL(*tdbb->getDefaultPool()) StreamType[STREAM_MAP_LENGTH]) - { - // Initialize the map so all streams initially resolve to the original number. As soon as - // copy creates new streams, the map are being overwritten. - // CVC: better in the heap, because we need larger map. - localMap = remap; - for (unsigned i = 0; i < STREAM_MAP_LENGTH; ++i) - localMap[i] = i; - } - - ~SubExprNodeCopier() - { - delete[] localMap; - } - - private: - //StreamType localMap[JrdStatement::MAP_LENGTH]; - StreamType* localMap; - }; -} // namespace - - //-------------------- @@ -1951,8 +1921,7 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc newInnerRse->rse_boolean = boolean; - SubExprNodeCopier copier(tdbb, csb); - + SubExprNodeCopier copier(csb); return copier.copy(tdbb, static_cast(newNode)); } diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index c12fcf5d48..20552ed03e 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -5695,16 +5695,14 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb) return ValueExprNode::pass1(tdbb, csb); } - //StreamType local_map[JrdStatement::MAP_LENGTH]; - AutoPtr > localMap; + StreamMap localMap; StreamType* map = tail->csb_map; if (!map) { - localMap = FB_NEW_POOL(*tdbb->getDefaultPool()) StreamType[STREAM_MAP_LENGTH]; - map = localMap; + map = localMap.getBuffer(STREAM_MAP_LENGTH); fb_assert(stream + 2u <= MAX_STREAMS); - localMap[0] = stream; + map[0] = stream; map[1] = stream + 1; map[2] = stream + 2; } diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h index fbb7a9af81..bc74526fad 100644 --- a/src/dsql/Nodes.h +++ b/src/dsql/Nodes.h @@ -1660,6 +1660,22 @@ public: Firebird::MetaName secName; }; +typedef Firebird::Array StreamMap; + +// Copy sub expressions (including subqueries). +class SubExprNodeCopier : private StreamMap, public NodeCopier +{ +public: + SubExprNodeCopier(CompilerScratch* aCsb) + : NodeCopier(aCsb, getBuffer(STREAM_MAP_LENGTH)) + { + // Initialize the map so all streams initially resolve to the original number. + // As soon as copy creates new streams, the map is being overwritten. + for (unsigned i = 0; i < STREAM_MAP_LENGTH; ++i) + remap[i] = i; + } +}; + } // namespace diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 168f417e4e..61db9df295 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -6774,15 +6774,13 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb) if (!vector) return; - //StreamType localMap[JrdStatement::MAP_LENGTH]; - AutoPtr > localMap; + StreamMap localMap; StreamType* map = csb->csb_rpt[stream].csb_map; if (!map) { - localMap = FB_NEW_POOL(*tdbb->getDefaultPool()) StreamType[STREAM_MAP_LENGTH]; - map = localMap; - fb_assert(stream <= MAX_STREAMS); // CVC: MAX_UCHAR relevant, too? + map = localMap.getBuffer(STREAM_MAP_LENGTH); + fb_assert(stream <= MAX_STREAMS); map[0] = stream; map[1] = 1; map[2] = 2; @@ -8963,14 +8961,13 @@ static void makeValidation(thread_db* tdbb, CompilerScratch* csb, StreamType str if (!vector) return; - //StreamType local_map[JrdStatement::MAP_LENGTH]; - AutoPtr > localMap; + StreamMap localMap; StreamType* map = csb->csb_rpt[stream].csb_map; + if (!map) { - localMap = FB_NEW_POOL(*tdbb->getDefaultPool()) StreamType[STREAM_MAP_LENGTH]; - map = localMap; - fb_assert(stream <= MAX_STREAMS); // CVC: MAX_UCHAR still relevant for the bitmap? + map = localMap.getBuffer(STREAM_MAP_LENGTH); + fb_assert(stream <= MAX_STREAMS); map[0] = stream; } diff --git a/src/jrd/JrdStatement.cpp b/src/jrd/JrdStatement.cpp index 3c02c0d041..97770ca4ed 100644 --- a/src/jrd/JrdStatement.cpp +++ b/src/jrd/JrdStatement.cpp @@ -203,9 +203,9 @@ JrdStatement* JrdStatement::makeStatement(thread_db* tdbb, CompilerScratch* csb, DmlNode::doPass1(tdbb, csb, &csb->csb_node); - // CVC: I'm going to allocate the map before the loop to avoid alloc/dealloc calls. - AutoPtr > localMap(FB_NEW_POOL(*tdbb->getDefaultPool()) - StreamType[STREAM_MAP_LENGTH]); + // CVC: I'm going to preallocate the map before the loop to avoid alloc/dealloc calls. + StreamMap localMap; + StreamType* const map = localMap.getBuffer(STREAM_MAP_LENGTH); // Copy and compile (pass1) domains DEFAULT and constraints. MapFieldInfo::Accessor accessor(&csb->csb_map_field_info); @@ -213,18 +213,17 @@ JrdStatement* JrdStatement::makeStatement(thread_db* tdbb, CompilerScratch* csb, for (bool found = accessor.getFirst(); found; found = accessor.getNext()) { FieldInfo& fieldInfo = accessor.current()->second; - //StreamType local_map[MAP_LENGTH]; AutoSetRestore autoRemapVariable(&csb->csb_remap_variable, (csb->csb_variables ? csb->csb_variables->count() : 0) + 1); - fieldInfo.defaultValue = NodeCopier::copy(tdbb, csb, fieldInfo.defaultValue, localMap); + fieldInfo.defaultValue = NodeCopier::copy(tdbb, csb, fieldInfo.defaultValue, map); csb->csb_remap_variable = (csb->csb_variables ? csb->csb_variables->count() : 0) + 1; if (fieldInfo.validationExpr) { - NodeCopier copier(csb, localMap); + NodeCopier copier(csb, map); fieldInfo.validationExpr = copier.copy(tdbb, fieldInfo.validationExpr); } diff --git a/src/jrd/cmp.cpp b/src/jrd/cmp.cpp index 3f83ab0fc0..5ead14d8ac 100644 --- a/src/jrd/cmp.cpp +++ b/src/jrd/cmp.cpp @@ -106,7 +106,8 @@ IMPLEMENT_TRACE_ROUTINE(cmp_trace, "CMP") // Clone a node. ValueExprNode* CMP_clone_node(thread_db* tdbb, CompilerScratch* csb, ValueExprNode* node) { - return NodeCopier::copy(tdbb, csb, node, NULL); + SubExprNodeCopier copier(csb); + return copier.copy(tdbb, node); } @@ -122,7 +123,8 @@ ValueExprNode* CMP_clone_node_opt(thread_db* tdbb, CompilerScratch* csb, ValueEx if (node->is()) return node; - ValueExprNode* clone = NodeCopier::copy(tdbb, csb, node, NULL); + SubExprNodeCopier copier(csb); + ValueExprNode* clone = copier.copy(tdbb, node); ExprNode::doPass2(tdbb, csb, &clone); return clone; @@ -134,9 +136,8 @@ BoolExprNode* CMP_clone_node_opt(thread_db* tdbb, CompilerScratch* csb, BoolExpr DEV_BLKCHK(csb, type_csb); - NodeCopier copier(csb, NULL); + SubExprNodeCopier copier(csb); BoolExprNode* clone = copier.copy(tdbb, node); - ExprNode::doPass2(tdbb, csb, &clone); return clone; From 191f700a19a35c6875c3d5a98032195094014a56 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 5 Jan 2017 22:26:32 +0300 Subject: [PATCH 060/134] This check does not seem actual anymore, addresses CORE-1095 and CORE-3530 --- src/jrd/opt.cpp | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/jrd/opt.cpp b/src/jrd/opt.cpp index 0d08429e5a..a194bbef75 100644 --- a/src/jrd/opt.cpp +++ b/src/jrd/opt.cpp @@ -291,7 +291,6 @@ static bool augment_stack(BoolExprNode*, BoolExprNodeStack&); static void check_indices(const CompilerScratch::csb_repeat*); static void check_sorts(RseNode*); static void class_mask(USHORT, ValueExprNode**, ULONG*); -static bool check_for_nod_from(const ValueExprNode*); static SLONG decompose(thread_db* tdbb, BoolExprNode* boolNode, BoolExprNodeStack& stack, CompilerScratch* csb); static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratch* csb, @@ -1313,29 +1312,6 @@ static void class_mask(USHORT count, ValueExprNode** eq_class, ULONG* mask) } -static bool check_for_nod_from(const ValueExprNode* node) -{ -/************************************** - * - * c h e c k _ f o r _ n o d _ f r o m - * - ************************************** - * - * Functional description - * Check for nod_from under >=0 CastNode nodes. - * - **************************************/ - const CastNode* castNode; - const SubQueryNode* subQueryNode; - - if ((castNode = node->as())) - return check_for_nod_from(castNode->source); - else if ((subQueryNode = node->as()) && subQueryNode->blrOp == blr_via) - return true; - - return false; -} - static SLONG decompose(thread_db* tdbb, BoolExprNode* boolNode, BoolExprNodeStack& stack, CompilerScratch* csb) { @@ -1405,14 +1381,6 @@ static SLONG decompose(thread_db* tdbb, BoolExprNode* boolNode, BoolExprNodeStac if (cmpNode->blrOp == blr_between) { - if (check_for_nod_from(cmpNode->arg1)) - { - // Without this ERR_punt(), server was crashing with sub queries - // under "between" predicate, Bug No. 73766 - ERR_post(Arg::Gds(isc_optimizer_between_err)); - // Msg 493: Unsupported field type specified in BETWEEN predicate - } - ComparativeBoolNode* newCmpNode = FB_NEW_POOL(csb->csb_pool) ComparativeBoolNode( csb->csb_pool, blr_geq); newCmpNode->arg1 = cmpNode->arg1; From 7bca83696172d08f3eac812a7062127c959bafb9 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 6 Jan 2017 00:02:24 +0000 Subject: [PATCH 061/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 3ac16bdebb..21648e7e75 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:483 + FORMAL BUILD NUMBER:487 */ -#define PRODUCT_VER_STRING "4.0.0.483" -#define FILE_VER_STRING "WI-T4.0.0.483" -#define LICENSE_VER_STRING "WI-T4.0.0.483" -#define FILE_VER_NUMBER 4, 0, 0, 483 +#define PRODUCT_VER_STRING "4.0.0.487" +#define FILE_VER_STRING "WI-T4.0.0.487" +#define LICENSE_VER_STRING "WI-T4.0.0.487" +#define FILE_VER_NUMBER 4, 0, 0, 487 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "483" +#define FB_BUILD_NO "487" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 1ffaa932a4..82d7d66844 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=483 +BuildNum=487 NowAt=`pwd` cd `dirname $0` From 10c6a14a0475f6a69bc161075a7e6d5c39c0c0f4 Mon Sep 17 00:00:00 2001 From: hvlad Date: Fri, 6 Jan 2017 11:08:43 +0200 Subject: [PATCH 062/134] Fixed bug CORE-5422 : Decompression overran buffer after rollback --- src/jrd/dpm.epp | 2 ++ src/jrd/vio.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 540d270ec5..919abb3087 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -1103,6 +1103,8 @@ bool DPM_fetch(thread_db* tdbb, record_param* rpb, USHORT lock) rpb->rpb_f_line, rpb->rpb_flags); #endif rpb->rpb_number = number; + if (!(rpb->rpb_flags & rpb_chained)) + rpb->rpb_prior = NULL; return true; } diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index e5e53ad4f5..ad6d1ea398 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -1302,7 +1302,13 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool) UCHAR* tail; const UCHAR* tail_end; UCHAR differences[MAX_DIFFERENCES]; - Record* prior = rpb->rpb_prior; + + // If the record is a primary version, prior should be NULL. + if (!(rpb->rpb_flags & rpb_chained)) + fb_assert(rpb->rpb_prior == NULL); + + Record* prior = (rpb->rpb_flags & rpb_chained) ? rpb->rpb_prior : NULL; + if (prior) { tail = differences; From 835c78cb35b9adf3399f3da133624660c29e4f79 Mon Sep 17 00:00:00 2001 From: hvlad Date: Fri, 6 Jan 2017 16:21:13 +0200 Subject: [PATCH 063/134] Correction for recent patch for CORE-5422. I was a bit wrong - DPM_fetch should not change rpb_prior --- src/jrd/dpm.epp | 2 -- src/jrd/vio.cpp | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 919abb3087..540d270ec5 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -1103,8 +1103,6 @@ bool DPM_fetch(thread_db* tdbb, record_param* rpb, USHORT lock) rpb->rpb_f_line, rpb->rpb_flags); #endif rpb->rpb_number = number; - if (!(rpb->rpb_flags & rpb_chained)) - rpb->rpb_prior = NULL; return true; } diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index ad6d1ea398..eb0a9249e2 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -1303,10 +1303,7 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool) const UCHAR* tail_end; UCHAR differences[MAX_DIFFERENCES]; - // If the record is a primary version, prior should be NULL. - if (!(rpb->rpb_flags & rpb_chained)) - fb_assert(rpb->rpb_prior == NULL); - + // Primary record version not uses prior version Record* prior = (rpb->rpb_flags & rpb_chained) ? rpb->rpb_prior : NULL; if (prior) From 3cc273d99dd193dcdec746d4d0fcfe079abf0ef7 Mon Sep 17 00:00:00 2001 From: hvlad Date: Fri, 6 Jan 2017 17:03:09 +0200 Subject: [PATCH 064/134] Correction --- src/jrd/tra.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index ea8fd2359c..442372d42f 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -1452,7 +1452,8 @@ void TRA_set_state(thread_db* tdbb, jrd_tra* transaction, TraNumber number, int CCH_MARK(tdbb, &window); const ULONG generation = tip->tip_header.pag_generation; #else - if (!(dbb->dbb_flags & DBB_shared) || transaction->tra_flags & TRA_write || + if (!(dbb->dbb_flags & DBB_shared) || !transaction || + transaction->tra_flags & TRA_write || old_state != tra_active || state != tra_committed) { CCH_MARK_MUST_WRITE(tdbb, &window); From 8e1421d64c58e5c5ec4b5415bfece17fcb137dda Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Fri, 6 Jan 2017 19:26:29 +0300 Subject: [PATCH 065/134] Fixed regression caused by commit for CORE-5433 --- src/jrd/Mapping.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index b9cb06abc0..dc2a33d7d7 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -329,12 +329,23 @@ public: dataFlag = true; downFlag = false; } - catch (const Exception&) + catch (const Exception& ex) { if (curs) curs->release(); if (tra) tra->release(); + + // If database is shutdown it's not a reason to fail mapping + StaticStatusVector status; + ex.stuffException(status); + const ISC_STATUS* s = status.begin(); + if (fb_utils::containsErrorCode(s, isc_shutdown)) + { + downFlag = true; + return; + } + throw; } } From ea77183d29afd79d55e3464cb6e9817df3eb592f Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Sat, 7 Jan 2017 00:02:26 +0000 Subject: [PATCH 066/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 21648e7e75..19c6596cbb 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:487 + FORMAL BUILD NUMBER:491 */ -#define PRODUCT_VER_STRING "4.0.0.487" -#define FILE_VER_STRING "WI-T4.0.0.487" -#define LICENSE_VER_STRING "WI-T4.0.0.487" -#define FILE_VER_NUMBER 4, 0, 0, 487 +#define PRODUCT_VER_STRING "4.0.0.491" +#define FILE_VER_STRING "WI-T4.0.0.491" +#define LICENSE_VER_STRING "WI-T4.0.0.491" +#define FILE_VER_NUMBER 4, 0, 0, 491 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "487" +#define FB_BUILD_NO "491" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 82d7d66844..1682e54550 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=487 +BuildNum=491 NowAt=`pwd` cd `dirname $0` From 6edb5af5151533a93a94466070e33206d56505ab Mon Sep 17 00:00:00 2001 From: hvlad Date: Fri, 30 Dec 2016 02:19:22 +0200 Subject: [PATCH 067/134] Improvement CORE-4563 : Add support for Windows 8/2012 fast/low-latency "TCP Loopback Fast Path" functionality --- src/remote/inet.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/remote/inet.cpp b/src/remote/inet.cpp index f2b2c29d8c..f89c00b046 100644 --- a/src/remote/inet.cpp +++ b/src/remote/inet.cpp @@ -127,6 +127,11 @@ using namespace Firebird; #include #include #include "../utilities/install/install_nt.h" +#include + +#ifndef SIO_LOOPBACK_FAST_PATH +#define SIO_LOOPBACK_FAST_PATH _WSAIOW(IOC_VENDOR,16) +#endif #define INET_RETRY_ERRNO WSAEINPROGRESS #define INET_ADDR_IN_USE WSAEADDRINUSE @@ -476,6 +481,7 @@ static int send_partial(rem_port*, PACKET *); static int xdrinet_create(XDR*, rem_port*, UCHAR *, USHORT, enum xdr_op); static bool setNoNagleOption(rem_port*); +static bool setFastLoopbackOption(SOCKET s); static FPTR_INT tryStopMainThread = 0; @@ -886,6 +892,8 @@ rem_port* INET_connect(const TEXT* name, goto err_close; } + setFastLoopbackOption(port->port_handle); + n = connect(port->port_handle, pai->ai_addr, pai->ai_addrlen); if (n != -1) { @@ -1010,6 +1018,8 @@ static rem_port* listener_socket(rem_port* port, USHORT flag, const addrinfo* pa inet_error(false, port, "listen", isc_net_connect_listen_err, INET_ERRNO); } + setFastLoopbackOption(port->port_handle); + inet_ports->registerPort(port); if (flag & SRVR_multi_client) @@ -1430,6 +1440,7 @@ static rem_port* aux_connect(rem_port* port, PACKET* packet) int optval = 1; setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, (SCHAR*) &optval, sizeof(optval)); + setFastLoopbackOption(n); status = address.connect(n); if (status < 0) @@ -1511,6 +1522,8 @@ static rem_port* aux_request( rem_port* port, PACKET* packet) inet_error(false, port, "listen", isc_net_event_listen_err, INET_ERRNO); } + setFastLoopbackOption(n); + rem_port* const new_port = alloc_port(port->port_parent, (port->port_flags & PORT_no_oob) | PORT_async | PORT_connecting); port->port_async = new_port; @@ -3162,6 +3175,21 @@ static bool setNoNagleOption(rem_port* port) return true; } +bool setFastLoopbackOption(SOCKET s) +{ +#ifdef WIN_NT + int optval = 1; + DWORD bytes = 0; + + int ret = WSAIoctl(s, SIO_LOOPBACK_FAST_PATH, &optval, sizeof(optval), + NULL, 0, &bytes, 0, 0); + + return (ret == 0); +#else + return false; +#endif +} + void setStopMainThread(FPTR_INT func) { /************************************** From 6cff46776320e948bb8ef989e037e8541cb43abc Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Sun, 8 Jan 2017 00:02:23 +0000 Subject: [PATCH 068/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 19c6596cbb..9b0bf55588 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:491 + FORMAL BUILD NUMBER:492 */ -#define PRODUCT_VER_STRING "4.0.0.491" -#define FILE_VER_STRING "WI-T4.0.0.491" -#define LICENSE_VER_STRING "WI-T4.0.0.491" -#define FILE_VER_NUMBER 4, 0, 0, 491 +#define PRODUCT_VER_STRING "4.0.0.492" +#define FILE_VER_STRING "WI-T4.0.0.492" +#define LICENSE_VER_STRING "WI-T4.0.0.492" +#define FILE_VER_NUMBER 4, 0, 0, 492 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "491" +#define FB_BUILD_NO "492" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 1682e54550..6f195f6529 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=491 +BuildNum=492 NowAt=`pwd` cd `dirname $0` From d5146be51e205dae9583847d09f8c0008d7707bb Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 9 Jan 2017 12:23:04 +0100 Subject: [PATCH 069/134] Don't use libintl.so SONAME for libfbintl.so (#74) POSIX build by default uses libintl.so.1 SONAME for libfbintl.so.1. This means that on Linux ldconfig will make libintl.so.1 symlink to libfbintl.so.1. However, actual libintl is a very different library, incompatible with libfbintl. This breaks other software which tries to link to libintl. Fix it by making libfbintl SONAME match its actual name. --- builds/posix/make.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builds/posix/make.defaults b/builds/posix/make.defaults index aa42dc8c09..681717f346 100755 --- a/builds/posix/make.defaults +++ b/builds/posix/make.defaults @@ -321,7 +321,7 @@ LINK_IB_UTIL = $(LIB_LINK) $(LINK_IBUTIL_SYMBOLS) $(LIB_LINK_OPTIONS) $(UNDEF_FL LINK_IB_UTIL_LIBS = $(THR_LIBS) LINK_INTL = $(LIB_LINK) $(LINK_FBINTL_SYMBOLS) $(LIB_LINK_OPTIONS) $(UNDEF_FLAGS)\ - $(call LIB_LINK_SONAME,libintl.$(SHRLIB_EXT).1) $(call LIB_LINK_RPATH,lib) + $(call LIB_LINK_SONAME,libfbintl.$(SHRLIB_EXT).1) $(call LIB_LINK_RPATH,lib) LINK_INTL_LIBS = -L$(LIB) $(SO_LINK_LIBS) $(FIREBIRD_LIBRARY_LINK) LINK_TRACE = $(LIB_LINK) $(LINK_PLUGIN_SYMBOLS) $(LIB_LINK_OPTIONS) $(UNDEF_FLAGS)\ From e722a4095ca2fe67c07163fc76a9b9b721d45339 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Mon, 9 Jan 2017 20:28:11 +0300 Subject: [PATCH 070/134] Implemented CORE-5442: Enhance control upon ability to share database crypt key between attachments in SS --- doc/Using_OO_API.html | 50 +++-- examples/dbcrypt/CryptKeyHolder.cpp | 11 + src/common/classes/GetPlugins.h | 12 +- src/include/firebird/FirebirdInterface.idl | 5 + src/include/firebird/IdlFbInterfaces.h | 34 ++- src/jrd/CryptoManager.cpp | 238 ++++++++++++++------- src/jrd/CryptoManager.h | 45 ++-- src/jrd/status.h | 5 + 8 files changed, 278 insertions(+), 122 deletions(-) diff --git a/doc/Using_OO_API.html b/doc/Using_OO_API.html index 86cd74e901..02ae9c4b04 100644 --- a/doc/Using_OO_API.html +++ b/doc/Using_OO_API.html @@ -7,7 +7,8 @@ - + + - - -

-Firebird interfaces.

-

Firebird's OO API is based -on use of interfaces. That interfaces, though looking in some aspects -like OLE2 interfaces (some of them have addRef() and release() -methods) are non standard and have features, missing in other widely -used types of interfaces. First of all Firebird interfaces are -language independentthat + p { margin-bottom: 0.08in; color: #000000 } + h1 { color: #000000 } + + + +

+Firebird +interfaces.

+

Firebird's +OO API is based on use of interfaces. That interfaces, though looking +in some aspects like OLE2 interfaces (some of them have addRef() and +release() methods) are non standard and have features, missing in +other widely used types of interfaces. First of all Firebird +interfaces are language +independentthat means that to define/use them one need not use language specific -constructions like class in -C++, interface may be defined using any language having concepts of -array and pointer to procedure/function. Next interfaces are -versioned -– i.e. we support different versions of same -interface. Binary layout of interfaces is designed to support that -features very efficient (there is no need in additional virtual calls -like in OLE2/COM with it's QueryInterface) -but +constructions like class +in C++, interface may be +defined using any language having concepts of array and pointer to +procedure/function. Next interfaces are versioned +– i.e. we support different +versions of same interface. Binary layout of interfaces is designed +to support that features very efficient (there is no need in +additional virtual calls like in OLE2/COM with it's QueryInterface) +but it's not convenient for direct use from most languages. Therefore language-specific wrappers should better be designed for different languages making use of API easier. Currently we have wrappers for C++ and Pascal, Java is coming soon. From end-user POV calls from C++ and Pascal have absolutely no difference, though some additional language-specific features present in C++ (like ability to turn off -automatic status check after API calls) are missing in Pascal.

-


-

-

Typically +automatic status check after API calls) are missing in Pascal.

+


+ +

+

Typically database API is used to access data stored in database. Firebird OO API certainly performs this task but in addition it supports writing -your own pluginsmodules, -making it possible to enhance Firebird capabilities according to your -needs. Therefore this document contains 2 big parts – accessing -databases and writing plugins. Certainly some interfaces (like status -vector) are used in both parts of API, they will be discussed in data -access part and freely referenced later when discussing plugins. -Therefore even if you plan to write some plugin you should better -start with the first part of this document. Moreover a lot of plugins -need to access databases themselves and data access API is typically -needed for it.

-


-

-

Firebird +your own plugins +– modules, making it +possible to enhance Firebird capabilities according to your needs. +Therefore this document contains 2 big parts – accessing databases +and writing plugins. Certainly some interfaces (like status vector) +are used in both parts of API, they will be discussed in data access +part and freely referenced later when discussing plugins. Therefore +even if you plan to write some plugin you should better start with +the first part of this document. Moreover a lot of plugins need to +access databases themselves and data access API is typically needed +for it.

+


+ +

+

Firebird installation package contains a number of live samples of use of OO API – they are in examples/interfaces (database access) and -examples/dbcrypt (plugin performing fictitious -database encryption) +examples/dbcrypt (plugin performing fictitious +database encryption) directories. It's supposed that the reader is familiar with ISC API -used in Firebird since interbase times.

-


-

-

This +used in Firebird since interbase times.

+


+ +

+

This document does not pretend to be a full Firebird 3 documentation – it just describes new object oriented API, and a reader should be familiar with main Firebird concepts, knowledge about ISC API is also much welcome. For example – when describing how to work with services there is no explanation what is service and why is it -needed, only description of how to obtain IService +needed, only description of how to obtain IService interface and how to use it. Also pay attention that samples of code do not use a lot of powerful features of C++. Not used reference counted pointers, not used other RAII holders, not used templates (except one present in firebird public headers), etc. Primary goal is to make this text usable not only to C++ people because our API is oriented to support not only C++ but other, more simple languages -too.

-


-

-

-Accessing databases.

-

Creating database and attaching to existing -database.

-

First of all we need to -get access to IMaster interface. IMaster is primary Firebird -interface, required to access all the rest of interfaces. Therefore -there is a special way of accessing it – the only one needed to use -OO API plain function called fb_get_master_interface(). This function -has no parameters and always succeeds. There is one and only one -instance of IMaster per Firebird client library, therefore one need -not care about releasing memory, used by master interface. A simplest -way to access it from your program is to have appropriate global or -static variable:

-

static IMaster* -master = fb_get_master_interface();

-


-

-

For a lot of methods, used -in Firebird API, first parameter is IStatus interface. It's a -logical replacement of ISC_STATUS_ARRAY, but works separately with -errors and warnings (not mixing them in same array), can contain -unlimited number of errors inside and (this will be important if you -plan to implement IStatus yourself) always keeps strings, referenced -by it, inside interface. Typically you need at least one instance of -IStatus to call other methods. You obtain it from IMaster:

-

IStatus* -st = master->getStatus();

-

If method getStatus() -fails for some reason (OOM for example) it returns NULL – obviously -we can't use generic error reporting method which is based on use of -IStatus here.

-


-

-

Now we are going to deal -with first interface, directly related to database calls. This is -IProvider – interface called this way cause -it's exactly that interface that must be implemented by any provider -in Firebird. Firebird client library also has it's own implementation -of IProvider, which must be used to start any database activity. To -obtain it we call IMaster's method:

-

IProvider* prov = -master->getDispatcher();

-


-

-

When attaching to existing -database or moreover creating new one it's often necessary to pass a -lot of additional parameters (logon/password, page size for new -database, etc.) to API call. Having separate language-level -parameters is close to unreal – we will have to modify a call too -often to add new parameters, and number of them will be very big no -matter of the fact that typically one needs to pass not too much of -them. Therefore to pass additional parameters special in-memory data -structure, called database parameters block -(DPB) is used. Format of it is well defined, and it's -possible to build DPB byte after byte. But it's much easier to use -special interface IXpbBuilder, +too.

+


+ +

+

+Accessing +databases.

+

Creating database and +attaching to existing database.

+

First +of all we need to get access to IMaster interface. IMaster is +primary Firebird interface, required to access all the rest of +interfaces. Therefore there is a special way of accessing it – the +only one needed to use OO API plain function called +fb_get_master_interface(). This function has no parameters and always +succeeds. There is one and only one instance of IMaster per Firebird +client library, therefore one need not care about releasing memory, +used by master interface. A simplest way to access it from your +program is to have appropriate global or static variable:

+

static +IMaster* master = fb_get_master_interface();

+


+ +

+

For +a lot of methods, used in Firebird API, first parameter is IStatus +interface. It's a logical replacement of ISC_STATUS_ARRAY, but works +separately with errors and warnings (not mixing them in same array), +can contain unlimited number of errors inside and (this will be +important if you plan to implement IStatus yourself) always keeps +strings, referenced by it, inside interface. Typically you need at +least one instance of IStatus to call other methods. You obtain it +from IMaster:

+

IStatus* +st = master->getStatus();

+

If +method getStatus() fails for some reason (OOM for example) it returns +NULL – obviously we can't use generic error reporting method which +is based on use of IStatus here.

+


+ +

+

Now +we are going to deal with first interface, directly related to +database calls. This is IProvider – +interface called this way cause it's exactly that interface that must +be implemented by any provider in Firebird. Firebird client library +also has it's own implementation of IProvider, which must be used to +start any database activity. To obtain it we call IMaster's method:

+

IProvider* +prov = master->getDispatcher();

+


+ +

+

When +attaching to existing database or moreover creating new one it's +often necessary to pass a lot of additional parameters +(logon/password, page size for new database, etc.) to API call. +Having separate language-level parameters is close to unreal – we +will have to modify a call too often to add new parameters, and +number of them will be very big no matter of the fact that typically +one needs to pass not too much of them. Therefore to pass additional +parameters special in-memory data structure, called database +parameters block (DPB) +is used. Format of it is well defined, and it's possible to build DPB +byte after byte. But it's much easier to use special interface +IXpbBuilder, which simplifies creation of various parameters blocks. To obtain an instance of IXpbBuilder you must know one more generic-use interface -of firebird API – IUtil. +of firebird API – IUtil. It's a kind of placeholder for the calls that do not fit well in -other places. So we do

-

IUtil* utl = -master->getUtilInterface();

-

IXpbBuilder* dpb = -utl->getXpbBuilder(&status, IXpbBuilder::DPB, NULL, 0);

-

This creates empty -parameters' block builder of DPB type. Now adding required parameter -to it is trivial:

-

dpb->insertInt(&status, -isc_dpb_page_size, 4 * 1024);

-

will make firebird to -create new database with pagesize equal to 4Kb and meaning of

-

dpb->insertString(&status, -isc_dpb_user_name, “sysdba”);

-

dpb->insertString(&status, -isc_dpb_password, “masterkey”);

-

is (I hope) obvious.

-


-

-

The -following is C++ specific: We are almost ready to call +other places. So we do

+

IUtil* +utl = master->getUtilInterface();

+

IXpbBuilder* +dpb = utl->getXpbBuilder(&status, IXpbBuilder::DPB, NULL, 0);

+

This +creates empty parameters' block builder of DPB type. Now adding +required parameter to it is trivial:

+

dpb->insertInt(&status, +isc_dpb_page_size, 4 * 1024);

+

will +make firebird to create new database with pagesize equal to 4Kb and +meaning of

+

dpb->insertString(&status, +isc_dpb_user_name, “sysdba”);

+

dpb->insertString(&status, +isc_dpb_password, “masterkey”);

+

is +(I hope) obvious.

+


+ +

+

The +following is C++ specific: We are almost ready to call createDatabase() method of IProvider, but before it a few words about -concept of Status Wrapper should be said. Status wrapper is +concept of Status Wrapper should be said. Status wrapper is not an interface, it's very thin envelope for IStatus interface. It helps to customize behavior of C++ API (change a way how errors, returned in IStatus interface, are processed). For the first time we -recommend use of ThrowStatusWrapper, which raises C++ -exception each time an error is returned in IStatus.

-

ThrowStatusWrapper -status(st);

-


-

-

Now we may create new -empty database:

-

IAttachment* +recommend use of ThrowStatusWrapper, which raises C++ +exception each time an error is returned in IStatus.

+

ThrowStatusWrapper +status(st);

+


+ +

+

Now +we may create new empty database:

+

IAttachment* att = prov->createDatabase(&status, "fbtests.fdb", -dpb->getBufferLength(&status), dpb->getBuffer(&status));

-

printf("Database -fbtests.fdb created\n");

-

Pay attention that we do -not check status after the call to createDatabase(), because in case -of error C++ or Pascal exception will be raised (therefore it's very -good idea to have try/catch/except syntax in your program). We also -use two new functions from IXpbBuilder – getBufferLength() and -getBuffer(), which extract data from interface in native parameters -block format. As you can see there is no need to check explicitly for -status of functions, returning intermediate results.

-


-

-

Detaching from just -created database is trivial:

-

att->detach(&status);

-


-

-

Now it remains to enclose -all operators into try block and write a handler in catch -block. When using ThrowStatusWrapper you should always catch defined -in C++ API exception class FbException, in Pascal you must also work -with class FbException. Exception handler block in simplest case may -look this way:

-

catch (const -FbException& error)

-

{

-

char buf[256];

-

utl->formatStatus(buf, -sizeof(buf), error.getStatus());

-

fprintf(stderr, "%s\n", -buf);

-

}

-

Pay attention that here we -use one more function from IUtil – -formatStatus(). It returns in buffer text, describing an error -(warning), stored in IStatus parameter.

-


-

-

To attach to existing -database just use attachDatabase() method of IProvider instead -createDatabase(). All parameters are the same for both methods.

-

att = -prov->attachDatabase(&status, "fbtests.fdb", 0, -NULL);

-

This sample is using no -additional DPB parameters. Take into account that without -logon/password any remote connection will fail if no trusted +dpb->getBufferLength(&status), dpb->getBuffer(&status));

+

printf("Database +fbtests.fdb created\n");

+

Pay +attention that we do not check status after the call to +createDatabase(), because in case of error C++ or Pascal exception +will be raised (therefore it's very good idea to have +try/catch/except syntax in your program). We also use two new +functions from IXpbBuilder – getBufferLength() and getBuffer(), +which extract data from interface in native parameters block format. +As you can see there is no need to check explicitly for status of +functions, returning intermediate results.

+


+ +

+

Detaching +from just created database is trivial:

+

att->detach(&status);

+


+ +

+

Now +it remains to enclose all operators into try block and write a +handler in catch block. When using ThrowStatusWrapper you should +always catch defined in C++ API exception class FbException, in +Pascal you must also work with class FbException. Exception handler +block in simplest case may look this way:

+

catch +(const FbException& error)

+

{

+

char +buf[256];

+

utl->formatStatus(buf, +sizeof(buf), error.getStatus());

+

fprintf(stderr, +"%s\n", buf);

+

}

+

Pay +attention that here we use one more function from IUtil +– formatStatus(). It returns in buffer text, describing an error +(warning), stored in IStatus parameter.

+


+ +

+

To +attach to existing database just use attachDatabase() method of +IProvider instead createDatabase(). All parameters are the same for +both methods.

+

att += prov->attachDatabase(&status, "fbtests.fdb", 0, +NULL);

+

This +sample is using no additional DPB parameters. Take into account that +without logon/password any remote connection will fail if no trusted authorization plugin is configured. Certainly login info may be also provided in environment (in ISC_USER and ISC_PASSWORD variables) like -it was before.

-


-

-

Our examples contain -complete samples, dedicated except others to creating databases – -01.create.cpp and 01.create.pas. When samples are present it will be -very useful to build and try to run appropriate samples when reading -this document.

-


-

-

Working with transactions.

-

Only creating empty -databases is definitely not enough to work with RDBMS. We want to be -able to create various objects (like tables and so on) in database -and insert data in that tables. Any operation within database is -performed by firebird under transaction control. Therefore first of -all we must learn to start transaction. Here we do not discuss -distributed transactions (supported by IDtc +it was before.

+


+ +

+

Our +examples contain complete samples, dedicated except others to +creating databases – 01.create.cpp and 01.create.pas. When samples +are present it will be very useful to build and try to run +appropriate samples when reading this document.

+


+ +

+

Working with transactions.

+

Only +creating empty databases is definitely not enough to work with RDBMS. +We want to be able to create various objects (like tables and so on) +in database and insert data in that tables. Any operation within +database is performed by firebird under transaction control. +Therefore first of all we must learn to start transaction. Here we do +not discuss distributed transactions (supported by IDtc interface) to avoid unneeded to most users overcomplication. Starting of non-distributed transaction is very simple and done via attachment -interface:

-

ITransaction* -tra = att->startTransaction(&status, 0, NULL);

-

In this sample default -transaction parameters are used – no TPB is passed to -startTransaction() method. If you need non-default parameters you may -create appropriate IXpbBuilder, add -required items to it:

-

IXpbBuilder* -tpb = utl->getXpbBuilder(&status, IXpbBuilder::TPB, NULL, 0);

-

tpb->insertTag(&status, -isc_tpb_read_committed);

-

and pass resulting TPB to -startTransaction():

-

ITransaction* tra = -att->startTransaction(&status, tpb->getBufferLength(&status), -tpb->getBuffer(&status));

-


-

-

Transaction interface is -used as a parameter in a lot of other API calls but itself it does -not perform any actions except commit/rollback transaction, may be -retaining:

-

tra->commit(&status);

-


-

-

You may take a look at how -to start and commit transaction in examples 01.create.cpp and -01.create.pas.

-


-

-

Executing SQL operator without input parameters and -returned rows.

-

With started transaction -we are ready to execute our first SQL operators. Used for it -execute() method in IAttachment is rather -universal and may be also used to execute SQL operators with input -and output parameters (which is typical for EXECUTE PROCEDURE -statement), but right now we will use the simple most form of it. -Both DDL and DML operators can be executed:

-

att->execute(&status, +interface:

+

ITransaction* +tra = att->startTransaction(&status, 0, NULL);

+

In +this sample default transaction parameters are used – no TPB is +passed to startTransaction() method. If you need non-default +parameters you may create appropriate IXpbBuilder, +add required items to it:

+

IXpbBuilder* +tpb = utl->getXpbBuilder(&status, IXpbBuilder::TPB, NULL, 0);

+

tpb->insertTag(&status, +isc_tpb_read_committed);

+

and +pass resulting TPB to startTransaction():

+

ITransaction* +tra = att->startTransaction(&status, +tpb->getBufferLength(&status), tpb->getBuffer(&status));

+


+ +

+

Transaction +interface is used as a parameter in a lot of other API calls but +itself it does not perform any actions except commit/rollback +transaction, may be retaining:

+

tra->commit(&status);

+


+ +

+

You +may take a look at how to start and commit transaction in examples +01.create.cpp and 01.create.pas.

+


+ +

+

Executing SQL operator +without input parameters and returned rows.

+

With +started transaction we are ready to execute our first SQL operators. +Used for it execute() method in IAttachment +is rather universal and may be also used to execute SQL operators +with input and output parameters (which is typical for EXECUTE +PROCEDURE statement), but right now we will use the simple most form +of it. Both DDL and DML operators can be executed:

+

att->execute(&status, tra, 0, "create table dates_table (d1 date)", -SQL_DIALECT_V6, NULL, NULL, NULL, NULL);

-

tra->commitRetaining(&status);

-

att->execute(&status, +SQL_DIALECT_V6, NULL, NULL, NULL, NULL);

+

tra->commitRetaining(&status);

+

att->execute(&status, tra, 0, "insert into dates_table values (CURRENT_DATE)", -SQL_DIALECT_V6, NULL, NULL, NULL, NULL);

-

As you can see transaction -interface is a required parameter for execute() method (must be NULL -only if you execute START TRANSACTION statement). Next follows length -of SQL operator (may be zero causing use of C rules to determine -string length), text of operator and SQL dialect that should be used -for it. The following for NULLs stand for metadata descriptions and -buffers of input parameters and output data. Complete description of -this method is provided in IAttachment -interface.

-


-

-

You may take a look at how -to start and commit transaction in examples 01.create.cpp and -01.create.pas.

-


-

-

Executing SQL operator with input parameters.

-

There are 2 ways to -execute statement with input parameters. Choice of correct method -depends upon do you need to execute it more than once and do you know -in advance format of parameters. When that format is known and -statement is needed to be run only once single call to +SQL_DIALECT_V6, NULL, NULL, NULL, NULL);

+

As +you can see transaction interface is a required parameter for +execute() method (must be NULL only if you execute START TRANSACTION +statement). Next follows length of SQL operator (may be zero causing +use of C rules to determine string length), text of operator and SQL +dialect that should be used for it. The following for NULLs stand for +metadata descriptions and buffers of input parameters and output +data. Complete description of this method is provided in IAttachment +interface.

+


+ +

+

You +may take a look at how to start and commit transaction in examples +01.create.cpp and 01.create.pas.

+


+ +

+

Executing SQL operator +with input parameters.

+

There +are 2 ways to execute statement with input parameters. Choice of +correct method depends upon do you need to execute it more than once +and do you know in advance format of parameters. When that format is +known and statement is needed to be run only once single call to IAttachment::execute() may be used. In other cases SQL statement should be prepared first and after it executed, may be many times -with different parameters.

-


-

-

To prepare SQL statement -for execution use prepare() method of IAttachment -interface:

-

IStatement* +with different parameters.

+


+ +

+

To +prepare SQL statement for execution use prepare() method of +IAttachment interface:

+

IStatement* stmt = att->prepare(&status, tra, 0, “UPDATE department SET -budget = ? * budget + budget WHERE dept_no = ?”,

-

SQL_DIALECT_V6, -IStatement::PREPARE_PREFETCH_METADATA);

-

If you are not going to -use parameters description from firebird (i.e. you can provide that -information yourself) please use IStatement::PREPARE_PREFETCH_NONE -instead PREPARE_PREFETCH_METADATA – this will save client/server -traffic and server resources a bit.

-


-

-

In ISC API XSQLDA is used -to describe format of statement parameters. New API does not use -XSQLDA – instead interface IMessageMetadata is used. A set of input -parameters (and also a row fetched from cursor) is described in -firebird API in same way and later called message. IMessageMetadata -is passed as a parameter to the methods performing message exchange -between your program and database engine. There are many ways to have -an instance of IMessageMetadata – one can:

- -


-

-

Getting metadata from -prepared statement is very simple – method getInputMetadata() -return interface describing input message (i.e. statement -parameters), interface returned by getOutputMetadata() describes -output message (i.e. row in selected data or values returned by -procedure). In our case we can:

-

IMessageMetadata* -meta = stmt->getInputMetadata(&status);

-


-

-

Or we can build message -metadata ourself. First of all we need builder interface for it:

-

IMetadataBuilder* -builder = master->getMetadataBuilder(&status, 2);

-

Second parameter is -expected number of fields in the message, it can be changed later, -i.e. that's just an optimization.

-

Now it's necessary to set -individual fields characteristics in the builder. An absolute minimum -is field types and length for string fields:

-

builder->setType(&status, -0, SQL_DOUBLE + 1);

-

builder->setType(&status, -1, SQL_TEXT + 1);

-

builder->setLength(&status, -1, 3);

-

New -API is using old constants for SQL types, smallest bit as earlier -stands for nullability. In some case it may also make sense to set -sub-type (for blobs), character set (for text fields) or scale (for -numeric fields). And finally it's time to get an instance of -IMessageMetadata:

-

IMessageMetadata* -meta = builder->getMetadata(&status);

-


-

-

Here -we do not discuss in details own implementation of IMessageMetadata. -If one cares there is a sample 05.user_metadata.cpp.

-

So finally we have -obtained (one or another way) an instance of metadata description of -input parameters. But to work with a message we also need buffer for -it. Buffer size is one of main message metadata characteristics and -it's returned by method in IMessageMetadata:

-

char* buffer = new -char[meta->getMessageLength(&status)];

-

To deal with individual -values inside buffer offset to them should be taken into an account. -IMessageMetadata is aware of offsets for all values in a message, -using it we can create pointers to them:

-

double* percent_inc = -(double*) &buffer[meta->getOffset(&status, 0)];

-

char* dept_no = -&buffer[meta->getOffset(&status, 1)];

-

Also let's do not forget -to set to NOT NULL null flags:

-

short* flag = -(short*)&buffer[meta->getNullOffset(&status, 0)];

-

*flag = 0;

-

flag = (short*) -&buffer[meta->getNullOffset(&status, 1)];

-

*flag = 0;

-


-

-

After finishing with -offsets we are ready to execute statement with some parameters -values:

-

getInputValues(dept_no, -percent_inc);

-

and may execute prepared -statement:

-

stmt->execute(&status, -tra, meta, buffer, NULL, NULL);

-

Two more NULLs in the end -of parameters stand for output message and is used typically for -EXECUTE PROCEDURE statement.

-


-

-

If you do not need to get -metadata from statement and plan to execute it only once you may -choose a simpler way – use method execute() in IAttachment -interface:

-

att->execute(&status, +budget = ? * budget + budget WHERE dept_no = ?”,

+

SQL_DIALECT_V6, +IStatement::PREPARE_PREFETCH_METADATA);

+

If +you are not going to use parameters description from firebird (i.e. +you can provide that information yourself) please use +IStatement::PREPARE_PREFETCH_NONE instead PREPARE_PREFETCH_METADATA – +this will save client/server traffic and server resources a bit.

+


+ +

+

In +ISC API XSQLDA is used to describe format of statement parameters. +New API does not use XSQLDA – instead interface IMessageMetadata is +used. A set of input parameters (and also a row fetched from cursor) +is described in firebird API in same way and later called message. +IMessageMetadata is passed as a +parameter to the methods performing message exchange between your +program and database engine. There are many ways to have an instance +of IMessageMetadata – one can:

+ +


+ +

+

Getting +metadata from prepared statement is very simple – method +getInputMetadata() return interface describing input message (i.e. +statement parameters), interface returned by getOutputMetadata() +describes output message (i.e. row in selected data or values +returned by procedure). In our case we can:

+

IMessageMetadata* +meta = stmt->getInputMetadata(&status);

+


+ +

+

Or +we can build message metadata ourself. First of all we need builder +interface for it:

+

IMetadataBuilder* +builder = master->getMetadataBuilder(&status, 2);

+

Second +parameter is expected number of fields in the message, it can be +changed later, i.e. that's just an optimization.

+

Now +it's necessary to set individual fields characteristics in the +builder. An absolute minimum is field types and length for string +fields:

+

builder->setType(&status, +0, SQL_DOUBLE + 1);

+

builder->setType(&status, +1, SQL_TEXT + 1);

+

builder->setLength(&status, +1, 3);

+

+New API is using old constants +for SQL types, smallest bit as earlier stands for nullability. In +some case it may also make sense to set sub-type (for blobs), +character set (for text fields) or scale (for numeric fields). And +finally it's time to get an instance of IMessageMetadata:

+

IMessageMetadata* +meta = builder->getMetadata(&status);

+


+ +

+

+Here we do not discuss in +details own implementation of IMessageMetadata. If one cares there is +a sample 05.user_metadata.cpp.

+

So +finally we have obtained (one or another way) an instance of metadata +description of input parameters. But to work with a message we also +need buffer for it. Buffer size is one of main message metadata +characteristics and it's returned by method in IMessageMetadata:

+

char* +buffer = new char[meta->getMessageLength(&status)];

+

To +deal with individual values inside buffer offset to them should be +taken into an account. IMessageMetadata is aware of offsets for all +values in a message, using it we can create pointers to them:

+

double* +percent_inc = (double*) &buffer[meta->getOffset(&status, +0)];

+

char* +dept_no = &buffer[meta->getOffset(&status, 1)];

+

Also +let's do not forget to set to NOT NULL null flags:

+

short* +flag = (short*)&buffer[meta->getNullOffset(&status, 0)];

+

*flag += 0;

+

flag += (short*) &buffer[meta->getNullOffset(&status, 1)];

+

*flag += 0;

+


+ +

+

After +finishing with offsets we are ready to execute statement with some +parameters values:

+

getInputValues(dept_no, +percent_inc);

+

and +may execute prepared statement:

+

stmt->execute(&status, +tra, meta, buffer, NULL, NULL);

+

Two +more NULLs in the end of parameters stand for output message and is +used typically for EXECUTE PROCEDURE statement.

+


+ +

+

If +you do not need to get metadata from statement and plan to execute it +only once you may choose a simpler way – use method execute() in +IAttachment interface:

+

att->execute(&status, tra, 0, "UPDATE department SET budget = ? * budget + budget -WHERE dept_no = ?", SQL_DIALECT_V6, meta, buffer, NULL, NULL);

-

In that case you do not -need to use IStatement at all.

-


-

-

An example how to execute -UPDATE with parameters is present in 02.update.cpp, you will also see -how raised in trigger/procedure exception may be caught by C++ -program.

-


-

-

Opening cursor and fetching data from it.

-

The only way to get rows -of data, returned by SELECT operator, in OO API is to use IResultSet -interface. This interface is returned by openCursor() method in both -IAttachment and IStatement. openCursor() is in most aspects alike -execute() and a choice how to open cursor (using prepared statement -or directly from attachment interface) is the same. In the samples -03.select.cpp and 04.print_table.cpp both methods are used. Let's pay -attention at one specific openCursor() feature compared with -execute() - one does not pass buffer for output message into -openCursor(), it will be passed later when data is fetched from -cursor. This makes it possible to open cursor with unknown format of -output message (NULL is passed instead output metadata). Firebird is -using in this case default message format which may be requested from -IResultSet interface:

-

const char* sql = -"select * from ..."; // some select statement

-


-

-

IResultSet* +WHERE dept_no = ?", SQL_DIALECT_V6, meta, buffer, NULL, NULL);

+

In +that case you do not need to use IStatement +at all.

+


+ +

+

An +example how to execute UPDATE with parameters is present in +02.update.cpp, you will also see how raised in trigger/procedure +exception may be caught by C++ program.

+


+ +

+

Opening cursor and +fetching data from it.

+

The +only way to get rows of data, returned by SELECT operator, in OO API +is to use IResultSet interface. This +interface is returned by openCursor() method in both IAttachment and +IStatement. openCursor() is in most aspects alike execute() and a +choice how to open cursor (using prepared statement or directly from +attachment interface) is the same. In the samples 03.select.cpp and +04.print_table.cpp both methods are used. Let's pay attention at one +specific openCursor() feature compared with execute() - one does not +pass buffer for output message into openCursor(), it will be passed +later when data is fetched from cursor. This makes it possible to +open cursor with unknown format of output message (NULL is passed +instead output metadata). Firebird is using in this case default +message format which may be requested from IResultSet interface:

+

const +char* sql = "select * from ..."; // some select statement

+


+ +

+

IResultSet* curs = att->openCursor(&status, tra, 0, sql, SQL_DIALECT_V6, -NULL, NULL, NULL, NULL, 0);

-

IMessageMetadata* -meta = curs->getMetadata(&status);

-

Later this metadata may be -used to allocate buffer for data and parse fetched rows.

-


-

-

As an alternative one can -first prepare statement, get metadata from prepared statement and -after it open cursor. This is preferred way if cursor is likely to be -opened >1 times.

-

IStatement* +NULL, NULL, NULL, NULL, 0);

+

IMessageMetadata* +meta = curs->getMetadata(&status);

+

Later +this metadata may be used to allocate buffer for data and parse +fetched rows.

+


+ +

+

As +an alternative one can first prepare statement, get metadata from +prepared statement and after it open cursor. This is preferred way if +cursor is likely to be opened >1 times.

+

IStatement* stmt = att->prepare(&status, tra, 0, sql, SQL_DIALECT_V6, -Istatement::PREPARE_PREFETCH_METADATA);

-

IMessageMetadata* -meta = stmt->getOutputMetadata(&status);

-

IResultSet* -curs = stmt->openCursor(&status, tra, NULL, NULL, NULL, 0);

-


-

-

We have obtained (one or -another way) an instance of metadata description of output fields (a -row in a set). To work with a message we also need buffer for it:

-

unsigned char* buffer = -new unsigned char[meta->getMessageLength(&status)];

-


-

-

IResultSet has a lot of -various fetch methods but when cursor is not opened with SCROLL -option only fetchNext() works, i.e. one can navigate only forward -record by record. In addition to errors and warnings in status -fetchNext() returns completion code, which may have values RESULT_OK -(when buffer is filled with values for next row) or RESULT_NO_DATA -(when no more rows left in cursor). RESULT_NO_DATA is not error -state, it's normal state after completion of the method, but we know -that data in cursor is over. If status wrapper, not throwing -exception in case of error return is used, one more value – +Istatement::PREPARE_PREFETCH_METADATA);

+

IMessageMetadata* +meta = stmt->getOutputMetadata(&status);

+

IResultSet* +curs = stmt->openCursor(&status, tra, NULL, NULL, NULL, 0);

+


+ +

+

We +have obtained (one or another way) an instance of metadata +description of output fields (a row in a set). To work with a message +we also need buffer for it:

+

unsigned +char* buffer = new unsigned char[meta->getMessageLength(&status)];

+


+ +

+

IResultSet +has a lot of various fetch methods but when cursor is not opened with +SCROLL option only fetchNext() works, i.e. one can navigate only +forward record by record. In addition to errors and warnings in +status fetchNext() returns completion code, which may have values +RESULT_OK (when buffer is filled with values for next row) or +RESULT_NO_DATA (when no more rows left in cursor). RESULT_NO_DATA is +not error state, it's normal state after completion of the method, +but we know that data in cursor is over. If status wrapper, not +throwing exception in case of error return is used, one more value – RESULT_ERROR – may be returned, that means no data in buffer and error vector in status. Method fetchNext() is usually called in a -cycle:

-

while -(curs->fetchNext(&status, buffer) == IStatus::RESULT_OK)

-

{

-

// row processing

-

}

-


-

-

What is done during row -processing depends upon your needs. To access particular field -field's offset should be used:

-

unsigned char* -field_N_ptr = buffer + meta->getOffset(&status, n);

-

where -n is the number of a field in a message. That pointer should be -casted to appropriate type, depending upon field type. For example, -for a VARCHAR field cast to struct vary should be used:

-

vary* v_ptr = (vary*) -(buffer + meta->getOffset(&status, n));

-

Now we may print the value -of a field:

-

printf(“field %s -value is %*.*s\n”, meta->getField(&status, n), -v_ptr->vary_length, v_ptr->vary_length, v_ptr->vary_string);

-


-

-

If you need maximum -performance it will be good idea to cache needed metadata values like -it's done in our samples 03.select.cpp and 04.print_table.cpp.

-


-

-

Using FB_MESSAGE macro for static messages.

-

Working with data using -offsets is rather efficient but requires a lot of code to be written. -In C++ this problem can be solved using templates, but even compared -with them the most convenient way to work with the message is to -represent it in native (for given language) way – structure in -C/C++, record in Pascal, etc. Certainly this works only if format of -a message is known in advance. To help building such structures in -C++ firebird contains special macro FB_MESSAGE.

-


-

-

FB_MESSAGE has 3 arguments -– message (struct) name, type of status wrapper and list of fields. -Usage of first and second is obvious, list of fields contains pairs -(field_type, field_name), where field_type is one of the following:

-

FB_BIGINT

-

FB_BLOB

-

FB_BOOLEAN

-

FB_CHAR(len)

-

FB_DATE

-

FB_DOUBLE

-

FB_FLOAT

-

FB_INTEGER

-

FB_INTL_CHAR(len, charSet)

-

FB_INTL_VARCHAR(len, -charSet)

-

FB_SCALED_BIGINT(x)

-

FB_SCALED_INTEGER(x)

-

FB_SCALED_SMALLINT(x)

-

FB_SMALLINT

-

FB_TIME

-

FB_TIMESTAMP

-

FB_VARCHAR(len)

-

In generated by -preprocessor structure integer and float types are matched with -appropriate C types, date and time – with classes FbDate -and FbTime (all mentioned here classes are in -namespace Firebird), timestamp – with class FbTimestamp, containing -two public data members date and time of appropriate class, char - -with struct FbChar and varchar – with struct -FbVarChar. For each field preprocessor -creates two data members in the message – name -for field/parameter value and nameNull -for NULL indicator. Message constructor has 2 parameters -– pointer to status wrapper and master interface:

-

FB_MESSAGE(Output, -ThrowStatusWrapper,

-

(FB_SMALLINT, -relationId)

-

(FB_CHAR(31), -relationName)

-

(FB_VARCHAR(100), -description)

-

) output(&status, -master);

-


-

-

For static messages use of -FB_MESSAGE is sooner of all the best choice – they can be at the -same time easily passed to execute, openCursor and fetch methods:

-

rs = -att->openCursor(&status, tra, 0, sqlText,

-

SQL_DIALECT_V6, NULL, -NULL, output.getMetadata(), NULL, 0);

-

and used to work with -values of individual fields:

-

while +cycle:

+

while +(curs->fetchNext(&status, buffer) == IStatus::RESULT_OK)

+

{

+

// +row processing

+

}

+


+ +

+

What +is done during row processing depends upon your needs. To access +particular field field's offset should be used:

+

unsigned +char* field_N_ptr = buffer + meta->getOffset(&status, n);

+

+where n is the number of a +field in a message. That pointer should be casted to appropriate +type, depending upon field type. For example, for a VARCHAR field +cast to struct vary should be used:

+

vary* +v_ptr = (vary*) (buffer + meta->getOffset(&status, n));

+

Now +we may print the value of a field:

+

printf(“field +%s value is %*.*s\n”, meta->getField(&status, n), +v_ptr->vary_length, v_ptr->vary_length, v_ptr->vary_string);

+


+ +

+

If +you need maximum performance it will be good idea to cache needed +metadata values like it's done in our samples 03.select.cpp and +04.print_table.cpp.

+


+ +

+

Using FB_MESSAGE macro for +static messages.

+

Working +with data using offsets is rather efficient but requires a lot of +code to be written. In C++ this problem can be solved using +templates, but even compared with them the most convenient way to +work with the message is to represent it in native (for given +language) way – structure in C/C++, record in Pascal, etc. +Certainly this works only if format of a message is known in advance. +To help building such structures in C++ firebird contains special +macro FB_MESSAGE.

+


+ +

+

FB_MESSAGE +has 3 arguments – message (struct) name, type of status wrapper and +list of fields. Usage of first and second is obvious, list of fields +contains pairs (field_type, field_name), where field_type is one of +the following:

+

FB_BIGINT

+

FB_BLOB

+

FB_BOOLEAN

+

FB_CHAR(len)

+

FB_DATE

+

FB_DOUBLE

+

FB_FLOAT

+

FB_INTEGER

+

FB_INTL_CHAR(len, +charSet)

+

FB_INTL_VARCHAR(len, +charSet)

+

FB_SCALED_BIGINT(x)

+

FB_SCALED_INTEGER(x)

+

FB_SCALED_SMALLINT(x)

+

FB_SMALLINT

+

FB_TIME

+

FB_TIMESTAMP

+

FB_VARCHAR(len)

+

In +generated by preprocessor structure integer and float types are +matched with appropriate C types, date and time – with classes +FbDate and FbTime (all +mentioned here classes are in namespace Firebird), timestamp – with +class FbTimestamp, containing two public data members date and time +of appropriate class, char - with struct FbChar +and varchar – with struct FbVarChar. For +each field preprocessor creates two data members in the message – +name for +field/parameter value and nameNull +for NULL indicator. Message +constructor has 2 parameters – pointer to status wrapper and master +interface:

+

FB_MESSAGE(Output, +ThrowStatusWrapper,

+

(FB_SMALLINT, +relationId)

+

(FB_CHAR(31), +relationName)

+

(FB_VARCHAR(100), +description)

+

) +output(&status, master);

+


+ +

+

For +static messages use of FB_MESSAGE is sooner of all the best choice – +they can be at the same time easily passed to execute, openCursor and +fetch methods:

+

rs += att->openCursor(&status, tra, 0, sqlText,

+

SQL_DIALECT_V6, +NULL, NULL, output.getMetadata(), NULL, 0);

+

and +used to work with values of individual fields:

+

while (rs->fetchNext(&status, output.getData()) == -IStatus::RESULT_OK)

-

{

-

printf("%4d +IStatus::RESULT_OK)

+

{

+

printf("%4d %31.31s %*.*s\n", output->relationId, -output->relationName.str,

-

output->descriptionNull -? 0 : output->description.length,

-

output->descriptionNull -? 0 : output->description.length, output->description.str);

-

}

-


-

-

An example of using macro -FB_MESSAGE to work with messages is in the sample 06.fb_message.cpp.

-


-

-

Working with blobs.

-

For blobs in message -buffer firebird stores blob identifier – an 8-byte entity which -should be aligned on 4-byte boundary. Identifier has ISC_QUAD type. -Interface IAttachment has 2 methods to work -with blobs – openBlob() and createBlob(), both returning interface -IBlob and having same set of parameters, but -performing somewhat contrary actions: openBlob() takes blob -identifier from the message and prepares blob for reading but -createBlob() creates new blob, puts it's identifier into message and -prepares blob for writing. -

-


-

-

To work with blobs one -must first of all include blob identifier into the message. If you -get metadata from firebird engine field of appropriate type will be -already present. You just use it's offset (assuming variable -blobFieldNumber contains number of blob field) (and appropriate null -offset to check for nulls or set null flag) to obtain pointer into -the message buffer:

-

ISC_QUAD* blobPtr = -(ISC_QUAD*) &buffer[metadata->getOffset(&status, -blobFieldNumber)];

-

ISC_SHORT* blobNullPtr -= (ISC_SHORT*) &buffer[metadata->getNullOffset(&status, -blobFieldNumber)];

-


-

-

If you use static messages -and FB_MESSAGE macro blob field is declared as having FB_BLOB type:

-

FB_MESSAGE(Msg, -ThrowStatusWrapper,

-

(FB_BLOB, b)

-

) message(&status, -master);

-

ISC_QUAD* blobPtr = -&message->b;

-

ISC_SHORT* blobNullPtr -= &message->bNull;

-


-

-

To create new blob invoke -createBlob() method:

-

IBlob* -blob = att->createBlob(status, tra, blobPtr, 0, NULL);

-

Last two parameters are -required only if you want to use blob filters or use stream blob, -that's out of scope here.

-

Blob interface is ready to -accept data into blob. Use putSegment() method to send data to -engine:

-

void* segmentData;

-

unsigned segmentLength;

-

while -(userFunctionProvidingBlobData(&segmentData, &segmentLength))

-

blob->putSegment(&status, -segmentLength, segmentData);

-

After sending some data to -blob do not forget to close blob interface:

-

blob->close(&status);

-

Make sure that null flag -is not set (not required if you nullified all message buffer before -creating blob):

-

*blobNullPtr = 0;

-

and message, containing -blob, may be used in insert or update statement. After execution of -that statement new blob will be stored in database.

-


-

-

To read a blob begin with -getting containing it's identifier message from firebird engine. This -may be done using fetch() or execute() methods. After it use -openBlob() attachment's method:

-

IBlob* -blob = att->openBlob(status, tra, blobPtr, 0, NULL);

-

Blob interface is ready to -provide blob data. Use getSegment() method to receive data from -engine:

-

char buffer[BUFSIZE];

-

unsigned actualLength;

-

for(;;)

-

{

-

switch +output->relationName.str,

+

output->descriptionNull +? 0 : output->description.length,

+

output->descriptionNull +? 0 : output->description.length, output->description.str);

+

}

+


+ +

+

An +example of using macro FB_MESSAGE to work with messages is in the +sample 06.fb_message.cpp.

+


+ +

+

Working with blobs.

+

For +blobs in message buffer firebird stores blob identifier – an 8-byte +entity which should be aligned on 4-byte boundary. Identifier has +ISC_QUAD type. Interface IAttachment has 2 +methods to work with blobs – openBlob() and createBlob(), both +returning interface IBlob and having same set of +parameters, but performing somewhat contrary actions: openBlob() +takes blob identifier from the message and prepares blob for reading +but createBlob() creates new blob, puts it's identifier into message +and prepares blob for writing. +

+


+ +

+

To +work with blobs one must first of all include blob identifier into +the message. If you get metadata from firebird engine field of +appropriate type will be already present. You just use it's offset +(assuming variable blobFieldNumber contains number of blob field) +(and appropriate null offset to check for nulls or set null flag) to +obtain pointer into the message buffer:

+

ISC_QUAD* +blobPtr = (ISC_QUAD*) &buffer[metadata->getOffset(&status, +blobFieldNumber)];

+

ISC_SHORT* +blobNullPtr = (ISC_SHORT*) &buffer[metadata->getNullOffset(&status, +blobFieldNumber)];

+


+ +

+

If +you use static messages and FB_MESSAGE macro blob field is declared +as having FB_BLOB type:

+

FB_MESSAGE(Msg, +ThrowStatusWrapper,

+

(FB_BLOB, +b)

+

) +message(&status, master);

+

ISC_QUAD* +blobPtr = &message->b;

+

ISC_SHORT* +blobNullPtr = &message->bNull;

+


+ +

+

To +create new blob invoke createBlob() method:

+

IBlob* +blob = att->createBlob(status, tra, blobPtr, 0, NULL);

+

Last +two parameters are required only if you want to use blob filters or +use stream blob, that's out of scope here.

+

Blob +interface is ready to accept data into blob. Use putSegment() method +to send data to engine:

+

void* +segmentData;

+

unsigned +segmentLength;

+

while +(userFunctionProvidingBlobData(&segmentData, &segmentLength))

+

blob->putSegment(&status, +segmentLength, segmentData);

+

After +sending some data to blob do not forget to close blob interface:

+

blob->close(&status);

+

Make +sure that null flag is not set (not required if you nullified all +message buffer before creating blob):

+

*blobNullPtr += 0;

+

and +message, containing blob, may be used in insert or update statement. +After execution of that statement new blob will be stored in +database.

+


+ +

+

To +read a blob begin with getting containing it's identifier message +from firebird engine. This may be done using fetch() or execute() +methods. After it use openBlob() attachment's method:

+

IBlob* +blob = att->openBlob(status, tra, blobPtr, 0, NULL);

+

Blob +interface is ready to provide blob data. Use getSegment() method to +receive data from engine:

+

char +buffer[BUFSIZE];

+

unsigned +actualLength;

+

for(;;)

+

{

+

switch (blob->getSegment(&status, sizeof(buffer), buffer, -&actualLength))

-

{

-

case -IStatus::RESULT_OK:

-

userFunctionAcceptingBlobData(buffer, -actualLength, true);

-

continue;

-

case -IStatus::RESULT_SEGMENT:

-

userFunctionAcceptingBlobData(buffer, -actualLength, false);

-

continue;

-

default:

-

break;

-

}

-

}

-

Last parameter in -userFunctionAcceptingBlobData() is a flag that end of segment is -reached – when getSegment() returns RESULT_SEGMENT completion code -that function is notified (by passing false as last parameter) that -segment was not read completely and continuation is expected at next -call.

-

After finishing with blob -do not forget top close it:

-

blob->close(&status);

-


-

-

Working with events.

-

Events interface was not -completed in FB3, we expect to have something more interesting in -next version. The minimum existing support is as follows: IAttachment -contains call queEvents() which performs almost same functions as -isc_que_events() call. Instead the pair of parameters -FPTR_EVENT_CALLBACK ast and -void* arg, required to +&actualLength))

+

{

+

case +IStatus::RESULT_OK:

+

userFunctionAcceptingBlobData(buffer, +actualLength, true);

+

continue;

+

case +IStatus::RESULT_SEGMENT:

+

userFunctionAcceptingBlobData(buffer, +actualLength, false);

+

continue;

+

default:

+

break;

+

}

+

}

+

Last +parameter in userFunctionAcceptingBlobData() is a flag that end of +segment is reached – when getSegment() returns RESULT_SEGMENT +completion code that function is notified (by passing false as last +parameter) that segment was not read completely and continuation is +expected at next call.

+

After +finishing with blob do not forget top close it:

+

blob->close(&status);

+


+ +

+

Working with events.

+

Events +interface was not completed in FB3, we expect to have something more +interesting in next version. The minimum existing support is as +follows: IAttachment contains call +queEvents() which performs almost same functions as isc_que_events() +call. Instead the pair of parameters FPTR_EVENT_CALLBACK +ast and void* +arg, required to invoke user code when event happens in firebird engine, callback interface IEventCallback is used. This is traditional approach which helps to avoid non-safe casts from void* in user function. Another important difference is that instead event identifier (a kind of -handler) this function returns reference counted interface IEvents +handler) this function returns reference counted interface IEvents having method cancel() used when waiting for event should be stopped. Unlike identifier which is automatically destroyed when event arrives interface can not be automatically destroyed – in case when event is received right before canceling interface call to cancel() would cause segfault when interface is already destroyed. Therefore -interface IEvents must be explicitly released +interface IEvents must be explicitly released after receiving an event. This may be done for example right before -queuing for an event next time:

-

events->release();

-

events = NULL;

-

events = -attachment->queEvents(&status, this, eveLen, eveBuffer);

-

Setting interface pointer -to NULL is useful in case of exception during queEvents. In other -aspects events handling did not change compared with ISC API. Please -use for additional details our sample 08.events.cpp. -

-


-

-

Using services.

-

To begin to use services -one should first of all connect to service manager. This is done -using attachServiceManager() method of IProvider. -This method returns IService interface which -is used later to talk to service. To prepare SPB to attach to service -manager one can use IXpbBuilder:

-

IXpbBuilder* spb1 = -utl->getXpbBuilder(&status, IXpbBuilder::SPB_ATTACH, NULL, 0);

-

spb1->insertString(&status, -isc_spb_user_name, “sysdba”);

-

spb1->insertString(&status, -isc_spb_password, “masterkey”);

-

and proceed with attach:

-

IService* +queuing for an event next time:

+

events->release();

+

events += NULL;

+

events += attachment->queEvents(&status, this, eveLen, eveBuffer);

+

Setting +interface pointer to NULL is useful in case of exception during +queEvents. In other aspects events handling did not change compared +with ISC API. Please use for additional details our sample +08.events.cpp. +

+


+ +

+

Using services.

+

To +begin to use services one should first of all connect to service +manager. This is done using attachServiceManager() method of +IProvider. This method returns IService +interface which is used later to talk to service. To prepare SPB to +attach to service manager one can use IXpbBuilder:

+

IXpbBuilder* +spb1 = utl->getXpbBuilder(&status, IXpbBuilder::SPB_ATTACH, +NULL, 0);

+

spb1->insertString(&status, +isc_spb_user_name, “sysdba”);

+

spb1->insertString(&status, +isc_spb_password, “masterkey”);

+

and +proceed with attach:

+

IService* svc = prov->attachServiceManager(&status, “service_mgr”, -spb1->getBufferLength(&status), spb1->getBuffer(&status));

-


-

-

Using IService one can -perform both available for services actions – start services and -query various information about started utilities and server in -general. When querying information one limitation takes place – -formats of parameter blocks, used by query() method, in Firebird 3 -are not supported by IXpbBuilder. Support will be probably added in -later versions, in Firebird 3 you will have to build and analyze that -blocks manually. Format of that blocks matches old format (used in -ISC API) one to one. -

-


-

-

To start service one -should first of all create appropriate SPB:

-

IXpbBuilder* spb2 = -utl->getXpbBuilder(&status, IXpbBuilder::SPB_START, NULL, 0);

-

and add required items to -it. For example, to print encryption statistics for database employee -the following should be placed into SPB:

-

spb2->insertTag(&status, -isc_action_svc_db_stats);

-

spb2->insertString(&status, -isc_spb_dbname, "employee");

-

spb2->insertInt(&status, -isc_spb_options, isc_spb_sts_encryption);

-

After it service can be -started using start() method of IService -interface:

-

svc->start(&status, -spb2->getBufferLength(&status), spb2->getBuffer(&status));

-


-

-

Many started services -(including mentioned here gstat) return text information during -execution. To display it one should query started service anout that -information line by line. This is done by calling query() method of -IService interface with appropriate send and -receive blocks of parameters. Send block may contain various helper -information (like timeout when querying service) or information to be -passed to stdin of service utility or may be empty in the simplest -case. Receive block must contain list of tags you want to receive -from service. For most of utilities this is single isc_info_svc_line:

-

const unsigned char -receiveItems1[] = {isc_info_svc_line};

-

To query information one -also needs a buffer for that information:

-

unsigned char -results[1024];

-

After that preliminary -steps we are ready to query service in a loop (each line returned in -a single call to query()):

-

do

-

{

-

svc->query(&status, +spb1->getBufferLength(&status), spb1->getBuffer(&status));

+


+ +

+

Using +IService one can perform both available for services actions – +start services and query various information about started utilities +and server in general. When querying information one limitation takes +place – formats of parameter blocks, used by query() method, in +Firebird 3 are not supported by IXpbBuilder. Support will be probably +added in later versions, in Firebird 3 you will have to build and +analyze that blocks manually. Format of that blocks matches old +format (used in ISC API) one to one. +

+


+ +

+

To +start service one should first of all create appropriate SPB:

+

IXpbBuilder* +spb2 = utl->getXpbBuilder(&status, IXpbBuilder::SPB_START, +NULL, 0);

+

and +add required items to it. For example, to print encryption statistics +for database employee the following should be placed into SPB:

+

spb2->insertTag(&status, +isc_action_svc_db_stats);

+

spb2->insertString(&status, +isc_spb_dbname, "employee");

+

spb2->insertInt(&status, +isc_spb_options, isc_spb_sts_encryption);

+

After +it service can be started using start() method of IService +interface:

+

svc->start(&status, +spb2->getBufferLength(&status), spb2->getBuffer(&status));

+


+ +

+

Many +started services (including mentioned here gstat) return text +information during execution. To display it one should query started +service anout that information line by line. This is done by calling +query() method of IService interface with +appropriate send and receive blocks of parameters. Send block may +contain various helper information (like timeout when querying +service) or information to be passed to stdin of service utility or +may be empty in the simplest case. Receive block must contain list of +tags you want to receive from service. For most of utilities this is +single isc_info_svc_line:

+

const +unsigned char receiveItems1[] = {isc_info_svc_line};

+

To +query information one also needs a buffer for that information:

+

unsigned +char results[1024];

+

After +that preliminary steps we are ready to query service in a loop (each +line returned in a single call to query()):

+

do

+

{

+

svc->query(&status, 0, NULL, sizeof(receiveItems1), receiveItems1, sizeof(results), -results);

-

} while -(printInfo(results, sizeof(results)));

-

In this example we suppose -that printInfo() function returns TRUE as long as service returns -results block containing next output line (i.e. till end of data -stream from service). Format of results block varies from service to -service, and some services like gsec produce historical formats that -are not trivial for parse – but this is out of our scope here. A -minimum working sample of printInfo() is present in example -09.service.cpp.

-


-

-

Same query method is used -to retrieve information about server but in this case query function -is not invoked in a loop, i.e. buffer must be big enough to fit all -information at once. This is not too hard – typically such calls do -not return much data. As in previous case begin with receive block -placing required items in it – in our example it's -isc_info_svc_server_version:

-

const unsigned char -receiveItems2[] = {isc_info_svc_server_version};

-

Existing from previous -call results buffer may be reused. No loop is needed here:

-

svc->query(&status, +results);

+

} +while (printInfo(results, sizeof(results)));

+

In +this example we suppose that printInfo() function returns TRUE as +long as service returns results block containing next output line +(i.e. till end of data stream from service). Format of results block +varies from service to service, and some services like gsec produce +historical formats that are not trivial for parse – but this is out +of our scope here. A minimum working sample of printInfo() is present +in example 09.service.cpp.

+


+ +

+

Same +query method is used to retrieve information about server but in this +case query function is not invoked in a loop, i.e. buffer must be big +enough to fit all information at once. This is not too hard – +typically such calls do not return much data. As in previous case +begin with receive block placing required items in it – in our +example it's isc_info_svc_server_version:

+

const +unsigned char receiveItems2[] = {isc_info_svc_server_version};

+

Existing +from previous call results buffer may be reused. No loop is needed +here:

+

svc->query(&status, 0, NULL, sizeof(receiveItems2), receiveItems2, sizeof(results), -results);

-

printInfo(results, -sizeof(results));

-


-

-

After finishing with -services tasks do not forget to close an interface:

-

svc->detach(&status);

-


-

-

-Writing plugins.

-

To write a plugin means to -implement some interfaces and place your implementation into dynamic -library (.dll in windows or .so in linux) later referenced as plugin -module or just module. +results);

+

printInfo(results, +sizeof(results));

+


+ +

+

After +finishing with services tasks do not forget to close an interface:

+

svc->detach(&status);

+


+ +

+

+Writing +plugins.

+

To +write a plugin means to implement some interfaces and place your +implementation into dynamic library (.dll in windows or .so in linux) +later referenced as plugin +module or just +module. In most cases single plugin is place in dynamic library but in common -case. One of that interfaces – IPluginModule +case. One of that interfaces – IPluginModule – is module-wide (as more or less clear from it's name), others are per plugin. Also each plugin module should contain special exported entrypoint firebird_plugin() which name is defined in include file -firebird/Interfaces.h as FB_PLUGIN_ENTRY_POINT.

-

In previous part of this -text we were mostly describing how to use existing interfaces, here -main attention will be paid to implementing interfaces yourself. -Certainly to do it one can and should use already existing interfaces -both generic needed for accessing firebird databases (already -described) and some more interfaces specifically designed for -plugins.

-


-

-

Following text is actively -using example of database encryption plugin +firebird/Interfaces.h as FB_PLUGIN_ENTRY_POINT.

+

In +previous part of this text we were mostly describing how to use +existing interfaces, here main attention will be paid to implementing +interfaces yourself. Certainly to do it one can and should use +already existing interfaces both generic needed for accessing +firebird databases (already described) and some more interfaces +specifically designed for plugins.

+


+ +

+

Following +text is actively using example of database encryption plugin examples/dbcrypt/DbCrypt.cpp. It will be good idea to compile this -sample yourself and learn it when reading later.

-


-

-

Implementation of plugin module.

-

Plugins actively interact -with special firebird component called plugin -manager. In particular plugin manager should -be aware what plugin modules were loaded and must be notified if -operating system tries to unload one of that modules without explicit -plugin manager command (this may happen first of all when using -embedded access – when exit() is called in a program or main -firebird library fbclient -is unloaded). Primary task of IPluginModule interface is -that notification. First of all one must decide - how to detect that -module is going to be unloaded? When dynamic library is unloaded for -some reason a lot of OS-dependent actions is performed and some of -that actions may be used to detect this fact in the program. When -writing plugins distributed with firebird we always use invocation of -destructor of global variable. The big “plus” for this method is -that it is OS independent (though something like atexit() function -maybe also used successfully). But use of destructor makes it -possible to easily concentrate almost everything related with unload -detection in single class implementing at the same time IPluginModule -interface.

-


-

-

Minimum implementation -looks as follows:

-


-

-

class PluginModule : -public IPluginModuleImpl<PluginModule, CheckStatusWrapper>

-

{

-

private:

-

IPluginManager* -pluginManager;

-


-

-

public:

-

PluginModule()

-

: pluginManager(NULL)

-

{ }

-


-

-

~PluginModule()

-

{

-

if (pluginManager)

-

{

-

pluginManager->unregisterModule(this);

-

doClean();

-

}

-

}

-


-

-

void -registerMe(IPluginManager* m)

-

{

-

pluginManager = m;

-

pluginManager->registerModule(this);

-

}

-


-

-

void doClean()

-

{

-

pluginManager = NULL;

-

}

-

};

-


-

-

The only data member is -plugin manager interface IPluginManager. +sample yourself and learn it when reading later.

+


+ +

+

Implementation of plugin +module.

+

Plugins +actively interact with special firebird component called plugin +manager. In +particular plugin manager should be aware what plugin modules were +loaded and must be notified if operating system tries to unload one +of that modules without explicit plugin manager command (this may +happen first of all when using embedded access – when exit() is +called in a program or main firebird library fbclient +is unloaded). Primary task of +IPluginModule interface is that notification. First of all one must +decide - how to detect that module is going to be unloaded? When +dynamic library is unloaded for some reason a lot of OS-dependent +actions is performed and some of that actions may be used to detect +this fact in the program. When writing plugins distributed with +firebird we always use invocation of destructor of global variable. +The big “plus” for this method is that it is OS independent +(though something like atexit() function maybe also used +successfully). But use of destructor makes it possible to easily +concentrate almost everything related with unload detection in single +class implementing at the same time IPluginModule +interface.

+


+ +

+

Minimum +implementation looks as follows:

+


+ +

+

class +PluginModule : public IPluginModuleImpl<PluginModule, +CheckStatusWrapper>

+

{

+

private:

+

IPluginManager* +pluginManager;

+


+ +

+

public:

+

PluginModule()

+

: +pluginManager(NULL)

+

{ +}

+


+ +

+

~PluginModule()

+

{

+

if +(pluginManager)

+

{

+

pluginManager->unregisterModule(this);

+

doClean();

+

}

+

}

+


+ +

+

void +registerMe(IPluginManager* m)

+

{

+

pluginManager += m;

+

pluginManager->registerModule(this);

+

}

+


+ +

+

void +doClean()

+

{

+

pluginManager += NULL;

+

}

+

};

+


+ +

+

The +only data member is plugin manager interface IPluginManager. It's passed to registerModule() function and saved in private variable, at the same time module is registered in plugin manager by the call to registerModule() method with own address as a single -parameter. Variable pluginManager not -only stores pointer to interface, at the same time it serves as a -flag that module is registered. When destructor of registered module -is invoked it notifies plugin manager (yes, this is what for this -class exists!) about unexpected unload by the call to -unregisterModule() passing pointer to itself. When plugin manager is -going to unload module in regular way in first of all calls doClean() -method changing module state to unregistered and this avoiding call -to unregisterModule() when OS performs actual unload.

-


-

-

Implementing plugin's -interface IPluginModule we met with first interface required to -implement plugins – IPluginManager. It -will be actively used later, the rest of internals of this class will -hardly be required to you after copying it to your program. Just +parameter. Variable pluginManager +not only stores +pointer to interface, at the same time it serves as a flag that +module is registered. When destructor of registered module is invoked +it notifies plugin manager (yes, this is what for this class exists!) +about unexpected unload by the call to unregisterModule() passing +pointer to itself. When plugin manager is going to unload module in +regular way in first of all calls doClean() method changing module +state to unregistered and this avoiding call to unregisterModule() +when OS performs actual unload.

+


+ +

+

Implementing +plugin's interface IPluginModule we met with first interface required +to implement plugins – IPluginManager. +It will be actively used later, the rest of internals of this class +will hardly be required to you after copying it to your program. Just don't forget to declare global variable of this type and call -registerMe() function from FB_PLUGIN_ENTRY_POINT.

-


-

-

Core interface of any plugin.

-

Let's start implementing -plugin itself. The type of main interface depends upon plugin type -(which is obvious), but all of them are based on common reference -counted interface IPluginBase which performs common for all plugins -(and very simple) tasks. Each plugin has some (also reference -counted) object which owns this plugin. In order to perform -smart plugin lifetime management any plugin must be able to store -that owner information and report it to plugin manager on request. -That means that each plugin must implement two trivial methods -setOwner() and getOwner() contained in IPluginBase interface. +registerMe() function from FB_PLUGIN_ENTRY_POINT.

+


+ +

+

Core interface of any +plugin.

+

Let's +start implementing plugin itself. The type of main interface depends +upon plugin type (which is obvious), but all of them are based on +common reference counted interface IPluginBase which performs common +for all plugins (and very simple) tasks. Each plugin has some (also +reference counted) object which owns this plugin. In order to +perform smart plugin lifetime management any plugin must be able to +store that owner information and report it to plugin manager on +request. That means that each plugin must implement two trivial +methods setOwner() and getOwner() contained in IPluginBase interface. Type-dependent methods are certainly more interesting - they are -discussed in interfaces description part.

-


-

-

Let's take a look at -typical part of any plugin implementation (here I specially use -non-existent type SomePlugin):

-

class MyPlugin : public -ISomePluginImpl<MyPlugin, CheckStatusWrapper>

-

{

-

public:

-

explicit -MyPlugin(IPluginConfig* cnf) throw()

-

: config(cnf), -refCounter(0), owner(NULL)

-

{

-

config->addRef();

-

}

-

Constructor -gets as parameter plugin configuration interface. If you are going to -have you plugin configured in some way it's good idea to save this -interface in your plugin and use it later. This will let you use -common for all firebird configuration style letting users have -familiar configuration and minimize code written. Certainly when -saving any reference counted interface it's better not forget to add -reference to it. Also set reference counter to 0 and plugin owner to -NULL.

-


-

-

~MyPlugin()

-

{

-

config->release();

-

}

-

Destructor -releases config interface. Pay attention – we do not change -reference counter of our owner cause it owns us, not we own it.

-


-

-

// IRefCounted -implementation

-

int release()

-

{

-

if (--refCounter == 0)

-

{

-

delete this;

-

return 0;

-

}

-

return 1;

-

}

-


-

-

void addRef()

-

{

-

++refCounter;

-

}

-

Absolutely -typical implementation of reference counted object.

-


-

-

// IPluginBase -implementation

-

void -setOwner(IReferenceCounted* o)

-

{

-

owner = o;

-

}

-


-

-

IReferenceCounted* -getOwner()

-

{

-

return owner;

-

}

-

As it -was promised implementation of IPluginBase is trivial.

-


-

-

// ISomePlugin -implementation

-

// … here go various -methods required for particular plugin type

-


-

-

private:

-

IPluginConfig* config;

-

FbSampleAtomic -refCounter;

-

IReferenceCounted* -owner;

-

};

-


-

-

With this sample formal -part of main plugin interface implementation is over. After adding -type-specific methods (and writing probably a lo-o-o-ot of code to -make them useful) interface is ready.

-


-

-

Plugin's factory.

-

One more interface -required for plugin to work is IPluginFactory. +discussed in interfaces description part.

+


+ +

+

Let's +take a look at typical part of any plugin implementation (here I +specially use non-existent type SomePlugin):

+

class +MyPlugin : public ISomePluginImpl<MyPlugin, CheckStatusWrapper>

+

{

+

public:

+

explicit +MyPlugin(IPluginConfig* cnf) throw()

+

: +config(cnf), refCounter(0), owner(NULL)

+

{

+

config->addRef();

+

}

+

+Constructor gets as parameter +plugin configuration interface. If you are going to have you plugin +configured in some way it's good idea to save this interface in your +plugin and use it later. This will let you use common for all +firebird configuration style letting users have familiar +configuration and minimize code written. Certainly when saving any +reference counted interface it's better not forget to add reference +to it. Also set reference counter to 0 and plugin owner to NULL.

+


+ +

+

~MyPlugin()

+

{

+

config->release();

+

}

+

+Destructor releases config +interface. Pay attention – we do not change reference counter of +our owner cause it owns us, not we own it.

+


+ +

+

// +IRefCounted implementation

+

int +release()

+

{

+

if +(--refCounter == 0)

+

{

+

delete +this;

+

return +0;

+

}

+

return +1;

+

}

+


+ +

+

void +addRef()

+

{

+

++refCounter;

+

}

+

+Absolutely typical +implementation of reference counted object.

+


+ +

+

// +IPluginBase implementation

+

void +setOwner(IReferenceCounted* o)

+

{

+

owner += o;

+

}

+


+ +

+

IReferenceCounted* +getOwner()

+

{

+

return +owner;

+

}

+

+As it was promised +implementation of IPluginBase is trivial.

+


+ +

+

// +ISomePlugin implementation

+

// +… here go various methods required for particular plugin type

+


+ +

+

private:

+

IPluginConfig* +config;

+

FbSampleAtomic +refCounter;

+

IReferenceCounted* +owner;

+

};

+


+ +

+

With +this sample formal part of main plugin interface implementation is +over. After adding type-specific methods (and writing probably a +lo-o-o-ot of code to make them useful) interface is ready.

+


+ +

+

Plugin's factory.

+

One +more interface required for plugin to work is IPluginFactory. Factory creates instances of plugin and returns them to plugin -manager. Factory typically looks this way:

-

class Factory : public -IPluginFactoryImpl<Factory, CheckStatusWrapper>

-

{

-

public:

-

IPluginBase* +manager. Factory typically looks this way:

+

class +Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>

+

{

+

public:

+

IPluginBase* createPlugin(CheckStatusWrapper* status, IPluginConfig* -factoryParameter)

-

{

-

MyPlugin* p = new -MyPlugin(factoryParameter);

-

p->addRef();

-

return p;

-

}

-

};

-


-

-

Here -attention should be payed to the fact that even in a case when code -in a function may throw exceptions (operator new may throw in a case -when memory exhausted) one need not always manually define try/catch -block – implementation of firebird interfaces does this job for -you, in implementation of IPluginFactory it's placed into template +factoryParameter)

+

{

+

MyPlugin* +p = new MyPlugin(factoryParameter);

+

p->addRef();

+

return +p;

+

}

+

};

+


+ +

+

+Here attention should be payed +to the fact that even in a case when code in a function may throw +exceptions (operator new may throw in a case when memory exhausted) +one need not always manually define try/catch block – +implementation of firebird interfaces does this job for you, in +implementation of IPluginFactory it's placed into template IPluginFactoryImpl. Take into an account that default status wrappers perform meaning-full processing only for FbException. But if you (that definitely makes sense if you work on some big project) define your own wrapper you can handle any type of C++ exception and pass -useful information about it from your plugin.

-


-

-

Plugin module initialization entrypoint.

-

When plugin manager loads -plugin module it invokes module initializing routine – the only -exported from plugin function FB_PLUGIN_ENTRY_POINT. To wrote it's -code one will need two global variables – plugin module and plugin -factory. In our case that is:

-

PluginModule module;

-

Factory factory;

-

If you module contains -more than one plugin you will need a factory per each plugin.

-


-

-

For FB_PLUGIN_ENTRY_POINT -we should not forget that it should be exported from plugin module, -and it requires taking into an account some OS specifics. We do it -using macro FB_DLL_EXPORT defined in +useful information about it from your plugin.

+


+ +

+

Plugin module +initialization entrypoint.

+

When +plugin manager loads plugin module it invokes module initializing +routine – the only exported from plugin function +FB_PLUGIN_ENTRY_POINT. To wrote it's code one will need two global +variables – plugin module and plugin factory. In our case that is:

+

PluginModule +module;

+

Factory +factory;

+

If +you module contains more than one plugin you will need a factory per +each plugin.

+


+ +

+

For +FB_PLUGIN_ENTRY_POINT we should not forget that it should be exported +from plugin module, and it requires taking into an account some OS +specifics. We do it using macro FB_DLL_EXPORT defined in examples/interfaces/ifaceExamples.h. If you are sure you write plugin only for some specific OS you can make this place a bit simpler. In minimum case the function should register module and all factories in -plugin manager:

-

extern "C" void -FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* master)

-

{

-

IPluginManager* -pluginManager = master->getPluginManager();

-


-

-

module.registerMe(pluginManager);

-

pluginManager->registerPluginFactory(IPluginManager::TYPE_DB_CRYPT, -"DbCrypt_example", &factory);

-

}

-

First of all we call -written by us not long ago PluginModule::registerMe() function which -will saves IPluginManager for future use and registers our plugin -module. Next time to register factory (or factories in case of -multiple plugins per module) takes place. We must pass correct plugin -type (valid types are enumerated in interface IPluginManager) and a -name under which plugin will be registered. In simple case it should -match with the name of dynamic library with plugin module. Following -last rule will help you avoid configuring your plugin manually in -plugins.conf.

-


-

-

Pay attention - unlike -applications plugins should not use fb_get_master_interface() to -obtain IMaster. Instance, passed to FB_PLUGIN_ENTRY_POINT, should be -used instead. If you ever need master interface in your plugin take -care about saving it in this function.

-


-

-


-

-

-Interfaces: from A to Z

-

In this glossary we do not -list interfaces that are not actively used (like IRequest, needed -first of all to support legacy ISC API requests). Same reference may -be made for a number of methods (like compileRequest() in -IAttachment). For interfaces / methods, having direct analogue in old -API, that analogue is provided.

-


-

-

Generic interfaces.

-

Attachment -interface – replaces isc_db_handle:

-
    -
  1. void +plugin manager:

    +

    extern +"C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* +master)

    +

    {

    +

    IPluginManager* +pluginManager = master->getPluginManager();

    +


    + +

    +

    module.registerMe(pluginManager);

    +

    pluginManager->registerPluginFactory(IPluginManager::TYPE_DB_CRYPT, +"DbCrypt_example", &factory);

    +

    }

    +

    First +of all we call written by us not long ago PluginModule::registerMe() +function which will saves IPluginManager for future use and registers +our plugin module. Next time to register factory (or factories in +case of multiple plugins per module) takes place. We must pass +correct plugin type (valid types are enumerated in interface +IPluginManager) and a name under which plugin will be registered. In +simple case it should match with the name of dynamic library with +plugin module. Following last rule will help you avoid configuring +your plugin manually in plugins.conf.

    +


    + +

    +

    Pay +attention - unlike applications plugins should not use +fb_get_master_interface() to obtain IMaster. Instance, passed to +FB_PLUGIN_ENTRY_POINT, should be used instead. If you ever need +master interface in your plugin take care about saving it in this +function.

    +


    + +

    +


    + +

    +

    +Interfaces: +from A to Z

    +

    In +this glossary we do not list interfaces that are not actively used +(like IRequest, needed first of all to support legacy ISC API +requests). Same reference may be made for a number of methods (like +compileRequest() in IAttachment). For interfaces / methods, having +direct analogue in old API, that analogue is provided.

    +


    + +

    +

    Generic interfaces.

    +

    Attachment +interface – replaces isc_db_handle:

    +
      +
    1. +

      void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) – - replaces isc_database_info().

      -
    2. ITransaction* + replaces isc_database_info().

      +
    3. +

      ITransaction* startTransaction(StatusType* status, unsigned tpbLength, const unsigned char* tpb) – partially replaces isc_start_multiple(), to - start >1 transaction distributed transactions - coordinator should be used, also possible to join - 2 transactions into single distributed transaction.

      -
    4. ITransaction* + start >1 transaction distributed transactions + coordinator should be used, also possible to join + 2 transactions into single distributed transaction.

      +
    5. +

      ITransaction* reconnectTransaction(StatusType* status, unsigned length, const unsigned char* id) – makes it possible to connect to a transaction in limbo. Id parameter contains transaction number in network format - of given length.

      -
    6. IRequest* + of given length.

      +
    7. +

      IRequest* compileRequest(StatusType* status, unsigned blrLength, const - unsigned char* blr) – support of ISC API.

      -
    8. void + unsigned char* blr) – support of ISC API.

      +
    9. +

      void transactRequest(StatusType* status, ITransaction* transaction, unsigned blrLength, const unsigned char* blr, unsigned inMsgLength, const unsigned char* inMsg, unsigned outMsgLength, unsigned char* - outMsg) – support of ISC API.

      -
    10. IBlob* + outMsg) – support of ISC API.

      +
    11. +

      IBlob* createBlob(StatusType* status, ITransaction* transaction, ISC_QUAD* id, unsigned bpbLength, const unsigned char* bpb) – creates new - blob, stores it's identifier in id, replaces isc_create_blob2().

      -
    12. IBlob* + blob, stores it's identifier in id, replaces isc_create_blob2().

      +
    13. +

      IBlob* openBlob(StatusType* status, ITransaction* transaction, ISC_QUAD* id, unsigned bpbLength, const unsigned char* bpb) – opens existing - blob, replaces isc_open_blob2().

      -
    14. int + blob, replaces isc_open_blob2().

      +
    15. +

      int getSlice(StatusType* status, ITransaction* transaction, ISC_QUAD* id, unsigned sdlLength, const unsigned char* sdl, unsigned paramLength, const unsigned char* param, int sliceLength, unsigned - char* slice) - support of ISC API.

      -
    16. void + char* slice) - support of ISC API.

      +
    17. +

      void putSlice(StatusType* status, ITransaction* transaction, ISC_QUAD* id, unsigned sdlLength, const unsigned char* sdl, unsigned paramLength, const unsigned char* param, int sliceLength, unsigned - char* slice) - support of ISC API.

      -
    18. void + char* slice) - support of ISC API.

      +
    19. +

      void executeDyn(StatusType* status, ITransaction* transaction, unsigned - length, const unsigned char* dyn) - support of ISC API.

      -
    20. IStatement* + length, const unsigned char* dyn) - support of ISC API.

      +
    21. +

      IStatement* prepare(StatusType* status, ITransaction* tra, unsigned stmtLength, const char* sqlStmt, unsigned dialect, unsigned flags) – replaces isc_dsql_prepare(). Additional parameter flags makes it possible to control what information will be preloaded from engine at once (i.e. - in single network packet for remote operation).

      -
    22. ITransaction* + in single network packet for remote operation).

      +
    23. +

      ITransaction* execute(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void* outBuffer) – executes any SQL statement except returning multiple rows of data. Partial analogue of isc_dsql_execute2() - in and out XSLQDAs replaced with input and output messages with appropriate - buffers.

      -
    24. IResultSet* + buffers.

      +
    25. +

      IResultSet* openCursor(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName, unsigned cursorFlags) – executes SQL statement - potentially returning multiple rows of data. Returns ResultSet + potentially returning multiple rows of data. Returns ResultSet interface which should be used to fetch that data. Format of output data is defined by outMetadata parameter, leaving it NULL default format may be used. Parameter cursorName specifies name of opened cursor (analogue of isc_dsql_set_cursor_name()). Parameter cursorFlags is needed to open bidirectional cursor setting it's - value to Istatement::CURSOR_TYPE_SCROLLABLE.

      -
    26. IEvents* + value to Istatement::CURSOR_TYPE_SCROLLABLE.

      +
    27. +

      IEvents* queEvents(StatusType* status, IEventCallback* callback, unsigned length, const unsigned char* events) – replaces isc_que_events() call. Instead callback function with void* parameter callback - interface is used.

      -
    28. void + interface is used.

      +
    29. +

      void cancelOperation(StatusType* status, int option) – replaces - fb_cancel_operation().

      -
    30. void ping(StatusType* - status) – check connection status. If test fails the only - operation possible with attachment is to close it.

      -
    31. void + fb_cancel_operation().

      +
    32. +

      void + ping(StatusType* status) – check connection status. If test fails + the only operation possible with attachment is to close it.

      +
    33. +

      void detach(StatusType* status) – replaces isc_detach_database(). On - success releases interface.

      -
    34. void + success releases interface.

      +
    35. +

      void dropDatabase(StatusType* status) - replaces isc_drop_database(). On - success releases interface.

      -
    -


    -

    -


    -

    -

    Blob -interface – replaces isc_blob_handle:

    -
      -
    1. void + success releases interface.

      +
    +


    + +

    +


    + +

    +

    Blob +interface – replaces isc_blob_handle:

    +
      +
    1. +

      void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) – - replaces isc_blob_info().

      -
    2. int + replaces isc_blob_info().

      +
    3. +

      int getSegment(StatusType* status, unsigned bufferLength, void* buffer, unsigned* segmentLength) – replaces isc_get_segment(). Unlike it never returns isc_segstr_eof and isc_segment errors (that are - actually not errors), instead returns completion - codes IStatus::RESULT_NO_DATA and IStatus::RESULT_SEGMENT, - normal return is IStatus::RESULT_OK.

      -
    4. void + actually not errors), instead returns completion + codes IStatus::RESULT_NO_DATA and IStatus::RESULT_SEGMENT, + normal return is IStatus::RESULT_OK.

      +
    5. +

      void putSegment(StatusType* status, unsigned length, const void* buffer) - – replaces isc_put_segment().

      -
    6. void + – replaces isc_put_segment().

      +
    7. +

      void cancel(StatusType* status) – replaces isc_cancel_blob(). On - success releases interface.

      -
    8. void + success releases interface.

      +
    9. +

      void close(StatusType* status) – replaces isc_close_blob(). On success - releases interface.

      -
    10. int seek(StatusType* - status, int mode, int offset) – replaces isc_seek_blob().

      -
    -


    -

    -


    -

    -

    Config -interface – generic configuration file interface:

    -
      -
    1. IConfigEntry* - find(StatusType* status, const char* name) – find entry by name.

      -
    2. IConfigEntry* + releases interface.

      +
    3. +

      int + seek(StatusType* status, int mode, int offset) – replaces + isc_seek_blob().

      +
    +


    + +

    +


    + +

    +

    Config +interface – generic configuration file interface:

    +
      +
    1. +

      IConfigEntry* + find(StatusType* status, const char* name) – find entry by name.

      +
    2. +

      IConfigEntry* findValue(StatusType* status, const char* name, const char* value) – - find entry by name and value.

      -
    3. IConfigEntry* + find entry by name and value.

      +
    4. +

      IConfigEntry* findPos(StatusType* status, const char* name, unsigned pos) – find - entry by name and position. If configuration file contains lines:

      -
    -

    Db=DBA

    -

    Db=DBB

    -

    Db=DBC

    -

    call to findPos(status, -“Db”, 2) will return entry with value DBB.

    -


    -

    -


    -

    -

    ConfigManager + entry by name and position. If configuration file contains lines:

    +
+

Db=DBA

+

Db=DBB

+

Db=DBC

+

call +to findPos(status, “Db”, 2) will return entry with value DBB.

+


+ +

+


+ +

+

ConfigManager interface – generic interface to access various configuration -objects:

-
    -
  1. const char* - getDirectory(unsigned code) – returns location of appropriate - directory in current firebird instance. See codes for this call a - few lines later.

    -
  2. IFirebirdConf* +objects:

    +
      +
    1. +

      const + char* getDirectory(unsigned code) – returns location of + appropriate directory in current firebird instance. See codes for + this call a few lines later.

      +
    2. +

      IFirebirdConf* getFirebirdConf() - returns interface to access default - configuration values (from firebird.conf).

      -
    3. IFirebirdConf* + configuration values (from firebird.conf).

      +
    4. +

      IFirebirdConf* getDatabaseConf(const char* dbName) - returns interface to access db-specific configuration (takes into an account firebird.conf and - appropriate part of databases.conf).

      -
    5. IConfig* + appropriate part of databases.conf).

      +
    6. +

      IConfig* getPluginConfig(const char* configuredPlugin) – returns interface - to access named plugin configuration.

      -
    7. const char* - getInstallDirectory() - returns directory where firebird is - installed.

      -
    8. const char* - getRootDirectory() - returns root directory of current instance, in - single-instance case usually matches install directory.

      -
    -

    Directory -codes:

    -

    DIR_BIN – bin (utilities -like isql, gbak, gstat)

    -

    DIR_SBIN – sbin (fbguard -and firebird server)

    -

    DIR_CONF – configuration -files (firebird.conf, databases.conf, plugins.conf)

    -

    DIR_LIB – lib (fbclient, -ib_util)

    -

    DIR_INC – include -(ibase.h, firebird/Interfaces.h)

    -

    DIR_DOC - documentation

    -

    DIR_UDF – UDF (ib_udf, -fbudf)

    -

    DIR_SAMPLE - samples

    -

    DIR_SAMPLEDB – samples -database (employee.fdb)

    -

    DIR_HELP – qli help -(help.fdb)

    -

    DIR_INTL – international -libraries (fbintl)

    -

    DIR_MISC – miscellaneous -files (like uninstall manifest and something else)

    -

    DIR_SECDB – where -security database is stored (securityN.fdb)

    -

    DIR_MSG – where messages -file is stored (firebird.msg)

    -

    DIR_LOG – where log file -is stored (firebird.log)

    -

    DIR_GUARD – where -guardian lock is stored (fb_guard)

    -

    DIR_PLUGINS – plugins -directory ([lib]Engine13.{dll|so})

    -


    -

    -


    -

    -

    ConfigEntry + to access named plugin configuration.

    +
  3. +

    const + char* getInstallDirectory() - returns directory where firebird is + installed.

    +
  4. +

    const + char* getRootDirectory() - returns root directory of current + instance, in single-instance case usually matches install directory.

    +
+

Directory +codes:

+

DIR_BIN +– bin (utilities like isql, gbak, gstat)

+

DIR_SBIN +– sbin (fbguard and firebird server)

+

DIR_CONF +– configuration files (firebird.conf, databases.conf, plugins.conf)

+

DIR_LIB +– lib (fbclient, ib_util)

+

DIR_INC +– include (ibase.h, firebird/Interfaces.h)

+

DIR_DOC +- documentation

+

DIR_UDF +– UDF (ib_udf, fbudf)

+

DIR_SAMPLE +- samples

+

DIR_SAMPLEDB +– samples database (employee.fdb)

+

DIR_HELP +– qli help (help.fdb)

+

DIR_INTL +– international libraries (fbintl)

+

DIR_MISC +– miscellaneous files (like uninstall manifest and something else)

+

DIR_SECDB +– where security database is stored (securityN.fdb)

+

DIR_MSG +– where messages file is stored (firebird.msg)

+

DIR_LOG +– where log file is stored (firebird.log)

+

DIR_GUARD +– where guardian lock is stored (fb_guard)

+

DIR_PLUGINS +– plugins directory ([lib]Engine13.{dll|so})

+


+ +

+


+ +

+

ConfigEntry interface – represents an entry (Key = Values with probably -sub-entries) in firebird configuration file:

-
    -
  1. const char* getName() - - returns key name.

    -
  2. const char* - getValue() - returns value as character string.

    -
  3. ISC_INT64 - getIntValue() - treats value as integer and returns it.

    -
  4. FB_BOOLEAN - getBoolValue() - treats value as boolean and returns it.

    -
  5. IConfig* +sub-entries) in firebird configuration file:

    +
      +
    1. +

      const + char* getName() - returns key name.

      +
    2. +

      const + char* getValue() - returns value as character string.

      +
    3. +

      ISC_INT64 + getIntValue() - treats value as integer and returns it.

      +
    4. +

      FB_BOOLEAN + getBoolValue() - treats value as boolean and returns it.

      +
    5. +

      IConfig* getSubConfig(StatusType* status) – treats sub-entries as separate - configuration file and returns Config interface for it.

      -
    -


    -

    -


    -

    -

    Dtc + configuration file and returns Config interface for it.

    +
+


+ +

+


+ +

+

Dtc interface – distributed transactions coordinator. Used to start distributed (working with 2 or more attachments) transaction. Unlike pre-FB3 approach where distributed transaction must be started in this way from the most beginning FB3's distributed transactions coordinator makes it also possible to join already started -transactions into single distributed transaction.

-
    -
  1. ITransaction* +transactions into single distributed transaction.

    +
      +
    1. +

      ITransaction* join(StatusType* status, ITransaction* one, ITransaction* two) – joins 2 independent transactions into distributed transaction. On success both transactions passed to join() are released and pointers - to them should not be used any more.

      -
    2. IDtcStart* - startBuilder(StatusType* status) – returns DtcStart - interface.

      -
    -


    -

    -


    -

    -

    DtcStart + to them should not be used any more.

    +
  2. +

    IDtcStart* + startBuilder(StatusType* status) – returns DtcStart + interface.

    +
+


+ +

+


+ +

+

DtcStart interface – replaces array of struct TEB (passed to isc_start_multiple() in ISC API). This interface accumulates attachments (and probably appropriate TPBs) for which dustributed -transaction should be started.

-
    -
  1. void +transaction should be started.

    +
      +
    1. +

      void addAttachment(StatusType* status, IAttachment* att) – adds - attachment, transaction for it will be started with default TPB.

      -
    2. void + attachment, transaction for it will be started with default TPB.

      +
    3. +

      void addWithTpb(StatusType* status, IAttachment* att, unsigned length, const unsigned char* tpb) - adds attachment and TPB which will be - used to start transaction for this attachment.

      -
    4. ITransaction* + used to start transaction for this attachment.

      +
    5. +

      ITransaction* start(StatusType* status) – start distributed transaction for accumulated attachments. On successful return DtcStart interface is - disposed automatically.

      -
    -


    -

    -


    -

    -

    EventCallback + disposed automatically.

    +
+


+ +

+


+ +

+

EventCallback interface – replaces callback function used in isc_que_events() call. Should be implemented by user to monitor events with -IAttachment::queEvents() method.

-
    -
  1. void +IAttachment::queEvents() method.

    +
      +
    1. +

      void eventCallbackFunction(unsigned length, const unsigned char* events) - – is called each time event happens.

      -
    -


    -

    -


    -

    -

    Events + – is called each time event happens.

    +
+


+ +

+


+ +

+

Events interface – replaces event identifier when working with events -monitoring.

-
    -
  1. void +monitoring.

    +
      +
    1. +

      void cancel(StatusType* status) - cancels events monitoring started by - IAttachment::queEvents().

      -
    -


    -

    -


    -

    -

    FirebirdConf interface – -access to main firebird configuration. Used for both default -configuration, set by firebird.conf, and per-database configuration, -adjusted by databases.conf. In order to speed up access to -configuration values calls accessing actual values use integer key -instead symbolic parameter name. Key is stable during server run -(i.e. plugin can get it once and than use to get configuration value -for different databases). -

    -
      -
    1. unsigned getKey(const - char* name) – get key for parameter name. ~0 (all bits are 1) is - returned in a case when there is no such parameter.

      -
    2. ISC_INT64 - asInteger(unsigned key) – return value of integer parameter.

      -
    3. const char* - asString(unsigned key) - return value of string parameter.

      -
    4. FB_BOOLEAN + IAttachment::queEvents().

      +
    +


    + +

    +


    + +

    +

    FirebirdConf +interface – access to main firebird configuration. Used for both +default configuration, set by firebird.conf, and per-database +configuration, adjusted by databases.conf. In order to speed up +access to configuration values calls accessing actual values use +integer key instead symbolic parameter name. Key is stable during +server run (i.e. plugin can get it once and than use to get +configuration value for different databases). +

    +
      +
    1. +

      unsigned + getKey(const char* name) – get key for parameter name. ~0 (all + bits are 1) is returned in a case when there is no such parameter.

      +
    2. +

      ISC_INT64 + asInteger(unsigned key) – return value of integer parameter.

      +
    3. +

      const + char* asString(unsigned key) - return value of string parameter.

      +
    4. +

      FB_BOOLEAN asBoolean(unsigned key) - return value of boolean parameter. Standard abbreviations (1/true/t/yes/y) are treated as “true”, - all other cases – false.

      -
    -


    -

    -


    -

    -

    Master + all other cases – false.

    +
+


+ +

+


+ +

+

Master interface – main interface from which start all operations with -firebird API.

-
    -
  1. IStatus* getStatus() - - get instance if Status interface.

    -
  2. IProvider* - getDispatcher() - get instance of Provider - interface, implemented by yValve (main provider instance).

    -
  3. IPluginManager* - getPluginManager() - get instance of PluginManager - interface.

    -
  4. ITimerControl* - getTimerControl() - get instance of TimerControl - interface.

    -
  5. IDtc* getDtc() - get - instance of Dtc interface.

    -
  6. IUtil* - getUtilInterface() - get instance of Util - interface.

    -
  7. IConfigManager* - getConfigManager() - get instance of ConfigManager - interface.

    -
-


-

-


-

-

MessageMetadata +firebird API.

+
    +
  1. +

    IStatus* + getStatus() - get instance if Status + interface.

    +
  2. +

    IProvider* + getDispatcher() - get instance of Provider + interface, implemented by yValve (main provider instance).

    +
  3. +

    IPluginManager* + getPluginManager() - get instance of PluginManager + interface.

    +
  4. +

    ITimerControl* + getTimerControl() - get instance of TimerControl + interface.

    +
  5. +

    IDtc* + getDtc() - get instance of Dtc interface.

    +
  6. +

    IUtil* + getUtilInterface() - get instance of Util + interface.

    +
  7. +

    IConfigManager* + getConfigManager() - get instance of ConfigManager + interface.

    +
+


+ +

+


+ +

+

MessageMetadata interface – partial analogue of XSQLDA (does not contain message data, only message format info is present). Used in a calls related -with execution of SQL statements.

-
    -
  1. unsigned +with execution of SQL statements.

    +
      +
    1. +

      unsigned getCount(StatusType* status) – returns number of fields/parameters in a message. In all calls, containing index parameter, it's value - should be: 0 <= index < getCount().

      -
    2. const char* - getField(StatusType* status, unsigned index) – returns field name.

      -
    3. const char* - getRelation(StatusType* status, unsigned index) – returns relation - name (from which given field is selected).

      -
    4. const char* - getOwner(StatusType* status, unsigned index) - returns relation's - owner name.

      -
    5. const char* - getAlias(StatusType* status, unsigned index) - returns field alias.

      -
    6. unsigned + should be: 0 <= index < getCount().

      +
    7. +

      const + char* getField(StatusType* status, unsigned index) – returns field + name.

      +
    8. +

      const + char* getRelation(StatusType* status, unsigned index) – returns + relation name (from which given field is selected).

      +
    9. +

      const + char* getOwner(StatusType* status, unsigned index) - returns + relation's owner name.

      +
    10. +

      const + char* getAlias(StatusType* status, unsigned index) - returns field + alias.

      +
    11. +

      unsigned getType(StatusType* status, unsigned index) - returns field SQL - type.

      -
    12. FB_BOOLEAN + type.

      +
    13. +

      FB_BOOLEAN isNullable(StatusType* status, unsigned index) - returns true if - field is nullable.

      -
    14. int + field is nullable.

      +
    15. +

      int getSubType(StatusType* status, unsigned index) - returns blof field - subtype (0 – binary, 1 – text, etc.).

      -
    16. unsigned + subtype (0 – binary, 1 – text, etc.).

      +
    17. +

      unsigned getLength(StatusType* status, unsigned index) - returns maximum - field length.

      -
    18. int + field length.

      +
    19. +

      int getScale(StatusType* status, unsigned index) - returns scale factor - for numeric field.

      -
    20. unsigned + for numeric field.

      +
    21. +

      unsigned getCharSet(StatusType* status, unsigned index) - returns character - set for character field and text blob.

      -
    22. unsigned + set for character field and text blob.

      +
    23. +

      unsigned getOffset(StatusType* status, unsigned index) - returns offset of field data in message buffer (use it to access data in message - buffer).

      -
    24. unsigned + buffer).

      +
    25. +

      unsigned getNullOffset(StatusType* status, unsigned index) - returns offset - of null indicator for a field in message buffer.

      -
    26. IMetadataBuilder* - getBuilder(StatusType* status) - returns MetadataBuilder - interface initialized with this message metadata.

      -
    27. unsigned + of null indicator for a field in message buffer.

      +
    28. +

      IMetadataBuilder* + getBuilder(StatusType* status) - returns MetadataBuilder + interface initialized with this message metadata.

      +
    29. +

      unsigned getMessageLength(StatusType* status) - returns length of message - buffer (use it to allocate memory for the buffer).

      -
    -


    -

    -


    -

    -

    MetadataBuilder + buffer (use it to allocate memory for the buffer).

    +
+


+ +

+


+ +

+

MetadataBuilder interface – makes it possible to coerce datatypes in existing -message or construct metadata from the beginning.

-
    -
  1. void +message or construct metadata from the beginning.

    +
      +
    1. +

      void setType(StatusType* status, unsigned index, unsigned type) – set - SQL type of a field.

      -
    2. void + SQL type of a field.

      +
    3. +

      void setSubType(StatusType* status, unsigned index, int subType) – set - blof field subtype.

      -
    4. void + blof field subtype.

      +
    5. +

      void setLength(StatusType* status, unsigned index, unsigned length) – - set maximum length of character field.

      -
    6. void + set maximum length of character field.

      +
    7. +

      void setCharSet(StatusType* status, unsigned index, unsigned charSet) – - set character set for character field and text blob.

      -
    8. void + set character set for character field and text blob.

      +
    9. +

      void setScale(StatusType* status, unsigned index, unsigned scale) – set - scale factor for numeric field -

      -
    10. void + scale factor for numeric field +

      +
    11. +

      void truncate(StatusType* status, unsigned count) – truncate message to - contain not more than count fields.

      -
    12. void + contain not more than count fields.

      +
    13. +

      void moveNameToIndex(StatusType* status, const char* name, unsigned index) – reorganize fields in a message – move field “name” - to given position.

      -
    14. void - remove(StatusType* status, unsigned index) – remove field.

      -
    15. unsigned - addField(StatusType* status) – add field.

      -
    16. IMessageMetadata* - getMetadata(StatusType* status) – get MessageMetadata - interface built by this builder.

      -
    -


    -

    -


    -

    -

    OffsetsCallback -interface:

    -
      -
    1. setOffset(StatusType* + to given position.

      +
    2. +

      void + remove(StatusType* status, unsigned index) – remove field.

      +
    3. +

      unsigned + addField(StatusType* status) – add field.

      +
    4. +

      IMessageMetadata* + getMetadata(StatusType* status) – get MessageMetadata + interface built by this builder.

      +
    +


    + +

    +


    + +

    +

    OffsetsCallback +interface:

    +
      +
    1. +

      setOffset(StatusType* status, unsigned index, unsigned offset, unsigned nullOffset) – notifies that offsets for field/parameter number “index” should be set to passed values. Should be implemented by user when - implementing MessageMetadata - interface and using Util::setOffsets().

      -
    -


    -

    -


    -

    -

    PluginConfig + implementing MessageMetadata + interface and using Util::setOffsets().

    +
+


+ +

+


+ +

+

PluginConfig interface – passed to plugin's factory when plugin instance (with -particular configuration) to be created.

-
    -
  1. const char* - getConfigFileName() - recommended file name where configuration for - plugin is expected to be stored.

    -
  2. IConfig* +particular configuration) to be created.

    +
      +
    1. +

      const + char* getConfigFileName() - recommended file name where + configuration for plugin is expected to be stored.

      +
    2. +

      IConfig* getDefaultConfig(StatusType* status) – plugin configuration loaded - with default rules.

      -
    3. IFirebirdConf* + with default rules.

      +
    4. +

      IFirebirdConf* getFirebirdConf(StatusType* status) – master firebird configuration taking into an account per-database settings for a - database with which will work new instance of plugin.

      -
    5. void + database with which will work new instance of plugin.

      +
    6. +

      void setReleaseDelay(StatusType* status, ISC_UINT64 microSeconds) – used by plugin to configure recommended delay during which plugin module will not be unloaded by plugin manager after release of last - plugin instance from that module.

      -
    -


    -

    -


    -

    -

    PluginFactory + plugin instance from that module.

    +
+


+ +

+


+ +

+

PluginFactory interface – should be implemented by plugin author when writing -plugin.

-
    -
  1. IPluginBase* +plugin.

    +
      +
    1. +

      IPluginBase* createPlugin(StatusType* status, IPluginConfig* factoryParameter) – creates new instance of plugin with passed recommended - configuration.

      -
    -


    -

    -


    -

    -

    PluginManager -interface – API of plugin manager.

    -
      -
    1. void + configuration.

      +
    +


    + +

    +


    + +

    +

    PluginManager +interface – API of plugin manager.

    +
      +
    1. +

      void registerPluginFactory(unsigned pluginType, const char* defaultName, IPluginFactory* factory) – registers named factory of plugins of - given type.

      -
    2. void - registerModule(IPluginModule* cleanup) – registers plugin module.

      -
    3. void + given type.

      +
    4. +

      void + registerModule(IPluginModule* cleanup) – registers plugin module.

      +
    5. +

      void unregisterModule(IPluginModule* cleanup) – unregisters plugin - module (in case of unexpected unload by OS).

      -
    6. IPluginSet* + module (in case of unexpected unload by OS).

      +
    7. +

      IPluginSet* getPlugins(StatusType* status, unsigned pluginType, const char* namesList, IFirebirdConf* firebirdConf) – returns PluginSet interface providing access to list of plugins of given type. Names @@ -1725,203 +2020,252 @@ interface – API of plugin manager.

      (NULL) – from configuration setting for given pluginType. If firebirdConf parameter is specified it is used for all configuration purporses (including getting list of plugins and passing to - PluginFactory::createPlugin() method), + PluginFactory::createPlugin() method), if missing (NULL) – default configuration (from firebird.conf) is - used.

      -
    8. IConfig* + used.

      +
    9. +

      IConfig* getConfig(StatusType* status, const char* filename) – returns Config interface for given configuration file name. Can be used by plugins to access configuration files with standard format but - non-default name.

      -
    10. void + non-default name.

      +
    11. +

      void releasePlugin(IPluginBase* plugin) – release given plugin. Should be used for plugins instead simple release() due to need to perform - additional actions with plugin owner before actual release.

      -
    -


    -

    -

    Constants defined by -PluginManager interface (plugin types):

    -

    TYPE_PROVIDER

    -

    TYPE_AUTH_SERVER

    -

    TYPE_AUTH_CLIENT

    -

    TYPE_AUTH_USER_MANAGEMENT

    -

    TYPE_EXTERNAL_ENGINE

    -

    TYPE_TRACE

    -

    TYPE_WIRE_CRYPT

    -

    TYPE_DB_CRYPT

    -

    TYPE_KEY_HOLDER

    -


    -

    -


    -

    -

    PluginModule + additional actions with plugin owner before actual release.

    +
+


+ +

+

Constants +defined by PluginManager interface (plugin types):

+

TYPE_PROVIDER

+

TYPE_AUTH_SERVER

+

TYPE_AUTH_CLIENT

+

TYPE_AUTH_USER_MANAGEMENT

+

TYPE_EXTERNAL_ENGINE

+

TYPE_TRACE

+

TYPE_WIRE_CRYPT

+

TYPE_DB_CRYPT

+

TYPE_KEY_HOLDER

+


+ +

+


+ +

+

PluginModule interface – represents plugin module (dynamic library). Should be implemented by plugin author in each plugin module (one instance per -module).

-
    -
  1. void doClean() - - called by plugin manager before normal unload of plugin module.

    -
-


-

-


-

-

PluginSet interface – -represents set of plugins of given type. Typically used by internal -firebird code but recommended for use in plugins loading other -plugins.

-
    -
  1. const char* getName() - - get name of current plugin in a set.

    -
  2. const char* - getModuleName() - get name of a module of current plugin in a set - (in simple case matches plugin name).

    -
  3. IPluginBase* +module).

    +
      +
    1. +

      void + doClean() - called by plugin manager before normal unload of plugin + module.

      +
    +


    + +

    +


    + +

    +

    PluginSet +interface – represents set of plugins of given type. Typically used +by internal firebird code but recommended for use in plugins loading +other plugins.

    +
      +
    1. +

      const + char* getName() - get name of current plugin in a set.

      +
    2. +

      const + char* getModuleName() - get name of a module of current plugin in a + set (in simple case matches plugin name).

      +
    3. +

      IPluginBase* getPlugin(StatusType* status) – get an instance of current plugin, returned interface should be casted to main interface of plugin of - requested in PluginManager::getPlugins() + requested in PluginManager::getPlugins() type. Returns NULL if set does not contain any more plugins. Reference counter of plugin, returned by this function, is incremented on return – do not forget to use releasePlugin() - method of PluginManager for plugins - returned by this method.

      -
    4. void next(StatusType* - status) – make set to switch to next plugin from the list.

      -
    5. void set(StatusType* - status, const char* list) – reset interface: make it work with - list of plugins provided by list parameter. Type of plugins remains - unchanged.

      -
    -


    -

    -


    -

    -

    Provider -interface – main interface to start database / service access.

    -
      -
    1. IAttachment* + method of PluginManager for plugins + returned by this method.

      +
    2. +

      void + next(StatusType* status) – make set to switch to next plugin from + the list.

      +
    3. +

      void + set(StatusType* status, const char* list) – reset interface: make + it work with list of plugins provided by list parameter. Type of + plugins remains unchanged.

      +
    +


    + +

    +


    + +

    +

    Provider +interface – main interface to start database / service access.

    +
      +
    1. +

      IAttachment* attachDatabase(StatusType* status, const char* fileName, unsigned dpbLength, const unsigned char* dpb) – replaces - isc_attach_database().

      -
    2. IAttachment* + isc_attach_database().

      +
    3. +

      IAttachment* createDatabase(StatusType* status, const char* fileName, unsigned dpbLength, const unsigned char* dpb) – replaces - isc_create_database().

      -
    4. IService* + isc_create_database().

      +
    5. +

      IService* attachServiceManager(StatusType* status, const char* service, unsigned spbLength, const unsigned char* spb) – replaces - isc_service_attach().

      -
    6. void + isc_service_attach().

      +
    7. +

      void shutdown(StatusType* status, unsigned timeout, const int reason) – - replaces fb_shutdown().

      -
    8. void + replaces fb_shutdown().

      +
    9. +

      void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback) – sets database encryption callback interface that will be used for following database and service attachments. See … - for details.

      -
    -


    -

    -


    -

    -

    ResultSet + for details.

    +
+


+ +

+


+ +

+

ResultSet interface – replaces (with extended functionality) some functions of isc_stmt_handle. This interface is returned by openCursor() call -in IAttachment or IStatement. +in IAttachment or IStatement. All fetch calls except fetchNext() work only for bidirectional -(opened with CURSOR_TYPE_SCROLLABLE flag) result set.

-
    -
  1. int +(opened with CURSOR_TYPE_SCROLLABLE flag) result set.

    +
      +
    1. +

      int fetchNext(StatusType* status, void* message) – fetch next record, replaces isc_dsql_fetch(). This method (and other fetch methods) - returns completion code + returns completion code Status::RESULT_NO_DATA when EOF is reached, Status::RESULT_OK on - success.

      -
    2. int + success.

      +
    3. +

      int fetchPrior(StatusType* status, void* message) – fetch previous - record.

      -
    4. int + record.

      +
    5. +

      int fetchFirst(StatusType* status, void* message) – fetch first - record.

      -
    6. int - fetchLast(StatusType* status, void* message) – fetch last record.

      -
    7. int + record.

      +
    8. +

      int + fetchLast(StatusType* status, void* message) – fetch last record.

      +
    9. +

      int fetchAbsolute(StatusType* status, int position, void* message) – - fetch record by it's absolute position in result set.

      -
    10. int + fetch record by it's absolute position in result set.

      +
    11. +

      int fetchRelative(StatusType* status, int offset, void* message) – - fetch record by position relative to current.

      -
    12. FB_BOOLEAN - isEof(StatusType* status) – check for EOF.

      -
    13. FB_BOOLEAN - isBof(StatusType* status) – check for BOF.

      -
    14. IMessageMetadata* + fetch record by position relative to current.

      +
    15. +

      FB_BOOLEAN + isEof(StatusType* status) – check for EOF.

      +
    16. +

      FB_BOOLEAN + isBof(StatusType* status) – check for BOF.

      +
    17. +

      IMessageMetadata* getMetadata(StatusType* status) – get metadata for messages in result set, specially useful when result set is opened by - IAttachment::openCursor() call with NULL + IAttachment::openCursor() call with NULL output metadata format parameter (this is the only way to obtain - message format in this case).

      -
    18. void + message format in this case).

      +
    19. +

      void close(StatusType* status) – close result set, releases interface - on success.

      -
    -


    -

    -


    -

    -

    Service -interface – replaces isc_svc_handle.

    -
      -
    1. void + on success.

      +
    +


    + +

    +


    + +

    +

    Service +interface – replaces isc_svc_handle.

    +
      +
    1. +

      void detach(StatusType* status) – close attachment to services manager, - on success releases interface. Replaces isc_service_detach().

      -
    2. void + on success releases interface. Replaces isc_service_detach().

      +
    3. +

      void query(StatusType* status, unsigned sendLength, const unsigned char* sendItems, unsigned receiveLength, const unsigned char* receiveItems, unsigned bufferLength, unsigned char* buffer) – send and request information to/from service, with different receiveItems may be used for both running services and to obtain various - server-wide information. Replaces isc_service_query().

      -
    4. void + server-wide information. Replaces isc_service_query().

      +
    5. +

      void start(StatusType* status, unsigned spbLength, const unsigned char* spb) – start utility in services manager. Replaces - isc_service_start().

      -
    -


    -

    -


    -

    -

    Statement -interface – replaces (partially) isc_stmt_handle.

    -
      -
    1. void + isc_service_start().

      +
    +


    + +

    +


    + +

    +

    Statement +interface – replaces (partially) isc_stmt_handle.

    +
      +
    1. +

      void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) – - replaces isc_dsql_sql_info().

      -
    2. unsigned + replaces isc_dsql_sql_info().

      +
    3. +

      unsigned getType(StatusType* status) – statement type, currently can be - found only in firebird sources in dsql/dsql.h.

      -
    4. const char* - getPlan(StatusType* status, FB_BOOLEAN detailed) – returns - statement execution plan.

      -
    5. ISC_UINT64 + found only in firebird sources in dsql/dsql.h.

      +
    6. +

      const + char* getPlan(StatusType* status, FB_BOOLEAN detailed) – returns + statement execution plan.

      +
    7. +

      ISC_UINT64 getAffectedRecords(StatusType* status) – returns number of records - affected by statement.

      -
    8. IMessageMetadata* + affected by statement.

      +
    9. +

      IMessageMetadata* getInputMetadata(StatusType* status) – returns parameters - metadata.

      -
    10. IMessageMetadata* + metadata.

      +
    11. +

      IMessageMetadata* getOutputMetadata(StatusType* status) – returns output values - metadata.

      -
    12. ITransaction* + metadata.

      +
    13. +

      ITransaction* execute(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void* outBuffer) – executes any SQL statement except returning multiple rows of data. Partial analogue of isc_dsql_execute2() - in and out XSLQDAs replaced with input and - output messages with appropriate buffers.

      -
    14. IResultSet* + output messages with appropriate buffers.

      +
    15. +

      IResultSet* openCursor(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned flags) – executes SQL statement potentially @@ -1929,352 +2273,450 @@ interface – replaces (partially) isc_stmt_handle.

      should be used to fetch that data. Format of output data is defined by outMetadata parameter, leaving it NULL default format may be used. Parameter flags is needed to open bidirectional cursor setting - it's value to Istatement::CURSOR_TYPE_SCROLLABLE.

      -
    16. void + it's value to Istatement::CURSOR_TYPE_SCROLLABLE.

      +
    17. +

      void setCursorName(StatusType* status, const char* name) – replaces - isc_dsql_set_cursor_name(). -

      -
    18. void free(StatusType* - status) – free statement, releases interface on success.

      -
    19. unsigned - getFlags(StatusType* status) – returns flags + isc_dsql_set_cursor_name(). +

      +
    20. +

      void + free(StatusType* status) – free statement, releases interface on + success.

      +
    21. +

      unsigned + getFlags(StatusType* status) – returns flags describing how this statement should be executed, simplified - replacement of getType() method.

      -
    -


    -

    -


    -

    -

    Constants defined by -Statement interface:

    -


    -

    -

    IAttachment::prepare() -flags:

    -

    -PREPARE_PREFETCH_NONE – constant to pass no flags, 0 -value.

    -

    The following flags may be -OR-ed to get desired set of flags:

    -
      -
    1. PREPARE_PREFETCH_TYPE

      -
    2. PREPARE_PREFETCH_INPUT_PARAMETERS

      -
    3. PREPARE_PREFETCH_OUTPUT_PARAMETERS

      -
    4. PREPARE_PREFETCH_LEGACY_PLAN

      -
    5. PREPARE_PREFETCH_DETAILED_PLAN

      -
    6. PREPARE_PREFETCH_AFFECTED_RECORDS

      -
    7. PREPARE_PREFETCH_FLAGS - (flags returned by getFlags() method)

      -
    -

    Frequently used -combinations of flags:

    -
      -
    1. PREPARE_PREFETCH_METADATA

      -
    2. PREPARE_PREFETCH_ALL -

      -
    -


    -

    -

    -Values returned by getFlags() method: -

    -

    FLAG_HAS_CURSOR – use -openCursor() to execute this statement, not execute()

    -

    FLAG_REPEAT_EXECUTE – -when prepared statement may be executed many times with different -parameters

    -


    -

    -

    -Flags passed to openCursor():

    -

    CURSOR_TYPE_SCROLLABLE – -open bidirectional cursor.

    -


    -

    -


    -

    -

    Status + replacement of getType() method.

    +
+


+ +

+


+ +

+

Constants +defined by Statement interface:

+


+ +

+

IAttachment::prepare() +flags:

+

+PREPARE_PREFETCH_NONE – +constant to pass no flags, 0 value.

+

The +following flags may be OR-ed to get desired set of flags:

+
    +
  1. +

    PREPARE_PREFETCH_TYPE

    +
  2. +

    PREPARE_PREFETCH_INPUT_PARAMETERS

    +
  3. +

    PREPARE_PREFETCH_OUTPUT_PARAMETERS

    +
  4. +

    PREPARE_PREFETCH_LEGACY_PLAN

    +
  5. +

    PREPARE_PREFETCH_DETAILED_PLAN

    +
  6. +

    PREPARE_PREFETCH_AFFECTED_RECORDS

    +
  7. +

    PREPARE_PREFETCH_FLAGS + (flags returned by getFlags() method)

    +
+

Frequently +used combinations of flags:

+
    +
  1. +

    PREPARE_PREFETCH_METADATA

    +
  2. +

    PREPARE_PREFETCH_ALL + +

    +
+


+ +

+

+Values returned by getFlags() +method: +

+

FLAG_HAS_CURSOR +– use openCursor() to execute this statement, not execute()

+

FLAG_REPEAT_EXECUTE +– when prepared statement may be executed many times with different +parameters

+


+ +

+

+Flags passed to openCursor():

+

CURSOR_TYPE_SCROLLABLE +– open bidirectional cursor.

+


+ +

+


+ +

+

Status interface – replaces ISC_STATUS_ARRAY. Functionality is extended – Status has separate access to errors and warnings vectors, can hold vectors of unlimited length, itself stores strings used in vectors avoiding need in circular strings buffer. In C++ Status is always -used under status wrapper, C++ API provides two different wrappers +used under status wrapper, C++ API provides two different wrappers having different behavior when error is returned from API call. Interface is on purpose minimized (methods like convert it to text -are moved to Util interface) in order to simplify -it's implementation by users when needed.

-
    -
  1. void init() - cleanup - interface, set it to initial state.

    -
  2. unsigned getState() - - get current state of interface, returns state - flags, may be OR-ed.

    -
  3. void +are moved to Util interface) in order to simplify +it's implementation by users when needed.

    +
      +
    1. +

      void + init() - cleanup interface, set it to initial state.

      +
    2. +

      unsigned + getState() - get current state of interface, returns state + flags, may be OR-ed.

      +
    3. +

      void setErrors2(unsigned length, const intptr_t* value) – set contents - of errors vector with length explicitly specified in a call.

      -
    4. void + of errors vector with length explicitly specified in a call.

      +
    5. +

      void setWarnings2(unsigned length, const intptr_t* value) – set contents of warnings vector with length explicitly specified in a - call.

      -
    6. void setErrors(const - intptr_t* value) – set contents of errors vector, length is - defined by value context.

      -
    7. void + call.

      +
    8. +

      void + setErrors(const intptr_t* value) – set contents of errors vector, + length is defined by value context.

      +
    9. +

      void setWarnings(const intptr_t* value) – set contents of warnings - vector, length is defined by value context.

      -
    10. const intptr_t* - getErrors() - get errors vector.

      -
    11. const intptr_t* - getWarnings() - get warnings vector.

      -
    12. IStatus* clone() - - create clone of current interface.

      -
    -


    -

    -

    Constants defined by -Status interface:

    -


    -

    -

    Flags -set in the value, returned by getState() method:

    -

    STATE_WARNINGS

    -

    STATE_ERRORS

    -


    -

    -

    Completion -codes:

    -

    RESULT_ERROR

    -

    RESULT_OK

    -

    RESULT_NO_DATA

    -

    RESULT_SEGMENT

    -


    -

    -


    -

    -

    Timer + vector, length is defined by value context.

    +
  4. +

    const + intptr_t* getErrors() - get errors vector.

    +
  5. +

    const + intptr_t* getWarnings() - get warnings vector.

    +
  6. +

    IStatus* + clone() - create clone of current interface.

    +
+


+ +

+

Constants +defined by Status interface:

+


+ +

+

Flags +set in the value, returned by getState() method:

+

STATE_WARNINGS

+

STATE_ERRORS

+


+ +

+

Completion +codes:

+

RESULT_ERROR

+

RESULT_OK

+

RESULT_NO_DATA

+

RESULT_SEGMENT

+


+ +

+


+ +

+

Timer interface – user timer. Callback interface which should be -implemented by user to use firebird timer.

-
    -
  1. void handler() - - method is called when timer rings (or when server is shutting down).

    -
-


-

-


-

-

TimerControl +implemented by user to use firebird timer.

+
    +
  1. +

    void + handler() - method is called when timer rings (or when server is + shutting down).

    +
+


+ +

+


+ +

+

TimerControl interface – very simple and not too precise implementation of timer. Arrived here because existing timers are very much OS dependent and may be used in programs that require to be portable and do not need really high precision timer. Particularly execution of given timer may be delayed if another one has not completed at the -moment when given timer should alarm.

-
    -
  1. void +moment when given timer should alarm.

    +
      +
    1. +

      void start(StatusType* status, ITimer* timer, ISC_UINT64 microSeconds) – - start ITimer to alarm after given delay (in - microseconds, 10-6 seconds). - Timer will be waked up only once after this call.

      -
    2. void stop(StatusType* - status, ITimer* timer) – stop ITimer. It's - not an error to stop not started timer thus avoiding problems with - races between stop() and timer alarm.

      -
    -


    -

    -

    Transaction -interface – replaces isc_tr_handle.

    -
      -
    1. void + start ITimer to alarm after given delay (in + microseconds, 10-6 + seconds). Timer will be waked + up only once after this call.

      +
    2. +

      void + stop(StatusType* status, ITimer* timer) – stop ITimer. + It's not an error to stop not started timer thus avoiding problems + with races between stop() and timer alarm.

      +
    +


    + +

    +

    Transaction +interface – replaces isc_tr_handle.

    +
      +
    1. +

      void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) – - replaces isc_transaction_info().

      -
    2. void + replaces isc_transaction_info().

      +
    3. +

      void prepare(StatusType* status, unsigned msgLength, const unsigned char* - message) – replaces isc_prepare_transaction2().

      -
    4. void - commit(StatusType* status) – replaces isc_commit_transaction().

      -
    5. void + message) – replaces isc_prepare_transaction2().

      +
    6. +

      void + commit(StatusType* status) – replaces isc_commit_transaction().

      +
    7. +

      void commitRetaining(StatusType* status) – replaces - isc_commit_retaining().

      -
    8. void + isc_commit_retaining().

      +
    9. +

      void rollback(StatusType* status) – replaces - isc_rollback_transaction().

      -
    10. void + isc_rollback_transaction().

      +
    11. +

      void rollbackRetaining(StatusType* status) – replaces - isc_rollback_retaining().

      -
    12. void + isc_rollback_retaining().

      +
    13. +

      void disconnect(StatusType* status) – replaces - fb_disconnect_transaction().

      -
    14. ITransaction* + fb_disconnect_transaction().

      +
    15. +

      ITransaction* join(StatusType* status, ITransaction* transaction) – joins current transaction and passed as parameter transaction into single - distributed transaction (using Dtc). On success + distributed transaction (using Dtc). On success both current transaction and passed as parameter transaction are - released and should not be used any more.

      -
    16. ITransaction* + released and should not be used any more.

      +
    17. +

      ITransaction* validate(StatusType* status, IAttachment* attachment) – this - method is used to support distributed transactions coordinator.

      -
    18. ITransaction* + method is used to support distributed transactions coordinator.

      +
    19. +

      ITransaction* enterDtc(StatusType* status) – this method is used to support - distributed transactions coordinator.

      -
    -


    -

    -


    -

    -

    VersionCallback -interface – callback for Util::getFbVersion().

    -
      -
    1. void + distributed transactions coordinator.

      +
    +


    + +

    +


    + +

    +

    VersionCallback +interface – callback for Util::getFbVersion().

    +
      +
    1. +

      void callback(StatusType* status, const char* text) – called by firebird engine for each line in multiline version report. Makes it possible to print that lines one by one, place them into message box - in any GUI, etc.

      -
    -


    -

    -


    -

    -

    Util -interface – various helper methods required here or there.

    -
      -
    1. void + in any GUI, etc.

      +
    +


    + +

    +


    + +

    +

    Util +interface – various helper methods required here or there.

    +
      +
    1. +

      void getFbVersion(StatusType* status, IAttachment* att, IVersionCallback* callback) – produce long and beautiful report about firebird - version used. It may be seen in ISQL when invoked with -Z switch.

      -
    2. void + version used. It may be seen in ISQL when invoked with -Z switch.

      +
    3. +

      void loadBlob(StatusType* status, ISC_QUAD* blobId, IAttachment* att, ITransaction* tra, const char* file, FB_BOOLEAN txt) – load blob - from file.

      -
    4. void + from file.

      +
    5. +

      void dumpBlob(StatusType* status, ISC_QUAD* blobId, IAttachment* att, ITransaction* tra, const char* file, FB_BOOLEAN txt) – save blob - to file.

      -
    6. void + to file.

      +
    7. +

      void getPerfCounters(StatusType* status, IAttachment* att, const char* countersSet, ISC_INT64* counters) – get statistics for given - attachment.

      -
    8. IAttachment* + attachment.

      +
    9. +

      IAttachment* executeCreateDatabase(StatusType* status, unsigned stmtLength, const char* creatDBstatement, unsigned dialect, FB_BOOLEAN* stmtIsCreateDb) – execute “CREATE DATABASE ...” statement – - ISC trick with NULL statement handle does not work with interfaces.

      -
    10. void + ISC trick with NULL statement handle does not work with interfaces.

      +
    11. +

      void decodeDate(ISC_DATE date, unsigned* year, unsigned* month, unsigned* - day) – replaces isc_decode_sql_date().

      -
    12. void + day) – replaces isc_decode_sql_date().

      +
    13. +

      void decodeTime(ISC_TIME time, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions) – replaces - isc_decode_sql_time().

      -
    14. ISC_DATE + isc_decode_sql_time().

      +
    15. +

      ISC_DATE encodeDate(unsigned year, unsigned month, unsigned day) – replaces - isc_encode_sql_date().

      -
    16. ISC_TIME + isc_encode_sql_date().

      +
    17. +

      ISC_TIME encodeTime(unsigned hours, unsigned minutes, unsigned seconds, - unsigned fractions) – replaces isc_encode_sql_time().

      -
    18. unsigned + unsigned fractions) – replaces isc_encode_sql_time().

      +
    19. +

      unsigned formatStatus(char* buffer, unsigned bufferSize, IStatus* status) – replaces fb_interpret(). Size of buffer, passed into this method, - should not be less than 50 bytes.

      -
    20. unsigned + should not be less than 50 bytes.

      +
    21. +

      unsigned getClientVersion() – returns integer, containing major version in - byte 0 and minor version in byte 1.

      -
    22. IXpbBuilder* + byte 0 and minor version in byte 1.

      +
    23. +

      IXpbBuilder* getXpbBuilder(StatusType* status, unsigned kind, const unsigned - char* buf, unsigned len) – returns XpbBuilder - interface. Valid kinds are - enumerated in XpbBuilder.

      -
    24. unsigned + char* buf, unsigned len) – returns XpbBuilder + interface. Valid kinds are + enumerated in XpbBuilder.

      +
    25. +

      unsigned setOffsets(StatusType* status, IMessageMetadata* metadata, IOffsetsCallback* callback) – sets valid offsets in - MessageMetadata. Performs calls to - callback in OffsetsCallback for each - field/parameter.

      -
    -


    -

    -


    -

    -

    XpbBuilder -methods:

    -
      -
    1. void - clear(StatusType* status) – reset builder to empty state.

      -
    2. void - removeCurrent(StatusType* status) – removes current clumplet.

      -
    3. void + MessageMetadata. Performs calls to + callback in OffsetsCallback for each + field/parameter.

      +
    +


    + +

    +


    + +

    +

    XpbBuilder +methods:

    +
      +
    1. +

      void + clear(StatusType* status) – reset builder to empty state.

      +
    2. +

      void + removeCurrent(StatusType* status) – removes current clumplet.

      +
    3. +

      void insertInt(StatusType* status, unsigned char tag, int value) – inserts a clumplet with value representing integer in network - format.

      -
    4. void + format.

      +
    5. +

      void insertBigInt(StatusType* status, unsigned char tag, ISC_INT64 value) – inserts a clumplet with value representing integer in network - format.

      -
    6. void + format.

      +
    7. +

      void insertBytes(StatusType* status, unsigned char tag, const void* bytes, unsigned length) - inserts a clumplet with value containing - passed bytes.

      -
    8. void + passed bytes.

      +
    9. +

      void insertTag(StatusType* status, unsigned char tag) – inserts a - clumplet without a value.

      -
    10. FB_BOOLEAN + clumplet without a value.

      +
    11. +

      FB_BOOLEAN isEof(StatusType* status) – checks that there is no current - clumplet.

      -
    12. void - moveNext(StatusType* status) – moves to next clumplet.

      -
    13. void - rewind(StatusType* status) – moves to first clumplet.

      -
    14. FB_BOOLEAN + clumplet.

      +
    15. +

      void + moveNext(StatusType* status) – moves to next clumplet.

      +
    16. +

      void + rewind(StatusType* status) – moves to first clumplet.

      +
    17. +

      FB_BOOLEAN findFirst(StatusType* status, unsigned char tag) – finds first - clumplet with given tag.

      -
    18. FB_BOOLEAN - findNext(StatusType* status) – finds next clumplet with given tag.

      -
    19. unsigned char - getTag(StatusType* status) – returns tag for current clumplet.

      -
    20. unsigned + clumplet with given tag.

      +
    21. +

      FB_BOOLEAN + findNext(StatusType* status) – finds next clumplet with given tag.

      +
    22. +

      unsigned + char getTag(StatusType* status) – returns tag for current + clumplet.

      +
    23. +

      unsigned getLength(StatusType* status) – returns length of current clumplet - value.

      -
    24. int + value.

      +
    25. +

      int getInt(StatusType* status) – returns value of current clumplet as - integer.

      -
    26. ISC_INT64 + integer.

      +
    27. +

      ISC_INT64 getBigInt(StatusType* status) – returns value of current clumplet - as 64-bit integer.

      -
    28. const char* - getString(StatusType* status) – returns value of current clumplet - as pointer to zero-terminated string (pointer is valid till next - call to this method).

      -
    29. const unsigned char* - getBytes(StatusType* status) – returns value of current clumplet - as pointer to unsigned char.

      -
    30. unsigned + as 64-bit integer.

      +
    31. +

      const + char* getString(StatusType* status) – returns value of current + clumplet as pointer to zero-terminated string (pointer is valid till + next call to this method).

      +
    32. +

      const + unsigned char* getBytes(StatusType* status) – returns value of + current clumplet as pointer to unsigned char.

      +
    33. +

      unsigned getBufferLength(StatusType* status) – returns length of parameters - block.

      -
    34. const unsigned char* - getBuffer(StatusType* status) – returns pointer to parameters - block.

      -
    -


    -

    -

    Constants defined by -XpbBuilder interface:

    -


    -

    -

    Valid -builder types:

    -

    DPB

    -

    SPB_ATTACH

    -

    SPB_START

    -

    TPB

    -


    -

    -

    Plugin, encrypting data transferred over the wire.

    -

    Algorithms performing -encryption of data for different purposes are well known for many -years. The only “little” typical problem remaining is where to -get the top secret key to be used by that algorithm. Luckily for -network traffic encryption there is one good solution – unique + block.

    +
  2. +

    const + unsigned char* getBuffer(StatusType* status) – returns pointer to + parameters block.

    +
+


+ +

+

Constants +defined by XpbBuilder interface:

+


+ +

+

Valid +builder types:

+

DPB

+

SPB_ATTACH

+

SPB_START

+

TPB

+


+ +

+

Plugin, encrypting data +transferred over the wire.

+

Algorithms +performing encryption of data for different purposes are well known +for many years. The only “little” typical problem remaining is +where to get the top secret key to be used by that algorithm. Luckily +for network traffic encryption there is one good solution – unique encryption key should be generated by authentication plugin. At least default SRP plugin can produce such a key. And that key is resistant to attacks, including man-in-the-middle. Therefore was chosen a @@ -2282,58 +2724,71 @@ method of providing keys for wire crypt plugin: get it from authentication plugin. (In case when used authentication plugin can not provide a key a pseudo-plugin may be added in AuthClient and AuthServer lists to produce keys, something like two asymmetric -private/public pairs.) -

-


-

-

CryptKey interface is used -to store a key provided by authentication plugin and pass it to wire -crypt plugin. This interface should be used as follows – when -server or client authentication plugin is ready to provide a key it -asks ServerBlock or ClientBlock -to produce new CryptKey interface and stores a key in it. Appropriate -for WireCryptPlugin type of key will -be selected by firebird and passed to that interface.

-
    -
  1. void +private/public pairs.) +

    +


    + +

    +

    CryptKey +interface is used to store a key provided by authentication plugin +and pass it to wire crypt plugin. This interface should be used as +follows – when server or client authentication plugin is ready to +provide a key it asks ServerBlock or +ClientBlock to produce new CryptKey +interface and stores a key in it. Appropriate for WireCryptPlugin +type of key will be selected by firebird and passed to that +interface.

    +
      +
    1. +

      void setSymmetric(StatusType* status, const char* type, unsigned keyLength, const void* key) – make it store symmetric key of given - type.

      -
    2. void + type.

      +
    3. +

      void setAsymmetric(StatusType* status, const char* type, unsigned encryptKeyLength, const void* encryptKey, unsigned decryptKeyLength, const void* decryptKey) – make it store pair of asymmetric keys of - given type.

      -
    4. const void* - getEncryptKey(unsigned* length) – get a key for encryption.

      -
    5. const void* - getDecryptKey(unsigned* length) – get a key for decryption (in - case of symmetric key produces same result as getEncryptKey()).

      -
    -


    -

    -

    WireCryptPlugin + given type.

    +
  2. +

    const + void* getEncryptKey(unsigned* length) – get a key for encryption.

    +
  3. +

    const + void* getDecryptKey(unsigned* length) – get a key for decryption + (in case of symmetric key produces same result as getEncryptKey()).

    +
+


+ +

+

WireCryptPlugin interface is main interface of network crypt plugin. Like any other -such interface it should be implemented by author of the plugin.

-
    -
  1. const char* - getKnownTypes(StatusType* status) – returns whitespace/tab/comma - separated list of acceptable keys.

    -
  2. void +such interface it should be implemented by author of the plugin.

    +
      +
    1. +

      const + char* getKnownTypes(StatusType* status) – returns + whitespace/tab/comma separated list of acceptable keys.

      +
    2. +

      void setKey(StatusType* status, ICryptKey* key) – plugin should use a - key passed to it by this call.

      -
    3. void + key passed to it by this call.

      +
    4. +

      void encrypt(StatusType* status, unsigned length, const void* from, void* - to) – encrypts a packet to be sent over the wire.

      -
    5. void + to) – encrypts a packet to be sent over the wire.

      +
    6. +

      void decrypt(StatusType* status, unsigned length, const void* from, void* - to) – decrypts a packet received from network.

      -
    -


    -

    -

    Server side of authentication plugin.

    -

    Authentication plugin -contains two required parts – client and server and may also + to) – decrypts a packet received from network.

    +
+


+ +

+

Server side of +authentication plugin.

+

Authentication +plugin contains two required parts – client and server and may also contain related third part - user manager. During authentication process firebird client invokes client plugin and sends generated by it data to server, next server invokes server plugin and sends @@ -2342,464 +2797,577 @@ plugins return AUTH_MORE_DATA code. AUTH_SUCCESS returned at server side means successful authentication, AUTH_FAILED at any side – immediate abort of iterative process and failure reported to client, AUTH_CONTINUE means that next plugin from the list of configured -authentication plugins should be tried.

-


-

-

There is no dedicated -sample of authentication plugins but in firebird sources in directory -src/auth one can find AuthDbg plugin using which one can learn on -trivial example (no complex calculations like in Srp and no calls to -crazy WinAPI functions like in AuthSspi) how client and server sides -perform authentication handshake. -

-


-

-

Auth interface does not -contain methods, only some constants defining codes return from -authenticate() method of Client and Server.

-

AUTH_FAILED

-

AUTH_SUCCESS

-

AUTH_MORE_DATA

-

AUTH_CONTINUE

-


-

-

Writer -interface – writes authentication parameters block.

-
    -
  1. void reset() - clear - target block.

    -
  2. void add(StatusType* - status, const char* name) – add login name.

    -
  3. void +authentication plugins should be tried.

    +


    + +

    +

    There +is no dedicated sample of authentication plugins but in firebird +sources in directory src/auth one can find AuthDbg plugin using which +one can learn on trivial example (no complex calculations like in Srp +and no calls to crazy WinAPI functions like in AuthSspi) how client +and server sides perform authentication handshake. +

    +


    + +

    +

    Auth +interface does not contain methods, only some constants defining +codes return from authenticate() method of Client +and Server.

    +

    AUTH_FAILED

    +

    AUTH_SUCCESS

    +

    AUTH_MORE_DATA

    +

    AUTH_CONTINUE

    +


    + +

    +

    Writer +interface – writes authentication parameters block.

    +
      +
    1. +

      void + reset() - clear target block.

      +
    2. +

      void + add(StatusType* status, const char* name) – add login name.

      +
    3. +

      void setType(StatusType* status, const char* value) – set type of added - login (user, group, etc).

      -
    4. void + login (user, group, etc).

      +
    5. +

      void setDb(StatusType* status, const char* value) – set security - database in which authentication was done.

      -
    -


    -

    -

    ServerBlock + database in which authentication was done.

    +
+


+ +

+

ServerBlock interface is used by server side of authentication plugin to exchange -data with client.

-
    -
  1. const char* - getLogin() - get login name passed from client.

    -
  2. const unsigned char* - getData(unsigned* length) – get authentication data passed from - client.

    -
  3. void +data with client.

    +
      +
    1. +

      const + char* getLogin() - get login name passed from client.

      +
    2. +

      const + unsigned char* getData(unsigned* length) – get authentication data + passed from client.

      +
    3. +

      void putData(StatusType* status, unsigned length, const void* data) – - pass authentication data to client.

      -
    4. ICryptKey* + pass authentication data to client.

      +
    5. +

      ICryptKey* newKey(StatusType* status) – create new wire crypt key and add it - to the list of available for wire crypt plugins.

      -
    -


    -

    -

    Server -interface is main interface of server side of authentication plugin. -

    -
      -
    1. int + to the list of available for wire crypt plugins.

      +
    +


    + +

    +

    Server +interface is main interface of server side of authentication plugin. +

    +
      +
    1. +

      int authenticate(StatusType* status, IServerBlock* sBlock, IWriter* writerInterface) – perform single authentication step. Data exchange with client is performed using sBlock interface. When some authentication item is produced it should be added to authentication block using writerInterface. Possible return values are defined in - Auth interface.

      -
    -


    -

    -

    Client side of authentication plugin.

    -

    ClientBlock + Auth interface.

    +
+


+ +

+

Client side of +authentication plugin.

+

ClientBlock interface is used by client side of authentication plugin to exchange -data with server.

-
    -
  1. const char* - getLogin() - get login name if it is present in DPB.

    -
  2. const char* - getPassword() - get password if it is present in DPB.

    -
  3. const unsigned char* - getData(unsigned* length) – get authentication data passed from - server.

    -
  4. void +data with server.

    +
      +
    1. +

      const + char* getLogin() - get login name if it is present in DPB.

      +
    2. +

      const + char* getPassword() - get password if it is present in DPB.

      +
    3. +

      const + unsigned char* getData(unsigned* length) – get authentication data + passed from server.

      +
    4. +

      void putData(StatusType* status, unsigned length, const void* data) – - pass authentication data to server.

      -
    5. ICryptKey* + pass authentication data to server.

      +
    6. +

      ICryptKey* newKey(StatusType* status) - create new wire crypt key and add it to - the list of available for wire crypt plugins.

      -
    -


    -

    -

    Client -interface is main interface of client side of authentication plugin.

    -
      -
    1. int + the list of available for wire crypt plugins.

      +
    +


    + +

    +

    Client +interface is main interface of client side of authentication plugin.

    +
      +
    1. +

      int authenticate(StatusType* status, IClientBlock* cBlock)1. – perform single authentication step. Data exchange with server is performed using cBlock interface. Possible return values are defined in Auth interface. AUTH_SUCCESS is treated by client side as AUTH_MORE_DATA (i.e. client sends generated data to server and waits for an answer - from it).

      -
    -


    -

    -

    User management plugin.

    -

    This plugin is actively -related with server side of authentication – it prepares users' -list for authentication plugin. Not each authentication plugin -requires user manager – some may access list of users created using -non-firebird software (AuthSspi for example). Record describing user -consists of a number of fields and operation which should be -performed like add user, modify user, list user(s), etc. Plugin must -interpret commands received in User interface.

    -


    -

    -

    UserField + from it).

    +
+


+ +

+

User management plugin.

+

This +plugin is actively related with server side of authentication – it +prepares users' list for authentication plugin. Not each +authentication plugin requires user manager – some may access list +of users created using non-firebird software (AuthSspi for example). +Record describing user consists of a number of fields and operation +which should be performed like add user, modify user, list user(s), +etc. Plugin must interpret commands received in User +interface.

+


+ +

+

UserField interface is not used as standalone interface, it's base for -CharUserField and IntUserField. -

-
    -
  1. int entered() - - returns non-zero if a value for a field was entered (assigned).

    -
  2. int specified() - - return non-zero if NULL value was assigned to the field.

    -
  3. void +CharUserField and IntUserField. +

    +
      +
    1. +

      int + entered() - returns non-zero if a value for a field was entered + (assigned).

      +
    2. +

      int + specified() - return non-zero if NULL value was assigned to the + field.

      +
    3. +

      void setEntered(StatusType* status, int newValue) – sets entered flag to 0/non-zero value for a field. There is no method to assign NULL for a field cause it's never needed. NULLs if used are assigned by the code implementing interfaces and therefore having full access to - internals of them.

      -
    -


    -

    -

    CharUserField -interface:

    -
      -
    1. const char* get() - - get field's value as C-string (\0 terminated).

      -
    2. void set(StatusType* - status, const char* newValue) – assigns value to the field. Sets - entered flag to true.

      -
    -


    -

    -

    IntUserField -interface:

    -
      -
    1. int get() - get - field's value.

      -
    2. void set(StatusType* - status, int newValue) – assigns value to the field. Sets entered - flag to true.

      -
    -


    -

    -

    User + internals of them.

    +
+


+ +

+

CharUserField +interface:

+
    +
  1. +

    const + char* get() - get field's value as C-string (\0 terminated).

    +
  2. +

    void + set(StatusType* status, const char* newValue) – assigns value to + the field. Sets entered flag to true.

    +
+


+ +

+

IntUserField +interface:

+
    +
  1. +

    int + get() - get field's value.

    +
  2. +

    void + set(StatusType* status, int newValue) – assigns value to the + field. Sets entered flag to true.

    +
+


+ +

+

User interface is a list of methods accessing fields included into record -about the user. -

-
    -
  1. int operation() - - code of operation (see list - below).

    -
  2. ICharUserField* - userName() - login name.

    -
  3. ICharUserField* - password() - password. Always empty when listing users.

    -
  4. ICharUserField* - firstName() - this and 2 next are components of full user name.

    -
  5. ICharUserField* - lastName()

    -
  6. ICharUserField* - middleName()

    -
  7. ICharUserField* - comment() - comment (from SQL operator COMMENT ON USER IS …).

    -
  8. ICharUserField* +about the user. +

    +
      +
    1. +

      unsigned + operation() - code of operation (see list + below).

      +
    2. +

      ICharUserField* + userName() - login name.

      +
    3. +

      ICharUserField* + password() - password. Always empty when listing users.

      +
    4. +

      ICharUserField* + firstName() - this and 2 next are components of full user name.

      +
    5. +

      ICharUserField* + lastName()

      +
    6. +

      ICharUserField* + middleName()

      +
    7. +

      ICharUserField* + comment() - comment (from SQL operator COMMENT ON USER IS …).

      +
    8. +

      ICharUserField* attributes() - tags in a form tag1=val1, tag2=val2, …, tagN=valN. - Val may be empty – than means that tag will be deleted.

      -
    9. IIntUserField* - active() - changes ACTIVE/INACTIVE setting for user.

      -
    10. IIntUserField* - admin() - sets/drops admin rights for the user.

      -
    11. void + Val may be empty – than means that tag will be deleted.

      +
    12. +

      IIntUserField* + active() - changes ACTIVE/INACTIVE setting for user.

      +
    13. +

      IIntUserField* + admin() - sets/drops admin rights for the user.

      +
    14. +

      void clear(StatusType* status) – sets all fields to not entered and not - specified.

      -
    -


    -

    -

    -Constants defined by User interface – valid codes of -operation.

    -

    OP_USER_ADD – create -user

    -

    OP_USER_MODIFY – alter -user

    -

    OP_USER_DELETE – drop -user

    -

    OP_USER_DISPLAY – show -user

    -

    OP_USER_SET_MAP – turn -on mapping of windows admins to role rdb$admin

    -

    OP_USER_DROP_MAP – turn -off mapping of windows admins to role rdb$admin

    -


    -

    -

    ListUsers + specified.

    +
+


+ +

+

+Constants defined by User +interface – valid codes of operation.

+

OP_USER_ADD +– create user

+

OP_USER_MODIFY +– alter user

+

OP_USER_DELETE +– drop user

+

OP_USER_DISPLAY +– show user

+

OP_USER_SET_MAP +– turn on mapping of windows admins to role rdb$admin

+

OP_USER_DROP_MAP +– turn off mapping of windows admins to role rdb$admin

+


+ +

+

ListUsers interface is callback used by authentication plugin when list users -operation is requested. Plugin fills User +operation is requested. Plugin fills User interface for all items in list of users one by one and for each user -calls list() method of this interface.

-
    -
  1. void list(StatusType* - status, IUser* user) – callback function. Implementation can do - what it wants with received data. For example, it may put data from - user parameter into output stream of listing service or place into - special tables from SEC$ group.

    -
-


-

-

LogonInfo +calls list() method of this interface.

+
    +
  1. +

    void + list(StatusType* status, IUser* user) – callback function. + Implementation can do what it wants with received data. For example, + it may put data from user parameter into output stream of listing + service or place into special tables from SEC$ group.

    +
+


+ +

+

LogonInfo interface contains data passed to user mamngement plugin to attach to -security database with valid credentials. Pres

-
    -
  1. const char* name() - - returns current attachment's login name.

    -
  2. const char* role() - - returns current attachment's active role.

    -
  3. const char* - networkProtocol() - returns current attachment's network protocol. - Currently not used by plugins.

    -
  4. const char* - remoteAddress() - returns current attachment's remote address. - Currently not used by plugins.

    -
  5. const unsigned char* - authBlock(unsigned* length) – returns current attachment's - authentication block. When not NULL overrides login name.

    -
-


-

-

Management -interface is main interface of user management plugin.

-
    -
  1. void +security database with valid credentials. Pres

    +
      +
    1. +

      const + char* name() - returns current attachment's login name.

      +
    2. +

      const + char* role() - returns current attachment's active role.

      +
    3. +

      const + char* networkProtocol() - returns current attachment's network + protocol. Currently not used by plugins.

      +
    4. +

      const + char* remoteAddress() - returns current attachment's remote address. + Currently not used by plugins.

      +
    5. +

      const + unsigned char* authBlock(unsigned* length) – returns current + attachment's authentication block. When not NULL overrides login + name.

      +
    +


    + +

    +

    Management +interface is main interface of user management plugin.

    +
      +
    1. +

      void start(StatusType* status, ILogonInfo* logonInfo) – starts plugin, if needed it attaches to security database to manage may be (it's plugin-dependent solution use it or not) using credentials from - logonInfo. -

      -
    2. int + logonInfo. +

      +
    3. +

      int execute(StatusType* status, IUser* user, IListUsers* callback) – executes a command provided by operation() method of user parameter. If needed callback interface will be used. Parameter callback may - have NULL value for commands not requiring users' listing.

      -
    4. void + have NULL value for commands not requiring users' listing.

      +
    5. +

      void commit(StatusType* status) – commits changes done by calls to - execute() method.

      -
    6. void + execute() method.

      +
    7. +

      void rollback(StatusType* status) – rollbacks changes done by calls to - execute() method.

      -
    -


    -

    -

    Database encryption plugin.

    -

    An ability to encrypt -database was present in firebird since interbase times but -appropriate places in the code were commented. Implementation was -suspicious – crypt key was always sent from the client in DPB, no -attempt was made to hide it from the world and no way was suggested -to encrypt existing database. FB3 solves most of the problems except -probably the worst one – how to manage crypt keys. We suggest a -kind of solution but it requires efforts in plugins, i.e. there is no -beautiful way to work with keys like it is for wire crypt plugins.

    -


    -

    -

    Before starting with own -db crypt plugin one should take into an account the following. We see -two main usages of database encryption – first, it may be needed to -avoid data loss if database server is physically stolen, and second, -it may be used to protect data in database which is sailed as a -source of some information together with special application -accessing that data. Requirements for this usages are quite -different. In first case we may trust database server that it is not -modified to steal keys passed to security plugin – i.e. we expect -that key will not be sent to inappropriate server. In second case -server may be modified in some way to steal keys (if they are passed -from application to plugin via server code) or even data (as the last -resort to dump blocks from the cache where they are in non-encrypted -form). Therefore your plugin should make sure that it's running with -not modified firebird binaries and your application before sending a -key to plugin should make sure it's really required plugin, may be -asking a kind of digital signature from it. Making sure that network -line is encrypted (parsing output of Util::getFbVersion()) + execute() method.

    +
+


+ +

+

Database encryption +plugin.

+

An +ability to encrypt database was present in firebird since interbase +times but appropriate places in the code were commented. +Implementation was suspicious – crypt key was always sent from the +client in DPB, no attempt was made to hide it from the world and no +way was suggested to encrypt existing database. FB3 solves most of +the problems except probably the worst one – how to manage crypt +keys. We suggest a kind of solution but it requires efforts in +plugins, i.e. there is no beautiful way to work with keys like it is +for wire crypt plugins.

+


+ +

+

Before +starting with own db crypt plugin one should take into an account the +following. We see two main usages of database encryption – first, +it may be needed to avoid data loss if database server is physically +stolen, and second, it may be used to protect data in database which +is sailed together with special application accessing that data. +Requirements for this usages are quite different. In first case we +may trust database server that it is not modified to steal keys +passed to security plugin – i.e. we expect that key will not be +sent to inappropriate server. In second case server may be modified +in some way to steal keys (if they are passed from application to +plugin via server code) or even data (as the last resort to dump +blocks from the cache where they are in non-encrypted form). +Therefore your plugin should make sure that it's running with not +modified firebird binaries and your application before sending a key +to plugin should make sure it's really required plugin, may be asking +a kind of digital signature from it. Making sure that network line is +encrypted (parsing output of Util::getFbVersion()) or using some own encryption of a key is also very good idea in case when network access to the server is used. All this job should be done in plugin (and application working with it) i.e. database block encryption algorithm by itself may happen to be easiest part of db -crypt plugin.

-


-

-

CryptKeyCallback +crypt plugin, specially +when some standard library is used for it.

+


+ +

+

CryptKeyCallback interface should be provided by a side sending crypt key to db crypt -plugin or key holder plugin.

-
    -
  1. unsigned +plugin or key holder plugin.

    +
      +
    1. +

      unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) – when performing callback information is passed in both directions. The source of a key receives dataLength bytes of data and may send up to bufferLength bytes into - buffer returning actual number of bytes placed into buffer.

      -
    -


    -

    -

    DbCryptPlugin -interface is main interface of database crypt plugin.

    -
      -
    1. void + buffer returning actual number of bytes placed into buffer.

      +
    +


    + +

    +

    DbCryptPlugin +interface is main interface of database crypt plugin.

    +
      +
    1. +

      void setKey(StatusType* status, unsigned length, IKeyHolderPlugin** sources, const char* keyName) – is used to provide to db crypt plugin information about encryption key. Firebird never passes keys - for this type of plugin directly. Instead array of KeyHolderPlugins + for this type of plugin directly. Instead array of KeyHolderPlugins of given length is passed to crypt plugin which must get from one of - it CryptKeyCallback interface and + it CryptKeyCallback interface and get a key using it. Parameter keyName is a name of a key like it was - entered in “ALTER DATABASE ENCRYPT …” operator.

      -
    2. void + entered in “ALTER DATABASE ENCRYPT …” operator.

      +
    3. +

      void encrypt(StatusType* status, unsigned length, const void* from, void* - to)

      -
    4. void + to) – encrypts data before writing block to database file.

      +
    5. +

      void decrypt(StatusType* status, unsigned length, const void* from, void* - to)

      -
    -


    -

    -

    Key holder for database encryption plugin.

    -

    This type of plugin is -needed to delineate functionality – db crypt plugin is dealing with -actual encryption, key holder solves questions related with providing -it a key in secure way. Plugin may be received from application or -loaded in some other way (up to using flash device inserted into -server at firebird startup time).

    -


    -

    -

    KeyHolderPlugin -interface is main interface of database crypt key holder plugin.

    -
      -
    1. int + to) – decrypts data after reading block from database file.

      +
    +


    + +

    +

    Key holder for database +encryption plugin.

    +

    This +type of plugin is needed to delineate functionality – db crypt +plugin is dealing with actual encryption, key holder solves questions +related with providing it a key in secure way. Plugin may be received +from application or loaded in some other way (up to using flash +device inserted into server at firebird startup time).

    +


    + +

    +

    KeyHolderPlugin +interface is main interface of database crypt key holder plugin.

    +
      +
    1. +

      int keyCallback(StatusType* status, ICryptKeyCallback* callback) – is - used to pass attachment's CryptKeyCallback - interface (if provided by user with Provider::setDbCryptCallback() + used to pass attachment's CryptKeyCallback + interface (if provided by user with Provider::setDbCryptCallback() call). This call is always performed at database attach moment, and some holders may reject attachment if satisfactory key was not - provided. This makes it possible to let only specific applications - (i.e. available to provide needed crypt key) access database even if - required key was already provided by another attachment.

      -
    2. ICryptKeyCallback* + provided.

      +
    3. +

      ICryptKeyCallback* keyHandle(StatusType* status, const char* keyName) – is intended - to be called by DbCryptPlugin directly + to be called by DbCryptPlugin directly to obtain callback interface for named key from key holder. This makes it possible for open source firebird code to never touch actual keys avoiding ability to steal a key changing firebird code. - After getting CryptKeyCallback + After getting CryptKeyCallback interface crypt plugin starts data exchange using it. Key holder can (for example) check digital signature of crypt plugin before sending a key to it in order to avoid use of modified crypt plugin able to - steal secret key.

      -
    4. FB_BOOLEAN - useOnlyOwnKeys(StatusType* status) – informs firebird engine can a - key, provided by another key holder, be used or not. Makes sense - only for SuperServer – only it can share database crypt keys + steal secret key.

      +
    5. +

      FB_BOOLEAN + useOnlyOwnKeys(StatusType* status) – informs firebird engine + whether a key, provided by another key holder, be used or not. Makes + sense only for SuperServer – only it can share database crypt keys between attachments. Returning FB_TRUE from this method enforces firebird to make sure that this particular key holder (and therefore in turn attachment related to it) provides correct crypt key before - letting it to work with database.

      -
    -


    -

    -

    Non-interface objects used by API (C++ specific -header Message.h).

    -

    Following 3 classes are -used to represent date, time and timestamp (datetime) when using -FB_MESSAGE macro. Members of data structure, representing static -message, correspondint to fields of types FB_DATE / FB_TIME / + letting it to work with database.

    +
  2. +

    ICryptKeyCallback* + chainHandle(StatusType* status) – support of a chain of key holders. In + some cases key has to pass through more than single key holder + before it reaches db crypt plugin. This is needed (for example) to + support execute statement in encrypted database. This is just a + sample – chains are also used in some other cases. Callback + interface, returned by this method, may differ from one returned by + keyHandle() function (see above). Typically is should be able to + duplicate one-to-one keys, received by KeyHolderPlugin when + keyCallback() function is invoked.

    +
+


+ +

+

Non-interface objects used +by API (C++ specific header Message.h).

+

Following +3 classes are used to represent date, time and timestamp (datetime) +when using FB_MESSAGE macro. Members of data structure, representing +static message, correspondint to fields of types FB_DATE / FB_TIME / FB_TIMESTAMP will have a type of one of this classes. Knowing methods / members (which are enough self-descriptive to avoid describing them here) of this classes is needed to access date and time fields in -static messages.

-


-

-

class -FbDate methods:

-

void decode(IUtil* util, -unsigned* year, unsigned* month, unsigned* day)

-

unsigned getYear(IUtil* -util) -

-

unsigned getMonth(IUtil* -util)

-

unsigned getDay(IUtil* -util)

-

void encode(IUtil* util, -unsigned year, unsigned month, unsigned day)

-


-

-

class -FbTime methods:

-

void decode(IUtil* util, -unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* -fractions)

-

unsigned getHours(IUtil* -util)

-

unsigned getMinutes(IUtil* -util)

-

unsigned getSeconds(IUtil* -util)

-

unsigned -getFractions(IUtil* util)

-

void encode(IUtil* util, -unsigned hours, unsigned minutes, unsigned seconds, unsigned -fractions)

-


-

-

class FbTimestamp members:

-

FbDate date;

-

FbTime time;

-


-

-


-

-

Following two templates -are used in static messages to represent CHAR(N) and VARCHAR(N) -fields. -

-


-

-

template <unsigned N>

-

struct -FbChar

-

{

-

char str[N];

-

};

-


-

-

template <unsigned N>

-

struct -FbVarChar

-

{

-

ISC_USHORT length;

-

char str[N];

-

void set(const char* s);

-

};

-


-

-


-

-
-

This document is currently -missing 2 types of plugins – ExternalEngine and Trace. Information -about them will be made available in next release of it.

-


-

- - \ No newline at end of file +static messages.

+


+ +

+

class +FbDate methods:

+

void +decode(IUtil* util, unsigned* year, unsigned* month, unsigned* day)

+

unsigned +getYear(IUtil* util) +

+

unsigned +getMonth(IUtil* util)

+

unsigned +getDay(IUtil* util)

+

void +encode(IUtil* util, unsigned year, unsigned month, unsigned day)

+


+ +

+

class +FbTime methods:

+

void +decode(IUtil* util, unsigned* hours, unsigned* minutes, unsigned* +seconds, unsigned* fractions)

+

unsigned +getHours(IUtil* util)

+

unsigned +getMinutes(IUtil* util)

+

unsigned +getSeconds(IUtil* util)

+

unsigned +getFractions(IUtil* util)

+

void +encode(IUtil* util, unsigned hours, unsigned minutes, unsigned +seconds, unsigned fractions)

+


+ +

+

class +FbTimestamp members:

+

FbDate +date;

+

FbTime +time;

+


+ +

+


+ +

+

Following +two templates are used in static messages to represent CHAR(N) and +VARCHAR(N) fields. +

+


+ +

+

template +<unsigned N>

+

struct +FbChar

+

{

+

char +str[N];

+

};

+


+ +

+

template +<unsigned N>

+

struct +FbVarChar

+

{

+

ISC_USHORT +length;

+

char +str[N];

+

void +set(const char* s);

+

};

+


+ +

+


+ +

+
+ +

This +document is currently missing 2 types of plugins – ExternalEngine +and Trace. Information about them will be made available in next +release of it.

+


+ +

+ + \ No newline at end of file diff --git a/examples/dbcrypt/CryptApplication.cpp b/examples/dbcrypt/CryptApplication.cpp index 3a2b11d35a..16fff91c83 100644 --- a/examples/dbcrypt/CryptApplication.cpp +++ b/examples/dbcrypt/CryptApplication.cpp @@ -25,6 +25,7 @@ */ #include "../interfaces/ifaceExamples.h" +#include using namespace Firebird; @@ -79,7 +80,7 @@ public: status->dispose(); } - enum Action {NONE, ENC, DEC}; + enum Action {NONE, ENC, DEC, EX_LCL, EX_RMT}; void execute(const char* dbName, const Action a) { @@ -104,18 +105,55 @@ public: throw "startTransaction"; } - if (a == ENC) + switch(a) { + case ENC: att->execute(status, tra, 0, "ALTER DATABASE ENCRYPT WITH \"DbCrypt_example\"", 3, NULL, NULL, NULL, NULL); if (status->getState() & IStatus::STATE_ERRORS) throw "execute"; - } - if (a == DEC) - { + break; + + case DEC: att->execute(status, tra, 0, "ALTER DATABASE DECRYPT", 3, NULL, NULL, NULL, NULL); if (status->getState() & IStatus::STATE_ERRORS) throw "execute"; + break; + + case EX_LCL: + case EX_RMT: + { + FB_MESSAGE(Output, CheckStatusWrapper, + (FB_VARCHAR(31), logon) + ) output(status, master); + + const char* sqlL = "select current_user from rdb$database"; + const char* sqlR = "execute block returns(logon varchar(31)) as begin " + "execute statement 'select current_user from rdb$database' " + "on external 'localhost:employee' as user 'test' password 'test' into :logon; " + "suspend; end"; + const char* sql = a == EX_LCL ? sqlL : sqlR; + + curs = att->openCursor(status, tra, 0, sql, 3, NULL, NULL, output.getMetadata(), NULL, 0); + if (status->getState() & IStatus::STATE_ERRORS) + throw "openCursor"; + + printf("\nExec SQL: %s\nReturns:\n", sql); + while (curs->fetchNext(status, output.getData()) == IStatus::RESULT_OK) + { + unsigned l = output->logonNull ? 0 : output->logon.length; + printf("%*.*s\n", l, l, output->logon.str); + } + printf("done.\n"); + if (status->getState() & IStatus::STATE_ERRORS) + throw "fetchNext"; + + curs->close(status); + if (status->getState() & IStatus::STATE_ERRORS) + throw "close"; + curs = NULL; + break; + } } if (tra) @@ -126,7 +164,7 @@ public: tra = NULL; } - printf("Providing key for crypt plugin - press enter to continue ..."); + printf("\nProviding key for crypt plugin - press enter to continue ..."); getchar(); att->detach(status); @@ -151,13 +189,14 @@ private: IProvider* p; IAttachment* att; ITransaction* tra; + IResultSet* curs; CryptKey key; }; int usage() { - fprintf(stderr, "Usage: CryptApplication [ -e | -d ] { db-name }\n"); + fprintf(stderr, "Usage: cryptAppSample [ -e | -d | -l | -r ] { db-name }\n"); return 2; } @@ -181,6 +220,12 @@ int main(int ac, char** av) case 'd': act = App::DEC; break; + case 'l': + act = App::EX_LCL; + break; + case 'r': + act = App::EX_RMT; + break; default: return usage(); } diff --git a/examples/dbcrypt/CryptKeyHolder.cpp b/examples/dbcrypt/CryptKeyHolder.cpp index cff91c5def..f1c9d0d796 100644 --- a/examples/dbcrypt/CryptKeyHolder.cpp +++ b/examples/dbcrypt/CryptKeyHolder.cpp @@ -77,6 +77,7 @@ public: // IKeyHolderPlugin implementation int keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback); ICryptKeyCallback* keyHandle(CheckStatusWrapper* status, const char* keyName); + ICryptKeyCallback* chainHandle(CheckStatusWrapper* status); int release() { @@ -200,8 +201,6 @@ IConfigEntry* CryptKeyHolder::getEntry(CheckStatusWrapper* status, const char* e int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback) { - status->init(); - if (key != 0) return 1; @@ -258,6 +257,12 @@ ICryptKeyCallback* CryptKeyHolder::keyHandle(CheckStatusWrapper* status, const c return NULL; } +ICryptKeyCallback* CryptKeyHolder::chainHandle(CheckStatusWrapper* status) +{ + return &callbackInterface; +} + + class Factory : public IPluginFactoryImpl { public: diff --git a/examples/dbcrypt/DbCrypt.cpp b/examples/dbcrypt/DbCrypt.cpp index ae20a28380..a8cc249c44 100644 --- a/examples/dbcrypt/DbCrypt.cpp +++ b/examples/dbcrypt/DbCrypt.cpp @@ -236,7 +236,9 @@ void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolder return; if (callback && callback->callback(0, NULL, 1, &key) == 1) + { return; + } } key = 0; diff --git a/src/auth/AuthDbg.cpp b/src/auth/AuthDbg.cpp index 27da2387df..94d58be706 100644 --- a/src/auth/AuthDbg.cpp +++ b/src/auth/AuthDbg.cpp @@ -123,6 +123,9 @@ int DebugServer::authenticate(Firebird::CheckStatusWrapper* status, Firebird::IS return AUTH_FAILED; } +void DebugServer::setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*) +{ /* ignore it */ } + int DebugServer::release() { if (--refCounter == 0) diff --git a/src/auth/AuthDbg.h b/src/auth/AuthDbg.h index a6e00eda9a..3504be0428 100644 --- a/src/auth/AuthDbg.h +++ b/src/auth/AuthDbg.h @@ -54,6 +54,7 @@ public: int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock, Firebird::IWriter* writerInterface); + void setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*); int release(); private: diff --git a/src/auth/SecureRemotePassword/server/SrpServer.cpp b/src/auth/SecureRemotePassword/server/SrpServer.cpp index 3e43866d46..34916a3f4a 100644 --- a/src/auth/SecureRemotePassword/server/SrpServer.cpp +++ b/src/auth/SecureRemotePassword/server/SrpServer.cpp @@ -55,7 +55,7 @@ public: : server(NULL), data(getPool()), account(getPool()), clientPubKey(getPool()), serverPubKey(getPool()), verifier(getPool()), salt(getPool()), sessionKey(getPool()), - secDbName(NULL) + secDbName(NULL), cryptCallback(NULL) { LocalStatus ls; CheckStatusWrapper s(&ls); @@ -65,6 +65,7 @@ public: // IServer implementation int authenticate(CheckStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface); + void setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback); int release(); private: @@ -82,6 +83,7 @@ private: UCharBuffer sessionKey; RefPtr config; const char* secDbName; + ICryptKeyCallback* cryptCallback; }; int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWriter* writerInterface) @@ -130,6 +132,12 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite try { + if (cryptCallback) + { + p->setDbCryptCallback(status, cryptCallback); + status->init(); // ignore possible errors like missing call in provider + } + ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); dpb.insertByte(isc_dpb_sec_attach, TRUE); dpb.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME)); @@ -287,6 +295,11 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite return AUTH_CONTINUE; } +void SrpServer::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback) +{ + cryptCallback = callback; +} + int SrpServer::release() { if (--refCounter == 0) diff --git a/src/auth/SecurityDatabase/LegacyServer.cpp b/src/auth/SecurityDatabase/LegacyServer.cpp index fc270372dd..4898985b3f 100644 --- a/src/auth/SecurityDatabase/LegacyServer.cpp +++ b/src/auth/SecurityDatabase/LegacyServer.cpp @@ -134,6 +134,7 @@ public: // IServer implementation int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock, Firebird::IWriter* writerInterface); + void setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*) { } // ignore int release(); private: diff --git a/src/common/classes/GetPlugins.h b/src/common/classes/GetPlugins.h index cfc84dde10..c226b30dfa 100644 --- a/src/common/classes/GetPlugins.h +++ b/src/common/classes/GetPlugins.h @@ -54,7 +54,7 @@ public: } GetPlugins(unsigned int interfaceType, - Config* knownConfig, const char* namesList = NULL) + const Config* knownConfig, const char* namesList = NULL) : masterInterface(), pluginInterface(), pluginSet(NULL), currentPlugin(NULL), ls(*getDefaultMemoryPool()), status(&ls) diff --git a/src/common/classes/RefCounted.h b/src/common/classes/RefCounted.h index 9a97e63e63..674e892f45 100644 --- a/src/common/classes/RefCounted.h +++ b/src/common/classes/RefCounted.h @@ -33,12 +33,12 @@ namespace Firebird class RefCounted { public: - virtual int addRef() + virtual int addRef() const { return ++m_refCnt; } - virtual int release() + virtual int release() const { fb_assert(m_refCnt.value() > 0); const int refCnt = --m_refCnt; @@ -56,7 +56,7 @@ namespace Firebird } private: - AtomicCounter m_refCnt; + mutable AtomicCounter m_refCnt; }; // reference counted object guard diff --git a/src/common/config/config.cpp b/src/common/config/config.cpp index 572133fb06..5f8ef0c7ad 100644 --- a/src/common/config/config.cpp +++ b/src/common/config/config.cpp @@ -69,12 +69,14 @@ public: } } -/* void changeDefaultConfig(Config* newConfig) +/* It was a kind of getting ready for changing config remotely... + + void changeDefaultConfig(Config* newConfig) { defaultConfig = newConfig; } */ - const Firebird::RefPtr& getDefaultConfig() const + Firebird::RefPtr& getDefaultConfig() { return defaultConfig; } @@ -92,7 +94,7 @@ public: } private: - Firebird::RefPtr defaultConfig; + Firebird::RefPtr defaultConfig; ConfigImpl(const ConfigImpl&); void operator=(const ConfigImpl&); @@ -194,7 +196,8 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] = {TYPE_BOOLEAN, "IPv6V6Only", (ConfigValue) false}, {TYPE_BOOLEAN, "WireCompression", (ConfigValue) false}, {TYPE_INTEGER, "MaxIdentifierByteLength", (ConfigValue) -1}, - {TYPE_INTEGER, "MaxIdentifierCharLength", (ConfigValue) -1} + {TYPE_INTEGER, "MaxIdentifierCharLength", (ConfigValue) -1}, + {TYPE_BOOLEAN, "CryptSecurityDatabase", (ConfigValue) false} }; /****************************************************************************** @@ -256,7 +259,7 @@ Config::Config(const ConfigFile& file, const Config& base, const Firebird::PathN notifyDatabase = notify; } -void Config::notify() +void Config::notify() const { if (!notifyDatabase.hasData()) return; @@ -264,7 +267,7 @@ void Config::notify() notifyDatabase.erase(); } -void Config::merge(Firebird::RefPtr& config, const Firebird::string* dpbConfig) +void Config::merge(Firebird::RefPtr& config, const Firebird::string* dpbConfig) { if (dpbConfig && dpbConfig->hasData()) { @@ -338,7 +341,7 @@ Config::~Config() * Public interface */ -const Firebird::RefPtr& Config::getDefaultConfig() +const Firebird::RefPtr& Config::getDefaultConfig() { return firebirdConf().getDefaultConfig(); } @@ -810,3 +813,8 @@ int Config::getMaxIdentifierCharLength() const return MIN(MAX(rc, 1), METADATA_IDENTIFIER_CHAR_LEN); } + +bool Config::getCryptSecurityDatabase() const +{ + return get(KEY_ENCRYPT_SECURITY_DATABASE); +} diff --git a/src/common/config/config.h b/src/common/config/config.h index d767a83f8a..835d988c3d 100644 --- a/src/common/config/config.h +++ b/src/common/config/config.h @@ -142,6 +142,7 @@ public: KEY_WIRE_COMPRESSION, KEY_MAX_IDENTIFIER_BYTE_LENGTH, KEY_MAX_IDENTIFIER_CHAR_LENGTH, + KEY_ENCRYPT_SECURITY_DATABASE, MAX_CONFIG_KEY // keep it last }; @@ -174,7 +175,7 @@ private: static const ConfigEntry entries[MAX_CONFIG_KEY]; ConfigValue values[MAX_CONFIG_KEY]; - Firebird::PathName notifyDatabase; + mutable Firebird::PathName notifyDatabase; public: explicit Config(const ConfigFile& file); // use to build default config @@ -184,7 +185,7 @@ public: // Call it when database with given config is created - void notify(); + void notify() const; // Check for missing firebird.conf @@ -199,10 +200,10 @@ public: static const Firebird::PathName* getCommandLineRootDirectory(); // Master config - needed to provide per-database config - static const Firebird::RefPtr& getDefaultConfig(); + static const Firebird::RefPtr& getDefaultConfig(); // Merge config entries from DPB into existing config - static void merge(Firebird::RefPtr& config, const Firebird::string* dpbConfig); + static void merge(Firebird::RefPtr& config, const Firebird::string* dpbConfig); // reports key to be used by the following functions static unsigned int getKeyByName(ConfigName name); @@ -349,6 +350,8 @@ public: int getMaxIdentifierByteLength() const; int getMaxIdentifierCharLength() const; + + bool getCryptSecurityDatabase() const; }; // Implementation of interface to access master configuration file @@ -356,7 +359,7 @@ class FirebirdConf FB_FINAL : public Firebird::RefCntIface > { public: - FirebirdConf(Config* existingConfig) + FirebirdConf(const Config* existingConfig) : config(existingConfig) { } @@ -369,7 +372,7 @@ public: int release(); private: - Firebird::RefPtr config; + Firebird::RefPtr config; }; // Create default instance of IFirebirdConf interface diff --git a/src/common/db_alias.cpp b/src/common/db_alias.cpp index b25628c4d8..3c7d680cf6 100644 --- a/src/common/db_alias.cpp +++ b/src/common/db_alias.cpp @@ -227,7 +227,7 @@ namespace } PathName name; - RefPtr config; + RefPtr config; #ifdef HAVE_ID_BY_NAME Id* id; #endif @@ -417,7 +417,7 @@ static inline bool hasSeparator(const PathName& name) // Search for 'alias' in databases.conf, return its value in 'file' if found. Else set file to alias. // Returns true if alias is found in databases.conf. -static bool resolveAlias(const PathName& alias, PathName& file, RefPtr* config) +static bool resolveAlias(const PathName& alias, PathName& file, RefPtr* config) { PathName correctedAlias = alias; replace_dir_sep(correctedAlias); @@ -492,7 +492,7 @@ static bool setPath(const PathName& filename, PathName& expandedName) // Returns true if alias was found in databases.conf bool expandDatabaseName(Firebird::PathName alias, Firebird::PathName& file, - Firebird::RefPtr* config) + Firebird::RefPtr* config) { try { diff --git a/src/common/db_alias.h b/src/common/db_alias.h index e708184688..7d1cb6c1fe 100644 --- a/src/common/db_alias.h +++ b/src/common/db_alias.h @@ -30,7 +30,7 @@ class Config; bool expandDatabaseName(Firebird::PathName alias, Firebird::PathName& file, - Firebird::RefPtr* config); + Firebird::RefPtr* config); bool notifyDatabaseName(const Firebird::PathName& file); diff --git a/src/common/security.cpp b/src/common/security.cpp index 9430ac55dd..4a4c4cef02 100644 --- a/src/common/security.cpp +++ b/src/common/security.cpp @@ -41,7 +41,7 @@ void raise() namespace Auth { -Get::Get(Config* firebirdConf) +Get::Get(const Config* firebirdConf) : GetPlugins(IPluginManager::TYPE_AUTH_USER_MANAGEMENT, firebirdConf) { if (!hasData()) @@ -50,7 +50,7 @@ Get::Get(Config* firebirdConf) } } -Get::Get(Config* firebirdConf, const char* plugName) +Get::Get(const Config* firebirdConf, const char* plugName) : GetPlugins(IPluginManager::TYPE_AUTH_USER_MANAGEMENT, firebirdConf, plugName) { if (!hasData()) diff --git a/src/common/security.h b/src/common/security.h index 5dee7743b5..2dfa024423 100644 --- a/src/common/security.h +++ b/src/common/security.h @@ -259,8 +259,8 @@ public: class Get : public Firebird::GetPlugins { public: - explicit Get(Config* firebirdConf); - Get(Config* firebirdConf, const char* plugName); + explicit Get(const Config* firebirdConf); + Get(const Config* firebirdConf, const char* plugName); }; int setGsecCode(int code, unsigned int operation); diff --git a/src/include/fb_api_proto.h b/src/include/fb_api_proto.h index eecb3a99bf..7c6b22d471 100644 --- a/src/include/fb_api_proto.h +++ b/src/include/fb_api_proto.h @@ -439,6 +439,9 @@ typedef ISC_STATUS API_ROUTINE prototype_fb_cancel_operation(ISC_STATUS *, isc_db_handle *, USHORT); +typedef ISC_STATUS API_ROUTINE prototype_fb_database_crypt_callback(ISC_STATUS *, + void *); + struct FirebirdApiPointers { prototype_isc_attach_database *isc_attach_database; @@ -519,6 +522,7 @@ struct FirebirdApiPointers prototype_isc_service_query *isc_service_query; prototype_isc_service_start *isc_service_start; prototype_fb_cancel_operation *fb_cancel_operation; + prototype_fb_database_crypt_callback *fb_database_crypt_callback; }; #endif diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index 131020db44..39955fa2b9 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -599,6 +599,8 @@ interface Server : Auth { [notImplemented(Auth::AUTH_FAILED)] int authenticate(Status status, ServerBlock sBlock, Writer writerInterface); +version: // 3.0.1 => 4.0 + void setDbCryptCallback(Status status, CryptKeyCallback cryptCallback); } // .. and corresponding client @@ -737,6 +739,8 @@ version: // 3.0.1 => 4.0 // With returning true here KeyHolder attachment can use only keys, provided by this KeyHolder. // Use of keys, got by database crypt plugin from other attachments, is prohibited. boolean useOnlyOwnKeys(Status status); + // Communication in a chain of key holders - get callback interface for chaining holders + CryptKeyCallback chainHandle(Status status); } diff --git a/src/include/firebird/IdlFbInterfaces.h b/src/include/firebird/IdlFbInterfaces.h index a754b720b9..fe07b69a87 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -2402,6 +2402,7 @@ namespace Firebird struct VTable : public IAuth::VTable { int (CLOOP_CARG *authenticate)(IServer* self, IStatus* status, IServerBlock* sBlock, IWriter* writerInterface) throw(); + void (CLOOP_CARG *setDbCryptCallback)(IServer* self, IStatus* status, ICryptKeyCallback* cryptCallback) throw(); }; protected: @@ -2415,7 +2416,7 @@ namespace Firebird } public: - static const unsigned VERSION = 5; + static const unsigned VERSION = 6; template int authenticate(StatusType* status, IServerBlock* sBlock, IWriter* writerInterface) { @@ -2424,6 +2425,19 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback) + { + if (cloopVTable->version < 6) + { + StatusType::setVersionError(status, "IServer", cloopVTable->version, 6); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->setDbCryptCallback(this, status, cryptCallback); + StatusType::checkException(status); + } }; class IClient : public IAuth @@ -2906,6 +2920,7 @@ namespace Firebird int (CLOOP_CARG *keyCallback)(IKeyHolderPlugin* self, IStatus* status, ICryptKeyCallback* callback) throw(); ICryptKeyCallback* (CLOOP_CARG *keyHandle)(IKeyHolderPlugin* self, IStatus* status, const char* keyName) throw(); FB_BOOLEAN (CLOOP_CARG *useOnlyOwnKeys)(IKeyHolderPlugin* self, IStatus* status) throw(); + ICryptKeyCallback* (CLOOP_CARG *chainHandle)(IKeyHolderPlugin* self, IStatus* status) throw(); }; protected: @@ -2950,6 +2965,20 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template ICryptKeyCallback* chainHandle(StatusType* status) + { + if (cloopVTable->version < 5) + { + StatusType::setVersionError(status, "IKeyHolderPlugin", cloopVTable->version, 5); + StatusType::checkException(status); + return 0; + } + StatusType::clearException(status); + ICryptKeyCallback* ret = static_cast(this->cloopVTable)->chainHandle(this, status); + StatusType::checkException(status); + return ret; + } }; class IDbCryptInfo : public IReferenceCounted @@ -10013,6 +10042,7 @@ namespace Firebird this->setOwner = &Name::cloopsetOwnerDispatcher; this->getOwner = &Name::cloopgetOwnerDispatcher; this->authenticate = &Name::cloopauthenticateDispatcher; + this->setDbCryptCallback = &Name::cloopsetDbCryptCallbackDispatcher; } } vTable; @@ -10034,6 +10064,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopsetDbCryptCallbackDispatcher(IServer* self, IStatus* status, ICryptKeyCallback* cryptCallback) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::setDbCryptCallback(&status2, cryptCallback); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw() { try @@ -10099,6 +10143,7 @@ namespace Firebird } virtual int authenticate(StatusType* status, IServerBlock* sBlock, IWriter* writerInterface) = 0; + virtual void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback) = 0; }; template @@ -11246,6 +11291,7 @@ namespace Firebird this->keyCallback = &Name::cloopkeyCallbackDispatcher; this->keyHandle = &Name::cloopkeyHandleDispatcher; this->useOnlyOwnKeys = &Name::cloopuseOnlyOwnKeysDispatcher; + this->chainHandle = &Name::cloopchainHandleDispatcher; } } vTable; @@ -11297,6 +11343,21 @@ namespace Firebird } } + static ICryptKeyCallback* CLOOP_CARG cloopchainHandleDispatcher(IKeyHolderPlugin* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::chainHandle(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } + static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw() { try @@ -11364,6 +11425,7 @@ namespace Firebird virtual int keyCallback(StatusType* status, ICryptKeyCallback* callback) = 0; virtual ICryptKeyCallback* keyHandle(StatusType* status, const char* keyName) = 0; virtual FB_BOOLEAN useOnlyOwnKeys(StatusType* status) = 0; + virtual ICryptKeyCallback* chainHandle(StatusType* status) = 0; }; template diff --git a/src/jrd/CryptoManager.cpp b/src/jrd/CryptoManager.cpp index 9b725178b0..7aaca51d78 100644 --- a/src/jrd/CryptoManager.cpp +++ b/src/jrd/CryptoManager.cpp @@ -47,7 +47,7 @@ #include "../jrd/Monitoring.h" #include "../jrd/os/pio_proto.h" #include "../common/isc_proto.h" -#include "../common/classes/GetPlugins.h" +#include "../common/classes/auto.h" #include "../common/classes/RefMutex.h" #include "../common/classes/ClumpletWriter.h" #include "../common/sha.h" @@ -69,6 +69,19 @@ namespace { const UCHAR CRYPT_INIT = LCK_EX; const int MAX_PLUGIN_NAME_LEN = 31; + + class ReleasePlugin + { + public: + static void clear(IPluginBase* ptr) + { + if (ptr) + { + PluginManagerInterfacePtr()->releasePlugin(ptr); + } + } + }; + } @@ -270,7 +283,7 @@ namespace Jrd { dbInfo(FB_NEW DbInfo(this)), cryptThreadId(0), cryptPlugin(NULL), - checkPlugin(NULL), + checkFactory(NULL), dbb(*tdbb->getDatabase()), cryptAtt(NULL), slowIO(0), @@ -291,6 +304,7 @@ namespace Jrd { delete stateLock; delete threadLock; + delete checkFactory; dbInfo->destroy(); } @@ -363,7 +377,7 @@ namespace Jrd { else keyName = ""; - loadPlugin(hdr->hdr_crypt_plugin); + loadPlugin(tdbb, hdr->hdr_crypt_plugin); string valid; calcValidation(valid, cryptPlugin); @@ -378,10 +392,10 @@ namespace Jrd { } if (flags & CRYPT_HDR_INIT) - checkDigitalSignature(hdr); + checkDigitalSignature(tdbb, hdr); } - void CryptoManager::loadPlugin(const char* pluginName) + void CryptoManager::loadPlugin(thread_db* tdbb, const char* pluginName) { if (cryptPlugin) { @@ -394,14 +408,14 @@ namespace Jrd { return; } - GetPlugins cryptControl(IPluginManager::TYPE_DB_CRYPT, dbb.dbb_config, pluginName); - if (!cryptControl.hasData()) + AutoPtr cryptControl(FB_NEW Factory(IPluginManager::TYPE_DB_CRYPT, dbb.dbb_config, pluginName)); + if (!cryptControl->hasData()) { (Arg::Gds(isc_no_crypt_plugin) << pluginName).raise(); } // do not assign cryptPlugin directly before key init complete - IDbCryptPlugin* p = cryptControl.plugin(); + IDbCryptPlugin* p = cryptControl->plugin(); FbLocalStatus status; p->setInfo(&status, dbInfo); @@ -416,17 +430,15 @@ namespace Jrd { cryptPlugin = p; cryptPlugin->addRef(); - // May be load second instance to validate keys - if (checkPlugin) - { - PluginManagerInterfacePtr()->releasePlugin(checkPlugin); - checkPlugin = NULL; - } + // remove old factory if present + delete checkFactory; + checkFactory = NULL; + // store new one if (dbb.dbb_config->getServerMode() == MODE_SUPER) { - checkPlugin = cryptControl.makeInstance(); - keyHolderPlugins.validate(checkPlugin, NULL, keyName); + checkFactory = cryptControl.release(); + keyHolderPlugins.validateNewAttachment(tdbb->getAttachment(), keyName); } } @@ -483,7 +495,7 @@ namespace Jrd { } keyName = key; - loadPlugin(plugName.c_str()); + loadPlugin(tdbb, plugName.c_str()); } } } @@ -560,7 +572,7 @@ namespace Jrd { // Load plugin if (newCryptState) { - loadPlugin(plugName.c_str()); + loadPlugin(tdbb, plugName.c_str()); } crypt = newCryptState; @@ -580,6 +592,9 @@ namespace Jrd { hc.deleteWithTag(Ods::HDR_crypt_key); if (keyName.hasData()) hc.insertString(Ods::HDR_crypt_key, keyName); + + if (checkFactory) + keyHolderPlugins.validateExistingAttachments(keyName); } else header->hdr_flags &= ~Ods::hdr_encrypted; @@ -591,7 +606,7 @@ namespace Jrd { header->hdr_flags |= Ods::hdr_crypt_process; process = true; - digitalySignDatabase(hdr); + digitalySignDatabase(tdbb, hdr); hdr.flush(); } catch (const Exception&) @@ -641,13 +656,13 @@ namespace Jrd { { keyHolderPlugins.attach(att, dbb.dbb_config); - IDbCryptPlugin* p = checkPlugin; + Factory* f = checkFactory; lockAndReadHeader(tdbb, CRYPT_HDR_INIT); - if (p && p == checkPlugin) + if (f && f == checkFactory) { - if (!keyHolderPlugins.validate(checkPlugin, att, keyName)) + if (!keyHolderPlugins.validateNewAttachment(att, keyName)) (Arg::Gds(isc_bad_crypt_key) << keyName).raise(); } } @@ -713,7 +728,7 @@ namespace Jrd { crypt = hdr->hdr_flags & Ods::hdr_encrypted ? true : false; // If we are going to start crypt thread, we need plugin to be loaded - loadPlugin(hdr->hdr_crypt_plugin); + loadPlugin(tdbb, hdr->hdr_crypt_plugin); releasingLock = true; LCK_release(tdbb, threadLock); @@ -956,7 +971,7 @@ namespace Jrd { } } - digitalySignDatabase(hdr); + digitalySignDatabase(tdbb, hdr); hdr.flush(); } @@ -1162,7 +1177,7 @@ namespace Jrd { return (crypt ? fb_info_crypt_encrypted : 0) | (process ? fb_info_crypt_process : 0); } - void CryptoManager::KeyHolderPlugins::attach(Attachment* att, Config* config) + void CryptoManager::KeyHolderPlugins::attach(Attachment* att, const Config* config) { MutexLockGuard g(holdersMutex, FB_FUNCTION); @@ -1196,7 +1211,7 @@ namespace Jrd { } } - if ((!pa) && config->getServerMode() == MODE_SUPER) + if (!pa) { pa = &(knownHolders.add()); pa->first = att; @@ -1254,7 +1269,7 @@ namespace Jrd { st.check(); } - bool CryptoManager::KeyHolderPlugins::validateHoldersGroup(PerAttHolders& pa, IDbCryptPlugin* crypt, const MetaName& keyName) + bool CryptoManager::KeyHolderPlugins::validateHoldersGroup(PerAttHolders& pa, const MetaName& keyName) { FbLocalStatus st; fb_assert(holdersMutex.locked()); @@ -1265,15 +1280,14 @@ namespace Jrd { if (!keyHolder->useOnlyOwnKeys(&st)) return true; - crypt->setKey(&st, 1, &keyHolder, keyName.c_str()); - if (st.isSuccess() && mgr->checkValidation(crypt)) + if (validateHolder(keyHolder, keyName)) return true; } - return true; + return false; } - bool CryptoManager::KeyHolderPlugins::validate(IDbCryptPlugin* crypt, Attachment* att, const MetaName& keyName) + bool CryptoManager::KeyHolderPlugins::validateNewAttachment(Attachment* att, const MetaName& keyName) { FbLocalStatus st; MutexLockGuard g(holdersMutex, FB_FUNCTION); @@ -1286,10 +1300,7 @@ namespace Jrd { if (pa.first == att) { bool empty = (pa.second.getCount() == 0); - bool result = empty ? false : validateHoldersGroup(pa, crypt, keyName); - - releaseHolders(pa); - knownHolders.remove(i); + bool result = empty ? false : validateHoldersGroup(pa, keyName); if (empty) break; @@ -1299,25 +1310,45 @@ namespace Jrd { } // Special case - holders not needed at all - crypt->setKey(&st, 0, NULL, keyName.c_str()); - if (st.isSuccess() && mgr->checkValidation(crypt)) - return true; + return validateHolder(NULL, keyName); + } + bool CryptoManager::KeyHolderPlugins::validateHolder(IKeyHolderPlugin* keyHolder, const MetaName& keyName) + { + fb_assert(mgr->checkFactory); + if (!mgr->checkFactory) + return false; + + FbLocalStatus st; + + AutoPtr crypt(mgr->checkFactory->makeInstance()); + crypt->setKey(&st, keyHolder ? 1 : 0, &keyHolder, keyName.c_str()); + + if (st.isSuccess()) + { + try + { + if (mgr->checkValidation(crypt)) + return true; + } + catch (const Exception&) + { } // Ignore possible errors, continue analysis + } return false; } - void CryptoManager::KeyHolderPlugins::validate(IDbCryptPlugin* crypt, const MetaName& keyName) + void CryptoManager::KeyHolderPlugins::validateExistingAttachments(const MetaName& keyName) { FbLocalStatus st; - MutexLockGuard g(holdersMutex, FB_FUNCTION); - fb_assert(mgr->dbb.dbb_sync.isLocked()); // Special case - holders not needed at all - crypt->setKey(&st, 0, NULL, keyName.c_str()); - if (st.isSuccess() && mgr->checkValidation(crypt)) + if (validateHolder(NULL, keyName)) return; - // Loop through whole attathment list of DBB, shutdown attachments missing any holders + // Loop through whole attachments list of DBB, shutdown attachments missing any holders + fb_assert(!mgr->dbb.dbb_sync.isLocked()); + MutexLockGuard g(holdersMutex, FB_FUNCTION); + SyncLockGuard dsGuard(&mgr->dbb.dbb_sync, SYNC_EXCLUSIVE, FB_FUNCTION); for (Attachment* att = mgr->dbb.dbb_attachments; att; att = att->att_next) { for (unsigned i = 0; i < knownHolders.getCount(); ++i) @@ -1326,21 +1357,16 @@ namespace Jrd { goto found; } - att->signalCancel(); + att->signalShutdown(); found:; } // Loop through internal attachments list closing one missing valid holders for (unsigned i = 0; i < knownHolders.getCount(); ++i) { - if (!validateHoldersGroup(knownHolders[i], crypt, keyName)) - knownHolders[i].first->signalCancel(); - - // Cleanup holders list - releaseHolders(knownHolders[i]); + if (!validateHoldersGroup(knownHolders[i], keyName)) + knownHolders[i].first->signalShutdown(); } - - knownHolders.clear(); } void CryptoManager::addClumplet(string& signature, ClumpletReader& block, UCHAR tag) @@ -1354,7 +1380,7 @@ found:; } } - void CryptoManager::calcDigitalSignature(string& signature, const Header& hdr) + void CryptoManager::calcDigitalSignature(thread_db* tdbb, string& signature, const Header& hdr) { /* We use the following items to calculate digital signature (hash of encrypted string) @@ -1383,7 +1409,7 @@ found:; unsigned len = signature.length(); len &= ~(QUANTUM - 1); - loadPlugin(hdr->hdr_crypt_plugin); + loadPlugin(tdbb, hdr->hdr_crypt_plugin); string enc; FbLocalStatus sv; @@ -1395,7 +1421,7 @@ found:; } - void CryptoManager::digitalySignDatabase(CchHdr& hdr) + void CryptoManager::digitalySignDatabase(thread_db* tdbb, CchHdr& hdr) { ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size); hdr.getClumplets(hc); @@ -1407,7 +1433,7 @@ found:; { wf = true; string signature; - calcDigitalSignature(signature, hdr); + calcDigitalSignature(tdbb, signature, hdr); hc.insertString(Ods::HDR_crypt_checksum, signature); } @@ -1415,7 +1441,7 @@ found:; hdr.setClumplets(hc); } - void CryptoManager::checkDigitalSignature(const Header& hdr) + void CryptoManager::checkDigitalSignature(thread_db* tdbb, const Header& hdr) { if (hdr->hdr_flags & (Ods::hdr_crypt_process | Ods::hdr_encrypted)) { @@ -1426,7 +1452,7 @@ found:; string sig1, sig2; hc.getString(sig1); - calcDigitalSignature(sig2, hdr); + calcDigitalSignature(tdbb, sig2, hdr); if (sig1 != sig2) Arg::Gds(isc_crypt_checksum).raise(); } diff --git a/src/jrd/CryptoManager.h b/src/jrd/CryptoManager.h index d5a4269c22..69fef7d79a 100644 --- a/src/jrd/CryptoManager.h +++ b/src/jrd/CryptoManager.h @@ -36,6 +36,7 @@ #include "../common/classes/objects_array.h" #include "../common/classes/condition.h" #include "../common/classes/MetaName.h" +#include "../common/classes/GetPlugins.h" #include "../common/ThreadStart.h" #include "../jrd/ods.h" #include "../jrd/status.h" @@ -268,6 +269,8 @@ private: class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync::IBar { public: + typedef Firebird::GetPlugins Factory; + explicit CryptoManager(thread_db* tdbb); ~CryptoManager(); @@ -324,31 +327,34 @@ private: class KeyHolderPlugins { public: + typedef CryptoManager::Factory Factory; + explicit KeyHolderPlugins(Firebird::MemoryPool& p, CryptoManager* m) : knownHolders(p), mgr(m) { } - void attach(Attachment* att, Config* config); + void attach(Attachment* att, const Config* config); void init(Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName); - bool validate(Firebird::IDbCryptPlugin* crypt, Attachment*, const Firebird::MetaName& keyName); - void validate(Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName); + bool validateNewAttachment(Attachment*, const Firebird::MetaName& keyName); + void validateExistingAttachments(const Firebird::MetaName& keyName); void detach(Attachment* att); private: Firebird::Mutex holdersMutex; typedef Firebird::Pair>> PerAttHolders; + Firebird::HalfStaticArray > > PerAttHolders; Firebird::ObjectsArray knownHolders; CryptoManager* mgr; - bool validateHoldersGroup(PerAttHolders& pa, Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName); + bool validateHoldersGroup(PerAttHolders& pa, const Firebird::MetaName& keyName); + bool validateHolder(Firebird::IKeyHolderPlugin* keyHolder, const Firebird::MetaName& keyName); void releaseHolders(PerAttHolders& pa); }; class DbInfo; friend class DbInfo; - class DbInfo FB_FINAL : public Firebird::RefCntIface> + class DbInfo FB_FINAL : public Firebird::RefCntIface > { public: DbInfo(CryptoManager* cm) @@ -383,7 +389,7 @@ private: void doOnTakenWriteSync(thread_db* tdbb); void doOnAst(thread_db* tdbb); - void loadPlugin(const char* pluginName); + void loadPlugin(thread_db* tdbb, const char* pluginName); ULONG getLastPage(thread_db* tdbb); void writeDbHeader(thread_db* tdbb, ULONG runpage); void calcValidation(Firebird::string& valid, Firebird::IDbCryptPlugin* plugin); @@ -394,9 +400,9 @@ private: static const unsigned CRYPT_HDR_NOWAIT = 0x02; void addClumplet(Firebird::string& value, Firebird::ClumpletReader& block, UCHAR tag); - void calcDigitalSignature(Firebird::string& signature, const class Header& hdr); - void digitalySignDatabase(class CchHdr& hdr); - void checkDigitalSignature(const class Header& hdr); + void calcDigitalSignature(thread_db* tdbb, Firebird::string& signature, const class Header& hdr); + void digitalySignDatabase(thread_db* tdbb, class CchHdr& hdr); + void checkDigitalSignature(thread_db* tdbb, const class Header& hdr); BarSync sync; Firebird::MetaName keyName; @@ -407,7 +413,7 @@ private: Firebird::RefPtr dbInfo; Thread::Handle cryptThreadId; Firebird::IDbCryptPlugin* cryptPlugin; - Firebird::IDbCryptPlugin* checkPlugin; + Factory* checkFactory; Database& dbb; Lock* stateLock; Lock* threadLock; diff --git a/src/jrd/Database.h b/src/jrd/Database.h index 962d1078b7..d15554e727 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -461,7 +461,7 @@ public: BackupManager* dbb_backup_manager; // physical backup manager Firebird::TimeStamp dbb_creation_date; // creation date ExternalFileDirectoryList* dbb_external_file_directory_list; - Firebird::RefPtr dbb_config; + Firebird::RefPtr dbb_config; SharedCounter dbb_shared_counter; CryptoManager* dbb_crypto_manager; diff --git a/src/jrd/event.cpp b/src/jrd/event.cpp index cb6dc33263..7aa94343bd 100644 --- a/src/jrd/event.cpp +++ b/src/jrd/event.cpp @@ -120,7 +120,7 @@ void EventManager::destroy(EventManager* eventMgr) } -EventManager::EventManager(const Firebird::string& id, Firebird::RefPtr conf) +EventManager::EventManager(const Firebird::string& id, Firebird::RefPtr conf) : PID(getpid()), m_process(NULL), m_processOffset(0), diff --git a/src/jrd/event_proto.h b/src/jrd/event_proto.h index 9bfd20e0b9..fa26259724 100644 --- a/src/jrd/event_proto.h +++ b/src/jrd/event_proto.h @@ -51,7 +51,7 @@ public: static void init(Attachment*); static void destroy(EventManager*); - EventManager(const Firebird::string& id, Firebird::RefPtr conf); + EventManager(const Firebird::string& id, Firebird::RefPtr conf); ~EventManager(); void deleteSession(SLONG); @@ -104,7 +104,7 @@ private: SLONG m_processOffset; Firebird::string m_dbId; - Firebird::RefPtr m_config; + Firebird::RefPtr m_config; Firebird::AutoPtr > m_sharedMemory; Firebird::Semaphore m_startupSemaphore; diff --git a/src/jrd/ext.cpp b/src/jrd/ext.cpp index 73c416400c..dae4dfe752 100644 --- a/src/jrd/ext.cpp +++ b/src/jrd/ext.cpp @@ -109,7 +109,7 @@ namespace Jrd } private: - RefPtr config; + RefPtr config; }; } diff --git a/src/jrd/extds/IscDS.cpp b/src/jrd/extds/IscDS.cpp index a290a473ce..b98bc170ac 100644 --- a/src/jrd/extds/IscDS.cpp +++ b/src/jrd/extds/IscDS.cpp @@ -124,12 +124,24 @@ void IscConnection::attach(thread_db* tdbb, const PathName& dbName, const MetaNa FbLocalStatus status; { EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); + + ICryptKeyCallback* cb = tdbb->getAttachment()->att_crypt_callback; + m_iscProvider.fb_database_crypt_callback(&status, cb); + if (status->getState() & IStatus::STATE_ERRORS) { + raise(&status, tdbb, "crypt_callback"); + } + m_iscProvider.isc_attach_database(&status, m_dbName.length(), m_dbName.c_str(), &m_handle, newDpb.getBufferLength(), reinterpret_cast(newDpb.getBuffer())); - } - if (status->getState() & IStatus::STATE_ERRORS) { - raise(&status, tdbb, "attach"); + if (status->getState() & IStatus::STATE_ERRORS) { + raise(&status, tdbb, "attach"); + } + + m_iscProvider.fb_database_crypt_callback(&status, NULL); + if (status->getState() & IStatus::STATE_ERRORS) { + raise(&status, tdbb, "crypt_callback"); + } } char buff[16]; @@ -1474,6 +1486,15 @@ ISC_STATUS ISC_EXPORT IscProvider::fb_cancel_operation(FbStatusVector* user_stat return notImplemented(user_status); } +ISC_STATUS ISC_EXPORT IscProvider::fb_database_crypt_callback(FbStatusVector* user_status, + void* cb) +{ + if (m_api.fb_database_crypt_callback) + return m_api.fb_database_crypt_callback(IscStatus(user_status), cb); + + return notImplemented(user_status); +} + void IscProvider::loadAPI() { FbLocalStatus status; @@ -1565,7 +1586,8 @@ static FirebirdApiPointers isc_callbacks = PROTO(isc_service_detach), PROTO(isc_service_query), PROTO(isc_service_start), - PROTO(fb_cancel_operation) + PROTO(fb_cancel_operation), + PROTO(fb_database_crypt_callback) }; diff --git a/src/jrd/extds/IscDS.h b/src/jrd/extds/IscDS.h index dd3abb95e5..e330170ba7 100644 --- a/src/jrd/extds/IscDS.h +++ b/src/jrd/extds/IscDS.h @@ -482,6 +482,9 @@ public: virtual ISC_STATUS ISC_EXPORT fb_cancel_operation(Jrd::FbStatusVector*, isc_db_handle*, USHORT); + + virtual ISC_STATUS ISC_EXPORT fb_database_crypt_callback(Jrd::FbStatusVector*, + void*); }; diff --git a/src/jrd/extds/ValidatePassword.cpp b/src/jrd/extds/ValidatePassword.cpp index 315c11b335..ee14bdb04f 100644 --- a/src/jrd/extds/ValidatePassword.cpp +++ b/src/jrd/extds/ValidatePassword.cpp @@ -180,7 +180,7 @@ void validatePassword(thread_db* tdbb, const PathName& file, ClumpletWriter& dpb Arg::Gds loginError(isc_login_error); // Build list of client/server plugins - RefPtr config; + RefPtr config; PathName list; expandDatabaseName(file, list /* unused value */, &config); PathName serverList = config->getPlugins(IPluginManager::TYPE_AUTH_SERVER); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 4b748d86bd..3f1918b536 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -969,7 +969,7 @@ public: void get(const UCHAR*, USHORT, bool&); - void setBuffers(RefPtr config) + void setBuffers(RefPtr config) { if (dpb_buffers == 0) { @@ -1046,7 +1046,7 @@ static VdnResult verifyDatabaseName(const PathName&, FbStatusVector*, bool); static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* userStatus, Jrd::Attachment* attachment, Database* dbb, bool internalFlag); -static JAttachment* initAttachment(thread_db*, const PathName&, const PathName&, RefPtr, bool, +static JAttachment* initAttachment(thread_db*, const PathName&, const PathName&, RefPtr, bool, const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*, JProvider*); static JAttachment* create_attachment(const PathName&, Database*, const DatabaseOptions&, bool newDb); static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*); @@ -1056,7 +1056,7 @@ static void release_attachment(thread_db*, Jrd::Attachment*); static void rollback(thread_db*, jrd_tra*, const bool); static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0); static void getUserInfo(UserId&, const DatabaseOptions&, const char*, const char*, - const RefPtr*, bool, IAttachment*, ICryptKeyCallback*); + const RefPtr*, bool, IAttachment*, ICryptKeyCallback*); static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM); @@ -1343,7 +1343,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch ThreadContextHolder tdbb(user_status); DatabaseOptions options; - RefPtr config; + RefPtr config; bool invalid_client_SQL_dialect = false; PathName org_filename, expanded_name; bool is_alias = false; @@ -2427,7 +2427,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch DatabaseOptions options; PathName org_filename, expanded_name; bool is_alias = false; - Firebird::RefPtr config; + Firebird::RefPtr config; try { @@ -5981,7 +5981,7 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli static JAttachment* initAttachment(thread_db* tdbb, const PathName& expanded_name, - const PathName& alias_name, RefPtr config, bool attach_flag, + const PathName& alias_name, RefPtr config, bool attach_flag, const DatabaseOptions& options, RefMutexUnlock& initGuard, IPluginConfig* pConf, JProvider* provider) { @@ -7126,7 +7126,7 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status if (!securityNameBuffer->hasData()) { - const RefPtr defConf(Config::getDefaultConfig()); + const RefPtr defConf(Config::getDefaultConfig()); securityNameBuffer->assign(defConf->getSecurityDatabase()); expandedSecurityNameBuffer->assign(securityNameBuffer); ISC_expand_filename(expandedSecurityNameBuffer, false); @@ -7166,7 +7166,7 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status **/ static void getUserInfo(UserId& user, const DatabaseOptions& options, - const char* aliasName, const char* dbName, const RefPtr* config, bool creating, + const char* aliasName, const char* dbName, const RefPtr* config, bool creating, IAttachment* iAtt, ICryptKeyCallback* cryptCb) { bool wheel = false; diff --git a/src/jrd/svc.cpp b/src/jrd/svc.cpp index d84ae989e2..98e21eea5f 100644 --- a/src/jrd/svc.cpp +++ b/src/jrd/svc.cpp @@ -729,7 +729,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d if (svc_auth_block.hasData()) { PathName dummy; - RefPtr config; + RefPtr config; expandDatabaseName(svc_expected_db, dummy, &config); string trusted_role; @@ -1310,7 +1310,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/, { // The path to the user security database (security2.fdb) char* pb = reinterpret_cast(buffer); - const RefPtr defConf(Config::getDefaultConfig()); + const RefPtr defConf(Config::getDefaultConfig()); strcpy(pb, defConf->getSecurityDatabase()); if (!(info = INF_put_item(item, static_cast(strlen(pb)), buffer, info, end))) @@ -1764,7 +1764,7 @@ void Service::query(USHORT send_item_length, { // The path to the user security database (security2.fdb) char* pb = reinterpret_cast(buffer); - const RefPtr defConf(Config::getDefaultConfig()); + const RefPtr defConf(Config::getDefaultConfig()); strcpy(pb, defConf->getSecurityDatabase()); if (!(info = INF_put_item(item, static_cast(strlen(pb)), buffer, info, end))) diff --git a/src/jrd/trace/TraceManager.cpp b/src/jrd/trace/TraceManager.cpp index 2a874a46cb..5de23e9740 100644 --- a/src/jrd/trace/TraceManager.cpp +++ b/src/jrd/trace/TraceManager.cpp @@ -285,7 +285,7 @@ void TraceManager::update_session(const TraceSession& session) if (session.ses_auth.hasData()) { PathName dummy; - RefPtr config; + RefPtr config; expandDatabaseName(service->getExpectedDb(), dummy, &config); if (mapUser(false, s_user, t_role, NULL, NULL, NULL, session.ses_auth, "services manager", diff --git a/src/lock/lock.cpp b/src/lock/lock.cpp index 00479a980e..4123d06bef 100644 --- a/src/lock/lock.cpp +++ b/src/lock/lock.cpp @@ -167,7 +167,7 @@ Firebird::GlobalPtr LockManager::g_lmMap; Firebird::GlobalPtr LockManager::g_mapMutex; -LockManager* LockManager::create(const Firebird::string& id, RefPtr conf) +LockManager* LockManager::create(const Firebird::string& id, RefPtr conf) { Firebird::MutexLockGuard guard(g_mapMutex, FB_FUNCTION); @@ -208,7 +208,7 @@ void LockManager::destroy(LockManager* lockMgr) } -LockManager::LockManager(const Firebird::string& id, RefPtr conf) +LockManager::LockManager(const Firebird::string& id, RefPtr conf) : PID(getpid()), m_bugcheck(false), m_sharedFileCreated(false), diff --git a/src/lock/lock_proto.h b/src/lock/lock_proto.h index 2faec49d1d..fe79dc2fc0 100644 --- a/src/lock/lock_proto.h +++ b/src/lock/lock_proto.h @@ -398,7 +398,7 @@ class LockManager : private Firebird::RefCounted, const int PID; public: - static LockManager* create(const Firebird::string&, Firebird::RefPtr); + static LockManager* create(const Firebird::string&, Firebird::RefPtr); static void destroy(LockManager*); bool initializeOwner(Firebird::CheckStatusWrapper*, LOCK_OWNER_T, UCHAR, SRQ_PTR*); @@ -421,7 +421,7 @@ public: void exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync::ThreadRoutine* routine); private: - explicit LockManager(const Firebird::string&, Firebird::RefPtr); + explicit LockManager(const Firebird::string&, Firebird::RefPtr); ~LockManager(); void acquire_shmem(SRQ_PTR); @@ -500,7 +500,7 @@ private: bool m_blockage; Firebird::string m_dbId; - Firebird::RefPtr m_config; + Firebird::RefPtr m_config; // configurations parameters - cached values const ULONG m_acquireSpins; diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp index 6108d9aa67..1548659784 100644 --- a/src/remote/client/interface.cpp +++ b/src/remote/client/interface.cpp @@ -693,7 +693,8 @@ static Rvnt* add_event(rem_port*); static void add_other_params(rem_port*, ClumpletWriter&, const ParametersSet&); static void add_working_directory(ClumpletWriter&, const PathName&); static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned flags, - ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name); + ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name, + Firebird::ICryptKeyCallback* cryptCb); static void batch_gds_receive(rem_port*, struct rmtque *, USHORT); static void batch_dsql_fetch(rem_port*, struct rmtque *, USHORT); static void clear_queue(rem_port*); @@ -798,7 +799,7 @@ IAttachment* RProvider::attach(CheckStatusWrapper* status, const char* filename, PathName node_name; ClntAuthBlock cBlock(&expanded_name, &newDpb, &dpbParam); - rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL); + rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL, cryptCallback); if (!port) { @@ -1420,7 +1421,7 @@ Firebird::IAttachment* RProvider::create(CheckStatusWrapper* status, const char* PathName node_name; ClntAuthBlock cBlock(&expanded_name, &newDpb, &dpbParam); - rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL); + rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL, cryptCallback); if (!port) { @@ -4631,7 +4632,7 @@ Firebird::IService* RProvider::attachSvc(CheckStatusWrapper* status, const char* if (newSpb.find(isc_spb_expected_db)) newSpb.getPath(refDbName); - rem_port* port = analyze(cBlock, expanded_name, flags, newSpb, spbParam, node_name, &refDbName); + rem_port* port = analyze(cBlock, expanded_name, flags, newSpb, spbParam, node_name, &refDbName, cryptCallback); RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION); Rdb* rdb = port->port_context; @@ -5400,7 +5401,8 @@ static void secureAuthentication(ClntAuthBlock& cBlock, rem_port* port) static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned flags, - ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name) + ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name, + Firebird::ICryptKeyCallback* cryptCb) { /************************************** * @@ -5464,7 +5466,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned } port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_UV, pb, - cBlock.getConfig(), ref_db_name, inet_af); + cBlock.getConfig(), ref_db_name, cryptCb, inet_af); } // We have a local connection string. If it's a file on a network share, @@ -5498,7 +5500,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned ISC_utf8ToSystem(node_name); port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_UV, pb, - cBlock.getConfig(), ref_db_name); + cBlock.getConfig(), ref_db_name, cryptCb); } } #endif @@ -5527,7 +5529,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned if (!port) { port = INET_analyze(&cBlock, attach_name, INET_LOCALHOST, flags & ANALYZE_UV, pb, - cBlock.getConfig(), ref_db_name); + cBlock.getConfig(), ref_db_name, cryptCb); } } } diff --git a/src/remote/inet.cpp b/src/remote/inet.cpp index 54c0907668..45320c230c 100644 --- a/src/remote/inet.cpp +++ b/src/remote/inet.cpp @@ -457,7 +457,7 @@ static rem_port* inet_try_connect( PACKET*, const PathName&, const TEXT*, ClumpletReader&, - RefPtr*, + RefPtr*, const PathName*, int); static bool inet_write(XDR*); @@ -538,8 +538,9 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock, const TEXT* node_name, bool uv_flag, ClumpletReader &dpb, - RefPtr* config, + RefPtr* config, const PathName* ref_db_name, + Firebird::ICryptKeyCallback* cryptCb, int af) { /************************************** @@ -619,7 +620,8 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock, REMOTE_PROTOCOL(PROTOCOL_VERSION11, ptype_lazy_send, 2), REMOTE_PROTOCOL(PROTOCOL_VERSION12, ptype_lazy_send, 3), REMOTE_PROTOCOL(PROTOCOL_VERSION13, ptype_lazy_send, 4), - REMOTE_PROTOCOL(PROTOCOL_VERSION14, ptype_lazy_send, 5) + REMOTE_PROTOCOL(PROTOCOL_VERSION14, ptype_lazy_send, 5), + REMOTE_PROTOCOL(PROTOCOL_VERSION15, ptype_lazy_send, 6) }; fb_assert(FB_NELEM(protocols_to_try) <= FB_NELEM(cnct->p_cnct_versions)); cnct->p_cnct_count = FB_NELEM(protocols_to_try); @@ -634,51 +636,96 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock, } rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb, config, ref_db_name, af); + P_ACPT* accept; - P_ACPT* accept = NULL; - switch (packet->p_operation) + for(;;) { - case op_accept_data: - case op_cond_accept: - accept = &packet->p_acpd; - if (cBlock) + accept = NULL; + switch (packet->p_operation) { - cBlock->storeDataForPlugin(packet->p_acpd.p_acpt_data.cstr_length, - packet->p_acpd.p_acpt_data.cstr_address); - cBlock->authComplete = packet->p_acpd.p_acpt_authenticated; - port->addServerKeys(&packet->p_acpd.p_acpt_keys); - cBlock->resetClnt(&file_name, &packet->p_acpd.p_acpt_keys); - } - break; + case op_accept_data: + case op_cond_accept: + accept = &packet->p_acpd; + if (cBlock) + { + cBlock->storeDataForPlugin(packet->p_acpd.p_acpt_data.cstr_length, + packet->p_acpd.p_acpt_data.cstr_address); + cBlock->authComplete = packet->p_acpd.p_acpt_authenticated; + port->addServerKeys(&packet->p_acpd.p_acpt_keys); + cBlock->resetClnt(&file_name, &packet->p_acpd.p_acpt_keys); + } + break; - case op_accept: - if (cBlock) - { - cBlock->resetClnt(&file_name); - } - accept = &packet->p_acpt; - break; + case op_accept: + if (cBlock) + { + cBlock->resetClnt(&file_name); + } + accept = &packet->p_acpt; + break; - case op_response: - try - { - LocalStatus warning; // Ignore connect warnings for a while - CheckStatusWrapper statusWrapper(&warning); - REMOTE_check_response(&statusWrapper, rdb, packet, false); - } - catch (const Exception&) - { + case op_crypt_key_callback: + try + { + UCharBuffer buf; + P_CRYPT_CALLBACK* cc = &packet->p_cc; + + if (cryptCb) + { + if (cc->p_cc_reply <= 0) + { + cc->p_cc_reply = 1; + } + UCHAR* reply = buf.getBuffer(cc->p_cc_reply); + unsigned l = cryptCb->callback(cc->p_cc_data.cstr_length, + cc->p_cc_data.cstr_address, cc->p_cc_reply, reply); + + REMOTE_free_packet(port, packet, true); + cc->p_cc_data.cstr_length = l; + cc->p_cc_data.cstr_address = reply; + } + else + { + REMOTE_free_packet(port, packet, true); + cc->p_cc_data.cstr_length = 0; + } + + packet->p_operation = op_crypt_key_callback; + cc->p_cc_reply = 0; + port->send(packet); + port->receive(packet); + continue; + } + catch (const Exception&) + { + disconnect(port); + delete rdb; + throw; + } + + case op_response: + try + { + LocalStatus warning; // Ignore connect warnings for a while + CheckStatusWrapper statusWrapper(&warning); + REMOTE_check_response(&statusWrapper, rdb, packet, false); + } + catch (const Exception&) + { + disconnect(port); + delete rdb; + throw; + } + // fall through - response is not a required accept + + default: disconnect(port); delete rdb; - throw; + Arg::Gds(isc_connect_reject).raise(); + break; } - // fall through - response is not a required accept - default: - disconnect(port); - delete rdb; - Arg::Gds(isc_connect_reject).raise(); - break; + break; // Always leave for() loop here } fb_assert(accept); @@ -720,7 +767,7 @@ rem_port* INET_connect(const TEXT* name, PACKET* packet, USHORT flag, ClumpletReader* dpb, - RefPtr* config, + RefPtr* config, int af) { /************************************** @@ -2662,7 +2709,7 @@ static rem_port* inet_try_connect(PACKET* packet, const PathName& file_name, const TEXT* node_name, ClumpletReader& dpb, - RefPtr* config, + RefPtr* config, const PathName* ref_db_name, int af) { diff --git a/src/remote/inet_proto.h b/src/remote/inet_proto.h index 6aeebace22..85db279bf5 100644 --- a/src/remote/inet_proto.h +++ b/src/remote/inet_proto.h @@ -34,10 +34,10 @@ namespace Firebird } rem_port* INET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*, - bool, Firebird::ClumpletReader&, Firebird::RefPtr*, - const Firebird::PathName*, int af = AF_UNSPEC); + bool, Firebird::ClumpletReader&, Firebird::RefPtr*, + const Firebird::PathName*, Firebird::ICryptKeyCallback*, int af = AF_UNSPEC); rem_port* INET_connect(const TEXT*, struct packet*, USHORT, Firebird::ClumpletReader*, - Firebird::RefPtr*, int af = AF_UNSPEC); + Firebird::RefPtr*, int af = AF_UNSPEC); rem_port* INET_reconnect(SOCKET); rem_port* INET_server(SOCKET); void setStopMainThread(FPTR_INT func); diff --git a/src/remote/os/win32/wnet.cpp b/src/remote/os/win32/wnet.cpp index 21682a4541..6af1d51371 100644 --- a/src/remote/os/win32/wnet.cpp +++ b/src/remote/os/win32/wnet.cpp @@ -72,7 +72,7 @@ static void disconnect(rem_port*); static void exit_handler(void*); #endif static void force_close(rem_port*); -static rem_str* make_pipe_name(const RefPtr&, const TEXT*, const TEXT*, const TEXT*); +static rem_str* make_pipe_name(const RefPtr&, const TEXT*, const TEXT*, const TEXT*); static rem_port* receive(rem_port*, PACKET*); static int send_full(rem_port*, PACKET*); static int send_partial(rem_port*, PACKET*); @@ -104,7 +104,7 @@ rem_port* WNET_analyze(ClntAuthBlock* cBlock, const PathName& file_name, const TEXT* node_name, bool uv_flag, - RefPtr* config, + RefPtr* config, const Firebird::PathName* ref_db_name) { /************************************** @@ -269,7 +269,7 @@ rem_port* WNET_analyze(ClntAuthBlock* cBlock, } -rem_port* WNET_connect(const TEXT* name, PACKET* packet, USHORT flag, Firebird::RefPtr* config) +rem_port* WNET_connect(const TEXT* name, PACKET* packet, USHORT flag, Firebird::RefPtr* config) { /************************************** * @@ -800,7 +800,7 @@ static void exit_handler(void* main_port) #endif -static rem_str* make_pipe_name(const RefPtr& config, const TEXT* connect_name, +static rem_str* make_pipe_name(const RefPtr& config, const TEXT* connect_name, const TEXT* suffix_name, const TEXT* str_pid) { /************************************** diff --git a/src/remote/os/win32/wnet_proto.h b/src/remote/os/win32/wnet_proto.h index c2fc22288a..ab1723d1f8 100644 --- a/src/remote/os/win32/wnet_proto.h +++ b/src/remote/os/win32/wnet_proto.h @@ -32,8 +32,8 @@ extern "C" { rem_port* WNET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*, bool, - Firebird::RefPtr*, const Firebird::PathName*); -rem_port* WNET_connect(const TEXT*, struct packet*, USHORT, Firebird::RefPtr*); + Firebird::RefPtr*, const Firebird::PathName*); +rem_port* WNET_connect(const TEXT*, struct packet*, USHORT, Firebird::RefPtr*); rem_port* WNET_reconnect(HANDLE); diff --git a/src/remote/os/win32/xnet.cpp b/src/remote/os/win32/xnet.cpp index cba8163b0e..f45862e91b 100644 --- a/src/remote/os/win32/xnet.cpp +++ b/src/remote/os/win32/xnet.cpp @@ -148,7 +148,7 @@ namespace Remote { } - rem_port* connect_client(PACKET*, const RefPtr*); + rem_port* connect_client(PACKET*, const RefPtr*); void server_shutdown(rem_port* port); private: @@ -238,7 +238,7 @@ static void xnet_log_error(const char* err_msg) rem_port* XNET_analyze(ClntAuthBlock* cBlock, const PathName& file_name, bool uv_flag, - RefPtr* config, + RefPtr* config, const Firebird::PathName* ref_db_name) { /************************************** @@ -403,7 +403,7 @@ rem_port* XNET_analyze(ClntAuthBlock* cBlock, rem_port* XNET_connect(PACKET* packet, USHORT flag, - Firebird::RefPtr* config) + Firebird::RefPtr* config) { /************************************** * @@ -1087,7 +1087,7 @@ static void raise_lostconn_or_syserror(const char* msg) } -rem_port* XnetClientEndPoint::connect_client(PACKET* packet, const RefPtr* config) +rem_port* XnetClientEndPoint::connect_client(PACKET* packet, const RefPtr* config) { /************************************** * @@ -1100,7 +1100,7 @@ rem_port* XnetClientEndPoint::connect_client(PACKET* packet, const RefPtr& conf(config ? *config : Config::getDefaultConfig()); + const Firebird::RefPtr& conf(config ? *config : Config::getDefaultConfig()); if (!xnet_initialized) { diff --git a/src/remote/os/win32/xnet_proto.h b/src/remote/os/win32/xnet_proto.h index cfd617ca18..4133827d56 100644 --- a/src/remote/os/win32/xnet_proto.h +++ b/src/remote/os/win32/xnet_proto.h @@ -32,9 +32,9 @@ #define rem_port void #endif -rem_port* XNET_analyze(ClntAuthBlock*, const Firebird::PathName&, bool, Firebird::RefPtr*, +rem_port* XNET_analyze(ClntAuthBlock*, const Firebird::PathName&, bool, Firebird::RefPtr*, const Firebird::PathName*); -rem_port* XNET_connect(struct packet*, USHORT, Firebird::RefPtr*); +rem_port* XNET_connect(struct packet*, USHORT, Firebird::RefPtr*); rem_port* XNET_reconnect(ULONG); #endif // REMOTE_XNET_PROTO_H diff --git a/src/remote/protocol.cpp b/src/remote/protocol.cpp index 8c4a4ab3da..ea31ff484f 100644 --- a/src/remote/protocol.cpp +++ b/src/remote/protocol.cpp @@ -803,7 +803,9 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p) MAP(xdr_cstring, cc->p_cc_data); rem_port* port = (rem_port*) xdrs->x_public; - if (port->port_protocol >= PROTOCOL_VERSION14) + // If the protocol is 0 we are in the process of establishing a connection. + // crypt_key_callback at this phaze means server protocol is at least P15 + if (port->port_protocol >= PROTOCOL_VERSION14 || port->port_protocol == 0) MAP(xdr_short, reinterpret_cast(cc->p_cc_reply)); DEBUG_PRINTSIZE(xdrs, p->p_operation); diff --git a/src/remote/protocol.h b/src/remote/protocol.h index 9ba758e932..35dc0e9d89 100644 --- a/src/remote/protocol.h +++ b/src/remote/protocol.h @@ -82,6 +82,11 @@ const USHORT PROTOCOL_VERSION13 = (FB_PROTOCOL_FLAG | 13); const USHORT PROTOCOL_VERSION14 = (FB_PROTOCOL_FLAG | 14); +// Protocol 15: +// - supports crypt key callback at connect phaze + +const USHORT PROTOCOL_VERSION15 = (FB_PROTOCOL_FLAG | 15); + // Architecture types enum P_ARCH diff --git a/src/remote/remot_proto.h b/src/remote/remot_proto.h index 7e2cdb6d25..09d99640b3 100644 --- a/src/remote/remot_proto.h +++ b/src/remote/remot_proto.h @@ -61,7 +61,7 @@ void REMOTE_reset_request (struct Rrq *, struct RMessage*); void REMOTE_reset_statement (struct Rsr *); bool_t REMOTE_getbytes (XDR*, SCHAR*, u_int); LegacyPlugin REMOTE_legacy_auth(const char* nm, int protocol); -Firebird::RefPtr REMOTE_get_config(const Firebird::PathName* dbName, +Firebird::RefPtr REMOTE_get_config(const Firebird::PathName* dbName, const Firebird::string* dpb_config = NULL); void REMOTE_check_response(Firebird::IStatus* warning, Rdb* rdb, PACKET* packet, bool checkKeys = false); bool REMOTE_inflate(rem_port*, PacketReceive*, UCHAR*, SSHORT, SSHORT*); diff --git a/src/remote/remote.cpp b/src/remote/remote.cpp index 574005e0ba..2862401732 100644 --- a/src/remote/remote.cpp +++ b/src/remote/remote.cpp @@ -604,7 +604,12 @@ void rem_port::linkParent(rem_port* const parent) parent->port_clients = parent->port_next = this; } -const Firebird::RefPtr& rem_port::getPortConfig() const +const Firebird::RefPtr& rem_port::getPortConfig() const +{ + return port_config.hasData() ? port_config : Config::getDefaultConfig(); +} + +Firebird::RefPtr rem_port::getPortConfig() { return port_config.hasData() ? port_config : Config::getDefaultConfig(); } @@ -1006,7 +1011,7 @@ void ClntAuthBlock::resetClnt(const Firebird::PathName* fileName, const CSTRING* plugins.set(final.c_str()); } -Firebird::RefPtr* ClntAuthBlock::getConfig() +Firebird::RefPtr* ClntAuthBlock::getConfig() { return clntConfig.hasData() ? &clntConfig : NULL; } @@ -1017,10 +1022,10 @@ void ClntAuthBlock::storeDataForPlugin(unsigned int length, const unsigned char* HANDSHAKE_DEBUG(fprintf(stderr, "Cli: accepted data for plugin length=%d\n", length)); } -Firebird::RefPtr REMOTE_get_config(const Firebird::PathName* dbName, +Firebird::RefPtr REMOTE_get_config(const Firebird::PathName* dbName, const Firebird::string* dpb_config) { - Firebird::RefPtr config; + Firebird::RefPtr config; if (dbName && dbName->hasData()) { diff --git a/src/remote/remote.h b/src/remote/remote.h index cee570f609..4f73c3cdbe 100644 --- a/src/remote/remote.h +++ b/src/remote/remote.h @@ -703,7 +703,7 @@ private: Firebird::UCharBuffer dataForPlugin, dataFromPlugin; Firebird::HalfStaticArray cryptKeys; // Wire crypt keys that came from plugin(s) last time Firebird::string dpbConfig; // Used to recreate config with new filename - Firebird::RefPtr clntConfig; // Used to get plugins list and pass to port + Firebird::RefPtr clntConfig; // Used to get plugins list and pass to port unsigned nextKey; // First key to be analyzed bool hasCryptKey; // DPB contains disk crypt key, may be passed only over encrypted wire @@ -733,7 +733,7 @@ public: Firebird::PathName getPluginName(); void tryNewKeys(rem_port*); void releaseKeys(unsigned from); - Firebird::RefPtr* getConfig(); + Firebird::RefPtr* getConfig(); // Firebird::IClientBlock implementation int release(); @@ -947,7 +947,7 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted OBJCT port_last_object_id; // cached last id Firebird::ObjectsArray< Firebird::Array > port_queue; FB_SIZE_T port_qoffset; // current packet in the queue - Firebird::RefPtr port_config; // connection-specific configuration info + Firebird::RefPtr port_config; // connection-specific configuration info // Authentication and crypt stuff ServerAuthBase* port_srv_auth; @@ -1023,7 +1023,8 @@ public: static bool checkCompression(); void linkParent(rem_port* const parent); void unlinkParent(); - const Firebird::RefPtr& getPortConfig() const; + Firebird::RefPtr getPortConfig(); + const Firebird::RefPtr& getPortConfig() const; void versionInfo(Firebird::string& version) const; bool extractNewKeys(CSTRING* to, bool flagPlugList = false) diff --git a/src/remote/server/os/posix/inet_server.cpp b/src/remote/server/os/posix/inet_server.cpp index f22f898cf2..56f6a1ff9b 100644 --- a/src/remote/server/os/posix/inet_server.cpp +++ b/src/remote/server/os/posix/inet_server.cpp @@ -399,7 +399,7 @@ int CLIB_ROUTINE main( int argc, char** argv) ISC_STATUS_ARRAY status; isc_db_handle db_handle = 0L; - const Firebird::RefPtr defConf(Config::getDefaultConfig()); + const Firebird::RefPtr defConf(Config::getDefaultConfig()); const char* path = defConf->getSecurityDatabase(); const char dpb[] = {isc_dpb_version1, isc_dpb_sec_attach, 1, 1, isc_dpb_address_path, 0}; diff --git a/src/remote/server/server.cpp b/src/remote/server/server.cpp index 0031b38097..bd6c50bde9 100644 --- a/src/remote/server/server.cpp +++ b/src/remote/server/server.cpp @@ -105,7 +105,175 @@ public: namespace { +// DB crypt key passthrough + +class NetworkCallback : public VersionedIface > +{ +public: + explicit NetworkCallback(rem_port* prt) + : port(prt), l(0), d(NULL), stopped(false), wake(false) + { } + + unsigned int callback(unsigned int dataLength, const void* data, + unsigned int bufferLength, void* buffer) + { + if (stopped) + return 0; + + if (port->port_protocol < PROTOCOL_VERSION13) + return 0; + + Reference r(*port); + + d = buffer; + l = bufferLength; + + PACKET p; + p.p_operation = op_crypt_key_callback; + p.p_cc.p_cc_data.cstr_length = dataLength; + p.p_cc.p_cc_data.cstr_address = (UCHAR*) data; + p.p_cc.p_cc_reply = bufferLength; + port->send(&p); + + if (!sem.tryEnter(60)) + return 0; + + return l; + } + + void wakeup(unsigned int length, const void* data) + { + if (l > length) + l = length; + memcpy(d, data, l); + + wake = true; + sem.release(); + } + + void stop() + { + stopped = true; + } + + bool isStopped() const + { + return stopped; + } + +private: + rem_port* port; + Semaphore sem; + unsigned int l; + void* d; + bool stopped; + +public: + bool wake; +}; + +class CryptKeyCallback : public VersionedIface > +{ +public: + explicit CryptKeyCallback(rem_port* prt) + : port(prt), networkCallback(prt), keyHolder(NULL), keyCallback(NULL) + { } + + ~CryptKeyCallback() + { + if (keyHolder) + PluginManagerInterfacePtr()->releasePlugin(keyHolder); + } + + unsigned int callback(unsigned int dataLength, const void* data, + unsigned int bufferLength, void* buffer) + { + if (keyCallback) + return keyCallback->callback(dataLength, data, bufferLength, buffer); + + if (networkCallback.isStopped()) + return 0; + + Reference r(*port); + + for (GetPlugins kh(IPluginManager::TYPE_KEY_HOLDER, port->getPortConfig()); + kh.hasData(); kh.next()) + { + IKeyHolderPlugin* keyPlugin = kh.plugin(); + LocalStatus ls; + CheckStatusWrapper st(&ls); + + networkCallback.wake = false; + if (keyPlugin->keyCallback(&st, &networkCallback) && networkCallback.wake) + { + // current holder has a key and it seems to be from the client + keyHolder = keyPlugin; + keyHolder->addRef(); + keyCallback = keyHolder->chainHandle(&st); + + if (st.isEmpty() && keyCallback) + break; + } + } + + unsigned rc = keyCallback ? + keyCallback->callback(dataLength, data, bufferLength, buffer) : + // use legacy behavior if holders to do wish to accept keys from client + networkCallback.callback(dataLength, data, bufferLength, buffer); + + //stop(); + return rc; + } + + void wakeup(unsigned int length, const void* data) + { + networkCallback.wakeup(length, data); + } + + void stop() + { + networkCallback.stop(); + } + +private: + rem_port* port; + NetworkCallback networkCallback; + IKeyHolderPlugin* keyHolder; + ICryptKeyCallback* keyCallback; +}; + +class ServerCallback : public ServerCallbackBase, public GlobalStorage +{ +public: + explicit ServerCallback(rem_port* prt) + : cryptCallback(prt) + { } + + ~ServerCallback() + { } + + void wakeup(unsigned int length, const void* data) + { + cryptCallback.wakeup(length, data); + } + + ICryptKeyCallback* getInterface() + { + return &cryptCallback; + } + + void stop() + { + cryptCallback.stop(); + } + +private: + CryptKeyCallback cryptCallback; +}; + + // Disable attempts to brute-force logins/passwords + class FailedLogin { public: @@ -287,6 +455,7 @@ static void getMultiPartConnectParameter(T& putTo, Firebird::ClumpletReader& id, // delayed authentication block for auth callback + class ServerAuth : public GlobalStorage, public ServerAuthBase { public: @@ -379,6 +548,11 @@ public: authPort->port_srv_auth_block->setDataForPlugin(u); } #endif + + if (!authPort->port_server_crypt_callback) + { + authPort->port_server_crypt_callback = FB_NEW ServerCallback(authPort); + } } ~ServerAuth() @@ -425,6 +599,13 @@ public: { authServer = authItr->plugin(); authPort->port_srv_auth_block->authBlockWriter.setPlugin(authItr->name()); + + if (authPort->getPortConfig()->getCryptSecurityDatabase() && + authPort->port_protocol >= PROTOCOL_VERSION15 && + authPort->port_server_crypt_callback) + { + authServer->setDbCryptCallback(&st, authPort->port_server_crypt_callback->getInterface()); + } } // if we asked for more data but received nothing switch to next plugin @@ -774,6 +955,9 @@ private: Rvnt* event; }; + +// Stores types of known wire crypt keys + class CryptKeyTypeManager : public PermanentStorage { class CryptKeyType : public PermanentStorage @@ -868,91 +1052,6 @@ private: InitInstance knownCryptKeyTypes; -class CryptKeyCallback : public VersionedIface > -{ -public: - explicit CryptKeyCallback(rem_port* prt) - : port(prt), l(0), d(NULL), stopped(false) - { } - - unsigned int callback(unsigned int dataLength, const void* data, - unsigned int bufferLength, void* buffer) - { - if (stopped) - return 0; - - Reference r(*port); - - PACKET p; - p.p_operation = op_crypt_key_callback; - p.p_cc.p_cc_data.cstr_length = dataLength; - p.p_cc.p_cc_data.cstr_address = (UCHAR*) data; - p.p_cc.p_cc_reply = bufferLength; - port->send(&p); - - if (!sem.tryEnter(10)) - return 0; - - if (bufferLength > l) - bufferLength = l; - memcpy(buffer, d, bufferLength); - if (l) - sem2.release(); - - return l; - } - - void wakeup(unsigned int length, const void* data) - { - l = length; - d = data; - sem.release(); - if (l) - sem2.enter(); - } - - void stop() - { - stopped = true; - } - -private: - rem_port* port; - Semaphore sem, sem2; - unsigned int l; - const void* d; - bool stopped; -}; - -class ServerCallback : public ServerCallbackBase, public GlobalStorage -{ -public: - explicit ServerCallback(rem_port* prt) - : cryptCallback(prt) - { } - - ~ServerCallback() - { } - - void wakeup(unsigned int length, const void* data) - { - cryptCallback.wakeup(length, data); - } - - ICryptKeyCallback* getInterface() - { - return &cryptCallback; - } - - void stop() - { - cryptCallback.stop(); - } - -private: - CryptKeyCallback cryptCallback; -}; - } // anonymous static void free_request(server_req_t*); @@ -1715,11 +1814,8 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send) for (const p_cnct::p_cnct_repeat* const end = protocol + connect->p_cnct_count; protocol < end; protocol++) { - if ((protocol->p_cnct_version == PROTOCOL_VERSION10 || - protocol->p_cnct_version == PROTOCOL_VERSION11 || - protocol->p_cnct_version == PROTOCOL_VERSION12 || - protocol->p_cnct_version == PROTOCOL_VERSION13 || - protocol->p_cnct_version == PROTOCOL_VERSION14) && + if ((protocol->p_cnct_version >= PROTOCOL_VERSION10 && + protocol->p_cnct_version <= PROTOCOL_VERSION15) && (protocol->p_cnct_architecture == arch_generic || protocol->p_cnct_architecture == ARCHITECTURE) && protocol->p_cnct_weight >= weight) @@ -2239,13 +2335,10 @@ void DatabaseAuth::accept(PACKET* send, Auth::WriterImplementation* authBlock) const UCHAR* dpb = pb->getBuffer(); unsigned int dl = (ULONG) pb->getBufferLength(); - if (!authPort->port_server_crypt_callback) - { - authPort->port_server_crypt_callback = FB_NEW ServerCallback(authPort); - } - LocalStatus ls; CheckStatusWrapper status_vector(&ls); + + fb_assert(authPort->port_server_crypt_callback); provider->setDbCryptCallback(&status_vector, authPort->port_server_crypt_callback->getInterface()); if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS)) @@ -5378,16 +5471,13 @@ ISC_STATUS rem_port::service_attach(const char* service_name, // they will be stuffed in the SPB if so. REMOTE_get_timeout_params(this, spb); - if (!port_server_crypt_callback) - { - port_server_crypt_callback = FB_NEW ServerCallback(this); - } - DispatcherPtr provider; LocalStatus ls; CheckStatusWrapper status_vector(&ls); + fb_assert(port_server_crypt_callback); provider->setDbCryptCallback(&status_vector, port_server_crypt_callback->getInterface()); + if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS)) { dumpAuthBlock("rem_port::service_attach()", spb, isc_spb_auth_block); @@ -6500,7 +6590,7 @@ void SrvAuthBlock::createPluginsItr() REMOTE_makeList(pluginList, final); - RefPtr portConf(port->getPortConfig()); + RefPtr portConf(port->getPortConfig()); plugins = FB_NEW AuthServerPlugins(IPluginManager::TYPE_AUTH_SERVER, portConf, pluginList.c_str()); } diff --git a/src/utilities/gsec/gsec.cpp b/src/utilities/gsec/gsec.cpp index 8f2f0ac6b7..687c33a7e5 100644 --- a/src/utilities/gsec/gsec.cpp +++ b/src/utilities/gsec/gsec.cpp @@ -379,7 +379,7 @@ int gsec(Firebird::UtilSvc* uSvc) } else { - const Firebird::RefPtr defConf(Config::getDefaultConfig()); + const Firebird::RefPtr defConf(Config::getDefaultConfig()); databaseName = defConf->getSecurityDatabase(); } @@ -460,8 +460,8 @@ int gsec(Firebird::UtilSvc* uSvc) Firebird::string databaseText; databaseText.printf("SecurityDatabase = %s\n", databaseName.c_str()); ConfigFile gsecDatabase(ConfigFile::USE_TEXT, databaseText.c_str()); - Firebird::RefPtr defaultConfig(Config::getDefaultConfig()); - Firebird::RefPtr pseudoConfig(FB_NEW Config(gsecDatabase, *defaultConfig)); + Firebird::RefPtr defaultConfig(Config::getDefaultConfig()); + Firebird::RefPtr pseudoConfig(FB_NEW Config(gsecDatabase, *defaultConfig)); uSvc->checkService(); diff --git a/src/yvalve/PluginManager.cpp b/src/yvalve/PluginManager.cpp index 7cf73764ca..9bb607e945 100644 --- a/src/yvalve/PluginManager.cpp +++ b/src/yvalve/PluginManager.cpp @@ -563,7 +563,7 @@ namespace { if (!firebirdConf.hasData()) { - RefPtr specificConf(Config::getDefaultConfig()); + RefPtr specificConf(Config::getDefaultConfig()); firebirdConf = FB_NEW FirebirdConf(specificConf); } @@ -1257,7 +1257,7 @@ public: try { PathName dummy; - Firebird::RefPtr config; + Firebird::RefPtr config; expandDatabaseName(dbName, dummy, &config); IFirebirdConf* firebirdConf = FB_NEW FirebirdConf(config); diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index 8a703e35c8..4b27496e75 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -5663,7 +5663,7 @@ YAttachment* Dispatcher::attachOrCreateDatabase(Firebird::CheckStatusWrapper* st orgFilename.rtrim(); PathName expandedFilename; - RefPtr config; + RefPtr config; if (expandDatabaseName(orgFilename, expandedFilename, &config)) { expandedFilename = orgFilename; @@ -5790,7 +5790,7 @@ YService* Dispatcher::attachServiceManager(CheckStatusWrapper* status, const cha } // Build correct config - RefPtr config(Config::getDefaultConfig()); + RefPtr config(Config::getDefaultConfig()); if (spbWriter.find(isc_spb_config)) { string spb_config; From feeea1b51aee0aa107198c674078f1366130aa67 Mon Sep 17 00:00:00 2001 From: hvlad Date: Tue, 31 Jan 2017 22:48:55 +0200 Subject: [PATCH 107/134] Fixed Windows build. Alex, please check --- src/auth/trusted/AuthSspi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/auth/trusted/AuthSspi.h b/src/auth/trusted/AuthSspi.h index a776a068d0..a1f8bbc9b7 100644 --- a/src/auth/trusted/AuthSspi.h +++ b/src/auth/trusted/AuthSspi.h @@ -107,6 +107,7 @@ public: // IServer implementation int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock, Firebird::IWriter* writerInterface); + void setDbCryptCallback(Firebird::CheckStatusWrapper* status, Firebird::ICryptKeyCallback* callback) {}; // do nothing int release(); WinSspiServer(Firebird::IPluginConfig*); From 006c026c06de8e1ed33091c61ea0c35bdbe6b914 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Wed, 1 Feb 2017 00:02:16 +0000 Subject: [PATCH 108/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index ecb60f9f1e..55ac093546 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:514 + FORMAL BUILD NUMBER:519 */ -#define PRODUCT_VER_STRING "4.0.0.514" -#define FILE_VER_STRING "WI-T4.0.0.514" -#define LICENSE_VER_STRING "WI-T4.0.0.514" -#define FILE_VER_NUMBER 4, 0, 0, 514 +#define PRODUCT_VER_STRING "4.0.0.519" +#define FILE_VER_STRING "WI-T4.0.0.519" +#define LICENSE_VER_STRING "WI-T4.0.0.519" +#define FILE_VER_NUMBER 4, 0, 0, 519 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "514" +#define FB_BUILD_NO "519" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 0d83660cde..42ab388cc9 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=514 +BuildNum=519 NowAt=`pwd` cd `dirname $0` From a5f73c57dee02fd236328201d7128f0b31649b9b Mon Sep 17 00:00:00 2001 From: hvlad Date: Thu, 2 Feb 2017 13:29:34 +0200 Subject: [PATCH 109/134] Fixed bug CORE-5448 : FB3 - crash (consistency check) when creating view on table which has column with character set none, database default charset is utf8, and utf8 default collation is 'unicode' --- src/jrd/dfw.epp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 89bfee7074..1395d6a521 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -5827,7 +5827,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$CHARACTER_SET_ID, collation)) { - if (REL.RDB$FORMAT.NULL) + if (null_view && REL.RDB$FORMAT.NULL) DPM_delete_relation(tdbb, relation); ERR_post(Arg::Gds(isc_no_meta_update) << @@ -5837,7 +5837,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ // Make sure the text type specified is implemented if (!validate_text_type(tdbb, tfb)) { - if (REL.RDB$FORMAT.NULL) + if (null_view && REL.RDB$FORMAT.NULL) DPM_delete_relation(tdbb, relation); ERR_post_nothrow(Arg::Gds(isc_no_meta_update) << From 2df9f4f6d3288f8966ef9069dc92d1eee7b531d9 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Thu, 2 Feb 2017 17:05:46 +0300 Subject: [PATCH 110/134] Postfix (mostly comments & documentation) for core-5472 --- doc/Using_OO_API.html | 36 +++++++++++++++++------ examples/dbcrypt/CryptApplication.cpp | 6 ++++ examples/dbcrypt/ReadMe.txt | 41 +++++++++++++++++++++++++-- src/jrd/extds/IscDS.cpp | 26 +++++++++++------ 4 files changed, 89 insertions(+), 20 deletions(-) diff --git a/doc/Using_OO_API.html b/doc/Using_OO_API.html index ce36b2e009..2c01816baf 100644 --- a/doc/Using_OO_API.html +++ b/doc/Using_OO_API.html @@ -5,8 +5,10 @@ - - + + + + @@ -3161,8 +3163,7 @@ or using some own encryption of a key is also very good idea in case when network access to the server is used. All this job should be done in plugin (and application working with it) i.e. database block encryption algorithm by itself may happen to be easiest part of db -crypt plugin, specially -when some standard library is used for it.

+crypt plugin, specially when some standard library is used for it.


@@ -3180,6 +3181,19 @@ plugin or key holder plugin.


+

+

DbCryptInfo +interface is passed to DbCryptPlugin by engine. Plugin may save this +interface and use when needed to obtain additional informatio about +database.

+
    +
  1. +

    const + char* getDatabaseFullPath(StatusType* status) – returns full + (including path) name of primary database file.

    +
+


+

DbCryptPlugin interface is main interface of database crypt plugin.

@@ -3202,6 +3216,10 @@ interface is main interface of database crypt plugin.

void decrypt(StatusType* status, unsigned length, const void* from, void* to) – decrypts data after reading block from database file.

+
  • +

    void + setInfo(StatusType* status, IDbCryptInfo* info) – in this method + crypt plugin typically saves informational interface for future use.


    @@ -3251,11 +3269,11 @@ interface is main interface of database crypt key holder plugin.

    letting it to work with database.

  • ICryptKeyCallback* - chainHandle(StatusType* status) – support of a chain of key holders. In - some cases key has to pass through more than single key holder - before it reaches db crypt plugin. This is needed (for example) to - support execute statement in encrypted database. This is just a - sample – chains are also used in some other cases. Callback + chainHandle(StatusType* status) – support of a chain of key + holders. In some cases key has to pass through more than single key + holder before it reaches db crypt plugin. This is needed (for + example) to support execute statement in encrypted database. This is + just a sample – chains are also used in some other cases. Callback interface, returned by this method, may differ from one returned by keyHandle() function (see above). Typically is should be able to duplicate one-to-one keys, received by KeyHolderPlugin when diff --git a/examples/dbcrypt/CryptApplication.cpp b/examples/dbcrypt/CryptApplication.cpp index 16fff91c83..ad6d385e65 100644 --- a/examples/dbcrypt/CryptApplication.cpp +++ b/examples/dbcrypt/CryptApplication.cpp @@ -81,6 +81,12 @@ public: } enum Action {NONE, ENC, DEC, EX_LCL, EX_RMT}; + // Switches/actions have the following meanings: + // ENC(-e) - encrypt database + // DEC(-d) - decrypt database + // EX_LCL(-l) - execute some predefined select command (demonstrates that database can respond to select request) + // EX_RMT(-r) - execute select using execute statement in remote datasource (demonstrates that dbcrypt key is + // passed to target database when using execute statement) void execute(const char* dbName, const Action a) { diff --git a/examples/dbcrypt/ReadMe.txt b/examples/dbcrypt/ReadMe.txt index c6c3deeade..90ad08f808 100644 --- a/examples/dbcrypt/ReadMe.txt +++ b/examples/dbcrypt/ReadMe.txt @@ -1,2 +1,39 @@ -All files in this directory are trivial samples. -They do not perform any real data encryption and should not be used in production! +************************************************************************************** +* All files in this directory are trivial samples. * +* They do not perform any real data encryption and should not be used in production! * +************************************************************************************** + +Brief description of the sample. + +Sample contains 3 components - DbCrypt plugin, KeyHolder plugin and application, which can pass +crypt key to server. Plugins do not perform any real encryption (XOR with single byte hardly can +be treated as encryption though makes database useless without crypt plugin), key is sent between +components in plain form - they just demonstrate what calls in plugins should be done and what +methods should be implemented in order for plugin to start to work. + +Depending upon settings in configuration file plugins may use different ways to manage encryption +key. DbCrypt's configuration file may contain following parameters: +Auto - boolean value, when FALSE plugin queries KeyHolder plugin for key value (this is default), + when TRUE get key value from "Value" configuration parameter. +Value - integer value (lower byte is actually used), used in "Auto" mode as key value (default 90). + +CryptKeyHolder's configuration file may contain following parameters: +Auto - boolean value, when FALSE plugin queries client application for key value (this is default), + when TRUE get key value from configuration file by name or use default (90) for unnamed key. +Key{Name} - integer value, a key with name "Name" (i.e. when one issues "ALTER DATABASE ENCRYPT ... + KEY Doggy" configuration parameter KeyDoggy should be present). +OnlyOwnKey - boolean value, enables/disables use of a key from another key holder in SuperServer. + Default value is TRUE (i.e. only key, owned by this KeyHolder, can be used by related + attachment). + +Crypt application has a few parameters making it possible to demonstrate different operations. +-e - Encrypt database (use gstat to monitor crypt progress). +-d - Decrypt database. +-l - Locally execute SELECT statement returning name of currently attached user. +-r - Execute same statement using remote datasource 'localhost:employee'. To make it work + user "test" with password "test" should be created in employee database. If employee was + encrypted in advance this demonstrates passing database crypt key through the chain of + key holders. + +cryptDb.pas is a minimum (XOR using fixed key hardcoded in plugin body) sample of database crypt +plugin written on Pascal. Was tested with both FreePascal and Delphi. diff --git a/src/jrd/extds/IscDS.cpp b/src/jrd/extds/IscDS.cpp index b98bc170ac..b1b9e73d11 100644 --- a/src/jrd/extds/IscDS.cpp +++ b/src/jrd/extds/IscDS.cpp @@ -126,16 +126,24 @@ void IscConnection::attach(thread_db* tdbb, const PathName& dbName, const MetaNa EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); ICryptKeyCallback* cb = tdbb->getAttachment()->att_crypt_callback; - m_iscProvider.fb_database_crypt_callback(&status, cb); - if (status->getState() & IStatus::STATE_ERRORS) { - raise(&status, tdbb, "crypt_callback"); - } + try + { + m_iscProvider.fb_database_crypt_callback(&status, cb); + if (status->getState() & IStatus::STATE_ERRORS) { + raise(&status, tdbb, "crypt_callback"); + } - m_iscProvider.isc_attach_database(&status, m_dbName.length(), m_dbName.c_str(), - &m_handle, newDpb.getBufferLength(), - reinterpret_cast(newDpb.getBuffer())); - if (status->getState() & IStatus::STATE_ERRORS) { - raise(&status, tdbb, "attach"); + m_iscProvider.isc_attach_database(&status, m_dbName.length(), m_dbName.c_str(), + &m_handle, newDpb.getBufferLength(), + reinterpret_cast(newDpb.getBuffer())); + if (status->getState() & IStatus::STATE_ERRORS) { + raise(&status, tdbb, "attach"); + } + } + catch(const Exception&) + { + m_iscProvider.fb_database_crypt_callback(&status, NULL); + throw; } m_iscProvider.fb_database_crypt_callback(&status, NULL); From 50c2148b194f52f0d77e7c4dea012a92ecb5f8dc Mon Sep 17 00:00:00 2001 From: Dimitry Sibiryakov Date: Thu, 2 Feb 2017 15:17:15 +0100 Subject: [PATCH 111/134] Fix for CORE-5469: Handles allocated with isc_dsql_alloc_statement2() are not cleaned on disconnect (#78) * Fix for CORE-5469: Handles allocated with isc_dsql_alloc_statement2() are not cleaned on disconnect --- src/yvalve/YObjects.h | 11 +- src/yvalve/why.cpp | 336 ++++++++++++++++++++++-------------------- 2 files changed, 187 insertions(+), 160 deletions(-) diff --git a/src/yvalve/YObjects.h b/src/yvalve/YObjects.h index a08f9fcce8..cfac854db3 100644 --- a/src/yvalve/YObjects.h +++ b/src/yvalve/YObjects.h @@ -49,6 +49,7 @@ class YRequest; class YResultSet; class YService; class YStatement; +class IscStatement; class YTransaction; class YObject @@ -98,10 +99,13 @@ public: void destroy(unsigned dstrFlags) { Firebird::MutexLockGuard guard(mtx, FB_FUNCTION); - FB_SIZE_T i; - while ((i = array.getCount()) > 0) - array[i - 1]->destroy(dstrFlags); + // Call destroy() only once even if handle is not removed from array + // by this call for any reason + for (int i = array.getCount() - 1; i >= 0; i--) + array[i]->destroy(dstrFlags); + + clear(); } void assign(HandleArray& from) @@ -473,6 +477,7 @@ public: HandleArray childEvents; HandleArray childRequests; HandleArray childStatements; + HandleArray childIscStatements; HandleArray childTransactions; Firebird::Array cleanupHandlers; Firebird::StatusHolder savedStatus; // Do not use raise() method of this class in yValve. diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index 4b27496e75..61c1c6dd44 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -634,55 +634,6 @@ int SQLDAMetadata::detach() } -class IscStatement : public RefCounted, public GlobalStorage, public YObject -{ -public: - static const ISC_STATUS ERROR_CODE = isc_bad_stmt_handle; - - explicit IscStatement(YAttachment* aAttachment) - : cursorName(getPool()), - attachment(aAttachment), - statement(NULL), - userHandle(NULL), - pseudoOpened(false), - delayedFormat(false) - { } - - FB_API_HANDLE& getHandle(); - void openCursor(CheckStatusWrapper* status, FB_API_HANDLE* traHandle, - IMessageMetadata* inMetadata, UCHAR* buffer, IMessageMetadata* outMetadata); - void closeCursor(CheckStatusWrapper* status, bool raise); - void closeStatement(CheckStatusWrapper* status); - - void execute(CheckStatusWrapper* status, FB_API_HANDLE* traHandle, - IMessageMetadata* inMetadata, UCHAR* inBuffer, IMessageMetadata* outMetadata, UCHAR* outBuffer); - FB_BOOLEAN fetch(CheckStatusWrapper* status, IMessageMetadata* outMetadata, UCHAR* outBuffer); - - void checkPrepared(ISC_STATUS code = isc_unprepared_stmt) const - { - if (!statement) - Arg::Gds(code).raise(); - } - - void checkCursorOpened() const - { - if (!statement || !statement->cursor) - Arg::Gds(isc_dsql_cursor_not_open).raise(); - } - - void checkCursorClosed() const - { - if (statement && statement->cursor) - Arg::Gds(isc_dsql_cursor_open_err).raise(); - } - - string cursorName; - YAttachment* attachment; - YStatement* statement; - FB_API_HANDLE* userHandle; - bool pseudoOpened, delayedFormat; -}; - GlobalPtr handleMappingLock; GlobalPtr > > > services; GlobalPtr > > > attachments; @@ -766,13 +717,6 @@ RefPtr translateHandle(GlobalPtr return RefPtr(*obj); } -FB_API_HANDLE& IscStatement::getHandle() -{ - if (!handle) - makeHandle(&statements, this, handle); - return handle; -} - //------------------------------------- const int SHUTDOWN_TIMEOUT = 5000; // 5 sec @@ -1241,6 +1185,58 @@ namespace Why RefPtr nextRef; }; + class IscStatement : public RefCounted, public GlobalStorage, public YObject + { + public: + static const ISC_STATUS ERROR_CODE = isc_bad_stmt_handle; + + explicit IscStatement(YAttachment* aAttachment) + : cursorName(getPool()), + attachment(aAttachment), + statement(NULL), + userHandle(NULL), + pseudoOpened(false), + delayedFormat(false) + { } + + ~IscStatement() override; + + FB_API_HANDLE& getHandle(); + void destroy(unsigned); + void openCursor(CheckStatusWrapper* status, FB_API_HANDLE* traHandle, + IMessageMetadata* inMetadata, UCHAR* buffer, IMessageMetadata* outMetadata); + void closeCursor(CheckStatusWrapper* status, bool raise); + void closeStatement(CheckStatusWrapper* status); + + void execute(CheckStatusWrapper* status, FB_API_HANDLE* traHandle, + IMessageMetadata* inMetadata, UCHAR* inBuffer, IMessageMetadata* outMetadata, UCHAR* outBuffer); + FB_BOOLEAN fetch(CheckStatusWrapper* status, IMessageMetadata* outMetadata, UCHAR* outBuffer); + + void checkPrepared(ISC_STATUS code = isc_unprepared_stmt) const + { + if (!statement) + Arg::Gds(code).raise(); + } + + void checkCursorOpened() const + { + if (!statement || !statement->cursor) + Arg::Gds(isc_dsql_cursor_not_open).raise(); + } + + void checkCursorClosed() const + { + if (statement && statement->cursor) + Arg::Gds(isc_dsql_cursor_open_err).raise(); + } + + string cursorName; + YAttachment* attachment; + YStatement* statement; + FB_API_HANDLE* userHandle; + bool pseudoOpened, delayedFormat; + }; + template <> YEntry::YEntry(CheckStatusWrapper* aStatus, YAttachment* aAttachment, int checkAttachment) : ref(aAttachment), nextRef(NULL) @@ -1311,103 +1307,6 @@ namespace Why } // namespace Why -namespace { - void IscStatement::openCursor(CheckStatusWrapper* status, FB_API_HANDLE* traHandle, - IMessageMetadata* inMetadata, UCHAR* buffer, IMessageMetadata* outMetadata) - { - checkCursorClosed(); - - // Transaction is not optional for statement returning result set - RefPtr transaction = translateHandle(transactions, traHandle);; - - statement->openCursor(status, transaction, inMetadata, buffer, outMetadata, 0); - - if (status->getState() & Firebird::IStatus::STATE_ERRORS) - return; - - fb_assert(statement->cursor); - - delayedFormat = (outMetadata == DELAYED_OUT_FORMAT); - } - - void IscStatement::closeCursor(CheckStatusWrapper* status, bool raise) - { - if (statement && statement->cursor) - { - fb_assert(!pseudoOpened); - - statement->cursor->close(status); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) - status_exception::raise(status); - - statement->cursor = NULL; - } - else if (pseudoOpened) - pseudoOpened = false; - else if (raise) - Arg::Gds(isc_dsql_cursor_close_err).raise(); - } - - void IscStatement::closeStatement(CheckStatusWrapper* status) - { - if (statement) - { - statement->free(status); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) - status_exception::raise(status); - - statement = NULL; - } - } - - void IscStatement::execute(CheckStatusWrapper* status, FB_API_HANDLE* traHandle, - IMessageMetadata* inMetadata, UCHAR* inBuffer, IMessageMetadata* outMetadata, - UCHAR* outBuffer) - { - checkCursorClosed(); - - RefPtr transaction; - if (traHandle && *traHandle) - transaction = translateHandle(transactions, traHandle); - - ITransaction* newTrans = statement->execute(status, transaction, - inMetadata, inBuffer, outMetadata, outBuffer); - - if (!(status->getState() & Firebird::IStatus::STATE_ERRORS)) - { - if (transaction && !newTrans) - { - transaction->destroy(0); - *traHandle = 0; - } - else if (!transaction && newTrans) - { - // in this case we know for sure that newTrans points to YTransaction - if (traHandle) - *traHandle = static_cast(newTrans)->getHandle(); - } - } - } - - FB_BOOLEAN IscStatement::fetch(CheckStatusWrapper* status, IMessageMetadata* outMetadata, - UCHAR* outBuffer) - { - checkCursorOpened(); - - if (delayedFormat) - { - statement->cursor->setDelayedOutputFormat(status, outMetadata); - - if (status->getState() & Firebird::IStatus::STATE_ERRORS) - return FB_FALSE; - - delayedFormat = false; - } - - return statement->cursor->fetchNext(status, outBuffer) == IStatus::RESULT_OK; - } -} - struct TEB { FB_API_HANDLE* teb_database; @@ -2163,6 +2062,7 @@ ISC_STATUS API_ROUTINE isc_dsql_allocate_statement(ISC_STATUS* userStatus, FB_AP statement = FB_NEW IscStatement(attachment); statement->addRef(); + attachment->childIscStatements.add(statement); *stmtHandle = statement->getHandle(); } catch (const Exception& e) @@ -2586,8 +2486,10 @@ ISC_STATUS API_ROUTINE isc_dsql_free_statement(ISC_STATUS* userStatus, FB_API_HA // Release everything statement->closeCursor(&statusWrapper, false); statement->closeStatement(&statusWrapper); - statement->release(); - removeHandle(&statements, *stmtHandle); + // statement->userHandle is not erased here because this routine can be called + // against a copy of original variable. + // This call must release statement and clean handles + statement->destroy(0); *stmtHandle = 0; } else if (option & DSQL_unprepare) @@ -4201,8 +4103,6 @@ void YStatement::destroy(unsigned dstrFlags) attachment->childStatements.remove(this); attachment = NULL; - removeHandle(&statements, handle); - destroy2(dstrFlags); } @@ -4443,6 +4343,126 @@ void YStatement::free(CheckStatusWrapper* status) } } +//------------------------------------- + +IscStatement::~IscStatement() +{ + if (userHandle) + { + *userHandle = 0; + userHandle = nullptr; + } + removeHandle(&statements, handle); +} + +void IscStatement::destroy(unsigned) +{ + attachment->childIscStatements.remove(this); + attachment = NULL; + release(); +} + +FB_API_HANDLE& IscStatement::getHandle() +{ + if (!handle) + makeHandle(&statements, this, handle); + return handle; +} + +void IscStatement::openCursor(CheckStatusWrapper* status, FB_API_HANDLE* traHandle, + IMessageMetadata* inMetadata, UCHAR* buffer, IMessageMetadata* outMetadata) +{ + checkCursorClosed(); + + // Transaction is not optional for statement returning result set + RefPtr transaction = translateHandle(transactions, traHandle);; + + statement->openCursor(status, transaction, inMetadata, buffer, outMetadata, 0); + + if (status->getState() & Firebird::IStatus::STATE_ERRORS) + return; + + fb_assert(statement->cursor); + + delayedFormat = (outMetadata == DELAYED_OUT_FORMAT); +} + +void IscStatement::closeCursor(CheckStatusWrapper* status, bool raise) +{ + if (statement && statement->cursor) + { + fb_assert(!pseudoOpened); + + statement->cursor->close(status); + if (status->getState() & Firebird::IStatus::STATE_ERRORS) + status_exception::raise(status); + + statement->cursor = NULL; + } + else if (pseudoOpened) + pseudoOpened = false; + else if (raise) + Arg::Gds(isc_dsql_cursor_close_err).raise(); +} + +void IscStatement::closeStatement(CheckStatusWrapper* status) +{ + if (statement) + { + statement->free(status); + if (status->getState() & Firebird::IStatus::STATE_ERRORS) + status_exception::raise(status); + + statement = NULL; + } +} + +void IscStatement::execute(CheckStatusWrapper* status, FB_API_HANDLE* traHandle, + IMessageMetadata* inMetadata, UCHAR* inBuffer, IMessageMetadata* outMetadata, + UCHAR* outBuffer) +{ + checkCursorClosed(); + + RefPtr transaction; + if (traHandle && *traHandle) + transaction = translateHandle(transactions, traHandle); + + ITransaction* newTrans = statement->execute(status, transaction, + inMetadata, inBuffer, outMetadata, outBuffer); + + if (!(status->getState() & Firebird::IStatus::STATE_ERRORS)) + { + if (transaction && !newTrans) + { + transaction->destroy(0); + *traHandle = 0; + } + else if (!transaction && newTrans) + { + // in this case we know for sure that newTrans points to YTransaction + if (traHandle) + *traHandle = static_cast(newTrans)->getHandle(); + } + } +} + +FB_BOOLEAN IscStatement::fetch(CheckStatusWrapper* status, IMessageMetadata* outMetadata, + UCHAR* outBuffer) +{ + checkCursorOpened(); + + if (delayedFormat) + { + statement->cursor->setDelayedOutputFormat(status, outMetadata); + + if (status->getState() & Firebird::IStatus::STATE_ERRORS) + return FB_FALSE; + + delayedFormat = false; + } + + return statement->cursor->fetchNext(status, outBuffer) == IStatus::RESULT_OK; +} //------------------------------------- @@ -4955,6 +4975,7 @@ YAttachment::YAttachment(IProvider* aProvider, IAttachment* aNext, const PathNam childEvents(getPool()), childRequests(getPool()), childStatements(getPool()), + childIscStatements(getPool()), childTransactions(getPool()), cleanupHandlers(getPool()) { @@ -4987,6 +5008,7 @@ void YAttachment::destroy(unsigned dstrFlags) childRequests.destroy(dstrFlags & ~DF_RELEASE); childStatements.destroy(dstrFlags & ~DF_RELEASE); + childIscStatements.destroy(dstrFlags & ~DF_RELEASE); childBlobs.destroy(dstrFlags & ~DF_RELEASE); childEvents.destroy(dstrFlags & ~DF_RELEASE); childTransactions.destroy(dstrFlags & ~DF_RELEASE); From 4d6995a87f0750de3c2dfd66f788c6ab480b9910 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Fri, 3 Feb 2017 00:02:30 +0000 Subject: [PATCH 112/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 55ac093546..50504f2481 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:519 + FORMAL BUILD NUMBER:522 */ -#define PRODUCT_VER_STRING "4.0.0.519" -#define FILE_VER_STRING "WI-T4.0.0.519" -#define LICENSE_VER_STRING "WI-T4.0.0.519" -#define FILE_VER_NUMBER 4, 0, 0, 519 +#define PRODUCT_VER_STRING "4.0.0.522" +#define FILE_VER_STRING "WI-T4.0.0.522" +#define LICENSE_VER_STRING "WI-T4.0.0.522" +#define FILE_VER_NUMBER 4, 0, 0, 522 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "519" +#define FB_BUILD_NO "522" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 42ab388cc9..61b29a605a 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=519 +BuildNum=522 NowAt=`pwd` cd `dirname $0` From 415fdc427318d71abad6d71e477c3cbbbed818fa Mon Sep 17 00:00:00 2001 From: hvlad Date: Sat, 4 Feb 2017 00:50:59 +0200 Subject: [PATCH 113/134] Fixed bug CORE-5476 : Trace shows info only after 2nd (repeated) .sql run (FB must be restarted before this) --- src/jrd/jrd.cpp | 2 ++ src/jrd/trace/TraceManager.cpp | 9 ++++++--- src/jrd/trace/TraceManager.h | 10 ++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 3f1918b536..bb1b8b63a2 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1847,6 +1847,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch CCH_release_exclusive(tdbb); + attachment->att_trace_manager->activate(); if (attachment->att_trace_manager->needs(ITraceFactory::TRACE_EVENT_ATTACH)) { TraceConnectionImpl conn(attachment); @@ -2779,6 +2780,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch guardDbInit.leave(); // Report that we created attachment to Trace API + attachment->att_trace_manager->activate(); if (attachment->att_trace_manager->needs(ITraceFactory::TRACE_EVENT_ATTACH)) { TraceConnectionImpl conn(attachment); diff --git a/src/jrd/trace/TraceManager.cpp b/src/jrd/trace/TraceManager.cpp index 5de23e9740..00f7b915c7 100644 --- a/src/jrd/trace/TraceManager.cpp +++ b/src/jrd/trace/TraceManager.cpp @@ -88,7 +88,8 @@ TraceManager::TraceManager(Attachment* in_att) : attachment(in_att), service(NULL), filename(NULL), - trace_sessions(*in_att->att_pool) + trace_sessions(*in_att->att_pool), + active(false) { init(); } @@ -97,7 +98,8 @@ TraceManager::TraceManager(Service* in_svc) : attachment(NULL), service(in_svc), filename(NULL), - trace_sessions(in_svc->getPool()) + trace_sessions(in_svc->getPool()), + active(true) { init(); } @@ -106,7 +108,8 @@ TraceManager::TraceManager(const char* in_filename) : attachment(NULL), service(NULL), filename(in_filename), - trace_sessions(*getDefaultMemoryPool()) + trace_sessions(*getDefaultMemoryPool()), + active(true) { init(); } diff --git a/src/jrd/trace/TraceManager.h b/src/jrd/trace/TraceManager.h index b46d44bd15..3d8ad72c12 100644 --- a/src/jrd/trace/TraceManager.h +++ b/src/jrd/trace/TraceManager.h @@ -121,11 +121,20 @@ public: inline bool needs(unsigned e) { + if (!active) + return 0; + if (changeNumber != getStorage()->getChangeNumber()) update_sessions(); return trace_needs & (FB_CONST64(1) << e); } + // should be called after attachment user is authenticated + void activate() + { + active = true; + } + /* DSQL-friendly routines to call Trace API hooks. Needed because DSQL cannot include JRD for the current engine */ static bool need_dsql_prepare(Attachment* att); @@ -229,6 +238,7 @@ private: static Firebird::GlobalPtr storageInstance; ULONG changeNumber; + bool active; }; } From e3b24b1734410ce5287f24bfbbd8ac6d26b32cb4 Mon Sep 17 00:00:00 2001 From: hvlad Date: Sat, 4 Feb 2017 01:20:12 +0200 Subject: [PATCH 114/134] Fixed bug CORE-5477 : Trace duplicates asci_char(13) in its output (Windows only) --- src/utilities/fbtracemgr/traceMgrMain.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/utilities/fbtracemgr/traceMgrMain.cpp b/src/utilities/fbtracemgr/traceMgrMain.cpp index 5071a3065b..85add12123 100644 --- a/src/utilities/fbtracemgr/traceMgrMain.cpp +++ b/src/utilities/fbtracemgr/traceMgrMain.cpp @@ -313,6 +313,11 @@ int CLIB_ROUTINE main(int argc, char* argv[]) setlocale(LC_CTYPE, ""); #endif +#ifdef WIN_NT + int binout = fileno(stdout); + _setmode(binout, _O_BINARY); +#endif + atexit(&atexit_fb_shutdown); AutoPtr uSvc(UtilSvc::createStandalone(argc, argv)); From 7d345af44db1749ee61e99507b41cc304e6e9bde Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Sat, 4 Feb 2017 00:02:35 +0000 Subject: [PATCH 115/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 50504f2481..cc692f572d 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:522 + FORMAL BUILD NUMBER:524 */ -#define PRODUCT_VER_STRING "4.0.0.522" -#define FILE_VER_STRING "WI-T4.0.0.522" -#define LICENSE_VER_STRING "WI-T4.0.0.522" -#define FILE_VER_NUMBER 4, 0, 0, 522 +#define PRODUCT_VER_STRING "4.0.0.524" +#define FILE_VER_STRING "WI-T4.0.0.524" +#define LICENSE_VER_STRING "WI-T4.0.0.524" +#define FILE_VER_NUMBER 4, 0, 0, 524 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "522" +#define FB_BUILD_NO "524" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 61b29a605a..2b6c6d5b51 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=522 +BuildNum=524 NowAt=`pwd` cd `dirname $0` From 800baa6f4411f9e8755dcd6abfbb08c0a55aeeb8 Mon Sep 17 00:00:00 2001 From: hvlad Date: Sun, 5 Feb 2017 11:40:49 +0200 Subject: [PATCH 116/134] Improvements CORE-5475 : Provide ability to filter out info and warnings from trace log, and CORE-4486 : Trace: provide filter to INCLUDE / EXCLUDE errors by their mnemonical names Also, fix text alignment issue in detailed per-table perf stats --- src/utilities/ntrace/TracePluginImpl.cpp | 174 ++++++++++++++++++++--- src/utilities/ntrace/TracePluginImpl.h | 7 + src/utilities/ntrace/fbtrace.conf | 36 +++++ src/utilities/ntrace/paramtable.h | 4 + 4 files changed, 204 insertions(+), 17 deletions(-) diff --git a/src/utilities/ntrace/TracePluginImpl.cpp b/src/utilities/ntrace/TracePluginImpl.cpp index 89269cf432..f946818124 100644 --- a/src/utilities/ntrace/TracePluginImpl.cpp +++ b/src/utilities/ntrace/TracePluginImpl.cpp @@ -33,6 +33,7 @@ #include "PluginLogWriter.h" #include "os/platform.h" #include "consts_pub.h" +#include "codetext.h" #include "../../common/isc_f_proto.h" #include "../../jrd/RuntimeStatistics.h" #include "../../common/dsc.h" @@ -97,7 +98,9 @@ TracePluginImpl::TracePluginImpl(IPluginBase* plugin, transactions(getDefaultMemoryPool()), statements(getDefaultMemoryPool()), services(getDefaultMemoryPool()), - unicodeCollation(*getDefaultMemoryPool()) + unicodeCollation(*getDefaultMemoryPool()), + include_codes(*getDefaultMemoryPool()), + exclude_codes(*getDefaultMemoryPool()) { const char* ses_name = initInfo->getTraceSessionName(); session_name = ses_name && *ses_name ? ses_name : " "; @@ -163,6 +166,13 @@ TracePluginImpl::TracePluginImpl(IPluginBase* plugin, } } + // parse filters for gds error codes + if (!config.include_gds_codes.isEmpty()) + str2Array(config.include_gds_codes, include_codes); + + if (!config.exclude_gds_codes.isEmpty()) + str2Array(config.exclude_gds_codes, exclude_codes); + operational = true; log_init(); } @@ -496,18 +506,30 @@ void TracePluginImpl::appendTableCounts(const PerformanceInfo *info) if (!config.print_perf || info->pin_count == 0) return; - record.append(NEWLINE - "Table Natural Index Update Insert Delete Backout Purge Expunge" NEWLINE - "***************************************************************************************************************" NEWLINE ); + const TraceCounts* trc = info->pin_tables; + const TraceCounts* trc_end = trc + info->pin_count; - const TraceCounts* trc; - const TraceCounts* trc_end; + FB_SIZE_T max_len = 0; + for (; trc < trc_end; trc++) + { + FB_SIZE_T len = fb_strlen(trc->trc_relation_name); + if (max_len < len) + max_len = len; + }; + if (max_len < 32) + max_len = 32; + + record.append(NEWLINE"Table"); + record.append(max_len - 5, ' '); + record.append(" Natural Index Update Insert Delete Backout Purge Expunge" NEWLINE); + record.append(max_len + 80, '*'); + record.append(NEWLINE); string temp; - for (trc = info->pin_tables, trc_end = trc + info->pin_count; trc < trc_end; trc++) + for (trc = info->pin_tables; trc < trc_end; trc++) { record.append(trc->trc_relation_name); - record.append(MAX_SQL_IDENTIFIER_LEN - fb_strlen(trc->trc_relation_name), ' '); + record.append(max_len - fb_strlen(trc->trc_relation_name), ' '); for (int j = 0; j < DBB_max_rel_count; j++) { if (trc->trc_counters[j] == 0) @@ -548,6 +570,101 @@ void TracePluginImpl::formatStringArgument(string& result, const UCHAR* str, siz } +bool TracePluginImpl::filterStatus(const ISC_STATUS* status, GdsCodesArray& arr) +{ + FB_SIZE_T pos; + while (*status != isc_arg_end) + { + const ISC_STATUS s = *status; + switch (s) + { + case isc_arg_gds: + case isc_arg_warning: + if (arr.find(status[1], pos)) + return true; + status += 2; + break; + + case isc_arg_cstring: + status += 3; + break; + + default: + status += 2; + break; + } + } + + return false; +} + + +class GdsName2CodeMap +{ +public: + GdsName2CodeMap(MemoryPool& pool) : + m_map(pool) + { + for (int i = 0; codes[i].code_string; i++) + m_map.put(codes[i].code_string, codes[i].code_number); + } + + bool find(const char* name, ISC_STATUS& code) const + { + return m_map.get(name, code); + } + +private: + class NocaseCmp + { + public: + static bool greaterThan(const char* i1, const char* i2) + { + return fb_utils::stricmp(i1, i2) > 0; + } + }; + + GenericMap >, NocaseCmp > m_map; +}; + +static InitInstance gdsNamesMap; + +void TracePluginImpl::str2Array(const Firebird::string& str, GdsCodesArray& arr) +{ + // input: string with comma-delimited list of gds codes values and\or gds codes names + // output: sorted array of gds codes values + + const char *sep = " ,"; + + FB_SIZE_T p1 = 0, p2 = 0; + while (p2 < str.length()) + { + p2 = str.find_first_of(sep, p1); + if (p2 == string::npos) + p2 = str.length(); + + string s = str.substr(p1, p2 - p1); + + ISC_STATUS code = atol(s.c_str()); + + if (!code && !gdsNamesMap().find(s.c_str(), code)) + fatal_exception::raiseFmt( + "Error parsing error codes filter: \n" + "\t%s\n" + "\tbad item is: %s, at position: %d", + str.c_str(), s.c_str(), p1 + 1); + + // avoid duplicates + + FB_SIZE_T ins_pos; + if (!arr.find(code, ins_pos)) + arr.insert(ins_pos, code); + + p1 = str.find_first_not_of(sep, p2); + } +} + + void TracePluginImpl::appendParams(ITraceParams* params) { const FB_SIZE_T paramcount = params->getCount(); @@ -931,14 +1048,20 @@ void TracePluginImpl::appendServiceQueryParams(size_t send_item_length, void TracePluginImpl::log_init() { - record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str()); - logRecord("TRACE_INIT"); + if (config.log_initfini) + { + record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str()); + logRecord("TRACE_INIT"); + } } void TracePluginImpl::log_finalize() { - record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str()); - logRecord("TRACE_FINI"); + if (config.log_initfini) + { + record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str()); + logRecord("TRACE_FINI"); + } logWriter->release(); logWriter = NULL; @@ -2037,14 +2160,31 @@ void TracePluginImpl::log_event_trigger_execute(ITraceDatabaseConnection* connec void TracePluginImpl::log_event_error(ITraceConnection* connection, ITraceStatusVector* status, const char* function) { - if (!config.log_errors) - return; - string event_type; - if (status->hasError()) + if (config.log_errors && status->hasError()) + { + const ISC_STATUS* errs = status->getStatus()->getErrors(); + + if (!include_codes.isEmpty() && !filterStatus(errs, include_codes)) + return; + + if (!exclude_codes.isEmpty() && filterStatus(errs, exclude_codes)) + return; + event_type.printf("ERROR AT %s", function); - else if (status->hasWarning()) + } + else if (config.log_warnings && status->hasWarning()) + { + const ISC_STATUS* warns = status->getStatus()->getWarnings(); + + if (!include_codes.isEmpty() && !filterStatus(warns, include_codes)) + return; + + if (!exclude_codes.isEmpty() && filterStatus(warns, exclude_codes)) + return; + event_type.printf("WARNING AT %s", function); + } else return; diff --git a/src/utilities/ntrace/TracePluginImpl.h b/src/utilities/ntrace/TracePluginImpl.h index adb58aac78..de05ced196 100644 --- a/src/utilities/ntrace/TracePluginImpl.h +++ b/src/utilities/ntrace/TracePluginImpl.h @@ -172,12 +172,19 @@ private: Firebird::AutoPtr > > include_matcher, exclude_matcher; + // Filters for gds error codes + typedef Firebird::SortedArray GdsCodesArray; + GdsCodesArray include_codes; + GdsCodesArray exclude_codes; + void appendGlobalCounts(const PerformanceInfo* info); void appendTableCounts(const PerformanceInfo* info); void appendParams(Firebird::ITraceParams* params); void appendServiceQueryParams(size_t send_item_length, const ntrace_byte_t* send_items, size_t recv_item_length, const ntrace_byte_t* recv_items); void formatStringArgument(Firebird::string& result, const UCHAR* str, size_t len); + bool filterStatus(const ISC_STATUS* status, GdsCodesArray& arr); + void str2Array(const Firebird::string& str, GdsCodesArray& arr); // register various objects void register_connection(Firebird::ITraceDatabaseConnection* connection); diff --git a/src/utilities/ntrace/fbtrace.conf b/src/utilities/ntrace/fbtrace.conf index 8cc4e208e6..bff9a7fca7 100644 --- a/src/utilities/ntrace/fbtrace.conf +++ b/src/utilities/ntrace/fbtrace.conf @@ -95,6 +95,24 @@ database # Put errors happened #log_errors = false + # Put warnings + #log_warnings = false + + # Filters for errors and warnings GDS codes. + # Comma separated list of GDS codes values and\or names. + # For example: deadlock, req_sync, 335544321 + + # Include filter. If empty, trace all errors\warnings events. + # Else trace event if any code from list is found in status-vector. + #include_gds_codes + + # Exclude filter. If empty, trace all errors\warnings events. + # Else trace event if no code from list is found in status-vector. + #exclude_gds_codes + + # Put trace session init and finish messages + #log_initfini = true + # Sweep activity #log_sweep = false @@ -199,6 +217,24 @@ services # Put errors happened #log_errors = false + + # Put warnings + #log_warnings = false + + # Filters for errors and warnings GDS codes. + # Comma separated list of GDS codes values and\or names. + # For example: deadlock, req_sync, 335544321 + + # Include filter. If empty, trace all errors\warnings events. + # Else trace event if any code from list is found in status-vector. + #include_gds_codes + + # Exclude filter. If empty, trace all errors\warnings events. + # Else trace event if no code from list is found in status-vector. + #exclude_gds_codes + + # Put trace session init and finish messages + #log_initfini = true } diff --git a/src/utilities/ntrace/paramtable.h b/src/utilities/ntrace/paramtable.h index 0441666f9d..5c8a67e975 100644 --- a/src/utilities/ntrace/paramtable.h +++ b/src/utilities/ntrace/paramtable.h @@ -36,6 +36,10 @@ STR_PARAMETER(include_filter, "") STR_PARAMETER(exclude_filter, "") PATH_PARAMETER(log_filename, "") BOOL_PARAMETER(log_errors, false) +BOOL_PARAMETER(log_warnings, false) +STR_PARAMETER(include_gds_codes, "") +STR_PARAMETER(exclude_gds_codes, "") +BOOL_PARAMETER(log_initfini, true) BOOL_PARAMETER(enabled, false) UINT_PARAMETER(max_log_size, 0) From a98d089a28bf25ebda3f9162993445aef51bde8b Mon Sep 17 00:00:00 2001 From: hvlad Date: Sun, 5 Feb 2017 11:47:16 +0200 Subject: [PATCH 117/134] Fixed bug CORE-5470 : Trace INCLUDE_FILTER with [[:WHITESPACE:]]+ does not work when statement contains newline is issued --- src/utilities/ntrace/TracePluginImpl.cpp | 4 ++-- src/utilities/ntrace/TracePluginImpl.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/utilities/ntrace/TracePluginImpl.cpp b/src/utilities/ntrace/TracePluginImpl.cpp index f946818124..9acdc700f1 100644 --- a/src/utilities/ntrace/TracePluginImpl.cpp +++ b/src/utilities/ntrace/TracePluginImpl.cpp @@ -135,7 +135,7 @@ TracePluginImpl::TracePluginImpl(IPluginBase* plugin, string filter(config.include_filter); ISC_systemToUtf8(filter); - include_matcher = FB_NEW SimilarToMatcher >( + include_matcher = FB_NEW TraceSimilarToMatcher( *getDefaultMemoryPool(), textType, (const UCHAR*) filter.c_str(), filter.length(), '\\', true); } @@ -146,7 +146,7 @@ TracePluginImpl::TracePluginImpl(IPluginBase* plugin, string filter(config.exclude_filter); ISC_systemToUtf8(filter); - exclude_matcher = FB_NEW SimilarToMatcher >( + exclude_matcher = FB_NEW TraceSimilarToMatcher( *getDefaultMemoryPool(), textType, (const UCHAR*) filter.c_str(), filter.length(), '\\', true); } diff --git a/src/utilities/ntrace/TracePluginImpl.h b/src/utilities/ntrace/TracePluginImpl.h index de05ced196..2e1412d5f4 100644 --- a/src/utilities/ntrace/TracePluginImpl.h +++ b/src/utilities/ntrace/TracePluginImpl.h @@ -169,8 +169,9 @@ private: Firebird::RWLock renameLock; UnicodeCollationHolder unicodeCollation; - Firebird::AutoPtr > > - include_matcher, exclude_matcher; + typedef Firebird::SimilarToMatcher > > + TraceSimilarToMatcher; + Firebird::AutoPtr include_matcher, exclude_matcher; // Filters for gds error codes typedef Firebird::SortedArray GdsCodesArray; From 29942f8d86c4c61b419c24ddc5b8884b1a91a8e8 Mon Sep 17 00:00:00 2001 From: hvlad Date: Sun, 5 Feb 2017 16:40:09 +0200 Subject: [PATCH 118/134] Misc --- src/utilities/ntrace/TracePluginImpl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utilities/ntrace/TracePluginImpl.cpp b/src/utilities/ntrace/TracePluginImpl.cpp index 9acdc700f1..be673e5443 100644 --- a/src/utilities/ntrace/TracePluginImpl.cpp +++ b/src/utilities/ntrace/TracePluginImpl.cpp @@ -599,6 +599,8 @@ bool TracePluginImpl::filterStatus(const ISC_STATUS* status, GdsCodesArray& arr) } +namespace { + class GdsName2CodeMap { public: @@ -627,6 +629,8 @@ private: GenericMap >, NocaseCmp > m_map; }; +}; // namespace + static InitInstance gdsNamesMap; void TracePluginImpl::str2Array(const Firebird::string& str, GdsCodesArray& arr) From c3639462f4cef83ea3f3022412e38343242679d8 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Sun, 5 Feb 2017 21:52:46 -0200 Subject: [PATCH 119/134] Feature CORE-5449 - Support DEFAULT context value in INSERT, UPDATE, MERGE and UPDATE OR INSERT statements. --- lang_helpers/gds_codes.ftn | 2 + lang_helpers/gds_codes.pas | 2 + src/dsql/DdlNodes.epp | 2 + src/dsql/ExprNodes.cpp | 149 ++++++++++++++++++++++++++++++++++++ src/dsql/ExprNodes.h | 30 ++++++++ src/dsql/Nodes.h | 5 +- src/dsql/StmtNodes.cpp | 91 ++++++++++++++-------- src/dsql/parse.y | 66 +++++++++++++--- src/include/gen/codetext.h | 1 + src/include/gen/iberror.h | 6 +- src/include/gen/msgs.h | 1 + src/include/gen/sql_code.h | 1 + src/include/gen/sql_state.h | 1 + src/jrd/Relation.h | 9 ++- src/jrd/blp.h | 1 + src/jrd/blr.h | 2 + src/jrd/met.epp | 12 +++ src/msgs/facilities2.sql | 2 +- src/msgs/messages2.sql | 1 + src/msgs/system_errors2.sql | 1 + src/yvalve/gds.cpp | 4 +- 21 files changed, 340 insertions(+), 49 deletions(-) diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index b7419617f1..4495523603 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -1796,6 +1796,8 @@ C -- PARAMETER (GDS__dsql_wrong_param_num = 336003111) INTEGER*4 GDS__dsql_invalid_drop_ss_clause PARAMETER (GDS__dsql_invalid_drop_ss_clause = 336003112) + INTEGER*4 GDS__upd_ins_cannot_default + PARAMETER (GDS__upd_ins_cannot_default = 336003113) INTEGER*4 GDS__dyn_filter_not_found PARAMETER (GDS__dyn_filter_not_found = 336068645) INTEGER*4 GDS__dyn_func_not_found diff --git a/lang_helpers/gds_codes.pas b/lang_helpers/gds_codes.pas index f428092767..513ee3e325 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -1791,6 +1791,8 @@ const gds_dsql_wrong_param_num = 336003111; isc_dsql_invalid_drop_ss_clause = 336003112; gds_dsql_invalid_drop_ss_clause = 336003112; + isc_upd_ins_cannot_default = 336003113; + gds_upd_ins_cannot_default = 336003113; isc_dyn_filter_not_found = 336068645; gds_dyn_filter_not_found = 336068645; isc_dyn_func_not_found = 336068649; diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index be233c6bb5..643dc06b0c 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -6881,6 +6881,8 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch, // DEFAULT and null flag) and another blr_domain_full with DEFAULT and null flag. We swallow the error when // transfering the value from the second to the first variable. + // This could be better done with blr_default, but let's maintain backward compatible BLR for now. + blrWriter.appendUChar(blr_dcl_variable); blrWriter.appendUShort(index); diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 20552ed03e..4a26a93c4f 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -4118,6 +4118,155 @@ dsc* DecodeNode::execute(thread_db* tdbb, jrd_req* request) const //-------------------- +static RegisterNode regDefaultNode(blr_default); + +DefaultNode::DefaultNode(MemoryPool& pool, const Firebird::MetaName& aRelationName, + const Firebird::MetaName& aFieldName) + : DsqlNode(pool), + relationName(aRelationName), + fieldName(aFieldName), + field(NULL) +{ +} + +DmlNode* DefaultNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/) +{ + MetaName relationName, fieldName; + csb->csb_blr_reader.getMetaName(relationName); + csb->csb_blr_reader.getMetaName(fieldName); + + CompilerScratch::Dependency dependency(obj_relation); + dependency.relation = MET_lookup_relation(tdbb, relationName); + dependency.subName = FB_NEW_POOL(pool) MetaName(fieldName); + csb->csb_dependencies.push(dependency); + + jrd_fld* fld = NULL; + + while (true) + { + jrd_rel* relation = MET_lookup_relation(tdbb, relationName); + + if (relation && relation->rel_fields) + { + int fieldId = MET_lookup_field(tdbb, relation, fieldName); + + if (fieldId >= 0) + { + fld = (*relation->rel_fields)[fieldId]; + + if (fld) + { + if (fld->fld_source_rel_field.first.hasData()) + { + relationName = fld->fld_source_rel_field.first; + fieldName = fld->fld_source_rel_field.second; + continue; + } + else + { + DefaultNode* node = FB_NEW_POOL(pool) DefaultNode(pool, relationName, fieldName); + node->field = fld; + return node; + } + } + } + } + + return FB_NEW_POOL(pool) NullNode(pool); + } +} + +ValueExprNode* DefaultNode::createFromField(thread_db* tdbb, CompilerScratch* csb, + StreamType* map, jrd_fld* fld) +{ + if (fld->fld_generator_name.hasData()) + { + // Make a (next value for ) expression. + + GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool) GenIdNode( + csb->csb_pool, (csb->blrVersion == 4), fld->fld_generator_name, NULL, true, true); + + bool sysGen = false; + if (!MET_load_generator(tdbb, genNode->generator, &sysGen, &genNode->step)) + PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(fld->fld_generator_name)); + + if (sysGen) + PAR_error(csb, Arg::Gds(isc_cant_modify_sysobj) << "generator" << fld->fld_generator_name); + + return genNode; + } + else if (fld->fld_default_value) + { + StreamMap localMap; + if (!map) + map = localMap.getBuffer(STREAM_MAP_LENGTH); + + return NodeCopier(csb, map).copy(tdbb, fld->fld_default_value); + } + else + return FB_NEW_POOL(csb->csb_pool) NullNode(csb->csb_pool); +} + +string DefaultNode::internalPrint(NodePrinter& printer) const +{ + ValueExprNode::internalPrint(printer); + + NODE_PRINT(printer, relationName); + NODE_PRINT(printer, fieldName); + + return "DefaultNode"; +} + +ValueExprNode* DefaultNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) +{ + DefaultNode* node = FB_NEW_POOL(getPool()) DefaultNode(getPool(), + relationName, fieldName); + return node; +} + +void DefaultNode::setParameterName(dsql_par* parameter) const +{ + parameter->par_name = parameter->par_alias = "DEFAULT"; +} + +bool DefaultNode::setParameterType(DsqlCompilerScratch* /*dsqlScratch*/, const dsc* /*desc*/, bool /*forceVarChar*/) +{ + return false; +} + +void DefaultNode::genBlr(DsqlCompilerScratch* dsqlScratch) +{ + dsqlScratch->appendUChar(blr_default); + dsqlScratch->appendMetaString(relationName.c_str()); + dsqlScratch->appendMetaString(fieldName.c_str()); +} + +void DefaultNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* /*desc*/) +{ +} + +bool DefaultNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const +{ + if (!ExprNode::dsqlMatch(other, ignoreMapCast)) + return false; + + const DefaultNode* o = other->as(); + fb_assert(o); + + return relationName == o->relationName && fieldName == o->fieldName; +} + +ValueExprNode* DefaultNode::pass1(thread_db* tdbb, CompilerScratch* csb) +{ + ValueExprNode* node = createFromField(tdbb, csb, NULL, field); + doPass1(tdbb, csb, &node); + return node; +} + + +//-------------------- + + static RegisterNode regDerivedExprNode(blr_derived_expr); DmlNode* DerivedExprNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/) diff --git a/src/dsql/ExprNodes.h b/src/dsql/ExprNodes.h index a9d475ac96..20d9f55f28 100644 --- a/src/dsql/ExprNodes.h +++ b/src/dsql/ExprNodes.h @@ -476,6 +476,36 @@ public: }; +class DefaultNode : public DsqlNode +{ +public: + explicit DefaultNode(MemoryPool& pool, const Firebird::MetaName& aRelationName, + const Firebird::MetaName& aFieldName); + + static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp); + static ValueExprNode* createFromField(thread_db* tdbb, CompilerScratch* csb, StreamType* map, jrd_fld* fld); + + virtual Firebird::string internalPrint(NodePrinter& printer) const; + virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual void setParameterName(dsql_par* parameter) const; + virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, + const dsc* desc, bool forceVarChar); + virtual void genBlr(DsqlCompilerScratch* dsqlScratch); + virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); + + virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const; + + virtual ValueExprNode* pass1(thread_db* tdbb, CompilerScratch* csb); + +public: + const Firebird::MetaName relationName; + const Firebird::MetaName fieldName; + +private: + jrd_fld* field; +}; + + class DerivedExprNode : public TypedNode { public: diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h index bc74526fad..67c3f441b6 100644 --- a/src/dsql/Nodes.h +++ b/src/dsql/Nodes.h @@ -408,6 +408,7 @@ public: TYPE_CURRENT_USER, TYPE_DERIVED_EXPR, TYPE_DECODE, + TYPE_DEFAULT, TYPE_DERIVED_FIELD, TYPE_DOMAIN_VALIDATION, TYPE_EXTRACT, @@ -853,13 +854,13 @@ public: fb_assert(false); } - virtual DsqlNode* pass1(thread_db* /*tdbb*/, CompilerScratch* /*csb*/) + virtual ValueExprNode* pass1(thread_db* /*tdbb*/, CompilerScratch* /*csb*/) { fb_assert(false); return NULL; } - virtual DsqlNode* pass2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/) + virtual ValueExprNode* pass2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/) { fb_assert(false); return NULL; diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 35bf9f5de6..4dedad6742 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -5877,6 +5877,51 @@ void ModifyNode::genBlr(DsqlCompilerScratch* dsqlScratch) ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb) { + CompoundStmtNode* compoundNode = statement->as(); + + // Remove assignments of DEFAULT to computed fields. + if (compoundNode) + { + for (size_t i = compoundNode->statements.getCount(); i--; ) + { + const AssignmentNode* assign = compoundNode->statements[i]->as(); + fb_assert(assign); + if (!assign) + continue; + + const ExprNode* assignFrom = assign->asgnFrom; + const FieldNode* assignToField = assign->asgnTo->as(); + + if (assignToField && assignFrom->is()) + { + jrd_rel* relation = csb->csb_rpt[newStream].csb_relation; + int fieldId = assignToField->fieldId; + + while (true) + { + jrd_fld* fld; + + if (assignToField->fieldStream == newStream && + relation && + relation->rel_fields && + (fld = (*relation->rel_fields)[fieldId])) + { + if (fld->fld_computation) + compoundNode->statements.remove(i); + else if (relation->rel_view_rse && fld->fld_source_rel_field.first.hasData()) + { + relation = MET_lookup_relation(tdbb, fld->fld_source_rel_field.first); + if ((fieldId = MET_lookup_field(tdbb, relation, fld->fld_source_rel_field.second)) >= 0) + continue; + } + } + + break; + } + } + } + } + pass1Modify(tdbb, csb, this); doPass1(tdbb, csb, statement.getAddress()); @@ -6557,12 +6602,15 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, NestConst* ptr2 = values->items.begin(); for (const NestConst* end = fields.end(); ptr != end; ++ptr, ++ptr2) { - AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool()); - temp->asgnFrom = *ptr2; - temp->asgnTo = *ptr; - assignStatements->statements.add(temp); + if (*ptr2) // it's NULL for DEFAULT + { + AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool()); + temp->asgnFrom = *ptr2; + temp->asgnTo = *ptr; + assignStatements->statements.add(temp); - PASS1_set_parameter_type(dsqlScratch, *ptr2, temp->asgnTo, false); + PASS1_set_parameter_type(dsqlScratch, *ptr2, temp->asgnTo, false); + } } } @@ -6830,32 +6878,9 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb) AssignmentNode* assign = FB_NEW_POOL(*tdbb->getDefaultPool()) AssignmentNode( *tdbb->getDefaultPool()); assign->asgnTo = PAR_gen_field(tdbb, stream, fieldId); + assign->asgnFrom = DefaultNode::createFromField(tdbb, csb, map, *ptr1); stack.push(assign); - - const MetaName& generatorName = (*ptr1)->fld_generator_name; - - if (generatorName.hasData()) - { - // Make a (next value for ) expression. - - GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool) GenIdNode( - csb->csb_pool, (csb->blrVersion == 4), generatorName, NULL, true, true); - - bool sysGen = false; - if (!MET_load_generator(tdbb, genNode->generator, &sysGen, &genNode->step)) - PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(generatorName)); - - if (sysGen) - PAR_error(csb, Arg::Gds(isc_cant_modify_sysobj) << "generator" << generatorName); - - assign->asgnFrom = genNode; - } - else //if (value) - { - // Clone the field default value. - assign->asgnFrom = RemapFieldNodeCopier(csb, map, fieldId).copy(tdbb, value); - } } } @@ -8047,7 +8072,10 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) for (; fieldPtr != fieldsCopy.end(); ++fieldPtr, ++valuePtr) { AssignmentNode* assign = FB_NEW_POOL(pool) AssignmentNode(pool); - assign->asgnFrom = *valuePtr; + + if (!(assign->asgnFrom = *valuePtr)) // it's NULL for DEFAULT + assign->asgnFrom = FB_NEW_POOL(pool) DefaultNode(pool, relation_name, (*fieldPtr)->dsqlName); + assign->asgnTo = *fieldPtr; assignments->statements.add(assign); @@ -8071,6 +8099,9 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (testField == fieldName) { + if (!*valuePtr) // it's NULL for DEFAULT + ERRD_post(Arg::Gds(isc_upd_ins_cannot_default) << fieldName); + ++matchCount; const FB_SIZE_T fieldPos = fieldPtr - fieldsCopy.begin(); diff --git a/src/dsql/parse.y b/src/dsql/parse.y index e2750949b8..f477953013 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -5913,7 +5913,7 @@ fetch_first_clause // IBO hack: replace column_parens_opt by ins_column_parens_opt. %type insert insert - : insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) VALUES '(' value_list ')' + : insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) VALUES '(' value_or_default_list ')' returning_clause { StoreNode* node = $$ = $1; @@ -5945,6 +5945,18 @@ insert_start } ; +%type value_or_default_list +value_or_default_list + : value_or_default { $$ = newNode($1); } + | value_or_default_list ',' value_or_default { $$ = $1->add($3); } + ; + +%type value_or_default +value_or_default + : value + | DEFAULT { $$ = NULL; } + ; + // MERGE statement %type merge @@ -5975,7 +5987,7 @@ merge_when_clause($mergeNode) merge_when_matched_clause($mergeNode) : WHEN MATCHED { $$ = &$mergeNode->whenMatched.add(); } - merge_update_specification(NOTRIAL($3)) + merge_update_specification(NOTRIAL($3), NOTRIAL(&$mergeNode->relation->dsqlName)) ; %type merge_when_not_matched_clause() @@ -5985,11 +5997,11 @@ merge_when_not_matched_clause($mergeNode) merge_insert_specification(NOTRIAL($4)) ; -%type merge_update_specification() -merge_update_specification($mergeMatchedClause) - : THEN UPDATE SET assignments +%type merge_update_specification(, ) +merge_update_specification($mergeMatchedClause, $relationName) + : THEN UPDATE SET update_assignments(NOTRIAL($relationName)) { $mergeMatchedClause->assignments = $4; } - | AND search_condition THEN UPDATE SET assignments + | AND search_condition THEN UPDATE SET update_assignments(NOTRIAL($relationName)) { $mergeMatchedClause->condition = $2; $mergeMatchedClause->assignments = $6; @@ -6002,10 +6014,10 @@ merge_update_specification($mergeMatchedClause) %type merge_insert_specification() merge_insert_specification($mergeNotMatchedClause) : THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) - VALUES '(' value_list ')' + VALUES '(' value_or_default_list ')' { $mergeNotMatchedClause->values = $6; } | AND search_condition THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) - VALUES '(' value_list ')' + VALUES '(' value_or_default_list ')' { $mergeNotMatchedClause->values = $8; $mergeNotMatchedClause->condition = $2; @@ -6059,7 +6071,7 @@ update %type update_searched update_searched - : UPDATE table_name SET assignments where_clause plan_clause + : UPDATE table_name SET update_assignments(NOTRIAL(&$2->dsqlName)) where_clause plan_clause order_clause_opt rows_clause_optional returning_clause { ModifyNode* node = newNode(); @@ -6076,7 +6088,7 @@ update_searched %type update_positioned update_positioned - : UPDATE table_name SET assignments cursor_clause returning_clause + : UPDATE table_name SET update_assignments(NOTRIAL(&$2->dsqlName)) cursor_clause returning_clause { ModifyNode* node = newNode(); node->dsqlRelation = $2; @@ -6097,7 +6109,7 @@ update_or_insert UpdateOrInsertNode* node = $$ = newNode(); node->relation = $5; } - ins_column_parens_opt(NOTRIAL(&$6->fields)) VALUES '(' value_list ')' + ins_column_parens_opt(NOTRIAL(&$6->fields)) VALUES '(' value_or_default_list ')' update_or_insert_matching_opt(NOTRIAL(&$6->matching)) returning_clause { UpdateOrInsertNode* node = $$ = $6; @@ -6169,6 +6181,38 @@ assignment } ; +%type update_assignments() +update_assignments($relationName) + : update_assignment($relationName) + { + $$ = newNode(); + $$->statements.add($1); + } + | update_assignments ',' update_assignment($relationName) + { + $1->statements.add($3); + $$ = $1; + } + ; + +%type update_assignment() +update_assignment($relationName) + : update_column_name '=' value + { + AssignmentNode* node = newNode(); + node->asgnTo = $1; + node->asgnFrom = $3; + $$ = node; + } + | update_column_name '=' DEFAULT + { + AssignmentNode* node = newNode(); + node->asgnTo = $1; + node->asgnFrom = newNode(*$relationName, $1->dsqlName); + $$ = node; + } + ; + %type exec_function exec_function : udf diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index 40409fd74d..aa5ce529bd 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -894,6 +894,7 @@ static const struct { {"dsql_no_output_sqlda", 336003110}, {"dsql_wrong_param_num", 336003111}, {"dsql_invalid_drop_ss_clause", 336003112}, + {"upd_ins_cannot_default", 336003113}, {"dyn_filter_not_found", 336068645}, {"dyn_func_not_found", 336068649}, {"dyn_index_not_found", 336068656}, diff --git a/src/include/gen/iberror.h b/src/include/gen/iberror.h index 6ecd4913a3..771f0f0d14 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -928,6 +928,7 @@ const ISC_STATUS isc_dsql_no_input_sqlda = 336003109L; const ISC_STATUS isc_dsql_no_output_sqlda = 336003110L; const ISC_STATUS isc_dsql_wrong_param_num = 336003111L; const ISC_STATUS isc_dsql_invalid_drop_ss_clause = 336003112L; +const ISC_STATUS isc_upd_ins_cannot_default = 336003113L; const ISC_STATUS isc_dyn_filter_not_found = 336068645L; const ISC_STATUS isc_dyn_func_not_found = 336068649L; const ISC_STATUS isc_dyn_index_not_found = 336068656L; @@ -1335,7 +1336,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 = 1279; +const ISC_STATUS isc_err_max = 1280; #else /* c definitions */ @@ -2233,6 +2234,7 @@ const ISC_STATUS isc_err_max = 1279; #define isc_dsql_no_output_sqlda 336003110L #define isc_dsql_wrong_param_num 336003111L #define isc_dsql_invalid_drop_ss_clause 336003112L +#define isc_upd_ins_cannot_default 336003113L #define isc_dyn_filter_not_found 336068645L #define isc_dyn_func_not_found 336068649L #define isc_dyn_index_not_found 336068656L @@ -2640,7 +2642,7 @@ const ISC_STATUS isc_err_max = 1279; #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 1279 +#define isc_err_max 1280 #endif diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index d11466ac8c..5379938ca2 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -897,6 +897,7 @@ Data source : @4"}, /* eds_statement */ {336003110, "No SQLDA for output values provided"}, /* dsql_no_output_sqlda */ {336003111, "Wrong number of parameters (expected @1, got @2)"}, /* dsql_wrong_param_num */ {336003112, "Invalid DROP SQL SECURITY clause"}, /* dsql_invalid_drop_ss_clause */ + {336003113, "UPDATE OR INSERT value for field @1, part of the implicit or explicit MATCHING clause, cannot be DEFAULT"}, /* upd_ins_cannot_default */ {336068645, "BLOB Filter @1 not found"}, /* dyn_filter_not_found */ {336068649, "Function @1 not found"}, /* dyn_func_not_found */ {336068656, "Index not found"}, /* dyn_index_not_found */ diff --git a/src/include/gen/sql_code.h b/src/include/gen/sql_code.h index ba0b149e91..215dea0a1c 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -893,6 +893,7 @@ static const struct { {336003110, -802}, /* 38 dsql_no_output_sqlda */ {336003111, -313}, /* 39 dsql_wrong_param_num */ {336003112, -817}, /* 40 dsql_invalid_drop_ss_clause */ + {336003113, -313}, /* 41 upd_ins_cannot_default */ {336068645, -901}, /* 37 dyn_filter_not_found */ {336068649, -901}, /* 41 dyn_func_not_found */ {336068656, -901}, /* 48 dyn_index_not_found */ diff --git a/src/include/gen/sql_state.h b/src/include/gen/sql_state.h index 4436c83cdf..a5d5b02536 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -893,6 +893,7 @@ static const struct { {336003110, "07002"}, // 38 dsql_no_output_sqlda {336003111, "07001"}, // 39 dsql_wrong_param_num {336003112, "42000"}, // 40 dsql_invalid_drop_ss_clause + {336003113, "42000"}, // 41 upd_ins_cannot_default {336068645, "42000"}, // 37 dyn_filter_not_found {336068649, "42000"}, // 41 dyn_func_not_found {336068656, "42000"}, // 48 dyn_index_not_found diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index 6842e63caf..adf26a14a2 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -484,11 +484,16 @@ public: Firebird::MetaName fld_name; // Field name Firebird::MetaName fld_security_name; // security class name for field Firebird::MetaName fld_generator_name; // identity generator name + Firebird::MetaNamePair fld_source_rel_field; // Relation/field source name public: explicit jrd_fld(MemoryPool& p) - : fld_name(p), fld_security_name(p), fld_generator_name(p) - { } + : fld_name(p), + fld_security_name(p), + fld_generator_name(p), + fld_source_rel_field(p) + { + } }; } diff --git a/src/jrd/blp.h b/src/jrd/blp.h index f89bbfe7b8..b6602db173 100644 --- a/src/jrd/blp.h +++ b/src/jrd/blp.h @@ -242,5 +242,6 @@ static const struct {"record_version2", byte_line}, {"gen_id2", gen_id2}, // 210 {"window_win", window_win}, + {"default", relation_field}, {0, 0} }; diff --git a/src/jrd/blr.h b/src/jrd/blr.h index 723be2fa46..3e17cb582a 100644 --- a/src/jrd/blr.h +++ b/src/jrd/blr.h @@ -420,4 +420,6 @@ #define blr_window_win_extent_frame_value (unsigned char) 6 #define blr_window_win_exclusion (unsigned char) 7 +#define blr_default (unsigned char) 212 + #endif // JRD_BLR_H diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 743902f45e..72cdf69009 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -3972,6 +3972,18 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) } else field->fld_source = PAR_make_field(tdbb, csb, view_context, (TEXT*) p); + + { // scope + const ViewContexts& ctx = relation->rel_view_contexts; + FB_SIZE_T pos; + + if (ctx.find(view_context, pos) && + (ctx[pos]->vcx_type == VCT_TABLE || ctx[pos]->vcx_type == VCT_VIEW)) + { + field->fld_source_rel_field = MetaNamePair(ctx[pos]->vcx_relation_name, (TEXT*) p); + } + } + break; case RSR_computed_blr: diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index 45406dd5d2..419f30ec04 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -5,7 +5,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM ('2015-03-17 18:33:00', 'QLI', 1, 533) ('2015-01-07 18:01:51', 'GFIX', 3, 134) ('1996-11-07 13:39:40', 'GPRE', 4, 1) -('2016-02-23 00:00:00', 'DSQL', 7, 40) +('2017-02-05 20:37:00', 'DSQL', 7, 41) ('2016-12-27 12:30:00', 'DYN', 8, 297) ('1996-11-07 13:39:40', 'INSTALL', 10, 1) ('1996-11-07 13:38:41', 'TEST', 11, 4) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index e5a6051a1e..3007b61648 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -1701,6 +1701,7 @@ COMMIT WORK; ('dsql_wrong_param_num', NULL, NULL, NULL, 7, 39, NULL, 'Wrong number of parameters (expected @1, got @2)', NULL, NULL); -- Do not change the arguments of the previous DSQL messages. ('dsql_invalid_drop_ss_clause', 'CreateAlterTriggerNode::dsqlPass', 'DdlNodes.epp', NULL, 7, 40, NULL, 'Invalid DROP SQL SECURITY clause', NULL, NULL); +('upd_ins_cannot_default', 'pass1_update_or_insert', 'pass1.cpp', NULL, 7, 41, NULL, 'UPDATE OR INSERT value for field @1, part of the implicit or explicit MATCHING clause, cannot be DEFAULT', NULL, NULL); -- Write the new DSQL messages here. -- DYN (NULL, NULL, 'dyn.c', NULL, 8, 1, NULL, 'ODS version not supported by DYN', NULL, NULL); diff --git a/src/msgs/system_errors2.sql b/src/msgs/system_errors2.sql index 0be14bbbf8..e5050008a6 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -881,6 +881,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-802, '07', '002', 7, 38, 'dsql_no_output_sqlda', NULL, NULL) (-313, '07', '001', 7, 39, 'dsql_wrong_param_num', NULL, NULL) (-817, '42', '000', 7, 40, 'dsql_invalid_drop_ss_clause', NULL, NULL) +(-313, '42', '000', 7, 41, 'upd_ins_cannot_default', NULL, NULL) -- DYN (-901, '42', '000', 8, 37, 'dyn_filter_not_found', NULL, NULL) (-901, '42', '000', 8, 41, 'dyn_func_not_found', NULL, NULL) diff --git a/src/yvalve/gds.cpp b/src/yvalve/gds.cpp index 466196f3f4..70b646588d 100644 --- a/src/yvalve/gds.cpp +++ b/src/yvalve/gds.cpp @@ -342,7 +342,9 @@ static const UCHAR op_line, op_args, 0}, subproc_decl[] = { op_subproc_decl, 0}, subfunc_decl[] = { op_subfunc_decl, 0}, - window_win[] = { op_byte, op_window_win, 0}; + window_win[] = { op_byte, op_window_win, 0}, + relation_field[] = { op_line, op_indent, op_byte, op_literal, + op_line, op_indent, op_byte, op_literal, op_pad, op_line, 0}; #include "../jrd/blp.h" From 862111814c58d8e9daa5d5d9c941f0102124720b Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Mon, 6 Feb 2017 00:02:36 +0000 Subject: [PATCH 120/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index cc692f572d..39f9b52ba0 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:524 + FORMAL BUILD NUMBER:528 */ -#define PRODUCT_VER_STRING "4.0.0.524" -#define FILE_VER_STRING "WI-T4.0.0.524" -#define LICENSE_VER_STRING "WI-T4.0.0.524" -#define FILE_VER_NUMBER 4, 0, 0, 524 +#define PRODUCT_VER_STRING "4.0.0.528" +#define FILE_VER_STRING "WI-T4.0.0.528" +#define LICENSE_VER_STRING "WI-T4.0.0.528" +#define FILE_VER_NUMBER 4, 0, 0, 528 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "524" +#define FB_BUILD_NO "528" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 2b6c6d5b51..dd9af1b947 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=524 +BuildNum=528 NowAt=`pwd` cd `dirname $0` From 8b2a9cb44bf6055e15f016d70a6842b8ada60375 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Mon, 6 Feb 2017 19:49:11 +0300 Subject: [PATCH 121/134] Fixed CORE-5474: 'Restrict UDF' is not effective, because fbudf.so is dynamically linked against libc --- src/common/os/mod_loader.h | 8 -------- src/common/os/posix/mod_loader.cpp | 20 +++++++++++++++++--- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/common/os/mod_loader.h b/src/common/os/mod_loader.h index b27d35630d..b57af4ac9f 100644 --- a/src/common/os/mod_loader.h +++ b/src/common/os/mod_loader.h @@ -70,23 +70,15 @@ public: /// Destructor virtual ~Module() {} -#ifdef WIN_NT const Firebird::PathName fileName; -#endif protected: /// The constructor is protected so normal code can't allocate instances /// of the class, but the class itself is still able to be subclassed. -#ifdef WIN_NT Module(MemoryPool& pool, const Firebird::PathName& aFileName) : fileName(pool, aFileName) { } -#else - Module() - { - } -#endif private: /// Copy construction is not supported, hence the copy constructor is private diff --git a/src/common/os/posix/mod_loader.cpp b/src/common/os/posix/mod_loader.cpp index 7693bc7188..10a81ed426 100644 --- a/src/common/os/posix/mod_loader.cpp +++ b/src/common/os/posix/mod_loader.cpp @@ -28,6 +28,7 @@ #include "firebird.h" #include "../common/os/mod_loader.h" #include "../common/os/os_utils.h" +#include "../common/os/path_utils.h" #ifdef HAVE_UNISTD_H #include #endif @@ -40,8 +41,9 @@ class DlfcnModule : public ModuleLoader::Module { public: - DlfcnModule(void* m) - : module(m) + DlfcnModule(MemoryPool& pool, const Firebird::PathName& aFileName, void* m) + : ModuleLoader::Module(pool, aFileName), + module(m) {} ~DlfcnModule(); @@ -109,7 +111,7 @@ ModuleLoader::Module* ModuleLoader::loadModule(const Firebird::PathName& modPath system(command.c_str()); #endif - return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(module); + return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(*getDefaultMemoryPool(), modPath, module); } DlfcnModule::~DlfcnModule() @@ -127,6 +129,18 @@ void* DlfcnModule::findSymbol(const Firebird::string& symName) result = dlsym(module, newSym.c_str()); } + +#ifdef HAVE_DLADDR + if (!PathUtils::isRelative(fileName)) + { + Dl_info info; + if (!dladdr(result, &info)) + return NULL; + if (fileName != info.dli_fname) + return NULL; + } +#endif + return result; } From 21c2c1e74030867dbdc3d9e7f8c879ee9e41a208 Mon Sep 17 00:00:00 2001 From: hvlad Date: Mon, 6 Feb 2017 23:38:53 +0200 Subject: [PATCH 122/134] Fixed VC10 build --- src/utilities/fbtracemgr/traceMgrMain.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/utilities/fbtracemgr/traceMgrMain.cpp b/src/utilities/fbtracemgr/traceMgrMain.cpp index 85add12123..520db30921 100644 --- a/src/utilities/fbtracemgr/traceMgrMain.cpp +++ b/src/utilities/fbtracemgr/traceMgrMain.cpp @@ -40,6 +40,11 @@ #include #endif +#ifdef WIN_NT +#include +#include +#endif + namespace Firebird { class TraceSvcUtil : public TraceSvcIntf From 969ebaa30aa8ec738b84605585dee8711fe87ed6 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Tue, 7 Feb 2017 00:02:34 +0000 Subject: [PATCH 123/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 39f9b52ba0..56d8a99870 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:528 + FORMAL BUILD NUMBER:530 */ -#define PRODUCT_VER_STRING "4.0.0.528" -#define FILE_VER_STRING "WI-T4.0.0.528" -#define LICENSE_VER_STRING "WI-T4.0.0.528" -#define FILE_VER_NUMBER 4, 0, 0, 528 +#define PRODUCT_VER_STRING "4.0.0.530" +#define FILE_VER_STRING "WI-T4.0.0.530" +#define LICENSE_VER_STRING "WI-T4.0.0.530" +#define FILE_VER_NUMBER 4, 0, 0, 530 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "528" +#define FB_BUILD_NO "530" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index dd9af1b947..e97fdf6ccf 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=528 +BuildNum=530 NowAt=`pwd` cd `dirname $0` From 00586d586d7aa3c3552f249e6bca88dea0682b45 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Tue, 7 Feb 2017 14:45:43 +0000 Subject: [PATCH 124/134] Fixed CORE-5447 - EXECUTE STATEMENT with a statement with "Unexpected end of command" error is reported with wrong column number. --- src/dsql/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsql/Parser.cpp b/src/dsql/Parser.cpp index ceeb0a30db..c650aa5a02 100644 --- a/src/dsql/Parser.cpp +++ b/src/dsql/Parser.cpp @@ -97,7 +97,7 @@ Parser::Parser(thread_db* tdbb, MemoryPool& pool, DsqlCompilerScratch* aScratch, yylexemes = 0; lex.start = string; - lex.line_start = lex.ptr = string; + lex.line_start = lex.last_token = lex.ptr = string; lex.end = string + length; lex.lines = 1; lex.att_charset = characterSet; From ebaf1841d3ff5b0773c112ee286fabf11eb88d2b Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Wed, 8 Feb 2017 00:02:33 +0000 Subject: [PATCH 125/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 56d8a99870..95ae51e380 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:530 + FORMAL BUILD NUMBER:531 */ -#define PRODUCT_VER_STRING "4.0.0.530" -#define FILE_VER_STRING "WI-T4.0.0.530" -#define LICENSE_VER_STRING "WI-T4.0.0.530" -#define FILE_VER_NUMBER 4, 0, 0, 530 +#define PRODUCT_VER_STRING "4.0.0.531" +#define FILE_VER_STRING "WI-T4.0.0.531" +#define LICENSE_VER_STRING "WI-T4.0.0.531" +#define FILE_VER_NUMBER 4, 0, 0, 531 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "530" +#define FB_BUILD_NO "531" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index e97fdf6ccf..de9fae5b4c 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=530 +BuildNum=531 NowAt=`pwd` cd `dirname $0` From fb18e52fe816280650eaf282ba094d73042166d6 Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Wed, 8 Feb 2017 13:05:30 +0300 Subject: [PATCH 126/134] Hiding password in fbtracemgr arguments from ps (#79) --- src/jrd/trace/TraceCmdLine.cpp | 89 +++++++++++++++++----------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/src/jrd/trace/TraceCmdLine.cpp b/src/jrd/trace/TraceCmdLine.cpp index ac6b902c39..40044e8a51 100644 --- a/src/jrd/trace/TraceCmdLine.cpp +++ b/src/jrd/trace/TraceCmdLine.cpp @@ -134,7 +134,8 @@ namespace Firebird void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) { - const char* const* end = uSvc->argv.end(); + UtilSvc::ArgvType& argv = uSvc->argv; + const int argc = argv.getCount(); bool version = false, help = false; // search for "action" switch, set NULL into recognized argv @@ -143,23 +144,22 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) false, true); const Switches::in_sw_tab_t* action_sw = NULL; - const char** argv = uSvc->argv.begin(); - for (++argv; argv < end; argv++) + for (int itr = 1; itr < argc; ++itr) { - if (!uSvc->isService() && strcmp(argv[0], "-?") == 0) + if (!uSvc->isService() && strcmp(argv[itr], "-?") == 0) { help = true; - *argv = NULL; + argv[itr] = NULL; break; } - const Switches::in_sw_tab_t* sw = actSwitches.findSwitch(*argv); + const Switches::in_sw_tab_t* sw = actSwitches.findSwitch(argv[itr]); if (sw) { if (sw->in_sw == IN_SW_TRACE_VERSION) { version = true; - *argv = NULL; + argv[itr] = NULL; continue; } if (action_sw) @@ -167,7 +167,7 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) else action_sw = sw; - *argv = NULL; + argv[itr] = NULL; } } @@ -190,17 +190,16 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) const Switches optSwitches(trace_option_in_sw_table, FB_NELEM(trace_option_in_sw_table), false, true); TraceSession session(*getDefaultMemoryPool()); - argv = uSvc->argv.begin(); - for (++argv; argv < end; argv++) + for (int itr = 1; itr < argc; ++itr) { - if (!*argv) + if (!argv[itr]) continue; - const Switches::in_sw_tab_t* sw = optSwitches.findSwitch(*argv); + const Switches::in_sw_tab_t* sw = optSwitches.findSwitch(argv[itr]); if (!sw) continue; - *argv = NULL; + argv[itr] = NULL; switch (sw->in_sw) { @@ -218,9 +217,9 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) if (!session.ses_config.empty()) usage(uSvc, isc_trace_switch_once, sw->in_sw_name); - argv++; - if (argv < end && *argv) - session.ses_config = *argv; + itr++; + if (itr < argc && argv[itr]) + session.ses_config = argv[itr]; else usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name); break; @@ -239,9 +238,9 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) if (!session.ses_name.empty()) usage(uSvc, isc_trace_switch_once, sw->in_sw_name); - argv++; - if (argv < end && *argv) - session.ses_name = *argv; + itr++; + if (itr < argc && argv[itr]) + session.ses_name = argv[itr]; else usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name); break; @@ -258,12 +257,12 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) if (session.ses_id) usage(uSvc, isc_trace_switch_once, sw->in_sw_name); - argv++; - if (argv < end && *argv) + itr++; + if (itr < argc && argv[itr]) { - session.ses_id = atol(*argv); + session.ses_id = atol(argv[itr]); if (!session.ses_id) - usage(uSvc, isc_trace_param_invalid, *argv, sw->in_sw_name); + usage(uSvc, isc_trace_param_invalid, argv[itr], sw->in_sw_name); } else usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name); @@ -272,7 +271,7 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) default: fb_assert(false); } - *argv = NULL; + argv[itr] = NULL; } // search for authentication parameters @@ -280,15 +279,14 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) false, true); string svc_name, user, role, pwd; bool adminRole = false; - argv = uSvc->argv.begin(); - for (++argv; argv < end; argv++) + for (int itr = 1; itr < argc; ++itr) { - if (!*argv) + if (!argv[itr]) continue; - const Switches::in_sw_tab_t* sw = authSwitches.findSwitch(*argv); + const Switches::in_sw_tab_t* sw = authSwitches.findSwitch(argv[itr]); if (!sw) { - usage(uSvc, isc_trace_switch_unknown, *argv); + usage(uSvc, isc_trace_switch_unknown, argv[itr]); } switch (sw->in_sw) @@ -297,9 +295,9 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) if (!user.empty()) usage(uSvc, isc_trace_switch_once, sw->in_sw_name); - argv++; - if (argv < end && *argv) - user = *argv; + itr++; + if (itr < argc && argv[itr]) + user = argv[itr]; else usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name); break; @@ -308,9 +306,9 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) if (!role.empty()) usage(uSvc, isc_trace_switch_once, sw->in_sw_name); - argv++; - if (argv < end && *argv) - role = *argv; + itr++; + if (itr < argc && argv[itr]) + role = argv[itr]; else usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name); break; @@ -319,9 +317,12 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) if (!pwd.empty()) usage(uSvc, isc_trace_switch_once, sw->in_sw_name); - argv++; - if (argv < end && *argv) - pwd = *argv; + itr++; + if (itr < argc && argv[itr]) + { + pwd = argv[itr]; + uSvc->hidePasswd(argv, itr); + } else usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name); break; @@ -333,10 +334,10 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) if (!pwd.empty()) usage(uSvc, isc_trace_switch_once, sw->in_sw_name); - argv++; - if (argv < end && *argv) + itr++; + if (itr < argc && argv[itr]) { - const PathName fileName(*argv); + const PathName fileName(argv[itr]); const char *s = NULL; switch (fb_utils::fetchPassword(fileName, s)) { @@ -374,9 +375,9 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) if (!svc_name.empty()) usage(uSvc, isc_trace_switch_once, sw->in_sw_name); - argv++; - if (argv < end && *argv) - svc_name = *argv; + itr++; + if (itr < argc && argv[itr]) + svc_name = argv[itr]; else usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name); break; From 99e52c055dd72038b931d8d803ef2a60c8dc7c70 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Thu, 9 Feb 2017 00:02:34 +0000 Subject: [PATCH 127/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 95ae51e380..795fcd4ee7 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:531 + FORMAL BUILD NUMBER:532 */ -#define PRODUCT_VER_STRING "4.0.0.531" -#define FILE_VER_STRING "WI-T4.0.0.531" -#define LICENSE_VER_STRING "WI-T4.0.0.531" -#define FILE_VER_NUMBER 4, 0, 0, 531 +#define PRODUCT_VER_STRING "4.0.0.532" +#define FILE_VER_STRING "WI-T4.0.0.532" +#define LICENSE_VER_STRING "WI-T4.0.0.532" +#define FILE_VER_NUMBER 4, 0, 0, 532 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "531" +#define FB_BUILD_NO "532" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index de9fae5b4c..a13988016c 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=531 +BuildNum=532 NowAt=`pwd` cd `dirname $0` From 1a7e52e84d68a61550aa84125f2de7f270d40e2e Mon Sep 17 00:00:00 2001 From: Ilya Eremin Date: Tue, 14 Feb 2017 13:23:10 +0300 Subject: [PATCH 128/134] gbak continues to write to stdout if write function returns -1 (#69) * Fixed: gbak continues to write to stdout if write function returns -1 * More clear implementation of write error handling in gbak --- src/burp/mvol.cpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/burp/mvol.cpp b/src/burp/mvol.cpp index adacb3d529..60c710f748 100644 --- a/src/burp/mvol.cpp +++ b/src/burp/mvol.cpp @@ -585,18 +585,33 @@ UCHAR MVOL_write(const UCHAR c, int* io_cnt, UCHAR** io_ptr) const size_t nBytesToWrite = size_t(longBytesToWrite); + bool error = false; + bool disk_full = false; + cnt = 0; #ifndef WIN_NT - cnt = write(tdgbl->file_desc, ptr, nBytesToWrite); -#else + ssize_t ret = write(tdgbl->file_desc, ptr, nBytesToWrite); - DWORD ret = 0; + if (ret == -1) + { + error = true; + + if (errno == ENOSPC || errno == EIO || errno == ENXIO || errno == EFBIG) + disk_full = true; + } + else + cnt = ret; +#else if (!WriteFile(tdgbl->file_desc, ptr, (DWORD) nBytesToWrite, &cnt, NULL)) { - ret = GetLastError(); + error = true; + DWORD ret = GetLastError(); + + if (ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL) + disk_full = true; } #endif // !WIN_NT tdgbl->mvol_io_buffer = tdgbl->mvol_io_data; - if (cnt > 0) + if (!error) { tdgbl->mvol_cumul_count += cnt; file_not_empty(); @@ -610,13 +625,7 @@ UCHAR MVOL_write(const UCHAR c, int* io_cnt, UCHAR** io_ptr) } else { - if (!cnt || -#ifndef WIN_NT - errno == ENOSPC || errno == EIO || errno == ENXIO || - errno == EFBIG) -#else - ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL) -#endif // !WIN_NT + if (disk_full) { if (tdgbl->action->act_action == ACT_backup_split) { From dcad4a875630530ca7706327716d71a9e81be51a Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Wed, 15 Feb 2017 00:02:33 +0000 Subject: [PATCH 129/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 795fcd4ee7..4993e4192d 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:532 + FORMAL BUILD NUMBER:533 */ -#define PRODUCT_VER_STRING "4.0.0.532" -#define FILE_VER_STRING "WI-T4.0.0.532" -#define LICENSE_VER_STRING "WI-T4.0.0.532" -#define FILE_VER_NUMBER 4, 0, 0, 532 +#define PRODUCT_VER_STRING "4.0.0.533" +#define FILE_VER_STRING "WI-T4.0.0.533" +#define LICENSE_VER_STRING "WI-T4.0.0.533" +#define FILE_VER_NUMBER 4, 0, 0, 533 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "532" +#define FB_BUILD_NO "533" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index a13988016c..c84bff9ec0 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=532 +BuildNum=533 NowAt=`pwd` cd `dirname $0` From 3c504ad75739224608b9ddcc02099ca26339c491 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Wed, 15 Feb 2017 16:42:54 +0300 Subject: [PATCH 130/134] Fixed CORE-5484: Database on NFS share is unavailable when accessed using mount point path --- src/jrd/EngineInterface.h | 2 +- src/jrd/Mapping.cpp | 3 +++ src/jrd/jrd.cpp | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/jrd/EngineInterface.h b/src/jrd/EngineInterface.h index 1d4e3390bd..58f8b1b693 100644 --- a/src/jrd/EngineInterface.h +++ b/src/jrd/EngineInterface.h @@ -433,7 +433,7 @@ public: int release(); private: - JAttachment* internalAttach(Firebird::CheckStatusWrapper* status, const char* fileName, + JAttachment* internalAttach(Firebird::CheckStatusWrapper* status, const char* const fileName, unsigned int dpbLength, const unsigned char* dpb, const UserId* existingId); Firebird::ICryptKeyCallback* cryptCallback; Firebird::IPluginConfig* pluginConfig; diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index f27e0e7bec..07c54213f0 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -947,12 +947,14 @@ public: embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE); embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE); + MAP_DEBUG(fprintf(stderr, "Attach %s\n", aliasDb)); IAttachment* att = prov->attachDatabase(&st, aliasDb, embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer()); if (st->getState() & IStatus::STATE_ERRORS) { const ISC_STATUS* s = st->getErrors(); + MAP_DEBUG(isc_print_status(s)); bool missing = fb_utils::containsErrorCode(s, isc_io_error); down = fb_utils::containsErrorCode(s, isc_shutdown); if (!(missing || down)) @@ -962,6 +964,7 @@ public: } else reset(att); + MAP_DEBUG(fprintf(stderr, "Att=%p\n", att)); return down; } diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index bb1b8b63a2..f8547f9a5b 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1322,7 +1322,7 @@ JAttachment* JProvider::attachDatabase(CheckStatusWrapper* user_status, const ch return internalAttach(user_status, filename, dpb_length, dpb, NULL); } -JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const char* filename, +JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const char* const filename, unsigned int dpb_length, const unsigned char* dpb, const UserId* existingId) { /************************************** @@ -1644,7 +1644,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch jAtt->getStable()->manualUnlock(attachment->att_flags); try { - getUserInfo(userId, options, org_filename.c_str(), expanded_name.c_str(), + getUserInfo(userId, options, filename, expanded_name.c_str(), &config, false, jAtt, cryptCallback); } catch(const Exception&) @@ -2472,7 +2472,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch ERR_post(Arg::Gds(isc_unavailable)); // Check for correct credentials supplied - getUserInfo(userId, options, org_filename.c_str(), NULL, &config, true, nullptr, cryptCallback); + getUserInfo(userId, options, filename, NULL, &config, true, nullptr, cryptCallback); #ifdef WIN_NT guardDbInit.enter(); // Required to correctly expand name of just created database From f3cc290b286c752a908ef37b671b1dbc57cfc03b Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Wed, 15 Feb 2017 16:45:41 +0300 Subject: [PATCH 131/134] Fixed CORE-5458: Connections fail due to dead NFS mount points --- src/common/isc_file.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/common/isc_file.cpp b/src/common/isc_file.cpp index 6c65352414..a6bb1072fe 100644 --- a/src/common/isc_file.cpp +++ b/src/common/isc_file.cpp @@ -57,6 +57,7 @@ #include "../common/classes/Aligner.h" #include "../common/utils_proto.h" #include "../common/os/os_utils.h" +#include "../common/os/path_utils.h" #include #ifdef HAVE_SYS_IPC_H @@ -84,6 +85,9 @@ #ifdef HAVE_ICONV_H #include #endif +#ifdef LINUX +#include +#endif #include "../common/config/config.h" @@ -228,6 +232,28 @@ bool ISC_analyze_nfs(tstring& expanded_filename, tstring& node_name) return false; } +#ifdef LINUX + // In order to avoid analyzing mtab in most cases check for non-device mounts first + struct stat fileStat; + unsigned m = 1; // use something that is known to be not non-device major + if (os_utils::stat(expanded_filename.c_str(), &fileStat) == 0) { + m = major(fileStat.st_dev); + } + else { // stat error - let's try with path component + tstring path, name; + PathUtils::splitLastComponent(path, name, expanded_filename); + if (path.hasData() && os_utils::stat(path.c_str(), &fileStat) == 0) + m = major(fileStat.st_dev); + } + + if (m != 0 && m != 144 && m != 145 && m != 146) { + // device mount or stat for file/path is impossible - definitely not NFS + return false; + } + + // proceed with deeper analysis +#endif + tstring max_node, max_path; size_t len = 0; From f9bbff5813b51f90d74b05a449b5594c5fa3ae87 Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Wed, 15 Feb 2017 22:38:59 +0100 Subject: [PATCH 132/134] Fix MSVC 15.0 detection (aka VS 2017) --- src/common/os/win32/mod_loader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/os/win32/mod_loader.cpp b/src/common/os/win32/mod_loader.cpp index 909de85026..bc599c6c37 100644 --- a/src/common/os/win32/mod_loader.cpp +++ b/src/common/os/win32/mod_loader.cpp @@ -103,6 +103,8 @@ public: "msvcr120.dll", #elif _MSC_VER == 1900 "vcruntime140.dll", +#elif _MSC_VER == 1910 + "vcruntime140.dll", #else #error Specify CRT DLL name here ! #endif From 154a088b88029e93b77106796c254106c0bb5311 Mon Sep 17 00:00:00 2001 From: firebirds <> Date: Thu, 16 Feb 2017 00:02:32 +0000 Subject: [PATCH 133/134] increment build number --- src/jrd/build_no.h | 12 ++++++------ src/misc/writeBuildNum.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 4993e4192d..909d6e5697 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:533 + FORMAL BUILD NUMBER:537 */ -#define PRODUCT_VER_STRING "4.0.0.533" -#define FILE_VER_STRING "WI-T4.0.0.533" -#define LICENSE_VER_STRING "WI-T4.0.0.533" -#define FILE_VER_NUMBER 4, 0, 0, 533 +#define PRODUCT_VER_STRING "4.0.0.537" +#define FILE_VER_STRING "WI-T4.0.0.537" +#define LICENSE_VER_STRING "WI-T4.0.0.537" +#define FILE_VER_NUMBER 4, 0, 0, 537 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "533" +#define FB_BUILD_NO "537" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index c84bff9ec0..4279d1c8f5 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=533 +BuildNum=537 NowAt=`pwd` cd `dirname $0` From 929378c2ac42b0398da374868ecaa6b6e9d05773 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Thu, 16 Feb 2017 12:55:18 +0300 Subject: [PATCH 134/134] Go lesser evil way --- src/jrd/CryptoManager.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/jrd/CryptoManager.cpp b/src/jrd/CryptoManager.cpp index 7aaca51d78..466d3f9501 100644 --- a/src/jrd/CryptoManager.cpp +++ b/src/jrd/CryptoManager.cpp @@ -1351,14 +1351,18 @@ namespace Jrd { SyncLockGuard dsGuard(&mgr->dbb.dbb_sync, SYNC_EXCLUSIVE, FB_FUNCTION); for (Attachment* att = mgr->dbb.dbb_attachments; att; att = att->att_next) { + bool found = false; for (unsigned i = 0; i < knownHolders.getCount(); ++i) { if (knownHolders[i].first == att) - goto found; + { + found = true; + break; + } } - att->signalShutdown(); -found:; + if (!found) + att->signalShutdown(); } // Loop through internal attachments list closing one missing valid holders