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

Int128 - new datatype (#220)

* Int128 support - work in progress

* Work in progress

* Int128 datatype appears to be mostly OK except sort & index

* Fixed divide scaling, added sorting & network (xdr) support

* Binding control, aggregate nodes, cleanup and documentation

* Fixed VS2017 AppVeyor build

* Next attempt to fix vs2017 build

* Next attempt to fix vs2017 build

* Next attempt to fix vs2017 build

* Update MSVC build.

* Set VS architecture correctly

* Fixed a number of issues noticed by Mark
This commit is contained in:
Alexander Peshkov 2019-09-16 20:59:54 +03:00 committed by GitHub
parent b265743642
commit 861d536fc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
89 changed files with 17082 additions and 826 deletions

View File

@ -27,9 +27,11 @@ install:
- cmd: for /r %%i in (*.bat) do unix2dos "%%i"
- cmd: if "%PLATFORM%" == "x64" set FB_PROCESSOR_ARCHITECTURE=AMD64
- cmd: if "%PLATFORM%" == "x64" set FB_OUTPUT_SUFFIX=x64
- cmd: if "%PLATFORM%" == "x64" set FB_VS_ARCH=amd64
- cmd: if "%PLATFORM%" == "x86" set FB_PROCESSOR_ARCHITECTURE=x86
- cmd: if "%PLATFORM%" == "x86" set FB_OUTPUT_SUFFIX=win32
- cmd: if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
- cmd: if "%PLATFORM%" == "x86" set FB_VS_ARCH=x86
- cmd: if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=%FB_VS_ARCH%
- cmd: cd builds\win32
- cmd: run_all.bat JUSTBUILD
- cmd: set ARTIFACTS_PATH=output_%FB_OUTPUT_SUFFIX%

View File

@ -41,6 +41,9 @@ if "%ERRLEV%"=="1" goto :END
call :decNumber
if "%ERRLEV%"=="1" goto :END
if "%FB_TARGET_PLATFORM%"=="x64" call :ttmath
if "%ERRLEV%"=="1" goto :END
call :re2
if "%ERRLEV%"=="1" goto :END
@ -162,6 +165,23 @@ if errorlevel 1 call :boot2 decNumber_%FB_OBJ_DIR%
@call set_build_target.bat %*
goto :EOF
::===================
:: BUILD ttmath
:ttmath
@echo.
@call set_build_target.bat %* RELEASE
@echo Building ttmath (%FB_OBJ_DIR%)...
@mkdir %FB_TEMP_DIR%\..\%FB_OBJ_DIR%\common 2>nul
@ml64.exe /c /Fo %FB_TEMP_DIR%\..\%FB_OBJ_DIR%\common\ttmathuint_x86_64_msvc.obj %FB_ROOT_PATH%\extern\ttmath\ttmathuint_x86_64_msvc.asm
if errorlevel 1 call :boot2 ttmath_%FB_OBJ_DIR%
@call set_build_target.bat %* DEBUG
@echo Building decNumber (%FB_OBJ_DIR%)...
@mkdir %FB_TEMP_DIR%\..\%FB_OBJ_DIR%\common 2>nul
@ml64.exe /c /Zi /Fo %FB_TEMP_DIR%\..\%FB_OBJ_DIR%\common\ttmathuint_x86_64_msvc.obj %FB_ROOT_PATH%\extern\ttmath\ttmathuint_x86_64_msvc.asm
if errorlevel 1 call :boot2 ttmath_%FB_OBJ_DIR%
@call set_build_target.bat %*
goto :EOF
::===================
:: BUILD re2
:re2

View File

@ -72,6 +72,7 @@
<ClCompile Include="..\..\..\src\common\DynamicStrings.cpp" />
<ClCompile Include="..\..\..\src\common\enc.cpp" />
<ClCompile Include="..\..\..\src\common\fb_exception.cpp" />
<ClCompile Include="..\..\..\src\common\Int128.cpp" />
<ClCompile Include="..\..\..\src\common\IntlParametersBlock.cpp" />
<ClCompile Include="..\..\..\src\common\IntlUtil.cpp" />
<ClCompile Include="..\..\..\src\common\isc.cpp" />
@ -180,6 +181,7 @@
<ClInclude Include="..\..\..\src\common\enc_proto.h" />
<ClInclude Include="..\..\..\src\common\file_params.h" />
<ClInclude Include="..\..\..\src\common\gdsassert.h" />
<ClInclude Include="..\..\..\src\common\Int128.h" />
<ClInclude Include="..\..\..\src\common\intlobj_new.h" />
<ClInclude Include="..\..\..\src\common\IntlParametersBlock.h" />
<ClInclude Include="..\..\..\src\common\IntlUtil.h" />
@ -335,7 +337,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Lib>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;$(TargetDir)\ttmathuint_x86_64_msvc.obj;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -353,7 +355,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Lib>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;$(TargetDir)\ttmathuint_x86_64_msvc.obj;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -240,6 +240,9 @@
<ClCompile Include="..\..\..\src\common\keywords.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\Int128.cpp">
<Filter>common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\common\xdr_proto.h">
@ -581,5 +584,8 @@
<ClInclude Include="..\..\..\src\common\keywords.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\common\Int128.h">
<Filter>headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -68,6 +68,7 @@
<ClCompile Include="..\..\..\src\common\DynamicStrings.cpp" />
<ClCompile Include="..\..\..\src\common\enc.cpp" />
<ClCompile Include="..\..\..\src\common\fb_exception.cpp" />
<ClCompile Include="..\..\..\src\common\Int128.cpp" />
<ClCompile Include="..\..\..\src\common\IntlParametersBlock.cpp" />
<ClCompile Include="..\..\..\src\common\IntlUtil.cpp" />
<ClCompile Include="..\..\..\src\common\isc.cpp" />
@ -176,6 +177,7 @@
<ClInclude Include="..\..\..\src\common\enc_proto.h" />
<ClInclude Include="..\..\..\src\common\file_params.h" />
<ClInclude Include="..\..\..\src\common\gdsassert.h" />
<ClInclude Include="..\..\..\src\common\Int128.h" />
<ClInclude Include="..\..\..\src\common\intlobj_new.h" />
<ClInclude Include="..\..\..\src\common\IntlParametersBlock.h" />
<ClInclude Include="..\..\..\src\common\IntlUtil.h" />
@ -335,7 +337,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Lib>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;$(TargetDir)\ttmathuint_x86_64_msvc.obj;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -353,7 +355,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Lib>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;$(TargetDir)\ttmathuint_x86_64_msvc.obj;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -240,6 +240,9 @@
<ClCompile Include="..\..\..\src\common\keywords.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\Int128.cpp">
<Filter>common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\common\xdr_proto.h">
@ -581,5 +584,8 @@
<ClInclude Include="..\..\..\src\common\classes\ParsedList.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\common\Int128.h">
<Filter>headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -68,6 +68,7 @@
<ClCompile Include="..\..\..\src\common\DynamicStrings.cpp" />
<ClCompile Include="..\..\..\src\common\enc.cpp" />
<ClCompile Include="..\..\..\src\common\fb_exception.cpp" />
<ClCompile Include="..\..\..\src\common\Int128.cpp" />
<ClCompile Include="..\..\..\src\common\IntlParametersBlock.cpp" />
<ClCompile Include="..\..\..\src\common\IntlUtil.cpp" />
<ClCompile Include="..\..\..\src\common\isc.cpp" />
@ -177,6 +178,7 @@
<ClInclude Include="..\..\..\src\common\enc_proto.h" />
<ClInclude Include="..\..\..\src\common\file_params.h" />
<ClInclude Include="..\..\..\src\common\gdsassert.h" />
<ClInclude Include="..\..\..\src\common\Int128.h" />
<ClInclude Include="..\..\..\src\common\intlobj_new.h" />
<ClInclude Include="..\..\..\src\common\IntlParametersBlock.h" />
<ClInclude Include="..\..\..\src\common\IntlUtil.h" />
@ -337,7 +339,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Lib>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;../../../extern/re2/builds/$(PlatformName)\$(Configuration)\re2.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;../../../extern/re2/builds/$(PlatformName)\$(Configuration)\re2.lib;$(TargetDir)\ttmathuint_x86_64_msvc.obj;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -355,7 +357,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Lib>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;../../../extern/re2/builds/$(PlatformName)\$(Configuration)\re2.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;../../../extern/re2/builds/$(PlatformName)\$(Configuration)\re2.lib;$(TargetDir)\ttmathuint_x86_64_msvc.obj;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -243,6 +243,9 @@
<ClCompile Include="..\..\..\src\common\keywords.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\Int128.cpp">
<Filter>common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\common\xdr_proto.h">
@ -587,5 +590,8 @@
<ClInclude Include="..\..\..\src\common\keywords.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\common\Int128.h">
<Filter>headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -68,6 +68,7 @@
<ClCompile Include="..\..\..\src\common\DynamicStrings.cpp" />
<ClCompile Include="..\..\..\src\common\enc.cpp" />
<ClCompile Include="..\..\..\src\common\fb_exception.cpp" />
<ClCompile Include="..\..\..\src\common\Int128.cpp" />
<ClCompile Include="..\..\..\src\common\IntlParametersBlock.cpp" />
<ClCompile Include="..\..\..\src\common\IntlUtil.cpp" />
<ClCompile Include="..\..\..\src\common\isc.cpp" />
@ -177,6 +178,7 @@
<ClInclude Include="..\..\..\src\common\enc_proto.h" />
<ClInclude Include="..\..\..\src\common\file_params.h" />
<ClInclude Include="..\..\..\src\common\gdsassert.h" />
<ClInclude Include="..\..\..\src\common\Int128.h" />
<ClInclude Include="..\..\..\src\common\intlobj_new.h" />
<ClInclude Include="..\..\..\src\common\IntlParametersBlock.h" />
<ClInclude Include="..\..\..\src\common\IntlUtil.h" />
@ -338,7 +340,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Lib>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;../../../extern/re2/builds/$(PlatformName)\$(Configuration)\re2.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;$(TargetDir)\ttmathuint_x86_64_msvc.obj;../../../extern/re2/builds/$(PlatformName)\$(Configuration)\re2.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -356,7 +358,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Lib>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;../../../extern/re2/builds/$(PlatformName)\$(Configuration)\re2.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/libtomcrypt/lib/$(PlatformName)\$(Configuration)\tomcrypt.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;../../../extern/re2/builds/$(PlatformName)\$(Configuration)\re2.lib;$(TargetDir)\ttmathuint_x86_64_msvc.obj;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -243,6 +243,9 @@
<ClCompile Include="..\..\..\src\common\keywords.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\Int128.cpp">
<Filter>common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\common\xdr_proto.h">
@ -587,5 +590,8 @@
<ClInclude Include="..\..\..\src\common\keywords.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\common\Int128.h">
<Filter>headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -200,7 +200,7 @@ Enhancement in precision of calculations with NUMERIC/DECIMAL (FB 4.0)
--------------
Function:
Maximum precision of NUMERIC and DECIMAL data types is increased to 34 digits.
Maximum precision of NUMERIC and DECIMAL data types is increased to 38 digits.
Author:
Alex Peshkoff <peshkoff@mail.ru>
@ -208,20 +208,35 @@ Enhancement in precision of calculations with NUMERIC/DECIMAL (FB 4.0)
Syntax rules:
NUMERIC ( P {, N} )
DECIMAL ( P {, N} )
where P is precision (P <= 34, was limited prior with 18 digits) and N is optional number
where P is precision (P <= 38, was limited prior with 18 digits) and N is optional number
of digits after decimal separator (as before).
Storage:
128-bit, format according to IEEE 754.
128-bit signed integer.
Example(s):
1. DECLARE VARIABLE VAR1 DECIMAL(25);
2. CREATE TABLE TABLE1 (FIELD1 NUMERIC(34, 17));
2. CREATE TABLE TABLE1 (FIELD1 NUMERIC(38, 19));
Note(s):
Numerics with precision less than 19 digits use SMALLINT, INTEGER, BIGINT or DOUBLE PRECISION
as base datatype depending upon number of digits and dialect. When precision is between 19 and
34 digits DECFLOAT(34) is used for it. Actual precision is always increased to 34 digits. For
complex calculations such digits are casted (internally, in trivial way) to DECFLOAT(34) and
the result of various math (log, exp, etc.) and aggregate functions using high precision
numeric argument is DECFLOAT(34).
38 digits 128-bit integer is used for it. Actual precision is always increased to 38 digits.
For complex calculations such digits are casted (internally) to DECFLOAT(34) and the result of
various math (log, exp, etc.) and aggregate functions using high precision numeric argument is
DECFLOAT(34).
SET INT128 BIND <bind-type> - controls how are INT128 values represented in outer
world (i.e. in messages or in XSQLDA). Valid binding types are: NATIVE (use 128-bit
binary representation), CHAR/CHARACTER (use ASCII string), DOUBLE PRECISION (use
8-byte FP representation - same as used for DOUBLE PRECISION fields) or BIGINT
with possible comma-separated SCALE clause (i.e. 'BIGINT, 3'). Various bindings
are useful if one plans to use 128-bit integers with some old client not supporting
native format. One can choose between strings (ideal precision, but poor support
for further processing), floating point values (ideal support for further processing
but poor precision) or scaled integers (good support for further processing and
required precision but range of values is very limited). When using in a tool like
generic purporse GUI client choice of CHAR binding is OK in most cases. By default
NATIVE binding is used.
The initial configuration may be specified with DPB isc_dpb_int128_bind followed
by a string with its value (case does not matter).

2843
extern/ttmath/ttmath.h vendored Normal file

File diff suppressed because it is too large Load Diff

1917
extern/ttmath/ttmathint.h vendored Normal file

File diff suppressed because it is too large Load Diff

250
extern/ttmath/ttmathmisc.h vendored Normal file
View File

@ -0,0 +1,250 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2006-2010, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name Tomasz Sowa nor the names of contributors to this
* project may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef headerfilettmathmisc
#define headerfilettmathmisc
/*!
\file ttmathmisc.h
\brief some helpful functions
*/
#include <string>
namespace ttmath
{
/*!
some helpful functions
*/
class Misc
{
public:
/*
*
* AssignString(result, str)
* result = str
*
*/
/*!
result = str
*/
static void AssignString(std::string & result, const char * str)
{
result = str;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
result = str
*/
static void AssignString(std::wstring & result, const char * str)
{
result.clear();
for( ; *str ; ++str )
result += *str;
}
/*!
result = str
*/
static void AssignString(std::wstring & result, const std::string & str)
{
return AssignString(result, str.c_str());
}
/*!
result = str
*/
static void AssignString(std::string & result, const wchar_t * str)
{
result.clear();
for( ; *str ; ++str )
result += static_cast<char>(*str);
}
/*!
result = str
*/
static void AssignString(std::string & result, const std::wstring & str)
{
return AssignString(result, str.c_str());
}
#endif
/*
*
* AddString(result, str)
* result += str
*
*/
/*!
result += str
*/
static void AddString(std::string & result, const char * str)
{
result += str;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
result += str
*/
static void AddString(std::wstring & result, const char * str)
{
for( ; *str ; ++str )
result += *str;
}
#endif
/*
this method omits any white characters from the string
char_type is char or wchar_t
*/
template<class char_type>
static void SkipWhiteCharacters(const char_type * & c)
{
// 13 is at the end in a DOS text file (\r\n)
while( (*c==' ' ) || (*c=='\t') || (*c==13 ) || (*c=='\n') )
++c;
}
/*!
this static method converts one character into its value
for example:
1 -> 1
8 -> 8
A -> 10
f -> 15
this method don't check whether c is correct or not
*/
static uint CharToDigit(uint c)
{
if(c>='0' && c<='9')
return c-'0';
if(c>='a' && c<='z')
return c-'a'+10;
return c-'A'+10;
}
/*!
this method changes a character 'c' into its value
(if there can't be a correct value it returns -1)
for example:
c=2, base=10 -> function returns 2
c=A, base=10 -> function returns -1
c=A, base=16 -> function returns 10
*/
static sint CharToDigit(uint c, uint base)
{
if( c>='0' && c<='9' )
c=c-'0';
else
if( c>='a' && c<='z' )
c=c-'a'+10;
else
if( c>='A' && c<='Z' )
c=c-'A'+10;
else
return -1;
if( c >= base )
return -1;
return sint(c);
}
/*!
this method converts a digit into a char
digit should be from <0,F>
(we don't have to get a base)
for example:
1 -> 1
8 -> 8
10 -> A
15 -> F
*/
static uint DigitToChar(uint digit)
{
if( digit < 10 )
return digit + '0';
return digit - 10 + 'A';
}
}; // struct Misc
}
#endif

809
extern/ttmath/ttmathobjects.h vendored Normal file
View File

@ -0,0 +1,809 @@
/*
* This file is a part of TTMath Mathematical Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2006-2010, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name Tomasz Sowa nor the names of contributors to this
* project may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef headerfilettmathobject
#define headerfilettmathobject
/*!
\file ttmathobjects.h
\brief Mathematic functions.
*/
#include <string>
#include <vector>
#include <list>
#include <map>
#include "ttmathtypes.h"
#include "ttmathmisc.h"
namespace ttmath
{
/*!
objects of this class are used with the mathematical parser
they hold variables or functions defined by a user
each object has its own table in which we're keeping variables or functions
*/
class Objects
{
public:
/*!
one item (variable or function)
'items' will be on the table
*/
struct Item
{
// name of a variable of a function
// internally we store variables and funcions as std::string (not std::wstring even when wide characters are used)
std::string value;
// number of parameters required by the function
// (if there's a variable this 'param' is ignored)
int param;
Item() {}
Item(const std::string & v, int p) : value(v), param(p) {}
};
// 'Table' is the type of our table
typedef std::map<std::string, Item> Table;
typedef Table::iterator Iterator;
typedef Table::const_iterator CIterator;
/*!
this method returns true if a character 'c' is a character
which can be in a name
if 'can_be_digit' is true that means when the 'c' is a digit this
method returns true otherwise it returns false
*/
static bool CorrectCharacter(int c, bool can_be_digit)
{
if( (c>='a' && c<='z') || (c>='A' && c<='Z') )
return true;
if( can_be_digit && ((c>='0' && c<='9') || c=='_') )
return true;
return false;
}
/*!
this method returns true if the name can be as a name of an object
*/
template<class string_type>
static bool IsNameCorrect(const string_type & name)
{
if( name.empty() )
return false;
if( !CorrectCharacter(name[0], false) )
return false;
typename string_type::const_iterator i = name.begin();
for(++i ; i!=name.end() ; ++i)
if( !CorrectCharacter(*i, true) )
return false;
return true;
}
/*!
this method returns true if such an object is defined (name exists)
*/
bool IsDefined(const std::string & name)
{
Iterator i = table.find(name);
if( i != table.end() )
// we have this object in our table
return true;
return false;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method returns true if such an object is defined (name exists)
*/
bool IsDefined(const std::wstring & name)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(name) )
return false;
Misc::AssignString(str_tmp1, name);
return IsDefined(str_tmp1);
}
#endif
/*!
this method adds one object (variable of function) into the table
*/
ErrorCode Add(const std::string & name, const std::string & value, int param = 0)
{
if( !IsNameCorrect(name) )
return err_incorrect_name;
Iterator i = table.find(name);
if( i != table.end() )
// we have this object in our table
return err_object_exists;
table.insert( std::make_pair(name, Item(value, param)) );
return err_ok;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method adds one object (variable of function) into the table
*/
ErrorCode Add(const std::wstring & name, const std::wstring & value, int param = 0)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(name) )
return err_incorrect_name;
Misc::AssignString(str_tmp1, name);
Misc::AssignString(str_tmp2, value);
return Add(str_tmp1, str_tmp2, param);
}
#endif
/*!
this method returns 'true' if the table is empty
*/
bool Empty() const
{
return table.empty();
}
/*!
this method clears the table
*/
void Clear()
{
return table.clear();
}
/*!
this method returns 'const_iterator' on the first item on the table
*/
CIterator Begin() const
{
return table.begin();
}
/*!
this method returns 'const_iterator' pointing at the space after last item
(returns table.end())
*/
CIterator End() const
{
return table.end();
}
/*!
this method changes the value and the number of parameters for a specific object
*/
ErrorCode EditValue(const std::string & name, const std::string & value, int param = 0)
{
if( !IsNameCorrect(name) )
return err_incorrect_name;
Iterator i = table.find(name);
if( i == table.end() )
return err_unknown_object;
i->second.value = value;
i->second.param = param;
return err_ok;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method changes the value and the number of parameters for a specific object
*/
ErrorCode EditValue(const std::wstring & name, const std::wstring & value, int param = 0)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(name) )
return err_incorrect_name;
Misc::AssignString(str_tmp1, name);
Misc::AssignString(str_tmp2, value);
return EditValue(str_tmp1, str_tmp2, param);
}
#endif
/*!
this method changes the name of a specific object
*/
ErrorCode EditName(const std::string & old_name, const std::string & new_name)
{
if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) )
return err_incorrect_name;
Iterator old_i = table.find(old_name);
if( old_i == table.end() )
return err_unknown_object;
if( old_name == new_name )
// the new name is the same as the old one
// we treat it as a normal situation
return err_ok;
ErrorCode err = Add(new_name, old_i->second.value, old_i->second.param);
if( err == err_ok )
{
old_i = table.find(old_name);
TTMATH_ASSERT( old_i != table.end() )
table.erase(old_i);
}
return err;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method changes the name of a specific object
*/
ErrorCode EditName(const std::wstring & old_name, const std::wstring & new_name)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) )
return err_incorrect_name;
Misc::AssignString(str_tmp1, old_name);
Misc::AssignString(str_tmp2, new_name);
return EditName(str_tmp1, str_tmp2);
}
#endif
/*!
this method deletes an object
*/
ErrorCode Delete(const std::string & name)
{
if( !IsNameCorrect(name) )
return err_incorrect_name;
Iterator i = table.find(name);
if( i == table.end() )
return err_unknown_object;
table.erase( i );
return err_ok;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method deletes an object
*/
ErrorCode Delete(const std::wstring & name)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(name) )
return err_incorrect_name;
Misc::AssignString(str_tmp1, name);
return Delete(str_tmp1);
}
#endif
/*!
this method gets the value of a specific object
*/
ErrorCode GetValue(const std::string & name, std::string & value) const
{
if( !IsNameCorrect(name) )
return err_incorrect_name;
CIterator i = table.find(name);
if( i == table.end() )
{
value.clear();
return err_unknown_object;
}
value = i->second.value;
return err_ok;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method gets the value of a specific object
*/
ErrorCode GetValue(const std::wstring & name, std::wstring & value)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(name) )
return err_incorrect_name;
Misc::AssignString(str_tmp1, name);
ErrorCode err = GetValue(str_tmp1, str_tmp2);
Misc::AssignString(value, str_tmp2);
return err;
}
#endif
/*!
this method gets the value of a specific object
(this version is used for not copying the whole string)
*/
ErrorCode GetValue(const std::string & name, const char ** value) const
{
if( !IsNameCorrect(name) )
return err_incorrect_name;
CIterator i = table.find(name);
if( i == table.end() )
{
*value = 0;
return err_unknown_object;
}
*value = i->second.value.c_str();
return err_ok;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method gets the value of a specific object
(this version is used for not copying the whole string)
*/
ErrorCode GetValue(const std::wstring & name, const char ** value)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(name) )
return err_incorrect_name;
Misc::AssignString(str_tmp1, name);
return GetValue(str_tmp1, value);
}
#endif
/*!
this method gets the value and the number of parameters
of a specific object
*/
ErrorCode GetValueAndParam(const std::string & name, std::string & value, int * param) const
{
if( !IsNameCorrect(name) )
return err_incorrect_name;
CIterator i = table.find(name);
if( i == table.end() )
{
value.empty();
*param = 0;
return err_unknown_object;
}
value = i->second.value;
*param = i->second.param;
return err_ok;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method gets the value and the number of parameters
of a specific object
*/
ErrorCode GetValueAndParam(const std::wstring & name, std::wstring & value, int * param)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(name) )
return err_incorrect_name;
Misc::AssignString(str_tmp1, name);
ErrorCode err = GetValueAndParam(str_tmp1, str_tmp2, param);
Misc::AssignString(value, str_tmp2);
return err;
}
#endif
/*!
this method sets the value and the number of parameters
of a specific object
(this version is used for not copying the whole string)
*/
ErrorCode GetValueAndParam(const std::string & name, const char ** value, int * param) const
{
if( !IsNameCorrect(name) )
return err_incorrect_name;
CIterator i = table.find(name);
if( i == table.end() )
{
*value = 0;
*param = 0;
return err_unknown_object;
}
*value = i->second.value.c_str();
*param = i->second.param;
return err_ok;
}
#ifndef TTMATH_DONT_USE_WCHAR
/*!
this method sets the value and the number of parameters
of a specific object
(this version is used for not copying the whole string
but in fact we make one copying during AssignString())
*/
ErrorCode GetValueAndParam(const std::wstring & name, const char ** value, int * param)
{
// we should check whether the name (in wide characters) are correct
// before calling AssignString() function
if( !IsNameCorrect(name) )
return err_incorrect_name;
Misc::AssignString(str_tmp1, name);
return GetValueAndParam(str_tmp1, value, param);
}
#endif
/*!
this method returns a pointer into the table
*/
Table * GetTable()
{
return &table;
}
private:
Table table;
std::string str_tmp1, str_tmp2;
}; // end of class Objects
/*!
objects of the class History are used to keep values in functions
which take a lot of time during calculating, for instance in the
function Factorial(x)
it means that when we're calculating e.g. Factorial(1000) and the
Factorial finds that we have calculated it before, the value (result)
is taken from the history
*/
template<class ValueType>
class History
{
/*!
one item in the History's object holds a key, a value for the key
and a corresponding error code
*/
struct Item
{
ValueType key, value;
ErrorCode err;
};
/*!
we use std::list for simply deleting the first item
but because we're searching through the whole container
(in the method Get) the container should not be too big
(linear time of searching)
*/
typedef std::list<Item> buffer_type;
buffer_type buffer;
typename buffer_type::size_type buffer_max_size;
public:
/*!
default constructor
default max size of the History's container is 15 items
*/
History()
{
buffer_max_size = 15;
}
/*!
a constructor which takes another value of the max size
of the History's container
*/
History(typename buffer_type::size_type new_size)
{
buffer_max_size = new_size;
}
/*!
this method adds one item into the History
if the size of the container is greater than buffer_max_size
the first item will be removed
*/
void Add(const ValueType & key, const ValueType & value, ErrorCode err)
{
Item item;
item.key = key;
item.value = value;
item.err = err;
buffer.insert( buffer.end(), item );
if( buffer.size() > buffer_max_size )
buffer.erase(buffer.begin());
}
/*!
this method checks whether we have an item which has the key equal 'key'
if there's such item the method sets the 'value' and the 'err'
and returns true otherwise it returns false and 'value' and 'err'
remain unchanged
*/
bool Get(const ValueType & key, ValueType & value, ErrorCode & err)
{
typename buffer_type::iterator i = buffer.begin();
for( ; i != buffer.end() ; ++i )
{
if( i->key == key )
{
value = i->value;
err = i->err;
return true;
}
}
return false;
}
/*!
this methods deletes an item
we assume that there is only one item with the 'key'
(this methods removes the first one)
*/
bool Remove(const ValueType & key)
{
typename buffer_type::iterator i = buffer.begin();
for( ; i != buffer.end() ; ++i )
{
if( i->key == key )
{
buffer.erase(i);
return true;
}
}
return false;
}
}; // end of class History
/*!
this is an auxiliary class used when calculating Gamma() or Factorial()
in multithreaded environment you can provide an object of this class to
the Gamma() or Factorial() function, e.g;
typedef Big<1, 3> MyBig;
MyBig x = 123456;
CGamma<MyBig> cgamma;
std::cout << Gamma(x, cgamma);
each thread should have its own CGamma<> object
in a single-thread environment a CGamma<> object is a static variable
in a second version of Gamma() and you don't have to explicitly use it, e.g.
typedef Big<1, 3> MyBig;
MyBig x = 123456;
std::cout << Gamma(x);
*/
template<class ValueType>
struct CGamma
{
/*!
this table holds factorials
1
1
2
6
24
120
720
.......
*/
std::vector<ValueType> fact;
/*!
this table holds Bernoulli numbers
1
-0.5
0.166666666666666666666666667
0
-0.0333333333333333333333333333
0
0.0238095238095238095238095238
0
-0.0333333333333333333333333333
0
0.075757575757575757575757576
.....
*/
std::vector<ValueType> bern;
/*!
here we store some calculated values
(this is for speeding up, if the next argument of Gamma() or Factorial()
is in the 'history' then the result we are not calculating but simply
return from the 'history' object)
*/
History<ValueType> history;
/*!
this method prepares some coefficients: factorials and Bernoulli numbers
stored in 'fact' and 'bern' objects
how many values should be depends on the size of the mantissa - if
the mantissa is larger then we must calculate more values
for a mantissa which consists of 256 bits (8 words on a 32bit platform)
we have to calculate about 30 values (the size of fact and bern will be 30),
and for a 2048 bits mantissa we have to calculate 306 coefficients
you don't have to call this method, these coefficients will be automatically calculated
when they are needed
you must note that calculating these coefficients is a little time-consuming operation,
(especially when the mantissa is large) and first call to Gamma() or Factorial()
can take more time than next calls, and in the end this is the point when InitAll()
comes in handy: you can call this method somewhere at the beginning of your program
*/
void InitAll();
// definition is in ttmath.h
};
} // namespace
#endif

250
extern/ttmath/ttmaththreads.h vendored Normal file
View File

@ -0,0 +1,250 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name Tomasz Sowa nor the names of contributors to this
* project may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef headerfilettmaththreads
#define headerfilettmaththreads
#include "ttmathtypes.h"
#ifdef TTMATH_WIN32_THREADS
#include <windows.h>
#include <cstdio>
#endif
#ifdef TTMATH_POSIX_THREADS
#include <pthread.h>
#endif
/*!
\file ttmaththreads.h
\brief Some objects used in multithreads environment
*/
/*
this is a simple skeleton of a program in multithreads environment:
#define TTMATH_MULTITHREADS
#include<ttmath/ttmath.h>
TTMATH_MULTITHREADS_HELPER
int main()
{
[...]
}
make sure that macro TTMATH_MULTITHREADS is defined and (somewhere in *.cpp file)
use TTMATH_MULTITHREADS_HELPER macro (outside of any classes/functions/namespaces scope)
*/
namespace ttmath
{
#ifdef TTMATH_WIN32_THREADS
/*
we use win32 threads
*/
/*!
in multithreads environment you should use TTMATH_MULTITHREADS_HELPER macro
somewhere in *.cpp file
(at the moment in win32 this macro does nothing)
*/
#define TTMATH_MULTITHREADS_HELPER
/*!
objects of this class are used to synchronize
*/
class ThreadLock
{
HANDLE mutex_handle;
void CreateName(char * buffer) const
{
#ifdef _MSC_VER
#pragma warning (disable : 4996)
// warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead.
#endif
sprintf(buffer, "TTMATH_LOCK_%ul", (unsigned long)GetCurrentProcessId());
#ifdef _MSC_VER
#pragma warning (default : 4996)
#endif
}
public:
bool Lock()
{
char buffer[50];
CreateName(buffer);
mutex_handle = CreateMutexA(0, false, buffer);
if( mutex_handle == 0 )
return false;
WaitForSingleObject(mutex_handle, INFINITE);
return true;
}
ThreadLock()
{
mutex_handle = 0;
}
~ThreadLock()
{
if( mutex_handle != 0 )
{
ReleaseMutex(mutex_handle);
CloseHandle(mutex_handle);
}
}
};
#endif // #ifdef TTMATH_WIN32_THREADS
#ifdef TTMATH_POSIX_THREADS
/*
we use posix threads
*/
/*!
in multithreads environment you should use TTMATH_MULTITHREADS_HELPER macro
somewhere in *.cpp file
(this macro defines a pthread_mutex_t object used by TTMath library)
*/
#define TTMATH_MULTITHREADS_HELPER \
namespace ttmath \
{ \
pthread_mutex_t ttmath_mutex = PTHREAD_MUTEX_INITIALIZER; \
}
/*!
ttmath_mutex will be defined by TTMATH_MULTITHREADS_HELPER macro
*/
extern pthread_mutex_t ttmath_mutex;
/*!
objects of this class are used to synchronize
*/
class ThreadLock
{
public:
bool Lock()
{
if( pthread_mutex_lock(&ttmath_mutex) != 0 )
return false;
return true;
}
~ThreadLock()
{
pthread_mutex_unlock(&ttmath_mutex);
}
};
#endif // #ifdef TTMATH_POSIX_THREADS
#if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS)
/*!
we don't use win32 and pthreads
*/
/*!
*/
#define TTMATH_MULTITHREADS_HELPER
/*!
objects of this class are used to synchronize
actually we don't synchronize, the method Lock() returns always 'false'
*/
class ThreadLock
{
public:
bool Lock()
{
return false;
}
};
#endif // #if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS)
} // namespace
#endif

676
extern/ttmath/ttmathtypes.h vendored Normal file
View File

@ -0,0 +1,676 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2006-2012, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name Tomasz Sowa nor the names of contributors to this
* project may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef headerfilettmathtypes
#define headerfilettmathtypes
/*!
\file ttmathtypes.h
\brief constants used in the library
As our library is written in header files (templates) we cannot use
constants like 'const int' etc. because we should have some source files
*.cpp to define this variables. Only what we can have are constants
defined by #define preprocessor macros.
All macros are preceded by TTMATH_ prefix
*/
#include <stdexcept>
#include <sstream>
#include <vector>
#ifndef _MSC_VER
#include <stdint.h>
// for uint64_t and int64_t on a 32 bit platform
#endif
/*!
the version of the library
TTMATH_PRERELEASE_VER is either zero or one
zero means that this is the release version of the library
(one means something like beta)
*/
#define TTMATH_MAJOR_VER 0
#define TTMATH_MINOR_VER 9
#define TTMATH_REVISION_VER 3
#define TTMATH_PRERELEASE_VER 0
/*!
you can define a platform explicitly by defining either
TTMATH_PLATFORM32 or TTMATH_PLATFORM64 macro
*/
#if !defined TTMATH_PLATFORM32 && !defined TTMATH_PLATFORM64
#if !defined _M_X64 && !defined __x86_64__
/*
other platforms than x86 and amd64 are not recognized at the moment
so you should set TTMATH_PLATFORMxx manually
*/
// we're using a 32bit platform
#define TTMATH_PLATFORM32
#else
// we're using a 64bit platform
#define TTMATH_PLATFORM64
#endif
#endif
/*!
asm version of the library is available by default only for:
x86 and amd64 platforms and for Microsoft Visual and GCC compilers
but you can force using asm version (the same asm as for Microsoft Visual)
by defining TTMATH_FORCEASM macro
you have to be sure that your compiler accept such an asm format
*/
#ifndef TTMATH_FORCEASM
#if !defined __i386__ && !defined _X86_ && !defined _M_IX86 && !defined __x86_64__ && !defined _M_X64
/*!
x86 architecture:
__i386__ defined by GNU C
_X86_ defined by MinGW32
_M_IX86 defined by Visual Studio, Intel C/C++, Digital Mars and Watcom C/C++
amd64 architecture:
__x86_64__ defined by GNU C, CLANG (LLVM) and Sun Studio
_M_X64 defined by Visual Studio
asm version is available only for x86 or amd64 platforms
*/
#define TTMATH_NOASM
#endif
#if !defined _MSC_VER && !defined __GNUC__
/*!
another compilers than MS VC or GCC or CLANG (LLVM) by default use no asm version
(CLANG defines __GNUC__ too)
*/
#define TTMATH_NOASM
#endif
#endif
namespace ttmath
{
#ifdef TTMATH_PLATFORM32
/*!
on 32bit platforms one word (uint, sint) will be equal 32bits
*/
typedef unsigned int uint;
typedef signed int sint;
/*!
on 32 bit platform ulint and slint will be equal 64 bits
*/
#ifdef _MSC_VER
// long long on MS Windows (Visual and GCC mingw compilers) have 64 bits
// stdint.h is not available on Visual Studio prior to VS 2010 version
typedef unsigned long long int ulint;
typedef signed long long int slint;
#else
// we do not use 'long' here because there is a difference in unix and windows
// environments: in unix 'long' has 64 bits but in windows it has only 32 bits
typedef uint64_t ulint;
typedef int64_t slint;
#endif
/*!
how many bits there are in the uint type
*/
#define TTMATH_BITS_PER_UINT 32u
/*!
the mask for the highest bit in the unsigned 32bit word (2^31)
*/
#define TTMATH_UINT_HIGHEST_BIT 2147483648u
/*!
the max value of the unsigned 32bit word (2^32 - 1)
(all bits equal one)
*/
#define TTMATH_UINT_MAX_VALUE 4294967295u
/*!
the number of words (32bit words on 32bit platform)
which are kept in built-in variables for a Big<> type
(these variables are defined in ttmathbig.h)
*/
#define TTMATH_BUILTIN_VARIABLES_SIZE 256u
/*!
this macro returns the number of machine words
capable to hold min_bits bits
e.g. TTMATH_BITS(128) returns 4
*/
#define TTMATH_BITS(min_bits) ((min_bits-1)/32 + 1)
#else
/*!
on 64bit platforms one word (uint, sint) will be equal 64bits
*/
#ifdef _MSC_VER
/* in VC 'long' type has 32 bits, __int64 is VC extension */
typedef unsigned __int64 uint;
typedef signed __int64 sint;
#else
typedef unsigned long uint;
typedef signed long sint;
#endif
/*!
on 64bit platforms we do not define ulint and slint
*/
/*!
how many bits there are in the uint type
*/
#define TTMATH_BITS_PER_UINT 64ul
/*!
the mask for the highest bit in the unsigned 64bit word (2^63)
*/
#define TTMATH_UINT_HIGHEST_BIT 9223372036854775808ul
/*!
the max value of the unsigned 64bit word (2^64 - 1)
(all bits equal one)
*/
#define TTMATH_UINT_MAX_VALUE 18446744073709551615ul
/*!
the number of words (64bit words on 64bit platforms)
which are kept in built-in variables for a Big<> type
(these variables are defined in ttmathbig.h)
*/
#define TTMATH_BUILTIN_VARIABLES_SIZE 128ul
/*!
this macro returns the number of machine words
capable to hold min_bits bits
e.g. TTMATH_BITS(128) returns 2
*/
#define TTMATH_BITS(min_bits) ((min_bits-1)/64 + 1)
#endif
}
#if defined(TTMATH_MULTITHREADS) && !defined(TTMATH_MULTITHREADS_NOSYNC)
#if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS)
#if defined(_WIN32)
#define TTMATH_WIN32_THREADS
#elif defined(unix) || defined(__unix__) || defined(__unix)
#define TTMATH_POSIX_THREADS
#endif
#endif
#endif
/*!
this variable defines how many iterations are performed
during some kind of calculating when we're making any long formulas
(for example Taylor series)
it's used in ExpSurrounding0(...), LnSurrounding1(...), Sin0pi05(...), etc.
note! there'll not be so many iterations, iterations are stopped when
there is no sense to continue calculating (for example when the result
still remains unchanged after adding next series and we know that the next
series are smaller than previous ones)
*/
#define TTMATH_ARITHMETIC_MAX_LOOP 10000
/*!
this is a limit when calculating Karatsuba multiplication
if the size of a vector is smaller than TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE
the Karatsuba algorithm will use standard schoolbook multiplication
*/
#ifdef TTMATH_DEBUG_LOG
// if TTMATH_DEBUG_LOG is defined then we should use the same size regardless of the compiler
#define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3
#else
#ifdef __GNUC__
#define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3
#else
#define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 5
#endif
#endif
/*!
this is a special value used when calculating the Gamma(x) function
if x is greater than this value then the Gamma(x) will be calculated using
some kind of series
don't use smaller values than about 100
*/
#define TTMATH_GAMMA_BOUNDARY 2000
namespace ttmath
{
/*!
lib type codes:
asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits)
asm_gcc_32 - with asm code designed for GCC (32 bits)
asm_vc_64 - with asm for VC (64 bit)
asm_gcc_64 - with asm for GCC (64 bit)
no_asm_32 - pure C++ version (32 bit) - without any asm code
no_asm_64 - pure C++ version (64 bit) - without any asm code
*/
enum LibTypeCode
{
asm_vc_32 = 0,
asm_gcc_32,
asm_vc_64,
asm_gcc_64,
no_asm_32,
no_asm_64
};
/*!
error codes
*/
enum ErrorCode
{
err_ok = 0,
err_nothing_has_read,
err_unknown_character,
err_unexpected_final_bracket,
err_stack_not_clear,
err_unknown_variable,
err_division_by_zero,
err_interrupt,
err_overflow,
err_unknown_function,
err_unknown_operator,
err_unexpected_semicolon_operator,
err_improper_amount_of_arguments,
err_improper_argument,
err_unexpected_end,
err_internal_error,
err_incorrect_name,
err_incorrect_value,
err_variable_exists,
err_variable_loop,
err_functions_loop,
err_must_be_only_one_value,
err_object_exists,
err_unknown_object,
err_still_calculating,
err_in_short_form_used_function,
err_percent_from
};
/*!
this struct is used when converting to/from a string
/temporarily only in Big::ToString() and Big::FromString()/
*/
struct Conv
{
/*!
base (radix) on which the value will be shown (or read)
default: 10
*/
uint base;
/*!
used only in Big::ToString()
if true the value will be always shown in the scientific mode, e.g: 123e+30
default: false
*/
bool scient;
/*!
used only in Big::ToString()
if scient is false then the value will be printed in the scientific mode
only if the exponent is greater than scien_from
default: 15
*/
sint scient_from;
/*!
if 'base_round' is true and 'base' is different from 2, 4, 8, or 16
and the result value is not an integer then we make an additional rounding
(after converting the last digit from the result is skipped)
default: true
e.g.
Conv c;
c.base_round = false;
Big<1, 1> a = "0.1"; // decimal input
std::cout << a.ToString(c) << std::endl; // the result is: 0.099999999
*/
bool base_round;
/*!
used only in Big::ToString()
tells how many digits after comma are possible
default: -1 which means all digits are printed
set it to zero if you want integer value only
for example when the value is:
12.345678 and 'round' is 4
then the result will be
12.3457 (the last digit was rounded)
*/
sint round;
/*!
if true that not mattered digits in the mantissa will be cut off
(zero characters at the end -- after the comma operator)
e.g. 1234,78000 will be: 1234,78
default: true
*/
bool trim_zeroes;
/*!
the main comma operator (used when reading and writing)
default is a dot '.'
*/
uint comma;
/*!
additional comma operator (used only when reading)
if you don't want it just set it to zero
default is a comma ','
this allowes you to convert from a value:
123.45 as well as from 123,45
*/
uint comma2;
/*!
it sets the character which is used for grouping
if group=' ' then: 1234,56789 will be printed as: 1 234,567 89
if you don't want grouping just set it to zero (which is default)
*/
uint group;
/*!
how many digits should be grouped (it is used if 'group' is non zero)
default: 3
*/
uint group_digits;
/*!
*/
uint group_exp; // not implemented yet
Conv()
{
// default values
base = 10;
scient = false;
scient_from = 15;
base_round = true;
round = -1;
trim_zeroes = true;
comma = '.';
comma2 = ',';
group = 0;
group_digits = 3;
group_exp = 0;
}
};
/*!
this simple class can be used in multithreading model
(you can write your own class derived from this one)
for example: in some functions like Factorial()
/at the moment only Factorial/ you can give a pointer to
the 'stop object', if the method WasStopSignal() of this
object returns true that means we should break the calculating
and return
*/
class StopCalculating
{
public:
virtual bool WasStopSignal() const volatile { return false; }
virtual ~StopCalculating(){}
};
/*!
a small class which is useful when compiling with gcc
object of this type holds the name and the line of a file
in which the macro TTMATH_ASSERT or TTMATH_REFERENCE_ASSERT was used
*/
class ExceptionInfo
{
const char * file;
int line;
public:
ExceptionInfo() : file(0), line(0) {}
ExceptionInfo(const char * f, int l) : file(f), line(l) {}
std::string Where() const
{
if( !file )
return "unknown";
std::ostringstream result;
result << file << ":" << line;
return result.str();
}
};
/*!
A small class used for reporting 'reference' errors
In the library is used macro TTMATH_REFERENCE_ASSERT which
can throw an exception of this type
** from version 0.9.2 this macro is removed from all methods
in public interface so you don't have to worry about it **
If you compile with gcc you can get a small benefit
from using method Where() (it returns std::string) with
the name and the line of a file where the macro TTMATH_REFERENCE_ASSERT
was used)
*/
class ReferenceError : public std::logic_error, public ExceptionInfo
{
public:
ReferenceError() : std::logic_error("reference error")
{
}
ReferenceError(const char * f, int l) :
std::logic_error("reference error"), ExceptionInfo(f,l)
{
}
std::string Where() const
{
return ExceptionInfo::Where();
}
};
/*!
a small class used for reporting errors
in the library is used macro TTMATH_ASSERT which
(if the condition in it is false) throw an exception
of this type
if you compile with gcc you can get a small benefit
from using method Where() (it returns std::string) with
the name and the line of a file where the macro TTMATH_ASSERT
was used)
*/
class RuntimeError : public std::runtime_error, public ExceptionInfo
{
public:
RuntimeError() : std::runtime_error("internal error")
{
}
RuntimeError(const char * f, int l) :
std::runtime_error("internal error"), ExceptionInfo(f,l)
{
}
std::string Where() const
{
return ExceptionInfo::Where();
}
};
/*!
TTMATH_DEBUG
this macro enables further testing during writing your code
you don't have to define it in a release mode
if this macro is set then macros TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT
are set as well and these macros can throw an exception if a condition in it
is not fulfilled (look at the definition of TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT)
TTMATH_DEBUG is set automatically if DEBUG or _DEBUG are defined
*/
#if defined DEBUG || defined _DEBUG
#define TTMATH_DEBUG
#endif
#ifdef TTMATH_DEBUG
#if defined(__FILE__) && defined(__LINE__)
#define TTMATH_REFERENCE_ASSERT(expression) \
if( &(expression) == this ) throw ttmath::ReferenceError(__FILE__, __LINE__);
#define TTMATH_ASSERT(expression) \
if( !(expression) ) throw ttmath::RuntimeError(__FILE__, __LINE__);
#else
#define TTMATH_REFERENCE_ASSERT(expression) \
if( &(expression) == this ) throw ReferenceError();
#define TTMATH_ASSERT(expression) \
if( !(expression) ) throw RuntimeError();
#endif
#else
#define TTMATH_REFERENCE_ASSERT(expression)
#define TTMATH_ASSERT(expression)
#endif
#ifdef TTMATH_DEBUG_LOG
#define TTMATH_LOG(msg) PrintLog(msg, std::cout);
#define TTMATH_LOGC(msg, carry) PrintLog(msg, carry, std::cout);
#define TTMATH_VECTOR_LOG(msg, vector, len) PrintVectorLog(msg, std::cout, vector, len);
#define TTMATH_VECTOR_LOGC(msg, carry, vector, len) PrintVectorLog(msg, carry, std::cout, vector, len);
#else
#define TTMATH_LOG(msg)
#define TTMATH_LOGC(msg, carry)
#define TTMATH_VECTOR_LOG(msg, vector, len)
#define TTMATH_VECTOR_LOGC(msg, carry, vector, len)
#endif
} // namespace
#endif

4126
extern/ttmath/ttmathuint.h vendored Normal file

File diff suppressed because it is too large Load Diff

1017
extern/ttmath/ttmathuint_noasm.h vendored Normal file

File diff suppressed because it is too large Load Diff

1602
extern/ttmath/ttmathuint_x86.h vendored Normal file

File diff suppressed because it is too large Load Diff

1146
extern/ttmath/ttmathuint_x86_64.h vendored Normal file

File diff suppressed because it is too large Load Diff

548
extern/ttmath/ttmathuint_x86_64_msvc.asm vendored Normal file
View File

@ -0,0 +1,548 @@
;
; This file is a part of TTMath Bignum Library
; and is distributed under the (new) BSD licence.
; Author: Christian Kaiser <chk@online.de>
;
;
; Copyright (c) 2009, Christian Kaiser
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;
; * Redistributions of source code must retain the above copyright notice,
; this list of conditions and the following disclaimer.
;
; * Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
;
; * Neither the name Christian Kaiser nor the names of contributors to this
; project may be used to endorse or promote products derived
; from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
; THE POSSIBILITY OF SUCH DAMAGE.
;
;
; compile with debug info: ml64.exe /c /Zd /Zi ttmathuint_x86_64_msvc.asm
; compile without debug info: ml64.exe /c ttmathuint_x86_64_msvc.asm
; this creates ttmathuint_x86_64_msvc.obj file which can be linked with your program
;
PUBLIC ttmath_adc_x64
PUBLIC ttmath_addindexed_x64
PUBLIC ttmath_addindexed2_x64
PUBLIC ttmath_addvector_x64
PUBLIC ttmath_sbb_x64
PUBLIC ttmath_subindexed_x64
PUBLIC ttmath_subvector_x64
PUBLIC ttmath_rcl_x64
PUBLIC ttmath_rcr_x64
PUBLIC ttmath_rcl2_x64
PUBLIC ttmath_rcr2_x64
PUBLIC ttmath_div_x64
;
; Microsoft x86_64 convention: http://msdn.microsoft.com/en-us/library/9b372w95.aspx
;
; "rax, rcx, rdx, r8-r11 are volatile."
; "rbx, rbp, rdi, rsi, r12-r15 are nonvolatile."
;
.CODE
ALIGN 8
;----------------------------------------
ttmath_adc_x64 PROC
; rcx = p1
; rdx = p2
; r8 = nSize
; r9 = nCarry
xor rax, rax
xor r11, r11
sub rax, r9 ; sets CARRY if r9 != 0
ALIGN 16
loop1:
mov rax,qword ptr [rdx + r11 * 8]
adc qword ptr [rcx + r11 * 8], rax
lea r11, [r11+1]
dec r8
jnz loop1
setc al
movzx rax, al
ret
ttmath_adc_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_addindexed_x64 PROC
; rcx = p1
; rdx = nSize
; r8 = nPos
; r9 = nValue
xor rax, rax ; rax = result
sub rdx, r8 ; rdx = remaining count of uints
add qword ptr [rcx + r8 * 8], r9
jc next1
ret
next1:
mov r9, 1
ALIGN 16
loop1:
dec rdx
jz done_with_cy
lea r8, [r8+1]
add qword ptr [rcx + r8 * 8], r9
jc loop1
ret
done_with_cy:
lea rax, [rax+1] ; rax = 1
ret
ttmath_addindexed_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_addindexed2_x64 PROC
; rcx = p1 (pointer)
; rdx = b (value size)
; r8 = nPos
; r9 = nValue1
; [esp+0x28] = nValue2
xor rax, rax ; return value
mov r11, rcx ; table
sub rdx, r8 ; rdx = remaining count of uints
mov r10, [esp+028h] ; r10 = nValue2
add qword ptr [r11 + r8 * 8], r9
lea r8, [r8+1]
lea rdx, [rdx-1]
adc qword ptr [r11 + r8 * 8], r10
jc next
ret
ALIGN 16
loop1:
lea r8, [r8+1]
add qword ptr [r11 + r8 * 8], 1
jc next
ret
next:
dec rdx ; does not modify CY too...
jnz loop1
lea rax, [rax+1]
ret
ttmath_addindexed2_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_addvector_x64 PROC
; rcx = ss1
; rdx = ss2
; r8 = ss1_size
; r9 = ss2_size
; [esp+0x28] = result
mov r10, [esp+028h]
sub r8, r9
xor r11, r11 ; r11=0, cf=0
ALIGN 16
loop1:
mov rax, qword ptr [rcx + r11 * 8]
adc rax, qword ptr [rdx + r11 * 8]
mov qword ptr [r10 + r11 * 8], rax
inc r11
dec r9
jnz loop1
adc r9, r9 ; r9 has the cf state
or r8, r8
jz done
neg r9 ; setting cf from r9
mov r9, 0 ; don't use xor here (cf is used)
loop2:
mov rax, qword ptr [rcx + r11 * 8]
adc rax, r9
mov qword ptr [r10 + r11 * 8], rax
inc r11
dec r8
jnz loop2
adc r8, r8
mov rax, r8
ret
done:
mov rax, r9
ret
ttmath_addvector_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_sbb_x64 PROC
; rcx = p1
; rdx = p2
; r8 = nCount
; r9 = nCarry
xor rax, rax
xor r11, r11
sub rax, r9 ; sets CARRY if r9 != 0
ALIGN 16
loop1:
mov rax,qword ptr [rdx + r11 * 8]
sbb qword ptr [rcx + r11 * 8], rax
lea r11, [r11+1]
dec r8
jnz loop1
setc al
movzx rax, al
ret
ttmath_sbb_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_subindexed_x64 PROC
; rcx = p1
; rdx = nSize
; r8 = nPos
; r9 = nValue
sub rdx, r8 ; rdx = remaining count of uints
ALIGN 16
loop1:
sub qword ptr [rcx + r8 * 8], r9
jnc done
lea r8, [r8+1]
mov r9, 1
dec rdx
jnz loop1
mov rax, 1
ret
done:
xor rax, rax
ret
ttmath_subindexed_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
; the same asm code as in addvector_x64 only two instructions 'adc' changed to 'sbb'
ttmath_subvector_x64 PROC
; rcx = ss1
; rdx = ss2
; r8 = ss1_size
; r9 = ss2_size
; [esp+0x28] = result
mov r10, [esp+028h]
sub r8, r9
xor r11, r11 ; r11=0, cf=0
ALIGN 16
loop1:
mov rax, qword ptr [rcx + r11 * 8]
sbb rax, qword ptr [rdx + r11 * 8]
mov qword ptr [r10 + r11 * 8], rax
inc r11
dec r9
jnz loop1
adc r9, r9 ; r9 has the cf state
or r8, r8
jz done
neg r9 ; setting cf from r9
mov r9, 0 ; don't use xor here (cf is used)
loop2:
mov rax, qword ptr [rcx + r11 * 8]
sbb rax, r9
mov qword ptr [r10 + r11 * 8], rax
inc r11
dec r8
jnz loop2
adc r8, r8
mov rax, r8
ret
done:
mov rax, r9
ret
ttmath_subvector_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_rcl_x64 PROC
; rcx = p1
; rdx = b
; r8 = nLowestBit
mov r11, rcx ; table
xor r10, r10
neg r8 ; CY set if r8 <> 0
ALIGN 16
loop1:
rcl qword ptr [r11 + r10 * 8], 1
lea r10, [r10+1]
dec rdx
jnz loop1
setc al
movzx rax, al
ret
ttmath_rcl_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_rcr_x64 PROC
; rcx = p1
; rdx = nSize
; r8 = nLowestBit
xor r10, r10
neg r8 ; CY set if r8 <> 0
ALIGN 16
loop1:
rcr qword ptr -8[rcx + rdx * 8], 1
dec rdx
jnz loop1
setc al
movzx rax, al
ret
ttmath_rcr_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_div_x64 PROC
; rcx = &Hi
; rdx = &Lo
; r8 = nDiv
mov r11, rcx
mov r10, rdx
mov rdx, qword ptr [r11]
mov rax, qword ptr [r10]
div r8
mov qword ptr [r10], rdx ; remainder
mov qword ptr [r11], rax ; value
ret
ttmath_div_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_rcl2_x64 PROC
; rcx = p1
; rdx = nSize
; r8 = bits
; r9 = c
push rbx
mov r10, rcx ; r10 = p1
xor rax, rax
mov rcx, 64
sub rcx, r8
mov r11, -1
shr r11, cl ; r11 = mask
mov rcx, r8 ; rcx = count of bits
mov rbx, rax ; rbx = old value = 0
or r9, r9
cmovnz rbx, r11 ; if (c) then old value = mask
mov r9, rax ; r9 = index (0..nSize-1)
ALIGN 16
loop1:
rol qword ptr [r10+r9*8], cl
mov rax, qword ptr [r10+r9*8]
and rax, r11
xor qword ptr [r10+r9*8], rax
or qword ptr [r10+r9*8], rbx
mov rbx, rax
lea r9, [r9+1]
dec rdx
jnz loop1
and rax, 1
pop rbx
ret
ttmath_rcl2_x64 ENDP
;----------------------------------------
ALIGN 8
;----------------------------------------
ttmath_rcr2_x64 PROC
; rcx = p1
; rdx = nSize
; r8 = bits
; r9 = c
push rbx
mov r10, rcx ; r10 = p1
xor rax, rax
mov rcx, 64
sub rcx, r8
mov r11, -1
shl r11, cl ; r11 = mask
mov rcx, r8 ; rcx = count of bits
mov rbx, rax ; rbx = old value = 0
or r9, r9
cmovnz rbx, r11 ; if (c) then old value = mask
mov r9, rdx ; r9 = index (0..nSize-1)
lea r9, [r9-1]
ALIGN 16
loop1:
ror qword ptr [r10+r9*8], cl
mov rax, qword ptr [r10+r9*8]
and rax, r11
xor qword ptr [r10+r9*8], rax
or qword ptr [r10+r9*8], rbx
mov rbx, rax
lea r9, [r9-1]
dec rdx
jnz loop1
rol rax, 1
and rax, 1
pop rbx
ret
ttmath_rcr2_x64 ENDP
END

View File

@ -1472,8 +1472,8 @@ void put_data(burp_rel* relation)
add_byte(blr, field->fld_scale);
break;
case blr_dec_fixed:
alignment = type_alignments[dtype_dec_fixed];
case blr_int128:
alignment = type_alignments[dtype_int128];
add_byte(blr, field->fld_type);
add_byte(blr, field->fld_scale);
break;

View File

@ -170,11 +170,15 @@ ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool d
break;
case dtype_dec128:
case dtype_dec_fixed:
if (!xdr_dec128(xdrs, (Firebird::Decimal128*) p))
return FALSE;
break;
case dtype_int128:
if (!xdr_int128(xdrs, (Firebird::Int128*) p))
return FALSE;
break;
case dtype_timestamp:
if (!xdr_long(xdrs, &((SLONG*) p)[0]))
return FALSE;

View File

@ -3579,7 +3579,7 @@ rec_type get_data_old(BurpGlobals* tdgbl, burp_rel* relation)
case blr_long:
case blr_quad:
case blr_int64:
case blr_dec_fixed:
case blr_int128:
add_byte(blr, field->fld_type);
add_byte(blr, field->fld_scale);
break;

View File

@ -28,6 +28,7 @@
#include "firebird.h"
#include "DecFloat.h"
#include "Int128.h"
#include "StatusArg.h"
#include "gen/iberror.h"
@ -49,7 +50,7 @@ extern "C"
using namespace Firebird;
const DecimalStatus DecimalStatus::DEFAULT(FB_DEC_Errors);
const DecimalBinding DecimalBinding::DEFAULT;
const NumericBinding NumericBinding::DEFAULT;
namespace {
@ -77,7 +78,7 @@ public:
init(DEC_INIT_DECIMAL64);
}
DecimalContext(const Decimal128Base*, DecimalStatus ds)
DecimalContext(const Decimal128*, DecimalStatus ds)
: decSt(ds)
{
init(DEC_INIT_DECIMAL128);
@ -126,6 +127,8 @@ const CDecimal128 dmax(DBL_MAX, DecimalStatus(0)), dmin(-DBL_MAX, DecimalStatus(
const CDecimal128 dzup(DBL_MIN, DecimalStatus(0)), dzlw(-DBL_MIN, DecimalStatus(0));
const CDecimal128 i64max(MAX_SINT64, DecimalStatus(0)), i64min(MIN_SINT64, DecimalStatus(0));
const CDecimal128 c1(1);
const CDecimal128 pow2_32("4294967296", DecimalStatus(0));
const CDecimal128 pow2_64("18446744073709551616", DecimalStatus(0));
unsigned digits(const unsigned pMax, unsigned char* const coeff, int& exp)
{
@ -265,7 +268,7 @@ Decimal64 Decimal64::set(SLONG value, DecimalStatus decSt, int scale)
return *this;
}
Decimal64 Decimal64::set(DecimalFixed value, DecimalStatus decSt, int scale)
Decimal64 Decimal64::set(Int128 value, DecimalStatus decSt, int scale)
{
Decimal128 tmp;
tmp.set(value, decSt, scale);
@ -518,11 +521,21 @@ Decimal128 Decimal128::set(SLONG value, DecimalStatus decSt, int scale)
return *this;
}
Decimal128 Decimal128::set(DecimalFixed value, DecimalStatus decSt, int scale)
Decimal128 Decimal128::set(Int128 value, DecimalStatus decSt, int scale)
{
*this = value;
setScale(decSt, -scale);
unsigned dwords[4];
value.getTable32(dwords);
DecimalContext context(this, decSt);
decQuadFromInt32(&dec, dwords[3]);
for (int i = 3; i--; )
{
decQuad dw;
decQuadFromUInt32(&dw, dwords[i]);
decQuadFMA(&dec, &dec, &pow2_32.dec, &dw, &context);
}
setScale(decSt, -scale);
return *this;
}
@ -533,13 +546,10 @@ Decimal128 Decimal128::set(SINT64 value, DecimalStatus decSt, int scale)
unsigned low = value & 0xFFFFFFFF;
DecimalContext context(this, decSt);
decQuad pow2_32;
decQuadFromString(&pow2_32, "4294967296", &context);
decQuad up, down;
decQuadFromInt32(&up, high);
decQuadFromUInt32(&down, low);
decQuadFMA(&dec, &up, &pow2_32, &down, &context);
decQuadFMA(&dec, &up, &pow2_32.dec, &down, &context);
}
setScale(decSt, -scale);
@ -565,80 +575,6 @@ Decimal128 Decimal128::set(double value, DecimalStatus decSt)
return *this;
}
DecimalFixed DecimalFixed::set(SLONG value)
{
decQuadFromInt32(&dec, value);
return *this;
}
DecimalFixed DecimalFixed::set(SINT64 value)
{
int high = value >> 32;
unsigned low = value & 0xFFFFFFFF;
DecimalContext context(this, DecimalStatus(0));
decQuad pow2_32;
decQuadFromString(&pow2_32, "4294967296", &context);
decQuad up, down;
decQuadFromInt32(&up, high);
decQuadFromUInt32(&down, low);
decQuadFMA(&dec, &up, &pow2_32, &down, &context);
return *this;
}
DecimalFixed DecimalFixed::set(const char* value, int scale, DecimalStatus decSt)
{
{ // scope for 'context'
DecimalContext context(this, decSt);
decQuadFromString(&dec, value, &context);
}
exactInt(decSt, scale);
return *this;
}
DecimalFixed DecimalFixed::set(double value, int scale, DecimalStatus decSt)
{
char s[50];
sprintf(s, "%18.016e", value);
{ // scope for 'context'
DecimalContext context(this, decSt);
decQuadFromString(&dec, s, &context);
}
exactInt(decSt, scale);
return *this;
}
void DecimalFixed::exactInt(DecimalStatus decSt, int scale)
{
setScale(decSt, -scale);
try
{
DecimalContext context(this, decSt);
decQuadToIntegralExact(&dec, &dec, &context);
decQuadQuantize(&dec, &dec, &c1.dec, &context);
}
catch (const Exception& ex)
{
FbLocalStatus st;
ex.stuffException(&st);
switch (st->getErrors()[1])
{
case isc_decfloat_invalid_operation:
(Arg::Gds(isc_decfloat_invalid_operation) <<
Arg::Gds(isc_numeric_out_of_range)).raise();
break;
}
throw;
}
}
Decimal128 Decimal128::operator=(Decimal64 d64)
{
decDoubleToWider(&d64.dec, &dec);
@ -654,13 +590,6 @@ int Decimal128::toInteger(DecimalStatus decSt, int scale) const
return decQuadToInt32(&tmp.dec, &context, rMode);
}
int DecimalFixed::toInteger(DecimalStatus decSt) const
{
DecimalContext context(this, decSt);
enum rounding rMode = decContextGetRounding(&context);
return decQuadToInt32(&dec, &context, rMode);
}
void Decimal128::toString(DecimalStatus decSt, unsigned length, char* to) const
{
DecimalContext context(this, decSt);
@ -690,24 +619,7 @@ void Decimal128::toString(string& to) const
to.recalculate_length();
}
Decimal128 DecimalFixed::scaled128(DecimalStatus decSt, int scale) const
{
Decimal128 tmp;
tmp.set(*this, decSt, -scale);
return tmp;
}
void DecimalFixed::toString(DecimalStatus decSt, int scale, unsigned length, char* to) const
{
scaled128(decSt, scale).toString(decSt, length, to);
}
void DecimalFixed::toString(DecimalStatus decSt, int scale, string& to) const
{
scaled128(decSt, scale).toString(to);
}
double Decimal128Base::toDouble(DecimalStatus decSt) const
double Decimal128::toDouble(DecimalStatus decSt) const
{
DecimalContext context(this, decSt);
@ -764,37 +676,12 @@ SINT64 Decimal128::toInt64(DecimalStatus decSt, int scale) const
return rc;
}
SINT64 DecimalFixed::toInt64(DecimalStatus decSt) const
{
if (compare(decSt, i64min) < 0 || compare(decSt, i64max) > 0)
{
DecimalContext context(this, decSt);
decContextSetStatus(&context, DEC_Invalid_operation);
return 0; // in case of no trap on invalid operation
}
unsigned char coeff[DECQUAD_Pmax];
int sign = decQuadGetCoefficient(&dec, coeff);
SINT64 rc = 0;
for (int i = 0; i < DECQUAD_Pmax; ++i)
{
rc *= 10;
if (sign)
rc -= coeff[i];
else
rc += coeff[i];
}
return rc;
}
UCHAR* Decimal128Base::getBytes()
UCHAR* Decimal128::getBytes()
{
return dec.bytes;
}
Decimal64 Decimal128Base::toDecimal64(DecimalStatus decSt) const
Decimal64 Decimal128::toDecimal64(DecimalStatus decSt) const
{
Decimal64 rc;
DecimalContext context(this, decSt);
@ -802,7 +689,7 @@ Decimal64 Decimal128Base::toDecimal64(DecimalStatus decSt) const
return rc;
}
void Decimal128Base::setScale(DecimalStatus decSt, int scale)
void Decimal128::setScale(DecimalStatus decSt, int scale)
{
if (scale)
{
@ -812,7 +699,7 @@ void Decimal128Base::setScale(DecimalStatus decSt, int scale)
}
}
int Decimal128Base::compare(DecimalStatus decSt, Decimal128Base tgt) const
int Decimal128::compare(DecimalStatus decSt, Decimal128 tgt) const
{
DecimalContext context(this, decSt);
decQuad r;
@ -820,7 +707,7 @@ int Decimal128Base::compare(DecimalStatus decSt, Decimal128Base tgt) const
return decQuadToInt32(&r, &context, DEC_ROUND_HALF_UP);
}
bool Decimal128Base::isInf() const
bool Decimal128::isInf() const
{
switch(decQuadClass(&dec))
{
@ -832,7 +719,7 @@ bool Decimal128Base::isInf() const
return false;
}
bool Decimal128Base::isNan() const
bool Decimal128::isNan() const
{
switch(decQuadClass(&dec))
{
@ -844,7 +731,7 @@ bool Decimal128Base::isNan() const
return false;
}
int Decimal128Base::sign() const
int Decimal128::sign() const
{
if (decQuadIsZero(&dec))
return 0;
@ -870,7 +757,7 @@ Decimal128 Decimal128::floor(DecimalStatus decSt) const
}
#ifdef DEV_BUILD
int Decimal128Base::show()
int Decimal128::show()
{
decQuadShow(&dec, "");
return 0;
@ -915,50 +802,6 @@ Decimal128 Decimal128::mul(DecimalStatus decSt, Decimal128 op2) const
return rc;
}
DecimalFixed DecimalFixed::abs() const
{
DecimalFixed rc;
decQuadCopyAbs(&rc.dec, &dec);
return rc;
}
DecimalFixed DecimalFixed::neg() const
{
DecimalFixed rc;
decQuadCopyNegate(&rc.dec, &dec);
return rc;
}
DecimalFixed DecimalFixed::add(DecimalStatus decSt, DecimalFixed op2) const
{
DecimalContext context(this, decSt);
DecimalFixed rc;
decQuadAdd(&rc.dec, &dec, &op2.dec, &context);
context.checkForExceptions();
decQuadQuantize(&rc.dec, &rc.dec, &c1.dec, &context);
return rc;
}
DecimalFixed DecimalFixed::sub(DecimalStatus decSt, DecimalFixed op2) const
{
DecimalContext context(this, decSt);
DecimalFixed rc;
decQuadSubtract(&rc.dec, &dec, &op2.dec, &context);
context.checkForExceptions();
decQuadQuantize(&rc.dec, &rc.dec, &c1.dec, &context);
return rc;
}
DecimalFixed DecimalFixed::mul(DecimalStatus decSt, DecimalFixed op2) const
{
DecimalContext context(this, decSt);
DecimalFixed rc;
decQuadMultiply(&rc.dec, &dec, &op2.dec, &context);
context.checkForExceptions();
decQuadQuantize(&rc.dec, &rc.dec, &c1.dec, &context);
return rc;
}
Decimal128 Decimal128::div(DecimalStatus decSt, Decimal128 op2) const
{
DecimalContext context(this, decSt);
@ -967,27 +810,6 @@ Decimal128 Decimal128::div(DecimalStatus decSt, Decimal128 op2) const
return rc;
}
DecimalFixed DecimalFixed::div(DecimalStatus decSt, DecimalFixed op2, int scale) const
{
DecimalContext context(this, decSt);
DecimalFixed rc;
// first divide with full decfloat precision
decQuadDivide(&rc.dec, &dec, &op2.dec, &context);
// next re-scale & int-ize
rc.exactInt(decSt, scale);
return rc;
}
DecimalFixed DecimalFixed::mod(DecimalStatus decSt, DecimalFixed op2) const
{
DecimalContext context(this, decSt);
DecimalFixed rc;
decQuadRemainder(&rc.dec, &dec, &op2.dec, &context);
return rc;
}
Decimal128 Decimal128::fma(DecimalStatus decSt, Decimal128 op2, Decimal128 op3) const
{
DecimalContext context(this, decSt);
@ -1049,7 +871,7 @@ Decimal128 Decimal128::log10(DecimalStatus decSt) const
return rc;
}
void Decimal128Base::makeKey(ULONG* key) const
void Decimal128::makeKey(ULONG* key) const
{
unsigned char coeff[DECQUAD_Pmax];
int sign = decQuadGetCoefficient(&dec, coeff);
@ -1058,7 +880,7 @@ void Decimal128Base::makeKey(ULONG* key) const
make(key, DECQUAD_Pmax, DECQUAD_Bias, sizeof(dec), coeff, sign, exp);
}
void Decimal128Base::grabKey(ULONG* key)
void Decimal128::grabKey(ULONG* key)
{
int exp, sign;
unsigned char bcd[DECQUAD_Pmax];
@ -1068,12 +890,12 @@ void Decimal128Base::grabKey(ULONG* key)
decQuadFromBCD(&dec, exp, bcd, sign);
}
ULONG Decimal128Base::getIndexKeyLength()
ULONG Decimal128::getIndexKeyLength()
{
return 17;
}
ULONG Decimal128Base::makeIndexKey(vary* buf)
ULONG Decimal128::makeIndexKey(vary* buf)
{
unsigned char coeff[DECQUAD_Pmax + 2];
int sign = decQuadGetCoefficient(&dec, coeff);
@ -1207,4 +1029,9 @@ short Decimal128::decCompare(Decimal128 op2) const
return 3;
}
void Decimal128::getBcd(BCD* bcd) const
{
bcd->sign = decQuadToBCD(&dec, &bcd->exp, bcd->bcd);
}
} // namespace Firebird

View File

@ -115,27 +115,27 @@ struct DecimalStatus
USHORT decExtFlag, roundingMode;
};
struct DecimalBinding
struct NumericBinding
{
enum Bind
{
DEC_NATIVE,
DEC_TEXT,
DEC_DOUBLE,
DEC_NUMERIC
NUM_NATIVE,
NUM_TEXT,
NUM_DOUBLE,
NUM_INT64
};
DecimalBinding()
: bind(DEC_NATIVE),
NumericBinding()
: bind(NUM_NATIVE),
numScale(0)
{}
DecimalBinding(Bind aBind, SCHAR aNumScale = 0)
NumericBinding(Bind aBind, SCHAR aNumScale = 0)
: bind(aBind),
numScale(aNumScale)
{}
static const DecimalBinding DEFAULT;
static const NumericBinding DEFAULT;
static const SCHAR MAX_SCALE = 18;
Bind bind;
@ -143,13 +143,11 @@ struct DecimalBinding
};
class DecimalFixed;
class Int128;
class Decimal64
{
friend class Decimal128;
friend class DecimalFixed;
friend class Decimal128Base;
public:
#if SIZEOF_LONG < 8
@ -159,7 +157,7 @@ public:
Decimal64 set(SINT64 value, DecimalStatus decSt, int scale);
Decimal64 set(const char* value, DecimalStatus decSt);
Decimal64 set(double value, DecimalStatus decSt);
Decimal64 set(DecimalFixed value, DecimalStatus decSt, int scale);
Decimal64 set(Int128 value, DecimalStatus decSt, int scale);
UCHAR* getBytes();
Decimal64 abs() const;
@ -193,38 +191,7 @@ private:
decDouble dec;
};
class Decimal128Base
{
friend class Decimal128;
friend class DecimalFixed;
public:
double toDouble(DecimalStatus decSt) const;
Decimal64 toDecimal64(DecimalStatus decSt) const;
UCHAR* getBytes();
int compare(DecimalStatus decSt, Decimal128Base tgt) const;
void setScale(DecimalStatus decSt, int scale);
bool isInf() const;
bool isNan() const;
int sign() const;
void makeKey(ULONG* key) const;
void grabKey(ULONG* key);
static ULONG getIndexKeyLength();
ULONG makeIndexKey(vary* buf);
#ifdef DEV_BUILD
int show();
#endif
private:
decQuad dec;
};
class Decimal128 : public Decimal128Base
class Decimal128
{
friend class Decimal64;
@ -237,7 +204,7 @@ public:
Decimal128 set(SINT64 value, DecimalStatus decSt, int scale);
Decimal128 set(const char* value, DecimalStatus decSt);
Decimal128 set(double value, DecimalStatus decSt);
Decimal128 set(DecimalFixed value, DecimalStatus decSt, int scale);
Decimal128 set(Int128 value, DecimalStatus decSt, int scale);
Decimal128 operator=(Decimal64 d64);
@ -265,12 +232,37 @@ public:
short totalOrder(Decimal128 op2) const;
short decCompare(Decimal128 op2) const;
private:
Decimal128 operator=(Decimal128Base d128b)
double toDouble(DecimalStatus decSt) const;
Decimal64 toDecimal64(DecimalStatus decSt) const;
UCHAR* getBytes();
int compare(DecimalStatus decSt, Decimal128 tgt) const;
void setScale(DecimalStatus decSt, int scale);
bool isInf() const;
bool isNan() const;
int sign() const;
void makeKey(ULONG* key) const;
void grabKey(ULONG* key);
static ULONG getIndexKeyLength();
ULONG makeIndexKey(vary* buf);
#ifdef DEV_BUILD
int show();
#endif
struct BCD
{
memcpy(&dec, &d128b.dec, sizeof(dec));
return *this;
}
int sign, exp;
unsigned char bcd[DECQUAD_Pmax];
};
void getBcd(BCD* bcd) const;
private:
decQuad dec;
};
class CDecimal128 : public Decimal128
@ -290,45 +282,11 @@ public:
{
set(value, DecimalStatus(0), 0);
}
};
class DecimalFixed : public Decimal128Base
{
public:
#if SIZEOF_LONG < 8
DecimalFixed set(int value)
CDecimal128(const char* value, DecimalStatus decSt)
{
return set(SLONG(value));
set(value, decSt);
}
#endif
DecimalFixed set(SLONG value);
DecimalFixed set(SINT64 value);
DecimalFixed set(const char* value, int scale, DecimalStatus decSt);
DecimalFixed set(double value, int scale, DecimalStatus decSt);
int toInteger(DecimalStatus decSt) const;
SINT64 toInt64(DecimalStatus decSt) const;
void toString(DecimalStatus decSt, int scale, unsigned length, char* to) const;
void toString(DecimalStatus decSt, int scale, string& to) const;
DecimalFixed abs() const;
DecimalFixed neg() const;
DecimalFixed add(DecimalStatus decSt, DecimalFixed op2) const;
DecimalFixed sub(DecimalStatus decSt, DecimalFixed op2) const;
DecimalFixed mul(DecimalStatus decSt, DecimalFixed op2) const;
DecimalFixed div(DecimalStatus decSt, DecimalFixed op2, int scale) const;
DecimalFixed mod(DecimalStatus decSt, DecimalFixed op2) const;
DecimalFixed operator=(Decimal128Base d128b)
{
memcpy(&dec, &d128b.dec, sizeof(dec));
return *this;
}
void exactInt(DecimalStatus decSt, int scale); // rescale & make it integer after conversions
private:
Decimal128 scaled128(DecimalStatus decSt, int scale) const;
};
} // namespace Firebird

492
src/common/Int128.cpp Normal file
View File

@ -0,0 +1,492 @@
/*
* PROGRAM: Integer 128 type.
* MODULE: Int128.cpp
* DESCRIPTION: Big integer support.
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2019 Alex Peshkov <peshkoff at mail dot ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#include "firebird.h"
#include "Int128.h"
#include "StatusArg.h"
#include "gen/iberror.h"
#include "status.h"
#include "DecFloat.h"
#include <limits>
#include <stdlib.h>
#include <string.h>
#include <float.h>
using namespace Firebird;
namespace {
const CInt128 i64max(MAX_SINT64), i64min(MIN_SINT64);
const double p2_32 = 4294967296.0;
const I128limit i128limit;
const CInt128 minus1(-1);
} // anonymous namespace
namespace Firebird {
Int128 Int128::set(SLONG value, int scale)
{
v = value;
setScale(scale);
return *this;
}
Int128 Int128::set(SINT64 value, int scale)
{
#ifdef TTMATH_PLATFORM32
v = ttmath::slint(value);
#else
v = ttmath::sint(value);
#endif
setScale(scale);
return *this;
}
Int128 Int128::set(const char* value)
{
// This is simplified method - it does not perform all what's needed for CVT_decompose
v.FromString(value);
return *this;
}
Int128 Int128::set(double value)
{
bool sgn = false;
if (value < 0.0)
{
value = -value;
sgn = true;
}
double parts[4];
for (int i = 0; i < 4; ++i)
{
parts[i] = value;
value /= p2_32;
}
fb_assert(value < 1.0);
unsigned dwords[4];
value = 0.0;
for (int i = 4; i--;)
{
dwords[i] = (parts[i] - value);
value += p2_32 * dwords[i];
}
setTable32(dwords);
if (sgn)
v.ChangeSign();
return *this;
}
Int128 Int128::set(DecimalStatus decSt, Decimal128 value)
{
static CDecimal128 quant(1);
value = value.quantize(decSt, quant);
Decimal128::BCD bcd;
value.getBcd(&bcd);
fb_assert(bcd.exp == 0);
v.SetZero();
for (unsigned b = 0; b < sizeof(bcd.bcd); ++b)
{
v.MulInt(10);
v.AddInt(bcd.bcd[b]);
}
if (bcd.sign < 0)
v.ChangeSign();
return *this;
}
void Int128::setScale(int scale)
{
if (scale > 0)
{
ttmath::sint rem = 0;
while (scale--)
v.DivInt(10, scale == 0 ? &rem : nullptr);
if (rem > 4)
v++;
else if (rem < -4)
v--;
}
else if (scale < 0)
{
while (scale++) {
if (v > i128limit.v || v < -i128limit.v)
(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)).raise();
v.MulInt(10);
}
}
}
int Int128::toInteger(int scale) const
{
Int128 tmp(*this);
tmp.setScale(scale);
int rc;
if (tmp.v.ToInt(rc))
overflow();
return rc;
}
void Int128::toString(int scale, unsigned length, char* to) const
{
string buffer;
toString(scale, buffer);
if (buffer.length() + 1 > length)
{
(Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) <<
Arg::Gds(isc_trunc_limits) << Arg::Num(length) << Arg::Num(buffer.length() + 1)).raise();
}
buffer.copyTo(to, length);
}
void Int128::toString(int scale, string& to) const
{
v.ToStringBase(to);
bool sgn = to[0] == '-';
if (sgn)
to.erase(0, 1);
if (scale)
{
if (scale < -38 || scale > 4)
{
string tmp;
tmp.printf("E%d", scale);
to += tmp;
}
else if (scale > 0)
{
string tmp(scale, '0');
to += tmp;
}
else
{
unsigned posScale = -scale;
if (posScale > to.length())
{
string tmp(posScale - to.length(), '0');
to.insert(0, tmp);
}
if (posScale == to.length())
{
to.insert(0, "0.");
}
else
to.insert(to.length() - posScale, ".");
}
}
if (sgn)
to.insert(0, "-");
}
SINT64 Int128::toInt64(int scale) const
{
Int128 tmp(*this);
tmp.setScale(scale);
if (tmp.v < i64min.v || tmp.v > i64max.v)
overflow();
unsigned dwords[4];
tmp.getTable32(dwords);
SINT64 rc = int(dwords[1]);
rc <<= 32;
rc += dwords[0];
return rc;
}
double Int128::toDouble() const
{
unsigned dwords[4];
getTable32(dwords);
double rc = int(dwords[3]);
for (int i = 3; i--;)
{
rc *= p2_32;
rc += dwords[i];
}
return rc;
}
int Int128::compare(Int128 tgt) const
{
return v < tgt.v ? -1 : v > tgt.v ? 1 : 0;
}
Int128 Int128::abs() const
{
Int128 rc(*this);
if (rc.v.Abs())
overflow();
return rc;
}
Int128 Int128::neg() const
{
Int128 rc(*this);
if (rc.v.ChangeSign())
overflow();
return rc;
}
Int128 Int128::add(Int128 op2) const
{
Int128 rc(*this);
if (rc.v.Add(op2.v))
overflow();
return rc;
}
Int128 Int128::sub(Int128 op2) const
{
Int128 rc(*this);
if (rc.v.Sub(op2.v))
overflow();
return rc;
}
Int128 Int128::mul(Int128 op2) const
{
Int128 rc(*this);
if (rc.v.Mul(op2.v))
overflow();
return rc;
}
Int128 Int128::div(Int128 op2, int scale) const
{
if (compare(MIN_Int128) == 0 && op2.compare(minus1) == 0)
Arg::Gds(isc_exception_integer_overflow).raise();
static const CInt128 MIN_BY10(MIN_Int128 / 10);
static const CInt128 MAX_BY10(MAX_Int128 / 10);
// Scale op1 by as many of the needed powers of 10 as possible without an overflow.
CInt128 op1(*this);
int sign1 = op1.sign();
while ((scale < 0) && (sign1 >= 0 ? op1.compare(MAX_BY10) <= 0 : op1.compare(MIN_BY10) >= 0))
{
op1 *= 10;
++scale;
}
// Scale op2 shifting it to the right as long as only zeroes are thrown away.
CInt128 tmp(op2);
while (scale < 0)
{
ttmath::sint rem = 0;
tmp.v.DivInt(10, &rem);
if (rem)
break;
op2 = tmp;
++scale;
}
if (op1.v.Div(op2.v))
zerodivide();
op1.setScale(scale);
return op1;
}
Int128 Int128::mod(Int128 op2) const
{
Int128 tmp(*this);
Int128 rc;
if (tmp.v.Div(op2.v, rc.v))
zerodivide();
return rc;
}
int Int128::sign() const
{
return v.IsSign() ? -1 : v.IsZero() ? 0 : 1;
}
UCHAR* Int128::getBytes()
{
return (UCHAR*)(v.table);
}
void Int128::getTable32(unsigned* dwords) const
{
static_assert((sizeof(v.table[0]) == 4) || (sizeof(v.table[0]) == 8),
"Unsupported size of integer in ttmath");
if (sizeof(v.table[0]) == 4)
{
for (int i = 0; i < 4; ++i)
dwords[i] = v.table[i];
}
else if (sizeof(v.table[0]) == 8)
{
for (int i = 0; i < 2; ++i)
{
dwords[i * 2] = v.table[i] & 0xFFFFFFFF;
dwords[i * 2 + 1] = (v.table[i] >> 32) & 0xFFFFFFFF;
}
}
}
void Int128::setTable32(const unsigned* dwords)
{
static_assert((sizeof(v.table[0]) == 4) || (sizeof(v.table[0]) == 8),
"Unsupported size of integer in ttmath");
if (sizeof(v.table[0]) == 4)
{
for (int i = 0; i < 4; ++i)
v.table[i] = dwords[i];
}
else if (sizeof(v.table[0]) == 8)
{
for (int i = 0; i < 2; ++i)
{
v.table[i] = dwords[i * 2 + 1];
v.table[i] <<= 32;
v.table[i] += dwords[i * 2];
}
}
}
Int128 Int128::operator&=(FB_UINT64 mask)
{
v.table[0] &= mask;
unsigned i = 1;
if (sizeof(v.table[0]) == 4)
{
i = 2;
v.table[1] &= (mask >> 32);
}
for (; i < FB_NELEM(v.table); ++i)
v.table[i] = 0;
return *this;
}
Int128 Int128::operator&=(ULONG mask)
{
v.table[0] &= mask;
for (unsigned i = 1; i < FB_NELEM(v.table); ++i)
v.table[i] = 0;
return *this;
}
Int128 Int128::operator/(unsigned value) const
{
Int128 rc;
rc.v.DivInt(value);
return rc;
}
Int128 Int128::operator-() const
{
return neg();
}
Int128 Int128::operator+=(unsigned value)
{
v.AddInt(value);
return *this;
}
Int128 Int128::operator*=(unsigned value)
{
v.MulInt(value);
return *this;
}
bool Int128::operator>(Int128 value) const
{
return v > value.v;
}
bool Int128::operator==(Int128 value) const
{
return v == value.v;
}
void Int128::zerodivide()
{
(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_integer_divide_by_zero)).raise();
}
void Int128::overflow()
{
(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_integer_overflow)).raise();
}
#ifdef DEV_BUILD
const char* Int128::show()
{
static char to[64];
toString(0, sizeof(to), to);
return to;
}
#endif
CInt128::CInt128(SINT64 value)
{
set(value, 0);
}
CInt128::CInt128(minmax mm)
{
switch(mm)
{
case MkMax:
v.SetMax();
break;
case MkMin:
v.SetMin();
break;
}
}
CInt128 MIN_Int128(CInt128::MkMin);
CInt128 MAX_Int128(CInt128::MkMax);
} // namespace Firebird

147
src/common/Int128.h Normal file
View File

@ -0,0 +1,147 @@
/*
* PROGRAM: Integer 128 type.
* MODULE: Int128.h
* DESCRIPTION: Big integer support.
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2019 Alex Peshkov <peshkoff at mail dot ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#ifndef FB_INT128
#define FB_INT128
#include "firebird/Interface.h"
#include "fb_exception.h"
#include <string.h>
#include "classes/fb_string.h"
#include "classes/MetaName.h"
#include "../../extern/ttmath/ttmath.h"
namespace Firebird {
class Decimal64;
class Decimal128;
struct DecimalStatus;
class Int128 //: public Decimal128Base
{
public:
#if SIZEOF_LONG < 8
Int128 set(int value)
{
return set(SLONG(value));
}
#endif
Int128 set(SLONG value, int scale);
Int128 set(SINT64 value, int scale);
Int128 set(double value);
Int128 set(DecimalStatus decSt, Decimal128 value);
Int128 set(Int128 value)
{
v = value.v;
return *this;
}
Int128 operator=(SINT64 value)
{
set(value, 0);
return *this;
}
#ifdef DEV_BUILD
const char* show();
#endif
int toInteger(int scale) const;
SINT64 toInt64(int scale) const;
void toString(int scale, unsigned length, char* to) const;
void toString(int scale, string& to) const;
double toDouble() const;
Int128 operator&=(FB_UINT64 mask);
Int128 operator&=(ULONG mask);
Int128 operator-() const;
Int128 operator/(unsigned value) const;
Int128 operator+=(unsigned value);
Int128 operator*=(unsigned value);
int compare(Int128 tgt) const;
bool operator>(Int128 value) const;
bool operator==(Int128 value) const;
int sign() const;
Int128 abs() const;
Int128 neg() const;
Int128 add(Int128 op2) const;
Int128 sub(Int128 op2) const;
Int128 mul(Int128 op2) const;
Int128 div(Int128 op2, int scale) const;
Int128 mod(Int128 op2) const;
void getTable32(unsigned* dwords) const; // internal data in per-32bit form
void setTable32(const unsigned* dwords);
void setScale(int scale);
UCHAR* getBytes();
protected:
ttmath::Int<TTMATH_BITS(128)> v;
static void overflow();
static void zerodivide();
Int128 set(const char* value);
};
class CInt128 : public Int128
{
public:
enum minmax {MkMax, MkMin};
CInt128(SINT64 value);
CInt128(minmax mm);
CInt128(const Int128& value)
{
set(value);
}
};
extern CInt128 MAX_Int128, MIN_Int128;
class I128limit : public Int128
{
public:
I128limit()
{
v.SetOne();
for (int i = 0; i < 126; ++i)
v.MulInt(2);
v.DivInt(5);
}
};
} // namespace Firebird
#endif // FB_INT128

View File

@ -192,9 +192,9 @@ MetadataFromBlr::MetadataFromBlr(unsigned aBlrLength, const unsigned char* aBlr,
item->length = sizeof(Decimal128);
break;
case blr_dec_fixed:
item->type = SQL_DEC_FIXED;
item->length = sizeof(DecimalFixed);
case blr_int128:
item->type = SQL_INT128;
item->length = sizeof(Int128);
item->scale = rdr.getByte();
break;

View File

@ -504,7 +504,10 @@ namespace Firebird
memset(baseInsert(p0, n), c, n);
return *this;
}
// iterator insert(iterator it, char_type c); // what to return here?
void insert(iterator it, char_type c)
{
insert(it - c_str(), 1, c);
}
void insert(iterator it, size_type n, char_type c)
{
insert(it - c_str(), n, c);
@ -519,6 +522,11 @@ namespace Firebird
baseErase(p0, n);
return *this;
}
AbstractString& clear() throw()
{
erase();
return *this;
}
iterator erase(iterator it) throw()
{
erase(it - c_str(), 1);

View File

@ -133,7 +133,7 @@ static void datetime_to_text(const dsc*, dsc*, Callbacks*);
static void float_to_text(const dsc*, dsc*, Callbacks*);
static void decimal_float_to_text(const dsc*, dsc*, DecimalStatus, Callbacks*);
static void integer_to_text(const dsc*, dsc*, Callbacks*);
static SINT64 hex_to_value(const char*& string, const char* end);
static void int128_to_text(const dsc*, dsc*, Callbacks* cb);
static void localError(const Firebird::Arg::StatusVector&);
class DummyException {};
@ -305,7 +305,35 @@ static void decimal_float_to_text(const dsc* from, dsc* to, DecimalStatus decSt,
else if (from->dsc_dtype == dtype_dec128)
((Decimal128*) from->dsc_address)->toString(decSt, sizeof(temp), temp);
else
((DecimalFixed*) from->dsc_address)->toString(decSt, from->dsc_scale, sizeof(temp), temp);
fb_assert(false);
}
catch (const Exception& ex)
{
// reraise using function passed in callbacks
Arg::StatusVector v(ex);
cb->err(v);
}
dsc intermediate;
intermediate.dsc_dtype = dtype_text;
intermediate.dsc_ttype() = ttype_ascii;
intermediate.dsc_address = reinterpret_cast<UCHAR*>(temp);
intermediate.dsc_length = strlen(temp);
CVT_move_common(&intermediate, to, 0, cb);
}
static void int128_to_text(const dsc* from, dsc* to, Callbacks* cb)
{
char temp[50];
try
{
if (from->dsc_dtype == dtype_int128)
((Int128*) from->dsc_address)->toString(from->dsc_scale, sizeof(temp), temp);
else
fb_assert(false);
}
catch (const Exception& ex)
{
@ -1070,9 +1098,8 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
return d128.toInteger(decSt, scale);
case dtype_dec_fixed:
value = ((DecimalFixed*) p)->toInteger(decSt);
break;
case dtype_int128:
return ((Int128*) p)->toInteger(scale);
case dtype_real:
case dtype_double:
@ -1121,7 +1148,7 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
{
USHORT length =
CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err);
scale -= CVT_decompose(p, length, dtype_long, &value, err);
scale -= CVT_decompose(p, length, &value, err);
}
break;
@ -1274,8 +1301,8 @@ double CVT_get_double(const dsc* desc, DecimalStatus decSt, ErrorFunction err, b
return d128.toDouble(decSt);
}
case dtype_dec_fixed:
value = ((DecimalFixed*) desc->dsc_address)->toDouble(decSt);
case dtype_int128:
value = ((Int128*) desc->dsc_address)->toDouble();
break;
case dtype_varying:
@ -1578,7 +1605,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_boolean:
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
CVT_conversion_error(from, cb->err);
break;
}
@ -1629,7 +1656,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_boolean:
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
CVT_conversion_error(from, cb->err);
break;
}
@ -1671,7 +1698,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_boolean:
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
CVT_conversion_error(from, cb->err);
break;
}
@ -1716,7 +1743,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_boolean:
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
CVT_conversion_error(from, cb->err);
break;
}
@ -1763,7 +1790,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_boolean:
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
CVT_conversion_error(from, cb->err);
break;
}
@ -1946,6 +1973,10 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
integer_to_text(from, to, cb);
return;
case dtype_int128:
int128_to_text(from, to, cb);
return;
case dtype_real:
case dtype_double:
float_to_text(from, to, cb);
@ -1953,7 +1984,6 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
decimal_float_to_text(from, to, decSt, cb);
return;
@ -2082,8 +2112,8 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
*((Decimal128*) p) = CVT_get_dec128(from, decSt, cb->err);
return;
case dtype_dec_fixed:
*((DecimalFixed*) p) = CVT_get_dec_fixed(from, (SSHORT) to->dsc_scale, decSt, cb->err);
case dtype_int128:
*((Int128*) p) = CVT_get_int128(from, (SSHORT) to->dsc_scale, decSt, cb->err);
return;
case dtype_boolean:
@ -2108,7 +2138,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
case dtype_double:
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
CVT_conversion_error(from, cb->err);
break;
}
@ -2494,11 +2524,28 @@ double CVT_power_of_ten(const int scale)
}
SSHORT CVT_decompose(const char* string,
USHORT length,
SSHORT dtype,
SLONG* return_value,
ErrorFunction err)
class RetPtr
{
public:
virtual ~RetPtr() { }
enum lb10 {RETVAL_OVERFLOW, RETVAL_POSSIBLE_OVERFLOW, RETVAL_NO_OVERFLOW};
virtual USHORT maxSize() = 0;
virtual void truncate8() = 0;
virtual void truncate16() = 0;
virtual lb10 compareLimitBy10() = 0;
virtual void nextDigit(unsigned digit, unsigned base) = 0;
virtual bool isLowerLimit() = 0;
virtual void neg() = 0;
};
static void hex_to_value(const char*& string, const char* end, RetPtr* retValue);
static SSHORT cvt_decompose(const char* string,
USHORT length,
RetPtr* return_value,
ErrorFunction err)
{
/**************************************
*
@ -2512,15 +2559,6 @@ SSHORT CVT_decompose(const char* string,
*
**************************************/
// For now, this routine does not handle quadwords unless this is
// supported by the platform as a native datatype.
if (dtype == dtype_quad)
{
fb_assert(false);
err(Arg::Gds(isc_badblk)); // internal error
}
dsc errd;
MOVE_CLEAR(&errd, sizeof(errd));
errd.dsc_dtype = dtype_text;
@ -2528,14 +2566,9 @@ SSHORT CVT_decompose(const char* string,
errd.dsc_length = length;
errd.dsc_address = reinterpret_cast<UCHAR*>(const_cast<char*>(string));
SINT64 value = 0;
SSHORT scale = 0;
int sign = 0;
bool digit_seen = false, fraction = false;
const SINT64 lower_limit = (dtype == dtype_long) ? MIN_SLONG : MIN_SINT64;
const SINT64 upper_limit = (dtype == dtype_long) ? MAX_SLONG : MAX_SINT64;
const SINT64 limit_by_10 = upper_limit / 10; // used to check for overflow
const char* p = string;
const char* end = p + length;
@ -2561,28 +2594,20 @@ SSHORT CVT_decompose(const char* string,
while (q < end && *q == ' ')
q++;
if (q != end || end - p == 0 || end - p > 16)
if (q != end || end - p == 0 || end - p > return_value->maxSize())
CVT_conversion_error(&errd, err);
q = p;
value = hex_to_value(q, digits_end);
hex_to_value(q, digits_end, return_value);
if (q != digits_end)
CVT_conversion_error(&errd, err);
// 0xFFFFFFFF = -1; 0x0FFFFFFFF = 4294967295
if (digits_end - p <= 8)
value = (SLONG) value;
if (dtype == dtype_long)
{
if (value < LONG_MIN_int64 || value > LONG_MAX_int64)
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
*return_value = (SLONG) value;
}
else
*((SINT64*) return_value) = value;
return_value->truncate8();
else if (digits_end - p <= 16)
return_value->truncate16();
return 0; // 0 scale for hex literals
}
@ -2598,20 +2623,33 @@ SSHORT CVT_decompose(const char* string,
// tricky: the value doesn't always become negative after an
// overflow!
if (value >= limit_by_10)
switch(return_value->compareLimitBy10())
{
// possibility of an overflow
if (value > limit_by_10)
{
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
}
else if ((*p > '8' && sign == -1) || (*p > '7' && sign != -1))
case RetPtr::RETVAL_OVERFLOW:
if (fraction)
{
while (p < end)
{
if (*p != '0')
break;
++p;
}
if (p >= end)
continue;
}
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
break;
case RetPtr::RETVAL_POSSIBLE_OVERFLOW:
if ((*p > '8' && sign == -1) || (*p > '7' && sign != -1))
{
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
}
break;
default:
break;
}
value = value * 10 + *p - '0';
return_value->nextDigit(*p - '0', 10);
if (fraction)
--scale;
}
@ -2645,8 +2683,8 @@ SSHORT CVT_decompose(const char* string,
if (!digit_seen)
CVT_conversion_error(&errd, err);
if ((sign == -1) && value != lower_limit)
value = -value;
if ((sign == -1) && !return_value->isLowerLimit())
return_value->neg();
// If there's still something left, there must be an explicit exponent
if (p < end)
@ -2693,18 +2731,160 @@ SSHORT CVT_decompose(const char* string,
if (!digit_seen)
CVT_conversion_error(&errd, err);
}
if (dtype == dtype_long)
*return_value = (SLONG) value;
else
*((SINT64 *) return_value) = value;
return scale;
}
template <class Traits>
class RetValue : public RetPtr
{
public:
RetValue(typename Traits::ValueType* ptr)
: return_value(ptr)
{
value = 0;
}
~RetValue()
{
*return_value = value;
}
USHORT maxSize()
{
return sizeof(typename Traits::ValueType);
}
void truncate8()
{
ULONG mask = 0xFFFFFFFF;
value &= mask;
}
void truncate16()
{
FB_UINT64 mask = 0xFFFFFFFFFFFFFFFF;
value &= mask;
}
lb10 compareLimitBy10()
{
if (value > Traits::UPPER_LIMIT / 10)
return RETVAL_OVERFLOW;
if (value == Traits::UPPER_LIMIT / 10)
return RETVAL_POSSIBLE_OVERFLOW;
return RETVAL_NO_OVERFLOW;
}
void nextDigit(unsigned digit, unsigned base)
{
value *= base;
value += digit;
}
bool isLowerLimit()
{
return value == Traits::LOWER_LIMIT;
}
void neg()
{
value = -value;
}
private:
typename Traits::ValueType value;
typename Traits::ValueType* return_value;
};
class SLONGTraits
{
public:
typedef SLONG ValueType;
static const SLONG UPPER_LIMIT = MAX_SLONG;
static const SLONG LOWER_LIMIT = MIN_SLONG;
};
SSHORT CVT_decompose(const char* str, USHORT len, SLONG* val, ErrorFunction err)
{
/**************************************
*
* d e c o m p o s e
*
**************************************
*
* Functional description
* Decompose a numeric string in mantissa and exponent,
* or if it is in hexadecimal notation.
*
**************************************/
RetValue<SLONGTraits> value(val);
return cvt_decompose(str, len, &value, err);
}
class SINT64Traits
{
public:
typedef SINT64 ValueType;
static const SINT64 UPPER_LIMIT = MAX_SINT64;
static const SINT64 LOWER_LIMIT = MIN_SINT64;
};
SSHORT CVT_decompose(const char* str, USHORT len, SINT64* val, ErrorFunction err)
{
/**************************************
*
* d e c o m p o s e
*
**************************************
*
* Functional description
* Decompose a numeric string in mantissa and exponent,
* or if it is in hexadecimal notation.
*
**************************************/
RetValue<SINT64Traits> value(val);
return cvt_decompose(str, len, &value, err);
}
class I128Traits
{
public:
typedef Int128 ValueType;
static const CInt128 UPPER_LIMIT;
static const CInt128 LOWER_LIMIT;
};
const CInt128 I128Traits::UPPER_LIMIT(MAX_Int128);
const CInt128 I128Traits::LOWER_LIMIT(MIN_Int128);
SSHORT CVT_decompose(const char* str, USHORT len, Int128* val, ErrorFunction err)
{
/**************************************
*
* d e c o m p o s e
*
**************************************
*
* Functional description
* Decompose a numeric string in mantissa and exponent,
* or if it is in hexadecimal notation.
*
**************************************/
RetValue<I128Traits> value(val);
return cvt_decompose(str, len, &value, err);
}
USHORT CVT_get_string_ptr_common(const dsc* desc, USHORT* ttype, UCHAR** address,
vary* temp, USHORT length, DecimalStatus decSt, Callbacks* cb)
{
@ -2851,10 +3031,10 @@ Decimal64 CVT_get_dec64(const dsc* desc, DecimalStatus decSt, ErrorFunction err)
return *(Decimal64*) p;
case dtype_dec128:
return ((Decimal128Base*) p)->toDecimal64(decSt);
return ((Decimal128*) p)->toDecimal64(decSt);
case dtype_dec_fixed:
return d64.set(*((DecimalFixed*) p), decSt, scale);
case dtype_int128:
return d64.set(*((Int128*) p), decSt, scale);
default:
fb_assert(false);
@ -2940,8 +3120,8 @@ Decimal128 CVT_get_dec128(const dsc* desc, DecimalStatus decSt, ErrorFunction er
case dtype_dec128:
return *(Decimal128*) p;
case dtype_dec_fixed:
return d128.set(*((DecimalFixed*) p), decSt, scale);
case dtype_int128:
return d128.set(*((Int128*) p), decSt, scale);
default:
fb_assert(false);
@ -2961,7 +3141,7 @@ Decimal128 CVT_get_dec128(const dsc* desc, DecimalStatus decSt, ErrorFunction er
}
DecimalFixed CVT_get_dec_fixed(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
Int128 CVT_get_int128(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
{
/**************************************
*
@ -2974,8 +3154,15 @@ DecimalFixed CVT_get_dec_fixed(const dsc* desc, SSHORT scale, DecimalStatus decS
*
**************************************/
VaryStr<1024> buffer; // represents unreasonably long decfloat literal in ASCII
DecimalFixed dfix;
Int128 int128;
Decimal128 tmp;
double d, eps;
static const double I128_MIN_dbl = -1.701411834604692e+38;
static const double I128_MAX_dbl = 1.701411834604692e+38;
static const CDecimal128 I128_MIN_dcft("-1.701411834604692317316873037158841E+38", decSt);
static const CDecimal128 I128_MAX_dcft("1.701411834604692317316873037158841E+38", decSt);
static const CDecimal128 DecFlt_05("0.5", decSt);
// adjust exact numeric values to same scaling
if (DTYPE_IS_EXACT(desc->dsc_dtype))
@ -2988,27 +3175,30 @@ DecimalFixed CVT_get_dec_fixed(const dsc* desc, SSHORT scale, DecimalStatus decS
switch (desc->dsc_dtype)
{
case dtype_short:
dfix.set(*(SSHORT*) p);
int128.set(SLONG(*(SSHORT*) p), scale);
break;
case dtype_long:
dfix.set(*(SLONG*) p);
int128.set(*(SLONG*) p, scale);
break;
case dtype_quad:
dfix.set(CVT_get_int64(desc, 0, decSt, err));
int128.set(CVT_get_int64(desc, 0, decSt, err), scale);
break;
case dtype_int64:
dfix.set(*(SINT64*) p);
int128.set(*(SINT64*) p, scale);
break;
case dtype_varying:
case dtype_cstring:
case dtype_text:
CVT_make_null_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer) - 1, decSt, err);
dfix.set(buffer.vary_string, scale, decSt);
return dfix; // scale already corrected
{
USHORT length =
CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err);
scale -= CVT_decompose(p, length, &int128, err);
int128.setScale(scale);
}
break;
case dtype_blob:
@ -3022,23 +3212,70 @@ DecimalFixed CVT_get_dec_fixed(const dsc* desc, SSHORT scale, DecimalStatus decS
break;
case dtype_real:
dfix.set(*((float*) p), scale, decSt);
return dfix; // scale already corrected
case dtype_double:
dfix.set(*((double*) p), scale, decSt);
return dfix; // scale already corrected
if (desc->dsc_dtype == dtype_real)
{
d = *((float*) p);
eps = eps_float;
}
else // if (desc->dsc_dtype == DEFAULT_DOUBLE)
{
d = *((double*) p);
eps = eps_double;
}
if (scale > 0)
d /= CVT_power_of_ten(scale);
else if (scale < 0)
d *= CVT_power_of_ten(-scale);
if (d > 0)
d += 0.5 + eps;
else
d -= 0.5 + eps;
/* make sure the cast will succeed
Note that adding or subtracting 0.5, as we do in CVT_get_long,
will never allow the rounded value to fit into an Int128,
because when the double value is too large in magnitude
to fit, 0.5 is less than half of the least significant bit
of the significant (sometimes miscalled "mantissa") of the
double, and thus will have no effect on the sum. */
if (d < I128_MIN_dbl || I128_MAX_dbl < d)
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
int128.set(d);
break;
case dtype_dec64:
dfix = tmp = *((Decimal64*) p);
break;
case dtype_dec128:
dfix = *((Decimal128*) p);
if (desc->dsc_dtype == dtype_dec64)
tmp = *((Decimal64*) p);
else
tmp = *((Decimal128*) p);
tmp.setScale(decSt, -scale);
/* make sure the cast will succeed
Note that adding or subtracting 0.5, as we do in CVT_get_long,
will never allow the rounded value to fit into an Int128,
because when the double value is too large in magnitude
to fit, 0.5 is less than half of the least significant bit
of the significant (sometimes miscalled "mantissa") of the
double, and thus will have no effect on the sum. */
if (tmp.compare(decSt, I128_MIN_dcft) < 0 || I128_MAX_dcft.compare(decSt, tmp) < 0)
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
int128.set(decSt, tmp);
break;
case dtype_dec_fixed:
dfix = *((DecimalFixed*) p);
case dtype_int128:
int128 = *((Int128*) p);
int128.setScale(scale);
break;
default:
@ -3054,8 +3291,7 @@ DecimalFixed CVT_get_dec_fixed(const dsc* desc, SSHORT scale, DecimalStatus decS
err(v);
}
dfix.exactInt(decSt, scale);
return dfix;
return int128;
}
@ -3154,7 +3390,9 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
{
USHORT length =
CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err);
scale -= CVT_decompose(p, length, dtype_quad, &value.gds_quad_high, err);
SINT64 i64;
scale -= CVT_decompose(p, length, &i64, err);
SINT64_to_SQUAD(i64, value);
}
break;
@ -3170,7 +3408,7 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
SINT64_to_SQUAD(CVT_get_int64(desc, scale, decSt, err), value);
break;
@ -3246,9 +3484,8 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu
return d128.toInt64(decSt, scale);
}
case dtype_dec_fixed:
value = ((DecimalFixed*) p)->toInt64(decSt);
break;
case dtype_int128:
return ((Int128*) p)->toInt64(scale);
case dtype_real:
case dtype_double:
@ -3295,7 +3532,7 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu
{
USHORT length =
CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err);
scale -= CVT_decompose(p, length, dtype_int64, (SLONG *) & value, err);
scale -= CVT_decompose(p, length, &value, err);
}
break;
@ -3349,7 +3586,7 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu
}
static SINT64 hex_to_value(const char*& string, const char* end)
static void hex_to_value(const char*& string, const char* end, RetPtr* retValue)
/*************************************
*
* hex_to_value
@ -3366,7 +3603,6 @@ static SINT64 hex_to_value(const char*& string, const char* end)
// we already know this is a hex string, and there is no prefix.
// So, string is something like DEADBEEF.
SINT64 value = 0;
UCHAR byte = 0;
int nibble = ((end - string) & 1);
char ch;
@ -3385,7 +3621,7 @@ static SINT64 hex_to_value(const char*& string, const char* end)
{
byte = (byte << 4) + (UCHAR) c;
nibble = 0;
value = (value << 8) + byte;
retValue->nextDigit(byte, 256);
}
else
{
@ -3397,8 +3633,6 @@ static SINT64 hex_to_value(const char*& string, const char* end)
}
fb_assert(string <= end);
return value;
}

View File

@ -80,7 +80,9 @@ enum EXPECT_DATETIME
expect_sql_time_tz
};
}
class Int128;
} // namespace Firebird
void CVT_conversion_error(const dsc*, ErrorFunction);
@ -90,12 +92,14 @@ bool CVT_get_boolean(const dsc*, ErrorFunction);
double CVT_get_double(const dsc*, Firebird::DecimalStatus, ErrorFunction, bool* getNumericOverflow = nullptr);
Firebird::Decimal64 CVT_get_dec64(const dsc*, Firebird::DecimalStatus, ErrorFunction);
Firebird::Decimal128 CVT_get_dec128(const dsc*, Firebird::DecimalStatus, ErrorFunction);
Firebird::DecimalFixed CVT_get_dec_fixed(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
Firebird::Int128 CVT_get_int128(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
USHORT CVT_make_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
void CVT_make_null_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
void CVT_move_common(const dsc*, dsc*, Firebird::DecimalStatus, Firebird::Callbacks*);
void CVT_move(const dsc*, dsc*, Firebird::DecimalStatus, ErrorFunction);
SSHORT CVT_decompose(const char*, USHORT, SSHORT, SLONG*, ErrorFunction);
SSHORT CVT_decompose(const char*, USHORT, SLONG*, ErrorFunction);
SSHORT CVT_decompose(const char*, USHORT, SINT64*, ErrorFunction);
SSHORT CVT_decompose(const char*, USHORT, Firebird::Int128*, ErrorFunction);
USHORT CVT_get_string_ptr(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
USHORT CVT_get_string_ptr_common(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, Firebird::Callbacks*);
SINT64 CVT_get_int64(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);

View File

@ -68,7 +68,7 @@ static const USHORT _DSC_convert_to_text_length[DTYPE_TYPE_MAX] =
5, // dtype_boolean
23, // dtype_dec64 1 + 1 + 1 + 1 + 16(34) + 3(4)
42, // dtype_dec128 +- . e +- coeff + exp
36, // dtype_dec_fixed coeff(34) + 1(+-) + 1(.)
47, // dtype_int128
14 + TimeZoneUtil::MAX_LEN, // dtype_sql_time_tz HH:MM:SS.MMMM +NN:NN
25 + TimeZoneUtil::MAX_LEN // dtype_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN
};
@ -122,7 +122,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double dtype_d_float dtype_sql_date dtype_sql_time
dtype_timestamp dtype_blob dtype_array dtype_int64
dtype_dbkey dtype_boolean dtype_dec64 dtype_dec128
dtype_dec_fixed dtype_sql_time_tz dtype_timestamp_tz
dtype_int128 dtype_sql_time_tz dtype_timestamp_tz
*/
// dtype_unknown
@ -141,7 +141,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, dtype_timestamp_tz},
dtype_int128, DTYPE_CANNOT, dtype_timestamp_tz},
// dtype_cstring
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -150,7 +150,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, dtype_timestamp_tz},
dtype_int128, DTYPE_CANNOT, dtype_timestamp_tz},
// dtype_varying
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -159,7 +159,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, dtype_timestamp_tz},
dtype_int128, DTYPE_CANNOT, dtype_timestamp_tz},
// 4 (unused)
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -204,7 +204,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, dtype_sql_time_tz, dtype_timestamp_tz},
dtype_int128, dtype_sql_time_tz, dtype_timestamp_tz},
// dtype_long
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -213,7 +213,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, dtype_sql_time_tz, dtype_timestamp_tz},
dtype_int128, dtype_sql_time_tz, dtype_timestamp_tz},
// dtype_quad
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -303,7 +303,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, dtype_sql_time_tz, dtype_timestamp_tz},
dtype_int128, dtype_sql_time_tz, dtype_timestamp_tz},
// dtype_dbkey
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -341,14 +341,14 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec128, dtype_sql_time_tz, dtype_timestamp_tz},
// dtype_dec_fixed
{dtype_unknown, dtype_dec_fixed, dtype_dec_fixed, dtype_dec_fixed,
// dtype_int128
{dtype_unknown, dtype_int128, dtype_int128, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_dec_fixed, dtype_dec_fixed, DTYPE_CANNOT, dtype_double,
dtype_int128, dtype_int128, DTYPE_CANNOT, dtype_double,
dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec_fixed,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, dtype_sql_time_tz, dtype_timestamp_tz},
dtype_int128, dtype_sql_time_tz, dtype_timestamp_tz},
// dtype_sql_time_tz
{dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -384,7 +384,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double dtype_d_float dtype_sql_date dtype_sql_time
dtype_timestamp dtype_blob dtype_array dtype_int64
dtype_dbkey dtype_boolean dtype_dec64 dtype_dec128
dtype_dec_fixed dtype_sql_time_tz dtype_timestamp_tz
dtype_int128 dtype_sql_time_tz dtype_timestamp_tz
*/
// dtype_unknown
@ -403,7 +403,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, dtype_timestamp_tz},
dtype_int128, DTYPE_CANNOT, dtype_timestamp_tz},
// dtype_cstring
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -412,7 +412,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, dtype_timestamp_tz},
dtype_int128, DTYPE_CANNOT, dtype_timestamp_tz},
// dtype_varying
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -421,7 +421,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, dtype_timestamp_tz},
dtype_int128, DTYPE_CANNOT, dtype_timestamp_tz},
// 4 (unused)
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -466,7 +466,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_long
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -475,7 +475,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_quad
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -565,7 +565,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_dbkey
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -603,14 +603,14 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_dec_fixed
{dtype_unknown, dtype_dec_fixed, dtype_dec_fixed, dtype_dec_fixed,
// dtype_int128
{dtype_unknown, dtype_int128, dtype_int128, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_dec_fixed, dtype_dec_fixed, DTYPE_CANNOT, dtype_double,
dtype_int128, dtype_int128, DTYPE_CANNOT, dtype_double,
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec_fixed,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_sql_time_tz
{dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -647,7 +647,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double dtype_d_float dtype_sql_date dtype_sql_time
dtype_timestamp dtype_blob dtype_array dtype_int64
dtype_dbkey dtype_boolean dtype_dec64 dtype_dec128
dtype_dec_fixed dtype_sql_time_tz dtype_timestamp_tz
dtype_int128 dtype_sql_time_tz dtype_timestamp_tz
*/
// dtype_unknown
@ -666,7 +666,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_cstring
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -675,7 +675,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_varying
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -684,7 +684,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// 4 (unused)
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -729,7 +729,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_long
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -738,7 +738,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_quad
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -826,9 +826,9 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_int64, dtype_int64, DTYPE_CANNOT, dtype_double,
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_dbkey
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -866,14 +866,14 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_dec_fixed
{dtype_unknown, dtype_dec_fixed, dtype_dec_fixed, dtype_dec_fixed,
// dtype_int128
{dtype_unknown, dtype_int128, dtype_int128, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_dec_fixed, dtype_dec_fixed, DTYPE_CANNOT, dtype_double,
dtype_int128, dtype_int128, DTYPE_CANNOT, dtype_double,
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec_fixed,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_sql_time_tz
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -909,7 +909,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double dtype_d_float dtype_sql_date dtype_sql_time
dtype_timestamp dtype_blob dtype_array dtype_int64
dtype_dbkey dtype_boolean dtype_dec64 dtype_dec128
dtype_dec_fixed dtype_sql_time_tz dtype_timestamp_tz
dtype_int128 dtype_sql_time_tz dtype_timestamp_tz
*/
// dtype_unknown
@ -928,7 +928,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_cstring
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -937,7 +937,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_varying
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -946,7 +946,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// 4 (unused)
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -991,7 +991,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_long
{dtype_unknown, dtype_double, dtype_double, dtype_double,
@ -1000,7 +1000,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_quad
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -1090,7 +1090,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_dbkey
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -1128,14 +1128,14 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] =
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_dec_fixed
{dtype_unknown, dtype_dec_fixed, dtype_dec_fixed, dtype_dec_fixed,
// dtype_int128
{dtype_unknown, dtype_int128, dtype_int128, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
dtype_dec_fixed, dtype_dec_fixed, DTYPE_CANNOT, dtype_double,
dtype_int128, dtype_int128, DTYPE_CANNOT, dtype_double,
dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec_fixed,
DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int128,
DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128,
dtype_dec_fixed, DTYPE_CANNOT, DTYPE_CANNOT},
dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT},
// dtype_sql_time_tz
{DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT,
@ -1268,9 +1268,9 @@ bool DSC_make_descriptor(DSC* desc,
desc->dsc_dtype = dtype_dec128;
break;
case blr_dec_fixed:
desc->dsc_length = sizeof(DecimalFixed);
desc->dsc_dtype = dtype_dec_fixed;
case blr_int128:
desc->dsc_length = sizeof(Int128);
desc->dsc_dtype = dtype_int128;
break;
case blr_timestamp:
@ -1448,7 +1448,7 @@ const char* dsc::typeToText() const
return "decfloat(16)";
case dtype_dec128:
return "decfloat(34)";
case dtype_dec_fixed:
case dtype_int128:
return "decimal";
case dtype_sql_time_tz:
return "time with timezone";
@ -1552,8 +1552,8 @@ void dsc::getSqlInfo(SLONG* sqlLength, SLONG* sqlSubType, SLONG* sqlScale, SLONG
*sqlScale = 0;
break;
case dtype_dec_fixed:
*sqlType = SQL_DEC_FIXED;
case dtype_int128:
*sqlType = SQL_INT128;
*sqlScale = dsc_scale;
if (dsc_sub_type)
*sqlSubType = dsc_sub_type;

View File

@ -32,6 +32,7 @@
#include "../jrd/ods.h"
#include "../intl/charsets.h"
#include "../common/DecFloat.h"
#include "../common/Int128.h"
// Data type information
@ -60,7 +61,7 @@ inline bool DTYPE_IS_BLOB_OR_QUAD(UCHAR d)
// Exact numeric?
inline bool DTYPE_IS_EXACT(UCHAR d)
{
return d == dtype_int64 || d == dtype_long || d == dtype_short || d == dtype_dec_fixed;
return d == dtype_int64 || d == dtype_long || d == dtype_short || d == dtype_int128;
}
inline bool DTYPE_IS_APPROX(UCHAR d)
@ -70,12 +71,13 @@ inline bool DTYPE_IS_APPROX(UCHAR d)
inline bool DTYPE_IS_DECFLOAT(UCHAR d)
{
return d == dtype_dec128 || d == dtype_dec64 || d == dtype_dec_fixed;
return d == dtype_dec128 || d == dtype_dec64;
}
inline bool DTYPE_IS_NUMERIC(UCHAR d)
{
return (d >= dtype_byte && d <= dtype_d_float) || d == dtype_int64 || DTYPE_IS_DECFLOAT(d);
return (d >= dtype_byte && d <= dtype_d_float) || d == dtype_int64 ||
d == dtype_int128 || DTYPE_IS_DECFLOAT(d);
}
// Descriptor format
@ -138,7 +140,8 @@ typedef struct dsc
bool isExact() const
{
return dsc_dtype == dtype_int64 || dsc_dtype == dtype_long || dsc_dtype == dtype_short;
return dsc_dtype == dtype_int128 || dsc_dtype == dtype_int64 ||
dsc_dtype == dtype_long || dsc_dtype == dtype_short;
}
bool isNumeric() const
@ -187,14 +190,14 @@ typedef struct dsc
return dsc_dtype == dtype_dec128 || dsc_dtype == dtype_dec64;
}
bool isDecFixed() const
bool isInt128() const
{
return dsc_dtype == dtype_dec_fixed;
return dsc_dtype == dtype_int128;
}
bool isDecOrInt() const
{
return isDecFloat() || isDecFixed() || isExact();
return isDecFloat() || isExact();
}
bool isApprox() const
@ -339,6 +342,15 @@ typedef struct dsc
dsc_address = (UCHAR*) address;
}
void makeInt128(SCHAR scale, Firebird::Int128* address = NULL)
{
clear();
dsc_dtype = dtype_int128;
dsc_length = sizeof(Firebird::Int128);
dsc_scale = scale;
dsc_address = (UCHAR*) address;
}
void makeLong(SCHAR scale, SLONG* address = NULL)
{
clear();

View File

@ -252,6 +252,7 @@ static const TOK tokens[] =
{TOK_INSERT, "INSERT", false},
{TOK_INSERTING, "INSERTING", false},
{TOK_INT, "INT", false},
{TOK_INT128, "INT128", true},
{TOK_INTEGER, "INTEGER", false},
{TOK_INTO, "INTO", false},
{TOK_INVOKER, "INVOKER", true},

View File

@ -855,9 +855,9 @@ static const UCHAR* sdl_desc(const UCHAR* ptr, DSC* desc)
desc->dsc_length = sizeof(Decimal128);
break;
case blr_dec_fixed:
desc->dsc_dtype = dtype_dec_fixed;
desc->dsc_length = sizeof(DecimalFixed);
case blr_int128:
desc->dsc_dtype = dtype_int128;
desc->dsc_length = sizeof(Int128);
break;
case blr_timestamp:

View File

@ -1522,8 +1522,8 @@ UCHAR sqlTypeToDscType(SSHORT sqlType)
return dtype_dec64;
case SQL_DEC34:
return dtype_dec128;
case SQL_DEC_FIXED:
return dtype_dec_fixed;
case SQL_INT128:
return dtype_int128;
case SQL_TIME_TZ:
return dtype_sql_time_tz;
case SQL_TIMESTAMP_TZ:

View File

@ -31,6 +31,7 @@
#include "../yvalve/gds_proto.h"
#include "../common/gdsassert.h"
#include "../common/DecFloat.h"
#include "../common/Int128.h"
inline UCHAR* XDR_ALLOC(ULONG size)
{
@ -268,12 +269,17 @@ bool_t xdr_datum( XDR* xdrs, const dsc* desc, UCHAR* buffer)
break;
case dtype_dec128:
case dtype_dec_fixed:
fb_assert(desc->dsc_length >= sizeof(Firebird::Decimal128));
if (!xdr_dec128(xdrs, reinterpret_cast<Firebird::Decimal128*>(p)))
return FALSE;
break;
case dtype_int128:
fb_assert(desc->dsc_length >= sizeof(Firebird::Int128));
if (!xdr_int128(xdrs, reinterpret_cast<Firebird::Int128*>(p)))
return FALSE;
break;
case dtype_timestamp:
fb_assert(desc->dsc_length >= 2 * sizeof(SLONG));
if (!xdr_long(xdrs, &((SLONG*) p)[0]))
@ -381,6 +387,19 @@ bool_t xdr_dec128(XDR* xdrs, Firebird::Decimal128* ip)
}
bool_t xdr_int128(XDR* xdrs, Firebird::Int128* ip)
{
UCHAR* bytes = ip->getBytes();
#ifndef WORDS_BIGENDIAN
return xdr_hyper(xdrs, &bytes[8]) && xdr_hyper(xdrs, &bytes[0]);
#else
fb_assert(false); // Dec64/128 XDR not tested on bigendians!
return xdr_hyper(xdrs, &bytes[0]) && xdr_hyper(xdrs, &bytes[8]);
#endif
}
bool_t xdr_enum(XDR* xdrs, xdr_op* ip)
{
/**************************************

View File

@ -29,8 +29,9 @@
bool_t xdr_datum(XDR*, const dsc*, UCHAR*);
bool_t xdr_double(XDR*, double*);
bool_t xdr_dec64(XDR*, Firebird::Decimal64*);
bool_t xdr_dec128(XDR*, Firebird::Decimal128*);
bool_t xdr_dec64(XDR*, Firebird::Decimal64*);
bool_t xdr_dec128(XDR*, Firebird::Decimal128*);
bool_t xdr_int128(XDR*, Firebird::Int128*);
bool_t xdr_enum(XDR*, xdr_op*);
bool_t xdr_float(XDR*, float*);
bool_t xdr_int(XDR*, int*);

View File

@ -540,6 +540,11 @@ void AvgAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_dsql_agg2_wrongarg) << Arg::Str("AVG"));
}
else if (desc->dsc_dtype == dtype_int64 || desc->dsc_dtype == dtype_int128)
{
desc->dsc_dtype = dtype_int128;
desc->dsc_length = sizeof(Int128);
}
else if (DTYPE_IS_EXACT(desc->dsc_dtype))
{
desc->dsc_dtype = dtype_int64;
@ -584,13 +589,10 @@ void AvgAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
return;
}
// In V6, the average of an exact type is computed in SINT64, rather than double as in prior
// releases.
switch (desc->dsc_dtype)
{
case dtype_short:
case dtype_long:
case dtype_int64:
desc->dsc_dtype = dtype_int64;
desc->dsc_length = sizeof(SINT64);
desc->dsc_sub_type = 0;
@ -598,6 +600,15 @@ void AvgAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
nodScale = desc->dsc_scale;
break;
case dtype_int64:
case dtype_int128:
desc->dsc_dtype = dtype_int128;
desc->dsc_length = sizeof(Int128);
desc->dsc_sub_type = 0;
desc->dsc_flags = 0;
nodScale = desc->dsc_scale;
break;
case dtype_unknown:
desc->dsc_dtype = dtype_unknown;
desc->dsc_length = 0;
@ -697,12 +708,19 @@ dsc* AvgAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const
SINT64 i;
double d;
Decimal128 dec;
Int128 i128;
if (!dialect1 && impure->vlu_desc.dsc_dtype == dtype_int64)
{
i = *((SINT64*) impure->vlu_desc.dsc_address) / impure->vlux_count;
temp.makeInt64(impure->vlu_desc.dsc_scale, &i);
}
else if (!dialect1 && impure->vlu_desc.dsc_dtype == dtype_int128)
{
i128.set(impure->vlux_count, 0);
i128 = ((Int128*) impure->vlu_desc.dsc_address)->div(i128, 0);
temp.makeInt128(impure->vlu_desc.dsc_scale, &i128);
}
else if (DTYPE_IS_DECFLOAT(impure->vlu_desc.dsc_dtype))
{
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
@ -1037,6 +1055,11 @@ void SumAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_dsql_agg2_wrongarg) << Arg::Str("SUM"));
}
else if (desc->dsc_dtype == dtype_int64 || desc->dsc_dtype == dtype_int128)
{
desc->dsc_dtype = dtype_int128;
desc->dsc_length = sizeof(Int128);
}
else if (DTYPE_IS_EXACT(desc->dsc_dtype))
{
desc->dsc_dtype = dtype_int64;
@ -1118,13 +1141,21 @@ void SumAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
{
case dtype_short:
case dtype_long:
case dtype_int64:
desc->dsc_dtype = dtype_int64;
desc->dsc_length = sizeof(SINT64);
nodScale = desc->dsc_scale;
desc->dsc_flags = 0;
return;
case dtype_int64:
case dtype_int128:
desc->dsc_dtype = dtype_int128;
desc->dsc_length = sizeof(Int128);
desc->dsc_sub_type = 0;
desc->dsc_flags = 0;
nodScale = desc->dsc_scale;
return;
case dtype_unknown:
desc->dsc_dtype = dtype_unknown;
desc->dsc_length = 0;

View File

@ -4491,7 +4491,7 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld)
case blr_float:
case blr_dec64:
case blr_dec128:
case blr_dec_fixed:
case blr_int128:
// Cannot convert column %s from character to non-character data.
errorCode = isc_dyn_dtype_conv_invalid;
break;
@ -4613,7 +4613,7 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld)
case blr_float:
case blr_dec64:
case blr_dec128:
case blr_dec_fixed:
case blr_int128:
switch (newFld.dyn_dtype)
{
case blr_blob:
@ -4741,7 +4741,7 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld)
case blr_double:
case blr_dec64:
case blr_dec128:
case blr_dec_fixed:
case blr_int128:
break;
default:
@ -4751,13 +4751,13 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld)
}
break;
case blr_dec_fixed:
case blr_int128:
switch (origFld.dyn_dtype)
{
case blr_short:
case blr_long:
case blr_int64:
case blr_dec_fixed:
case blr_int128:
break;
default:

View File

@ -506,17 +506,19 @@ namespace
const UCHAR DSC_ZTYPE_FLT64 = 0;
const UCHAR DSC_ZTYPE_FLT128 = 1;
const UCHAR DSC_ZTYPE_FIXED = 2;
const UCHAR DSC_ZTYPE_INT = 3;
const UCHAR DSC_ZTYPE_OTHER = 4;
const UCHAR DSC_ZTYPE_BAD = 5;
const UCHAR DSC_ZTYPE_INT64 = 3;
const UCHAR DSC_ZTYPE_INT = 4;
const UCHAR DSC_ZTYPE_OTHER = 5;
const UCHAR DSC_ZTYPE_BAD = 6;
const UCHAR decimalDescTable[5][5] = {
/* DSC_ZTYPE_FLT64 DSC_ZTYPE_FLT128 DSC_ZTYPE_FIXED DSC_ZTYPE_INT DSC_ZTYPE_OTHER */
/* DSC_ZTYPE_FLT64 */ {DSC_ZTYPE_FLT64, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128},
/* DSC_ZTYPE_FLT128 */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128},
/* DSC_ZTYPE_FIXED */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_FLT128},
/* DSC_ZTYPE_INT */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD},
/* DSC_ZTYPE_OTHER */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD}
const UCHAR decimalDescTable[6][6] = {
/* DSC_ZTYPE_FLT64 DSC_ZTYPE_FLT128 DSC_ZTYPE_FIXED DSC_ZTYPE_INT64 DSC_ZTYPE_INT DSC_ZTYPE_OTHER */
/* DSC_ZTYPE_FLT64 */ {DSC_ZTYPE_FLT64, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128},
/* DSC_ZTYPE_FLT128 */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128},
/* DSC_ZTYPE_FIXED */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_FLT128},
/* DSC_ZTYPE_INT64 */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD},
/* DSC_ZTYPE_INT */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD},
/* DSC_ZTYPE_OTHER */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD}
};
UCHAR getFType(const dsc& desc)
@ -527,8 +529,10 @@ UCHAR getFType(const dsc& desc)
return DSC_ZTYPE_FLT64;
case dtype_dec128:
return DSC_ZTYPE_FLT128;
case dtype_dec_fixed:
case dtype_int128:
return DSC_ZTYPE_FIXED;
case dtype_int64:
return DSC_ZTYPE_INT64;
}
if (DTYPE_IS_EXACT(desc.dsc_dtype))
@ -547,7 +551,7 @@ unsigned setDecDesc(dsc* desc, const dsc& desc1, const dsc& desc2, Scaling sc, S
zipType = DSC_ZTYPE_FLT128; // In production case fallback to Decimal128
desc->dsc_dtype = zipType == DSC_ZTYPE_FLT64 ? dtype_dec64 :
zipType == DSC_ZTYPE_FLT128 ? dtype_dec128 : dtype_dec_fixed;
zipType == DSC_ZTYPE_FLT128 ? dtype_dec128 : dtype_int128;
desc->dsc_sub_type = 0;
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
desc->dsc_scale = 0;
@ -569,9 +573,9 @@ unsigned setDecDesc(dsc* desc, const dsc& desc1, const dsc& desc2, Scaling sc, S
*nodScale = desc->dsc_scale;
desc->dsc_length = zipType == DSC_ZTYPE_FLT64 ? sizeof(Decimal64) :
zipType == DSC_ZTYPE_FLT128 ? sizeof(Decimal128) : sizeof(DecimalFixed);
zipType == DSC_ZTYPE_FLT128 ? sizeof(Decimal128) : sizeof(Int128);
return zipType == DSC_ZTYPE_FIXED ? ExprNode::FLAG_DECFIXED : ExprNode::FLAG_DECFLOAT;
return zipType == DSC_ZTYPE_FIXED ? ExprNode::FLAG_INT128 : ExprNode::FLAG_DECFLOAT;
}
} // anon namespace
@ -764,7 +768,7 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2)
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
setDecDesc(desc, desc1, desc2, SCALE_MIN);
break;
@ -792,7 +796,7 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2)
switch (dtype)
{
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
setDecDesc(desc, desc1, desc2, SCALE_SUM);
break;
@ -887,8 +891,8 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
// <timestamp> arithmetic, but returns a <double>
if (DTYPE_IS_EXACT(dtype1) && DTYPE_IS_EXACT(dtype2))
{
if (desc1.isDecFixed() || desc2.isDecFixed())
dtype = dtype_dec_fixed;
if (desc1.isInt128() || desc2.isInt128())
dtype = dtype_int128;
else
dtype = dtype_int64;
}
@ -1027,7 +1031,7 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
setDecDesc(desc, desc1, desc2, SCALE_MIN);
break;
@ -1076,7 +1080,7 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
switch (dtype)
{
case dtype_dec_fixed:
case dtype_int128:
case dtype_dec128:
setDecDesc(desc, desc1, desc2, SCALE_SUM);
break;
@ -1135,7 +1139,7 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
break;
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
setDecDesc(desc, desc1, desc2, SCALE_SUM);
break;
@ -1347,7 +1351,7 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
nodFlags |= setDecDesc(desc, desc1, desc2, SCALE_MIN, &nodScale);
break;
@ -1394,7 +1398,7 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
return;
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
nodFlags |= setDecDesc(desc, desc1, desc2, SCALE_SUM, &nodScale);
break;
@ -1469,8 +1473,8 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
if (DTYPE_IS_EXACT(dtype1) && DTYPE_IS_EXACT(dtype2))
{
if (desc1.isDecFixed() || desc2.isDecFixed())
dtype = dtype_dec_fixed;
if (desc1.isInt128() || desc2.isInt128())
dtype = dtype_int128;
else
dtype = dtype_int64;
}
@ -1620,7 +1624,7 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
nodFlags |= setDecDesc(desc, desc1, desc2, SCALE_MIN, &nodScale);
return;
@ -1674,7 +1678,7 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
return;
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
nodFlags |= setDecDesc(desc, desc1, desc2, SCALE_SUM, &nodScale);
return;
@ -1900,23 +1904,6 @@ dsc* ArithmeticNode::add(thread_db* tdbb, const dsc* desc, impure_value* value,
return result;
}
if (node->nodFlags & FLAG_DECFIXED)
{
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, desc, node->nodScale);
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, node->nodScale);
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
value->vlu_misc.vlu_dec_fixed = (blrOp == blr_subtract) ? d2.sub(decSt, d1) : d1.add(decSt, d2);
result->dsc_dtype = dtype_dec_fixed;
result->dsc_length = sizeof(DecimalFixed);
result->dsc_scale = node->nodScale;
result->dsc_sub_type = 0;
result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
return result;
}
// Handle floating arithmetic
if (node->nodFlags & FLAG_DOUBLE)
@ -1996,19 +1983,20 @@ dsc* ArithmeticNode::add2(thread_db* tdbb, const dsc* desc, impure_value* value,
return result;
}
if (node->nodFlags & FLAG_DECFIXED)
// 128-bit arithmetic
if (node->nodFlags & FLAG_INT128)
{
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, desc, node->nodScale);
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, node->nodScale);
const Int128 d1 = MOV_get_int128(tdbb, desc, node->nodScale);
const Int128 d2 = MOV_get_int128(tdbb, &value->vlu_desc, node->nodScale);
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
value->vlu_misc.vlu_dec_fixed = (blrOp == blr_subtract) ? d2.sub(decSt, d1) : d1.add(decSt, d2);
value->vlu_misc.vlu_int128 = (blrOp == blr_subtract) ? d2.sub(d1) : d1.add(d2);
result->dsc_dtype = dtype_dec_fixed;
result->dsc_length = sizeof(DecimalFixed);
result->dsc_dtype = dtype_int128;
result->dsc_length = sizeof(Int128);
result->dsc_scale = node->nodScale;
result->dsc_sub_type = 0;
result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_int128;
return result;
}
@ -2099,19 +2087,20 @@ dsc* ArithmeticNode::multiply(const dsc* desc, impure_value* value) const
return &value->vlu_desc;
}
if (nodFlags & FLAG_DECFIXED)
// 128-bit arithmetic
if (nodFlags & FLAG_INT128)
{
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, desc, nodScale);
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, nodScale);
const Int128 d1 = MOV_get_int128(tdbb, desc, nodScale);
const Int128 d2 = MOV_get_int128(tdbb, &value->vlu_desc, nodScale);
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
value->vlu_misc.vlu_dec_fixed = d1.mul(decSt, d2);
value->vlu_misc.vlu_int128 = d1.mul(d2);
value->vlu_desc.dsc_dtype = dtype_dec_fixed;
value->vlu_desc.dsc_length = sizeof(DecimalFixed);
value->vlu_desc.dsc_dtype = dtype_int128;
value->vlu_desc.dsc_length = sizeof(Int128);
value->vlu_desc.dsc_scale = nodScale;
value->vlu_desc.dsc_sub_type = 0;
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_int128;
return &value->vlu_desc;
}
@ -2210,20 +2199,21 @@ dsc* ArithmeticNode::multiply2(const dsc* desc, impure_value* value) const
return &value->vlu_desc;
}
if (nodFlags & FLAG_DECFIXED)
// 128-bit arithmetic
if (nodFlags & FLAG_INT128)
{
const SSHORT scale = NUMERIC_SCALE(*desc);
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, desc, scale);
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, nodScale - scale);
const Int128 d1 = MOV_get_int128(tdbb, desc, scale);
const Int128 d2 = MOV_get_int128(tdbb, &value->vlu_desc, nodScale - scale);
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
value->vlu_misc.vlu_dec_fixed = d1.mul(decSt, d2);
value->vlu_misc.vlu_int128 = d1.mul(d2);
value->vlu_desc.dsc_dtype = dtype_dec_fixed;
value->vlu_desc.dsc_length = sizeof(DecimalFixed);
value->vlu_desc.dsc_dtype = dtype_int128;
value->vlu_desc.dsc_length = sizeof(Int128);
value->vlu_desc.dsc_scale = nodScale;
value->vlu_desc.dsc_sub_type = 0;
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_int128;
return &value->vlu_desc;
}
@ -2324,20 +2314,21 @@ dsc* ArithmeticNode::divide2(const dsc* desc, impure_value* value) const
return &value->vlu_desc;
}
if (nodFlags & FLAG_DECFIXED)
// 128-bit arithmetic
if (nodFlags & FLAG_INT128)
{
const SSHORT scale = NUMERIC_SCALE(*desc);
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, desc, scale);
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, nodScale - scale);
const Int128 d2 = MOV_get_int128(tdbb, desc, scale);
const Int128 d1 = MOV_get_int128(tdbb, &value->vlu_desc, nodScale - scale);
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
value->vlu_misc.vlu_dec_fixed = d1.div(decSt, d2, scale * 2);
value->vlu_misc.vlu_int128 = d1.div(d2, scale * 2);
value->vlu_desc.dsc_dtype = dtype_dec_fixed;
value->vlu_desc.dsc_length = sizeof(DecimalFixed);
value->vlu_desc.dsc_dtype = dtype_int128;
value->vlu_desc.dsc_length = sizeof(Int128);
value->vlu_desc.dsc_scale = nodScale;
value->vlu_desc.dsc_sub_type = 0;
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_int128;
return &value->vlu_desc;
}
@ -7383,18 +7374,17 @@ DmlNode* LiteralNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
case dtype_double:
case dtype_dec128:
{
SSHORT scale;
UCHAR dtype;
// The double literal could potentially be used for any numeric literal - the value is
// passed as if it were a text string. Convert the numeric string to its binary value
// (int64, long or double as appropriate).
l = csb->csb_blr_reader.getWord();
q = csb->csb_blr_reader.getPos();
dtype = CVT_get_numeric(q, l, &scale, p);
SSHORT scale = 0;
UCHAR dtype = CVT_get_numeric(q, l, &scale, p);
node->litDesc.dsc_dtype = dtype;
node->dsqlStr = FB_NEW_POOL(pool) IntlString(pool, string(q, l));
node->litDesc.dsc_scale = (SCHAR) scale;
switch (dtype)
{
@ -7406,11 +7396,9 @@ DmlNode* LiteralNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
break;
case dtype_long:
node->litDesc.dsc_length = sizeof(SLONG);
node->litDesc.dsc_scale = (SCHAR) scale;
break;
default:
node->litDesc.dsc_length = sizeof(SINT64);
node->litDesc.dsc_scale = (SCHAR) scale;
}
break;
}
@ -7846,25 +7834,34 @@ bool LiteralNode::sameAs(CompilerScratch* csb, const ExprNode* other, bool ignor
ValueExprNode* LiteralNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
if (DTYPE_IS_DECFLOAT(csb->csb_preferredDataType) && dsqlStr)
if (csb->csb_preferredDesc && ((DTYPE_IS_DECFLOAT(csb->csb_preferredDesc->dsc_dtype) ||
csb->csb_preferredDesc->dsc_dtype == dtype_int128) && dsqlStr))
{
const string& s(dsqlStr->getString());
dsc desc;
desc.makeText(s.length(), CS_ASCII, (UCHAR*) s.c_str());
switch (csb->csb_preferredDataType)
switch (csb->csb_preferredDesc->dsc_dtype)
{
case dtype_dec64:
*((Decimal64*) litDesc.dsc_address) = CVT_get_dec64(&desc,
tdbb->getAttachment()->att_dec_status, ERR_post);
litDesc.dsc_dtype = dtype_dec64;
litDesc.dsc_scale = 0;
break;
case dtype_dec128:
case dtype_dec_fixed:
*((Decimal128*) litDesc.dsc_address) = CVT_get_dec128(&desc,
tdbb->getAttachment()->att_dec_status, ERR_post);
litDesc.dsc_dtype = dtype_dec128;
litDesc.dsc_scale = 0;
break;
case dtype_int128:
*((Int128*) litDesc.dsc_address) = CVT_get_int128(&desc,
csb->csb_preferredDesc->dsc_scale, tdbb->getAttachment()->att_dec_status, ERR_post);
litDesc.dsc_dtype = dtype_int128;
litDesc.dsc_scale = csb->csb_preferredDesc->dsc_scale;
break;
}
}
@ -8744,8 +8741,8 @@ dsc* NegateNode::execute(thread_db* tdbb, jrd_req* request) const
impure->vlu_misc.vlu_dec128 = impure->vlu_misc.vlu_dec128.neg();
break;
case dtype_dec_fixed:
impure->vlu_misc.vlu_dec_fixed = impure->vlu_misc.vlu_dec_fixed.neg();
case dtype_int128:
impure->vlu_misc.vlu_int128 = impure->vlu_misc.vlu_int128.neg();
break;
case dtype_int64:
@ -11091,7 +11088,7 @@ void SubQueryNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
desc->dsc_dtype = dtype_dec128;
desc->dsc_length = sizeof(Decimal128);
desc->dsc_scale = 0;

View File

@ -532,7 +532,7 @@ public:
static const unsigned FLAG_DATE = 0x20;
static const unsigned FLAG_DECFLOAT = 0x40;
static const unsigned FLAG_VALUE = 0x80; // Full value area required in impure space.
static const unsigned FLAG_DECFIXED = 0x100;
static const unsigned FLAG_INT128 = 0x100;
explicit ExprNode(Type aType, MemoryPool& pool)
: DmlNode(pool),

View File

@ -501,7 +501,7 @@ AssignmentNode* AssignmentNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{ // scope
dsc desc;
asgnTo->getDesc(tdbb, csb, &desc);
AutoSetRestore<UCHAR> dataType(&csb->csb_preferredDataType, desc.dsc_dtype);
AutoSetRestore<dsc*> dataType(&csb->csb_preferredDesc, &desc);
ExprNode::doPass2(tdbb, csb, asgnFrom.getAddress());
}
ExprNode::doPass2(tdbb, csb, asgnTo.getAddress());
@ -8360,11 +8360,14 @@ void SetDecFloatTrapsNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_t
//--------------------
void SetDecFloatBindNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const
void SetHighPrecBindNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const
{
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
attachment->att_dec_binding = bind;
if (bindInt128)
attachment->att_i128_binding = bind;
else
attachment->att_dec_binding = bind;
}

View File

@ -30,6 +30,7 @@
#include "../dsql/Nodes.h"
#include "../dsql/DdlNodes.h"
#include "../dsql/NodePrinter.h"
#include "../common/DecFloat.h"
namespace Jrd {
@ -1748,11 +1749,13 @@ public:
};
class SetDecFloatBindNode : public SessionManagementNode
class SetHighPrecBindNode : public SessionManagementNode
{
public:
SetDecFloatBindNode(MemoryPool& pool)
: SessionManagementNode(pool)
SetHighPrecBindNode(MemoryPool& pool, bool isInt128)
: SessionManagementNode(pool),
bind(Firebird::NumericBinding::NUM_NATIVE),
bindInt128(isInt128)
{
}
@ -1764,13 +1767,14 @@ public:
NODE_PRINT(printer, bind.bind);
NODE_PRINT(printer, bind.numScale);
return "SetDecFloatBindNode";
return "SetHighPrecBindNode";
}
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
public:
Firebird::DecimalBinding bind;
Firebird::NumericBinding bind;
bool bindInt128;
};

View File

@ -60,7 +60,7 @@ const USHORT blr_dtypes[] = {
blr_bool, // dtype_boolean
blr_dec64, // dtype_dec64
blr_dec128, // dtype_dec128
blr_dec_fixed, // dtype_dec_fixed
blr_int128, // dtype_int128
blr_sql_time_tz, // dtype_sql_time_tz
blr_timestamp_tz // dtype_timestamp_tz
};

View File

@ -1148,7 +1148,7 @@ void dsql_req::mapInOut(thread_db* tdbb, bool toExternal, const dsql_msg* messag
desc.dsc_address = dsql_msg_buf + (IPTR) desc.dsc_address;
if (notNull)
MOVD_move(tdbb, &parDesc, &desc, toExternal);
MOVD_move(tdbb, &parDesc, &desc);
else
memset(desc.dsc_address, 0, desc.dsc_length);
}
@ -1156,7 +1156,7 @@ void dsql_req::mapInOut(thread_db* tdbb, bool toExternal, const dsql_msg* messag
{
// Safe cast because desc is used as source only.
desc.dsc_address = const_cast<UCHAR*>(in_dsql_msg_buf) + (IPTR) desc.dsc_address;
MOVD_move(tdbb, &desc, &parDesc, toExternal);
MOVD_move(tdbb, &desc, &parDesc);
}
else
memset(parDesc.dsc_address, 0, parDesc.dsc_length);
@ -1191,7 +1191,7 @@ void dsql_req::mapInOut(thread_db* tdbb, bool toExternal, const dsql_msg* messag
dsc desc = parameter->par_desc;
desc.dsc_address = msgBuffer + (IPTR) desc.dsc_address;
MOVD_move(tdbb, &parentDesc, &desc, false);
MOVD_move(tdbb, &parentDesc, &desc);
dsql_par* null_ind = parameter->par_null;
if (null_ind != NULL)
@ -1221,7 +1221,7 @@ void dsql_req::mapInOut(thread_db* tdbb, bool toExternal, const dsql_msg* messag
dsc desc = parameter->par_desc;
desc.dsc_address = msgBuffer + (IPTR) desc.dsc_address;
MOVD_move(tdbb, &parentDesc, &desc, false);
MOVD_move(tdbb, &parentDesc, &desc);
dsql_par* null_ind = parameter->par_null;
if (null_ind != NULL)

View File

@ -256,8 +256,8 @@ public:
precision = 18;
break;
case dtype_dec_fixed:
precision = 34;
case dtype_int128:
precision = 38;
break;
default:

View File

@ -203,21 +203,24 @@ void GEN_port(DsqlCompilerScratch* dsqlScratch, dsql_msg* message)
if (fromCharSet != toCharSet)
parameter->par_desc.setTextType(toCharSet);
}
else if (parameter->par_desc.isDecFloat())
else if (parameter->par_desc.isDecFloat() ||
parameter->par_desc.dsc_dtype == dtype_int128)
{
const DecimalBinding& b = tdbb->getAttachment()->att_dec_binding;
const NumericBinding& b(parameter->par_desc.dsc_dtype == dtype_int128 ?
tdbb->getAttachment()->att_i128_binding : tdbb->getAttachment()->att_dec_binding);
switch (b.bind)
{
case DecimalBinding::DEC_NATIVE:
case NumericBinding::NUM_NATIVE:
break;
case DecimalBinding::DEC_TEXT:
case NumericBinding::NUM_TEXT:
parameter->par_desc.makeText((parameter->par_desc.dsc_dtype == dtype_dec64 ?
IDecFloat16::STRING_SIZE : IDecFloat34::STRING_SIZE) - 1, ttype_ascii);
IDecFloat16::STRING_SIZE : parameter->par_desc.dsc_dtype == dtype_dec128 ?
IDecFloat34::STRING_SIZE : IInt128::STRING_SIZE) - 1, ttype_ascii);
break;
case DecimalBinding::DEC_DOUBLE:
case NumericBinding::NUM_DOUBLE:
parameter->par_desc.makeDouble();
break;
case DecimalBinding::DEC_NUMERIC:
case NumericBinding::NUM_INT64:
parameter->par_desc.makeInt64(b.numScale);
break;
}
@ -415,8 +418,8 @@ void GEN_descriptor( DsqlCompilerScratch* dsqlScratch, const dsc* desc, bool tex
dsqlScratch->appendUChar(blr_dec128);
break;
case dtype_dec_fixed:
dsqlScratch->appendUChar(blr_dec_fixed);
case dtype_int128:
dsqlScratch->appendUChar(blr_int128);
dsqlScratch->appendUChar(desc->dsc_scale);
break;

View File

@ -33,11 +33,11 @@ using namespace Firebird;
// Move (and possible convert) something to something else.
void MOVD_move(thread_db* tdbb, dsc* from, dsc* to, bool toExternal)
void MOVD_move(thread_db* tdbb, dsc* from, dsc* to)
{
try
{
MOV_move_ext(tdbb, from, to, toExternal);
MOV_move(tdbb, from, to);
}
catch (const status_exception& ex)
{

View File

@ -24,6 +24,6 @@
#ifndef DSQL_MOVD_PROTO_H
#define DSQL_MOVD_PROTO_H
void MOVD_move(Jrd::thread_db* tdbb, dsc*, dsc*, bool toExternal);
void MOVD_move(Jrd::thread_db* tdbb, dsc*, dsc*);
#endif // DSQL_MOVD_PROTO_H

View File

@ -613,6 +613,7 @@ using namespace Firebird;
%token <metaNamePtr> HEX_ENCODE
%token <metaNamePtr> IDLE
%token <metaNamePtr> INVOKER
%token <metaNamePtr> INT128
%token <metaNamePtr> IV
%token <metaNamePtr> LAST_DAY
%token <metaNamePtr> LEGACY
@ -816,7 +817,7 @@ using namespace Firebird;
Jrd::CreateAlterRoleNode* createAlterRoleNode;
Jrd::SetDecFloatRoundNode* setDecFloatRoundNode;
Jrd::SetDecFloatTrapsNode* setDecFloatTrapsNode;
Jrd::SetDecFloatBindNode* setDecFloatBindNode;
Jrd::SetHighPrecBindNode* setHighPrecBindNode;
Jrd::SessionResetNode* sessionResetNode;
}
@ -4224,6 +4225,7 @@ keyword_or_column
| VAR_SAMP
| VAR_POP
| DECFLOAT // added in FB 4.0
| INT128
| LOCAL
| LOCALTIME
| LOCALTIMESTAMP
@ -4971,14 +4973,14 @@ prec_scale
{
$$ = newNode<dsql_fld>();
if ($2 < 1 || $2 > 34)
yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(34));
// Precision must be between 1 and 34
if ($2 < 1 || $2 > 38)
yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(38));
// Precision must be between 1 and 38
if ($2 > 18)
{
$$->dtype = dtype_dec_fixed;
$$->length = sizeof(DecimalFixed);
$$->dtype = dtype_int128;
$$->length = sizeof(Int128);
}
else if ($2 > 9)
{
@ -5027,17 +5029,17 @@ prec_scale
{
$$ = newNode<dsql_fld>();
if ($2 < 1 || $2 > 34)
yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(34));
// Precision must be between 1 and 34
if ($2 < 1 || $2 > 38)
yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(38));
// Precision must be between 1 and 38
if ($4 > $2 || $4 < 0)
yyabandon(YYPOSNARG(4), -842, isc_scale_nogt); // Scale must be between 0 and precision
if ($2 > 18)
{
$$->dtype = dtype_dec_fixed;
$$->length = sizeof(DecimalFixed);
$$->dtype = dtype_int128;
$$->length = sizeof(Int128);
}
else if ($2 > 9)
{
@ -5270,14 +5272,20 @@ set_decfloat_traps
{ $$ = $5; }
;
%type <setDecFloatBindNode> set_decfloat_bind
%type <setHighPrecBindNode> set_decfloat_bind
set_decfloat_bind
: SET DECFLOAT BIND
{ $$ = newNode<SetDecFloatBindNode>(); }
: SET bind_to_type BIND
{ $$ = newNode<SetHighPrecBindNode>($2); }
decfloat_bind_clause($4)
{ $$ = $4; }
;
%type <boolVal> bind_to_type
bind_to_type
: DECFLOAT { $$ = false; }
| INT128 { $$ = true; }
;
%type decfloat_traps_list_opt(<setDecFloatTrapsNode>)
decfloat_traps_list_opt($setDecFloatTrapsNode)
: // nothing
@ -5296,26 +5304,26 @@ decfloat_trap($setDecFloatTrapsNode)
{ $setDecFloatTrapsNode->trap($1); }
;
%type decfloat_bind_clause(<setDecFloatBindNode>)
decfloat_bind_clause($setDecFloatBindNode)
%type decfloat_bind_clause(<setHighPrecBindNode>)
decfloat_bind_clause($setHighPrecBindNode)
: NATIVE
// do nothing
| character_keyword
{ $setDecFloatBindNode->bind.bind = DecimalBinding::DEC_TEXT; }
{ $setHighPrecBindNode->bind.bind = NumericBinding::NUM_TEXT; }
| DOUBLE PRECISION
{ $setDecFloatBindNode->bind.bind = DecimalBinding::DEC_DOUBLE; }
| BIGINT decfloat_scale_clause($setDecFloatBindNode)
{ $setDecFloatBindNode->bind.bind = DecimalBinding::DEC_NUMERIC; }
{ $setHighPrecBindNode->bind.bind = NumericBinding::NUM_DOUBLE; }
| BIGINT decfloat_scale_clause($setHighPrecBindNode)
{ $setHighPrecBindNode->bind.bind = NumericBinding::NUM_INT64; }
;
%type decfloat_scale_clause(<setDecFloatBindNode>)
decfloat_scale_clause($setDecFloatBindNode)
%type decfloat_scale_clause(<setHighPrecBindNode>)
decfloat_scale_clause($setHighPrecBindNode)
: // nothing
| ',' signed_long_integer
{
if ($2 > DecimalBinding::MAX_SCALE || $2 < 0)
if ($2 > NumericBinding::MAX_SCALE || $2 < 0)
yyabandon(YYPOSNARG(2), -842, isc_scale_nogt); // Scale must be between 0 and precision
$setDecFloatBindNode->bind.numScale = -$2;
$setHighPrecBindNode->bind.numScale = -$2;
}
%type <setSessionNode> session_statement

View File

@ -34,6 +34,7 @@ typedef ISC_TIME_TZ;
typedef ISC_TIMESTAMP_TZ;
typedef FB_DEC16;
typedef FB_DEC34;
typedef FB_I128;
typedef isc_tr_handle;
typedef isc_stmt_handle;
@ -1093,7 +1094,7 @@ interface Util : Versioned
XpbBuilder getXpbBuilder(Status status, uint kind, const uchar* buf, uint len);
uint setOffsets(Status status, MessageMetadata metadata, OffsetsCallback callback);
version: // 3.0 => 4.0
version: // 3.0 => 4.0 Alpha1
DecFloat16 getDecFloat16(Status status);
DecFloat34 getDecFloat34(Status status);
Transaction getTransactionByHandle(Status status, isc_tr_handle* hndlPtr);
@ -1106,6 +1107,9 @@ version: // 3.0 => 4.0
uint fractions, const string timeZone);
void encodeTimeStampTz(Status status, ISC_TIMESTAMP_TZ* timeStampTz, uint year, uint month, uint day,
uint hours, uint minutes, uint seconds, uint fractions, const string timeZone);
version: // 4.0 Beta1 => 4.0 Beta2
Int128 getInt128(Status status);
}
interface OffsetsCallback : Versioned
@ -1515,6 +1519,15 @@ interface DecFloat34 : Versioned
void fromString(Status status, const string from, FB_DEC34* to);
}
interface Int128 : Versioned
{
// - 170141183460469231731687303715884105728 e - 128 \0
// 1 + 39 + 1 + 1 + 3 + 1 = 46
const uint STRING_SIZE = 46; // includes terminating \0
void toString(Status status, const FB_I128* from, int scale, uint bufferLength, string buffer);
void fromString(Status status, int scale, const string from, FB_I128* to);
}
// Replication interfaces
interface ReplicatedRecord : Versioned

View File

@ -116,6 +116,7 @@ namespace Firebird
class IUdrPlugin;
class IDecFloat16;
class IDecFloat34;
class IInt128;
class IReplicatedRecord;
class IReplicatedBlob;
class IReplicatedTransaction;
@ -4051,6 +4052,7 @@ namespace Firebird
void (CLOOP_CARG *decodeTimeStampTz)(IUtil* self, IStatus* status, const ISC_TIMESTAMP_TZ* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) throw();
void (CLOOP_CARG *encodeTimeTz)(IUtil* self, IStatus* status, ISC_TIME_TZ* timeTz, unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone) throw();
void (CLOOP_CARG *encodeTimeStampTz)(IUtil* self, IStatus* status, ISC_TIMESTAMP_TZ* timeStampTz, unsigned year, unsigned month, unsigned day, unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone) throw();
IInt128* (CLOOP_CARG *getInt128)(IUtil* self, IStatus* status) throw();
};
protected:
@ -4064,7 +4066,7 @@ namespace Firebird
}
public:
static const unsigned VERSION = 3;
static const unsigned VERSION = 4;
template <typename StatusType> void getFbVersion(StatusType* status, IAttachment* att, IVersionCallback* callback)
{
@ -4259,6 +4261,20 @@ namespace Firebird
static_cast<VTable*>(this->cloopVTable)->encodeTimeStampTz(this, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZone);
StatusType::checkException(status);
}
template <typename StatusType> IInt128* getInt128(StatusType* status)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IUtil", cloopVTable->version, 4);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
IInt128* ret = static_cast<VTable*>(this->cloopVTable)->getInt128(this, status);
StatusType::checkException(status);
return ret;
}
};
class IOffsetsCallback : public IVersioned
@ -5856,6 +5872,45 @@ namespace Firebird
}
};
class IInt128 : public IVersioned
{
public:
struct VTable : public IVersioned::VTable
{
void (CLOOP_CARG *toString)(IInt128* self, IStatus* status, const FB_I128* from, int scale, unsigned bufferLength, char* buffer) throw();
void (CLOOP_CARG *fromString)(IInt128* self, IStatus* status, int scale, const char* from, FB_I128* to) throw();
};
protected:
IInt128(DoNotInherit)
: IVersioned(DoNotInherit())
{
}
~IInt128()
{
}
public:
static const unsigned VERSION = 2;
static const unsigned STRING_SIZE = 46;
template <typename StatusType> void toString(StatusType* status, const FB_I128* from, int scale, unsigned bufferLength, char* buffer)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->toString(this, status, from, scale, bufferLength, buffer);
StatusType::checkException(status);
}
template <typename StatusType> void fromString(StatusType* status, int scale, const char* from, FB_I128* to)
{
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->fromString(this, status, scale, from, to);
StatusType::checkException(status);
}
};
class IReplicatedRecord : public IVersioned
{
public:
@ -14332,6 +14387,7 @@ namespace Firebird
this->decodeTimeStampTz = &Name::cloopdecodeTimeStampTzDispatcher;
this->encodeTimeTz = &Name::cloopencodeTimeTzDispatcher;
this->encodeTimeStampTz = &Name::cloopencodeTimeStampTzDispatcher;
this->getInt128 = &Name::cloopgetInt128Dispatcher;
}
} vTable;
@ -14630,6 +14686,21 @@ namespace Firebird
StatusType::catchException(&status2);
}
}
static IInt128* CLOOP_CARG cloopgetInt128Dispatcher(IUtil* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::getInt128(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<IInt128*>(0);
}
}
};
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IUtil> > >
@ -14666,6 +14737,7 @@ namespace Firebird
virtual void decodeTimeStampTz(StatusType* status, const ISC_TIMESTAMP_TZ* timeStampTz, unsigned* year, unsigned* month, unsigned* day, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, unsigned timeZoneBufferLength, char* timeZoneBuffer) = 0;
virtual void encodeTimeTz(StatusType* status, ISC_TIME_TZ* timeTz, unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone) = 0;
virtual void encodeTimeStampTz(StatusType* status, ISC_TIMESTAMP_TZ* timeStampTz, unsigned year, unsigned month, unsigned day, unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone) = 0;
virtual IInt128* getInt128(StatusType* status) = 0;
};
template <typename Name, typename StatusType, typename Base>
@ -18081,6 +18153,73 @@ namespace Firebird
virtual void fromString(StatusType* status, const char* from, FB_DEC34* to) = 0;
};
template <typename Name, typename StatusType, typename Base>
class IInt128BaseImpl : public Base
{
public:
typedef IInt128 Declaration;
IInt128BaseImpl(DoNotInherit = DoNotInherit())
{
static struct VTableImpl : Base::VTable
{
VTableImpl()
{
this->version = Base::VERSION;
this->toString = &Name::clooptoStringDispatcher;
this->fromString = &Name::cloopfromStringDispatcher;
}
} vTable;
this->cloopVTable = &vTable;
}
static void CLOOP_CARG clooptoStringDispatcher(IInt128* self, IStatus* status, const FB_I128* from, int scale, unsigned bufferLength, char* buffer) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::toString(&status2, from, scale, bufferLength, buffer);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopfromStringDispatcher(IInt128* self, IStatus* status, int scale, const char* from, FB_I128* to) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::fromString(&status2, scale, from, to);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
};
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IInt128> > >
class IInt128Impl : public IInt128BaseImpl<Name, StatusType, Base>
{
protected:
IInt128Impl(DoNotInherit = DoNotInherit())
{
}
public:
virtual ~IInt128Impl()
{
}
virtual void toString(StatusType* status, const FB_I128* from, int scale, unsigned bufferLength, char* buffer) = 0;
virtual void fromString(StatusType* status, int scale, const char* from, FB_I128* to) = 0;
};
template <typename Name, typename StatusType, typename Base>
class IReplicatedRecordBaseImpl : public Base
{

View File

@ -69,7 +69,7 @@
#define blr_bool (unsigned char)23
#define blr_dec64 (unsigned char)24
#define blr_dec128 (unsigned char)25
#define blr_dec_fixed (unsigned char)26
#define blr_int128 (unsigned char)26
#define blr_sql_time_tz (unsigned char)28
#define blr_timestamp_tz (unsigned char)29

View File

@ -129,6 +129,7 @@
#define isc_dpb_decfloat_bind 94
#define isc_dpb_decfloat_round 95
#define isc_dpb_decfloat_traps 96
#define isc_dpb_int128_bind 97
/**************************************************/

View File

@ -63,7 +63,7 @@
#define dtype_boolean 21
#define dtype_dec64 22
#define dtype_dec128 23
#define dtype_dec_fixed 24
#define dtype_int128 24
#define dtype_sql_time_tz 25
#define dtype_timestamp_tz 26
#define DTYPE_TYPE_MAX 27

View File

@ -78,9 +78,9 @@ typedef struct
#define SQL_TYPE_TIME 560
#define SQL_TYPE_DATE 570
#define SQL_INT64 580
#define SQL_INT128 32752
#define SQL_TIMESTAMP_TZ 32754
#define SQL_TIME_TZ 32756
#define SQL_DEC_FIXED 32758
#define SQL_DEC16 32760
#define SQL_DEC34 32762
#define SQL_BOOLEAN 32764

View File

@ -197,7 +197,12 @@ struct FB_DEC34_t {
ISC_UINT64 fb_data[2];
};
struct FB_I128_t {
ISC_UINT64 fb_data[2];
};
typedef struct FB_DEC16_t FB_DEC16;
typedef struct FB_DEC34_t FB_DEC34;
typedef struct FB_I128_t FB_I128;
#endif /* FIREBIRD_IMPL_TYPES_PUB_H */

View File

@ -320,6 +320,7 @@ IsqlGlobals::IsqlGlobals()
df16 = Firebird::UtilInterfacePtr()->getDecFloat16(&statusWrapper);
df34 = Firebird::UtilInterfacePtr()->getDecFloat34(&statusWrapper);
i128 = Firebird::UtilInterfacePtr()->getInt128(&statusWrapper);
}
// I s q l G l o b a l s : : p r i n t f
@ -1838,7 +1839,7 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int
case INTEGER:
case BIGINT:
case DOUBLE_PRECISION:
case DEC_FIXED_TYPE:
case blr_int128:
// Handle Integral subtypes NUMERIC and DECIMAL
// We are ODS >= 10 and could be any Dialect
@ -1872,8 +1873,8 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int
case DOUBLE_PRECISION:
isqlGlob.printf("NUMERIC(15, %d)", -fieldScale);
break;
case DEC_FIXED_TYPE:
isqlGlob.printf("NUMERIC(34, %d)", -fieldScale);
case blr_int128:
isqlGlob.printf("NUMERIC(38, %d)", -fieldScale);
break;
}
}
@ -2288,6 +2289,7 @@ static processing_state add_row(TEXT* tabname)
double* dvalue;
FB_DEC16* d64value;
FB_DEC34* d128value;
FB_I128* i128value;
UCHAR* boolean;
ISC_QUAD* blobid;
vary* avary;
@ -2361,11 +2363,27 @@ static processing_state add_row(TEXT* tabname)
if ((!isqlGlob.df16) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
{
STDERROUT("Input parsing problem");
ISQL_errmsg(fbStatus);
done = true;
}
break;
case SQL_INT128:
scale = msg->getScale(fbStatus, i);
if (ISQL_errmsg(fbStatus))
return (SKIP);
i128value = (FB_I128*) datap;
if (isqlGlob.i128)
isqlGlob.i128->fromString(fbStatus, scale, lastInputLine, i128value);
if ((!isqlGlob.i128) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
{
STDERROUT("Input parsing problem");
ISQL_errmsg(fbStatus);
done = true;
}
break;
case SQL_DEC_FIXED:
case SQL_DEC34:
d128value = (FB_DEC34*) datap;
if (isqlGlob.df34)
@ -2373,6 +2391,7 @@ static processing_state add_row(TEXT* tabname)
if ((!isqlGlob.df34) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
{
STDERROUT("Input parsing problem");
ISQL_errmsg(fbStatus);
done = true;
}
break;
@ -3068,6 +3087,7 @@ static processing_state bulk_insert_hack(const char* command)
tm times;
FB_DEC16* d64value;
FB_DEC34* d128value;
FB_I128* i128value;
// Initialize the time structure.
memset(&times, 0, sizeof(times));
char msec_str[5] = "";
@ -3134,18 +3154,38 @@ static processing_state bulk_insert_hack(const char* command)
if ((!isqlGlob.df16) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
{
STDERROUT("Input parsing problem");
ISQL_errmsg(fbStatus);
done = true;
}
break;
case SQL_DEC34:
case SQL_DEC_FIXED:
d128value = (FB_DEC34*) datap;
if (isqlGlob.df34)
isqlGlob.df34->fromString(fbStatus, get_numeric_value(lastPos).c_str(), d128value);
if ((!isqlGlob.df34) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
{
STDERROUT("Input parsing problem");
ISQL_errmsg(fbStatus);
done = true;
}
break;
case SQL_INT128:
scale = message->getScale(fbStatus, i);
if (ISQL_errmsg(fbStatus))
return (SKIP);
i128value = (FB_I128*) datap;
if (isqlGlob.i128)
{
isqlGlob.i128->fromString(fbStatus, scale,
get_numeric_value(lastPos).c_str(), i128value);
}
if ((!isqlGlob.i128) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
{
STDERROUT("Input parsing problem");
ISQL_errmsg(fbStatus);
done = true;
}
break;
@ -7312,7 +7352,6 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
break;
case SQL_DEC34:
case SQL_DEC_FIXED:
{
char decStr[Firebird::IDecFloat34::STRING_SIZE];
if (isqlGlob.df34)
@ -7325,9 +7364,34 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
strcpy(decStr, convErr);
if (setValues.List)
isqlGlob.printf("%*.*s%s", sizeof(decStr) - 1, sizeof(decStr) - 1, decStr, NEWLINE);
{
isqlGlob.printf("%*.*s%s", int(sizeof(decStr) - 1), int(sizeof(decStr) - 1),
decStr, NEWLINE);
}
else
sprintf(p, "%*.*s ", sizeof(decStr) - 1, sizeof(decStr) - 1, decStr);
sprintf(p, "%*.*s ", int(sizeof(decStr) - 1), int(sizeof(decStr) - 1), decStr);
}
break;
case SQL_INT128:
{
char intStr[Firebird::IInt128::STRING_SIZE];
if (isqlGlob.i128)
{
isqlGlob.i128->toString(fbStatus, var->value.asInt128, dscale, sizeof(intStr), intStr);
if (ISQL_errmsg(fbStatus))
strcpy(intStr, convErr);
}
else
strcpy(intStr, convErr);
if (setValues.List)
{
isqlGlob.printf("%*.*s%s", int(sizeof(intStr) - 1), int(sizeof(intStr) - 1),
intStr, NEWLINE);
}
else
sprintf(p, "%*.*s ", int(sizeof(intStr) - 1), int(sizeof(intStr) - 1), intStr);
}
break;
@ -8169,7 +8233,9 @@ static unsigned process_message_display(Firebird::IMessageMetadata* message, uns
case SQL_DEC16:
disp_length = Firebird::IDecFloat16::STRING_SIZE - 1;
break;
case SQL_DEC_FIXED:
case SQL_INT128:
disp_length = Firebird::IInt128::STRING_SIZE - 1;
break;
case SQL_DEC34:
disp_length = Firebird::IDecFloat34::STRING_SIZE - 1;
break;
@ -8847,8 +8913,8 @@ static const char* sqltype_to_string(unsigned sqltype)
return "DECFLOAT(16)";
case SQL_DEC34:
return "DECFLOAT(34)";
case SQL_DEC_FIXED:
return "DECIMAL FIXED";
case SQL_INT128:
return "NUMERIC(38)";
case SQL_D_FLOAT:
return "D_FLOAT";
case SQL_TIMESTAMP:

View File

@ -306,7 +306,6 @@ const int BIGINT = 16;
const int BOOLEAN_TYPE = 23;
const int DEC64_TYPE = 24;
const int DEC128_TYPE = 25;
const int DEC_FIXED_TYPE = 26;
static const sqltypes Column_types[] = {
{SMALLINT, "SMALLINT"}, // keyword
@ -326,7 +325,7 @@ static const sqltypes Column_types[] = {
{BOOLEAN_TYPE, "BOOLEAN"}, // keyword
{DEC64_TYPE, "DECFLOAT(16)"},
{DEC128_TYPE, "DECFLOAT(34)"},
{DEC_FIXED_TYPE, "<Should not be shown>"},
{blr_int128, "INT64"},
{blr_sql_time_tz, "TIME WITH TIME ZONE"}, // keyword
{blr_timestamp_tz, "TIMESTAMP WITH TIME ZONE"}, // keyword
{0, ""}
@ -417,6 +416,7 @@ public:
USHORT att_charset;
Firebird::IDecFloat16* df16;
Firebird::IDecFloat34* df34;
Firebird::IInt128* i128;
void printf(const char* buffer, ...);
void prints(const char* buffer);
@ -478,6 +478,7 @@ struct IsqlVar
char* asChar;
FB_DEC16* asDec16;
FB_DEC34* asDec34;
FB_I128* asInt128;
void* setPtr;
};
TypeMix value;

View File

@ -243,7 +243,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb, const InitialOption
att_internal(*pool),
att_dyn_req(*pool),
att_dec_status(DecimalStatus::DEFAULT),
att_dec_binding(DecimalBinding::DEFAULT),
att_dec_binding(NumericBinding::DEFAULT),
att_charsets(*pool),
att_charset_ids(*pool),
att_pools(*pool),

View File

@ -363,8 +363,11 @@ public:
void resetAttachment(Attachment* attachment) const;
private:
void setBinding(Firebird::string option, Firebird::NumericBinding& bind);
Firebird::DecimalStatus decFloatStatus = Firebird::DecimalStatus::DEFAULT;
Firebird::DecimalBinding decFloatBinding = Firebird::DecimalBinding::DEFAULT;
Firebird::NumericBinding decFloatBinding = Firebird::NumericBinding::DEFAULT;
Firebird::NumericBinding int128Binding = Firebird::NumericBinding::DEFAULT;
Firebird::TimeZoneUtil::Bind timeZoneBind = Firebird::TimeZoneUtil::BIND_NATIVE;
USHORT originalTimeZone = Firebird::TimeZoneUtil::GMT_ZONE;
@ -466,7 +469,8 @@ public:
Firebird::Array<JrdStatement*> att_dyn_req; // internal dyn statements
Firebird::ICryptKeyCallback* att_crypt_callback; // callback for DB crypt
Firebird::DecimalStatus att_dec_status; // error handling and rounding
Firebird::DecimalBinding att_dec_binding; // use legacy datatype for DecFloat in outer world
Firebird::NumericBinding att_dec_binding; // use legacy datatype for DecFloat in outer world
Firebird::NumericBinding att_i128_binding; // use legacy datatype for INT128 in outer world
jrd_req* findSystemRequest(thread_db* tdbb, USHORT id, USHORT which);

View File

@ -1570,9 +1570,6 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T
if (field)
{
dsc d(relFormat->fmt_desc[i]);
if (d.dsc_dtype == dtype_dec_fixed)
d.dsc_dtype = dtype_dec128;
fieldsMsg->addItem(field->fld_name, !field->fld_not_null, d);
}
}

View File

@ -109,10 +109,10 @@ namespace
item.length = sizeof(Decimal128);
break;
case dtype_dec_fixed:
item.type = SQL_DEC_FIXED;
case dtype_int128:
item.type = SQL_INT128;
item.scale = desc->dsc_scale;
item.length = sizeof(DecimalFixed);
item.length = sizeof(Int128);
break;
case dtype_sql_date:

View File

@ -44,7 +44,7 @@ MsgMetadata* Routine::createMetadata(const Array<NestConst<Parameter> >& paramet
++i)
{
dsc d((*i)->prm_desc);
if (isExtern && d.dsc_dtype == dtype_dec_fixed)
if (isExtern && d.dsc_dtype == dtype_int128)
d.dsc_dtype = dtype_dec128;
metadata->addItem((*i)->prm_name, (*i)->prm_nullable, d);
}

View File

@ -33,6 +33,7 @@ Maximum alignments for corresponding data types are defined in dsc.h
*/
#include "../common/DecFloat.h"
#include "../common/Int128.h"
#include "firebird/impl/blr.h"
/* The following macro must be defined as the highest-numericly-valued
@ -70,7 +71,7 @@ static const USHORT gds_cvt_blr_dtype[DTYPE_BLR_MAX + 1] =
dtype_boolean, // blr_bool == 23
dtype_dec64, /* blr_dec64 == 24 */
dtype_dec128, /* blr_dec128 == 25 */
dtype_dec_fixed, /* blr_dec_fixed == 26 */
dtype_int128, /* blr_int128 == 26 */
dtype_double, /* blr_double == 27 */
dtype_sql_time_tz, /* blr_sql_time_tz == 28 */
dtype_timestamp_tz, /* blr_timestamp_tz == 29 */
@ -111,7 +112,7 @@ static const USHORT type_alignments[DTYPE_TYPE_MAX] =
sizeof(UCHAR), /* dtype_boolean */
sizeof(Firebird::Decimal64),/* dtype_dec64 */
sizeof(Firebird::Decimal64),/* dtype_dec128 */
sizeof(Firebird::Decimal64),/* dtype_dec_fixed */
sizeof(Firebird::Decimal64),/* dtype_int128 */
sizeof(GDS_TIME), /* dtype_sql_time_tz */
sizeof(GDS_DATE) /* dtype_timestamp_tz */
};
@ -142,7 +143,7 @@ static const USHORT type_lengths[DTYPE_TYPE_MAX] =
sizeof(UCHAR), /* dtype_boolean */
sizeof(Firebird::Decimal64),/* dtype_dec64 */
sizeof(Firebird::Decimal128),/*dtype_dec128 */
sizeof(Firebird::DecimalFixed), /* dtype_dec_fixed */
sizeof(Firebird::Int128), /* dtype_int128 */
sizeof(ISC_TIME_TZ), /* dtype_sql_time_tz */
sizeof(ISC_TIMESTAMP_TZ) /* dtype_timestamp_tz */
};
@ -176,7 +177,7 @@ static const USHORT type_significant_bits[DTYPE_TYPE_MAX] =
0, // dtype_boolean
0, // dtype_dec64
0, // dtype_dec128
0, // dtype_dec_fixed
0, // dtype_int128
0, // dtype_sql_time_tz
0 // dtype_timestamp_tz
};

View File

@ -223,19 +223,20 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v
// tricky: the value doesn't always become negative after an
// overflow!
if (value >= NUMERIC_LIMIT)
if (!over)
{
// possibility of an overflow
if ((value > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1))
if (value >= NUMERIC_LIMIT)
{
over = true;
break;
// possibility of an overflow
if ((value > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1))
over = true;
}
// Force the subtraction to be performed before the addition,
// thus preventing a possible signed arithmetic overflow.
value = value * 10 + (*p - '0');
}
// Force the subtraction to be performed before the addition,
// thus preventing a possible signed arithmetic overflow.
value = value * 10 + (*p - '0');
if (fraction)
--local_scale;
}
@ -262,6 +263,8 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v
if ((local_scale > MAX_SCHAR) || (local_scale < MIN_SCHAR))
over = true;
*scale = local_scale;
if ((!over) && ((p < end) || // there is an exponent
((value < 0) && (sign != -1)))) // MAX_SINT64+1 wrapped around
{
@ -278,8 +281,6 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v
return dtype_dec128;
}
*scale = local_scale;
// The literal has already been converted to a 64-bit integer: return
// a long if the value fits into a long, else return an int64.

View File

@ -85,7 +85,7 @@ const BYTE CVT2_compare_priority[] =
9, // dtype_long
// Move quad up by one to make room for int64 at its proper place in the table.
11, // dtype_quad
// Also leave space for dec_fixed, dec64 and dec 128.
// Also leave space for int128, dec64 and dec 128.
15, // dtype_real
16, // dtype_double
17, // dtype_d_float
@ -99,8 +99,8 @@ const BYTE CVT2_compare_priority[] =
10, // dtype_int64 - goes right after long
25, // dtype_dbkey - compares with nothing except itself
26, // dtype_boolean - compares with nothing except itself
12, // dtype_dec_fixed - go after quad
13, // dec64 - go after dtype_dec_fixed
12, // dtype_int128 - go after quad
13, // dec64 - go after dtype_int128
14, // dec128 - go after dec64 and before real
20, // dtype_sql_time_tz - go after dtype_sql_time
22 // dtype_timestamp_tz - go after dtype_timestamp
@ -305,8 +305,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
case dtype_dec128:
return ((Decimal128*) p1)->compare(decSt, *(Decimal128*) p2);
case dtype_dec_fixed:
return ((DecimalFixed*) p1)->compare(decSt, *(DecimalFixed*) p2);
case dtype_int128:
return ((Int128*) p1)->compare(*(Int128*) p2);
case dtype_boolean:
return *p1 == *p2 ? 0 : *p1 < *p2 ? -1 : 1;
@ -564,7 +564,7 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
return temp1.compare(decSt, temp2);
}
case dtype_dec_fixed:
case dtype_int128:
{
SSHORT scale;
if (arg2->dsc_dtype > dtype_varying)
@ -572,9 +572,9 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
else
scale = arg1->dsc_scale;
const DecimalFixed temp1 = CVT_get_dec_fixed(arg1, scale, decSt, ERR_post);
const DecimalFixed temp2 = CVT_get_dec_fixed(arg2, scale, decSt, ERR_post);
return temp1.compare(decSt, temp2);
const Int128 temp1 = CVT_get_int128(arg1, scale, decSt, ERR_post);
const Int128 temp2 = CVT_get_int128(arg2, scale, decSt, ERR_post);
return temp1.compare(temp2);
}
case dtype_blob:

View File

@ -1302,7 +1302,7 @@ USHORT DFW_assign_index_type(thread_db* tdbb, const Firebird::MetaName& name, SS
return idx_boolean;
case dtype_dec64:
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
return idx_decimal;
default:
return idx_numeric;

View File

@ -432,8 +432,8 @@ void EVL_make_value(thread_db* tdbb, const dsc* desc, impure_value* value, Memor
value->vlu_misc.vlu_dec128 = *((Decimal128*) from.dsc_address);
return;
case dtype_dec_fixed:
value->vlu_misc.vlu_dec_fixed = *((DecimalFixed*) from.dsc_address);
case dtype_int128:
value->vlu_misc.vlu_int128 = *((Int128*) from.dsc_address);
return;
case dtype_sql_time:

View File

@ -64,7 +64,6 @@ DEFINE_TRACE_ROUTINE(cmp_trace);
#endif
class VaryingString;
struct dsc;
namespace Jrd {
@ -463,7 +462,7 @@ public:
csb_currentForNode(NULL),
csb_currentDMLNode(NULL),
csb_currentAssignTarget(NULL),
csb_preferredDataType(0),
csb_preferredDesc(NULL),
csb_rpt(p)
{
csb_dbg_info = FB_NEW_POOL(p) Firebird::DbgInfo(p);
@ -546,7 +545,7 @@ public:
ForNode* csb_currentForNode;
StmtNode* csb_currentDMLNode; // could be StoreNode or ModifyNode
ExprNode* csb_currentAssignTarget;
UCHAR csb_preferredDataType; // expected by receiving side datatype
dsc* csb_preferredDesc; // expected by receiving side data format
struct csb_repeat
{

View File

@ -606,7 +606,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
break;
case dtype_dec128:
case dtype_dec_fixed:
case dtype_int128:
{
const Decimal128 d = MOV_get_dec128(tdbb, input);
if (parameter->prm_fun_mechanism == FUN_value)
@ -820,21 +820,6 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
Arg::Str(function->getName().toString()));
}
break;
case dtype_dec_fixed:
if (value->vlu_misc.vlu_dec_fixed.isInf())
{
status_exception::raise(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_udf_fp_overflow) <<
Arg::Str(function->getName().toString()));
}
else if (value->vlu_misc.vlu_dec_fixed.isNan())
{
status_exception::raise(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_udf_fp_nan) <<
Arg::Str(function->getName().toString()));
}
break;
}
request->req_flags &= ~req_null;
@ -1148,8 +1133,8 @@ static void invoke(thread_db* tdbb,
value->vlu_misc.vlu_dec128 = CALL_UDF<Decimal128>(tdbb, function->fun_entrypoint, args);
break;
case dtype_dec_fixed:
value->vlu_misc.vlu_dec_fixed = CALL_UDF<DecimalFixed>(tdbb, function->fun_entrypoint, args);
case dtype_int128:
value->vlu_misc.vlu_int128 = CALL_UDF<Int128>(tdbb, function->fun_entrypoint, args);
break;
case dtype_timestamp:

View File

@ -1020,6 +1020,7 @@ namespace Jrd
string dpb_decfloat_bind;
string dpb_decfloat_round;
string dpb_decfloat_traps;
string dpb_int128_bind;
public:
static const ULONG DPB_FLAGS_MASK = DBB_damaged;
@ -1062,6 +1063,43 @@ namespace Jrd
}
};
void Attachment::InitialOptions::setBinding(string option, NumericBinding& bind)
{
option.lower();
if (option == "native")
bind = NumericBinding::DEFAULT;
else if (option == "char" || option == "character")
bind = NumericBinding(NumericBinding::NUM_TEXT);
else if (option == "double" || option == "double precision")
bind = NumericBinding(NumericBinding::NUM_DOUBLE);
else if (option == "bigint")
bind = NumericBinding(NumericBinding::NUM_INT64);
else if (option.substr(0, 7) == "bigint,")
{
const char* p = option.c_str() + 7;
while (*p == ' ')
++p;
const char* start = p;
int scale = 0;
while (*p >= '0' && *p <= '9')
{
scale = scale * 10 + (*p - '0');
++p;
}
if (*p != '\0' || p - start == 0 || p - start > 2 || scale > NumericBinding::MAX_SCALE)
(Arg::Gds(isc_invalid_decfloat_bind) << option).raise();
bind = NumericBinding(NumericBinding::NUM_INT64, static_cast<SCHAR>(-scale));
}
else
(Arg::Gds(isc_invalid_decfloat_bind) << option).raise();
}
Attachment::InitialOptions::InitialOptions(const DatabaseOptions& options)
{
if (options.dpb_time_zone_bind.hasData())
@ -1078,42 +1116,10 @@ namespace Jrd
}
if (options.dpb_decfloat_bind.hasData())
{
auto option = options.dpb_decfloat_bind;
option.lower();
setBinding(options.dpb_decfloat_bind, decFloatBinding);
if (option == "native")
decFloatBinding = DecimalBinding::DEFAULT;
else if (option == "char" || option == "character")
decFloatBinding = DecimalBinding(DecimalBinding::DEC_TEXT);
else if (option == "double" || option == "double precision")
decFloatBinding = DecimalBinding(DecimalBinding::DEC_DOUBLE);
else if (option == "bigint")
decFloatBinding = DecimalBinding(DecimalBinding::DEC_NUMERIC);
else if (option.substr(0, 7) == "bigint,")
{
const char* p = option.c_str() + 7;
while (*p == ' ')
++p;
const char* start = p;
int scale = 0;
while (*p >= '0' && *p <= '9')
{
scale = scale * 10 + (*p - '0');
++p;
}
if (*p != '\0' || p - start == 0 || p - start > 2 || scale > DecimalBinding::MAX_SCALE)
(Arg::Gds(isc_invalid_decfloat_bind) << option).raise();
decFloatBinding = DecimalBinding(DecimalBinding::DEC_NUMERIC, static_cast<SCHAR>(-scale));
}
else
(Arg::Gds(isc_invalid_decfloat_bind) << option).raise();
}
if (options.dpb_int128_bind.hasData())
setBinding(options.dpb_int128_bind, int128Binding);
if (options.dpb_decfloat_round.hasData())
{
@ -1172,6 +1178,7 @@ namespace Jrd
// reset DecFloat options
attachment->att_dec_status = decFloatStatus;
attachment->att_dec_binding = decFloatBinding;
attachment->att_i128_binding = int128Binding;
// reset time zone options
attachment->att_timezone_bind = timeZoneBind;
@ -6969,6 +6976,10 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
rdr.getString(dpb_decfloat_bind);
break;
case isc_dpb_int128_bind:
rdr.getString(dpb_int128_bind);
break;
case isc_dpb_decfloat_round:
rdr.getString(dpb_decfloat_round);
break;

View File

@ -450,42 +450,6 @@ void MOV_move(Jrd::thread_db* tdbb, /*const*/ dsc* from, dsc* to)
}
void MOV_move_ext(Jrd::thread_db* tdbb, /*const*/ dsc* from, dsc* to, bool toExtern)
{
/**************************************
*
* M O V _ m o v e _ e x t
*
**************************************
*
* Functional description
* Move data to/from outer world.
*
**************************************/
MOV_move(tdbb, from, to);
switch (to->dsc_dtype)
{
case dtype_dec_fixed:
if (toExtern)
{
((Decimal128*) to->dsc_address)->setScale(tdbb->getAttachment()->att_dec_status,
to->dsc_scale);
}
else
{
((DecimalFixed*) to->dsc_address)->exactInt(tdbb->getAttachment()->att_dec_status,
to->dsc_scale);
}
break;
default:
break;
}
}
Decimal64 MOV_get_dec64(Jrd::thread_db* tdbb, const dsc* desc)
{
/**************************************
@ -510,7 +474,7 @@ Decimal128 MOV_get_dec128(Jrd::thread_db* tdbb, const dsc* desc)
}
DecimalFixed MOV_get_dec_fixed(Jrd::thread_db* tdbb, const dsc* desc, SSHORT scale)
Int128 MOV_get_int128(Jrd::thread_db* tdbb, const dsc* desc, SSHORT scale)
{
/**************************************
*
@ -518,7 +482,7 @@ DecimalFixed MOV_get_dec_fixed(Jrd::thread_db* tdbb, const dsc* desc, SSHORT sca
*
**************************************/
return CVT_get_dec_fixed(desc, scale, tdbb->getAttachment()->att_dec_status, ERR_post);
return CVT_get_int128(desc, scale, tdbb->getAttachment()->att_dec_status, ERR_post);
}

View File

@ -52,10 +52,9 @@ int MOV_make_string2(Jrd::thread_db*, const dsc*, USHORT, UCHAR**, Jrd::MoveBuf
Firebird::string MOV_make_string2(Jrd::thread_db* tdbb, const dsc* desc, USHORT ttype,
bool limit = true);
void MOV_move(Jrd::thread_db*, /*const*/ dsc*, dsc*);
void MOV_move_ext(Jrd::thread_db* tdbb, /*const*/ dsc* from, dsc* to, bool toExtern);
Firebird::Decimal64 MOV_get_dec64(Jrd::thread_db*, const dsc*);
Firebird::Decimal128 MOV_get_dec128(Jrd::thread_db*, const dsc*);
Firebird::DecimalFixed MOV_get_dec_fixed(Jrd::thread_db*, const dsc*, SSHORT);
Firebird::Int128 MOV_get_int128(Jrd::thread_db*, const dsc*, SSHORT);
namespace Jrd
{

View File

@ -419,7 +419,7 @@ static const UCHAR sort_dtypes[] =
SKD_bytes, // dtype_boolean
SKD_dec64, // dtype_dec64
SKD_dec128, // dtype_dec128
SKD_dec128, // dtype_dec_fixed
SKD_int128, // dtype_int128
SKD_sql_time_tz, // dtype_sql_time_tz
SKD_timestamp_tz // dtype_timestamp_tz
};

View File

@ -405,9 +405,9 @@ USHORT PAR_datatype(BlrReader& blrReader, dsc* desc)
desc->dsc_length = sizeof(Decimal128);
break;
case blr_dec_fixed:
desc->dsc_dtype = dtype_dec_fixed;
desc->dsc_length = sizeof(DecimalFixed);
case blr_int128:
desc->dsc_dtype = dtype_int128;
desc->dsc_length = sizeof(Int128);
desc->dsc_scale = (int) blrReader.getByte();
break;

View File

@ -804,6 +804,7 @@ void Sort::diddleKey(UCHAR* record, bool direction, bool duplicateHandling)
case SKD_timestamp:
case SKD_sql_date:
case SKD_int64:
case SKD_int128:
*p ^= 1 << 7;
break;
@ -1047,6 +1048,24 @@ void Sort::diddleKey(UCHAR* record, bool direction, bool duplicateHandling)
SWAP_LONGS(lwp[0], lwp[1], lw);
break;
case SKD_int128:
// INT128 fits in four long, and hence two swaps should happen
// here for the right order comparison using DO_32_COMPARE
if (!direction)
{
SWAP_LONGS(lwp[0], lwp[3], lw);
SWAP_LONGS(lwp[1], lwp[2], lw);
}
p[15] ^= 1 << 7;
if (direction)
{
SWAP_LONGS(lwp[0], lwp[3], lw);
SWAP_LONGS(lwp[1], lwp[2], lw);
}
break;
#ifdef IEEE
case SKD_double:
if (!direction)

View File

@ -145,6 +145,7 @@ const int SKD_dec64 = 16;
const int SKD_dec128 = 17;
const int SKD_sql_time_tz = 18;
const int SKD_timestamp_tz = 19;
const int SKD_int128 = 20;
// skd_flags
const UCHAR SKD_ascending = 0; // default initializer

View File

@ -85,7 +85,7 @@ struct impure_value
double vlu_double;
Firebird::Decimal64 vlu_dec64;
Firebird::Decimal128 vlu_dec128;
Firebird::DecimalFixed vlu_dec_fixed;
Firebird::Int128 vlu_int128;
GDS_TIMESTAMP vlu_timestamp;
ISC_TIMESTAMP_TZ vlu_timestamp_tz;
GDS_TIME vlu_sql_time;
@ -101,7 +101,7 @@ struct impure_value
void make_int64(const SINT64 val, const signed char scale = 0);
void make_double(const double val);
void make_decimal128(const Firebird::Decimal128 val);
void make_decimal_fixed(const Firebird::DecimalFixed val, const signed char scale);
void make_decimal_fixed(const Firebird::Int128 val, const signed char scale);
};
// Do not use these methods where dsc_sub_type is not explicitly set to zero.
@ -145,14 +145,14 @@ inline void impure_value::make_decimal128(const Firebird::Decimal128 val)
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_dec128);
}
inline void impure_value::make_decimal_fixed(const Firebird::DecimalFixed val, const signed char scale)
inline void impure_value::make_decimal_fixed(const Firebird::Int128 val, const signed char scale)
{
this->vlu_misc.vlu_dec_fixed = val;
this->vlu_desc.dsc_dtype = dtype_dec_fixed;
this->vlu_desc.dsc_length = sizeof(Firebird::DecimalFixed);
this->vlu_misc.vlu_int128 = val;
this->vlu_desc.dsc_dtype = dtype_int128;
this->vlu_desc.dsc_length = sizeof(Firebird::Int128);
this->vlu_desc.dsc_scale = scale;
this->vlu_desc.dsc_sub_type = 0;
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_dec_fixed);
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_int128);
}
struct impure_value_ex : public impure_value

View File

@ -17,7 +17,7 @@
ISC_QUAD = array [1..2] of Integer;
FB_DEC16 = array [1..1] of Int64;
FB_DEC34 = array [1..2] of Int64;
FB_DEC_FIXED = array [1..2] of Int64;
FB_INT128 = array [1..2] of Int64;
isc_tr_handle = ^integer32;
isc_stmt_handle = ^integer32;

View File

@ -127,10 +127,10 @@ void BlrFromMessage::buildBlr(IMessageMetadata* metadata)
dtype = dtype_dec128;
break;
case SQL_DEC_FIXED:
appendUChar(blr_dec_fixed);
case SQL_INT128:
appendUChar(blr_int128);
appendUChar(scale);
dtype = dtype_dec_fixed;
dtype = dtype_int128;
break;
case SQL_DOUBLE:

View File

@ -300,11 +300,11 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
align = type_alignments[dtype_dec128];
break;
case blr_dec_fixed:
desc->dsc_dtype = dtype_dec_fixed;
desc->dsc_length = sizeof(DecimalFixed);
case blr_int128:
desc->dsc_dtype = dtype_int128;
desc->dsc_length = sizeof(Int128);
desc->dsc_scale = *blr++;
align = type_alignments[dtype_dec_fixed];
align = type_alignments[dtype_int128];
break;
// this case cannot occur as switch paramater is char and blr_blob

View File

@ -762,7 +762,7 @@ void TracePluginImpl::appendParams(ITraceParams* params)
case dtype_dec128:
paramtype = "decfloat(34)";
break;
case dtype_dec_fixed:
case dtype_int128:
paramtype = "decimal";
break;
@ -887,11 +887,10 @@ void TracePluginImpl::appendParams(ITraceParams* params)
((Decimal128*) parameters->dsc_address)->toString(paramvalue);
break;
case dtype_dec_fixed:
case dtype_int128:
try
{
DecimalStatus decSt(FB_DEC_Errors);
((DecimalFixed*) parameters->dsc_address)->toString(decSt, parameters->dsc_scale, paramvalue);
((Int128*) parameters->dsc_address)->toString(parameters->dsc_scale, paramvalue);
}
catch (const Exception& ex)
{

View File

@ -686,6 +686,7 @@ public:
void encodeTimeStampTz(Firebird::CheckStatusWrapper* status, ISC_TIMESTAMP_TZ* timeStampTz,
unsigned year, unsigned month, unsigned day,
unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions, const char* timeZone);
Firebird::IInt128* getInt128(Firebird::CheckStatusWrapper* status);
};
} // namespace Why

View File

@ -60,6 +60,7 @@
#include "../common/classes/TempFile.h"
#include "../common/utils_proto.h"
#include "../common/ThreadStart.h"
#include "../common/Int128.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@ -3034,9 +3035,9 @@ static int blr_print_dtype(gds_ctl* control)
length = sizeof(Firebird::Decimal64);
break;
case blr_dec_fixed:
string = "dec_fixed";
length = sizeof(Firebird::DecimalFixed);
case blr_int128:
string = "int128";
length = sizeof(Firebird::Int128);
break;
case blr_domain_name:
@ -3100,7 +3101,7 @@ static int blr_print_dtype(gds_ctl* control)
case blr_long:
case blr_quad:
case blr_int64:
case blr_dec_fixed:
case blr_int128:
blr_print_byte(control);
break;

View File

@ -1303,6 +1303,49 @@ IDecFloat34* UtilInterface::getDecFloat34(CheckStatusWrapper* status)
return &decFloat34;
}
class IfaceInt128 FB_FINAL : public AutoIface<IInt128Impl<IfaceInt128, CheckStatusWrapper> >
{
public:
// IInt128 implementation
void toString(CheckStatusWrapper* status, const FB_I128* from, int scale, unsigned bufSize, char* buffer)
{
try
{
const Int128* i128 = (Int128*)from;
i128->toString(scale, bufSize, buffer);
}
catch (const Exception& ex)
{
ex.stuffException(status);
}
}
void fromString(CheckStatusWrapper* status, int scale, const char* from, FB_I128* to)
{
try
{
Int128* i128 = (Int128*)to;
scale -= CVT_decompose(from, static_cast<USHORT>(strlen(from)), i128, errorFunction);
i128->setScale(scale);
}
catch (const Exception& ex)
{
ex.stuffException(status);
}
}
static void errorFunction(const Arg::StatusVector& v)
{
v.raise();
}
};
IInt128* UtilInterface::getInt128(CheckStatusWrapper* status)
{
static IfaceInt128 ifaceInt128;
return &ifaceInt128;
}
unsigned UtilInterface::setOffsets(CheckStatusWrapper* status, IMessageMetadata* metadata,
IOffsetsCallback* callback)
{