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

Profiler.

This commit is contained in:
Adriano dos Santos Fernandes 2021-12-23 15:08:04 -03:00
parent f60cf7f674
commit 2f503f2e2d
71 changed files with 4512 additions and 363 deletions

View File

@ -543,7 +543,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)
@ -553,13 +553,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
@ -588,6 +589,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

@ -72,9 +72,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/recsrc) $(call dirObjects,jrd/replication) $(call dirObjects,jrd/trace) \

View File

@ -82,6 +82,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "udf_compat", "udf_compat.vc
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chacha", "chacha.vcxproj", "{F2E1A852-5A4B-4162-9DA8-0363805FCFD0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "default_profiler", "default_profiler.vcxproj", "{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -234,14 +236,6 @@ Global
{DEE75AD5-F165-40E1-80B2-400E27725D5C}.Release|Win32.Build.0 = Release|Win32
{DEE75AD5-F165-40E1-80B2-400E27725D5C}.Release|x64.ActiveCfg = Release|x64
{DEE75AD5-F165-40E1-80B2-400E27725D5C}.Release|x64.Build.0 = Release|x64
{EBB8361B-49D5-43A5-8771-940DF3E308EF}.Debug|Win32.ActiveCfg = Debug|Win32
{EBB8361B-49D5-43A5-8771-940DF3E308EF}.Debug|Win32.Build.0 = Debug|Win32
{EBB8361B-49D5-43A5-8771-940DF3E308EF}.Debug|x64.ActiveCfg = Debug|x64
{EBB8361B-49D5-43A5-8771-940DF3E308EF}.Debug|x64.Build.0 = Debug|x64
{EBB8361B-49D5-43A5-8771-940DF3E308EF}.Release|Win32.ActiveCfg = Release|Win32
{EBB8361B-49D5-43A5-8771-940DF3E308EF}.Release|Win32.Build.0 = Release|Win32
{EBB8361B-49D5-43A5-8771-940DF3E308EF}.Release|x64.ActiveCfg = Release|x64
{EBB8361B-49D5-43A5-8771-940DF3E308EF}.Release|x64.Build.0 = Release|x64
{4BCC693D-1745-45ED-8302-E5E2F979549A}.Debug|Win32.ActiveCfg = Debug|Win32
{4BCC693D-1745-45ED-8302-E5E2F979549A}.Debug|Win32.Build.0 = Debug|Win32
{4BCC693D-1745-45ED-8302-E5E2F979549A}.Debug|x64.ActiveCfg = Debug|x64
@ -360,6 +354,14 @@ Global
{F2E1A852-5A4B-4162-9DA8-0363805FCFD0}.Release|Win32.Build.0 = Release|Win32
{F2E1A852-5A4B-4162-9DA8-0363805FCFD0}.Release|x64.ActiveCfg = Release|x64
{F2E1A852-5A4B-4162-9DA8-0363805FCFD0}.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

@ -106,6 +106,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" />
@ -302,6 +303,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>
@ -896,6 +899,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>

View File

@ -0,0 +1,349 @@
# 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 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.
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 where the session was started.
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`.
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('Default_Profiler', '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('Default_Profiler', '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
select * from fbprof$sessions;
select * from fbprof$psql_stats_view;
select * from fbprof$record_source_stats_view;
select preq.*
from fbprof$requests preq
join fbprof$sessions pses
on pses.session_id = preq.session_id and
pses.description = 'Profile Session 1';
select pstat.*
from fbprof$psql_stats pstat
join fbprof$sessions pses
on pses.session_id = pstat.session_id and
pses.description = 'Profile Session 1'
order by pstat.session_id,
pstat.request_id,
pstat.line_num,
pstat.column_num;
select pstat.*
from fbprof$record_source_stats pstat
join fbprof$sessions pses
on pses.session_id = pstat.session_id and
pses.description = 'Profile Session 2'
order by pstat.session_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 and return its identifier.
Input parameters:
- `PLUGIN_NAME` type `VARCHAR(255) CHARACTER SET UTF8`
- `DESCRIPTION` type `VARCHAR(255) CHARACTER SET UTF8`
Return type: `BIGINT NOT NULL`.
## Procedure `PAUSE_SESSION`
`RDB$PROFILER.PAUSE_SESSION` pauses the current profiler session 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`.
Input parameters:
- `FLUSH` type `BOOLEAN NOT NULL`
## Procedure `RESUME_SESSION`
`RDB$PROFILER.RESUME_SESSION` resumes the current profiler session if it was paused so the next executed statements statistics are collected again.
## Procedure `FINISH_SESSION`
`RDB$PROFILER.FINISH_SESSION` finishes the current profiler session.
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`.
Input parameters:
- `FLUSH` type `BOOLEAN NOT NULL`
## Procedure `FLUSH`
`RDB$PROFILER.FLUSH` updates the snapshot tables with data from the profile sessions in memory.
After update data is stored in tables `FBPROF$SESSIONS`, `FBPROF$STATEMENTS`, `FBPROF$RECORD_SOURCES`, `FBPROF$REQUESTS`, `FBPROF$PSQL_STATS` and `FBPROF$RECORD_SOURCE_STATS` and may be read and analyzed by the user.
It also removes finished sessions from memory.
# 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 `FBPROF$SESSIONS`
- `SESSION_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: `SESSION_ID`
## Table `FBPROF$STATEMENTS`
- `SESSION_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: `SESSION_ID, STATEMENT_ID`
## Table `FBPROF$RECORD_SOURCES`
- `SESSION_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: `SESSION_ID, STATEMENT_ID, CURSOR_ID, RECORD_SOURCE_ID`
## Table `FBPROF$REQUESTS`
- `SESSION_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
- Primary key: `SESSION_ID, REQUEST_ID`
## Table `FBPROF$PSQL_STATS`
- `SESSION_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 statement
- `MIN_TIME` type `BIGINT` - Minimal time (in nanoseconds) of a statement execution
- `MAX_TIME` type `BIGINT` - Maximum time (in nanoseconds) of a statement execution
- `TOTAL_TIME` type `BIGINT` - Accumulated execution time (in nanoseconds) of the statement
- Primary key: `SESSION_ID, REQUEST_ID, LINE_NUM, COLUMN_NUM`
## Table `FBPROF$RECORD_SOURCE_STATS`
- `SESSION_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_TIME` type `BIGINT` - Minimal time (in nanoseconds) of a record source open
- `OPEN_MAX_TIME` type `BIGINT` - Maximum time (in nanoseconds) of a record source open
- `OPEN_TOTAL_TIME` type `BIGINT` - Accumulated open time (in nanoseconds) of the record source
- `FETCH_COUNTER` type `BIGINT` - Number of fetch times of the record source
- `FETCH_MIN_TIME` type `BIGINT` - Minimal time (in nanoseconds) of a record source fetch
- `FETCH_MAX_TIME` type `BIGINT` - Maximum time (in nanoseconds) of a record source fetch
- `FETCH_TOTAL_TIME` type `BIGINT` - Accumulated fetch time (in nanoseconds) of the record source
- Primary key: `SESSION_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 `FBPROF$PSQL_STATS_VIEW`
```
select pstat.session_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 fbprof$statements
where session_id = pstat.session_id and
statement_id = coalesce(sta.parent_statement_id, pstat.statement_id)
) sql_text,
pstat.line_num,
pstat.column_num,
sum(pstat.counter) counter,
min(pstat.min_time) min_time,
max(pstat.max_time) max_time,
sum(pstat.total_time) total_time,
sum(pstat.total_time) / nullif(sum(pstat.counter), 0) avg_time
from fbprof$psql_stats pstat
join fbprof$statements sta
on sta.session_id = pstat.session_id and
sta.statement_id = pstat.statement_id
left join fbprof$statements sta_parent
on sta_parent.session_id = sta.session_id and
sta_parent.statement_id = sta.parent_statement_id
group by pstat.session_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_time) desc
```
## View `FBPROF$RECORD_SOURCE_STATS_VIEW`
```
select rstat.session_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 fbprof$statements
where session_id = rstat.session_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,
sum(rstat.open_counter) open_counter,
min(rstat.open_min_time) open_min_time,
max(rstat.open_max_time) open_max_time,
sum(rstat.open_total_time) open_total_time,
sum(rstat.open_total_time) / nullif(sum(rstat.open_counter), 0) open_avg_time,
sum(rstat.fetch_counter) fetch_counter,
min(rstat.fetch_min_time) fetch_min_time,
max(rstat.fetch_max_time) fetch_max_time,
sum(rstat.fetch_total_time) fetch_total_time,
sum(rstat.fetch_total_time) / nullif(sum(rstat.fetch_counter), 0) fetch_avg_time,
coalesce(sum(rstat.open_total_time), 0) + coalesce(sum(rstat.fetch_total_time), 0) open_fetch_total_time
from fbprof$record_source_stats rstat
join fbprof$record_sources recsrc
on recsrc.session_id = rstat.session_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 fbprof$statements sta
on sta.session_id = rstat.session_id and
sta.statement_id = rstat.statement_id
left join fbprof$statements sta_parent
on sta_parent.session_id = sta.session_id and
sta_parent.statement_id = sta.parent_statement_id
group by rstat.session_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_time), 0) + coalesce(sum(rstat.fetch_total_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)

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

@ -6839,7 +6839,7 @@ dsc* FieldNode::execute(thread_db* tdbb, jrd_req* 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, jrd_req* request, ExeState* exeState) const = 0;
public:

View File

@ -845,7 +845,7 @@ const StmtNode* CompoundStmtNode::execute(thread_db* tdbb, jrd_req* request, Exe
{
const NestConst<StmtNode>* end = statements.end();
if (onlyAssignments)
if (onlyAssignments && !request->req_attachment->isProfilerActive())
{
if (request->req_operation == jrd_req::req_evaluate)
{
@ -8714,6 +8714,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

@ -279,6 +279,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);

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);
@ -1695,3 +1696,49 @@ interface ReplicatedSession : PluginBase
void setSequence(Status status, const string name, int64 value);
}
// Profiler interfaces
interface ProfilerPlugin : PluginBase
{
void init(Status status, Attachment attachment, Transaction transaction);
ProfilerSession startSession(Status status, Transaction transaction, const string description,
ISC_TIMESTAMP_TZ timestamp);
void flush(Status status, Transaction transaction);
}
interface ProfilerSession : Disposable
{
const uint FLAG_BEFORE_EVENTS = 0x1;
const uint FLAG_AFTER_EVENTS = 0x2;
int64 getId();
uint getFlags();
void finish(Status status, ISC_TIMESTAMP_TZ timestamp);
//// FIXME: Add memory stats
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);
void beforePsqlLineColumn(int64 requestId, uint line, uint column);
void afterPsqlLineColumn(int64 requestId, uint line, uint column, uint64 runTime);
void beforeRecordSourceOpen(int64 requestId, uint cursorId, uint recSourceId);
void afterRecordSourceOpen(int64 requestId, uint cursorId, uint recSourceId, uint64 runTime);
void beforeRecordSourceGetRecord(int64 requestId, uint cursorId, uint recSourceId);
void afterRecordSourceGetRecord(int64 requestId, uint cursorId, uint recSourceId, uint64 runTime);
}

View File

@ -121,6 +121,8 @@ namespace Firebird
class IReplicatedRecord;
class IReplicatedTransaction;
class IReplicatedSession;
class IProfilerPlugin;
class IProfilerSession;
// Interfaces declarations
@ -825,7 +827,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)
{
@ -6640,6 +6643,164 @@ namespace Firebird
}
};
class IProfilerPlugin : public IPluginBase
{
public:
struct VTable : public IPluginBase::VTable
{
void (CLOOP_CARG *init)(IProfilerPlugin* self, IStatus* status, IAttachment* attachment, ITransaction* transaction) throw();
IProfilerSession* (CLOOP_CARG *startSession)(IProfilerPlugin* self, IStatus* status, ITransaction* transaction, const char* description, ISC_TIMESTAMP_TZ timestamp) throw();
void (CLOOP_CARG *flush)(IProfilerPlugin* self, IStatus* status, ITransaction* transaction) throw();
};
protected:
IProfilerPlugin(DoNotInherit)
: IPluginBase(DoNotInherit())
{
}
~IProfilerPlugin()
{
}
public:
static const unsigned VERSION = 4;
template <typename StatusType> void init(StatusType* status, IAttachment* attachment, ITransaction* transaction)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->init(this, status, attachment, transaction);
StatusType::checkException(status);
}
template <typename StatusType> IProfilerSession* startSession(StatusType* status, ITransaction* transaction, const char* description, ISC_TIMESTAMP_TZ timestamp)
{
StatusType::clearException(status);
IProfilerSession* ret = static_cast<VTable*>(this->cloopVTable)->startSession(this, status, transaction, description, timestamp);
StatusType::checkException(status);
return ret;
}
template <typename StatusType> void flush(StatusType* status, ITransaction* transaction)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->flush(this, status, transaction);
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 *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) 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, ISC_UINT64 runTime) 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, ISC_UINT64 runTime) 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, ISC_UINT64 runTime) 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 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)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->onRequestFinish(this, status, requestId, timestamp);
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, ISC_UINT64 runTime)
{
static_cast<VTable*>(this->cloopVTable)->afterPsqlLineColumn(this, requestId, line, column, runTime);
}
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, ISC_UINT64 runTime)
{
static_cast<VTable*>(this->cloopVTable)->afterRecordSourceOpen(this, requestId, cursorId, recSourceId, runTime);
}
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, ISC_UINT64 runTime)
{
static_cast<VTable*>(this->cloopVTable)->afterRecordSourceGetRecord(this, requestId, cursorId, recSourceId, runTime);
}
};
// Interfaces implementations
template <typename Name, typename StatusType, typename Base>
@ -19768,6 +19929,384 @@ 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, ITransaction* transaction) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::init(&status2, attachment, transaction);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static IProfilerSession* CLOOP_CARG cloopstartSessionDispatcher(IProfilerPlugin* self, IStatus* status, ITransaction* transaction, const char* description, ISC_TIMESTAMP_TZ timestamp) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::startSession(&status2, transaction, description, timestamp);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<IProfilerSession*>(0);
}
}
static void CLOOP_CARG cloopflushDispatcher(IProfilerPlugin* self, IStatus* status, ITransaction* transaction) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::flush(&status2, transaction);
}
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, ITransaction* transaction) = 0;
virtual IProfilerSession* startSession(StatusType* status, ITransaction* transaction, const char* description, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void flush(StatusType* status, ITransaction* transaction) = 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->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 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) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::onRequestFinish(&status2, requestId, timestamp);
}
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, ISC_UINT64 runTime) throw()
{
try
{
static_cast<Name*>(self)->Name::afterPsqlLineColumn(requestId, line, column, runTime);
}
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, ISC_UINT64 runTime) throw()
{
try
{
static_cast<Name*>(self)->Name::afterRecordSourceOpen(requestId, cursorId, recSourceId, runTime);
}
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, ISC_UINT64 runTime) throw()
{
try
{
static_cast<Name*>(self)->Name::afterRecordSourceGetRecord(requestId, cursorId, recSourceId, runTime);
}
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 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) = 0;
virtual void beforePsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column) = 0;
virtual void afterPsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column, ISC_UINT64 runTime) = 0;
virtual void beforeRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) = 0;
virtual void afterRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, ISC_UINT64 runTime) = 0;
virtual void beforeRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) = 0;
virtual void afterRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, ISC_UINT64 runTime) = 0;
};
};

View File

@ -111,6 +111,8 @@ type
IReplicatedRecord = class;
IReplicatedTransaction = class;
IReplicatedSession = class;
IProfilerPlugin = class;
IProfilerSession = class;
FbException = class(Exception)
public
@ -712,6 +714,22 @@ 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; transaction: ITransaction); cdecl;
IProfilerPlugin_startSessionPtr = function(this: IProfilerPlugin; status: IStatus; transaction: ITransaction; description: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl;
IProfilerPlugin_flushPtr = procedure(this: IProfilerPlugin; status: IStatus; transaction: ITransaction); cdecl;
IProfilerSession_getIdPtr = function(this: IProfilerSession): Int64; cdecl;
IProfilerSession_getFlagsPtr = function(this: IProfilerSession): Cardinal; 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); cdecl;
IProfilerSession_beforePsqlLineColumnPtr = procedure(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal); cdecl;
IProfilerSession_afterPsqlLineColumnPtr = procedure(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal; runTime: QWord); cdecl;
IProfilerSession_beforeRecordSourceOpenPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
IProfilerSession_afterRecordSourceOpenPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; runTime: QWord); cdecl;
IProfilerSession_beforeRecordSourceGetRecordPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
IProfilerSession_afterRecordSourceGetRecordPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; runTime: QWord); cdecl;
VersionedVTable = class
version: NativeInt;
@ -1079,7 +1097,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);
@ -3746,6 +3765,87 @@ 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; transaction: ITransaction);
function startSession(status: IStatus; transaction: ITransaction; description: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession;
procedure flush(status: IStatus; transaction: ITransaction);
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; transaction: ITransaction); virtual; abstract;
function startSession(status: IStatus; transaction: ITransaction; description: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; virtual; abstract;
procedure flush(status: IStatus; transaction: ITransaction); virtual; abstract;
end;
ProfilerSessionVTable = class(DisposableVTable)
getId: IProfilerSession_getIdPtr;
getFlags: IProfilerSession_getFlagsPtr;
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 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);
procedure beforePsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal);
procedure afterPsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal; runTime: QWord);
procedure beforeRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
procedure afterRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; runTime: QWord);
procedure beforeRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
procedure afterRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; runTime: QWord);
end;
IProfilerSessionImpl = class(IProfilerSession)
constructor create;
procedure dispose(); virtual; abstract;
function getId(): Int64; virtual; abstract;
function getFlags(): Cardinal; 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); virtual; abstract;
procedure beforePsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal); virtual; abstract;
procedure afterPsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal; runTime: QWord); virtual; abstract;
procedure beforeRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); virtual; abstract;
procedure afterRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; runTime: QWord); virtual; abstract;
procedure beforeRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); virtual; abstract;
procedure afterRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; runTime: QWord); virtual; abstract;
end;
function fb_get_master_interface : IMaster; cdecl; external 'fbclient';
const
@ -8841,6 +8941,93 @@ begin
FbException.checkException(status);
end;
procedure IProfilerPlugin.init(status: IStatus; attachment: IAttachment; transaction: ITransaction);
begin
ProfilerPluginVTable(vTable).init(Self, status, attachment, transaction);
FbException.checkException(status);
end;
function IProfilerPlugin.startSession(status: IStatus; transaction: ITransaction; description: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession;
begin
Result := ProfilerPluginVTable(vTable).startSession(Self, status, transaction, description, timestamp);
FbException.checkException(status);
end;
procedure IProfilerPlugin.flush(status: IStatus; transaction: ITransaction);
begin
ProfilerPluginVTable(vTable).flush(Self, status, transaction);
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.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);
begin
ProfilerSessionVTable(vTable).onRequestFinish(Self, status, requestId, timestamp);
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; runTime: QWord);
begin
ProfilerSessionVTable(vTable).afterPsqlLineColumn(Self, requestId, line, column, runTime);
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; runTime: QWord);
begin
ProfilerSessionVTable(vTable).afterRecordSourceOpen(Self, requestId, cursorId, recSourceId, runTime);
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; runTime: QWord);
begin
ProfilerSessionVTable(vTable).afterRecordSourceGetRecord(Self, requestId, cursorId, recSourceId, runTime);
end;
var
IVersionedImpl_vTable: VersionedVTable;
@ -15343,6 +15530,211 @@ 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; transaction: ITransaction); cdecl;
begin
try
IProfilerPluginImpl(this).init(status, attachment, transaction);
except
on e: Exception do FbException.catchException(status, e);
end
end;
function IProfilerPluginImpl_startSessionDispatcher(this: IProfilerPlugin; status: IStatus; transaction: ITransaction; description: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl;
begin
try
Result := IProfilerPluginImpl(this).startSession(status, transaction, description, timestamp);
except
on e: Exception do FbException.catchException(status, e);
end
end;
procedure IProfilerPluginImpl_flushDispatcher(this: IProfilerPlugin; status: IStatus; transaction: ITransaction); cdecl;
begin
try
IProfilerPluginImpl(this).flush(status, transaction);
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_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); cdecl;
begin
try
IProfilerSessionImpl(this).onRequestFinish(status, requestId, timestamp);
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; runTime: QWord); cdecl;
begin
try
IProfilerSessionImpl(this).afterPsqlLineColumn(requestId, line, column, runTime);
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; runTime: QWord); cdecl;
begin
try
IProfilerSessionImpl(this).afterRecordSourceOpen(requestId, cursorId, recSourceId, runTime);
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; runTime: QWord); cdecl;
begin
try
IProfilerSessionImpl(this).afterRecordSourceGetRecord(requestId, cursorId, recSourceId, runTime);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
var
IProfilerSessionImpl_vTable: ProfilerSessionVTable;
constructor IProfilerSessionImpl.create;
begin
vTable := IProfilerSessionImpl_vTable;
end;
constructor FbException.create(status: IStatus);
begin
inherited Create('FbException');
@ -16331,6 +16723,33 @@ 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.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;
finalization
IVersionedImpl_vTable.destroy;
IReferenceCountedImpl_vTable.destroy;
@ -16427,5 +16846,7 @@ finalization
IReplicatedRecordImpl_vTable.destroy;
IReplicatedTransactionImpl_vTable.destroy;
IReplicatedSessionImpl_vTable.destroy;
IProfilerPluginImpl_vTable.destroy;
IProfilerSessionImpl_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"
@ -1150,3 +1150,16 @@ 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();
}

View File

@ -95,6 +95,7 @@ namespace Jrd
class TrigVector;
class Function;
class JrdStatement;
class ProfilerManager;
class Validation;
class Applier;
@ -562,6 +563,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
@ -795,6 +797,9 @@ public:
void checkReplSetLock(thread_db* tdbb);
void invalidateReplSet(thread_db* tdbb, bool broadcast);
ProfilerManager* getProfilerManager(thread_db* tdbb);
bool isProfilerActive();
JProvider* getProvider()
{
fb_assert(att_provider);
@ -814,6 +819,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.
@ -477,8 +480,6 @@ namespace
}
namespace Jrd {
template <typename T> class ExtEngineManager::ContextManager
{
public:
@ -556,7 +557,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);
@ -736,7 +737,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);
@ -792,7 +793,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);
@ -804,7 +805,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();
}
}
@ -824,7 +825,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);
@ -914,7 +915,7 @@ void ExtEngineManager::Trigger::execute(thread_db* tdbb, jrd_req* 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,
@ -1232,7 +1233,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())
@ -1310,7 +1311,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);
@ -1393,7 +1394,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;
}
@ -1435,7 +1436,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);
@ -1525,7 +1526,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;
}
@ -1586,7 +1587,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,
@ -1624,7 +1625,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;
}
@ -1733,7 +1734,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
}
@ -1776,4 +1777,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();
}

View File

@ -648,10 +648,7 @@ void JrdStatement::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;

526
src/jrd/ProfilerManager.cpp Normal file
View File

@ -0,0 +1,526 @@
/*
* 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): ______________________________________.
*/
#include "firebird.h"
#include "../jrd/ProfilerManager.h"
#include "../jrd/Record.h"
#include "../jrd/ini.h"
#include "../jrd/tra.h"
#include "../jrd/ids.h"
#include "../jrd/recsrc/Cursor.h"
#include "../jrd/dpm_proto.h"
#include "../jrd/met_proto.h"
using namespace Jrd;
using namespace Firebird;
//--------------------------------------
IExternalResultSet* ProfilerPackage::flushProcedure(ThrowStatusExceptionWrapper* /*status*/,
IExternalContext* context, const void* in, void* out)
{
const auto tdbb = JRD_get_thread_data();
const auto attachment = tdbb->getAttachment();
const auto transaction = tdbb->getTransaction();
const auto profilerManager = attachment->getProfilerManager(tdbb);
AutoSetRestore<bool> pauseProfiler(&profilerManager->paused, true);
profilerManager->flush(transaction->getInterface(true));
return nullptr;
}
IExternalResultSet* ProfilerPackage::finishSessionProcedure(ThrowStatusExceptionWrapper* /*status*/,
IExternalContext* context, const FinishSessionInput::Type* in, void* out)
{
const auto tdbb = JRD_get_thread_data();
const auto attachment = tdbb->getAttachment();
const auto transaction = tdbb->getTransaction();
const auto profilerManager = attachment->getProfilerManager(tdbb);
AutoSetRestore<bool> pauseProfiler(&profilerManager->paused, true);
if (profilerManager->currentSession)
{
const auto timestamp = TimeZoneUtil::getCurrentTimeStamp(attachment->att_current_timezone);
LogLocalStatus status("Profiler finish");
profilerManager->currentSession->pluginSession->finish(&status, timestamp);
profilerManager->currentSession = nullptr;
}
if (in->flush)
profilerManager->flush(transaction->getInterface(true));
return nullptr;
}
IExternalResultSet* ProfilerPackage::pauseSessionProcedure(ThrowStatusExceptionWrapper* /*status*/,
IExternalContext* context, const PauseSessionInput::Type* in, void* out)
{
const auto tdbb = JRD_get_thread_data();
const auto attachment = tdbb->getAttachment();
const auto transaction = tdbb->getTransaction();
const auto profilerManager = attachment->getProfilerManager(tdbb);
if (!profilerManager->currentSession)
return nullptr;
profilerManager->paused = true;
if (in->flush)
profilerManager->flush(transaction->getInterface(true));
return nullptr;
}
IExternalResultSet* ProfilerPackage::resumeSessionProcedure(ThrowStatusExceptionWrapper* /*status*/,
IExternalContext* context, const void* in, void* out)
{
const auto tdbb = JRD_get_thread_data();
const auto attachment = tdbb->getAttachment();
const auto profilerManager = attachment->getProfilerManager(tdbb);
if (profilerManager->currentSession && profilerManager->paused)
profilerManager->paused = false;
return nullptr;
}
void ProfilerPackage::startSessionFunction(ThrowStatusExceptionWrapper* /*status*/,
IExternalContext* context, const StartSessionInput::Type* in, StartSessionOutput::Type* out)
{
const auto tdbb = JRD_get_thread_data();
const auto attachment = tdbb->getAttachment();
const auto transaction = tdbb->getTransaction();
const PathName pluginName(in->pluginName.str, in->pluginName.length);
const string description(in->description.str, in->descriptionNull ? 0 : in->description.length);
const auto profilerManager = attachment->getProfilerManager(tdbb);
AutoSetRestore<bool> pauseProfiler(&profilerManager->paused, true);
out->sessionIdNull = FB_FALSE;
out->sessionId = profilerManager->startSession(tdbb, pluginName, description);
}
//--------------------------------------
ProfilerManager::ProfilerManager(thread_db* tdbb)
: activePlugins(*tdbb->getAttachment()->att_pool)
{
}
ProfilerManager* ProfilerManager::create(thread_db* tdbb)
{
return FB_NEW_POOL(*tdbb->getAttachment()->att_pool) ProfilerManager(tdbb);
}
SINT64 ProfilerManager::startSession(thread_db* tdbb, const PathName& pluginName, const string& description)
{
const auto attachment = tdbb->getAttachment();
const auto transaction = tdbb->getTransaction();
ThrowLocalStatus status;
const auto timestamp = TimeZoneUtil::getCurrentTimeStamp(attachment->att_current_timezone);
if (currentSession)
{
currentSession->pluginSession->finish(&status, timestamp);
currentSession = nullptr;
}
auto pluginPtr = activePlugins.get(pluginName);
AutoPlugin<IProfilerPlugin> plugin;
if (pluginPtr)
{
(*pluginPtr)->addRef();
plugin.reset(pluginPtr->get());
}
else
{
GetPlugins<IProfilerPlugin> plugins(IPluginManager::TYPE_PROFILER, pluginName.c_str());
if (!plugins.hasData())
{
string msg;
msg.printf("Profiler plugin %s is not found", pluginName.c_str());
(Arg::Gds(isc_random) << msg).raise();
}
plugin.reset(plugins.plugin());
plugin->addRef();
plugin->init(&status, attachment->getInterface(), transaction->getInterface(true));
plugin->addRef();
activePlugins.put(pluginName)->reset(plugin.get());
}
AutoDispose<IProfilerSession> pluginSession = plugin->startSession(&status,
transaction->getInterface(true),
description.c_str(),
timestamp);
auto& pool = *tdbb->getAttachment()->att_pool;
currentSession.reset(FB_NEW_POOL(pool) ProfilerManager::Session(pool));
currentSession->pluginSession = std::move(pluginSession);
currentSession->plugin = std::move(plugin);
currentSession->flags = currentSession->pluginSession->getFlags();
paused = false;
return currentSession->pluginSession->getId();
}
void ProfilerManager::prepareRecSource(thread_db* tdbb, jrd_req* request, const RecordSource* rsb)
{
auto profileStatement = getStatement(request);
if (!profileStatement)
return;
if (profileStatement->recSourceSequence.exist(rsb->getRecSourceProfileId()))
return;
Array<NonPooledPair<const RecordSource*, const RecordSource*>> tree;
tree.add({rsb, nullptr});
for (unsigned pos = 0; pos < tree.getCount(); ++pos)
{
const auto thisRsb = tree[pos].first;
Array<const RecordSource*> children;
thisRsb->getChildren(children);
unsigned childPos = pos;
for (const auto child : children)
tree.insert(++childPos, {child, thisRsb});
}
NonPooledMap<ULONG, ULONG> idSequenceMap;
auto sequencePtr = profileStatement->cursorNextSequence.getOrPut(rsb->getCursorProfileId());
for (const auto& pair : tree)
{
const auto cursorId = pair.first->getCursorProfileId();
const auto recSourceId = pair.first->getRecSourceProfileId();
idSequenceMap.put(recSourceId, ++*sequencePtr);
string accessPath;
pair.first->print(tdbb, accessPath, true, 0, false);
constexpr auto INDENT_MARKER = "\n ";
if (accessPath.find(INDENT_MARKER) == 0)
{
unsigned pos = 0;
do {
accessPath.erase(pos + 1, 4);
} while ((pos = accessPath.find(INDENT_MARKER, pos + 1)) != string::npos);
}
ULONG parentSequence = 0;
if (pair.second)
parentSequence = *idSequenceMap.get(pair.second->getRecSourceProfileId());
currentSession->pluginSession->defineRecordSource(profileStatement->id, cursorId,
*sequencePtr, accessPath.c_str(), parentSequence);
profileStatement->recSourceSequence.put(recSourceId, *sequencePtr);
}
}
void ProfilerManager::onRequestFinish(jrd_req* request)
{
if (const auto profileRequestId = getRequest(request, 0))
{
const auto timestamp = TimeZoneUtil::getCurrentTimeStamp(request->req_attachment->att_current_timezone);
LogLocalStatus status("Profiler onRequestFinish");
currentSession->pluginSession->onRequestFinish(&status, profileRequestId, timestamp);
currentSession->requests.findAndRemove(profileRequestId);
}
}
void ProfilerManager::beforePsqlLineColumn(jrd_req* request, ULONG line, ULONG column)
{
if (const auto profileRequestId = getRequest(request, IProfilerSession::FLAG_BEFORE_EVENTS))
currentSession->pluginSession->beforePsqlLineColumn(profileRequestId, line, column);
}
void ProfilerManager::afterPsqlLineColumn(jrd_req* request, ULONG line, ULONG column, FB_UINT64 runTime)
{
if (const auto profileRequestId = getRequest(request, IProfilerSession::FLAG_AFTER_EVENTS))
currentSession->pluginSession->afterPsqlLineColumn(profileRequestId, line, column, runTime);
}
void ProfilerManager::beforeRecordSourceOpen(jrd_req* request, const RecordSource* rsb)
{
if (const auto profileRequestId = getRequest(request, IProfilerSession::FLAG_BEFORE_EVENTS))
{
const auto profileStatement = getStatement(request);
const auto sequencePtr = profileStatement->recSourceSequence.get(rsb->getRecSourceProfileId());
fb_assert(sequencePtr);
currentSession->pluginSession->beforeRecordSourceOpen(
profileRequestId, rsb->getCursorProfileId(), *sequencePtr);
}
}
void ProfilerManager::afterRecordSourceOpen(jrd_req* request, const RecordSource* rsb, FB_UINT64 runTime)
{
if (const auto profileRequestId = getRequest(request, IProfilerSession::FLAG_AFTER_EVENTS))
{
const auto profileStatement = getStatement(request);
const auto sequencePtr = profileStatement->recSourceSequence.get(rsb->getRecSourceProfileId());
fb_assert(sequencePtr);
currentSession->pluginSession->afterRecordSourceOpen(
profileRequestId, rsb->getCursorProfileId(), *sequencePtr, runTime);
}
}
void ProfilerManager::beforeRecordSourceGetRecord(jrd_req* request, const RecordSource* rsb)
{
if (const auto profileRequestId = getRequest(request, IProfilerSession::FLAG_BEFORE_EVENTS))
{
const auto profileStatement = getStatement(request);
const auto sequencePtr = profileStatement->recSourceSequence.get(rsb->getRecSourceProfileId());
fb_assert(sequencePtr);
currentSession->pluginSession->beforeRecordSourceGetRecord(
profileRequestId, rsb->getCursorProfileId(), *sequencePtr);
}
}
void ProfilerManager::afterRecordSourceGetRecord(jrd_req* request, const RecordSource* rsb, FB_UINT64 runTime)
{
if (const auto profileRequestId = getRequest(request, IProfilerSession::FLAG_AFTER_EVENTS))
{
const auto profileStatement = getStatement(request);
const auto sequencePtr = profileStatement->recSourceSequence.get(rsb->getRecSourceProfileId());
fb_assert(sequencePtr);
currentSession->pluginSession->afterRecordSourceGetRecord(
profileRequestId, rsb->getCursorProfileId(), *sequencePtr, runTime);
}
}
void ProfilerManager::flush(ITransaction* transaction)
{
auto pluginAccessor = activePlugins.accessor();
for (bool hasNext = pluginAccessor.getFirst(); hasNext;)
{
auto& pluginName = pluginAccessor.current()->first;
auto& plugin = pluginAccessor.current()->second;
LogLocalStatus status("Profiler flush");
plugin->flush(&status, transaction);
hasNext = pluginAccessor.getNext();
if (!currentSession || plugin.get() != currentSession->plugin.get())
activePlugins.remove(pluginName);
}
}
ProfilerManager::Statement* ProfilerManager::getStatement(jrd_req* request)
{
if (!isActive())
return nullptr;
auto mainProfileStatement = currentSession->statements.get(request->getStatement()->getStatementId());
if (mainProfileStatement)
return mainProfileStatement;
for (const auto* statement = request->getStatement();
statement && !currentSession->statements.exist(statement->getStatementId());
statement = statement->parentStatement)
{
MetaName packageName;
MetaName routineName;
const char* type;
if (const auto routine = statement->getRoutine())
{
if (statement->procedure)
type = "PROCEDURE";
else if (statement->function)
type = "FUNCTION";
packageName = routine->getName().package;
routineName = routine->getName().identifier;
}
else if (statement->triggerName.hasData())
{
type = "TRIGGER";
routineName = statement->triggerName;
}
else
type = "BLOCK";
const StmtNumber parentStatementId = statement->parentStatement ?
statement->parentStatement->getStatementId() : 0;
LogLocalStatus status("Profiler defineStatement");
currentSession->pluginSession->defineStatement(&status,
(SINT64) statement->getStatementId(), (SINT64) parentStatementId,
type, packageName.nullStr(), routineName.nullStr(),
(statement->sqlText.hasData() ? statement->sqlText->c_str() : ""));
auto profileStatement = currentSession->statements.put(statement->getStatementId());
profileStatement->id = statement->getStatementId();
if (!mainProfileStatement)
mainProfileStatement = profileStatement;
}
return mainProfileStatement;
}
SINT64 ProfilerManager::getRequest(jrd_req* request, unsigned flags)
{
if (!isActive() || (flags && !(currentSession->flags & flags)))
return 0;
const auto mainRequestId = request->getRequestId();
if (!currentSession->requests.exist(mainRequestId))
{
const auto timestamp = TimeZoneUtil::getCurrentTimeStamp(request->req_attachment->att_current_timezone);
do
{
getStatement(request); // define the statement and ignore the result
const StmtNumber callerRequestId = request->req_caller ? request->req_caller->getRequestId() : 0;
LogLocalStatus status("Profiler onRequestStart");
currentSession->pluginSession->onRequestStart(&status,
(SINT64) request->getRequestId(), (SINT64) request->getStatement()->getStatementId(),
(SINT64) callerRequestId, timestamp);
currentSession->requests.add(request->getRequestId());
request = request->req_caller;
} while (request && !currentSession->requests.exist(request->getRequestId()));
}
return mainRequestId;
}
//--------------------------------------
ProfilerPackage::ProfilerPackage(MemoryPool& pool)
: SystemPackage(
pool,
"RDB$PROFILER",
ODS_13_1,
// procedures
{
SystemProcedure(
pool,
"FINISH_SESSION",
SystemProcedureFactory<FinishSessionInput, VoidMessage, finishSessionProcedure>(),
prc_executable,
// input parameters
{
{"FLUSH", fld_bool, false}
},
// output parameters
{
}
),
SystemProcedure(
pool,
"FLUSH",
SystemProcedureFactory<VoidMessage, VoidMessage, flushProcedure>(),
prc_executable,
// input parameters
{
},
// output parameters
{
}
),
SystemProcedure(
pool,
"PAUSE_SESSION",
SystemProcedureFactory<PauseSessionInput, VoidMessage, pauseSessionProcedure>(),
prc_executable,
// input parameters
{
{"FLUSH", fld_bool, false}
},
// output parameters
{
}
),
SystemProcedure(
pool,
"RESUME_SESSION",
SystemProcedureFactory<VoidMessage, VoidMessage, resumeSessionProcedure>(),
prc_executable,
// input parameters
{
},
// output parameters
{
}
)
},
// functions
{
SystemFunction(
pool,
"START_SESSION",
SystemFunctionFactory<StartSessionInput, StartSessionOutput, startSessionFunction>(),
// parameters
{
{"PLUGIN_NAME", fld_file_name2, true},
{"DESCRIPTION", fld_short_description, true}
},
{fld_prof_ses_id, false}
)
}
)
{
}

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

@ -0,0 +1,172 @@
/*
* 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 "../jrd/Monitoring.h"
#include "../jrd/SystemPackages.h"
namespace Jrd {
class Attachment;
class jrd_req;
class thread_db;
class Profiler;
class ProfilerManager final
{
friend class ProfilerPackage;
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:
static ProfilerManager* create(thread_db* tdbb);
ProfilerManager(const ProfilerManager&) = delete;
void operator=(const ProfilerManager&) = delete;
public:
SINT64 startSession(thread_db* tdbb, const Firebird::PathName& pluginName, const Firebird::string& description);
void prepareRecSource(thread_db* tdbb, jrd_req* request, const RecordSource* rsb);
void onRequestFinish(jrd_req* request);
void beforePsqlLineColumn(jrd_req* request, ULONG line, ULONG column);
void afterPsqlLineColumn(jrd_req* request, ULONG line, ULONG column, FB_UINT64 runTime);
void beforeRecordSourceOpen(jrd_req* request, const RecordSource* rsb);
void afterRecordSourceOpen(jrd_req* request, const RecordSource* rsb, FB_UINT64 runTime);
void beforeRecordSourceGetRecord(jrd_req* request, const RecordSource* rsb);
void afterRecordSourceGetRecord(jrd_req* request, const RecordSource* rsb, FB_UINT64 runTime);
bool isActive() const
{
return currentSession && !paused;
}
private:
void flush(Firebird::ITransaction* transaction);
Statement* getStatement(jrd_req* request);
SINT64 getRequest(jrd_req* request, unsigned flags);
private:
Firebird::LeftPooledMap<Firebird::PathName, Firebird::AutoPlugin<Firebird::IProfilerPlugin>> activePlugins;
Firebird::AutoPtr<Session> currentSession;
bool paused = false;
};
class ProfilerPackage : public SystemPackage
{
public:
ProfilerPackage(Firebird::MemoryPool& pool);
private:
static Firebird::IExternalResultSet* flushProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const void* in, void* out);
//----------
FB_MESSAGE(FinishSessionInput, Firebird::ThrowStatusExceptionWrapper,
(FB_BOOLEAN, flush)
);
static Firebird::IExternalResultSet* finishSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const FinishSessionInput::Type* in, void* out);
//----------
FB_MESSAGE(PauseSessionInput, Firebird::ThrowStatusExceptionWrapper,
(FB_BOOLEAN, flush)
);
static Firebird::IExternalResultSet* pauseSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const PauseSessionInput::Type* in, void* out);
//----------
static Firebird::IExternalResultSet* resumeSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const void* in, void* out);
//----------
FB_MESSAGE(StartSessionInput, Firebird::ThrowStatusExceptionWrapper,
(FB_INTL_VARCHAR(255, CS_METADATA), pluginName)
//// TODO: Options: PSQL, SQL.
(FB_INTL_VARCHAR(255, CS_METADATA), description)
//// TODO: Plugin options.
);
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

@ -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>
@ -190,6 +191,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<
@ -203,6 +239,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);
}
@ -223,10 +262,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()(
@ -265,6 +311,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);
}
@ -279,10 +328,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

@ -515,6 +515,8 @@ RecordSource* CMP_post_rse(thread_db* tdbb, CompilerScratch* csb, RseNode* rse)
DEV_BLKCHK(csb, type_csb);
DEV_BLKCHK(rse, type_nod);
AutoSetRestore<ULONG> autoCurrentCursorProfileId(&csb->csb_currentCursorProfileId, csb->csb_nextCursorProfileId++);
RecordSource* rsb = OPT_compile(tdbb, csb, rse, NULL);
if (rse->flags & RseNode::FLAG_SINGULAR)

View File

@ -111,6 +111,7 @@
#include "../jrd/recsrc/RecordSource.h"
#include "../jrd/recsrc/Cursor.h"
#include "../jrd/Function.h"
#include "../jrd/ProfilerManager.h"
using namespace Jrd;
@ -998,6 +999,11 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request)
}
release_blobs(tdbb, request);
const auto attachment = request->req_attachment;
if (attachment->isProfilerActive() && !request->hasInternalStatement())
attachment->getProfilerManager(tdbb)->onRequestFinish(request);
}
request->req_sorts.unlinkAll();
@ -1336,10 +1342,10 @@ const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* 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
@ -1353,6 +1359,11 @@ const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* no
// Execute stuff until we drop
SINT64 lastPerfCounter = fb_utils::query_performance_counter();
const StmtNode* profileNode = nullptr;
ULONG lastProfiledLine = node->line;
ULONG lastProfiledColumn = node->column;
while (node && !(request->req_flags & req_stall))
{
try
@ -1366,6 +1377,33 @@ const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* no
request->req_src_line = node->line;
request->req_src_column = node->column;
}
if (attachment->isProfilerActive() && !request->hasInternalStatement())
{
if (profileNode &&
profileNode->hasLineColumn &&
profileNode->isProfileAware() &&
(profileNode->line != lastProfiledLine || profileNode->column != lastProfiledColumn))
{
const SINT64 currentPerfCounter = fb_utils::query_performance_counter();
attachment->getProfilerManager(tdbb)->afterPsqlLineColumn(request,
profileNode->line, profileNode->column,
currentPerfCounter - lastPerfCounter);
lastPerfCounter = currentPerfCounter;
lastProfiledLine = profileNode->line;
lastProfiledColumn = profileNode->column;
}
if (node->hasLineColumn)
{
profileNode = node;
attachment->getProfilerManager(tdbb)->beforePsqlLineColumn(request,
profileNode->line, profileNode->column);
}
}
}
node = node->execute(tdbb, request, &exeState);
@ -1410,6 +1448,20 @@ const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* no
}
} // while()
if (attachment->isProfilerActive() &&
!request->hasInternalStatement() &&
profileNode &&
profileNode->hasLineColumn &&
profileNode->isProfileAware() &&
(profileNode->line != lastProfiledLine || profileNode->column != lastProfiledColumn))
{
const SINT64 currentPerfCounter = fb_utils::query_performance_counter();
attachment->getProfilerManager(tdbb)->afterPsqlLineColumn(request,
profileNode->line, profileNode->column,
currentPerfCounter - lastPerfCounter);
}
request->adjustCallerStats();
fb_assert(request->req_auto_trans.getCount() == 0);

View File

@ -549,6 +549,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,6 @@
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_prof_ses_id , nam_prof_ses_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true)

View File

@ -944,7 +944,7 @@ void Trigger::compile(thread_db* tdbb)
statement->triggerInvoker = att->getUserId(owner);
if (sysTrigger)
statement->flags |= JrdStatement::FLAG_SYS_TRIGGER;
statement->flags |= JrdStatement::FLAG_SYS_TRIGGER | JrdStatement::FLAG_INTERNAL;
if (flags & TRG_ignore_perm)
statement->flags |= JrdStatement::FLAG_IGNORE_PERM;
@ -5136,7 +5136,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);
}
@ -5548,7 +5548,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();

View File

@ -1078,18 +1078,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()
@ -1123,7 +1133,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);
}
}
@ -1151,7 +1161,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

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

View File

@ -460,3 +460,6 @@ 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$PROFILE_SESSION_ID", nam_prof_ses_id)

View File

@ -79,6 +79,7 @@
#include "../jrd/RecordSourceNodes.h"
#include "../jrd/VirtualTable.h"
#include "../jrd/Monitoring.h"
#include "../jrd/ProfilerManager.h"
#include "../jrd/TimeZone.h"
#include "../jrd/UserManagement.h"
#include "../common/classes/array.h"
@ -462,7 +463,7 @@ string OPT_get_plan(thread_db* tdbb, const JrdStatement* statement, bool detaile
for (FB_SIZE_T i = 0; i < fors.getCount(); i++)
{
plan += detailed ? "\nSelect Expression" : "\nPLAN ";
fors[i]->print(tdbb, plan, detailed, 0);
fors[i]->print(tdbb, plan, detailed, 0, true);
}
}

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

@ -52,7 +52,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
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = getImpure(request);
@ -365,15 +365,21 @@ 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)
plan += printIndent(++level) + "Aggregate";
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

@ -46,7 +46,7 @@ BitmapTableScan::BitmapTableScan(CompilerScratch* csb, const string& alias,
m_impure = csb->allocImpure<Impure>();
}
void BitmapTableScan::open(thread_db* tdbb) const
void BitmapTableScan::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -80,7 +80,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);
@ -121,8 +121,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);
@ -112,7 +114,7 @@ BufferedStream::BufferedStream(CompilerScratch* csb, RecordSource* next)
m_format = format;
}
void BufferedStream::open(thread_db* tdbb) const
void BufferedStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -147,7 +149,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);
@ -311,7 +313,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)
{
@ -321,7 +328,8 @@ void BufferedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
plan += printIndent(++level) + "Record Buffer" + extras;
}
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void BufferedStream::markRecursive()

View File

@ -41,14 +41,17 @@ 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);
m_impure = csb->allocImpure<Impure>();
}
void ConditionalStream::open(thread_db* tdbb) const
void ConditionalStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -75,7 +78,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);
@ -110,24 +113,34 @@ 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";
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,9 @@ Cursor::Cursor(CompilerScratch* csb, const RecordSource* rsb,
void Cursor::open(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
const auto attachment = tdbb->getAttachment();
Impure* impure = request->getImpure<Impure>(m_impure);
impure->irsb_active = true;
@ -132,7 +135,9 @@ bool Cursor::fetchNext(thread_db* tdbb) const
if (!validate(tdbb))
return false;
jrd_req* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
const auto attachment = tdbb->getAttachment();
Impure* const impure = request->getImpure<Impure>(m_impure);
if (!impure->irsb_active)
@ -197,7 +202,9 @@ bool Cursor::fetchPrior(thread_db* tdbb) const
if (!validate(tdbb))
return false;
jrd_req* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
const auto attachment = tdbb->getAttachment();
Impure* const impure = request->getImpure<Impure>(m_impure);
if (!impure->irsb_active)
@ -274,7 +281,9 @@ bool Cursor::fetchAbsolute(thread_db* tdbb, SINT64 offset) const
if (!validate(tdbb))
return false;
jrd_req* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
const auto attachment = tdbb->getAttachment();
Impure* const impure = request->getImpure<Impure>(m_impure);
if (!impure->irsb_active)
@ -323,7 +332,9 @@ bool Cursor::fetchRelative(thread_db* tdbb, SINT64 offset) const
if (!validate(tdbb))
return false;
jrd_req* const request = tdbb->getRequest();
const auto request = tdbb->getRequest();
const auto attachment = tdbb->getAttachment();
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_impure = csb->allocImpure<Impure>();
}
void ExternalTableScan::open(thread_db* tdbb) const
void ExternalTableScan::internalOpen(thread_db* tdbb) const
{
Database* const dbb = tdbb->getDatabase();
jrd_req* 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,15 +36,20 @@ using namespace Jrd;
// ------------------------------------
FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean)
: m_next(next), m_boolean(boolean), m_anyBoolean(NULL),
m_ansiAny(false), m_ansiAll(false), m_ansiNot(false)
: 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);
m_impure = csb->allocImpure<Impure>();
}
void FilteredStream::open(thread_db* tdbb) const
void FilteredStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -70,7 +75,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);
@ -102,12 +107,18 @@ 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)
plan += printIndent(++level) + "Filter";
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void FilteredStream::markRecursive()

View File

@ -37,14 +37,16 @@ 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);
m_impure = csb->allocImpure<Impure>();
}
void FirstRowsStream::open(thread_db* tdbb) const
void FirstRowsStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -81,7 +83,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);
@ -112,12 +114,18 @@ 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)
plan += printIndent(++level) + "First N Records";
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void FirstRowsStream::markRecursive()

View File

@ -38,14 +38,16 @@ 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);
m_impure = csb->allocImpure<Impure>();
}
void FullOuterJoin::open(thread_db* tdbb) const
void FullOuterJoin::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -74,7 +76,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);
@ -110,21 +112,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

@ -47,7 +47,7 @@ FullTableScan::FullTableScan(CompilerScratch* csb, const string& alias,
m_impure = csb->allocImpure<Impure>();
}
void FullTableScan::open(thread_db* tdbb) const
void FullTableScan::internalOpen(thread_db* tdbb) const
{
Database* const dbb = tdbb->getDatabase();
Attachment* const attachment = tdbb->getAttachment();
@ -131,7 +131,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);
@ -161,7 +161,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

@ -209,7 +209,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);
@ -281,7 +282,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
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -346,7 +347,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);
@ -426,29 +427,40 @@ 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)";
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

@ -60,7 +60,7 @@ IndexTableScan::IndexTableScan(CompilerScratch* csb, const string& alias,
m_impure = csb->allocImpure(FB_ALIGNMENT, static_cast<ULONG>(size));
}
void IndexTableScan::open(thread_db* tdbb) const
void IndexTableScan::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -123,7 +123,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);
@ -263,7 +263,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

@ -44,7 +44,7 @@ LocalTableStream::LocalTableStream(CompilerScratch* csb, StreamType stream, cons
m_impure = csb->allocImpure<Impure>();
}
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);
@ -69,7 +69,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);
@ -108,7 +112,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,14 +35,15 @@ using namespace Jrd;
// ------------------------------------
LockedStream::LockedStream(CompilerScratch* csb, RecordSource* next)
: m_next(next)
: RecordSource(csb),
m_next(next)
{
fb_assert(m_next);
m_impure = csb->allocImpure<Impure>();
}
void LockedStream::open(thread_db* tdbb) const
void LockedStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -68,7 +69,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);
@ -102,12 +103,18 @@ 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)
plan += printIndent(++level) + "Write Lock";
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));
@ -56,7 +58,7 @@ MergeJoin::MergeJoin(CompilerScratch* csb, FB_SIZE_T count,
}
}
void MergeJoin::open(thread_db* tdbb) const
void MergeJoin::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -125,7 +127,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);
@ -180,7 +182,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;
}
@ -224,7 +226,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;
@ -255,7 +257,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);
@ -336,14 +338,23 @@ 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)";
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
{
@ -354,7 +365,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 += ")";
}
@ -434,7 +445,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
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);

View File

@ -35,7 +35,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>();
@ -47,7 +50,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);
@ -57,7 +63,7 @@ NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, Record
m_args.add(inner);
}
void NestedLoopJoin::open(thread_db* tdbb) const
void NestedLoopJoin::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -82,7 +88,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);
@ -196,7 +202,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())
{
@ -226,8 +238,11 @@ void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigne
fb_assert(false);
}
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
{
@ -238,7 +253,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

@ -53,7 +53,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())
{
@ -159,7 +159,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);
@ -241,7 +241,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

@ -26,6 +26,7 @@
#include "../jrd/intl.h"
#include "../jrd/req.h"
#include "../jrd/rse.h"
#include "../jrd/ProfilerManager.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dpm_proto.h"
#include "../jrd/err_proto.h"
@ -44,6 +45,72 @@ using namespace Jrd;
// Record source class
// -------------------
RecordSource::RecordSource(CompilerScratch* csb)
: m_impure(0),
m_cursorProfileId(csb->csb_currentCursorProfileId),
m_recSourceProfileId(csb->csb_nextRecSourceProfileId++),
m_recursive(false)
{
}
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->afterRecordSourceOpen(request, this, currentPerfCounter - lastPerfCounter);
}
}
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->afterRecordSourceGetRecord(request, this, currentPerfCounter - lastPerfCounter);
}
return ret;
}
string RecordSource::printName(thread_db* tdbb, const string& name, bool quote)
{
const string result(name.c_str(), name.length());
@ -182,7 +249,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

@ -58,15 +58,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(jrd_req* request) const = 0;
@ -86,6 +86,20 @@ namespace Jrd
return true;
}
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
@ -99,9 +113,7 @@ namespace Jrd
static const ULONG irsb_mustread = 8;
static const ULONG irsb_singular_processed = 16;
RecordSource()
: m_impure(0), m_recursive(false)
{}
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,
@ -115,7 +127,12 @@ namespace Jrd
static void saveRecord(thread_db* tdbb, record_param* rpb);
static void restoreRecord(thread_db* tdbb, record_param* rpb);
virtual void internalOpen(thread_db* tdbb) const = 0;
virtual bool internalGetRecord(thread_db* tdbb) const = 0;
ULONG m_impure;
ULONG m_cursorProfileId;
ULONG m_recSourceProfileId;
bool m_recursive;
};
@ -157,13 +174,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;
@ -182,13 +202,16 @@ namespace Jrd
BitmapTableScan(CompilerScratch* csb, const Firebird::string& alias,
StreamType stream, jrd_rel* relation, InversionNode* inversion);
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;
@ -217,13 +240,12 @@ namespace Jrd
StreamType stream, jrd_rel* relation,
InversionNode* index, USHORT keyLength);
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)
{
@ -232,6 +254,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;
@ -262,15 +288,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;
@ -283,17 +313,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;
@ -316,15 +349,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,
@ -345,15 +382,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(jrd_req* request) const override;
@ -361,9 +398,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;
};
@ -373,15 +412,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(jrd_req* request) const override;
@ -389,6 +428,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;
};
@ -403,15 +446,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(jrd_req* request) const override;
@ -424,6 +467,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;
@ -439,15 +486,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(jrd_req* request) const override;
@ -460,6 +507,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;
@ -470,15 +521,15 @@ namespace Jrd
public:
FilteredStream(CompilerScratch* csb, RecordSource* next, 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(jrd_req* request) const override;
@ -496,6 +547,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;
@ -565,15 +620,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(jrd_req* request) const override;
@ -614,6 +669,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;
@ -708,7 +767,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;
@ -720,6 +778,8 @@ namespace Jrd
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
protected:
void internalOpen(thread_db* tdbb) const override;
Impure* getImpure(jrd_req* request) const
{
return request->getImpure<typename ThisType::Impure>(m_impure);
@ -782,8 +842,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
@ -846,16 +910,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(jrd_req* request) const
{
return request->getImpure<Impure>(m_impure);
@ -883,15 +949,15 @@ namespace Jrd
WindowedStream(thread_db* tdbb, CompilerScratch* csb,
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(jrd_req* request) const override;
@ -899,6 +965,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;
@ -908,6 +978,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(jrd_req* request) const = 0;
@ -943,15 +1017,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(jrd_req* request) const override;
@ -968,6 +1042,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;
@ -983,15 +1061,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(jrd_req* request) const override;
@ -999,6 +1077,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;
@ -1012,15 +1094,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(jrd_req* request) const override;
@ -1028,6 +1110,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;
@ -1061,15 +1147,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(jrd_req* request) const override;
@ -1077,6 +1163,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:
ULONG computeHash(thread_db* tdbb, jrd_req* request,
const SubStream& sub, UCHAR* buffer) const;
@ -1121,15 +1211,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(jrd_req* request) const override;
@ -1137,11 +1227,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;
@ -1153,14 +1247,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;
@ -1178,20 +1277,24 @@ namespace Jrd
FB_SIZE_T argCount, RecordSource* const* args, NestConst<MapNode>* maps,
FB_SIZE_T streamCount, const StreamType* 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(jrd_req* 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;
@ -1219,20 +1322,24 @@ namespace Jrd
FB_SIZE_T streamCount, const StreamType* 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(jrd_req* 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(jrd_req* request, Impure* impure) const;
@ -1257,15 +1364,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(jrd_req* request) const override;
@ -1273,6 +1380,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

@ -66,7 +66,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
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -115,7 +115,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);
@ -243,24 +243,34 @@ 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";
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

@ -33,7 +33,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);
@ -42,7 +44,7 @@ SingularStream::SingularStream(CompilerScratch* csb, RecordSource* next)
m_impure = csb->allocImpure<Impure>();
}
void SingularStream::open(thread_db* tdbb) const
void SingularStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -68,7 +70,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);
@ -83,55 +85,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
{
jrd_req* 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);
@ -142,12 +137,18 @@ 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)
plan += printIndent(++level) + "Singularity Check";
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void SingularStream::markRecursive()

View File

@ -37,14 +37,16 @@ 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);
m_impure = csb->allocImpure<Impure>();
}
void SkipRowsStream::open(thread_db* tdbb) const
void SkipRowsStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -80,7 +82,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);
@ -113,12 +115,18 @@ 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)
plan += printIndent(++level) + "Skip N Records";
m_next->print(tdbb, plan, detailed, level);
if (recurse)
m_next->print(tdbb, plan, detailed, level, recurse);
}
void SkipRowsStream::markRecursive()

View File

@ -43,14 +43,16 @@ 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);
m_impure = csb->allocImpure<Impure>();
}
void SortedStream::open(thread_db* tdbb) const
void SortedStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -84,7 +86,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);
@ -114,8 +116,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)
{
@ -129,13 +136,14 @@ void SortedStream::print(thread_db* tdbb, string& plan,
plan += printIndent(++level) +
((m_map->flags & FLAG_PROJECT) ? "Unique Sort" : "Sort") + extras;
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

@ -59,7 +59,7 @@ Union::Union(CompilerScratch* csb, StreamType stream,
m_streams[i] = streams[i];
}
void Union::open(thread_db* tdbb) const
void Union::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -97,7 +97,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);
@ -164,14 +164,23 @@ 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");
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
{
@ -183,7 +192,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_impure = csb->allocImpure<Impure>();
}
void VirtualTableScan::open(thread_db* tdbb) const
void VirtualTableScan::internalOpen(thread_db* tdbb) const
{
jrd_req* 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

@ -50,34 +50,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(jrd_req* 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(jrd_req* 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
{
jrd_req* 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(jrd_req* request) const
FB_UINT64 getPosition(jrd_req* request) const override
{
Impure* const impure = request->getImpure<Impure>(m_impure);
return impure->irsb_position;
@ -90,12 +92,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
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -116,7 +119,7 @@ namespace
impure->irsb_flags &= ~irsb_open;
}
bool BufferedStreamWindow::getRecord(thread_db* tdbb) const
bool BufferedStreamWindow::internalGetRecord(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -142,9 +145,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()
@ -184,7 +193,8 @@ namespace
WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb,
ObjectsArray<WindowSourceNode::Window>& windows, RecordSource* next)
: m_next(FB_NEW_POOL(csb->csb_pool) BufferedStream(csb, next)),
: RecordSource(csb),
m_next(FB_NEW_POOL(csb->csb_pool) BufferedStream(csb, next)),
m_joinedStream(NULL)
{
m_impure = csb->allocImpure<Impure>();
@ -330,7 +340,7 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb,
}
}
void WindowedStream::open(thread_db* tdbb) const
void WindowedStream::internalOpen(thread_db* tdbb) const
{
jrd_req* const request = tdbb->getRequest();
Impure* const impure = request->getImpure<Impure>(m_impure);
@ -357,7 +367,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);
@ -384,9 +394,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()
@ -502,9 +518,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);
jrd_req* const request = tdbb->getRequest();
Impure* const impure = getImpure(request);
@ -539,7 +555,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);
@ -867,13 +883,19 @@ 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)
plan += printIndent(++level) + "Window";
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

@ -828,7 +828,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

@ -88,6 +88,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"

View File

@ -414,7 +414,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);
}
@ -1398,7 +1398,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);
}
@ -3826,7 +3826,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