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

Merge branch 'work/profiler-plugin' into work/profiler-plugin-merge

This commit is contained in:
Adriano dos Santos Fernandes 2022-08-10 22:26:38 -03:00
commit 581795ed78
84 changed files with 6030 additions and 478 deletions

View File

@ -507,6 +507,12 @@
#
#UserManager = Srp
# Default profiler plugin used to profile connections using the RDB$PROFILER package.
#
# Per-database configurable.
#
#DefaultProfilerPlugin = Default_Profiler
# TracePlugin is used by firebird trace facility to send trace data to the user
# or log file in audit case.
#

View File

@ -548,7 +548,7 @@ $(NBACKUP): $(NBACKUP_Objects) $(COMMON_LIB)
# plugins - some of them are required to build examples, use separate entry for them
#
.PHONY: udr legacy_user_management legacy_auth_server trace auth_debug udf_compat chacha
.PHONY: udr legacy_user_management legacy_auth_server trace auth_debug udf_compat chacha profiler
UDR_PLUGIN = $(call makePluginName,udr_engine)
LEGACY_USER_MANAGER = $(call makePluginName,Legacy_UserManager)
LEGACY_AUTH_SERVER = $(call makePluginName,Legacy_Auth)
@ -558,13 +558,14 @@ AUTH_DEBUGGER = $(call makePluginName,Auth_Debug)
UDF_BACKWARD_COMPATIBILITY_BASENAME = $(LIB_PREFIX)udf_compat.$(SHRLIB_EXT)
UDF_BACKWARD_COMPATIBILITY = $(PLUGINS)/udr/$(UDF_BACKWARD_COMPATIBILITY_BASENAME)
CHACHA = $(call makePluginName,ChaCha)
PROFILER = $(call makePluginName,Default_Profiler)
BUILD_DEBUG:=
ifeq ($(TARGET),Debug)
BUILD_DEBUG:=auth_debug
endif
plugins: udr legacy_user_management legacy_auth_server srp_user_management trace $(BUILD_DEBUG) udf_compat chacha
plugins: udr legacy_user_management legacy_auth_server srp_user_management trace $(BUILD_DEBUG) udf_compat chacha profiler
udr: $(UDR_PLUGIN) $(PLUGINS)/udr_engine.conf
@ -593,6 +594,12 @@ $(LEGACY_AUTH_SERVER): $(LEGACY_AUTH_SERVER_Objects) $(COMMON_LIB)
$(LINK_PLUGIN) $(call LIB_LINK_SONAME,$(notdir $@).0) -o $@ $^ $(LINK_PLUG_LIBS) $(FIREBIRD_LIBRARY_LINK)\
$(call LIB_LINK_DARWIN_INSTALL_NAME,plugins/libLegacy_Auth.$(SHRLIB_EXT))
profiler: $(PROFILER)
$(PROFILER): $(Profiler_Objects) $(COMMON_LIB)
$(LINK_PLUGIN) $(call LIB_LINK_SONAME,$(notdir $@).0) -o $@ $^ $(LINK_PLUG_LIBS) $(FIREBIRD_LIBRARY_LINK)\
$(call LIB_LINK_DARWIN_INSTALL_NAME,plugins/libDefault_Profiler.$(SHRLIB_EXT))
trace: $(FBTRACE)
$(FBTRACE): $(FBTRACE_UTIL_Objects) $(COMMON_LIB)

View File

@ -79,9 +79,12 @@ AllObjects += $(Remote_Common) $(Remote_Server) $(Remote_Client)
# Chacha plugin
Chacha_Objects:= $(call dirObjects,plugins/crypt/chacha)
AllObjects += $(Chacha_Objects)
# Profiler plugin
Profiler_Objects:= $(call dirObjects,plugins/profiler)
AllObjects += $(Profiler_Objects)
# Engine
Engine_Objects:= $(call dirObjects,jrd) $(call dirObjects,dsql) $(call dirObjects,jrd/extds) \
$(call dirObjects,jrd/optimizer) $(call dirObjects,jrd/recsrc) $(call dirObjects,jrd/replication) $(call dirObjects,jrd/trace) \

View File

@ -84,6 +84,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chacha", "chacha.vcxproj",
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "engine_static", "engine_static.vcxproj", "{B32D1B09-8161-451E-8D20-D30F26094EC0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "default_profiler", "default_profiler.vcxproj", "{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LIBs", "LIBs", "{DA5015E4-8349-4DAB-A1E5-18BDBDDA3022}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EXEs", "EXEs", "{3E6F3FA4-225F-4591-A466-05FDBEF56DBF}"
@ -390,6 +392,14 @@ Global
{3314D6AD-554F-4AE1-B297-6D2D6207DD7C}.Release|Win32.Build.0 = Release|Win32
{3314D6AD-554F-4AE1-B297-6D2D6207DD7C}.Release|x64.ActiveCfg = Release|x64
{3314D6AD-554F-4AE1-B297-6D2D6207DD7C}.Release|x64.Build.0 = Release|x64
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Debug|Win32.ActiveCfg = Debug|Win32
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Debug|Win32.Build.0 = Debug|Win32
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Debug|x64.ActiveCfg = Debug|x64
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Debug|x64.Build.0 = Debug|x64
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Release|Win32.ActiveCfg = Release|Win32
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Release|Win32.Build.0 = Release|Win32
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Release|x64.ActiveCfg = Release|x64
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source files">
<UniqueIdentifier>{3ce83b57-8830-4673-8c73-0b1e607fe2e7}</UniqueIdentifier>
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header files">
<UniqueIdentifier>{5a3fd64b-6882-4e1d-b7ac-83fb12f1c8e8}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl</Extensions>
</Filter>
<Filter Include="Resource files">
<UniqueIdentifier>{e5b5aa94-df00-43cf-ac73-248edd148f20}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\plugins\profiler\Profiler.cpp">
<Filter>Source files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\jrd\version.rc">
<Filter>Resource files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\defs\plugin.def" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}</ProjectGuid>
<WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='15.0'">10.0.17763.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='16.0'">10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='17.0'">10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141_xp</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16.0'">v142</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17.0'">v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141_xp</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16.0'">v142</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17.0'">v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16.0'">v142</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17.0'">v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16.0'">v142</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17.0'">v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="FirebirdCommon.props" />
<Import Project="FirebirdRelease.props" />
<Import Project="DllNoEmbedManifest.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="FirebirdCommon.props" />
<Import Project="FirebirdDebug.props" />
<Import Project="DllNoEmbedManifest.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="FirebirdCommon.props" />
<Import Project="FirebirdRelease.props" />
<Import Project="DllNoEmbedManifest.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="FirebirdCommon.props" />
<Import Project="FirebirdDebug.props" />
<Import Project="DllNoEmbedManifest.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\..\temp\$(PlatformName)\$(Configuration)\firebird\plugins\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\..\temp\$(PlatformName)\$(Configuration)\firebird\plugins\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\..\temp\$(PlatformName)\$(Configuration)\firebird\plugins\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\..\temp\$(PlatformName)\$(Configuration)\firebird\plugins\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<TargetEnvironment>Win32</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;WINDOWS_ONLY;SUPERCLIENT;WIN32;DEV_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;ws2_32.lib;mpr.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>..\..\..\temp\$(Platform)\$(Configuration)\firebird\plugins\$(ProjectName).dll</OutputFile>
<ModuleDefinitionFile>..\defs\plugin.def</ModuleDefinitionFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;WINDOWS_ONLY;SUPERCLIENT;WIN32;DEV_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;ws2_32.lib;mpr.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>..\..\..\temp\$(Platform)\$(Configuration)\firebird\plugins\$(ProjectName).dll</OutputFile>
<ModuleDefinitionFile>..\defs\plugin.def</ModuleDefinitionFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX64</TargetMachine>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<TargetEnvironment>Win32</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;WINDOWS_ONLY;SUPERCLIENT;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;ws2_32.lib;mpr.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>..\..\..\temp\$(Platform)\$(Configuration)\firebird\plugins\$(ProjectName).dll</OutputFile>
<ModuleDefinitionFile>..\defs\plugin.def</ModuleDefinitionFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;WINDOWS_ONLY;SUPERCLIENT;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;ws2_32.lib;mpr.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>..\..\..\temp\$(Platform)\$(Configuration)\firebird\plugins\$(ProjectName).dll</OutputFile>
<ModuleDefinitionFile>..\defs\plugin.def</ModuleDefinitionFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX64</TargetMachine>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\plugins\profiler\Profiler.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\src\jrd\version.rc">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\..\src\jrd</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\..\src\jrd</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\..\src\jrd</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\..\src\jrd</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\defs\plugin.def" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="common.vcxproj">
<Project>{15605f44-bffd-444f-ad4c-55dc9d704465}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="yvalve.vcxproj">
<Project>{4fe03933-98cd-4879-a135-fd9430087a6b}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -13,4 +13,4 @@
<Filter>Resource files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
</Project>

View File

@ -109,6 +109,7 @@
<ClCompile Include="..\..\..\src\jrd\pag.cpp" />
<ClCompile Include="..\..\..\src\jrd\par.cpp" />
<ClCompile Include="..\..\..\src\jrd\PreparedStatement.cpp" />
<ClCompile Include="..\..\..\src\jrd\ProfilerManager.cpp" />
<ClCompile Include="..\..\..\src\jrd\RandomGenerator.cpp" />
<ClCompile Include="..\..\..\src\jrd\RecordBuffer.cpp" />
<ClCompile Include="..\..\..\src\jrd\RecordSourceNodes.cpp" />
@ -308,6 +309,7 @@
<ClInclude Include="..\..\..\src\jrd\pag_proto.h" />
<ClInclude Include="..\..\..\src\jrd\par_proto.h" />
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h" />
<ClInclude Include="..\..\..\src\jrd\ProfilerManager.h" />
<ClInclude Include="..\..\..\src\jrd\QualifiedName.h" />
<ClInclude Include="..\..\..\src\jrd\que.h" />
<ClInclude Include="..\..\..\src\jrd\RandomGenerator.h" />

View File

@ -327,6 +327,9 @@
<ClCompile Include="..\..\..\src\jrd\PreparedStatement.cpp">
<Filter>JRD files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\jrd\ProfilerManager.cpp">
<Filter>JRD files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\jrd\RandomGenerator.cpp">
<Filter>JRD files</Filter>
</ClCompile>
@ -914,6 +917,9 @@
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\jrd\ProfilerManager.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\jrd\que.h">
<Filter>Header files</Filter>
</ClInclude>
@ -1112,4 +1118,4 @@
<Filter>DSQL</Filter>
</None>
</ItemGroup>
</Project>
</Project>

View File

@ -558,6 +558,7 @@ GRANT_REVOKE_ANY_DDL_RIGHT GRANT and REVOKE any DDL rights
CREATE_PRIVILEGED_ROLES Use SET SYSTEM PRIVILEGES in roles
MODIFY_EXT_CONN_POOL Manage properties of pool of external connections
REPLICATE_INTO_DATABASE Use replication API to load changesets into database
PROFILE_ANY_ATTACHMENT Profile other users' attachments
22) New grantee type in GRANT and REVOKE operators - SYSTEM PRIVILEGE.

View File

@ -0,0 +1,445 @@
# Profiler (FB 5.0)
The profiler allows users to measure performance cost of SQL and PSQL code.
It's implemented with a system package in the engine passing data to a profiler plugin.
This documentation treats the engine and plugin parts as a single thing, in the way the default profiler (`Default_Profiler`) is going to be used.
The `RDB$PROFILER` package allows to profile execution of PSQL code collecting statistics of how many times each line was executed along with its minimum, maximum and accumulated execution times (with nanoseconds precision), as well open and fetch statistics of implicit and explicit SQL cursors.
To collect profile data, an user must first start a profile session with `RDB$PROFILER.START_SESSION`. This function returns an profile session ID which is later stored in the profiler snapshot tables to be queried and analyzed by the user. A profiler session may be local (same attachment) or remote (another attachment).
Remote profiling just forwards commands to the remote attachment. So it's possible that a client simultaneous profile multiple attachments. It's also possible that a locally or remotely started profile session have commands issued by another attachment.
Remote issued commands needs that the target attachment be in an idle state, i.e., not executing others requests. When they are not idle the call blocks waiting for that state.
If remote attachment is from a different user, the calling user must have system privilege PROFILE_ANY_ATTACHMENT.
After a session is started, PSQL and SQL statements statistics starts to be collected in memory. Note that a profile session collects data only of statements executed in the same attachment associated with the session.
Data is aggregated and stored per requests (i.e. a statement execution). When querying snapshot tables, user may do extra aggregation per statements or use the auxiliary views that do that automatically.
A session may be paused to temporary disable statistics collecting. It may be resumed later to return statistics collection in the same session.
A new session may be started when a session is already active. In this case it has the same semantics of finishing the current session with `RDB$PROFILER.FINISH_SESSION(FALSE)` so snapshots tables are not updated in the same moment.
To analyze the collected data, the user must flush the data to the snapshot tables, which may be done finishing or pausing a session (with `FLUSH` parameter set to `TRUE`) or calling `RDB$PROFILER.FLUSH`. Data is flushed using an autonomous transaction (a transaction started and finished for the specific purpose of profiler data update).
Following is a sample profile session and queries for data analysis.
```
-- Preparation - create table and routines that will be analyzed
create table tab (
id integer not null,
val integer not null
);
set term !;
create or alter function mult(p1 integer, p2 integer) returns integer
as
begin
return p1 * p2;
end!
create or alter procedure ins
as
declare n integer = 1;
begin
while (n <= 1000)
do
begin
if (mod(n, 2) = 1) then
insert into tab values (:n, mult(:n, 2));
n = n + 1;
end
end!
set term ;!
-- Start profiling
select rdb$profiler.start_session('Profile Session 1') from rdb$database;
set term !;
execute block
as
begin
execute procedure ins;
delete from tab;
end!
set term ;!
execute procedure rdb$profiler.finish_session(true);
execute procedure ins;
select rdb$profiler.start_session('Profile Session 2') from rdb$database;
select mod(id, 5),
sum(val)
from tab
where id <= 50
group by mod(id, 5)
order by sum(val);
execute procedure rdb$profiler.finish_session(true);
-- Data analysis
set transaction read committed;
select * from plg$prof_sessions;
select * from plg$prof_psql_stats_view;
select * from plg$prof_record_source_stats_view;
select preq.*
from plg$prof_requests preq
join plg$prof_sessions pses
on pses.profile_id = preq.profile_id and
pses.description = 'Profile Session 1';
select pstat.*
from plg$prof_psql_stats pstat
join plg$prof_sessions pses
on pses.profile_id = pstat.profile_id and
pses.description = 'Profile Session 1'
order by pstat.profile_id,
pstat.request_id,
pstat.line_num,
pstat.column_num;
select pstat.*
from plg$prof_record_source_stats pstat
join plg$prof_sessions pses
on pses.profile_id = pstat.profile_id and
pses.description = 'Profile Session 2'
order by pstat.profile_id,
pstat.request_id,
pstat.cursor_id,
pstat.record_source_id;
```
## Function `START_SESSION`
`RDB$PROFILER.START_SESSION` starts a new profiler session, turns it the current session (of the given `ATTACHMENT_ID`) and return its identifier.
If `FLUSH_INTERVAL` is different than `NULL` auto-flush is setup in the same way as manually calling `RDB$PROFILER.SET_FLUSH_INTERVAL`.
If `PLUGIN_NAME` is `NULL` (the default) it uses the database configuration `DefaultProfilerPlugin`.
`PLUGIN_OPTIONS` is plugin specific options and currently should be `NULL` for `Default_Profiler` plugin.
Input parameters:
- `DESCRIPTION` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
- `FLUSH_INTERVAL` type `INTEGER` default `NULL`
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
- `PLUGIN_NAME` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
- `PLUGIN_OPTIONS` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
Return type: `BIGINT NOT NULL`.
## Procedure `PAUSE_SESSION`
`RDB$PROFILER.PAUSE_SESSION` pauses the current profiler session (of the given `ATTACHMENT_ID`) so the next executed statements statistics are not collected.
If `FLUSH` is `TRUE` the snapshot tables are updated with data up to the current moment. Otherwise data remains only in memory for later update.
Calling `RDB$PROFILER.PAUSE_SESSION(TRUE)` has the same semantics of calling `RDB$PROFILER.PAUSE_SESSION(FALSE)` followed by `RDB$PROFILER.FLUSH` (using the same `ATTACHMENT_ID`).
Input parameters:
- `FLUSH` type `BOOLEAN NOT NULL` default `FALSE`
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
## Procedure `RESUME_SESSION`
`RDB$PROFILER.RESUME_SESSION` resumes the current profiler session (of the given `ATTACHMENT_ID`) if it was paused so the next executed statements statistics are collected again.
Input parameters:
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
## Procedure `FINISH_SESSION`
`RDB$PROFILER.FINISH_SESSION` finishes the current profiler session (of the given `ATTACHMENT_ID`).
If `FLUSH` is `TRUE` the snapshot tables are updated with data of the finished session (and old finished sessions not yet present in the snapshot). Otherwise data remains only in memory for later update.
Calling `RDB$PROFILER.FINISH_SESSION(TRUE)` has the same semantics of calling `RDB$PROFILER.FINISH_SESSION(FALSE)` followed by `RDB$PROFILER.FLUSH` (using the same `ATTACHMENT_ID`).
Input parameters:
- `FLUSH` type `BOOLEAN NOT NULL` default `TRUE`
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
## Procedure `CANCEL_SESSION`
`RDB$PROFILER.CANCEL_SESSION` cancels the current profiler session (of the given `ATTACHMENT_ID`).
All session data present in the profiler plugin is discarded and will not be flushed.
Data already flushed is not deleted automatically.
Input parameters:
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
## Procedure `DISCARD`
`RDB$PROFILER.DISCARD` removes all sessions (of the given `ATTACHMENT_ID`) from memory, without flushing them.
If there is a active session, it is cancelled.
Input parameters:
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
## Procedure `FLUSH`
`RDB$PROFILER.FLUSH` updates the snapshot tables with data from the profile sessions (of the given `ATTACHMENT_ID`) in memory.
After update data is stored in tables `PLG$PROF_SESSIONS`, `PLG$PROF_STATEMENTS`, `PLG$PROF_RECORD_SOURCES`, `PLG$PROF_REQUESTS`, `PLG$PROF_PSQL_STATS` and `PLG$PROF_RECORD_SOURCE_STATS` and may be read and analyzed by the user.
Data is updated using an autonomous transaction, so if the procedure is called in a snapshot transaction, data will not be directly readable in the same transaction.
Once flush happens, finished sessions are removed from memory.
Input parameters:
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
## Procedure `SET_FLUSH_INTERVAL`
`RDB$PROFILER.SET_FLUSH_INTERVAL` turns periodic auto-flush on (when `FLUSH_INTERVAL` is greater than 0) or off (when `FLUSH_INTERVAL` is equal to 0).
`FLUSH_INTERVAL` is interpreted as number of seconds.
Input parameters:
- `FLUSH_INTERVAL` type `INTEGER NOT NULL`
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
# Snapshot tables
Snapshot tables (as well views and sequence) are automatically created in the first usage of the profiler. They are owned by the current user with read/write permissions for `PUBLIC`.
When a session is deleted the related data in others profiler snapshot tables are automatically deleted too through foregin keys with `DELETE CASCADE` option.
Below is the list of tables that stores profile data.
## Table `PLG$PROF_SESSIONS`
- `PROFILE_ID` type `BIGINT` - Profile session ID
- `ATTACHMENT_ID` type `BIGINT` - Attachment ID
- `USER_NAME` type `CHAR(63) CHARACTER SET UTF8` - User name
- `DESCRIPTION` type `VARCHAR(255) CHARACTER SET UTF8` - Description passed in `RDB$PROFILER.START_SESSION`
- `START_TIMESTAMP` type `TIMESTAMP WITH TIME ZONE` - Moment the profile session was started
- `FINISH_TIMESTAMP` type `TIMESTAMP WITH TIME ZONE` - Moment the profile session was finished (NULL when not finished)
- Primary key: `PROFILE_ID`
## Table `PLG$PROF_STATEMENTS`
- `PROFILE_ID` type `BIGINT` - Profile session ID
- `STATEMENT_ID` type `BIGINT` - Statement ID
- `PARENT_STATEMENT_ID` type `BIGINT` - Parent statement ID - related to sub routines
- `STATEMENT_TYPE` type `VARCHAR(20) CHARACTER SET UTF8` - BLOCK, FUNCTION, PROCEDURE or TRIGGER
- `PACKAGE_NAME` type `CHAR(63) CHARACTER SET UTF8` - Package of FUNCTION or PROCEDURE
- `ROUTINE_NAME` type `CHAR(63) CHARACTER SET UTF8` - Routine name of FUNCTION, PROCEDURE or TRIGGER
- `SQL_TEXT` type `BLOB subtype TEXT CHARACTER SET UTF8` - SQL text for BLOCK
- Primary key: `PROFILE_ID, STATEMENT_ID`
## Table `PLG$PROF_RECORD_SOURCES`
- `PROFILE_ID` type `BIGINT` - Profile session ID
- `STATEMENT_ID` type `BIGINT` - Statement ID
- `CURSOR_ID` type `BIGINT` - Cursor ID
- `RECORD_SOURCE_ID` type `BIGINT` - Record source ID
- `PARENT_RECORD_SOURCE_ID` type `BIGINT` - Parent record source ID
- `ACCESS_PATH` type `VARCHAR(255) CHARACTER SET UTF8` - Access path for the record source
- Primary key: `PROFILE_ID, STATEMENT_ID, CURSOR_ID, RECORD_SOURCE_ID`
## Table `PLG$PROF_REQUESTS`
- `PROFILE_ID` type `BIGINT` - Profile session ID
- `REQUEST_ID` type `BIGINT` - Request ID
- `STATEMENT_ID` type `BIGINT` - Statement ID
- `CALLER_REQUEST_ID` type `BIGINT` - Caller request ID
- `START_TIMESTAMP` type `TIMESTAMP WITH TIME ZONE` - Moment this request was first gathered profile data
- `FINISH_TIMESTAMP` type `TIMESTAMP WITH TIME ZONE` - Moment this request was finished
- `TOTAL_ELAPSED_TIME` type `BIGINT` - Accumulated elapsed time (in nanoseconds) of the request
- Primary key: `PROFILE_ID, REQUEST_ID`
## Table `PLG$PROF_PSQL_STATS`
- `PROFILE_ID` type `BIGINT` - Profile session ID
- `REQUEST_ID` type `BIGINT` - Request ID
- `LINE_NUM` type `INTEGER` - Line number of the statement
- `COLUMN_NUM` type `INTEGER` - Column number of the statement
- `STATEMENT_ID` type `BIGINT` - Statement ID
- `COUNTER` type `BIGINT` - Number of executed times of the line/column
- `MIN_ELAPSED_TIME` type `BIGINT` - Minimal elapsed time (in nanoseconds) of a line/column execution
- `MAX_ELAPSED_TIME` type `BIGINT` - Maximum elapsed time (in nanoseconds) of a line/column execution
- `TOTAL_ELAPSED_TIME` type `BIGINT` - Accumulated elapsed time (in nanoseconds) of the line/column executions
- Primary key: `PROFILE_ID, REQUEST_ID, LINE_NUM, COLUMN_NUM`
## Table `PLG$PROF_RECORD_SOURCE_STATS`
- `PROFILE_ID` type `BIGINT` - Profile session ID
- `REQUEST_ID` type `BIGINT` - Request ID
- `CURSOR_ID` type `BIGINT` - Cursor ID
- `RECORD_SOURCE_ID` type `BIGINT` - Record source ID
- `STATEMENT_ID` type `BIGINT` - Statement ID
- `OPEN_COUNTER` type `BIGINT` - Number of open times of the record source
- `OPEN_MIN_ELAPSED_TIME` type `BIGINT` - Minimal elapsed time (in nanoseconds) of a record source open
- `OPEN_MAX_ELAPSED_TIME` type `BIGINT` - Maximum elapsed time (in nanoseconds) of a record source open
- `OPEN_TOTAL_ELAPSED_TIME` type `BIGINT` - Accumulated elapsed time (in nanoseconds) of the record source openings
- `FETCH_COUNTER` type `BIGINT` - Number of fetch times of the record source
- `FETCH_MIN_ELAPSED_TIME` type `BIGINT` - Minimal elapsed time (in nanoseconds) of a record source fetch
- `FETCH_MAX_ELAPSED_TIME` type `BIGINT` - Maximum elapsed time (in nanoseconds) of a record source fetch
- `FETCH_TOTAL_ELAPSED_TIME` type `BIGINT` - Accumulated elapsed time (in nanoseconds) of the record source fetches
- Primary key: `PROFILE_ID, REQUEST_ID, CURSOR_ID, RECORD_SOURCE_ID`
# Auxiliary views
These views help profile data extraction aggregated at statement level.
They should be the preferred way to analyze the collected data. They can also be used together with the tables to get additional data not present on the views.
After hot spots are found, one can drill down in the data at the request level through the tables.
## View `PLG$PROF_STATEMENT_STATS_VIEW`
```
select req.profile_id,
req.statement_id,
sta.statement_type,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
sta_parent.statement_type parent_statement_type,
sta_parent.routine_name parent_routine_name,
(select sql_text
from plg$prof_statements
where profile_id = req.profile_id and
statement_id = coalesce(sta.parent_statement_id, req.statement_id)
) sql_text,
count(*) counter,
min(req.total_elapsed_time) min_elapsed_time,
max(req.total_elapsed_time) max_elapsed_time,
cast(sum(req.total_elapsed_time) as bigint) total_elapsed_time,
cast(sum(req.total_elapsed_time) / count(*) as bigint) avg_elapsed_time
from plg$prof_requests req
join plg$prof_statements sta
on sta.profile_id = req.profile_id and
sta.statement_id = req.statement_id
left join plg$prof_statements sta_parent
on sta_parent.profile_id = sta.profile_id and
sta_parent.statement_id = sta.parent_statement_id
group by req.profile_id,
req.statement_id,
sta.statement_type,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
sta_parent.statement_type,
sta_parent.routine_name
order by sum(req.total_elapsed_time) desc
```
## View `PLG$PROF_PSQL_STATS_VIEW`
```
select pstat.profile_id,
pstat.statement_id,
sta.statement_type,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
sta_parent.statement_type parent_statement_type,
sta_parent.routine_name parent_routine_name,
(select sql_text
from plg$prof_statements
where profile_id = pstat.profile_id and
statement_id = coalesce(sta.parent_statement_id, pstat.statement_id)
) sql_text,
pstat.line_num,
pstat.column_num,
cast(sum(pstat.counter) as bigint) counter,
min(pstat.min_elapsed_time) min_elapsed_time,
max(pstat.max_elapsed_time) max_elapsed_time,
cast(sum(pstat.total_elapsed_time) as bigint) total_elapsed_time,
cast(sum(pstat.total_elapsed_time) / nullif(sum(pstat.counter), 0) as bigint) avg_elapsed_time
from plg$prof_psql_stats pstat
join plg$prof_statements sta
on sta.profile_id = pstat.profile_id and
sta.statement_id = pstat.statement_id
left join plg$prof_statements sta_parent
on sta_parent.profile_id = sta.profile_id and
sta_parent.statement_id = sta.parent_statement_id
group by pstat.profile_id,
pstat.statement_id,
sta.statement_type,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
sta_parent.statement_type,
sta_parent.routine_name,
pstat.line_num,
pstat.column_num
order by sum(pstat.total_elapsed_time) desc
```
## View `PLG$PROF_RECORD_SOURCE_STATS_VIEW`
```
select rstat.profile_id,
rstat.statement_id,
sta.statement_type,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
sta_parent.statement_type parent_statement_type,
sta_parent.routine_name parent_routine_name,
(select sql_text
from plg$prof_statements
where profile_id = rstat.profile_id and
statement_id = coalesce(sta.parent_statement_id, rstat.statement_id)
) sql_text,
rstat.cursor_id,
rstat.record_source_id,
recsrc.parent_record_source_id,
recsrc.access_path,
cast(sum(rstat.open_counter) as bigint) open_counter,
min(rstat.open_min_elapsed_time) open_min_elapsed_time,
max(rstat.open_max_elapsed_time) open_max_elapsed_time,
cast(sum(rstat.open_total_elapsed_time) as bigint) open_total_elapsed_time,
cast(sum(rstat.open_total_elapsed_time) / nullif(sum(rstat.open_counter), 0) as bigint) open_avg_elapsed_time,
cast(sum(rstat.fetch_counter) as bigint) fetch_counter,
min(rstat.fetch_min_elapsed_time) fetch_min_elapsed_time,
max(rstat.fetch_max_elapsed_time) fetch_max_elapsed_time,
cast(sum(rstat.fetch_total_elapsed_time) as bigint) fetch_total_elapsed_time,
cast(sum(rstat.fetch_total_elapsed_time) / nullif(sum(rstat.fetch_counter), 0) as bigint) fetch_avg_elapsed_time,
cast(coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) as bigint) open_fetch_total_elapsed_time
from plg$prof_record_source_stats rstat
join plg$prof_record_sources recsrc
on recsrc.profile_id = rstat.profile_id and
recsrc.statement_id = rstat.statement_id and
recsrc.cursor_id = rstat.cursor_id and
recsrc.record_source_id = rstat.record_source_id
join plg$prof_statements sta
on sta.profile_id = rstat.profile_id and
sta.statement_id = rstat.statement_id
left join plg$prof_statements sta_parent
on sta_parent.profile_id = sta.profile_id and
sta_parent.statement_id = sta.parent_statement_id
group by rstat.profile_id,
rstat.statement_id,
sta.statement_type,
sta.package_name,
sta.routine_name,
sta.parent_statement_id,
sta_parent.statement_type,
sta_parent.routine_name,
rstat.cursor_id,
rstat.record_source_id,
recsrc.parent_record_source_id,
recsrc.access_path
order by coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) desc
```

View File

@ -113,6 +113,13 @@ public:
static ISC_TIMESTAMP_TZ getCurrentSystemTimeStamp();
static ISC_TIMESTAMP_TZ getCurrentGmtTimeStamp();
static ISC_TIMESTAMP_TZ getCurrentTimeStamp(USHORT timeZone)
{
auto tsTz = getCurrentGmtTimeStamp();
tsTz.time_zone = timeZone;
return tsTz;
}
static void validateGmtTimeStamp(NoThrowTimeStamp& ts);
static ISC_TIME timeTzToTime(const ISC_TIME_TZ& timeTz, Callbacks* cb);

View File

@ -283,6 +283,15 @@ public:
return NULL;
}
// If the key is not present, add it. Not synchronized.
ValueType* getOrPut(const KeyType& key)
{
if (auto value = get(key))
return value;
return put(key);
}
bool exist(const KeyType& key) const
{
return ConstTreeAccessor(&tree).locate(key);
@ -370,16 +379,16 @@ private:
typedef GenericMap<Pair<Full<string, string> > > StringMap;
template <typename T, typename V, typename KeyComparator = DefaultComparator<T>>
using NonPooledMap = GenericMap<Pair<NonPooled<T, V>>, KeyComparator>;
using NonPooledMap = GenericMap<NonPooledPair<T, V>, KeyComparator>;
template <typename T, typename V, typename KeyComparator = DefaultComparator<T>>
using LeftPooledMap = GenericMap<Pair<Left<T, V>>, KeyComparator>;
using LeftPooledMap = GenericMap<LeftPooledPair<T, V>, KeyComparator>;
template <typename T, typename V, typename KeyComparator = DefaultComparator<T>>
using RightPooledMap = GenericMap<Pair<Right<T, V>>, KeyComparator>;
using RightPooledMap = GenericMap<RightPooledPair<T, V>, KeyComparator>;
template <typename T, typename V, typename KeyComparator = DefaultComparator<T>>
using FullPooledMap = GenericMap<Pair<Full<T, V>>, KeyComparator>;
using FullPooledMap = GenericMap<FullPooledPair<T, V>, KeyComparator>;
}

View File

@ -121,6 +121,12 @@ namespace Firebird
r.ptr = nullptr;
}
RefPtr(MemoryPool&, RefPtr&& r)
: ptr(r.ptr)
{
r.ptr = nullptr;
}
~RefPtr()
{
if (ptr)
@ -214,6 +220,11 @@ namespace Firebird
return ptr;
}
const T* getPtr() const
{
return ptr;
}
protected:
T* assign(T* const p)
{

View File

@ -553,6 +553,18 @@ public:
!Cmp::greaterThan(KeyOfValue::generate(this->data[lowBound]), item);
}
bool findAndRemove(const Key& item)
{
size_type pos;
if (find(item, pos))
{
this->remove(pos);
return true;
}
return false;
}
bool exist(const Key& item) const
{
size_type pos; // ignored

View File

@ -144,6 +144,18 @@ template<typename BasePair>
}
};
template<typename parLeft, typename parRight>
using NonPooledPair = Pair<NonPooled<parLeft, parRight>>;
template<typename parLeft, typename parRight>
using LeftPooledPair = Pair<Left<parLeft, parRight>>;
template<typename parLeft, typename parRight>
using RightPooledPair = Pair<Right<parLeft, parRight>>;
template<typename parLeft, typename parRight>
using FullPooledPair = Pair<Full<parLeft, parRight>>;
template <typename P>
class FirstKey
{

View File

@ -662,7 +662,8 @@ namespace Firebird
StringBase() : AbstractString(Comparator::getMaxLength()) {}
StringBase(const StringType& v) : AbstractString(Comparator::getMaxLength(), v) {}
StringBase(const void* s, size_type n) : AbstractString(Comparator::getMaxLength(), n, s) {}
StringBase(const_pointer s) : AbstractString(Comparator::getMaxLength(), static_cast<size_type>(strlen(s)), s) {}
StringBase(const_pointer s) :
AbstractString(Comparator::getMaxLength(), static_cast<size_type>(s ? strlen(s) : 0), s) {}
explicit StringBase(const unsigned char* s) :
AbstractString(Comparator::getMaxLength(), static_cast<size_type>(strlen((char*)s)), (char*)s) {}
StringBase(const MetaString& v) : AbstractString(Comparator::getMaxLength(), v) {}
@ -671,6 +672,8 @@ namespace Firebird
AbstractString(Comparator::getMaxLength(), last - first, first) {}
explicit StringBase(MemoryPool& p) : AbstractString(Comparator::getMaxLength(), p) {}
StringBase(MemoryPool& p, const AbstractString& v) : AbstractString(Comparator::getMaxLength(), p, v) {}
StringBase(MemoryPool& p, const_pointer s) :
AbstractString(Comparator::getMaxLength(), p, s, static_cast<size_type>(s ? strlen(s) : 0)) {}
StringBase(MemoryPool& p, const char_type* s, size_type l) :
AbstractString(Comparator::getMaxLength(), p, s, l) {}

View File

@ -214,6 +214,12 @@ namespace Firebird
return inherited::add(dataL);
}
size_type add(T&& item)
{
T* dataL = FB_NEW_POOL(this->getPool()) T(this->getPool(), std::move(item));
return inherited::add(dataL);
}
T& add()
{
T* dataL = FB_NEW_POOL(this->getPool()) T(this->getPool());

View File

@ -655,6 +655,12 @@ const char* Config::getPlugins(unsigned int type) const
aKey = key;
break;
}
case IPluginManager::TYPE_PROFILER:
{
DECLARE_PER_DB_KEY(KEY_PLUG_PROFILER);
aKey = key;
break;
}
case IPluginManager::TYPE_TRACE:
{
DECLARE_PER_DB_KEY(KEY_PLUG_TRACE);

View File

@ -162,6 +162,7 @@ enum ConfigKey
KEY_PLUG_AUTH_SERVER,
KEY_PLUG_AUTH_CLIENT,
KEY_PLUG_AUTH_MANAGE,
KEY_PLUG_PROFILER,
KEY_PLUG_TRACE,
KEY_SECURITY_DATABASE,
KEY_SERVER_MODE,
@ -273,6 +274,7 @@ constexpr ConfigEntry entries[MAX_CONFIG_KEY] =
{TYPE_STRING, "AuthClient", false, "Srp256, Srp, Legacy_Auth"},
#endif
{TYPE_STRING, "UserManager", false, "Srp"},
{TYPE_STRING, "DefaultProfilerPlugin", false, "Default_Profiler"},
{TYPE_STRING, "TracePlugin", false, "fbtrace"},
{TYPE_STRING, "SecurityDatabase", false, nullptr}, // sec/db alias - rely on ConfigManager::getDefaultSecurityDb(
{TYPE_STRING, "ServerMode", true, nullptr}, // actual value differs in boot/regular cases and set at setupDefaultConfig(

View File

@ -54,6 +54,8 @@ static const char* const FB_TRACE_LOG_MUTEX = "fb_trace_log_mutex";
// Per-trace session usage (for interactive trace)
static const char* const FB_TRACE_FILE = "fb_trace.";
static const char* const PROFILER_FILE = "fb_profiler_%s_%" UQUADFORMAT;
#ifdef UNIX
static const char* const INIT_FILE = "fb_init";
static const char* const SEM_FILE = "fb_sem";

View File

@ -330,7 +330,8 @@ public:
SRAM_TPC_BLOCK = 0xF8,
SRAM_TPC_SNAPSHOTS = 0xF7,
SRAM_CHANGELOG_STATE = 0xF6,
SRAM_TRACE_AUDIT_MTX = 0xF5
SRAM_TRACE_AUDIT_MTX = 0xF5,
SRAM_PROFILER = 0XF4
};
protected:

View File

@ -30,8 +30,10 @@
#define COMMON_STATUS_H
#include "fb_exception.h"
#include "../common/isc_proto.h"
#include "../common/StatusHolder.h"
#include "../common/utils_proto.h"
#include <utility>
const int MAX_ERRMSG_LEN = 128;
const int MAX_ERRSTR_LEN = 1024;
@ -42,12 +44,14 @@ namespace Firebird
class LocalStatusWrapper
{
public:
LocalStatusWrapper()
: localStatusVector(&localStatus)
template <typename... Args>
LocalStatusWrapper(Args&&... args)
: localStatusVector(&localStatus, std::forward<Args>(args)...)
{ }
explicit LocalStatusWrapper(Firebird::MemoryPool& p)
: localStatus(p), localStatusVector(&localStatus)
template <typename... Args>
explicit LocalStatusWrapper(Firebird::MemoryPool& p, Args&&... args)
: localStatus(p), localStatusVector(&localStatus, std::forward<Args>(args)...)
{ }
SW* operator->()
@ -112,6 +116,28 @@ namespace Firebird
typedef LocalStatusWrapper<CheckStatusWrapper> FbLocalStatus;
class LogWrapper : public BaseStatusWrapper<LogWrapper>
{
public:
LogWrapper(IStatus* aStatus, const char* aText = nullptr)
: BaseStatusWrapper(aStatus),
text(aText)
{
}
public:
static void checkException(LogWrapper* status)
{
if (status->dirty && (status->getState() & IStatus::STATE_ERRORS))
iscLogStatus(status->text, status->status);
}
private:
const char* text;
};
typedef LocalStatusWrapper<LogWrapper> LogLocalStatus;
class ThrowWrapper : public BaseStatusWrapper<ThrowWrapper>
{
public:

View File

@ -6812,7 +6812,7 @@ dsc* FieldNode::execute(thread_db* tdbb, Request* request) const
{
// Computed fields shouldn't be present at this point
jrd_fld* field = MET_get_field(relation, fieldId);
fb_assert(field && !field->fld_computation);
fb_assert(!field || !field->fld_computation);
}
#endif

View File

@ -1530,6 +1530,11 @@ public:
return NULL;
}
virtual bool isProfileAware() const
{
return true;
}
virtual const StmtNode* execute(thread_db* tdbb, Request* request, ExeState* exeState) const = 0;
public:

View File

@ -845,7 +845,7 @@ const StmtNode* CompoundStmtNode::execute(thread_db* tdbb, Request* request, Exe
{
const NestConst<StmtNode>* end = statements.end();
if (onlyAssignments)
if (onlyAssignments && !request->req_attachment->isProfilerActive())
{
if (request->req_operation == Request::req_evaluate)
{
@ -8705,6 +8705,10 @@ string ReturnNode::internalPrint(NodePrinter& printer) const
void ReturnNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
dsqlScratch->appendUChar(blr_begin);
if (hasLineColumn)
dsqlScratch->putDebugSrcInfo(line, column);
dsqlScratch->appendUChar(blr_assignment);
GEN_expr(dsqlScratch, value);
dsqlScratch->appendUChar(blr_variable);

View File

@ -195,6 +195,11 @@ public:
public:
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
virtual bool isProfileAware() const
{
return false;
}
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual CompoundStmtNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
@ -390,6 +395,11 @@ public:
public:
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
virtual bool isProfileAware() const
{
return false;
}
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual DeclareSubFuncNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
@ -451,6 +461,11 @@ public:
public:
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
virtual bool isProfileAware() const
{
return false;
}
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual DeclareSubProcNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);

View File

@ -250,8 +250,9 @@ interface PluginManager : Versioned
const uint TYPE_DB_CRYPT = 9;
const uint TYPE_KEY_HOLDER = 10;
const uint TYPE_REPLICATOR = 11;
const uint TYPE_COUNT = 12; // keep in sync
//// TODO: TYPE_COUNT is not count. And these constants starts from 1, different than DIR_* ones.
const uint TYPE_PROFILER = 12;
const uint TYPE_COUNT = 13; // keep in sync
//// TYPE_COUNT is not count. And these constants starts from 1, different than DIR_* ones.
// Main function called by plugin modules in firebird_plugin()
void registerPluginFactory(uint pluginType, const string defaultName, PluginFactory factory);
@ -1712,3 +1713,55 @@ interface ReplicatedSession : PluginBase
void setSequence(Status status, const string name, int64 value);
}
// Profiler interfaces
interface ProfilerPlugin : PluginBase
{
void init(Status status, Attachment attachment);
ProfilerSession startSession(Status status, const string description,
const string options, ISC_TIMESTAMP_TZ timestamp);
void flush(Status status);
}
interface ProfilerSession : Disposable
{
const uint FLAG_BEFORE_EVENTS = 0x1;
const uint FLAG_AFTER_EVENTS = 0x2;
int64 getId();
uint getFlags();
// When closing an attachment, the engine is free to dispose the ProfilerPlugin without call this method in advance.
void cancel(Status status);
void finish(Status status, ISC_TIMESTAMP_TZ timestamp);
void defineStatement(Status status, int64 statementId, int64 parentStatementId,
const string type, const string packageName, const string routineName, const string sqlText);
//// TODO: Add defineCursor with line/column
void defineRecordSource(int64 statementId, uint cursorId, uint recSourceId,
const string accessPath, uint parentRecSourceId);
void onRequestStart(Status status, int64 requestId, int64 statementId, int64 callerRequestId,
ISC_TIMESTAMP_TZ timestamp);
void onRequestFinish(Status status, int64 requestId, ISC_TIMESTAMP_TZ timestamp, ProfilerStats stats);
void beforePsqlLineColumn(int64 requestId, uint line, uint column);
void afterPsqlLineColumn(int64 requestId, uint line, uint column, ProfilerStats stats);
void beforeRecordSourceOpen(int64 requestId, uint cursorId, uint recSourceId);
void afterRecordSourceOpen(int64 requestId, uint cursorId, uint recSourceId, ProfilerStats stats);
void beforeRecordSourceGetRecord(int64 requestId, uint cursorId, uint recSourceId);
void afterRecordSourceGetRecord(int64 requestId, uint cursorId, uint recSourceId, ProfilerStats stats);
}
interface ProfilerStats : Versioned
{
uint64 getElapsedTime();
}

View File

@ -121,6 +121,9 @@ namespace Firebird
class IReplicatedRecord;
class IReplicatedTransaction;
class IReplicatedSession;
class IProfilerPlugin;
class IProfilerSession;
class IProfilerStats;
// Interfaces declarations
@ -825,7 +828,8 @@ namespace Firebird
static const unsigned TYPE_DB_CRYPT = 9;
static const unsigned TYPE_KEY_HOLDER = 10;
static const unsigned TYPE_REPLICATOR = 11;
static const unsigned TYPE_COUNT = 12;
static const unsigned TYPE_PROFILER = 12;
static const unsigned TYPE_COUNT = 13;
void registerPluginFactory(unsigned pluginType, const char* defaultName, IPluginFactory* factory)
{
@ -6682,6 +6686,200 @@ namespace Firebird
}
};
class IProfilerPlugin : public IPluginBase
{
public:
struct VTable : public IPluginBase::VTable
{
void (CLOOP_CARG *init)(IProfilerPlugin* self, IStatus* status, IAttachment* attachment) throw();
IProfilerSession* (CLOOP_CARG *startSession)(IProfilerPlugin* self, IStatus* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) throw();
void (CLOOP_CARG *flush)(IProfilerPlugin* self, IStatus* status) throw();
};
protected:
IProfilerPlugin(DoNotInherit)
: IPluginBase(DoNotInherit())
{
}
~IProfilerPlugin()
{
}
public:
static const unsigned VERSION = 4;
template <typename StatusType> void init(StatusType* status, IAttachment* attachment)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->init(this, status, attachment);
StatusType::checkException(status);
}
template <typename StatusType> IProfilerSession* startSession(StatusType* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp)
{
StatusType::clearException(status);
IProfilerSession* ret = static_cast<VTable*>(this->cloopVTable)->startSession(this, status, description, options, timestamp);
StatusType::checkException(status);
return ret;
}
template <typename StatusType> void flush(StatusType* status)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->flush(this, status);
StatusType::checkException(status);
}
};
class IProfilerSession : public IDisposable
{
public:
struct VTable : public IDisposable::VTable
{
ISC_INT64 (CLOOP_CARG *getId)(IProfilerSession* self) throw();
unsigned (CLOOP_CARG *getFlags)(IProfilerSession* self) throw();
void (CLOOP_CARG *cancel)(IProfilerSession* self, IStatus* status) throw();
void (CLOOP_CARG *finish)(IProfilerSession* self, IStatus* status, ISC_TIMESTAMP_TZ timestamp) throw();
void (CLOOP_CARG *defineStatement)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) throw();
void (CLOOP_CARG *defineRecordSource)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) throw();
void (CLOOP_CARG *onRequestStart)(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) throw();
void (CLOOP_CARG *onRequestFinish)(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) throw();
void (CLOOP_CARG *beforePsqlLineColumn)(IProfilerSession* self, ISC_INT64 requestId, unsigned line, unsigned column) throw();
void (CLOOP_CARG *afterPsqlLineColumn)(IProfilerSession* self, ISC_INT64 requestId, unsigned line, unsigned column, IProfilerStats* stats) throw();
void (CLOOP_CARG *beforeRecordSourceOpen)(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) throw();
void (CLOOP_CARG *afterRecordSourceOpen)(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) throw();
void (CLOOP_CARG *beforeRecordSourceGetRecord)(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) throw();
void (CLOOP_CARG *afterRecordSourceGetRecord)(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) throw();
};
protected:
IProfilerSession(DoNotInherit)
: IDisposable(DoNotInherit())
{
}
~IProfilerSession()
{
}
public:
static const unsigned VERSION = 3;
static const unsigned FLAG_BEFORE_EVENTS = 0x1;
static const unsigned FLAG_AFTER_EVENTS = 0x2;
ISC_INT64 getId()
{
ISC_INT64 ret = static_cast<VTable*>(this->cloopVTable)->getId(this);
return ret;
}
unsigned getFlags()
{
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getFlags(this);
return ret;
}
template <typename StatusType> void cancel(StatusType* status)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->cancel(this, status);
StatusType::checkException(status);
}
template <typename StatusType> void finish(StatusType* status, ISC_TIMESTAMP_TZ timestamp)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->finish(this, status, timestamp);
StatusType::checkException(status);
}
template <typename StatusType> void defineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->defineStatement(this, status, statementId, parentStatementId, type, packageName, routineName, sqlText);
StatusType::checkException(status);
}
void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId)
{
static_cast<VTable*>(this->cloopVTable)->defineRecordSource(this, statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
}
template <typename StatusType> void onRequestStart(StatusType* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->onRequestStart(this, status, requestId, statementId, callerRequestId, timestamp);
StatusType::checkException(status);
}
template <typename StatusType> void onRequestFinish(StatusType* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->onRequestFinish(this, status, requestId, timestamp, stats);
StatusType::checkException(status);
}
void beforePsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column)
{
static_cast<VTable*>(this->cloopVTable)->beforePsqlLineColumn(this, requestId, line, column);
}
void afterPsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column, IProfilerStats* stats)
{
static_cast<VTable*>(this->cloopVTable)->afterPsqlLineColumn(this, requestId, line, column, stats);
}
void beforeRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId)
{
static_cast<VTable*>(this->cloopVTable)->beforeRecordSourceOpen(this, requestId, cursorId, recSourceId);
}
void afterRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats)
{
static_cast<VTable*>(this->cloopVTable)->afterRecordSourceOpen(this, requestId, cursorId, recSourceId, stats);
}
void beforeRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId)
{
static_cast<VTable*>(this->cloopVTable)->beforeRecordSourceGetRecord(this, requestId, cursorId, recSourceId);
}
void afterRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats)
{
static_cast<VTable*>(this->cloopVTable)->afterRecordSourceGetRecord(this, requestId, cursorId, recSourceId, stats);
}
};
class IProfilerStats : public IVersioned
{
public:
struct VTable : public IVersioned::VTable
{
ISC_UINT64 (CLOOP_CARG *getElapsedTime)(IProfilerStats* self) throw();
};
protected:
IProfilerStats(DoNotInherit)
: IVersioned(DoNotInherit())
{
}
~IProfilerStats()
{
}
public:
static const unsigned VERSION = 2;
ISC_UINT64 getElapsedTime()
{
ISC_UINT64 ret = static_cast<VTable*>(this->cloopVTable)->getElapsedTime(this);
return ret;
}
};
// Interfaces implementations
template <typename Name, typename StatusType, typename Base>
@ -19857,6 +20055,450 @@ namespace Firebird
virtual void cleanupTransaction(StatusType* status, ISC_INT64 number) = 0;
virtual void setSequence(StatusType* status, const char* name, ISC_INT64 value) = 0;
};
template <typename Name, typename StatusType, typename Base>
class IProfilerPluginBaseImpl : public Base
{
public:
typedef IProfilerPlugin Declaration;
IProfilerPluginBaseImpl(DoNotInherit = DoNotInherit())
{
static struct VTableImpl : Base::VTable
{
VTableImpl()
{
this->version = Base::VERSION;
this->addRef = &Name::cloopaddRefDispatcher;
this->release = &Name::cloopreleaseDispatcher;
this->setOwner = &Name::cloopsetOwnerDispatcher;
this->getOwner = &Name::cloopgetOwnerDispatcher;
this->init = &Name::cloopinitDispatcher;
this->startSession = &Name::cloopstartSessionDispatcher;
this->flush = &Name::cloopflushDispatcher;
}
} vTable;
this->cloopVTable = &vTable;
}
static void CLOOP_CARG cloopinitDispatcher(IProfilerPlugin* self, IStatus* status, IAttachment* attachment) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::init(&status2, attachment);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static IProfilerSession* CLOOP_CARG cloopstartSessionDispatcher(IProfilerPlugin* self, IStatus* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::startSession(&status2, description, options, timestamp);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<IProfilerSession*>(0);
}
}
static void CLOOP_CARG cloopflushDispatcher(IProfilerPlugin* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::flush(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw()
{
try
{
static_cast<Name*>(self)->Name::setOwner(r);
}
catch (...)
{
StatusType::catchException(0);
}
}
static IReferenceCounted* CLOOP_CARG cloopgetOwnerDispatcher(IPluginBase* self) throw()
{
try
{
return static_cast<Name*>(self)->Name::getOwner();
}
catch (...)
{
StatusType::catchException(0);
return static_cast<IReferenceCounted*>(0);
}
}
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
{
try
{
static_cast<Name*>(self)->Name::addRef();
}
catch (...)
{
StatusType::catchException(0);
}
}
static int CLOOP_CARG cloopreleaseDispatcher(IReferenceCounted* self) throw()
{
try
{
return static_cast<Name*>(self)->Name::release();
}
catch (...)
{
StatusType::catchException(0);
return static_cast<int>(0);
}
}
};
template <typename Name, typename StatusType, typename Base = IPluginBaseImpl<Name, StatusType, Inherit<IReferenceCountedImpl<Name, StatusType, Inherit<IVersionedImpl<Name, StatusType, Inherit<IProfilerPlugin> > > > > > >
class IProfilerPluginImpl : public IProfilerPluginBaseImpl<Name, StatusType, Base>
{
protected:
IProfilerPluginImpl(DoNotInherit = DoNotInherit())
{
}
public:
virtual ~IProfilerPluginImpl()
{
}
virtual void init(StatusType* status, IAttachment* attachment) = 0;
virtual IProfilerSession* startSession(StatusType* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void flush(StatusType* status) = 0;
};
template <typename Name, typename StatusType, typename Base>
class IProfilerSessionBaseImpl : public Base
{
public:
typedef IProfilerSession Declaration;
IProfilerSessionBaseImpl(DoNotInherit = DoNotInherit())
{
static struct VTableImpl : Base::VTable
{
VTableImpl()
{
this->version = Base::VERSION;
this->dispose = &Name::cloopdisposeDispatcher;
this->getId = &Name::cloopgetIdDispatcher;
this->getFlags = &Name::cloopgetFlagsDispatcher;
this->cancel = &Name::cloopcancelDispatcher;
this->finish = &Name::cloopfinishDispatcher;
this->defineStatement = &Name::cloopdefineStatementDispatcher;
this->defineRecordSource = &Name::cloopdefineRecordSourceDispatcher;
this->onRequestStart = &Name::clooponRequestStartDispatcher;
this->onRequestFinish = &Name::clooponRequestFinishDispatcher;
this->beforePsqlLineColumn = &Name::cloopbeforePsqlLineColumnDispatcher;
this->afterPsqlLineColumn = &Name::cloopafterPsqlLineColumnDispatcher;
this->beforeRecordSourceOpen = &Name::cloopbeforeRecordSourceOpenDispatcher;
this->afterRecordSourceOpen = &Name::cloopafterRecordSourceOpenDispatcher;
this->beforeRecordSourceGetRecord = &Name::cloopbeforeRecordSourceGetRecordDispatcher;
this->afterRecordSourceGetRecord = &Name::cloopafterRecordSourceGetRecordDispatcher;
}
} vTable;
this->cloopVTable = &vTable;
}
static ISC_INT64 CLOOP_CARG cloopgetIdDispatcher(IProfilerSession* self) throw()
{
try
{
return static_cast<Name*>(self)->Name::getId();
}
catch (...)
{
StatusType::catchException(0);
return static_cast<ISC_INT64>(0);
}
}
static unsigned CLOOP_CARG cloopgetFlagsDispatcher(IProfilerSession* self) throw()
{
try
{
return static_cast<Name*>(self)->Name::getFlags();
}
catch (...)
{
StatusType::catchException(0);
return static_cast<unsigned>(0);
}
}
static void CLOOP_CARG cloopcancelDispatcher(IProfilerSession* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::cancel(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopfinishDispatcher(IProfilerSession* self, IStatus* status, ISC_TIMESTAMP_TZ timestamp) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::finish(&status2, timestamp);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopdefineStatementDispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::defineStatement(&status2, statementId, parentStatementId, type, packageName, routineName, sqlText);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopdefineRecordSourceDispatcher(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) throw()
{
try
{
static_cast<Name*>(self)->Name::defineRecordSource(statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
}
catch (...)
{
StatusType::catchException(0);
}
}
static void CLOOP_CARG clooponRequestStartDispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::onRequestStart(&status2, requestId, statementId, callerRequestId, timestamp);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG clooponRequestFinishDispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::onRequestFinish(&status2, requestId, timestamp, stats);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopbeforePsqlLineColumnDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned line, unsigned column) throw()
{
try
{
static_cast<Name*>(self)->Name::beforePsqlLineColumn(requestId, line, column);
}
catch (...)
{
StatusType::catchException(0);
}
}
static void CLOOP_CARG cloopafterPsqlLineColumnDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned line, unsigned column, IProfilerStats* stats) throw()
{
try
{
static_cast<Name*>(self)->Name::afterPsqlLineColumn(requestId, line, column, stats);
}
catch (...)
{
StatusType::catchException(0);
}
}
static void CLOOP_CARG cloopbeforeRecordSourceOpenDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) throw()
{
try
{
static_cast<Name*>(self)->Name::beforeRecordSourceOpen(requestId, cursorId, recSourceId);
}
catch (...)
{
StatusType::catchException(0);
}
}
static void CLOOP_CARG cloopafterRecordSourceOpenDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) throw()
{
try
{
static_cast<Name*>(self)->Name::afterRecordSourceOpen(requestId, cursorId, recSourceId, stats);
}
catch (...)
{
StatusType::catchException(0);
}
}
static void CLOOP_CARG cloopbeforeRecordSourceGetRecordDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) throw()
{
try
{
static_cast<Name*>(self)->Name::beforeRecordSourceGetRecord(requestId, cursorId, recSourceId);
}
catch (...)
{
StatusType::catchException(0);
}
}
static void CLOOP_CARG cloopafterRecordSourceGetRecordDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) throw()
{
try
{
static_cast<Name*>(self)->Name::afterRecordSourceGetRecord(requestId, cursorId, recSourceId, stats);
}
catch (...)
{
StatusType::catchException(0);
}
}
static void CLOOP_CARG cloopdisposeDispatcher(IDisposable* self) throw()
{
try
{
static_cast<Name*>(self)->Name::dispose();
}
catch (...)
{
StatusType::catchException(0);
}
}
};
template <typename Name, typename StatusType, typename Base = IDisposableImpl<Name, StatusType, Inherit<IVersionedImpl<Name, StatusType, Inherit<IProfilerSession> > > > >
class IProfilerSessionImpl : public IProfilerSessionBaseImpl<Name, StatusType, Base>
{
protected:
IProfilerSessionImpl(DoNotInherit = DoNotInherit())
{
}
public:
virtual ~IProfilerSessionImpl()
{
}
virtual ISC_INT64 getId() = 0;
virtual unsigned getFlags() = 0;
virtual void cancel(StatusType* status) = 0;
virtual void finish(StatusType* status, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void defineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) = 0;
virtual void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) = 0;
virtual void onRequestStart(StatusType* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void onRequestFinish(StatusType* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) = 0;
virtual void beforePsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column) = 0;
virtual void afterPsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column, IProfilerStats* stats) = 0;
virtual void beforeRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) = 0;
virtual void afterRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) = 0;
virtual void beforeRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) = 0;
virtual void afterRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) = 0;
};
template <typename Name, typename StatusType, typename Base>
class IProfilerStatsBaseImpl : public Base
{
public:
typedef IProfilerStats Declaration;
IProfilerStatsBaseImpl(DoNotInherit = DoNotInherit())
{
static struct VTableImpl : Base::VTable
{
VTableImpl()
{
this->version = Base::VERSION;
this->getElapsedTime = &Name::cloopgetElapsedTimeDispatcher;
}
} vTable;
this->cloopVTable = &vTable;
}
static ISC_UINT64 CLOOP_CARG cloopgetElapsedTimeDispatcher(IProfilerStats* self) throw()
{
try
{
return static_cast<Name*>(self)->Name::getElapsedTime();
}
catch (...)
{
StatusType::catchException(0);
return static_cast<ISC_UINT64>(0);
}
}
};
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IProfilerStats> > >
class IProfilerStatsImpl : public IProfilerStatsBaseImpl<Name, StatusType, Base>
{
protected:
IProfilerStatsImpl(DoNotInherit = DoNotInherit())
{
}
public:
virtual ~IProfilerStatsImpl()
{
}
virtual ISC_UINT64 getElapsedTime() = 0;
};
};

View File

@ -111,6 +111,9 @@ type
IReplicatedRecord = class;
IReplicatedTransaction = class;
IReplicatedSession = class;
IProfilerPlugin = class;
IProfilerSession = class;
IProfilerStats = class;
FbException = class(Exception)
public
@ -715,6 +718,24 @@ type
IReplicatedSession_startTransactionPtr = function(this: IReplicatedSession; status: IStatus; transaction: ITransaction; number: Int64): IReplicatedTransaction; cdecl;
IReplicatedSession_cleanupTransactionPtr = procedure(this: IReplicatedSession; status: IStatus; number: Int64); cdecl;
IReplicatedSession_setSequencePtr = procedure(this: IReplicatedSession; status: IStatus; name: PAnsiChar; value: Int64); cdecl;
IProfilerPlugin_initPtr = procedure(this: IProfilerPlugin; status: IStatus; attachment: IAttachment); cdecl;
IProfilerPlugin_startSessionPtr = function(this: IProfilerPlugin; status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl;
IProfilerPlugin_flushPtr = procedure(this: IProfilerPlugin; status: IStatus); cdecl;
IProfilerSession_getIdPtr = function(this: IProfilerSession): Int64; cdecl;
IProfilerSession_getFlagsPtr = function(this: IProfilerSession): Cardinal; cdecl;
IProfilerSession_cancelPtr = procedure(this: IProfilerSession; status: IStatus); cdecl;
IProfilerSession_finishPtr = procedure(this: IProfilerSession; status: IStatus; timestamp: ISC_TIMESTAMP_TZ); cdecl;
IProfilerSession_defineStatementPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl;
IProfilerSession_defineRecordSourcePtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
IProfilerSession_onRequestStartPtr = procedure(this: IProfilerSession; status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); cdecl;
IProfilerSession_onRequestFinishPtr = procedure(this: IProfilerSession; status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); cdecl;
IProfilerSession_beforePsqlLineColumnPtr = procedure(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal); cdecl;
IProfilerSession_afterPsqlLineColumnPtr = procedure(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats); cdecl;
IProfilerSession_beforeRecordSourceOpenPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
IProfilerSession_afterRecordSourceOpenPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl;
IProfilerSession_beforeRecordSourceGetRecordPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
IProfilerSession_afterRecordSourceGetRecordPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl;
IProfilerStats_getElapsedTimePtr = function(this: IProfilerStats): QWord; cdecl;
VersionedVTable = class
version: NativeInt;
@ -1082,7 +1103,8 @@ type
const TYPE_DB_CRYPT = Cardinal(9);
const TYPE_KEY_HOLDER = Cardinal(10);
const TYPE_REPLICATOR = Cardinal(11);
const TYPE_COUNT = Cardinal(12);
const TYPE_PROFILER = Cardinal(12);
const TYPE_COUNT = Cardinal(13);
procedure registerPluginFactory(pluginType: Cardinal; defaultName: PAnsiChar; factory: IPluginFactory);
procedure registerModule(cleanup: IPluginModule);
@ -3760,6 +3782,106 @@ type
procedure setSequence(status: IStatus; name: PAnsiChar; value: Int64); virtual; abstract;
end;
ProfilerPluginVTable = class(PluginBaseVTable)
init: IProfilerPlugin_initPtr;
startSession: IProfilerPlugin_startSessionPtr;
flush: IProfilerPlugin_flushPtr;
end;
IProfilerPlugin = class(IPluginBase)
const VERSION = 4;
procedure init(status: IStatus; attachment: IAttachment);
function startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession;
procedure flush(status: IStatus);
end;
IProfilerPluginImpl = class(IProfilerPlugin)
constructor create;
procedure addRef(); virtual; abstract;
function release(): Integer; virtual; abstract;
procedure setOwner(r: IReferenceCounted); virtual; abstract;
function getOwner(): IReferenceCounted; virtual; abstract;
procedure init(status: IStatus; attachment: IAttachment); virtual; abstract;
function startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; virtual; abstract;
procedure flush(status: IStatus); virtual; abstract;
end;
ProfilerSessionVTable = class(DisposableVTable)
getId: IProfilerSession_getIdPtr;
getFlags: IProfilerSession_getFlagsPtr;
cancel: IProfilerSession_cancelPtr;
finish: IProfilerSession_finishPtr;
defineStatement: IProfilerSession_defineStatementPtr;
defineRecordSource: IProfilerSession_defineRecordSourcePtr;
onRequestStart: IProfilerSession_onRequestStartPtr;
onRequestFinish: IProfilerSession_onRequestFinishPtr;
beforePsqlLineColumn: IProfilerSession_beforePsqlLineColumnPtr;
afterPsqlLineColumn: IProfilerSession_afterPsqlLineColumnPtr;
beforeRecordSourceOpen: IProfilerSession_beforeRecordSourceOpenPtr;
afterRecordSourceOpen: IProfilerSession_afterRecordSourceOpenPtr;
beforeRecordSourceGetRecord: IProfilerSession_beforeRecordSourceGetRecordPtr;
afterRecordSourceGetRecord: IProfilerSession_afterRecordSourceGetRecordPtr;
end;
IProfilerSession = class(IDisposable)
const VERSION = 3;
const FLAG_BEFORE_EVENTS = Cardinal($1);
const FLAG_AFTER_EVENTS = Cardinal($2);
function getId(): Int64;
function getFlags(): Cardinal;
procedure cancel(status: IStatus);
procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ);
procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar);
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
procedure onRequestStart(status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ);
procedure onRequestFinish(status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats);
procedure beforePsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal);
procedure afterPsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats);
procedure beforeRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
procedure afterRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats);
procedure beforeRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
procedure afterRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats);
end;
IProfilerSessionImpl = class(IProfilerSession)
constructor create;
procedure dispose(); virtual; abstract;
function getId(): Int64; virtual; abstract;
function getFlags(): Cardinal; virtual; abstract;
procedure cancel(status: IStatus); virtual; abstract;
procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract;
procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); virtual; abstract;
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); virtual; abstract;
procedure onRequestStart(status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract;
procedure onRequestFinish(status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); virtual; abstract;
procedure beforePsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal); virtual; abstract;
procedure afterPsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats); virtual; abstract;
procedure beforeRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); virtual; abstract;
procedure afterRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); virtual; abstract;
procedure beforeRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); virtual; abstract;
procedure afterRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); virtual; abstract;
end;
ProfilerStatsVTable = class(VersionedVTable)
getElapsedTime: IProfilerStats_getElapsedTimePtr;
end;
IProfilerStats = class(IVersioned)
const VERSION = 2;
function getElapsedTime(): QWord;
end;
IProfilerStatsImpl = class(IProfilerStats)
constructor create;
function getElapsedTime(): QWord; virtual; abstract;
end;
{$IFNDEF NO_FBCLIENT}
function fb_get_master_interface : IMaster; cdecl; external 'fbclient';
{$ENDIF}
@ -8899,6 +9021,104 @@ begin
FbException.checkException(status);
end;
procedure IProfilerPlugin.init(status: IStatus; attachment: IAttachment);
begin
ProfilerPluginVTable(vTable).init(Self, status, attachment);
FbException.checkException(status);
end;
function IProfilerPlugin.startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession;
begin
Result := ProfilerPluginVTable(vTable).startSession(Self, status, description, options, timestamp);
FbException.checkException(status);
end;
procedure IProfilerPlugin.flush(status: IStatus);
begin
ProfilerPluginVTable(vTable).flush(Self, status);
FbException.checkException(status);
end;
function IProfilerSession.getId(): Int64;
begin
Result := ProfilerSessionVTable(vTable).getId(Self);
end;
function IProfilerSession.getFlags(): Cardinal;
begin
Result := ProfilerSessionVTable(vTable).getFlags(Self);
end;
procedure IProfilerSession.cancel(status: IStatus);
begin
ProfilerSessionVTable(vTable).cancel(Self, status);
FbException.checkException(status);
end;
procedure IProfilerSession.finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ);
begin
ProfilerSessionVTable(vTable).finish(Self, status, timestamp);
FbException.checkException(status);
end;
procedure IProfilerSession.defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar);
begin
ProfilerSessionVTable(vTable).defineStatement(Self, status, statementId, parentStatementId, type_, packageName, routineName, sqlText);
FbException.checkException(status);
end;
procedure IProfilerSession.defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
begin
ProfilerSessionVTable(vTable).defineRecordSource(Self, statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
end;
procedure IProfilerSession.onRequestStart(status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ);
begin
ProfilerSessionVTable(vTable).onRequestStart(Self, status, requestId, statementId, callerRequestId, timestamp);
FbException.checkException(status);
end;
procedure IProfilerSession.onRequestFinish(status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats);
begin
ProfilerSessionVTable(vTable).onRequestFinish(Self, status, requestId, timestamp, stats);
FbException.checkException(status);
end;
procedure IProfilerSession.beforePsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal);
begin
ProfilerSessionVTable(vTable).beforePsqlLineColumn(Self, requestId, line, column);
end;
procedure IProfilerSession.afterPsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats);
begin
ProfilerSessionVTable(vTable).afterPsqlLineColumn(Self, requestId, line, column, stats);
end;
procedure IProfilerSession.beforeRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
begin
ProfilerSessionVTable(vTable).beforeRecordSourceOpen(Self, requestId, cursorId, recSourceId);
end;
procedure IProfilerSession.afterRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats);
begin
ProfilerSessionVTable(vTable).afterRecordSourceOpen(Self, requestId, cursorId, recSourceId, stats);
end;
procedure IProfilerSession.beforeRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
begin
ProfilerSessionVTable(vTable).beforeRecordSourceGetRecord(Self, requestId, cursorId, recSourceId);
end;
procedure IProfilerSession.afterRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats);
begin
ProfilerSessionVTable(vTable).afterRecordSourceGetRecord(Self, requestId, cursorId, recSourceId, stats);
end;
function IProfilerStats.getElapsedTime(): QWord;
begin
Result := ProfilerStatsVTable(vTable).getElapsedTime(Self);
end;
var
IVersionedImpl_vTable: VersionedVTable;
@ -15428,6 +15648,237 @@ begin
vTable := IReplicatedSessionImpl_vTable;
end;
procedure IProfilerPluginImpl_addRefDispatcher(this: IProfilerPlugin); cdecl;
begin
try
IProfilerPluginImpl(this).addRef();
except
on e: Exception do FbException.catchException(nil, e);
end
end;
function IProfilerPluginImpl_releaseDispatcher(this: IProfilerPlugin): Integer; cdecl;
begin
try
Result := IProfilerPluginImpl(this).release();
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerPluginImpl_setOwnerDispatcher(this: IProfilerPlugin; r: IReferenceCounted); cdecl;
begin
try
IProfilerPluginImpl(this).setOwner(r);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
function IProfilerPluginImpl_getOwnerDispatcher(this: IProfilerPlugin): IReferenceCounted; cdecl;
begin
try
Result := IProfilerPluginImpl(this).getOwner();
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerPluginImpl_initDispatcher(this: IProfilerPlugin; status: IStatus; attachment: IAttachment); cdecl;
begin
try
IProfilerPluginImpl(this).init(status, attachment);
except
on e: Exception do FbException.catchException(status, e);
end
end;
function IProfilerPluginImpl_startSessionDispatcher(this: IProfilerPlugin; status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl;
begin
try
Result := IProfilerPluginImpl(this).startSession(status, description, options, timestamp);
except
on e: Exception do FbException.catchException(status, e);
end
end;
procedure IProfilerPluginImpl_flushDispatcher(this: IProfilerPlugin; status: IStatus); cdecl;
begin
try
IProfilerPluginImpl(this).flush(status);
except
on e: Exception do FbException.catchException(status, e);
end
end;
var
IProfilerPluginImpl_vTable: ProfilerPluginVTable;
constructor IProfilerPluginImpl.create;
begin
vTable := IProfilerPluginImpl_vTable;
end;
procedure IProfilerSessionImpl_disposeDispatcher(this: IProfilerSession); cdecl;
begin
try
IProfilerSessionImpl(this).dispose();
except
on e: Exception do FbException.catchException(nil, e);
end
end;
function IProfilerSessionImpl_getIdDispatcher(this: IProfilerSession): Int64; cdecl;
begin
try
Result := IProfilerSessionImpl(this).getId();
except
on e: Exception do FbException.catchException(nil, e);
end
end;
function IProfilerSessionImpl_getFlagsDispatcher(this: IProfilerSession): Cardinal; cdecl;
begin
try
Result := IProfilerSessionImpl(this).getFlags();
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerSessionImpl_cancelDispatcher(this: IProfilerSession; status: IStatus); cdecl;
begin
try
IProfilerSessionImpl(this).cancel(status);
except
on e: Exception do FbException.catchException(status, e);
end
end;
procedure IProfilerSessionImpl_finishDispatcher(this: IProfilerSession; status: IStatus; timestamp: ISC_TIMESTAMP_TZ); cdecl;
begin
try
IProfilerSessionImpl(this).finish(status, timestamp);
except
on e: Exception do FbException.catchException(status, e);
end
end;
procedure IProfilerSessionImpl_defineStatementDispatcher(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl;
begin
try
IProfilerSessionImpl(this).defineStatement(status, statementId, parentStatementId, type_, packageName, routineName, sqlText);
except
on e: Exception do FbException.catchException(status, e);
end
end;
procedure IProfilerSessionImpl_defineRecordSourceDispatcher(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
begin
try
IProfilerSessionImpl(this).defineRecordSource(statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerSessionImpl_onRequestStartDispatcher(this: IProfilerSession; status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); cdecl;
begin
try
IProfilerSessionImpl(this).onRequestStart(status, requestId, statementId, callerRequestId, timestamp);
except
on e: Exception do FbException.catchException(status, e);
end
end;
procedure IProfilerSessionImpl_onRequestFinishDispatcher(this: IProfilerSession; status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); cdecl;
begin
try
IProfilerSessionImpl(this).onRequestFinish(status, requestId, timestamp, stats);
except
on e: Exception do FbException.catchException(status, e);
end
end;
procedure IProfilerSessionImpl_beforePsqlLineColumnDispatcher(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal); cdecl;
begin
try
IProfilerSessionImpl(this).beforePsqlLineColumn(requestId, line, column);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerSessionImpl_afterPsqlLineColumnDispatcher(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats); cdecl;
begin
try
IProfilerSessionImpl(this).afterPsqlLineColumn(requestId, line, column, stats);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerSessionImpl_beforeRecordSourceOpenDispatcher(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
begin
try
IProfilerSessionImpl(this).beforeRecordSourceOpen(requestId, cursorId, recSourceId);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerSessionImpl_afterRecordSourceOpenDispatcher(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl;
begin
try
IProfilerSessionImpl(this).afterRecordSourceOpen(requestId, cursorId, recSourceId, stats);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerSessionImpl_beforeRecordSourceGetRecordDispatcher(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
begin
try
IProfilerSessionImpl(this).beforeRecordSourceGetRecord(requestId, cursorId, recSourceId);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerSessionImpl_afterRecordSourceGetRecordDispatcher(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl;
begin
try
IProfilerSessionImpl(this).afterRecordSourceGetRecord(requestId, cursorId, recSourceId, stats);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
var
IProfilerSessionImpl_vTable: ProfilerSessionVTable;
constructor IProfilerSessionImpl.create;
begin
vTable := IProfilerSessionImpl_vTable;
end;
function IProfilerStatsImpl_getElapsedTimeDispatcher(this: IProfilerStats): QWord; cdecl;
begin
try
Result := IProfilerStatsImpl(this).getElapsedTime();
except
on e: Exception do FbException.catchException(nil, e);
end
end;
var
IProfilerStatsImpl_vTable: ProfilerStatsVTable;
constructor IProfilerStatsImpl.create;
begin
vTable := IProfilerStatsImpl_vTable;
end;
constructor FbException.create(status: IStatus);
begin
inherited Create('FbException');
@ -16419,6 +16870,38 @@ initialization
IReplicatedSessionImpl_vTable.cleanupTransaction := @IReplicatedSessionImpl_cleanupTransactionDispatcher;
IReplicatedSessionImpl_vTable.setSequence := @IReplicatedSessionImpl_setSequenceDispatcher;
IProfilerPluginImpl_vTable := ProfilerPluginVTable.create;
IProfilerPluginImpl_vTable.version := 4;
IProfilerPluginImpl_vTable.addRef := @IProfilerPluginImpl_addRefDispatcher;
IProfilerPluginImpl_vTable.release := @IProfilerPluginImpl_releaseDispatcher;
IProfilerPluginImpl_vTable.setOwner := @IProfilerPluginImpl_setOwnerDispatcher;
IProfilerPluginImpl_vTable.getOwner := @IProfilerPluginImpl_getOwnerDispatcher;
IProfilerPluginImpl_vTable.init := @IProfilerPluginImpl_initDispatcher;
IProfilerPluginImpl_vTable.startSession := @IProfilerPluginImpl_startSessionDispatcher;
IProfilerPluginImpl_vTable.flush := @IProfilerPluginImpl_flushDispatcher;
IProfilerSessionImpl_vTable := ProfilerSessionVTable.create;
IProfilerSessionImpl_vTable.version := 3;
IProfilerSessionImpl_vTable.dispose := @IProfilerSessionImpl_disposeDispatcher;
IProfilerSessionImpl_vTable.getId := @IProfilerSessionImpl_getIdDispatcher;
IProfilerSessionImpl_vTable.getFlags := @IProfilerSessionImpl_getFlagsDispatcher;
IProfilerSessionImpl_vTable.cancel := @IProfilerSessionImpl_cancelDispatcher;
IProfilerSessionImpl_vTable.finish := @IProfilerSessionImpl_finishDispatcher;
IProfilerSessionImpl_vTable.defineStatement := @IProfilerSessionImpl_defineStatementDispatcher;
IProfilerSessionImpl_vTable.defineRecordSource := @IProfilerSessionImpl_defineRecordSourceDispatcher;
IProfilerSessionImpl_vTable.onRequestStart := @IProfilerSessionImpl_onRequestStartDispatcher;
IProfilerSessionImpl_vTable.onRequestFinish := @IProfilerSessionImpl_onRequestFinishDispatcher;
IProfilerSessionImpl_vTable.beforePsqlLineColumn := @IProfilerSessionImpl_beforePsqlLineColumnDispatcher;
IProfilerSessionImpl_vTable.afterPsqlLineColumn := @IProfilerSessionImpl_afterPsqlLineColumnDispatcher;
IProfilerSessionImpl_vTable.beforeRecordSourceOpen := @IProfilerSessionImpl_beforeRecordSourceOpenDispatcher;
IProfilerSessionImpl_vTable.afterRecordSourceOpen := @IProfilerSessionImpl_afterRecordSourceOpenDispatcher;
IProfilerSessionImpl_vTable.beforeRecordSourceGetRecord := @IProfilerSessionImpl_beforeRecordSourceGetRecordDispatcher;
IProfilerSessionImpl_vTable.afterRecordSourceGetRecord := @IProfilerSessionImpl_afterRecordSourceGetRecordDispatcher;
IProfilerStatsImpl_vTable := ProfilerStatsVTable.create;
IProfilerStatsImpl_vTable.version := 2;
IProfilerStatsImpl_vTable.getElapsedTime := @IProfilerStatsImpl_getElapsedTimeDispatcher;
finalization
IVersionedImpl_vTable.destroy;
IReferenceCountedImpl_vTable.destroy;
@ -16515,5 +16998,8 @@ finalization
IReplicatedRecordImpl_vTable.destroy;
IReplicatedTransactionImpl_vTable.destroy;
IReplicatedSessionImpl_vTable.destroy;
IProfilerPluginImpl_vTable.destroy;
IProfilerSessionImpl_vTable.destroy;
IProfilerStatsImpl_vTable.destroy;
end.

View File

@ -42,7 +42,7 @@
#include "../jrd/tpc_proto.h"
#include "../jrd/extds/ExtDS.h"
#include "../jrd/ProfilerManager.h"
#include "../jrd/replication/Applier.h"
#include "../jrd/replication/Manager.h"
@ -728,6 +728,12 @@ void Jrd::Attachment::initLocks(thread_db* tdbb)
lock = FB_NEW_RPT(*att_pool, 0)
Lock(tdbb, 0, LCK_repl_tables, this, blockingAstReplSet);
att_repl_lock = lock;
lock = FB_NEW_RPT(*att_pool, 0)
Lock(tdbb, sizeof(AttNumber), LCK_profiler_listener, this, ProfilerManager::blockingAst);
att_profiler_listener_lock = lock;
lock->setKey(att_attachment_id);
LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT);
}
}
@ -845,6 +851,9 @@ void Jrd::Attachment::releaseLocks(thread_db* tdbb)
if (att_repl_lock)
LCK_release(tdbb, att_repl_lock);
if (att_profiler_listener_lock)
LCK_release(tdbb, att_profiler_listener_lock);
// And release the system requests
for (Statement** itr = att_internal.begin(); itr != att_internal.end(); ++itr)
@ -1154,3 +1163,21 @@ int Attachment::blockingAstReplSet(void* ast_object)
return 0;
}
ProfilerManager* Attachment::getProfilerManager(thread_db* tdbb)
{
auto profilerManager = att_profiler_manager.get();
if (!profilerManager)
att_profiler_manager.reset(profilerManager = ProfilerManager::create(tdbb));
return profilerManager;
}
bool Attachment::isProfilerActive()
{
return att_profiler_manager && att_profiler_manager->isActive();
}
void Attachment::releaseProfilerManager()
{
att_profiler_manager.reset();
}

View File

@ -95,6 +95,7 @@ namespace Jrd
class TrigVector;
class Function;
class Statement;
class ProfilerManager;
class Validation;
class Applier;
@ -558,6 +559,7 @@ public:
AttNumber att_attachment_id; // Attachment ID
Lock* att_cancel_lock; // Lock to cancel the active request
Lock* att_monitor_lock; // Lock for monitoring purposes
Lock* att_profiler_listener_lock; // Lock for remote profiler listener
const ULONG att_lock_owner_id; // ID for the lock manager
SLONG att_lock_owner_handle; // Handle for the lock manager
ULONG att_backup_state_counter; // Counter of backup state locks for attachment
@ -569,6 +571,7 @@ public:
ULONG att_flags; // Flags describing the state of the attachment
SSHORT att_client_charset; // user's charset specified in dpb
SSHORT att_charset; // current (client or external) attachment charset
bool att_in_system_routine = false; // running a system routine
Lock* att_long_locks; // outstanding two phased locks
#ifdef DEBUG_LCK_LIST
UCHAR att_long_locks_type; // Lock type of the first lock in list
@ -803,6 +806,10 @@ public:
void checkReplSetLock(thread_db* tdbb);
void invalidateReplSet(thread_db* tdbb, bool broadcast);
ProfilerManager* getProfilerManager(thread_db* tdbb);
bool isProfilerActive();
void releaseProfilerManager();
JProvider* getProvider()
{
fb_assert(att_provider);
@ -820,6 +827,7 @@ private:
Firebird::Array<JBatch*> att_batches;
InitialOptions att_initial_options; // Initial session options
DebugOptions att_debug_options;
Firebird::AutoPtr<ProfilerManager> att_profiler_manager; // ProfilerManager
Lock* att_repl_lock; // Replication set lock
JProvider* att_provider; // Provider which created this attachment

View File

@ -60,6 +60,9 @@ using namespace Firebird;
using namespace Jrd;
static EngineCheckout::Type checkoutType(IExternalEngine* engine);
namespace
{
// Internal message node.
@ -481,8 +484,6 @@ namespace
}
namespace Jrd {
template <typename T> class ExtEngineManager::ContextManager
{
public:
@ -560,7 +561,7 @@ private:
char charSetName[MAX_SQL_IDENTIFIER_SIZE];
{ // scope
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
FbLocalStatus status;
obj->getCharSet(&status, attInfo->context, charSetName, MAX_SQL_IDENTIFIER_LEN);
@ -740,7 +741,7 @@ void ExtEngineManager::Function::execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* o
CallerName(obj_udf, udf->getName().identifier, userName) :
CallerName(obj_package_header, udf->getName().package, userName)));
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
FbLocalStatus status;
function->execute(&status, attInfo->context, inMsg, outMsg);
@ -796,7 +797,7 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* out
charSet = attachment->att_charset;
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
FbLocalStatus status;
resultSet = procedure->procedure->open(&status, attInfo->context, inMsg, outMsg);
@ -808,7 +809,7 @@ ExtEngineManager::ResultSet::~ResultSet()
{
if (resultSet)
{
EngineCheckout cout(JRD_get_thread_data(), FB_FUNCTION);
EngineCheckout cout(JRD_get_thread_data(), FB_FUNCTION, checkoutType(attInfo->engine));
resultSet->dispose();
}
}
@ -828,7 +829,7 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb)
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
CallerName(obj_package_header, procedure->prc->getName().package, userName)));
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
FbLocalStatus status;
bool ret = resultSet->fetch(&status);
@ -918,7 +919,7 @@ void ExtEngineManager::Trigger::execute(thread_db* tdbb, Request* request, unsig
setValues(tdbb, request, newMsg, newRpb);
{ // scope
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
FbLocalStatus status;
trigger->execute(&status, attInfo->context, action,
@ -1236,7 +1237,7 @@ void ExtEngineManager::closeAttachment(thread_db* tdbb, Attachment* attachment)
enginesCopy.put(accessor.current()->first, accessor.current()->second);
}
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
EnginesMap::Accessor accessor(&enginesCopy);
for (bool found = accessor.getFirst(); found; found = accessor.getNext())
@ -1317,7 +1318,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
RefPtr<IMessageMetadata> extInputParameters, extOutputParameters;
{ // scope
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
externalFunction = attInfo->engine->makeFunction(&status, attInfo->context, metadata,
inBuilder, outBuilder);
@ -1408,7 +1409,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
}
catch (...)
{
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
externalFunction->dispose();
throw;
}
@ -1453,7 +1454,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
RefPtr<IMessageMetadata> extInputParameters, extOutputParameters;
{ // scope
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
externalProcedure = attInfo->engine->makeProcedure(&status, attInfo->context, metadata,
inBuilder, outBuilder);
@ -1551,7 +1552,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
}
catch (...)
{
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
externalProcedure->dispose();
throw;
}
@ -1612,7 +1613,7 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T
IExternalTrigger* externalTrigger;
{ // scope
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
FbLocalStatus status;
externalTrigger = attInfo->engine->makeTrigger(&status, attInfo->context, metadata,
@ -1650,7 +1651,7 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T
}
catch (...)
{
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
externalTrigger->dispose();
throw;
}
@ -1759,7 +1760,7 @@ ExtEngineManager::EngineAttachmentInfo* ExtEngineManager::getEngineAttachment(
enginesAttachments.put(key, attInfo);
ContextManager<IExternalFunction> ctxManager(tdbb, attInfo, attInfo->adminCharSet);
EngineCheckout cout(tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
FbLocalStatus status;
engine->openAttachment(&status, attInfo->context); //// FIXME: log status
}
@ -1802,4 +1803,10 @@ void ExtEngineManager::setupAdminCharSet(thread_db* tdbb, IExternalEngine* engin
}
} // namespace Jrd
//---------------------
static EngineCheckout::Type checkoutType(IExternalEngine* engine)
{
return engine == SystemEngine::INSTANCE ? EngineCheckout::AVOID : EngineCheckout::REQUIRED;
}

View File

@ -111,7 +111,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
while (readers > 0 )
{
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
noReaders.wait(counterMutex);
}
@ -120,7 +120,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
while (currentWriter || pendingLock)
{
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
writerFinished.wait(counterMutex);
}
@ -237,7 +237,7 @@ bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
while (pendingWriters > 0 || currentWriter)
{
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
writerFinished.wait(counterMutex);
}
@ -248,7 +248,7 @@ bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
break;
MutexUnlockGuard cout(counterMutex, FB_FUNCTION);
EngineCheckout cout2(tdbb, FB_FUNCTION, true);
EngineCheckout cout2(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
Thread::yield();
}

1241
src/jrd/ProfilerManager.cpp Normal file

File diff suppressed because it is too large Load Diff

267
src/jrd/ProfilerManager.h Normal file
View File

@ -0,0 +1,267 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2020 Adriano dos Santos Fernandes <adrianosf@gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef JRD_PROFILER_MANAGER_H
#define JRD_PROFILER_MANAGER_H
#include "firebird.h"
#include "firebird/Message.h"
#include "../common/classes/auto.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/Nullable.h"
#include "../common/classes/RefCounted.h"
#include "../common/classes/TimerImpl.h"
#include "../jrd/SystemPackages.h"
namespace Jrd {
class Attachment;
class Request;
class RecordSource;
class thread_db;
class ProfilerListener;
class ProfilerManager final
{
friend class ProfilerListener;
friend class ProfilerPackage;
public:
class Stats final : public Firebird::IProfilerStatsImpl<Stats, Firebird::ThrowStatusExceptionWrapper>
{
public:
explicit Stats(FB_UINT64 aElapsedTime)
: elapsedTime(aElapsedTime)
{}
public:
FB_UINT64 getElapsedTime() override
{
return elapsedTime;
}
private:
FB_UINT64 elapsedTime = 0;
};
private:
class Statement final
{
public:
Statement(MemoryPool& pool)
: cursorNextSequence(pool),
recSourceSequence(pool)
{
}
Statement(const Statement&) = delete;
void operator=(const Statement&) = delete;
SINT64 id = 0;
Firebird::NonPooledMap<ULONG, ULONG> cursorNextSequence;
Firebird::NonPooledMap<ULONG, ULONG> recSourceSequence;
};
class Session final
{
public:
Session(MemoryPool& pool)
: statements(pool),
requests(pool)
{
}
Session(const Session&) = delete;
void operator=(const Session&) = delete;
Firebird::AutoPlugin<Firebird::IProfilerPlugin> plugin;
Firebird::AutoDispose<Firebird::IProfilerSession> pluginSession;
Firebird::RightPooledMap<StmtNumber, Statement> statements;
Firebird::SortedArray<StmtNumber> requests;
unsigned flags = 0;
};
private:
ProfilerManager(thread_db* tdbb);
public:
~ProfilerManager();
public:
static ProfilerManager* create(thread_db* tdbb);
static int blockingAst(void* astObject);
ProfilerManager(const ProfilerManager&) = delete;
void operator=(const ProfilerManager&) = delete;
public:
SINT64 startSession(thread_db* tdbb, Nullable<SLONG> flushInterval,
const Firebird::PathName& pluginName, const Firebird::string& description, const Firebird::string& options);
void prepareRecSource(thread_db* tdbb, Request* request, const RecordSource* rsb);
void onRequestFinish(Request* request, Stats& stats);
void beforePsqlLineColumn(Request* request, ULONG line, ULONG column);
void afterPsqlLineColumn(Request* request, ULONG line, ULONG column, Stats& stats);
void beforeRecordSourceOpen(Request* request, const RecordSource* rsb);
void afterRecordSourceOpen(Request* request, const RecordSource* rsb, Stats& stats);
void beforeRecordSourceGetRecord(Request* request, const RecordSource* rsb);
void afterRecordSourceGetRecord(Request* request, const RecordSource* rsb, Stats& stats);
bool isActive() const
{
return currentSession && !paused;
}
static void checkFlushInterval(SLONG interval)
{
if (interval < 0)
{
Firebird::status_exception::raise(
Firebird::Arg::Gds(isc_not_valid_for_var) <<
"FLUSH_INTERVAL" <<
Firebird::Arg::Num(interval));
}
}
private:
void cancelSession();
void finishSession(thread_db* tdbb, bool flushData);
void pauseSession(bool flushData);
void resumeSession();
void setFlushInterval(SLONG interval);
void discard();
void flush(bool updateTimer = true);
void updateFlushTimer(bool canStopTimer = true);
Statement* getStatement(Request* request);
SINT64 getRequest(Request* request, unsigned flags);
private:
Firebird::AutoPtr<ProfilerListener> listener;
Firebird::LeftPooledMap<Firebird::PathName, Firebird::AutoPlugin<Firebird::IProfilerPlugin>> activePlugins;
Firebird::AutoPtr<Session> currentSession;
Firebird::RefPtr<Firebird::TimerImpl> flushTimer;
unsigned currentFlushInterval = 0;
bool paused = false;
};
class ProfilerPackage final : public SystemPackage
{
friend class ProfilerListener;
friend class ProfilerManager;
public:
ProfilerPackage(Firebird::MemoryPool& pool);
ProfilerPackage(const ProfilerPackage&) = delete;
ProfilerPackage& operator=(const ProfilerPackage&) = delete;
private:
FB_MESSAGE(AttachmentIdMessage, Firebird::ThrowStatusExceptionWrapper,
(FB_BIGINT, attachmentId)
);
//----------
using DiscardInput = AttachmentIdMessage;
static Firebird::IExternalResultSet* discardProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const DiscardInput::Type* in, void* out);
//----------
using FlushInput = AttachmentIdMessage;
static Firebird::IExternalResultSet* flushProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const FlushInput::Type* in, void* out);
//----------
using CancelSessionInput = AttachmentIdMessage;
static Firebird::IExternalResultSet* cancelSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const CancelSessionInput::Type* in, void* out);
//----------
FB_MESSAGE(FinishSessionInput, Firebird::ThrowStatusExceptionWrapper,
(FB_BOOLEAN, flush)
(FB_BIGINT, attachmentId)
);
static Firebird::IExternalResultSet* finishSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const FinishSessionInput::Type* in, void* out);
//----------
FB_MESSAGE(PauseSessionInput, Firebird::ThrowStatusExceptionWrapper,
(FB_BOOLEAN, flush)
(FB_BIGINT, attachmentId)
);
static Firebird::IExternalResultSet* pauseSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const PauseSessionInput::Type* in, void* out);
//----------
using ResumeSessionInput = AttachmentIdMessage;
static Firebird::IExternalResultSet* resumeSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const ResumeSessionInput::Type* in, void* out);
//----------
FB_MESSAGE(SetFlushIntervalInput, Firebird::ThrowStatusExceptionWrapper,
(FB_INTEGER, flushInterval)
(FB_BIGINT, attachmentId)
);
static Firebird::IExternalResultSet* setFlushIntervalProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const SetFlushIntervalInput::Type* in, void* out);
//----------
FB_MESSAGE(StartSessionInput, Firebird::ThrowStatusExceptionWrapper,
(FB_INTL_VARCHAR(255, CS_METADATA), description)
(FB_INTEGER, flushInterval)
(FB_BIGINT, attachmentId)
(FB_INTL_VARCHAR(255, CS_METADATA), pluginName)
(FB_INTL_VARCHAR(255, CS_METADATA), pluginOptions)
);
FB_MESSAGE(StartSessionOutput, Firebird::ThrowStatusExceptionWrapper,
(FB_BIGINT, sessionId)
);
static void startSessionFunction(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const StartSessionInput::Type* in, StartSessionOutput::Type* out);
};
} // namespace
#endif // JRD_PROFILER_MANAGER_H

View File

@ -336,6 +336,8 @@ Statement* Statement::makeStatement(thread_db* tdbb, CompilerScratch* csb, bool
attachment->att_statements.add(statement);
tdbb->getAttachment()->att_statements.add(statement);
return statement;
}
@ -693,10 +695,7 @@ void Statement::release(thread_db* tdbb)
const auto attachment = tdbb->getAttachment();
FB_SIZE_T pos;
if (attachment->att_statements.find(this, pos))
attachment->att_statements.remove(pos);
else
if (!attachment->att_statements.findAndRemove(this))
fb_assert(false);
sqlText = NULL;
@ -714,7 +713,7 @@ string Statement::getPlan(thread_db* tdbb, bool detailed) const
for (const auto rsb : fors)
{
plan += detailed ? "\nSelect Expression" : "\nPLAN ";
rsb->print(tdbb, plan, detailed, 0);
rsb->print(tdbb, plan, detailed, 0, true);
}
return plan;

View File

@ -23,6 +23,7 @@
#include "firebird.h"
#include "../jrd/SystemPackages.h"
#include "../jrd/TimeZone.h"
#include "../jrd/ProfilerManager.h"
using namespace Firebird;
using namespace Jrd;
@ -36,6 +37,7 @@ namespace
: list(FB_NEW_POOL(pool) ObjectsArray<SystemPackage>(pool))
{
list->add(TimeZonePackage(pool));
list->add(ProfilerPackage(pool));
}
static InitInstance<SystemPackagesInit> INSTANCE;

View File

@ -30,6 +30,7 @@
#include "../common/classes/objects_array.h"
#include "../jrd/constants.h"
#include "../jrd/ini.h"
#include "../jrd/jrd.h"
#include "firebird/Interface.h"
#include <initializer_list>
#include <functional>
@ -236,6 +237,41 @@ namespace Jrd
>
struct SystemProcedureFactory
{
class SystemResultSet :
public
Firebird::DisposeIface<
Firebird::IExternalResultSetImpl<
SystemResultSet,
Firebird::ThrowStatusExceptionWrapper
>
>
{
public:
SystemResultSet(Attachment* aAttachment, Firebird::IExternalResultSet* aResultSet)
: attachment(aAttachment),
resultSet(aResultSet)
{
}
public:
void dispose() override
{
delete this;
}
public:
FB_BOOLEAN fetch(Firebird::ThrowStatusExceptionWrapper* status) override
{
Firebird::AutoSetRestore<bool> autoInSystemPackage(&attachment->att_in_system_routine, true);
return resultSet->fetch(status);
}
private:
Attachment* attachment;
Firebird::AutoDispose<Firebird::IExternalResultSet> resultSet;
};
class SystemProcedureImpl :
public
Firebird::DisposeIface<
@ -249,6 +285,9 @@ namespace Jrd
SystemProcedureImpl(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IMetadataBuilder* inBuilder, Firebird::IMetadataBuilder* outBuilder)
{
const auto tdbb = JRD_get_thread_data();
attachment = tdbb->getAttachment();
Input::setup(status, inBuilder);
Output::setup(status, outBuilder);
}
@ -269,10 +308,17 @@ namespace Jrd
Firebird::IExternalResultSet* open(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, void* inMsg, void* outMsg) override
{
return OpenFunction(status, context,
Firebird::AutoSetRestore<bool> autoInSystemPackage(&attachment->att_in_system_routine, true);
const auto resultSet = OpenFunction(status, context,
static_cast<typename Input::Type*>(inMsg),
static_cast<typename Output::Type*>(outMsg));
return resultSet ? FB_NEW SystemResultSet(attachment, resultSet) : nullptr;
}
private:
Attachment* attachment;
};
SystemProcedureImpl* operator()(
@ -311,6 +357,9 @@ namespace Jrd
SystemFunctionImpl(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IMetadataBuilder* inBuilder, Firebird::IMetadataBuilder* outBuilder)
{
const auto tdbb = JRD_get_thread_data();
attachment = tdbb->getAttachment();
Input::setup(status, inBuilder);
Output::setup(status, outBuilder);
}
@ -325,10 +374,15 @@ namespace Jrd
void execute(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, void* inMsg, void* outMsg) override
{
Firebird::AutoSetRestore<bool> autoInSystemPackage(&attachment->att_in_system_routine, true);
ExecFunction(status, context,
static_cast<typename Input::Type*>(inMsg),
static_cast<typename Output::Type*>(outMsg));
}
private:
Attachment* attachment;
};
SystemFunctionImpl* operator()(

View File

@ -65,6 +65,7 @@ SYSTEM_PRIVILEGE(CREATE_PRIVILEGED_ROLES)
SYSTEM_PRIVILEGE(GET_DBCRYPT_INFO)
SYSTEM_PRIVILEGE(MODIFY_EXT_CONN_POOL)
SYSTEM_PRIVILEGE(REPLICATE_INTO_DATABASE)
SYSTEM_PRIVILEGE(PROFILE_ANY_ATTACHMENT)
#ifdef FB_JRD_SYSTEM_PRIVILEGES_TMP
maxSystemPrivilege

View File

@ -518,6 +518,8 @@ RecordSource* CMP_post_rse(thread_db* tdbb, CompilerScratch* csb, RseNode* rse)
**************************************/
SET_TDBB(tdbb);
AutoSetRestore<ULONG> autoCurrentCursorProfileId(&csb->csb_currentCursorProfileId, csb->csb_nextCursorProfileId++);
const auto rsb = Optimizer::compile(tdbb, csb, rse);
// Mark all the substreams as inactive

View File

@ -109,6 +109,7 @@
#include "../jrd/recsrc/RecordSource.h"
#include "../jrd/recsrc/Cursor.h"
#include "../jrd/Function.h"
#include "../jrd/ProfilerManager.h"
using namespace Jrd;
@ -899,6 +900,8 @@ void EXE_start(thread_db* tdbb, Request* request, jrd_tra* transaction)
request->req_records_affected.clear();
request->req_profiler_time = 0;
// Store request start time for timestamp work
request->validateTimeStamp();
@ -988,6 +991,14 @@ void EXE_unwind(thread_db* tdbb, Request* request)
}
release_blobs(tdbb, request);
const auto attachment = request->req_attachment;
if (attachment->isProfilerActive() && !request->hasInternalStatement())
{
ProfilerManager::Stats stats(request->req_profiler_time);
attachment->getProfilerManager(tdbb)->onRequestFinish(request, stats);
}
}
request->req_sorts.unlinkAll();
@ -1363,10 +1374,10 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
ERR_post(Arg::Gds(isc_req_no_trans));
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
const auto dbb = tdbb->getDatabase();
const auto attachment = tdbb->getAttachment();
// ASF: It's already a StmtNode, so do not do a virtual call in execution.
if (!node) /// if (!node || node->getKind() != DmlNode::KIND_STATEMENT
if (!node)
BUGCHECK(147);
// Save the old pool and request to restore on exit
@ -1380,6 +1391,25 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
// Execute stuff until we drop
SINT64 initialPerfCounter = fb_utils::query_performance_counter();
SINT64 lastPerfCounter = initialPerfCounter;
const StmtNode* profileNode = nullptr;
const auto profilerCallAfterPsqlLineColumn = [&] {
const SINT64 currentPerfCounter = fb_utils::query_performance_counter();
if (profileNode)
{
ProfilerManager::Stats stats(currentPerfCounter - lastPerfCounter);
attachment->getProfilerManager(tdbb)->afterPsqlLineColumn(request,
profileNode->line, profileNode->column,
stats);
}
return currentPerfCounter;
};
while (node && !(request->req_flags & req_stall))
{
try
@ -1393,12 +1423,33 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
request->req_src_line = node->line;
request->req_src_column = node->column;
}
if (attachment->isProfilerActive() && !request->hasInternalStatement())
{
if (node->hasLineColumn &&
node->isProfileAware() &&
(!profileNode ||
!(node->line == profileNode->line && node->column == profileNode->column)))
{
lastPerfCounter = profilerCallAfterPsqlLineColumn();
profileNode = node;
attachment->getProfilerManager(tdbb)->beforePsqlLineColumn(request,
profileNode->line, profileNode->column);
}
}
}
node = node->execute(tdbb, request, &exeState);
if (exeState.exit)
{
if (attachment->isProfilerActive() && !request->hasInternalStatement())
request->req_profiler_time += profilerCallAfterPsqlLineColumn() - initialPerfCounter;
return node;
}
} // try
catch (const Firebird::Exception& ex)
{
@ -1437,6 +1488,9 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
}
} // while()
if (attachment->isProfilerActive() && !request->hasInternalStatement())
request->req_profiler_time += profilerCallAfterPsqlLineColumn() - initialPerfCounter;
request->adjustCallerStats();
fb_assert(request->req_auto_trans.getCount() == 0);
@ -1461,6 +1515,12 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
request->req_flags &= ~(req_active | req_reserved);
request->invalidateTimeStamp();
release_blobs(tdbb, request);
if (attachment->isProfilerActive() && !request->hasInternalStatement())
{
ProfilerManager::Stats stats(request->req_profiler_time);
attachment->getProfilerManager(tdbb)->onRequestFinish(request, stats);
}
}
request->req_next = node;

View File

@ -592,6 +592,10 @@ public:
ExprNode* csb_currentAssignTarget;
dsc* csb_preferredDesc; // expected by receiving side data format
ULONG csb_currentCursorProfileId = 0;
ULONG csb_nextCursorProfileId = 1;
ULONG csb_nextRecSourceProfileId = 1;
struct csb_repeat
{
// We must zero-initialize this one

View File

@ -223,3 +223,7 @@
FIELD(fld_keyword_name , nam_keyword_name , dtype_varying , METADATA_IDENTIFIER_CHAR_LEN, dsc_text_type_ascii , NULL , false)
FIELD(fld_keyword_reserved, nam_keyword_reserved, dtype_boolean, 1 , 0 , NULL , false)
FIELD(fld_short_description, nam_short_description, dtype_varying, 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata, NULL , true)
FIELD(fld_seconds_interval, nam_seconds_interval, dtype_long, sizeof(SLONG) , 0 , NULL , true)
FIELD(fld_prof_ses_id , nam_prof_ses_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true)

View File

@ -722,118 +722,6 @@ namespace
validateHandle(tdbb, applier->getAttachment());
}
class AttachmentHolder
{
public:
static const unsigned ATT_LOCK_ASYNC = 1;
static const unsigned ATT_DONT_LOCK = 2;
static const unsigned ATT_NO_SHUTDOWN_CHECK = 4;
static const unsigned ATT_NON_BLOCKING = 8;
AttachmentHolder(thread_db* tdbb, StableAttachmentPart* sa, unsigned lockFlags, const char* from)
: sAtt(sa),
async(lockFlags & ATT_LOCK_ASYNC),
nolock(lockFlags & ATT_DONT_LOCK),
blocking(!(lockFlags & ATT_NON_BLOCKING))
{
if (!sa)
Arg::Gds(isc_att_shutdown).raise();
if (blocking)
sAtt->getBlockingMutex()->enter(from);
try
{
if (!nolock)
sAtt->getSync(async)->enter(from);
Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex
try
{
if (!attachment || (engineShutdown && !(lockFlags & ATT_NO_SHUTDOWN_CHECK)))
{
// This shutdown check is an optimization, threads can still enter engine
// with the flag set cause shutdownMutex mutex is not locked here.
// That's not a danger cause check of att_use_count
// in shutdown code makes it anyway safe.
Arg::Gds err(isc_att_shutdown);
if (sAtt->getShutError())
err << Arg::Gds(sAtt->getShutError());
err.raise();
}
tdbb->setAttachment(attachment);
tdbb->setDatabase(attachment->att_database);
if (!async)
{
attachment->att_use_count++;
attachment->setupIdleTimer(true);
}
}
catch (const Firebird::Exception&)
{
if (!nolock)
sAtt->getSync(async)->leave();
throw;
}
}
catch (const Firebird::Exception&)
{
if (blocking)
sAtt->getBlockingMutex()->leave();
throw;
}
}
~AttachmentHolder()
{
Jrd::Attachment* attachment = sAtt->getHandle();
if (attachment && !async)
{
attachment->att_use_count--;
if (!attachment->att_use_count)
attachment->setupIdleTimer(false);
}
if (!nolock)
sAtt->getSync(async)->leave();
if (blocking)
sAtt->getBlockingMutex()->leave();
}
private:
RefPtr<StableAttachmentPart> sAtt;
bool async; // async mutex should be locked instead normal
bool nolock; // if locked manually, no need to take lock recursively
bool blocking; // holder instance is blocking other instances
private:
// copying is prohibited
AttachmentHolder(const AttachmentHolder&);
AttachmentHolder& operator =(const AttachmentHolder&);
};
class EngineContextHolder : public ThreadContextHolder, private AttachmentHolder,
private DatabaseContextHolder
{
public:
template <typename I>
EngineContextHolder(CheckStatusWrapper* status, I* interfacePtr, const char* from,
unsigned lockFlags = 0)
: ThreadContextHolder(status),
AttachmentHolder(*this, interfacePtr->getAttachment(), lockFlags, from),
DatabaseContextHolder(operator thread_db*())
{
validateHandle(*this, interfacePtr->getHandle());
}
};
void validateAccess(thread_db* tdbb, Jrd::Attachment* attachment, SystemPrivilege sp)
{
if (!attachment->locksmith(tdbb, sp))
@ -877,6 +765,98 @@ namespace
} // anonymous
AttachmentHolder::AttachmentHolder(thread_db* tdbb, StableAttachmentPart* sa, unsigned lockFlags, const char* from)
: sAtt(sa),
async(lockFlags & ATT_LOCK_ASYNC),
nolock(lockFlags & ATT_DONT_LOCK),
blocking(!(lockFlags & ATT_NON_BLOCKING))
{
if (!sa)
Arg::Gds(isc_att_shutdown).raise();
if (blocking)
sAtt->getBlockingMutex()->enter(from);
try
{
if (!nolock)
sAtt->getSync(async)->enter(from);
Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex
try
{
if (!attachment || (engineShutdown && !(lockFlags & ATT_NO_SHUTDOWN_CHECK)))
{
// This shutdown check is an optimization, threads can still enter engine
// with the flag set cause shutdownMutex mutex is not locked here.
// That's not a danger cause check of att_use_count
// in shutdown code makes it anyway safe.
Arg::Gds err(isc_att_shutdown);
if (sAtt->getShutError())
err << Arg::Gds(sAtt->getShutError());
err.raise();
}
tdbb->setAttachment(attachment);
tdbb->setDatabase(attachment->att_database);
if (!async)
{
attachment->att_use_count++;
attachment->setupIdleTimer(true);
}
}
catch (const Firebird::Exception&)
{
if (!nolock)
sAtt->getSync(async)->leave();
throw;
}
}
catch (const Firebird::Exception&)
{
if (blocking)
sAtt->getBlockingMutex()->leave();
throw;
}
}
AttachmentHolder::~AttachmentHolder()
{
Jrd::Attachment* attachment = sAtt->getHandle();
if (attachment && !async)
{
attachment->att_use_count--;
if (!attachment->att_use_count)
attachment->setupIdleTimer(false);
}
if (!nolock)
sAtt->getSync(async)->leave();
if (blocking)
sAtt->getBlockingMutex()->leave();
}
template <typename I>
EngineContextHolder::EngineContextHolder(CheckStatusWrapper* status, I* interfacePtr, const char* from,
unsigned lockFlags)
: ThreadContextHolder(status),
AttachmentHolder(*this, interfacePtr->getAttachment(), lockFlags, from),
DatabaseContextHolder(operator thread_db*())
{
validateHandle(*this, interfacePtr->getHandle());
}
// Used in ProfilerManager.cpp
template EngineContextHolder::EngineContextHolder(
CheckStatusWrapper* status, JAttachment* interfacePtr, const char* from, unsigned lockFlags);
#ifdef WIN_NT
#include <windows.h>
// these should stop a most annoying warning
@ -956,7 +936,7 @@ void Trigger::compile(thread_db* tdbb)
statement->triggerInvoker = att->getUserId(owner);
if (sysTrigger)
statement->flags |= Statement::FLAG_SYS_TRIGGER;
statement->flags |= Statement::FLAG_SYS_TRIGGER | Statement::FLAG_INTERNAL;
if (flags & TRG_ignore_perm)
statement->flags |= Statement::FLAG_IGNORE_PERM;
@ -5188,7 +5168,7 @@ ITransaction* JAttachment::execute(CheckStatusWrapper* user_status, ITransaction
DSQL_execute_immediate(tdbb, getHandle(), &tra, length, string, dialect,
inMetadata, static_cast<UCHAR*>(inBuffer),
outMetadata, static_cast<UCHAR*>(outBuffer),
false);
getHandle()->att_in_system_routine);
jt = checkTranIntf(getStable(), jt, tra);
}
@ -5628,7 +5608,7 @@ JStatement* JAttachment::prepare(CheckStatusWrapper* user_status, ITransaction*
StatementMetadata::buildInfoItems(items, flags);
statement = DSQL_prepare(tdbb, getHandle(), tra, stmtLength, sqlStmt, dialect, flags,
&items, &buffer, false);
&items, &buffer, getHandle()->att_in_system_routine);
rc = FB_NEW JStatement(statement, getStable(), buffer);
rc->addRef();
@ -7642,6 +7622,8 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment, XThreadEns
if (!attachment)
return;
attachment->releaseProfilerManager();
attachment->att_replicator = nullptr;
if (attachment->att_dsql_instance)

View File

@ -1034,6 +1034,37 @@ namespace Jrd {
BackgroundContextHolder& operator=(const BackgroundContextHolder&);
};
class AttachmentHolder
{
public:
static const unsigned ATT_LOCK_ASYNC = 1;
static const unsigned ATT_DONT_LOCK = 2;
static const unsigned ATT_NO_SHUTDOWN_CHECK = 4;
static const unsigned ATT_NON_BLOCKING = 8;
AttachmentHolder(thread_db* tdbb, StableAttachmentPart* sa, unsigned lockFlags, const char* from);
~AttachmentHolder();
private:
Firebird::RefPtr<StableAttachmentPart> sAtt;
bool async; // async mutex should be locked instead normal
bool nolock; // if locked manually, no need to take lock recursively
bool blocking; // holder instance is blocking other instances
private:
// copying is prohibited
AttachmentHolder(const AttachmentHolder&);
AttachmentHolder& operator =(const AttachmentHolder&);
};
class EngineContextHolder final : public ThreadContextHolder, private AttachmentHolder, private DatabaseContextHolder
{
public:
template <typename I>
EngineContextHolder(Firebird::CheckStatusWrapper* status, I* interfacePtr, const char* from,
unsigned lockFlags = 0);
};
class AstLockHolder : public Firebird::ReadLockGuard
{
public:
@ -1083,18 +1114,28 @@ namespace Jrd {
class EngineCheckout
{
public:
EngineCheckout(thread_db* tdbb, const char* from, bool optional = false)
enum Type
{
REQUIRED,
UNNECESSARY,
AVOID
};
EngineCheckout(thread_db* tdbb, const char* from, Type type = REQUIRED)
: m_tdbb(tdbb), m_from(from)
{
Attachment* const att = tdbb ? tdbb->getAttachment() : NULL;
if (type != AVOID)
{
Attachment* const att = tdbb ? tdbb->getAttachment() : NULL;
if (att)
m_ref = att->getStable();
if (att)
m_ref = att->getStable();
fb_assert(optional || m_ref.hasData());
fb_assert(type == UNNECESSARY || m_ref.hasData());
if (m_ref.hasData())
m_ref->getSync()->leave();
if (m_ref.hasData())
m_ref->getSync()->leave();
}
}
EngineCheckout(Attachment* att, const char* from, bool optional = false)
@ -1140,7 +1181,7 @@ namespace Jrd {
{
if (!m_mutex.tryEnter(from))
{
EngineCheckout cout(tdbb, from, optional);
EngineCheckout cout(tdbb, from, optional ? EngineCheckout::UNNECESSARY : EngineCheckout::REQUIRED);
m_mutex.enter(from);
}
}
@ -1168,7 +1209,7 @@ namespace Jrd {
{
if (!m_sync.lockConditional(type, from))
{
EngineCheckout cout(tdbb, from, optional);
EngineCheckout cout(tdbb, from, optional ? EngineCheckout::UNNECESSARY : EngineCheckout::REQUIRED);
m_sync.lock(type);
}
}

View File

@ -585,6 +585,7 @@ static lck_owner_t get_owner_type(enum lck_t lock_type)
case LCK_alter_database:
case LCK_repl_tables:
case LCK_dsql_statement_cache:
case LCK_profiler_listener:
owner_type = LCK_OWNER_attachment;
break;

View File

@ -75,7 +75,8 @@ enum lck_t {
LCK_alter_database, // ALTER DATABASE lock
LCK_repl_state, // Replication state lock
LCK_repl_tables, // Replication set lock
LCK_dsql_statement_cache // DSQL statement cache lock
LCK_dsql_statement_cache, // DSQL statement cache lock
LCK_profiler_listener // Remote profiler listener
};
// Lock owner types

View File

@ -3225,7 +3225,7 @@ void MET_parse_sys_trigger(thread_db* tdbb, jrd_rel* relation)
statement->triggerName = name;
statement->flags |= Statement::FLAG_SYS_TRIGGER;
statement->flags |= Statement::FLAG_SYS_TRIGGER | Statement::FLAG_INTERNAL;
if (trig_flags & TRG_ignore_perm)
statement->flags |= Statement::FLAG_IGNORE_PERM;

View File

@ -460,3 +460,7 @@ NAME("RDB$KEYWORD_RESERVED", nam_keyword_reserved)
NAME("MON$COMPILED_STATEMENTS", nam_mon_compiled_statements)
NAME("MON$COMPILED_STATEMENT_ID", nam_mon_cmp_stmt_id)
NAME("RDB$SHORT_DESCRIPTION", nam_short_description)
NAME("RDB$SECONDS_INTERVAL", nam_seconds_interval)
NAME("RDB$PROFILE_SESSION_ID", nam_prof_ses_id)

53
src/jrd/opt_proto.h Normal file
View File

@ -0,0 +1,53 @@
/*
* PROGRAM: JRD Access Method
* MODULE: opt_proto.h
* DESCRIPTION: Prototype header file for opt.cpp
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef JRD_OPT_PROTO_H
#define JRD_OPT_PROTO_H
#include "../jrd/jrd.h"
#include "../jrd/btr.h"
#include "../jrd/lls.h"
namespace Jrd {
class Request;
class jrd_rel;
class RecordSource;
struct index_desc;
class CompilerScratch;
class OptimizerBlk;
class SortedStream;
class SortNode;
class MapNode;
}
Firebird::string OPT_get_plan(Jrd::thread_db* tdbb, const Jrd::Statement* statement, bool detailed);
Jrd::RecordSource* OPT_compile(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb,
Jrd::RseNode* rse, Jrd::BoolExprNodeStack* parent_stack);
void OPT_compile_relation(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, Jrd::CompilerScratch* csb,
StreamType stream, bool needIndices);
void OPT_gen_aggregate_distincts(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb, Jrd::MapNode* map);
Jrd::SortedStream* OPT_gen_sort(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb, const Jrd::StreamList& streams,
const Jrd::StreamList* dbkey_streams, Jrd::RecordSource* prior_rsb, Jrd::SortNode* sort,
bool refetch_flag, bool project_flag);
#endif // JRD_OPT_PROTO_H

View File

@ -318,7 +318,7 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
#if defined(HAVE_LINUX_FALLOC_H) && defined(HAVE_FALLOCATE)
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
ULONG leftPages = extPages;
for (jrd_file* file = main_file; file && leftPages; file = file->fil_next)
@ -388,7 +388,7 @@ void PIO_flush(thread_db* tdbb, jrd_file* main_file)
// Since all SUPERSERVER_V2 database and shadow I/O is synchronous, this is a no-op.
#ifndef SUPERSERVER_V2
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
MutexLockGuard guard(main_file->fil_mutex, FB_FUNCTION);
for (jrd_file* file = main_file; file; file = file->fil_next)
@ -608,7 +608,7 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
FB_UINT64 offset;
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
jrd_file* file = seek_file(main_file, &bdb, &offset, status_vector);
@ -756,7 +756,7 @@ bool PIO_read(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
Database* const dbb = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
const SLONG size = dbb->dbb_page_size;
@ -808,7 +808,7 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
Database* const dbb = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
const SLONG size = dbb->dbb_page_size;

View File

@ -270,7 +270,7 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
if (!main_file->fil_ext_lock)
return;
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
FileExtendLockGuard extLock(main_file->fil_ext_lock, true);
ULONG leftPages = extPages;
@ -314,7 +314,7 @@ void PIO_flush(thread_db* tdbb, jrd_file* main_file)
* Flush the operating system cache back to good, solid oxide.
*
**************************************/
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
for (jrd_file* file = main_file; file; file = file->fil_next)
FlushFileBuffers(file->fil_desc);
@ -440,7 +440,7 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
Database* const dbb = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
FileExtendLockGuard extLock(main_file->fil_ext_lock, false);
// Fake buffer, used in seek_file. Page space ID doesn't matter there
@ -578,7 +578,7 @@ bool PIO_read(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
const DWORD size = dbb->dbb_page_size;
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
FileExtendLockGuard extLock(file->fil_ext_lock, false);
OVERLAPPED overlapped;
@ -626,7 +626,7 @@ bool PIO_read_ahead(thread_db* tdbb,
Database* const dbb = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
// If an I/O status block was passed the caller wants to queue an asynchronous I/O.
@ -712,7 +712,7 @@ bool PIO_status(thread_db* tdbb, phys_io_blk* piob, FbStatusVector* status_vecto
* Check the status of an asynchronous I/O.
*
**************************************/
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
if (!(piob->piob_flags & PIOB_success))
{
@ -755,7 +755,7 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
const DWORD size = dbb->dbb_page_size;
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
FileExtendLockGuard extLock(file->fil_ext_lock, false);
OVERLAPPED overlapped;

View File

@ -63,7 +63,7 @@ BaseAggWinStream<ThisType, NextType>::BaseAggWinStream(thread_db* tdbb, Compiler
}
template <typename ThisType, typename NextType>
void BaseAggWinStream<ThisType, NextType>::open(thread_db* tdbb) const
void BaseAggWinStream<ThisType, NextType>::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = getImpure(request);
@ -376,7 +376,12 @@ AggregatedStream::AggregatedStream(thread_db* tdbb, CompilerScratch* csb, Stream
fb_assert(map);
}
void AggregatedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void AggregatedStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void AggregatedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
@ -384,10 +389,11 @@ void AggregatedStream::print(thread_db* tdbb, string& plan, bool detailed, unsig
printOptInfo(plan);
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
bool AggregatedStream::getRecord(thread_db* tdbb) const
bool AggregatedStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);

View File

@ -47,7 +47,7 @@ BitmapTableScan::BitmapTableScan(CompilerScratch* csb, const string& alias,
m_cardinality = csb->csb_rpt[stream].csb_cardinality * selectivity;
}
void BitmapTableScan::open(thread_db* tdbb) const
void BitmapTableScan::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -81,7 +81,7 @@ void BitmapTableScan::close(thread_db* tdbb) const
}
}
bool BitmapTableScan::getRecord(thread_db* tdbb) const
bool BitmapTableScan::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -122,8 +122,12 @@ bool BitmapTableScan::getRecord(thread_db* tdbb) const
return false;
}
void BitmapTableScan::getChildren(Array<const RecordSource*>& children) const
{
}
void BitmapTableScan::print(thread_db* tdbb, string& plan,
bool detailed, unsigned level) const
bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{

View File

@ -40,7 +40,9 @@ using namespace Jrd;
// --------------------------
BufferedStream::BufferedStream(CompilerScratch* csb, RecordSource* next)
: m_next(next), m_map(csb->csb_pool)
: BaseBufferedStream(csb),
m_next(next),
m_map(csb->csb_pool)
{
fb_assert(m_next);
@ -113,7 +115,7 @@ BufferedStream::BufferedStream(CompilerScratch* csb, RecordSource* next)
m_format = format;
}
void BufferedStream::open(thread_db* tdbb) const
void BufferedStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -148,7 +150,7 @@ void BufferedStream::close(thread_db* tdbb) const
}
}
bool BufferedStream::getRecord(thread_db* tdbb) const
bool BufferedStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -312,7 +314,12 @@ bool BufferedStream::lockRecord(thread_db* tdbb) const
return m_next->lockRecord(tdbb);
}
void BufferedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void BufferedStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void BufferedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
@ -323,7 +330,8 @@ void BufferedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
printOptInfo(plan);
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void BufferedStream::markRecursive()

View File

@ -41,7 +41,10 @@ using namespace Jrd;
ConditionalStream::ConditionalStream(CompilerScratch* csb,
RecordSource* first, RecordSource* second,
BoolExprNode* boolean)
: m_first(first), m_second(second), m_boolean(boolean)
: RecordSource(csb),
m_first(first),
m_second(second),
m_boolean(boolean)
{
fb_assert(m_first && m_second && m_boolean);
@ -49,7 +52,7 @@ ConditionalStream::ConditionalStream(CompilerScratch* csb,
m_cardinality = (first->getCardinality() + second->getCardinality()) / 2;
}
void ConditionalStream::open(thread_db* tdbb) const
void ConditionalStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -76,7 +79,7 @@ void ConditionalStream::close(thread_db* tdbb) const
}
}
bool ConditionalStream::getRecord(thread_db* tdbb) const
bool ConditionalStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -111,26 +114,35 @@ bool ConditionalStream::lockRecord(thread_db* tdbb) const
return impure->irsb_next->lockRecord(tdbb);
}
void ConditionalStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void ConditionalStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_first);
children.add(m_second);
}
void ConditionalStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
plan += printIndent(++level) + "Condition";
printOptInfo(plan);
m_first->print(tdbb, plan, true, level);
m_second->print(tdbb, plan, true, level);
if (recurse)
{
m_first->print(tdbb, plan, true, level, recurse);
m_second->print(tdbb, plan, true, level, recurse);
}
}
else
{
if (!level)
plan += "(";
m_first->print(tdbb, plan, false, level + 1);
m_first->print(tdbb, plan, false, level + 1, recurse);
plan += ", ";
m_second->print(tdbb, plan, false, level + 1);
m_second->print(tdbb, plan, false, level + 1, recurse);
if (!level)
plan += ")";

View File

@ -23,6 +23,7 @@
#include "firebird.h"
#include "../jrd/jrd.h"
#include "../jrd/req.h"
#include "../jrd/ProfilerManager.h"
#include "../jrd/cmp_proto.h"
#include "RecordSource.h"
@ -105,7 +106,7 @@ Cursor::Cursor(CompilerScratch* csb, const RecordSource* rsb,
void Cursor::open(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
Impure* impure = request->getImpure<Impure>(m_impure);
impure->irsb_active = true;
@ -135,7 +136,7 @@ bool Cursor::fetchNext(thread_db* tdbb) const
if (!validate(tdbb))
return false;
Request* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
if (!impure->irsb_active)
@ -207,7 +208,7 @@ bool Cursor::fetchAbsolute(thread_db* tdbb, SINT64 offset) const
if (!validate(tdbb))
return false;
Request* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
if (!impure->irsb_active)
@ -268,7 +269,7 @@ bool Cursor::fetchRelative(thread_db* tdbb, SINT64 offset) const
if (!validate(tdbb))
return false;
Request* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
if (!impure->irsb_active)

View File

@ -45,7 +45,7 @@ ExternalTableScan::ExternalTableScan(CompilerScratch* csb, const string& alias,
m_cardinality = csb->csb_rpt[stream].csb_cardinality;
}
void ExternalTableScan::open(thread_db* tdbb) const
void ExternalTableScan::internalOpen(thread_db* tdbb) const
{
Database* const dbb = tdbb->getDatabase();
Request* const request = tdbb->getRequest();
@ -76,7 +76,7 @@ void ExternalTableScan::close(thread_db* tdbb) const
impure->irsb_flags &= ~irsb_open;
}
bool ExternalTableScan::getRecord(thread_db* tdbb) const
bool ExternalTableScan::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -116,8 +116,12 @@ bool ExternalTableScan::lockRecord(thread_db* tdbb) const
return false; // compiler silencer
}
void ExternalTableScan::getChildren(Array<const RecordSource*>& children) const
{
}
void ExternalTableScan::print(thread_db* tdbb, string& plan,
bool detailed, unsigned level) const
bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{

View File

@ -36,10 +36,14 @@ using namespace Jrd;
// Data access: predicate driven filter
// ------------------------------------
FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next,
BoolExprNode* boolean, double selectivity)
: m_next(next), m_boolean(boolean), m_anyBoolean(NULL),
m_ansiAny(false), m_ansiAll(false), m_ansiNot(false)
FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean, double selectivity)
: RecordSource(csb),
m_next(next),
m_boolean(boolean),
m_anyBoolean(NULL),
m_ansiAny(false),
m_ansiAll(false),
m_ansiNot(false)
{
fb_assert(m_next && m_boolean);
@ -50,7 +54,7 @@ FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next,
m_cardinality = cardinality * selectivity;
}
void FilteredStream::open(thread_db* tdbb) const
void FilteredStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -76,7 +80,7 @@ void FilteredStream::close(thread_db* tdbb) const
}
}
bool FilteredStream::getRecord(thread_db* tdbb) const
bool FilteredStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -108,7 +112,12 @@ bool FilteredStream::lockRecord(thread_db* tdbb) const
return m_next->lockRecord(tdbb);
}
void FilteredStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void FilteredStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void FilteredStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
@ -116,7 +125,8 @@ void FilteredStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
printOptInfo(plan);
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void FilteredStream::markRecursive()

View File

@ -38,7 +38,9 @@ using namespace Jrd;
// --------------------------------
FirstRowsStream::FirstRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value)
: m_next(next), m_value(value)
: RecordSource(csb),
m_next(next),
m_value(value)
{
fb_assert(m_next && m_value);
@ -50,7 +52,7 @@ FirstRowsStream::FirstRowsStream(CompilerScratch* csb, RecordSource* next, Value
valueConst->getSlong() : DEFAULT_CARDINALITY;
}
void FirstRowsStream::open(thread_db* tdbb) const
void FirstRowsStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -87,7 +89,7 @@ void FirstRowsStream::close(thread_db* tdbb) const
}
}
bool FirstRowsStream::getRecord(thread_db* tdbb) const
bool FirstRowsStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -118,7 +120,12 @@ bool FirstRowsStream::lockRecord(thread_db* tdbb) const
return m_next->lockRecord(tdbb);
}
void FirstRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void FirstRowsStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void FirstRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
@ -126,7 +133,8 @@ void FirstRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsign
printOptInfo(plan);
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void FirstRowsStream::markRecursive()

View File

@ -38,7 +38,9 @@ using namespace Jrd;
// ----------------------------
FullOuterJoin::FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSource* arg2)
: m_arg1(arg1), m_arg2(arg2)
: RecordSource(csb),
m_arg1(arg1),
m_arg2(arg2)
{
fb_assert(m_arg1 && m_arg2);
@ -46,7 +48,7 @@ FullOuterJoin::FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSou
m_cardinality = arg1->getCardinality() + arg2->getCardinality();
}
void FullOuterJoin::open(thread_db* tdbb) const
void FullOuterJoin::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -75,7 +77,7 @@ void FullOuterJoin::close(thread_db* tdbb) const
}
}
bool FullOuterJoin::getRecord(thread_db* tdbb) const
bool FullOuterJoin::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -111,21 +113,31 @@ bool FullOuterJoin::lockRecord(thread_db* tdbb) const
return false; // compiler silencer
}
void FullOuterJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void FullOuterJoin::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_arg1);
children.add(m_arg2);
}
void FullOuterJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
plan += printIndent(++level) + "Full Outer Join";
m_arg1->print(tdbb, plan, true, level);
m_arg2->print(tdbb, plan, true, level);
if (recurse)
{
m_arg1->print(tdbb, plan, true, level, recurse);
m_arg2->print(tdbb, plan, true, level, recurse);
}
}
else
{
level++;
plan += "JOIN (";
m_arg1->print(tdbb, plan, false, level);
m_arg1->print(tdbb, plan, false, level, recurse);
plan += ", ";
m_arg2->print(tdbb, plan, false, level);
m_arg2->print(tdbb, plan, false, level, recurse);
plan += ")";
}
}

View File

@ -48,7 +48,7 @@ FullTableScan::FullTableScan(CompilerScratch* csb, const string& alias,
m_cardinality = csb->csb_rpt[stream].csb_cardinality;
}
void FullTableScan::open(thread_db* tdbb) const
void FullTableScan::internalOpen(thread_db* tdbb) const
{
Database* const dbb = tdbb->getDatabase();
Attachment* const attachment = tdbb->getAttachment();
@ -132,7 +132,7 @@ void FullTableScan::close(thread_db* tdbb) const
}
}
bool FullTableScan::getRecord(thread_db* tdbb) const
bool FullTableScan::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -162,7 +162,11 @@ bool FullTableScan::getRecord(thread_db* tdbb) const
return false;
}
void FullTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void FullTableScan::getChildren(Array<const RecordSource*>& children) const
{
}
void FullTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{

View File

@ -219,7 +219,8 @@ private:
HashJoin::HashJoin(thread_db* tdbb, CompilerScratch* csb, FB_SIZE_T count,
RecordSource* const* args, NestValueArray* const* keys)
: m_args(csb->csb_pool, count - 1)
: RecordSource(csb),
m_args(csb->csb_pool, count - 1)
{
fb_assert(count >= 2);
@ -296,7 +297,7 @@ HashJoin::HashJoin(thread_db* tdbb, CompilerScratch* csb, FB_SIZE_T count,
}
}
void HashJoin::open(thread_db* tdbb) const
void HashJoin::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -361,7 +362,7 @@ void HashJoin::close(thread_db* tdbb) const
}
}
bool HashJoin::getRecord(thread_db* tdbb) const
bool HashJoin::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -441,30 +442,41 @@ bool HashJoin::lockRecord(thread_db* /*tdbb*/) const
return false; // compiler silencer
}
void HashJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void HashJoin::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_leader.source);
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
children.add(m_args[i].source);
}
void HashJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
plan += printIndent(++level) + "Hash Join (inner)";
printOptInfo(plan);
m_leader.source->print(tdbb, plan, true, level);
if (recurse)
{
m_leader.source->print(tdbb, plan, true, level, recurse);
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
m_args[i].source->print(tdbb, plan, true, level);
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
m_args[i].source->print(tdbb, plan, true, level, recurse);
}
}
else
{
level++;
plan += "HASH (";
m_leader.source->print(tdbb, plan, false, level);
m_leader.source->print(tdbb, plan, false, level, recurse);
plan += ", ";
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
{
if (i)
plan += ", ";
m_args[i].source->print(tdbb, plan, false, level);
m_args[i].source->print(tdbb, plan, false, level, recurse);
}
plan += ")";
}

View File

@ -61,7 +61,7 @@ IndexTableScan::IndexTableScan(CompilerScratch* csb, const string& alias,
m_cardinality = csb->csb_rpt[stream].csb_cardinality * selectivity;
}
void IndexTableScan::open(thread_db* tdbb) const
void IndexTableScan::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -146,7 +146,7 @@ void IndexTableScan::close(thread_db* tdbb) const
#endif
}
bool IndexTableScan::getRecord(thread_db* tdbb) const
bool IndexTableScan::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -303,7 +303,11 @@ bool IndexTableScan::getRecord(thread_db* tdbb) const
return false;
}
void IndexTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void IndexTableScan::getChildren(Array<const RecordSource*>& children) const
{
}
void IndexTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{

View File

@ -46,7 +46,7 @@ LocalTableStream::LocalTableStream(CompilerScratch* csb, StreamType stream, cons
m_cardinality = DEFAULT_CARDINALITY;
}
void LocalTableStream::open(thread_db* tdbb) const
void LocalTableStream::internalOpen(thread_db* tdbb) const
{
const auto request = tdbb->getRequest();
const auto impure = request->getImpure<Impure>(m_impure);
@ -71,7 +71,11 @@ void LocalTableStream::close(thread_db* tdbb) const
impure->irsb_flags &= ~irsb_open;
}
bool LocalTableStream::getRecord(thread_db* tdbb) const
void LocalTableStream::getChildren(Array<const RecordSource*>& children) const
{
}
bool LocalTableStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -110,7 +114,7 @@ bool LocalTableStream::lockRecord(thread_db* tdbb) const
return false; // compiler silencer
}
void LocalTableStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void LocalTableStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
//// TODO: Use Local Table name/alias.

View File

@ -35,7 +35,8 @@ using namespace Jrd;
// ------------------------------------
LockedStream::LockedStream(CompilerScratch* csb, RecordSource* next)
: m_next(next)
: RecordSource(csb),
m_next(next)
{
fb_assert(m_next);
@ -43,7 +44,7 @@ LockedStream::LockedStream(CompilerScratch* csb, RecordSource* next)
m_cardinality = next->getCardinality();
}
void LockedStream::open(thread_db* tdbb) const
void LockedStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -69,7 +70,7 @@ void LockedStream::close(thread_db* tdbb) const
}
}
bool LockedStream::getRecord(thread_db* tdbb) const
bool LockedStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -103,7 +104,12 @@ bool LockedStream::lockRecord(thread_db* tdbb) const
return m_next->lockRecord(tdbb);
}
void LockedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void LockedStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void LockedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
@ -111,7 +117,8 @@ void LockedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned
printOptInfo(plan);
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void LockedStream::markRecursive()

View File

@ -38,7 +38,9 @@ static const char* const SCRATCH = "fb_merge_";
MergeJoin::MergeJoin(CompilerScratch* csb, FB_SIZE_T count,
SortedStream* const* args, const NestValueArray* const* keys)
: m_args(csb->csb_pool), m_keys(csb->csb_pool)
: RecordSource(csb),
m_args(csb->csb_pool),
m_keys(csb->csb_pool)
{
const size_t size = sizeof(struct Impure) + count * sizeof(Impure::irsb_mrg_repeat);
m_impure = csb->allocImpure(FB_ALIGNMENT, static_cast<ULONG>(size));
@ -61,7 +63,7 @@ MergeJoin::MergeJoin(CompilerScratch* csb, FB_SIZE_T count,
}
}
void MergeJoin::open(thread_db* tdbb) const
void MergeJoin::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -130,7 +132,7 @@ void MergeJoin::close(thread_db* tdbb) const
}
}
bool MergeJoin::getRecord(thread_db* tdbb) const
bool MergeJoin::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -185,7 +187,7 @@ bool MergeJoin::getRecord(thread_db* tdbb) const
{
mfb->mfb_current_block = 0;
mfb->mfb_equal_records = 0;
if ((record = getRecord(tdbb, i)) < 0)
if ((record = getRecordByIndex(tdbb, i)) < 0)
return false;
}
@ -229,7 +231,7 @@ bool MergeJoin::getRecord(thread_db* tdbb) const
mfb->mfb_current_block = 0;
mfb->mfb_equal_records = 0;
const SLONG record = getRecord(tdbb, i);
const SLONG record = getRecordByIndex(tdbb, i);
if (record < 0)
return false;
@ -260,7 +262,7 @@ bool MergeJoin::getRecord(thread_db* tdbb) const
memcpy(first_data, getData(tdbb, mfb, 0), key_length);
SLONG record;
while ((record = getRecord(tdbb, i)) >= 0)
while ((record = getRecordByIndex(tdbb, i)) >= 0)
{
const UCHAR* p = first_data;
const UCHAR* q = getData(tdbb, mfb, record);
@ -341,15 +343,24 @@ bool MergeJoin::lockRecord(thread_db* /*tdbb*/) const
return false; // compiler silencer
}
void MergeJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void MergeJoin::getChildren(Array<const RecordSource*>& children) const
{
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
children.add(m_args[i]);
}
void MergeJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
plan += printIndent(++level) + "Merge Join (inner)";
printOptInfo(plan);
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
m_args[i]->print(tdbb, plan, true, level);
if (recurse)
{
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
m_args[i]->print(tdbb, plan, true, level, recurse);
}
}
else
{
@ -360,7 +371,7 @@ void MergeJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned lev
if (i)
plan += ", ";
m_args[i]->print(tdbb, plan, false, level);
m_args[i]->print(tdbb, plan, false, level, recurse);
}
plan += ")";
}
@ -440,7 +451,7 @@ UCHAR* MergeJoin::getData(thread_db* /*tdbb*/, MergeFile* mfb, SLONG record) con
return mfb->mfb_block_data + merge_offset;
}
SLONG MergeJoin::getRecord(thread_db* tdbb, FB_SIZE_T index) const
SLONG MergeJoin::getRecordByIndex(thread_db* tdbb, FB_SIZE_T index) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);

View File

@ -36,7 +36,10 @@ using namespace Jrd;
// ------------------------------
NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, FB_SIZE_T count, RecordSource* const* args)
: m_joinType(INNER_JOIN), m_args(csb->csb_pool), m_boolean(NULL)
: RecordSource(csb),
m_joinType(INNER_JOIN),
m_args(csb->csb_pool),
m_boolean(NULL)
{
m_impure = csb->allocImpure<Impure>();
m_cardinality = MINIMUM_CARDINALITY;
@ -52,7 +55,10 @@ NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, FB_SIZE_T count, RecordSour
NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
BoolExprNode* boolean, JoinType joinType)
: m_joinType(joinType), m_args(csb->csb_pool), m_boolean(boolean)
: RecordSource(csb),
m_joinType(joinType),
m_args(csb->csb_pool),
m_boolean(boolean)
{
fb_assert(outer && inner);
@ -64,7 +70,7 @@ NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, Record
m_cardinality = outer->getCardinality() * inner->getCardinality();
}
void NestedLoopJoin::open(thread_db* tdbb) const
void NestedLoopJoin::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -89,7 +95,7 @@ void NestedLoopJoin::close(thread_db* tdbb) const
}
}
bool NestedLoopJoin::getRecord(thread_db* tdbb) const
bool NestedLoopJoin::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -203,7 +209,13 @@ bool NestedLoopJoin::lockRecord(thread_db* /*tdbb*/) const
return false; // compiler silencer
}
void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void NestedLoopJoin::getChildren(Array<const RecordSource*>& children) const
{
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
children.add(m_args[i]);
}
void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (m_args.hasData())
{
@ -235,8 +247,11 @@ void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigne
printOptInfo(plan);
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
m_args[i]->print(tdbb, plan, true, level);
if (recurse)
{
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
m_args[i]->print(tdbb, plan, true, level, recurse);
}
}
else
{
@ -247,7 +262,7 @@ void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigne
if (i)
plan += ", ";
m_args[i]->print(tdbb, plan, false, level);
m_args[i]->print(tdbb, plan, false, level, recurse);
}
plan += ")";
}

View File

@ -55,7 +55,7 @@ ProcedureScan::ProcedureScan(CompilerScratch* csb, const string& alias, StreamTy
fb_assert(sourceList->items.getCount() == targetList->items.getCount());
}
void ProcedureScan::open(thread_db* tdbb) const
void ProcedureScan::internalOpen(thread_db* tdbb) const
{
if (!m_procedure->isImplemented())
{
@ -167,7 +167,7 @@ void ProcedureScan::close(thread_db* tdbb) const
}
}
bool ProcedureScan::getRecord(thread_db* tdbb) const
bool ProcedureScan::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -249,7 +249,11 @@ bool ProcedureScan::lockRecord(thread_db* /*tdbb*/) const
return false; // compiler silencer
}
void ProcedureScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void ProcedureScan::getChildren(Array<const RecordSource*>& children) const
{
}
void ProcedureScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{

View File

@ -25,6 +25,7 @@
#include "../jrd/btr.h"
#include "../jrd/intl.h"
#include "../jrd/req.h"
#include "../jrd/ProfilerManager.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dpm_proto.h"
#include "../jrd/err_proto.h"
@ -46,6 +47,72 @@ using namespace Jrd;
// Record source class
// -------------------
RecordSource::RecordSource(CompilerScratch* csb)
: m_cursorProfileId(csb->csb_currentCursorProfileId),
m_recSourceProfileId(csb->csb_nextRecSourceProfileId++)
{
}
void RecordSource::open(thread_db* tdbb) const
{
const auto attachment = tdbb->getAttachment();
const auto request = tdbb->getRequest();
const auto profilerManager = attachment->isProfilerActive() && !request->hasInternalStatement() ?
attachment->getProfilerManager(tdbb) :
nullptr;
const SINT64 lastPerfCounter = profilerManager ?
fb_utils::query_performance_counter() :
0;
if (profilerManager)
{
profilerManager->prepareRecSource(tdbb, request, this);
profilerManager->beforeRecordSourceOpen(request, this);
}
internalOpen(tdbb);
if (profilerManager)
{
const SINT64 currentPerfCounter = fb_utils::query_performance_counter();
ProfilerManager::Stats stats(currentPerfCounter - lastPerfCounter);
profilerManager->afterRecordSourceOpen(request, this, stats);
}
}
bool RecordSource::getRecord(thread_db* tdbb) const
{
const auto attachment = tdbb->getAttachment();
const auto request = tdbb->getRequest();
const auto profilerManager = attachment->isProfilerActive() && !request->hasInternalStatement() ?
attachment->getProfilerManager(tdbb) :
nullptr;
const SINT64 lastPerfCounter = profilerManager ?
fb_utils::query_performance_counter() :
0;
if (profilerManager)
{
profilerManager->prepareRecSource(tdbb, request, this);
profilerManager->beforeRecordSourceGetRecord(request, this);
}
const auto ret = internalGetRecord(tdbb);
if (profilerManager)
{
const SINT64 currentPerfCounter = fb_utils::query_performance_counter();
ProfilerManager::Stats stats(currentPerfCounter - lastPerfCounter);
profilerManager->afterRecordSourceGetRecord(request, this, stats);
}
return ret;
}
string RecordSource::printName(thread_db* tdbb, const string& name, bool quote)
{
const string result(name.c_str(), name.length());
@ -194,7 +261,9 @@ RecordSource::~RecordSource()
// ------------------
RecordStream::RecordStream(CompilerScratch* csb, StreamType stream, const Format* format)
: m_stream(stream), m_format(format ? format : csb->csb_rpt[stream].csb_format)
: RecordSource(csb),
m_stream(stream),
m_format(format ? format : csb->csb_rpt[stream].csb_format)
{
fb_assert(m_format);
}

View File

@ -57,15 +57,15 @@ namespace Jrd
class RecordSource
{
public:
virtual void open(thread_db* tdbb) const = 0;
virtual void close(thread_db* tdbb) const = 0;
virtual bool getRecord(thread_db* tdbb) const = 0;
virtual bool refetchRecord(thread_db* tdbb) const = 0;
virtual bool lockRecord(thread_db* tdbb) const = 0;
virtual void getChildren(Firebird::Array<const RecordSource*>& children) const = 0;
virtual void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const = 0;
bool detailed, unsigned level, bool recurse) const = 0;
virtual void markRecursive() = 0;
virtual void invalidateRecords(Request* request) const = 0;
@ -90,6 +90,20 @@ namespace Jrd
return m_cardinality;
}
ULONG getCursorProfileId() const
{
return m_cursorProfileId;
}
ULONG getRecSourceProfileId() const
{
return m_recSourceProfileId;
}
void open(thread_db* tdbb) const;
bool getRecord(thread_db* tdbb) const;
protected:
// Generic impure block
struct Impure
@ -103,9 +117,7 @@ namespace Jrd
static const ULONG irsb_mustread = 8;
static const ULONG irsb_singular_processed = 16;
RecordSource()
: m_impure(0), m_recursive(false), m_cardinality(0.0)
{}
RecordSource(CompilerScratch* csb);
static Firebird::string printName(thread_db* tdbb, const Firebird::string& name, bool quote = true);
static Firebird::string printName(thread_db* tdbb, const Firebird::string& name,
@ -120,9 +132,14 @@ namespace Jrd
static void saveRecord(thread_db* tdbb, record_param* rpb);
static void restoreRecord(thread_db* tdbb, record_param* rpb);
ULONG m_impure;
bool m_recursive;
double m_cardinality;
virtual void internalOpen(thread_db* tdbb) const = 0;
virtual bool internalGetRecord(thread_db* tdbb) const = 0;
double m_cardinality = 0.0;
ULONG m_impure = 0;
bool m_recursive = false;
ULONG m_cursorProfileId;
ULONG m_recSourceProfileId;
};
@ -163,13 +180,16 @@ namespace Jrd
StreamType stream, jrd_rel* relation,
const Firebird::Array<DbKeyRangeNode*>& dbkeyRanges);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
const Firebird::string m_alias;
@ -189,13 +209,16 @@ namespace Jrd
StreamType stream, jrd_rel* relation,
InversionNode* inversion, double selectivity);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
const Firebird::string m_alias;
@ -229,13 +252,12 @@ namespace Jrd
InversionNode* index, USHORT keyLength,
double selectivity);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void setInversion(InversionNode* inversion, BoolExprNode* condition)
{
@ -244,6 +266,10 @@ namespace Jrd
m_condition = condition;
}
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
int compareKeys(const index_desc*, const UCHAR*, USHORT, const temporary_key*, USHORT) const;
bool findSavedNode(thread_db* tdbb, Impure* impure, win* window, UCHAR**) const;
@ -276,15 +302,19 @@ namespace Jrd
ExternalTableScan(CompilerScratch* csb, const Firebird::string& alias,
StreamType stream, jrd_rel* relation);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
jrd_rel* const m_relation;
@ -297,17 +327,20 @@ namespace Jrd
VirtualTableScan(CompilerScratch* csb, const Firebird::string& alias,
StreamType stream, jrd_rel* relation);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
virtual const Format* getFormat(thread_db* tdbb, jrd_rel* relation) const = 0;
virtual bool retrieveRecord(thread_db* tdbb, jrd_rel* relation,
FB_UINT64 position, Record* record) const = 0;
@ -330,15 +363,19 @@ namespace Jrd
const jrd_prc* procedure, const ValueListNode* sourceList,
const ValueListNode* targetList, MessageNode* message);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
void assignParams(thread_db* tdbb, const dsc* from_desc, const dsc* flag_desc,
@ -359,15 +396,15 @@ namespace Jrd
public:
SingularStream(CompilerScratch* csb, RecordSource* next);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -375,9 +412,11 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
void nullRecords(thread_db* tdbb) const override;
private:
void doGetRecord(thread_db* tdbb) const;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
NestConst<RecordSource> m_next;
StreamList m_streams;
};
@ -387,15 +426,15 @@ namespace Jrd
public:
LockedStream(CompilerScratch* csb, RecordSource* next);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -403,6 +442,10 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
void nullRecords(thread_db* tdbb) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
NestConst<RecordSource> m_next;
};
@ -417,15 +460,15 @@ namespace Jrd
public:
FirstRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -438,6 +481,10 @@ namespace Jrd
m_next->setAnyBoolean(anyBoolean, ansiAny, ansiNot);
}
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
NestConst<RecordSource> m_next;
NestConst<ValueExprNode> const m_value;
@ -453,15 +500,15 @@ namespace Jrd
public:
SkipRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -474,6 +521,10 @@ namespace Jrd
m_next->setAnyBoolean(anyBoolean, ansiAny, ansiNot);
}
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
NestConst<RecordSource> m_next;
NestConst<ValueExprNode> const m_value;
@ -485,15 +536,15 @@ namespace Jrd
FilteredStream(CompilerScratch* csb, RecordSource* next,
BoolExprNode* boolean, double selectivity);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -511,6 +562,10 @@ namespace Jrd
m_ansiNot = ansiNot;
}
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
bool evaluateBoolean(thread_db* tdbb) const;
@ -589,15 +644,15 @@ namespace Jrd
SortedStream(CompilerScratch* csb, RecordSource* next, SortMap* map);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -638,6 +693,10 @@ namespace Jrd
return (IS_INTL_DATA(desc) || desc->isDecFloat() || desc->isDateTimeTz());
}
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
Sort* init(thread_db* tdbb) const;
@ -732,7 +791,6 @@ namespace Jrd
const NestValueArray* group, MapNode* groupMap, bool oneRowWhenEmpty, NextType* next);
public:
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
@ -744,6 +802,8 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
Impure* getImpure(Request* request) const
{
return request->getImpure<typename ThisType::Impure>(m_impure);
@ -806,8 +866,12 @@ namespace Jrd
const NestValueArray* group, MapNode* map, RecordSource* next);
public:
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const;
bool getRecord(thread_db* tdbb) const;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level, bool recurse) const override;
protected:
bool internalGetRecord(thread_db* tdbb) const override;
};
class WindowedStream : public RecordSource
@ -870,16 +934,18 @@ namespace Jrd
Exclusion exclusion);
public:
void open(thread_db* tdbb) const;
void close(thread_db* tdbb) const;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const;
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
void nullRecords(thread_db* tdbb) const;
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level, bool recurse) const override;
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
void nullRecords(thread_db* tdbb) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
Impure* getImpure(Request* request) const
{
return request->getImpure<Impure>(m_impure);
@ -907,15 +973,15 @@ namespace Jrd
WindowedStream(thread_db* tdbb, Optimizer* opt,
Firebird::ObjectsArray<WindowSourceNode::Window>& windows, RecordSource* next);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -923,6 +989,10 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
void nullRecords(thread_db* tdbb) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
NestConst<BufferedStream> m_next;
NestConst<RecordSource> m_joinedStream;
@ -932,6 +1002,10 @@ namespace Jrd
class BaseBufferedStream : public RecordSource
{
public:
BaseBufferedStream(CompilerScratch* csb)
: RecordSource(csb)
{}
virtual void locate(thread_db* tdbb, FB_UINT64 position) const = 0;
virtual FB_UINT64 getCount(thread_db* tdbb) const = 0;
virtual FB_UINT64 getPosition(Request* request) const = 0;
@ -967,15 +1041,15 @@ namespace Jrd
public:
BufferedStream(CompilerScratch* csb, RecordSource* next);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -992,6 +1066,10 @@ namespace Jrd
return impure->irsb_position;
}
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
NestConst<RecordSource> m_next;
Firebird::HalfStaticArray<FieldMap, OPT_STATIC_ITEMS> m_map;
@ -1007,15 +1085,15 @@ namespace Jrd
NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
BoolExprNode* boolean, JoinType joinType);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -1023,6 +1101,10 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
void nullRecords(thread_db* tdbb) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
bool fetchRecord(thread_db*, FB_SIZE_T) const;
@ -1036,15 +1118,15 @@ namespace Jrd
public:
FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSource* arg2);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -1052,6 +1134,10 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
void nullRecords(thread_db* tdbb) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
NestConst<RecordSource> m_arg1;
NestConst<RecordSource> m_arg2;
@ -1085,15 +1171,15 @@ namespace Jrd
HashJoin(thread_db* tdbb, CompilerScratch* csb, FB_SIZE_T count,
RecordSource* const* args, NestValueArray* const* keys);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -1103,6 +1189,10 @@ namespace Jrd
static unsigned maxCapacity();
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
ULONG computeHash(thread_db* tdbb, Request* request,
const SubStream& sub, UCHAR* buffer) const;
@ -1147,15 +1237,15 @@ namespace Jrd
SortedStream* const* args,
const NestValueArray* const* keys);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -1163,11 +1253,15 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
void nullRecords(thread_db* tdbb) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
int compare(thread_db* tdbb, const NestValueArray* node1,
const NestValueArray* node2) const;
UCHAR* getData(thread_db* tdbb, MergeFile* mfb, SLONG record) const;
SLONG getRecord(thread_db* tdbb, FB_SIZE_T index) const;
SLONG getRecordByIndex(thread_db* tdbb, FB_SIZE_T index) const;
bool fetchRecord(thread_db* tdbb, FB_SIZE_T index) const;
Firebird::Array<NestConst<SortedStream> > m_args;
@ -1179,14 +1273,19 @@ namespace Jrd
public:
LocalTableStream(CompilerScratch* csb, StreamType stream, const DeclareLocalTableNode* table);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level, bool recurse) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
const DeclareLocalTableNode* m_table;
@ -1204,20 +1303,24 @@ namespace Jrd
FB_SIZE_T argCount, RecordSource* const* args, NestConst<MapNode>* maps,
const StreamList& streams);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
Firebird::Array<NestConst<RecordSource> > m_args;
Firebird::Array<NestConst<MapNode> > m_maps;
@ -1245,20 +1348,24 @@ namespace Jrd
const StreamList& innerStreams,
ULONG saveOffset);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
void cleanupLevel(Request* request, Impure* impure) const;
@ -1283,15 +1390,15 @@ namespace Jrd
ConditionalStream(CompilerScratch* csb, RecordSource* first, RecordSource* second,
BoolExprNode* boolean);
void open(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void print(thread_db* tdbb, Firebird::string& plan,
bool detailed, unsigned level) const override;
bool detailed, unsigned level, bool recurse) const override;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
@ -1299,6 +1406,10 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
void nullRecords(thread_db* tdbb) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
bool internalGetRecord(thread_db* tdbb) const override;
private:
NestConst<RecordSource> m_first;
NestConst<RecordSource> m_second;

View File

@ -62,7 +62,7 @@ RecursiveStream::RecursiveStream(CompilerScratch* csb, StreamType stream, Stream
m_inner->markRecursive();
}
void RecursiveStream::open(thread_db* tdbb) const
void RecursiveStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -111,7 +111,7 @@ void RecursiveStream::close(thread_db* tdbb) const
}
}
bool RecursiveStream::getRecord(thread_db* tdbb) const
bool RecursiveStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -239,26 +239,35 @@ bool RecursiveStream::lockRecord(thread_db* /*tdbb*/) const
return false; // compiler silencer
}
void RecursiveStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void RecursiveStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_root);
children.add(m_inner);
}
void RecursiveStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
plan += printIndent(++level) + "Recursion";
printOptInfo(plan);
m_root->print(tdbb, plan, true, level);
m_inner->print(tdbb, plan, true, level);
if (recurse)
{
m_root->print(tdbb, plan, true, level, recurse);
m_inner->print(tdbb, plan, true, level, recurse);
}
}
else
{
if (!level)
plan += "(";
m_root->print(tdbb, plan, false, level + 1);
m_root->print(tdbb, plan, false, level + 1, recurse);
plan += ", ";
m_inner->print(tdbb, plan, false, level + 1);
m_inner->print(tdbb, plan, false, level + 1, recurse);
if (!level)
plan += ")";

View File

@ -34,7 +34,9 @@ using namespace Jrd;
// ------------------------------
SingularStream::SingularStream(CompilerScratch* csb, RecordSource* next)
: m_next(next), m_streams(csb->csb_pool)
: RecordSource(csb),
m_next(next),
m_streams(csb->csb_pool)
{
fb_assert(m_next);
@ -44,7 +46,7 @@ SingularStream::SingularStream(CompilerScratch* csb, RecordSource* next)
m_cardinality = MINIMUM_CARDINALITY;
}
void SingularStream::open(thread_db* tdbb) const
void SingularStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -70,7 +72,7 @@ void SingularStream::close(thread_db* tdbb) const
}
}
bool SingularStream::getRecord(thread_db* tdbb) const
bool SingularStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -85,55 +87,48 @@ bool SingularStream::getRecord(thread_db* tdbb) const
if (m_next->getRecord(tdbb))
{
doGetRecord(tdbb);
const FB_SIZE_T streamCount = m_streams.getCount();
MemoryPool& pool = *tdbb->getDefaultPool();
HalfStaticArray<record_param, 16> rpbs(pool, streamCount);
for (FB_SIZE_T i = 0; i < streamCount; i++)
{
rpbs.add(request->req_rpb[m_streams[i]]);
record_param& rpb = rpbs.back();
Record* const orgRecord = rpb.rpb_record;
if (orgRecord)
rpb.rpb_record = FB_NEW_POOL(pool) Record(pool, orgRecord);
}
if (m_next->getRecord(tdbb))
status_exception::raise(Arg::Gds(isc_sing_select_err));
for (FB_SIZE_T i = 0; i < streamCount; i++)
{
record_param& rpb = request->req_rpb[m_streams[i]];
Record* orgRecord = rpb.rpb_record;
rpb = rpbs[i];
const AutoPtr<Record> newRecord(rpb.rpb_record);
if (newRecord)
{
if (!orgRecord)
BUGCHECK(284); // msg 284 cannot restore singleton select data
rpb.rpb_record = orgRecord;
orgRecord->copyFrom(newRecord);
}
}
impure->irsb_flags |= irsb_singular_processed;
return true;
}
return false;
}
void SingularStream::doGetRecord(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
const FB_SIZE_T streamCount = m_streams.getCount();
MemoryPool& pool = *tdbb->getDefaultPool();
HalfStaticArray<record_param, 16> rpbs(pool, streamCount);
for (FB_SIZE_T i = 0; i < streamCount; i++)
{
rpbs.add(request->req_rpb[m_streams[i]]);
record_param& rpb = rpbs.back();
Record* const orgRecord = rpb.rpb_record;
if (orgRecord)
rpb.rpb_record = FB_NEW_POOL(pool) Record(pool, orgRecord);
}
if (m_next->getRecord(tdbb))
status_exception::raise(Arg::Gds(isc_sing_select_err));
for (FB_SIZE_T i = 0; i < streamCount; i++)
{
record_param& rpb = request->req_rpb[m_streams[i]];
Record* orgRecord = rpb.rpb_record;
rpb = rpbs[i];
const AutoPtr<Record> newRecord(rpb.rpb_record);
if (newRecord)
{
if (!orgRecord)
BUGCHECK(284); // msg 284 cannot restore singleton select data
rpb.rpb_record = orgRecord;
orgRecord->copyFrom(newRecord);
}
}
impure->irsb_flags |= irsb_singular_processed;
}
bool SingularStream::refetchRecord(thread_db* tdbb) const
{
return m_next->refetchRecord(tdbb);
@ -144,7 +139,12 @@ bool SingularStream::lockRecord(thread_db* tdbb) const
return m_next->lockRecord(tdbb);
}
void SingularStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void SingularStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void SingularStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
@ -152,7 +152,8 @@ void SingularStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
printOptInfo(plan);
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void SingularStream::markRecursive()

View File

@ -37,7 +37,9 @@ using namespace Jrd;
// -------------------------------
SkipRowsStream::SkipRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value)
: m_next(next), m_value(value)
: RecordSource(csb),
m_next(next),
m_value(value)
{
fb_assert(m_next && m_value);
@ -45,7 +47,7 @@ SkipRowsStream::SkipRowsStream(CompilerScratch* csb, RecordSource* next, ValueEx
m_cardinality = next->getCardinality();
}
void SkipRowsStream::open(thread_db* tdbb) const
void SkipRowsStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -81,7 +83,7 @@ void SkipRowsStream::close(thread_db* tdbb) const
}
}
bool SkipRowsStream::getRecord(thread_db* tdbb) const
bool SkipRowsStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -114,7 +116,12 @@ bool SkipRowsStream::lockRecord(thread_db* tdbb) const
return m_next->lockRecord(tdbb);
}
void SkipRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void SkipRowsStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void SkipRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
@ -122,7 +129,8 @@ void SkipRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
printOptInfo(plan);
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void SkipRowsStream::markRecursive()

View File

@ -44,7 +44,9 @@ using namespace Jrd;
// -----------------------------
SortedStream::SortedStream(CompilerScratch* csb, RecordSource* next, SortMap* map)
: m_next(next), m_map(map)
: RecordSource(csb),
m_next(next),
m_map(map)
{
fb_assert(m_next && m_map);
@ -55,7 +57,7 @@ SortedStream::SortedStream(CompilerScratch* csb, RecordSource* next, SortMap* ma
m_cardinality *= DEFAULT_SELECTIVITY;
}
void SortedStream::open(thread_db* tdbb) const
void SortedStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -89,7 +91,7 @@ void SortedStream::close(thread_db* tdbb) const
}
}
bool SortedStream::getRecord(thread_db* tdbb) const
bool SortedStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -119,8 +121,13 @@ bool SortedStream::lockRecord(thread_db* tdbb) const
return m_next->lockRecord(tdbb);
}
void SortedStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void SortedStream::print(thread_db* tdbb, string& plan,
bool detailed, unsigned level) const
bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
@ -135,13 +142,14 @@ void SortedStream::print(thread_db* tdbb, string& plan,
((m_map->flags & FLAG_PROJECT) ? "Unique Sort" : "Sort") + extras;
printOptInfo(plan);
m_next->print(tdbb, plan, true, level);
if (recurse)
m_next->print(tdbb, plan, true, level, recurse);
}
else
{
level++;
plan += "SORT (";
m_next->print(tdbb, plan, false, level);
m_next->print(tdbb, plan, false, level, recurse);
plan += ")";
}
}

View File

@ -57,7 +57,7 @@ Union::Union(CompilerScratch* csb, StreamType stream,
m_maps[i] = maps[i];
}
void Union::open(thread_db* tdbb) const
void Union::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -95,7 +95,7 @@ void Union::close(thread_db* tdbb) const
}
}
bool Union::getRecord(thread_db* tdbb) const
bool Union::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -162,15 +162,24 @@ bool Union::lockRecord(thread_db* tdbb) const
return m_args[impure->irsb_count]->lockRecord(tdbb);
}
void Union::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void Union::getChildren(Array<const RecordSource*>& children) const
{
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
children.add(m_args[i]);
}
void Union::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{
plan += printIndent(++level) + (m_args.getCount() == 1 ? "Materialize" : "Union");
printOptInfo(plan);
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
m_args[i]->print(tdbb, plan, true, level);
if (recurse)
{
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
m_args[i]->print(tdbb, plan, true, level, recurse);
}
}
else
{
@ -182,7 +191,7 @@ void Union::print(thread_db* tdbb, string& plan, bool detailed, unsigned level)
if (i)
plan += ", ";
m_args[i]->print(tdbb, plan, false, level + 1);
m_args[i]->print(tdbb, plan, false, level + 1, recurse);
}
if (!level)

View File

@ -44,7 +44,7 @@ VirtualTableScan::VirtualTableScan(CompilerScratch* csb, const string& alias,
m_cardinality = csb->csb_rpt[stream].csb_cardinality;
}
void VirtualTableScan::open(thread_db* tdbb) const
void VirtualTableScan::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -71,7 +71,7 @@ void VirtualTableScan::close(thread_db* tdbb) const
impure->irsb_flags &= ~irsb_open;
}
bool VirtualTableScan::getRecord(thread_db* tdbb) const
bool VirtualTableScan::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -110,7 +110,11 @@ bool VirtualTableScan::lockRecord(thread_db* /*tdbb*/) const
return false; // compiler silencer
}
void VirtualTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void VirtualTableScan::getChildren(Array<const RecordSource*>& children) const
{
}
void VirtualTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (detailed)
{

View File

@ -51,34 +51,36 @@ namespace
public:
BufferedStreamWindow(CompilerScratch* csb, BufferedStream* next);
void open(thread_db* tdbb) const;
void close(thread_db* tdbb) const;
void internalOpen(thread_db* tdbb) const override;
void close(thread_db* tdbb) const override;
bool getRecord(thread_db* tdbb) const;
bool refetchRecord(thread_db* tdbb) const;
bool lockRecord(thread_db* tdbb) const;
bool internalGetRecord(thread_db* tdbb) const override;
bool refetchRecord(thread_db* tdbb) const override;
bool lockRecord(thread_db* tdbb) const override;
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const;
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
void markRecursive();
void invalidateRecords(Request* request) const;
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level, bool recurse) const override;
void findUsedStreams(StreamList& streams, bool expandAll) const;
void nullRecords(thread_db* tdbb) const;
void markRecursive() override;
void invalidateRecords(Request* request) const override;
void locate(thread_db* tdbb, FB_UINT64 position) const
void findUsedStreams(StreamList& streams, bool expandAll) const override;
void nullRecords(thread_db* tdbb) const override;
void locate(thread_db* tdbb, FB_UINT64 position) const override
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
impure->irsb_position = position;
}
FB_UINT64 getCount(thread_db* tdbb) const
FB_UINT64 getCount(thread_db* tdbb) const override
{
return m_next->getCount(tdbb);
}
FB_UINT64 getPosition(Request* request) const
FB_UINT64 getPosition(Request* request) const override
{
Impure* const impure = request->getImpure<Impure>(m_impure);
return impure->irsb_position;
@ -91,12 +93,13 @@ namespace
// BufferedStreamWindow implementation
BufferedStreamWindow::BufferedStreamWindow(CompilerScratch* csb, BufferedStream* next)
: m_next(next)
: BaseBufferedStream(csb),
m_next(next)
{
m_impure = csb->allocImpure<Impure>();
}
void BufferedStreamWindow::open(thread_db* tdbb) const
void BufferedStreamWindow::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -117,7 +120,7 @@ namespace
impure->irsb_flags &= ~irsb_open;
}
bool BufferedStreamWindow::getRecord(thread_db* tdbb) const
bool BufferedStreamWindow::internalGetRecord(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -143,9 +146,15 @@ namespace
return m_next->lockRecord(tdbb);
}
void BufferedStreamWindow::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void BufferedStreamWindow::getChildren(Array<const RecordSource*>& children) const
{
m_next->print(tdbb, plan, detailed, level);
children.add(m_next);
}
void BufferedStreamWindow::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void BufferedStreamWindow::markRecursive()
@ -185,7 +194,8 @@ namespace
WindowedStream::WindowedStream(thread_db* tdbb, Optimizer* opt,
ObjectsArray<WindowSourceNode::Window>& windows, RecordSource* next)
: m_joinedStream(nullptr)
: RecordSource(opt->getCompilerScratch()),
m_joinedStream(nullptr)
{
const auto csb = opt->getCompilerScratch();
@ -334,7 +344,7 @@ WindowedStream::WindowedStream(thread_db* tdbb, Optimizer* opt,
}
}
void WindowedStream::open(thread_db* tdbb) const
void WindowedStream::internalOpen(thread_db* tdbb) const
{
Request* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -361,7 +371,7 @@ void WindowedStream::close(thread_db* tdbb) const
}
}
bool WindowedStream::getRecord(thread_db* tdbb) const
bool WindowedStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -388,9 +398,15 @@ bool WindowedStream::lockRecord(thread_db* /*tdbb*/) const
return false; // compiler silencer
}
void WindowedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
void WindowedStream::getChildren(Array<const RecordSource*>& children) const
{
m_joinedStream->print(tdbb, plan, detailed, level);
children.add(m_joinedStream);
}
void WindowedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
{
if (recurse)
m_joinedStream->print(tdbb, plan, detailed, level, recurse);
}
void WindowedStream::markRecursive()
@ -506,9 +522,9 @@ WindowedStream::WindowStream::WindowStream(thread_db* tdbb, CompilerScratch* csb
(void) m_exclusion; // avoid warning
}
void WindowedStream::WindowStream::open(thread_db* tdbb) const
void WindowedStream::WindowStream::internalOpen(thread_db* tdbb) const
{
BaseAggWinStream::open(tdbb);
BaseAggWinStream::internalOpen(tdbb);
Request* const request = tdbb->getRequest();
Impure* const impure = getImpure(request);
@ -543,7 +559,7 @@ void WindowedStream::WindowStream::close(thread_db* tdbb) const
BaseAggWinStream::close(tdbb);
}
bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const
bool WindowedStream::WindowStream::internalGetRecord(thread_db* tdbb) const
{
JRD_reschedule(tdbb);
@ -871,8 +887,13 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const
return true;
}
void WindowedStream::WindowStream::getChildren(Array<const RecordSource*>& children) const
{
children.add(m_next);
}
void WindowedStream::WindowStream::print(thread_db* tdbb, string& plan, bool detailed,
unsigned level) const
unsigned level, bool recurse) const
{
if (detailed)
{
@ -880,7 +901,8 @@ void WindowedStream::WindowStream::print(thread_db* tdbb, string& plan, bool det
printOptInfo(plan);
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void WindowedStream::WindowStream::findUsedStreams(StreamList& streams, bool expandAll) const

View File

@ -374,6 +374,7 @@ public:
RuntimeStatistics req_stats;
RuntimeStatistics req_base_stats;
AffectedRows req_records_affected; // records affected by the last statement
FB_UINT64 req_profiler_time; // profiler time
const StmtNode* req_next; // next node for execution
EDS::Statement* req_ext_stmt; // head of list of active dynamic statements

View File

@ -827,7 +827,7 @@ void TRA_invalidate(thread_db* tdbb, ULONG mask)
Database* const database = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
SyncLockGuard dbbSync(&database->dbb_sync, SYNC_SHARED, "TRA_invalidate");

View File

@ -87,6 +87,7 @@
#include "../jrd/Function.h"
#include "../common/StatusArg.h"
#include "../jrd/GarbageCollector.h"
#include "../jrd/ProfilerManager.h"
#include "../jrd/trace/TraceManager.h"
#include "../jrd/trace/TraceJrdHelpers.h"
#include "../common/Task.h"

View File

@ -413,7 +413,7 @@ void LockManager::shutdownOwner(thread_db* tdbb, SRQ_PTR* owner_handle)
{
{ // checkout scope
LockTableCheckout checkout(this, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
Thread::sleep(10);
}
@ -1397,7 +1397,7 @@ void LockManager::blocking_action(thread_db* tdbb, SRQ_PTR blocking_owner_offset
{ // checkout scope
LockTableCheckout checkout(this, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
(*routine)(arg);
}
@ -3810,7 +3810,7 @@ void LockManager::wait_for_request(thread_db* tdbb, lrq* request, SSHORT lck_wai
}
{ // scope
EngineCheckout cout(tdbb, FB_FUNCTION, true);
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
ret = m_sharedMemory->eventWait(&owner->own_wakeup, value, (timeout - current_time) * 1000000);
--m_waitingOwners;
}

File diff suppressed because it is too large Load Diff