mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 17:23:03 +01:00
Merge branch 'work/profiler-plugin' into work/profiler-plugin-merge
This commit is contained in:
commit
581795ed78
@ -507,6 +507,12 @@
|
||||
#
|
||||
#UserManager = Srp
|
||||
|
||||
# Default profiler plugin used to profile connections using the RDB$PROFILER package.
|
||||
#
|
||||
# Per-database configurable.
|
||||
#
|
||||
#DefaultProfilerPlugin = Default_Profiler
|
||||
|
||||
# TracePlugin is used by firebird trace facility to send trace data to the user
|
||||
# or log file in audit case.
|
||||
#
|
||||
|
@ -548,7 +548,7 @@ $(NBACKUP): $(NBACKUP_Objects) $(COMMON_LIB)
|
||||
# plugins - some of them are required to build examples, use separate entry for them
|
||||
#
|
||||
|
||||
.PHONY: udr legacy_user_management legacy_auth_server trace auth_debug udf_compat chacha
|
||||
.PHONY: udr legacy_user_management legacy_auth_server trace auth_debug udf_compat chacha profiler
|
||||
UDR_PLUGIN = $(call makePluginName,udr_engine)
|
||||
LEGACY_USER_MANAGER = $(call makePluginName,Legacy_UserManager)
|
||||
LEGACY_AUTH_SERVER = $(call makePluginName,Legacy_Auth)
|
||||
@ -558,13 +558,14 @@ AUTH_DEBUGGER = $(call makePluginName,Auth_Debug)
|
||||
UDF_BACKWARD_COMPATIBILITY_BASENAME = $(LIB_PREFIX)udf_compat.$(SHRLIB_EXT)
|
||||
UDF_BACKWARD_COMPATIBILITY = $(PLUGINS)/udr/$(UDF_BACKWARD_COMPATIBILITY_BASENAME)
|
||||
CHACHA = $(call makePluginName,ChaCha)
|
||||
PROFILER = $(call makePluginName,Default_Profiler)
|
||||
|
||||
BUILD_DEBUG:=
|
||||
ifeq ($(TARGET),Debug)
|
||||
BUILD_DEBUG:=auth_debug
|
||||
endif
|
||||
|
||||
plugins: udr legacy_user_management legacy_auth_server srp_user_management trace $(BUILD_DEBUG) udf_compat chacha
|
||||
plugins: udr legacy_user_management legacy_auth_server srp_user_management trace $(BUILD_DEBUG) udf_compat chacha profiler
|
||||
|
||||
udr: $(UDR_PLUGIN) $(PLUGINS)/udr_engine.conf
|
||||
|
||||
@ -593,6 +594,12 @@ $(LEGACY_AUTH_SERVER): $(LEGACY_AUTH_SERVER_Objects) $(COMMON_LIB)
|
||||
$(LINK_PLUGIN) $(call LIB_LINK_SONAME,$(notdir $@).0) -o $@ $^ $(LINK_PLUG_LIBS) $(FIREBIRD_LIBRARY_LINK)\
|
||||
$(call LIB_LINK_DARWIN_INSTALL_NAME,plugins/libLegacy_Auth.$(SHRLIB_EXT))
|
||||
|
||||
profiler: $(PROFILER)
|
||||
|
||||
$(PROFILER): $(Profiler_Objects) $(COMMON_LIB)
|
||||
$(LINK_PLUGIN) $(call LIB_LINK_SONAME,$(notdir $@).0) -o $@ $^ $(LINK_PLUG_LIBS) $(FIREBIRD_LIBRARY_LINK)\
|
||||
$(call LIB_LINK_DARWIN_INSTALL_NAME,plugins/libDefault_Profiler.$(SHRLIB_EXT))
|
||||
|
||||
trace: $(FBTRACE)
|
||||
|
||||
$(FBTRACE): $(FBTRACE_UTIL_Objects) $(COMMON_LIB)
|
||||
|
@ -79,9 +79,12 @@ AllObjects += $(Remote_Common) $(Remote_Server) $(Remote_Client)
|
||||
|
||||
# Chacha plugin
|
||||
Chacha_Objects:= $(call dirObjects,plugins/crypt/chacha)
|
||||
|
||||
AllObjects += $(Chacha_Objects)
|
||||
|
||||
# Profiler plugin
|
||||
Profiler_Objects:= $(call dirObjects,plugins/profiler)
|
||||
AllObjects += $(Profiler_Objects)
|
||||
|
||||
# Engine
|
||||
Engine_Objects:= $(call dirObjects,jrd) $(call dirObjects,dsql) $(call dirObjects,jrd/extds) \
|
||||
$(call dirObjects,jrd/optimizer) $(call dirObjects,jrd/recsrc) $(call dirObjects,jrd/replication) $(call dirObjects,jrd/trace) \
|
||||
|
@ -84,6 +84,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chacha", "chacha.vcxproj",
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "engine_static", "engine_static.vcxproj", "{B32D1B09-8161-451E-8D20-D30F26094EC0}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "default_profiler", "default_profiler.vcxproj", "{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LIBs", "LIBs", "{DA5015E4-8349-4DAB-A1E5-18BDBDDA3022}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EXEs", "EXEs", "{3E6F3FA4-225F-4591-A466-05FDBEF56DBF}"
|
||||
@ -390,6 +392,14 @@ Global
|
||||
{3314D6AD-554F-4AE1-B297-6D2D6207DD7C}.Release|Win32.Build.0 = Release|Win32
|
||||
{3314D6AD-554F-4AE1-B297-6D2D6207DD7C}.Release|x64.ActiveCfg = Release|x64
|
||||
{3314D6AD-554F-4AE1-B297-6D2D6207DD7C}.Release|x64.Build.0 = Release|x64
|
||||
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Debug|x64.Build.0 = Debug|x64
|
||||
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Release|Win32.Build.0 = Release|Win32
|
||||
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Release|x64.ActiveCfg = Release|x64
|
||||
{9821F2C0-4EC1-4ACB-BF32-DEB4C21032DE}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
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>
|
@ -13,4 +13,4 @@
|
||||
<Filter>Resource files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -109,6 +109,7 @@
|
||||
<ClCompile Include="..\..\..\src\jrd\pag.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\par.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\PreparedStatement.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\ProfilerManager.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RandomGenerator.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordBuffer.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordSourceNodes.cpp" />
|
||||
@ -308,6 +309,7 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\pag_proto.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\par_proto.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\ProfilerManager.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\QualifiedName.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\que.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RandomGenerator.h" />
|
||||
|
@ -327,6 +327,9 @@
|
||||
<ClCompile Include="..\..\..\src\jrd\PreparedStatement.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\jrd\ProfilerManager.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\jrd\RandomGenerator.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
@ -914,6 +917,9 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\ProfilerManager.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\que.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
@ -1112,4 +1118,4 @@
|
||||
<Filter>DSQL</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -558,6 +558,7 @@ GRANT_REVOKE_ANY_DDL_RIGHT GRANT and REVOKE any DDL rights
|
||||
CREATE_PRIVILEGED_ROLES Use SET SYSTEM PRIVILEGES in roles
|
||||
MODIFY_EXT_CONN_POOL Manage properties of pool of external connections
|
||||
REPLICATE_INTO_DATABASE Use replication API to load changesets into database
|
||||
PROFILE_ANY_ATTACHMENT Profile other users' attachments
|
||||
|
||||
|
||||
22) New grantee type in GRANT and REVOKE operators - SYSTEM PRIVILEGE.
|
||||
|
445
doc/sql.extensions/README.profiler.md
Normal file
445
doc/sql.extensions/README.profiler.md
Normal file
@ -0,0 +1,445 @@
|
||||
# Profiler (FB 5.0)
|
||||
|
||||
The profiler allows users to measure performance cost of SQL and PSQL code.
|
||||
|
||||
It's implemented with a system package in the engine passing data to a profiler plugin.
|
||||
|
||||
This documentation treats the engine and plugin parts as a single thing, in the way the default profiler (`Default_Profiler`) is going to be used.
|
||||
|
||||
The `RDB$PROFILER` package allows to profile execution of PSQL code collecting statistics of how many times each line was executed along with its minimum, maximum and accumulated execution times (with nanoseconds precision), as well open and fetch statistics of implicit and explicit SQL cursors.
|
||||
|
||||
To collect profile data, an user must first start a profile session with `RDB$PROFILER.START_SESSION`. This function returns an profile session ID which is later stored in the profiler snapshot tables to be queried and analyzed by the user. A profiler session may be local (same attachment) or remote (another attachment).
|
||||
|
||||
Remote profiling just forwards commands to the remote attachment. So it's possible that a client simultaneous profile multiple attachments. It's also possible that a locally or remotely started profile session have commands issued by another attachment.
|
||||
|
||||
Remote issued commands needs that the target attachment be in an idle state, i.e., not executing others requests. When they are not idle the call blocks waiting for that state.
|
||||
|
||||
If remote attachment is from a different user, the calling user must have system privilege PROFILE_ANY_ATTACHMENT.
|
||||
|
||||
After a session is started, PSQL and SQL statements statistics starts to be collected in memory. Note that a profile session collects data only of statements executed in the same attachment associated with the session.
|
||||
|
||||
Data is aggregated and stored per requests (i.e. a statement execution). When querying snapshot tables, user may do extra aggregation per statements or use the auxiliary views that do that automatically.
|
||||
|
||||
A session may be paused to temporary disable statistics collecting. It may be resumed later to return statistics collection in the same session.
|
||||
|
||||
A new session may be started when a session is already active. In this case it has the same semantics of finishing the current session with `RDB$PROFILER.FINISH_SESSION(FALSE)` so snapshots tables are not updated in the same moment.
|
||||
|
||||
To analyze the collected data, the user must flush the data to the snapshot tables, which may be done finishing or pausing a session (with `FLUSH` parameter set to `TRUE`) or calling `RDB$PROFILER.FLUSH`. Data is flushed using an autonomous transaction (a transaction started and finished for the specific purpose of profiler data update).
|
||||
|
||||
Following is a sample profile session and queries for data analysis.
|
||||
|
||||
```
|
||||
-- Preparation - create table and routines that will be analyzed
|
||||
|
||||
create table tab (
|
||||
id integer not null,
|
||||
val integer not null
|
||||
);
|
||||
|
||||
set term !;
|
||||
|
||||
create or alter function mult(p1 integer, p2 integer) returns integer
|
||||
as
|
||||
begin
|
||||
return p1 * p2;
|
||||
end!
|
||||
|
||||
create or alter procedure ins
|
||||
as
|
||||
declare n integer = 1;
|
||||
begin
|
||||
while (n <= 1000)
|
||||
do
|
||||
begin
|
||||
if (mod(n, 2) = 1) then
|
||||
insert into tab values (:n, mult(:n, 2));
|
||||
n = n + 1;
|
||||
end
|
||||
end!
|
||||
|
||||
set term ;!
|
||||
|
||||
-- Start profiling
|
||||
|
||||
select rdb$profiler.start_session('Profile Session 1') from rdb$database;
|
||||
|
||||
set term !;
|
||||
|
||||
execute block
|
||||
as
|
||||
begin
|
||||
execute procedure ins;
|
||||
delete from tab;
|
||||
end!
|
||||
|
||||
set term ;!
|
||||
|
||||
execute procedure rdb$profiler.finish_session(true);
|
||||
|
||||
execute procedure ins;
|
||||
|
||||
select rdb$profiler.start_session('Profile Session 2') from rdb$database;
|
||||
|
||||
select mod(id, 5),
|
||||
sum(val)
|
||||
from tab
|
||||
where id <= 50
|
||||
group by mod(id, 5)
|
||||
order by sum(val);
|
||||
|
||||
execute procedure rdb$profiler.finish_session(true);
|
||||
|
||||
-- Data analysis
|
||||
|
||||
set transaction read committed;
|
||||
|
||||
select * from plg$prof_sessions;
|
||||
|
||||
select * from plg$prof_psql_stats_view;
|
||||
|
||||
select * from plg$prof_record_source_stats_view;
|
||||
|
||||
select preq.*
|
||||
from plg$prof_requests preq
|
||||
join plg$prof_sessions pses
|
||||
on pses.profile_id = preq.profile_id and
|
||||
pses.description = 'Profile Session 1';
|
||||
|
||||
select pstat.*
|
||||
from plg$prof_psql_stats pstat
|
||||
join plg$prof_sessions pses
|
||||
on pses.profile_id = pstat.profile_id and
|
||||
pses.description = 'Profile Session 1'
|
||||
order by pstat.profile_id,
|
||||
pstat.request_id,
|
||||
pstat.line_num,
|
||||
pstat.column_num;
|
||||
|
||||
select pstat.*
|
||||
from plg$prof_record_source_stats pstat
|
||||
join plg$prof_sessions pses
|
||||
on pses.profile_id = pstat.profile_id and
|
||||
pses.description = 'Profile Session 2'
|
||||
order by pstat.profile_id,
|
||||
pstat.request_id,
|
||||
pstat.cursor_id,
|
||||
pstat.record_source_id;
|
||||
```
|
||||
|
||||
## Function `START_SESSION`
|
||||
|
||||
`RDB$PROFILER.START_SESSION` starts a new profiler session, turns it the current session (of the given `ATTACHMENT_ID`) and return its identifier.
|
||||
|
||||
If `FLUSH_INTERVAL` is different than `NULL` auto-flush is setup in the same way as manually calling `RDB$PROFILER.SET_FLUSH_INTERVAL`.
|
||||
|
||||
If `PLUGIN_NAME` is `NULL` (the default) it uses the database configuration `DefaultProfilerPlugin`.
|
||||
|
||||
`PLUGIN_OPTIONS` is plugin specific options and currently should be `NULL` for `Default_Profiler` plugin.
|
||||
|
||||
Input parameters:
|
||||
- `DESCRIPTION` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
|
||||
- `FLUSH_INTERVAL` type `INTEGER` default `NULL`
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
- `PLUGIN_NAME` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
|
||||
- `PLUGIN_OPTIONS` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
|
||||
|
||||
Return type: `BIGINT NOT NULL`.
|
||||
|
||||
## Procedure `PAUSE_SESSION`
|
||||
|
||||
`RDB$PROFILER.PAUSE_SESSION` pauses the current profiler session (of the given `ATTACHMENT_ID`) so the next executed statements statistics are not collected.
|
||||
|
||||
If `FLUSH` is `TRUE` the snapshot tables are updated with data up to the current moment. Otherwise data remains only in memory for later update.
|
||||
|
||||
Calling `RDB$PROFILER.PAUSE_SESSION(TRUE)` has the same semantics of calling `RDB$PROFILER.PAUSE_SESSION(FALSE)` followed by `RDB$PROFILER.FLUSH` (using the same `ATTACHMENT_ID`).
|
||||
|
||||
Input parameters:
|
||||
- `FLUSH` type `BOOLEAN NOT NULL` default `FALSE`
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
## Procedure `RESUME_SESSION`
|
||||
|
||||
`RDB$PROFILER.RESUME_SESSION` resumes the current profiler session (of the given `ATTACHMENT_ID`) if it was paused so the next executed statements statistics are collected again.
|
||||
|
||||
Input parameters:
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
## Procedure `FINISH_SESSION`
|
||||
|
||||
`RDB$PROFILER.FINISH_SESSION` finishes the current profiler session (of the given `ATTACHMENT_ID`).
|
||||
|
||||
If `FLUSH` is `TRUE` the snapshot tables are updated with data of the finished session (and old finished sessions not yet present in the snapshot). Otherwise data remains only in memory for later update.
|
||||
|
||||
Calling `RDB$PROFILER.FINISH_SESSION(TRUE)` has the same semantics of calling `RDB$PROFILER.FINISH_SESSION(FALSE)` followed by `RDB$PROFILER.FLUSH` (using the same `ATTACHMENT_ID`).
|
||||
|
||||
Input parameters:
|
||||
- `FLUSH` type `BOOLEAN NOT NULL` default `TRUE`
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
## Procedure `CANCEL_SESSION`
|
||||
|
||||
`RDB$PROFILER.CANCEL_SESSION` cancels the current profiler session (of the given `ATTACHMENT_ID`).
|
||||
|
||||
All session data present in the profiler plugin is discarded and will not be flushed.
|
||||
|
||||
Data already flushed is not deleted automatically.
|
||||
|
||||
Input parameters:
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
## Procedure `DISCARD`
|
||||
|
||||
`RDB$PROFILER.DISCARD` removes all sessions (of the given `ATTACHMENT_ID`) from memory, without flushing them.
|
||||
|
||||
If there is a active session, it is cancelled.
|
||||
|
||||
Input parameters:
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
## Procedure `FLUSH`
|
||||
|
||||
`RDB$PROFILER.FLUSH` updates the snapshot tables with data from the profile sessions (of the given `ATTACHMENT_ID`) in memory.
|
||||
|
||||
After update data is stored in tables `PLG$PROF_SESSIONS`, `PLG$PROF_STATEMENTS`, `PLG$PROF_RECORD_SOURCES`, `PLG$PROF_REQUESTS`, `PLG$PROF_PSQL_STATS` and `PLG$PROF_RECORD_SOURCE_STATS` and may be read and analyzed by the user.
|
||||
|
||||
Data is updated using an autonomous transaction, so if the procedure is called in a snapshot transaction, data will not be directly readable in the same transaction.
|
||||
|
||||
Once flush happens, finished sessions are removed from memory.
|
||||
|
||||
Input parameters:
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
## Procedure `SET_FLUSH_INTERVAL`
|
||||
|
||||
`RDB$PROFILER.SET_FLUSH_INTERVAL` turns periodic auto-flush on (when `FLUSH_INTERVAL` is greater than 0) or off (when `FLUSH_INTERVAL` is equal to 0).
|
||||
|
||||
`FLUSH_INTERVAL` is interpreted as number of seconds.
|
||||
|
||||
Input parameters:
|
||||
- `FLUSH_INTERVAL` type `INTEGER NOT NULL`
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
# Snapshot tables
|
||||
|
||||
Snapshot tables (as well views and sequence) are automatically created in the first usage of the profiler. They are owned by the current user with read/write permissions for `PUBLIC`.
|
||||
|
||||
When a session is deleted the related data in others profiler snapshot tables are automatically deleted too through foregin keys with `DELETE CASCADE` option.
|
||||
|
||||
Below is the list of tables that stores profile data.
|
||||
|
||||
## Table `PLG$PROF_SESSIONS`
|
||||
|
||||
- `PROFILE_ID` type `BIGINT` - Profile session ID
|
||||
- `ATTACHMENT_ID` type `BIGINT` - Attachment ID
|
||||
- `USER_NAME` type `CHAR(63) CHARACTER SET UTF8` - User name
|
||||
- `DESCRIPTION` type `VARCHAR(255) CHARACTER SET UTF8` - Description passed in `RDB$PROFILER.START_SESSION`
|
||||
- `START_TIMESTAMP` type `TIMESTAMP WITH TIME ZONE` - Moment the profile session was started
|
||||
- `FINISH_TIMESTAMP` type `TIMESTAMP WITH TIME ZONE` - Moment the profile session was finished (NULL when not finished)
|
||||
- Primary key: `PROFILE_ID`
|
||||
|
||||
## Table `PLG$PROF_STATEMENTS`
|
||||
|
||||
- `PROFILE_ID` type `BIGINT` - Profile session ID
|
||||
- `STATEMENT_ID` type `BIGINT` - Statement ID
|
||||
- `PARENT_STATEMENT_ID` type `BIGINT` - Parent statement ID - related to sub routines
|
||||
- `STATEMENT_TYPE` type `VARCHAR(20) CHARACTER SET UTF8` - BLOCK, FUNCTION, PROCEDURE or TRIGGER
|
||||
- `PACKAGE_NAME` type `CHAR(63) CHARACTER SET UTF8` - Package of FUNCTION or PROCEDURE
|
||||
- `ROUTINE_NAME` type `CHAR(63) CHARACTER SET UTF8` - Routine name of FUNCTION, PROCEDURE or TRIGGER
|
||||
- `SQL_TEXT` type `BLOB subtype TEXT CHARACTER SET UTF8` - SQL text for BLOCK
|
||||
- Primary key: `PROFILE_ID, STATEMENT_ID`
|
||||
|
||||
## Table `PLG$PROF_RECORD_SOURCES`
|
||||
|
||||
- `PROFILE_ID` type `BIGINT` - Profile session ID
|
||||
- `STATEMENT_ID` type `BIGINT` - Statement ID
|
||||
- `CURSOR_ID` type `BIGINT` - Cursor ID
|
||||
- `RECORD_SOURCE_ID` type `BIGINT` - Record source ID
|
||||
- `PARENT_RECORD_SOURCE_ID` type `BIGINT` - Parent record source ID
|
||||
- `ACCESS_PATH` type `VARCHAR(255) CHARACTER SET UTF8` - Access path for the record source
|
||||
- Primary key: `PROFILE_ID, STATEMENT_ID, CURSOR_ID, RECORD_SOURCE_ID`
|
||||
|
||||
## Table `PLG$PROF_REQUESTS`
|
||||
|
||||
- `PROFILE_ID` type `BIGINT` - Profile session ID
|
||||
- `REQUEST_ID` type `BIGINT` - Request ID
|
||||
- `STATEMENT_ID` type `BIGINT` - Statement ID
|
||||
- `CALLER_REQUEST_ID` type `BIGINT` - Caller request ID
|
||||
- `START_TIMESTAMP` type `TIMESTAMP WITH TIME ZONE` - Moment this request was first gathered profile data
|
||||
- `FINISH_TIMESTAMP` type `TIMESTAMP WITH TIME ZONE` - Moment this request was finished
|
||||
- `TOTAL_ELAPSED_TIME` type `BIGINT` - Accumulated elapsed time (in nanoseconds) of the request
|
||||
- Primary key: `PROFILE_ID, REQUEST_ID`
|
||||
|
||||
## Table `PLG$PROF_PSQL_STATS`
|
||||
|
||||
- `PROFILE_ID` type `BIGINT` - Profile session ID
|
||||
- `REQUEST_ID` type `BIGINT` - Request ID
|
||||
- `LINE_NUM` type `INTEGER` - Line number of the statement
|
||||
- `COLUMN_NUM` type `INTEGER` - Column number of the statement
|
||||
- `STATEMENT_ID` type `BIGINT` - Statement ID
|
||||
- `COUNTER` type `BIGINT` - Number of executed times of the line/column
|
||||
- `MIN_ELAPSED_TIME` type `BIGINT` - Minimal elapsed time (in nanoseconds) of a line/column execution
|
||||
- `MAX_ELAPSED_TIME` type `BIGINT` - Maximum elapsed time (in nanoseconds) of a line/column execution
|
||||
- `TOTAL_ELAPSED_TIME` type `BIGINT` - Accumulated elapsed time (in nanoseconds) of the line/column executions
|
||||
- Primary key: `PROFILE_ID, REQUEST_ID, LINE_NUM, COLUMN_NUM`
|
||||
|
||||
## Table `PLG$PROF_RECORD_SOURCE_STATS`
|
||||
|
||||
- `PROFILE_ID` type `BIGINT` - Profile session ID
|
||||
- `REQUEST_ID` type `BIGINT` - Request ID
|
||||
- `CURSOR_ID` type `BIGINT` - Cursor ID
|
||||
- `RECORD_SOURCE_ID` type `BIGINT` - Record source ID
|
||||
- `STATEMENT_ID` type `BIGINT` - Statement ID
|
||||
- `OPEN_COUNTER` type `BIGINT` - Number of open times of the record source
|
||||
- `OPEN_MIN_ELAPSED_TIME` type `BIGINT` - Minimal elapsed time (in nanoseconds) of a record source open
|
||||
- `OPEN_MAX_ELAPSED_TIME` type `BIGINT` - Maximum elapsed time (in nanoseconds) of a record source open
|
||||
- `OPEN_TOTAL_ELAPSED_TIME` type `BIGINT` - Accumulated elapsed time (in nanoseconds) of the record source openings
|
||||
- `FETCH_COUNTER` type `BIGINT` - Number of fetch times of the record source
|
||||
- `FETCH_MIN_ELAPSED_TIME` type `BIGINT` - Minimal elapsed time (in nanoseconds) of a record source fetch
|
||||
- `FETCH_MAX_ELAPSED_TIME` type `BIGINT` - Maximum elapsed time (in nanoseconds) of a record source fetch
|
||||
- `FETCH_TOTAL_ELAPSED_TIME` type `BIGINT` - Accumulated elapsed time (in nanoseconds) of the record source fetches
|
||||
- Primary key: `PROFILE_ID, REQUEST_ID, CURSOR_ID, RECORD_SOURCE_ID`
|
||||
|
||||
# Auxiliary views
|
||||
|
||||
These views help profile data extraction aggregated at statement level.
|
||||
|
||||
They should be the preferred way to analyze the collected data. They can also be used together with the tables to get additional data not present on the views.
|
||||
|
||||
After hot spots are found, one can drill down in the data at the request level through the tables.
|
||||
|
||||
## View `PLG$PROF_STATEMENT_STATS_VIEW`
|
||||
```
|
||||
select req.profile_id,
|
||||
req.statement_id,
|
||||
sta.statement_type,
|
||||
sta.package_name,
|
||||
sta.routine_name,
|
||||
sta.parent_statement_id,
|
||||
sta_parent.statement_type parent_statement_type,
|
||||
sta_parent.routine_name parent_routine_name,
|
||||
(select sql_text
|
||||
from plg$prof_statements
|
||||
where profile_id = req.profile_id and
|
||||
statement_id = coalesce(sta.parent_statement_id, req.statement_id)
|
||||
) sql_text,
|
||||
count(*) counter,
|
||||
min(req.total_elapsed_time) min_elapsed_time,
|
||||
max(req.total_elapsed_time) max_elapsed_time,
|
||||
cast(sum(req.total_elapsed_time) as bigint) total_elapsed_time,
|
||||
cast(sum(req.total_elapsed_time) / count(*) as bigint) avg_elapsed_time
|
||||
from plg$prof_requests req
|
||||
join plg$prof_statements sta
|
||||
on sta.profile_id = req.profile_id and
|
||||
sta.statement_id = req.statement_id
|
||||
left join plg$prof_statements sta_parent
|
||||
on sta_parent.profile_id = sta.profile_id and
|
||||
sta_parent.statement_id = sta.parent_statement_id
|
||||
group by req.profile_id,
|
||||
req.statement_id,
|
||||
sta.statement_type,
|
||||
sta.package_name,
|
||||
sta.routine_name,
|
||||
sta.parent_statement_id,
|
||||
sta_parent.statement_type,
|
||||
sta_parent.routine_name
|
||||
order by sum(req.total_elapsed_time) desc
|
||||
```
|
||||
|
||||
## View `PLG$PROF_PSQL_STATS_VIEW`
|
||||
```
|
||||
select pstat.profile_id,
|
||||
pstat.statement_id,
|
||||
sta.statement_type,
|
||||
sta.package_name,
|
||||
sta.routine_name,
|
||||
sta.parent_statement_id,
|
||||
sta_parent.statement_type parent_statement_type,
|
||||
sta_parent.routine_name parent_routine_name,
|
||||
(select sql_text
|
||||
from plg$prof_statements
|
||||
where profile_id = pstat.profile_id and
|
||||
statement_id = coalesce(sta.parent_statement_id, pstat.statement_id)
|
||||
) sql_text,
|
||||
pstat.line_num,
|
||||
pstat.column_num,
|
||||
cast(sum(pstat.counter) as bigint) counter,
|
||||
min(pstat.min_elapsed_time) min_elapsed_time,
|
||||
max(pstat.max_elapsed_time) max_elapsed_time,
|
||||
cast(sum(pstat.total_elapsed_time) as bigint) total_elapsed_time,
|
||||
cast(sum(pstat.total_elapsed_time) / nullif(sum(pstat.counter), 0) as bigint) avg_elapsed_time
|
||||
from plg$prof_psql_stats pstat
|
||||
join plg$prof_statements sta
|
||||
on sta.profile_id = pstat.profile_id and
|
||||
sta.statement_id = pstat.statement_id
|
||||
left join plg$prof_statements sta_parent
|
||||
on sta_parent.profile_id = sta.profile_id and
|
||||
sta_parent.statement_id = sta.parent_statement_id
|
||||
group by pstat.profile_id,
|
||||
pstat.statement_id,
|
||||
sta.statement_type,
|
||||
sta.package_name,
|
||||
sta.routine_name,
|
||||
sta.parent_statement_id,
|
||||
sta_parent.statement_type,
|
||||
sta_parent.routine_name,
|
||||
pstat.line_num,
|
||||
pstat.column_num
|
||||
order by sum(pstat.total_elapsed_time) desc
|
||||
```
|
||||
|
||||
## View `PLG$PROF_RECORD_SOURCE_STATS_VIEW`
|
||||
```
|
||||
select rstat.profile_id,
|
||||
rstat.statement_id,
|
||||
sta.statement_type,
|
||||
sta.package_name,
|
||||
sta.routine_name,
|
||||
sta.parent_statement_id,
|
||||
sta_parent.statement_type parent_statement_type,
|
||||
sta_parent.routine_name parent_routine_name,
|
||||
(select sql_text
|
||||
from plg$prof_statements
|
||||
where profile_id = rstat.profile_id and
|
||||
statement_id = coalesce(sta.parent_statement_id, rstat.statement_id)
|
||||
) sql_text,
|
||||
rstat.cursor_id,
|
||||
rstat.record_source_id,
|
||||
recsrc.parent_record_source_id,
|
||||
recsrc.access_path,
|
||||
cast(sum(rstat.open_counter) as bigint) open_counter,
|
||||
min(rstat.open_min_elapsed_time) open_min_elapsed_time,
|
||||
max(rstat.open_max_elapsed_time) open_max_elapsed_time,
|
||||
cast(sum(rstat.open_total_elapsed_time) as bigint) open_total_elapsed_time,
|
||||
cast(sum(rstat.open_total_elapsed_time) / nullif(sum(rstat.open_counter), 0) as bigint) open_avg_elapsed_time,
|
||||
cast(sum(rstat.fetch_counter) as bigint) fetch_counter,
|
||||
min(rstat.fetch_min_elapsed_time) fetch_min_elapsed_time,
|
||||
max(rstat.fetch_max_elapsed_time) fetch_max_elapsed_time,
|
||||
cast(sum(rstat.fetch_total_elapsed_time) as bigint) fetch_total_elapsed_time,
|
||||
cast(sum(rstat.fetch_total_elapsed_time) / nullif(sum(rstat.fetch_counter), 0) as bigint) fetch_avg_elapsed_time,
|
||||
cast(coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) as bigint) open_fetch_total_elapsed_time
|
||||
from plg$prof_record_source_stats rstat
|
||||
join plg$prof_record_sources recsrc
|
||||
on recsrc.profile_id = rstat.profile_id and
|
||||
recsrc.statement_id = rstat.statement_id and
|
||||
recsrc.cursor_id = rstat.cursor_id and
|
||||
recsrc.record_source_id = rstat.record_source_id
|
||||
join plg$prof_statements sta
|
||||
on sta.profile_id = rstat.profile_id and
|
||||
sta.statement_id = rstat.statement_id
|
||||
left join plg$prof_statements sta_parent
|
||||
on sta_parent.profile_id = sta.profile_id and
|
||||
sta_parent.statement_id = sta.parent_statement_id
|
||||
group by rstat.profile_id,
|
||||
rstat.statement_id,
|
||||
sta.statement_type,
|
||||
sta.package_name,
|
||||
sta.routine_name,
|
||||
sta.parent_statement_id,
|
||||
sta_parent.statement_type,
|
||||
sta_parent.routine_name,
|
||||
rstat.cursor_id,
|
||||
rstat.record_source_id,
|
||||
recsrc.parent_record_source_id,
|
||||
recsrc.access_path
|
||||
order by coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) desc
|
||||
```
|
@ -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)
|
||||
@ -214,6 +220,11 @@ namespace Firebird
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const T* getPtr() const
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
T* assign(T* const p)
|
||||
{
|
||||
|
@ -553,6 +553,18 @@ public:
|
||||
!Cmp::greaterThan(KeyOfValue::generate(this->data[lowBound]), item);
|
||||
}
|
||||
|
||||
bool findAndRemove(const Key& item)
|
||||
{
|
||||
size_type pos;
|
||||
if (find(item, pos))
|
||||
{
|
||||
this->remove(pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool exist(const Key& item) const
|
||||
{
|
||||
size_type pos; // ignored
|
||||
|
@ -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());
|
||||
|
@ -655,6 +655,12 @@ const char* Config::getPlugins(unsigned int type) const
|
||||
aKey = key;
|
||||
break;
|
||||
}
|
||||
case IPluginManager::TYPE_PROFILER:
|
||||
{
|
||||
DECLARE_PER_DB_KEY(KEY_PLUG_PROFILER);
|
||||
aKey = key;
|
||||
break;
|
||||
}
|
||||
case IPluginManager::TYPE_TRACE:
|
||||
{
|
||||
DECLARE_PER_DB_KEY(KEY_PLUG_TRACE);
|
||||
|
@ -162,6 +162,7 @@ enum ConfigKey
|
||||
KEY_PLUG_AUTH_SERVER,
|
||||
KEY_PLUG_AUTH_CLIENT,
|
||||
KEY_PLUG_AUTH_MANAGE,
|
||||
KEY_PLUG_PROFILER,
|
||||
KEY_PLUG_TRACE,
|
||||
KEY_SECURITY_DATABASE,
|
||||
KEY_SERVER_MODE,
|
||||
@ -273,6 +274,7 @@ constexpr ConfigEntry entries[MAX_CONFIG_KEY] =
|
||||
{TYPE_STRING, "AuthClient", false, "Srp256, Srp, Legacy_Auth"},
|
||||
#endif
|
||||
{TYPE_STRING, "UserManager", false, "Srp"},
|
||||
{TYPE_STRING, "DefaultProfilerPlugin", false, "Default_Profiler"},
|
||||
{TYPE_STRING, "TracePlugin", false, "fbtrace"},
|
||||
{TYPE_STRING, "SecurityDatabase", false, nullptr}, // sec/db alias - rely on ConfigManager::getDefaultSecurityDb(
|
||||
{TYPE_STRING, "ServerMode", true, nullptr}, // actual value differs in boot/regular cases and set at setupDefaultConfig(
|
||||
|
@ -54,6 +54,8 @@ static const char* const FB_TRACE_LOG_MUTEX = "fb_trace_log_mutex";
|
||||
// Per-trace session usage (for interactive trace)
|
||||
static const char* const FB_TRACE_FILE = "fb_trace.";
|
||||
|
||||
static const char* const PROFILER_FILE = "fb_profiler_%s_%" UQUADFORMAT;
|
||||
|
||||
#ifdef UNIX
|
||||
static const char* const INIT_FILE = "fb_init";
|
||||
static const char* const SEM_FILE = "fb_sem";
|
||||
|
@ -330,7 +330,8 @@ public:
|
||||
SRAM_TPC_BLOCK = 0xF8,
|
||||
SRAM_TPC_SNAPSHOTS = 0xF7,
|
||||
SRAM_CHANGELOG_STATE = 0xF6,
|
||||
SRAM_TRACE_AUDIT_MTX = 0xF5
|
||||
SRAM_TRACE_AUDIT_MTX = 0xF5,
|
||||
SRAM_PROFILER = 0XF4
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -30,8 +30,10 @@
|
||||
#define COMMON_STATUS_H
|
||||
|
||||
#include "fb_exception.h"
|
||||
#include "../common/isc_proto.h"
|
||||
#include "../common/StatusHolder.h"
|
||||
#include "../common/utils_proto.h"
|
||||
#include <utility>
|
||||
|
||||
const int MAX_ERRMSG_LEN = 128;
|
||||
const int MAX_ERRSTR_LEN = 1024;
|
||||
@ -42,12 +44,14 @@ namespace Firebird
|
||||
class LocalStatusWrapper
|
||||
{
|
||||
public:
|
||||
LocalStatusWrapper()
|
||||
: localStatusVector(&localStatus)
|
||||
template <typename... Args>
|
||||
LocalStatusWrapper(Args&&... args)
|
||||
: localStatusVector(&localStatus, std::forward<Args>(args)...)
|
||||
{ }
|
||||
|
||||
explicit LocalStatusWrapper(Firebird::MemoryPool& p)
|
||||
: localStatus(p), localStatusVector(&localStatus)
|
||||
template <typename... Args>
|
||||
explicit LocalStatusWrapper(Firebird::MemoryPool& p, Args&&... args)
|
||||
: localStatus(p), localStatusVector(&localStatus, std::forward<Args>(args)...)
|
||||
{ }
|
||||
|
||||
SW* operator->()
|
||||
@ -112,6 +116,28 @@ namespace Firebird
|
||||
|
||||
typedef LocalStatusWrapper<CheckStatusWrapper> FbLocalStatus;
|
||||
|
||||
class LogWrapper : public BaseStatusWrapper<LogWrapper>
|
||||
{
|
||||
public:
|
||||
LogWrapper(IStatus* aStatus, const char* aText = nullptr)
|
||||
: BaseStatusWrapper(aStatus),
|
||||
text(aText)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static void checkException(LogWrapper* status)
|
||||
{
|
||||
if (status->dirty && (status->getState() & IStatus::STATE_ERRORS))
|
||||
iscLogStatus(status->text, status->status);
|
||||
}
|
||||
|
||||
private:
|
||||
const char* text;
|
||||
};
|
||||
|
||||
typedef LocalStatusWrapper<LogWrapper> LogLocalStatus;
|
||||
|
||||
class ThrowWrapper : public BaseStatusWrapper<ThrowWrapper>
|
||||
{
|
||||
public:
|
||||
|
@ -6812,7 +6812,7 @@ dsc* FieldNode::execute(thread_db* tdbb, Request* request) const
|
||||
{
|
||||
// Computed fields shouldn't be present at this point
|
||||
jrd_fld* field = MET_get_field(relation, fieldId);
|
||||
fb_assert(field && !field->fld_computation);
|
||||
fb_assert(!field || !field->fld_computation);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1530,6 +1530,11 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual bool isProfileAware() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual const StmtNode* execute(thread_db* tdbb, Request* request, ExeState* exeState) const = 0;
|
||||
|
||||
public:
|
||||
|
@ -845,7 +845,7 @@ const StmtNode* CompoundStmtNode::execute(thread_db* tdbb, Request* request, Exe
|
||||
{
|
||||
const NestConst<StmtNode>* end = statements.end();
|
||||
|
||||
if (onlyAssignments)
|
||||
if (onlyAssignments && !request->req_attachment->isProfilerActive())
|
||||
{
|
||||
if (request->req_operation == Request::req_evaluate)
|
||||
{
|
||||
@ -8705,6 +8705,10 @@ string ReturnNode::internalPrint(NodePrinter& printer) const
|
||||
void ReturnNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
||||
{
|
||||
dsqlScratch->appendUChar(blr_begin);
|
||||
|
||||
if (hasLineColumn)
|
||||
dsqlScratch->putDebugSrcInfo(line, column);
|
||||
|
||||
dsqlScratch->appendUChar(blr_assignment);
|
||||
GEN_expr(dsqlScratch, value);
|
||||
dsqlScratch->appendUChar(blr_variable);
|
||||
|
@ -195,6 +195,11 @@ public:
|
||||
public:
|
||||
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
|
||||
|
||||
virtual bool isProfileAware() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Firebird::string internalPrint(NodePrinter& printer) const;
|
||||
virtual CompoundStmtNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
|
||||
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
|
||||
@ -390,6 +395,11 @@ public:
|
||||
public:
|
||||
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
|
||||
|
||||
virtual bool isProfileAware() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Firebird::string internalPrint(NodePrinter& printer) const;
|
||||
virtual DeclareSubFuncNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
|
||||
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
|
||||
@ -451,6 +461,11 @@ public:
|
||||
public:
|
||||
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
|
||||
|
||||
virtual bool isProfileAware() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Firebird::string internalPrint(NodePrinter& printer) const;
|
||||
virtual DeclareSubProcNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
|
||||
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
|
||||
|
@ -250,8 +250,9 @@ interface PluginManager : Versioned
|
||||
const uint TYPE_DB_CRYPT = 9;
|
||||
const uint TYPE_KEY_HOLDER = 10;
|
||||
const uint TYPE_REPLICATOR = 11;
|
||||
const uint TYPE_COUNT = 12; // keep in sync
|
||||
//// TODO: TYPE_COUNT is not count. And these constants starts from 1, different than DIR_* ones.
|
||||
const uint TYPE_PROFILER = 12;
|
||||
const uint TYPE_COUNT = 13; // keep in sync
|
||||
//// TYPE_COUNT is not count. And these constants starts from 1, different than DIR_* ones.
|
||||
|
||||
// Main function called by plugin modules in firebird_plugin()
|
||||
void registerPluginFactory(uint pluginType, const string defaultName, PluginFactory factory);
|
||||
@ -1712,3 +1713,55 @@ interface ReplicatedSession : PluginBase
|
||||
void setSequence(Status status, const string name, int64 value);
|
||||
}
|
||||
|
||||
// Profiler interfaces
|
||||
|
||||
interface ProfilerPlugin : PluginBase
|
||||
{
|
||||
void init(Status status, Attachment attachment);
|
||||
|
||||
ProfilerSession startSession(Status status, const string description,
|
||||
const string options, ISC_TIMESTAMP_TZ timestamp);
|
||||
|
||||
void flush(Status status);
|
||||
}
|
||||
|
||||
interface ProfilerSession : Disposable
|
||||
{
|
||||
const uint FLAG_BEFORE_EVENTS = 0x1;
|
||||
const uint FLAG_AFTER_EVENTS = 0x2;
|
||||
|
||||
int64 getId();
|
||||
uint getFlags();
|
||||
|
||||
// When closing an attachment, the engine is free to dispose the ProfilerPlugin without call this method in advance.
|
||||
void cancel(Status status);
|
||||
|
||||
void finish(Status status, ISC_TIMESTAMP_TZ timestamp);
|
||||
|
||||
void defineStatement(Status status, int64 statementId, int64 parentStatementId,
|
||||
const string type, const string packageName, const string routineName, const string sqlText);
|
||||
|
||||
//// TODO: Add defineCursor with line/column
|
||||
|
||||
void defineRecordSource(int64 statementId, uint cursorId, uint recSourceId,
|
||||
const string accessPath, uint parentRecSourceId);
|
||||
|
||||
void onRequestStart(Status status, int64 requestId, int64 statementId, int64 callerRequestId,
|
||||
ISC_TIMESTAMP_TZ timestamp);
|
||||
|
||||
void onRequestFinish(Status status, int64 requestId, ISC_TIMESTAMP_TZ timestamp, ProfilerStats stats);
|
||||
|
||||
void beforePsqlLineColumn(int64 requestId, uint line, uint column);
|
||||
void afterPsqlLineColumn(int64 requestId, uint line, uint column, ProfilerStats stats);
|
||||
|
||||
void beforeRecordSourceOpen(int64 requestId, uint cursorId, uint recSourceId);
|
||||
void afterRecordSourceOpen(int64 requestId, uint cursorId, uint recSourceId, ProfilerStats stats);
|
||||
|
||||
void beforeRecordSourceGetRecord(int64 requestId, uint cursorId, uint recSourceId);
|
||||
void afterRecordSourceGetRecord(int64 requestId, uint cursorId, uint recSourceId, ProfilerStats stats);
|
||||
}
|
||||
|
||||
interface ProfilerStats : Versioned
|
||||
{
|
||||
uint64 getElapsedTime();
|
||||
}
|
||||
|
@ -121,6 +121,9 @@ namespace Firebird
|
||||
class IReplicatedRecord;
|
||||
class IReplicatedTransaction;
|
||||
class IReplicatedSession;
|
||||
class IProfilerPlugin;
|
||||
class IProfilerSession;
|
||||
class IProfilerStats;
|
||||
|
||||
// Interfaces declarations
|
||||
|
||||
@ -825,7 +828,8 @@ namespace Firebird
|
||||
static const unsigned TYPE_DB_CRYPT = 9;
|
||||
static const unsigned TYPE_KEY_HOLDER = 10;
|
||||
static const unsigned TYPE_REPLICATOR = 11;
|
||||
static const unsigned TYPE_COUNT = 12;
|
||||
static const unsigned TYPE_PROFILER = 12;
|
||||
static const unsigned TYPE_COUNT = 13;
|
||||
|
||||
void registerPluginFactory(unsigned pluginType, const char* defaultName, IPluginFactory* factory)
|
||||
{
|
||||
@ -6682,6 +6686,200 @@ namespace Firebird
|
||||
}
|
||||
};
|
||||
|
||||
class IProfilerPlugin : public IPluginBase
|
||||
{
|
||||
public:
|
||||
struct VTable : public IPluginBase::VTable
|
||||
{
|
||||
void (CLOOP_CARG *init)(IProfilerPlugin* self, IStatus* status, IAttachment* attachment) throw();
|
||||
IProfilerSession* (CLOOP_CARG *startSession)(IProfilerPlugin* self, IStatus* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) throw();
|
||||
void (CLOOP_CARG *flush)(IProfilerPlugin* self, IStatus* status) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
IProfilerPlugin(DoNotInherit)
|
||||
: IPluginBase(DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
~IProfilerPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static const unsigned VERSION = 4;
|
||||
|
||||
template <typename StatusType> void init(StatusType* status, IAttachment* attachment)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->init(this, status, attachment);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
template <typename StatusType> IProfilerSession* startSession(StatusType* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
IProfilerSession* ret = static_cast<VTable*>(this->cloopVTable)->startSession(this, status, description, options, timestamp);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> void flush(StatusType* status)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->flush(this, status);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
};
|
||||
|
||||
class IProfilerSession : public IDisposable
|
||||
{
|
||||
public:
|
||||
struct VTable : public IDisposable::VTable
|
||||
{
|
||||
ISC_INT64 (CLOOP_CARG *getId)(IProfilerSession* self) throw();
|
||||
unsigned (CLOOP_CARG *getFlags)(IProfilerSession* self) throw();
|
||||
void (CLOOP_CARG *cancel)(IProfilerSession* self, IStatus* status) throw();
|
||||
void (CLOOP_CARG *finish)(IProfilerSession* self, IStatus* status, ISC_TIMESTAMP_TZ timestamp) throw();
|
||||
void (CLOOP_CARG *defineStatement)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) throw();
|
||||
void (CLOOP_CARG *defineRecordSource)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) throw();
|
||||
void (CLOOP_CARG *onRequestStart)(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) throw();
|
||||
void (CLOOP_CARG *onRequestFinish)(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) throw();
|
||||
void (CLOOP_CARG *beforePsqlLineColumn)(IProfilerSession* self, ISC_INT64 requestId, unsigned line, unsigned column) throw();
|
||||
void (CLOOP_CARG *afterPsqlLineColumn)(IProfilerSession* self, ISC_INT64 requestId, unsigned line, unsigned column, IProfilerStats* stats) throw();
|
||||
void (CLOOP_CARG *beforeRecordSourceOpen)(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) throw();
|
||||
void (CLOOP_CARG *afterRecordSourceOpen)(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) throw();
|
||||
void (CLOOP_CARG *beforeRecordSourceGetRecord)(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) throw();
|
||||
void (CLOOP_CARG *afterRecordSourceGetRecord)(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
IProfilerSession(DoNotInherit)
|
||||
: IDisposable(DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
~IProfilerSession()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static const unsigned VERSION = 3;
|
||||
|
||||
static const unsigned FLAG_BEFORE_EVENTS = 0x1;
|
||||
static const unsigned FLAG_AFTER_EVENTS = 0x2;
|
||||
|
||||
ISC_INT64 getId()
|
||||
{
|
||||
ISC_INT64 ret = static_cast<VTable*>(this->cloopVTable)->getId(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned getFlags()
|
||||
{
|
||||
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getFlags(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> void cancel(StatusType* status)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->cancel(this, status);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
template <typename StatusType> void finish(StatusType* status, ISC_TIMESTAMP_TZ timestamp)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->finish(this, status, timestamp);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
template <typename StatusType> void defineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->defineStatement(this, status, statementId, parentStatementId, type, packageName, routineName, sqlText);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->defineRecordSource(this, statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
|
||||
}
|
||||
|
||||
template <typename StatusType> void onRequestStart(StatusType* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->onRequestStart(this, status, requestId, statementId, callerRequestId, timestamp);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
template <typename StatusType> void onRequestFinish(StatusType* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->onRequestFinish(this, status, requestId, timestamp, stats);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
void beforePsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->beforePsqlLineColumn(this, requestId, line, column);
|
||||
}
|
||||
|
||||
void afterPsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column, IProfilerStats* stats)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->afterPsqlLineColumn(this, requestId, line, column, stats);
|
||||
}
|
||||
|
||||
void beforeRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->beforeRecordSourceOpen(this, requestId, cursorId, recSourceId);
|
||||
}
|
||||
|
||||
void afterRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->afterRecordSourceOpen(this, requestId, cursorId, recSourceId, stats);
|
||||
}
|
||||
|
||||
void beforeRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->beforeRecordSourceGetRecord(this, requestId, cursorId, recSourceId);
|
||||
}
|
||||
|
||||
void afterRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->afterRecordSourceGetRecord(this, requestId, cursorId, recSourceId, stats);
|
||||
}
|
||||
};
|
||||
|
||||
class IProfilerStats : public IVersioned
|
||||
{
|
||||
public:
|
||||
struct VTable : public IVersioned::VTable
|
||||
{
|
||||
ISC_UINT64 (CLOOP_CARG *getElapsedTime)(IProfilerStats* self) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
IProfilerStats(DoNotInherit)
|
||||
: IVersioned(DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
~IProfilerStats()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static const unsigned VERSION = 2;
|
||||
|
||||
ISC_UINT64 getElapsedTime()
|
||||
{
|
||||
ISC_UINT64 ret = static_cast<VTable*>(this->cloopVTable)->getElapsedTime(this);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// Interfaces implementations
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
@ -19857,6 +20055,450 @@ namespace Firebird
|
||||
virtual void cleanupTransaction(StatusType* status, ISC_INT64 number) = 0;
|
||||
virtual void setSequence(StatusType* status, const char* name, ISC_INT64 value) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
class IProfilerPluginBaseImpl : public Base
|
||||
{
|
||||
public:
|
||||
typedef IProfilerPlugin Declaration;
|
||||
|
||||
IProfilerPluginBaseImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
static struct VTableImpl : Base::VTable
|
||||
{
|
||||
VTableImpl()
|
||||
{
|
||||
this->version = Base::VERSION;
|
||||
this->addRef = &Name::cloopaddRefDispatcher;
|
||||
this->release = &Name::cloopreleaseDispatcher;
|
||||
this->setOwner = &Name::cloopsetOwnerDispatcher;
|
||||
this->getOwner = &Name::cloopgetOwnerDispatcher;
|
||||
this->init = &Name::cloopinitDispatcher;
|
||||
this->startSession = &Name::cloopstartSessionDispatcher;
|
||||
this->flush = &Name::cloopflushDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
this->cloopVTable = &vTable;
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopinitDispatcher(IProfilerPlugin* self, IStatus* status, IAttachment* attachment) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::init(&status2, attachment);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static IProfilerSession* CLOOP_CARG cloopstartSessionDispatcher(IProfilerPlugin* self, IStatus* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::startSession(&status2, description, options, timestamp);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
return static_cast<IProfilerSession*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopflushDispatcher(IProfilerPlugin* self, IStatus* status) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::flush(&status2);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::setOwner(r);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static IReferenceCounted* CLOOP_CARG cloopgetOwnerDispatcher(IPluginBase* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getOwner();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<IReferenceCounted*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::addRef();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int CLOOP_CARG cloopreleaseDispatcher(IReferenceCounted* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::release();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<int>(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IPluginBaseImpl<Name, StatusType, Inherit<IReferenceCountedImpl<Name, StatusType, Inherit<IVersionedImpl<Name, StatusType, Inherit<IProfilerPlugin> > > > > > >
|
||||
class IProfilerPluginImpl : public IProfilerPluginBaseImpl<Name, StatusType, Base>
|
||||
{
|
||||
protected:
|
||||
IProfilerPluginImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~IProfilerPluginImpl()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void init(StatusType* status, IAttachment* attachment) = 0;
|
||||
virtual IProfilerSession* startSession(StatusType* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) = 0;
|
||||
virtual void flush(StatusType* status) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
class IProfilerSessionBaseImpl : public Base
|
||||
{
|
||||
public:
|
||||
typedef IProfilerSession Declaration;
|
||||
|
||||
IProfilerSessionBaseImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
static struct VTableImpl : Base::VTable
|
||||
{
|
||||
VTableImpl()
|
||||
{
|
||||
this->version = Base::VERSION;
|
||||
this->dispose = &Name::cloopdisposeDispatcher;
|
||||
this->getId = &Name::cloopgetIdDispatcher;
|
||||
this->getFlags = &Name::cloopgetFlagsDispatcher;
|
||||
this->cancel = &Name::cloopcancelDispatcher;
|
||||
this->finish = &Name::cloopfinishDispatcher;
|
||||
this->defineStatement = &Name::cloopdefineStatementDispatcher;
|
||||
this->defineRecordSource = &Name::cloopdefineRecordSourceDispatcher;
|
||||
this->onRequestStart = &Name::clooponRequestStartDispatcher;
|
||||
this->onRequestFinish = &Name::clooponRequestFinishDispatcher;
|
||||
this->beforePsqlLineColumn = &Name::cloopbeforePsqlLineColumnDispatcher;
|
||||
this->afterPsqlLineColumn = &Name::cloopafterPsqlLineColumnDispatcher;
|
||||
this->beforeRecordSourceOpen = &Name::cloopbeforeRecordSourceOpenDispatcher;
|
||||
this->afterRecordSourceOpen = &Name::cloopafterRecordSourceOpenDispatcher;
|
||||
this->beforeRecordSourceGetRecord = &Name::cloopbeforeRecordSourceGetRecordDispatcher;
|
||||
this->afterRecordSourceGetRecord = &Name::cloopafterRecordSourceGetRecordDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
this->cloopVTable = &vTable;
|
||||
}
|
||||
|
||||
static ISC_INT64 CLOOP_CARG cloopgetIdDispatcher(IProfilerSession* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getId();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<ISC_INT64>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned CLOOP_CARG cloopgetFlagsDispatcher(IProfilerSession* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getFlags();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<unsigned>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopcancelDispatcher(IProfilerSession* self, IStatus* status) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::cancel(&status2);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopfinishDispatcher(IProfilerSession* self, IStatus* status, ISC_TIMESTAMP_TZ timestamp) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::finish(&status2, timestamp);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopdefineStatementDispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::defineStatement(&status2, statementId, parentStatementId, type, packageName, routineName, sqlText);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopdefineRecordSourceDispatcher(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::defineRecordSource(statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG clooponRequestStartDispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::onRequestStart(&status2, requestId, statementId, callerRequestId, timestamp);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG clooponRequestFinishDispatcher(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::onRequestFinish(&status2, requestId, timestamp, stats);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopbeforePsqlLineColumnDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned line, unsigned column) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::beforePsqlLineColumn(requestId, line, column);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopafterPsqlLineColumnDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned line, unsigned column, IProfilerStats* stats) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::afterPsqlLineColumn(requestId, line, column, stats);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopbeforeRecordSourceOpenDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::beforeRecordSourceOpen(requestId, cursorId, recSourceId);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopafterRecordSourceOpenDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::afterRecordSourceOpen(requestId, cursorId, recSourceId, stats);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopbeforeRecordSourceGetRecordDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::beforeRecordSourceGetRecord(requestId, cursorId, recSourceId);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopafterRecordSourceGetRecordDispatcher(IProfilerSession* self, ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::afterRecordSourceGetRecord(requestId, cursorId, recSourceId, stats);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopdisposeDispatcher(IDisposable* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::dispose();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IDisposableImpl<Name, StatusType, Inherit<IVersionedImpl<Name, StatusType, Inherit<IProfilerSession> > > > >
|
||||
class IProfilerSessionImpl : public IProfilerSessionBaseImpl<Name, StatusType, Base>
|
||||
{
|
||||
protected:
|
||||
IProfilerSessionImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~IProfilerSessionImpl()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ISC_INT64 getId() = 0;
|
||||
virtual unsigned getFlags() = 0;
|
||||
virtual void cancel(StatusType* status) = 0;
|
||||
virtual void finish(StatusType* status, ISC_TIMESTAMP_TZ timestamp) = 0;
|
||||
virtual void defineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) = 0;
|
||||
virtual void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) = 0;
|
||||
virtual void onRequestStart(StatusType* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) = 0;
|
||||
virtual void onRequestFinish(StatusType* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) = 0;
|
||||
virtual void beforePsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column) = 0;
|
||||
virtual void afterPsqlLineColumn(ISC_INT64 requestId, unsigned line, unsigned column, IProfilerStats* stats) = 0;
|
||||
virtual void beforeRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) = 0;
|
||||
virtual void afterRecordSourceOpen(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) = 0;
|
||||
virtual void beforeRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId) = 0;
|
||||
virtual void afterRecordSourceGetRecord(ISC_INT64 requestId, unsigned cursorId, unsigned recSourceId, IProfilerStats* stats) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
class IProfilerStatsBaseImpl : public Base
|
||||
{
|
||||
public:
|
||||
typedef IProfilerStats Declaration;
|
||||
|
||||
IProfilerStatsBaseImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
static struct VTableImpl : Base::VTable
|
||||
{
|
||||
VTableImpl()
|
||||
{
|
||||
this->version = Base::VERSION;
|
||||
this->getElapsedTime = &Name::cloopgetElapsedTimeDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
this->cloopVTable = &vTable;
|
||||
}
|
||||
|
||||
static ISC_UINT64 CLOOP_CARG cloopgetElapsedTimeDispatcher(IProfilerStats* self) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getElapsedTime();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
return static_cast<ISC_UINT64>(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IProfilerStats> > >
|
||||
class IProfilerStatsImpl : public IProfilerStatsBaseImpl<Name, StatusType, Base>
|
||||
{
|
||||
protected:
|
||||
IProfilerStatsImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~IProfilerStatsImpl()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ISC_UINT64 getElapsedTime() = 0;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
@ -111,6 +111,9 @@ type
|
||||
IReplicatedRecord = class;
|
||||
IReplicatedTransaction = class;
|
||||
IReplicatedSession = class;
|
||||
IProfilerPlugin = class;
|
||||
IProfilerSession = class;
|
||||
IProfilerStats = class;
|
||||
|
||||
FbException = class(Exception)
|
||||
public
|
||||
@ -715,6 +718,24 @@ type
|
||||
IReplicatedSession_startTransactionPtr = function(this: IReplicatedSession; status: IStatus; transaction: ITransaction; number: Int64): IReplicatedTransaction; cdecl;
|
||||
IReplicatedSession_cleanupTransactionPtr = procedure(this: IReplicatedSession; status: IStatus; number: Int64); cdecl;
|
||||
IReplicatedSession_setSequencePtr = procedure(this: IReplicatedSession; status: IStatus; name: PAnsiChar; value: Int64); cdecl;
|
||||
IProfilerPlugin_initPtr = procedure(this: IProfilerPlugin; status: IStatus; attachment: IAttachment); cdecl;
|
||||
IProfilerPlugin_startSessionPtr = function(this: IProfilerPlugin; status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl;
|
||||
IProfilerPlugin_flushPtr = procedure(this: IProfilerPlugin; status: IStatus); cdecl;
|
||||
IProfilerSession_getIdPtr = function(this: IProfilerSession): Int64; cdecl;
|
||||
IProfilerSession_getFlagsPtr = function(this: IProfilerSession): Cardinal; cdecl;
|
||||
IProfilerSession_cancelPtr = procedure(this: IProfilerSession; status: IStatus); cdecl;
|
||||
IProfilerSession_finishPtr = procedure(this: IProfilerSession; status: IStatus; timestamp: ISC_TIMESTAMP_TZ); cdecl;
|
||||
IProfilerSession_defineStatementPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl;
|
||||
IProfilerSession_defineRecordSourcePtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
|
||||
IProfilerSession_onRequestStartPtr = procedure(this: IProfilerSession; status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); cdecl;
|
||||
IProfilerSession_onRequestFinishPtr = procedure(this: IProfilerSession; status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); cdecl;
|
||||
IProfilerSession_beforePsqlLineColumnPtr = procedure(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal); cdecl;
|
||||
IProfilerSession_afterPsqlLineColumnPtr = procedure(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats); cdecl;
|
||||
IProfilerSession_beforeRecordSourceOpenPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
|
||||
IProfilerSession_afterRecordSourceOpenPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl;
|
||||
IProfilerSession_beforeRecordSourceGetRecordPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
|
||||
IProfilerSession_afterRecordSourceGetRecordPtr = procedure(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl;
|
||||
IProfilerStats_getElapsedTimePtr = function(this: IProfilerStats): QWord; cdecl;
|
||||
|
||||
VersionedVTable = class
|
||||
version: NativeInt;
|
||||
@ -1082,7 +1103,8 @@ type
|
||||
const TYPE_DB_CRYPT = Cardinal(9);
|
||||
const TYPE_KEY_HOLDER = Cardinal(10);
|
||||
const TYPE_REPLICATOR = Cardinal(11);
|
||||
const TYPE_COUNT = Cardinal(12);
|
||||
const TYPE_PROFILER = Cardinal(12);
|
||||
const TYPE_COUNT = Cardinal(13);
|
||||
|
||||
procedure registerPluginFactory(pluginType: Cardinal; defaultName: PAnsiChar; factory: IPluginFactory);
|
||||
procedure registerModule(cleanup: IPluginModule);
|
||||
@ -3760,6 +3782,106 @@ type
|
||||
procedure setSequence(status: IStatus; name: PAnsiChar; value: Int64); virtual; abstract;
|
||||
end;
|
||||
|
||||
ProfilerPluginVTable = class(PluginBaseVTable)
|
||||
init: IProfilerPlugin_initPtr;
|
||||
startSession: IProfilerPlugin_startSessionPtr;
|
||||
flush: IProfilerPlugin_flushPtr;
|
||||
end;
|
||||
|
||||
IProfilerPlugin = class(IPluginBase)
|
||||
const VERSION = 4;
|
||||
|
||||
procedure init(status: IStatus; attachment: IAttachment);
|
||||
function startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession;
|
||||
procedure flush(status: IStatus);
|
||||
end;
|
||||
|
||||
IProfilerPluginImpl = class(IProfilerPlugin)
|
||||
constructor create;
|
||||
|
||||
procedure addRef(); virtual; abstract;
|
||||
function release(): Integer; virtual; abstract;
|
||||
procedure setOwner(r: IReferenceCounted); virtual; abstract;
|
||||
function getOwner(): IReferenceCounted; virtual; abstract;
|
||||
procedure init(status: IStatus; attachment: IAttachment); virtual; abstract;
|
||||
function startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; virtual; abstract;
|
||||
procedure flush(status: IStatus); virtual; abstract;
|
||||
end;
|
||||
|
||||
ProfilerSessionVTable = class(DisposableVTable)
|
||||
getId: IProfilerSession_getIdPtr;
|
||||
getFlags: IProfilerSession_getFlagsPtr;
|
||||
cancel: IProfilerSession_cancelPtr;
|
||||
finish: IProfilerSession_finishPtr;
|
||||
defineStatement: IProfilerSession_defineStatementPtr;
|
||||
defineRecordSource: IProfilerSession_defineRecordSourcePtr;
|
||||
onRequestStart: IProfilerSession_onRequestStartPtr;
|
||||
onRequestFinish: IProfilerSession_onRequestFinishPtr;
|
||||
beforePsqlLineColumn: IProfilerSession_beforePsqlLineColumnPtr;
|
||||
afterPsqlLineColumn: IProfilerSession_afterPsqlLineColumnPtr;
|
||||
beforeRecordSourceOpen: IProfilerSession_beforeRecordSourceOpenPtr;
|
||||
afterRecordSourceOpen: IProfilerSession_afterRecordSourceOpenPtr;
|
||||
beforeRecordSourceGetRecord: IProfilerSession_beforeRecordSourceGetRecordPtr;
|
||||
afterRecordSourceGetRecord: IProfilerSession_afterRecordSourceGetRecordPtr;
|
||||
end;
|
||||
|
||||
IProfilerSession = class(IDisposable)
|
||||
const VERSION = 3;
|
||||
const FLAG_BEFORE_EVENTS = Cardinal($1);
|
||||
const FLAG_AFTER_EVENTS = Cardinal($2);
|
||||
|
||||
function getId(): Int64;
|
||||
function getFlags(): Cardinal;
|
||||
procedure cancel(status: IStatus);
|
||||
procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ);
|
||||
procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar);
|
||||
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
|
||||
procedure onRequestStart(status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ);
|
||||
procedure onRequestFinish(status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats);
|
||||
procedure beforePsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal);
|
||||
procedure afterPsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats);
|
||||
procedure beforeRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
|
||||
procedure afterRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats);
|
||||
procedure beforeRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
|
||||
procedure afterRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats);
|
||||
end;
|
||||
|
||||
IProfilerSessionImpl = class(IProfilerSession)
|
||||
constructor create;
|
||||
|
||||
procedure dispose(); virtual; abstract;
|
||||
function getId(): Int64; virtual; abstract;
|
||||
function getFlags(): Cardinal; virtual; abstract;
|
||||
procedure cancel(status: IStatus); virtual; abstract;
|
||||
procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract;
|
||||
procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); virtual; abstract;
|
||||
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); virtual; abstract;
|
||||
procedure onRequestStart(status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract;
|
||||
procedure onRequestFinish(status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); virtual; abstract;
|
||||
procedure beforePsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal); virtual; abstract;
|
||||
procedure afterPsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats); virtual; abstract;
|
||||
procedure beforeRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); virtual; abstract;
|
||||
procedure afterRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); virtual; abstract;
|
||||
procedure beforeRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); virtual; abstract;
|
||||
procedure afterRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); virtual; abstract;
|
||||
end;
|
||||
|
||||
ProfilerStatsVTable = class(VersionedVTable)
|
||||
getElapsedTime: IProfilerStats_getElapsedTimePtr;
|
||||
end;
|
||||
|
||||
IProfilerStats = class(IVersioned)
|
||||
const VERSION = 2;
|
||||
|
||||
function getElapsedTime(): QWord;
|
||||
end;
|
||||
|
||||
IProfilerStatsImpl = class(IProfilerStats)
|
||||
constructor create;
|
||||
|
||||
function getElapsedTime(): QWord; virtual; abstract;
|
||||
end;
|
||||
|
||||
{$IFNDEF NO_FBCLIENT}
|
||||
function fb_get_master_interface : IMaster; cdecl; external 'fbclient';
|
||||
{$ENDIF}
|
||||
@ -8899,6 +9021,104 @@ begin
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IProfilerPlugin.init(status: IStatus; attachment: IAttachment);
|
||||
begin
|
||||
ProfilerPluginVTable(vTable).init(Self, status, attachment);
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
function IProfilerPlugin.startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession;
|
||||
begin
|
||||
Result := ProfilerPluginVTable(vTable).startSession(Self, status, description, options, timestamp);
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IProfilerPlugin.flush(status: IStatus);
|
||||
begin
|
||||
ProfilerPluginVTable(vTable).flush(Self, status);
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
function IProfilerSession.getId(): Int64;
|
||||
begin
|
||||
Result := ProfilerSessionVTable(vTable).getId(Self);
|
||||
end;
|
||||
|
||||
function IProfilerSession.getFlags(): Cardinal;
|
||||
begin
|
||||
Result := ProfilerSessionVTable(vTable).getFlags(Self);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.cancel(status: IStatus);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).cancel(Self, status);
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).finish(Self, status, timestamp);
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).defineStatement(Self, status, statementId, parentStatementId, type_, packageName, routineName, sqlText);
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).defineRecordSource(Self, statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.onRequestStart(status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).onRequestStart(Self, status, requestId, statementId, callerRequestId, timestamp);
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.onRequestFinish(status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).onRequestFinish(Self, status, requestId, timestamp, stats);
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.beforePsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).beforePsqlLineColumn(Self, requestId, line, column);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.afterPsqlLineColumn(requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).afterPsqlLineColumn(Self, requestId, line, column, stats);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.beforeRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).beforeRecordSourceOpen(Self, requestId, cursorId, recSourceId);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.afterRecordSourceOpen(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).afterRecordSourceOpen(Self, requestId, cursorId, recSourceId, stats);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.beforeRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).beforeRecordSourceGetRecord(Self, requestId, cursorId, recSourceId);
|
||||
end;
|
||||
|
||||
procedure IProfilerSession.afterRecordSourceGetRecord(requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats);
|
||||
begin
|
||||
ProfilerSessionVTable(vTable).afterRecordSourceGetRecord(Self, requestId, cursorId, recSourceId, stats);
|
||||
end;
|
||||
|
||||
function IProfilerStats.getElapsedTime(): QWord;
|
||||
begin
|
||||
Result := ProfilerStatsVTable(vTable).getElapsedTime(Self);
|
||||
end;
|
||||
|
||||
var
|
||||
IVersionedImpl_vTable: VersionedVTable;
|
||||
|
||||
@ -15428,6 +15648,237 @@ begin
|
||||
vTable := IReplicatedSessionImpl_vTable;
|
||||
end;
|
||||
|
||||
procedure IProfilerPluginImpl_addRefDispatcher(this: IProfilerPlugin); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerPluginImpl(this).addRef();
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
function IProfilerPluginImpl_releaseDispatcher(this: IProfilerPlugin): Integer; cdecl;
|
||||
begin
|
||||
try
|
||||
Result := IProfilerPluginImpl(this).release();
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerPluginImpl_setOwnerDispatcher(this: IProfilerPlugin; r: IReferenceCounted); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerPluginImpl(this).setOwner(r);
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
function IProfilerPluginImpl_getOwnerDispatcher(this: IProfilerPlugin): IReferenceCounted; cdecl;
|
||||
begin
|
||||
try
|
||||
Result := IProfilerPluginImpl(this).getOwner();
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerPluginImpl_initDispatcher(this: IProfilerPlugin; status: IStatus; attachment: IAttachment); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerPluginImpl(this).init(status, attachment);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
function IProfilerPluginImpl_startSessionDispatcher(this: IProfilerPlugin; status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl;
|
||||
begin
|
||||
try
|
||||
Result := IProfilerPluginImpl(this).startSession(status, description, options, timestamp);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerPluginImpl_flushDispatcher(this: IProfilerPlugin; status: IStatus); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerPluginImpl(this).flush(status);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
var
|
||||
IProfilerPluginImpl_vTable: ProfilerPluginVTable;
|
||||
|
||||
constructor IProfilerPluginImpl.create;
|
||||
begin
|
||||
vTable := IProfilerPluginImpl_vTable;
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_disposeDispatcher(this: IProfilerSession); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).dispose();
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
function IProfilerSessionImpl_getIdDispatcher(this: IProfilerSession): Int64; cdecl;
|
||||
begin
|
||||
try
|
||||
Result := IProfilerSessionImpl(this).getId();
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
function IProfilerSessionImpl_getFlagsDispatcher(this: IProfilerSession): Cardinal; cdecl;
|
||||
begin
|
||||
try
|
||||
Result := IProfilerSessionImpl(this).getFlags();
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_cancelDispatcher(this: IProfilerSession; status: IStatus); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).cancel(status);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_finishDispatcher(this: IProfilerSession; status: IStatus; timestamp: ISC_TIMESTAMP_TZ); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).finish(status, timestamp);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_defineStatementDispatcher(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).defineStatement(status, statementId, parentStatementId, type_, packageName, routineName, sqlText);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_defineRecordSourceDispatcher(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).defineRecordSource(statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_onRequestStartDispatcher(this: IProfilerSession; status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).onRequestStart(status, requestId, statementId, callerRequestId, timestamp);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_onRequestFinishDispatcher(this: IProfilerSession; status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).onRequestFinish(status, requestId, timestamp, stats);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_beforePsqlLineColumnDispatcher(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).beforePsqlLineColumn(requestId, line, column);
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_afterPsqlLineColumnDispatcher(this: IProfilerSession; requestId: Int64; line: Cardinal; column: Cardinal; stats: IProfilerStats); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).afterPsqlLineColumn(requestId, line, column, stats);
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_beforeRecordSourceOpenDispatcher(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).beforeRecordSourceOpen(requestId, cursorId, recSourceId);
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_afterRecordSourceOpenDispatcher(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).afterRecordSourceOpen(requestId, cursorId, recSourceId, stats);
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_beforeRecordSourceGetRecordDispatcher(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).beforeRecordSourceGetRecord(requestId, cursorId, recSourceId);
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IProfilerSessionImpl_afterRecordSourceGetRecordDispatcher(this: IProfilerSession; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl;
|
||||
begin
|
||||
try
|
||||
IProfilerSessionImpl(this).afterRecordSourceGetRecord(requestId, cursorId, recSourceId, stats);
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
var
|
||||
IProfilerSessionImpl_vTable: ProfilerSessionVTable;
|
||||
|
||||
constructor IProfilerSessionImpl.create;
|
||||
begin
|
||||
vTable := IProfilerSessionImpl_vTable;
|
||||
end;
|
||||
|
||||
function IProfilerStatsImpl_getElapsedTimeDispatcher(this: IProfilerStats): QWord; cdecl;
|
||||
begin
|
||||
try
|
||||
Result := IProfilerStatsImpl(this).getElapsedTime();
|
||||
except
|
||||
on e: Exception do FbException.catchException(nil, e);
|
||||
end
|
||||
end;
|
||||
|
||||
var
|
||||
IProfilerStatsImpl_vTable: ProfilerStatsVTable;
|
||||
|
||||
constructor IProfilerStatsImpl.create;
|
||||
begin
|
||||
vTable := IProfilerStatsImpl_vTable;
|
||||
end;
|
||||
|
||||
constructor FbException.create(status: IStatus);
|
||||
begin
|
||||
inherited Create('FbException');
|
||||
@ -16419,6 +16870,38 @@ initialization
|
||||
IReplicatedSessionImpl_vTable.cleanupTransaction := @IReplicatedSessionImpl_cleanupTransactionDispatcher;
|
||||
IReplicatedSessionImpl_vTable.setSequence := @IReplicatedSessionImpl_setSequenceDispatcher;
|
||||
|
||||
IProfilerPluginImpl_vTable := ProfilerPluginVTable.create;
|
||||
IProfilerPluginImpl_vTable.version := 4;
|
||||
IProfilerPluginImpl_vTable.addRef := @IProfilerPluginImpl_addRefDispatcher;
|
||||
IProfilerPluginImpl_vTable.release := @IProfilerPluginImpl_releaseDispatcher;
|
||||
IProfilerPluginImpl_vTable.setOwner := @IProfilerPluginImpl_setOwnerDispatcher;
|
||||
IProfilerPluginImpl_vTable.getOwner := @IProfilerPluginImpl_getOwnerDispatcher;
|
||||
IProfilerPluginImpl_vTable.init := @IProfilerPluginImpl_initDispatcher;
|
||||
IProfilerPluginImpl_vTable.startSession := @IProfilerPluginImpl_startSessionDispatcher;
|
||||
IProfilerPluginImpl_vTable.flush := @IProfilerPluginImpl_flushDispatcher;
|
||||
|
||||
IProfilerSessionImpl_vTable := ProfilerSessionVTable.create;
|
||||
IProfilerSessionImpl_vTable.version := 3;
|
||||
IProfilerSessionImpl_vTable.dispose := @IProfilerSessionImpl_disposeDispatcher;
|
||||
IProfilerSessionImpl_vTable.getId := @IProfilerSessionImpl_getIdDispatcher;
|
||||
IProfilerSessionImpl_vTable.getFlags := @IProfilerSessionImpl_getFlagsDispatcher;
|
||||
IProfilerSessionImpl_vTable.cancel := @IProfilerSessionImpl_cancelDispatcher;
|
||||
IProfilerSessionImpl_vTable.finish := @IProfilerSessionImpl_finishDispatcher;
|
||||
IProfilerSessionImpl_vTable.defineStatement := @IProfilerSessionImpl_defineStatementDispatcher;
|
||||
IProfilerSessionImpl_vTable.defineRecordSource := @IProfilerSessionImpl_defineRecordSourceDispatcher;
|
||||
IProfilerSessionImpl_vTable.onRequestStart := @IProfilerSessionImpl_onRequestStartDispatcher;
|
||||
IProfilerSessionImpl_vTable.onRequestFinish := @IProfilerSessionImpl_onRequestFinishDispatcher;
|
||||
IProfilerSessionImpl_vTable.beforePsqlLineColumn := @IProfilerSessionImpl_beforePsqlLineColumnDispatcher;
|
||||
IProfilerSessionImpl_vTable.afterPsqlLineColumn := @IProfilerSessionImpl_afterPsqlLineColumnDispatcher;
|
||||
IProfilerSessionImpl_vTable.beforeRecordSourceOpen := @IProfilerSessionImpl_beforeRecordSourceOpenDispatcher;
|
||||
IProfilerSessionImpl_vTable.afterRecordSourceOpen := @IProfilerSessionImpl_afterRecordSourceOpenDispatcher;
|
||||
IProfilerSessionImpl_vTable.beforeRecordSourceGetRecord := @IProfilerSessionImpl_beforeRecordSourceGetRecordDispatcher;
|
||||
IProfilerSessionImpl_vTable.afterRecordSourceGetRecord := @IProfilerSessionImpl_afterRecordSourceGetRecordDispatcher;
|
||||
|
||||
IProfilerStatsImpl_vTable := ProfilerStatsVTable.create;
|
||||
IProfilerStatsImpl_vTable.version := 2;
|
||||
IProfilerStatsImpl_vTable.getElapsedTime := @IProfilerStatsImpl_getElapsedTimeDispatcher;
|
||||
|
||||
finalization
|
||||
IVersionedImpl_vTable.destroy;
|
||||
IReferenceCountedImpl_vTable.destroy;
|
||||
@ -16515,5 +16998,8 @@ finalization
|
||||
IReplicatedRecordImpl_vTable.destroy;
|
||||
IReplicatedTransactionImpl_vTable.destroy;
|
||||
IReplicatedSessionImpl_vTable.destroy;
|
||||
IProfilerPluginImpl_vTable.destroy;
|
||||
IProfilerSessionImpl_vTable.destroy;
|
||||
IProfilerStatsImpl_vTable.destroy;
|
||||
|
||||
end.
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include "../jrd/tpc_proto.h"
|
||||
|
||||
#include "../jrd/extds/ExtDS.h"
|
||||
|
||||
#include "../jrd/ProfilerManager.h"
|
||||
#include "../jrd/replication/Applier.h"
|
||||
#include "../jrd/replication/Manager.h"
|
||||
|
||||
@ -728,6 +728,12 @@ void Jrd::Attachment::initLocks(thread_db* tdbb)
|
||||
lock = FB_NEW_RPT(*att_pool, 0)
|
||||
Lock(tdbb, 0, LCK_repl_tables, this, blockingAstReplSet);
|
||||
att_repl_lock = lock;
|
||||
|
||||
lock = FB_NEW_RPT(*att_pool, 0)
|
||||
Lock(tdbb, sizeof(AttNumber), LCK_profiler_listener, this, ProfilerManager::blockingAst);
|
||||
att_profiler_listener_lock = lock;
|
||||
lock->setKey(att_attachment_id);
|
||||
LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -845,6 +851,9 @@ void Jrd::Attachment::releaseLocks(thread_db* tdbb)
|
||||
if (att_repl_lock)
|
||||
LCK_release(tdbb, att_repl_lock);
|
||||
|
||||
if (att_profiler_listener_lock)
|
||||
LCK_release(tdbb, att_profiler_listener_lock);
|
||||
|
||||
// And release the system requests
|
||||
|
||||
for (Statement** itr = att_internal.begin(); itr != att_internal.end(); ++itr)
|
||||
@ -1154,3 +1163,21 @@ int Attachment::blockingAstReplSet(void* ast_object)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ProfilerManager* Attachment::getProfilerManager(thread_db* tdbb)
|
||||
{
|
||||
auto profilerManager = att_profiler_manager.get();
|
||||
if (!profilerManager)
|
||||
att_profiler_manager.reset(profilerManager = ProfilerManager::create(tdbb));
|
||||
return profilerManager;
|
||||
}
|
||||
|
||||
bool Attachment::isProfilerActive()
|
||||
{
|
||||
return att_profiler_manager && att_profiler_manager->isActive();
|
||||
}
|
||||
|
||||
void Attachment::releaseProfilerManager()
|
||||
{
|
||||
att_profiler_manager.reset();
|
||||
}
|
||||
|
@ -95,6 +95,7 @@ namespace Jrd
|
||||
class TrigVector;
|
||||
class Function;
|
||||
class Statement;
|
||||
class ProfilerManager;
|
||||
class Validation;
|
||||
class Applier;
|
||||
|
||||
@ -558,6 +559,7 @@ public:
|
||||
AttNumber att_attachment_id; // Attachment ID
|
||||
Lock* att_cancel_lock; // Lock to cancel the active request
|
||||
Lock* att_monitor_lock; // Lock for monitoring purposes
|
||||
Lock* att_profiler_listener_lock; // Lock for remote profiler listener
|
||||
const ULONG att_lock_owner_id; // ID for the lock manager
|
||||
SLONG att_lock_owner_handle; // Handle for the lock manager
|
||||
ULONG att_backup_state_counter; // Counter of backup state locks for attachment
|
||||
@ -569,6 +571,7 @@ public:
|
||||
ULONG att_flags; // Flags describing the state of the attachment
|
||||
SSHORT att_client_charset; // user's charset specified in dpb
|
||||
SSHORT att_charset; // current (client or external) attachment charset
|
||||
bool att_in_system_routine = false; // running a system routine
|
||||
Lock* att_long_locks; // outstanding two phased locks
|
||||
#ifdef DEBUG_LCK_LIST
|
||||
UCHAR att_long_locks_type; // Lock type of the first lock in list
|
||||
@ -803,6 +806,10 @@ public:
|
||||
void checkReplSetLock(thread_db* tdbb);
|
||||
void invalidateReplSet(thread_db* tdbb, bool broadcast);
|
||||
|
||||
ProfilerManager* getProfilerManager(thread_db* tdbb);
|
||||
bool isProfilerActive();
|
||||
void releaseProfilerManager();
|
||||
|
||||
JProvider* getProvider()
|
||||
{
|
||||
fb_assert(att_provider);
|
||||
@ -820,6 +827,7 @@ private:
|
||||
Firebird::Array<JBatch*> att_batches;
|
||||
InitialOptions att_initial_options; // Initial session options
|
||||
DebugOptions att_debug_options;
|
||||
Firebird::AutoPtr<ProfilerManager> att_profiler_manager; // ProfilerManager
|
||||
|
||||
Lock* att_repl_lock; // Replication set lock
|
||||
JProvider* att_provider; // Provider which created this attachment
|
||||
|
@ -60,6 +60,9 @@ using namespace Firebird;
|
||||
using namespace Jrd;
|
||||
|
||||
|
||||
static EngineCheckout::Type checkoutType(IExternalEngine* engine);
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// Internal message node.
|
||||
@ -481,8 +484,6 @@ namespace
|
||||
}
|
||||
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
template <typename T> class ExtEngineManager::ContextManager
|
||||
{
|
||||
public:
|
||||
@ -560,7 +561,7 @@ private:
|
||||
char charSetName[MAX_SQL_IDENTIFIER_SIZE];
|
||||
|
||||
{ // scope
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
|
||||
FbLocalStatus status;
|
||||
obj->getCharSet(&status, attInfo->context, charSetName, MAX_SQL_IDENTIFIER_LEN);
|
||||
@ -740,7 +741,7 @@ void ExtEngineManager::Function::execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* o
|
||||
CallerName(obj_udf, udf->getName().identifier, userName) :
|
||||
CallerName(obj_package_header, udf->getName().package, userName)));
|
||||
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
|
||||
FbLocalStatus status;
|
||||
function->execute(&status, attInfo->context, inMsg, outMsg);
|
||||
@ -796,7 +797,7 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* out
|
||||
|
||||
charSet = attachment->att_charset;
|
||||
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
|
||||
FbLocalStatus status;
|
||||
resultSet = procedure->procedure->open(&status, attInfo->context, inMsg, outMsg);
|
||||
@ -808,7 +809,7 @@ ExtEngineManager::ResultSet::~ResultSet()
|
||||
{
|
||||
if (resultSet)
|
||||
{
|
||||
EngineCheckout cout(JRD_get_thread_data(), FB_FUNCTION);
|
||||
EngineCheckout cout(JRD_get_thread_data(), FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
resultSet->dispose();
|
||||
}
|
||||
}
|
||||
@ -828,7 +829,7 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb)
|
||||
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
|
||||
CallerName(obj_package_header, procedure->prc->getName().package, userName)));
|
||||
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
|
||||
FbLocalStatus status;
|
||||
bool ret = resultSet->fetch(&status);
|
||||
@ -918,7 +919,7 @@ void ExtEngineManager::Trigger::execute(thread_db* tdbb, Request* request, unsig
|
||||
setValues(tdbb, request, newMsg, newRpb);
|
||||
|
||||
{ // scope
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
|
||||
FbLocalStatus status;
|
||||
trigger->execute(&status, attInfo->context, action,
|
||||
@ -1236,7 +1237,7 @@ void ExtEngineManager::closeAttachment(thread_db* tdbb, Attachment* attachment)
|
||||
enginesCopy.put(accessor.current()->first, accessor.current()->second);
|
||||
}
|
||||
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
|
||||
EnginesMap::Accessor accessor(&enginesCopy);
|
||||
for (bool found = accessor.getFirst(); found; found = accessor.getNext())
|
||||
@ -1317,7 +1318,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
|
||||
RefPtr<IMessageMetadata> extInputParameters, extOutputParameters;
|
||||
|
||||
{ // scope
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
|
||||
externalFunction = attInfo->engine->makeFunction(&status, attInfo->context, metadata,
|
||||
inBuilder, outBuilder);
|
||||
@ -1408,7 +1409,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
externalFunction->dispose();
|
||||
throw;
|
||||
}
|
||||
@ -1453,7 +1454,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
|
||||
RefPtr<IMessageMetadata> extInputParameters, extOutputParameters;
|
||||
|
||||
{ // scope
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
|
||||
externalProcedure = attInfo->engine->makeProcedure(&status, attInfo->context, metadata,
|
||||
inBuilder, outBuilder);
|
||||
@ -1551,7 +1552,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
externalProcedure->dispose();
|
||||
throw;
|
||||
}
|
||||
@ -1612,7 +1613,7 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T
|
||||
IExternalTrigger* externalTrigger;
|
||||
|
||||
{ // scope
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
|
||||
FbLocalStatus status;
|
||||
externalTrigger = attInfo->engine->makeTrigger(&status, attInfo->context, metadata,
|
||||
@ -1650,7 +1651,7 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
externalTrigger->dispose();
|
||||
throw;
|
||||
}
|
||||
@ -1759,7 +1760,7 @@ ExtEngineManager::EngineAttachmentInfo* ExtEngineManager::getEngineAttachment(
|
||||
enginesAttachments.put(key, attInfo);
|
||||
|
||||
ContextManager<IExternalFunction> ctxManager(tdbb, attInfo, attInfo->adminCharSet);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, checkoutType(attInfo->engine));
|
||||
FbLocalStatus status;
|
||||
engine->openAttachment(&status, attInfo->context); //// FIXME: log status
|
||||
}
|
||||
@ -1802,4 +1803,10 @@ void ExtEngineManager::setupAdminCharSet(thread_db* tdbb, IExternalEngine* engin
|
||||
}
|
||||
|
||||
|
||||
} // namespace Jrd
|
||||
//---------------------
|
||||
|
||||
|
||||
static EngineCheckout::Type checkoutType(IExternalEngine* engine)
|
||||
{
|
||||
return engine == SystemEngine::INSTANCE ? EngineCheckout::AVOID : EngineCheckout::REQUIRED;
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
|
||||
|
||||
while (readers > 0 )
|
||||
{
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
noReaders.wait(counterMutex);
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
|
||||
|
||||
while (currentWriter || pendingLock)
|
||||
{
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
writerFinished.wait(counterMutex);
|
||||
}
|
||||
|
||||
@ -237,7 +237,7 @@ bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
|
||||
|
||||
while (pendingWriters > 0 || currentWriter)
|
||||
{
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
writerFinished.wait(counterMutex);
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@ bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
|
||||
break;
|
||||
|
||||
MutexUnlockGuard cout(counterMutex, FB_FUNCTION);
|
||||
EngineCheckout cout2(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout2(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
Thread::yield();
|
||||
}
|
||||
|
||||
|
1241
src/jrd/ProfilerManager.cpp
Normal file
1241
src/jrd/ProfilerManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
267
src/jrd/ProfilerManager.h
Normal file
267
src/jrd/ProfilerManager.h
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Adriano dos Santos Fernandes
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2020 Adriano dos Santos Fernandes <adrianosf@gmail.com>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#ifndef JRD_PROFILER_MANAGER_H
|
||||
#define JRD_PROFILER_MANAGER_H
|
||||
|
||||
#include "firebird.h"
|
||||
#include "firebird/Message.h"
|
||||
#include "../common/classes/auto.h"
|
||||
#include "../common/classes/fb_string.h"
|
||||
#include "../common/classes/Nullable.h"
|
||||
#include "../common/classes/RefCounted.h"
|
||||
#include "../common/classes/TimerImpl.h"
|
||||
#include "../jrd/SystemPackages.h"
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class Attachment;
|
||||
class Request;
|
||||
class RecordSource;
|
||||
class thread_db;
|
||||
|
||||
class ProfilerListener;
|
||||
|
||||
|
||||
class ProfilerManager final
|
||||
{
|
||||
friend class ProfilerListener;
|
||||
friend class ProfilerPackage;
|
||||
|
||||
public:
|
||||
class Stats final : public Firebird::IProfilerStatsImpl<Stats, Firebird::ThrowStatusExceptionWrapper>
|
||||
{
|
||||
public:
|
||||
explicit Stats(FB_UINT64 aElapsedTime)
|
||||
: elapsedTime(aElapsedTime)
|
||||
{}
|
||||
|
||||
public:
|
||||
FB_UINT64 getElapsedTime() override
|
||||
{
|
||||
return elapsedTime;
|
||||
}
|
||||
|
||||
private:
|
||||
FB_UINT64 elapsedTime = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
class Statement final
|
||||
{
|
||||
public:
|
||||
Statement(MemoryPool& pool)
|
||||
: cursorNextSequence(pool),
|
||||
recSourceSequence(pool)
|
||||
{
|
||||
}
|
||||
|
||||
Statement(const Statement&) = delete;
|
||||
void operator=(const Statement&) = delete;
|
||||
|
||||
SINT64 id = 0;
|
||||
Firebird::NonPooledMap<ULONG, ULONG> cursorNextSequence;
|
||||
Firebird::NonPooledMap<ULONG, ULONG> recSourceSequence;
|
||||
};
|
||||
|
||||
class Session final
|
||||
{
|
||||
public:
|
||||
Session(MemoryPool& pool)
|
||||
: statements(pool),
|
||||
requests(pool)
|
||||
{
|
||||
}
|
||||
|
||||
Session(const Session&) = delete;
|
||||
void operator=(const Session&) = delete;
|
||||
|
||||
Firebird::AutoPlugin<Firebird::IProfilerPlugin> plugin;
|
||||
Firebird::AutoDispose<Firebird::IProfilerSession> pluginSession;
|
||||
Firebird::RightPooledMap<StmtNumber, Statement> statements;
|
||||
Firebird::SortedArray<StmtNumber> requests;
|
||||
unsigned flags = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
ProfilerManager(thread_db* tdbb);
|
||||
|
||||
public:
|
||||
~ProfilerManager();
|
||||
|
||||
public:
|
||||
static ProfilerManager* create(thread_db* tdbb);
|
||||
|
||||
static int blockingAst(void* astObject);
|
||||
|
||||
ProfilerManager(const ProfilerManager&) = delete;
|
||||
void operator=(const ProfilerManager&) = delete;
|
||||
|
||||
public:
|
||||
SINT64 startSession(thread_db* tdbb, Nullable<SLONG> flushInterval,
|
||||
const Firebird::PathName& pluginName, const Firebird::string& description, const Firebird::string& options);
|
||||
|
||||
void prepareRecSource(thread_db* tdbb, Request* request, const RecordSource* rsb);
|
||||
void onRequestFinish(Request* request, Stats& stats);
|
||||
void beforePsqlLineColumn(Request* request, ULONG line, ULONG column);
|
||||
void afterPsqlLineColumn(Request* request, ULONG line, ULONG column, Stats& stats);
|
||||
void beforeRecordSourceOpen(Request* request, const RecordSource* rsb);
|
||||
void afterRecordSourceOpen(Request* request, const RecordSource* rsb, Stats& stats);
|
||||
void beforeRecordSourceGetRecord(Request* request, const RecordSource* rsb);
|
||||
void afterRecordSourceGetRecord(Request* request, const RecordSource* rsb, Stats& stats);
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return currentSession && !paused;
|
||||
}
|
||||
|
||||
static void checkFlushInterval(SLONG interval)
|
||||
{
|
||||
if (interval < 0)
|
||||
{
|
||||
Firebird::status_exception::raise(
|
||||
Firebird::Arg::Gds(isc_not_valid_for_var) <<
|
||||
"FLUSH_INTERVAL" <<
|
||||
Firebird::Arg::Num(interval));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void cancelSession();
|
||||
void finishSession(thread_db* tdbb, bool flushData);
|
||||
void pauseSession(bool flushData);
|
||||
void resumeSession();
|
||||
void setFlushInterval(SLONG interval);
|
||||
void discard();
|
||||
void flush(bool updateTimer = true);
|
||||
|
||||
void updateFlushTimer(bool canStopTimer = true);
|
||||
|
||||
Statement* getStatement(Request* request);
|
||||
SINT64 getRequest(Request* request, unsigned flags);
|
||||
|
||||
private:
|
||||
Firebird::AutoPtr<ProfilerListener> listener;
|
||||
Firebird::LeftPooledMap<Firebird::PathName, Firebird::AutoPlugin<Firebird::IProfilerPlugin>> activePlugins;
|
||||
Firebird::AutoPtr<Session> currentSession;
|
||||
Firebird::RefPtr<Firebird::TimerImpl> flushTimer;
|
||||
unsigned currentFlushInterval = 0;
|
||||
bool paused = false;
|
||||
};
|
||||
|
||||
|
||||
class ProfilerPackage final : public SystemPackage
|
||||
{
|
||||
friend class ProfilerListener;
|
||||
friend class ProfilerManager;
|
||||
|
||||
public:
|
||||
ProfilerPackage(Firebird::MemoryPool& pool);
|
||||
|
||||
ProfilerPackage(const ProfilerPackage&) = delete;
|
||||
ProfilerPackage& operator=(const ProfilerPackage&) = delete;
|
||||
|
||||
private:
|
||||
FB_MESSAGE(AttachmentIdMessage, Firebird::ThrowStatusExceptionWrapper,
|
||||
(FB_BIGINT, attachmentId)
|
||||
);
|
||||
|
||||
//----------
|
||||
|
||||
using DiscardInput = AttachmentIdMessage;
|
||||
|
||||
static Firebird::IExternalResultSet* discardProcedure(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const DiscardInput::Type* in, void* out);
|
||||
|
||||
//----------
|
||||
|
||||
using FlushInput = AttachmentIdMessage;
|
||||
|
||||
static Firebird::IExternalResultSet* flushProcedure(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const FlushInput::Type* in, void* out);
|
||||
|
||||
//----------
|
||||
|
||||
using CancelSessionInput = AttachmentIdMessage;
|
||||
|
||||
static Firebird::IExternalResultSet* cancelSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const CancelSessionInput::Type* in, void* out);
|
||||
|
||||
//----------
|
||||
|
||||
FB_MESSAGE(FinishSessionInput, Firebird::ThrowStatusExceptionWrapper,
|
||||
(FB_BOOLEAN, flush)
|
||||
(FB_BIGINT, attachmentId)
|
||||
);
|
||||
|
||||
static Firebird::IExternalResultSet* finishSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const FinishSessionInput::Type* in, void* out);
|
||||
|
||||
//----------
|
||||
|
||||
FB_MESSAGE(PauseSessionInput, Firebird::ThrowStatusExceptionWrapper,
|
||||
(FB_BOOLEAN, flush)
|
||||
(FB_BIGINT, attachmentId)
|
||||
);
|
||||
|
||||
static Firebird::IExternalResultSet* pauseSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const PauseSessionInput::Type* in, void* out);
|
||||
|
||||
//----------
|
||||
|
||||
using ResumeSessionInput = AttachmentIdMessage;
|
||||
|
||||
static Firebird::IExternalResultSet* resumeSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const ResumeSessionInput::Type* in, void* out);
|
||||
|
||||
//----------
|
||||
|
||||
FB_MESSAGE(SetFlushIntervalInput, Firebird::ThrowStatusExceptionWrapper,
|
||||
(FB_INTEGER, flushInterval)
|
||||
(FB_BIGINT, attachmentId)
|
||||
);
|
||||
|
||||
static Firebird::IExternalResultSet* setFlushIntervalProcedure(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const SetFlushIntervalInput::Type* in, void* out);
|
||||
|
||||
//----------
|
||||
|
||||
FB_MESSAGE(StartSessionInput, Firebird::ThrowStatusExceptionWrapper,
|
||||
(FB_INTL_VARCHAR(255, CS_METADATA), description)
|
||||
(FB_INTEGER, flushInterval)
|
||||
(FB_BIGINT, attachmentId)
|
||||
(FB_INTL_VARCHAR(255, CS_METADATA), pluginName)
|
||||
(FB_INTL_VARCHAR(255, CS_METADATA), pluginOptions)
|
||||
);
|
||||
|
||||
FB_MESSAGE(StartSessionOutput, Firebird::ThrowStatusExceptionWrapper,
|
||||
(FB_BIGINT, sessionId)
|
||||
);
|
||||
|
||||
static void startSessionFunction(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const StartSessionInput::Type* in, StartSessionOutput::Type* out);
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // JRD_PROFILER_MANAGER_H
|
@ -336,6 +336,8 @@ Statement* Statement::makeStatement(thread_db* tdbb, CompilerScratch* csb, bool
|
||||
|
||||
attachment->att_statements.add(statement);
|
||||
|
||||
tdbb->getAttachment()->att_statements.add(statement);
|
||||
|
||||
return statement;
|
||||
}
|
||||
|
||||
@ -693,10 +695,7 @@ void Statement::release(thread_db* tdbb)
|
||||
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
|
||||
FB_SIZE_T pos;
|
||||
if (attachment->att_statements.find(this, pos))
|
||||
attachment->att_statements.remove(pos);
|
||||
else
|
||||
if (!attachment->att_statements.findAndRemove(this))
|
||||
fb_assert(false);
|
||||
|
||||
sqlText = NULL;
|
||||
@ -714,7 +713,7 @@ string Statement::getPlan(thread_db* tdbb, bool detailed) const
|
||||
for (const auto rsb : fors)
|
||||
{
|
||||
plan += detailed ? "\nSelect Expression" : "\nPLAN ";
|
||||
rsb->print(tdbb, plan, detailed, 0);
|
||||
rsb->print(tdbb, plan, detailed, 0, true);
|
||||
}
|
||||
|
||||
return plan;
|
||||
|
@ -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>
|
||||
@ -236,6 +237,41 @@ namespace Jrd
|
||||
>
|
||||
struct SystemProcedureFactory
|
||||
{
|
||||
class SystemResultSet :
|
||||
public
|
||||
Firebird::DisposeIface<
|
||||
Firebird::IExternalResultSetImpl<
|
||||
SystemResultSet,
|
||||
Firebird::ThrowStatusExceptionWrapper
|
||||
>
|
||||
>
|
||||
{
|
||||
public:
|
||||
SystemResultSet(Attachment* aAttachment, Firebird::IExternalResultSet* aResultSet)
|
||||
: attachment(aAttachment),
|
||||
resultSet(aResultSet)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
void dispose() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
public:
|
||||
FB_BOOLEAN fetch(Firebird::ThrowStatusExceptionWrapper* status) override
|
||||
{
|
||||
Firebird::AutoSetRestore<bool> autoInSystemPackage(&attachment->att_in_system_routine, true);
|
||||
|
||||
return resultSet->fetch(status);
|
||||
}
|
||||
|
||||
private:
|
||||
Attachment* attachment;
|
||||
Firebird::AutoDispose<Firebird::IExternalResultSet> resultSet;
|
||||
};
|
||||
|
||||
class SystemProcedureImpl :
|
||||
public
|
||||
Firebird::DisposeIface<
|
||||
@ -249,6 +285,9 @@ namespace Jrd
|
||||
SystemProcedureImpl(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IMetadataBuilder* inBuilder, Firebird::IMetadataBuilder* outBuilder)
|
||||
{
|
||||
const auto tdbb = JRD_get_thread_data();
|
||||
attachment = tdbb->getAttachment();
|
||||
|
||||
Input::setup(status, inBuilder);
|
||||
Output::setup(status, outBuilder);
|
||||
}
|
||||
@ -269,10 +308,17 @@ namespace Jrd
|
||||
Firebird::IExternalResultSet* open(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, void* inMsg, void* outMsg) override
|
||||
{
|
||||
return OpenFunction(status, context,
|
||||
Firebird::AutoSetRestore<bool> autoInSystemPackage(&attachment->att_in_system_routine, true);
|
||||
|
||||
const auto resultSet = OpenFunction(status, context,
|
||||
static_cast<typename Input::Type*>(inMsg),
|
||||
static_cast<typename Output::Type*>(outMsg));
|
||||
|
||||
return resultSet ? FB_NEW SystemResultSet(attachment, resultSet) : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
Attachment* attachment;
|
||||
};
|
||||
|
||||
SystemProcedureImpl* operator()(
|
||||
@ -311,6 +357,9 @@ namespace Jrd
|
||||
SystemFunctionImpl(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IMetadataBuilder* inBuilder, Firebird::IMetadataBuilder* outBuilder)
|
||||
{
|
||||
const auto tdbb = JRD_get_thread_data();
|
||||
attachment = tdbb->getAttachment();
|
||||
|
||||
Input::setup(status, inBuilder);
|
||||
Output::setup(status, outBuilder);
|
||||
}
|
||||
@ -325,10 +374,15 @@ namespace Jrd
|
||||
void execute(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, void* inMsg, void* outMsg) override
|
||||
{
|
||||
Firebird::AutoSetRestore<bool> autoInSystemPackage(&attachment->att_in_system_routine, true);
|
||||
|
||||
ExecFunction(status, context,
|
||||
static_cast<typename Input::Type*>(inMsg),
|
||||
static_cast<typename Output::Type*>(outMsg));
|
||||
}
|
||||
|
||||
private:
|
||||
Attachment* attachment;
|
||||
};
|
||||
|
||||
SystemFunctionImpl* operator()(
|
||||
|
@ -65,6 +65,7 @@ SYSTEM_PRIVILEGE(CREATE_PRIVILEGED_ROLES)
|
||||
SYSTEM_PRIVILEGE(GET_DBCRYPT_INFO)
|
||||
SYSTEM_PRIVILEGE(MODIFY_EXT_CONN_POOL)
|
||||
SYSTEM_PRIVILEGE(REPLICATE_INTO_DATABASE)
|
||||
SYSTEM_PRIVILEGE(PROFILE_ANY_ATTACHMENT)
|
||||
|
||||
#ifdef FB_JRD_SYSTEM_PRIVILEGES_TMP
|
||||
maxSystemPrivilege
|
||||
|
@ -518,6 +518,8 @@ RecordSource* CMP_post_rse(thread_db* tdbb, CompilerScratch* csb, RseNode* rse)
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
AutoSetRestore<ULONG> autoCurrentCursorProfileId(&csb->csb_currentCursorProfileId, csb->csb_nextCursorProfileId++);
|
||||
|
||||
const auto rsb = Optimizer::compile(tdbb, csb, rse);
|
||||
|
||||
// Mark all the substreams as inactive
|
||||
|
@ -109,6 +109,7 @@
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../jrd/recsrc/Cursor.h"
|
||||
#include "../jrd/Function.h"
|
||||
#include "../jrd/ProfilerManager.h"
|
||||
|
||||
|
||||
using namespace Jrd;
|
||||
@ -899,6 +900,8 @@ void EXE_start(thread_db* tdbb, Request* request, jrd_tra* transaction)
|
||||
|
||||
request->req_records_affected.clear();
|
||||
|
||||
request->req_profiler_time = 0;
|
||||
|
||||
// Store request start time for timestamp work
|
||||
request->validateTimeStamp();
|
||||
|
||||
@ -988,6 +991,14 @@ void EXE_unwind(thread_db* tdbb, Request* request)
|
||||
}
|
||||
|
||||
release_blobs(tdbb, request);
|
||||
|
||||
const auto attachment = request->req_attachment;
|
||||
|
||||
if (attachment->isProfilerActive() && !request->hasInternalStatement())
|
||||
{
|
||||
ProfilerManager::Stats stats(request->req_profiler_time);
|
||||
attachment->getProfilerManager(tdbb)->onRequestFinish(request, stats);
|
||||
}
|
||||
}
|
||||
|
||||
request->req_sorts.unlinkAll();
|
||||
@ -1363,10 +1374,10 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
|
||||
ERR_post(Arg::Gds(isc_req_no_trans));
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
const auto dbb = tdbb->getDatabase();
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
|
||||
// ASF: It's already a StmtNode, so do not do a virtual call in execution.
|
||||
if (!node) /// if (!node || node->getKind() != DmlNode::KIND_STATEMENT
|
||||
if (!node)
|
||||
BUGCHECK(147);
|
||||
|
||||
// Save the old pool and request to restore on exit
|
||||
@ -1380,6 +1391,25 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
|
||||
|
||||
// Execute stuff until we drop
|
||||
|
||||
SINT64 initialPerfCounter = fb_utils::query_performance_counter();
|
||||
SINT64 lastPerfCounter = initialPerfCounter;
|
||||
const StmtNode* profileNode = nullptr;
|
||||
|
||||
const auto profilerCallAfterPsqlLineColumn = [&] {
|
||||
const SINT64 currentPerfCounter = fb_utils::query_performance_counter();
|
||||
|
||||
if (profileNode)
|
||||
{
|
||||
ProfilerManager::Stats stats(currentPerfCounter - lastPerfCounter);
|
||||
|
||||
attachment->getProfilerManager(tdbb)->afterPsqlLineColumn(request,
|
||||
profileNode->line, profileNode->column,
|
||||
stats);
|
||||
}
|
||||
|
||||
return currentPerfCounter;
|
||||
};
|
||||
|
||||
while (node && !(request->req_flags & req_stall))
|
||||
{
|
||||
try
|
||||
@ -1393,12 +1423,33 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
|
||||
request->req_src_line = node->line;
|
||||
request->req_src_column = node->column;
|
||||
}
|
||||
|
||||
if (attachment->isProfilerActive() && !request->hasInternalStatement())
|
||||
{
|
||||
if (node->hasLineColumn &&
|
||||
node->isProfileAware() &&
|
||||
(!profileNode ||
|
||||
!(node->line == profileNode->line && node->column == profileNode->column)))
|
||||
{
|
||||
lastPerfCounter = profilerCallAfterPsqlLineColumn();
|
||||
|
||||
profileNode = node;
|
||||
|
||||
attachment->getProfilerManager(tdbb)->beforePsqlLineColumn(request,
|
||||
profileNode->line, profileNode->column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node = node->execute(tdbb, request, &exeState);
|
||||
|
||||
if (exeState.exit)
|
||||
{
|
||||
if (attachment->isProfilerActive() && !request->hasInternalStatement())
|
||||
request->req_profiler_time += profilerCallAfterPsqlLineColumn() - initialPerfCounter;
|
||||
|
||||
return node;
|
||||
}
|
||||
} // try
|
||||
catch (const Firebird::Exception& ex)
|
||||
{
|
||||
@ -1437,6 +1488,9 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
|
||||
}
|
||||
} // while()
|
||||
|
||||
if (attachment->isProfilerActive() && !request->hasInternalStatement())
|
||||
request->req_profiler_time += profilerCallAfterPsqlLineColumn() - initialPerfCounter;
|
||||
|
||||
request->adjustCallerStats();
|
||||
|
||||
fb_assert(request->req_auto_trans.getCount() == 0);
|
||||
@ -1461,6 +1515,12 @@ const StmtNode* EXE_looper(thread_db* tdbb, Request* request, const StmtNode* no
|
||||
request->req_flags &= ~(req_active | req_reserved);
|
||||
request->invalidateTimeStamp();
|
||||
release_blobs(tdbb, request);
|
||||
|
||||
if (attachment->isProfilerActive() && !request->hasInternalStatement())
|
||||
{
|
||||
ProfilerManager::Stats stats(request->req_profiler_time);
|
||||
attachment->getProfilerManager(tdbb)->onRequestFinish(request, stats);
|
||||
}
|
||||
}
|
||||
|
||||
request->req_next = node;
|
||||
|
@ -592,6 +592,10 @@ public:
|
||||
ExprNode* csb_currentAssignTarget;
|
||||
dsc* csb_preferredDesc; // expected by receiving side data format
|
||||
|
||||
ULONG csb_currentCursorProfileId = 0;
|
||||
ULONG csb_nextCursorProfileId = 1;
|
||||
ULONG csb_nextRecSourceProfileId = 1;
|
||||
|
||||
struct csb_repeat
|
||||
{
|
||||
// We must zero-initialize this one
|
||||
|
@ -223,3 +223,7 @@
|
||||
|
||||
FIELD(fld_keyword_name , nam_keyword_name , dtype_varying , METADATA_IDENTIFIER_CHAR_LEN, dsc_text_type_ascii , NULL , false)
|
||||
FIELD(fld_keyword_reserved, nam_keyword_reserved, dtype_boolean, 1 , 0 , NULL , false)
|
||||
|
||||
FIELD(fld_short_description, nam_short_description, dtype_varying, 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata, NULL , true)
|
||||
FIELD(fld_seconds_interval, nam_seconds_interval, dtype_long, sizeof(SLONG) , 0 , NULL , true)
|
||||
FIELD(fld_prof_ses_id , nam_prof_ses_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true)
|
||||
|
212
src/jrd/jrd.cpp
212
src/jrd/jrd.cpp
@ -722,118 +722,6 @@ namespace
|
||||
validateHandle(tdbb, applier->getAttachment());
|
||||
}
|
||||
|
||||
class AttachmentHolder
|
||||
{
|
||||
public:
|
||||
static const unsigned ATT_LOCK_ASYNC = 1;
|
||||
static const unsigned ATT_DONT_LOCK = 2;
|
||||
static const unsigned ATT_NO_SHUTDOWN_CHECK = 4;
|
||||
static const unsigned ATT_NON_BLOCKING = 8;
|
||||
|
||||
AttachmentHolder(thread_db* tdbb, StableAttachmentPart* sa, unsigned lockFlags, const char* from)
|
||||
: sAtt(sa),
|
||||
async(lockFlags & ATT_LOCK_ASYNC),
|
||||
nolock(lockFlags & ATT_DONT_LOCK),
|
||||
blocking(!(lockFlags & ATT_NON_BLOCKING))
|
||||
{
|
||||
if (!sa)
|
||||
Arg::Gds(isc_att_shutdown).raise();
|
||||
|
||||
if (blocking)
|
||||
sAtt->getBlockingMutex()->enter(from);
|
||||
|
||||
try
|
||||
{
|
||||
if (!nolock)
|
||||
sAtt->getSync(async)->enter(from);
|
||||
|
||||
Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex
|
||||
|
||||
try
|
||||
{
|
||||
if (!attachment || (engineShutdown && !(lockFlags & ATT_NO_SHUTDOWN_CHECK)))
|
||||
{
|
||||
// This shutdown check is an optimization, threads can still enter engine
|
||||
// with the flag set cause shutdownMutex mutex is not locked here.
|
||||
// That's not a danger cause check of att_use_count
|
||||
// in shutdown code makes it anyway safe.
|
||||
Arg::Gds err(isc_att_shutdown);
|
||||
if (sAtt->getShutError())
|
||||
err << Arg::Gds(sAtt->getShutError());
|
||||
|
||||
err.raise();
|
||||
}
|
||||
|
||||
tdbb->setAttachment(attachment);
|
||||
tdbb->setDatabase(attachment->att_database);
|
||||
|
||||
if (!async)
|
||||
{
|
||||
attachment->att_use_count++;
|
||||
attachment->setupIdleTimer(true);
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
if (!nolock)
|
||||
sAtt->getSync(async)->leave();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
if (blocking)
|
||||
sAtt->getBlockingMutex()->leave();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
~AttachmentHolder()
|
||||
{
|
||||
Jrd::Attachment* attachment = sAtt->getHandle();
|
||||
|
||||
if (attachment && !async)
|
||||
{
|
||||
attachment->att_use_count--;
|
||||
if (!attachment->att_use_count)
|
||||
attachment->setupIdleTimer(false);
|
||||
}
|
||||
|
||||
if (!nolock)
|
||||
sAtt->getSync(async)->leave();
|
||||
|
||||
if (blocking)
|
||||
sAtt->getBlockingMutex()->leave();
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<StableAttachmentPart> sAtt;
|
||||
bool async; // async mutex should be locked instead normal
|
||||
bool nolock; // if locked manually, no need to take lock recursively
|
||||
bool blocking; // holder instance is blocking other instances
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
AttachmentHolder(const AttachmentHolder&);
|
||||
AttachmentHolder& operator =(const AttachmentHolder&);
|
||||
};
|
||||
|
||||
class EngineContextHolder : public ThreadContextHolder, private AttachmentHolder,
|
||||
private DatabaseContextHolder
|
||||
{
|
||||
public:
|
||||
template <typename I>
|
||||
EngineContextHolder(CheckStatusWrapper* status, I* interfacePtr, const char* from,
|
||||
unsigned lockFlags = 0)
|
||||
: ThreadContextHolder(status),
|
||||
AttachmentHolder(*this, interfacePtr->getAttachment(), lockFlags, from),
|
||||
DatabaseContextHolder(operator thread_db*())
|
||||
{
|
||||
validateHandle(*this, interfacePtr->getHandle());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void validateAccess(thread_db* tdbb, Jrd::Attachment* attachment, SystemPrivilege sp)
|
||||
{
|
||||
if (!attachment->locksmith(tdbb, sp))
|
||||
@ -877,6 +765,98 @@ namespace
|
||||
} // anonymous
|
||||
|
||||
|
||||
AttachmentHolder::AttachmentHolder(thread_db* tdbb, StableAttachmentPart* sa, unsigned lockFlags, const char* from)
|
||||
: sAtt(sa),
|
||||
async(lockFlags & ATT_LOCK_ASYNC),
|
||||
nolock(lockFlags & ATT_DONT_LOCK),
|
||||
blocking(!(lockFlags & ATT_NON_BLOCKING))
|
||||
{
|
||||
if (!sa)
|
||||
Arg::Gds(isc_att_shutdown).raise();
|
||||
|
||||
if (blocking)
|
||||
sAtt->getBlockingMutex()->enter(from);
|
||||
|
||||
try
|
||||
{
|
||||
if (!nolock)
|
||||
sAtt->getSync(async)->enter(from);
|
||||
|
||||
Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex
|
||||
|
||||
try
|
||||
{
|
||||
if (!attachment || (engineShutdown && !(lockFlags & ATT_NO_SHUTDOWN_CHECK)))
|
||||
{
|
||||
// This shutdown check is an optimization, threads can still enter engine
|
||||
// with the flag set cause shutdownMutex mutex is not locked here.
|
||||
// That's not a danger cause check of att_use_count
|
||||
// in shutdown code makes it anyway safe.
|
||||
Arg::Gds err(isc_att_shutdown);
|
||||
if (sAtt->getShutError())
|
||||
err << Arg::Gds(sAtt->getShutError());
|
||||
|
||||
err.raise();
|
||||
}
|
||||
|
||||
tdbb->setAttachment(attachment);
|
||||
tdbb->setDatabase(attachment->att_database);
|
||||
|
||||
if (!async)
|
||||
{
|
||||
attachment->att_use_count++;
|
||||
attachment->setupIdleTimer(true);
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
if (!nolock)
|
||||
sAtt->getSync(async)->leave();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
if (blocking)
|
||||
sAtt->getBlockingMutex()->leave();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
AttachmentHolder::~AttachmentHolder()
|
||||
{
|
||||
Jrd::Attachment* attachment = sAtt->getHandle();
|
||||
|
||||
if (attachment && !async)
|
||||
{
|
||||
attachment->att_use_count--;
|
||||
if (!attachment->att_use_count)
|
||||
attachment->setupIdleTimer(false);
|
||||
}
|
||||
|
||||
if (!nolock)
|
||||
sAtt->getSync(async)->leave();
|
||||
|
||||
if (blocking)
|
||||
sAtt->getBlockingMutex()->leave();
|
||||
}
|
||||
|
||||
|
||||
template <typename I>
|
||||
EngineContextHolder::EngineContextHolder(CheckStatusWrapper* status, I* interfacePtr, const char* from,
|
||||
unsigned lockFlags)
|
||||
: ThreadContextHolder(status),
|
||||
AttachmentHolder(*this, interfacePtr->getAttachment(), lockFlags, from),
|
||||
DatabaseContextHolder(operator thread_db*())
|
||||
{
|
||||
validateHandle(*this, interfacePtr->getHandle());
|
||||
}
|
||||
|
||||
// Used in ProfilerManager.cpp
|
||||
template EngineContextHolder::EngineContextHolder(
|
||||
CheckStatusWrapper* status, JAttachment* interfacePtr, const char* from, unsigned lockFlags);
|
||||
|
||||
|
||||
#ifdef WIN_NT
|
||||
#include <windows.h>
|
||||
// these should stop a most annoying warning
|
||||
@ -956,7 +936,7 @@ void Trigger::compile(thread_db* tdbb)
|
||||
statement->triggerInvoker = att->getUserId(owner);
|
||||
|
||||
if (sysTrigger)
|
||||
statement->flags |= Statement::FLAG_SYS_TRIGGER;
|
||||
statement->flags |= Statement::FLAG_SYS_TRIGGER | Statement::FLAG_INTERNAL;
|
||||
|
||||
if (flags & TRG_ignore_perm)
|
||||
statement->flags |= Statement::FLAG_IGNORE_PERM;
|
||||
@ -5188,7 +5168,7 @@ ITransaction* JAttachment::execute(CheckStatusWrapper* user_status, ITransaction
|
||||
DSQL_execute_immediate(tdbb, getHandle(), &tra, length, string, dialect,
|
||||
inMetadata, static_cast<UCHAR*>(inBuffer),
|
||||
outMetadata, static_cast<UCHAR*>(outBuffer),
|
||||
false);
|
||||
getHandle()->att_in_system_routine);
|
||||
|
||||
jt = checkTranIntf(getStable(), jt, tra);
|
||||
}
|
||||
@ -5628,7 +5608,7 @@ JStatement* JAttachment::prepare(CheckStatusWrapper* user_status, ITransaction*
|
||||
StatementMetadata::buildInfoItems(items, flags);
|
||||
|
||||
statement = DSQL_prepare(tdbb, getHandle(), tra, stmtLength, sqlStmt, dialect, flags,
|
||||
&items, &buffer, false);
|
||||
&items, &buffer, getHandle()->att_in_system_routine);
|
||||
rc = FB_NEW JStatement(statement, getStable(), buffer);
|
||||
rc->addRef();
|
||||
|
||||
@ -7642,6 +7622,8 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment, XThreadEns
|
||||
if (!attachment)
|
||||
return;
|
||||
|
||||
attachment->releaseProfilerManager();
|
||||
|
||||
attachment->att_replicator = nullptr;
|
||||
|
||||
if (attachment->att_dsql_instance)
|
||||
|
@ -1034,6 +1034,37 @@ namespace Jrd {
|
||||
BackgroundContextHolder& operator=(const BackgroundContextHolder&);
|
||||
};
|
||||
|
||||
class AttachmentHolder
|
||||
{
|
||||
public:
|
||||
static const unsigned ATT_LOCK_ASYNC = 1;
|
||||
static const unsigned ATT_DONT_LOCK = 2;
|
||||
static const unsigned ATT_NO_SHUTDOWN_CHECK = 4;
|
||||
static const unsigned ATT_NON_BLOCKING = 8;
|
||||
|
||||
AttachmentHolder(thread_db* tdbb, StableAttachmentPart* sa, unsigned lockFlags, const char* from);
|
||||
~AttachmentHolder();
|
||||
|
||||
private:
|
||||
Firebird::RefPtr<StableAttachmentPart> sAtt;
|
||||
bool async; // async mutex should be locked instead normal
|
||||
bool nolock; // if locked manually, no need to take lock recursively
|
||||
bool blocking; // holder instance is blocking other instances
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
AttachmentHolder(const AttachmentHolder&);
|
||||
AttachmentHolder& operator =(const AttachmentHolder&);
|
||||
};
|
||||
|
||||
class EngineContextHolder final : public ThreadContextHolder, private AttachmentHolder, private DatabaseContextHolder
|
||||
{
|
||||
public:
|
||||
template <typename I>
|
||||
EngineContextHolder(Firebird::CheckStatusWrapper* status, I* interfacePtr, const char* from,
|
||||
unsigned lockFlags = 0);
|
||||
};
|
||||
|
||||
class AstLockHolder : public Firebird::ReadLockGuard
|
||||
{
|
||||
public:
|
||||
@ -1083,18 +1114,28 @@ namespace Jrd {
|
||||
class EngineCheckout
|
||||
{
|
||||
public:
|
||||
EngineCheckout(thread_db* tdbb, const char* from, bool optional = false)
|
||||
enum Type
|
||||
{
|
||||
REQUIRED,
|
||||
UNNECESSARY,
|
||||
AVOID
|
||||
};
|
||||
|
||||
EngineCheckout(thread_db* tdbb, const char* from, Type type = REQUIRED)
|
||||
: m_tdbb(tdbb), m_from(from)
|
||||
{
|
||||
Attachment* const att = tdbb ? tdbb->getAttachment() : NULL;
|
||||
if (type != AVOID)
|
||||
{
|
||||
Attachment* const att = tdbb ? tdbb->getAttachment() : NULL;
|
||||
|
||||
if (att)
|
||||
m_ref = att->getStable();
|
||||
if (att)
|
||||
m_ref = att->getStable();
|
||||
|
||||
fb_assert(optional || m_ref.hasData());
|
||||
fb_assert(type == UNNECESSARY || m_ref.hasData());
|
||||
|
||||
if (m_ref.hasData())
|
||||
m_ref->getSync()->leave();
|
||||
if (m_ref.hasData())
|
||||
m_ref->getSync()->leave();
|
||||
}
|
||||
}
|
||||
|
||||
EngineCheckout(Attachment* att, const char* from, bool optional = false)
|
||||
@ -1140,7 +1181,7 @@ namespace Jrd {
|
||||
{
|
||||
if (!m_mutex.tryEnter(from))
|
||||
{
|
||||
EngineCheckout cout(tdbb, from, optional);
|
||||
EngineCheckout cout(tdbb, from, optional ? EngineCheckout::UNNECESSARY : EngineCheckout::REQUIRED);
|
||||
m_mutex.enter(from);
|
||||
}
|
||||
}
|
||||
@ -1168,7 +1209,7 @@ namespace Jrd {
|
||||
{
|
||||
if (!m_sync.lockConditional(type, from))
|
||||
{
|
||||
EngineCheckout cout(tdbb, from, optional);
|
||||
EngineCheckout cout(tdbb, from, optional ? EngineCheckout::UNNECESSARY : EngineCheckout::REQUIRED);
|
||||
m_sync.lock(type);
|
||||
}
|
||||
}
|
||||
|
@ -585,6 +585,7 @@ static lck_owner_t get_owner_type(enum lck_t lock_type)
|
||||
case LCK_alter_database:
|
||||
case LCK_repl_tables:
|
||||
case LCK_dsql_statement_cache:
|
||||
case LCK_profiler_listener:
|
||||
owner_type = LCK_OWNER_attachment;
|
||||
break;
|
||||
|
||||
|
@ -75,7 +75,8 @@ enum lck_t {
|
||||
LCK_alter_database, // ALTER DATABASE lock
|
||||
LCK_repl_state, // Replication state lock
|
||||
LCK_repl_tables, // Replication set lock
|
||||
LCK_dsql_statement_cache // DSQL statement cache lock
|
||||
LCK_dsql_statement_cache, // DSQL statement cache lock
|
||||
LCK_profiler_listener // Remote profiler listener
|
||||
};
|
||||
|
||||
// Lock owner types
|
||||
|
@ -3225,7 +3225,7 @@ void MET_parse_sys_trigger(thread_db* tdbb, jrd_rel* relation)
|
||||
|
||||
statement->triggerName = name;
|
||||
|
||||
statement->flags |= Statement::FLAG_SYS_TRIGGER;
|
||||
statement->flags |= Statement::FLAG_SYS_TRIGGER | Statement::FLAG_INTERNAL;
|
||||
if (trig_flags & TRG_ignore_perm)
|
||||
statement->flags |= Statement::FLAG_IGNORE_PERM;
|
||||
|
||||
|
@ -460,3 +460,7 @@ NAME("RDB$KEYWORD_RESERVED", nam_keyword_reserved)
|
||||
|
||||
NAME("MON$COMPILED_STATEMENTS", nam_mon_compiled_statements)
|
||||
NAME("MON$COMPILED_STATEMENT_ID", nam_mon_cmp_stmt_id)
|
||||
|
||||
NAME("RDB$SHORT_DESCRIPTION", nam_short_description)
|
||||
NAME("RDB$SECONDS_INTERVAL", nam_seconds_interval)
|
||||
NAME("RDB$PROFILE_SESSION_ID", nam_prof_ses_id)
|
||||
|
53
src/jrd/opt_proto.h
Normal file
53
src/jrd/opt_proto.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* PROGRAM: JRD Access Method
|
||||
* MODULE: opt_proto.h
|
||||
* DESCRIPTION: Prototype header file for opt.cpp
|
||||
*
|
||||
* The contents of this file are subject to the Interbase Public
|
||||
* License Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy
|
||||
* of the License at http://www.Inprise.com/IPL.html
|
||||
*
|
||||
* Software distributed under the License is distributed on an
|
||||
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Inprise Corporation
|
||||
* and its predecessors. Portions created by Inprise Corporation are
|
||||
* Copyright (C) Inprise Corporation.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#ifndef JRD_OPT_PROTO_H
|
||||
#define JRD_OPT_PROTO_H
|
||||
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/btr.h"
|
||||
#include "../jrd/lls.h"
|
||||
|
||||
namespace Jrd {
|
||||
class Request;
|
||||
class jrd_rel;
|
||||
class RecordSource;
|
||||
struct index_desc;
|
||||
class CompilerScratch;
|
||||
class OptimizerBlk;
|
||||
class SortedStream;
|
||||
class SortNode;
|
||||
class MapNode;
|
||||
}
|
||||
|
||||
Firebird::string OPT_get_plan(Jrd::thread_db* tdbb, const Jrd::Statement* statement, bool detailed);
|
||||
Jrd::RecordSource* OPT_compile(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb,
|
||||
Jrd::RseNode* rse, Jrd::BoolExprNodeStack* parent_stack);
|
||||
void OPT_compile_relation(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, Jrd::CompilerScratch* csb,
|
||||
StreamType stream, bool needIndices);
|
||||
void OPT_gen_aggregate_distincts(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb, Jrd::MapNode* map);
|
||||
Jrd::SortedStream* OPT_gen_sort(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb, const Jrd::StreamList& streams,
|
||||
const Jrd::StreamList* dbkey_streams, Jrd::RecordSource* prior_rsb, Jrd::SortNode* sort,
|
||||
bool refetch_flag, bool project_flag);
|
||||
|
||||
#endif // JRD_OPT_PROTO_H
|
@ -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;
|
||||
|
@ -63,7 +63,7 @@ BaseAggWinStream<ThisType, NextType>::BaseAggWinStream(thread_db* tdbb, Compiler
|
||||
}
|
||||
|
||||
template <typename ThisType, typename NextType>
|
||||
void BaseAggWinStream<ThisType, NextType>::open(thread_db* tdbb) const
|
||||
void BaseAggWinStream<ThisType, NextType>::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = getImpure(request);
|
||||
@ -376,7 +376,12 @@ AggregatedStream::AggregatedStream(thread_db* tdbb, CompilerScratch* csb, Stream
|
||||
fb_assert(map);
|
||||
}
|
||||
|
||||
void AggregatedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void AggregatedStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void AggregatedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -384,10 +389,11 @@ void AggregatedStream::print(thread_db* tdbb, string& plan, bool detailed, unsig
|
||||
printOptInfo(plan);
|
||||
}
|
||||
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
bool AggregatedStream::getRecord(thread_db* tdbb) const
|
||||
bool AggregatedStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
|
@ -47,7 +47,7 @@ BitmapTableScan::BitmapTableScan(CompilerScratch* csb, const string& alias,
|
||||
m_cardinality = csb->csb_rpt[stream].csb_cardinality * selectivity;
|
||||
}
|
||||
|
||||
void BitmapTableScan::open(thread_db* tdbb) const
|
||||
void BitmapTableScan::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -81,7 +81,7 @@ void BitmapTableScan::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool BitmapTableScan::getRecord(thread_db* tdbb) const
|
||||
bool BitmapTableScan::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -122,8 +122,12 @@ bool BitmapTableScan::getRecord(thread_db* tdbb) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void BitmapTableScan::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
}
|
||||
|
||||
void BitmapTableScan::print(thread_db* tdbb, string& plan,
|
||||
bool detailed, unsigned level) const
|
||||
bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
|
@ -40,7 +40,9 @@ using namespace Jrd;
|
||||
// --------------------------
|
||||
|
||||
BufferedStream::BufferedStream(CompilerScratch* csb, RecordSource* next)
|
||||
: m_next(next), m_map(csb->csb_pool)
|
||||
: BaseBufferedStream(csb),
|
||||
m_next(next),
|
||||
m_map(csb->csb_pool)
|
||||
{
|
||||
fb_assert(m_next);
|
||||
|
||||
@ -113,7 +115,7 @@ BufferedStream::BufferedStream(CompilerScratch* csb, RecordSource* next)
|
||||
m_format = format;
|
||||
}
|
||||
|
||||
void BufferedStream::open(thread_db* tdbb) const
|
||||
void BufferedStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -148,7 +150,7 @@ void BufferedStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool BufferedStream::getRecord(thread_db* tdbb) const
|
||||
bool BufferedStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -312,7 +314,12 @@ bool BufferedStream::lockRecord(thread_db* tdbb) const
|
||||
return m_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void BufferedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void BufferedStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void BufferedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -323,7 +330,8 @@ void BufferedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
|
||||
printOptInfo(plan);
|
||||
}
|
||||
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void BufferedStream::markRecursive()
|
||||
|
@ -41,7 +41,10 @@ using namespace Jrd;
|
||||
ConditionalStream::ConditionalStream(CompilerScratch* csb,
|
||||
RecordSource* first, RecordSource* second,
|
||||
BoolExprNode* boolean)
|
||||
: m_first(first), m_second(second), m_boolean(boolean)
|
||||
: RecordSource(csb),
|
||||
m_first(first),
|
||||
m_second(second),
|
||||
m_boolean(boolean)
|
||||
{
|
||||
fb_assert(m_first && m_second && m_boolean);
|
||||
|
||||
@ -49,7 +52,7 @@ ConditionalStream::ConditionalStream(CompilerScratch* csb,
|
||||
m_cardinality = (first->getCardinality() + second->getCardinality()) / 2;
|
||||
}
|
||||
|
||||
void ConditionalStream::open(thread_db* tdbb) const
|
||||
void ConditionalStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -76,7 +79,7 @@ void ConditionalStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool ConditionalStream::getRecord(thread_db* tdbb) const
|
||||
bool ConditionalStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -111,26 +114,35 @@ bool ConditionalStream::lockRecord(thread_db* tdbb) const
|
||||
return impure->irsb_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void ConditionalStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void ConditionalStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_first);
|
||||
children.add(m_second);
|
||||
}
|
||||
|
||||
void ConditionalStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
plan += printIndent(++level) + "Condition";
|
||||
printOptInfo(plan);
|
||||
|
||||
m_first->print(tdbb, plan, true, level);
|
||||
m_second->print(tdbb, plan, true, level);
|
||||
if (recurse)
|
||||
{
|
||||
m_first->print(tdbb, plan, true, level, recurse);
|
||||
m_second->print(tdbb, plan, true, level, recurse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!level)
|
||||
plan += "(";
|
||||
|
||||
m_first->print(tdbb, plan, false, level + 1);
|
||||
m_first->print(tdbb, plan, false, level + 1, recurse);
|
||||
|
||||
plan += ", ";
|
||||
|
||||
m_second->print(tdbb, plan, false, level + 1);
|
||||
m_second->print(tdbb, plan, false, level + 1, recurse);
|
||||
|
||||
if (!level)
|
||||
plan += ")";
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "firebird.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/req.h"
|
||||
#include "../jrd/ProfilerManager.h"
|
||||
#include "../jrd/cmp_proto.h"
|
||||
|
||||
#include "RecordSource.h"
|
||||
@ -105,7 +106,7 @@ Cursor::Cursor(CompilerScratch* csb, const RecordSource* rsb,
|
||||
|
||||
void Cursor::open(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
const auto request = tdbb->getRequest();
|
||||
Impure* impure = request->getImpure<Impure>(m_impure);
|
||||
|
||||
impure->irsb_active = true;
|
||||
@ -135,7 +136,7 @@ bool Cursor::fetchNext(thread_db* tdbb) const
|
||||
if (!validate(tdbb))
|
||||
return false;
|
||||
|
||||
Request* const request = tdbb->getRequest();
|
||||
const auto request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
|
||||
if (!impure->irsb_active)
|
||||
@ -207,7 +208,7 @@ bool Cursor::fetchAbsolute(thread_db* tdbb, SINT64 offset) const
|
||||
if (!validate(tdbb))
|
||||
return false;
|
||||
|
||||
Request* const request = tdbb->getRequest();
|
||||
const auto request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
|
||||
if (!impure->irsb_active)
|
||||
@ -268,7 +269,7 @@ bool Cursor::fetchRelative(thread_db* tdbb, SINT64 offset) const
|
||||
if (!validate(tdbb))
|
||||
return false;
|
||||
|
||||
Request* const request = tdbb->getRequest();
|
||||
const auto request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
|
||||
if (!impure->irsb_active)
|
||||
|
@ -45,7 +45,7 @@ ExternalTableScan::ExternalTableScan(CompilerScratch* csb, const string& alias,
|
||||
m_cardinality = csb->csb_rpt[stream].csb_cardinality;
|
||||
}
|
||||
|
||||
void ExternalTableScan::open(thread_db* tdbb) const
|
||||
void ExternalTableScan::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Request* const request = tdbb->getRequest();
|
||||
@ -76,7 +76,7 @@ void ExternalTableScan::close(thread_db* tdbb) const
|
||||
impure->irsb_flags &= ~irsb_open;
|
||||
}
|
||||
|
||||
bool ExternalTableScan::getRecord(thread_db* tdbb) const
|
||||
bool ExternalTableScan::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -116,8 +116,12 @@ bool ExternalTableScan::lockRecord(thread_db* tdbb) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void ExternalTableScan::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
}
|
||||
|
||||
void ExternalTableScan::print(thread_db* tdbb, string& plan,
|
||||
bool detailed, unsigned level) const
|
||||
bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
|
@ -36,10 +36,14 @@ using namespace Jrd;
|
||||
// Data access: predicate driven filter
|
||||
// ------------------------------------
|
||||
|
||||
FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next,
|
||||
BoolExprNode* boolean, double selectivity)
|
||||
: m_next(next), m_boolean(boolean), m_anyBoolean(NULL),
|
||||
m_ansiAny(false), m_ansiAll(false), m_ansiNot(false)
|
||||
FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean, double selectivity)
|
||||
: RecordSource(csb),
|
||||
m_next(next),
|
||||
m_boolean(boolean),
|
||||
m_anyBoolean(NULL),
|
||||
m_ansiAny(false),
|
||||
m_ansiAll(false),
|
||||
m_ansiNot(false)
|
||||
{
|
||||
fb_assert(m_next && m_boolean);
|
||||
|
||||
@ -50,7 +54,7 @@ FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next,
|
||||
m_cardinality = cardinality * selectivity;
|
||||
}
|
||||
|
||||
void FilteredStream::open(thread_db* tdbb) const
|
||||
void FilteredStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -76,7 +80,7 @@ void FilteredStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool FilteredStream::getRecord(thread_db* tdbb) const
|
||||
bool FilteredStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -108,7 +112,12 @@ bool FilteredStream::lockRecord(thread_db* tdbb) const
|
||||
return m_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void FilteredStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void FilteredStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void FilteredStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -116,7 +125,8 @@ void FilteredStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
|
||||
printOptInfo(plan);
|
||||
}
|
||||
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void FilteredStream::markRecursive()
|
||||
|
@ -38,7 +38,9 @@ using namespace Jrd;
|
||||
// --------------------------------
|
||||
|
||||
FirstRowsStream::FirstRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value)
|
||||
: m_next(next), m_value(value)
|
||||
: RecordSource(csb),
|
||||
m_next(next),
|
||||
m_value(value)
|
||||
{
|
||||
fb_assert(m_next && m_value);
|
||||
|
||||
@ -50,7 +52,7 @@ FirstRowsStream::FirstRowsStream(CompilerScratch* csb, RecordSource* next, Value
|
||||
valueConst->getSlong() : DEFAULT_CARDINALITY;
|
||||
}
|
||||
|
||||
void FirstRowsStream::open(thread_db* tdbb) const
|
||||
void FirstRowsStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -87,7 +89,7 @@ void FirstRowsStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool FirstRowsStream::getRecord(thread_db* tdbb) const
|
||||
bool FirstRowsStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -118,7 +120,12 @@ bool FirstRowsStream::lockRecord(thread_db* tdbb) const
|
||||
return m_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void FirstRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void FirstRowsStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void FirstRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -126,7 +133,8 @@ void FirstRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsign
|
||||
printOptInfo(plan);
|
||||
}
|
||||
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void FirstRowsStream::markRecursive()
|
||||
|
@ -38,7 +38,9 @@ using namespace Jrd;
|
||||
// ----------------------------
|
||||
|
||||
FullOuterJoin::FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSource* arg2)
|
||||
: m_arg1(arg1), m_arg2(arg2)
|
||||
: RecordSource(csb),
|
||||
m_arg1(arg1),
|
||||
m_arg2(arg2)
|
||||
{
|
||||
fb_assert(m_arg1 && m_arg2);
|
||||
|
||||
@ -46,7 +48,7 @@ FullOuterJoin::FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSou
|
||||
m_cardinality = arg1->getCardinality() + arg2->getCardinality();
|
||||
}
|
||||
|
||||
void FullOuterJoin::open(thread_db* tdbb) const
|
||||
void FullOuterJoin::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -75,7 +77,7 @@ void FullOuterJoin::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool FullOuterJoin::getRecord(thread_db* tdbb) const
|
||||
bool FullOuterJoin::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -111,21 +113,31 @@ bool FullOuterJoin::lockRecord(thread_db* tdbb) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void FullOuterJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void FullOuterJoin::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_arg1);
|
||||
children.add(m_arg2);
|
||||
}
|
||||
|
||||
void FullOuterJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
plan += printIndent(++level) + "Full Outer Join";
|
||||
m_arg1->print(tdbb, plan, true, level);
|
||||
m_arg2->print(tdbb, plan, true, level);
|
||||
|
||||
if (recurse)
|
||||
{
|
||||
m_arg1->print(tdbb, plan, true, level, recurse);
|
||||
m_arg2->print(tdbb, plan, true, level, recurse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level++;
|
||||
plan += "JOIN (";
|
||||
m_arg1->print(tdbb, plan, false, level);
|
||||
m_arg1->print(tdbb, plan, false, level, recurse);
|
||||
plan += ", ";
|
||||
m_arg2->print(tdbb, plan, false, level);
|
||||
m_arg2->print(tdbb, plan, false, level, recurse);
|
||||
plan += ")";
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ FullTableScan::FullTableScan(CompilerScratch* csb, const string& alias,
|
||||
m_cardinality = csb->csb_rpt[stream].csb_cardinality;
|
||||
}
|
||||
|
||||
void FullTableScan::open(thread_db* tdbb) const
|
||||
void FullTableScan::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
Attachment* const attachment = tdbb->getAttachment();
|
||||
@ -132,7 +132,7 @@ void FullTableScan::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool FullTableScan::getRecord(thread_db* tdbb) const
|
||||
bool FullTableScan::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -162,7 +162,11 @@ bool FullTableScan::getRecord(thread_db* tdbb) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void FullTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void FullTableScan::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
}
|
||||
|
||||
void FullTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
|
@ -219,7 +219,8 @@ private:
|
||||
|
||||
HashJoin::HashJoin(thread_db* tdbb, CompilerScratch* csb, FB_SIZE_T count,
|
||||
RecordSource* const* args, NestValueArray* const* keys)
|
||||
: m_args(csb->csb_pool, count - 1)
|
||||
: RecordSource(csb),
|
||||
m_args(csb->csb_pool, count - 1)
|
||||
{
|
||||
fb_assert(count >= 2);
|
||||
|
||||
@ -296,7 +297,7 @@ HashJoin::HashJoin(thread_db* tdbb, CompilerScratch* csb, FB_SIZE_T count,
|
||||
}
|
||||
}
|
||||
|
||||
void HashJoin::open(thread_db* tdbb) const
|
||||
void HashJoin::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -361,7 +362,7 @@ void HashJoin::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool HashJoin::getRecord(thread_db* tdbb) const
|
||||
bool HashJoin::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -441,30 +442,41 @@ bool HashJoin::lockRecord(thread_db* /*tdbb*/) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void HashJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void HashJoin::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_leader.source);
|
||||
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
children.add(m_args[i].source);
|
||||
}
|
||||
|
||||
void HashJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
plan += printIndent(++level) + "Hash Join (inner)";
|
||||
printOptInfo(plan);
|
||||
|
||||
m_leader.source->print(tdbb, plan, true, level);
|
||||
if (recurse)
|
||||
{
|
||||
m_leader.source->print(tdbb, plan, true, level, recurse);
|
||||
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
m_args[i].source->print(tdbb, plan, true, level);
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
m_args[i].source->print(tdbb, plan, true, level, recurse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level++;
|
||||
plan += "HASH (";
|
||||
m_leader.source->print(tdbb, plan, false, level);
|
||||
m_leader.source->print(tdbb, plan, false, level, recurse);
|
||||
plan += ", ";
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
{
|
||||
if (i)
|
||||
plan += ", ";
|
||||
|
||||
m_args[i].source->print(tdbb, plan, false, level);
|
||||
m_args[i].source->print(tdbb, plan, false, level, recurse);
|
||||
}
|
||||
plan += ")";
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ IndexTableScan::IndexTableScan(CompilerScratch* csb, const string& alias,
|
||||
m_cardinality = csb->csb_rpt[stream].csb_cardinality * selectivity;
|
||||
}
|
||||
|
||||
void IndexTableScan::open(thread_db* tdbb) const
|
||||
void IndexTableScan::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -146,7 +146,7 @@ void IndexTableScan::close(thread_db* tdbb) const
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IndexTableScan::getRecord(thread_db* tdbb) const
|
||||
bool IndexTableScan::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -303,7 +303,11 @@ bool IndexTableScan::getRecord(thread_db* tdbb) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void IndexTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void IndexTableScan::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
}
|
||||
|
||||
void IndexTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ LocalTableStream::LocalTableStream(CompilerScratch* csb, StreamType stream, cons
|
||||
m_cardinality = DEFAULT_CARDINALITY;
|
||||
}
|
||||
|
||||
void LocalTableStream::open(thread_db* tdbb) const
|
||||
void LocalTableStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
const auto request = tdbb->getRequest();
|
||||
const auto impure = request->getImpure<Impure>(m_impure);
|
||||
@ -71,7 +71,11 @@ void LocalTableStream::close(thread_db* tdbb) const
|
||||
impure->irsb_flags &= ~irsb_open;
|
||||
}
|
||||
|
||||
bool LocalTableStream::getRecord(thread_db* tdbb) const
|
||||
void LocalTableStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
}
|
||||
|
||||
bool LocalTableStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -110,7 +114,7 @@ bool LocalTableStream::lockRecord(thread_db* tdbb) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void LocalTableStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void LocalTableStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
//// TODO: Use Local Table name/alias.
|
||||
|
||||
|
@ -35,7 +35,8 @@ using namespace Jrd;
|
||||
// ------------------------------------
|
||||
|
||||
LockedStream::LockedStream(CompilerScratch* csb, RecordSource* next)
|
||||
: m_next(next)
|
||||
: RecordSource(csb),
|
||||
m_next(next)
|
||||
{
|
||||
fb_assert(m_next);
|
||||
|
||||
@ -43,7 +44,7 @@ LockedStream::LockedStream(CompilerScratch* csb, RecordSource* next)
|
||||
m_cardinality = next->getCardinality();
|
||||
}
|
||||
|
||||
void LockedStream::open(thread_db* tdbb) const
|
||||
void LockedStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -69,7 +70,7 @@ void LockedStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool LockedStream::getRecord(thread_db* tdbb) const
|
||||
bool LockedStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -103,7 +104,12 @@ bool LockedStream::lockRecord(thread_db* tdbb) const
|
||||
return m_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void LockedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void LockedStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void LockedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -111,7 +117,8 @@ void LockedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned
|
||||
printOptInfo(plan);
|
||||
}
|
||||
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void LockedStream::markRecursive()
|
||||
|
@ -38,7 +38,9 @@ static const char* const SCRATCH = "fb_merge_";
|
||||
|
||||
MergeJoin::MergeJoin(CompilerScratch* csb, FB_SIZE_T count,
|
||||
SortedStream* const* args, const NestValueArray* const* keys)
|
||||
: m_args(csb->csb_pool), m_keys(csb->csb_pool)
|
||||
: RecordSource(csb),
|
||||
m_args(csb->csb_pool),
|
||||
m_keys(csb->csb_pool)
|
||||
{
|
||||
const size_t size = sizeof(struct Impure) + count * sizeof(Impure::irsb_mrg_repeat);
|
||||
m_impure = csb->allocImpure(FB_ALIGNMENT, static_cast<ULONG>(size));
|
||||
@ -61,7 +63,7 @@ MergeJoin::MergeJoin(CompilerScratch* csb, FB_SIZE_T count,
|
||||
}
|
||||
}
|
||||
|
||||
void MergeJoin::open(thread_db* tdbb) const
|
||||
void MergeJoin::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -130,7 +132,7 @@ void MergeJoin::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool MergeJoin::getRecord(thread_db* tdbb) const
|
||||
bool MergeJoin::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -185,7 +187,7 @@ bool MergeJoin::getRecord(thread_db* tdbb) const
|
||||
{
|
||||
mfb->mfb_current_block = 0;
|
||||
mfb->mfb_equal_records = 0;
|
||||
if ((record = getRecord(tdbb, i)) < 0)
|
||||
if ((record = getRecordByIndex(tdbb, i)) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -229,7 +231,7 @@ bool MergeJoin::getRecord(thread_db* tdbb) const
|
||||
mfb->mfb_current_block = 0;
|
||||
mfb->mfb_equal_records = 0;
|
||||
|
||||
const SLONG record = getRecord(tdbb, i);
|
||||
const SLONG record = getRecordByIndex(tdbb, i);
|
||||
if (record < 0)
|
||||
return false;
|
||||
|
||||
@ -260,7 +262,7 @@ bool MergeJoin::getRecord(thread_db* tdbb) const
|
||||
memcpy(first_data, getData(tdbb, mfb, 0), key_length);
|
||||
|
||||
SLONG record;
|
||||
while ((record = getRecord(tdbb, i)) >= 0)
|
||||
while ((record = getRecordByIndex(tdbb, i)) >= 0)
|
||||
{
|
||||
const UCHAR* p = first_data;
|
||||
const UCHAR* q = getData(tdbb, mfb, record);
|
||||
@ -341,15 +343,24 @@ bool MergeJoin::lockRecord(thread_db* /*tdbb*/) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void MergeJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void MergeJoin::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
children.add(m_args[i]);
|
||||
}
|
||||
|
||||
void MergeJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
plan += printIndent(++level) + "Merge Join (inner)";
|
||||
printOptInfo(plan);
|
||||
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
m_args[i]->print(tdbb, plan, true, level);
|
||||
if (recurse)
|
||||
{
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
m_args[i]->print(tdbb, plan, true, level, recurse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -360,7 +371,7 @@ void MergeJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned lev
|
||||
if (i)
|
||||
plan += ", ";
|
||||
|
||||
m_args[i]->print(tdbb, plan, false, level);
|
||||
m_args[i]->print(tdbb, plan, false, level, recurse);
|
||||
}
|
||||
plan += ")";
|
||||
}
|
||||
@ -440,7 +451,7 @@ UCHAR* MergeJoin::getData(thread_db* /*tdbb*/, MergeFile* mfb, SLONG record) con
|
||||
return mfb->mfb_block_data + merge_offset;
|
||||
}
|
||||
|
||||
SLONG MergeJoin::getRecord(thread_db* tdbb, FB_SIZE_T index) const
|
||||
SLONG MergeJoin::getRecordByIndex(thread_db* tdbb, FB_SIZE_T index) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
|
@ -36,7 +36,10 @@ using namespace Jrd;
|
||||
// ------------------------------
|
||||
|
||||
NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, FB_SIZE_T count, RecordSource* const* args)
|
||||
: m_joinType(INNER_JOIN), m_args(csb->csb_pool), m_boolean(NULL)
|
||||
: RecordSource(csb),
|
||||
m_joinType(INNER_JOIN),
|
||||
m_args(csb->csb_pool),
|
||||
m_boolean(NULL)
|
||||
{
|
||||
m_impure = csb->allocImpure<Impure>();
|
||||
m_cardinality = MINIMUM_CARDINALITY;
|
||||
@ -52,7 +55,10 @@ NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, FB_SIZE_T count, RecordSour
|
||||
|
||||
NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
|
||||
BoolExprNode* boolean, JoinType joinType)
|
||||
: m_joinType(joinType), m_args(csb->csb_pool), m_boolean(boolean)
|
||||
: RecordSource(csb),
|
||||
m_joinType(joinType),
|
||||
m_args(csb->csb_pool),
|
||||
m_boolean(boolean)
|
||||
{
|
||||
fb_assert(outer && inner);
|
||||
|
||||
@ -64,7 +70,7 @@ NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, Record
|
||||
m_cardinality = outer->getCardinality() * inner->getCardinality();
|
||||
}
|
||||
|
||||
void NestedLoopJoin::open(thread_db* tdbb) const
|
||||
void NestedLoopJoin::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -89,7 +95,7 @@ void NestedLoopJoin::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool NestedLoopJoin::getRecord(thread_db* tdbb) const
|
||||
bool NestedLoopJoin::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -203,7 +209,13 @@ bool NestedLoopJoin::lockRecord(thread_db* /*tdbb*/) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void NestedLoopJoin::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
children.add(m_args[i]);
|
||||
}
|
||||
|
||||
void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (m_args.hasData())
|
||||
{
|
||||
@ -235,8 +247,11 @@ void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigne
|
||||
|
||||
printOptInfo(plan);
|
||||
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
m_args[i]->print(tdbb, plan, true, level);
|
||||
if (recurse)
|
||||
{
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
m_args[i]->print(tdbb, plan, true, level, recurse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -247,7 +262,7 @@ void NestedLoopJoin::print(thread_db* tdbb, string& plan, bool detailed, unsigne
|
||||
if (i)
|
||||
plan += ", ";
|
||||
|
||||
m_args[i]->print(tdbb, plan, false, level);
|
||||
m_args[i]->print(tdbb, plan, false, level, recurse);
|
||||
}
|
||||
plan += ")";
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ ProcedureScan::ProcedureScan(CompilerScratch* csb, const string& alias, StreamTy
|
||||
fb_assert(sourceList->items.getCount() == targetList->items.getCount());
|
||||
}
|
||||
|
||||
void ProcedureScan::open(thread_db* tdbb) const
|
||||
void ProcedureScan::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
if (!m_procedure->isImplemented())
|
||||
{
|
||||
@ -167,7 +167,7 @@ void ProcedureScan::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcedureScan::getRecord(thread_db* tdbb) const
|
||||
bool ProcedureScan::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -249,7 +249,11 @@ bool ProcedureScan::lockRecord(thread_db* /*tdbb*/) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void ProcedureScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void ProcedureScan::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
}
|
||||
|
||||
void ProcedureScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "../jrd/btr.h"
|
||||
#include "../jrd/intl.h"
|
||||
#include "../jrd/req.h"
|
||||
#include "../jrd/ProfilerManager.h"
|
||||
#include "../jrd/cmp_proto.h"
|
||||
#include "../jrd/dpm_proto.h"
|
||||
#include "../jrd/err_proto.h"
|
||||
@ -46,6 +47,72 @@ using namespace Jrd;
|
||||
// Record source class
|
||||
// -------------------
|
||||
|
||||
RecordSource::RecordSource(CompilerScratch* csb)
|
||||
: m_cursorProfileId(csb->csb_currentCursorProfileId),
|
||||
m_recSourceProfileId(csb->csb_nextRecSourceProfileId++)
|
||||
{
|
||||
}
|
||||
|
||||
void RecordSource::open(thread_db* tdbb) const
|
||||
{
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
const auto request = tdbb->getRequest();
|
||||
|
||||
const auto profilerManager = attachment->isProfilerActive() && !request->hasInternalStatement() ?
|
||||
attachment->getProfilerManager(tdbb) :
|
||||
nullptr;
|
||||
|
||||
const SINT64 lastPerfCounter = profilerManager ?
|
||||
fb_utils::query_performance_counter() :
|
||||
0;
|
||||
|
||||
if (profilerManager)
|
||||
{
|
||||
profilerManager->prepareRecSource(tdbb, request, this);
|
||||
profilerManager->beforeRecordSourceOpen(request, this);
|
||||
}
|
||||
|
||||
internalOpen(tdbb);
|
||||
|
||||
if (profilerManager)
|
||||
{
|
||||
const SINT64 currentPerfCounter = fb_utils::query_performance_counter();
|
||||
ProfilerManager::Stats stats(currentPerfCounter - lastPerfCounter);
|
||||
profilerManager->afterRecordSourceOpen(request, this, stats);
|
||||
}
|
||||
}
|
||||
|
||||
bool RecordSource::getRecord(thread_db* tdbb) const
|
||||
{
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
const auto request = tdbb->getRequest();
|
||||
|
||||
const auto profilerManager = attachment->isProfilerActive() && !request->hasInternalStatement() ?
|
||||
attachment->getProfilerManager(tdbb) :
|
||||
nullptr;
|
||||
|
||||
const SINT64 lastPerfCounter = profilerManager ?
|
||||
fb_utils::query_performance_counter() :
|
||||
0;
|
||||
|
||||
if (profilerManager)
|
||||
{
|
||||
profilerManager->prepareRecSource(tdbb, request, this);
|
||||
profilerManager->beforeRecordSourceGetRecord(request, this);
|
||||
}
|
||||
|
||||
const auto ret = internalGetRecord(tdbb);
|
||||
|
||||
if (profilerManager)
|
||||
{
|
||||
const SINT64 currentPerfCounter = fb_utils::query_performance_counter();
|
||||
ProfilerManager::Stats stats(currentPerfCounter - lastPerfCounter);
|
||||
profilerManager->afterRecordSourceGetRecord(request, this, stats);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
string RecordSource::printName(thread_db* tdbb, const string& name, bool quote)
|
||||
{
|
||||
const string result(name.c_str(), name.length());
|
||||
@ -194,7 +261,9 @@ RecordSource::~RecordSource()
|
||||
// ------------------
|
||||
|
||||
RecordStream::RecordStream(CompilerScratch* csb, StreamType stream, const Format* format)
|
||||
: m_stream(stream), m_format(format ? format : csb->csb_rpt[stream].csb_format)
|
||||
: RecordSource(csb),
|
||||
m_stream(stream),
|
||||
m_format(format ? format : csb->csb_rpt[stream].csb_format)
|
||||
{
|
||||
fb_assert(m_format);
|
||||
}
|
||||
|
@ -57,15 +57,15 @@ namespace Jrd
|
||||
class RecordSource
|
||||
{
|
||||
public:
|
||||
virtual void open(thread_db* tdbb) const = 0;
|
||||
virtual void close(thread_db* tdbb) const = 0;
|
||||
|
||||
virtual bool getRecord(thread_db* tdbb) const = 0;
|
||||
virtual bool refetchRecord(thread_db* tdbb) const = 0;
|
||||
virtual bool lockRecord(thread_db* tdbb) const = 0;
|
||||
|
||||
virtual void getChildren(Firebird::Array<const RecordSource*>& children) const = 0;
|
||||
|
||||
virtual void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const = 0;
|
||||
bool detailed, unsigned level, bool recurse) const = 0;
|
||||
|
||||
virtual void markRecursive() = 0;
|
||||
virtual void invalidateRecords(Request* request) const = 0;
|
||||
@ -90,6 +90,20 @@ namespace Jrd
|
||||
return m_cardinality;
|
||||
}
|
||||
|
||||
ULONG getCursorProfileId() const
|
||||
{
|
||||
return m_cursorProfileId;
|
||||
}
|
||||
|
||||
ULONG getRecSourceProfileId() const
|
||||
{
|
||||
return m_recSourceProfileId;
|
||||
}
|
||||
|
||||
void open(thread_db* tdbb) const;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const;
|
||||
|
||||
protected:
|
||||
// Generic impure block
|
||||
struct Impure
|
||||
@ -103,9 +117,7 @@ namespace Jrd
|
||||
static const ULONG irsb_mustread = 8;
|
||||
static const ULONG irsb_singular_processed = 16;
|
||||
|
||||
RecordSource()
|
||||
: m_impure(0), m_recursive(false), m_cardinality(0.0)
|
||||
{}
|
||||
RecordSource(CompilerScratch* csb);
|
||||
|
||||
static Firebird::string printName(thread_db* tdbb, const Firebird::string& name, bool quote = true);
|
||||
static Firebird::string printName(thread_db* tdbb, const Firebird::string& name,
|
||||
@ -120,9 +132,14 @@ namespace Jrd
|
||||
static void saveRecord(thread_db* tdbb, record_param* rpb);
|
||||
static void restoreRecord(thread_db* tdbb, record_param* rpb);
|
||||
|
||||
ULONG m_impure;
|
||||
bool m_recursive;
|
||||
double m_cardinality;
|
||||
virtual void internalOpen(thread_db* tdbb) const = 0;
|
||||
virtual bool internalGetRecord(thread_db* tdbb) const = 0;
|
||||
|
||||
double m_cardinality = 0.0;
|
||||
ULONG m_impure = 0;
|
||||
bool m_recursive = false;
|
||||
ULONG m_cursorProfileId;
|
||||
ULONG m_recSourceProfileId;
|
||||
};
|
||||
|
||||
|
||||
@ -163,13 +180,16 @@ namespace Jrd
|
||||
StreamType stream, jrd_rel* relation,
|
||||
const Firebird::Array<DbKeyRangeNode*>& dbkeyRanges);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
const Firebird::string m_alias;
|
||||
@ -189,13 +209,16 @@ namespace Jrd
|
||||
StreamType stream, jrd_rel* relation,
|
||||
InversionNode* inversion, double selectivity);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
const Firebird::string m_alias;
|
||||
@ -229,13 +252,12 @@ namespace Jrd
|
||||
InversionNode* index, USHORT keyLength,
|
||||
double selectivity);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void setInversion(InversionNode* inversion, BoolExprNode* condition)
|
||||
{
|
||||
@ -244,6 +266,10 @@ namespace Jrd
|
||||
m_condition = condition;
|
||||
}
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
int compareKeys(const index_desc*, const UCHAR*, USHORT, const temporary_key*, USHORT) const;
|
||||
bool findSavedNode(thread_db* tdbb, Impure* impure, win* window, UCHAR**) const;
|
||||
@ -276,15 +302,19 @@ namespace Jrd
|
||||
ExternalTableScan(CompilerScratch* csb, const Firebird::string& alias,
|
||||
StreamType stream, jrd_rel* relation);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
jrd_rel* const m_relation;
|
||||
@ -297,17 +327,20 @@ namespace Jrd
|
||||
VirtualTableScan(CompilerScratch* csb, const Firebird::string& alias,
|
||||
StreamType stream, jrd_rel* relation);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
virtual const Format* getFormat(thread_db* tdbb, jrd_rel* relation) const = 0;
|
||||
virtual bool retrieveRecord(thread_db* tdbb, jrd_rel* relation,
|
||||
FB_UINT64 position, Record* record) const = 0;
|
||||
@ -330,15 +363,19 @@ namespace Jrd
|
||||
const jrd_prc* procedure, const ValueListNode* sourceList,
|
||||
const ValueListNode* targetList, MessageNode* message);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
void assignParams(thread_db* tdbb, const dsc* from_desc, const dsc* flag_desc,
|
||||
@ -359,15 +396,15 @@ namespace Jrd
|
||||
public:
|
||||
SingularStream(CompilerScratch* csb, RecordSource* next);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -375,9 +412,11 @@ namespace Jrd
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
void doGetRecord(thread_db* tdbb) const;
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
NestConst<RecordSource> m_next;
|
||||
StreamList m_streams;
|
||||
};
|
||||
@ -387,15 +426,15 @@ namespace Jrd
|
||||
public:
|
||||
LockedStream(CompilerScratch* csb, RecordSource* next);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -403,6 +442,10 @@ namespace Jrd
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
NestConst<RecordSource> m_next;
|
||||
};
|
||||
@ -417,15 +460,15 @@ namespace Jrd
|
||||
public:
|
||||
FirstRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -438,6 +481,10 @@ namespace Jrd
|
||||
m_next->setAnyBoolean(anyBoolean, ansiAny, ansiNot);
|
||||
}
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
NestConst<RecordSource> m_next;
|
||||
NestConst<ValueExprNode> const m_value;
|
||||
@ -453,15 +500,15 @@ namespace Jrd
|
||||
public:
|
||||
SkipRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -474,6 +521,10 @@ namespace Jrd
|
||||
m_next->setAnyBoolean(anyBoolean, ansiAny, ansiNot);
|
||||
}
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
NestConst<RecordSource> m_next;
|
||||
NestConst<ValueExprNode> const m_value;
|
||||
@ -485,15 +536,15 @@ namespace Jrd
|
||||
FilteredStream(CompilerScratch* csb, RecordSource* next,
|
||||
BoolExprNode* boolean, double selectivity);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -511,6 +562,10 @@ namespace Jrd
|
||||
m_ansiNot = ansiNot;
|
||||
}
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
bool evaluateBoolean(thread_db* tdbb) const;
|
||||
|
||||
@ -589,15 +644,15 @@ namespace Jrd
|
||||
|
||||
SortedStream(CompilerScratch* csb, RecordSource* next, SortMap* map);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -638,6 +693,10 @@ namespace Jrd
|
||||
return (IS_INTL_DATA(desc) || desc->isDecFloat() || desc->isDateTimeTz());
|
||||
}
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
Sort* init(thread_db* tdbb) const;
|
||||
|
||||
@ -732,7 +791,6 @@ namespace Jrd
|
||||
const NestValueArray* group, MapNode* groupMap, bool oneRowWhenEmpty, NextType* next);
|
||||
|
||||
public:
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
@ -744,6 +802,8 @@ namespace Jrd
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
|
||||
Impure* getImpure(Request* request) const
|
||||
{
|
||||
return request->getImpure<typename ThisType::Impure>(m_impure);
|
||||
@ -806,8 +866,12 @@ namespace Jrd
|
||||
const NestValueArray* group, MapNode* map, RecordSource* next);
|
||||
|
||||
public:
|
||||
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const;
|
||||
bool getRecord(thread_db* tdbb) const;
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
protected:
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
};
|
||||
|
||||
class WindowedStream : public RecordSource
|
||||
@ -870,16 +934,18 @@ namespace Jrd
|
||||
Exclusion exclusion);
|
||||
|
||||
public:
|
||||
void open(thread_db* tdbb) const;
|
||||
void close(thread_db* tdbb) const;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const;
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const;
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
||||
void nullRecords(thread_db* tdbb) const;
|
||||
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level, bool recurse) const override;
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
Impure* getImpure(Request* request) const
|
||||
{
|
||||
return request->getImpure<Impure>(m_impure);
|
||||
@ -907,15 +973,15 @@ namespace Jrd
|
||||
WindowedStream(thread_db* tdbb, Optimizer* opt,
|
||||
Firebird::ObjectsArray<WindowSourceNode::Window>& windows, RecordSource* next);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -923,6 +989,10 @@ namespace Jrd
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
NestConst<BufferedStream> m_next;
|
||||
NestConst<RecordSource> m_joinedStream;
|
||||
@ -932,6 +1002,10 @@ namespace Jrd
|
||||
class BaseBufferedStream : public RecordSource
|
||||
{
|
||||
public:
|
||||
BaseBufferedStream(CompilerScratch* csb)
|
||||
: RecordSource(csb)
|
||||
{}
|
||||
|
||||
virtual void locate(thread_db* tdbb, FB_UINT64 position) const = 0;
|
||||
virtual FB_UINT64 getCount(thread_db* tdbb) const = 0;
|
||||
virtual FB_UINT64 getPosition(Request* request) const = 0;
|
||||
@ -967,15 +1041,15 @@ namespace Jrd
|
||||
public:
|
||||
BufferedStream(CompilerScratch* csb, RecordSource* next);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -992,6 +1066,10 @@ namespace Jrd
|
||||
return impure->irsb_position;
|
||||
}
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
NestConst<RecordSource> m_next;
|
||||
Firebird::HalfStaticArray<FieldMap, OPT_STATIC_ITEMS> m_map;
|
||||
@ -1007,15 +1085,15 @@ namespace Jrd
|
||||
NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
|
||||
BoolExprNode* boolean, JoinType joinType);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -1023,6 +1101,10 @@ namespace Jrd
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
bool fetchRecord(thread_db*, FB_SIZE_T) const;
|
||||
|
||||
@ -1036,15 +1118,15 @@ namespace Jrd
|
||||
public:
|
||||
FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSource* arg2);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -1052,6 +1134,10 @@ namespace Jrd
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
NestConst<RecordSource> m_arg1;
|
||||
NestConst<RecordSource> m_arg2;
|
||||
@ -1085,15 +1171,15 @@ namespace Jrd
|
||||
HashJoin(thread_db* tdbb, CompilerScratch* csb, FB_SIZE_T count,
|
||||
RecordSource* const* args, NestValueArray* const* keys);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -1103,6 +1189,10 @@ namespace Jrd
|
||||
|
||||
static unsigned maxCapacity();
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
ULONG computeHash(thread_db* tdbb, Request* request,
|
||||
const SubStream& sub, UCHAR* buffer) const;
|
||||
@ -1147,15 +1237,15 @@ namespace Jrd
|
||||
SortedStream* const* args,
|
||||
const NestValueArray* const* keys);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -1163,11 +1253,15 @@ namespace Jrd
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
int compare(thread_db* tdbb, const NestValueArray* node1,
|
||||
const NestValueArray* node2) const;
|
||||
UCHAR* getData(thread_db* tdbb, MergeFile* mfb, SLONG record) const;
|
||||
SLONG getRecord(thread_db* tdbb, FB_SIZE_T index) const;
|
||||
SLONG getRecordByIndex(thread_db* tdbb, FB_SIZE_T index) const;
|
||||
bool fetchRecord(thread_db* tdbb, FB_SIZE_T index) const;
|
||||
|
||||
Firebird::Array<NestConst<SortedStream> > m_args;
|
||||
@ -1179,14 +1273,19 @@ namespace Jrd
|
||||
public:
|
||||
LocalTableStream(CompilerScratch* csb, StreamType stream, const DeclareLocalTableNode* table);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const override;
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
const DeclareLocalTableNode* m_table;
|
||||
@ -1204,20 +1303,24 @@ namespace Jrd
|
||||
FB_SIZE_T argCount, RecordSource* const* args, NestConst<MapNode>* maps,
|
||||
const StreamList& streams);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
Firebird::Array<NestConst<RecordSource> > m_args;
|
||||
Firebird::Array<NestConst<MapNode> > m_maps;
|
||||
@ -1245,20 +1348,24 @@ namespace Jrd
|
||||
const StreamList& innerStreams,
|
||||
ULONG saveOffset);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
void cleanupLevel(Request* request, Impure* impure) const;
|
||||
|
||||
@ -1283,15 +1390,15 @@ namespace Jrd
|
||||
ConditionalStream(CompilerScratch* csb, RecordSource* first, RecordSource* second,
|
||||
BoolExprNode* boolean);
|
||||
|
||||
void open(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan,
|
||||
bool detailed, unsigned level) const override;
|
||||
bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
@ -1299,6 +1406,10 @@ namespace Jrd
|
||||
void findUsedStreams(StreamList& streams, bool expandAll = false) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
protected:
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
|
||||
private:
|
||||
NestConst<RecordSource> m_first;
|
||||
NestConst<RecordSource> m_second;
|
||||
|
@ -62,7 +62,7 @@ RecursiveStream::RecursiveStream(CompilerScratch* csb, StreamType stream, Stream
|
||||
m_inner->markRecursive();
|
||||
}
|
||||
|
||||
void RecursiveStream::open(thread_db* tdbb) const
|
||||
void RecursiveStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -111,7 +111,7 @@ void RecursiveStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool RecursiveStream::getRecord(thread_db* tdbb) const
|
||||
bool RecursiveStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -239,26 +239,35 @@ bool RecursiveStream::lockRecord(thread_db* /*tdbb*/) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void RecursiveStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void RecursiveStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_root);
|
||||
children.add(m_inner);
|
||||
}
|
||||
|
||||
void RecursiveStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
plan += printIndent(++level) + "Recursion";
|
||||
printOptInfo(plan);
|
||||
|
||||
m_root->print(tdbb, plan, true, level);
|
||||
m_inner->print(tdbb, plan, true, level);
|
||||
if (recurse)
|
||||
{
|
||||
m_root->print(tdbb, plan, true, level, recurse);
|
||||
m_inner->print(tdbb, plan, true, level, recurse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!level)
|
||||
plan += "(";
|
||||
|
||||
m_root->print(tdbb, plan, false, level + 1);
|
||||
m_root->print(tdbb, plan, false, level + 1, recurse);
|
||||
|
||||
plan += ", ";
|
||||
|
||||
m_inner->print(tdbb, plan, false, level + 1);
|
||||
m_inner->print(tdbb, plan, false, level + 1, recurse);
|
||||
|
||||
if (!level)
|
||||
plan += ")";
|
||||
|
@ -34,7 +34,9 @@ using namespace Jrd;
|
||||
// ------------------------------
|
||||
|
||||
SingularStream::SingularStream(CompilerScratch* csb, RecordSource* next)
|
||||
: m_next(next), m_streams(csb->csb_pool)
|
||||
: RecordSource(csb),
|
||||
m_next(next),
|
||||
m_streams(csb->csb_pool)
|
||||
{
|
||||
fb_assert(m_next);
|
||||
|
||||
@ -44,7 +46,7 @@ SingularStream::SingularStream(CompilerScratch* csb, RecordSource* next)
|
||||
m_cardinality = MINIMUM_CARDINALITY;
|
||||
}
|
||||
|
||||
void SingularStream::open(thread_db* tdbb) const
|
||||
void SingularStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -70,7 +72,7 @@ void SingularStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool SingularStream::getRecord(thread_db* tdbb) const
|
||||
bool SingularStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -85,55 +87,48 @@ bool SingularStream::getRecord(thread_db* tdbb) const
|
||||
|
||||
if (m_next->getRecord(tdbb))
|
||||
{
|
||||
doGetRecord(tdbb);
|
||||
const FB_SIZE_T streamCount = m_streams.getCount();
|
||||
MemoryPool& pool = *tdbb->getDefaultPool();
|
||||
HalfStaticArray<record_param, 16> rpbs(pool, streamCount);
|
||||
|
||||
for (FB_SIZE_T i = 0; i < streamCount; i++)
|
||||
{
|
||||
rpbs.add(request->req_rpb[m_streams[i]]);
|
||||
record_param& rpb = rpbs.back();
|
||||
Record* const orgRecord = rpb.rpb_record;
|
||||
|
||||
if (orgRecord)
|
||||
rpb.rpb_record = FB_NEW_POOL(pool) Record(pool, orgRecord);
|
||||
}
|
||||
|
||||
if (m_next->getRecord(tdbb))
|
||||
status_exception::raise(Arg::Gds(isc_sing_select_err));
|
||||
|
||||
for (FB_SIZE_T i = 0; i < streamCount; i++)
|
||||
{
|
||||
record_param& rpb = request->req_rpb[m_streams[i]];
|
||||
Record* orgRecord = rpb.rpb_record;
|
||||
rpb = rpbs[i];
|
||||
const AutoPtr<Record> newRecord(rpb.rpb_record);
|
||||
|
||||
if (newRecord)
|
||||
{
|
||||
if (!orgRecord)
|
||||
BUGCHECK(284); // msg 284 cannot restore singleton select data
|
||||
|
||||
rpb.rpb_record = orgRecord;
|
||||
orgRecord->copyFrom(newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
impure->irsb_flags |= irsb_singular_processed;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SingularStream::doGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
|
||||
const FB_SIZE_T streamCount = m_streams.getCount();
|
||||
MemoryPool& pool = *tdbb->getDefaultPool();
|
||||
HalfStaticArray<record_param, 16> rpbs(pool, streamCount);
|
||||
|
||||
for (FB_SIZE_T i = 0; i < streamCount; i++)
|
||||
{
|
||||
rpbs.add(request->req_rpb[m_streams[i]]);
|
||||
record_param& rpb = rpbs.back();
|
||||
Record* const orgRecord = rpb.rpb_record;
|
||||
|
||||
if (orgRecord)
|
||||
rpb.rpb_record = FB_NEW_POOL(pool) Record(pool, orgRecord);
|
||||
}
|
||||
|
||||
if (m_next->getRecord(tdbb))
|
||||
status_exception::raise(Arg::Gds(isc_sing_select_err));
|
||||
|
||||
for (FB_SIZE_T i = 0; i < streamCount; i++)
|
||||
{
|
||||
record_param& rpb = request->req_rpb[m_streams[i]];
|
||||
Record* orgRecord = rpb.rpb_record;
|
||||
rpb = rpbs[i];
|
||||
const AutoPtr<Record> newRecord(rpb.rpb_record);
|
||||
|
||||
if (newRecord)
|
||||
{
|
||||
if (!orgRecord)
|
||||
BUGCHECK(284); // msg 284 cannot restore singleton select data
|
||||
|
||||
rpb.rpb_record = orgRecord;
|
||||
orgRecord->copyFrom(newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
impure->irsb_flags |= irsb_singular_processed;
|
||||
}
|
||||
|
||||
bool SingularStream::refetchRecord(thread_db* tdbb) const
|
||||
{
|
||||
return m_next->refetchRecord(tdbb);
|
||||
@ -144,7 +139,12 @@ bool SingularStream::lockRecord(thread_db* tdbb) const
|
||||
return m_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void SingularStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void SingularStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void SingularStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -152,7 +152,8 @@ void SingularStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
|
||||
printOptInfo(plan);
|
||||
}
|
||||
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void SingularStream::markRecursive()
|
||||
|
@ -37,7 +37,9 @@ using namespace Jrd;
|
||||
// -------------------------------
|
||||
|
||||
SkipRowsStream::SkipRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value)
|
||||
: m_next(next), m_value(value)
|
||||
: RecordSource(csb),
|
||||
m_next(next),
|
||||
m_value(value)
|
||||
{
|
||||
fb_assert(m_next && m_value);
|
||||
|
||||
@ -45,7 +47,7 @@ SkipRowsStream::SkipRowsStream(CompilerScratch* csb, RecordSource* next, ValueEx
|
||||
m_cardinality = next->getCardinality();
|
||||
}
|
||||
|
||||
void SkipRowsStream::open(thread_db* tdbb) const
|
||||
void SkipRowsStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -81,7 +83,7 @@ void SkipRowsStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool SkipRowsStream::getRecord(thread_db* tdbb) const
|
||||
bool SkipRowsStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -114,7 +116,12 @@ bool SkipRowsStream::lockRecord(thread_db* tdbb) const
|
||||
return m_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void SkipRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void SkipRowsStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void SkipRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -122,7 +129,8 @@ void SkipRowsStream::print(thread_db* tdbb, string& plan, bool detailed, unsigne
|
||||
printOptInfo(plan);
|
||||
}
|
||||
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void SkipRowsStream::markRecursive()
|
||||
|
@ -44,7 +44,9 @@ using namespace Jrd;
|
||||
// -----------------------------
|
||||
|
||||
SortedStream::SortedStream(CompilerScratch* csb, RecordSource* next, SortMap* map)
|
||||
: m_next(next), m_map(map)
|
||||
: RecordSource(csb),
|
||||
m_next(next),
|
||||
m_map(map)
|
||||
{
|
||||
fb_assert(m_next && m_map);
|
||||
|
||||
@ -55,7 +57,7 @@ SortedStream::SortedStream(CompilerScratch* csb, RecordSource* next, SortMap* ma
|
||||
m_cardinality *= DEFAULT_SELECTIVITY;
|
||||
}
|
||||
|
||||
void SortedStream::open(thread_db* tdbb) const
|
||||
void SortedStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -89,7 +91,7 @@ void SortedStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool SortedStream::getRecord(thread_db* tdbb) const
|
||||
bool SortedStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -119,8 +121,13 @@ bool SortedStream::lockRecord(thread_db* tdbb) const
|
||||
return m_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void SortedStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void SortedStream::print(thread_db* tdbb, string& plan,
|
||||
bool detailed, unsigned level) const
|
||||
bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -135,13 +142,14 @@ void SortedStream::print(thread_db* tdbb, string& plan,
|
||||
((m_map->flags & FLAG_PROJECT) ? "Unique Sort" : "Sort") + extras;
|
||||
printOptInfo(plan);
|
||||
|
||||
m_next->print(tdbb, plan, true, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, true, level, recurse);
|
||||
}
|
||||
else
|
||||
{
|
||||
level++;
|
||||
plan += "SORT (";
|
||||
m_next->print(tdbb, plan, false, level);
|
||||
m_next->print(tdbb, plan, false, level, recurse);
|
||||
plan += ")";
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ Union::Union(CompilerScratch* csb, StreamType stream,
|
||||
m_maps[i] = maps[i];
|
||||
}
|
||||
|
||||
void Union::open(thread_db* tdbb) const
|
||||
void Union::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -95,7 +95,7 @@ void Union::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool Union::getRecord(thread_db* tdbb) const
|
||||
bool Union::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -162,15 +162,24 @@ bool Union::lockRecord(thread_db* tdbb) const
|
||||
return m_args[impure->irsb_count]->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void Union::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void Union::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
children.add(m_args[i]);
|
||||
}
|
||||
|
||||
void Union::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
plan += printIndent(++level) + (m_args.getCount() == 1 ? "Materialize" : "Union");
|
||||
printOptInfo(plan);
|
||||
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
m_args[i]->print(tdbb, plan, true, level);
|
||||
if (recurse)
|
||||
{
|
||||
for (FB_SIZE_T i = 0; i < m_args.getCount(); i++)
|
||||
m_args[i]->print(tdbb, plan, true, level, recurse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -182,7 +191,7 @@ void Union::print(thread_db* tdbb, string& plan, bool detailed, unsigned level)
|
||||
if (i)
|
||||
plan += ", ";
|
||||
|
||||
m_args[i]->print(tdbb, plan, false, level + 1);
|
||||
m_args[i]->print(tdbb, plan, false, level + 1, recurse);
|
||||
}
|
||||
|
||||
if (!level)
|
||||
|
@ -44,7 +44,7 @@ VirtualTableScan::VirtualTableScan(CompilerScratch* csb, const string& alias,
|
||||
m_cardinality = csb->csb_rpt[stream].csb_cardinality;
|
||||
}
|
||||
|
||||
void VirtualTableScan::open(thread_db* tdbb) const
|
||||
void VirtualTableScan::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -71,7 +71,7 @@ void VirtualTableScan::close(thread_db* tdbb) const
|
||||
impure->irsb_flags &= ~irsb_open;
|
||||
}
|
||||
|
||||
bool VirtualTableScan::getRecord(thread_db* tdbb) const
|
||||
bool VirtualTableScan::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -110,7 +110,11 @@ bool VirtualTableScan::lockRecord(thread_db* /*tdbb*/) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void VirtualTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void VirtualTableScan::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
}
|
||||
|
||||
void VirtualTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
|
@ -51,34 +51,36 @@ namespace
|
||||
public:
|
||||
BufferedStreamWindow(CompilerScratch* csb, BufferedStream* next);
|
||||
|
||||
void open(thread_db* tdbb) const;
|
||||
void close(thread_db* tdbb) const;
|
||||
void internalOpen(thread_db* tdbb) const override;
|
||||
void close(thread_db* tdbb) const override;
|
||||
|
||||
bool getRecord(thread_db* tdbb) const;
|
||||
bool refetchRecord(thread_db* tdbb) const;
|
||||
bool lockRecord(thread_db* tdbb) const;
|
||||
bool internalGetRecord(thread_db* tdbb) const override;
|
||||
bool refetchRecord(thread_db* tdbb) const override;
|
||||
bool lockRecord(thread_db* tdbb) const override;
|
||||
|
||||
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const;
|
||||
void getChildren(Firebird::Array<const RecordSource*>& children) const override;
|
||||
|
||||
void markRecursive();
|
||||
void invalidateRecords(Request* request) const;
|
||||
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level, bool recurse) const override;
|
||||
|
||||
void findUsedStreams(StreamList& streams, bool expandAll) const;
|
||||
void nullRecords(thread_db* tdbb) const;
|
||||
void markRecursive() override;
|
||||
void invalidateRecords(Request* request) const override;
|
||||
|
||||
void locate(thread_db* tdbb, FB_UINT64 position) const
|
||||
void findUsedStreams(StreamList& streams, bool expandAll) const override;
|
||||
void nullRecords(thread_db* tdbb) const override;
|
||||
|
||||
void locate(thread_db* tdbb, FB_UINT64 position) const override
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
impure->irsb_position = position;
|
||||
}
|
||||
|
||||
FB_UINT64 getCount(thread_db* tdbb) const
|
||||
FB_UINT64 getCount(thread_db* tdbb) const override
|
||||
{
|
||||
return m_next->getCount(tdbb);
|
||||
}
|
||||
|
||||
FB_UINT64 getPosition(Request* request) const
|
||||
FB_UINT64 getPosition(Request* request) const override
|
||||
{
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
return impure->irsb_position;
|
||||
@ -91,12 +93,13 @@ namespace
|
||||
// BufferedStreamWindow implementation
|
||||
|
||||
BufferedStreamWindow::BufferedStreamWindow(CompilerScratch* csb, BufferedStream* next)
|
||||
: m_next(next)
|
||||
: BaseBufferedStream(csb),
|
||||
m_next(next)
|
||||
{
|
||||
m_impure = csb->allocImpure<Impure>();
|
||||
}
|
||||
|
||||
void BufferedStreamWindow::open(thread_db* tdbb) const
|
||||
void BufferedStreamWindow::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -117,7 +120,7 @@ namespace
|
||||
impure->irsb_flags &= ~irsb_open;
|
||||
}
|
||||
|
||||
bool BufferedStreamWindow::getRecord(thread_db* tdbb) const
|
||||
bool BufferedStreamWindow::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -143,9 +146,15 @@ namespace
|
||||
return m_next->lockRecord(tdbb);
|
||||
}
|
||||
|
||||
void BufferedStreamWindow::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void BufferedStreamWindow::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void BufferedStreamWindow::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void BufferedStreamWindow::markRecursive()
|
||||
@ -185,7 +194,8 @@ namespace
|
||||
|
||||
WindowedStream::WindowedStream(thread_db* tdbb, Optimizer* opt,
|
||||
ObjectsArray<WindowSourceNode::Window>& windows, RecordSource* next)
|
||||
: m_joinedStream(nullptr)
|
||||
: RecordSource(opt->getCompilerScratch()),
|
||||
m_joinedStream(nullptr)
|
||||
{
|
||||
const auto csb = opt->getCompilerScratch();
|
||||
|
||||
@ -334,7 +344,7 @@ WindowedStream::WindowedStream(thread_db* tdbb, Optimizer* opt,
|
||||
}
|
||||
}
|
||||
|
||||
void WindowedStream::open(thread_db* tdbb) const
|
||||
void WindowedStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||
@ -361,7 +371,7 @@ void WindowedStream::close(thread_db* tdbb) const
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowedStream::getRecord(thread_db* tdbb) const
|
||||
bool WindowedStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -388,9 +398,15 @@ bool WindowedStream::lockRecord(thread_db* /*tdbb*/) const
|
||||
return false; // compiler silencer
|
||||
}
|
||||
|
||||
void WindowedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||
void WindowedStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
m_joinedStream->print(tdbb, plan, detailed, level);
|
||||
children.add(m_joinedStream);
|
||||
}
|
||||
|
||||
void WindowedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level, bool recurse) const
|
||||
{
|
||||
if (recurse)
|
||||
m_joinedStream->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void WindowedStream::markRecursive()
|
||||
@ -506,9 +522,9 @@ WindowedStream::WindowStream::WindowStream(thread_db* tdbb, CompilerScratch* csb
|
||||
(void) m_exclusion; // avoid warning
|
||||
}
|
||||
|
||||
void WindowedStream::WindowStream::open(thread_db* tdbb) const
|
||||
void WindowedStream::WindowStream::internalOpen(thread_db* tdbb) const
|
||||
{
|
||||
BaseAggWinStream::open(tdbb);
|
||||
BaseAggWinStream::internalOpen(tdbb);
|
||||
|
||||
Request* const request = tdbb->getRequest();
|
||||
Impure* const impure = getImpure(request);
|
||||
@ -543,7 +559,7 @@ void WindowedStream::WindowStream::close(thread_db* tdbb) const
|
||||
BaseAggWinStream::close(tdbb);
|
||||
}
|
||||
|
||||
bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const
|
||||
bool WindowedStream::WindowStream::internalGetRecord(thread_db* tdbb) const
|
||||
{
|
||||
JRD_reschedule(tdbb);
|
||||
|
||||
@ -871,8 +887,13 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowedStream::WindowStream::getChildren(Array<const RecordSource*>& children) const
|
||||
{
|
||||
children.add(m_next);
|
||||
}
|
||||
|
||||
void WindowedStream::WindowStream::print(thread_db* tdbb, string& plan, bool detailed,
|
||||
unsigned level) const
|
||||
unsigned level, bool recurse) const
|
||||
{
|
||||
if (detailed)
|
||||
{
|
||||
@ -880,7 +901,8 @@ void WindowedStream::WindowStream::print(thread_db* tdbb, string& plan, bool det
|
||||
printOptInfo(plan);
|
||||
}
|
||||
|
||||
m_next->print(tdbb, plan, detailed, level);
|
||||
if (recurse)
|
||||
m_next->print(tdbb, plan, detailed, level, recurse);
|
||||
}
|
||||
|
||||
void WindowedStream::WindowStream::findUsedStreams(StreamList& streams, bool expandAll) const
|
||||
|
@ -374,6 +374,7 @@ public:
|
||||
RuntimeStatistics req_stats;
|
||||
RuntimeStatistics req_base_stats;
|
||||
AffectedRows req_records_affected; // records affected by the last statement
|
||||
FB_UINT64 req_profiler_time; // profiler time
|
||||
|
||||
const StmtNode* req_next; // next node for execution
|
||||
EDS::Statement* req_ext_stmt; // head of list of active dynamic statements
|
||||
|
@ -827,7 +827,7 @@ void TRA_invalidate(thread_db* tdbb, ULONG mask)
|
||||
|
||||
Database* const database = tdbb->getDatabase();
|
||||
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
|
||||
SyncLockGuard dbbSync(&database->dbb_sync, SYNC_SHARED, "TRA_invalidate");
|
||||
|
||||
|
@ -87,6 +87,7 @@
|
||||
#include "../jrd/Function.h"
|
||||
#include "../common/StatusArg.h"
|
||||
#include "../jrd/GarbageCollector.h"
|
||||
#include "../jrd/ProfilerManager.h"
|
||||
#include "../jrd/trace/TraceManager.h"
|
||||
#include "../jrd/trace/TraceJrdHelpers.h"
|
||||
#include "../common/Task.h"
|
||||
|
@ -413,7 +413,7 @@ void LockManager::shutdownOwner(thread_db* tdbb, SRQ_PTR* owner_handle)
|
||||
{
|
||||
{ // checkout scope
|
||||
LockTableCheckout checkout(this, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
Thread::sleep(10);
|
||||
}
|
||||
|
||||
@ -1397,7 +1397,7 @@ void LockManager::blocking_action(thread_db* tdbb, SRQ_PTR blocking_owner_offset
|
||||
|
||||
{ // checkout scope
|
||||
LockTableCheckout checkout(this, FB_FUNCTION);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
(*routine)(arg);
|
||||
}
|
||||
|
||||
@ -3810,7 +3810,7 @@ void LockManager::wait_for_request(thread_db* tdbb, lrq* request, SSHORT lck_wai
|
||||
}
|
||||
|
||||
{ // scope
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
|
||||
ret = m_sharedMemory->eventWait(&owner->own_wakeup, value, (timeout - current_time) * 1000000);
|
||||
--m_waitingOwners;
|
||||
}
|
||||
|
1384
src/plugins/profiler/Profiler.cpp
Normal file
1384
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