diff --git a/Data/Data_vs120.vcxproj b/Data/Data_vs120.vcxproj index c79317c55..621e408a1 100644 --- a/Data/Data_vs120.vcxproj +++ b/Data/Data_vs120.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="debug_shared|Win32"> @@ -32,7 +32,7 @@ <RootNamespace>Data</RootNamespace> <Keyword>Win32Proj</Keyword> </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> @@ -63,27 +63,27 @@ <CharacterSet>MultiByte</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/> - <ImportGroup Label="ExtensionSettings"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings" /> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|Win32'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|Win32'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|Win32'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|Win32'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> - <PropertyGroup Label="UserMacros"/> + <PropertyGroup Label="UserMacros" /> <PropertyGroup> <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion> <TargetName Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'">PocoDatad</TargetName> @@ -125,17 +125,18 @@ <AdditionalIncludeDirectories>.\include;..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;Data_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <OutputFile>..\bin\PocoDatad.dll</OutputFile> @@ -163,9 +164,9 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> </ClCompile> <Link> @@ -186,18 +187,19 @@ <AdditionalIncludeDirectories>.\include;..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <ProgramDataBaseFileName>..\lib\PocoDatamtd.pdb</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib\PocoDatamtd.lib</OutputFile> @@ -218,9 +220,9 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> </ClCompile> <Lib> @@ -233,18 +235,19 @@ <AdditionalIncludeDirectories>.\include;..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <ProgramDataBaseFileName>..\lib\PocoDatamdd.pdb</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib\PocoDatamdd.lib</OutputFile> @@ -265,10 +268,10 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <ProgramDataBaseFileName>..\lib\PocoDatamd.pdb</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> </ClCompile> <Lib> @@ -365,6 +368,6 @@ <ClCompile Include="src\Time.cpp"/> <ClCompile Include="src\Transaction.cpp"/> </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> - <ImportGroup Label="ExtensionTargets"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets" /> </Project> diff --git a/Data/Data_x64_vs120.vcxproj b/Data/Data_x64_vs120.vcxproj index 75d41a25b..256bf3644 100644 --- a/Data/Data_x64_vs120.vcxproj +++ b/Data/Data_x64_vs120.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="debug_shared|x64"> @@ -32,7 +32,7 @@ <RootNamespace>Data</RootNamespace> <Keyword>Win32Proj</Keyword> </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> @@ -63,27 +63,27 @@ <CharacterSet>MultiByte</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/> - <ImportGroup Label="ExtensionSettings"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings" /> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> - <PropertyGroup Label="UserMacros"/> + <PropertyGroup Label="UserMacros" /> <PropertyGroup> <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion> <TargetName Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'">PocoData64d</TargetName> @@ -125,18 +125,19 @@ <AdditionalIncludeDirectories>.\include;..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;Data_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <OutputFile>..\bin64\PocoData64d.dll</OutputFile> @@ -164,11 +165,12 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <OutputFile>..\bin64\PocoData64.dll</OutputFile> @@ -188,19 +190,20 @@ <AdditionalIncludeDirectories>.\include;..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <ProgramDataBaseFileName>..\lib64\PocoDatamtd.pdb</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib64\PocoDatamtd.lib</OutputFile> @@ -221,11 +224,12 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib64\PocoDatamt.lib</OutputFile> @@ -237,19 +241,20 @@ <AdditionalIncludeDirectories>.\include;..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <ProgramDataBaseFileName>..\lib64\PocoDatamdd.pdb</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib64\PocoDatamdd.lib</OutputFile> @@ -270,11 +275,12 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib64\PocoDatamd.lib</OutputFile> @@ -370,6 +376,6 @@ <ClCompile Include="src\Time.cpp"/> <ClCompile Include="src\Transaction.cpp"/> </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> - <ImportGroup Label="ExtensionTargets"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets" /> </Project> diff --git a/Data/MySQL/include/Poco/Data/MySQL/Binder.h b/Data/MySQL/include/Poco/Data/MySQL/Binder.h index 6f6374acd..5c1c15752 100644 --- a/Data/MySQL/include/Poco/Data/MySQL/Binder.h +++ b/Data/MySQL/include/Poco/Data/MySQL/Binder.h @@ -42,71 +42,71 @@ public: virtual ~Binder(); /// Destroys the Binder. - virtual void bind(std::size_t pos, const Poco::Int8& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::Int8& val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int8. - virtual void bind(std::size_t pos, const Poco::UInt8& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::UInt8& val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt8. - virtual void bind(std::size_t pos, const Poco::Int16& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::Int16& val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int16. - virtual void bind(std::size_t pos, const Poco::UInt16& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::UInt16& val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt16. - virtual void bind(std::size_t pos, const Poco::Int32& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::Int32& val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int32. - virtual void bind(std::size_t pos, const Poco::UInt32& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::UInt32& val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt32. - virtual void bind(std::size_t pos, const Poco::Int64& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::Int64& val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int64. - virtual void bind(std::size_t pos, const Poco::UInt64& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::UInt64& val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt64. #ifndef POCO_LONG_IS_64_BIT - virtual void bind(std::size_t pos, const long& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const long& val, Direction dir, const WhenNullCb& nullCb); /// Binds a long. - virtual void bind(std::size_t pos, const unsigned long& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const unsigned long& val, Direction dir, const WhenNullCb& nullCb); /// Binds an unsigned long. #endif // POCO_LONG_IS_64_BIT - virtual void bind(std::size_t pos, const bool& val, Direction dir); + virtual void bind(std::size_t pos, const bool& val, Direction dir, const WhenNullCb& nullCb); /// Binds a boolean. - virtual void bind(std::size_t pos, const float& val, Direction dir); + virtual void bind(std::size_t pos, const float& val, Direction dir, const WhenNullCb& nullCb); /// Binds a float. - virtual void bind(std::size_t pos, const double& val, Direction dir); + virtual void bind(std::size_t pos, const double& val, Direction dir, const WhenNullCb& nullCb); /// Binds a double. - virtual void bind(std::size_t pos, const char& val, Direction dir); + virtual void bind(std::size_t pos, const char& val, Direction dir, const WhenNullCb& nullCb); /// Binds a single character. - virtual void bind(std::size_t pos, const std::string& val, Direction dir); + virtual void bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& nullCb); /// Binds a string. - virtual void bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir, const WhenNullCb& nullCb); /// Binds a BLOB. - virtual void bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir); + virtual void bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir, const WhenNullCb& nullCb); /// Binds a CLOB. - virtual void bind(std::size_t pos, const DateTime& val, Direction dir); + virtual void bind(std::size_t pos, const DateTime& val, Direction dir, const WhenNullCb& nullCb); /// Binds a DateTime. - virtual void bind(std::size_t pos, const Date& val, Direction dir); + virtual void bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& nullCb); /// Binds a Date. - virtual void bind(std::size_t pos, const Time& val, Direction dir); + virtual void bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& nullCb); /// Binds a Time. - virtual void bind(std::size_t pos, const NullData& val, Direction dir); + virtual void bind(std::size_t pos, const NullData& val, Direction dir, const std::type_info& bindType); /// Binds a null. @@ -212,11 +212,11 @@ public: virtual void bind(std::size_t pos, const std::list<Time>& val, Direction dir = PD_IN); - virtual void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir, const std::type_info& bindType); - virtual void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir, const std::type_info& bindType); - virtual void bind(std::size_t pos, const std::list<NullData>& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const std::list<NullData>& val, Direction dir, const std::type_info& bindType); virtual void bind(std::size_t pos, const std::vector<std::string>& val, Direction dir = PD_IN); @@ -237,7 +237,7 @@ private: Binder(const Binder&); /// Don't copy the binder - virtual void bind(std::size_t, const char* const&, Direction) + virtual void bind(std::size_t, const char* const&, Direction, const WhenNullCb& ) /// Binds a const char ptr. /// This is a private no-op in this implementation /// due to security risk. diff --git a/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h b/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h index 1aedb9bf6..520e2dc5e 100644 --- a/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h +++ b/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h @@ -54,7 +54,7 @@ protected: /// Returns the number of affected rows. /// Used to find out the number of rows affected by insert, delete or update. - virtual const MetaColumn& metaColumn(std::size_t pos) const; + virtual const MetaColumn& metaColumn(std::size_t pos, std::size_t dataSet) const; /// Returns column meta data. virtual bool hasNext(); diff --git a/Data/MySQL/src/Binder.cpp b/Data/MySQL/src/Binder.cpp index 6a97f0e1d..6ccc077bc 100644 --- a/Data/MySQL/src/Binder.cpp +++ b/Data/MySQL/src/Binder.cpp @@ -37,56 +37,56 @@ Binder::~Binder() } -void Binder::bind(std::size_t pos, const Poco::Int8& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int8& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_TINY, &val, 0); } -void Binder::bind(std::size_t pos, const Poco::UInt8& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UInt8& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_TINY, &val, 0, true); } -void Binder::bind(std::size_t pos, const Poco::Int16& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int16& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_SHORT, &val, 0); } -void Binder::bind(std::size_t pos, const Poco::UInt16& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UInt16& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_SHORT, &val, 0, true); } -void Binder::bind(std::size_t pos, const Poco::Int32& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int32& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_LONG, &val, 0); } -void Binder::bind(std::size_t pos, const Poco::UInt32& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UInt32& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_LONG, &val, 0, true); } -void Binder::bind(std::size_t pos, const Poco::Int64& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int64& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_LONGLONG, &val, 0); } -void Binder::bind(std::size_t pos, const Poco::UInt64& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UInt64& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_LONGLONG, &val, 0, true); @@ -95,14 +95,14 @@ void Binder::bind(std::size_t pos, const Poco::UInt64& val, Direction dir) #ifndef POCO_LONG_IS_64_BIT -void Binder::bind(std::size_t pos, const long& val, Direction dir) +void Binder::bind(std::size_t pos, const long& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_LONG, &val, 0); } -void Binder::bind(std::size_t pos, const unsigned long& val, Direction dir) +void Binder::bind(std::size_t pos, const unsigned long& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_LONG, &val, 0, true); @@ -111,56 +111,56 @@ void Binder::bind(std::size_t pos, const unsigned long& val, Direction dir) #endif // POCO_LONG_IS_64_BIT -void Binder::bind(std::size_t pos, const bool& val, Direction dir) +void Binder::bind(std::size_t pos, const bool& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_TINY, &val, 0); } -void Binder::bind(std::size_t pos, const float& val, Direction dir) +void Binder::bind(std::size_t pos, const float& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_FLOAT, &val, 0); } -void Binder::bind(std::size_t pos, const double& val, Direction dir) +void Binder::bind(std::size_t pos, const double& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_DOUBLE, &val, 0); } -void Binder::bind(std::size_t pos, const char& val, Direction dir) +void Binder::bind(std::size_t pos, const char& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_TINY, &val, 0); } -void Binder::bind(std::size_t pos, const std::string& val, Direction dir) +void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_STRING, val.c_str(), static_cast<int>(val.length())); } -void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_BLOB, val.rawContent(), static_cast<int>(val.size())); } -void Binder::bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_BLOB, val.rawContent(), static_cast<int>(val.size())); } -void Binder::bind(std::size_t pos, const DateTime& val, Direction dir) +void Binder::bind(std::size_t pos, const DateTime& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); MYSQL_TIME mt = {0}; @@ -181,7 +181,7 @@ void Binder::bind(std::size_t pos, const DateTime& val, Direction dir) } -void Binder::bind(std::size_t pos, const Date& val, Direction dir) +void Binder::bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); MYSQL_TIME mt = {0}; @@ -198,7 +198,7 @@ void Binder::bind(std::size_t pos, const Date& val, Direction dir) } -void Binder::bind(std::size_t pos, const Time& val, Direction dir) +void Binder::bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& nullCb) { poco_assert(dir == PD_IN); MYSQL_TIME mt = {0}; @@ -215,7 +215,7 @@ void Binder::bind(std::size_t pos, const Time& val, Direction dir) } -void Binder::bind(std::size_t pos, const NullData&, Direction dir) +void Binder::bind(std::size_t pos, const NullData&, Direction dir, const std::type_info& bindType) { poco_assert(dir == PD_IN); realBind(pos, MYSQL_TYPE_NULL, 0, 0); @@ -601,19 +601,19 @@ void Binder::bind(std::size_t pos, const std::list<Poco::Data::Time>& val, Direc } -void Binder::bind(std::size_t pos, const std::vector<Poco::Data::NullData>& val, Direction dir) +void Binder::bind(std::size_t pos, const std::vector<Poco::Data::NullData>& val, Direction dir, const std::type_info& bindType) { throw NotImplementedException(); } -void Binder::bind(std::size_t pos, const std::deque<Poco::Data::NullData>& val, Direction dir) +void Binder::bind(std::size_t pos, const std::deque<Poco::Data::NullData>& val, Direction dir, const std::type_info& bindType) { throw NotImplementedException(); } -void Binder::bind(std::size_t pos, const std::list<Poco::Data::NullData>& val, Direction dir) +void Binder::bind(std::size_t pos, const std::list<Poco::Data::NullData>& val, Direction dir, const std::type_info& bindType) { throw NotImplementedException(); } diff --git a/Data/MySQL/src/MySQLStatementImpl.cpp b/Data/MySQL/src/MySQLStatementImpl.cpp index c96896f4f..849d01d3c 100644 --- a/Data/MySQL/src/MySQLStatementImpl.cpp +++ b/Data/MySQL/src/MySQLStatementImpl.cpp @@ -48,8 +48,10 @@ int MySQLStatementImpl::affectedRowCount() const } -const MetaColumn& MySQLStatementImpl::metaColumn(std::size_t pos) const +const MetaColumn& MySQLStatementImpl::metaColumn(std::size_t pos, std::size_t dataSet) const { + // mysql doesn't support multiple result sets + poco_assert_dbg(dataSet == 0); return _metadata.metaColumn(pos); } diff --git a/Data/ODBC/ODBC_vs120.vcxproj b/Data/ODBC/ODBC_vs120.vcxproj index 78876ec8d..789b9a8af 100644 --- a/Data/ODBC/ODBC_vs120.vcxproj +++ b/Data/ODBC/ODBC_vs120.vcxproj @@ -125,7 +125,8 @@ <AdditionalIncludeDirectories>.\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;THREADSAFE;ODBC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -188,7 +189,8 @@ <AdditionalIncludeDirectories>.\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;THREADSAFE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -235,7 +237,8 @@ <AdditionalIncludeDirectories>.\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;THREADSAFE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> diff --git a/Data/ODBC/ODBC_x64_vs120.vcxproj b/Data/ODBC/ODBC_x64_vs120.vcxproj index 1ff80c2b7..b58dbdd27 100644 --- a/Data/ODBC/ODBC_x64_vs120.vcxproj +++ b/Data/ODBC/ODBC_x64_vs120.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="debug_shared|x64"> @@ -32,7 +32,7 @@ <RootNamespace>ODBC</RootNamespace> <Keyword>Win32Proj</Keyword> </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> @@ -63,27 +63,27 @@ <CharacterSet>MultiByte</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/> - <ImportGroup Label="ExtensionSettings"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings" /> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> - <PropertyGroup Label="UserMacros"/> + <PropertyGroup Label="UserMacros" /> <PropertyGroup> <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion> <TargetName Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'">PocoDataODBC64d</TargetName> @@ -125,17 +125,18 @@ <AdditionalIncludeDirectories>.\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;THREADSAFE;ODBC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -164,10 +165,11 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -188,18 +190,19 @@ <AdditionalIncludeDirectories>.\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;THREADSAFE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <ProgramDataBaseFileName>..\..\lib64\PocoDataODBCmtd.pdb</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\..\lib64\PocoDataODBCmtd.lib</OutputFile> @@ -220,10 +223,11 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\..\lib64\PocoDataODBCmt.lib</OutputFile> @@ -235,18 +239,19 @@ <AdditionalIncludeDirectories>.\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;THREADSAFE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <ProgramDataBaseFileName>..\..\lib64\PocoDataODBCmdd.pdb</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\..\lib64\PocoDataODBCmdd.lib</OutputFile> @@ -267,51 +272,52 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\..\lib64\PocoDataODBCmd.lib</OutputFile> </Lib> </ItemDefinitionGroup> <ItemGroup> - <ClInclude Include="include\Poco\Data\ODBC\Binder.h"/> - <ClInclude Include="include\Poco\Data\ODBC\ConnectionHandle.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Connector.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Diagnostics.h"/> - <ClInclude Include="include\Poco\Data\ODBC\EnvironmentHandle.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Error.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Extractor.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Handle.h"/> - <ClInclude Include="include\Poco\Data\ODBC\ODBC.h"/> - <ClInclude Include="include\Poco\Data\ODBC\ODBCException.h"/> - <ClInclude Include="include\Poco\Data\ODBC\ODBCMetaColumn.h"/> - <ClInclude Include="include\Poco\Data\ODBC\ODBCStatementImpl.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Parameter.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Preparator.h"/> - <ClInclude Include="include\Poco\Data\ODBC\SessionImpl.h"/> - <ClInclude Include="include\Poco\Data\ODBC\TypeInfo.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Unicode.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Unicode_UNIXODBC.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Unicode_WIN32.h"/> - <ClInclude Include="include\Poco\Data\ODBC\Utility.h"/> + <ClInclude Include="include\Poco\Data\ODBC\Binder.h" /> + <ClInclude Include="include\Poco\Data\ODBC\ConnectionHandle.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Connector.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Diagnostics.h" /> + <ClInclude Include="include\Poco\Data\ODBC\EnvironmentHandle.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Error.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Extractor.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Handle.h" /> + <ClInclude Include="include\Poco\Data\ODBC\ODBC.h" /> + <ClInclude Include="include\Poco\Data\ODBC\ODBCException.h" /> + <ClInclude Include="include\Poco\Data\ODBC\ODBCMetaColumn.h" /> + <ClInclude Include="include\Poco\Data\ODBC\ODBCStatementImpl.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Parameter.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Preparator.h" /> + <ClInclude Include="include\Poco\Data\ODBC\SessionImpl.h" /> + <ClInclude Include="include\Poco\Data\ODBC\TypeInfo.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Unicode.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Unicode_UNIXODBC.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Unicode_WIN32.h" /> + <ClInclude Include="include\Poco\Data\ODBC\Utility.h" /> </ItemGroup> <ItemGroup> - <ClCompile Include="src\Binder.cpp"/> - <ClCompile Include="src\ConnectionHandle.cpp"/> - <ClCompile Include="src\Connector.cpp"/> - <ClCompile Include="src\EnvironmentHandle.cpp"/> - <ClCompile Include="src\Extractor.cpp"/> - <ClCompile Include="src\ODBCException.cpp"/> - <ClCompile Include="src\ODBCMetaColumn.cpp"/> - <ClCompile Include="src\ODBCStatementImpl.cpp"/> - <ClCompile Include="src\Parameter.cpp"/> - <ClCompile Include="src\Preparator.cpp"/> - <ClCompile Include="src\SessionImpl.cpp"/> - <ClCompile Include="src\TypeInfo.cpp"/> - <ClCompile Include="src\Unicode.cpp"/> + <ClCompile Include="src\Binder.cpp" /> + <ClCompile Include="src\ConnectionHandle.cpp" /> + <ClCompile Include="src\Connector.cpp" /> + <ClCompile Include="src\EnvironmentHandle.cpp" /> + <ClCompile Include="src\Extractor.cpp" /> + <ClCompile Include="src\ODBCException.cpp" /> + <ClCompile Include="src\ODBCMetaColumn.cpp" /> + <ClCompile Include="src\ODBCStatementImpl.cpp" /> + <ClCompile Include="src\Parameter.cpp" /> + <ClCompile Include="src\Preparator.cpp" /> + <ClCompile Include="src\SessionImpl.cpp" /> + <ClCompile Include="src\TypeInfo.cpp" /> + <ClCompile Include="src\Unicode.cpp" /> <ClCompile Include="src\Unicode_UNIXODBC.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'">true</ExcludedFromBuild> @@ -328,8 +334,8 @@ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'">true</ExcludedFromBuild> </ClCompile> - <ClCompile Include="src\Utility.cpp"/> + <ClCompile Include="src\Utility.cpp" /> </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> - <ImportGroup Label="ExtensionTargets"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets" /> </Project> diff --git a/Data/ODBC/include/Poco/Data/ODBC/Binder.h b/Data/ODBC/include/Poco/Data/ODBC/Binder.h index 7e0e11e03..a968d9c29 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Binder.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Binder.h @@ -58,12 +58,28 @@ namespace ODBC { class ODBC_API Binder: public Poco::Data::AbstractBinder /// Binds placeholders in the sql query to the provided values. Performs data types mapping. { + + struct ParamDescriptor + { + ParamDescriptor() : colSize(0), cDataType(0), decDigits(-1) + {} + + ParamDescriptor(SQLINTEGER colSize_, SQLSMALLINT cDataType_, SQLSMALLINT decDigits_) : colSize(colSize_), cDataType(cDataType_), decDigits(decDigits_) + {} + + bool defined() const { return cDataType != 0; } + SQLINTEGER colSize; + SQLSMALLINT cDataType; + SQLSMALLINT decDigits; + }; + public: typedef AbstractBinder::Direction Direction; typedef std::map<SQLPOINTER, SQLLEN> ParamMap; static const size_t DEFAULT_PARAM_SIZE = 1024; + enum ParameterBinding { PB_IMMEDIATE, @@ -72,14 +88,16 @@ public: Binder(const StatementHandle& rStmt, std::size_t maxFieldSize, - ParameterBinding dataBinding = PB_IMMEDIATE, - TypeInfo* pDataTypes = 0); + ParameterBinding dataBinding, + TypeInfo* pDataTypes, + ODBCMetaColumn::NumericConversion numericConversion, + bool insertOnly); /// Creates the Binder. ~Binder(); /// Destroys the Binder. - void bind(std::size_t pos, const Poco::Int8& val, Direction dir); + void bind(std::size_t pos, const Poco::Int8& val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int8. void bind(std::size_t pos, const std::vector<Poco::Int8>& val, Direction dir); @@ -91,7 +109,7 @@ public: void bind(std::size_t pos, const std::list<Poco::Int8>& val, Direction dir); /// Binds an Int8 list. - void bind(std::size_t pos, const Poco::UInt8& val, Direction dir); + void bind(std::size_t pos, const Poco::UInt8& val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt8. void bind(std::size_t pos, const std::vector<Poco::UInt8>& val, Direction dir); @@ -103,7 +121,7 @@ public: void bind(std::size_t pos, const std::list<Poco::UInt8>& val, Direction dir); /// Binds an UInt8 list. - void bind(std::size_t pos, const Poco::Int16& val, Direction dir); + void bind(std::size_t pos, const Poco::Int16& val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int16. void bind(std::size_t pos, const std::vector<Poco::Int16>& val, Direction dir); @@ -115,7 +133,7 @@ public: void bind(std::size_t pos, const std::list<Poco::Int16>& val, Direction dir); /// Binds an Int16 list. - void bind(std::size_t pos, const Poco::UInt16& val, Direction dir); + void bind(std::size_t pos, const Poco::UInt16& val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt16. void bind(std::size_t pos, const std::vector<Poco::UInt16>& val, Direction dir); @@ -127,7 +145,7 @@ public: void bind(std::size_t pos, const std::list<Poco::UInt16>& val, Direction dir); /// Binds an UInt16 list. - void bind(std::size_t pos, const Poco::Int32& val, Direction dir); + void bind(std::size_t pos, const Poco::Int32& val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int32. void bind(std::size_t pos, const std::vector<Poco::Int32>& val, Direction dir); @@ -139,7 +157,7 @@ public: void bind(std::size_t pos, const std::list<Poco::Int32>& val, Direction dir); /// Binds an Int32 list. - void bind(std::size_t pos, const Poco::UInt32& val, Direction dir); + void bind(std::size_t pos, const Poco::UInt32& val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt32. void bind(std::size_t pos, const std::vector<Poco::UInt32>& val, Direction dir); @@ -151,7 +169,7 @@ public: void bind(std::size_t pos, const std::list<Poco::UInt32>& val, Direction dir); /// Binds an UInt32 list. - void bind(std::size_t pos, const Poco::Int64& val, Direction dir); + void bind(std::size_t pos, const Poco::Int64& val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int64. void bind(std::size_t pos, const std::vector<Poco::Int64>& val, Direction dir); @@ -163,7 +181,7 @@ public: void bind(std::size_t pos, const std::list<Poco::Int64>& val, Direction dir); /// Binds an Int64 list. - void bind(std::size_t pos, const Poco::UInt64& val, Direction dir); + void bind(std::size_t pos, const Poco::UInt64& val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt64. void bind(std::size_t pos, const std::vector<Poco::UInt64>& val, Direction dir); @@ -176,10 +194,10 @@ public: /// Binds an UInt64 list. #ifndef POCO_LONG_IS_64_BIT - void bind(std::size_t pos, const long& val, Direction dir); + void bind(std::size_t pos, const long& val, Direction dir, const WhenNullCb& nullCb); /// Binds a long. - void bind(std::size_t pos, const unsigned long& val, Direction dir); + void bind(std::size_t pos, const unsigned long& val, Direction dir, const WhenNullCb& nullCb); /// Binds an unsigned long. void bind(std::size_t pos, const std::vector<long>& val, Direction dir); @@ -192,7 +210,7 @@ public: /// Binds a long list. #endif - void bind(std::size_t pos, const bool& val, Direction dir); + void bind(std::size_t pos, const bool& val, Direction dir, const WhenNullCb& nullCb); /// Binds a boolean. void bind(std::size_t pos, const std::vector<bool>& val, Direction dir); @@ -204,7 +222,7 @@ public: void bind(std::size_t pos, const std::list<bool>& val, Direction dir); /// Binds a boolean list. - void bind(std::size_t pos, const float& val, Direction dir); + void bind(std::size_t pos, const float& val, Direction dir, const WhenNullCb& nullCb); /// Binds a float. void bind(std::size_t pos, const std::vector<float>& val, Direction dir); @@ -216,7 +234,7 @@ public: void bind(std::size_t pos, const std::list<float>& val, Direction dir); /// Binds a float list. - void bind(std::size_t pos, const double& val, Direction dir); + void bind(std::size_t pos, const double& val, Direction dir, const WhenNullCb& nullCb); /// Binds a double. void bind(std::size_t pos, const std::vector<double>& val, Direction dir); @@ -228,7 +246,7 @@ public: void bind(std::size_t pos, const std::list<double>& val, Direction dir); /// Binds a double list. - void bind(std::size_t pos, const char& val, Direction dir); + void bind(std::size_t pos, const char& val, Direction dir, const WhenNullCb& nullCb); /// Binds a single character. void bind(std::size_t pos, const std::vector<char>& val, Direction dir); @@ -240,7 +258,7 @@ public: void bind(std::size_t pos, const std::list<char>& val, Direction dir); /// Binds a character list. - void bind(std::size_t pos, const std::string& val, Direction dir); + void bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& nullCb); /// Binds a string. void bind(std::size_t pos, const std::vector<std::string>& val, Direction dir); @@ -252,7 +270,7 @@ public: void bind(std::size_t pos, const std::list<std::string>& val, Direction dir); /// Binds a string list. - void bind(std::size_t pos, const UTF16String& val, Direction dir); + void bind(std::size_t pos, const UTF16String& val, Direction dir, const WhenNullCb& nullCb); /// Binds a string. void bind(std::size_t pos, const std::vector<UTF16String>& val, Direction dir); @@ -264,10 +282,10 @@ public: void bind(std::size_t pos, const std::list<UTF16String>& val, Direction dir); /// Binds a string list. - void bind(std::size_t pos, const BLOB& val, Direction dir); + void bind(std::size_t pos, const BLOB& val, Direction dir, const WhenNullCb& nullCb); /// Binds a BLOB. In-bound only. - void bind(std::size_t pos, const CLOB& val, Direction dir); + void bind(std::size_t pos, const CLOB& val, Direction dir, const WhenNullCb& nullCb); /// Binds a CLOB. In-bound only. void bind(std::size_t pos, const std::vector<BLOB>& val, Direction dir); @@ -288,7 +306,7 @@ public: void bind(std::size_t pos, const std::list<CLOB>& val, Direction dir); /// Binds a CLOB list. - void bind(std::size_t pos, const Date& val, Direction dir); + void bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& nullCb); /// Binds a Date. void bind(std::size_t pos, const std::vector<Date>& val, Direction dir); @@ -300,7 +318,7 @@ public: void bind(std::size_t pos, const std::list<Date>& val, Direction dir); /// Binds a Date list. - void bind(std::size_t pos, const Time& val, Direction dir); + void bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& nullCb); /// Binds a Time. void bind(std::size_t pos, const std::vector<Time>& val, Direction dir); @@ -312,7 +330,7 @@ public: void bind(std::size_t pos, const std::list<Time>& val, Direction dir); /// Binds a Time list. - void bind(std::size_t pos, const DateTime& val, Direction dir); + void bind(std::size_t pos, const DateTime& val, Direction dir, const WhenNullCb& nullCb); /// Binds a DateTime. void bind(std::size_t pos, const std::vector<DateTime>& val, Direction dir); @@ -324,16 +342,16 @@ public: void bind(std::size_t pos, const std::list<DateTime>& val, Direction dir); /// Binds a DateTime list. - void bind(std::size_t pos, const NullData& val, Direction dir); + void bind(std::size_t pos, const NullData& val, Direction dir, const std::type_info& bindType); /// Binds a null. In-bound only. - void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir); + void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir, const std::type_info& bindType); /// Binds a null vector. - void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir); + void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir, const std::type_info& bindType); /// Binds a null deque. - void bind(std::size_t pos, const std::list<NullData>& val, Direction dir); + void bind(std::size_t pos, const std::list<NullData>& val, Direction dir, const std::type_info& bindType); /// Binds a null list. void setDataBinding(ParameterBinding binding); @@ -353,6 +371,7 @@ public: /// Clears the cached storage. private: + typedef std::vector<ParamDescriptor> ParameterInfoVec; typedef std::vector<SQLLEN*> LengthPtrVec; typedef std::vector<SQLLEN> LengthVec; typedef std::vector<LengthVec*> LengthVecVec; @@ -365,18 +384,19 @@ private: typedef std::vector<TimeVec*> TimeVecVec; typedef std::vector<SQL_TIMESTAMP_STRUCT> DateTimeVec; typedef std::vector<DateTimeVec*> DateTimeVecVec; - typedef std::vector<Poco::Any> AnyVec; - typedef std::vector<AnyVec> AnyVecVec; + typedef std::vector<Poco::Any*> AnyPtrVec; + typedef std::vector<AnyPtrVec> AnyPtrVecVec; typedef std::map<char*, std::string*> StringMap; typedef std::map<UTF16String::value_type*, UTF16String*> UTF16StringMap; typedef std::map<SQL_DATE_STRUCT*, Date*> DateMap; typedef std::map<SQL_TIME_STRUCT*, Time*> TimeMap; typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap; + typedef std::map<SQLLEN*, WhenNullCb> NullCbMap; void describeParameter(std::size_t pos); /// Sets the description field for the parameter, if needed. - void bind(std::size_t pos, const char* const& pVal, Direction dir); + void bind(std::size_t pos, const char* const& pVal, Direction dir, const WhenNullCb& nullCb); /// Binds a const char ptr. /// This is a private no-op in this implementation /// due to security risk. @@ -386,13 +406,19 @@ private: /// specified by user. template <typename T> - void bindImpl(std::size_t pos, T& val, SQLSMALLINT cDataType, Direction dir) + void bindImpl(std::size_t pos, T& val, SQLSMALLINT cDataType, Direction dir, const WhenNullCb& nullCb) { SQLINTEGER colSize = 0; SQLSMALLINT decDigits = 0; getColSizeAndPrecision(pos, cDataType, colSize, decDigits); - - _lengthIndicator.push_back(0); + SQLLEN* pLenIn = NULL; + if (isOutBound(dir) && nullCb.defined()) + { + pLenIn = new SQLLEN; + *pLenIn = SQL_NTS; // microsoft example does that, otherwise no null indicator is returned + _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb)); + } + _lengthIndicator.push_back(pLenIn); if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT) pos + 1, @@ -401,14 +427,15 @@ private: Utility::sqlDataType(cDataType), colSize, decDigits, - (SQLPOINTER) &val, 0, 0))) + (SQLPOINTER)&val, 0, + _lengthIndicator.back()))) { throw StatementException(_rStmt, "SQLBindParameter()"); } } template <typename L> - void bindImplLOB(std::size_t pos, const L& val, Direction dir) + void bindImplLOB(std::size_t pos, const L& val, Direction dir, const WhenNullCb& nullCb) { if (isOutBound(dir) || !isInBound(dir)) throw NotImplementedException("LOB parameter type can only be inbound."); @@ -424,13 +451,17 @@ private: if (PB_AT_EXEC == _paramBinding) *pLenIn = SQL_LEN_DATA_AT_EXEC(size); + if (isOutBound(dir) && nullCb.defined()) + _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb)); + _lengthIndicator.push_back(pLenIn); + SQLSMALLINT sqlType = (isInBound(dir) && size <= _maxVarBinColSize) ? SQL_VARBINARY : SQL_LONGVARBINARY; if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT) pos + 1, SQL_PARAM_INPUT, SQL_C_BINARY, - SQL_LONGVARBINARY, + sqlType, (SQLUINTEGER) size, 0, pVal, @@ -485,9 +516,9 @@ private: if (_containers.size() <= pos) _containers.resize(pos + 1); - _containers[pos].push_back(std::vector<Type>()); + _containers[pos].push_back( new Any(std::vector<Type>()) ); - std::vector<Type>& cont = RefAnyCast<std::vector<Type> >(_containers[pos].back()); + std::vector<Type>& cont = RefAnyCast<std::vector<Type> >( *_containers[pos].back() ); cont.assign(val.begin(), val.end()); bindImplVec(pos, cont, cDataType, dir); } @@ -586,12 +617,13 @@ private: std::memcpy(_charPtrs[pos] + offset, it->c_str(), strSize); offset += size; } + SQLSMALLINT sqlType = (isInBound(dir) && size < _maxCharColLength) ? SQL_VARCHAR : SQL_LONGVARCHAR; if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_CHAR, - SQL_LONGVARCHAR, + sqlType, (SQLUINTEGER) size - 1, 0, _charPtrs[pos], @@ -652,12 +684,12 @@ private: std::memcpy(_utf16CharPtrs[pos] + offset, it->data(), strSize); offset += (size / sizeof(UTF16Char)); } - + SQLSMALLINT sqlType = (isInBound(dir) && size < _maxWCharColLength) ? SQL_WVARCHAR : SQL_WLONGVARCHAR; if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT)pos + 1, toODBCDirection(dir), SQL_C_WCHAR, - SQL_WLONGVARCHAR, + sqlType, (SQLUINTEGER)size - 1, 0, _utf16CharPtrs[pos], @@ -722,12 +754,13 @@ private: std::memcpy(_charPtrs[pos] + offset, cIt->rawContent(), blobSize * sizeof(CharType)); offset += size; } + SQLSMALLINT sqlType = (isInBound(dir) && size <= _maxVarBinColSize) ? SQL_VARBINARY : SQL_LONGVARBINARY; if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT) pos + 1, SQL_PARAM_INPUT, SQL_C_BINARY, - SQL_LONGVARBINARY, + sqlType, (SQLUINTEGER) size, 0, _charPtrs[pos], @@ -754,8 +787,6 @@ private: setParamSetSize(length); - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_DATE_STRUCT); - if (_vecLengthIndicator.size() <= pos) { _vecLengthIndicator.resize(pos + 1, 0); @@ -804,8 +835,6 @@ private: setParamSetSize(val.size()); - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIME_STRUCT); - if (_vecLengthIndicator.size() <= pos) { _vecLengthIndicator.resize(pos + 1, 0); @@ -855,8 +884,6 @@ private: setParamSetSize(length); - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIMESTAMP_STRUCT); - if (_vecLengthIndicator.size() <= pos) { _vecLengthIndicator.resize(pos + 1, 0); @@ -891,7 +918,7 @@ private: } template<typename C> - void bindImplNullContainer(std::size_t pos, const C& val, Direction dir) + void bindImplNullContainer(std::size_t pos, const C& val, Direction dir, const std::type_info& bindElemType) { if (isOutBound(dir) || !isInBound(dir)) throw NotImplementedException("Null container parameter type can only be inbound."); @@ -906,8 +933,6 @@ private: setParamSetSize(length); - SQLINTEGER size = SQL_NULL_DATA; - if (_vecLengthIndicator.size() <= pos) { _vecLengthIndicator.resize(pos + 1, 0); @@ -916,13 +941,14 @@ private: SQLINTEGER colSize = 0; SQLSMALLINT decDigits = 0; - getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits); + SQLSMALLINT colType = _pTypeInfo->tryTypeidToCType(bindElemType, SQL_C_STINYINT); + getColSizeAndPrecision(pos, colType, colSize, decDigits); if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT) pos + 1, SQL_PARAM_INPUT, - SQL_C_STINYINT, - Utility::sqlDataType(SQL_C_STINYINT), + colType, + Utility::sqlDataType(colType), colSize, decDigits, 0, @@ -957,6 +983,7 @@ private: void freeMemory(); /// Frees all dynamically allocated memory resources. + template<typename T> void getMinValueSize(T& val, SQLINTEGER& size) /// Some ODBC drivers return DB-wide maximum allowed size for variable size columns, @@ -995,6 +1022,7 @@ private: ParamMap _inParams; ParamMap _outParams; ParameterBinding _paramBinding; + ParameterInfoVec _parameters; DateMap _dates; TimeMap _times; @@ -1011,16 +1039,22 @@ private: const TypeInfo* _pTypeInfo; SQLINTEGER _paramSetSize; std::size_t _maxFieldSize; - AnyVecVec _containers; + AnyPtrVecVec _containers; + std::size_t _maxCharColLength; + std::size_t _maxWCharColLength; + std::size_t _maxVarBinColSize; + ODBCMetaColumn::NumericConversion _numericConversion; + NullCbMap _nullCbMap; + bool _insertOnly; }; // // inlines // -inline void Binder::bind(std::size_t pos, const Poco::Int8& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::Int8& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_STINYINT, dir); + bindImpl(pos, val, SQL_C_STINYINT, dir, nullCb); } @@ -1042,9 +1076,9 @@ inline void Binder::bind(std::size_t pos, const std::list<Poco::Int8>& val, Dire } -inline void Binder::bind(std::size_t pos, const Poco::UInt8& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::UInt8& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_UTINYINT, dir); + bindImpl(pos, val, SQL_C_UTINYINT, dir, nullCb); } @@ -1066,9 +1100,9 @@ inline void Binder::bind(std::size_t pos, const std::list<Poco::UInt8>& val, Dir } -inline void Binder::bind(std::size_t pos, const Poco::Int16& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::Int16& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_SSHORT, dir); + bindImpl(pos, val, SQL_C_SSHORT, dir, nullCb); } @@ -1090,9 +1124,9 @@ inline void Binder::bind(std::size_t pos, const std::list<Poco::Int16>& val, Dir } -inline void Binder::bind(std::size_t pos, const Poco::UInt16& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::UInt16& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_USHORT, dir); + bindImpl(pos, val, SQL_C_USHORT, dir, nullCb); } @@ -1114,9 +1148,9 @@ inline void Binder::bind(std::size_t pos, const std::list<Poco::UInt16>& val, Di } -inline void Binder::bind(std::size_t pos, const Poco::Int32& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::Int32& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_SLONG, dir); + bindImpl(pos, val, SQL_C_SLONG, dir, nullCb); } @@ -1138,9 +1172,9 @@ inline void Binder::bind(std::size_t pos, const std::list<Poco::Int32>& val, Dir } -inline void Binder::bind(std::size_t pos, const Poco::UInt32& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::UInt32& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_ULONG, dir); + bindImpl(pos, val, SQL_C_ULONG, dir, nullCb); } @@ -1162,9 +1196,9 @@ inline void Binder::bind(std::size_t pos, const std::list<Poco::UInt32>& val, Di } -inline void Binder::bind(std::size_t pos, const Poco::Int64& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::Int64& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_SBIGINT, dir); + bindImpl(pos, val, SQL_C_SBIGINT, dir, nullCb); } @@ -1186,9 +1220,9 @@ inline void Binder::bind(std::size_t pos, const std::list<Poco::Int64>& val, Dir } -inline void Binder::bind(std::size_t pos, const Poco::UInt64& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::UInt64& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_UBIGINT, dir); + bindImpl(pos, val, SQL_C_UBIGINT, dir, nullCb); } @@ -1211,15 +1245,15 @@ inline void Binder::bind(std::size_t pos, const std::list<Poco::UInt64>& val, Di #ifndef POCO_LONG_IS_64_BIT -inline void Binder::bind(std::size_t pos, const long& val, Direction dir) +inline void Binder::bind(std::size_t pos, const long& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_SLONG, dir); + bindImpl(pos, val, SQL_C_SLONG, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const unsigned long& val, Direction dir) +inline void Binder::bind(std::size_t pos, const unsigned long& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_SLONG, dir); + bindImpl(pos, val, SQL_C_SLONG, dir, nullCb); } @@ -1242,9 +1276,9 @@ inline void Binder::bind(std::size_t pos, const std::list<long>& val, Direction #endif -inline void Binder::bind(std::size_t pos, const float& val, Direction dir) +inline void Binder::bind(std::size_t pos, const float& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_FLOAT, dir); + bindImpl(pos, val, SQL_C_FLOAT, dir, nullCb); } @@ -1266,9 +1300,9 @@ inline void Binder::bind(std::size_t pos, const std::list<float>& val, Direction } -inline void Binder::bind(std::size_t pos, const double& val, Direction dir) +inline void Binder::bind(std::size_t pos, const double& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_DOUBLE, dir); + bindImpl(pos, val, SQL_C_DOUBLE, dir, nullCb); } @@ -1290,9 +1324,9 @@ inline void Binder::bind(std::size_t pos, const std::list<double>& val, Directio } -inline void Binder::bind(std::size_t pos, const bool& val, Direction dir) +inline void Binder::bind(std::size_t pos, const bool& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_BIT, dir); + bindImpl(pos, val, SQL_C_BIT, dir, nullCb); } @@ -1314,9 +1348,9 @@ inline void Binder::bind(std::size_t pos, const std::list<bool>& val, Direction } -inline void Binder::bind(std::size_t pos, const char& val, Direction dir) +inline void Binder::bind(std::size_t pos, const char& val, Direction dir, const WhenNullCb& nullCb) { - bindImpl(pos, val, SQL_C_STINYINT, dir); + bindImpl(pos, val, SQL_C_STINYINT, dir, nullCb); } @@ -1373,15 +1407,15 @@ inline void Binder::bind(std::size_t pos, const std::list<UTF16String>& val, Dir bindImplContainerUTF16String(pos, val, dir); } -inline void Binder::bind(std::size_t pos, const BLOB& val, Direction dir) +inline void Binder::bind(std::size_t pos, const BLOB& val, Direction dir, const WhenNullCb& nullCb) { - bindImplLOB<BLOB>(pos, val, dir); + bindImplLOB<BLOB>(pos, val, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const CLOB& val, Direction dir) +inline void Binder::bind(std::size_t pos, const CLOB& val, Direction dir, const WhenNullCb& nullCb) { - bindImplLOB<CLOB>(pos, val, dir); + bindImplLOB<CLOB>(pos, val, dir, nullCb); } @@ -1475,21 +1509,21 @@ inline void Binder::bind(std::size_t pos, const std::list<DateTime>& val, Direct } -inline void Binder::bind(std::size_t pos, const std::vector<NullData>& val, Direction dir) +inline void Binder::bind(std::size_t pos, const std::vector<NullData>& val, Direction dir, const std::type_info& bindElemType) { - bindImplNullContainer(pos, val, dir); + bindImplNullContainer(pos, val, dir, bindElemType); } -inline void Binder::bind(std::size_t pos, const std::deque<NullData>& val, Direction dir) +inline void Binder::bind(std::size_t pos, const std::deque<NullData>& val, Direction dir, const std::type_info& bindElemType) { - bindImplNullContainer(pos, val, dir); + bindImplNullContainer(pos, val, dir, bindElemType); } -inline void Binder::bind(std::size_t pos, const std::list<NullData>& val, Direction dir) +inline void Binder::bind(std::size_t pos, const std::list<NullData>& val, Direction dir, const std::type_info& bindElemType) { - bindImplNullContainer(pos, val, dir); + bindImplNullContainer(pos, val, dir, bindElemType); } diff --git a/Data/ODBC/include/Poco/Data/ODBC/ConnectionHandle.h b/Data/ODBC/include/Poco/Data/ODBC/ConnectionHandle.h index 693f61b21..1353bb545 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/ConnectionHandle.h +++ b/Data/ODBC/include/Poco/Data/ODBC/ConnectionHandle.h @@ -19,7 +19,6 @@ #ifndef Data_ODBC_ConnectionHandle_INCLUDED #define Data_ODBC_ConnectionHandle_INCLUDED - #include "Poco/Data/ODBC/ODBC.h" #include "Poco/Data/ODBC/EnvironmentHandle.h" #ifdef POCO_OS_FAMILY_WINDOWS @@ -49,6 +48,9 @@ public: const SQLHDBC& handle() const; /// Returns const reference to handle; + operator bool() const; + /// Returns true if the handle is valid + private: operator SQLHDBC& (); /// Conversion operator into reference to native type. @@ -59,9 +61,8 @@ private: ConnectionHandle(const ConnectionHandle&); const ConnectionHandle& operator=(const ConnectionHandle&); - const EnvironmentHandle* _pEnvironment; + const EnvironmentHandle _environment; SQLHDBC _hdbc; - bool _ownsEnvironment; }; @@ -92,6 +93,11 @@ inline SQLHDBC& ConnectionHandle::handle() } +inline ConnectionHandle::operator bool () const +{ + return _hdbc != SQL_NULL_HDBC; +} + } } } // namespace Poco::Data::ODBC diff --git a/Data/ODBC/include/Poco/Data/ODBC/Diagnostics.h b/Data/ODBC/include/Poco/Data/ODBC/Diagnostics.h index 48d268af9..a3a1dfc33 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Diagnostics.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Diagnostics.h @@ -59,12 +59,12 @@ public: typedef std::vector<DiagnosticFields> FieldVec; typedef typename FieldVec::const_iterator Iterator; - explicit Diagnostics(const H& handle): _handle(handle) + explicit Diagnostics(const H& handle) /// Creates and initializes the Diagnostics. { std::memset(_connectionName, 0, sizeof(_connectionName)); std::memset(_serverName, 0, sizeof(_serverName)); - diagnostics(); + diagnostics(handle); } ~Diagnostics() @@ -138,7 +138,7 @@ public: return _fields.end(); } - const Diagnostics& diagnostics() + const Diagnostics& diagnostics(const H& handle) { DiagnosticFields df; SQLSMALLINT count = 1; @@ -149,7 +149,7 @@ public: reset(); while (!Utility::isError(SQLGetDiagRec(handleType, - _handle, + handle, count, df._sqlState, &df._nativeError, @@ -163,7 +163,7 @@ public: // (they fail if connection has not been established yet // or return empty string if not applicable for the context) if (Utility::isError(SQLGetDiagField(handleType, - _handle, + handle, count, SQL_DIAG_CONNECTION_NAME, _connectionName, @@ -182,7 +182,7 @@ public: } if (Utility::isError(SQLGetDiagField(handleType, - _handle, + handle, count, SQL_DIAG_SERVER_NAME, _serverName, @@ -223,9 +223,6 @@ private: /// Diagnostics container FieldVec _fields; - - /// Context handle - const H& _handle; }; diff --git a/Data/ODBC/include/Poco/Data/ODBC/EnvironmentHandle.h b/Data/ODBC/include/Poco/Data/ODBC/EnvironmentHandle.h index cbc4821e3..db0fd08b2 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/EnvironmentHandle.h +++ b/Data/ODBC/include/Poco/Data/ODBC/EnvironmentHandle.h @@ -39,6 +39,9 @@ public: EnvironmentHandle(); /// Creates the EnvironmentHandle. + explicit EnvironmentHandle(const SQLHENV* henv); + /// Creates the EnvironmentHandle which doesn't own the handle + ~EnvironmentHandle(); /// Destroys the EnvironmentHandle. @@ -52,8 +55,7 @@ private: operator SQLHENV& (); /// Conversion operator into reference to native type. - SQLHENV& handle(); - /// Returns reference to handle. + void init(); EnvironmentHandle(const EnvironmentHandle&); const EnvironmentHandle& operator=(const EnvironmentHandle&); @@ -79,12 +81,6 @@ inline const SQLHENV& EnvironmentHandle::handle() const inline EnvironmentHandle::operator SQLHENV& () -{ - return handle(); -} - - -inline SQLHENV& EnvironmentHandle::handle() { return _henv; } diff --git a/Data/ODBC/include/Poco/Data/ODBC/Extractor.h b/Data/ODBC/include/Poco/Data/ODBC/Extractor.h index 29655ccfc..f2f1c26c6 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Extractor.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Extractor.h @@ -491,6 +491,9 @@ private: return true; } + template<typename T> + bool extractManualLOBImpl(std::size_t pos, Poco::Data::LOB<T>& val, SQLSMALLINT cType); + template <typename T, typename NT> bool extAny(std::size_t pos, T& val) { @@ -511,7 +514,7 @@ private: bool extractImpl(std::size_t pos, T& val) /// Utility function for extraction of Any and DynamicAny. { - ODBCMetaColumn column(_rStmt, pos); + ODBCMetaColumn column(_rStmt, pos, _pPreparator->numericConversion()); switch (column.type()) { @@ -717,7 +720,7 @@ inline bool Extractor::isNullLengthIndicator(SQLLEN val) const inline SQLINTEGER Extractor::columnSize(std::size_t pos) const { - std::size_t size = ODBCMetaColumn(_rStmt, pos).length(); + std::size_t size = ODBCMetaColumn(_rStmt, pos, _pPreparator->numericConversion()).length(); std::size_t maxSize = _pPreparator->maxDataSize(pos); if (size > maxSize) size = maxSize; return (SQLINTEGER) size; diff --git a/Data/ODBC/include/Poco/Data/ODBC/ODBCException.h b/Data/ODBC/include/Poco/Data/ODBC/ODBCException.h index a66feac3f..af0cdb193 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/ODBCException.h +++ b/Data/ODBC/include/Poco/Data/ODBC/ODBCException.h @@ -43,7 +43,9 @@ template <class H, SQLSMALLINT handleType> class HandleException: public ODBCException { public: - HandleException(const H& handle): _error(handle) + HandleException(const H& handle, int code = 0) : + ODBCException(code), + _error(handle) /// Creates HandleException { message(_error.toString()); @@ -129,12 +131,24 @@ public: _error.toString()); } + std::string errorString() const + /// Returns the error diagnostics string + { + return _error.toString(); + } + static std::string errorString(const H& handle) /// Returns the error diagnostics string for the handle. { return Error<H, handleType>(handle).toString(); } +protected: + const Error<H, handleType>& error() const + { + return _error; + } + private: Error<H, handleType> _error; }; diff --git a/Data/ODBC/include/Poco/Data/ODBC/ODBCMetaColumn.h b/Data/ODBC/include/Poco/Data/ODBC/ODBCMetaColumn.h index f706c06e2..5d27aedf2 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/ODBCMetaColumn.h +++ b/Data/ODBC/include/Poco/Data/ODBC/ODBCMetaColumn.h @@ -39,7 +39,15 @@ namespace ODBC { class ODBC_API ODBCMetaColumn: public MetaColumn { public: - explicit ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position); + + enum NumericConversion + { + NC_BEST_FIT = 0, + NC_FORCE_STRING = 1, + NC_BEST_FIT_DBL_LIMIT = 2 + }; + + ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position, NumericConversion numericConversion); /// Creates the ODBCMetaColumn. ~ODBCMetaColumn(); @@ -73,6 +81,7 @@ private: SQLLEN _dataLength; const StatementHandle& _rStmt; ColumnDescription _columnDesc; + NumericConversion _numericConversion; }; diff --git a/Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h b/Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h index 89c74b359..33057b1f6 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h +++ b/Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h @@ -60,7 +60,7 @@ protected: /// Returns the number of affected rows. /// Used to find out the number of rows affected by insert or update. - const MetaColumn& metaColumn(std::size_t pos) const; + const MetaColumn& metaColumn(std::size_t pos, size_t dataSet) const; /// Returns column meta data. bool hasNext(); @@ -93,6 +93,10 @@ protected: std::string nativeSQL(); /// Returns the SQL string as modified by the driver. +protected: + + virtual void insertHint(); + private: typedef Poco::Data::AbstractBindingVec Bindings; typedef Poco::SharedPtr<Binder> BinderPtr; @@ -140,9 +144,10 @@ private: void getData(); - void addPreparator(); - void fillColumns(); + bool addPreparator(bool addAlways = true); + void fillColumns(size_t dataSetPos); void checkError(SQLRETURN rc, const std::string& msg=""); + bool nextResultSet(); const SQLHDBC& _rConnection; const StatementHandle _stmt; @@ -155,6 +160,9 @@ private: bool _prepared; mutable std::size_t _affectedRowCount; bool _canCompile; + ODBCMetaColumn::NumericConversion _numericConversion; + bool _isPostgres; + bool _insertHint; }; diff --git a/Data/ODBC/include/Poco/Data/ODBC/Preparator.h b/Data/ODBC/include/Poco/Data/ODBC/Preparator.h index 275777f52..586c14498 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Preparator.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Preparator.h @@ -101,7 +101,10 @@ public: Preparator(const StatementHandle& rStmt, const std::string& statement, std::size_t maxFieldSize, - DataExtraction dataExtraction = DE_BOUND); + DataExtraction dataExtraction, + ODBCMetaColumn::NumericConversion numericConversion , + bool isPostgres + ); /// Creates the Preparator. Preparator(const Preparator& other); @@ -416,6 +419,9 @@ public: DataExtraction getDataExtraction() const; /// Returns data extraction mode. + ODBCMetaColumn::NumericConversion numericConversion() const; + /// Tells if numeric values are always converted to string + private: typedef std::vector<Poco::Any> ValueVec; typedef std::vector<SQLLEN> LengthVec; @@ -429,7 +435,7 @@ private: void prepareImpl(std::size_t pos, const C* pVal = 0) /// Utility function to prepare Any and DynamicAny. { - ODBCMetaColumn col(_rStmt, pos); + ODBCMetaColumn col(_rStmt, pos, _numericConversion); switch (col.type()) { @@ -681,6 +687,7 @@ private: mutable IndexMap _varLengthArrays; std::size_t _maxFieldSize; DataExtraction _dataExtraction; + ODBCMetaColumn::NumericConversion _numericConversion; }; @@ -1267,6 +1274,12 @@ inline Poco::Any& Preparator::at(std::size_t pos) } +inline ODBCMetaColumn::NumericConversion Preparator::numericConversion() const +{ + return _numericConversion; +} + + } } } // namespace Poco::Data::ODBC diff --git a/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h b/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h index 22a3d6063..641052493 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h +++ b/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h @@ -45,6 +45,7 @@ class ODBC_API SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl> { public: static const std::size_t ODBC_MAX_FIELD_SIZE = 1024u; + static const char* const NUMERIC_CONVERSION_PROPERTY; enum TransactionCapability { @@ -167,10 +168,24 @@ public: Poco::Any dataTypeInfo(const std::string& rName=""); /// Returns the data types information. + ODBCMetaColumn::NumericConversion numericConversion() const; + /// Tells if NUMERIC values to be always + /// converted to string + + void setNumericConversion(ODBCMetaColumn::NumericConversion value); + /// Sets flag to tell if NUMERIC values are always returned as + /// string + private: void setDataTypeInfo(const std::string& rName, const Poco::Any& rValue); /// No-op. Throws InvalidAccessException. + void setNumericConversion(const std::string&, const Poco::Any& rValue); + + Poco::Any numericConversion(const std::string& nm); + + void init(); + static const int FUNCTIONS = SQL_API_ODBC3_ALL_FUNCTIONS_SIZE; void checkError(SQLRETURN rc, const std::string& msg=""); @@ -184,6 +199,7 @@ private: Poco::Any _maxFieldSize; bool _autoBind; bool _autoExtract; + ODBCMetaColumn::NumericConversion _numericConversion; TypeInfo _dataTypes; char _canTransact; bool _inTransaction; @@ -286,6 +302,30 @@ inline int SessionImpl::queryTimeout() const } +inline ODBCMetaColumn::NumericConversion SessionImpl::numericConversion() const +{ + return _numericConversion; +} + + +inline Poco::Any SessionImpl::numericConversion(const std::string&) +{ + return numericConversion(); +} + + +inline void SessionImpl::setNumericConversion(ODBCMetaColumn::NumericConversion value) +{ + _numericConversion = value; +} + + +inline void SessionImpl::setNumericConversion(const std::string&, const Poco::Any& rValue) +{ + setNumericConversion( Poco::AnyCast<ODBCMetaColumn::NumericConversion>(rValue) ); +} + + } } } // namespace Poco::Data::ODBC diff --git a/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h b/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h index dd24e96b1..b81aa4050 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h +++ b/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h @@ -23,8 +23,10 @@ #include "Poco/Data/ODBC/ODBC.h" #include "Poco/NamedTuple.h" #include "Poco/DynamicAny.h" +#include "Poco/Data/AbstractBinder.h" #include <vector> #include <map> +#include <typeinfo> #ifdef POCO_OS_FAMILY_WINDOWS #include <windows.h> #endif @@ -71,6 +73,17 @@ public: SQLINTEGER, SQLSMALLINT> TypeInfoTup; typedef std::vector<TypeInfoTup> TypeInfoVec; + typedef const std::type_info* TypeInfoPtr; + + struct TypeInfoComp : public std::binary_function<TypeInfoPtr, TypeInfoPtr, bool> + { + bool operator()(const TypeInfoPtr& left, const TypeInfoPtr& right) const + { // apply operator< to operands + return ( left->before( *right ) ); + } + }; + + typedef std::map<TypeInfoPtr, SQLSMALLINT, TypeInfoComp> CppTypeInfoMap; explicit TypeInfo(SQLHDBC* pHDBC=0); /// Creates the TypeInfo. @@ -102,6 +115,13 @@ public: /// Prints all the types (as reported by the underlying database) /// to the supplied output stream. + SQLSMALLINT tryTypeidToCType(const std::type_info& ti, SQLSMALLINT defaultVal = SQL_C_TINYINT) const; + /// try to find mapping of the given C++ typeid to the ODBC C-Type Code + /// will return the defaultVal if no match is found + + SQLSMALLINT nullDataType(const NullData val) const; + /// Map the null value type to ODBC buffer type + private: void fillCTypes(); void fillSQLTypes(); @@ -109,6 +129,7 @@ private: DataTypeMap _cDataTypes; DataTypeMap _sqlDataTypes; TypeInfoVec _typeInfo; + CppTypeInfoMap _cppDataTypes; SQLHDBC* _pHDBC; }; diff --git a/Data/ODBC/include/Poco/Data/ODBC/Unicode_UNIXODBC.h b/Data/ODBC/include/Poco/Data/ODBC/Unicode_UNIXODBC.h index 466f6d0a5..9013877cc 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Unicode_UNIXODBC.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Unicode_UNIXODBC.h @@ -40,13 +40,6 @@ void makeUTF8(Poco::Buffer<SQLWCHAR>& buffer, SQLINTEGER length, SQLPOINTER pTar /// Utility function for conversion from UTF-16 to UTF-8. -inline void makeUTF8(Poco::Buffer<SQLWCHAR>& buffer, int length, SQLPOINTER pTarget, SQLSMALLINT targetLength) - /// Utility function for conversion from UTF-16 to UTF-8. -{ - makeUTF8(buffer, length, pTarget, (SQLINTEGER) targetLength); -} - - } } } // namespace Poco::Data::ODBC diff --git a/Data/ODBC/src/Binder.cpp b/Data/ODBC/src/Binder.cpp index 5f2e99a28..2f7246cf9 100644 --- a/Data/ODBC/src/Binder.cpp +++ b/Data/ODBC/src/Binder.cpp @@ -27,17 +27,39 @@ namespace Poco { namespace Data { namespace ODBC { +static void getProp(const TypeInfo& dataTypes, SQLSMALLINT sqlType, size_t& val) +{ + const std::string NM("COLUMN_SIZE"); + Poco::DynamicAny r; + if (dataTypes.tryGetInfo(sqlType, NM, r)) + { + long sz = r.convert<long>(); + // Postgres driver returns SQL_NO_TOTAL(-4) in some cases + if (sz >= 0) + val = static_cast<size_t>(sz); + } +} Binder::Binder(const StatementHandle& rStmt, std::size_t maxFieldSize, Binder::ParameterBinding dataBinding, - TypeInfo* pDataTypes): + TypeInfo* pDataTypes, + ODBCMetaColumn::NumericConversion numericConversion, + bool insertOnly) : _rStmt(rStmt), _paramBinding(dataBinding), _pTypeInfo(pDataTypes), _paramSetSize(0), - _maxFieldSize(maxFieldSize) + _maxFieldSize(maxFieldSize), + _maxCharColLength(1024), + _maxWCharColLength(1024), + _maxVarBinColSize(1024), + _numericConversion(numericConversion), + _insertOnly(insertOnly) { + getProp(*_pTypeInfo, SQL_WVARCHAR, _maxWCharColLength); + getProp(*_pTypeInfo, SQL_VARCHAR, _maxCharColLength); + getProp(*_pTypeInfo, SQL_VARBINARY, _maxVarBinColSize); } @@ -49,61 +71,110 @@ Binder::~Binder() void Binder::freeMemory() { - LengthPtrVec::iterator itLen = _lengthIndicator.begin(); - LengthPtrVec::iterator itLenEnd = _lengthIndicator.end(); - for(; itLen != itLenEnd; ++itLen) delete *itLen; + if (_lengthIndicator.size() > 0) + { + LengthPtrVec::iterator itLen = _lengthIndicator.begin(); + LengthPtrVec::iterator itLenEnd = _lengthIndicator.end(); + for (; itLen != itLenEnd; ++itLen) delete *itLen; + } - LengthVecVec::iterator itVecLen = _vecLengthIndicator.begin(); - LengthVecVec::iterator itVecLenEnd = _vecLengthIndicator.end(); - for (; itVecLen != itVecLenEnd; ++itVecLen) delete *itVecLen; + if (_vecLengthIndicator.size() > 0) + { + LengthVecVec::iterator itVecLen = _vecLengthIndicator.begin(); + LengthVecVec::iterator itVecLenEnd = _vecLengthIndicator.end(); + for (; itVecLen != itVecLenEnd; ++itVecLen) delete *itVecLen; + } - TimeMap::iterator itT = _times.begin(); - TimeMap::iterator itTEnd = _times.end(); - for(; itT != itTEnd; ++itT) delete itT->first; + if (_times.size() > 0) + { + TimeMap::iterator itT = _times.begin(); + TimeMap::iterator itTEnd = _times.end(); + for (; itT != itTEnd; ++itT) delete itT->first; + } - DateMap::iterator itD = _dates.begin(); - DateMap::iterator itDEnd = _dates.end(); - for(; itD != itDEnd; ++itD) delete itD->first; + if (_dates.size() > 0) + { + DateMap::iterator itD = _dates.begin(); + DateMap::iterator itDEnd = _dates.end(); + for (; itD != itDEnd; ++itD) delete itD->first; + } - TimestampMap::iterator itTS = _timestamps.begin(); - TimestampMap::iterator itTSEnd = _timestamps.end(); - for(; itTS != itTSEnd; ++itTS) delete itTS->first; + if (_timestamps.size() > 0) + { + TimestampMap::iterator itTS = _timestamps.begin(); + TimestampMap::iterator itTSEnd = _timestamps.end(); + for (; itTS != itTSEnd; ++itTS) delete itTS->first; + } - StringMap::iterator itStr = _strings.begin(); - StringMap::iterator itStrEnd = _strings.end(); - for(; itStr != itStrEnd; ++itStr) std::free(itStr->first); + if (_strings.size() > 0) + { + StringMap::iterator itStr = _strings.begin(); + StringMap::iterator itStrEnd = _strings.end(); + for (; itStr != itStrEnd; ++itStr) std::free(itStr->first); + } - CharPtrVec::iterator itChr = _charPtrs.begin(); - CharPtrVec::iterator endChr = _charPtrs.end(); - for (; itChr != endChr; ++itChr) std::free(*itChr); + if (_charPtrs.size() > 0) + { + CharPtrVec::iterator itChr = _charPtrs.begin(); + CharPtrVec::iterator endChr = _charPtrs.end(); + for (; itChr != endChr; ++itChr) std::free(*itChr); + } - UTF16CharPtrVec::iterator itUTF16Chr = _utf16CharPtrs.begin(); - UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end(); - for (; itUTF16Chr != endUTF16Chr; ++itUTF16Chr) std::free(*itUTF16Chr); + if (_utf16CharPtrs.size() > 0) + { + UTF16CharPtrVec::iterator itUTF16Chr = _utf16CharPtrs.begin(); + UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end(); + for (; itUTF16Chr != endUTF16Chr; ++itUTF16Chr) std::free(*itUTF16Chr); + } - BoolPtrVec::iterator itBool = _boolPtrs.begin(); - BoolPtrVec::iterator endBool = _boolPtrs.end(); - for (; itBool != endBool; ++itBool) delete [] *itBool; + if (_boolPtrs.size() > 0) + { + BoolPtrVec::iterator itBool = _boolPtrs.begin(); + BoolPtrVec::iterator endBool = _boolPtrs.end(); + for (; itBool != endBool; ++itBool) delete[] * itBool; + } - DateVecVec::iterator itDateVec = _dateVecVec.begin(); - DateVecVec::iterator itDateVecEnd = _dateVecVec.end(); - for (; itDateVec != itDateVecEnd; ++itDateVec) delete *itDateVec; + if (_dateVecVec.size() > 0) + { + DateVecVec::iterator itDateVec = _dateVecVec.begin(); + DateVecVec::iterator itDateVecEnd = _dateVecVec.end(); + for (; itDateVec != itDateVecEnd; ++itDateVec) delete *itDateVec; + } - TimeVecVec::iterator itTimeVec = _timeVecVec.begin(); - TimeVecVec::iterator itTimeVecEnd = _timeVecVec.end(); - for (; itTimeVec != itTimeVecEnd; ++itTimeVec) delete *itTimeVec; + if (_timeVecVec.size() > 0) + { + TimeVecVec::iterator itTimeVec = _timeVecVec.begin(); + TimeVecVec::iterator itTimeVecEnd = _timeVecVec.end(); + for (; itTimeVec != itTimeVecEnd; ++itTimeVec) delete *itTimeVec; + } - DateTimeVecVec::iterator itDateTimeVec = _dateTimeVecVec.begin(); - DateTimeVecVec::iterator itDateTimeVecEnd = _dateTimeVecVec.end(); - for (; itDateTimeVec != itDateTimeVecEnd; ++itDateTimeVec) delete *itDateTimeVec; + if (_dateTimeVecVec.size() > 0) + { + DateTimeVecVec::iterator itDateTimeVec = _dateTimeVecVec.begin(); + DateTimeVecVec::iterator itDateTimeVecEnd = _dateTimeVecVec.end(); + for (; itDateTimeVec != itDateTimeVecEnd; ++itDateTimeVec) delete *itDateTimeVec; + } + + if (_containers.size() > 0) + { + AnyPtrVecVec::iterator itAnyVec = _containers.begin(); + AnyPtrVecVec::iterator itAnyVecEnd = _containers.end(); + for (; itAnyVec != itAnyVecEnd; ++itAnyVec) + { + AnyPtrVec::iterator b = itAnyVec->begin(); + AnyPtrVec::iterator e = itAnyVec->end(); + for (; b != e; ++b) delete *b; + } + } } -void Binder::bind(std::size_t pos, const std::string& val, Direction dir) +void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& nullCb) { SQLPOINTER pVal = 0; SQLINTEGER size = (SQLINTEGER) val.size(); + SQLSMALLINT sqType = SQL_LONGVARCHAR; if (isOutBound(dir)) { getColumnOrParameterSize(pos, size); @@ -111,16 +182,20 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir) pVal = (SQLPOINTER) pChar; _outParams.insert(ParamMap::value_type(pVal, size)); _strings.insert(StringMap::value_type(pChar, const_cast<std::string*>(&val))); + if (size < _maxCharColLength) sqType = SQL_VARCHAR; } else if (isInBound(dir)) { pVal = (SQLPOINTER) val.c_str(); _inParams.insert(ParamMap::value_type(pVal, size)); + if (size < _maxCharColLength) sqType = SQL_VARCHAR; } else throw InvalidArgumentException("Parameter must be [in] OR [out] bound."); SQLLEN* pLenIn = new SQLLEN; + if (isOutBound(dir) && nullCb.defined()) + _nullCbMap.insert(NullCbMap::value_type( pLenIn, nullCb) ); SQLINTEGER colSize = 0; SQLSMALLINT decDigits = 0; getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits); @@ -135,7 +210,7 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir) (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_CHAR, - SQL_LONGVARCHAR, + sqType, (SQLUINTEGER) colSize, 0, pVal, @@ -147,13 +222,13 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir) } -void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir) +void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir, const WhenNullCb& nullCb) { typedef UTF16String::value_type CharT; SQLPOINTER pVal = 0; SQLINTEGER size = (SQLINTEGER)(val.size() * sizeof(CharT)); - + SQLSMALLINT sqType = (val.size() < _maxWCharColLength) ? SQL_WVARCHAR : SQL_WLONGVARCHAR; if (isOutBound(dir)) { getColumnOrParameterSize(pos, size); @@ -171,6 +246,9 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir) throw InvalidArgumentException("Parameter must be [in] OR [out] bound."); SQLLEN* pLenIn = new SQLLEN; + if (isOutBound(dir) && nullCb.defined()) + _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb)); + SQLINTEGER colSize = 0; SQLSMALLINT decDigits = 0; getColSizeAndPrecision(pos, SQL_C_WCHAR, colSize, decDigits); @@ -187,7 +265,7 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir) (SQLUSMALLINT)pos + 1, toODBCDirection(dir), SQL_C_WCHAR, - SQL_WLONGVARCHAR, + sqType, (SQLUINTEGER)colSize, 0, pVal, @@ -199,14 +277,14 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir) } -void Binder::bind(std::size_t pos, const Date& val, Direction dir) +void Binder::bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& nullCb) { - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_DATE_STRUCT); SQLLEN* pLenIn = new SQLLEN; - *pLenIn = size; + *pLenIn = SQL_NTS; // microsoft example does that, otherwise no null indicator is returned _lengthIndicator.push_back(pLenIn); - + if (isOutBound(dir) && nullCb.defined()) + _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb)); SQL_DATE_STRUCT* pDS = new SQL_DATE_STRUCT; Utility::dateSync(*pDS, val); @@ -232,11 +310,12 @@ void Binder::bind(std::size_t pos, const Date& val, Direction dir) } -void Binder::bind(std::size_t pos, const Time& val, Direction dir) +void Binder::bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& nullCb) { - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIME_STRUCT); SQLLEN* pLenIn = new SQLLEN; - *pLenIn = size; + *pLenIn = SQL_NTS; // microsoft example does that, otherwise no null indicator is returned + if (isOutBound(dir) && nullCb.defined()) + _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb)); _lengthIndicator.push_back(pLenIn); @@ -265,11 +344,12 @@ void Binder::bind(std::size_t pos, const Time& val, Direction dir) } -void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir, const WhenNullCb& nullCb) { - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIMESTAMP_STRUCT); SQLLEN* pLenIn = new SQLLEN; - *pLenIn = size; + *pLenIn = SQL_NTS; // microsoft example does that, otherwise no null indicator is returned + if (isOutBound(dir) && nullCb.defined()) + _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb)); _lengthIndicator.push_back(pLenIn); @@ -298,7 +378,7 @@ void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir) } -void Binder::bind(std::size_t pos, const NullData& val, Direction dir) +void Binder::bind(std::size_t pos, const NullData& val, Direction dir, const std::type_info& bindType) { if (isOutBound(dir) || !isInBound(dir)) throw NotImplementedException("NULL parameter type can only be inbound."); @@ -312,13 +392,16 @@ void Binder::bind(std::size_t pos, const NullData& val, Direction dir) SQLINTEGER colSize = 0; SQLSMALLINT decDigits = 0; - getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits); + + const SQLSMALLINT colType = (bindType == typeid(void) || bindType == typeid(NullData) || bindType == typeid(NullType)) ? + _pTypeInfo->nullDataType(val) : _pTypeInfo->tryTypeidToCType(bindType, SQL_C_TINYINT); + getColSizeAndPrecision(pos, colType, colSize, decDigits); if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT) pos + 1, SQL_PARAM_INPUT, - SQL_C_STINYINT, - Utility::sqlDataType(SQL_C_STINYINT), + colType, + Utility::sqlDataType(colType), colSize, decDigits, 0, @@ -342,7 +425,7 @@ std::size_t Binder::parameterSize(SQLPOINTER pAddr) const } -void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir) +void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir, const WhenNullCb& nullCb) { throw NotImplementedException("char* binding not implemented, Use std::string instead."); } @@ -364,6 +447,7 @@ SQLSMALLINT Binder::toODBCDirection(Direction dir) const void Binder::synchronize() { + if (_dates.size()) { DateMap::iterator it = _dates.begin(); @@ -395,26 +479,52 @@ void Binder::synchronize() for(; it != end; ++it) it->second->assign(it->first, std::strlen(it->first)); } + + if (_nullCbMap.size()) + { + NullCbMap::iterator it = _nullCbMap.begin(); + NullCbMap::iterator end = _nullCbMap.end(); + for (; it != end; ++it) + if (*it->first == SQL_NULL_DATA) it->second.onNull(); + } } void Binder::reset() { freeMemory(); - LengthPtrVec().swap(_lengthIndicator); - _inParams.clear(); - _outParams.clear(); - _dates.clear(); - _times.clear(); - _timestamps.clear(); - _strings.clear(); - _dateVecVec.clear(); - _timeVecVec.clear(); - _dateTimeVecVec.clear(); - _charPtrs.clear(); - _boolPtrs.clear(); - _containers.clear(); + + if (_lengthIndicator.size() > 0) + LengthPtrVec().swap(_lengthIndicator); + if (_inParams.size() > 0) + _inParams.clear(); + if (_outParams.size() > 0) + _outParams.clear(); + if (_dates.size() > 0) + _dates.clear(); + if (_times.size() > 0) + _times.clear(); + if (_timestamps.size() > 0) + _timestamps.clear(); + if (_strings.size() > 0) + _strings.clear(); + if (_dateVecVec.size() > 0) + _dateVecVec.clear(); + if (_timeVecVec.size() > 0) + _timeVecVec.clear(); + if (_dateTimeVecVec.size() > 0) + _dateTimeVecVec.clear(); + if (_charPtrs.size() > 0) + _charPtrs.clear(); + if (_boolPtrs.size() > 0) + _boolPtrs.clear(); + if (_containers.size() > 0) + _containers.clear(); + if (_nullCbMap.size() > 0) + _nullCbMap.clear(); _paramSetSize = 0; + if (!_insertOnly) + _parameters.clear(); } @@ -425,11 +535,11 @@ void Binder::getColSizeAndPrecision(std::size_t pos, { // Not all drivers are equally willing to cooperate in this matter. // Hence the funky flow control. - DynamicAny tmp; - bool found(false); + if (_pTypeInfo) { - found = _pTypeInfo->tryGetInfo(cDataType, "COLUMN_SIZE", tmp); + DynamicAny tmp; + bool found = _pTypeInfo->tryGetInfo(cDataType, "COLUMN_SIZE", tmp); if (found) colSize = tmp; found = _pTypeInfo->tryGetInfo(cDataType, "MINIMUM_SCALE", tmp); if (found) @@ -439,27 +549,34 @@ void Binder::getColSizeAndPrecision(std::size_t pos, } } - try + if (_parameters.size() <= pos || !_parameters[pos].defined()) { - Parameter p(_rStmt, pos); - colSize = (SQLINTEGER) p.columnSize(); - decDigits = (SQLSMALLINT) p.decimalDigits(); - return; - } catch (StatementException&) { } + if (_parameters.size() <= pos) + _parameters.resize(pos + 1); + _parameters[pos] = ParamDescriptor(0, cDataType, 0); - try - { - ODBCMetaColumn c(_rStmt, pos); - colSize = (SQLINTEGER) c.length(); - decDigits = (SQLSMALLINT) c.precision(); - return; - } catch (StatementException&) { } + try + { + { + Parameter p(_rStmt, pos); + _parameters[pos] = ParamDescriptor(static_cast<SQLINTEGER>(p.columnSize()), cDataType, static_cast<SQLSMALLINT>(p.decimalDigits())); + } + } + catch (StatementException&) + { + try + { + ODBCMetaColumn c(_rStmt, pos, _numericConversion); + _parameters[pos] = ParamDescriptor(static_cast<SQLINTEGER>(c.length()), cDataType, static_cast<SQLSMALLINT>(c.precision())); + } + catch (StatementException&) {} + } + } - // no success, set to zero and hope for the best + // we may have no success, so use zeros and hope for the best // (most drivers do not require these most of the times anyway) - colSize = 0; - decDigits = 0; - return; + colSize = _parameters[pos].colSize; + decDigits = _parameters[pos].decDigits; } @@ -470,7 +587,7 @@ void Binder::getColumnOrParameterSize(std::size_t pos, SQLINTEGER& size) try { - ODBCMetaColumn col(_rStmt, pos); + ODBCMetaColumn col(_rStmt, pos, _numericConversion); colSize = col.length(); } catch (StatementException&) { } @@ -486,10 +603,10 @@ void Binder::getColumnOrParameterSize(std::size_t pos, SQLINTEGER& size) //On Linux, PostgreSQL driver segfaults on SQLGetDescField, so this is disabled for now #ifdef POCO_OS_FAMILY_WINDOWS SQLHDESC hIPD = 0; - if (!Utility::isError(SQLGetStmtAttr(_rStmt, SQL_ATTR_IMP_PARAM_DESC, &hIPD, SQL_IS_POINTER, 0))) + if (!Utility::isError(Poco::Data::ODBC::SQLGetStmtAttr(_rStmt, SQL_ATTR_IMP_PARAM_DESC, &hIPD, SQL_IS_POINTER, 0))) { SQLUINTEGER sz = 0; - if (!Utility::isError(SQLGetDescField(hIPD, (SQLSMALLINT) pos + 1, SQL_DESC_LENGTH, &sz, SQL_IS_UINTEGER, 0)) && + if (!Utility::isError(Poco::Data::ODBC::SQLGetDescField(hIPD, (SQLSMALLINT)pos + 1, SQL_DESC_LENGTH, &sz, SQL_IS_UINTEGER, 0)) && sz > 0) { size = sz; diff --git a/Data/ODBC/src/ConnectionHandle.cpp b/Data/ODBC/src/ConnectionHandle.cpp index a4fed4884..e416c5c3b 100644 --- a/Data/ODBC/src/ConnectionHandle.cpp +++ b/Data/ODBC/src/ConnectionHandle.cpp @@ -25,12 +25,11 @@ namespace ODBC { ConnectionHandle::ConnectionHandle(EnvironmentHandle* pEnvironment): - _pEnvironment(pEnvironment ? pEnvironment : new EnvironmentHandle), - _hdbc(SQL_NULL_HDBC), - _ownsEnvironment(pEnvironment ? false : true) + _environment(pEnvironment ? &pEnvironment->handle() : 0), + _hdbc(SQL_NULL_HDBC) { if (Utility::isError(SQLAllocHandle(SQL_HANDLE_DBC, - _pEnvironment->handle(), + _environment.handle(), &_hdbc))) { throw ODBCException("Could not allocate connection handle."); @@ -42,12 +41,14 @@ ConnectionHandle::~ConnectionHandle() { try { - SQLDisconnect(_hdbc); - SQLRETURN rc = SQLFreeHandle(SQL_HANDLE_DBC, _hdbc); + if (_hdbc != SQL_NULL_HDBC) + { + SQLDisconnect(_hdbc); + SQLRETURN rc = SQLFreeHandle(SQL_HANDLE_DBC, _hdbc); + _hdbc = SQL_NULL_HDBC; - if (_ownsEnvironment) delete _pEnvironment; - - poco_assert (!Utility::isError(rc)); + poco_assert(!Utility::isError(rc)); + } } catch (...) { diff --git a/Data/ODBC/src/EnvironmentHandle.cpp b/Data/ODBC/src/EnvironmentHandle.cpp index f8c9b11f3..4dd4fd6b8 100644 --- a/Data/ODBC/src/EnvironmentHandle.cpp +++ b/Data/ODBC/src/EnvironmentHandle.cpp @@ -24,27 +24,46 @@ namespace Data { namespace ODBC { -EnvironmentHandle::EnvironmentHandle(): _henv(SQL_NULL_HENV) +EnvironmentHandle::EnvironmentHandle(): _henv(SQL_NULL_HENV), + _isOwner(false) { - if (Utility::isError(SQLAllocHandle(SQL_HANDLE_ENV, - SQL_NULL_HANDLE, - &_henv)) || - Utility::isError(SQLSetEnvAttr(_henv, - SQL_ATTR_ODBC_VERSION, - (SQLPOINTER) SQL_OV_ODBC3, - 0))) + init(); +} + +EnvironmentHandle::EnvironmentHandle(const SQLHENV* henv) : _henv(SQL_NULL_HENV), + _isOwner(false) +{ + if (!henv || *henv == SQL_NULL_HENV) + init(); + else + _henv = *henv; +} + +void EnvironmentHandle::init() +{ + if (Utility::isError(SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &_henv)) || + Utility::isError(SQLSetEnvAttr(_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER)SQL_OV_ODBC3, + 0))) { throw ODBCException("Could not initialize environment."); } + _isOwner = true; } - EnvironmentHandle::~EnvironmentHandle() { try { - SQLRETURN rc = SQLFreeHandle(SQL_HANDLE_ENV, _henv); - poco_assert (!Utility::isError(rc)); + if (_isOwner && _henv != SQL_NULL_HENV) + { + SQLRETURN rc = SQLFreeHandle(SQL_HANDLE_ENV, _henv); + _henv = SQL_NULL_HENV; + poco_assert(!Utility::isError(rc)); + } } catch (...) { diff --git a/Data/ODBC/src/Extractor.cpp b/Data/ODBC/src/Extractor.cpp index df394bd8d..b802fc6d0 100644 --- a/Data/ODBC/src/Extractor.cpp +++ b/Data/ODBC/src/Extractor.cpp @@ -352,18 +352,37 @@ bool Extractor::extractManualImpl<UTF16String>(std::size_t pos, UTF16String& val template<> -bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos, - Poco::Data::CLOB& val, +bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos, + Poco::Data::CLOB& val, + SQLSMALLINT cType) +{ + return extractManualLOBImpl(pos, val, cType); +} + + +template<> +bool Extractor::extractManualImpl<Poco::Data::BLOB>(std::size_t pos, + Poco::Data::BLOB& val, + SQLSMALLINT cType) +{ + return extractManualLOBImpl(pos, val, cType); +} + + +template<typename T> +bool Extractor::extractManualLOBImpl(std::size_t pos, + Poco::Data::LOB<T>& val, SQLSMALLINT cType) { std::size_t maxSize = _pPreparator->getMaxFieldSize(); - std::size_t fetchedSize = 0; + const int bufSize = CHUNK_SIZE; + std::size_t fetchedSize = bufSize; std::size_t totalSize = 0; SQLLEN len; - const int bufSize = CHUNK_SIZE; - Poco::Buffer<char> apChar(bufSize); - char* pChar = apChar.begin(); + + Poco::Buffer<T> apChar(bufSize); + T* pChar = apChar.begin(); SQLRETURN rc = 0; val.clear(); @@ -371,7 +390,9 @@ bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos, do { - std::memset(pChar, 0, bufSize); + // clear out the latest data in the buffer + if (fetchedSize > 0) + std::memset(pChar, 0, fetchedSize); len = 0; rc = SQLGetData(_rStmt, (SQLUSMALLINT) pos + 1, @@ -394,7 +415,7 @@ bool Extractor::extractManualImpl<Poco::Data::CLOB>(std::size_t pos, if (SQL_NO_DATA == rc || !len) break; - fetchedSize = len > CHUNK_SIZE ? CHUNK_SIZE : len; + fetchedSize = len > bufSize ? bufSize : len; totalSize += fetchedSize; if (totalSize <= maxSize) val.appendRaw(pChar, fetchedSize); diff --git a/Data/ODBC/src/ODBCMetaColumn.cpp b/Data/ODBC/src/ODBCMetaColumn.cpp index 2373a525f..871a33655 100644 --- a/Data/ODBC/src/ODBCMetaColumn.cpp +++ b/Data/ODBC/src/ODBCMetaColumn.cpp @@ -23,9 +23,10 @@ namespace Data { namespace ODBC { -ODBCMetaColumn::ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position) : + ODBCMetaColumn::ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position, NumericConversion numericConversion) : MetaColumn(position), - _rStmt(rStmt) + _rStmt(rStmt), + _numericConversion(numericConversion) { init(); } @@ -92,6 +93,7 @@ void ODBCMetaColumn::init() case SQL_WCHAR: case SQL_WVARCHAR: case SQL_WLONGVARCHAR: + case -350: // IBM DB2 CLOB, which long unicode string setType(MetaColumn::FDT_WSTRING); break; case SQL_TINYINT: @@ -112,12 +114,46 @@ void ODBCMetaColumn::init() case SQL_NUMERIC: case SQL_DECIMAL: - if (0 == _columnDesc.decimalDigits) - setType(MetaColumn::FDT_INT32); - else - setType(MetaColumn::FDT_DOUBLE); - - break; + { + bool toString = false; + switch (_numericConversion) + { + case NC_BEST_FIT: + case NC_BEST_FIT_DBL_LIMIT: + if (0 == _columnDesc.decimalDigits) + { + if (_columnDesc.size <= 9) + setType(MetaColumn::FDT_INT32); + else if (_columnDesc.size <= 18) + setType(MetaColumn::FDT_INT64); + else if (_numericConversion != NC_BEST_FIT_DBL_LIMIT) + toString = true; + else + setType(MetaColumn::FDT_DOUBLE); + } + else + { + // we can't have more than 16 digits in double, but we may be asked to + if (_columnDesc.size > 16 && _numericConversion != NC_BEST_FIT_DBL_LIMIT) + toString = true; + else + setType(MetaColumn::FDT_DOUBLE); + } + break; + case NC_FORCE_STRING: + toString = true; + } + if (toString) + { + setLength(_columnDesc.size + 4); +#if defined(UNICODE) + setType(MetaColumn::FDT_WSTRING); +#else + setType(MetaColumn::FDT_STRING); +#endif + } + } + break; case SQL_REAL: setType(MetaColumn::FDT_FLOAT); break; @@ -126,8 +162,12 @@ void ODBCMetaColumn::init() case SQL_VARBINARY: case SQL_LONGVARBINARY: case -98:// IBM DB2 non-standard type + case -370: // IBM DB2 XML, documentation advises to bind it as BLOB, not CLOB setType(MetaColumn::FDT_BLOB); break; - + + case -99: // IBM DB2 CLOB + setType(MetaColumn::FDT_CLOB); break; + case SQL_TYPE_DATE: setType(MetaColumn::FDT_DATE); break; diff --git a/Data/ODBC/src/ODBCStatementImpl.cpp b/Data/ODBC/src/ODBCStatementImpl.cpp index c4e507107..673578372 100644 --- a/Data/ODBC/src/ODBCStatementImpl.cpp +++ b/Data/ODBC/src/ODBCStatementImpl.cpp @@ -46,7 +46,10 @@ ODBCStatementImpl::ODBCStatementImpl(SessionImpl& rSession): _nextResponse(0), _prepared(false), _affectedRowCount(0), - _canCompile(true) + _canCompile(true), + _numericConversion(rSession.numericConversion()), + _isPostgres(false), + _insertHint(false) { int queryTimeout = rSession.queryTimeout(); if (queryTimeout >= 0) @@ -57,6 +60,15 @@ ODBCStatementImpl::ODBCStatementImpl(SessionImpl& rSession): (SQLPOINTER) uqt, 0); } + SQLSMALLINT t; + SQLRETURN r = Poco::Data::ODBC::SQLGetInfo(_rConnection, SQL_DRIVER_NAME, NULL, 0, &t); + if (!Utility::isError(r) && t > 0) + { + std::string serverString; + serverString.resize(static_cast<std::size_t>(t) + 2); + r = Poco::Data::ODBC::SQLGetInfo(_rConnection, SQL_DRIVER_NAME, &serverString[0], SQLSMALLINT((serverString.length() - 1) * sizeof(serverString[0])), &t); + _isPostgres = (!Utility::isError(r) && Poco::toUpperInPlace(serverString).find("PSQLODBC") == 0); + } } @@ -95,14 +107,15 @@ void ODBCStatementImpl::compileImpl() pDT = AnyCast<TypeInfo*>(dti); }catch (NotSupportedException&) { } - std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize")); + const std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize")); + const ODBCMetaColumn::NumericConversion numericConversion = dynamic_cast<SessionImpl&>(session()).numericConversion(); - _pBinder = new Binder(_stmt, maxFieldSize, bind, pDT); + _pBinder = new Binder(_stmt, maxFieldSize, bind, pDT, numericConversion, _insertHint); makeInternalExtractors(); doPrepare(); - _canCompile = false; + _canCompile = false; } @@ -112,7 +125,7 @@ void ODBCStatementImpl::makeInternalExtractors() { try { - fillColumns(); + fillColumns(currentDataSet()); } catch (DataFormatException&) { if (isStoredProcedure()) return; @@ -125,25 +138,34 @@ void ODBCStatementImpl::makeInternalExtractors() } -void ODBCStatementImpl::addPreparator() +bool ODBCStatementImpl::addPreparator(bool addAlways) { + Preparator* prep = 0; if (0 == _preparations.size()) { std::string statement(toString()); if (statement.empty()) throw ODBCException("Empty statements are illegal"); - Preparator::DataExtraction ext = session().getFeature("autoExtract") ? + Preparator::DataExtraction ext = session().getFeature("autoExtract") ? Preparator::DE_BOUND : Preparator::DE_MANUAL; std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize")); - _preparations.push_back(new Preparator(_stmt, statement, maxFieldSize, ext)); + prep = new Preparator(_stmt, statement, maxFieldSize, ext, _numericConversion, _isPostgres); } else - _preparations.push_back(new Preparator(*_preparations[0])); + prep = new Preparator(*_preparations[0]); + if (addAlways || prep->columns() > 0) + { + _preparations.push_back(prep); + _extractors.push_back(new Extractor(_stmt, _preparations.back())); - _extractors.push_back(new Extractor(_stmt, _preparations.back())); + return true; + } + + delete prep; + return false; } @@ -214,7 +236,6 @@ void ODBCStatementImpl::doBind() void ODBCStatementImpl::bindImpl() { doBind(); - SQLRETURN rc = SQLExecute(_stmt); if (SQL_NEED_DATA == rc) putData(); @@ -279,6 +300,24 @@ void ODBCStatementImpl::clear() } } +bool ODBCStatementImpl::nextResultSet() +{ + SQLRETURN ret = SQLMoreResults(_stmt); + + if (SQL_NO_DATA == ret) + return false; + + if (Utility::isError(ret)) { + throw StatementException(_stmt, "SQLMoreResults()"); + } + + // need to remove old bindings, as Sybase doesn't like old ones + if (Utility::isError(SQLFreeStmt(_stmt, SQL_UNBIND))) { + throw StatementException(_stmt, "SQLFreeStmt(SQL_UNBIND)"); + } + return true; +} + bool ODBCStatementImpl::hasNext() { @@ -296,17 +335,29 @@ bool ODBCStatementImpl::hasNext() if (!nextRowReady()) { - if (hasMoreDataSets()) activateNextDataSet(); - else return false; - - if (SQL_NO_DATA == SQLMoreResults(_stmt)) - return false; - - addPreparator(); - doPrepare(); - fixupExtraction(); - makeStep(); - } + // have a loop here, as there could be one or more empty results + do { + if (hasMoreDataSets()) { + activateNextDataSet(); + if (!nextResultSet()) + return false; + addPreparator(); + } + else { + if (nextResultSet()) { + if (!addPreparator(false)) // skip the result set if it has no columns + continue; + fillColumns(currentDataSet() + 1); + makeExtractors(_preparations.back()->columns(), static_cast<Position::PositionType>(currentDataSet() + 1)); + activateNextDataSet(); + } + else return false; + } + doPrepare(); + fixupExtraction(); + makeStep(); + } while (!nextRowReady()); + } else if (Utility::isError(_nextResponse)) checkError(_nextResponse, "SQLFetch()"); @@ -405,15 +456,16 @@ void ODBCStatementImpl::checkError(SQLRETURN rc, const std::string& msg) } -void ODBCStatementImpl::fillColumns() +void ODBCStatementImpl::fillColumns(size_t dataSetPos) { - std::size_t colCount = columnsReturned(); - std::size_t curDataSet = currentDataSet(); - if (curDataSet >= _columnPtrs.size()) - _columnPtrs.resize(curDataSet + 1); + poco_assert_dbg(dataSetPos < _preparations.size()); + poco_assert_dbg(_preparations[dataSetPos]); + std::size_t colCount = static_cast<std::size_t>(_preparations[dataSetPos]->columns()); + if (dataSetPos >= _columnPtrs.size()) + _columnPtrs.resize(dataSetPos + 1); for (int i = 0; i < colCount; ++i) - _columnPtrs[curDataSet].push_back(new ODBCMetaColumn(_stmt, i)); + _columnPtrs[dataSetPos].push_back(new ODBCMetaColumn(_stmt, i, _numericConversion)); } @@ -426,17 +478,16 @@ bool ODBCStatementImpl::isStoredProcedure() const } -const MetaColumn& ODBCStatementImpl::metaColumn(std::size_t pos) const +const MetaColumn& ODBCStatementImpl::metaColumn(std::size_t pos, size_t dataSet) const { - std::size_t curDataSet = currentDataSet(); - poco_assert_dbg (curDataSet < _columnPtrs.size()); + poco_assert_dbg(dataSet < _columnPtrs.size()); - std::size_t sz = _columnPtrs[curDataSet].size(); + std::size_t sz = _columnPtrs[dataSet].size(); if (0 == sz || pos > sz - 1) throw InvalidAccessException(format("Invalid column number: %u", pos)); - return *_columnPtrs[curDataSet][pos]; + return *_columnPtrs[dataSet][pos]; } @@ -453,4 +504,10 @@ int ODBCStatementImpl::affectedRowCount() const } +void ODBCStatementImpl::insertHint() +{ + _insertHint = true; +} + + } } } // namespace Poco::Data::ODBC diff --git a/Data/ODBC/src/Preparator.cpp b/Data/ODBC/src/Preparator.cpp index 11560e3d2..c7645cf86 100644 --- a/Data/ODBC/src/Preparator.cpp +++ b/Data/ODBC/src/Preparator.cpp @@ -30,21 +30,35 @@ namespace ODBC { Preparator::Preparator(const StatementHandle& rStmt, const std::string& statement, std::size_t maxFieldSize, - DataExtraction dataExtraction): + DataExtraction dataExtraction, + ODBCMetaColumn::NumericConversion numericConversion, + bool isPostgres) : _rStmt(rStmt), _maxFieldSize(maxFieldSize), - _dataExtraction(dataExtraction) + _dataExtraction(dataExtraction), + _numericConversion(numericConversion) { SQLCHAR* pStr = (SQLCHAR*) statement.c_str(); if (Utility::isError(Poco::Data::ODBC::SQLPrepare(_rStmt, pStr, (SQLINTEGER) statement.length()))) throw StatementException(_rStmt); + // PostgreSQL error swallowing workaround: + // Postgres may execute a statement with sintax error fine, + // but would return error once num of columns requested! + if (isPostgres) + { + SQLSMALLINT t = 0; + SQLRETURN r = SQLNumResultCols(rStmt, &t); + if (r != SQL_NO_DATA && Utility::isError(r)) + throw StatementException(rStmt, "Failed to get number of columns"); + } } Preparator::Preparator(const Preparator& other): _rStmt(other._rStmt), _maxFieldSize(other._maxFieldSize), - _dataExtraction(other._dataExtraction) + _dataExtraction(other._dataExtraction), + _numericConversion(other._numericConversion) { resize(); } @@ -155,7 +169,7 @@ std::size_t Preparator::maxDataSize(std::size_t pos) const try { - ODBCMetaColumn mc(_rStmt, pos); + ODBCMetaColumn mc(_rStmt, pos, _numericConversion); sz = mc.length(); // accommodate for terminating zero (non-bulk only!) diff --git a/Data/ODBC/src/SessionImpl.cpp b/Data/ODBC/src/SessionImpl.cpp index 4e7647b95..cc4bc9580 100644 --- a/Data/ODBC/src/SessionImpl.cpp +++ b/Data/ODBC/src/SessionImpl.cpp @@ -29,6 +29,8 @@ namespace Data { namespace ODBC { +const char* const SessionImpl::NUMERIC_CONVERSION_PROPERTY= "numericConversion"; + SessionImpl::SessionImpl(const std::string& connect, std::size_t loginTimeout, std::size_t maxFieldSize, @@ -39,13 +41,12 @@ SessionImpl::SessionImpl(const std::string& connect, _maxFieldSize(maxFieldSize), _autoBind(autoBind), _autoExtract(autoExtract), + _numericConversion(ODBCMetaColumn::NC_BEST_FIT), _canTransact(ODBC_TXN_CAPABILITY_UNKNOWN), _inTransaction(false), _queryTimeout(-1) { - setFeature("bulk", true); - open(); - setProperty("handle", _db.handle()); + init(); } @@ -62,6 +63,15 @@ SessionImpl::SessionImpl(const std::string& connect, _inTransaction(false), _queryTimeout(-1) { + init(); +} + + +void SessionImpl::init() +{ + addProperty(NUMERIC_CONVERSION_PROPERTY, + &SessionImpl::setNumericConversion, + &SessionImpl::numericConversion); setFeature("bulk", true); open(); setProperty("handle", _db.handle()); @@ -72,7 +82,7 @@ SessionImpl::~SessionImpl() { try { - if (isTransaction() && !getFeature("autoCommit")) + if (static_cast<bool>(_db) && isTransaction() && !getFeature("autoCommit")) { try { rollback(); } catch (...) { } @@ -107,13 +117,13 @@ void SessionImpl::open(const std::string& connect) poco_assert_dbg (!connectionString().empty()); SQLULEN tout = static_cast<SQLULEN>(getLoginTimeout()); - if (Utility::isError(SQLSetConnectAttr(_db, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) tout, 0))) + if (Utility::isError(Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)tout, 0))) { - if (Utility::isError(SQLGetConnectAttr(_db, SQL_ATTR_LOGIN_TIMEOUT, &tout, 0, 0)) || + if (Utility::isError(Poco::Data::ODBC::SQLGetConnectAttr(_db, SQL_ATTR_LOGIN_TIMEOUT, &tout, 0, 0)) || getLoginTimeout() != tout) { - ConnectionError e(_db); - throw ConnectionFailedException(e.toString()); + ConnectionException e(_db); + throw ConnectionFailedException(e.errorString(), e); } } @@ -129,10 +139,9 @@ void SessionImpl::open(const std::string& connect) , &result , SQL_DRIVER_NOPROMPT))) { - ConnectionError err(_db); - std::string errStr = err.toString(); + ConnectionException e(_db); close(); - throw ConnectionFailedException(errStr); + throw ConnectionFailedException(e.errorString(), e); } _dataTypes.fillTypeInfo(_db); @@ -171,7 +180,7 @@ bool SessionImpl::isConnected() { SQLULEN value = 0; - if (Utility::isError(Poco::Data::ODBC::SQLGetConnectAttr(_db, + if (!static_cast<bool>(_db) || Utility::isError(Poco::Data::ODBC::SQLGetConnectAttr(_db, SQL_ATTR_CONNECTION_DEAD, &value, 0, @@ -211,12 +220,18 @@ bool SessionImpl::canTransact() if (ODBC_TXN_CAPABILITY_UNKNOWN == _canTransact) { SQLUSMALLINT ret; - checkError(Poco::Data::ODBC::SQLGetInfo(_db, SQL_TXN_CAPABLE, &ret, 0, 0), - "Failed to obtain transaction capability info."); - - _canTransact = (SQL_TC_NONE != ret) ? - ODBC_TXN_CAPABILITY_TRUE : - ODBC_TXN_CAPABILITY_FALSE; + SQLRETURN res = Poco::Data::ODBC::SQLGetInfo(_db, SQL_TXN_CAPABLE, &ret, 0, 0); + if (!Utility::isError(res)) + { + _canTransact = (SQL_TC_NONE != ret) ? + ODBC_TXN_CAPABILITY_TRUE : + ODBC_TXN_CAPABILITY_FALSE; + } + else + { + Error<SQLHDBC, SQL_HANDLE_DBC> err(_db); + _canTransact = ODBC_TXN_CAPABILITY_FALSE; + } } return ODBC_TXN_CAPABILITY_TRUE == _canTransact; @@ -239,14 +254,14 @@ void SessionImpl::setTransactionIsolation(Poco::UInt32 ti) if (ti & Session::TRANSACTION_SERIALIZABLE) isolation |= SQL_TXN_SERIALIZABLE; - checkError(SQLSetConnectAttr(_db, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER) isolation, 0)); + checkError(Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER)isolation, 0)); } Poco::UInt32 SessionImpl::getTransactionIsolation() { SQLULEN isolation = 0; - checkError(SQLGetConnectAttr(_db, SQL_ATTR_TXN_ISOLATION, + checkError(Poco::Data::ODBC::SQLGetConnectAttr(_db, SQL_ATTR_TXN_ISOLATION, &isolation, 0, 0)); @@ -271,7 +286,7 @@ bool SessionImpl::hasTransactionIsolation(Poco::UInt32 ti) Poco::UInt32 SessionImpl::getDefaultTransactionIsolation() { SQLUINTEGER isolation = 0; - checkError(SQLGetInfo(_db, SQL_DEFAULT_TXN_ISOLATION, + checkError(Poco::Data::ODBC::SQLGetInfo(_db, SQL_DEFAULT_TXN_ISOLATION, &isolation, 0, 0)); diff --git a/Data/ODBC/src/TypeInfo.cpp b/Data/ODBC/src/TypeInfo.cpp index 25809b4fa..bcb558c7c 100644 --- a/Data/ODBC/src/TypeInfo.cpp +++ b/Data/ODBC/src/TypeInfo.cpp @@ -16,6 +16,7 @@ #include "Poco/Data/ODBC/TypeInfo.h" #include "Poco/Data/ODBC/ODBCException.h" +#include "Poco/Data/LOB.h" #include "Poco/Format.h" #include "Poco/Exception.h" #include <iostream> @@ -30,6 +31,17 @@ TypeInfo::TypeInfo(SQLHDBC* pHDBC): _pHDBC(pHDBC) fillCTypes(); fillSQLTypes(); if (_pHDBC) fillTypeInfo(*_pHDBC); + + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(std::string), SQL_C_CHAR)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(std::wstring), SQL_C_WCHAR)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(Poco::UTF16String), SQL_C_WCHAR)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(Date), SQL_TYPE_DATE)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(Time), SQL_TYPE_TIME)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(DateTime), SQL_TYPE_TIMESTAMP)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(BLOB), SQL_BINARY)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(float), SQL_REAL)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(double), SQL_DOUBLE)); + _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(bool), SQL_BIT)); } @@ -102,7 +114,7 @@ void TypeInfo::fillTypeInfo(SQLHDBC pHDBC) if (!SQL_SUCCEEDED(rc)) throw StatementException(hstmt, "SQLGetData()"); - rc = SQLGetTypeInfo(hstmt, SQL_ALL_TYPES); + rc = Poco::Data::ODBC::SQLGetTypeInfo(hstmt, SQL_ALL_TYPES); if (SQL_SUCCEEDED(rc)) { while (SQLFetch(hstmt) != SQL_NO_DATA_FOUND) @@ -264,4 +276,43 @@ void TypeInfo::print(std::ostream& ostr) } +SQLSMALLINT TypeInfo::tryTypeidToCType(const std::type_info& ti, SQLSMALLINT defaultVal) const +{ + CppTypeInfoMap::const_iterator res = _cppDataTypes.find(&ti); + if (res == _cppDataTypes.end()) + return defaultVal; + return res->second; +} + + +SQLSMALLINT TypeInfo::nullDataType(const NullData val) const +{ + switch (val) + { + case NULL_GENERIC: + case DATA_NULL_INTEGER: + return SQL_C_TINYINT; + + case DATA_NULL_STRING: + return SQL_C_CHAR; + + case DATA_NULL_DATE: + return SQL_C_TYPE_DATE; + + case DATA_NULL_TIME: + return SQL_C_TYPE_TIME; + + case DATA_NULL_DATETIME: + return SQL_C_TYPE_TIMESTAMP; + + case DATA_NULL_BLOB: + return SQL_C_BINARY; + + case DATA_NULL_FLOAT: + return SQL_C_FLOAT; + } + + return SQL_C_TINYINT; +} + } } } // namespace Poco::Data::ODBC diff --git a/Data/ODBC/src/Unicode_UNIXODBC.cpp b/Data/ODBC/src/Unicode_UNIXODBC.cpp index 4b7231d27..9dc87ecca 100644 --- a/Data/ODBC/src/Unicode_UNIXODBC.cpp +++ b/Data/ODBC/src/Unicode_UNIXODBC.cpp @@ -31,6 +31,7 @@ using Poco::TextConverter; using Poco::InvalidArgumentException; using Poco::NotImplementedException; +#ifdef POCO_ODBC_UNICODE namespace Poco { namespace Data { @@ -775,3 +776,4 @@ SQLRETURN SQLDrivers(SQLHENV henv, } } } // namespace Poco::Data::ODBC +#endif diff --git a/Data/ODBC/src/Utility.cpp b/Data/ODBC/src/Utility.cpp index 74b61a2cd..e6e8fb835 100644 --- a/Data/ODBC/src/Utility.cpp +++ b/Data/ODBC/src/Utility.cpp @@ -43,7 +43,7 @@ Utility::DriverMap& Utility::drivers(Utility::DriverMap& driverMap) SQLSMALLINT len2 = length; RETCODE rc = 0; - if (!Utility::isError(rc = SQLDrivers(henv, + if (!Utility::isError(rc = Poco::Data::ODBC::SQLDrivers(henv, SQL_FETCH_FIRST, desc, length, @@ -59,7 +59,7 @@ Utility::DriverMap& Utility::drivers(Utility::DriverMap& driverMap) std::memset(desc, 0, length); std::memset(attr, 0, length); len2 = length; - }while (!Utility::isError(rc = SQLDrivers(henv, + }while (!Utility::isError(rc = Poco::Data::ODBC::SQLDrivers(henv, SQL_FETCH_NEXT, desc, length, diff --git a/Data/ODBC/testsuite/Makefile b/Data/ODBC/testsuite/Makefile index b50776cb3..2eacd766f 100644 --- a/Data/ODBC/testsuite/Makefile +++ b/Data/ODBC/testsuite/Makefile @@ -29,7 +29,7 @@ endif objects = ODBCTestSuite Driver \ ODBCDB2Test ODBCMySQLTest ODBCOracleTest ODBCPostgreSQLTest \ - ODBCSQLiteTest ODBCSQLServerTest ODBCTest SQLExecutor + ODBCSQLiteTest ODBCSQLServerTest ODBCTest SQLExecutor ODBCSybaseTest ifeq ($(POCO_CONFIG),MinGW) objects += ODBCAccessTest diff --git a/Data/ODBC/testsuite/TestSuite_vs120.vcxproj b/Data/ODBC/testsuite/TestSuite_vs120.vcxproj index f9e88a477..7c913d23d 100644 --- a/Data/ODBC/testsuite/TestSuite_vs120.vcxproj +++ b/Data/ODBC/testsuite/TestSuite_vs120.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="UTF-8"?> <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="debug_shared|Win32"> @@ -129,7 +129,7 @@ <AdditionalIncludeDirectories>..\include;..\..\..\CppUnit\include;..\..\..\CppUnit\WinTestRunner\include;..\..\..\Foundation\include;..\..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -140,6 +140,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitd.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -189,7 +190,7 @@ <AdditionalIncludeDirectories>..\include;..\..\..\CppUnit\include;..\..\..\CppUnit\WinTestRunner\include;..\..\..\Foundation\include;..\..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -200,6 +201,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmtd.lib;iphlpapi.lib;winmm.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -249,7 +251,7 @@ <AdditionalIncludeDirectories>..\include;..\..\..\CppUnit\include;..\..\..\CppUnit\WinTestRunner\include;..\..\..\Foundation\include;..\..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -260,6 +262,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmdd.lib;iphlpapi.lib;winmm.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -314,6 +317,7 @@ <ClInclude Include="src\ODBCTest.h"/> <ClInclude Include="src\ODBCTestSuite.h"/> <ClInclude Include="src\SQLExecutor.h"/> + <ClInclude Include="src\ODBCSybaseTest.h"/> </ItemGroup> <ItemGroup> <ClCompile Include="src\Driver.cpp"/> @@ -327,6 +331,7 @@ <ClCompile Include="src\ODBCTest.cpp"/> <ClCompile Include="src\ODBCTestSuite.cpp"/> <ClCompile Include="src\SQLExecutor.cpp"/> + <ClCompile Include="src\ODBCSybaseTest.cpp"/> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> <ImportGroup Label="ExtensionTargets"/> diff --git a/Data/ODBC/testsuite/TestSuite_vs120.vcxproj.filters b/Data/ODBC/testsuite/TestSuite_vs120.vcxproj.filters index a3621f42b..46783ebeb 100644 --- a/Data/ODBC/testsuite/TestSuite_vs120.vcxproj.filters +++ b/Data/ODBC/testsuite/TestSuite_vs120.vcxproj.filters @@ -54,8 +54,11 @@ <ClInclude Include="src\SQLExecutor.h"> <Filter>ODBC\Header Files</Filter> </ClInclude> + <ClInclude Include="src\ODBCSybaseTest.h"> + <Filter>ODBC\Header Files</Filter> + </ClInclude> <ClInclude Include="src\ODBCTestSuite.h"> - <Filter>_Suite\Header Files</Filter> + <Filter>ODBC\Header Files</Filter> </ClInclude> </ItemGroup> <ItemGroup> @@ -92,5 +95,8 @@ <ClCompile Include="src\Driver.cpp"> <Filter>_Driver\Source Files</Filter> </ClCompile> + <ClCompile Include="src\ODBCSybaseTest.cpp"> + <Filter>ODBC\Source Files</Filter> + </ClCompile> </ItemGroup> </Project> \ No newline at end of file diff --git a/Data/ODBC/testsuite/TestSuite_x64_vs110.vcxproj b/Data/ODBC/testsuite/TestSuite_x64_vs110.vcxproj index 627c2340d..ce9eeaf29 100644 --- a/Data/ODBC/testsuite/TestSuite_x64_vs110.vcxproj +++ b/Data/ODBC/testsuite/TestSuite_x64_vs110.vcxproj @@ -322,6 +322,7 @@ <ClInclude Include="src\ODBCTest.h"/> <ClInclude Include="src\SQLExecutor.h"/> <ClInclude Include="src\ODBCTestSuite.h"/> + <ClInclude Include="src\ODBCSybaseTest.h"/> </ItemGroup> <ItemGroup> <ClCompile Include="src\ODBCAccessTest.cpp"/> @@ -334,6 +335,7 @@ <ClCompile Include="src\ODBCTest.cpp"/> <ClCompile Include="src\SQLExecutor.cpp"/> <ClCompile Include="src\ODBCTestSuite.cpp"/> + <ClCompile Include="src\/ODBCSybaseTest.cpp"/> <ClCompile Include="src\WinDriver.cpp"/> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> diff --git a/Data/ODBC/testsuite/TestSuite_x64_vs120.vcxproj b/Data/ODBC/testsuite/TestSuite_x64_vs120.vcxproj index 5c87ec804..648e126f0 100644 --- a/Data/ODBC/testsuite/TestSuite_x64_vs120.vcxproj +++ b/Data/ODBC/testsuite/TestSuite_x64_vs120.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="debug_shared|x64"> @@ -32,7 +32,7 @@ <RootNamespace>TestSuite</RootNamespace> <Keyword>Win32Proj</Keyword> </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> @@ -63,27 +63,27 @@ <CharacterSet>MultiByte</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/> - <ImportGroup Label="ExtensionSettings"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings" /> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_md|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_shared|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'" Label="PropertySheets"> - <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" /> </ImportGroup> - <PropertyGroup Label="UserMacros"/> + <PropertyGroup Label="UserMacros" /> <PropertyGroup> <_ProjectFileVersion>12.0.30501.0</_ProjectFileVersion> <TargetName Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'">TestSuited</TargetName> @@ -129,17 +129,18 @@ <AdditionalIncludeDirectories>..\include;..\..\..\CppUnit\include;..\..\..\CppUnit\WinTestRunner\include;..\..\..\Foundation\include;..\..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitd.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -167,10 +168,11 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnit.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -189,17 +191,18 @@ <AdditionalIncludeDirectories>..\include;..\..\..\CppUnit\include;..\..\..\CppUnit\WinTestRunner\include;..\..\..\Foundation\include;..\..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmtd.lib;iphlpapi.lib;winmm.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -227,10 +230,11 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmt.lib;iphlpapi.lib;winmm.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -249,17 +253,18 @@ <AdditionalIncludeDirectories>..\include;..\..\..\CppUnit\include;..\..\..\CppUnit\WinTestRunner\include;..\..\..\Foundation\include;..\..\..\Data\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmdd.lib;iphlpapi.lib;winmm.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -287,10 +292,11 @@ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> - <PrecompiledHeader/> + <PrecompiledHeader /> <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat/> + <DebugInformationFormat /> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmd.lib;iphlpapi.lib;winmm.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -304,30 +310,32 @@ </Link> </ItemDefinitionGroup> <ItemGroup> - <ClInclude Include="src\ODBCAccessTest.h"/> - <ClInclude Include="src\ODBCDB2Test.h"/> - <ClInclude Include="src\ODBCMySQLTest.h"/> - <ClInclude Include="src\ODBCOracleTest.h"/> - <ClInclude Include="src\ODBCPostgreSQLTest.h"/> - <ClInclude Include="src\ODBCSQLiteTest.h"/> - <ClInclude Include="src\ODBCSQLServerTest.h"/> - <ClInclude Include="src\ODBCTest.h"/> - <ClInclude Include="src\ODBCTestSuite.h"/> - <ClInclude Include="src\SQLExecutor.h"/> + <ClInclude Include="src\ODBCAccessTest.h" /> + <ClInclude Include="src\ODBCDB2Test.h" /> + <ClInclude Include="src\ODBCMySQLTest.h" /> + <ClInclude Include="src\ODBCOracleTest.h" /> + <ClInclude Include="src\ODBCPostgreSQLTest.h" /> + <ClInclude Include="src\ODBCSQLiteTest.h" /> + <ClInclude Include="src\ODBCSQLServerTest.h" /> + <ClInclude Include="src\ODBCTest.h" /> + <ClInclude Include="src\ODBCTestSuite.h" /> + <ClInclude Include="src\SQLExecutor.h" /> + <ClInclude Include="src\ODBCSybaseTest.h" /> </ItemGroup> <ItemGroup> - <ClCompile Include="src\Driver.cpp"/> - <ClCompile Include="src\ODBCAccessTest.cpp"/> - <ClCompile Include="src\ODBCDB2Test.cpp"/> - <ClCompile Include="src\ODBCMySQLTest.cpp"/> - <ClCompile Include="src\ODBCOracleTest.cpp"/> - <ClCompile Include="src\ODBCPostgreSQLTest.cpp"/> - <ClCompile Include="src\ODBCSQLiteTest.cpp"/> - <ClCompile Include="src\ODBCSQLServerTest.cpp"/> - <ClCompile Include="src\ODBCTest.cpp"/> - <ClCompile Include="src\ODBCTestSuite.cpp"/> - <ClCompile Include="src\SQLExecutor.cpp"/> + <ClCompile Include="src\Driver.cpp" /> + <ClCompile Include="src\ODBCAccessTest.cpp" /> + <ClCompile Include="src\ODBCDB2Test.cpp" /> + <ClCompile Include="src\ODBCMySQLTest.cpp" /> + <ClCompile Include="src\ODBCOracleTest.cpp" /> + <ClCompile Include="src\ODBCPostgreSQLTest.cpp" /> + <ClCompile Include="src\ODBCSQLiteTest.cpp" /> + <ClCompile Include="src\ODBCSQLServerTest.cpp" /> + <ClCompile Include="src\ODBCTest.cpp" /> + <ClCompile Include="src\ODBCTestSuite.cpp" /> + <ClCompile Include="src\SQLExecutor.cpp" /> + <ClCompile Include="src\ODBCSybaseTest.cpp" /> </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> - <ImportGroup Label="ExtensionTargets"/> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets" /> </Project> diff --git a/Data/ODBC/testsuite/TestSuite_x64_vs120.vcxproj.filters b/Data/ODBC/testsuite/TestSuite_x64_vs120.vcxproj.filters index 7198f6d74..54c41d629 100644 --- a/Data/ODBC/testsuite/TestSuite_x64_vs120.vcxproj.filters +++ b/Data/ODBC/testsuite/TestSuite_x64_vs120.vcxproj.filters @@ -57,6 +57,9 @@ <ClInclude Include="src\ODBCTestSuite.h"> <Filter>_Suite\Header Files</Filter> </ClInclude> + <ClInclude Include="src\ODBCSybaseTest.h"> + <Filter>ODBC\Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="src\ODBCAccessTest.cpp"> @@ -89,8 +92,14 @@ <ClCompile Include="src\ODBCTestSuite.cpp"> <Filter>_Suite\Source Files</Filter> </ClCompile> + <ClCompile Include="src\ODBCSybaseTest.cpp"> + <Filter>_Suite\Source Files</Filter> + </ClCompile> <ClCompile Include="src\Driver.cpp"> <Filter>_Driver\Source Files</Filter> </ClCompile> + <ClCompile Include="src\ODBCSybaseTest.cpp"> + <Filter>ODBC\Source Files</Filter> + </ClCompile> </ItemGroup> </Project> \ No newline at end of file diff --git a/Data/ODBC/testsuite/src/ODBCAccessTest.cpp b/Data/ODBC/testsuite/src/ODBCAccessTest.cpp index c09f00bd8..2444273e9 100644 --- a/Data/ODBC/testsuite/src/ODBCAccessTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCAccessTest.cpp @@ -114,8 +114,8 @@ void ODBCAccessTest::dropTable(const std::string& tableName) void ODBCAccessTest::recreatePersonTable() { - dropTable("Person"); - *_pSession << "CREATE TABLE Person (LastName TEXT(30), FirstName TEXT(30), Address TEXT(30), Age INTEGER)", now; + dropTable(ExecUtil::person()); + *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName TEXT(30), FirstName TEXT(30), Address TEXT(30), Age INTEGER)", now; } @@ -176,7 +176,7 @@ void ODBCAccessTest::setUp() void ODBCAccessTest::tearDown() { - dropTable("Person"); + dropTable(ExecUtil::person()); } diff --git a/Data/ODBC/testsuite/src/ODBCDB2Test.cpp b/Data/ODBC/testsuite/src/ODBCDB2Test.cpp index dc4078eb4..39ee880ac 100644 --- a/Data/ODBC/testsuite/src/ODBCDB2Test.cpp +++ b/Data/ODBC/testsuite/src/ODBCDB2Test.cpp @@ -21,11 +21,13 @@ #include "Poco/Exception.h" #include "Poco/Data/LOB.h" #include "Poco/Data/StatementImpl.h" +#include "Poco/Data/RecordSet.h" #include "Poco/Data/ODBC/Connector.h" #include "Poco/Data/ODBC/Utility.h" #include "Poco/Data/ODBC/Diagnostics.h" #include "Poco/Data/ODBC/ODBCException.h" #include "Poco/Data/ODBC/ODBCStatementImpl.h" +#include "Poco/Environment.h" #include <sqltypes.h> #include <iostream> @@ -43,29 +45,58 @@ using Poco::AnyCast; using Poco::DynamicAny; using Poco::NotFoundException; +static std::string db2Driver() +{ + return Poco::Environment::get("POCO_TEST_DB2_DRIVER", +#if defined(POCO_OS_FAMILY_WINDOWS) + "IBM DB2 ODBC DRIVER - DB2COPY1" +#else + "libdb2o.so" +#endif + ); +} + +static std::string db2Uid() +{ + return Poco::Environment::get("POCO_TEST_DB2_UID", "db2admin"); +} + +static std::string db2Db() +{ + return Poco::Environment::get("POCO_TEST_DB2_DB", "POCOTEST"); +} + +static std::string db2Pwd() +{ + return Poco::Environment::get("POCO_TEST_DB2_PWD", "db2admin"); +} + +static std::string db2Extra() +{ + std::string e = Poco::Environment::get("POCO_TEST_DB2_EXTRA", ""); + return (e.empty() ? "" : e + ";"); +} -#define DB2_ODBC_DRIVER "IBM DB2 ODBC DRIVER - DB2COPY1" #define DB2_DSN "PocoDataDB2Test" #define DB2_SERVER POCO_ODBC_TEST_DATABASE_SERVER #define DB2_PORT "50000" -#define DB2_DB "POCOTEST" -#define DB2_UID "db2admin" -#define DB2_PWD "db2admin" ODBCTest::SessionPtr ODBCDB2Test::_pSession; ODBCTest::ExecPtr ODBCDB2Test::_pExecutor; -std::string ODBCDB2Test::_driver = DB2_ODBC_DRIVER; +std::string ODBCDB2Test::_driver = db2Driver(); std::string ODBCDB2Test::_dsn = DB2_DSN; -std::string ODBCDB2Test::_uid = DB2_UID; -std::string ODBCDB2Test::_pwd = DB2_PWD; -std::string ODBCDB2Test::_connectString = "Driver=" DB2_ODBC_DRIVER ";" - "Database=" DB2_DB ";" +std::string ODBCDB2Test::_uid = db2Uid(); +std::string ODBCDB2Test::_pwd = db2Pwd(); +std::string ODBCDB2Test::_connectString = "Driver=" + db2Driver() + ";" + + db2Extra() + + "Database=" + db2Db() + ";" "Hostname=" DB2_SERVER ";" "Port=" DB2_PORT ";" "Protocol=TCPIP;" - "Uid=" DB2_UID ";" - "Pwd=" DB2_PWD ";"; + "Uid=" + db2Uid() + ";" + "Pwd=" + db2Pwd() + ";" + ; ODBCDB2Test::ODBCDB2Test(const std::string& name): @@ -81,9 +112,9 @@ ODBCDB2Test::~ODBCDB2Test() void ODBCDB2Test::testBareboneODBC() { - if (!_pSession) fail ("Test not available."); + if (! &session()) fail ("Test not available."); - std::string tableCreateString = "CREATE TABLE Test " + std::string tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third BLOB," @@ -91,55 +122,55 @@ void ODBCDB2Test::testBareboneODBC() "Fifth FLOAT," "Sixth TIMESTAMP)"; - _pExecutor->bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL); - _pExecutor->bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND); - _pExecutor->bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); - _pExecutor->bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); + executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL); + executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND); + executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); + executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); - tableCreateString = "CREATE TABLE Test " + tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second INTEGER," "Third FLOAT)"; - _pExecutor->bareboneODBCMultiResultTest(dbConnString(), tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL); - _pExecutor->bareboneODBCMultiResultTest(dbConnString(), tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND); - _pExecutor->bareboneODBCMultiResultTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); - _pExecutor->bareboneODBCMultiResultTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); + executor().bareboneODBCMultiResultTest(dbConnString(), tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_MANUAL); + executor().bareboneODBCMultiResultTest(dbConnString(), tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND); + executor().bareboneODBCMultiResultTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); + executor().bareboneODBCMultiResultTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); } void ODBCDB2Test::testBLOB() { - if (!_pSession) fail ("Test not available."); + if (! &session()) fail ("Test not available."); const std::size_t maxFldSize = 1000000; - _pSession->setProperty("maxFieldSize", Poco::Any(maxFldSize-1)); + session().setProperty("maxFieldSize", Poco::Any(maxFldSize-1)); recreatePersonBLOBTable(); try { - _pExecutor->blob(maxFldSize); + executor().blob(maxFldSize); fail ("must fail"); } catch (DataException&) { - _pSession->setProperty("maxFieldSize", Poco::Any(maxFldSize)); + session().setProperty("maxFieldSize", Poco::Any(maxFldSize)); } for (int i = 0; i < 8;) { recreatePersonBLOBTable(); - _pSession->setFeature("autoBind", bindValue(i)); - _pSession->setFeature("autoExtract", bindValue(i+1)); - _pExecutor->blob(maxFldSize); + session().setFeature("autoBind", bindValue(i)); + session().setFeature("autoExtract", bindValue(i+1)); + executor().blob(maxFldSize); i += 2; } recreatePersonBLOBTable(); try { - _pExecutor->blob(maxFldSize+1); + executor().blob(maxFldSize+1); fail ("must fail"); } catch (DataException&) { } @@ -148,14 +179,14 @@ void ODBCDB2Test::testBLOB() void ODBCDB2Test::testFilter() { - if (!_pSession) fail ("Test not available."); + if (! &session()) fail ("Test not available."); for (int i = 0; i < 8;) { recreateVectorsTable(); - _pSession->setFeature("autoBind", bindValue(i)); - _pSession->setFeature("autoExtract", bindValue(i+1)); - _pExecutor->filter("SELECT * FROM Vectors ORDER BY i0 ASC", "i0"); + session().setFeature("autoBind", bindValue(i)); + session().setFeature("autoExtract", bindValue(i+1)); + executor().filter("SELECT * FROM " + ExecUtil::vectors() + " ORDER BY i0 ASC", "i0"); i += 2; } } @@ -163,50 +194,54 @@ void ODBCDB2Test::testFilter() void ODBCDB2Test::testStoredProcedure() { - if (!_pSession) fail ("Test not available."); + if (! &session()) fail ("Test not available."); + + const std::string nm = ExecUtil::stored_proc(); + + dropObject("PROCEDURE", nm + "(INTEGER)"); + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); + dropObject("PROCEDURE", nm + "(VARCHAR(1000), VARCHAR(1000))"); for (int k = 0; k < 8;) { - _pSession->setFeature("autoBind", bindValue(k)); - _pSession->setFeature("autoExtract", bindValue(k+1)); + session().setFeature("autoBind", bindValue(k)); + session().setFeature("autoExtract", bindValue(k+1)); - dropObject("PROCEDURE", "storedProcedure"); - *_pSession << "CREATE PROCEDURE storedProcedure(OUT outParam INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(OUT outParam INTEGER) " "BEGIN " " SET outParam = -1; " "END" , now; int i = 0; - *_pSession << "{call storedProcedure(?)}", out(i), now; + session() << "{call " + db2Db() + "." << nm << "(?)}", out(i), now; + dropObject("PROCEDURE", nm + "(INTEGER)"); assert(-1 == i); - dropObject("PROCEDURE", "storedProcedure"); - *_pSession << "CREATE PROCEDURE storedProcedure(inParam INTEGER, OUT outParam INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(inParam INTEGER, OUT outParam INTEGER) " "BEGIN " " SET outParam = inParam*inParam; " "END" , now; - i = 2; int j = 0; - *_pSession << "{call storedProcedure(?, ?)}", in(i), out(j), now; + session() << "{call " + db2Db() + "." << nm << "(?, ?)}", in(i), out(j), now; + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); assert(4 == j); - dropObject("PROCEDURE", "storedProcedure"); - *_pSession << "CREATE PROCEDURE storedProcedure(INOUT ioParam INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(INOUT ioParam INTEGER) " "BEGIN " " SET ioParam = ioParam*ioParam; " "END" , now; i = 2; - *_pSession << "{call storedProcedure(?)}", io(i), now; + session() << "{call " + db2Db() + "." << nm << "(?)}", io(i), now; + dropObject("PROCEDURE", nm + "(INTEGER)"); assert(4 == i); - dropObject("PROCEDURE", "storedProcedure"); //TIMESTAMP is not supported as stored procedure parameter in DB2 //(SQL0182N An expression with a datetime value or a labeled duration is not valid.) - *_pSession << "CREATE PROCEDURE storedProcedure(inParam VARCHAR(1000), OUT outParam VARCHAR(1000)) " + session() << "CREATE PROCEDURE " << nm << "(inParam VARCHAR(1000), OUT outParam VARCHAR(1000)) " "BEGIN " " SET outParam = inParam; " "END" , now; @@ -222,9 +257,9 @@ void ODBCDB2Test::testStoredProcedure() "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; std::string outParam; - *_pSession << "{call storedProcedure(?,?)}", in(inParam), out(outParam), now; + session() << "{call " + db2Db() + "." << nm << "(?,?)}", in(inParam), out(outParam), now; + dropObject("PROCEDURE", nm + "(VARCHAR(1000), VARCHAR(1000))"); assert(inParam == outParam); - dropObject("PROCEDURE", "storedProcedure"); k += 2; } @@ -233,35 +268,39 @@ void ODBCDB2Test::testStoredProcedure() void ODBCDB2Test::testStoredProcedureAny() { - if (!_pSession) fail ("Test not available."); + if (! &session()) fail ("Test not available."); + const std::string nm = ExecUtil::stored_proc(); + + dropObject("PROCEDURE", nm + "(INTEGER)"); + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); for (int k = 0; k < 8;) { - _pSession->setFeature("autoBind", bindValue(k)); - _pSession->setFeature("autoExtract", bindValue(k+1)); + session().setFeature("autoBind", bindValue(k)); + session().setFeature("autoExtract", bindValue(k+1)); Any i = 2; Any j = 0; - *_pSession << "CREATE PROCEDURE storedProcedure(inParam INTEGER, OUT outParam INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(inParam INTEGER, OUT outParam INTEGER) " "BEGIN " " SET outParam = inParam*inParam; " "END" , now; - *_pSession << "{call storedProcedure(?, ?)}", in(i), out(j), now; + session() << "{call " + db2Db() + "." << nm << "(?, ?)}", in(i), out(j), now; + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); assert(4 == AnyCast<int>(j)); - *_pSession << "DROP PROCEDURE storedProcedure;", now; - *_pSession << "CREATE PROCEDURE storedProcedure(INOUT ioParam INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(INOUT ioParam INTEGER) " "BEGIN " " SET ioParam = ioParam*ioParam; " "END" , now; i = 2; - *_pSession << "{call storedProcedure(?)}", io(i), now; + session() << "{call " + db2Db() + "." << nm << "(?)}", io(i), now; + dropObject("PROCEDURE", nm + "(INTEGER)"); assert(4 == AnyCast<int>(i)); - dropObject("PROCEDURE", "storedProcedure"); - + k += 2; } } @@ -269,33 +308,37 @@ void ODBCDB2Test::testStoredProcedureAny() void ODBCDB2Test::testStoredProcedureDynamicAny() { - if (!_pSession) fail ("Test not available."); + if (! &session()) fail ("Test not available."); + const std::string nm = ExecUtil::stored_proc(); + + dropObject("PROCEDURE", nm + "(INTEGER)"); + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); for (int k = 0; k < 8;) { - _pSession->setFeature("autoBind", bindValue(k)); + session().setFeature("autoBind", bindValue(k)); DynamicAny i = 2; DynamicAny j = 0; - *_pSession << "CREATE PROCEDURE storedProcedure(inParam INTEGER, OUT outParam INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(inParam INTEGER, OUT outParam INTEGER) " "BEGIN " " SET outParam = inParam*inParam; " "END" , now; - *_pSession << "{call storedProcedure(?, ?)}", in(i), out(j), now; + session() << "{call " + db2Db() + "." << nm << "(?, ?)}", in(i), out(j), now; + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); assert(4 == j); - *_pSession << "DROP PROCEDURE storedProcedure;", now; - *_pSession << "CREATE PROCEDURE storedProcedure(INOUT ioParam INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(INOUT ioParam INTEGER) " "BEGIN " " SET ioParam = ioParam*ioParam; " "END" , now; i = 2; - *_pSession << "{call storedProcedure(?)}", io(i), now; + session() << "{call " + db2Db() + "." << nm << "(?)}", io(i), now; + dropObject("PROCEDURE", nm + "(INTEGER)"); assert(4 == i); - dropObject("PROCEDURE", "storedProcedure"); k += 2; } @@ -304,36 +347,89 @@ void ODBCDB2Test::testStoredProcedureDynamicAny() void ODBCDB2Test::testStoredFunction() { - if (!_pSession) fail ("Test not available."); + const std::string nm = ExecUtil::stored_func(); + if (! &session()) fail ("Test not available."); + + dropObject("PROCEDURE", nm + "()"); + dropObject("PROCEDURE", nm + "(INTEGER)"); + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); + dropObject("PROCEDURE", nm + "(VARCHAR(10), DATE, TIME, TIMESTAMP, INTEGER, SMALLINT, REAL, DOUBLE, VARCHAR(10), INTEGER)"); + dropObject("PROCEDURE", nm + "(VARCHAR(10), VARCHAR(10))"); for (int k = 0; k < 8;) { - _pSession->setFeature("autoBind", bindValue(k)); - _pSession->setFeature("autoExtract", bindValue(k+1)); + session().setFeature("autoBind", bindValue(k)); + session().setFeature("autoExtract", bindValue(k + 1)); - dropObject("PROCEDURE", "storedFunction"); - *_pSession << "CREATE PROCEDURE storedFunction() " + { + session() << "CREATE PROCEDURE " << nm << "() " + "BEGIN " + " DECLARE C1 CURSOR FOR select * from sysibm.sysdummy1 where 1=2;" + " OPEN C1;" + " RETURN;" + "END", now; + + Poco::Data::Statement stat(session()); + stat << "{ call " + db2Db() + "." << nm << "()}", now; + Poco::Data::RecordSet rs(stat); + + assert(0 == rs.rowCount()); + dropObject("PROCEDURE", nm + "()"); + } + { + session() << "CREATE PROCEDURE " << nm << "(inp VARCHAR(10), out dt DATE, out tm TIME, out tms TIMESTAMP, out int32 INTEGER, " + "out si SMALLINT, out fl REAL, out dbl DOUBLE, out s2 VARCHAR(10), out an INTEGER)" + "BEGIN " + "set dt =null; set tm =null; set tms =null; set int32 =null; set si =null; set fl =null; set dbl =null; set s2 = inp; set an = inp;" + "END", now; + + Poco::Data::Statement stat(session()); + Poco::Nullable<std::string> ns; + Poco::Nullable<Poco::Data::Date> nd = Poco::Nullable<Poco::Data::Date>(Poco::Data::Date()); + Poco::Nullable<int> n_i(1); + Poco::Nullable<Poco::Data::Time> tm = Poco::Nullable<Poco::Data::Time>(Poco::Data::Time()); + Poco::Nullable<Poco::DateTime> tms = Poco::Nullable<Poco::DateTime>(Poco::DateTime()); + Poco::Nullable<Poco::Int16> i16(1); + Poco::Nullable<float> flt(1); + Poco::Nullable<double> dbl(1); + Poco::Nullable<std::string> s2("ddd"); + Poco::Nullable<Any> an(Any(2)); + stat << "{call " + db2Db() + "." << nm << "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}", useRef(ns), out(nd), out(tm), out(tms), out(n_i), out(i16), out(flt), out(dbl), out(s2), out(an), now; + dropObject("PROCEDURE", nm + "(VARCHAR(10), DATE, TIME, TIMESTAMP, INTEGER, SMALLINT, REAL, DOUBLE, VARCHAR(10), INTEGER)"); + assert(nd.isNull()); + assert(n_i.isNull()); + assert(tm.isNull()); + assert(tms.isNull()); + assert(i16.isNull()); + assert(flt.isNull()); + assert(dbl.isNull()); + assert(s2.isNull()); + assert(an.isNull()); + } + + session() << "CREATE PROCEDURE " << nm << "() " "BEGIN " " RETURN -1; " "END" , now; int i = 0; - *_pSession << "{? = call storedFunction()}", out(i), now; + session() << "{? = call " + db2Db() + "." << nm << "()}", out(i), now; + dropObject("PROCEDURE", nm + "()"); assert(-1 == i); - dropObject("PROCEDURE", "storedFunction"); - - *_pSession << "CREATE PROCEDURE storedFunction(inParam INTEGER) " + + + session() << "CREATE PROCEDURE " << nm << "(inParam INTEGER) " "BEGIN " " RETURN inParam*inParam; " "END" , now; i = 2; int result = 0; - *_pSession << "{? = call storedFunction(?)}", out(result), in(i), now; + session() << "{? = call " + db2Db() + "." << nm << "(?)}", out(result), in(i), now; + dropObject("PROCEDURE", nm + "(INTEGER)"); assert(4 == result); - dropObject("PROCEDURE", "storedFunction"); - *_pSession << "CREATE PROCEDURE storedFunction(inParam INTEGER, OUT outParam INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(inParam INTEGER, OUT outParam INTEGER) " "BEGIN " " SET outParam = inParam*inParam; " " RETURN outParam; " @@ -342,12 +438,12 @@ void ODBCDB2Test::testStoredFunction() i = 2; int j = 0; result = 0; - *_pSession << "{? = call storedFunction(?, ?)}", out(result), in(i), out(j), now; + session() << "{? = call " + db2Db() + "." << nm << "(?, ?)}", out(result), in(i), out(j), now; + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); assert(4 == j); assert(j == result); - dropObject("PROCEDURE", "storedFunction"); - *_pSession << "CREATE PROCEDURE storedFunction(INOUT param1 INTEGER, INOUT param2 INTEGER) " + session() << "CREATE PROCEDURE " << nm << "(INOUT param1 INTEGER, INOUT param2 INTEGER) " "BEGIN " " DECLARE temp INTEGER;" " SET temp = param1; " @@ -359,7 +455,7 @@ void ODBCDB2Test::testStoredFunction() i = 1; j = 2; result = 0; - *_pSession << "{? = call storedFunction(?, ?)}", out(result), io(i), io(j), now; + session() << "{? = call " + db2Db() + "." << nm << "(?, ?)}", out(result), io(i), io(j), now; assert(1 == j); assert(2 == i); assert(3 == result); @@ -368,16 +464,15 @@ void ODBCDB2Test::testStoredFunction() assert(1 == params.get<0>()); assert(2 == params.get<1>()); result = 0; - *_pSession << "{? = call storedFunction(?, ?)}", out(result), io(params), now; + session() << "{? = call " + db2Db() + "." << nm << "(?, ?)}", out(result), io(params), now; + dropObject("PROCEDURE", nm + "(INTEGER, INTEGER)"); assert(1 == params.get<1>()); assert(2 == params.get<0>()); assert(3 == result); - dropObject("PROCEDURE", "storedFunction"); + session().setFeature("autoBind", true); - _pSession->setFeature("autoBind", true); - - *_pSession << "CREATE PROCEDURE storedFunction(inParam VARCHAR(10), OUT outParam VARCHAR(10)) " + session() << "CREATE PROCEDURE " << nm << "(inParam VARCHAR(10), OUT outParam VARCHAR(10)) " "BEGIN " " SET outParam = inParam; " " RETURN LENGTH(outParam);"//DB2 allows only integer as return type @@ -386,21 +481,74 @@ void ODBCDB2Test::testStoredFunction() std::string inParam = "123456789"; std::string outParam; int ret; - *_pSession << "{? = call storedFunction(?,?)}", out(ret), in(inParam), out(outParam), now; + session() << "{? = call " + db2Db() + "." << nm << "(?,?)}", out(ret), in(inParam), out(outParam), now; + dropObject("PROCEDURE", nm + "(VARCHAR(10), VARCHAR(10))"); assert(inParam == outParam); assert(ret == inParam.size()); - dropObject("PROCEDURE", "storedFunction"); k += 2; } } +void ODBCDB2Test::testXMLColumn() +{ + const std::string tbl = ExecUtil::mangleTable("xmlColumn"); + dropObject("TABLE", tbl); + try { + const std::string xmlStr = "<a> xml text </a>"; + Poco::UTF16String uStr; + for (unsigned c = 0x400; c < 0x409; ++c) uStr.append(3, Poco::UTF16Char(c) ); + session() << "CREATE TABLE " << tbl << " (id integer, x XML, cl CLOB, dbcl DBCLOB)", now; + session() << "INSERT INTO " << tbl << " (id , x, cl, dbcl) VALUES(1, '" << xmlStr << "', ?, ?)", bind(xmlStr), bind(uStr), now; + Poco::Data::Statement stat(session()); + stat << "SELECT id, x,cl, dbcl FROM " << tbl, now; + + Poco::Data::RecordSet rs(stat); + assert(1 == rs.rowCount()); + assert(4 == rs.columnCount()); + int id = rs.value<int>(0); + assert(1 == id); + + Poco::Data::BLOB xml = rs.value<Poco::Data::BLOB>(1); + std::string readStr(reinterpret_cast<const char*>(xml.rawContent()), xml.size()); + assert(readStr.find(xmlStr) < readStr.length()); + + Poco::Data::CLOB cl = rs.value<Poco::Data::CLOB>(2); + assert(xmlStr == std::string(cl.rawContent(), cl.size())); + + const Poco::UTF16String us = rs.value<Poco::UTF16String>(3); + assert(uStr == us); + // check nullables + Poco::Nullable<Poco::Data::CLOB> ncl = Poco::Nullable<Poco::Data::CLOB>(Poco::Data::CLOB()); + assert(false == ncl.isNull()); + Poco::Nullable<Poco::Data::BLOB> nbl = Poco::Nullable<Poco::Data::BLOB>(Poco::Data::BLOB()); + assert(false == nbl.isNull()); + Poco::Nullable<Poco::UTF16String> usn(Poco::UTF16String(2, Poco::UTF16Char('a'))); + assert(false == usn.isNull()); + session() << "INSERT INTO " << tbl << " (id) VALUES (99) ", now; + session() << "SELECT x,cl, dbcl FROM " << tbl << " WHERE id > 1", into(nbl), into(ncl), into(usn), now; + + assert(true == ncl.isNull()); + assert(true == nbl.isNull()); + assert(true == usn.isNull()); + } + catch (const Poco::Exception& e) + { + dropObject("TABLE", tbl); + + std::cerr << e.message() << std::endl; + throw; + } + dropObject("TABLE", tbl); +} + + void ODBCDB2Test::dropObject(const std::string& type, const std::string& name) { try { - *_pSession << format("DROP %s %s", type, name), now; + session() << format("DROP %s %s", type, name), now; } catch (StatementException& ex) { @@ -408,8 +556,9 @@ void ODBCDB2Test::dropObject(const std::string& type, const std::string& name) const StatementDiagnostics::FieldVec& flds = ex.diagnostics().fields(); StatementDiagnostics::Iterator it = flds.begin(); for (; it != flds.end(); ++it) - { - if (-204 == it->_nativeError)//(table does not exist) + { + //(table does not exist) // procedure not found + if (-204 == it->_nativeError || (-458 == it->_nativeError) ) { ignoreError = true; break; @@ -423,17 +572,28 @@ void ODBCDB2Test::dropObject(const std::string& type, const std::string& name) void ODBCDB2Test::recreateNullableTable() { - dropObject("TABLE", "NullableTest"); - try { *_pSession << "CREATE TABLE NullableTest (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat FLOAT NULL , EmptyDateTime TIMESTAMP NULL)", now; } + dropObject("TABLE", ExecUtil::nullabletest()); + try { session() << "CREATE TABLE " << ExecUtil::nullabletest() << " (EmptyString VARCHAR(30), EmptyInteger INTEGER , EmptyFloat FLOAT , EmptyDateTime TIMESTAMP)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } +void ODBCDB2Test::recreateNumericTable() +{ + dropObject("TABLE", ExecUtil::numeric_tbl()); + try { + session() << "CREATE TABLE " << ExecUtil::numeric_tbl() << + " (id integer, num8 NUMERIC(8), num16_3 NUMERIC(16,3), num18 NUMERIC(18), num18_8 NUMERIC(18,8), num22 NUMERIC(22))", now; + } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateNumericTable()"); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateNumericTable()"); } +} + void ODBCDB2Test::recreatePersonTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() <<" (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -441,8 +601,8 @@ void ODBCDB2Test::recreatePersonTable() void ODBCDB2Test::recreatePersonBLOBTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() <<" (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } } @@ -450,8 +610,8 @@ void ODBCDB2Test::recreatePersonBLOBTable() void ODBCDB2Test::recreatePersonDateTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() <<" (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTable()"); } } @@ -459,8 +619,8 @@ void ODBCDB2Test::recreatePersonDateTable() void ODBCDB2Test::recreatePersonTimeTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornTime TIME)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() <<" (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornTime TIME)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTimeTable()"); } } @@ -468,8 +628,8 @@ void ODBCDB2Test::recreatePersonTimeTable() void ODBCDB2Test::recreatePersonDateTimeTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born TIMESTAMP)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() <<" (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born TIMESTAMP)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } } @@ -477,8 +637,8 @@ void ODBCDB2Test::recreatePersonDateTimeTable() void ODBCDB2Test::recreateIntsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str INTEGER)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() << " (str INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateIntsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateIntsTable()"); } } @@ -486,8 +646,8 @@ void ODBCDB2Test::recreateIntsTable() void ODBCDB2Test::recreateStringsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() << " (str VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateStringsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateStringsTable()"); } } @@ -495,8 +655,8 @@ void ODBCDB2Test::recreateStringsTable() void ODBCDB2Test::recreateFloatsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str FLOAT)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() << " (str FLOAT)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateFloatsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateFloatsTable()"); } } @@ -504,8 +664,8 @@ void ODBCDB2Test::recreateFloatsTable() void ODBCDB2Test::recreateTuplesTable() { - dropObject("TABLE", "Tuples"); - try { *_pSession << "CREATE TABLE Tuples " + dropObject("TABLE", ExecUtil::tuples()); + try { session() << "CREATE TABLE " << ExecUtil::tuples() << "(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, " "int7 INTEGER, int8 INTEGER, int9 INTEGER, int10 INTEGER, int11 INTEGER, int12 INTEGER, int13 INTEGER," "int14 INTEGER, int15 INTEGER, int16 INTEGER, int17 INTEGER, int18 INTEGER, int19 INTEGER)", now; } @@ -516,8 +676,8 @@ void ODBCDB2Test::recreateTuplesTable() void ODBCDB2Test::recreateVectorsTable() { - dropObject("TABLE", "Vectors"); - try { *_pSession << "CREATE TABLE Vectors (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::vectors()); + try { session() << "CREATE TABLE " << ExecUtil::vectors() << " (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateVectorsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateVectorsTable()"); } } @@ -525,8 +685,8 @@ void ODBCDB2Test::recreateVectorsTable() void ODBCDB2Test::recreateAnysTable() { - dropObject("TABLE", "Anys"); - try { *_pSession << "CREATE TABLE Anys (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::anys() ); + try { session() << "CREATE TABLE " << ExecUtil::anys() << " (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateAnysTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateAnysTable()"); } } @@ -534,8 +694,8 @@ void ODBCDB2Test::recreateAnysTable() void ODBCDB2Test::recreateNullsTable(const std::string& notNull) { - dropObject("TABLE", "NullTest"); - try { *_pSession << format("CREATE TABLE NullTest (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)", + dropObject("TABLE", ExecUtil::nulltest()); + try { session() << format("CREATE TABLE %s (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)", ExecUtil::nulltest(), notNull, notNull, notNull), now; } @@ -546,10 +706,10 @@ void ODBCDB2Test::recreateNullsTable(const std::string& notNull) void ODBCDB2Test::recreateMiscTable() { - dropObject("TABLE", "MiscTest"); + dropObject("TABLE", ExecUtil::misctest()); try { - session() << "CREATE TABLE MiscTest " + session() << "CREATE TABLE " << ExecUtil::misctest() << "(First VARCHAR(30)," "Second BLOB," "Third INTEGER," @@ -562,8 +722,8 @@ void ODBCDB2Test::recreateMiscTable() void ODBCDB2Test::recreateLogTable() { - dropObject("TABLE", "T_POCO_LOG"); - dropObject("TABLE", "T_POCO_LOG_ARCHIVE"); + dropObject("TABLE", ExecUtil::pocolog());; + dropObject("TABLE", ExecUtil::pocolog_a());; try { @@ -577,8 +737,8 @@ void ODBCDB2Test::recreateLogTable() "Text VARCHAR(100)," "DateTime TIMESTAMP)"; - session() << sql, "T_POCO_LOG", now; - session() << sql, "T_POCO_LOG_ARCHIVE", now; + session() << sql, ExecUtil::pocolog(), now; + session() << sql, ExecUtil::pocolog_a(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); } @@ -597,6 +757,7 @@ CppUnit::Test* ODBCDB2Test::suite() CppUnit_addTest(pSuite, ODBCDB2Test, testBareboneODBC); CppUnit_addTest(pSuite, ODBCDB2Test, testZeroRows); + CppUnit_addTest(pSuite, ODBCDB2Test, testSyntaxError); CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccess); CppUnit_addTest(pSuite, ODBCDB2Test, testComplexType); CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccessVector); @@ -666,13 +827,20 @@ CppUnit::Test* ODBCDB2Test::suite() CppUnit_addTest(pSuite, ODBCDB2Test, testAny); CppUnit_addTest(pSuite, ODBCDB2Test, testDynamicAny); CppUnit_addTest(pSuite, ODBCDB2Test, testMultipleResults); + CppUnit_addTest(pSuite, ODBCDB2Test, testMultipleResultsNoProj); CppUnit_addTest(pSuite, ODBCDB2Test, testSQLChannel); CppUnit_addTest(pSuite, ODBCDB2Test, testSQLLogger); - CppUnit_addTest(pSuite, ODBCDB2Test, testSessionTransaction); + //CppUnit_addTest(pSuite, ODBCDB2Test, testSessionTransaction); // this test fails when connection is fast CppUnit_addTest(pSuite, ODBCDB2Test, testTransaction); CppUnit_addTest(pSuite, ODBCDB2Test, testTransactor); CppUnit_addTest(pSuite, ODBCDB2Test, testNullable); CppUnit_addTest(pSuite, ODBCDB2Test, testReconnect); + CppUnit_addTest(pSuite, ODBCDB2Test, testNumeric); + CppUnit_addTest(pSuite, ODBCDB2Test, testXMLColumn); + CppUnit_addTest(pSuite, ODBCDB2Test, testInsertStatReuse); + + ODBCDB2Test::_pExecutor = 0; + ODBCDB2Test::_pSession = 0; return pSuite; } diff --git a/Data/ODBC/testsuite/src/ODBCDB2Test.h b/Data/ODBC/testsuite/src/ODBCDB2Test.h index dee55a7c8..8f620ba2d 100644 --- a/Data/ODBC/testsuite/src/ODBCDB2Test.h +++ b/Data/ODBC/testsuite/src/ODBCDB2Test.h @@ -41,6 +41,7 @@ public: void testStoredProcedureAny(); void testStoredProcedureDynamicAny(); void testStoredFunction(); + void testXMLColumn(); static CppUnit::Test* suite(); @@ -61,6 +62,7 @@ private: void recreateNullsTable(const std::string& notNull = ""); void recreateMiscTable(); void recreateLogTable(); + void recreateNumericTable(); static ODBCTest::SessionPtr _pSession; static ODBCTest::ExecPtr _pExecutor; diff --git a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp index ba1aedf30..e30e34de7 100644 --- a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp @@ -77,7 +77,7 @@ void ODBCMySQLTest::testBareboneODBC() { if (!_pSession) fail ("Test not available."); - std::string tableCreateString = "CREATE TABLE Test " + std::string tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third VARBINARY(30)," @@ -97,7 +97,7 @@ has different SQL syntax for it and behaves differently compared to other DBMS systems in regards to SQLMoreResults. So, we skip this test. - tableCreateString = "CREATE TABLE Test " + tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second INTEGER," "Third FLOAT)"; @@ -236,7 +236,7 @@ void ODBCMySQLTest::testFilter() recreateVectorsTable(); _pSession->setFeature("autoBind", bindValue(i)); _pSession->setFeature("autoExtract", bindValue(i+1)); - _pExecutor->filter("SELECT * FROM Vectors ORDER BY i0 ASC", "i0"); + _pExecutor->filter("SELECT * FROM " + ExecUtil::vectors() + " ORDER BY i0 ASC", "i0"); i += 2; } } @@ -250,8 +250,8 @@ void ODBCMySQLTest::dropObject(const std::string& type, const std::string& name) void ODBCMySQLTest::recreateNullableTable() { - dropObject("TABLE", "NullableTest"); - try { *_pSession << "CREATE TABLE NullableTest (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat FLOAT NULL , EmptyDateTime TIMESTAMP NULL)", now; } + dropObject("TABLE", ExecUtil::nullabletest()); + try { *_pSession << "CREATE TABLE " << ExecUtil::nullabletest() << " (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat FLOAT NULL , EmptyDateTime TIMESTAMP NULL)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -259,8 +259,8 @@ void ODBCMySQLTest::recreateNullableTable() void ODBCMySQLTest::recreatePersonTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -268,8 +268,8 @@ void ODBCMySQLTest::recreatePersonTable() void ODBCMySQLTest::recreatePersonBLOBTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } } @@ -277,8 +277,8 @@ void ODBCMySQLTest::recreatePersonBLOBTable() void ODBCMySQLTest::recreatePersonDateTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTable()"); } } @@ -286,8 +286,8 @@ void ODBCMySQLTest::recreatePersonDateTable() void ODBCMySQLTest::recreatePersonTimeTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornTime TIME)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornTime TIME)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTimeTable()"); } } @@ -295,8 +295,8 @@ void ODBCMySQLTest::recreatePersonTimeTable() void ODBCMySQLTest::recreatePersonDateTimeTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born DATETIME)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born DATETIME)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } } @@ -304,8 +304,8 @@ void ODBCMySQLTest::recreatePersonDateTimeTable() void ODBCMySQLTest::recreateIntsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str INTEGER)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { *_pSession << "CREATE TABLE " << ExecUtil::strings() << " (str INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateIntsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateIntsTable()"); } } @@ -313,8 +313,8 @@ void ODBCMySQLTest::recreateIntsTable() void ODBCMySQLTest::recreateStringsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::strings()); + try { *_pSession << "CREATE TABLE " << ExecUtil::strings() << " (str VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateStringsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateStringsTable()"); } } @@ -322,8 +322,8 @@ void ODBCMySQLTest::recreateStringsTable() void ODBCMySQLTest::recreateFloatsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str FLOAT)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (str FLOAT)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateFloatsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateFloatsTable()"); } } @@ -331,8 +331,8 @@ void ODBCMySQLTest::recreateFloatsTable() void ODBCMySQLTest::recreateTuplesTable() { - dropObject("TABLE", "Tuples"); - try { *_pSession << "CREATE TABLE Tuples " + dropObject("TABLE", ExecUtil::tuples()); + try { *_pSession << "CREATE TABLE " << ExecUtil::tuples() << "(i0 INTEGER, i1 INTEGER, i2 INTEGER, i3 INTEGER, i4 INTEGER, i5 INTEGER, i6 INTEGER, " "i7 INTEGER, i8 INTEGER, i9 INTEGER, i10 INTEGER, i11 INTEGER, i12 INTEGER, i13 INTEGER," "i14 INTEGER, i15 INTEGER, i16 INTEGER, i17 INTEGER, i18 INTEGER, i19 INTEGER)", now; } @@ -343,8 +343,8 @@ void ODBCMySQLTest::recreateTuplesTable() void ODBCMySQLTest::recreateVectorsTable() { - dropObject("TABLE", "Vectors"); - try { *_pSession << "CREATE TABLE Vectors (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::vectors() ); + try { *_pSession << "CREATE TABLE " << ExecUtil::vectors() << " (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateVectorsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateVectorsTable()"); } } @@ -352,8 +352,8 @@ void ODBCMySQLTest::recreateVectorsTable() void ODBCMySQLTest::recreateAnysTable() { - dropObject("TABLE", "Anys"); - try { *_pSession << "CREATE TABLE Anys (i0 INTEGER, flt0 DOUBLE, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::anys() ); + try { *_pSession << "CREATE TABLE " << ExecUtil::anys() << " (i0 INTEGER, flt0 DOUBLE, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateAnysTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateAnysTable()"); } } @@ -361,8 +361,8 @@ void ODBCMySQLTest::recreateAnysTable() void ODBCMySQLTest::recreateNullsTable(const std::string& notNull) { - dropObject("TABLE", "NullTest"); - try { *_pSession << format("CREATE TABLE NullTest (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)", + dropObject("TABLE", ExecUtil::nulltest()); + try { *_pSession << format("CREATE TABLE %s (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)", ExecUtil::nulltest(), notNull, notNull, notNull), now; } @@ -373,8 +373,8 @@ void ODBCMySQLTest::recreateNullsTable(const std::string& notNull) void ODBCMySQLTest::recreateMiscTable() { - dropObject("TABLE", "MiscTest"); - try { *_pSession << "CREATE TABLE MiscTest " + dropObject("TABLE", ExecUtil::misctest()); + try { *_pSession << "CREATE TABLE "<< ExecUtil::misctest() << "(First VARCHAR(30)," "Second VARBINARY(30)," "Third INTEGER," @@ -387,8 +387,8 @@ void ODBCMySQLTest::recreateMiscTable() void ODBCMySQLTest::recreateLogTable() { - dropObject("TABLE", "T_POCO_LOG"); - dropObject("TABLE", "T_POCO_LOG_ARCHIVE"); + dropObject("TABLE", ExecUtil::pocolog());; + dropObject("TABLE", ExecUtil::pocolog_a());; try { @@ -402,8 +402,8 @@ void ODBCMySQLTest::recreateLogTable() "Text VARCHAR(100)," "DateTime DATETIME)"; - session() << sql, "T_POCO_LOG", now; - session() << sql, "T_POCO_LOG_ARCHIVE", now; + session() << sql, ExecUtil::pocolog(), now; + session() << sql, ExecUtil::pocolog_a(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); } @@ -422,6 +422,7 @@ CppUnit::Test* ODBCMySQLTest::suite() CppUnit_addTest(pSuite, ODBCMySQLTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCMySQLTest, testZeroRows); + CppUnit_addTest(pSuite, ODBCMySQLTest, testSyntaxError); CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCMySQLTest, testComplexType); CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccessVector); diff --git a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp index 75ecd7c2c..24280216f 100644 --- a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp @@ -85,11 +85,11 @@ std::string ODBCOracleTest::_connectString = "DRIVER={" ORACLE_ODBC_DRI const std::string ODBCOracleTest::MULTI_INSERT = "BEGIN " - "INSERT INTO Test VALUES ('1', 2, 3.5);" - "INSERT INTO Test VALUES ('2', 3, 4.5);" - "INSERT INTO Test VALUES ('3', 4, 5.5);" - "INSERT INTO Test VALUES ('4', 5, 6.5);" - "INSERT INTO Test VALUES ('5', 6, 7.5);" + "INSERT INTO " + ExecUtil::test_tbl() + " VALUES ('1', 2, 3.5);" + "INSERT INTO " + ExecUtil::test_tbl() + " VALUES ('2', 3, 4.5);" + "INSERT INTO " + ExecUtil::test_tbl() + " VALUES ('3', 4, 5.5);" + "INSERT INTO " + ExecUtil::test_tbl() + " VALUES ('4', 5, 6.5);" + "INSERT INTO " + ExecUtil::test_tbl() + " VALUES ('5', 6, 7.5);" "END;"; const std::string ODBCOracleTest::MULTI_SELECT = @@ -109,7 +109,7 @@ ODBCOracleTest::~ODBCOracleTest() void ODBCOracleTest::testBarebone() { - std::string tableCreateString = "CREATE TABLE Test " + std::string tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third BLOB," @@ -122,7 +122,7 @@ void ODBCOracleTest::testBarebone() _pExecutor->bareboneODBCTest(_connectString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); _pExecutor->bareboneODBCTest(_connectString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); - tableCreateString = "CREATE TABLE Test " + tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second INTEGER," "Third NUMBER)"; @@ -134,11 +134,11 @@ void ODBCOracleTest::testBarebone() "ret4 OUT SYS_REFCURSOR," "ret5 OUT SYS_REFCURSOR) IS " "BEGIN " - "OPEN ret1 FOR SELECT * FROM Test WHERE First = '1';" - "OPEN ret2 FOR SELECT * FROM Test WHERE First = '2';" - "OPEN ret3 FOR SELECT * FROM Test WHERE First = '3';" - "OPEN ret4 FOR SELECT * FROM Test WHERE First = '4';" - "OPEN ret5 FOR SELECT * FROM Test WHERE First = '5';" + "OPEN ret1 FOR SELECT * FROM " + ExecUtil::test_tbl() + " WHERE First = '1';" + "OPEN ret2 FOR SELECT * FROM " + ExecUtil::test_tbl() + " WHERE First = '2';" + "OPEN ret3 FOR SELECT * FROM " + ExecUtil::test_tbl() + " WHERE First = '3';" + "OPEN ret4 FOR SELECT * FROM " + ExecUtil::test_tbl() + " WHERE First = '4';" + "OPEN ret5 FOR SELECT * FROM " + ExecUtil::test_tbl() + " WHERE First = '5';" "END multiResultsProcedure;" , now; _pExecutor->bareboneODBCMultiResultTest(_connectString, @@ -385,14 +385,14 @@ void ODBCOracleTest::testCursorStoredProcedure() people.push_back(Person("Simpson", "Homer", "Springfield", 42)); people.push_back(Person("Simpson", "Bart", "Springfield", 12)); people.push_back(Person("Simpson", "Lisa", "Springfield", 10)); - *_pSession << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now; + *_pSession << "INSERT INTO " << ExecUtil::person() << " VALUES (?, ?, ?, ?)", use(people), now; *_pSession << "CREATE OR REPLACE " "PROCEDURE storedCursorProcedure(ret OUT SYS_REFCURSOR, ageLimit IN NUMBER) IS " " BEGIN " " OPEN ret FOR " " SELECT * " - " FROM Person " + " FROM " << ExecUtil::person() << " WHERE Age < ageLimit " " ORDER BY Age DESC; " " END storedCursorProcedure;" , now; @@ -413,7 +413,7 @@ void ODBCOracleTest::testCursorStoredProcedure() assert (rs["Address"] == "Springfield"); assert (rs["Age"] == 12); - dropObject("TABLE", "Person"); + dropObject("TABLE", ExecUtil::person()); dropObject("PROCEDURE", "storedCursorProcedure"); k += 2; @@ -523,7 +523,7 @@ void ODBCOracleTest::testCursorStoredFunction() people.push_back(Person("Simpson", "Homer", "Springfield", 42)); people.push_back(Person("Simpson", "Bart", "Springfield", 12)); people.push_back(Person("Simpson", "Lisa", "Springfield", 10)); - *_pSession << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now; + *_pSession << "INSERT INTO " << ExecUtil::person() << " VALUES (?, ?, ?, ?)", use(people), now; *_pSession << "CREATE OR REPLACE " "FUNCTION storedCursorFunction(ageLimit IN NUMBER) RETURN SYS_REFCURSOR IS " @@ -531,7 +531,7 @@ void ODBCOracleTest::testCursorStoredFunction() " BEGIN " " OPEN ret FOR " " SELECT * " - " FROM Person " + " FROM " << ExecUtil::person() << " WHERE Age < ageLimit " " ORDER BY Age DESC; " " RETURN ret; " @@ -553,7 +553,7 @@ void ODBCOracleTest::testCursorStoredFunction() assert (rs["Address"] == "Springfield"); assert (rs["Age"] == 12); - dropObject("TABLE", "Person"); + dropObject("TABLE", ExecUtil::person()); dropObject("FUNCTION", "storedCursorFunction"); k += 2; @@ -571,9 +571,9 @@ void ODBCOracleTest::testMultipleResults() " ret2 OUT SYS_REFCURSOR," " ret3 OUT SYS_REFCURSOR) IS " "BEGIN " - " OPEN ret1 FOR SELECT * FROM Person WHERE Age = paramAge1;" - " OPEN ret2 FOR SELECT Age FROM Person WHERE FirstName = 'Bart';" - " OPEN ret3 FOR SELECT * FROM Person WHERE Age = paramAge2 OR Age = paramAge3 ORDER BY Age;" + " OPEN ret1 FOR SELECT * FROM " + ExecUtil::person() + " WHERE Age = paramAge1;" + " OPEN ret2 FOR SELECT Age FROM " + ExecUtil::person() + " WHERE FirstName = 'Bart';" + " OPEN ret3 FOR SELECT * FROM " + ExecUtil::person() + " WHERE Age = paramAge2 OR Age = paramAge3 ORDER BY Age;" "END multiResultsProcedure;"; for (int i = 0; i < 8;) @@ -598,18 +598,18 @@ void ODBCOracleTest::testAutoTransaction() recreateIntsTable(); session().setFeature("autoCommit", true); - session() << "INSERT INTO Strings VALUES (1)", now; - localSession << "SELECT count(*) FROM Strings", into(count), now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (1)", now; + localSession << "SELECT count(*) FROM " << ExecUtil::person() , into(count), now; assert (1 == count); - session() << "INSERT INTO Strings VALUES (2)", now; - localSession << "SELECT count(*) FROM Strings", into(count), now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (2)", now; + localSession << "SELECT count(*) FROM " << ExecUtil::strings(), into(count), now; assert (2 == count); - session() << "INSERT INTO Strings VALUES (3)", now; - localSession << "SELECT count(*) FROM Strings", into(count), now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (3)", now; + localSession << "SELECT count(*) FROM " << ExecUtil::strings(), into(count), now; assert (3 == count); - session() << "DELETE FROM Strings", now; - localSession << "SELECT count(*) FROM Strings", into(count), now; + session() << "DELETE FROM " << ExecUtil::strings(), now; + localSession << "SELECT count(*) FROM " << ExecUtil::strings(), into(count), now; assert (0 == count); session().setFeature("autoCommit", false); @@ -617,26 +617,26 @@ void ODBCOracleTest::testAutoTransaction() try { AutoTransaction at(session()); - session() << "INSERT INTO Strings VALUES (1)", now; - session() << "INSERT INTO Strings VALUES (2)", now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (1)", now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (2)", now; session() << "BAD QUERY", now; } catch (Poco::Exception&) {} - session() << "SELECT count(*) FROM Strings", into(count), now; + session() << "SELECT count(*) FROM " << ExecUtil::strings(), into(count), now; assert (0 == count); AutoTransaction at(session()); - session() << "INSERT INTO Strings VALUES (1)", now; - session() << "INSERT INTO Strings VALUES (2)", now; - session() << "INSERT INTO Strings VALUES (3)", now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (1)", now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (2)", now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (3)", now; - localSession << "SELECT count(*) FROM Strings", into(count), now; + localSession << "SELECT count(*) FROM " << ExecUtil::strings(), into(count), now; assert (0 == count); at.commit(); - localSession << "SELECT count(*) FROM Strings", into(count), now; + localSession << "SELECT count(*) FROM " << ExecUtil::strings(), into(count), now; assert (3 == count); session().setFeature("autoCommit", ac); @@ -671,8 +671,8 @@ void ODBCOracleTest::dropObject(const std::string& type, const std::string& name void ODBCOracleTest::recreateNullableTable() { - dropObject("TABLE", "NullableTest"); - try { *_pSession << "CREATE TABLE NullableTest (EmptyString VARCHAR2(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat NUMBER NULL , EmptyDateTime TIMESTAMP NULL)", now; } + dropObject("TABLE", ExecUtil::nullabletest()); + try { *_pSession << "CREATE TABLE " << ExecUtil::nullabletest() << " (EmptyString VARCHAR2(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat NUMBER NULL , EmptyDateTime TIMESTAMP NULL)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -680,8 +680,8 @@ void ODBCOracleTest::recreateNullableTable() void ODBCOracleTest::recreatePersonTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR2(30), FirstName VARCHAR2(30), Address VARCHAR2(30), Age INTEGER)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR2(30), FirstName VARCHAR2(30), Address VARCHAR2(30), Age INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -689,8 +689,8 @@ void ODBCOracleTest::recreatePersonTable() void ODBCOracleTest::recreatePersonTupleTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName1 VARCHAR2(30), FirstName1 VARCHAR2(30), Address1 VARCHAR2(30), Age1 INTEGER," + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName1 VARCHAR2(30), FirstName1 VARCHAR2(30), Address1 VARCHAR2(30), Age1 INTEGER," "LastName2 VARCHAR2(30), FirstName2 VARCHAR2(30), Address2 VARCHAR2(30), Age2 INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTupleTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTupleTable()"); } @@ -699,8 +699,8 @@ void ODBCOracleTest::recreatePersonTupleTable() void ODBCOracleTest::recreatePersonBLOBTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } } @@ -708,8 +708,8 @@ void ODBCOracleTest::recreatePersonBLOBTable() void ODBCOracleTest::recreatePersonDateTimeTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born TIMESTAMP)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born TIMESTAMP)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } } @@ -717,8 +717,8 @@ void ODBCOracleTest::recreatePersonDateTimeTable() void ODBCOracleTest::recreatePersonDateTable() { - dropObject("TABLE", "Person"); - try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; } + dropObject("TABLE", ExecUtil::person()); + try { *_pSession << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTable()"); } } @@ -726,8 +726,8 @@ void ODBCOracleTest::recreatePersonDateTable() void ODBCOracleTest::recreateIntsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str INTEGER)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { *_pSession << "CREATE TABLE " << ExecUtil::strings() <<" (str INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateIntsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateIntsTable()"); } } @@ -735,8 +735,8 @@ void ODBCOracleTest::recreateIntsTable() void ODBCOracleTest::recreateStringsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::strings()); + try { *_pSession << "CREATE TABLE " << ExecUtil::strings() <<" (str VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateStringsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateStringsTable()"); } } @@ -744,8 +744,8 @@ void ODBCOracleTest::recreateStringsTable() void ODBCOracleTest::recreateFloatsTable() { - dropObject("TABLE", "Strings"); - try { *_pSession << "CREATE TABLE Strings (str NUMBER)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { *_pSession << "CREATE TABLE " << ExecUtil::strings() <<" (str NUMBER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateFloatsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateFloatsTable()"); } } @@ -753,8 +753,8 @@ void ODBCOracleTest::recreateFloatsTable() void ODBCOracleTest::recreateTuplesTable() { - dropObject("TABLE", "Tuples"); - try { *_pSession << "CREATE TABLE Tuples " + dropObject("TABLE", ExecUtil::tuples()); + try { *_pSession << "CREATE TABLE " << ExecUtil::tuples() << "(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, " "int7 INTEGER, int8 INTEGER, int9 INTEGER, int10 INTEGER, int11 INTEGER, int12 INTEGER, int13 INTEGER," "int14 INTEGER, int15 INTEGER, int16 INTEGER, int17 INTEGER, int18 INTEGER, int19 INTEGER)", now; } @@ -765,8 +765,8 @@ void ODBCOracleTest::recreateTuplesTable() void ODBCOracleTest::recreateVectorsTable() { - dropObject("TABLE", "Vectors"); - try { *_pSession << "CREATE TABLE Vectors (int0 INTEGER, flt0 NUMBER(5,2), str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::vectors()); + try { *_pSession << "CREATE TABLE " << ExecUtil::vectors() << " (int0 INTEGER, flt0 NUMBER(5,2), str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateVectorsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateVectorsTable()"); } } @@ -774,8 +774,8 @@ void ODBCOracleTest::recreateVectorsTable() void ODBCOracleTest::recreateAnysTable() { - dropObject("TABLE", "Anys"); - try { *_pSession << "CREATE TABLE Anys (int0 INTEGER, flt0 NUMBER, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::anys() ); + try { *_pSession << "CREATE TABLE " << ExecUtil::anys() << " (int0 INTEGER, flt0 NUMBER, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateAnysTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateAnysTable()"); } } @@ -783,8 +783,8 @@ void ODBCOracleTest::recreateAnysTable() void ODBCOracleTest::recreateNullsTable(const std::string& notNull) { - dropObject("TABLE", "NullTest"); - try { *_pSession << format("CREATE TABLE NullTest (i INTEGER %s, r NUMBER %s, v VARCHAR(30) %s)", + dropObject("TABLE", ExecUtil::nulltest()); + try { *_pSession << format("CREATE TABLE %s (i INTEGER %s, r NUMBER %s, v VARCHAR(30) %s)",ExecUtil::nulltest(), notNull, notNull, notNull), now; } @@ -795,10 +795,10 @@ void ODBCOracleTest::recreateNullsTable(const std::string& notNull) void ODBCOracleTest::recreateMiscTable() { - dropObject("TABLE", "MiscTest"); + dropObject("TABLE", ExecUtil::misctest()); try { - session() << "CREATE TABLE MiscTest " + session() << "CREATE TABLE " << ExecUtil::misctest() << "(First VARCHAR(30)," "Second BLOB," "Third INTEGER," @@ -811,8 +811,8 @@ void ODBCOracleTest::recreateMiscTable() void ODBCOracleTest::recreateLogTable() { - dropObject("TABLE", "T_POCO_LOG"); - dropObject("TABLE", "T_POCO_LOG_ARCHIVE"); + dropObject("TABLE", ExecUtil::pocolog());; + dropObject("TABLE", ExecUtil::pocolog_a());; try { @@ -826,8 +826,8 @@ void ODBCOracleTest::recreateLogTable() "Text VARCHAR(100)," "DateTime TIMESTAMP)"; - session() << sql, "T_POCO_LOG", now; - session() << sql, "T_POCO_LOG_ARCHIVE", now; + session() << sql, ExecUtil::pocolog(), now; + session() << sql, ExecUtil::pocolog_a(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); } @@ -857,6 +857,7 @@ CppUnit::Test* ODBCOracleTest::suite() CppUnit_addTest(pSuite, ODBCOracleTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCOracleTest, testZeroRows); + CppUnit_addTest(pSuite, ODBCOracleTest, testSyntaxError); CppUnit_addTest(pSuite, ODBCOracleTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCOracleTest, testComplexType); CppUnit_addTest(pSuite, ODBCOracleTest, testComplexTypeTuple); diff --git a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp index a4f9b95d6..6b2bcdeb2 100644 --- a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp @@ -21,6 +21,7 @@ #include "Poco/Data/ODBC/Diagnostics.h" #include "Poco/Data/ODBC/ODBCException.h" #include <iostream> +#include "Poco/Environment.h" using namespace Poco::Data::Keywords; @@ -58,12 +59,42 @@ using Poco::DateTime; #endif #define POSTGRESQL_SERVER POCO_ODBC_TEST_DATABASE_SERVER -#define POSTGRESQL_PORT "5432" -#define POSTGRESQL_DB "postgres" -#define POSTGRESQL_UID "postgres" -#define POSTGRESQL_PWD "postgres" + +static std::string postgreSchema() +{ + return Poco::Environment::get("POCO_TEST_POSTGRES_SCHEMA", "public"); +} + + +static std::string postgreDriver() +{ + return Poco::Environment::get("POCO_TEST_POSTGRES_DRIVER", POSTGRESQL_ODBC_DRIVER); +} + +static std::string postgreSettings() +{ + return Poco::Environment::get("POCO_TEST_POSTGRES_SETTINGS", ""); +} + #define POSTGRESQL_VERSION "9.3" +static std::string postgreConnParams() +{ + return Poco::Environment::get("POCO_TEST_POSTGRES_CONN", "DATABASE=postgres;" + "SERVER=postgres;" + "PORT=5432;"); +} + +static std::string postgreUid() +{ + return Poco::Environment::get("POCO_TEST_POSTGRES_UID", ""); +} + +static std::string postgrePwd() +{ + return Poco::Environment::get("POCO_TEST_POSTGRES_PWD", ""); +} + #ifdef POCO_OS_FAMILY_WINDOWS const std::string ODBCPostgreSQLTest::_libDir = "C:\\\\Program Files\\\\PostgreSQL\\\\" POSTGRESQL_VERSION "\\\\lib\\\\"; #else @@ -73,17 +104,15 @@ const std::string ODBCPostgreSQLTest::_libDir = "/usr/local/pgsql/lib/"; ODBCTest::SessionPtr ODBCPostgreSQLTest::_pSession; ODBCTest::ExecPtr ODBCPostgreSQLTest::_pExecutor; -std::string ODBCPostgreSQLTest::_driver = POSTGRESQL_ODBC_DRIVER; +std::string ODBCPostgreSQLTest::_driver = postgreDriver(); std::string ODBCPostgreSQLTest::_dsn = POSTGRESQL_DSN; -std::string ODBCPostgreSQLTest::_uid = POSTGRESQL_UID; -std::string ODBCPostgreSQLTest::_pwd = POSTGRESQL_PWD; -std::string ODBCPostgreSQLTest::_connectString = - "DRIVER=" POSTGRESQL_ODBC_DRIVER ";" - "DATABASE=" POSTGRESQL_DB ";" - "SERVER=" POSTGRESQL_SERVER ";" - "PORT=" POSTGRESQL_PORT ";" - "UID=" POSTGRESQL_UID ";" - "PWD=" POSTGRESQL_PWD ";" +std::string ODBCPostgreSQLTest::_uid = postgreUid(); +std::string ODBCPostgreSQLTest::_pwd = postgrePwd(); +std::string ODBCPostgreSQLTest::_connectString = + "DRIVER=" + postgreDriver() + ";" + + postgreConnParams() + ";" + + "UID=" + postgreUid() + ";" + "PWD=" + postgrePwd() + ";" "SSLMODE=prefer;" "LowerCaseIdentifier=0;" "UseServerSidePrepare=0;" @@ -108,7 +137,7 @@ std::string ODBCPostgreSQLTest::_connectString = "UnknownSizes=0;" "Socket=8192;" "Fetch=100;" - "ConnSettings=;" + "ConnSettings=" + postgreSettings() + ";" "ShowSystemTables=0;" "RowVersioning=0;" "ShowOidColumn=0;" @@ -129,7 +158,7 @@ ODBCPostgreSQLTest::~ODBCPostgreSQLTest() void ODBCPostgreSQLTest::testBareboneODBC() { - std::string tableCreateString = "CREATE TABLE Test " + std::string tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third BYTEA," @@ -142,7 +171,7 @@ void ODBCPostgreSQLTest::testBareboneODBC() executor().bareboneODBCTest(_connectString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); executor().bareboneODBCTest(_connectString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); - tableCreateString = "CREATE TABLE Test " + tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third BYTEA," @@ -157,7 +186,7 @@ void ODBCPostgreSQLTest::testBareboneODBC() //neither pSQL ODBC nor Mammoth drivers support multiple results properly /* - tableCreateString = "CREATE TABLE Test " + tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second INTEGER," "Third FLOAT)"; @@ -201,17 +230,18 @@ void ODBCPostgreSQLTest::testStoredFunction() { configurePLPgSQL(); - std::string func("testStoredFunction()"); + const std::string func("testStoredFunction()"); + const std::string nm = ExecUtil::stored_func(); for (int k = 0; k < 8;) { session().setFeature("autoBind", bindValue(k)); session().setFeature("autoExtract", bindValue(k+1)); - dropObject("FUNCTION", "storedFunction()"); + dropObject("FUNCTION", nm + "()"); try { - session() << "CREATE FUNCTION storedFunction() RETURNS INTEGER AS '" + session() << "CREATE FUNCTION " << nm << "() RETURNS INTEGER AS '" "BEGIN " " return -1; " "END;'" @@ -221,13 +251,13 @@ void ODBCPostgreSQLTest::testStoredFunction() catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (func); } int i = 0; - session() << "{? = call storedFunction()}", out(i), now; + session() << "{? = call "<< nm << "()}", out(i), now; assert(-1 == i); - dropObject("FUNCTION", "storedFunction()"); + dropObject("FUNCTION", nm + "(INTEGER)"); try { - session() << "CREATE FUNCTION storedFunction(INTEGER) RETURNS INTEGER AS '" + session() << "CREATE FUNCTION " << nm << "(INTEGER) RETURNS INTEGER AS '" "BEGIN " " RETURN $1 * $1; " "END;'" @@ -238,14 +268,14 @@ void ODBCPostgreSQLTest::testStoredFunction() i = 2; int result = 0; - session() << "{? = call storedFunction(?)}", out(result), in(i), now; + session() << "{? = call " << nm << "(?)}", out(result), in(i), now; assert(4 == result); - dropObject("FUNCTION", "storedFunction(INTEGER)"); + dropObject("FUNCTION", nm + "(INTEGER)"); - dropObject("FUNCTION", "storedFunction(TIMESTAMP)"); + dropObject("FUNCTION", nm + "(TIMESTAMP)"); try { - session() << "CREATE FUNCTION storedFunction(TIMESTAMP) RETURNS TIMESTAMP AS '" + session() << "CREATE FUNCTION " << nm << "(TIMESTAMP) RETURNS TIMESTAMP AS '" "BEGIN " " RETURN $1; " "END;'" @@ -256,14 +286,14 @@ void ODBCPostgreSQLTest::testStoredFunction() DateTime dtIn(1965, 6, 18, 5, 35, 1); DateTime dtOut; - session() << "{? = call storedFunction(?)}", out(dtOut), in(dtIn), now; + session() << "{? = call " << nm << "(?)}", out(dtOut), in(dtIn), now; assert(dtOut == dtIn); - dropObject("FUNCTION", "storedFunction(TIMESTAMP)"); + dropObject("FUNCTION", nm + "(TIMESTAMP)"); - dropObject("FUNCTION", "storedFunction(TEXT, TEXT)"); + dropObject("FUNCTION", nm + "(TEXT, TEXT)"); try { - session() << "CREATE FUNCTION storedFunction(TEXT,TEXT) RETURNS TEXT AS '" + session() << "CREATE FUNCTION " << nm << "(TEXT,TEXT) RETURNS TEXT AS '" "BEGIN " " RETURN $1 || '', '' || $2 || ''!'';" "END;'" @@ -277,13 +307,13 @@ void ODBCPostgreSQLTest::testStoredFunction() std::string ret; try { - session() << "{? = call storedFunction(?,?)}", out(ret), in(param1), in(param2), now; + session() << "{? = call " << nm << "(?,?)}", out(ret), in(param1), in(param2), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (func); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (func); } assert(ret == "Hello, world!"); - dropObject("FUNCTION", "storedFunction(TEXT, TEXT)"); + dropObject("FUNCTION", nm + "(TEXT, TEXT)"); k += 2; } @@ -292,7 +322,10 @@ void ODBCPostgreSQLTest::testStoredFunction() void ODBCPostgreSQLTest::testStoredFunctionAny() { - session() << "CREATE FUNCTION storedFunction(INTEGER) RETURNS INTEGER AS '" + const std::string nm = ExecUtil::stored_func(); + + dropObject("FUNCTION", nm + "(INTEGER)"); + session() << "CREATE FUNCTION "<< nm << "(INTEGER) RETURNS INTEGER AS '" "BEGIN " " RETURN $1 * $1; " "END;'" @@ -305,19 +338,23 @@ void ODBCPostgreSQLTest::testStoredFunctionAny() Any i = 2; Any result = 0; - session() << "{? = call storedFunction(?)}", out(result), in(i), now; + session() << "{? = call " << nm << "(?)}", out(result), in(i), now; assert(4 == AnyCast<int>(result)); k += 2; } - dropObject("FUNCTION", "storedFunction(INTEGER)"); + dropObject("FUNCTION", nm + "(INTEGER)"); } void ODBCPostgreSQLTest::testStoredFunctionDynamicAny() { - session() << "CREATE FUNCTION storedFunction(INTEGER) RETURNS INTEGER AS '" + const std::string nm = ExecUtil::stored_func(); + + dropObject("FUNCTION", nm + "(INTEGER)"); + + session() << "CREATE FUNCTION " << nm << "(INTEGER) RETURNS INTEGER AS '" "BEGIN " " RETURN $1 * $1; " "END;'" @@ -330,13 +367,13 @@ void ODBCPostgreSQLTest::testStoredFunctionDynamicAny() DynamicAny i = 2; DynamicAny result = 0; - session() << "{? = call storedFunction(?)}", out(result), in(i), now; + session() << "{? = call " << nm << "(?)}", out(result), in(i), now; assert(4 == result); k += 2; } - dropObject("FUNCTION", "storedFunction(INTEGER)"); + dropObject("FUNCTION", nm + "(INTEGER)"); } @@ -390,8 +427,8 @@ void ODBCPostgreSQLTest::dropObject(const std::string& type, const std::string& void ODBCPostgreSQLTest::recreateNullableTable() { - dropObject("TABLE", "NullableTest"); - try { *_pSession << "CREATE TABLE NullableTest (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat FLOAT NULL , EmptyDateTime TIMESTAMP NULL)", now; } + dropObject("TABLE", ExecUtil::nullabletest()); + try { *_pSession << "CREATE TABLE "<< ExecUtil::nullabletest() << " (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat FLOAT NULL , EmptyDateTime TIMESTAMP NULL)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -399,8 +436,8 @@ void ODBCPostgreSQLTest::recreateNullableTable() void ODBCPostgreSQLTest::recreatePersonTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -408,8 +445,8 @@ void ODBCPostgreSQLTest::recreatePersonTable() void ODBCPostgreSQLTest::recreatePersonBLOBTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BYTEA)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BYTEA)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } } @@ -418,8 +455,8 @@ void ODBCPostgreSQLTest::recreatePersonBLOBTable() void ODBCPostgreSQLTest::recreatePersonDateTimeTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born TIMESTAMP)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born TIMESTAMP)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } } @@ -427,8 +464,8 @@ void ODBCPostgreSQLTest::recreatePersonDateTimeTable() void ODBCPostgreSQLTest::recreatePersonDateTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTable()"); } } @@ -436,8 +473,8 @@ void ODBCPostgreSQLTest::recreatePersonDateTable() void ODBCPostgreSQLTest::recreatePersonTimeTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornTime TIME)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornTime TIME)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTimeTable()"); } } @@ -445,8 +482,8 @@ void ODBCPostgreSQLTest::recreatePersonTimeTable() void ODBCPostgreSQLTest::recreateIntsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str INTEGER)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateIntsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateIntsTable()"); } } @@ -454,8 +491,8 @@ void ODBCPostgreSQLTest::recreateIntsTable() void ODBCPostgreSQLTest::recreateStringsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateStringsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateStringsTable()"); } } @@ -463,8 +500,8 @@ void ODBCPostgreSQLTest::recreateStringsTable() void ODBCPostgreSQLTest::recreateFloatsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str FLOAT)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str FLOAT)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateFloatsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateFloatsTable()"); } } @@ -472,8 +509,8 @@ void ODBCPostgreSQLTest::recreateFloatsTable() void ODBCPostgreSQLTest::recreateTuplesTable() { - dropObject("TABLE", "Tuples"); - try { session() << "CREATE TABLE Tuples " + dropObject("TABLE", ExecUtil::tuples()); + try { session() << "CREATE TABLE " << ExecUtil::tuples() << "(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, " "int7 INTEGER, int8 INTEGER, int9 INTEGER, int10 INTEGER, int11 INTEGER, int12 INTEGER, int13 INTEGER," "int14 INTEGER, int15 INTEGER, int16 INTEGER, int17 INTEGER, int18 INTEGER, int19 INTEGER)", now; } @@ -484,8 +521,8 @@ void ODBCPostgreSQLTest::recreateTuplesTable() void ODBCPostgreSQLTest::recreateVectorsTable() { - dropObject("TABLE", "Vectors"); - try { session() << "CREATE TABLE Vectors (int0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::vectors()); + try { session() << "CREATE TABLE " << ExecUtil::vectors() << " (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateVectorsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateVectorsTable()"); } } @@ -493,8 +530,8 @@ void ODBCPostgreSQLTest::recreateVectorsTable() void ODBCPostgreSQLTest::recreateAnysTable() { - dropObject("TABLE", "Anys"); - try { session() << "CREATE TABLE Anys (int0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::anys() ); + try { session() << "CREATE TABLE " << ExecUtil::anys() << " (int0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateAnysTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateAnysTable()"); } } @@ -502,8 +539,8 @@ void ODBCPostgreSQLTest::recreateAnysTable() void ODBCPostgreSQLTest::recreateNullsTable(const std::string& notNull) { - dropObject("TABLE", "NullTest"); - try { session() << format("CREATE TABLE NullTest (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)", + dropObject("TABLE", ExecUtil::nulltest()); + try { session() << format("CREATE TABLE %s (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)",ExecUtil::nulltest(), notNull, notNull, notNull), now; } @@ -523,11 +560,11 @@ void ODBCPostgreSQLTest::recreateBoolTable() void ODBCPostgreSQLTest::recreateMiscTable() { - dropObject("TABLE", "MiscTest"); + dropObject("TABLE", ExecUtil::misctest()); try { // Mammoth does not bind columns properly - session() << "CREATE TABLE MiscTest " + session() << "CREATE TABLE "<< ExecUtil::misctest() << "(First VARCHAR(30)," "Second BYTEA," "Third INTEGER," @@ -540,8 +577,8 @@ void ODBCPostgreSQLTest::recreateMiscTable() void ODBCPostgreSQLTest::recreateLogTable() { - dropObject("TABLE", "T_POCO_LOG"); - dropObject("TABLE", "T_POCO_LOG_ARCHIVE"); + dropObject("TABLE", ExecUtil::pocolog());; + dropObject("TABLE", ExecUtil::pocolog_a());; try { @@ -555,8 +592,8 @@ void ODBCPostgreSQLTest::recreateLogTable() "Text VARCHAR," "DateTime TIMESTAMP)"; - session() << sql, "T_POCO_LOG", now; - session() << sql, "T_POCO_LOG_ARCHIVE", now; + session() << sql, ExecUtil::pocolog(), now; + session() << sql, ExecUtil::pocolog_a(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); } @@ -580,12 +617,20 @@ CppUnit::Test* ODBCPostgreSQLTest::suite() { std::cout << "*** Connected to [" << _driver << "] test database." << std::endl; - _pExecutor = new SQLExecutor(_driver + " SQL Executor", _pSession); + std::string initSql; + if (!postgreSchema().empty()) + { + initSql = "SET search_path TO " + postgreSchema() + (postgreSchema() != std::string("public") ? ", public;" : ";"); + (*_pSession) << initSql, now; + } + + _pExecutor = new SQLExecutor(_driver + " SQL Executor", _pSession, initSql, postgreSchema()); CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCPostgreSQLTest"); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testZeroRows); + CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSyntaxError); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testComplexType); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccessVector); @@ -668,7 +713,8 @@ CppUnit::Test* ODBCPostgreSQLTest::suite() CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAny); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testDynamicAny); //neither pSQL ODBC nor Mammoth drivers support multiple results properly - //CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults); + CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults); + CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResultsNoProj); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLChannel); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLLogger); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSessionTransaction); @@ -677,6 +723,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite() CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testNullable); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testUnicode); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testReconnect); + CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInsertStatReuse); return pSuite; } diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp index 3ba078628..f2d39fdf1 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp @@ -121,7 +121,7 @@ ODBCSQLServerTest::~ODBCSQLServerTest() void ODBCSQLServerTest::testBareboneODBC() { - std::string tableCreateString = "CREATE TABLE Test " + std::string tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third VARBINARY(30)," @@ -138,7 +138,7 @@ void ODBCSQLServerTest::testBareboneODBC() executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, true, "CONVERT(VARBINARY(30),?)"); - tableCreateString = "CREATE TABLE Test " + tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second INTEGER," "Third FLOAT)"; @@ -334,13 +334,13 @@ void ODBCSQLServerTest::testCursorStoredProcedure() people.push_back(Person("Simpson", "Homer", "Springfield", 42)); people.push_back(Person("Simpson", "Bart", "Springfield", 12)); people.push_back(Person("Simpson", "Lisa", "Springfield", 10)); - session() << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now; + session() << "INSERT INTO " << ExecUtil::person() << " VALUES (?, ?, ?, ?)", use(people), now; dropObject("PROCEDURE", "storedCursorProcedure"); session() << "CREATE PROCEDURE storedCursorProcedure(@ageLimit int) AS " "BEGIN " " SELECT * " - " FROM Person " + " FROM " << ExecUtil::person() << " WHERE Age < @ageLimit " " ORDER BY Age DESC; " "END;" @@ -362,7 +362,7 @@ void ODBCSQLServerTest::testCursorStoredProcedure() assert (rs["Address"] == "Springfield"); assert (rs["Age"] == 12); - dropObject("TABLE", "Person"); + dropObject("TABLE", ExecUtil::person()); dropObject("PROCEDURE", "storedCursorProcedure"); k += 2; @@ -553,8 +553,8 @@ void ODBCSQLServerTest::dropObject(const std::string& type, const std::string& n void ODBCSQLServerTest::recreateNullableTable() { - dropObject("TABLE", "NullableTest"); - try { *_pSession << "CREATE TABLE NullableTest (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat FLOAT NULL , EmptyDateTime DATETIME NULL)", now; } + dropObject("TABLE", ExecUtil::nullabletest()); + try { *_pSession << "CREATE TABLE " << ExecUtil::nullabletest() << " (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat FLOAT NULL , EmptyDateTime DATETIME NULL)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -562,8 +562,8 @@ void ODBCSQLServerTest::recreateNullableTable() void ODBCSQLServerTest::recreatePersonTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -571,8 +571,8 @@ void ODBCSQLServerTest::recreatePersonTable() void ODBCSQLServerTest::recreatePersonBLOBTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image VARBINARY(MAX))", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image VARBINARY(MAX))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } } @@ -580,8 +580,8 @@ void ODBCSQLServerTest::recreatePersonBLOBTable() void ODBCSQLServerTest::recreatePersonDateTimeTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born DATETIME)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born DATETIME)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } } @@ -589,8 +589,8 @@ void ODBCSQLServerTest::recreatePersonDateTimeTable() void ODBCSQLServerTest::recreateIntsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str INTEGER)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateIntsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateIntsTable()"); } } @@ -598,8 +598,8 @@ void ODBCSQLServerTest::recreateIntsTable() void ODBCSQLServerTest::recreateStringsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateStringsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateStringsTable()"); } } @@ -607,8 +607,8 @@ void ODBCSQLServerTest::recreateStringsTable() void ODBCSQLServerTest::recreateFloatsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str FLOAT)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str FLOAT)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateFloatsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateFloatsTable()"); } } @@ -616,8 +616,8 @@ void ODBCSQLServerTest::recreateFloatsTable() void ODBCSQLServerTest::recreateTuplesTable() { - dropObject("TABLE", "Tuples"); - try { session() << "CREATE TABLE Tuples " + dropObject("TABLE", ExecUtil::tuples()); + try { session() << "CREATE TABLE " << ExecUtil::tuples() << "(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, " "int7 INTEGER, int8 INTEGER, int9 INTEGER, int10 INTEGER, int11 INTEGER, int12 INTEGER, int13 INTEGER," "int14 INTEGER, int15 INTEGER, int16 INTEGER, int17 INTEGER, int18 INTEGER, int19 INTEGER)", now; } @@ -637,8 +637,8 @@ void ODBCSQLServerTest::recreateVectorTable() void ODBCSQLServerTest::recreateVectorsTable() { - dropObject("TABLE", "Vectors"); - try { session() << "CREATE TABLE Vectors (int0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::vectors()); + try { session() << "CREATE TABLE " << ExecUtil::vectors() << " (int0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateVectorsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateVectorsTable()"); } } @@ -646,8 +646,8 @@ void ODBCSQLServerTest::recreateVectorsTable() void ODBCSQLServerTest::recreateAnysTable() { - dropObject("TABLE", "Anys"); - try { session() << "CREATE TABLE Anys (int0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::anys() ); + try { session() << "CREATE TABLE " << ExecUtil::anys() << " (int0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateAnysTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateAnysTable()"); } } @@ -655,8 +655,8 @@ void ODBCSQLServerTest::recreateAnysTable() void ODBCSQLServerTest::recreateNullsTable(const std::string& notNull) { - dropObject("TABLE", "NullTest"); - try { session() << format("CREATE TABLE NullTest (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)", + dropObject("TABLE", ExecUtil::nulltest()); + try { session() << format("CREATE TABLE %s (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)", ExecUtil::nulltest(), notNull, notNull, notNull), now; } @@ -675,10 +675,10 @@ void ODBCSQLServerTest::recreateBoolTable() void ODBCSQLServerTest::recreateMiscTable() { - dropObject("TABLE", "MiscTest"); + dropObject("TABLE", ExecUtil::misctest()); try { - session() << "CREATE TABLE MiscTest " + session() << "CREATE TABLE "<< ExecUtil::misctest() << "(First VARCHAR(30)," "Second VARBINARY(30)," "Third INTEGER," @@ -692,8 +692,8 @@ void ODBCSQLServerTest::recreateMiscTable() void ODBCSQLServerTest::recreateLogTable() { - dropObject("TABLE", "T_POCO_LOG"); - dropObject("TABLE", "T_POCO_LOG_ARCHIVE"); + dropObject("TABLE", ExecUtil::pocolog());; + dropObject("TABLE", ExecUtil::pocolog_a());; try { @@ -707,8 +707,8 @@ void ODBCSQLServerTest::recreateLogTable() "Text VARCHAR(max)," "DateTime DATETIME)"; - session() << sql, "T_POCO_LOG", now; - session() << sql, "T_POCO_LOG_ARCHIVE", now; + session() << sql, ExecUtil::pocolog(), now; + session() << sql, ExecUtil::pocolog_a(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); } @@ -738,6 +738,7 @@ CppUnit::Test* ODBCSQLServerTest::suite() CppUnit_addTest(pSuite, ODBCSQLServerTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCSQLServerTest, testZeroRows); + CppUnit_addTest(pSuite, ODBCSQLServerTest, testSyntaxError); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCSQLServerTest, testComplexType); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccessVector); diff --git a/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp index 9c47b5c16..a6997deb8 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp @@ -64,7 +64,7 @@ ODBCSQLiteTest::~ODBCSQLiteTest() void ODBCSQLiteTest::testBareboneODBC() { - std::string tableCreateString = "CREATE TABLE Test " + std::string tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third BLOB," @@ -77,7 +77,7 @@ void ODBCSQLiteTest::testBareboneODBC() executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); - tableCreateString = "CREATE TABLE Test " + tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third BLOB," @@ -90,7 +90,7 @@ void ODBCSQLiteTest::testBareboneODBC() executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL); executor().bareboneODBCTest(dbConnString(), tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND); - tableCreateString = "CREATE TABLE Test " + tableCreateString = "CREATE TABLE " + ExecUtil::test_tbl() + "(First VARCHAR(30)," "Second VARCHAR(30)," "Third BLOB," @@ -169,8 +169,8 @@ void ODBCSQLiteTest::dropObject(const std::string& type, const std::string& name void ODBCSQLiteTest::recreateNullableTable() { - dropObject("TABLE", "NullableTest"); - try { *_pSession << "CREATE TABLE NullableTest (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat REAL NULL , EmptyDateTime TIMESTAMP NULL)", now; } + dropObject("TABLE", ExecUtil::nullabletest()); + try { *_pSession << "CREATE TABLE " << ExecUtil::nullabletest() << " (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat REAL NULL , EmptyDateTime TIMESTAMP NULL)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -178,8 +178,8 @@ void ODBCSQLiteTest::recreateNullableTable() void ODBCSQLiteTest::recreatePersonTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonTable()"); } } @@ -187,8 +187,8 @@ void ODBCSQLiteTest::recreatePersonTable() void ODBCSQLiteTest::recreatePersonBLOBTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonBLOBTable()"); } } @@ -196,8 +196,8 @@ void ODBCSQLiteTest::recreatePersonBLOBTable() void ODBCSQLiteTest::recreatePersonDateTimeTable() { - dropObject("TABLE", "Person"); - try { session() << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born TIMESTAMP)", now; } + dropObject("TABLE", ExecUtil::person()); + try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born TIMESTAMP)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonDateTimeTable()"); } } @@ -205,8 +205,8 @@ void ODBCSQLiteTest::recreatePersonDateTimeTable() void ODBCSQLiteTest::recreateIntsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str INTEGER)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str INTEGER)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateIntsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateIntsTable()"); } } @@ -214,8 +214,8 @@ void ODBCSQLiteTest::recreateIntsTable() void ODBCSQLiteTest::recreateStringsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str VARCHAR(30))", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str VARCHAR(30))", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateStringsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateStringsTable()"); } } @@ -223,8 +223,8 @@ void ODBCSQLiteTest::recreateStringsTable() void ODBCSQLiteTest::recreateFloatsTable() { - dropObject("TABLE", "Strings"); - try { session() << "CREATE TABLE Strings (str REAL)", now; } + dropObject("TABLE", ExecUtil::strings()); + try { session() << "CREATE TABLE " << ExecUtil::strings() <<" (str REAL)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateFloatsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateFloatsTable()"); } } @@ -232,8 +232,8 @@ void ODBCSQLiteTest::recreateFloatsTable() void ODBCSQLiteTest::recreateTuplesTable() { - dropObject("TABLE", "Tuples"); - try { session() << "CREATE TABLE Tuples " + dropObject("TABLE", ExecUtil::tuples()); + try { session() << "CREATE TABLE " << ExecUtil::tuples() << "(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, " "int7 INTEGER, int8 INTEGER, int9 INTEGER, int10 INTEGER, int11 INTEGER, int12 INTEGER, int13 INTEGER," "int14 INTEGER, int15 INTEGER, int16 INTEGER, int17 INTEGER, int18 INTEGER, int19 INTEGER)", now; } @@ -244,8 +244,8 @@ void ODBCSQLiteTest::recreateTuplesTable() void ODBCSQLiteTest::recreateVectorsTable() { - dropObject("TABLE", "Vectors"); - try { session() << "CREATE TABLE Vectors (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now; } + dropObject("TABLE", ExecUtil::vectors() ); + try { session() << "CREATE TABLE " << ExecUtil::vectors() << " (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateVectorsTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateVectorsTable()"); } } @@ -253,8 +253,8 @@ void ODBCSQLiteTest::recreateVectorsTable() void ODBCSQLiteTest::recreateAnysTable() { - dropObject("TABLE", "Anys"); - try { session() << "CREATE TABLE Anys (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now; } + dropObject("TABLE", ExecUtil::anys() ); + try { session() << "CREATE TABLE " << ExecUtil::anys() << " (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateAnysTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateAnysTable()"); } } @@ -262,8 +262,8 @@ void ODBCSQLiteTest::recreateAnysTable() void ODBCSQLiteTest::recreateNullsTable(const std::string& notNull) { - dropObject("TABLE", "NullTest"); - try { session() << format("CREATE TABLE NullTest (i INTEGER %s, r REAL %s, v VARCHAR(30) %s)", + dropObject("TABLE", ExecUtil::nulltest()); + try { session() << format("CREATE TABLE %s (i INTEGER %s, r REAL %s, v VARCHAR(30) %s)",ExecUtil::nulltest(), notNull, notNull, notNull), now; } @@ -274,11 +274,11 @@ void ODBCSQLiteTest::recreateNullsTable(const std::string& notNull) void ODBCSQLiteTest::recreateMiscTable() { - dropObject("TABLE", "MiscTest"); + dropObject("TABLE", ExecUtil::misctest()); try { // SQLite fails with BLOB bulk operations - session() << "CREATE TABLE MiscTest " + session() << "CREATE TABLE "<< ExecUtil::misctest() << "(First VARCHAR(30)," //"Second BLOB," "Third INTEGER," @@ -291,8 +291,8 @@ void ODBCSQLiteTest::recreateMiscTable() void ODBCSQLiteTest::recreateLogTable() { - dropObject("TABLE", "T_POCO_LOG"); - dropObject("TABLE", "T_POCO_LOG_ARCHIVE"); + dropObject("TABLE", ExecUtil::pocolog());; + dropObject("TABLE", ExecUtil::pocolog_a());; try { @@ -306,8 +306,8 @@ void ODBCSQLiteTest::recreateLogTable() "Text VARCHAR," "DateTime DATETIME)"; - session() << sql, "T_POCO_LOG", now; - session() << sql, "T_POCO_LOG_ARCHIVE", now; + session() << sql, ExecUtil::pocolog(), now; + session() << sql, ExecUtil::pocolog_a(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); } @@ -326,6 +326,7 @@ CppUnit::Test* ODBCSQLiteTest::suite() CppUnit_addTest(pSuite, ODBCSQLiteTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCSQLiteTest, testZeroRows); + CppUnit_addTest(pSuite, ODBCSQLiteTest, testSyntaxError); CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCSQLiteTest, testComplexType); CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccessVector); diff --git a/Data/ODBC/testsuite/src/ODBCTest.cpp b/Data/ODBC/testsuite/src/ODBCTest.cpp index fe1323f5d..5c57636b6 100644 --- a/Data/ODBC/testsuite/src/ODBCTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCTest.cpp @@ -22,6 +22,7 @@ #include "Poco/Exception.h" #include "Poco/Data/LOB.h" #include "Poco/Data/StatementImpl.h" +#include "Poco/Data/RecordSet.h" #include "Poco/Data/ODBC/Connector.h" #include "Poco/Data/ODBC/Utility.h" #include "Poco/Data/ODBC/Diagnostics.h" @@ -41,6 +42,7 @@ using Poco::Data::ODBC::ODBCException; using Poco::Data::ODBC::ConnectionException; using Poco::Data::ODBC::StatementException; using Poco::Data::ODBC::StatementDiagnostics; +using Poco::Data::Statement; using Poco::format; using Poco::Tuple; using Poco::Any; @@ -1029,7 +1031,7 @@ void ODBCTest::testNull() recreateNullsTable(); _pSession->setFeature("autoBind", bindValue(i)); _pSession->setFeature("autoExtract", bindValue(i+1)); - _pExecutor->nulls(); + _pExecutor->nulls(emptyStringIsSpace()); i += 2; } } @@ -1127,6 +1129,20 @@ void ODBCTest::testMultipleResults() } } +void ODBCTest::testMultipleResultsNoProj() +{ + if (! &session()) fail("Test not available."); + session().setFeature("autoBind", true); // DB2 fails without that + for (int autoE = 0; autoE < 2; ++autoE) + { + recreatePersonTable(); + _pSession->setFeature("autoExtract", autoE != 0); + _pExecutor->multipleResultsNoProj("SELECT * FROM " + ExecUtil::person() + " WHERE Age = ?; " + "SELECT Age FROM " + ExecUtil::person() + " WHERE FirstName = ?; " + "SELECT * FROM " + ExecUtil::person() + " WHERE Age = ? OR Age = ? ORDER BY Age;"); + } +} + void ODBCTest::testSQLChannel() { @@ -1219,6 +1235,46 @@ void ODBCTest::testNullable() } } +void ODBCTest::testNumeric() +{ + if (!_pSession) fail("Test not available."); + + recreateNumericTable(); + std::vector<std::string> vals; + vals.push_back("12345678"); + vals.push_back("123456789012.123"); + vals.push_back("123456789012345678"); + vals.push_back("1234567890.12345678"); + vals.push_back("1234567890123456789012"); + + const std::string sqlStr = std::string("INSERT INTO ") + ExecUtil::numeric_tbl() + + "(id, num8, num16_3, num18, num18_8, num22) VALUES (1, " + str2NumExpr(vals[0],8,0) + " , " + str2NumExpr(vals[1],16,3) + ", " + str2NumExpr(vals[2], 18,0) + + " , " + str2NumExpr(vals[3], 18, 8) + " , " + str2NumExpr(vals[4], 22, 0) + ")"; + + session() << sqlStr, now; + + for (int i = 0; i < 8;) + { + _pSession->setFeature("autoBind", bindValue(i)); + _pSession->setFeature("autoExtract", bindValue(i + 1)); + _pExecutor->numericTypes(vals); + i += 2; + } +} + + +void ODBCTest::testInsertStatReuse() +{ + for (int i = 0; i < 8; i += 2) + { + recreatePersonTable(); + session().setFeature("autoBind", bindValue(i)); + session().setFeature("autoExtract", bindValue(i + 1)); + + _pExecutor->insertStatReuse(); + } +} + void ODBCTest::testUnicode() { @@ -1256,6 +1312,28 @@ void ODBCTest::testReconnect() } +void ODBCTest::testSyntaxError() +{ + try { + session() << "select fro oops", now; + fail("Expected syntax error exception"); + } + catch (const StatementException&) + { + } + + try { + Statement stat(session()); + stat << "select fro oops"; + stat.execute(); + fail("Expected syntax error exception"); + } + catch (const StatementException&) + { + } +} + + bool ODBCTest::canConnect(const std::string& driver, std::string& dsn, std::string& uid, @@ -1274,7 +1352,7 @@ bool ODBCTest::canConnect(const std::string& driver, } } - if (_drivers.end() == itDrv) + if ((_drivers.end() == itDrv) && (driver.length() != 0) && (driver[0] != '/')) { dsn = ""; uid = ""; diff --git a/Data/ODBC/testsuite/src/ODBCTest.h b/Data/ODBC/testsuite/src/ODBCTest.h index a0a09c01d..aa0591a21 100644 --- a/Data/ODBC/testsuite/src/ODBCTest.h +++ b/Data/ODBC/testsuite/src/ODBCTest.h @@ -141,6 +141,7 @@ public: virtual void testDynamicAny(); virtual void testMultipleResults(); + virtual void testMultipleResultsNoProj(); virtual void testSQLChannel(); virtual void testSQLLogger(); @@ -153,6 +154,9 @@ public: virtual void testUnicode(); virtual void testReconnect(); + virtual void testNumeric(); + virtual void testSyntaxError(); + virtual void testInsertStatReuse(); protected: typedef Poco::Data::ODBC::Utility::DriverMap Drivers; @@ -176,6 +180,9 @@ protected: virtual void recreateMiscTable(); virtual void recreateLogTable(); virtual void recreateUnicodeTable(); + virtual void recreateNumericTable(); + virtual bool emptyStringIsSpace() { return false; } + virtual std::string str2NumExpr(const std::string& num, unsigned len, unsigned dec) { return num; } static SessionPtr init(const std::string& driver, std::string& dsn, @@ -264,6 +271,11 @@ inline void ODBCTest::recreateNullableTable() throw Poco::NotImplementedException("ODBCTest::recreateNullableTable()"); } +inline void ODBCTest::recreateNumericTable() +{ + throw Poco::NotImplementedException("ODBCTest::recreateNumericTable()"); +} + inline void ODBCTest::recreatePersonTable() { diff --git a/Data/ODBC/testsuite/src/ODBCTestSuite.cpp b/Data/ODBC/testsuite/src/ODBCTestSuite.cpp index 08d8e4138..734cf7d8d 100644 --- a/Data/ODBC/testsuite/src/ODBCTestSuite.cpp +++ b/Data/ODBC/testsuite/src/ODBCTestSuite.cpp @@ -12,6 +12,7 @@ #include "ODBCTestSuite.h" #include "ODBCDB2Test.h" +#include "ODBCSybaseTest.h" #include "ODBCMySQLTest.h" #include "ODBCOracleTest.h" #include "ODBCPostgreSQLTest.h" @@ -44,6 +45,7 @@ CppUnit::Test* ODBCTestSuite::suite() addTest(pSuite, ODBCPostgreSQLTest::suite()); addTest(pSuite, ODBCSQLiteTest::suite()); addTest(pSuite, ODBCSQLServerTest::suite()); + addTest(pSuite, SybaseODBC::suite()); addTest(pSuite, ODBCDB2Test::suite()); // MS Access driver does not support connection status detection // disabled for the time being diff --git a/Data/ODBC/testsuite/src/SQLExecutor.cpp b/Data/ODBC/testsuite/src/SQLExecutor.cpp index 9baf6d7f4..62bf10194 100644 --- a/Data/ODBC/testsuite/src/SQLExecutor.cpp +++ b/Data/ODBC/testsuite/src/SQLExecutor.cpp @@ -48,6 +48,8 @@ #include "Poco/Data/ODBC/ODBCStatementImpl.h" #include "Poco/UnicodeConverter.h" #include "Poco/UTFString.h" +#include "Poco/Environment.h" +#include "Poco/Checksum.h" #include <sqltypes.h> #include <iostream> #include <sstream> @@ -100,6 +102,36 @@ using Poco::UnicodeConverter; using Poco::UTF16String; using Poco::UTF32String; + + +static +std::string idGen() +{ + std::string host = Poco::Environment::nodeName() + "_" + +#if defined(POCO_OS_FAMILY_WINDOWS) + Poco::Environment::get("USERNAME"); +#else + Poco::Environment::get("USER", "U"); +#endif + if (host.length() > 12) //Sybase has got 30 char length limit + { + Poco::Checksum crc; + crc.update(host); + host = Poco::format("%s%X", host.substr(0, 4), crc.checksum()); + } + std::replace(host.begin(), host.end(), '.', '_'); + std::replace(host.begin(), host.end(), '-', '_'); + return host; +} + +std::string ExecUtil::mangleTable(const std::string& name) +{ + static std::string id = idGen(); + const std::string nm = "pt_" + name + id; + poco_assert_dbg(nm.length() <= 30); + return nm; +} + struct Person { std::string lastName; @@ -173,6 +205,11 @@ private: RefCountedPerson& operator = (const RefCountedPerson&); }; +#define assertTU(tu, condition) \ + (tu->assertImpl((condition), (#condition), __LINE__, __FILE__)) + +#define failTU(tu, message) \ + (tu->failImpl(message, __LINE__, __FILE__)) namespace Poco { namespace Data { @@ -284,23 +321,25 @@ private: const std::string SQLExecutor::MULTI_INSERT = - "INSERT INTO Test VALUES ('1', 2, 3.5);" - "INSERT INTO Test VALUES ('2', 3, 4.5);" - "INSERT INTO Test VALUES ('3', 4, 5.5);" - "INSERT INTO Test VALUES ('4', 5, 6.5);" - "INSERT INTO Test VALUES ('5', 6, 7.5);"; + "INSERT INTO " +ExecUtil::test_tbl() + " VALUES ('1', 2, 3.5);" + + "INSERT INTO " +ExecUtil::test_tbl() + " VALUES ('2', 3, 4.5);" + + "INSERT INTO " +ExecUtil::test_tbl() + " VALUES ('3', 4, 5.5);" + + "INSERT INTO " +ExecUtil::test_tbl() + " VALUES ('4', 5, 6.5);" + + "INSERT INTO " +ExecUtil::test_tbl() + " VALUES ('5', 6, 7.5);"; const std::string SQLExecutor::MULTI_SELECT = - "SELECT * FROM Test WHERE First = '1';" - "SELECT * FROM Test WHERE First = '2';" - "SELECT * FROM Test WHERE First = '3';" - "SELECT * FROM Test WHERE First = '4';" - "SELECT * FROM Test WHERE First = '5';"; + "SELECT * FROM " +ExecUtil::test_tbl() + " WHERE First = '1';" + + "SELECT * FROM " +ExecUtil::test_tbl() + " WHERE First = '2';" + + "SELECT * FROM " +ExecUtil::test_tbl() + " WHERE First = '3';" + + "SELECT * FROM " +ExecUtil::test_tbl() + " WHERE First = '4';" + + "SELECT * FROM " +ExecUtil::test_tbl() + " WHERE First = '5';"; -SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession): +SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession, const std::string& connInitSql, const std::string& schemaName) : CppUnit::TestCase(name), - _pSession(pSession) + _pSession(pSession), + _connInitSql(connInitSql), + _schemaName(schemaName) { } @@ -372,11 +411,19 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString, rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); poco_odbc_check_stmt (rc, hstmt); + if (!_connInitSql.empty()) + { + rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + poco_odbc_check_stmt(rc, hstmt); + SQLCHAR* pStr = (SQLCHAR*)_connInitSql.c_str(); + SQLExecDirect(hstmt, pStr, (SQLINTEGER)_connInitSql.length()); + } + // Statement begin rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); poco_odbc_check_stmt (rc, hstmt); - std::string sql = "DROP TABLE Test"; + std::string sql = "DROP TABLE " + ExecUtil::test_tbl(); SQLCHAR* pStr = (SQLCHAR*) sql.c_str(); SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length()); //no return code check - ignore drop errors @@ -390,7 +437,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString, rc = SQLExecute(hstmt); poco_odbc_check_stmt (rc, hstmt); - sql = format("INSERT INTO Test VALUES (?,?,%s,?,?,?)", blobPlaceholder); + sql = format("INSERT INTO " + ExecUtil::test_tbl() + " VALUES(? , ? , %s, ? , ? , ? )", blobPlaceholder); pStr = (SQLCHAR*) sql.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); @@ -546,7 +593,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString, } poco_odbc_check_stmt (rc, hstmt); - sql = "SELECT * FROM Test"; + sql = "SELECT * FROM " + ExecUtil::test_tbl(); pStr = (SQLCHAR*) sql.c_str(); rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); @@ -703,7 +750,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString, rc = SQLCloseCursor(hstmt); poco_odbc_check_stmt (rc, hstmt); - sql = "DROP TABLE Test"; + sql = "DROP TABLE " + ExecUtil::test_tbl(); pStr = (SQLCHAR*) sql.c_str(); rc = SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); @@ -761,7 +808,7 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString, rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); poco_odbc_check_stmt (rc, hstmt); - std::string sql = "DROP TABLE Test"; + std::string sql = "DROP TABLE " + ExecUtil::test_tbl(); SQLCHAR* pStr = (SQLCHAR*) sql.c_str(); SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length()); //no return code check - ignore drop errors @@ -789,7 +836,7 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString, } while (SQL_NO_DATA != SQLMoreResults(hstmt)); // make sure all five rows made it in - sql = "select count(*) from Test"; + sql = "select count(*) from " + ExecUtil::test_tbl(); int count = 0; SQLLEN length = 0; pStr = (SQLCHAR*) sql.c_str(); @@ -914,7 +961,7 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString, assert (5 == count); - sql = "DROP TABLE Test"; + sql = "DROP TABLE " + ExecUtil::test_tbl(); pStr = (SQLCHAR*) sql.c_str(); rc = SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length()); poco_odbc_check_stmt (rc, hstmt); @@ -944,7 +991,7 @@ void SQLExecutor::execute(const std::string& sql) void SQLExecutor::zeroRows() { - Statement stmt = (session() << "SELECT * FROM Person WHERE 0 = 1"); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::person() << " WHERE 0 = 1"); assert(0 == stmt.execute()); } @@ -959,22 +1006,23 @@ void SQLExecutor::simpleAccess() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { + session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 1); - try { session() << "SELECT LastName FROM Person", into(result), now; } + try { session() << "SELECT LastName FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (lastName == result); - try { session() << "SELECT Age FROM Person", into(count), now; } + try { session() << "SELECT Age FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == age); @@ -987,22 +1035,22 @@ void SQLExecutor::complexType() Person p1("LN1", "FN1", "ADDR1", 1); Person p2("LN2", "FN2", "ADDR2", 2); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(p1), now; } + try { session() << "INSERT INTO " << ExecUtil::person() << " VALUES (?,?,?,?)", use(p1), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(p2), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(p2), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person c1; - try { session() << "SELECT * FROM Person WHERE LastName = 'LN1'", into(c1), now; } + try { session() << "SELECT * FROM " << ExecUtil::person() <<" WHERE LastName = 'LN1'", into(c1), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (c1 == p1); @@ -1016,13 +1064,13 @@ void SQLExecutor::complexTypeTuple() Person p2("LN2", "FN2", "ADDR2", 2); Tuple<Person,Person> t(p1,p2); - try { *_pSession << "INSERT INTO Person VALUES(?,?,?,?,?,?,?,?)", use(t), now; } + try { *_pSession << "INSERT INTO " << ExecUtil::person() <<" VALUES(?,?,?,?,?,?,?,?)", use(t), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } Tuple<Person,Person> ret; assert (ret != t); - try { *_pSession << "SELECT * FROM Person", into(ret), now; } + try { *_pSession << "SELECT * FROM " << ExecUtil::person(), into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ret == t); @@ -1036,7 +1084,7 @@ void SQLExecutor::simpleAccessVector() std::vector<std::string> firstNames; std::vector<std::string> addresses; std::vector<int> ages; - std::string tableName("Person"); + std::string tableName(ExecUtil::person()); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); @@ -1048,11 +1096,11 @@ void SQLExecutor::simpleAccessVector() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); @@ -1061,7 +1109,7 @@ void SQLExecutor::simpleAccessVector() std::vector<std::string> firstNamesR; std::vector<std::string> addressesR; std::vector<int> agesR; - try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ages == agesR); @@ -1078,18 +1126,18 @@ void SQLExecutor::complexTypeVector() people.push_back(Person("LN1", "FN1", "ADDR1", 1)); people.push_back(Person("LN2", "FN2", "ADDR2", 2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::vector<Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result == people); @@ -1103,18 +1151,18 @@ void SQLExecutor::sharedPtrComplexTypeVector() people.push_back(new Person("LN1", "FN1", "ADDR1", 1)); people.push_back(new Person("LN2", "FN2", "ADDR2", 2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::vector<Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (2 == result.size()); @@ -1130,18 +1178,18 @@ void SQLExecutor::autoPtrComplexTypeVector() people.push_back(new RefCountedPerson("LN1", "FN1", "ADDR1", 1)); people.push_back(new RefCountedPerson("LN2", "FN2", "ADDR2", 2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::vector<Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (2 == result.size()); @@ -1167,8 +1215,8 @@ void SQLExecutor::insertVector() int count = 100; { - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + Statement stmt((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(str))); + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 0); @@ -1176,13 +1224,13 @@ void SQLExecutor::insertVector() try { stmt.execute(); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 4); } count = 0; - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 4); @@ -1196,7 +1244,7 @@ void SQLExecutor::insertEmptyVector() try { - session() << "INSERT INTO Strings VALUES (?)", use(str), now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(str), now; fail("empty collections should not work"); } catch (Poco::Exception&) @@ -1212,7 +1260,7 @@ void SQLExecutor::simpleAccessList() std::list<std::string> firstNames; std::list<std::string> addresses; std::list<int> ages; - std::string tableName("Person"); + const std::string tableName(ExecUtil::person()); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); @@ -1224,11 +1272,11 @@ void SQLExecutor::simpleAccessList() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); @@ -1237,7 +1285,7 @@ void SQLExecutor::simpleAccessList() std::list<std::string> firstNamesR; std::list<std::string> addressesR; std::list<int> agesR; - try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ages == agesR); @@ -1254,18 +1302,18 @@ void SQLExecutor::complexTypeList() people.push_back(Person("LN1", "FN1", "ADDR1", 1)); people.push_back(Person("LN2", "FN2", "ADDR2", 2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::list<Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result == people); @@ -1283,8 +1331,8 @@ void SQLExecutor::insertList() int count = 100; { - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + Statement stmt((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(str))); + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 0); @@ -1292,13 +1340,13 @@ void SQLExecutor::insertList() try { stmt.execute(); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 4); } count = 0; - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 4); @@ -1312,7 +1360,7 @@ void SQLExecutor::insertEmptyList() try { - session() << "INSERT INTO Strings VALUES (?)", use(str), now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(str), now; fail("empty collections should not work"); } catch (Poco::Exception&) @@ -1328,7 +1376,7 @@ void SQLExecutor::simpleAccessDeque() std::deque<std::string> firstNames; std::deque<std::string> addresses; std::deque<int> ages; - std::string tableName("Person"); + const std::string tableName(ExecUtil::person()); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); @@ -1340,11 +1388,11 @@ void SQLExecutor::simpleAccessDeque() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); @@ -1353,7 +1401,7 @@ void SQLExecutor::simpleAccessDeque() std::deque<std::string> firstNamesR; std::deque<std::string> addressesR; std::deque<int> agesR; - try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ages == agesR); @@ -1370,18 +1418,18 @@ void SQLExecutor::complexTypeDeque() people.push_back(Person("LN1", "FN1", "ADDR1", 1)); people.push_back(Person("LN2", "FN2", "ADDR2", 2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::deque<Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result == people); @@ -1399,8 +1447,8 @@ void SQLExecutor::insertDeque() int count = 100; { - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(str))); - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + Statement stmt((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(str))); + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 0); @@ -1408,13 +1456,13 @@ void SQLExecutor::insertDeque() try { stmt.execute(); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 4); } count = 0; - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 4); @@ -1428,7 +1476,7 @@ void SQLExecutor::insertEmptyDeque() try { - session() << "INSERT INTO Strings VALUES (?)", use(str), now; + session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(str), now; fail("empty collections should not work"); } catch (Poco::Exception&) @@ -1446,21 +1494,21 @@ void SQLExecutor::affectedRows(const std::string& whereClause) str.push_back("s3"); int count = 100; - Statement stmt1((session() << "INSERT INTO Strings VALUES(?)", use(str))); - session() << "SELECT COUNT(*) FROM Strings", into(count), now; + Statement stmt1((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES(?)", use(str))); + session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; assert (count == 0); assert (4 == stmt1.execute()); - session() << "SELECT COUNT(*) FROM Strings", into(count), now; + session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; assert (count == 4); - Statement stmt2(session() << "UPDATE Strings SET str = 's4' WHERE str = 's3'"); + Statement stmt2(session() << "UPDATE " << ExecUtil::strings() << " SET str = 's4' WHERE str = 's3'"); assert (2 == stmt2.execute()); - Statement stmt3(session() << "DELETE FROM Strings WHERE str = 's1'"); + Statement stmt3(session() << "DELETE FROM " << ExecUtil::strings() << " WHERE str = 's1'"); assert (1 == stmt3.execute()); std::string sql; - format(sql, "DELETE FROM Strings %s", whereClause); + format(sql, "DELETE FROM %s %s", ExecUtil::strings(), whereClause); Statement stmt4(session() << sql); assert (3 == stmt4.execute()); } @@ -1470,7 +1518,7 @@ void SQLExecutor::insertSingleBulk() { std::string funct = "insertSingleBulk()"; int x = 0; - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(x))); + Statement stmt((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(x))); for (x = 0; x < 100; ++x) { @@ -1478,12 +1526,12 @@ void SQLExecutor::insertSingleBulk() assert (1 == i); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 100); - try { session() << "SELECT SUM(str) FROM Strings", into(count), now; } + try { session() << "SELECT SUM(str) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == ((0+99)*100/2)); @@ -1496,17 +1544,17 @@ void SQLExecutor::floats() float data = 1.5f; float ret = 0.0f; - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 1); - try { session() << "SELECT str FROM Strings", into(ret), now; } + try { session() << "SELECT str FROM " << ExecUtil::strings(), into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ret == data); @@ -1519,17 +1567,17 @@ void SQLExecutor::doubles() double data = 1.5; double ret = 0.0; - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 1); - try { session() << "SELECT str FROM Strings", into(ret), now; } + try { session() << "SELECT str FROM " << ExecUtil::strings(), into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ret == data); @@ -1544,16 +1592,16 @@ void SQLExecutor::insertSingleBulkVec() for (int x = 0; x < 100; ++x) data.push_back(x); - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(data))); + Statement stmt((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(data))); stmt.execute(); int count = 0; - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 100); - try { session() << "SELECT SUM(str) FROM Strings", into(count), now; } + try { session() << "SELECT SUM(str) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == ((0+99)*100/2)); @@ -1569,12 +1617,12 @@ void SQLExecutor::limits() data.push_back(x); } - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } std::vector<int> retData; - try { session() << "SELECT * FROM Strings", into(retData), limit(50), now; } + try { session() << "SELECT * FROM " << ExecUtil::strings(), into(retData), limit(50), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (retData.size() == 50); @@ -1594,12 +1642,12 @@ void SQLExecutor::limitZero() data.push_back(x); } - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } std::vector<int> retData; - try { session() << "SELECT * FROM Strings", into(retData), limit(0), now; }// stupid test, but at least we shouldn't crash + try { session() << "SELECT * FROM " << ExecUtil::strings(), into(retData), limit(0), now; }// stupid test, but at least we shouldn't crash catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (retData.size() == 0); @@ -1615,12 +1663,12 @@ void SQLExecutor::limitOnce() data.push_back(x); } - try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; } + try { session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(data), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } std::vector<int> retData; - Statement stmt = (session() << "SELECT * FROM Strings", into(retData), limit(50), now); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::strings(), into(retData), limit(50), now); assert (!stmt.done()); assert (retData.size() == 50); stmt.execute(); @@ -1648,14 +1696,14 @@ void SQLExecutor::limitPrepare() try { - Statement stmt = (session() << "INSERT INTO Strings VALUES (?)", use(data)); + Statement stmt = (session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(data)); assert (100 == stmt.execute()); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } std::vector<int> retData; - Statement stmt = (session() << "SELECT * FROM Strings", into(retData), limit(50)); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::strings(), into(retData), limit(50)); assert (retData.size() == 0); assert (!stmt.done()); @@ -1691,17 +1739,84 @@ void SQLExecutor::prepare() } { - Statement stmt((session() << "INSERT INTO Strings VALUES (?)", use(data))); + Statement stmt((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(data))); } // stmt should not have been executed when destroyed int count = 100; - try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 0); } +void SQLExecutor::numericTypes(const std::vector<std::string>& vals) +{ + std::string funct = "numericTypes()"; + try { + + session().setProperty(Poco::Data::ODBC::SessionImpl::NUMERIC_CONVERSION_PROPERTY, Poco::Data::ODBC::ODBCMetaColumn::NC_BEST_FIT); + + { + Statement stat(session()); + stat << "SELECT * FROM " << ExecUtil::numeric_tbl(), now; + RecordSet rs(stat); + + assert(vals.size() + 1 == rs.columnCount()); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_INT32 == rs.columnType(0)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_INT32 == rs.columnType(1)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_DOUBLE == rs.columnType(2)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_INT64 == rs.columnType(3)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_STRING == rs.columnType(4)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_STRING == rs.columnType(5)); + for (size_t i = 0; i < vals.size(); ++i) + { + std::string v = rs.value(i + 1).convert<std::string>(); + assert(vals[i] == v); + } + } + + session().setProperty(Poco::Data::ODBC::SessionImpl::NUMERIC_CONVERSION_PROPERTY, Poco::Data::ODBC::ODBCMetaColumn::NC_FORCE_STRING); + { + Statement stat(session()); + stat << "SELECT * FROM " << ExecUtil::numeric_tbl(), now; + RecordSet rs(stat); + + assert(vals.size() + 1 == rs.columnCount()); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_INT32 == rs.columnType(0)); + for (size_t i = 0; i < vals.size(); ++i) + { + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_STRING == rs.columnType(i + 1)); + std::string v = rs.value<std::string>(i + 1); + assert(vals[i] == v); + } + } + + session().setProperty(Poco::Data::ODBC::SessionImpl::NUMERIC_CONVERSION_PROPERTY, Poco::Data::ODBC::ODBCMetaColumn::NC_BEST_FIT_DBL_LIMIT); + { + Statement stat(session()); + stat << "SELECT * FROM " << ExecUtil::numeric_tbl(), now; + RecordSet rs(stat); + + assert(vals.size() + 1 == rs.columnCount()); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_INT32 == rs.columnType(0)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_INT32 == rs.columnType(1)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_DOUBLE == rs.columnType(2)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_INT64 == rs.columnType(3)); + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_DOUBLE == rs.columnType(4)); //conversion would be done with precision loss + assert(Poco::Data::ODBC::ODBCMetaColumn::FDT_DOUBLE == rs.columnType(5)); //conversion would be done with precision loss + for (size_t i = 0; i < vals.size(); ++i) + { + std::string v = rs.value(i + 1).convert<std::string>(); + if (i < 3) // we've lost precision, so can't compare values + assert(vals[i] == v); + } + } + + } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } +} void SQLExecutor::doBulkPerformance(Poco::UInt32 size) { @@ -1715,7 +1830,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) try { sw.start(); - session() << "INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)", + session() << "INSERT INTO "<< ExecUtil::misctest() <<" (First, Third, Fourth, Fifth) VALUES (?,?,?,?)", use(strings), use(ints), use(floats), @@ -1726,14 +1841,14 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) double time = sw.elapsed() / 1000.0; - try { session() << "DELETE FROM MiscTest", now; } + try { session() << "DELETE FROM "<< ExecUtil::misctest(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { sw.restart(); - session() << "INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)", + session() << "INSERT INTO "<< ExecUtil::misctest() <<" (First, Third, Fourth, Fifth) VALUES (?,?,?,?)", use(strings, bulk), use(ints, bulk), use(floats, bulk), @@ -1767,7 +1882,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) try { sw.restart(); - session() << "SELECT First, Third, Fourth, Fifth FROM MiscTest", + session() << "SELECT First, Third, Fourth, Fifth FROM "<< ExecUtil::misctest(), into(strings), into(ints), into(floats), @@ -1789,7 +1904,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) try { sw.restart(); - session() << "SELECT First, Third, Fourth, Fifth FROM MiscTest", + session() << "SELECT First, Third, Fourth, Fifth FROM "<< ExecUtil::misctest(), into(strings, bulk(size)), into(ints, bulk(size)), into(floats, bulk(size)), @@ -1826,7 +1941,7 @@ void SQLExecutor::setSimple() std::set<std::string> firstNames; std::set<std::string> addresses; std::set<int> ages; - std::string tableName("Person"); + std::string tableName(ExecUtil::person()); lastNames.insert("LN1"); lastNames.insert("LN2"); firstNames.insert("FN1"); @@ -1838,10 +1953,10 @@ void SQLExecutor::setSimple() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); @@ -1850,7 +1965,7 @@ void SQLExecutor::setSimple() std::set<std::string> firstNamesR; std::set<std::string> addressesR; std::set<int> agesR; - try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ages == agesR); @@ -1867,17 +1982,17 @@ void SQLExecutor::setComplex() people.insert(Person("LN1", "FN1", "ADDR1", 1)); people.insert(Person("LN2", "FN2", "ADDR2", 2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::set<Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result == people); @@ -1896,17 +2011,17 @@ void SQLExecutor::setComplexUnique() Person p2("LN2", "FN2", "ADDR2", 2); people.push_back(p2); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 5); std::set<Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result.size() == 2); @@ -1921,7 +2036,7 @@ void SQLExecutor::multiSetSimple() std::multiset<std::string> firstNames; std::multiset<std::string> addresses; std::multiset<int> ages; - std::string tableName("Person"); + std::string tableName(ExecUtil::person()); lastNames.insert("LN1"); lastNames.insert("LN2"); firstNames.insert("FN1"); @@ -1933,10 +2048,10 @@ void SQLExecutor::multiSetSimple() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); @@ -1945,7 +2060,7 @@ void SQLExecutor::multiSetSimple() std::multiset<std::string> firstNamesR; std::multiset<std::string> addressesR; std::multiset<int> agesR; - try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ages.size() == agesR.size()); @@ -1967,17 +2082,17 @@ void SQLExecutor::multiSetComplex() Person p2("LN2", "FN2", "ADDR2", 2); people.insert(p2); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 5); std::multiset<Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result.size() == people.size()); @@ -1993,17 +2108,17 @@ void SQLExecutor::mapComplex() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::map<std::string, Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result == people); @@ -2022,17 +2137,17 @@ void SQLExecutor::mapComplexUnique() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 5); std::map<std::string, Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result.size() == 2); @@ -2051,17 +2166,17 @@ void SQLExecutor::multiMapComplex() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 5); std::multimap<std::string, Person> result; - try { session() << "SELECT * FROM Person", into(result), now; } + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result.size() == people.size()); @@ -2077,16 +2192,16 @@ void SQLExecutor::selectIntoSingle() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person result; - try { session() << "SELECT * FROM Person ORDER BY LastName", into(result), limit(1), now; }// will return 1 object into one single result + try { session() << "SELECT * FROM " << ExecUtil::person() << " ORDER BY LastName", into(result), limit(1), now; }// will return 1 object into one single result catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result == p1); @@ -2102,17 +2217,17 @@ void SQLExecutor::selectIntoSingleStep() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person result; - Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1)); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::person(), into(result), limit(1)); stmt.execute(); assert (result == p1); assert (!stmt.done()); @@ -2131,18 +2246,18 @@ void SQLExecutor::selectIntoSingleFail() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN2", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), limit(2, true), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), limit(2, true), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person result; try { - session() << "SELECT * FROM Person", into(result), limit(1, true), now; // will fail now + session() << "SELECT * FROM " << ExecUtil::person(), into(result), limit(1, true), now; // will fail now fail("hardLimit is set: must fail"); } catch(Poco::Data::LimitException&) @@ -2160,19 +2275,19 @@ void SQLExecutor::lowerLimitOk() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person result; try { - session() << "SELECT * FROM Person", into(result), lowerLimit(2), now; // will return 2 objects into one single result but only room for one! + session() << "SELECT * FROM " << ExecUtil::person(), into(result), lowerLimit(2), now; // will return 2 objects into one single result but only room for one! fail("Not enough space for results"); } catch(Poco::Exception&) @@ -2190,17 +2305,17 @@ void SQLExecutor::singleSelect() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person result; - Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1)); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::person(), into(result), limit(1)); stmt.execute(); assert (result == p1); assert (!stmt.done()); @@ -2219,18 +2334,18 @@ void SQLExecutor::lowerLimitFail() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person result; try { - session() << "SELECT * FROM Person", into(result), lowerLimit(3), now; // will fail + session() << "SELECT * FROM " << ExecUtil::person(), into(result), lowerLimit(3), now; // will fail fail("should fail. not enough data"); } catch(Poco::Exception&) @@ -2248,16 +2363,16 @@ void SQLExecutor::combinedLimits() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::vector <Person> result; - try { session() << "SELECT * FROM Person", into(result), lowerLimit(2), upperLimit(2), now; }// will return 2 objects + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), lowerLimit(2), upperLimit(2), now; }// will return 2 objects catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result.size() == 2); @@ -2276,16 +2391,16 @@ void SQLExecutor::ranges() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); std::vector <Person> result; - try { session() << "SELECT * FROM Person", into(result), range(2, 2), now; }// will return 2 objects + try { session() << "SELECT * FROM " << ExecUtil::person(), into(result), range(2, 2), now; }// will return 2 objects catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (result.size() == 2); @@ -2303,18 +2418,18 @@ void SQLExecutor::combinedIllegalLimits() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person result; try { - session() << "SELECT * FROM Person", into(result), lowerLimit(3), upperLimit(2), now; + session() << "SELECT * FROM " << ExecUtil::person(), into(result), lowerLimit(3), upperLimit(2), now; fail("lower > upper is not allowed"); } catch(LimitException&) @@ -2332,18 +2447,18 @@ void SQLExecutor::illegalRange() people.insert(std::make_pair("LN1", p1)); people.insert(std::make_pair("LN1", p2)); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(people), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 2); Person result; try { - session() << "SELECT * FROM Person", into(result), range(3, 2), now; + session() << "SELECT * FROM " << ExecUtil::person(), into(result), range(3, 2), now; fail("lower > upper is not allowed"); } catch(LimitException&) @@ -2356,63 +2471,149 @@ void SQLExecutor::emptyDB() { std::string funct = "emptyDB()"; int count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 0); Person result; - Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1)); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::person(), into(result), limit(1)); stmt.execute(); assert (result.firstName.empty()); assert (stmt.done()); } +struct LobTester +{ + + template <typename TargetBlb, typename SrcBlb> + static TargetBlb convertBlob(const SrcBlb& s) + { + TargetBlb t; + for (typename SrcBlb::Iterator i = s.begin(); i != s.end(); ++i) + { + typename TargetBlb::ValueType v = static_cast<typename TargetBlb::ValueType>(*i); + t.appendRaw(&v, 1); + } + return t; + } + + template <typename ContType, typename BlobType> + static void doTest(SQLExecutor* tc, Session& sess, const std::string& blobPlaceholder, int bigSize, const std::string& funct) + { + const std::string lastName("lastname"); + const std::string firstName("firstname"); + const std::string address("Address"); + const std::string tblName(ExecUtil::person()); + + sess << "DELETE FROM " << ExecUtil::person(), now; + ContType blobs; + for (size_t n = 0; n < 2; ++n) + { + BlobType img; + const size_t sz = 10; + for (size_t c = 0; c < sz; ++c) + { + typename BlobType::ValueType v = static_cast<typename BlobType::ValueType>('0' + c + sz * n); + img.appendRaw(&v, 1); + } + blobs.push_back(img); + } + + try { + char rn = '1'; + for (typename ContType::const_iterator it = blobs.begin(); it != blobs.end(); ++it, ++rn) + { + sess << format("INSERT INTO %s VALUES (?,?,?,%s)", tblName, blobPlaceholder), + bind(lastName + rn), useRef(firstName), useRef(address), useRef(*it), now; + } + } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; failTU(tc, funct); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; failTU(tc, funct); } + + int count = 0; + try { sess << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; failTU(tc, funct); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; failTU(tc, funct); } + assertTU (tc, count == blobs.size()); + + ContType resV; + assertTU (tc, resV.size() == 0); + try { sess << "SELECT Image FROM " << ExecUtil::person() << " ORDER BY LastName", into(resV), now; } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; failTU(tc, funct); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; failTU(tc, funct); } + bool r = resV == blobs; + assertTU (tc, r); + + try { + ContType resV2; + Statement stat(sess); + stat << "SELECT Image FROM " << ExecUtil::person() << " ORDER BY LastName", now; + RecordSet rs(stat); + Poco::Data::ODBC::ODBCMetaColumn::ColumnDataType tp = rs.columnType(0); + for (bool cont = rs.moveFirst(); cont; cont = rs.moveNext()) + { + switch (tp) + { + case Poco::Data::ODBC::ODBCMetaColumn::FDT_BLOB: + resV2.push_back(convertBlob<BlobType>(rs.value<Poco::Data::BLOB>(0))); + break; + case Poco::Data::ODBC::ODBCMetaColumn::FDT_CLOB: + resV2.push_back(convertBlob<BlobType>(rs.value<Poco::Data::CLOB>(0))); + break; + default: + failTU(tc, funct); + } + + } + bool r = resV2 == blobs; + assertTU(tc, r); + } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; failTU(tc, funct); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; failTU(tc, funct); } + + BlobType big; + typename BlobType::Container v(bigSize); + for (size_t p = 0; p < bigSize; ++p) + v[p] = static_cast<typename BlobType::ValueType>(p); + big.assignRaw(&v[0], v.size()); + + assertTU (tc, big.size() == bigSize); + + try { sess << "DELETE FROM " << ExecUtil::person(), now; } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; failTU(tc, funct); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; failTU(tc, funct); } + + try { + sess << format("INSERT INTO %s VALUES (?,?,?,%s)", tblName, blobPlaceholder), + useRef(lastName), useRef(firstName), bind(address), use(big), now; + } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; failTU(tc, funct); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; failTU(tc, funct); } + + BlobType res; + try { sess << "SELECT Image FROM " << ExecUtil::person(), into(res), now; } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; failTU(tc, funct); } + catch (StatementException& se){ std::cout << se.toString() << std::endl; failTU(tc, funct); } + assertTU (tc, res == big); + + } +}; + + void SQLExecutor::blob(int bigSize, const std::string& blobPlaceholder) { - std::string funct = "blob()"; - std::string lastName("lastname"); - std::string firstName("firstname"); - std::string address("Address"); + const std::string funct = "blob()"; - CLOB img("0123456789", 10); - int count = 0; - try { session() << format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder), - use(lastName), use(firstName), use(address), use(img), now; } - catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } - catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - assert (count == 1); + LobTester::doTest< std::vector<CLOB>, CLOB>(this, session(), blobPlaceholder, bigSize, funct + "-1"); + LobTester::doTest< std::vector<Poco::Data::BLOB>, Poco::Data::BLOB>(this, session(), blobPlaceholder, bigSize, funct + "-2"); - CLOB res; - assert (res.size() == 0); - try { session() << "SELECT Image FROM Person", into(res), now; } - catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - assert (res == img); + LobTester::doTest< std::list<CLOB>, CLOB>(this, session(), blobPlaceholder, bigSize, funct + "-3"); + LobTester::doTest< std::list<Poco::Data::BLOB>, Poco::Data::BLOB>(this, session(), blobPlaceholder, bigSize, funct + "-4"); - CLOB big; - std::vector<char> v(bigSize, 'x'); - big.assignRaw(&v[0], v.size()); - - assert (big.size() == bigSize); - - try { session() << "DELETE FROM Person", now; } - catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - - try { session() << format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder), - use(lastName), use(firstName), use(address), use(big), now; } - catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - - try { session() << "SELECT Image FROM Person", into(res), now; } - catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } - catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - assert (res == big); + LobTester::doTest< std::deque<CLOB>, CLOB>(this, session(), blobPlaceholder, bigSize, funct + "-5"); + LobTester::doTest< std::deque<Poco::Data::BLOB>, Poco::Data::BLOB>(this, session(), blobPlaceholder, bigSize, funct + "-6"); } @@ -2425,16 +2626,16 @@ void SQLExecutor::blobStmt() CLOB blob("0123456789", 10); int count = 0; - Statement ins = (session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(blob)); + Statement ins = (session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(blob)); ins.execute(); - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 1); CLOB res; poco_assert (res.size() == 0); - Statement stmt = (session() << "SELECT Image FROM Person", into(res)); + Statement stmt = (session() << "SELECT Image FROM " << ExecUtil::person(), into(res)); try { stmt.execute(); } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } @@ -2451,21 +2652,21 @@ void SQLExecutor::dateTime() DateTime born(1965, 6, 18, 5, 35, 1); int count = 0; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(born), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(born), now; } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } assert(count == 1); DateTime res; - try { session() << "SELECT Born FROM Person", into(res), now; } + try { session() << "SELECT Born FROM " << ExecUtil::person(), into(res), now; } catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } catch (StatementException& se){ std::cout << se.toString() << std::endl; fail(funct); } assert(res == born); - Statement stmt = (session() << "SELECT Born FROM Person", now); + Statement stmt = (session() << "SELECT Born FROM " << ExecUtil::person(), now); RecordSet rset(stmt); res = rset["Born"].convert<DateTime>(); @@ -2482,7 +2683,7 @@ void SQLExecutor::date() Date bornDate(1965, 6, 18); int count = 0; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), @@ -2490,19 +2691,19 @@ void SQLExecutor::date() now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 1); Date d; Time t; - try { session() << "SELECT BornDate FROM Person", into(d), now; } + try { session() << "SELECT BornDate FROM " << ExecUtil::person(), into(d), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (d == bornDate); - Statement stmt = (session() << "SELECT BornDate FROM Person", now); + Statement stmt = (session() << "SELECT BornDate FROM " << ExecUtil::person(), now); RecordSet rset(stmt); DateTime dt1 = rset["BornDate"].convert<DateTime>(); @@ -2521,7 +2722,7 @@ void SQLExecutor::time() Time bornTime (5, 35, 1); int count = 0; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), @@ -2529,19 +2730,19 @@ void SQLExecutor::time() now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 1); Date d; Time t; - try { session() << "SELECT BornTime FROM Person", into(t), now; } + try { session() << "SELECT BornTime FROM " << ExecUtil::person(), into(t), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (t == bornTime); - Statement stmt = (session() << "SELECT BornTime FROM Person", now); + Statement stmt = (session() << "SELECT BornTime FROM " << ExecUtil::person(), now); RecordSet rset(stmt); DateTime dt2 = rset["BornTime"].convert<DateTime>(); @@ -2556,13 +2757,13 @@ void SQLExecutor::tuples() std::string funct = "tuples()"; TupleType t(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19); - try { session() << "INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(t), now; } + try { session() << "INSERT INTO " << ExecUtil::tuples() << " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(t), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } TupleType ret(-10,-11,-12,-13,-14,-15,-16,-17,-18,-19); assert (ret != t); - try { session() << "SELECT * FROM Tuples", into(ret), now; } + try { session() << "SELECT * FROM " << ExecUtil::tuples(), into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ret == t); @@ -2581,18 +2782,18 @@ void SQLExecutor::tupleVector() v.push_back(t10); v.push_back(t100); - try { session() << "INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(v), now; } + try { session() << "INSERT INTO " << ExecUtil::tuples() << " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } int count = 0; - try { session() << "SELECT COUNT(*) FROM Tuples", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::tuples(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (v.size() == count); std::vector<Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> > ret; - try { session() << "SELECT * FROM Tuples", into(ret), now; } + try { session() << "SELECT * FROM " << ExecUtil::tuples(), into(ret), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (ret == v); @@ -2608,13 +2809,13 @@ void SQLExecutor::internalExtraction() v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5")); v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6")); - try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } + try { session() << "INSERT INTO " << ExecUtil::vectors() << " VALUES (?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { - Statement stmt = (session() << "SELECT * FROM Vectors", now); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::vectors() , now); RecordSet rset(stmt); assert (3 == rset.columnCount()); @@ -2676,7 +2877,7 @@ void SQLExecutor::internalExtraction() for (int i = 1; it != end; ++it, ++i) assert (*it == i); - rset = (session() << "SELECT COUNT(*) AS cnt FROM Vectors", now); + rset = (session() << "SELECT COUNT(*) AS cnt FROM " << ExecUtil::vectors(), now); //various results for COUNT(*) are received from different drivers try @@ -2710,7 +2911,7 @@ void SQLExecutor::internalExtraction() try { rset.value<std::string>(0,0); fail ("must fail"); } catch (BadCastException&) { } - stmt = (session() << "DELETE FROM Vectors", now); + stmt = (session() << "DELETE FROM " << ExecUtil::vectors(), now); rset = stmt; try { rset.column<std::deque<int> >(0); fail ("must fail"); } @@ -2730,7 +2931,7 @@ void SQLExecutor::filter(const std::string& query, const std::string& intFldName v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5")); v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6")); - try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } + try { session() << "INSERT INTO " << ExecUtil::vectors() << " VALUES (?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } @@ -2820,7 +3021,7 @@ void SQLExecutor::internalBulkExtraction() try { - session() << "INSERT INTO Person VALUES (?,?,?,?)", + session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastName, bulk), use(firstName, bulk), use(address, bulk), @@ -2832,7 +3033,7 @@ void SQLExecutor::internalBulkExtraction() try { - Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::person(), bulk(size), now); RecordSet rset(stmt); assert (size == rset.rowCount()); assert("LN0" == rset["LastName"]); @@ -2849,7 +3050,7 @@ void SQLExecutor::internalBulkExtraction() try { - Statement stmt = (session() << "SELECT * FROM Person", limit(size), bulk, now); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::person(), limit(size), bulk, now); RecordSet rset(stmt); assert (size == rset.rowCount()); assert ("LN0" == rset["LastName"]); @@ -2882,7 +3083,7 @@ void SQLExecutor::internalBulkExtractionUTF16() try { - session() << "INSERT INTO Person VALUES (?,?,?,?)", + session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastName, bulk), use(firstName, bulk), use(address, bulk), @@ -2894,7 +3095,7 @@ void SQLExecutor::internalBulkExtractionUTF16() try { - Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::person(), bulk(size), now); RecordSet rset(stmt); assert(size == rset.rowCount()); assert(Poco::UnicodeConverter::to<UTF16String>("LN0") == rset["LastName"]); @@ -2911,7 +3112,7 @@ void SQLExecutor::internalBulkExtractionUTF16() try { - Statement stmt = (session() << "SELECT * FROM Person", limit(size), bulk, now); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::person(), limit(size), bulk, now); RecordSet rset(stmt); assert(size == rset.rowCount()); assert("LN0" == rset["LastName"]); @@ -2939,7 +3140,7 @@ void SQLExecutor::internalStorageType() v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5")); v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6")); - try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } + try { session() << "INSERT INTO " << ExecUtil::vectors() << " VALUES (?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } @@ -2950,7 +3151,7 @@ void SQLExecutor::internalStorageType() for (; it != end; ++it) { - Statement stmt = (session() << "SELECT * FROM Vectors", *it, now); + Statement stmt = (session() << "SELECT * FROM " << ExecUtil::vectors(), *it, now); RecordSet rset(stmt); assert (3 == rset.columnCount()); @@ -2970,21 +3171,21 @@ void SQLExecutor::internalStorageType() try { - stmt = (session() << "SELECT * FROM Vectors", now, *it); + stmt = (session() << "SELECT * FROM " << ExecUtil::vectors(), now, *it); fail ("must fail"); } catch(InvalidAccessException&){} try { - stmt = (session() << "SELECT * FROM Vectors", into(v), now, *it); + stmt = (session() << "SELECT * FROM " << ExecUtil::vectors(), into(v), now, *it); fail ("must fail"); } catch(InvalidAccessException&){} try { - stmt = (session() << "SELECT * FROM Vectors", into(v), *it, now); + stmt = (session() << "SELECT * FROM " << ExecUtil::vectors(), into(v), *it, now); fail ("must fail"); } catch(InvalidAccessException&){} @@ -2999,7 +3200,7 @@ void SQLExecutor::notNulls(const std::string& sqlState) { try { - session() << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now; + session() << "INSERT INTO "<< ExecUtil::nulltest() << " (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now; fail ("must fail"); }catch (StatementException& se) { @@ -3016,15 +3217,15 @@ void SQLExecutor::notNulls(const std::string& sqlState) } -void SQLExecutor::nulls() +void SQLExecutor::nulls(bool emptyStrIsSpace) { std::string funct = "nulls()"; - try { session() << "INSERT INTO NullTest (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now; } + try { session() << "INSERT INTO " << ExecUtil::nulltest() << " (i,r,v) VALUES (?,?,?)", use(null), use(null), use(null), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - RecordSet rs(session(), "SELECT * FROM NullTest"); + RecordSet rs(session(), "SELECT * FROM " + ExecUtil::nulltest()); assert (1 == rs.rowCount()); rs.moveFirst(); assert (rs.isNull("i")); @@ -3038,7 +3239,7 @@ void SQLExecutor::nulls() assert (rs.nvl("r", -1.5) == -1.5); assert (rs.nvl<std::string>("v") == ""); assert (rs.nvl("v", "123") == "123"); - try { session() << "DELETE FROM NullTest", now; } + try { session() << "DELETE FROM " << ExecUtil::nulltest(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } @@ -3046,10 +3247,10 @@ void SQLExecutor::nulls() double f = 1.5; std::string s = "123"; - try { session() << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(f), use(s), now; } + try { session() << "INSERT INTO " << ExecUtil::nulltest() << " (i, r, v) VALUES (?,?,?)", use(i), use(f), use(s), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - rs = (session() << "SELECT * FROM NullTest", now); + rs = (session() << "SELECT * FROM " << ExecUtil::nulltest(), now); assert (1 == rs.rowCount()); rs.moveFirst(); assert (!rs.isNull("i")); @@ -3063,15 +3264,15 @@ void SQLExecutor::nulls() assert (rs.nvl("r", -1.5) == 1.5); assert (rs.nvl<std::string>("v") == "123"); assert (rs.nvl("v", "456") == "123"); - try { session() << "UPDATE NullTest SET v = ? WHERE i = ?", use(null), use(i), now; } + try { session() << "UPDATE " << ExecUtil::nulltest() << " SET v = ? WHERE i = ?", use(null), use(i), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } i = 2; f = 3.4; - try { session() << "INSERT INTO NullTest (i, r, v) VALUES (?,?,?)", use(i), use(null), use(null), now; } + try { session() << "INSERT INTO " << ExecUtil::nulltest() << " (i, r, v) VALUES (?,?,?)", use(i), use(null), use(null), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - rs = (session() << "SELECT i, r, v FROM NullTest ORDER BY i ASC", now); + rs = (session() << "SELECT i, r, v FROM " << ExecUtil::nulltest() << " ORDER BY i ASC", now); assert (2 == rs.rowCount()); rs.moveFirst(); assert (!rs.isNull("i")); @@ -3087,11 +3288,11 @@ void SQLExecutor::nulls() assert (rs.isNull("v")); assert (rs["v"] != ""); - try { session() << "DELETE FROM NullTest", now; } + try { session() << "DELETE FROM " << ExecUtil::nulltest(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "INSERT INTO NullTest (v) VALUES (?)", bind(""), now; } + try { session() << "INSERT INTO " << ExecUtil::nulltest() << " (v) VALUES (?)", bind(""), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } @@ -3107,19 +3308,25 @@ void SQLExecutor::nulls() bool fes = session().getFeature("forceEmptyString"); session().setFeature("forceEmptyString", false); - RecordSet rs1(session(), "SELECT v FROM NullTest"); + RecordSet rs1(session(), "SELECT v FROM " + ExecUtil::nulltest()); assert (1 == rs1.rowCount()); rs1.moveFirst(); - assert (rs1.isNull("v")); - assert (!(rs["v"] == "")); + if (!emptyStrIsSpace) + { + assert (rs1.isNull("v")); + assert (!(rs["v"] == "")); + } session().setFeature("emptyStringIsNull", false); session().setFeature("forceEmptyString", true); - RecordSet rs2(session(), "SELECT v FROM NullTest"); + RecordSet rs2(session(), "SELECT v FROM " + ExecUtil::nulltest()); assert (1 == rs2.rowCount()); rs2.moveFirst(); - assert (!rs2.isNull("v")); - assert ((rs2["v"] == "")); + assert(!rs2.isNull("v")); + if (!emptyStrIsSpace) + { + assert((rs2["v"] == "")); + } try { @@ -3141,18 +3348,18 @@ void SQLExecutor::rowIterator() v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5")); v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6")); - try { session() << "DELETE FROM Vectors", now; } + try { session() << "DELETE FROM " << ExecUtil::vectors(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - RecordSet rset0(session(), "SELECT * FROM Vectors"); + RecordSet rset0(session(), "SELECT * FROM " + ExecUtil::vectors()); assert (rset0.begin() == rset0.end()); - try { session() << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } + try { session() << "INSERT INTO " << ExecUtil::vectors() << " VALUES (?,?,?)", use(v), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - RecordSet rset(session(), "SELECT * FROM Vectors"); + RecordSet rset(session(), "SELECT * FROM " + ExecUtil::vectors()); std::ostringstream osLoop; RecordSet::Iterator it = rset.begin(); @@ -3245,14 +3452,15 @@ void SQLExecutor::stdVectorBool() void SQLExecutor::asynchronous(int rowCount) { Session tmp = session(); + if (!_connInitSql.empty()) tmp << _connInitSql, now; std::vector<int> data(rowCount); - Statement stmt = (tmp << "INSERT INTO Strings VALUES(?)", use(data)); + Statement stmt = (tmp << "INSERT INTO " << ExecUtil::strings() << " VALUES(?)", use(data)); Statement::Result result = stmt.executeAsync(); assert (!stmt.isAsync()); result.wait(); - Statement stmt1 = (tmp << "SELECT * FROM Strings", into(data), async, now); + Statement stmt1 = (tmp << "SELECT * FROM " << ExecUtil::strings(), into(data), async, now); assert (stmt1.isAsync()); assert (stmt1.wait() == rowCount); @@ -3270,7 +3478,7 @@ void SQLExecutor::asynchronous(int rowCount) } // --- - stmt = tmp << "SELECT * FROM Strings", into(data), async, now; + stmt = tmp << "SELECT * FROM " << ExecUtil::strings(), into(data), async, now; assert (stmt.isAsync()); stmt.wait(); assert (stmt.execute() == 0); @@ -3294,7 +3502,7 @@ void SQLExecutor::asynchronous(int rowCount) assert (!stmt.isAsync()); assert (stmt.execute() == rowCount); - stmt = tmp << "SELECT * FROM Strings", into(data), sync, now; + stmt = tmp << "SELECT * FROM " << ExecUtil::strings(), into(data), sync, now; assert (!stmt.isAsync()); assert (stmt.wait() == 0); assert (stmt.execute() == rowCount); @@ -3306,7 +3514,7 @@ void SQLExecutor::asynchronous(int rowCount) assert (0 == rowCount % 10); int step = (int) (rowCount/10); data.clear(); - Statement stmt2 = (tmp << "SELECT * FROM Strings", into(data), async, limit(step)); + Statement stmt2 = (tmp << "SELECT * FROM " << ExecUtil::strings(), into(data), async, limit(step)); assert (data.size() == 0); assert (!stmt2.done()); std::size_t rows = 0; @@ -3321,7 +3529,7 @@ void SQLExecutor::asynchronous(int rowCount) assert (stmt2.done()); assert (rowCount == data.size()); - stmt2 = tmp << "SELECT * FROM Strings", reset; + stmt2 = tmp << "SELECT * FROM " << ExecUtil::strings(), reset; assert (!stmt2.isAsync()); assert ("deque" == stmt2.getStorage()); assert (stmt2.execute() == rowCount); @@ -3340,17 +3548,18 @@ void SQLExecutor::any() s = us; #endif Session tmp = session(); + if (!_connInitSql.empty()) tmp << _connInitSql, now; - tmp << "INSERT INTO Anys VALUES (?, ?, ?)", use(i), use(f), use(s), now; + tmp << "INSERT INTO " << ExecUtil::anys() << " VALUES (?, ?, ?)", use(i), use(f), use(s), now; int count = 0; - tmp << "SELECT COUNT(*) FROM Anys", into(count), now; + tmp << "SELECT COUNT(*) FROM " << ExecUtil::anys(), into(count), now; assert (1 == count); i = 0; f = 0.0; s = std::string(""); - tmp << "SELECT * FROM Anys", into(i), into(f), into(s), now; + tmp << "SELECT * FROM " << ExecUtil::anys(), into(i), into(f), into(s), now; assert (AnyCast<int>(i) == 42); assert (AnyCast<double>(f) == 42.5); #ifdef POCO_ODBC_UNICODE @@ -3376,16 +3585,18 @@ void SQLExecutor::dynamicAny() Var s = "42"; Session tmp = session(); - tmp << "INSERT INTO Anys VALUES (?, ?, ?)", use(i), use(f), use(s), now; + if (!_connInitSql.empty()) tmp << _connInitSql, now; + + tmp << "INSERT INTO " << ExecUtil::anys() << " VALUES (?, ?, ?)", use(i), use(f), use(s), now; int count = 0; - tmp << "SELECT COUNT(*) FROM Anys", into(count), now; + tmp << "SELECT COUNT(*) FROM " << ExecUtil::anys(), into(count), now; assert (1 == count); i = 0; f = 0.0; s = std::string(""); - tmp << "SELECT * FROM Anys", into(i), into(f), into(s), now; + tmp << "SELECT * FROM " << ExecUtil::anys(), into(i), into(f), into(s), now; assert (42 == i); assert (42.5 == f); assert ("42" == s); @@ -3401,7 +3612,7 @@ void SQLExecutor::multipleResults(const std::string& sql) people.push_back(Person("Simpson", "Bart", "Springfield", 10)); people.push_back(Person("Simpson", "Lisa", "Springfield", 8)); people.push_back(Person("Simpson", "Maggie", "Springfield", 3)); - session() << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now; + session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?, ?, ?, ?)", use(people), now; Person pHomer; int aHomer = 42, aLisa = 8; @@ -3423,12 +3634,160 @@ void SQLExecutor::multipleResults(const std::string& sql) assert (Person("Simpson", "Homer", "Springfield", 42) == people2[1]); } +typedef Tuple<std::string, std::string, std::string, Poco::UInt32> PersonMRT; + +struct ReadPerson +{ + + template <typename T> + static PersonMRT rd(const T& rs) + { + PersonMRT pHomer; + pHomer.set<0>(rs.value(0)); + pHomer.set<1>(rs.value(1)); + pHomer.set<2>(rs.value(2)); + pHomer.set<3>(rs.value(3)); + return pHomer; + } + + template <typename Rdr> + static void compare(SQLExecutor* tc, const Poco::Dynamic::Var& val,const Rdr& rdr) + { + if (val.type() == typeid(PersonMRT)) + { + const PersonMRT p = rd(rdr); + assertTU(tc, p == val.extract<PersonMRT>()); + } + else + { + const Poco::Dynamic::Var val1 = rdr.value(0); + assertTU(tc, val == val1); + } + } + + struct RSReader + { + RSReader(RecordSet& rs, size_t rowNo) :_rs(rs), _rowNo(rowNo) + {} + RecordSet& _rs; + size_t _rowNo; + Var value(size_t col) const + { + return _rs.value(col, _rowNo); + } + }; + + struct ITReader + { + ITReader(const RowIterator& it) :_it(it) + {} + const RowIterator& _it; + Var value(size_t col) const + { + return (*_it)[col]; + } + }; + + struct RSReaderCur + { + RSReaderCur(RecordSet& rs) :_rs(rs) + {} + RecordSet& _rs; + Var value(size_t col) const + { + return _rs.value(col); + } + }; + +}; + +void SQLExecutor::multipleResultsNoProj(const std::string& sql) +{ + std::vector<PersonMRT> people; + const PersonMRT Homer("Simpson", "Homer", "Springfield", 42); + const int BartAge = 10; + const int HomerAge = 42; + const int LisaAge = 8; + people.push_back(Homer); + people.push_back(PersonMRT("Simpson", "Marge", "Springfield", 38)); + const std::string BartName("Bart"); + people.push_back(PersonMRT("Simpson", BartName, "Springfield", BartAge)); + const PersonMRT Lisa = PersonMRT("Simpson", "Lisa", "Springfield", LisaAge); + people.push_back(Lisa); + people.push_back(PersonMRT("Simpson", "Maggie", "Springfield", 3)); + session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?, ?, ?, ?)", use(people), now; + + Poco::Data::Statement stmt(session()); + stmt << sql, useRef(HomerAge), useRef(BartName), useRef(LisaAge), useRef(HomerAge); + + const size_t rowsToGet = stmt.execute(); + assert(3 == stmt.dataSetCount()); + stmt.firstDataSet(); + std::vector<Poco::Dynamic::Var> vals; + vals.push_back(Poco::Dynamic::Var(Homer)); + vals.push_back(Poco::Dynamic::Var(BartAge)); + vals.push_back(Poco::Dynamic::Var(Lisa)); + vals.push_back(Poco::Dynamic::Var(Homer)); + + std::vector<Poco::Dynamic::Var>::const_iterator valIt = vals.begin(); + size_t rowCnt = 0; + for (size_t dsNo = 0; dsNo < stmt.dataSetCount(); dsNo = stmt.nextDataSet()) + { + Poco::Data::RecordSet rs(stmt); + bool r = rs.moveFirst(); + RowIterator rowIt = rs.begin(); + for (size_t rowNo = 0; r; ++rowNo, r = rs.moveNext(), ++valIt, ++rowIt, ++rowCnt) + { + ReadPerson::compare(this, *valIt, ReadPerson::RSReader(rs, rowNo)); + ReadPerson::compare(this, *valIt, ReadPerson::ITReader(rowIt)); + ReadPerson::compare(this, *valIt, ReadPerson::RSReaderCur(rs)); + } + assert(rowIt == rs.end()); + if (!stmt.hasMoreDataSets()) + break; + } + assert(rowCnt == rowsToGet); + assert(vals.end() == valIt); + //// now check that limit() works as well + for (size_t lim = 1; lim <= vals.size(); ++lim) + { + Poco::Data::Statement stmt(session()); + stmt << sql, useRef(HomerAge), useRef(BartName), useRef(LisaAge), useRef(HomerAge), limit(lim); + std::vector<Poco::Dynamic::Var>::const_iterator valIt = vals.begin(); + + while (!stmt.done()) + { + stmt.execute(); + for (bool doId = true; doId;) + { + Poco::Data::RecordSet rs(stmt); + + RowIterator rIt = rs.begin(); + bool mf = rs.moveFirst(); + for (size_t row = 0; row < rs.rowCount(); ++row, ++rIt, mf = rs.moveNext(), ++valIt) + { + assert(mf); + ReadPerson::compare(this, *valIt, ReadPerson::RSReader(rs, row)); + ReadPerson::compare(this, *valIt, ReadPerson::ITReader(rIt)); + ReadPerson::compare(this, *valIt, ReadPerson::RSReaderCur(rs)); + } + assert(rIt == rs.end()); + + doId = rs.rowCount() < lim && stmt.hasMoreDataSets() && stmt.nextDataSet() > 0; + } + } + } + +} + void SQLExecutor::sqlChannel(const std::string& connect) { try { AutoPtr<SQLChannel> pChannel = new SQLChannel(Poco::Data::ODBC::Connector::KEY, connect, "TestSQLChannel"); + pChannel->setProperty("table", schemaTable(ExecUtil::pocolog())); // has to be the first, as otherwise "table" won't take effect + pChannel->setProperty("archive", schemaTable(ExecUtil::pocolog_a())); pChannel->setProperty("keep", "2 seconds"); Message msgInf("InformationSource", "a Informational async message", Message::PRIO_INFORMATION); @@ -3443,7 +3802,7 @@ void SQLExecutor::sqlChannel(const std::string& connect) Message msgWarnS("WarningSource", "d Warning sync message", Message::PRIO_WARNING); pChannel->log(msgWarnS); - RecordSet rs(session(), "SELECT * FROM T_POCO_LOG ORDER by Text"); + RecordSet rs(session(), "SELECT * FROM " + ExecUtil::pocolog() + " ORDER by Text"); assert (4 == rs.rowCount()); assert ("InformationSource" == rs["Source"]); assert ("a Informational async message" == rs["Text"]); @@ -3464,12 +3823,12 @@ void SQLExecutor::sqlChannel(const std::string& connect) Message msgWarnA("WarningSource", "f Warning sync message", Message::PRIO_WARNING); pChannel->log(msgWarnA); - RecordSet rs1(session(), "SELECT * FROM T_POCO_LOG_ARCHIVE"); + RecordSet rs1(session(), "SELECT * FROM " + ExecUtil::pocolog_a()); assert (4 == rs1.rowCount()); pChannel->setProperty("keep", ""); assert ("forever" == pChannel->getProperty("keep")); - RecordSet rs2(session(), "SELECT * FROM T_POCO_LOG ORDER by Text"); + RecordSet rs2(session(), "SELECT * FROM " + ExecUtil::pocolog() + " ORDER by Text"); assert (2 == rs2.rowCount()); assert ("InformationSource" == rs2["Source"]); assert ("e Informational sync message" == rs2["Text"]); @@ -3488,7 +3847,9 @@ void SQLExecutor::sqlLogger(const std::string& connect) try { Logger& root = Logger::root(); - root.setChannel(new SQLChannel(Poco::Data::ODBC::Connector::KEY, connect, "TestSQLChannel")); + SQLChannel* ch = new SQLChannel(Poco::Data::ODBC::Connector::KEY, connect, "TestSQLChannel"); + ch->setProperty("table", schemaTable(ExecUtil::pocolog())); + root.setChannel(ch); root.setLevel(Message::PRIO_INFORMATION); root.information("a Informational message"); @@ -3496,7 +3857,7 @@ void SQLExecutor::sqlLogger(const std::string& connect) root.debug("Debug message"); Thread::sleep(100); - RecordSet rs(session(), "SELECT * FROM T_POCO_LOG ORDER by Text"); + RecordSet rs(session(), "SELECT * FROM " + ExecUtil::pocolog() + " ORDER by Text"); assert (2 == rs.rowCount()); assert ("TestSQLChannel" == rs["Source"]); assert ("a Informational message" == rs["Text"]); @@ -3558,6 +3919,7 @@ void SQLExecutor::sessionTransaction(const std::string& connect) } Session local("odbc", connect); + if (!_connInitSql.empty()) local << _connInitSql, now; local.setFeature("autoCommit", true); std::string funct = "transaction()"; @@ -3565,7 +3927,7 @@ void SQLExecutor::sessionTransaction(const std::string& connect) std::vector<std::string> firstNames; std::vector<std::string> addresses; std::vector<int> ages; - std::string tableName("Person"); + const std::string tableName(ExecUtil::person()); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); @@ -3592,14 +3954,14 @@ void SQLExecutor::sessionTransaction(const std::string& connect) session().begin(); assert (session().isTransaction()); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (session().isTransaction()); - Statement stmt = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); + Statement stmt = (local << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(locCount), async, now); - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (2 == count); @@ -3610,19 +3972,21 @@ void SQLExecutor::sessionTransaction(const std::string& connect) stmt.wait(); assert (0 == locCount); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); assert (!session().isTransaction()); session().begin(); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (session().isTransaction()); - Statement stmt1 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); + //TODO: this looks to be wrong - if a DB is fast it'd manage to execute this before another session commit is done + // so assert below WILL fail + Statement stmt1 = (local << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(locCount), async, now); session().commit(); assert (!session().isTransaction()); @@ -3630,7 +3994,7 @@ void SQLExecutor::sessionTransaction(const std::string& connect) stmt1.wait(); assert (2 == locCount); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (2 == count); @@ -3649,6 +4013,7 @@ void SQLExecutor::transaction(const std::string& connect) Session local("odbc", connect); local.setFeature("autoCommit", true); + if (!_connInitSql.empty()) local << _connInitSql, now; setTransactionIsolation(session(), Session::TRANSACTION_READ_COMMITTED); if (local.hasTransactionIsolation(Session::TRANSACTION_READ_UNCOMMITTED)) @@ -3661,7 +4026,7 @@ void SQLExecutor::transaction(const std::string& connect) std::vector<std::string> firstNames; std::vector<std::string> addresses; std::vector<int> ages; - std::string tableName("Person"); + const std::string tableName(ExecUtil::person()); lastNames.push_back("LN1"); lastNames.push_back("LN2"); firstNames.push_back("FN1"); @@ -3686,14 +4051,14 @@ void SQLExecutor::transaction(const std::string& connect) assert (trans.isActive()); assert (session().isTransaction()); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (session().isTransaction()); assert (trans.isActive()); - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (2 == count); @@ -3702,7 +4067,7 @@ void SQLExecutor::transaction(const std::string& connect) } assert (!session().isTransaction()); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); @@ -3710,11 +4075,11 @@ void SQLExecutor::transaction(const std::string& connect) { Transaction trans(session()); - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - Statement stmt1 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); + Statement stmt1 = (local << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(locCount), async, now); assert (session().isTransaction()); assert (trans.isActive()); @@ -3726,18 +4091,18 @@ void SQLExecutor::transaction(const std::string& connect) assert (2 == locCount); } - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (2 == count); - try { session() << "DELETE FROM Person", now; } + try { session() << "DELETE FROM " << ExecUtil::person(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - Statement stmt1 = (local << "SELECT count(*) FROM Person", into(locCount), async, now); + Statement stmt1 = (local << "SELECT count(*) FROM " << ExecUtil::person(), into(locCount), async, now); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); @@ -3753,12 +4118,12 @@ void SQLExecutor::transaction(const std::string& connect) if (local.getTransactionIsolation() == Session::TRANSACTION_READ_COMMITTED) { stmt1.wait(); - local << "SELECT count(*) FROM Person", into(locCount), now; + local << "SELECT count(*) FROM " << ExecUtil::person(), into(locCount), now; assert (0 == locCount); } - std::string sql1 = format("INSERT INTO Person VALUES ('%s','%s','%s',%d)", lastNames[0], firstNames[0], addresses[0], ages[0]); - std::string sql2 = format("INSERT INTO Person VALUES ('%s','%s','%s',%d)", lastNames[1], firstNames[1], addresses[1], ages[1]); + std::string sql1 = format("INSERT INTO %s VALUES ('%s','%s','%s',%d)", tableName, lastNames[0], firstNames[0], addresses[0], ages[0]); + std::string sql2 = format("INSERT INTO %s VALUES ('%s','%s','%s',%d)", tableName, lastNames[1], firstNames[1], addresses[1], ages[1]); std::vector<std::string> sql; sql.push_back(sql1); sql.push_back(sql2); @@ -3766,34 +4131,34 @@ void SQLExecutor::transaction(const std::string& connect) Transaction trans(session()); trans.execute(sql1, false); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (1 == count); trans.execute(sql2, false); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (2 == count); - Statement stmt2 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); + Statement stmt2 = (local << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(locCount), async, now); trans.rollback(); stmt2.wait(); assert (0 == locCount); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); trans.execute(sql); - Statement stmt3 = (local << "SELECT COUNT(*) FROM Person", into(locCount), now); + Statement stmt3 = (local << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(locCount), now); assert (2 == locCount); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (2 == count); @@ -3806,7 +4171,7 @@ struct TestCommitTransactor { void operator () (Session& session) const { - session << "INSERT INTO Person VALUES ('lastName','firstName','address',10)", now; + session << "INSERT INTO " << ExecUtil::person() <<" VALUES ('lastName','firstName','address',10)", now; } }; @@ -3815,7 +4180,7 @@ struct TestRollbackTransactor { void operator () (Session& session) const { - session << "INSERT INTO Person VALUES ('lastName','firstName','address',10)", now; + session << "INSERT INTO " << ExecUtil::person() <<" VALUES ('lastName','firstName','address',10)", now; throw Poco::Exception("test"); } }; @@ -3833,16 +4198,16 @@ void SQLExecutor::transactor() TestCommitTransactor ct; Transaction t1(session(), ct); - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (1 == count); - try { session() << "DELETE FROM Person", now; session().commit();} + try { session() << "DELETE FROM " << ExecUtil::person(), now; session().commit();} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); @@ -3854,7 +4219,7 @@ void SQLExecutor::transactor() fail ("must fail"); } catch (Poco::Exception&) { } - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); @@ -3867,7 +4232,7 @@ void SQLExecutor::transactor() fail ("must fail"); } catch (Poco::Exception&) { } - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); @@ -3880,7 +4245,7 @@ void SQLExecutor::transactor() fail ("must fail"); } catch (Poco::Exception&) { } - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); @@ -3893,7 +4258,7 @@ void SQLExecutor::transactor() fail ("must fail"); } catch (Poco::Exception&) { } - try { session() << "SELECT count(*) FROM Person", into(count), now; } + try { session() << "SELECT count(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (0 == count); @@ -3904,7 +4269,12 @@ void SQLExecutor::transactor() void SQLExecutor::nullable() { - try { session() << "INSERT INTO NullableTest VALUES(NULL, NULL, NULL, NULL)", now; } + Statement stat(session()); + try { + Nullable<int> nint; + session() << "INSERT INTO " << ExecUtil::nullabletest() << + " VALUES(?, ?, ?, ?)", useRef(nint), bind(Nullable<double>()), bind(Any()), bind(Nullable<DateTime>()), now; + } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("nullable()"); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("nullable()"); } @@ -3918,14 +4288,14 @@ void SQLExecutor::nullable() assert (!s.isNull()); assert (!d.isNull()); - session() << "SELECT EmptyString, EmptyInteger, EmptyFloat, EmptyDateTime FROM NullableTest", into(s), into(i), into(f), into(d), now; + session() << "SELECT EmptyString, EmptyInteger, EmptyFloat, EmptyDateTime FROM " << ExecUtil::nullabletest(), into(s), into(i), into(f), into(d), now; assert (i.isNull()); assert (f.isNull()); assert (s.isNull()); assert (d.isNull()); - RecordSet rs(session(), "SELECT * FROM NullableTest"); + RecordSet rs(session(), "SELECT * FROM " + ExecUtil::nullabletest()); rs.moveFirst(); assert (rs.isNull("EmptyString")); @@ -3943,7 +4313,7 @@ void SQLExecutor::nullable() assert (!ds.isEmpty()); assert (!dd.isEmpty()); - Statement stmt = (session() << "SELECT EmptyString, EmptyInteger, EmptyFloat, EmptyDateTime FROM NullableTest", into(ds), into(di), into(df), into(dd), now); + Statement stmt = (session() << "SELECT EmptyString, EmptyInteger, EmptyFloat, EmptyDateTime FROM " << ExecUtil::nullabletest(), into(ds), into(di), into(df), into(dd), now); assert (di.isEmpty()); assert (df.isEmpty()); @@ -3962,12 +4332,12 @@ void SQLExecutor::reconnect() int count = 0; std::string result; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; } + try { session() << "INSERT INTO " << ExecUtil::person() <<" VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } count = 0; - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == 1); @@ -3977,15 +4347,16 @@ void SQLExecutor::reconnect() assert (!session().isConnected()); try { - session() << "SELECT LastName FROM Person", into(result), now; + session() << "SELECT LastName FROM " << ExecUtil::person(), into(result), now; fail ("must fail"); } catch(NotConnectedException&){ } assert (!session().isConnected()); session().open(); + if (!_connInitSql.empty()) session() << _connInitSql, now; assert (session().isConnected()); - try { session() << "SELECT Age FROM Person", into(count), now; } + try { session() << "SELECT Age FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == age); @@ -4006,4 +4377,37 @@ void SQLExecutor::unicode(const std::string& dbConnString) session() << "SELECT str FROM UnicodeTable", into(wtext), now; Poco::UnicodeConverter::convert(wtext, text); assert(text == std::string((const char*)supp)); -} \ No newline at end of file +} + + +void SQLExecutor::insertStatReuse() +{ + const std::string funct = "insertStatReuse()"; + Statement stat(session()); + try { + Var lastName; + std::string firstName("zzz"); + Any address; + Nullable<int> age(0); + stat << "INSERT INTO " << ExecUtil::person() << "(LastName, FirstName, Address, Age) VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age); + stat.insertHint(); + for (size_t i = 1; i < 5; ++i) + { + lastName = Var("Last Name " + NumberFormatter::format(i)); + firstName = "First Name " + NumberFormatter::format(i); + address = "Address" + NumberFormatter::format(i); + age = 10 + static_cast<int>(i); + stat.execute(); + } + std::vector<int> rowCnt; + session() << "SELECT count(*) FROM " << ExecUtil::person() << " AS p " + << " WHERE p.LastName LIKE 'Last%' AND p.FirstName LIKE 'First%' AND p.Address LIKE 'Address%' AND p.Age>10" + << " GROUP BY p.LastName, p.FirstName, p.Address, p.Age", into(rowCnt), now; + assert(4 == rowCnt.size()); + size_t sum = 0; + for (size_t i = 0; i < rowCnt.size(); ++i) + sum += rowCnt[i]; + assert(4 == sum); + } + catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail(funct); } +} diff --git a/Data/ODBC/testsuite/src/SQLExecutor.h b/Data/ODBC/testsuite/src/SQLExecutor.h index 259b39f9d..85721163a 100644 --- a/Data/ODBC/testsuite/src/SQLExecutor.h +++ b/Data/ODBC/testsuite/src/SQLExecutor.h @@ -73,6 +73,81 @@ using Poco::Data::ODBC::ConnectionException; \ using Poco::Data::ODBC::StatementException +struct ExecUtil +{ + static std::string mangleTable(const std::string& name); + + static std::string person() + { + return mangleTable("Person"); + } + + static std::string strings() + { + return mangleTable("Strings"); + } + + static std::string tuples() + { + return mangleTable("Tuples"); + } + + static std::string vectors() + { + return mangleTable("Vectors"); + } + + static std::string anys() + { + return mangleTable("Anys"); + } + + static std::string nulltest() + { + return mangleTable("NullTest"); + } + + static std::string misctest() + { + return mangleTable("MiscTest"); + } + + static std::string nullabletest() + { + return mangleTable("NullableTest"); + } + + static std::string pocolog() + { + return mangleTable("POCO_LOG"); + } + + static std::string pocolog_a() + { + return mangleTable("POCO_LOG_A"); + } + + static std::string stored_func() + { + return mangleTable("storedFunc"); + } + + static std::string stored_proc() + { + return mangleTable("storedProc"); + } + + static std::string test_tbl() + { + return mangleTable("Test"); + } + + static std::string numeric_tbl() + { + return mangleTable("numer_t"); + } +}; + class SQLExecutor: public CppUnit::TestCase { @@ -89,7 +164,7 @@ public: DE_BOUND }; - SQLExecutor(const std::string& name, Poco::Data::Session* _pSession); + SQLExecutor(const std::string& name, Poco::Data::Session* _pSession, const std::string& connInitSql = std::string(), const std::string& schemaName = std::string()); ~SQLExecutor(); void execute(const std::string& sql); @@ -147,6 +222,8 @@ public: void limitPrepare(); void limitZero(); void prepare(); + void numericTypes(const std::vector<std::string>& vals); + void insertStatReuse(); template <typename C1, typename C2, typename C3, typename C4, typename C5, typename C6> void doBulkWithBool(Poco::UInt32 size, const std::string& blobPlaceholder="?") @@ -173,7 +250,7 @@ public: try { session() << - Poco::format("INSERT INTO MiscTest VALUES (?,%s,?,?,?,?)", blobPlaceholder), + Poco::format("INSERT INTO %s VALUES (?,%s,?,?,?,?)", ExecUtil::misctest(), blobPlaceholder), use(strings), use(blobs), use(ints), @@ -183,14 +260,14 @@ public: } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "DELETE FROM MiscTest", now; } + try { session() << "DELETE FROM "<< ExecUtil::misctest(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { session() << - Poco::format("INSERT INTO MiscTest VALUES (?,%s,?,?,?,?)", blobPlaceholder), + Poco::format("INSERT INTO %s VALUES (?,%s,?,?,?,?)", ExecUtil::misctest(), blobPlaceholder), use(strings, bulk), use(blobs, bulk), use(ints, bulk), @@ -209,7 +286,7 @@ public: try { - session() << "SELECT * FROM MiscTest ORDER BY Third", + session() << "SELECT * FROM "<< ExecUtil::misctest() <<" ORDER BY Third", into(strings), into(blobs), into(ints), @@ -239,14 +316,14 @@ public: try { - session() << "SELECT First FROM MiscTest", into(ints, bulk(size)), limit(size+1), now; + session() << "SELECT First FROM "<< ExecUtil::misctest(), into(ints, bulk(size)), limit(size+1), now; fail ("must fail"); } catch(Poco::InvalidArgumentException&){ } try { - session() << "SELECT First FROM MiscTest", into(ints), bulk(size), now; + session() << "SELECT First FROM "<< ExecUtil::misctest(), into(ints), bulk(size), now; fail ("must fail"); } catch(Poco::InvalidAccessException&){ } @@ -263,7 +340,7 @@ public: try { - session() << "SELECT First, Second, Third, Fourth, Fifth, Sixth FROM MiscTest ORDER BY Third", + session() << "SELECT First, Second, Third, Fourth, Fifth, Sixth FROM "<< ExecUtil::misctest() <<" ORDER BY Third", into(strings, bulk), into(blobs, bulk(size)), into(ints, bulk(size)), @@ -313,7 +390,7 @@ public: try { - session() << "INSERT INTO MiscTest VALUES (?,?,?,?,?)", + session() << "INSERT INTO "<< ExecUtil::misctest() <<" VALUES (?,?,?,?,?)", use(strings), use(blobs), use(ints), @@ -322,13 +399,13 @@ public: } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "DELETE FROM MiscTest", now; } + try { session() << "DELETE FROM "<< ExecUtil::misctest(), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } try { - session() << "INSERT INTO MiscTest VALUES (?,?,?,?,?)", + session() << "INSERT INTO "<< ExecUtil::misctest() <<" VALUES (?,?,?,?,?)", use(strings, bulk), use(blobs, bulk), use(ints, bulk), @@ -345,7 +422,7 @@ public: try { - session() << "SELECT * FROM MiscTest ORDER BY First", + session() << "SELECT * FROM "<< ExecUtil::misctest() <<" ORDER BY First", into(strings), into(blobs), into(ints), @@ -372,14 +449,14 @@ public: try { - session() << "SELECT First FROM MiscTest", into(ints, bulk(size)), limit(size+1), now; + session() << "SELECT First FROM "<< ExecUtil::misctest(), into(ints, bulk(size)), limit(size+1), now; fail ("must fail"); } catch(Poco::InvalidArgumentException&){ } try { - session() << "SELECT First FROM MiscTest", into(ints), bulk(size), now; + session() << "SELECT First FROM "<< ExecUtil::misctest(), into(ints), bulk(size), now; fail ("must fail"); } catch(Poco::InvalidAccessException&){ } @@ -392,7 +469,7 @@ public: try { - session() << "SELECT * FROM MiscTest ORDER BY First", + session() << "SELECT * FROM "<< ExecUtil::misctest() <<" ORDER BY First", into(strings, bulk(size)), into(blobs, bulk(size)), into(ints, bulk(size)), @@ -435,6 +512,17 @@ public: void singleSelect(); void emptyDB(); + void assertImpl(bool condition, const std::string& conditionExpression, long lineNumber, const std::string& fileName) + { + assertImplementation(condition, conditionExpression, lineNumber, fileName); + } + + void failImpl(const std::string& message, long lineNumber, const std::string& fileName) + { + fail(message, lineNumber, fileName); + } + + void blob(int bigSize = 1024, const std::string& blobPlaceholder = "?"); template <typename C1, typename C2> @@ -448,16 +536,16 @@ public: C1 address(size, "Address"); C2 img(size, CLOB("0123456789", 10)); int count = 0; - try { session() << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(img), now; } + try { session() << "INSERT INTO " << ExecUtil::person() << " VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(img), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } + try { session() << "SELECT COUNT(*) FROM " << ExecUtil::person(), into(count), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (count == size); C2 res; - try { session() << "SELECT Image FROM Person", into(res), now; } + try { session() << "SELECT Image FROM " << ExecUtil::person(), into(res), now; } catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); } assert (res.size() == img.size()); @@ -476,13 +564,13 @@ public: void internalExtraction(); void filter(const std::string& query = - "SELECT * FROM Vectors ORDER BY int0 ASC", - const std::string& intFldName = "int0"); + "SELECT * FROM " + ExecUtil::vectors() + " ORDER BY i0 ASC", + const std::string& intFldName = "i0"); void internalBulkExtraction(); void internalBulkExtractionUTF16(); void internalStorageType(); - void nulls(); + void nulls(bool emptyStrIsSpace = false); void notNulls(const std::string& sqlState = "23502"); void rowIterator(); void stdVectorBool(); @@ -493,9 +581,11 @@ public: void dynamicAny(); void multipleResults(const std::string& sql = - "SELECT * FROM Person WHERE Age = ?; " - "SELECT Age FROM Person WHERE FirstName = 'Bart'; " - "SELECT * FROM Person WHERE Age = ? OR Age = ? ORDER BY Age;"); + "SELECT * FROM " + ExecUtil::person() + " WHERE Age = ?; " + "SELECT Age FROM " + ExecUtil::person() +" WHERE FirstName = 'Bart'; " + "SELECT * FROM " + ExecUtil::person() + " WHERE Age = ? OR Age = ? ORDER BY Age;"); + + void multipleResultsNoProj(const std::string& sql); void sqlChannel(const std::string& connect); void sqlLogger(const std::string& connect); @@ -514,9 +604,12 @@ private: static const std::string MULTI_SELECT; void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti); + std::string schemaTable(const std::string& tblName) const; Poco::Data::Session& session(); Poco::Data::Session* _pSession; + std::string _connInitSql; + std::string _schemaName; }; @@ -527,4 +620,10 @@ inline Poco::Data::Session& SQLExecutor::session() } +inline std::string SQLExecutor::schemaTable(const std::string& tblName) const +{ + return _schemaName.empty() ? tblName : _schemaName + "." + tblName; +} + + #endif // SQLExecutor_INCLUDED diff --git a/Data/SQLite/include/Poco/Data/SQLite/Binder.h b/Data/SQLite/include/Poco/Data/SQLite/Binder.h index c19770f41..00e3f96a8 100644 --- a/Data/SQLite/include/Poco/Data/SQLite/Binder.h +++ b/Data/SQLite/include/Poco/Data/SQLite/Binder.h @@ -43,72 +43,72 @@ public: ~Binder(); /// Destroys the Binder. - void bind(std::size_t pos, const Poco::Int8 &val, Direction dir); + void bind(std::size_t pos, const Poco::Int8 &val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int8. - void bind(std::size_t pos, const Poco::UInt8 &val, Direction dir); + void bind(std::size_t pos, const Poco::UInt8 &val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt8. - void bind(std::size_t pos, const Poco::Int16 &val, Direction dir); + void bind(std::size_t pos, const Poco::Int16 &val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int16. - void bind(std::size_t pos, const Poco::UInt16 &val, Direction dir); + void bind(std::size_t pos, const Poco::UInt16 &val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt16. - void bind(std::size_t pos, const Poco::Int32 &val, Direction dir); + void bind(std::size_t pos, const Poco::Int32 &val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int32. - void bind(std::size_t pos, const Poco::UInt32 &val, Direction dir); + void bind(std::size_t pos, const Poco::UInt32 &val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt32. - void bind(std::size_t pos, const Poco::Int64 &val, Direction dir); + void bind(std::size_t pos, const Poco::Int64 &val, Direction dir, const WhenNullCb& nullCb); /// Binds an Int64. - void bind(std::size_t pos, const Poco::UInt64 &val, Direction dir); + void bind(std::size_t pos, const Poco::UInt64 &val, Direction dir, const WhenNullCb& nullCb); /// Binds an UInt64. #ifndef POCO_LONG_IS_64_BIT - void bind(std::size_t pos, const long &val, Direction dir); + void bind(std::size_t pos, const long &val, Direction dir, const WhenNullCb& nullCb); /// Binds a long - void bind(std::size_t pos, const unsigned long &val, Direction dir); + void bind(std::size_t pos, const unsigned long &val, Direction dir, const WhenNullCb& nullCb); /// Binds an unsigned long #endif - void bind(std::size_t pos, const bool &val, Direction dir); + void bind(std::size_t pos, const bool &val, Direction dir, const WhenNullCb& nullCb); /// Binds a boolean. - void bind(std::size_t pos, const float &val, Direction dir); + void bind(std::size_t pos, const float &val, Direction dir, const WhenNullCb& nullCb); /// Binds a float. - void bind(std::size_t pos, const double &val, Direction dir); + void bind(std::size_t pos, const double &val, Direction dir, const WhenNullCb& nullCb); /// Binds a double. - void bind(std::size_t pos, const char &val, Direction dir); + void bind(std::size_t pos, const char &val, Direction dir, const WhenNullCb& nullCb); /// Binds a single character. - void bind(std::size_t pos, const char* const &pVal, Direction dir); + void bind(std::size_t pos, const char* const &pVal, Direction dir, const WhenNullCb& nullCb); /// Binds a const char ptr. - void bind(std::size_t pos, const std::string& val, Direction dir); + void bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& nullCb); /// Binds a string. - void bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir); + void bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir, const WhenNullCb& nullCb); /// Binds a BLOB. - void bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir); + void bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir, const WhenNullCb& nullCb); /// Binds a CLOB. - void bind(std::size_t pos, const Date& val, Direction dir); + void bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& nullCb); /// Binds a Date. - void bind(std::size_t pos, const Time& val, Direction dir); + void bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& nullCb); /// Binds a Time. - void bind(std::size_t pos, const DateTime& val, Direction dir); + void bind(std::size_t pos, const DateTime& val, Direction dir, const WhenNullCb& nullCb); /// Binds a DateTime. - void bind(std::size_t pos, const NullData& val, Direction dir); + void bind(std::size_t pos, const NullData& val, Direction dir, const std::type_info& bindType); /// Binds a null. private: @@ -117,7 +117,7 @@ private: /// if error has occurred. template <typename T> - void bindLOB(std::size_t pos, const Poco::Data::LOB<T>& val, Direction dir) + void bindLOB(std::size_t pos, const Poco::Data::LOB<T>& val, Direction dir, const WhenNullCb& nullCb) { // convert a blob to a an unsigned char* array const T* pData = reinterpret_cast<const T*>(val.rawContent()); @@ -134,85 +134,85 @@ private: // // inlines // -inline void Binder::bind(std::size_t pos, const Poco::Int8 &val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::Int8 &val, Direction dir, const WhenNullCb& nullCb) { Poco::Int32 tmp = val; - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const Poco::UInt8 &val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::UInt8 &val, Direction dir, const WhenNullCb& nullCb) { Poco::Int32 tmp = val; - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const Poco::Int16 &val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::Int16 &val, Direction dir, const WhenNullCb& nullCb) { Poco::Int32 tmp = val; - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const Poco::UInt16 &val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::UInt16 &val, Direction dir, const WhenNullCb& nullCb) { Poco::Int32 tmp = val; - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const Poco::UInt32 &val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::UInt32 &val, Direction dir, const WhenNullCb& nullCb) { Poco::Int32 tmp = static_cast<Poco::Int32>(val); - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const Poco::UInt64 &val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::UInt64 &val, Direction dir, const WhenNullCb& nullCb) { Poco::Int64 tmp = static_cast<Poco::Int64>(val); - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const bool &val, Direction dir) +inline void Binder::bind(std::size_t pos, const bool &val, Direction dir, const WhenNullCb& nullCb) { Poco::Int32 tmp = (val ? 1 : 0); - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const float &val, Direction dir) +inline void Binder::bind(std::size_t pos, const float &val, Direction dir, const WhenNullCb& nullCb) { double tmp = val; - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const char &val, Direction dir) +inline void Binder::bind(std::size_t pos, const char &val, Direction dir, const WhenNullCb& nullCb) { Poco::Int32 tmp = val; - bind(pos, tmp, dir); + bind(pos, tmp, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir) +inline void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir, const WhenNullCb& nullCb) { std::string val(pVal); - bind(pos, val, dir); + bind(pos, val, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir, const WhenNullCb& nullCb) { - bindLOB<Poco::Data::BLOB::ValueType>(pos, val, dir); + bindLOB<Poco::Data::BLOB::ValueType>(pos, val, dir, nullCb); } -inline void Binder::bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir) +inline void Binder::bind(std::size_t pos, const Poco::Data::CLOB& val, Direction dir, const WhenNullCb& nullCb) { - bindLOB<Poco::Data::CLOB::ValueType>(pos, val, dir); + bindLOB<Poco::Data::CLOB::ValueType>(pos, val, dir, nullCb); } diff --git a/Data/SQLite/include/Poco/Data/SQLite/SQLiteStatementImpl.h b/Data/SQLite/include/Poco/Data/SQLite/SQLiteStatementImpl.h index 5ff43d430..2dc20c817 100644 --- a/Data/SQLite/include/Poco/Data/SQLite/SQLiteStatementImpl.h +++ b/Data/SQLite/include/Poco/Data/SQLite/SQLiteStatementImpl.h @@ -60,7 +60,7 @@ protected: /// All changes are counted, even if they are later undone by a ROLLBACK or ABORT. /// Changes associated with creating and dropping tables are not counted. - const MetaColumn& metaColumn(std::size_t pos) const; + const MetaColumn& metaColumn(std::size_t pos, std::size_t dataSet) const; /// Returns column meta data. bool hasNext(); diff --git a/Data/SQLite/src/Binder.cpp b/Data/SQLite/src/Binder.cpp index 2375645a8..0cc9ff8e6 100644 --- a/Data/SQLite/src/Binder.cpp +++ b/Data/SQLite/src/Binder.cpp @@ -44,14 +44,14 @@ Binder::~Binder() } -void Binder::bind(std::size_t pos, const Poco::Int32 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int32 &val, Direction dir, const WhenNullCb& nullCb) { int rc = sqlite3_bind_int(_pStmt, (int) pos, val); checkReturn(rc); } -void Binder::bind(std::size_t pos, const Poco::Int64 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int64 &val, Direction dir, const WhenNullCb& nullCb) { int rc = sqlite3_bind_int64(_pStmt, (int) pos, val); checkReturn(rc); @@ -59,14 +59,14 @@ void Binder::bind(std::size_t pos, const Poco::Int64 &val, Direction dir) #ifndef POCO_LONG_IS_64_BIT -void Binder::bind(std::size_t pos, const long &val, Direction dir) +void Binder::bind(std::size_t pos, const long &val, Direction dir, const WhenNullCb& nullCb) { long tmp = static_cast<long>(val); int rc = sqlite3_bind_int(_pStmt, (int) pos, tmp); checkReturn(rc); } -void Binder::bind(std::size_t pos, const unsigned long &val, Direction dir) +void Binder::bind(std::size_t pos, const unsigned long &val, Direction dir, const WhenNullCb& nullCb) { long tmp = static_cast<long>(val); int rc = sqlite3_bind_int(_pStmt, (int) pos, tmp); @@ -75,45 +75,45 @@ void Binder::bind(std::size_t pos, const unsigned long &val, Direction dir) #endif -void Binder::bind(std::size_t pos, const double &val, Direction dir) +void Binder::bind(std::size_t pos, const double &val, Direction dir, const WhenNullCb& nullCb) { int rc = sqlite3_bind_double(_pStmt, (int) pos, val); checkReturn(rc); } -void Binder::bind(std::size_t pos, const std::string& val, Direction dir) +void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& nullCb) { int rc = sqlite3_bind_text(_pStmt, (int) pos, val.c_str(), (int) val.size()*sizeof(char), SQLITE_TRANSIENT); checkReturn(rc); } -void Binder::bind(std::size_t pos, const Date& val, Direction dir) +void Binder::bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& nullCb) { DateTime dt(val.year(), val.month(), val.day()); std::string str(DateTimeFormatter::format(dt, Utility::SQLITE_DATE_FORMAT)); - bind(pos, str, dir); + bind(pos, str, dir, nullCb); } -void Binder::bind(std::size_t pos, const Time& val, Direction dir) +void Binder::bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& nullCb) { DateTime dt; dt.assign(dt.year(), dt.month(), dt.day(), val.hour(), val.minute(), val.second()); std::string str(DateTimeFormatter::format(dt, Utility::SQLITE_TIME_FORMAT)); - bind(pos, str, dir); + bind(pos, str, dir, nullCb); } -void Binder::bind(std::size_t pos, const DateTime& val, Direction dir) +void Binder::bind(std::size_t pos, const DateTime& val, Direction dir, const WhenNullCb& nullCb) { std::string dt(DateTimeFormatter::format(val, DateTimeFormat::ISO8601_FORMAT)); - bind(pos, dt, dir); + bind(pos, dt, dir, nullCb); } -void Binder::bind(std::size_t pos, const NullData&, Direction) +void Binder::bind(std::size_t pos, const NullData&, Direction, const std::type_info& bindType) { sqlite3_bind_null(_pStmt, pos); } diff --git a/Data/SQLite/src/SQLiteStatementImpl.cpp b/Data/SQLite/src/SQLiteStatementImpl.cpp index 5f0b6c725..4906fadf8 100644 --- a/Data/SQLite/src/SQLiteStatementImpl.cpp +++ b/Data/SQLite/src/SQLiteStatementImpl.cpp @@ -302,11 +302,10 @@ std::size_t SQLiteStatementImpl::columnsReturned() const } -const MetaColumn& SQLiteStatementImpl::metaColumn(std::size_t pos) const +const MetaColumn& SQLiteStatementImpl::metaColumn(std::size_t pos, std::size_t dataSet) const { - std::size_t curDataSet = currentDataSet(); - poco_assert (pos >= 0 && pos <= _columns[curDataSet].size()); - return _columns[curDataSet][pos]; + poco_assert (pos >= 0 && pos <= _columns[dataSet].size()); + return _columns[dataSet][pos]; } diff --git a/Data/include/Poco/Data/AbstractBinder.h b/Data/include/Poco/Data/AbstractBinder.h index d478b96bb..c1e6ace1e 100644 --- a/Data/include/Poco/Data/AbstractBinder.h +++ b/Data/include/Poco/Data/AbstractBinder.h @@ -39,24 +39,86 @@ namespace Poco { namespace Data { -typedef NullType NullData; +enum NullData +{ + NULL_GENERIC = Poco::NULL_GENERIC, + DATA_NULL_INTEGER = 1, + DATA_NULL_STRING = 2, + DATA_NULL_DATE = 3, + DATA_NULL_TIME = 4, + DATA_NULL_DATETIME = 5, + DATA_NULL_BLOB = 6, + DATA_NULL_FLOAT = 7 +}; + + +struct NullValue +{ + + NullValue() + {} + + template <typename T> + operator Poco::Nullable<T>() const + { + return Poco::Nullable<T>(); + } + + template <typename T> + static NullData nullCode() + { + return Data::NULL_GENERIC; + } + +}; namespace Keywords { - -static const NullData null = NULL_GENERIC; - +static const NullValue null; } // namespace Keywords +template <typename T> +inline bool operator==(const NullValue& nv, const Nullable<T>& n) +{ + return n.isNull(); +} + + +template <typename T> +inline bool operator!=(const NullValue& nv, const Nullable<T>& n) +{ + return !n.isNull(); +} + + class Data_API AbstractBinder /// Interface for Binding data types to placeholders. { public: typedef SharedPtr<AbstractBinder> Ptr; + struct WhenNullCb + { + WhenNullCb() :_func(NULL) + {} + + inline bool defined() const + { + return (_func != NULL); + } + + inline void onNull() + { + if (_func) _func(_data); + } + protected: + void* _data; + void (*_func)(void*); + }; + enum Direction /// Binding direction for a parameter. { @@ -71,7 +133,7 @@ public: virtual ~AbstractBinder(); /// Destroys the AbstractBinder. - virtual void bind(std::size_t pos, const Poco::Int8& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Poco::Int8& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds an Int8. virtual void bind(std::size_t pos, const std::vector<Poco::Int8>& val, Direction dir = PD_IN); @@ -83,7 +145,7 @@ public: virtual void bind(std::size_t pos, const std::list<Poco::Int8>& val, Direction dir = PD_IN); /// Binds an Int8 list. - virtual void bind(std::size_t pos, const Poco::UInt8& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Poco::UInt8& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds an UInt8. virtual void bind(std::size_t pos, const std::vector<Poco::UInt8>& val, Direction dir = PD_IN); @@ -95,7 +157,7 @@ public: virtual void bind(std::size_t pos, const std::list<Poco::UInt8>& val, Direction dir = PD_IN); /// Binds an UInt8 list. - virtual void bind(std::size_t pos, const Poco::Int16& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Poco::Int16& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds an Int16. virtual void bind(std::size_t pos, const std::vector<Poco::Int16>& val, Direction dir = PD_IN); @@ -107,7 +169,7 @@ public: virtual void bind(std::size_t pos, const std::list<Poco::Int16>& val, Direction dir = PD_IN); /// Binds an Int16 list. - virtual void bind(std::size_t pos, const Poco::UInt16& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Poco::UInt16& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds an UInt16. virtual void bind(std::size_t pos, const std::vector<Poco::UInt16>& val, Direction dir = PD_IN); @@ -119,7 +181,7 @@ public: virtual void bind(std::size_t pos, const std::list<Poco::UInt16>& val, Direction dir = PD_IN); /// Binds an UInt16 list. - virtual void bind(std::size_t pos, const Poco::Int32& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Poco::Int32& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds an Int32. virtual void bind(std::size_t pos, const std::vector<Poco::Int32>& val, Direction dir = PD_IN); @@ -131,7 +193,7 @@ public: virtual void bind(std::size_t pos, const std::list<Poco::Int32>& val, Direction dir = PD_IN); /// Binds an Int32 list. - virtual void bind(std::size_t pos, const Poco::UInt32& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Poco::UInt32& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds an UInt32. virtual void bind(std::size_t pos, const std::vector<Poco::UInt32>& val, Direction dir = PD_IN); @@ -143,7 +205,7 @@ public: virtual void bind(std::size_t pos, const std::list<Poco::UInt32>& val, Direction dir = PD_IN); /// Binds an UInt32 list. - virtual void bind(std::size_t pos, const Poco::Int64& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Poco::Int64& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds an Int64. virtual void bind(std::size_t pos, const std::vector<Poco::Int64>& val, Direction dir = PD_IN); @@ -155,7 +217,7 @@ public: virtual void bind(std::size_t pos, const std::list<Poco::Int64>& val, Direction dir = PD_IN); /// Binds an Int64 list. - virtual void bind(std::size_t pos, const Poco::UInt64& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Poco::UInt64& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds an UInt64. virtual void bind(std::size_t pos, const std::vector<Poco::UInt64>& val, Direction dir = PD_IN); @@ -168,11 +230,11 @@ public: /// Binds an UInt64 list. #ifndef POCO_LONG_IS_64_BIT - virtual void bind(std::size_t pos, const long& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const long& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a long. - virtual void bind(std::size_t pos, const unsigned long& val, Direction dir = PD_IN) = 0; - /// Binds an unsigned long. + virtual void bind(std::size_t pos, const unsigned long& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; + /// Binds an unsiged long. virtual void bind(std::size_t pos, const std::vector<long>& val, Direction dir = PD_IN); /// Binds a long vector. @@ -184,7 +246,7 @@ public: /// Binds a long list. #endif - virtual void bind(std::size_t pos, const bool& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const bool& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a boolean. virtual void bind(std::size_t pos, const std::vector<bool>& val, Direction dir = PD_IN); @@ -196,7 +258,7 @@ public: virtual void bind(std::size_t pos, const std::list<bool>& val, Direction dir = PD_IN); /// Binds a boolean list. - virtual void bind(std::size_t pos, const float& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const float& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a float. virtual void bind(std::size_t pos, const std::vector<float>& val, Direction dir = PD_IN); @@ -208,7 +270,7 @@ public: virtual void bind(std::size_t pos, const std::list<float>& val, Direction dir = PD_IN); /// Binds a float list. - virtual void bind(std::size_t pos, const double& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const double& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a double. virtual void bind(std::size_t pos, const std::vector<double>& val, Direction dir = PD_IN); @@ -220,7 +282,7 @@ public: virtual void bind(std::size_t pos, const std::list<double>& val, Direction dir = PD_IN); /// Binds a double list. - virtual void bind(std::size_t pos, const char& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const char& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a single character. virtual void bind(std::size_t pos, const std::vector<char>& val, Direction dir = PD_IN); @@ -232,10 +294,10 @@ public: virtual void bind(std::size_t pos, const std::list<char>& val, Direction dir = PD_IN); /// Binds a character list. - virtual void bind(std::size_t pos, const char* const& pVal, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const char* const& pVal, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a const char ptr. - virtual void bind(std::size_t pos, const std::string& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const std::string& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a string. virtual void bind(std::size_t pos, const std::vector<std::string>& val, Direction dir = PD_IN); @@ -247,7 +309,7 @@ public: virtual void bind(std::size_t pos, const std::list<std::string>& val, Direction dir = PD_IN); /// Binds a string list. - virtual void bind(std::size_t pos, const UTF16String& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const UTF16String& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()); /// Binds a UTF-16 Unicode string. virtual void bind(std::size_t pos, const std::vector<UTF16String>& val, Direction dir = PD_IN); @@ -259,10 +321,10 @@ public: virtual void bind(std::size_t pos, const std::list<UTF16String>& val, Direction dir = PD_IN); /// Binds a UTF-16 Unicode string list. - virtual void bind(std::size_t pos, const BLOB& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const BLOB& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a BLOB. - virtual void bind(std::size_t pos, const CLOB& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const CLOB& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a CLOB. virtual void bind(std::size_t pos, const std::vector<BLOB>& val, Direction dir = PD_IN); @@ -283,7 +345,7 @@ public: virtual void bind(std::size_t pos, const std::list<CLOB>& val, Direction dir = PD_IN); /// Binds a CLOB list. - virtual void bind(std::size_t pos, const DateTime& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const DateTime& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a DateTime. virtual void bind(std::size_t pos, const std::vector<DateTime>& val, Direction dir = PD_IN); @@ -295,7 +357,7 @@ public: virtual void bind(std::size_t pos, const std::list<DateTime>& val, Direction dir = PD_IN); /// Binds a DateTime list. - virtual void bind(std::size_t pos, const Date& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Date& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a Date. virtual void bind(std::size_t pos, const std::vector<Date>& val, Direction dir = PD_IN); @@ -307,7 +369,7 @@ public: virtual void bind(std::size_t pos, const std::list<Date>& val, Direction dir = PD_IN); /// Binds a Date list. - virtual void bind(std::size_t pos, const Time& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const Time& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()) = 0; /// Binds a Time. virtual void bind(std::size_t pos, const std::vector<Time>& val, Direction dir = PD_IN); @@ -319,22 +381,22 @@ public: virtual void bind(std::size_t pos, const std::list<Time>& val, Direction dir = PD_IN); /// Binds a Time list. - virtual void bind(std::size_t pos, const NullData& val, Direction dir = PD_IN) = 0; + virtual void bind(std::size_t pos, const NullData& val, Direction dir = PD_IN, const std::type_info& bindType = typeid(void)) = 0; /// Binds a null. - virtual void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir = PD_IN, const std::type_info& bindElemType = typeid(void)); /// Binds a null vector. - virtual void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir = PD_IN, const std::type_info& bindElemType = typeid(void)); /// Binds a null deque. - virtual void bind(std::size_t pos, const std::list<NullData>& val, Direction dir = PD_IN); + virtual void bind(std::size_t pos, const std::list<NullData>& val, Direction dir = PD_IN, const std::type_info& bindElemType = typeid(void)); /// Binds a null list. - void bind(std::size_t pos, const Any& val, Direction dir = PD_IN); + void bind(std::size_t pos, const Any& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()); /// Binds an Any. - void bind(std::size_t pos, const Poco::Dynamic::Var& val, Direction dir = PD_IN); + void bind(std::size_t pos, const Poco::Dynamic::Var& val, Direction dir = PD_IN, const WhenNullCb& nullCb = WhenNullCb()); /// Binds a Var. virtual void reset(); diff --git a/Data/include/Poco/Data/Binding.h b/Data/include/Poco/Data/Binding.h index c22396aff..af8398dc7 100644 --- a/Data/include/Poco/Data/Binding.h +++ b/Data/include/Poco/Data/Binding.h @@ -1401,6 +1401,13 @@ inline AbstractBinding::Ptr use(const NullData& t, const std::string& name = "") return new Binding<NullData>(const_cast<NullData&>(t), name, AbstractBinding::PD_IN); } +inline AbstractBinding::Ptr use(const NullValue& t, const std::string& name = "") +/// NullData overload. +{ + return use(NullValue::nullCode<void>(), name); +} + + template <typename T> inline AbstractBinding::Ptr useRef(T& t, const std::string& name = "") diff --git a/Data/include/Poco/Data/Extraction.h b/Data/include/Poco/Data/Extraction.h index 42dbd6c16..bbfb293bb 100644 --- a/Data/include/Poco/Data/Extraction.h +++ b/Data/include/Poco/Data/Extraction.h @@ -39,6 +39,43 @@ namespace Poco { namespace Data { + template <typename CollTp, typename ElemTp = typename CollTp::value_type> + struct DefaultInitializer + { + static void appendElem(CollTp& coll, const ElemTp& defVal) + { + coll.push_back(defVal); + } + }; + + template <typename CollTp> + struct DefaultInitializer<CollTp, CLOB> + { + static void appendElem(CollTp& coll, const CLOB& defVal) + { + CLOB v(defVal.rawContent(), defVal.size()); + coll.push_back(v); + } + }; + + template <typename CollTp> + struct DefaultInitializer<CollTp, BLOB> + { + static void appendElem(CollTp& coll, const BLOB& defVal) + { + BLOB v(defVal.rawContent(), defVal.size()); + coll.push_back(v); + } + }; + + template <typename CollTp> + inline void appendElem(CollTp& coll, const typename CollTp::value_type& defVal) + { + DefaultInitializer<CollTp, typename CollTp::value_type>::appendElem(coll, defVal); + } + + + template <class T> class Extraction: public AbstractExtraction /// Concrete Data Type specific extraction of values from a query result set. @@ -190,7 +227,7 @@ public: std::size_t extract(std::size_t pos) { AbstractExtractor::Ptr pExt = getExtractor(); - _rResult.push_back(_default); + appendElem(_rResult, _default); TypeHandler<T>::extract(pos, _rResult.back(), _default, pExt); _nulls.push_back(isValueNull(_rResult.back(), pExt->isNull(pos))); return 1u; @@ -372,7 +409,7 @@ public: std::size_t extract(std::size_t pos) { AbstractExtractor::Ptr pExt = getExtractor(); - _rResult.push_back(_default); + appendElem(_rResult, _default); TypeHandler<T>::extract(pos, _rResult.back(), _default, pExt); _nulls.push_back(isValueNull(_rResult.back(), pExt->isNull(pos))); return 1u; @@ -462,7 +499,7 @@ public: std::size_t extract(std::size_t pos) { AbstractExtractor::Ptr pExt = getExtractor(); - _rResult.push_back(_default); + appendElem(_rResult, _default); TypeHandler<T>::extract(pos, _rResult.back(), _default, pExt); _nulls.push_back(isValueNull(_rResult.back(), pExt->isNull(pos))); return 1u; diff --git a/Data/include/Poco/Data/Position.h b/Data/include/Poco/Data/Position.h index 0d0f251eb..8301301b8 100644 --- a/Data/include/Poco/Data/Position.h +++ b/Data/include/Poco/Data/Position.h @@ -32,26 +32,28 @@ class Data_API Position /// indicate the recordset position in batch SQL statements. { public: - Position(Poco::UInt32 value); + typedef Poco::UInt32 PositionType; + + Position(PositionType value); /// Creates the Position. ~Position(); /// Destroys the Position. - Poco::UInt32 value() const; + PositionType value() const; /// Returns the position value. private: Position(); - Poco::UInt32 _value; + PositionType _value; }; /// /// inlines /// -inline Poco::UInt32 Position::value() const +inline Position::PositionType Position::value() const { return _value; } diff --git a/Data/include/Poco/Data/RecordSet.h b/Data/include/Poco/Data/RecordSet.h index 9bc9f3c33..722511a67 100644 --- a/Data/include/Poco/Data/RecordSet.h +++ b/Data/include/Poco/Data/RecordSet.h @@ -190,6 +190,10 @@ public: /// Returns reference to row at position pos. /// Rows are lazy-created and cached. + template <class T> + const T& value(std::size_t col) const; + /// Returns the reference to data value at [col] location. + template <class T> const T& value(std::size_t col, std::size_t dataRow, bool useFilter = true) const /// Returns the reference to data value at [col, row] location. @@ -315,16 +319,16 @@ public: /// Returns true if there is at least one row in the RecordSet, /// false otherwise. - Poco::Dynamic::Var value(const std::string& name); + Poco::Dynamic::Var value(const std::string& name) const; /// Returns the value in the named column of the current row. - Poco::Dynamic::Var value(std::size_t index); + Poco::Dynamic::Var value(std::size_t index) const; /// Returns the value in the given column of the current row. - Poco::Dynamic::Var operator [] (const std::string& name); + Poco::Dynamic::Var operator [] (const std::string& name) const; /// Returns the value in the named column of the current row. - Poco::Dynamic::Var operator [] (std::size_t index); + Poco::Dynamic::Var operator [] (std::size_t index) const; /// Returns the value in the named column of the current row. MetaColumn::ColumnDataType columnType(std::size_t pos) const; @@ -353,6 +357,9 @@ public: bool isNull(const std::string& name) const; /// Returns true if column value of the current row is null. + bool isNull(std::size_t& colNo) const; + /// Returns true if column value of the current row is null. + std::ostream& copyNames(std::ostream& os) const; /// Copies the column names to the target output stream. /// Copied string is formatted by the current RowFormatter. @@ -457,6 +464,8 @@ private: } } + size_t storageRowCount() const; + bool isAllowed(std::size_t row) const; /// Returns true if the specified row is allowed by the /// currently active filter. @@ -530,29 +539,35 @@ inline Statement& RecordSet::operator = (const Statement& stmt) } -inline Poco::Dynamic::Var RecordSet::value(const std::string& name) +inline Poco::Dynamic::Var RecordSet::value(const std::string& name) const { return value(name, _currentRow); } -inline Poco::Dynamic::Var RecordSet::value(std::size_t index) +inline Poco::Dynamic::Var RecordSet::value(std::size_t index) const { return value(index, _currentRow); } -inline Poco::Dynamic::Var RecordSet::operator [] (const std::string& name) +inline Poco::Dynamic::Var RecordSet::operator [] (const std::string& name) const { return value(name, _currentRow); } -inline Poco::Dynamic::Var RecordSet::operator [] (std::size_t index) +inline Poco::Dynamic::Var RecordSet::operator [] (std::size_t index) const { return value(index, _currentRow); } +template <class T> +inline const T& RecordSet::value(std::size_t col) const +{ + return value<T>(col, _currentRow); +} + inline MetaColumn::ColumnDataType RecordSet::columnType(std::size_t pos)const { @@ -602,6 +617,11 @@ inline bool RecordSet::isNull(const std::string& name) const } +inline bool RecordSet::isNull(std::size_t& colNo) const +{ + return isNull(colNo, _currentRow); +} + inline RecordSet::ConstIterator& RecordSet::begin() const { return *_pBegin; @@ -638,6 +658,11 @@ inline void RecordSet::formatNames() const } +inline size_t RecordSet::storageRowCount() const +{ + return impl()->rowsExtracted(); +} + /* TODO namespace Keywords { diff --git a/Data/include/Poco/Data/Row.h b/Data/include/Poco/Data/Row.h index 3af4f60f2..44545f964 100644 --- a/Data/include/Poco/Data/Row.h +++ b/Data/include/Poco/Data/Row.h @@ -104,6 +104,15 @@ public: Poco::Dynamic::Var& operator [] (const std::string& name); /// Returns the reference to data value at named column location. + const Poco::Dynamic::Var& get(std::size_t col) const; + /// Returns the reference to data value at column location. + + const Poco::Dynamic::Var& operator [] (std::size_t col) const; + /// Returns the reference to data value at column location. + + const Poco::Dynamic::Var& operator [] (const std::string& name) const; + /// Returns the reference to data value at named column location. + template <typename T> void append(const std::string& name, const T& val) /// Appends the value to the row. @@ -225,7 +234,7 @@ private: ValueVec& values(); /// Returns the reference to values vector. - std::size_t getPosition(const std::string& name); + std::size_t getPosition(const std::string& name) const; bool isEqualSize(const Row& other) const; bool isEqualType(const Row& other) const; @@ -287,6 +296,18 @@ inline Poco::Dynamic::Var& Row::operator [] (const std::string& name) } +inline const Poco::Dynamic::Var& Row::operator [] (std::size_t col) const +{ + return get(col); +} + + +inline const Poco::Dynamic::Var& Row::operator [] (const std::string& name) const +{ + return get(getPosition(name)); +} + + inline const RowFormatter& Row::getFormatter() const { return *_pFormatter; diff --git a/Data/include/Poco/Data/Statement.h b/Data/include/Poco/Data/Statement.h index 17cb974e2..a706995e3 100644 --- a/Data/include/Poco/Data/Statement.h +++ b/Data/include/Poco/Data/Statement.h @@ -365,10 +365,18 @@ public: /// Returns false if the current data set index points to the last /// data set. Otherwise, it returns true. + std::size_t firstDataSet(); + /// Activates the first data set + + std::size_t currentDataSet() const; + /// Returns the current data set. + void setRowFormatter(RowFormatter::Ptr pRowFormatter); /// Sets the row formatter for this statement. /// Statement takes the ownership of the formatter. + void insertHint(); + /// Tells the statement that it is an sinsert one protected: typedef StatementImpl::Ptr ImplPtr; @@ -670,7 +678,7 @@ inline const AbstractExtractionVec& Statement::extractions() const inline const MetaColumn& Statement::metaColumn(std::size_t pos) const { - return _pImpl->metaColumn(pos); + return _pImpl->metaColumn(pos, _pImpl->currentDataSet()); } @@ -770,6 +778,19 @@ inline bool Statement::isBulkExtraction() const } +inline std::size_t Statement::firstDataSet() +{ + _pImpl->firstDataSet(); + return 0; +} + + +inline std::size_t Statement::currentDataSet() const +{ + return _pImpl->currentDataSet(); +} + + inline bool Statement::isAsync() const { return _async; @@ -789,6 +810,11 @@ inline const RowFormatter::Ptr& Statement::getRowFormatter() } +inline void Statement::insertHint() +{ + _pImpl->insertHint(); +} + inline void swap(Statement& s1, Statement& s2) { s1.swap(s2); diff --git a/Data/include/Poco/Data/StatementImpl.h b/Data/include/Poco/Data/StatementImpl.h index 859cc2d57..0c8b8e117 100644 --- a/Data/include/Poco/Data/StatementImpl.h +++ b/Data/include/Poco/Data/StatementImpl.h @@ -44,6 +44,8 @@ namespace Poco { namespace Data { +class RecordSet; + class Data_API StatementImpl /// StatementImpl interface that subclasses must implement to define database dependent query execution. /// @@ -157,7 +159,13 @@ public: std::size_t dataSetCount() const; /// Returns the number of data sets associated with the statement. + std::size_t currentDataSet() const; + /// Returns the current data set. + protected: + virtual void insertHint(); + /// Hints the implementation that it is an insert statement + virtual std::size_t columnsReturned() const = 0; /// Returns number of columns returned by query. @@ -169,7 +177,7 @@ protected: /// some ODBC drivers when this function is called after a select statement /// execution). - virtual const MetaColumn& metaColumn(std::size_t pos) const = 0; + virtual const MetaColumn& metaColumn(std::size_t pos, size_t dataSet) const = 0; /// Returns column meta data. const MetaColumn& metaColumn(const std::string& name) const; @@ -252,6 +260,9 @@ protected: /// - std::vector /// - std::list + void makeExtractors(std::size_t count, const Position& position); + /// Create extractors for the specified dataset + SessionImpl& session(); /// Returns session associated with this statement. @@ -284,9 +295,6 @@ protected: /// When connector-specific behavior is desired, it should be overriden /// by the statement implementation. - std::size_t currentDataSet() const; - /// Returns the current data set. - std::size_t activateNextDataSet(); /// Returns the next data set index, or throws NoDataException if the last /// data set was reached. @@ -295,10 +303,14 @@ protected: /// Returns the previous data set index, or throws NoDataException if the last /// data set was reached. + void firstDataSet(); + /// Activate first data set + bool hasMoreDataSets() const; /// Returns true if there are data sets not activated yet. private: + void compile(); /// Compiles the statement. @@ -319,26 +331,26 @@ private: /// Resets extraction so it can be reused again. template <class C> - SharedPtr<InternalExtraction<C> > createExtract(const MetaColumn& mc) + SharedPtr<InternalExtraction<C> > createExtract(const MetaColumn& mc, size_t position) { C* pData = new C; Column<C>* pCol = new Column<C>(mc, pData); - return new InternalExtraction<C>(*pData, pCol, Poco::UInt32(currentDataSet())); + return new InternalExtraction<C>(*pData, pCol, Poco::UInt32(position)); } template <class C> - SharedPtr<InternalBulkExtraction<C> > createBulkExtract(const MetaColumn& mc) + SharedPtr<InternalBulkExtraction<C> > createBulkExtract(const MetaColumn& mc, size_t position) { C* pData = new C; Column<C>* pCol = new Column<C>(mc, pData); return new InternalBulkExtraction<C>(*pData, pCol, static_cast<Poco::UInt32>(getExtractionLimit()), - Position(static_cast<Poco::UInt32>(currentDataSet()))); + Position(static_cast<Poco::UInt32>(position))); } template <class T> - void addInternalExtract(const MetaColumn& mc) + void addInternalExtract(const MetaColumn& mc, size_t position) /// Creates and adds the internal extraction. /// /// The decision about internal extraction container is done @@ -370,23 +382,23 @@ private: if (0 == icompare(DEQUE, storage)) { if (!isBulkExtraction()) - addExtract(createExtract<std::deque<T> >(mc)); + addExtract(createExtract<std::deque<T> >(mc, position)); else - addExtract(createBulkExtract<std::deque<T> >(mc)); + addExtract(createBulkExtract<std::deque<T> >(mc, position)); } else if (0 == icompare(VECTOR, storage)) { if (!isBulkExtraction()) - addExtract(createExtract<std::vector<T> >(mc)); + addExtract(createExtract<std::vector<T> >(mc, position)); else - addExtract(createBulkExtract<std::vector<T> >(mc)); + addExtract(createBulkExtract<std::vector<T> >(mc, position)); } else if (0 == icompare(LIST, storage)) { if (!isBulkExtraction()) - addExtract(createExtract<std::list<T> >(mc)); + addExtract(createExtract<std::list<T> >(mc, position)); else - addExtract(createBulkExtract<std::list<T> >(mc)); + addExtract(createBulkExtract<std::list<T> >(mc, position)); } } @@ -427,7 +439,7 @@ private: void formatSQL(std::vector<Any>& arguments); /// Formats the SQL string by filling in placeholders with values from supplied vector. - void assignSubTotal(bool reset); + void assignSubTotal(bool reset, size_t firstDs); StatementImpl(const StatementImpl& stmt); StatementImpl& operator = (const StatementImpl& stmt); @@ -444,11 +456,13 @@ private: AbstractBindingVec _bindings; AbstractExtractionVecVec _extractors; std::size_t _curDataSet; + std::size_t _pendingDSNo; BulkType _bulkBinding; BulkType _bulkExtraction; CountVec _subTotalRowCount; friend class Statement; + friend class RecordSet; }; @@ -627,6 +641,13 @@ inline bool StatementImpl::hasMoreDataSets() const } +inline void StatementImpl::firstDataSet() +{ + _curDataSet = 0; + _pendingDSNo = 0; +} + + } } // namespace Poco::Data diff --git a/Data/include/Poco/Data/TypeHandler.h b/Data/include/Poco/Data/TypeHandler.h index 06ad089ac..9f7d85c2e 100644 --- a/Data/include/Poco/Data/TypeHandler.h +++ b/Data/include/Poco/Data/TypeHandler.h @@ -254,6 +254,21 @@ template <typename T> class TypeHandler<Nullable<T> > /// Specialization of type handler for Nullable. { + class NullHandler : public AbstractBinder::WhenNullCb + { + public: + explicit NullHandler(const Nullable<T>& obj) + { + _data = &const_cast<Nullable<T>&>(obj); + _func = handle; + } + private: + static void handle(void* ptr) + { + reinterpret_cast<Nullable<T>*>(ptr)->clear(); + } + }; + public: static void bind(std::size_t pos, const Nullable<T>& obj, AbstractBinder::Ptr pBinder, AbstractBinder::Direction dir) @@ -261,11 +276,14 @@ public: poco_assert_dbg (!pBinder.isNull()); if (obj.isNull()) { - pBinder->bind(pos++, Poco::Data::Keywords::null, dir); + pBinder->bind(pos++, NullValue::nullCode<T>(), dir, typeid(T)); } else { - pBinder->bind(pos++, obj.value(), dir); + if (AbstractBinder::isOutBound(dir)) + pBinder->bind(pos++, obj.value(), dir, NullHandler(obj)); + else + pBinder->bind(pos++, obj.value(), dir); } } @@ -274,7 +292,7 @@ public: poco_assert_dbg (!pPreparator.isNull()); if (obj.isNull()) { - pPreparator->prepare(pos++, Poco::Data::Keywords::null); + pPreparator->prepare(pos++, NullValue::nullCode<T>()); } else { diff --git a/Data/src/AbstractBinder.cpp b/Data/src/AbstractBinder.cpp index 465338e4d..0eb8689c8 100644 --- a/Data/src/AbstractBinder.cpp +++ b/Data/src/AbstractBinder.cpp @@ -292,7 +292,7 @@ void AbstractBinder::bind(std::size_t pos, const std::list<std::string>& val, Di } -void AbstractBinder::bind(std::size_t pos, const UTF16String& val, Direction dir) +void AbstractBinder::bind(std::size_t pos, const UTF16String& val, Direction dir, const WhenNullCb& nullCb) { throw NotImplementedException("UTF16String binder must be implemented."); } @@ -406,120 +406,124 @@ void AbstractBinder::bind(std::size_t pos, const std::list<Time>& val, Direction } -void AbstractBinder::bind(std::size_t pos, const std::vector<NullData>& val, Direction dir) +void AbstractBinder::bind(std::size_t pos, const std::vector<NullData>& val, Direction dir, const std::type_info& bindElemType) { throw NotImplementedException("std::vector binder must be implemented."); } -void AbstractBinder::bind(std::size_t pos, const std::deque<NullData>& val, Direction dir) +void AbstractBinder::bind(std::size_t pos, const std::deque<NullData>& val, Direction dir, const std::type_info& bindElemType) { throw NotImplementedException("std::deque binder must be implemented."); } -void AbstractBinder::bind(std::size_t pos, const std::list<NullData>& val, Direction dir) +void AbstractBinder::bind(std::size_t pos, const std::list<NullData>& val, Direction dir, const std::type_info& bindElemType) { throw NotImplementedException("std::list binder must be implemented."); } -void AbstractBinder::bind(std::size_t pos, const Any& val, Direction dir) +void AbstractBinder::bind(std::size_t pos, const Any& val, Direction dir, const WhenNullCb& nullCb) { const std::type_info& type = val.type(); if(type == typeid(Int32)) - bind(pos, RefAnyCast<Int32>(val), dir); + bind(pos, RefAnyCast<Int32>(val), dir, nullCb); else if(type == typeid(std::string)) - bind(pos, RefAnyCast<std::string>(val), dir); + bind(pos, RefAnyCast<std::string>(val), dir, nullCb); else if (type == typeid(Poco::UTF16String)) - bind(pos, RefAnyCast<Poco::UTF16String>(val), dir); + bind(pos, RefAnyCast<Poco::UTF16String>(val), dir, nullCb); else if (type == typeid(bool)) - bind(pos, RefAnyCast<bool>(val), dir); + bind(pos, RefAnyCast<bool>(val), dir, nullCb); else if(type == typeid(char)) - bind(pos, RefAnyCast<char>(val), dir); + bind(pos, RefAnyCast<char>(val), dir, nullCb); else if(type == typeid(Int8)) - bind(pos, RefAnyCast<Int8>(val), dir); + bind(pos, RefAnyCast<Int8>(val), dir, nullCb); else if(type == typeid(UInt8)) - bind(pos, RefAnyCast<UInt8>(val), dir); + bind(pos, RefAnyCast<UInt8>(val), dir, nullCb); else if(type == typeid(Int16)) - bind(pos, RefAnyCast<Int16>(val), dir); + bind(pos, RefAnyCast<Int16>(val), dir, nullCb); else if(type == typeid(UInt16)) - bind(pos, RefAnyCast<UInt16>(val), dir); + bind(pos, RefAnyCast<UInt16>(val), dir, nullCb); else if(type == typeid(UInt32)) - bind(pos, RefAnyCast<UInt32>(val), dir); + bind(pos, RefAnyCast<UInt32>(val), dir, nullCb); else if(type == typeid(Int64)) - bind(pos, RefAnyCast<Int64>(val), dir); + bind(pos, RefAnyCast<Int64>(val), dir, nullCb); else if(type == typeid(UInt64)) - bind(pos, RefAnyCast<UInt64>(val), dir); + bind(pos, RefAnyCast<UInt64>(val), dir, nullCb); else if(type == typeid(float)) - bind(pos, RefAnyCast<float>(val), dir); + bind(pos, RefAnyCast<float>(val), dir, nullCb); else if(type == typeid(double)) - bind(pos, RefAnyCast<double>(val), dir); + bind(pos, RefAnyCast<double>(val), dir, nullCb); else if(type == typeid(DateTime)) - bind(pos, RefAnyCast<DateTime>(val), dir); + bind(pos, RefAnyCast<DateTime>(val), dir, nullCb); else if(type == typeid(Date)) - bind(pos, RefAnyCast<Date>(val), dir); + bind(pos, RefAnyCast<Date>(val), dir, nullCb); else if(type == typeid(Time)) - bind(pos, RefAnyCast<Time>(val), dir); + bind(pos, RefAnyCast<Time>(val), dir, nullCb); else if(type == typeid(BLOB)) - bind(pos, RefAnyCast<BLOB>(val), dir); + bind(pos, RefAnyCast<BLOB>(val), dir, nullCb); else if(type == typeid(void)) - bind(pos, Keywords::null, dir); + bind(pos, NULL_GENERIC, dir, type); #ifndef POCO_LONG_IS_64_BIT else if(type == typeid(long)) - bind(pos, RefAnyCast<long>(val), dir); + bind(pos, RefAnyCast<long>(val), dir, nullCb); #endif else throw UnknownTypeException(std::string(val.type().name())); } -void AbstractBinder::bind(std::size_t pos, const Poco::Dynamic::Var& val, Direction dir) +void AbstractBinder::bind(std::size_t pos, const Poco::Dynamic::Var& val, Direction dir, const WhenNullCb& nullCb) { const std::type_info& type = val.type(); if(type == typeid(Int32)) - bind(pos, val.extract<Int32>(), dir); + bind(pos, val.extract<Int32>(), dir, nullCb); else if(type == typeid(std::string)) - bind(pos, val.extract<std::string>(), dir); + bind(pos, val.extract<std::string>(), dir, nullCb); else if (type == typeid(Poco::UTF16String)) - bind(pos, val.extract<Poco::UTF16String>(), dir); + bind(pos, val.extract<Poco::UTF16String>(), dir, nullCb); else if (type == typeid(bool)) - bind(pos, val.extract<bool>(), dir); + bind(pos, val.extract<bool>(), dir, nullCb); else if(type == typeid(char)) - bind(pos, val.extract<char>(), dir); + bind(pos, val.extract<char>(), dir, nullCb); else if(type == typeid(Int8)) - bind(pos, val.extract<Int8>(), dir); + bind(pos, val.extract<Int8>(), dir, nullCb); else if(type == typeid(UInt8)) - bind(pos, val.extract<UInt8>(), dir); + bind(pos, val.extract<UInt8>(), dir, nullCb); else if(type == typeid(Int16)) - bind(pos, val.extract<Int16>(), dir); + bind(pos, val.extract<Int16>(), dir, nullCb); else if(type == typeid(UInt16)) - bind(pos, val.extract<UInt16>(), dir); + bind(pos, val.extract<UInt16>(), dir, nullCb); else if(type == typeid(UInt32)) - bind(pos, val.extract<UInt32>(), dir); + bind(pos, val.extract<UInt32>(), dir, nullCb); else if(type == typeid(Int64)) - bind(pos, val.extract<Int64>(), dir); + bind(pos, val.extract<Int64>(), dir, nullCb); else if(type == typeid(UInt64)) - bind(pos, val.extract<UInt64>(), dir); + bind(pos, val.extract<UInt64>(), dir, nullCb); else if(type == typeid(float)) - bind(pos, val.extract<float>(), dir); + bind(pos, val.extract<float>(), dir, nullCb); else if(type == typeid(double)) - bind(pos, val.extract<double>(), dir); + bind(pos, val.extract<double>(), dir, nullCb); else if(type == typeid(DateTime)) - bind(pos, val.extract<DateTime>(), dir); + bind(pos, val.extract<DateTime>(), dir, nullCb); else if(type == typeid(Date)) - bind(pos, val.extract<Date>(), dir); + bind(pos, val.extract<Date>(), dir, nullCb); else if(type == typeid(Time)) - bind(pos, val.extract<Time>(), dir); + bind(pos, val.extract<Time>(), dir, nullCb); else if(type == typeid(BLOB)) - bind(pos, val.extract<BLOB>(), dir); + bind(pos, val.extract<BLOB>(), dir, nullCb); else if(type == typeid(void)) - bind(pos, Keywords::null, dir); + bind(pos, NULL_GENERIC, dir, type); + else if (type == typeid(NullData)) + bind(pos, val.extract<NullData>(), dir, type); + else if (type == typeid(NullType)) + bind(pos, static_cast<NullData>(val.extract<NullType>()), dir, type); #ifndef POCO_LONG_IS_64_BIT else if(type == typeid(long)) - bind(pos, val.extract<long>(), dir); + bind(pos, val.extract<long>(), dir, nullCb); #endif else throw UnknownTypeException(std::string(val.type().name())); diff --git a/Data/src/RecordSet.cpp b/Data/src/RecordSet.cpp index 654cbd621..03843fd30 100644 --- a/Data/src/RecordSet.cpp +++ b/Data/src/RecordSet.cpp @@ -200,8 +200,10 @@ Row& RecordSet::row(std::size_t pos) std::size_t RecordSet::rowCount() const { + if (0 == extractions().size() && 0 == columnsExtracted()) + return 0; poco_assert (extractions().size()); - std::size_t rc = subTotalRowCount(); + std::size_t rc = storageRowCount(); if (!isFiltered()) return rc; std::size_t counter = 0; @@ -223,7 +225,8 @@ bool RecordSet::isAllowed(std::size_t dataRow) const bool RecordSet::moveFirst() { - if (subTotalRowCount() > 0) + const size_t rc = storageRowCount(); + if (rc > 0) { if (!isFiltered()) { @@ -235,7 +238,7 @@ bool RecordSet::moveFirst() currentRow = 0; while (!isAllowed(currentRow)) { - if (currentRow >= subTotalRowCount() - 1) return false; + if (currentRow >= rc - 1) return false; ++currentRow; } @@ -251,7 +254,7 @@ bool RecordSet::moveNext() std::size_t currentRow = _currentRow; do { - if (currentRow >= subTotalRowCount() - 1) return false; + if (currentRow >= storageRowCount() -1) return false; ++currentRow; } while (isFiltered() && !isAllowed(currentRow)); @@ -276,10 +279,10 @@ bool RecordSet::movePrevious() bool RecordSet::moveLast() { - if (subTotalRowCount() > 0) + if (storageRowCount() > 0) { std::size_t currentRow = _currentRow; - currentRow = subTotalRowCount() - 1; + currentRow = storageRowCount() - 1; if (!isFiltered()) { _currentRow = currentRow; diff --git a/Data/src/Row.cpp b/Data/src/Row.cpp index 7006a171c..6d32fa2d8 100644 --- a/Data/src/Row.cpp +++ b/Data/src/Row.cpp @@ -94,7 +94,20 @@ Poco::Dynamic::Var& Row::get(std::size_t col) } -std::size_t Row::getPosition(const std::string& name) +const Poco::Dynamic::Var& Row::get(std::size_t col) const +{ + try + { + return _values.at(col); + } + catch (std::out_of_range& re) + { + throw RangeException(re.what()); + } +} + + +std::size_t Row::getPosition(const std::string& name) const { if (!_pNames) throw NullPointerException(); diff --git a/Data/src/RowIterator.cpp b/Data/src/RowIterator.cpp index e8629665f..521f37b83 100644 --- a/Data/src/RowIterator.cpp +++ b/Data/src/RowIterator.cpp @@ -69,7 +69,7 @@ void RowIterator::increment() const if (POSITION_END == _position) throw RangeException("End of iterator reached."); - if (_position < _pRecordSet->subTotalRowCount() - 1) + if (_position < _pRecordSet->storageRowCount() - 1) ++_position; else _position = POSITION_END; @@ -90,7 +90,7 @@ void RowIterator::decrement() const if (0 == _position) throw RangeException("Beginning of iterator reached."); else if (POSITION_END == _position) - _position = _pRecordSet->subTotalRowCount() - 1; + _position = _pRecordSet->storageRowCount() - 1; else --_position; @@ -126,15 +126,15 @@ void RowIterator::setPosition(std::size_t pos) const std::size_t end = pos - _position; for (; start < end; ++start) { - if (_pRecordSet->subTotalRowCount() != pos) ++pos; + if (_pRecordSet->storageRowCount() != pos) ++pos; else throw RangeException("Invalid position argument."); } } } - if (pos < _pRecordSet->subTotalRowCount()) + if (pos < _pRecordSet->storageRowCount()) _position = pos; - else if (pos == _pRecordSet->subTotalRowCount()) + else if (pos == _pRecordSet->storageRowCount()) _position = POSITION_END; else throw RangeException("Invalid position argument."); diff --git a/Data/src/StatementImpl.cpp b/Data/src/StatementImpl.cpp index 81a55f344..502887d77 100644 --- a/Data/src/StatementImpl.cpp +++ b/Data/src/StatementImpl.cpp @@ -52,6 +52,7 @@ StatementImpl::StatementImpl(SessionImpl& rSession): _storage(STORAGE_UNKNOWN_IMPL), _ostr(), _curDataSet(0), + _pendingDSNo(0), _bulkBinding(BULK_UNDEFINED), _bulkExtraction(BULK_UNDEFINED) { @@ -83,6 +84,10 @@ std::size_t StatementImpl::execute(const bool& rReset) if (_lowerLimit > _extrLimit.value()) throw LimitException("Illegal Statement state. Upper limit must not be smaller than the lower limit."); + size_t pds = _pendingDSNo; + while (pds > currentDataSet()) activateNextDataSet(); + + const size_t savedDs = currentDataSet(); do { compile(); @@ -92,25 +97,30 @@ std::size_t StatementImpl::execute(const bool& rReset) lim += executeWithLimit(); } while (canCompile()); + // rewind ds back here!!!! + pds = currentDataSet(); + while (savedDs < currentDataSet()) activatePreviousDataSet(); + _pendingDSNo = pds; + if (_extrLimit.value() == Limit::LIMIT_UNLIMITED) _state = ST_DONE; + assignSubTotal(rReset, savedDs); + if (lim < _lowerLimit) throw LimitException("Did not receive enough data."); - assignSubTotal(rReset); - return lim; } -void StatementImpl::assignSubTotal(bool doReset) +void StatementImpl::assignSubTotal(bool doReset, size_t firstDs) { if (_extractors.size() == _subTotalRowCount.size()) { - CountVec::iterator it = _subTotalRowCount.begin(); + CountVec::iterator it = _subTotalRowCount.begin() + firstDs; CountVec::iterator end = _subTotalRowCount.end(); - for (int counter = 0; it != end; ++it, ++counter) + for (size_t counter = firstDs; it != end; ++it, ++counter) { if (_extractors[counter].size()) { @@ -137,9 +147,9 @@ std::size_t StatementImpl::executeWithLimit() count += next(); } while (count < limit && canBind()); - if (!canBind() && (!hasNext() || limit == 0)) + if (!canBind() && (!hasNext() || limit == 0)) _state = ST_DONE; - else if (hasNext() && limit == count && _extrLimit.isHardLimit()) + else if (limit == count && _extrLimit.isHardLimit() && hasNext()) throw LimitException("HardLimit reached (retrieved more data than requested)."); else _state = ST_PAUSED; @@ -246,10 +256,6 @@ void StatementImpl::setBulkExtraction(const Bulk& b) void StatementImpl::fixupExtraction() { - CountVec::iterator sIt = _subTotalRowCount.begin(); - CountVec::iterator sEnd = _subTotalRowCount.end(); - for (; sIt != sEnd; ++sIt) *sIt = 0; - if (_curDataSet >= _columnsExtracted.size()) { _columnsExtracted.resize(_curDataSet + 1, 0); @@ -311,46 +317,54 @@ void StatementImpl::setStorage(const std::string& storage) void StatementImpl::makeExtractors(std::size_t count) +{ + // type cast is needed when size_t is 64 bit + makeExtractors(count, static_cast<Position::PositionType>(currentDataSet())); +} + +void StatementImpl::makeExtractors(std::size_t count, const Position& position) { for (int i = 0; i < count; ++i) { - const MetaColumn& mc = metaColumn(i); + const MetaColumn& mc = metaColumn(i, position.value()); switch (mc.type()) { case MetaColumn::FDT_BOOL: - addInternalExtract<bool>(mc); break; + addInternalExtract<bool>(mc, position.value()); break; case MetaColumn::FDT_INT8: - addInternalExtract<Int8>(mc); break; + addInternalExtract<Int8>(mc, position.value()); break; case MetaColumn::FDT_UINT8: - addInternalExtract<UInt8>(mc); break; + addInternalExtract<UInt8>(mc, position.value()); break; case MetaColumn::FDT_INT16: - addInternalExtract<Int16>(mc); break; + addInternalExtract<Int16>(mc, position.value()); break; case MetaColumn::FDT_UINT16: - addInternalExtract<UInt16>(mc); break; + addInternalExtract<UInt16>(mc, position.value()); break; case MetaColumn::FDT_INT32: - addInternalExtract<Int32>(mc); break; + addInternalExtract<Int32>(mc, position.value()); break; case MetaColumn::FDT_UINT32: - addInternalExtract<UInt32>(mc); break; + addInternalExtract<UInt32>(mc, position.value()); break; case MetaColumn::FDT_INT64: - addInternalExtract<Int64>(mc); break; + addInternalExtract<Int64>(mc, position.value()); break; case MetaColumn::FDT_UINT64: - addInternalExtract<UInt64>(mc); break; + addInternalExtract<UInt64>(mc, position.value()); break; case MetaColumn::FDT_FLOAT: - addInternalExtract<float>(mc); break; + addInternalExtract<float>(mc, position.value()); break; case MetaColumn::FDT_DOUBLE: - addInternalExtract<double>(mc); break; + addInternalExtract<double>(mc, position.value()); break; case MetaColumn::FDT_STRING: - addInternalExtract<std::string>(mc); break; + addInternalExtract<std::string>(mc, position.value()); break; case MetaColumn::FDT_WSTRING: - addInternalExtract<Poco::UTF16String>(mc); break; - case MetaColumn::FDT_BLOB: - addInternalExtract<BLOB>(mc); break; + addInternalExtract<Poco::UTF16String>(mc, position.value()); break; + case MetaColumn::FDT_BLOB: + addInternalExtract<BLOB>(mc, position.value()); break; + case MetaColumn::FDT_CLOB: + addInternalExtract<CLOB>(mc, position.value()); break; case MetaColumn::FDT_DATE: - addInternalExtract<Date>(mc); break; + addInternalExtract<Date>(mc, position.value()); break; case MetaColumn::FDT_TIME: - addInternalExtract<Time>(mc); break; + addInternalExtract<Time>(mc, position.value()); break; case MetaColumn::FDT_TIMESTAMP: - addInternalExtract<DateTime>(mc); break; + addInternalExtract<DateTime>(mc, position.value()); break; default: throw Poco::InvalidArgumentException("Data type not supported."); } @@ -363,7 +377,7 @@ const MetaColumn& StatementImpl::metaColumn(const std::string& name) const std::size_t cols = columnsReturned(); for (std::size_t i = 0; i < cols; ++i) { - const MetaColumn& column = metaColumn(i); + const MetaColumn& column = metaColumn(i, currentDataSet()); if (0 == icompare(column.name(), name)) return column; } @@ -374,7 +388,10 @@ const MetaColumn& StatementImpl::metaColumn(const std::string& name) const std::size_t StatementImpl::activateNextDataSet() { if (_curDataSet + 1 < dataSetCount()) - return ++_curDataSet; + { + _pendingDSNo = ++_curDataSet; + return _curDataSet; + } else throw NoDataException("End of data sets reached."); } @@ -383,7 +400,10 @@ std::size_t StatementImpl::activateNextDataSet() std::size_t StatementImpl::activatePreviousDataSet() { if (_curDataSet > 0) - return --_curDataSet; + { + _pendingDSNo = --_curDataSet; + return _curDataSet; + } else throw NoDataException("Beginning of data sets reached."); } @@ -475,4 +495,8 @@ void StatementImpl::formatSQL(std::vector<Any>& arguments) } +void StatementImpl::insertHint() +{ +} + } } // namespace Poco::Data diff --git a/Data/testsuite/TestSuite_vs120.vcxproj b/Data/testsuite/TestSuite_vs120.vcxproj index 2f2a5411d..c1085cfee 100644 --- a/Data/testsuite/TestSuite_vs120.vcxproj +++ b/Data/testsuite/TestSuite_vs120.vcxproj @@ -129,7 +129,7 @@ <AdditionalIncludeDirectories>..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -140,6 +140,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitd.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -171,6 +172,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnit.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -189,7 +191,7 @@ <AdditionalIncludeDirectories>..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -200,6 +202,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmtd.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -231,6 +234,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmt.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -249,7 +253,7 @@ <AdditionalIncludeDirectories>..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -260,6 +264,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmdd.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -291,6 +296,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmd.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies> diff --git a/Data/testsuite/src/Binder.cpp b/Data/testsuite/src/Binder.cpp index fbac5ccfc..a83449d36 100644 --- a/Data/testsuite/src/Binder.cpp +++ b/Data/testsuite/src/Binder.cpp @@ -30,119 +30,119 @@ Binder::~Binder() } -void Binder::bind(std::size_t pos, const Poco::Int8 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int8 &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Poco::UInt8 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UInt8 &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Poco::Int16 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int16 &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Poco::UInt16 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UInt16 &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Poco::Int32 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int32 &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Poco::UInt32 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UInt32 &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Poco::Int64 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::Int64 &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Poco::UInt64 &val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UInt64 &val, Direction dir, const WhenNullCb& nullCb) { } #ifndef POCO_LONG_IS_64_BIT -void Binder::bind(std::size_t pos, const long& val, Direction dir) +void Binder::bind(std::size_t pos, const long& val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const unsigned long& val, Direction dir) +void Binder::bind(std::size_t pos, const unsigned long& val, Direction dir, const WhenNullCb& nullCb) { } #endif -void Binder::bind(std::size_t pos, const bool &val, Direction dir) +void Binder::bind(std::size_t pos, const bool &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const float &val, Direction dir) +void Binder::bind(std::size_t pos, const float &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const double &val, Direction dir) +void Binder::bind(std::size_t pos, const double &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const char &val, Direction dir) +void Binder::bind(std::size_t pos, const char &val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir) +void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const std::string& val, Direction dir) +void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Poco::UTF16String& val, Direction dir) +void Binder::bind(std::size_t pos, const Poco::UTF16String& val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const BLOB& val, Direction dir) +void Binder::bind(std::size_t pos, const BLOB& val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const CLOB& val, Direction dir) +void Binder::bind(std::size_t pos, const CLOB& val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Date& val, Direction dir) +void Binder::bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const Time& val, Direction dir) +void Binder::bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const DateTime& val, Direction dir) +void Binder::bind(std::size_t pos, const DateTime& val, Direction dir, const WhenNullCb& nullCb) { } -void Binder::bind(std::size_t pos, const NullData& val, Direction dir) +void Binder::bind(std::size_t pos, const NullData& val, Direction dir, const std::type_info& bindType) { } diff --git a/Data/testsuite/src/Binder.h b/Data/testsuite/src/Binder.h index 318efe68a..8790dd57c 100644 --- a/Data/testsuite/src/Binder.h +++ b/Data/testsuite/src/Binder.h @@ -34,75 +34,75 @@ public: ~Binder(); /// Destroys the Binder. - void bind(std::size_t pos, const Poco::Int8 &val, Direction dir); + void bind(std::size_t pos, const Poco::Int8 &val, Direction dir, const WhenNullCb& cb); /// Binds an Int8. - void bind(std::size_t pos, const Poco::UInt8 &val, Direction dir); + void bind(std::size_t pos, const Poco::UInt8 &val, Direction dir, const WhenNullCb& cb); /// Binds an UInt8. - void bind(std::size_t pos, const Poco::Int16 &val, Direction dir); + void bind(std::size_t pos, const Poco::Int16 &val, Direction dir, const WhenNullCb& cb); /// Binds an Int16. - void bind(std::size_t pos, const Poco::UInt16 &val, Direction dir); + void bind(std::size_t pos, const Poco::UInt16 &val, Direction dir, const WhenNullCb& cb); /// Binds an UInt16. - void bind(std::size_t pos, const Poco::Int32 &val, Direction dir); + void bind(std::size_t pos, const Poco::Int32 &val, Direction dir, const WhenNullCb& cb); /// Binds an Int32. - void bind(std::size_t pos, const Poco::UInt32 &val, Direction dir); + void bind(std::size_t pos, const Poco::UInt32 &val, Direction dir, const WhenNullCb& cb); /// Binds an UInt32. - void bind(std::size_t pos, const Poco::Int64 &val, Direction dir); + void bind(std::size_t pos, const Poco::Int64 &val, Direction dir, const WhenNullCb& cb); /// Binds an Int64. - void bind(std::size_t pos, const Poco::UInt64 &val, Direction dir); + void bind(std::size_t pos, const Poco::UInt64 &val, Direction dir, const WhenNullCb& cb); /// Binds an UInt64. #ifndef POCO_LONG_IS_64_BIT - void bind(std::size_t pos, const long& val, Direction dir); + void bind(std::size_t pos, const long& val, Direction dir, const WhenNullCb& cb); /// Binds a long. - void bind(std::size_t pos, const unsigned long& val, Direction dir); + void bind(std::size_t pos, const unsigned long& val, Direction dir, const WhenNullCb& cb); /// Binds an unsigned long. #endif - void bind(std::size_t pos, const bool &val, Direction dir); + void bind(std::size_t pos, const bool &val, Direction dir, const WhenNullCb& cb); /// Binds a boolean. - void bind(std::size_t pos, const float &val, Direction dir); + void bind(std::size_t pos, const float &val, Direction dir, const WhenNullCb& cb); /// Binds a float. - void bind(std::size_t pos, const double &val, Direction dir); + void bind(std::size_t pos, const double &val, Direction dir, const WhenNullCb& cb); /// Binds a double. - void bind(std::size_t pos, const char &val, Direction dir); + void bind(std::size_t pos, const char &val, Direction dir, const WhenNullCb& cb); /// Binds a single character. - void bind(std::size_t pos, const char* const &pVal, Direction dir); + void bind(std::size_t pos, const char* const &pVal, Direction dir, const WhenNullCb& cb); /// Binds a const char ptr. - void bind(std::size_t pos, const std::string& val, Direction dir); + void bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& cb); /// Binds a string. - void bind(std::size_t pos, const Poco::UTF16String& val, Direction dir); + void bind(std::size_t pos, const Poco::UTF16String& val, Direction dir, const WhenNullCb& cb); /// Binds a UTF16String. - void bind(std::size_t pos, const BLOB& val, Direction dir); + void bind(std::size_t pos, const BLOB& val, Direction dir, const WhenNullCb& cb); /// Binds a BLOB. - void bind(std::size_t pos, const CLOB& val, Direction dir); + void bind(std::size_t pos, const CLOB& val, Direction dir, const WhenNullCb& cb); /// Binds a CLOB. - void bind(std::size_t pos, const Date& val, Direction dir); + void bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& cb); /// Binds a Date. - void bind(std::size_t pos, const Time& val, Direction dir); + void bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& cb); /// Binds a Time. - void bind(std::size_t pos, const DateTime& val, Direction dir); + void bind(std::size_t pos, const DateTime& val, Direction dir, const WhenNullCb& cb); /// Binds a DateTime. - void bind(std::size_t pos, const NullData& val, Direction dir); + void bind(std::size_t pos, const NullData& val, Direction dir, const std::type_info& bindType); /// Binds a DateTime. void reset(); diff --git a/Data/testsuite/src/DataTest.cpp b/Data/testsuite/src/DataTest.cpp index bec8145fc..37c2fb9bd 100644 --- a/Data/testsuite/src/DataTest.cpp +++ b/Data/testsuite/src/DataTest.cpp @@ -904,6 +904,11 @@ void DataTest::testRow() assert (row[3] == 3); assert (row[4] == 4); + const Row& cr = row; + assert(cr["field0"] == 0); + assert(cr[0] == 0); + assert(cr.get(0) == 0); + try { int i; i = row[5].convert<int>(); // to silence gcc diff --git a/Data/testsuite/src/TestStatementImpl.cpp b/Data/testsuite/src/TestStatementImpl.cpp index 425f1fae1..957a24dba 100644 --- a/Data/testsuite/src/TestStatementImpl.cpp +++ b/Data/testsuite/src/TestStatementImpl.cpp @@ -72,7 +72,7 @@ std::size_t TestStatementImpl::columnsReturned() const } -const MetaColumn& TestStatementImpl::metaColumn(std::size_t pos) const +const MetaColumn& TestStatementImpl::metaColumn(std::size_t pos, std::size_t /*rsPos*/) const { static MetaColumn c(pos, "", MetaColumn::FDT_BOOL, 0); return c; diff --git a/Data/testsuite/src/TestStatementImpl.h b/Data/testsuite/src/TestStatementImpl.h index ae60bcbb3..c480bef32 100644 --- a/Data/testsuite/src/TestStatementImpl.h +++ b/Data/testsuite/src/TestStatementImpl.h @@ -50,7 +50,7 @@ protected: /// Returns the number of affected rows. /// Used to find out the number of rows affected by insert or update. - const MetaColumn& metaColumn(std::size_t pos) const; + const MetaColumn& metaColumn(std::size_t pos, std::size_t rsPos) const; /// Returns column meta data. bool hasNext(); diff --git a/Foundation/Foundation_vs120.vcxproj b/Foundation/Foundation_vs120.vcxproj index 8f13daf65..f5d08dba0 100644 --- a/Foundation/Foundation_vs120.vcxproj +++ b/Foundation/Foundation_vs120.vcxproj @@ -125,7 +125,7 @@ <AdditionalIncludeDirectories>.\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;Foundation_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -136,6 +136,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -215,6 +216,7 @@ <AdditionalIncludeDirectories>.\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> + <MinimalRebuild>false</MinimalRebuild> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> @@ -224,6 +226,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib\PocoFoundationmt.lib</OutputFile> @@ -235,7 +238,7 @@ <AdditionalIncludeDirectories>.\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -247,6 +250,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib\PocoFoundationmdd.lib</OutputFile> diff --git a/Foundation/Foundation_x64_vs120.vcxproj b/Foundation/Foundation_x64_vs120.vcxproj index 82d720763..f2f9b953e 100644 --- a/Foundation/Foundation_x64_vs120.vcxproj +++ b/Foundation/Foundation_x64_vs120.vcxproj @@ -125,7 +125,7 @@ <AdditionalIncludeDirectories>.\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;Foundation_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -136,6 +136,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -168,6 +169,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -200,6 +202,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib64\PocoFoundationmtd.lib</OutputFile> @@ -217,6 +220,7 @@ <StringPooling>true</StringPooling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> + <MinimalRebuild>false</MinimalRebuild> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> <RuntimeTypeInfo>true</RuntimeTypeInfo> @@ -224,6 +228,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib64\PocoFoundationmt.lib</OutputFile> @@ -235,7 +240,7 @@ <AdditionalIncludeDirectories>.\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -247,6 +252,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib64\PocoFoundationmdd.lib</OutputFile> @@ -271,6 +277,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Lib> <OutputFile>..\lib64\PocoFoundationmd.lib</OutputFile> diff --git a/Foundation/testsuite/TestSuite_vs120.vcxproj b/Foundation/testsuite/TestSuite_vs120.vcxproj index 5f8dcdc2c..c975ea8c3 100644 --- a/Foundation/testsuite/TestSuite_vs120.vcxproj +++ b/Foundation/testsuite/TestSuite_vs120.vcxproj @@ -129,7 +129,7 @@ <AdditionalIncludeDirectories>..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -140,6 +140,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitd.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -249,7 +250,7 @@ <AdditionalIncludeDirectories>..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -260,6 +261,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmdd.lib;iphlpapi.lib;winmm.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -291,6 +293,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat /> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmd.lib;iphlpapi.lib;winmm.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -589,4 +592,4 @@ </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets" /> -</Project> \ No newline at end of file +</Project> diff --git a/Foundation/testsuite/TestSuite_x64_vs120.vcxproj b/Foundation/testsuite/TestSuite_x64_vs120.vcxproj index 7b1596b0d..efafcc8ed 100644 --- a/Foundation/testsuite/TestSuite_x64_vs120.vcxproj +++ b/Foundation/testsuite/TestSuite_x64_vs120.vcxproj @@ -129,7 +129,7 @@ <AdditionalIncludeDirectories>..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -140,6 +140,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitd.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -171,6 +172,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnit.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -231,6 +233,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmt.lib;iphlpapi.lib;winmm.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -249,7 +252,7 @@ <AdditionalIncludeDirectories>..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> - <MinimalRebuild>true</MinimalRebuild> + <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>true</BufferSecurityCheck> @@ -260,6 +263,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmdd.lib;iphlpapi.lib;winmm.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -291,6 +295,7 @@ <WarningLevel>Level3</WarningLevel> <DebugInformationFormat/> <CompileAs>Default</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <AdditionalDependencies>CppUnitmd.lib;iphlpapi.lib;winmm.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> diff --git a/buildwin.ps1 b/buildwin.ps1 index b9e11452e..0140ba97f 100644 --- a/buildwin.ps1 +++ b/buildwin.ps1 @@ -195,8 +195,8 @@ function Process-Input } # NB: this won't work in PowerShell ISE - Write-Host "Press Ctrl-C to exit or any other key to continue ..." - $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") + # Write-Host "Press Ctrl-C to exit or any other key to continue ..." + # $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") } }