mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 20:03:02 +01:00
Profiler.
This commit is contained in:
parent
f60cf7f674
commit
2f503f2e2d
@ -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)
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
29
builds/win32/msvc15/default_profiler.filters
Normal file
29
builds/win32/msvc15/default_profiler.filters
Normal 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>
|
230
builds/win32/msvc15/default_profiler.vcxproj
Normal file
230
builds/win32/msvc15/default_profiler.vcxproj
Normal 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>
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
349
doc/sql.extensions/README.profiler.md
Normal file
349
doc/sql.extensions/README.profiler.md
Normal 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
|
||||
```
|
@ -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);
|
||||
|
@ -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>;
|
||||
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,12 @@ namespace Firebird
|
||||
r.ptr = nullptr;
|
||||
}
|
||||
|
||||
RefPtr(MemoryPool&, RefPtr&& r)
|
||||
: ptr(r.ptr)
|
||||
{
|
||||
r.ptr = nullptr;
|
||||
}
|
||||
|
||||
~RefPtr()
|
||||
{
|
||||
if (ptr)
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
526
src/jrd/ProfilerManager.cpp
Normal 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
172
src/jrd/ProfilerManager.h
Normal 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
|
@ -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;
|
||||
|
@ -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()(
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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 += ")";
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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 += ")";
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 += ")";
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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 += ")";
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 += ")";
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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 += ")";
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
1224
src/plugins/profiler/Profiler.cpp
Normal file
1224
src/plugins/profiler/Profiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user