From bdc7bd8d3e77f0535f5df41cf3541b8a7a12ce39 Mon Sep 17 00:00:00 2001 From: hvlad Date: Mon, 10 Jul 2017 23:54:42 +0300 Subject: [PATCH] Merge branch 'master' into read_consistency --- .gitignore | 1 + CHANGELOG.md | 148 +- .../linux/makeInstallImage.sh.in | 2 +- builds/make.new/config/install-sh | 354 +- builds/posix/Makefile.in | 19 +- builds/posix/make.android.arme | 1 - builds/posix/make.defaults | 6 +- builds/posix/make.platform.solaris.examples | 1 - builds/posix/make.shared.variables | 4 +- builds/posix/prefix.solx86gcc | 1 - builds/posix/prefix.solx86gcc_64 | 3 +- builds/win32/make_boot.bat | 18 + builds/win32/msvc12/common.vcxproj | 10 +- builds/win32/msvc12/common.vcxproj.filters | 6 + configure.ac | 10 + doc/sql.extensions/README.data_types | 84 + examples/interfaces/06.fb_message.cpp | 17 +- extern/cloop/src/tests/test1/CTest.c | 2 +- extern/decNumber/.gitignore | 2 + extern/decNumber/ICU-license.html | 45 + extern/decNumber/Makefile | 11 + extern/decNumber/decBasic.c | 3908 ++++++++ extern/decNumber/decCommon.c | 1835 ++++ extern/decNumber/decContext.c | 437 + extern/decNumber/decContext.h | 254 + extern/decNumber/decDPD.h | 1185 +++ extern/decNumber/decDouble.c | 140 + extern/decNumber/decDouble.h | 155 + extern/decNumber/decNumber.c | 8141 +++++++++++++++++ extern/decNumber/decNumber.h | 182 + extern/decNumber/decNumberLocal.h | 757 ++ extern/decNumber/decPacked.c | 220 + extern/decNumber/decPacked.h | 52 + extern/decNumber/decQuad.c | 135 + extern/decNumber/decQuad.h | 177 + extern/decNumber/decSingle.c | 71 + extern/decNumber/decSingle.h | 86 + extern/decNumber/decimal128.c | 553 ++ extern/decNumber/decimal128.h | 81 + extern/decNumber/decimal32.c | 476 + extern/decNumber/decimal32.h | 81 + extern/decNumber/decimal64.c | 839 ++ extern/decNumber/decimal64.h | 83 + extern/decNumber/decnumber.pdf | Bin 0 -> 1416382 bytes extern/decNumber/msvc/decNumber_MSVC12.sln | 28 + .../decNumber/msvc/decNumber_MSVC12.vcxproj | 267 + .../msvc/decNumber_MSVC12.vcxproj.filters | 84 + extern/decNumber/readme.txt | 81 + lang_helpers/gds_codes.ftn | 12 + lang_helpers/gds_codes.pas | 12 + .../manage/SrpManagement.cpp | 1 + .../SecureRemotePassword/server/SrpServer.cpp | 3 +- .../SecurityDatabase/LegacyManagement.epp | 14 +- src/auth/SecurityDatabase/LegacyServer.cpp | 3 +- src/burp/backup.epp | 8 + src/burp/canonical.cpp | 18 +- src/burp/restore.epp | 29 +- src/common/CharSet.h | 7 +- src/common/DecFloat.cpp | 986 ++ src/common/DecFloat.h | 195 + src/common/IntlUtil.cpp | 14 +- src/common/IntlUtil.h | 2 + src/common/MsgMetadata.cpp | 1 + src/common/StatementMetadata.cpp | 6 +- src/common/classes/Hash.cpp | 7 +- src/common/classes/ImplementHelper.h | 2 +- src/common/classes/InternalMessageBuffer.cpp | 10 + src/common/classes/RefCounted.h | 3 +- src/common/common.h | 9 +- src/common/cvt.cpp | 405 +- src/common/cvt.h | 23 +- src/common/dsc.cpp | 317 +- src/common/dsc.h | 39 +- src/common/dsc_pub.h | 4 +- src/common/sdl.cpp | 10 + src/common/utils.cpp | 117 +- src/common/utils_proto.h | 3 + src/common/xdr.cpp | 41 +- src/common/xdr_proto.h | 6 +- src/dsql/AggNodes.cpp | 564 +- src/dsql/AggNodes.h | 33 +- src/dsql/BoolNodes.cpp | 60 +- src/dsql/DdlNodes.epp | 122 +- src/dsql/DsqlCompilerScratch.cpp | 30 +- src/dsql/ExprNodes.cpp | 613 +- src/dsql/ExprNodes.h | 8 +- src/dsql/Nodes.h | 91 +- src/dsql/Parser.cpp | 97 +- src/dsql/Parser.h | 7 +- src/dsql/StmtNodes.cpp | 277 +- src/dsql/StmtNodes.h | 108 +- src/dsql/WinNodes.cpp | 8 +- src/dsql/ddl_proto.h | 4 +- src/dsql/dsql.cpp | 28 +- src/dsql/dsql.h | 52 +- src/dsql/gen.cpp | 31 +- src/dsql/make.cpp | 30 +- src/dsql/make_proto.h | 1 + src/dsql/parse.y | 275 +- src/dsql/pass1.cpp | 178 +- src/dsql/sqlda_pub.h | 2 + src/gpre/c_cxx.cpp | 10 +- src/gpre/cmp.cpp | 16 +- src/gpre/movg.cpp | 2 +- src/gpre/std/gpre_meta.epp | 49 +- src/include/firebird/FirebirdInterface.idl | 26 +- src/include/firebird/IdlFbInterfaces.h | 360 + src/include/firebird/Message.h | 10 + src/include/firebird/UdrCppEngine.h | 6 +- src/include/gen/autoconfig_msvc.h | 5 + src/include/gen/codetext.h | 6 + src/include/gen/iberror.h | 16 +- src/include/gen/msgs.h | 8 +- src/include/gen/sql_code.h | 6 + src/include/gen/sql_state.h | 6 + src/include/types_pub.h | 11 + src/intl/lc_ascii.cpp | 3 +- src/intl/lc_icu.cpp | 3 +- src/intl/ld.cpp | 3 +- src/isql/isql.epp | 131 +- src/isql/isql.h | 11 + src/isql/show.epp | 4 +- src/jrd/Attachment.cpp | 1 + src/jrd/Attachment.h | 2 + src/jrd/CryptoManager.cpp | 2 +- src/jrd/DataTypeUtil.cpp | 2 +- src/jrd/DbCreators.cpp | 1 + src/jrd/ExtEngineManager.cpp | 360 +- src/jrd/JrdStatement.cpp | 2 +- src/jrd/Mapping.cpp | 1236 +-- src/jrd/Mapping.h | 138 +- src/jrd/Optimizer.cpp | 56 +- src/jrd/PreparedStatement.cpp | 10 + src/jrd/RecordSourceNodes.cpp | 64 +- src/jrd/SysFunction.cpp | 676 +- src/jrd/VirtualTable.cpp | 4 +- src/jrd/align.h | 17 +- src/jrd/blb.cpp | 6 +- src/jrd/blr.h | 4 +- src/jrd/btr.cpp | 27 +- src/jrd/btr.h | 1 + src/jrd/build_no.h | 14 +- src/jrd/cmp.cpp | 2 +- src/jrd/constants.h | 1 + src/jrd/cvt.cpp | 39 +- src/jrd/cvt2.cpp | 105 +- src/jrd/cvt2_proto.h | 8 +- src/jrd/cvt_proto.h | 10 +- src/jrd/dfw.epp | 32 +- src/jrd/err.cpp | 20 + src/jrd/err_proto.h | 1 + src/jrd/evl.cpp | 26 +- src/jrd/exe.cpp | 17 +- src/jrd/ext.cpp | 8 +- src/jrd/extds/InternalDS.cpp | 2 +- src/jrd/extds/IscDS.cpp | 47 +- src/jrd/flu.cpp | 13 +- src/jrd/flu.h | 2 + src/jrd/fun.epp | 86 +- src/jrd/idx.cpp | 16 +- src/jrd/inf.cpp | 2 +- src/jrd/intl.cpp | 6 +- src/jrd/jrd.cpp | 65 +- src/jrd/jrd.h | 7 +- src/jrd/mov.cpp | 67 +- src/jrd/mov_proto.h | 21 +- src/jrd/opt.cpp | 123 +- src/jrd/pag.cpp | 8 + src/jrd/par.cpp | 10 + src/jrd/recsrc/AggregatedStream.cpp | 14 +- src/jrd/recsrc/FilteredStream.cpp | 2 +- src/jrd/recsrc/FirstRowsStream.cpp | 2 +- src/jrd/recsrc/MergeJoin.cpp | 2 +- src/jrd/recsrc/SkipRowsStream.cpp | 2 +- src/jrd/recsrc/SortedStream.cpp | 7 +- src/jrd/recsrc/WindowedStream.cpp | 20 +- src/jrd/sort.cpp | 107 +- src/jrd/sort.h | 62 +- src/jrd/svc.cpp | 15 +- src/jrd/tra.cpp | 31 +- src/jrd/tra.h | 2 +- src/jrd/trace/TraceManager.cpp | 24 +- src/jrd/trace/TraceObjects.cpp | 10 +- src/jrd/trig.h | 4 +- src/jrd/types.h | 2 + src/jrd/val.h | 13 + src/jrd/vio.cpp | 177 +- src/lock/print.cpp | 2 +- src/misc/pascal/Pascal.interface.pas | 2 + src/misc/writeBuildNum.sh | 13 +- src/msgs/facilities2.sql | 2 +- src/msgs/messages2.sql | 8 +- src/msgs/system_errors2.sql | 6 + src/qli/show.epp | 4 +- src/remote/client/BlrFromMessage.cpp | 10 + src/remote/client/interface.cpp | 2 +- src/remote/os/win32/wnet_proto.h | 10 - src/remote/parser.cpp | 16 +- src/remote/remote.h | 12 + src/remote/server/server.cpp | 37 +- src/utilities/nbackup/nbackup.cpp | 10 +- src/utilities/ntrace/TracePluginImpl.cpp | 33 +- src/yvalve/YObjects.h | 2 + src/yvalve/keywords.cpp | 8 + src/yvalve/utl.cpp | 122 + 205 files changed, 27977 insertions(+), 2856 deletions(-) create mode 100644 extern/decNumber/.gitignore create mode 100644 extern/decNumber/ICU-license.html create mode 100644 extern/decNumber/Makefile create mode 100644 extern/decNumber/decBasic.c create mode 100644 extern/decNumber/decCommon.c create mode 100644 extern/decNumber/decContext.c create mode 100644 extern/decNumber/decContext.h create mode 100644 extern/decNumber/decDPD.h create mode 100644 extern/decNumber/decDouble.c create mode 100644 extern/decNumber/decDouble.h create mode 100644 extern/decNumber/decNumber.c create mode 100644 extern/decNumber/decNumber.h create mode 100644 extern/decNumber/decNumberLocal.h create mode 100644 extern/decNumber/decPacked.c create mode 100644 extern/decNumber/decPacked.h create mode 100644 extern/decNumber/decQuad.c create mode 100644 extern/decNumber/decQuad.h create mode 100644 extern/decNumber/decSingle.c create mode 100644 extern/decNumber/decSingle.h create mode 100644 extern/decNumber/decimal128.c create mode 100644 extern/decNumber/decimal128.h create mode 100644 extern/decNumber/decimal32.c create mode 100644 extern/decNumber/decimal32.h create mode 100644 extern/decNumber/decimal64.c create mode 100644 extern/decNumber/decimal64.h create mode 100644 extern/decNumber/decnumber.pdf create mode 100644 extern/decNumber/msvc/decNumber_MSVC12.sln create mode 100644 extern/decNumber/msvc/decNumber_MSVC12.vcxproj create mode 100644 extern/decNumber/msvc/decNumber_MSVC12.vcxproj.filters create mode 100644 extern/decNumber/readme.txt create mode 100644 src/common/DecFloat.cpp create mode 100644 src/common/DecFloat.h diff --git a/.gitignore b/.gitignore index eb61c88c8a..57aaf99cc6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ libtool *.tmp src/dsql/parse.cpp .vscode/.browse.VC.db +extern/decNumber/libdecFloat.a diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a65a677ae..def6b77e5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,103 @@ # v4.0 Alpha 1 (unreleased) +## New features + +* [CORE-5568](http://tracker.firebirdsql.org/browse/CORE-5568): SQL SECURITY feature + Reference(s): [/doc/sql.extentions/README.sql_security](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.sql_security.txt) + Contributor(s): Roman Simakov + +* [CORE-5525](http://tracker.firebirdsql.org/browse/CORE-5525): Create high-precision floating point datatype named DECFLOAT + Reference(s): [/doc/sql.extentions/README.data_types](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.data_types) + Contributor(s): Alex Peshkoff + +* [CORE-5488](http://tracker.firebirdsql.org/browse/CORE-5488): Timeouts for running SQL statements and idle connections + Reference(s): [/doc/README.session_idle_timeouts](https://github.com/FirebirdSQL/firebird/raw/master/doc/README.session_idle_timeouts), [/doc/README.statement_timeouts](https://github.com/FirebirdSQL/firebird/raw/master/doc/README.statement_timeouts) + Contributor(s): Vlad Khorsun + +* [CORE-5463](http://tracker.firebirdsql.org/browse/CORE-5463): Support DEFAULT context value in INSERT, UPDATE, MERGE and UPDATE OR INSERT statements + Contributor(s): Adriano dos Santos Fernandes + +* [CORE-5449](http://tracker.firebirdsql.org/browse/CORE-5449): Support GENERATED ALWAYS identity columns and OVERRIDE clause + Reference(s): [doc/sql.extensions/README.identity_columns](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.identity_columns.txt) + Contributor(s): Adriano dos Santos Fernandes + +* [CORE-5346](http://tracker.firebirdsql.org/browse/CORE-5346): Named windows + Reference(s): [doc/sql.extensions/README.window_functions](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.window_functions.md) + Contributor(s): Adriano dos Santos Fernandes + +* [CORE-5343](http://tracker.firebirdsql.org/browse/CORE-5343): Allow particular DBA privileges to be transferred to regular users + Reference(s): [doc/sql.extensions/README.builtin_functions](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.builtin_functions.txt), [doc/sql.extensions/README.ddl](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.ddl.txt) + Contributor(s): Alex Peshkoff + +* [CORE-3647](http://tracker.firebirdsql.org/browse/CORE-3647): Frames for window functions + Reference(s): [doc/sql.extensions/README.window_functions](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.window_functions.md) + Contributor(s): Adriano dos Santos Fernandes + +* [CORE-2762](http://tracker.firebirdsql.org/browse/CORE-2762): New built-in function to check whether some role is implicitly active + Reference(s): [doc/sql.extensions/README.cumulative_roles](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.cumulative_roles.txt) + Contributor(s): Roman Simakov + +* [CORE-1815](http://tracker.firebirdsql.org/browse/CORE-1815): Ability to grant role to another role + Reference(s): [doc/sql.extensions/README.cumulative_roles](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.cumulative_roles.txt) + Contributor(s): Roman Simakov + +* [CORE-1688](http://tracker.firebirdsql.org/browse/CORE-1688): More ANSI SQL:2003 window functions (PERCENK_RANK, CUME_DIST, NTILE) + Reference(s): [doc/sql.extensions/README.window_functions](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.window_functions.md) + Contributor(s): Hajime Nakagami, Adriano dos Santos Fernandes + +* [CORE-751](http://tracker.firebirdsql.org/browse/CORE-751): Implicitly active roles (and their permissions summarized) + Contributor(s): Roman Simakov + +## Improvements + +* [CORE-5431](http://tracker.firebirdsql.org/browse/CORE-5431): Support for DROP IDENTITY clause + Reference(s): [doc/sql.extensions/README.identity_columns](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.identity_columns.txt) + Contributor(s): Adriano dos Santos Fernandes + +* [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5430): Support for INCREMENT option in identity columns + Reference(s): [doc/sql.extensions/README.identity_columns](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.identity_columns.txt) + Contributor(s): Adriano dos Santos Fernandes + +* [CORE-5119](http://tracker.firebirdsql.org/browse/CORE-5119): Support autocommit mode in SET TRANSACTION statement + Contributor(s): Dmitry Yemanov + +* [CORE-5064](http://tracker.firebirdsql.org/browse/CORE-5064): Add datatypes (VAR)BINARY(n) and BINARY VARYING(n) as aliases for (VAR)CHAR(n) CHARACTER SET OCTETS + Contributor(s): Dimitry Sibiryakov + +* [CORE-2557](http://tracker.firebirdsql.org/browse/CORE-2557): Grants on MON$ tables + Contributor(s): Alex Peshkoff + +* [CORE-2216](http://tracker.firebirdsql.org/browse/CORE-2216): NBackup as online dump + Contributor(s): Roman Simakov, Vlad Khorsun + +* [CORE-2192](http://tracker.firebirdsql.org/browse/CORE-2192): Extend maximum database page size to 32KB + Contributor(s): Dmitry Yemanov + +* [CORE-2040](http://tracker.firebirdsql.org/browse/CORE-2040): Allow exception name and possibly exception text to be determined within a "WHEN ANY" error handling block + Reference(s): [doc/sql.extensions/README.context_variables](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.context_variables) + Contributor(s): Dmitry Yemanov + +* [CORE-1132](http://tracker.firebirdsql.org/browse/CORE-1132): Exception context in PSQL exception handlers + Reference(s): [doc/sql.extensions/README.context_variables](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.context_variables) + Contributor(s): Dmitry Yemanov + +* [CORE-749](http://tracker.firebirdsql.org/browse/CORE-749): Increase maximum length of object names to 63 characters + Contributor(s): Adriano dos Santos Fernandes + ## Bugfixes +* [CORE-5545](http://tracker.firebirdsql.org/browse/CORE-5545): Wrong syntax with CREATE TRIGGER ... ON used with POSITION + Contributor(s): Adriano dos Santos Fernandes + +* [CORE-5454](http://tracker.firebirdsql.org/browse/CORE-5454): INSERT into updatable view without explicit field list failed + Contributor(s): Adriano dos Santos Fernandes + * [CORE-5408](http://tracker.firebirdsql.org/browse/CORE-5408): Result of boolean expression can not be concatenated with string literal Contributor(s): Adriano dos Santos Fernandes +* [CORE-5404](http://tracker.firebirdsql.org/browse/CORE-5404): Inconsistent column/line references when PSQL definitions return errors + Contributor(s): Adriano dos Santos Fernandes + * [CORE-5237](http://tracker.firebirdsql.org/browse/CORE-5237): Invalid handling of dot (.) and asterisk (*) in config file name and path for include clause Contributor(s): Dimitry Sibiryakov @@ -26,58 +119,3 @@ * [CORE-4424](http://tracker.firebirdsql.org/browse/CORE-4424): Rollback to wrong savepoint if several exception handlers on the same level are executed Contributor(s): Dimitry Sibiryakov -## Improvements - -* [CORE-5431](http://tracker.firebirdsql.org/browse/CORE-5431): Support for DROP IDENTITY clause - Contributor(s): Adriano dos Santos Fernandes - -* [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5430): Support for INCREMENT option in identity columns - Contributor(s): Adriano dos Santos Fernandes - -* [CORE-5119](http://tracker.firebirdsql.org/browse/CORE-5119): Support autocommit mode in SET TRANSACTION statement - Contributor(s): Dmitry Yemanov - -* [CORE-2557](http://tracker.firebirdsql.org/browse/CORE-2557): Grants on MON$ tables - Contributor(s): Alex Peshkoff - -* [CORE-2216](http://tracker.firebirdsql.org/browse/CORE-2216): NBackup as online dump - Contributor(s): Roman Simakov, Vlad Khorsun - -* [CORE-2192](http://tracker.firebirdsql.org/browse/CORE-2192): Extend maximum database page size to 32KB - Contributor(s): Dmitry Yemanov - -* [CORE-2040](http://tracker.firebirdsql.org/browse/CORE-2040): Allow exception name and possibly exception text to be determined within a "WHEN ANY" error handling block - Contributor(s): Dmitry Yemanov - -* [CORE-1132](http://tracker.firebirdsql.org/browse/CORE-1132): Exception context in PSQL exception handlers - Contributor(s): Dmitry Yemanov - -* [CORE-749](http://tracker.firebirdsql.org/browse/CORE-749): Increase maximum length of object names to 63 characters - Contributor(s): Adriano dos Santos Fernandes - -## New features - -* [CORE-5346](http://tracker.firebirdsql.org/browse/CORE-5346): Named windows - Contributor(s): Adriano dos Santos Fernandes - -* [CORE-5343](http://tracker.firebirdsql.org/browse/CORE-5343): Allow particular DBA privileges to be transferred to regular users - Contributor(s): Alex Peshkoff - -* [CORE-3647](http://tracker.firebirdsql.org/browse/CORE-3647): Frames for window functions - Contributor(s): Adriano dos Santos Fernandes - -* [CORE-2990](http://tracker.firebirdsql.org/browse/CORE-2990): Physical (page-level) standby replication / page shipping - Contributor(s): Roman Simakov, Vlad Khorsun - -* [CORE-2762](http://tracker.firebirdsql.org/browse/CORE-2762): New built-in function to check whether some role is implicitly active - Contributor(s): Roman Simakov - -* [CORE-1815](http://tracker.firebirdsql.org/browse/CORE-1815): Ability to grant role to another role - Contributor(s): Roman Simakov - -* [CORE-1688](http://tracker.firebirdsql.org/browse/CORE-1688): More ANSI SQL:2003 window functions (PERCENK_RANK, CUME_DIST, NTILE) - Contributor(s): Hajime Nakagami, Adriano dos Santos Fernandes - -* [CORE-751](http://tracker.firebirdsql.org/browse/CORE-751): Implicitly active roles (and their permissions summarized) - Contributor(s): Roman Simakov - diff --git a/builds/install/arch-specific/linux/makeInstallImage.sh.in b/builds/install/arch-specific/linux/makeInstallImage.sh.in index 70b3f7af5d..0cf0fbe504 100644 --- a/builds/install/arch-specific/linux/makeInstallImage.sh.in +++ b/builds/install/arch-specific/linux/makeInstallImage.sh.in @@ -206,7 +206,7 @@ copyFiles() { cp $BuiltFBDir/examples/empbuild/*.fdb ${TargetDir}@FB_SAMPLEDBDIR@ ReadOnlyTree ${TargetDir}@FB_SAMPLEDIR@ - chmod 0444 ${TargetDir}@FB_SAMPLEDBDIR@/*.fdb + chmod 0664 ${TargetDir}@FB_SAMPLEDBDIR@/*.fdb fi #QLI help diff --git a/builds/make.new/config/install-sh b/builds/make.new/config/install-sh index 377bb8687f..0b0fdcbba6 100755 --- a/builds/make.new/config/install-sh +++ b/builds/make.new/config/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2011-11-20.07; # UTC +scriptversion=2013-12-25.23; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC # This script is compatible with the BSD install script, but was written # from scratch. +tab=' ' nl=' ' -IFS=" "" $nl" +IFS=" $tab$nl" -# set DOITPROG to echo to test this script +# Set DOITPROG to "echo" to test this script. -# Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi +doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. @@ -68,17 +64,6 @@ mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - posix_mkdir= # Desired mode of installed file. @@ -97,7 +82,7 @@ dir_arg= dst_arg= copy_on_change=false -no_target_directory= +is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE @@ -137,46 +122,57 @@ while test $# -ne 0; do -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" - shift;; + shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; -o) chowncmd="$chownprog $2" - shift;; + shift;; -s) stripcmd=$stripprog;; - -t) dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; - -T) no_target_directory=true;; + -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; - --) shift - break;; + --) shift + break;; - -*) echo "$0: invalid option: $1" >&2 - exit 1;; + -*) echo "$0: invalid option: $1" >&2 + exit 1;; *) break;; esac shift done +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. @@ -207,6 +203,15 @@ if test $# -eq 0; then exit 0 fi +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 @@ -223,16 +228,16 @@ if test -z "$dir_arg"; then *[0-7]) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw='% 200' + u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw=,u+rw + u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac @@ -269,41 +274,15 @@ do # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - + dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi @@ -314,74 +293,74 @@ do if test $dstdir_status != 0; then case $posix_mkdir in '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; esac if $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else @@ -391,53 +370,51 @@ do # directory the slow way, step by step, checking for races as we go. case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; esac - eval "$initialize_posix_glob" - oIFS=$IFS IFS=/ - $posix_glob set -f + set -f set fnord $dstdir shift - $posix_glob set +f + set +f IFS=$oIFS prefixes= for d do - test X"$d" = X && continue + test X"$d" = X && continue - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ done if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true fi fi fi @@ -472,15 +449,12 @@ do # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - + set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then @@ -493,24 +467,24 @@ do # to itself, or perhaps because mv is so ancient that it does not # support -f. { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 diff --git a/builds/posix/Makefile.in b/builds/posix/Makefile.in index a8e17a130e..6014a3748b 100644 --- a/builds/posix/Makefile.in +++ b/builds/posix/Makefile.in @@ -66,7 +66,7 @@ else GCC=gcc endif -.PHONY: master_process cross_process firebird Debug Release extern +.PHONY: master_process cross_process firebird Debug Release external all: firebird @@ -130,10 +130,13 @@ $(GEN_ROOT)/Make.Version : $(SRC_ROOT)/misc/writeBuildNum.sh # build external software # -extern: +external: $(MAKE) -C $(ROOT)/extern/btyacc $(MAKE) -C $(ROOT)/extern/cloop TARGET=release WITH_FPC=0 BUILD_DIR=$(TMP_ROOT)/cloop OUT_DIR=$(GEN_ROOT)/$(TARGET)/cloop + $(MAKE) -C $(ROOT)/extern/decNumber + ln -sf $(ROOT)/extern/decNumber/libdecFloat.a $(LIB) + ifeq ($(TOMBUILD_FLG),Y) CFLAGS="$(CFLAGS)" $(MAKE) -C $(ROOT)/extern/libtommath -f makefile.shared GCC=$(GCC) ln -sf $(TOMMATH_SO).$(TOMMATH_VER) $(LIB) @@ -180,7 +183,7 @@ master_process: ln -sf $(SRC_ROOT)/include/gen/autoconfig.auto $(SRC_ROOT)/include/gen/autoconfig.h $(MAKE) updateBuildNum $(MAKE) export_lists - $(MAKE) extern + $(MAKE) external $(MAKE) updateCloopInterfaces $(MAKE) boot $(MAKE) yvalve @@ -215,7 +218,7 @@ cross1: ln -sf $(SRC_ROOT)/include/gen/autoconfig.auto $(SRC_ROOT)/include/gen/autoconfig.h $(MAKE) updateBuildNum $(MAKE) export_lists - $(MAKE) extern + $(MAKE) external $(MAKE) updateCloopInterfaces $(MAKE) boot $(MAKE) yvalve @@ -657,11 +660,12 @@ install install-embedded silent_install package packages dist: # .PHONY: clean clean_objects clean_dependancies clean_extern_objects clean_build \ clean_gpre_gen clean_icu clean_dbs clean_examples clean_makefiles \ - clean_editline clean_all + clean_editline clean_all clean_decfloat clean: clean_objects clean_dependancies clean_extern_objects clean_build \ - clean_yacc_gen clean_gpre_gen clean_dbs clean_examples clean_tommath + clean_yacc_gen clean_gpre_gen clean_dbs clean_examples clean_tommath \ + clean_decfloat ifeq ($(EDITLINE_FLG),Y) ifeq ($(STD_EDITLINE),false) @@ -701,6 +705,9 @@ clean_editline: clean_tommath: -$(MAKE) -C $(ROOT)/extern/libtommath clean +clean_decfloat: + -$(MAKE) -C $(ROOT)/extern/decNumber clean + clean_objects: $(RM) `find $(TMP_ROOT)/ -type f -name '*.o' -print` $(RM) `find $(TMP_ROOT)/ -type f -name '*.a' -print` diff --git a/builds/posix/make.android.arme b/builds/posix/make.android.arme index c968944253..4547bb7590 100644 --- a/builds/posix/make.android.arme +++ b/builds/posix/make.android.arme @@ -56,7 +56,6 @@ LDFLAGS += --sysroot=$(CROSS_PLATFORM) -L$(NDK)/sources/cxx-stl/gnu-libstdc++/$( DroidLibs := -lm -ldl -lsupc++ LINK_LIBS = $(DroidLibs) -STATICLINK_LIBS = $(DroidLibs) SO_LINK_LIBS = $(DroidLibs) EXE_LINK_OPTIONS= $(LDFLAGS) $(UNDEF_FLAGS) $(LIB_PATH_OPTS) $(LINK_EMPTY_SYMBOLS) diff --git a/builds/posix/make.defaults b/builds/posix/make.defaults index 681717f346..145792cf9b 100755 --- a/builds/posix/make.defaults +++ b/builds/posix/make.defaults @@ -132,6 +132,7 @@ CAS_OPTIONS=@CAS_OPTIONS@ # multiple-precision integer library MATHLIB=@MATHLIB@ +DECLIB=-ldecFloat LSB_FLG=@LSB_FLG@ ifeq ($(LSB_FLG), Y) @@ -177,9 +178,8 @@ STATICLIB_LINK = $(AR) crus EXE_LINK = $(CXX) $(GLOB_OPTIONS) $(CXXFLAGS) STATICEXE_LINK = $(CXX) $(GLOB_OPTIONS) $(CXXFLAGS) -LINK_LIBS = @LIBS@ -STATICLINK_LIBS = @LIBS@ -SO_LINK_LIBS = @LIBS@ +LINK_LIBS = @LIBS@ $(DECLIB) +SO_LINK_LIBS = @LIBS@ $(DECLIB) # Default extensions diff --git a/builds/posix/make.platform.solaris.examples b/builds/posix/make.platform.solaris.examples index 3c9321aa2a..b0a20a54db 100644 --- a/builds/posix/make.platform.solaris.examples +++ b/builds/posix/make.platform.solaris.examples @@ -30,7 +30,6 @@ DEV_FLAGS=$(COMM_SOLX_FLAGS) -ggdb -g3 -p $(WARNINGS) ifdef SFIO LINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio -STATICLINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio SO_LINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio endif diff --git a/builds/posix/make.shared.variables b/builds/posix/make.shared.variables index 2d3143fc49..54888bf9fe 100644 --- a/builds/posix/make.shared.variables +++ b/builds/posix/make.shared.variables @@ -1,8 +1,8 @@ # Helper functions doObjects= $(patsubst %.y,%.o,$(patsubst %.epp,%.o,$(patsubst %.c,%.o,$(1:.cpp=.o)))) makeObjects= $(addprefix $(OBJ)/$(1)/,$(call doObjects,$2)) -dirFiles= $(notdir $(wildcard ../src/$(1)/*.cpp)) $(notdir $(wildcard ../src/$(1)/*.c)) \ - $(notdir $(wildcard ../src/$(1)/*.epp)) $(notdir $(wildcard ../src/$(1)/*.y)) +dirFiles= $(sort $(notdir $(wildcard ../src/$(1)/*.cpp)) $(notdir $(wildcard ../src/$(1)/*.c)) \ + $(notdir $(wildcard ../src/$(1)/*.epp)) $(notdir $(wildcard ../src/$(1)/*.y))) dirInPath= $(call makeObjects,$(1),$(call dirFiles,$(1))) dirMaster= $(call dirInPath,$(1)) diff --git a/builds/posix/prefix.solx86gcc b/builds/posix/prefix.solx86gcc index 570fe400dc..f6464b4dba 100644 --- a/builds/posix/prefix.solx86gcc +++ b/builds/posix/prefix.solx86gcc @@ -36,7 +36,6 @@ PROD_FLAGS=-w $(COMM_SOLX_FLAGS) -O2 -march=pentium DEV_FLAGS=$(COMM_SOLX_FLAGS) -ggdb -g3 -p $(WARNINGS) ifdef SFIO LINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio -STATICLINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio SO_LINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio endif diff --git a/builds/posix/prefix.solx86gcc_64 b/builds/posix/prefix.solx86gcc_64 index 30a396c76c..1585b964dd 100644 --- a/builds/posix/prefix.solx86gcc_64 +++ b/builds/posix/prefix.solx86gcc_64 @@ -27,7 +27,7 @@ # ./configure --build=x86_64-pc-solaris2.10 # copy libncurses.a from the ncurses build to gen/firebird/lib # make sure that make.defaults uses -lncurses instead of -lcurses for -# LINK_LIBS and STATICLINK_LIBS e.g. -lncurses -leditline +# LINK_LIBS and SO_LINK_LIBS e.g. -lncurses -leditline WARNINGS=-Wall -Wno-switch -Wno-parentheses -Wno-unused-variable -Wno-non-virtual-dtor COMM_SOLX_FLAGS:=-DSOLARIS -DBSD_COMP -DAMD64 -pipe -fmessage-length=0 -MMD -fPIC @@ -46,7 +46,6 @@ PROD_FLAGS=-w $(COMM_SOLX_FLAGS) -O2 DEV_FLAGS=$(COMM_SOLX_FLAGS) -ggdb $(WARNINGS) ifdef SFIO LINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio -STATICLINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio SO_LINK_LIBS+=$(SFIO_LDFLAGS) -lstdio -lsfio endif diff --git a/builds/win32/make_boot.bat b/builds/win32/make_boot.bat index ea8ce10ef0..6c62dcb18e 100644 --- a/builds/win32/make_boot.bat +++ b/builds/win32/make_boot.bat @@ -38,6 +38,9 @@ if "%ERRLEV%"=="1" goto :END call :LibTomMath if "%ERRLEV%"=="1" goto :END +call :decNumber +if "%ERRLEV%"=="1" goto :END + call :zlib if "%ERRLEV%"=="1" goto :END @@ -133,6 +136,21 @@ if errorlevel 1 call :boot2 libtommath_%FB_OBJ_DIR% @call set_build_target.bat %* goto :EOF +::=================== +:: BUILD decNumber +:decNumber +@echo. +@call set_build_target.bat %* RELEASE +@echo Building decNumber (%FB_OBJ_DIR%)... +@call compile.bat %FB_ROOT_PATH%\extern\decNumber\msvc\decNumber_MSVC%MSVC_VERSION% decNumber_%FB_OBJ_DIR%_%FB_TARGET_PLATFORM%.log decNumber +if errorlevel 1 call :boot2 decNumber_%FB_OBJ_DIR% +@call set_build_target.bat %* DEBUG +@echo Building decNumber (%FB_OBJ_DIR%)... +@call compile.bat %FB_ROOT_PATH%\extern\decNumber\msvc\decNumber_MSVC%MSVC_VERSION% decNumber_%FB_OBJ_DIR%_%FB_TARGET_PLATFORM%.log decNumber +if errorlevel 1 call :boot2 decNumber_%FB_OBJ_DIR% +@call set_build_target.bat %* +goto :EOF + ::=================== :: Extract zlib :zlib diff --git a/builds/win32/msvc12/common.vcxproj b/builds/win32/msvc12/common.vcxproj index 89d9da898e..7fe6f7c086 100644 --- a/builds/win32/msvc12/common.vcxproj +++ b/builds/win32/msvc12/common.vcxproj @@ -58,6 +58,7 @@ + @@ -154,6 +155,7 @@ + @@ -283,7 +285,7 @@ 0x041d - ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\Release\tommath.lib;%(AdditionalDependencies) + ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;%(AdditionalDependencies) @@ -299,7 +301,7 @@ 0x041d - ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\Debug\tommath.lib;%(AdditionalDependencies) + ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;%(AdditionalDependencies) @@ -318,7 +320,7 @@ 0x041d - ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\Release\tommath.lib;%(AdditionalDependencies) + ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;%(AdditionalDependencies) @@ -336,7 +338,7 @@ 0x041d - ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\Debug\tommath.lib;%(AdditionalDependencies) + ws2_32.lib;../../../extern/libtommath/lib/$(PlatformName)\$(Configuration)\tommath.lib;../../../extern/decNumber/lib/$(PlatformName)\$(Configuration)\decnumber.lib;%(AdditionalDependencies) diff --git a/builds/win32/msvc12/common.vcxproj.filters b/builds/win32/msvc12/common.vcxproj.filters index fb87986102..8fec78de3a 100644 --- a/builds/win32/msvc12/common.vcxproj.filters +++ b/builds/win32/msvc12/common.vcxproj.filters @@ -216,6 +216,9 @@ common + + classes + @@ -530,5 +533,8 @@ headers + + headers + \ No newline at end of file diff --git a/configure.ac b/configure.ac index d8bb4a30cb..b89067f521 100644 --- a/configure.ac +++ b/configure.ac @@ -870,6 +870,16 @@ dnl if 64-bit mode, then archive tool, ar, needs -X64 option [AC_LANG_PROGRAM(,[[int lp64 = __64BIT__; ]])], [AR_OPTIONS=-X64],) fi + +XE_SAVE_ENV() +CXXFLAGS="$CXXFLAGS -std=c++11" +AC_CACHE_CHECK([whether the C++ compiler understands noexcept], [ac_cv_cxx_noexcept], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int f(int x) noexcept { return x + 1; }]], [[]])], + [ac_cv_cxx_noexcept=yes], [ac_cv_cxx_noexcept=no])]) +XE_RESTORE_ENV() +if test "$ac_cv_cxx_noexcept" = yes; then + AC_DEFINE([HAS_NOEXCEPT], [1], [Define if the C++ compiler understands noexcept.]) +fi AC_LANG_POP(C++) dnl Check for functions diff --git a/doc/sql.extensions/README.data_types b/doc/sql.extensions/README.data_types index 050e702696..553e24d533 100644 --- a/doc/sql.extensions/README.data_types +++ b/doc/sql.extensions/README.data_types @@ -101,3 +101,87 @@ BINARY, VARBINARY, BINARY VARYING (FB 4.0) 2. Can be distinguished from text types by value 1 in RDB$FIELD_SUB_TYPE. 3. Character set is set to OCTETS for backward compatibility. 4. In API are similar to corresponding text types, getSubType() returns 0. + + +DECFLOAT (FB 4.0) +-------------- + + Function: + DB2-compliant numeric type. DECFLOAT precisely (unlike FLOAT or DOUBLE PRECISION that provide + binary approximation) stores decimal values being therefore ideal choice for business appli- + cations. Firebird according to IEEE standard has both 16- and 34-digit decimal float encodings. + All intermediate calculations are performed with 34-digit values. + + Author: + Alex Peshkoff + + Syntax rules: + DECFLOAT(16) + DECFLOAT(34) + + Storage: + 64-bit / 128-bit, format according to IEEE 754. + + Example(s): + 1. DECLARE VARIABLE VAR1 DECFLOAT(34); + 2. CREATE TABLE TABLE1 (FIELD1 DECFLOAT(16)); + + Note(s): + 1. A number of standard functions can be used with DECFLOAT datatype. It is: + ABS, CEILING, EXP, FLOOR, LN, LOG, LOG10, POWER, SIGN, SQRT. + Agregate functions SUM, AVG, MAX and MIN also work with DECFLOAT data. + All statistics aggregates (like but not limited to STDDEV or CORR) work with DECFLOAT data. + + 2. Firebird supports four functions, specially designed to support DECFLOAT data: + - COMPARE_DECFLOAT - compares two DECFLOAT values to be equal, different or unordered. + Returns SMALLINT value which can be as follows: + 0 - values are equal + 1 - first value is less than second + 2 - first value is greater than second + 3 - values unordered (i.e. one or both is NAN / SNAN) + Unlike comparison operators ('<', '=', '>', etc.) comparison is exact - i.e. + COMPARE_DECFLOAT(2.17, 2.170) returns 2, not 0. + - NORMALIZE_DECFLOAT - has single DECFLOAT argument returned in it's simplest form. That + means that for any nonzero value trailing zero are removed with appropriate correction + of an exponent. For example NORMALIZE_DECFLOAT(12.00) returns 12 and + NORMALIZE_DECFLOAT(120) returns 1.2E+2. + - QUANTIZE - has two DECFLOAT arguments. The returned value is first argument scaled using + second value as a pattern. For example QUANTIZE(1234, 9.999) returns 1234.000. + - TOTALORDER - compares two DECFLOAT values including any special value. The comparison is + exact. Returns SMALLINT value which can be as follows: + -1 - first value is less than second + 0 - values are equal + 1 - first value is greater than second + DECFLOAT values are ordered as follows: + -nan < -snan < -inf < -0.1 < -0.10 < -0 < 0 < 0.10 < 0.1 < inf < snan < nan + + 3. Firebird supports new session control operator SET DECFLOAT. It has following forms: + SET DECFLOAT ROUND - controls rounding mode used in operations with DECFLOAT + values. Valid modes are: CEILING (towards +infinity), UP (away from 0), HALF_UP + (to nearest, if equidistant - up), HALF_EVEN (to nearest, if equidistant - ensure + last digit in the result to be even), HALF_DOWN (to nearest, if equidistant - down), + DOWN (towards 0), FLOOR (towards -infinity), REROUND (up if digit to be rounded is + 0 or 5, down in other cases). + + SET DECFLOAT TRAPS TO - controls which + exceptional conditions cause a trap. Valid traps are: Division_by_zero, Inexact, + Invalid_operation, Overflow and Underflow. By default traps are set to: + Division_by_zero, Invalid_operation, Overflow, Underflow. + + SET DECFLOAT BIND - controls how are DECFLOAT values represented in outer + world (i.e. in messages or in XSQLDA). Valid binding types are: NATIVE (use IEEE754 + 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 DECFLOAT values 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 is a tool like + generic purporse GUI client choice of CHAR binding is OK in most cases. + + 4. The length of DECFLOAT literals are limited to 1024 characters. For longer values, you will + need to use the scientific notation. For example, the 0.0<1020 zeroes>11 cannot be used + as a literal, instead you can use the equivalent in scientific notation: 1.1E-1022. + Similarly 10<1022 zeroes>0 can be presented as 1.0E1024. + diff --git a/examples/interfaces/06.fb_message.cpp b/examples/interfaces/06.fb_message.cpp index 239d794322..9d76658a30 100644 --- a/examples/interfaces/06.fb_message.cpp +++ b/examples/interfaces/06.fb_message.cpp @@ -4,6 +4,9 @@ * DESCRIPTION: A sample of using static messages. * Prints user-defined tables with comments. * + * Example for the following interface: + * IDecFloat16 - support for IEEE-754 64-bit decimal float numbers + * * Example for the following macro: * * FB_MESSAGE - defines static messages @@ -32,6 +35,7 @@ #include static IMaster* master = fb_get_master_interface(); +static IDecFloat16* idf = NULL; int main() { @@ -51,6 +55,8 @@ int main() try { + idf = master->getUtilInterface()->getDecFloat16(&status); + att = prov->attachDatabase(&status, dbName, 0, NULL); tra = att->startTransaction(&status, 0, NULL); @@ -72,13 +78,15 @@ int main() (FB_SMALLINT, relationId) (FB_VARCHAR(31), relationName) (FB_VARCHAR(100), description) + (FB_DECFLOAT16, df16) ) output(&status, master); input.clear(); input->systemFlag = 0; rs = att->openCursor(&status, tra, 0, - "select rdb$relation_id, rdb$relation_name, rdb$description" + "select rdb$relation_id, rdb$relation_name, rdb$description," + " cast (rdb$relation_id as decfloat(16)) * 0.05 as df16" " from rdb$relations" " where rdb$system_flag = ?" " order by rdb$relation_id", @@ -89,10 +97,13 @@ int main() { unsigned lRelName = output->relationNameNull ? 0 : output->relationName.length; unsigned lDesc = output->descriptionNull ? 0 : output->description.length; - printf("%4d %*.*s%c%*.*s\n", output->relationId, + char t[IDecFloat16::STRING_SIZE]; + idf->toStr(&output->df16, t); + + printf("%4d %*.*s%c%*.*s (%s)\n", output->relationId, lRelName, lRelName, output->relationName.str, lDesc ? '/' : ' ', - lDesc, lDesc, output->description.str); + lDesc, lDesc, output->description.str, t); } rs->close(&status); diff --git a/extern/cloop/src/tests/test1/CTest.c b/extern/cloop/src/tests/test1/CTest.c index a3739ce411..b2a5b00b55 100644 --- a/extern/cloop/src/tests/test1/CTest.c +++ b/extern/cloop/src/tests/test1/CTest.c @@ -20,7 +20,7 @@ */ #include "CalcCApi.h" -#include +#include #include #ifdef WIN32 diff --git a/extern/decNumber/.gitignore b/extern/decNumber/.gitignore new file mode 100644 index 0000000000..ac8f109172 --- /dev/null +++ b/extern/decNumber/.gitignore @@ -0,0 +1,2 @@ +temp/ +lib/ diff --git a/extern/decNumber/ICU-license.html b/extern/decNumber/ICU-license.html new file mode 100644 index 0000000000..00d356d452 --- /dev/null +++ b/extern/decNumber/ICU-license.html @@ -0,0 +1,45 @@ + + + + +ICU License - ICU 1.8.1 and later + + + +

ICU License - ICU 1.8.1 and later

+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1995-2005 International Business Machines Corporation and others
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies of
+the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
+
+--------------------------------------------------------------------------------
+All trademarks and registered trademarks mentioned herein are the property of their respective owners.
+
+ + diff --git a/extern/decNumber/Makefile b/extern/decNumber/Makefile new file mode 100644 index 0000000000..7aa18ad805 --- /dev/null +++ b/extern/decNumber/Makefile @@ -0,0 +1,11 @@ +LIBRARY=libdecFloat.a + +$(LIBRARY): $(wildcard *.c) $(wildcard *.h) Makefile + $(RM) -f *.o + $(CC) -c -O3 -fPIC $(subst decCommon.c,,$(subst decBasic.c,,$(wildcard *.c))) + $(AR) crs $(LIBRARY) *.o + $(RM) -f *.o + +.PHONY: clean +clean: + $(RM) -f *.o $(LIBRARY) diff --git a/extern/decNumber/decBasic.c b/extern/decNumber/decBasic.c new file mode 100644 index 0000000000..56396f8da7 --- /dev/null +++ b/extern/decNumber/decBasic.c @@ -0,0 +1,3908 @@ +/* ------------------------------------------------------------------ */ +/* decBasic.c -- common base code for Basic decimal types */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is included in the package as decNumber.pdf. This */ +/* document is also available in HTML, together with specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises code that is shared between decDouble and */ +/* decQuad (but not decSingle). The main arithmetic operations are */ +/* here (Add, Subtract, Multiply, FMA, and Division operators). */ +/* */ +/* Unlike decNumber, parameterization takes place at compile time */ +/* rather than at runtime. The parameters are set in the decDouble.c */ +/* (etc.) files, which then include this one to produce the compiled */ +/* code. The functions here, therefore, are code shared between */ +/* multiple formats. */ +/* */ +/* This must be included after decCommon.c. */ +/* ------------------------------------------------------------------ */ +// Names here refer to decFloat rather than to decDouble, etc., and +// the functions are in strict alphabetical order. + +// The compile-time flags SINGLE, DOUBLE, and QUAD are set up in +// decCommon.c +#if !defined(QUAD) + #error decBasic.c must be included after decCommon.c +#endif +#if SINGLE + #error Routines in decBasic.c are for decDouble and decQuad only +#endif + +/* Private constants */ +#define DIVIDE 0x80000000 // Divide operations [as flags] +#define REMAINDER 0x40000000 // .. +#define DIVIDEINT 0x20000000 // .. +#define REMNEAR 0x10000000 // .. + +/* Private functions (local, used only by routines in this module) */ +static decFloat *decDivide(decFloat *, const decFloat *, + const decFloat *, decContext *, uInt); +static decFloat *decCanonical(decFloat *, const decFloat *); +static void decFiniteMultiply(bcdnum *, uByte *, const decFloat *, + const decFloat *); +static decFloat *decInfinity(decFloat *, const decFloat *); +static decFloat *decInvalid(decFloat *, decContext *); +static decFloat *decNaNs(decFloat *, const decFloat *, const decFloat *, + decContext *); +static Int decNumCompare(const decFloat *, const decFloat *, Flag); +static decFloat *decToIntegral(decFloat *, const decFloat *, decContext *, + enum rounding, Flag); +static uInt decToInt32(const decFloat *, decContext *, enum rounding, + Flag, Flag); + +/* ------------------------------------------------------------------ */ +/* decCanonical -- copy a decFloat, making canonical */ +/* */ +/* result gets the canonicalized df */ +/* df is the decFloat to copy and make canonical */ +/* returns result */ +/* */ +/* This is exposed via decFloatCanonical for Double and Quad only. */ +/* This works on specials, too; no error or exception is possible. */ +/* ------------------------------------------------------------------ */ +static decFloat * decCanonical(decFloat *result, const decFloat *df) { + uInt encode, precode, dpd; // work + uInt inword, uoff, canon; // .. + Int n; // counter (down) + if (df!=result) *result=*df; // effect copy if needed + if (DFISSPECIAL(result)) { + if (DFISINF(result)) return decInfinity(result, df); // clean Infinity + // is a NaN + DFWORD(result, 0)&=~ECONNANMASK; // clear ECON except selector + if (DFISCCZERO(df)) return result; // coefficient continuation is 0 + // drop through to check payload + } + // return quickly if the coefficient continuation is canonical + { // declare block + #if DOUBLE + uInt sourhi=DFWORD(df, 0); + uInt sourlo=DFWORD(df, 1); + if (CANONDPDOFF(sourhi, 8) + && CANONDPDTWO(sourhi, sourlo, 30) + && CANONDPDOFF(sourlo, 20) + && CANONDPDOFF(sourlo, 10) + && CANONDPDOFF(sourlo, 0)) return result; + #elif QUAD + uInt sourhi=DFWORD(df, 0); + uInt sourmh=DFWORD(df, 1); + uInt sourml=DFWORD(df, 2); + uInt sourlo=DFWORD(df, 3); + if (CANONDPDOFF(sourhi, 4) + && CANONDPDTWO(sourhi, sourmh, 26) + && CANONDPDOFF(sourmh, 16) + && CANONDPDOFF(sourmh, 6) + && CANONDPDTWO(sourmh, sourml, 28) + && CANONDPDOFF(sourml, 18) + && CANONDPDOFF(sourml, 8) + && CANONDPDTWO(sourml, sourlo, 30) + && CANONDPDOFF(sourlo, 20) + && CANONDPDOFF(sourlo, 10) + && CANONDPDOFF(sourlo, 0)) return result; + #endif + } // block + + // Loop to repair a non-canonical coefficent, as needed + inword=DECWORDS-1; // current input word + uoff=0; // bit offset of declet + encode=DFWORD(result, inword); + for (n=DECLETS-1; n>=0; n--) { // count down declets of 10 bits + dpd=encode>>uoff; + uoff+=10; + if (uoff>32) { // crossed uInt boundary + inword--; + encode=DFWORD(result, inword); + uoff-=32; + dpd|=encode<<(10-uoff); // get pending bits + } + dpd&=0x3ff; // clear uninteresting bits + if (dpd<0x16e) continue; // must be canonical + canon=BIN2DPD[DPD2BIN[dpd]]; // determine canonical declet + if (canon==dpd) continue; // have canonical declet + // need to replace declet + if (uoff>=10) { // all within current word + encode&=~(0x3ff<<(uoff-10)); // clear the 10 bits ready for replace + encode|=canon<<(uoff-10); // insert the canonical form + DFWORD(result, inword)=encode; // .. and save + continue; + } + // straddled words + precode=DFWORD(result, inword+1); // get previous + precode&=0xffffffff>>(10-uoff); // clear top bits + DFWORD(result, inword+1)=precode|(canon<<(32-(10-uoff))); + encode&=0xffffffff<>(10-uoff); // insert canonical + DFWORD(result, inword)=encode; // .. and save + } // n + return result; + } // decCanonical + +/* ------------------------------------------------------------------ */ +/* decDivide -- divide operations */ +/* */ +/* result gets the result of dividing dfl by dfr: */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* op is the operation selector */ +/* returns result */ +/* */ +/* op is one of DIVIDE, REMAINDER, DIVIDEINT, or REMNEAR. */ +/* ------------------------------------------------------------------ */ +#define DIVCOUNT 0 // 1 to instrument subtractions counter +#define DIVBASE ((uInt)BILLION) // the base used for divide +#define DIVOPLEN DECPMAX9 // operand length ('digits' base 10**9) +#define DIVACCLEN (DIVOPLEN*3) // accumulator length (ditto) +static decFloat * decDivide(decFloat *result, const decFloat *dfl, + const decFloat *dfr, decContext *set, uInt op) { + decFloat quotient; // for remainders + bcdnum num; // for final conversion + uInt acc[DIVACCLEN]; // coefficent in base-billion .. + uInt div[DIVOPLEN]; // divisor in base-billion .. + uInt quo[DIVOPLEN+1]; // quotient in base-billion .. + uByte bcdacc[(DIVOPLEN+1)*9+2]; // for quotient in BCD, +1, +1 + uInt *msua, *msud, *msuq; // -> msu of acc, div, and quo + Int divunits, accunits; // lengths + Int quodigits; // digits in quotient + uInt *lsua, *lsuq; // -> current acc and quo lsus + Int length, multiplier; // work + uInt carry, sign; // .. + uInt *ua, *ud, *uq; // .. + uByte *ub; // .. + uInt uiwork; // for macros + uInt divtop; // top unit of div adjusted for estimating + #if DIVCOUNT + static uInt maxcount=0; // worst-seen subtractions count + uInt divcount=0; // subtractions count [this divide] + #endif + + // calculate sign + num.sign=(DFWORD(dfl, 0)^DFWORD(dfr, 0)) & DECFLOAT_Sign; + + if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) { // either is special? + // NaNs are handled as usual + if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + // one or two infinities + if (DFISINF(dfl)) { + if (DFISINF(dfr)) return decInvalid(result, set); // Two infinities bad + if (op&(REMAINDER|REMNEAR)) return decInvalid(result, set); // as is rem + // Infinity/x is infinite and quiet, even if x=0 + DFWORD(result, 0)=num.sign; + return decInfinity(result, result); + } + // must be x/Infinity -- remainders are lhs + if (op&(REMAINDER|REMNEAR)) return decCanonical(result, dfl); + // divides: return zero with correct sign and exponent depending + // on op (Etiny for divide, 0 for divideInt) + decFloatZero(result); + if (op==DIVIDEINT) DFWORD(result, 0)|=num.sign; // add sign + else DFWORD(result, 0)=num.sign; // zeros the exponent, too + return result; + } + // next, handle zero operands (x/0 and 0/x) + if (DFISZERO(dfr)) { // x/0 + if (DFISZERO(dfl)) { // 0/0 is undefined + decFloatZero(result); + DFWORD(result, 0)=DECFLOAT_qNaN; + set->status|=DEC_Division_undefined; + return result; + } + if (op&(REMAINDER|REMNEAR)) return decInvalid(result, set); // bad rem + set->status|=DEC_Division_by_zero; + DFWORD(result, 0)=num.sign; + return decInfinity(result, result); // x/0 -> signed Infinity + } + num.exponent=GETEXPUN(dfl)-GETEXPUN(dfr); // ideal exponent + if (DFISZERO(dfl)) { // 0/x (x!=0) + // if divide, result is 0 with ideal exponent; divideInt has + // exponent=0, remainders give zero with lower exponent + if (op&DIVIDEINT) { + decFloatZero(result); + DFWORD(result, 0)|=num.sign; // add sign + return result; + } + if (!(op&DIVIDE)) { // a remainder + // exponent is the minimum of the operands + num.exponent=MINI(GETEXPUN(dfl), GETEXPUN(dfr)); + // if the result is zero the sign shall be sign of dfl + num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign; + } + bcdacc[0]=0; + num.msd=bcdacc; // -> 0 + num.lsd=bcdacc; // .. + return decFinalize(result, &num, set); // [divide may clamp exponent] + } // 0/x + // [here, both operands are known to be finite and non-zero] + + // extract the operand coefficents into 'units' which are + // base-billion; the lhs is high-aligned in acc and the msu of both + // acc and div is at the right-hand end of array (offset length-1); + // the quotient can need one more unit than the operands as digits + // in it are not necessarily aligned neatly; further, the quotient + // may not start accumulating until after the end of the initial + // operand in acc if that is small (e.g., 1) so the accumulator + // must have at least that number of units extra (at the ls end) + GETCOEFFBILL(dfl, acc+DIVACCLEN-DIVOPLEN); + GETCOEFFBILL(dfr, div); + // zero the low uInts of acc + acc[0]=0; + acc[1]=0; + acc[2]=0; + acc[3]=0; + #if DOUBLE + #if DIVOPLEN!=2 + #error Unexpected Double DIVOPLEN + #endif + #elif QUAD + acc[4]=0; + acc[5]=0; + acc[6]=0; + acc[7]=0; + #if DIVOPLEN!=4 + #error Unexpected Quad DIVOPLEN + #endif + #endif + + // set msu and lsu pointers + msua=acc+DIVACCLEN-1; // [leading zeros removed below] + msuq=quo+DIVOPLEN; + //[loop for div will terminate because operands are non-zero] + for (msud=div+DIVOPLEN-1; *msud==0;) msud--; + // the initial least-significant unit of acc is set so acc appears + // to have the same length as div. + // This moves one position towards the least possible for each + // iteration + divunits=(Int)(msud-div+1); // precalculate + lsua=msua-divunits+1; // initial working lsu of acc + lsuq=msuq; // and of quo + + // set up the estimator for the multiplier; this is the msu of div, + // plus two bits from the unit below (if any) rounded up by one if + // there are any non-zero bits or units below that [the extra two + // bits makes for a much better estimate when the top unit is small] + divtop=*msud<<2; + if (divunits>1) { + uInt *um=msud-1; + uInt d=*um; + if (d>=750000000) {divtop+=3; d-=750000000;} + else if (d>=500000000) {divtop+=2; d-=500000000;} + else if (d>=250000000) {divtop++; d-=250000000;} + if (d) divtop++; + else for (um--; um>=div; um--) if (*um) { + divtop++; + break; + } + } // >1 unit + + #if DECTRACE + {Int i; + printf("----- div="); + for (i=divunits-1; i>=0; i--) printf("%09ld ", (LI)div[i]); + printf("\n");} + #endif + + // now collect up to DECPMAX+1 digits in the quotient (this may + // need OPLEN+1 uInts if unaligned) + quodigits=0; // no digits yet + for (;; lsua--) { // outer loop -- each input position + #if DECCHECK + if (lsua=lsua;) msua--; + accunits=(Int)(msua-lsua+1); // [maybe 0] + // subtraction is only necessary and possible if there are as + // least as many units remaining in acc for this iteration as + // there are in div + if (accunitsdiv: subtraction necessary at this position + for (ud=msud, ua=msua; ud>div; ud--, ua--) if (*ud!=*ua) break; + // [now at first mismatch or lsu] + if (*ud>*ua) break; // next time... + if (*ud==*ua) { // all compared equal + *lsuq+=1; // increment result + msua=lsua; // collapse acc units + *msua=0; // .. to a zero + break; + } + + // subtraction necessary; estimate multiplier [see above] + // if both *msud and *msua are small it is cost-effective to + // bring in part of the following units (if any) to get a + // better estimate (assume some other non-zero in div) + #define DIVLO 1000000U + #define DIVHI (DIVBASE/DIVLO) + #if DECUSE64 + if (divunits>1) { + // there cannot be a *(msud-2) for DECDOUBLE so next is + // an exact calculation unless DECQUAD (which needs to + // assume bits out there if divunits>2) + uLong mul=(uLong)*msua * DIVBASE + *(msua-1); + uLong div=(uLong)*msud * DIVBASE + *(msud-1); + #if QUAD + if (divunits>2) div++; + #endif + mul/=div; + multiplier=(Int)mul; + } + else multiplier=*msua/(*msud); + #else + if (divunits>1 && *msuadivunits + // msud is one unit 'lower' than msua, so estimate differently + #if DECUSE64 + uLong mul; + // as before, bring in extra digits if possible + if (divunits>1 && *msua>DIVSHIFTA); + carry=(uInt)(((uLong)hop*DIVMAGIC)>>DIVSHIFTB); + // the estimate is now in hi; now calculate sub-hi*10**9 + // to get the remainder (which will be =DIVBASE) { + lo-=DIVBASE; // correct by +1 + carry++; + } + } + #else // 32-bit + uInt hi; + // calculate multiplier*(*ud) into hi and lo + LONGMUL32HI(hi, *ud, multiplier); // get the high word + lo=multiplier*(*ud); // .. and the low + lo+=carry; // add the old hi + carry=hi+(lo=DIVBASE) { // split is needed + hop=(carry<<3)+(lo>>DIVSHIFTA); // hi:lo/2**29 + LONGMUL32HI(carry, hop, DIVMAGIC); // only need the high word + // [DIVSHIFTB is 32, so carry can be used directly] + // the estimate is now in carry; now calculate hi:lo-est*10**9; + // happily the top word of the result is irrelevant because it + // will always be zero so this needs only one multiplication + lo-=(carry*DIVBASE); + // the correction here will be at most +1; do it + if (lo>=DIVBASE) { + lo-=DIVBASE; + carry++; + } + } + #endif + if (lo>*ua) { // borrow needed + *ua+=DIVBASE; + carry++; + } + *ua-=lo; + } // ud loop + if (carry) *ua-=carry; // accdigits>divdigits [cannot borrow] + } // inner loop + + // the outer loop terminates when there is either an exact result + // or enough digits; first update the quotient digit count and + // pointer (if any significant digits) + #if DECTRACE + if (*lsuq || quodigits) printf("*lsuq=%09ld\n", (LI)*lsuq); + #endif + if (quodigits) { + quodigits+=9; // had leading unit earlier + lsuq--; + if (quodigits>DECPMAX+1) break; // have enough + } + else if (*lsuq) { // first quotient digits + const uInt *pow; + for (pow=DECPOWERS; *lsuq>=*pow; pow++) quodigits++; + lsuq--; + // [cannot have >DECPMAX+1 on first unit] + } + + if (*msua!=0) continue; // not an exact result + // acc is zero iff used all of original units and zero down to lsua + // (must also continue to original lsu for correct quotient length) + if (lsua>acc+DIVACCLEN-DIVOPLEN) continue; + for (; msua>lsua && *msua==0;) msua--; + if (*msua==0 && msua==lsua) break; + } // outer loop + + // all of the original operand in acc has been covered at this point + // quotient now has at least DECPMAX+2 digits + // *msua is now non-0 if inexact and sticky bits + // lsuq is one below the last uint of the quotient + lsuq++; // set -> true lsu of quo + if (*msua) *lsuq|=1; // apply sticky bit + + // quo now holds the (unrounded) quotient in base-billion; one + // base-billion 'digit' per uInt. + #if DECTRACE + printf("DivQuo:"); + for (uq=msuq; uq>=lsuq; uq--) printf(" %09ld", (LI)*uq); + printf("\n"); + #endif + + // Now convert to BCD for rounding and cleanup, starting from the + // most significant end [offset by one into bcdacc to leave room + // for a possible carry digit if rounding for REMNEAR is needed] + for (uq=msuq, ub=bcdacc+1; uq>=lsuq; uq--, ub+=9) { + uInt top, mid, rem; // work + if (*uq==0) { // no split needed + UBFROMUI(ub, 0); // clear 9 BCD8s + UBFROMUI(ub+4, 0); // .. + *(ub+8)=0; // .. + continue; + } + // *uq is non-zero -- split the base-billion digit into + // hi, mid, and low three-digits + #define divsplit9 1000000 // divisor + #define divsplit6 1000 // divisor + // The splitting is done by simple divides and remainders, + // assuming the compiler will optimize these [GCC does] + top=*uq/divsplit9; + rem=*uq%divsplit9; + mid=rem/divsplit6; + rem=rem%divsplit6; + // lay out the nine BCD digits (plus one unwanted byte) + UBFROMUI(ub, UBTOUI(&BIN2BCD8[top*4])); + UBFROMUI(ub+3, UBTOUI(&BIN2BCD8[mid*4])); + UBFROMUI(ub+6, UBTOUI(&BIN2BCD8[rem*4])); + } // BCD conversion loop + ub--; // -> lsu + + // complete the bcdnum; quodigits is correct, so the position of + // the first non-zero is known + num.msd=bcdacc+1+(msuq-lsuq+1)*9-quodigits; + num.lsd=ub; + + // make exponent adjustments, etc + if (lsuamaxcount) { // new high-water nark + maxcount=divcount; + printf("DivNewMaxCount: %ld\n", (LI)maxcount); + } + #endif + + if (op&DIVIDE) return decFinalize(result, &num, set); // all done + + // Is DIVIDEINT or a remainder; there is more to do -- first form + // the integer (this is done 'after the fact', unlike as in + // decNumber, so as not to tax DIVIDE) + + // The first non-zero digit will be in the first 9 digits, known + // from quodigits and num.msd, so there is always space for DECPMAX + // digits + + length=(Int)(num.lsd-num.msd+1); + //printf("Length exp: %ld %ld\n", (LI)length, (LI)num.exponent); + + if (length+num.exponent>DECPMAX) { // cannot fit + decFloatZero(result); + DFWORD(result, 0)=DECFLOAT_qNaN; + set->status|=DEC_Division_impossible; + return result; + } + + if (num.exponent>=0) { // already an int, or need pad zeros + for (ub=num.lsd+1; ub<=num.lsd+num.exponent; ub++) *ub=0; + num.lsd+=num.exponent; + } + else { // too long: round or truncate needed + Int drop=-num.exponent; + if (!(op&REMNEAR)) { // simple truncate + num.lsd-=drop; + if (num.lsd re-round digit + uByte reround; // reround value + *(num.msd-1)=0; // in case of left carry, or make 0 + if (drop 0] + reround=*roundat; + for (ub=roundat+1; ub<=num.lsd; ub++) { + if (*ub!=0) { + reround=DECSTICKYTAB[reround]; + break; + } + } // check stickies + if (roundat>num.msd) num.lsd=roundat-1; + else { + num.msd--; // use the 0 .. + num.lsd=num.msd; // .. at the new MSD place + } + if (reround!=0) { // discarding non-zero + uInt bump=0; + // rounding is DEC_ROUND_HALF_EVEN always + if (reround>5) bump=1; // >0.5 goes up + else if (reround==5) // exactly 0.5000 .. + bump=*(num.lsd) & 0x01; // .. up iff [new] lsd is odd + if (bump!=0) { // need increment + // increment the coefficient; this might end up with 1000... + ub=num.lsd; + for (; UBTOUI(ub-3)==0x09090909; ub-=4) UBFROMUI(ub-3, 0); + for (; *ub==9; ub--) *ub=0; // at most 3 more + *ub+=1; + if (ub9 + #error Exponent may overflow when doubled for Multiply +#endif +#if MULACCLEN!=(MULACCLEN/4)*4 + // This assumption is used below only for initialization + #error MULACCLEN is not a multiple of 4 +#endif + +static void decFiniteMultiply(bcdnum *num, uByte *bcdacc, + const decFloat *dfl, const decFloat *dfr) { + uInt bufl[MULOPLEN]; // left coefficient (base-billion) + uInt bufr[MULOPLEN]; // right coefficient (base-billion) + uInt *ui, *uj; // work + uByte *ub; // .. + uInt uiwork; // for macros + + #if DECUSE64 + uLong accl[MULACCLEN]; // lazy accumulator (base-billion+) + uLong *pl; // work -> lazy accumulator + uInt acc[MULACCLEN]; // coefficent in base-billion .. + #else + uInt acc[MULACCLEN*2]; // accumulator in base-billion .. + #endif + uInt *pa; // work -> accumulator + //printf("Base10**9: OpLen=%d MulAcclen=%d\n", OPLEN, MULACCLEN); + + /* Calculate sign and exponent */ + num->sign=(DFWORD(dfl, 0)^DFWORD(dfr, 0)) & DECFLOAT_Sign; + num->exponent=GETEXPUN(dfl)+GETEXPUN(dfr); // [see assertion above] + + /* Extract the coefficients and prepare the accumulator */ + // the coefficients of the operands are decoded into base-billion + // numbers in uInt arrays (bufl and bufr, LSD at offset 0) of the + // appropriate size. + GETCOEFFBILL(dfl, bufl); + GETCOEFFBILL(dfr, bufr); + #if DECTRACE && 0 + printf("CoeffbL:"); + for (ui=bufl+MULOPLEN-1; ui>=bufl; ui--) printf(" %08lx", (LI)*ui); + printf("\n"); + printf("CoeffbR:"); + for (uj=bufr+MULOPLEN-1; uj>=bufr; uj--) printf(" %08lx", (LI)*uj); + printf("\n"); + #endif + + // start the 64-bit/32-bit differing paths... +#if DECUSE64 + + // zero the accumulator + #if MULACCLEN==4 + accl[0]=0; accl[1]=0; accl[2]=0; accl[3]=0; + #else // use a loop + // MULACCLEN is a multiple of four, asserted above + for (pl=accl; pl1 may be + // needed. Values of A and B are chosen to satisfy the constraints + // just mentioned while minimizing the maximum error (and hence the + // maximum correction), as shown in the following table: + // + // Type OPLEN A B maxX maxError maxCorrection + // --------------------------------------------------------- + // DOUBLE 2 29 32 <2*10**18 0.63 1 + // QUAD 4 30 31 <4*10**18 1.17 2 + // + // In the OPLEN==2 case there is most choice, but the value for B + // of 32 has a big advantage as then the calculation of the + // estimate requires no shifting; the compiler can extract the high + // word directly after multiplying magic*hop. + #define MULMAGIC 2305843009U // 2**61/10**9 [both cases] + #if DOUBLE + #define MULSHIFTA 29 + #define MULSHIFTB 32 + #elif QUAD + #define MULSHIFTA 30 + #define MULSHIFTB 31 + #else + #error Unexpected type + #endif + + #if DECTRACE + printf("MulAccl:"); + for (pl=accl+MULACCLEN-1; pl>=accl; pl--) + printf(" %08lx:%08lx", (LI)(*pl>>32), (LI)(*pl&0xffffffff)); + printf("\n"); + #endif + + for (pl=accl, pa=acc; pl=MULTBASE) { + // *pl holds a binary number which needs to be split + hop=(uInt)(*pl>>MULSHIFTA); + est=(uInt)(((uLong)hop*MULMAGIC)>>MULSHIFTB); + // the estimate is now in est; now calculate hi:lo-est*10**9; + // happily the top word of the result is irrelevant because it + // will always be zero so this needs only one multiplication + lo=(uInt)(*pl-((uLong)est*MULTBASE)); // low word of result + // If QUAD, the correction here could be +2 + if (lo>=MULTBASE) { + lo-=MULTBASE; // correct by +1 + est++; + #if QUAD + // may need to correct by +2 + if (lo>=MULTBASE) { + lo-=MULTBASE; + est++; + } + #endif + } + // finally place lo as the new coefficient 'digit' and add est to + // the next place up [this is safe because this path is never + // taken on the final iteration as *pl will fit] + *pa=lo; + *(pl+1)+=est; + } // *pl needed split + else { // *pl1 may be + // needed. Values of A and B are chosen to satisfy the constraints + // just mentioned while minimizing the maximum error (and hence the + // maximum correction), as shown in the following table: + // + // Type OPLEN A B maxX maxError maxCorrection + // --------------------------------------------------------- + // DOUBLE 2 29 32 <2*10**18 0.63 1 + // QUAD 4 30 31 <4*10**18 1.17 2 + // + // In the OPLEN==2 case there is most choice, but the value for B + // of 32 has a big advantage as then the calculation of the + // estimate requires no shifting; the high word is simply + // calculated from multiplying magic*hop. + #define MULMAGIC 2305843009U // 2**61/10**9 [both cases] + #if DOUBLE + #define MULSHIFTA 29 + #define MULSHIFTB 32 + #elif QUAD + #define MULSHIFTA 30 + #define MULSHIFTB 31 + #else + #error Unexpected type + #endif + + #if DECTRACE + printf("MulHiLo:"); + for (pa=acc+MULACCLEN-1; pa>=acc; pa--) + printf(" %08lx:%08lx", (LI)*(pa+MULACCLEN), (LI)*pa); + printf("\n"); + #endif + + for (pa=acc;; pa++) { // each low uInt + uInt hi, lo; // words of exact multiply result + uInt hop, estlo; // work + #if QUAD + uInt esthi; // .. + #endif + + lo=*pa; + hi=*(pa+MULACCLEN); // top 32 bits + // hi and lo now hold a binary number which needs to be split + + #if DOUBLE + hop=(hi<<3)+(lo>>MULSHIFTA); // hi:lo/2**29 + LONGMUL32HI(estlo, hop, MULMAGIC);// only need the high word + // [MULSHIFTB is 32, so estlo can be used directly] + // the estimate is now in estlo; now calculate hi:lo-est*10**9; + // happily the top word of the result is irrelevant because it + // will always be zero so this needs only one multiplication + lo-=(estlo*MULTBASE); + // esthi=0; // high word is ignored below + // the correction here will be at most +1; do it + if (lo>=MULTBASE) { + lo-=MULTBASE; + estlo++; + } + #elif QUAD + hop=(hi<<2)+(lo>>MULSHIFTA); // hi:lo/2**30 + LONGMUL32HI(esthi, hop, MULMAGIC);// shift will be 31 .. + estlo=hop*MULMAGIC; // .. so low word needed + estlo=(esthi<<1)+(estlo>>MULSHIFTB); // [just the top bit] + // esthi=0; // high word is ignored below + lo-=(estlo*MULTBASE); // as above + // the correction here could be +1 or +2 + if (lo>=MULTBASE) { + lo-=MULTBASE; + estlo++; + } + if (lo>=MULTBASE) { + lo-=MULTBASE; + estlo++; + } + #else + #error Unexpected type + #endif + + // finally place lo as the new accumulator digit and add est to + // the next place up; this latter add could cause a carry of 1 + // to the high word of the next place + *pa=lo; + *(pa+1)+=estlo; + // esthi is always 0 for DOUBLE and QUAD so this is skipped + // *(pa+1+MULACCLEN)+=esthi; + if (*(pa+1)=acc; pa--) printf(" %09ld", (LI)*pa); + printf("\n"); + #endif + + // Now convert to BCD for rounding and cleanup, starting from the + // most significant end + pa=acc+MULACCLEN-1; + if (*pa!=0) num->msd=bcdacc+LEADZEROS;// drop known lead zeros + else { // >=1 word of leading zeros + num->msd=bcdacc; // known leading zeros are gone + pa--; // skip first word .. + for (; *pa==0; pa--) if (pa==acc) break; // .. and any more leading 0s + } + for (ub=bcdacc;; pa--, ub+=9) { + if (*pa!=0) { // split(s) needed + uInt top, mid, rem; // work + // *pa is non-zero -- split the base-billion acc digit into + // hi, mid, and low three-digits + #define mulsplit9 1000000 // divisor + #define mulsplit6 1000 // divisor + // The splitting is done by simple divides and remainders, + // assuming the compiler will optimize these where useful + // [GCC does] + top=*pa/mulsplit9; + rem=*pa%mulsplit9; + mid=rem/mulsplit6; + rem=rem%mulsplit6; + // lay out the nine BCD digits (plus one unwanted byte) + UBFROMUI(ub, UBTOUI(&BIN2BCD8[top*4])); + UBFROMUI(ub+3, UBTOUI(&BIN2BCD8[mid*4])); + UBFROMUI(ub+6, UBTOUI(&BIN2BCD8[rem*4])); + } + else { // *pa==0 + UBFROMUI(ub, 0); // clear 9 BCD8s + UBFROMUI(ub+4, 0); // .. + *(ub+8)=0; // .. + } + if (pa==acc) break; + } // BCD conversion loop + + num->lsd=ub+8; // complete the bcdnum .. + + #if DECTRACE + decShowNum(num, "postmult"); + decFloatShow(dfl, "dfl"); + decFloatShow(dfr, "dfr"); + #endif + return; + } // decFiniteMultiply + +/* ------------------------------------------------------------------ */ +/* decFloatAbs -- absolute value, heeding NaNs, etc. */ +/* */ +/* result gets the canonicalized df with sign 0 */ +/* df is the decFloat to abs */ +/* set is the context */ +/* returns result */ +/* */ +/* This has the same effect as decFloatPlus unless df is negative, */ +/* in which case it has the same effect as decFloatMinus. The */ +/* effect is also the same as decFloatCopyAbs except that NaNs are */ +/* handled normally (the sign of a NaN is not affected, and an sNaN */ +/* will signal) and the result will be canonical. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatAbs(decFloat *result, const decFloat *df, + decContext *set) { + if (DFISNAN(df)) return decNaNs(result, df, NULL, set); + decCanonical(result, df); // copy and check + DFBYTE(result, 0)&=~0x80; // zero sign bit + return result; + } // decFloatAbs + +/* ------------------------------------------------------------------ */ +/* decFloatAdd -- add two decFloats */ +/* */ +/* result gets the result of adding dfl and dfr: */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* ------------------------------------------------------------------ */ +#if QUAD +// Table for testing MSDs for fastpath elimination; returns the MSD of +// a decDouble or decQuad (top 6 bits tested) ignoring the sign. +// Infinities return -32 and NaNs return -128 so that summing the two +// MSDs also allows rapid tests for the Specials (see code below). +const Int DECTESTMSD[64]={ + 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, -32, -128, + 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, -32, -128}; +#else +// The table for testing MSDs is shared between the modules +extern const Int DECTESTMSD[64]; +#endif + +decFloat * decFloatAdd(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + bcdnum num; // for final conversion + Int bexpl, bexpr; // left and right biased exponents + uByte *ub, *us, *ut; // work + uInt uiwork; // for macros + #if QUAD + uShort uswork; // .. + #endif + + uInt sourhil, sourhir; // top words from source decFloats + // [valid only through end of + // fastpath code -- before swap] + uInt diffsign; // non-zero if signs differ + uInt carry; // carry: 0 or 1 before add loop + Int overlap; // coefficient overlap (if full) + Int summ; // sum of the MSDs + // the following buffers hold coefficients with various alignments + // (see commentary and diagrams below) + uByte acc[4+2+DECPMAX*3+8]; + uByte buf[4+2+DECPMAX*2]; + uByte *umsd, *ulsd; // local MSD and LSD pointers + + #if DECLITEND + #define CARRYPAT 0x01000000 // carry=1 pattern + #else + #define CARRYPAT 0x00000001 // carry=1 pattern + #endif + + /* Start decoding the arguments */ + // The initial exponents are placed into the opposite Ints to + // that which might be expected; there are two sets of data to + // keep track of (each decFloat and the corresponding exponent), + // and this scheme means that at the swap point (after comparing + // exponents) only one pair of words needs to be swapped + // whichever path is taken (thereby minimising worst-case path). + // The calculated exponents will be nonsense when the arguments are + // Special, but are not used in that path + sourhil=DFWORD(dfl, 0); // LHS top word + summ=DECTESTMSD[sourhil>>26]; // get first MSD for testing + bexpr=DECCOMBEXP[sourhil>>26]; // get exponent high bits (in place) + bexpr+=GETECON(dfl); // .. + continuation + + sourhir=DFWORD(dfr, 0); // RHS top word + summ+=DECTESTMSD[sourhir>>26]; // sum MSDs for testing + bexpl=DECCOMBEXP[sourhir>>26]; + bexpl+=GETECON(dfr); + + // here bexpr has biased exponent from lhs, and vice versa + + diffsign=(sourhil^sourhir)&DECFLOAT_Sign; + + // now determine whether to take a fast path or the full-function + // slow path. The slow path must be taken when: + // -- both numbers are finite, and: + // the exponents are different, or + // the signs are different, or + // the sum of the MSDs is >8 (hence might overflow) + // specialness and the sum of the MSDs can be tested at once using + // the summ value just calculated, so the test for specials is no + // longer on the worst-case path (as of 3.60) + + if (summ<=8) { // MSD+MSD is good, or there is a special + if (summ<0) { // there is a special + // Inf+Inf would give -64; Inf+finite is -32 or higher + if (summ<-64) return decNaNs(result, dfl, dfr, set); // one or two NaNs + // two infinities with different signs is invalid + if (summ==-64 && diffsign) return decInvalid(result, set); + if (DFISINF(dfl)) return decInfinity(result, dfl); // LHS is infinite + return decInfinity(result, dfr); // RHS must be Inf + } + // Here when both arguments are finite; fast path is possible + // (currently only for aligned and same-sign) + if (bexpr==bexpl && !diffsign) { + uInt tac[DECLETS+1]; // base-1000 coefficient + uInt encode; // work + + // Get one coefficient as base-1000 and add the other + GETCOEFFTHOU(dfl, tac); // least-significant goes to [0] + ADDCOEFFTHOU(dfr, tac); + // here the sum of the MSDs (plus any carry) will be <10 due to + // the fastpath test earlier + + // construct the result; low word is the same for both formats + encode =BIN2DPD[tac[0]]; + encode|=BIN2DPD[tac[1]]<<10; + encode|=BIN2DPD[tac[2]]<<20; + encode|=BIN2DPD[tac[3]]<<30; + DFWORD(result, (DECBYTES/4)-1)=encode; + + // collect next two declets (all that remains, for Double) + encode =BIN2DPD[tac[3]]>>2; + encode|=BIN2DPD[tac[4]]<<8; + + #if QUAD + // complete and lay out middling words + encode|=BIN2DPD[tac[5]]<<18; + encode|=BIN2DPD[tac[6]]<<28; + DFWORD(result, 2)=encode; + + encode =BIN2DPD[tac[6]]>>4; + encode|=BIN2DPD[tac[7]]<<6; + encode|=BIN2DPD[tac[8]]<<16; + encode|=BIN2DPD[tac[9]]<<26; + DFWORD(result, 1)=encode; + + // and final two declets + encode =BIN2DPD[tac[9]]>>6; + encode|=BIN2DPD[tac[10]]<<4; + #endif + + // add exponent continuation and sign (from either argument) + encode|=sourhil & (ECONMASK | DECFLOAT_Sign); + + // create lookup index = MSD + top two bits of biased exponent <<4 + tac[DECLETS]|=(bexpl>>DECECONL)<<4; + encode|=DECCOMBFROM[tac[DECLETS]]; // add constructed combination field + DFWORD(result, 0)=encode; // complete + + // decFloatShow(result, ">"); + return result; + } // fast path OK + // drop through to slow path + } // low sum or Special(s) + + /* Slow path required -- arguments are finite and might overflow, */ + /* or require alignment, or might have different signs */ + + // now swap either exponents or argument pointers + if (bexpl<=bexpr) { + // original left is bigger + Int bexpswap=bexpl; + bexpl=bexpr; + bexpr=bexpswap; + // printf("left bigger\n"); + } + else { + const decFloat *dfswap=dfl; + dfl=dfr; + dfr=dfswap; + // printf("right bigger\n"); + } + // [here dfl and bexpl refer to the datum with the larger exponent, + // of if the exponents are equal then the original LHS argument] + + // if lhs is zero then result will be the rhs (now known to have + // the smaller exponent), which also may need to be tested for zero + // for the weird IEEE 754 sign rules + if (DFISZERO(dfl)) { + decCanonical(result, dfr); // clean copy + // "When the sum of two operands with opposite signs is + // exactly zero, the sign of that sum shall be '+' in all + // rounding modes except round toward -Infinity, in which + // mode that sign shall be '-'." + if (diffsign && DFISZERO(result)) { + DFWORD(result, 0)&=~DECFLOAT_Sign; // assume sign 0 + if (set->round==DEC_ROUND_FLOOR) DFWORD(result, 0)|=DECFLOAT_Sign; + } + return result; + } // numfl is zero + // [here, LHS is non-zero; code below assumes that] + + // Coefficients layout during the calculations to follow: + // + // Overlap case: + // +------------------------------------------------+ + // acc: |0000| coeffa | tail B | | + // +------------------------------------------------+ + // buf: |0000| pad0s | coeffb | | + // +------------------------------------------------+ + // + // Touching coefficients or gap: + // +------------------------------------------------+ + // acc: |0000| coeffa | gap | coeffb | + // +------------------------------------------------+ + // [buf not used or needed; gap clamped to Pmax] + + // lay out lhs coefficient into accumulator; this starts at acc+4 + // for decDouble or acc+6 for decQuad so the LSD is word- + // aligned; the top word gap is there only in case a carry digit + // is prefixed after the add -- it does not need to be zeroed + #if DOUBLE + #define COFF 4 // offset into acc + #elif QUAD + UBFROMUS(acc+4, 0); // prefix 00 + #define COFF 6 // offset into acc + #endif + + GETCOEFF(dfl, acc+COFF); // decode from decFloat + ulsd=acc+COFF+DECPMAX-1; + umsd=acc+4; // [having this here avoids + + #if DECTRACE + {bcdnum tum; + tum.msd=umsd; + tum.lsd=ulsd; + tum.exponent=bexpl-DECBIAS; + tum.sign=DFWORD(dfl, 0) & DECFLOAT_Sign; + decShowNum(&tum, "dflx");} + #endif + + // if signs differ, take ten's complement of lhs (here the + // coefficient is subtracted from all-nines; the 1 is added during + // the later add cycle -- zeros to the right do not matter because + // the complement of zero is zero); these are fixed-length inverts + // where the lsd is known to be at a 4-byte boundary (so no borrow + // possible) + carry=0; // assume no carry + if (diffsign) { + carry=CARRYPAT; // for +1 during add + UBFROMUI(acc+ 4, 0x09090909-UBTOUI(acc+ 4)); + UBFROMUI(acc+ 8, 0x09090909-UBTOUI(acc+ 8)); + UBFROMUI(acc+12, 0x09090909-UBTOUI(acc+12)); + UBFROMUI(acc+16, 0x09090909-UBTOUI(acc+16)); + #if QUAD + UBFROMUI(acc+20, 0x09090909-UBTOUI(acc+20)); + UBFROMUI(acc+24, 0x09090909-UBTOUI(acc+24)); + UBFROMUI(acc+28, 0x09090909-UBTOUI(acc+28)); + UBFROMUI(acc+32, 0x09090909-UBTOUI(acc+32)); + UBFROMUI(acc+36, 0x09090909-UBTOUI(acc+36)); + #endif + } // diffsign + + // now process the rhs coefficient; if it cannot overlap lhs then + // it can be put straight into acc (with an appropriate gap, if + // needed) because no actual addition will be needed (except + // possibly to complete ten's complement) + overlap=DECPMAX-(bexpl-bexpr); + #if DECTRACE + printf("exps: %ld %ld\n", (LI)(bexpl-DECBIAS), (LI)(bexpr-DECBIAS)); + printf("Overlap=%ld carry=%08lx\n", (LI)overlap, (LI)carry); + #endif + + if (overlap<=0) { // no overlap possible + uInt gap; // local work + // since a full addition is not needed, a ten's complement + // calculation started above may need to be completed + if (carry) { + for (ub=ulsd; *ub==9; ub--) *ub=0; + *ub+=1; + carry=0; // taken care of + } + // up to DECPMAX-1 digits of the final result can extend down + // below the LSD of the lhs, so if the gap is >DECPMAX then the + // rhs will be simply sticky bits. In this case the gap is + // clamped to DECPMAX and the exponent adjusted to suit [this is + // safe because the lhs is non-zero]. + gap=-overlap; + if (gap>DECPMAX) { + bexpr+=gap-1; + gap=DECPMAX; + } + ub=ulsd+gap+1; // where MSD will go + // Fill the gap with 0s; note that there is no addition to do + ut=acc+COFF+DECPMAX; // start of gap + for (; ut DECPMAX + *ub=(uByte)(!DFISZERO(dfr)); // make sticky digit + } + else { // need full coefficient + GETCOEFF(dfr, ub); // decode from decFloat + ub+=DECPMAX-1; // new LSD... + } + ulsd=ub; // save new LSD + } // no overlap possible + + else { // overlap>0 + // coefficients overlap (perhaps completely, although also + // perhaps only where zeros) + if (overlap==DECPMAX) { // aligned + ub=buf+COFF; // where msd will go + #if QUAD + UBFROMUS(buf+4, 0); // clear quad's 00 + #endif + GETCOEFF(dfr, ub); // decode from decFloat + } + else { // unaligned + ub=buf+COFF+DECPMAX-overlap; // where MSD will go + // Fill the prefix gap with 0s; 8 will cover most common + // unalignments, so start with direct assignments (a loop is + // then used for any remaining -- the loop (and the one in a + // moment) is not then on the critical path because the number + // of additions is reduced by (at least) two in this case) + UBFROMUI(buf+4, 0); // [clears decQuad 00 too] + UBFROMUI(buf+8, 0); + if (ub>buf+12) { + ut=buf+12; // start any remaining + for (; ut=acc+4; ut-=4, us-=4) { // big-endian add loop + // bcd8 add + carry+=UBTOUI(us); // rhs + carry + if (carry==0) continue; // no-op + carry+=UBTOUI(ut); // lhs + // Big-endian BCD adjust (uses internal carry) + carry+=0x76f6f6f6; // note top nibble not all bits + // apply BCD adjust and save + UBFROMUI(ut, (carry & 0x0f0f0f0f) - ((carry & 0x60606060)>>4)); + carry>>=31; // true carry was at far left + } // add loop + #else + for (; ut>=acc+4; ut-=4, us-=4) { // little-endian add loop + // bcd8 add + carry+=UBTOUI(us); // rhs + carry + if (carry==0) continue; // no-op [common if unaligned] + carry+=UBTOUI(ut); // lhs + // Little-endian BCD adjust; inter-digit carry must be manual + // because the lsb from the array will be in the most-significant + // byte of carry + carry+=0x76767676; // note no inter-byte carries + carry+=(carry & 0x80000000)>>15; + carry+=(carry & 0x00800000)>>15; + carry+=(carry & 0x00008000)>>15; + carry-=(carry & 0x60606060)>>4; // BCD adjust back + UBFROMUI(ut, carry & 0x0f0f0f0f); // clear debris and save + // here, final carry-out bit is at 0x00000080; move it ready + // for next word-add (i.e., to 0x01000000) + carry=(carry & 0x00000080)<<17; + } // add loop + #endif + + #if DECTRACE + {bcdnum tum; + printf("Add done, carry=%08lx, diffsign=%ld\n", (LI)carry, (LI)diffsign); + tum.msd=umsd; // acc+4; + tum.lsd=ulsd; + tum.exponent=0; + tum.sign=0; + decShowNum(&tum, "dfadd");} + #endif + } // overlap possible + + // ordering here is a little strange in order to have slowest path + // first in GCC asm listing + if (diffsign) { // subtraction + if (!carry) { // no carry out means RHS=umsd+BNEXT) { // unaligned + // eight will handle most unaligments for Double; 16 for Quad + UBFROMUI(umsd+BNEXT, 0x09090909-UBTOUI(umsd+BNEXT)); + UBFROMUI(umsd+BNEXT+4, 0x09090909-UBTOUI(umsd+BNEXT+4)); + #if DOUBLE + #define BNEXTY (BNEXT+8) + #elif QUAD + UBFROMUI(umsd+BNEXT+8, 0x09090909-UBTOUI(umsd+BNEXT+8)); + UBFROMUI(umsd+BNEXT+12, 0x09090909-UBTOUI(umsd+BNEXT+12)); + #define BNEXTY (BNEXT+16) + #endif + if (ulsd>=umsd+BNEXTY) { // very unaligned + ut=umsd+BNEXTY; // -> continue + for (;;ut+=4) { + UBFROMUI(ut, 0x09090909-UBTOUI(ut)); // invert four digits + if (ut>=ulsd-3) break; // all done + } + } + } + // complete the ten's complement by adding 1 + for (ub=ulsd; *ub==9; ub--) *ub=0; + *ub+=1; + } // borrowed + + else { // carry out means RHS>=LHS + num.sign=DFWORD(dfr, 0) & DECFLOAT_Sign; + // all done except for the special IEEE 754 exact-zero-result + // rule (see above); while testing for zero, strip leading + // zeros (which will save decFinalize doing it) (this is in + // diffsign path, so carry impossible and true umsd is + // acc+COFF) + + // Check the initial coefficient area using the fast macro; + // this will often be all that needs to be done (as on the + // worst-case path when the subtraction was aligned and + // full-length) + if (ISCOEFFZERO(acc+COFF)) { + umsd=acc+COFF+DECPMAX-1; // so far, so zero + if (ulsd>umsd) { // more to check + umsd++; // to align after checked area + for (; UBTOUI(umsd)==0 && umsd+3round==DEC_ROUND_FLOOR) num.sign=DECFLOAT_Sign; + } + } + // [else was not zero, might still have leading zeros] + } // subtraction gave positive result + } // diffsign + + else { // same-sign addition + num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign; + #if DOUBLE + if (carry) { // only possible with decDouble + *(acc+3)=1; // [Quad has leading 00] + umsd=acc+3; + } + #endif + } // same sign + + num.msd=umsd; // set MSD .. + num.lsd=ulsd; // .. and LSD + num.exponent=bexpr-DECBIAS; // set exponent to smaller, unbiassed + + #if DECTRACE + decFloatShow(dfl, "dfl"); + decFloatShow(dfr, "dfr"); + decShowNum(&num, "postadd"); + #endif + return decFinalize(result, &num, set); // round, check, and lay out + } // decFloatAdd + +/* ------------------------------------------------------------------ */ +/* decFloatAnd -- logical digitwise AND of two decFloats */ +/* */ +/* result gets the result of ANDing dfl and dfr */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result, which will be canonical with sign=0 */ +/* */ +/* The operands must be positive, finite with exponent q=0, and */ +/* comprise just zeros and ones; if not, Invalid operation results. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatAnd(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + if (!DFISUINT01(dfl) || !DFISUINT01(dfr) + || !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set); + // the operands are positive finite integers (q=0) with just 0s and 1s + #if DOUBLE + DFWORD(result, 0)=ZEROWORD + |((DFWORD(dfl, 0) & DFWORD(dfr, 0))&0x04009124); + DFWORD(result, 1)=(DFWORD(dfl, 1) & DFWORD(dfr, 1))&0x49124491; + #elif QUAD + DFWORD(result, 0)=ZEROWORD + |((DFWORD(dfl, 0) & DFWORD(dfr, 0))&0x04000912); + DFWORD(result, 1)=(DFWORD(dfl, 1) & DFWORD(dfr, 1))&0x44912449; + DFWORD(result, 2)=(DFWORD(dfl, 2) & DFWORD(dfr, 2))&0x12449124; + DFWORD(result, 3)=(DFWORD(dfl, 3) & DFWORD(dfr, 3))&0x49124491; + #endif + return result; + } // decFloatAnd + +/* ------------------------------------------------------------------ */ +/* decFloatCanonical -- copy a decFloat, making canonical */ +/* */ +/* result gets the canonicalized df */ +/* df is the decFloat to copy and make canonical */ +/* returns result */ +/* */ +/* This works on specials, too; no error or exception is possible. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCanonical(decFloat *result, const decFloat *df) { + return decCanonical(result, df); + } // decFloatCanonical + +/* ------------------------------------------------------------------ */ +/* decFloatClass -- return the class of a decFloat */ +/* */ +/* df is the decFloat to test */ +/* returns the decClass that df falls into */ +/* ------------------------------------------------------------------ */ +enum decClass decFloatClass(const decFloat *df) { + Int exp; // exponent + if (DFISSPECIAL(df)) { + if (DFISQNAN(df)) return DEC_CLASS_QNAN; + if (DFISSNAN(df)) return DEC_CLASS_SNAN; + // must be an infinity + if (DFISSIGNED(df)) return DEC_CLASS_NEG_INF; + return DEC_CLASS_POS_INF; + } + if (DFISZERO(df)) { // quite common + if (DFISSIGNED(df)) return DEC_CLASS_NEG_ZERO; + return DEC_CLASS_POS_ZERO; + } + // is finite and non-zero; similar code to decFloatIsNormal, here + // [this could be speeded up slightly by in-lining decFloatDigits] + exp=GETEXPUN(df) // get unbiased exponent .. + +decFloatDigits(df)-1; // .. and make adjusted exponent + if (exp>=DECEMIN) { // is normal + if (DFISSIGNED(df)) return DEC_CLASS_NEG_NORMAL; + return DEC_CLASS_POS_NORMAL; + } + // is subnormal + if (DFISSIGNED(df)) return DEC_CLASS_NEG_SUBNORMAL; + return DEC_CLASS_POS_SUBNORMAL; + } // decFloatClass + +/* ------------------------------------------------------------------ */ +/* decFloatClassString -- return the class of a decFloat as a string */ +/* */ +/* df is the decFloat to test */ +/* returns a constant string describing the class df falls into */ +/* ------------------------------------------------------------------ */ +const char *decFloatClassString(const decFloat *df) { + enum decClass eclass=decFloatClass(df); + if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN; + if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN; + if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ; + if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ; + if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS; + if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS; + if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI; + if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI; + if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN; + if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN; + return DEC_ClassString_UN; // Unknown + } // decFloatClassString + +/* ------------------------------------------------------------------ */ +/* decFloatCompare -- compare two decFloats; quiet NaNs allowed */ +/* */ +/* result gets the result of comparing dfl and dfr */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result, which may be -1, 0, 1, or NaN (Unordered) */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCompare(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int comp; // work + // NaNs are handled as usual + if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + // numeric comparison needed + comp=decNumCompare(dfl, dfr, 0); + decFloatZero(result); + if (comp==0) return result; + DFBYTE(result, DECBYTES-1)=0x01; // LSD=1 + if (comp<0) DFBYTE(result, 0)|=0x80; // set sign bit + return result; + } // decFloatCompare + +/* ------------------------------------------------------------------ */ +/* decFloatCompareSignal -- compare two decFloats; all NaNs signal */ +/* */ +/* result gets the result of comparing dfl and dfr */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result, which may be -1, 0, 1, or NaN (Unordered) */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCompareSignal(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int comp; // work + // NaNs are handled as usual, except that all NaNs signal + if (DFISNAN(dfl) || DFISNAN(dfr)) { + set->status|=DEC_Invalid_operation; + return decNaNs(result, dfl, dfr, set); + } + // numeric comparison needed + comp=decNumCompare(dfl, dfr, 0); + decFloatZero(result); + if (comp==0) return result; + DFBYTE(result, DECBYTES-1)=0x01; // LSD=1 + if (comp<0) DFBYTE(result, 0)|=0x80; // set sign bit + return result; + } // decFloatCompareSignal + +/* ------------------------------------------------------------------ */ +/* decFloatCompareTotal -- compare two decFloats with total ordering */ +/* */ +/* result gets the result of comparing dfl and dfr */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* returns result, which may be -1, 0, or 1 */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCompareTotal(decFloat *result, + const decFloat *dfl, const decFloat *dfr) { + Int comp; // work + uInt uiwork; // for macros + #if QUAD + uShort uswork; // .. + #endif + if (DFISNAN(dfl) || DFISNAN(dfr)) { + Int nanl, nanr; // work + // morph NaNs to +/- 1 or 2, leave numbers as 0 + nanl=DFISSNAN(dfl)+DFISQNAN(dfl)*2; // quiet > signalling + if (DFISSIGNED(dfl)) nanl=-nanl; + nanr=DFISSNAN(dfr)+DFISQNAN(dfr)*2; + if (DFISSIGNED(dfr)) nanr=-nanr; + if (nanl>nanr) comp=+1; + else if (nanl*uc) comp=sigl; // difference found + else comp=-sigl; // .. + break; + } + } + } // same NaN type and sign + } + else { + // numeric comparison needed + comp=decNumCompare(dfl, dfr, 1); // total ordering + } + decFloatZero(result); + if (comp==0) return result; + DFBYTE(result, DECBYTES-1)=0x01; // LSD=1 + if (comp<0) DFBYTE(result, 0)|=0x80; // set sign bit + return result; + } // decFloatCompareTotal + +/* ------------------------------------------------------------------ */ +/* decFloatCompareTotalMag -- compare magnitudes with total ordering */ +/* */ +/* result gets the result of comparing abs(dfl) and abs(dfr) */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* returns result, which may be -1, 0, or 1 */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCompareTotalMag(decFloat *result, + const decFloat *dfl, const decFloat *dfr) { + decFloat a, b; // for copy if needed + // copy and redirect signed operand(s) + if (DFISSIGNED(dfl)) { + decFloatCopyAbs(&a, dfl); + dfl=&a; + } + if (DFISSIGNED(dfr)) { + decFloatCopyAbs(&b, dfr); + dfr=&b; + } + return decFloatCompareTotal(result, dfl, dfr); + } // decFloatCompareTotalMag + +/* ------------------------------------------------------------------ */ +/* decFloatCopy -- copy a decFloat as-is */ +/* */ +/* result gets the copy of dfl */ +/* dfl is the decFloat to copy */ +/* returns result */ +/* */ +/* This is a bitwise operation; no errors or exceptions are possible. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCopy(decFloat *result, const decFloat *dfl) { + if (dfl!=result) *result=*dfl; // copy needed + return result; + } // decFloatCopy + +/* ------------------------------------------------------------------ */ +/* decFloatCopyAbs -- copy a decFloat as-is and set sign bit to 0 */ +/* */ +/* result gets the copy of dfl with sign bit 0 */ +/* dfl is the decFloat to copy */ +/* returns result */ +/* */ +/* This is a bitwise operation; no errors or exceptions are possible. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCopyAbs(decFloat *result, const decFloat *dfl) { + if (dfl!=result) *result=*dfl; // copy needed + DFBYTE(result, 0)&=~0x80; // zero sign bit + return result; + } // decFloatCopyAbs + +/* ------------------------------------------------------------------ */ +/* decFloatCopyNegate -- copy a decFloat as-is with inverted sign bit */ +/* */ +/* result gets the copy of dfl with sign bit inverted */ +/* dfl is the decFloat to copy */ +/* returns result */ +/* */ +/* This is a bitwise operation; no errors or exceptions are possible. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCopyNegate(decFloat *result, const decFloat *dfl) { + if (dfl!=result) *result=*dfl; // copy needed + DFBYTE(result, 0)^=0x80; // invert sign bit + return result; + } // decFloatCopyNegate + +/* ------------------------------------------------------------------ */ +/* decFloatCopySign -- copy a decFloat with the sign of another */ +/* */ +/* result gets the result of copying dfl with the sign of dfr */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* returns result */ +/* */ +/* This is a bitwise operation; no errors or exceptions are possible. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatCopySign(decFloat *result, + const decFloat *dfl, const decFloat *dfr) { + uByte sign=(uByte)(DFBYTE(dfr, 0)&0x80); // save sign bit + if (dfl!=result) *result=*dfl; // copy needed + DFBYTE(result, 0)&=~0x80; // clear sign .. + DFBYTE(result, 0)=(uByte)(DFBYTE(result, 0)|sign); // .. and set saved + return result; + } // decFloatCopySign + +/* ------------------------------------------------------------------ */ +/* decFloatDigits -- return the number of digits in a decFloat */ +/* */ +/* df is the decFloat to investigate */ +/* returns the number of significant digits in the decFloat; a */ +/* zero coefficient returns 1 as does an infinity (a NaN returns */ +/* the number of digits in the payload) */ +/* ------------------------------------------------------------------ */ +// private macro to extract a declet according to provided formula +// (form), and if it is non-zero then return the calculated digits +// depending on the declet number (n), where n=0 for the most +// significant declet; uses uInt dpd for work +#define dpdlenchk(n, form) dpd=(form)&0x3ff; \ + if (dpd) return (DECPMAX-1-3*(n))-(3-DPD2BCD8[dpd*4+3]) +// next one is used when it is known that the declet must be +// non-zero, or is the final zero declet +#define dpdlendun(n, form) dpd=(form)&0x3ff; \ + if (dpd==0) return 1; \ + return (DECPMAX-1-3*(n))-(3-DPD2BCD8[dpd*4+3]) + +uInt decFloatDigits(const decFloat *df) { + uInt dpd; // work + uInt sourhi=DFWORD(df, 0); // top word from source decFloat + #if QUAD + uInt sourmh, sourml; + #endif + uInt sourlo; + + if (DFISINF(df)) return 1; + // A NaN effectively has an MSD of 0; otherwise if non-zero MSD + // then the coefficient is full-length + if (!DFISNAN(df) && DECCOMBMSD[sourhi>>26]) return DECPMAX; + + #if DOUBLE + if (sourhi&0x0003ffff) { // ends in first + dpdlenchk(0, sourhi>>8); + sourlo=DFWORD(df, 1); + dpdlendun(1, (sourhi<<2) | (sourlo>>30)); + } // [cannot drop through] + sourlo=DFWORD(df, 1); // sourhi not involved now + if (sourlo&0xfff00000) { // in one of first two + dpdlenchk(1, sourlo>>30); // very rare + dpdlendun(2, sourlo>>20); + } // [cannot drop through] + dpdlenchk(3, sourlo>>10); + dpdlendun(4, sourlo); + // [cannot drop through] + + #elif QUAD + if (sourhi&0x00003fff) { // ends in first + dpdlenchk(0, sourhi>>4); + sourmh=DFWORD(df, 1); + dpdlendun(1, ((sourhi)<<6) | (sourmh>>26)); + } // [cannot drop through] + sourmh=DFWORD(df, 1); + if (sourmh) { + dpdlenchk(1, sourmh>>26); + dpdlenchk(2, sourmh>>16); + dpdlenchk(3, sourmh>>6); + sourml=DFWORD(df, 2); + dpdlendun(4, ((sourmh)<<4) | (sourml>>28)); + } // [cannot drop through] + sourml=DFWORD(df, 2); + if (sourml) { + dpdlenchk(4, sourml>>28); + dpdlenchk(5, sourml>>18); + dpdlenchk(6, sourml>>8); + sourlo=DFWORD(df, 3); + dpdlendun(7, ((sourml)<<2) | (sourlo>>30)); + } // [cannot drop through] + sourlo=DFWORD(df, 3); + if (sourlo&0xfff00000) { // in one of first two + dpdlenchk(7, sourlo>>30); // very rare + dpdlendun(8, sourlo>>20); + } // [cannot drop through] + dpdlenchk(9, sourlo>>10); + dpdlendun(10, sourlo); + // [cannot drop through] + #endif + } // decFloatDigits + +/* ------------------------------------------------------------------ */ +/* decFloatDivide -- divide a decFloat by another */ +/* */ +/* result gets the result of dividing dfl by dfr: */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* ------------------------------------------------------------------ */ +// This is just a wrapper. +decFloat * decFloatDivide(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + return decDivide(result, dfl, dfr, set, DIVIDE); + } // decFloatDivide + +/* ------------------------------------------------------------------ */ +/* decFloatDivideInteger -- integer divide a decFloat by another */ +/* */ +/* result gets the result of dividing dfl by dfr: */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatDivideInteger(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + return decDivide(result, dfl, dfr, set, DIVIDEINT); + } // decFloatDivideInteger + +/* ------------------------------------------------------------------ */ +/* decFloatFMA -- multiply and add three decFloats, fused */ +/* */ +/* result gets the result of (dfl*dfr)+dff with a single rounding */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* dff is the final decFloat (fhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatFMA(decFloat *result, const decFloat *dfl, + const decFloat *dfr, const decFloat *dff, + decContext *set) { + + // The accumulator has the bytes needed for FiniteMultiply, plus + // one byte to the left in case of carry, plus DECPMAX+2 to the + // right for the final addition (up to full fhs + round & sticky) + #define FMALEN (ROUNDUP4(1+ (DECPMAX9*18+1) +DECPMAX+2)) + uByte acc[FMALEN]; // for multiplied coefficient in BCD + // .. and for final result + bcdnum mul; // for multiplication result + bcdnum fin; // for final operand, expanded + uByte coe[ROUNDUP4(DECPMAX)]; // dff coefficient in BCD + bcdnum *hi, *lo; // bcdnum with higher/lower exponent + uInt diffsign; // non-zero if signs differ + uInt hipad; // pad digit for hi if needed + Int padding; // excess exponent + uInt carry; // +1 for ten's complement and during add + uByte *ub, *uh, *ul; // work + uInt uiwork; // for macros + + // handle all the special values [any special operand leads to a + // special result] + if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr) || DFISSPECIAL(dff)) { + decFloat proxy; // multiplication result proxy + // NaNs are handled as usual, giving priority to sNaNs + if (DFISSNAN(dfl) || DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set); + if (DFISSNAN(dff)) return decNaNs(result, dff, NULL, set); + if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + if (DFISNAN(dff)) return decNaNs(result, dff, NULL, set); + // One or more of the three is infinite + // infinity times zero is bad + decFloatZero(&proxy); + if (DFISINF(dfl)) { + if (DFISZERO(dfr)) return decInvalid(result, set); + decInfinity(&proxy, &proxy); + } + else if (DFISINF(dfr)) { + if (DFISZERO(dfl)) return decInvalid(result, set); + decInfinity(&proxy, &proxy); + } + // compute sign of multiplication and place in proxy + DFWORD(&proxy, 0)|=(DFWORD(dfl, 0)^DFWORD(dfr, 0))&DECFLOAT_Sign; + if (!DFISINF(dff)) return decFloatCopy(result, &proxy); + // dff is Infinite + if (!DFISINF(&proxy)) return decInfinity(result, dff); + // both sides of addition are infinite; different sign is bad + if ((DFWORD(dff, 0)&DECFLOAT_Sign)!=(DFWORD(&proxy, 0)&DECFLOAT_Sign)) + return decInvalid(result, set); + return decFloatCopy(result, &proxy); + } + + /* Here when all operands are finite */ + + // First multiply dfl*dfr + decFiniteMultiply(&mul, acc+1, dfl, dfr); + // The multiply is complete, exact and unbounded, and described in + // mul with the coefficient held in acc[1...] + + // now add in dff; the algorithm is essentially the same as + // decFloatAdd, but the code is different because the code there + // is highly optimized for adding two numbers of the same size + fin.exponent=GETEXPUN(dff); // get dff exponent and sign + fin.sign=DFWORD(dff, 0)&DECFLOAT_Sign; + diffsign=mul.sign^fin.sign; // note if signs differ + fin.msd=coe; + fin.lsd=coe+DECPMAX-1; + GETCOEFF(dff, coe); // extract the coefficient + + // now set hi and lo so that hi points to whichever of mul and fin + // has the higher exponent and lo points to the other [don't care, + // if the same]. One coefficient will be in acc, the other in coe. + if (mul.exponent>=fin.exponent) { + hi=&mul; + lo=&fin; + } + else { + hi=&fin; + lo=&mul; + } + + // remove leading zeros on both operands; this will save time later + // and make testing for zero trivial (tests are safe because acc + // and coe are rounded up to uInts) + for (; UBTOUI(hi->msd)==0 && hi->msd+3lsd;) hi->msd+=4; + for (; *hi->msd==0 && hi->msdlsd;) hi->msd++; + for (; UBTOUI(lo->msd)==0 && lo->msd+3lsd;) lo->msd+=4; + for (; *lo->msd==0 && lo->msdlsd;) lo->msd++; + + // if hi is zero then result will be lo (which has the smaller + // exponent), which also may need to be tested for zero for the + // weird IEEE 754 sign rules + if (*hi->msd==0) { // hi is zero + // "When the sum of two operands with opposite signs is + // exactly zero, the sign of that sum shall be '+' in all + // rounding modes except round toward -Infinity, in which + // mode that sign shall be '-'." + if (diffsign) { + if (*lo->msd==0) { // lo is zero + lo->sign=0; + if (set->round==DEC_ROUND_FLOOR) lo->sign=DECFLOAT_Sign; + } // diffsign && lo=0 + } // diffsign + return decFinalize(result, lo, set); // may need clamping + } // numfl is zero + // [here, both are minimal length and hi is non-zero] + // (if lo is zero then padding with zeros may be needed, below) + + // if signs differ, take the ten's complement of hi (zeros to the + // right do not matter because the complement of zero is zero); the + // +1 is done later, as part of the addition, inserted at the + // correct digit + hipad=0; + carry=0; + if (diffsign) { + hipad=9; + carry=1; + // exactly the correct number of digits must be inverted + for (uh=hi->msd; uhlsd-3; uh+=4) UBFROMUI(uh, 0x09090909-UBTOUI(uh)); + for (; uh<=hi->lsd; uh++) *uh=(uByte)(0x09-*uh); + } + + // ready to add; note that hi has no leading zeros so gap + // calculation does not have to be as pessimistic as in decFloatAdd + // (this is much more like the arbitrary-precision algorithm in + // Rexx and decNumber) + + // padding is the number of zeros that would need to be added to hi + // for its lsd to be aligned with the lsd of lo + padding=hi->exponent-lo->exponent; + // printf("FMA pad %ld\n", (LI)padding); + + // the result of the addition will be built into the accumulator, + // starting from the far right; this could be either hi or lo, and + // will be aligned + ub=acc+FMALEN-1; // where lsd of result will go + ul=lo->lsd; // lsd of rhs + + if (padding!=0) { // unaligned + // if the msd of lo is more than DECPMAX+2 digits to the right of + // the original msd of hi then it can be reduced to a single + // digit at the right place, as it stays clear of hi digits + // [it must be DECPMAX+2 because during a subtraction the msd + // could become 0 after a borrow from 1.000 to 0.9999...] + + Int hilen=(Int)(hi->lsd-hi->msd+1); // length of hi + Int lolen=(Int)(lo->lsd-lo->msd+1); // and of lo + + if (hilen+padding-lolen > DECPMAX+2) { // can reduce lo to single + // make sure it is virtually at least DECPMAX from hi->msd, at + // least to right of hi->lsd (in case of destructive subtract), + // and separated by at least two digits from either of those + // (the tricky DOUBLE case is when hi is a 1 that will become a + // 0.9999... by subtraction: + // hi: 1 E+16 + // lo: .................1000000000000000 E-16 + // which for the addition pads to: + // hi: 1000000000000000000 E-16 + // lo: .................1000000000000000 E-16 + Int newexp=MINI(hi->exponent, hi->exponent+hilen-DECPMAX)-3; + + // printf("FMA reduce: %ld\n", (LI)reduce); + lo->lsd=lo->msd; // to single digit [maybe 0] + lo->exponent=newexp; // new lowest exponent + padding=hi->exponent-lo->exponent; // recalculate + ul=lo->lsd; // .. and repoint + } + + // padding is still > 0, but will fit in acc (less leading carry slot) + #if DECCHECK + if (padding<=0) printf("FMA low padding: %ld\n", (LI)padding); + if (hilen+padding+1>FMALEN) + printf("FMA excess hilen+padding: %ld+%ld \n", (LI)hilen, (LI)padding); + // printf("FMA padding: %ld\n", (LI)padding); + #endif + + // padding digits can now be set in the result; one or more of + // these will come from lo; others will be zeros in the gap + for (; ul-3>=lo->msd && padding>3; padding-=4, ul-=4, ub-=4) { + UBFROMUI(ub-3, UBTOUI(ul-3)); // [cannot overlap] + } + for (; ul>=lo->msd && padding>0; padding--, ul--, ub--) *ub=*ul; + for (;padding>0; padding--, ub--) *ub=0; // mind the gap + } + + // addition now complete to the right of the rightmost digit of hi + uh=hi->lsd; + + // dow do the add from hi->lsd to the left + // [bytewise, because either operand can run out at any time] + // carry was set up depending on ten's complement above + // first assume both operands have some digits + for (;; ub--) { + if (uhmsd || ulmsd) break; + *ub=(uByte)(carry+(*uh--)+(*ul--)); + carry=0; + if (*ub<10) continue; + *ub-=10; + carry=1; + } // both loop + + if (ulmsd) { // to left of lo + for (;; ub--) { + if (uhmsd) break; + *ub=(uByte)(carry+(*uh--)); // [+0] + carry=0; + if (*ub<10) continue; + *ub-=10; + carry=1; + } // hi loop + } + else { // to left of hi + for (;; ub--) { + if (ulmsd) break; + *ub=(uByte)(carry+hipad+(*ul--)); + carry=0; + if (*ub<10) continue; + *ub-=10; + carry=1; + } // lo loop + } + + // addition complete -- now handle carry, borrow, etc. + // use lo to set up the num (its exponent is already correct, and + // sign usually is) + lo->msd=ub+1; + lo->lsd=acc+FMALEN-1; + // decShowNum(lo, "lo"); + if (!diffsign) { // same-sign addition + if (carry) { // carry out + *ub=1; // place the 1 .. + lo->msd--; // .. and update + } + } // same sign + else { // signs differed (subtraction) + if (!carry) { // no carry out means hisign=hi->sign; // sign is lhs sign + for (ul=lo->msd; ullsd-3; ul+=4) UBFROMUI(ul, 0x09090909-UBTOUI(ul)); + for (; ul<=lo->lsd; ul++) *ul=(uByte)(0x09-*ul); // [leaves ul at lsd+1] + // complete the ten's complement by adding 1 [cannot overrun] + for (ul--; *ul==9; ul--) *ul=0; + *ul+=1; + } // borrowed + else { // carry out means hi>=lo + // sign to use is lo->sign + // all done except for the special IEEE 754 exact-zero-result + // rule (see above); while testing for zero, strip leading + // zeros (which will save decFinalize doing it) + for (; UBTOUI(lo->msd)==0 && lo->msd+3lsd;) lo->msd+=4; + for (; *lo->msd==0 && lo->msdlsd;) lo->msd++; + if (*lo->msd==0) { // must be true zero (and diffsign) + lo->sign=0; // assume + + if (set->round==DEC_ROUND_FLOOR) lo->sign=DECFLOAT_Sign; + } + // [else was not zero, might still have leading zeros] + } // subtraction gave positive result + } // diffsign + + #if DECCHECK + // assert no left underrun + if (lo->msdmsd)); + } + #endif + + return decFinalize(result, lo, set); // round, check, and lay out + } // decFloatFMA + +/* ------------------------------------------------------------------ */ +/* decFloatFromInt -- initialise a decFloat from an Int */ +/* */ +/* result gets the converted Int */ +/* n is the Int to convert */ +/* returns result */ +/* */ +/* The result is Exact; no errors or exceptions are possible. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatFromInt32(decFloat *result, Int n) { + uInt u=(uInt)n; // copy as bits + uInt encode; // work + DFWORD(result, 0)=ZEROWORD; // always + #if QUAD + DFWORD(result, 1)=0; + DFWORD(result, 2)=0; + #endif + if (n<0) { // handle -n with care + // [This can be done without the test, but is then slightly slower] + u=(~u)+1; + DFWORD(result, 0)|=DECFLOAT_Sign; + } + // Since the maximum value of u now is 2**31, only the low word of + // result is affected + encode=BIN2DPD[u%1000]; + u/=1000; + encode|=BIN2DPD[u%1000]<<10; + u/=1000; + encode|=BIN2DPD[u%1000]<<20; + u/=1000; // now 0, 1, or 2 + encode|=u<<30; + DFWORD(result, DECWORDS-1)=encode; + return result; + } // decFloatFromInt32 + +/* ------------------------------------------------------------------ */ +/* decFloatFromUInt -- initialise a decFloat from a uInt */ +/* */ +/* result gets the converted uInt */ +/* n is the uInt to convert */ +/* returns result */ +/* */ +/* The result is Exact; no errors or exceptions are possible. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatFromUInt32(decFloat *result, uInt u) { + uInt encode; // work + DFWORD(result, 0)=ZEROWORD; // always + #if QUAD + DFWORD(result, 1)=0; + DFWORD(result, 2)=0; + #endif + encode=BIN2DPD[u%1000]; + u/=1000; + encode|=BIN2DPD[u%1000]<<10; + u/=1000; + encode|=BIN2DPD[u%1000]<<20; + u/=1000; // now 0 -> 4 + encode|=u<<30; + DFWORD(result, DECWORDS-1)=encode; + DFWORD(result, DECWORDS-2)|=u>>2; // rarely non-zero + return result; + } // decFloatFromUInt32 + +/* ------------------------------------------------------------------ */ +/* decFloatInvert -- logical digitwise INVERT of a decFloat */ +/* */ +/* result gets the result of INVERTing df */ +/* df is the decFloat to invert */ +/* set is the context */ +/* returns result, which will be canonical with sign=0 */ +/* */ +/* The operand must be positive, finite with exponent q=0, and */ +/* comprise just zeros and ones; if not, Invalid operation results. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatInvert(decFloat *result, const decFloat *df, + decContext *set) { + uInt sourhi=DFWORD(df, 0); // top word of dfs + + if (!DFISUINT01(df) || !DFISCC01(df)) return decInvalid(result, set); + // the operand is a finite integer (q=0) + #if DOUBLE + DFWORD(result, 0)=ZEROWORD|((~sourhi)&0x04009124); + DFWORD(result, 1)=(~DFWORD(df, 1)) &0x49124491; + #elif QUAD + DFWORD(result, 0)=ZEROWORD|((~sourhi)&0x04000912); + DFWORD(result, 1)=(~DFWORD(df, 1)) &0x44912449; + DFWORD(result, 2)=(~DFWORD(df, 2)) &0x12449124; + DFWORD(result, 3)=(~DFWORD(df, 3)) &0x49124491; + #endif + return result; + } // decFloatInvert + +/* ------------------------------------------------------------------ */ +/* decFloatIs -- decFloat tests (IsSigned, etc.) */ +/* */ +/* df is the decFloat to test */ +/* returns 0 or 1 in a uInt */ +/* */ +/* Many of these could be macros, but having them as real functions */ +/* is a little cleaner (and they can be referred to here by the */ +/* generic names) */ +/* ------------------------------------------------------------------ */ +uInt decFloatIsCanonical(const decFloat *df) { + if (DFISSPECIAL(df)) { + if (DFISINF(df)) { + if (DFWORD(df, 0)&ECONMASK) return 0; // exponent continuation + if (!DFISCCZERO(df)) return 0; // coefficient continuation + return 1; + } + // is a NaN + if (DFWORD(df, 0)&ECONNANMASK) return 0; // exponent continuation + if (DFISCCZERO(df)) return 1; // coefficient continuation + // drop through to check payload + } + { // declare block + #if DOUBLE + uInt sourhi=DFWORD(df, 0); + uInt sourlo=DFWORD(df, 1); + if (CANONDPDOFF(sourhi, 8) + && CANONDPDTWO(sourhi, sourlo, 30) + && CANONDPDOFF(sourlo, 20) + && CANONDPDOFF(sourlo, 10) + && CANONDPDOFF(sourlo, 0)) return 1; + #elif QUAD + uInt sourhi=DFWORD(df, 0); + uInt sourmh=DFWORD(df, 1); + uInt sourml=DFWORD(df, 2); + uInt sourlo=DFWORD(df, 3); + if (CANONDPDOFF(sourhi, 4) + && CANONDPDTWO(sourhi, sourmh, 26) + && CANONDPDOFF(sourmh, 16) + && CANONDPDOFF(sourmh, 6) + && CANONDPDTWO(sourmh, sourml, 28) + && CANONDPDOFF(sourml, 18) + && CANONDPDOFF(sourml, 8) + && CANONDPDTWO(sourml, sourlo, 30) + && CANONDPDOFF(sourlo, 20) + && CANONDPDOFF(sourlo, 10) + && CANONDPDOFF(sourlo, 0)) return 1; + #endif + } // block + return 0; // a declet is non-canonical + } + +uInt decFloatIsFinite(const decFloat *df) { + return !DFISSPECIAL(df); + } +uInt decFloatIsInfinite(const decFloat *df) { + return DFISINF(df); + } +uInt decFloatIsInteger(const decFloat *df) { + return DFISINT(df); + } +uInt decFloatIsLogical(const decFloat *df) { + return DFISUINT01(df) & DFISCC01(df); + } +uInt decFloatIsNaN(const decFloat *df) { + return DFISNAN(df); + } +uInt decFloatIsNegative(const decFloat *df) { + return DFISSIGNED(df) && !DFISZERO(df) && !DFISNAN(df); + } +uInt decFloatIsNormal(const decFloat *df) { + Int exp; // exponent + if (DFISSPECIAL(df)) return 0; + if (DFISZERO(df)) return 0; + // is finite and non-zero + exp=GETEXPUN(df) // get unbiased exponent .. + +decFloatDigits(df)-1; // .. and make adjusted exponent + return (exp>=DECEMIN); // < DECEMIN is subnormal + } +uInt decFloatIsPositive(const decFloat *df) { + return !DFISSIGNED(df) && !DFISZERO(df) && !DFISNAN(df); + } +uInt decFloatIsSignaling(const decFloat *df) { + return DFISSNAN(df); + } +uInt decFloatIsSignalling(const decFloat *df) { + return DFISSNAN(df); + } +uInt decFloatIsSigned(const decFloat *df) { + return DFISSIGNED(df); + } +uInt decFloatIsSubnormal(const decFloat *df) { + if (DFISSPECIAL(df)) return 0; + // is finite + if (decFloatIsNormal(df)) return 0; + // it is Use |A| */ +/* A=0 -> -Infinity (Division by zero) */ +/* A=Infinite -> +Infinity (Exact) */ +/* A=1 exactly -> 0 (Exact) */ +/* NaNs are propagated as usual */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatLogB(decFloat *result, const decFloat *df, + decContext *set) { + Int ae; // adjusted exponent + if (DFISNAN(df)) return decNaNs(result, df, NULL, set); + if (DFISINF(df)) { + DFWORD(result, 0)=0; // need +ve + return decInfinity(result, result); // canonical +Infinity + } + if (DFISZERO(df)) { + set->status|=DEC_Division_by_zero; // as per 754 + DFWORD(result, 0)=DECFLOAT_Sign; // make negative + return decInfinity(result, result); // canonical -Infinity + } + ae=GETEXPUN(df) // get unbiased exponent .. + +decFloatDigits(df)-1; // .. and make adjusted exponent + // ae has limited range (3 digits for DOUBLE and 4 for QUAD), so + // it is worth using a special case of decFloatFromInt32 + DFWORD(result, 0)=ZEROWORD; // always + if (ae<0) { + DFWORD(result, 0)|=DECFLOAT_Sign; // -0 so far + ae=-ae; + } + #if DOUBLE + DFWORD(result, 1)=BIN2DPD[ae]; // a single declet + #elif QUAD + DFWORD(result, 1)=0; + DFWORD(result, 2)=0; + DFWORD(result, 3)=(ae/1000)<<10; // is <10, so need no DPD encode + DFWORD(result, 3)|=BIN2DPD[ae%1000]; + #endif + return result; + } // decFloatLogB + +/* ------------------------------------------------------------------ */ +/* decFloatMax -- return maxnum of two operands */ +/* */ +/* result gets the chosen decFloat */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* If just one operand is a quiet NaN it is ignored. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatMax(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int comp; + if (DFISNAN(dfl)) { + // sNaN or both NaNs leads to normal NaN processing + if (DFISNAN(dfr) || DFISSNAN(dfl)) return decNaNs(result, dfl, dfr, set); + return decCanonical(result, dfr); // RHS is numeric + } + if (DFISNAN(dfr)) { + // sNaN leads to normal NaN processing (both NaN handled above) + if (DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set); + return decCanonical(result, dfl); // LHS is numeric + } + // Both operands are numeric; numeric comparison needed -- use + // total order for a well-defined choice (and +0 > -0) + comp=decNumCompare(dfl, dfr, 1); + if (comp>=0) return decCanonical(result, dfl); + return decCanonical(result, dfr); + } // decFloatMax + +/* ------------------------------------------------------------------ */ +/* decFloatMaxMag -- return maxnummag of two operands */ +/* */ +/* result gets the chosen decFloat */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* Returns according to the magnitude comparisons if both numeric and */ +/* unequal, otherwise returns maxnum */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatMaxMag(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int comp; + decFloat absl, absr; + if (DFISNAN(dfl) || DFISNAN(dfr)) return decFloatMax(result, dfl, dfr, set); + + decFloatCopyAbs(&absl, dfl); + decFloatCopyAbs(&absr, dfr); + comp=decNumCompare(&absl, &absr, 0); + if (comp>0) return decCanonical(result, dfl); + if (comp<0) return decCanonical(result, dfr); + return decFloatMax(result, dfl, dfr, set); + } // decFloatMaxMag + +/* ------------------------------------------------------------------ */ +/* decFloatMin -- return minnum of two operands */ +/* */ +/* result gets the chosen decFloat */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* If just one operand is a quiet NaN it is ignored. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatMin(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int comp; + if (DFISNAN(dfl)) { + // sNaN or both NaNs leads to normal NaN processing + if (DFISNAN(dfr) || DFISSNAN(dfl)) return decNaNs(result, dfl, dfr, set); + return decCanonical(result, dfr); // RHS is numeric + } + if (DFISNAN(dfr)) { + // sNaN leads to normal NaN processing (both NaN handled above) + if (DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set); + return decCanonical(result, dfl); // LHS is numeric + } + // Both operands are numeric; numeric comparison needed -- use + // total order for a well-defined choice (and +0 > -0) + comp=decNumCompare(dfl, dfr, 1); + if (comp<=0) return decCanonical(result, dfl); + return decCanonical(result, dfr); + } // decFloatMin + +/* ------------------------------------------------------------------ */ +/* decFloatMinMag -- return minnummag of two operands */ +/* */ +/* result gets the chosen decFloat */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* Returns according to the magnitude comparisons if both numeric and */ +/* unequal, otherwise returns minnum */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatMinMag(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int comp; + decFloat absl, absr; + if (DFISNAN(dfl) || DFISNAN(dfr)) return decFloatMin(result, dfl, dfr, set); + + decFloatCopyAbs(&absl, dfl); + decFloatCopyAbs(&absr, dfr); + comp=decNumCompare(&absl, &absr, 0); + if (comp<0) return decCanonical(result, dfl); + if (comp>0) return decCanonical(result, dfr); + return decFloatMin(result, dfl, dfr, set); + } // decFloatMinMag + +/* ------------------------------------------------------------------ */ +/* decFloatMinus -- negate value, heeding NaNs, etc. */ +/* */ +/* result gets the canonicalized 0-df */ +/* df is the decFloat to minus */ +/* set is the context */ +/* returns result */ +/* */ +/* This has the same effect as 0-df where the exponent of the zero is */ +/* the same as that of df (if df is finite). */ +/* The effect is also the same as decFloatCopyNegate except that NaNs */ +/* are handled normally (the sign of a NaN is not affected, and an */ +/* sNaN will signal), the result is canonical, and zero gets sign 0. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatMinus(decFloat *result, const decFloat *df, + decContext *set) { + if (DFISNAN(df)) return decNaNs(result, df, NULL, set); + decCanonical(result, df); // copy and check + if (DFISZERO(df)) DFBYTE(result, 0)&=~0x80; // turn off sign bit + else DFBYTE(result, 0)^=0x80; // flip sign bit + return result; + } // decFloatMinus + +/* ------------------------------------------------------------------ */ +/* decFloatMultiply -- multiply two decFloats */ +/* */ +/* result gets the result of multiplying dfl and dfr: */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatMultiply(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + bcdnum num; // for final conversion + uByte bcdacc[DECPMAX9*18+1]; // for coefficent in BCD + + if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) { // either is special? + // NaNs are handled as usual + if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + // infinity times zero is bad + if (DFISINF(dfl) && DFISZERO(dfr)) return decInvalid(result, set); + if (DFISINF(dfr) && DFISZERO(dfl)) return decInvalid(result, set); + // both infinite; return canonical infinity with computed sign + DFWORD(result, 0)=DFWORD(dfl, 0)^DFWORD(dfr, 0); // compute sign + return decInfinity(result, result); + } + + /* Here when both operands are finite */ + decFiniteMultiply(&num, bcdacc, dfl, dfr); + return decFinalize(result, &num, set); // round, check, and lay out + } // decFloatMultiply + +/* ------------------------------------------------------------------ */ +/* decFloatNextMinus -- next towards -Infinity */ +/* */ +/* result gets the next lesser decFloat */ +/* dfl is the decFloat to start with */ +/* set is the context */ +/* returns result */ +/* */ +/* This is 754 nextdown; Invalid is the only status possible (from */ +/* an sNaN). */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatNextMinus(decFloat *result, const decFloat *dfl, + decContext *set) { + decFloat delta; // tiny increment + uInt savestat; // saves status + enum rounding saveround; // .. and mode + + // +Infinity is the special case + if (DFISINF(dfl) && !DFISSIGNED(dfl)) { + DFSETNMAX(result); + return result; // [no status to set] + } + // other cases are effected by sutracting a tiny delta -- this + // should be done in a wider format as the delta is unrepresentable + // here (but can be done with normal add if the sign of zero is + // treated carefully, because no Inexactitude is interesting); + // rounding to -Infinity then pushes the result to next below + decFloatZero(&delta); // set up tiny delta + DFWORD(&delta, DECWORDS-1)=1; // coefficient=1 + DFWORD(&delta, 0)=DECFLOAT_Sign; // Sign=1 + biased exponent=0 + // set up for the directional round + saveround=set->round; // save mode + set->round=DEC_ROUND_FLOOR; // .. round towards -Infinity + savestat=set->status; // save status + decFloatAdd(result, dfl, &delta, set); + // Add rules mess up the sign when going from +Ntiny to 0 + if (DFISZERO(result)) DFWORD(result, 0)^=DECFLOAT_Sign; // correct + set->status&=DEC_Invalid_operation; // preserve only sNaN status + set->status|=savestat; // restore pending flags + set->round=saveround; // .. and mode + return result; + } // decFloatNextMinus + +/* ------------------------------------------------------------------ */ +/* decFloatNextPlus -- next towards +Infinity */ +/* */ +/* result gets the next larger decFloat */ +/* dfl is the decFloat to start with */ +/* set is the context */ +/* returns result */ +/* */ +/* This is 754 nextup; Invalid is the only status possible (from */ +/* an sNaN). */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatNextPlus(decFloat *result, const decFloat *dfl, + decContext *set) { + uInt savestat; // saves status + enum rounding saveround; // .. and mode + decFloat delta; // tiny increment + + // -Infinity is the special case + if (DFISINF(dfl) && DFISSIGNED(dfl)) { + DFSETNMAX(result); + DFWORD(result, 0)|=DECFLOAT_Sign; // make negative + return result; // [no status to set] + } + // other cases are effected by sutracting a tiny delta -- this + // should be done in a wider format as the delta is unrepresentable + // here (but can be done with normal add if the sign of zero is + // treated carefully, because no Inexactitude is interesting); + // rounding to +Infinity then pushes the result to next above + decFloatZero(&delta); // set up tiny delta + DFWORD(&delta, DECWORDS-1)=1; // coefficient=1 + DFWORD(&delta, 0)=0; // Sign=0 + biased exponent=0 + // set up for the directional round + saveround=set->round; // save mode + set->round=DEC_ROUND_CEILING; // .. round towards +Infinity + savestat=set->status; // save status + decFloatAdd(result, dfl, &delta, set); + // Add rules mess up the sign when going from -Ntiny to -0 + if (DFISZERO(result)) DFWORD(result, 0)^=DECFLOAT_Sign; // correct + set->status&=DEC_Invalid_operation; // preserve only sNaN status + set->status|=savestat; // restore pending flags + set->round=saveround; // .. and mode + return result; + } // decFloatNextPlus + +/* ------------------------------------------------------------------ */ +/* decFloatNextToward -- next towards a decFloat */ +/* */ +/* result gets the next decFloat */ +/* dfl is the decFloat to start with */ +/* dfr is the decFloat to move toward */ +/* set is the context */ +/* returns result */ +/* */ +/* This is 754-1985 nextafter, as modified during revision (dropped */ +/* from 754-2008); status may be set unless the result is a normal */ +/* number. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatNextToward(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + decFloat delta; // tiny increment or decrement + decFloat pointone; // 1e-1 + uInt savestat; // saves status + enum rounding saveround; // .. and mode + uInt deltatop; // top word for delta + Int comp; // work + + if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + // Both are numeric, so Invalid no longer a possibility + comp=decNumCompare(dfl, dfr, 0); + if (comp==0) return decFloatCopySign(result, dfl, dfr); // equal + // unequal; do NextPlus or NextMinus but with different status rules + + if (comp<0) { // lhsround; // save mode + set->round=DEC_ROUND_CEILING; // .. round towards +Infinity + deltatop=0; // positive delta + } + else { // lhs>rhs, do NextMinus, see above for commentary + if (DFISINF(dfl) && !DFISSIGNED(dfl)) { // +Infinity special case + DFSETNMAX(result); + return result; + } + saveround=set->round; // save mode + set->round=DEC_ROUND_FLOOR; // .. round towards -Infinity + deltatop=DECFLOAT_Sign; // negative delta + } + savestat=set->status; // save status + // Here, Inexact is needed where appropriate (and hence Underflow, + // etc.). Therefore the tiny delta which is otherwise + // unrepresentable (see NextPlus and NextMinus) is constructed + // using the multiplication of FMA. + decFloatZero(&delta); // set up tiny delta + DFWORD(&delta, DECWORDS-1)=1; // coefficient=1 + DFWORD(&delta, 0)=deltatop; // Sign + biased exponent=0 + decFloatFromString(&pointone, "1E-1", set); // set up multiplier + decFloatFMA(result, &delta, &pointone, dfl, set); + // [Delta is truly tiny, so no need to correct sign of zero] + // use new status unless the result is normal + if (decFloatIsNormal(result)) set->status=savestat; // else goes forward + set->round=saveround; // restore mode + return result; + } // decFloatNextToward + +/* ------------------------------------------------------------------ */ +/* decFloatOr -- logical digitwise OR of two decFloats */ +/* */ +/* result gets the result of ORing dfl and dfr */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result, which will be canonical with sign=0 */ +/* */ +/* The operands must be positive, finite with exponent q=0, and */ +/* comprise just zeros and ones; if not, Invalid operation results. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatOr(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + if (!DFISUINT01(dfl) || !DFISUINT01(dfr) + || !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set); + // the operands are positive finite integers (q=0) with just 0s and 1s + #if DOUBLE + DFWORD(result, 0)=ZEROWORD + |((DFWORD(dfl, 0) | DFWORD(dfr, 0))&0x04009124); + DFWORD(result, 1)=(DFWORD(dfl, 1) | DFWORD(dfr, 1))&0x49124491; + #elif QUAD + DFWORD(result, 0)=ZEROWORD + |((DFWORD(dfl, 0) | DFWORD(dfr, 0))&0x04000912); + DFWORD(result, 1)=(DFWORD(dfl, 1) | DFWORD(dfr, 1))&0x44912449; + DFWORD(result, 2)=(DFWORD(dfl, 2) | DFWORD(dfr, 2))&0x12449124; + DFWORD(result, 3)=(DFWORD(dfl, 3) | DFWORD(dfr, 3))&0x49124491; + #endif + return result; + } // decFloatOr + +/* ------------------------------------------------------------------ */ +/* decFloatPlus -- add value to 0, heeding NaNs, etc. */ +/* */ +/* result gets the canonicalized 0+df */ +/* df is the decFloat to plus */ +/* set is the context */ +/* returns result */ +/* */ +/* This has the same effect as 0+df where the exponent of the zero is */ +/* the same as that of df (if df is finite). */ +/* The effect is also the same as decFloatCopy except that NaNs */ +/* are handled normally (the sign of a NaN is not affected, and an */ +/* sNaN will signal), the result is canonical, and zero gets sign 0. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatPlus(decFloat *result, const decFloat *df, + decContext *set) { + if (DFISNAN(df)) return decNaNs(result, df, NULL, set); + decCanonical(result, df); // copy and check + if (DFISZERO(df)) DFBYTE(result, 0)&=~0x80; // turn off sign bit + return result; + } // decFloatPlus + +/* ------------------------------------------------------------------ */ +/* decFloatQuantize -- quantize a decFloat */ +/* */ +/* result gets the result of quantizing dfl to match dfr */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs), which sets the exponent */ +/* set is the context */ +/* returns result */ +/* */ +/* Unless there is an error or the result is infinite, the exponent */ +/* of result is guaranteed to be the same as that of dfr. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatQuantize(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int explb, exprb; // left and right biased exponents + uByte *ulsd; // local LSD pointer + uByte *ub, *uc; // work + Int drop; // .. + uInt dpd; // .. + uInt encode; // encoding accumulator + uInt sourhil, sourhir; // top words from source decFloats + uInt uiwork; // for macros + #if QUAD + uShort uswork; // .. + #endif + // the following buffer holds the coefficient for manipulation + uByte buf[4+DECPMAX*3+2*QUAD]; // + space for zeros to left or right + #if DECTRACE + bcdnum num; // for trace displays + #endif + + /* Start decoding the arguments */ + sourhil=DFWORD(dfl, 0); // LHS top word + explb=DECCOMBEXP[sourhil>>26]; // get exponent high bits (in place) + sourhir=DFWORD(dfr, 0); // RHS top word + exprb=DECCOMBEXP[sourhir>>26]; + + if (EXPISSPECIAL(explb | exprb)) { // either is special? + // NaNs are handled as usual + if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + // one infinity but not both is bad + if (DFISINF(dfl)!=DFISINF(dfr)) return decInvalid(result, set); + // both infinite; return canonical infinity with sign of LHS + return decInfinity(result, dfl); + } + + /* Here when both arguments are finite */ + // complete extraction of the exponents [no need to unbias] + explb+=GETECON(dfl); // + continuation + exprb+=GETECON(dfr); // .. + + // calculate the number of digits to drop from the coefficient + drop=exprb-explb; // 0 if nothing to do + if (drop==0) return decCanonical(result, dfl); // return canonical + + // the coefficient is needed; lay it out into buf, offset so zeros + // can be added before or after as needed -- an extra heading is + // added so can safely pad Quad DECPMAX-1 zeros to the left by + // fours + #define BUFOFF (buf+4+DECPMAX) + GETCOEFF(dfl, BUFOFF); // decode from decFloat + // [now the msd is at BUFOFF and the lsd is at BUFOFF+DECPMAX-1] + + #if DECTRACE + num.msd=BUFOFF; + num.lsd=BUFOFF+DECPMAX-1; + num.exponent=explb-DECBIAS; + num.sign=sourhil & DECFLOAT_Sign; + decShowNum(&num, "dfl"); + #endif + + if (drop>0) { // [most common case] + // (this code is very similar to that in decFloatFinalize, but + // has many differences so is duplicated here -- so any changes + // may need to be made there, too) + uByte *roundat; // -> re-round digit + uByte reround; // reround value + // printf("Rounding; drop=%ld\n", (LI)drop); + + // there is at least one zero needed to the left, in all but one + // exceptional (all-nines) case, so place four zeros now; this is + // needed almost always and makes rounding all-nines by fours safe + UBFROMUI(BUFOFF-4, 0); + + // Three cases here: + // 1. new LSD is in coefficient (almost always) + // 2. new LSD is digit to left of coefficient (so MSD is + // round-for-reround digit) + // 3. new LSD is to left of case 2 (whole coefficient is sticky) + // Note that leading zeros can safely be treated as useful digits + + // [duplicate check-stickies code to save a test] + // [by-digit check for stickies as runs of zeros are rare] + if (dropstatus|=DEC_Inexact; + + // next decide whether to increment the coefficient + if (set->round==DEC_ROUND_HALF_EVEN) { // fastpath slowest case + if (reround>5) bump=1; // >0.5 goes up + else if (reround==5) // exactly 0.5000 .. + bump=*ulsd & 0x01; // .. up iff [new] lsd is odd + } // r-h-e + else switch (set->round) { + case DEC_ROUND_DOWN: { + // no change + break;} // r-d + case DEC_ROUND_HALF_DOWN: { + if (reround>5) bump=1; + break;} // r-h-d + case DEC_ROUND_HALF_UP: { + if (reround>=5) bump=1; + break;} // r-h-u + case DEC_ROUND_UP: { + if (reround>0) bump=1; + break;} // r-u + case DEC_ROUND_CEILING: { + // same as _UP for positive numbers, and as _DOWN for negatives + if (!(sourhil&DECFLOAT_Sign) && reround>0) bump=1; + break;} // r-c + case DEC_ROUND_FLOOR: { + // same as _UP for negative numbers, and as _DOWN for positive + // [negative reround cannot occur on 0] + if (sourhil&DECFLOAT_Sign && reround>0) bump=1; + break;} // r-f + case DEC_ROUND_05UP: { + if (reround>0) { // anything out there is 'sticky' + // bump iff lsd=0 or 5; this cannot carry so it could be + // effected immediately with no bump -- but the code + // is clearer if this is done the same way as the others + if (*ulsd==0 || *ulsd==5) bump=1; + } + break;} // r-r + default: { // e.g., DEC_ROUND_MAX + set->status|=DEC_Invalid_context; + #if DECCHECK + printf("Unknown rounding mode: %ld\n", (LI)set->round); + #endif + break;} + } // switch (not r-h-e) + // printf("ReRound: %ld bump: %ld\n", (LI)reround, (LI)bump); + + if (bump!=0) { // need increment + // increment the coefficient; this could give 1000... (after + // the all nines case) + ub=ulsd; + for (; UBTOUI(ub-3)==0x09090909; ub-=4) UBFROMUI(ub-3, 0); + // now at most 3 digits left to non-9 (usually just the one) + for (; *ub==9; ub--) *ub=0; + *ub+=1; + // [the all-nines case will have carried one digit to the + // left of the original MSD -- just where it is needed] + } // bump needed + } // inexact rounding + + // now clear zeros to the left so exactly DECPMAX digits will be + // available in the coefficent -- the first word to the left was + // cleared earlier for safe carry; now add any more needed + if (drop>4) { + UBFROMUI(BUFOFF-8, 0); // must be at least 5 + for (uc=BUFOFF-12; uc>ulsd-DECPMAX-3; uc-=4) UBFROMUI(uc, 0); + } + } // need round (drop>0) + + else { // drop<0; padding with -drop digits is needed + // This is the case where an error can occur if the padded + // coefficient will not fit; checking for this can be done in the + // same loop as padding for zeros if the no-hope and zero cases + // are checked first + if (-drop>DECPMAX-1) { // cannot fit unless 0 + if (!ISCOEFFZERO(BUFOFF)) return decInvalid(result, set); + // a zero can have any exponent; just drop through and use it + ulsd=BUFOFF+DECPMAX-1; + } + else { // padding will fit (but may still be too long) + // final-word mask depends on endianess + #if DECLITEND + static const uInt dmask[]={0, 0x000000ff, 0x0000ffff, 0x00ffffff}; + #else + static const uInt dmask[]={0, 0xff000000, 0xffff0000, 0xffffff00}; + #endif + // note that here zeros to the right are added by fours, so in + // the Quad case this could write 36 zeros if the coefficient has + // fewer than three significant digits (hence the +2*QUAD for buf) + for (uc=BUFOFF+DECPMAX;; uc+=4) { + UBFROMUI(uc, 0); + if (UBTOUI(uc-DECPMAX)!=0) { // could be bad + // if all four digits should be zero, definitely bad + if (uc<=BUFOFF+DECPMAX+(-drop)-4) + return decInvalid(result, set); + // must be a 1- to 3-digit sequence; check more carefully + if ((UBTOUI(uc-DECPMAX)&dmask[(-drop)%4])!=0) + return decInvalid(result, set); + break; // no need for loop end test + } + if (uc>=BUFOFF+DECPMAX+(-drop)-4) break; // done + } + ulsd=BUFOFF+DECPMAX+(-drop)-1; + } // pad and check leading zeros + } // drop<0 + + #if DECTRACE + num.msd=ulsd-DECPMAX+1; + num.lsd=ulsd; + num.exponent=explb-DECBIAS; + num.sign=sourhil & DECFLOAT_Sign; + decShowNum(&num, "res"); + #endif + + /*------------------------------------------------------------------*/ + /* At this point the result is DECPMAX digits, ending at ulsd, so */ + /* fits the encoding exactly; there is no possibility of error */ + /*------------------------------------------------------------------*/ + encode=((exprb>>DECECONL)<<4) + *(ulsd-DECPMAX+1); // make index + encode=DECCOMBFROM[encode]; // indexed by (0-2)*16+msd + // the exponent continuation can be extracted from the original RHS + encode|=sourhir & ECONMASK; + encode|=sourhil&DECFLOAT_Sign; // add the sign from LHS + + // finally encode the coefficient + // private macro to encode a declet; this version can be used + // because all coefficient digits exist + #define getDPD3q(dpd, n) ub=ulsd-(3*(n))-2; \ + dpd=BCD2DPD[(*ub*256)+(*(ub+1)*16)+*(ub+2)]; + + #if DOUBLE + getDPD3q(dpd, 4); encode|=dpd<<8; + getDPD3q(dpd, 3); encode|=dpd>>2; + DFWORD(result, 0)=encode; + encode=dpd<<30; + getDPD3q(dpd, 2); encode|=dpd<<20; + getDPD3q(dpd, 1); encode|=dpd<<10; + getDPD3q(dpd, 0); encode|=dpd; + DFWORD(result, 1)=encode; + + #elif QUAD + getDPD3q(dpd,10); encode|=dpd<<4; + getDPD3q(dpd, 9); encode|=dpd>>6; + DFWORD(result, 0)=encode; + encode=dpd<<26; + getDPD3q(dpd, 8); encode|=dpd<<16; + getDPD3q(dpd, 7); encode|=dpd<<6; + getDPD3q(dpd, 6); encode|=dpd>>4; + DFWORD(result, 1)=encode; + encode=dpd<<28; + getDPD3q(dpd, 5); encode|=dpd<<18; + getDPD3q(dpd, 4); encode|=dpd<<8; + getDPD3q(dpd, 3); encode|=dpd>>2; + DFWORD(result, 2)=encode; + encode=dpd<<30; + getDPD3q(dpd, 2); encode|=dpd<<20; + getDPD3q(dpd, 1); encode|=dpd<<10; + getDPD3q(dpd, 0); encode|=dpd; + DFWORD(result, 3)=encode; + #endif + return result; + } // decFloatQuantize + +/* ------------------------------------------------------------------ */ +/* decFloatReduce -- reduce finite coefficient to minimum length */ +/* */ +/* result gets the reduced decFloat */ +/* df is the source decFloat */ +/* set is the context */ +/* returns result, which will be canonical */ +/* */ +/* This removes all possible trailing zeros from the coefficient; */ +/* some may remain when the number is very close to Nmax. */ +/* Special values are unchanged and no status is set unless df=sNaN. */ +/* Reduced zero has an exponent q=0. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatReduce(decFloat *result, const decFloat *df, + decContext *set) { + bcdnum num; // work + uByte buf[DECPMAX], *ub; // coefficient and pointer + if (df!=result) *result=*df; // copy, if needed + if (DFISNAN(df)) return decNaNs(result, df, NULL, set); // sNaN + // zeros and infinites propagate too + if (DFISINF(df)) return decInfinity(result, df); // canonical + if (DFISZERO(df)) { + uInt sign=DFWORD(df, 0)&DECFLOAT_Sign; + decFloatZero(result); + DFWORD(result, 0)|=sign; + return result; // exponent dropped, sign OK + } + // non-zero finite + GETCOEFF(df, buf); + ub=buf+DECPMAX-1; // -> lsd + if (*ub) return result; // no trailing zeros + for (ub--; *ub==0;) ub--; // terminates because non-zero + // *ub is the first non-zero from the right + num.sign=DFWORD(df, 0)&DECFLOAT_Sign; // set up number... + num.exponent=GETEXPUN(df)+(Int)(buf+DECPMAX-1-ub); // adjusted exponent + num.msd=buf; + num.lsd=ub; + return decFinalize(result, &num, set); + } // decFloatReduce + +/* ------------------------------------------------------------------ */ +/* decFloatRemainder -- integer divide and return remainder */ +/* */ +/* result gets the remainder of dividing dfl by dfr: */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatRemainder(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + return decDivide(result, dfl, dfr, set, REMAINDER); + } // decFloatRemainder + +/* ------------------------------------------------------------------ */ +/* decFloatRemainderNear -- integer divide to nearest and remainder */ +/* */ +/* result gets the remainder of dividing dfl by dfr: */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* This is the IEEE remainder, where the nearest integer is used. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatRemainderNear(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + return decDivide(result, dfl, dfr, set, REMNEAR); + } // decFloatRemainderNear + +/* ------------------------------------------------------------------ */ +/* decFloatRotate -- rotate the coefficient of a decFloat left/right */ +/* */ +/* result gets the result of rotating dfl */ +/* dfl is the source decFloat to rotate */ +/* dfr is the count of digits to rotate, an integer (with q=0) */ +/* set is the context */ +/* returns result */ +/* */ +/* The digits of the coefficient of dfl are rotated to the left (if */ +/* dfr is positive) or to the right (if dfr is negative) without */ +/* adjusting the exponent or the sign of dfl. */ +/* */ +/* dfr must be in the range -DECPMAX through +DECPMAX. */ +/* NaNs are propagated as usual. An infinite dfl is unaffected (but */ +/* dfr must be valid). No status is set unless dfr is invalid or an */ +/* operand is an sNaN. The result is canonical. */ +/* ------------------------------------------------------------------ */ +#define PHALF (ROUNDUP(DECPMAX/2, 4)) // half length, rounded up +decFloat * decFloatRotate(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int rotate; // dfr as an Int + uByte buf[DECPMAX+PHALF]; // coefficient + half + uInt digits, savestat; // work + bcdnum num; // .. + uByte *ub; // .. + + if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + if (!DFISINT(dfr)) return decInvalid(result, set); + digits=decFloatDigits(dfr); // calculate digits + if (digits>2) return decInvalid(result, set); // definitely out of range + rotate=DPD2BIN[DFWORD(dfr, DECWORDS-1)&0x3ff]; // is in bottom declet + if (rotate>DECPMAX) return decInvalid(result, set); // too big + // [from here on no error or status change is possible] + if (DFISINF(dfl)) return decInfinity(result, dfl); // canonical + // handle no-rotate cases + if (rotate==0 || rotate==DECPMAX) return decCanonical(result, dfl); + // a real rotate is needed: 0 < rotate < DECPMAX + // reduce the rotation to no more than half to reduce copying later + // (for QUAD in fact half + 2 digits) + if (DFISSIGNED(dfr)) rotate=-rotate; + if (abs(rotate)>PHALF) { + if (rotate<0) rotate=DECPMAX+rotate; + else rotate=rotate-DECPMAX; + } + // now lay out the coefficient, leaving room to the right or the + // left depending on the direction of rotation + ub=buf; + if (rotate<0) ub+=PHALF; // rotate right, so space to left + GETCOEFF(dfl, ub); + // copy half the digits to left or right, and set num.msd + if (rotate<0) { + memcpy(buf, buf+DECPMAX, PHALF); + num.msd=buf+PHALF+rotate; + } + else { + memcpy(buf+DECPMAX, buf, PHALF); + num.msd=buf+rotate; + } + // fill in rest of num + num.lsd=num.msd+DECPMAX-1; + num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign; + num.exponent=GETEXPUN(dfl); + savestat=set->status; // record + decFinalize(result, &num, set); + set->status=savestat; // restore + return result; + } // decFloatRotate + +/* ------------------------------------------------------------------ */ +/* decFloatSameQuantum -- test decFloats for same quantum */ +/* */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* returns 1 if the operands have the same quantum, 0 otherwise */ +/* */ +/* No error is possible and no status results. */ +/* ------------------------------------------------------------------ */ +uInt decFloatSameQuantum(const decFloat *dfl, const decFloat *dfr) { + if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) { + if (DFISNAN(dfl) && DFISNAN(dfr)) return 1; + if (DFISINF(dfl) && DFISINF(dfr)) return 1; + return 0; // any other special mixture gives false + } + if (GETEXP(dfl)==GETEXP(dfr)) return 1; // biased exponents match + return 0; + } // decFloatSameQuantum + +/* ------------------------------------------------------------------ */ +/* decFloatScaleB -- multiply by a power of 10, as per 754 */ +/* */ +/* result gets the result of the operation */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs), am integer (with q=0) */ +/* set is the context */ +/* returns result */ +/* */ +/* This computes result=dfl x 10**dfr where dfr is an integer in the */ +/* range +/-2*(emax+pmax), typically resulting from LogB. */ +/* Underflow and Overflow (with Inexact) may occur. NaNs propagate */ +/* as usual. */ +/* ------------------------------------------------------------------ */ +#define SCALEBMAX 2*(DECEMAX+DECPMAX) // D=800, Q=12356 +decFloat * decFloatScaleB(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + uInt digits; // work + Int expr; // dfr as an Int + + if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + if (!DFISINT(dfr)) return decInvalid(result, set); + digits=decFloatDigits(dfr); // calculate digits + + #if DOUBLE + if (digits>3) return decInvalid(result, set); // definitely out of range + expr=DPD2BIN[DFWORD(dfr, 1)&0x3ff]; // must be in bottom declet + #elif QUAD + if (digits>5) return decInvalid(result, set); // definitely out of range + expr=DPD2BIN[DFWORD(dfr, 3)&0x3ff] // in bottom 2 declets .. + +DPD2BIN[(DFWORD(dfr, 3)>>10)&0x3ff]*1000; // .. + #endif + if (expr>SCALEBMAX) return decInvalid(result, set); // oops + // [from now on no error possible] + if (DFISINF(dfl)) return decInfinity(result, dfl); // canonical + if (DFISSIGNED(dfr)) expr=-expr; + // dfl is finite and expr is valid + *result=*dfl; // copy to target + return decFloatSetExponent(result, set, GETEXPUN(result)+expr); + } // decFloatScaleB + +/* ------------------------------------------------------------------ */ +/* decFloatShift -- shift the coefficient of a decFloat left or right */ +/* */ +/* result gets the result of shifting dfl */ +/* dfl is the source decFloat to shift */ +/* dfr is the count of digits to shift, an integer (with q=0) */ +/* set is the context */ +/* returns result */ +/* */ +/* The digits of the coefficient of dfl are shifted to the left (if */ +/* dfr is positive) or to the right (if dfr is negative) without */ +/* adjusting the exponent or the sign of dfl. */ +/* */ +/* dfr must be in the range -DECPMAX through +DECPMAX. */ +/* NaNs are propagated as usual. An infinite dfl is unaffected (but */ +/* dfr must be valid). No status is set unless dfr is invalid or an */ +/* operand is an sNaN. The result is canonical. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatShift(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + Int shift; // dfr as an Int + uByte buf[DECPMAX*2]; // coefficient + padding + uInt digits, savestat; // work + bcdnum num; // .. + uInt uiwork; // for macros + + if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); + if (!DFISINT(dfr)) return decInvalid(result, set); + digits=decFloatDigits(dfr); // calculate digits + if (digits>2) return decInvalid(result, set); // definitely out of range + shift=DPD2BIN[DFWORD(dfr, DECWORDS-1)&0x3ff]; // is in bottom declet + if (shift>DECPMAX) return decInvalid(result, set); // too big + // [from here on no error or status change is possible] + + if (DFISINF(dfl)) return decInfinity(result, dfl); // canonical + // handle no-shift and all-shift (clear to zero) cases + if (shift==0) return decCanonical(result, dfl); + if (shift==DECPMAX) { // zero with sign + uByte sign=(uByte)(DFBYTE(dfl, 0)&0x80); // save sign bit + decFloatZero(result); // make +0 + DFBYTE(result, 0)=(uByte)(DFBYTE(result, 0)|sign); // and set sign + // [cannot safely use CopySign] + return result; + } + // a real shift is needed: 0 < shift < DECPMAX + num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign; + num.exponent=GETEXPUN(dfl); + num.msd=buf; + GETCOEFF(dfl, buf); + if (DFISSIGNED(dfr)) { // shift right + // edge cases are taken care of, so this is easy + num.lsd=buf+DECPMAX-shift-1; + } + else { // shift left -- zero padding needed to right + UBFROMUI(buf+DECPMAX, 0); // 8 will handle most cases + UBFROMUI(buf+DECPMAX+4, 0); // .. + if (shift>8) memset(buf+DECPMAX+8, 0, 8+QUAD*18); // all other cases + num.msd+=shift; + num.lsd=num.msd+DECPMAX-1; + } + savestat=set->status; // record + decFinalize(result, &num, set); + set->status=savestat; // restore + return result; + } // decFloatShift + +/* ------------------------------------------------------------------ */ +/* decFloatSubtract -- subtract a decFloat from another */ +/* */ +/* result gets the result of subtracting dfr from dfl: */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result */ +/* */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatSubtract(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + decFloat temp; + // NaNs must propagate without sign change + if (DFISNAN(dfr)) return decFloatAdd(result, dfl, dfr, set); + temp=*dfr; // make a copy + DFBYTE(&temp, 0)^=0x80; // flip sign + return decFloatAdd(result, dfl, &temp, set); // and add to the lhs + } // decFloatSubtract + +/* ------------------------------------------------------------------ */ +/* decFloatToInt -- round to 32-bit binary integer (4 flavours) */ +/* */ +/* df is the decFloat to round */ +/* set is the context */ +/* round is the rounding mode to use */ +/* returns a uInt or an Int, rounded according to the name */ +/* */ +/* Invalid will always be signaled if df is a NaN, is Infinite, or is */ +/* outside the range of the target; Inexact will not be signaled for */ +/* simple rounding unless 'Exact' appears in the name. */ +/* ------------------------------------------------------------------ */ +uInt decFloatToUInt32(const decFloat *df, decContext *set, + enum rounding round) { + return decToInt32(df, set, round, 0, 1);} + +uInt decFloatToUInt32Exact(const decFloat *df, decContext *set, + enum rounding round) { + return decToInt32(df, set, round, 1, 1);} + +Int decFloatToInt32(const decFloat *df, decContext *set, + enum rounding round) { + return (Int)decToInt32(df, set, round, 0, 0);} + +Int decFloatToInt32Exact(const decFloat *df, decContext *set, + enum rounding round) { + return (Int)decToInt32(df, set, round, 1, 0);} + +/* ------------------------------------------------------------------ */ +/* decFloatToIntegral -- round to integral value (two flavours) */ +/* */ +/* result gets the result */ +/* df is the decFloat to round */ +/* set is the context */ +/* round is the rounding mode to use */ +/* returns result */ +/* */ +/* No exceptions, even Inexact, are raised except for sNaN input, or */ +/* if 'Exact' appears in the name. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatToIntegralValue(decFloat *result, const decFloat *df, + decContext *set, enum rounding round) { + return decToIntegral(result, df, set, round, 0);} + +decFloat * decFloatToIntegralExact(decFloat *result, const decFloat *df, + decContext *set) { + return decToIntegral(result, df, set, set->round, 1);} + +/* ------------------------------------------------------------------ */ +/* decFloatXor -- logical digitwise XOR of two decFloats */ +/* */ +/* result gets the result of XORing dfl and dfr */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) */ +/* set is the context */ +/* returns result, which will be canonical with sign=0 */ +/* */ +/* The operands must be positive, finite with exponent q=0, and */ +/* comprise just zeros and ones; if not, Invalid operation results. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatXor(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + if (!DFISUINT01(dfl) || !DFISUINT01(dfr) + || !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set); + // the operands are positive finite integers (q=0) with just 0s and 1s + #if DOUBLE + DFWORD(result, 0)=ZEROWORD + |((DFWORD(dfl, 0) ^ DFWORD(dfr, 0))&0x04009124); + DFWORD(result, 1)=(DFWORD(dfl, 1) ^ DFWORD(dfr, 1))&0x49124491; + #elif QUAD + DFWORD(result, 0)=ZEROWORD + |((DFWORD(dfl, 0) ^ DFWORD(dfr, 0))&0x04000912); + DFWORD(result, 1)=(DFWORD(dfl, 1) ^ DFWORD(dfr, 1))&0x44912449; + DFWORD(result, 2)=(DFWORD(dfl, 2) ^ DFWORD(dfr, 2))&0x12449124; + DFWORD(result, 3)=(DFWORD(dfl, 3) ^ DFWORD(dfr, 3))&0x49124491; + #endif + return result; + } // decFloatXor + +/* ------------------------------------------------------------------ */ +/* decInvalid -- set Invalid_operation result */ +/* */ +/* result gets a canonical NaN */ +/* set is the context */ +/* returns result */ +/* */ +/* status has Invalid_operation added */ +/* ------------------------------------------------------------------ */ +static decFloat *decInvalid(decFloat *result, decContext *set) { + decFloatZero(result); + DFWORD(result, 0)=DECFLOAT_qNaN; + set->status|=DEC_Invalid_operation; + return result; + } // decInvalid + +/* ------------------------------------------------------------------ */ +/* decInfinity -- set canonical Infinity with sign from a decFloat */ +/* */ +/* result gets a canonical Infinity */ +/* df is source decFloat (only the sign is used) */ +/* returns result */ +/* */ +/* df may be the same as result */ +/* ------------------------------------------------------------------ */ +static decFloat *decInfinity(decFloat *result, const decFloat *df) { + uInt sign=DFWORD(df, 0); // save source signword + decFloatZero(result); // clear everything + DFWORD(result, 0)=DECFLOAT_Inf | (sign & DECFLOAT_Sign); + return result; + } // decInfinity + +/* ------------------------------------------------------------------ */ +/* decNaNs -- handle NaN argument(s) */ +/* */ +/* result gets the result of handling dfl and dfr, one or both of */ +/* which is a NaN */ +/* dfl is the first decFloat (lhs) */ +/* dfr is the second decFloat (rhs) -- may be NULL for a single- */ +/* operand operation */ +/* set is the context */ +/* returns result */ +/* */ +/* Called when one or both operands is a NaN, and propagates the */ +/* appropriate result to res. When an sNaN is found, it is changed */ +/* to a qNaN and Invalid operation is set. */ +/* ------------------------------------------------------------------ */ +static decFloat *decNaNs(decFloat *result, + const decFloat *dfl, const decFloat *dfr, + decContext *set) { + // handle sNaNs first + if (dfr!=NULL && DFISSNAN(dfr) && !DFISSNAN(dfl)) dfl=dfr; // use RHS + if (DFISSNAN(dfl)) { + decCanonical(result, dfl); // propagate canonical sNaN + DFWORD(result, 0)&=~(DECFLOAT_qNaN ^ DECFLOAT_sNaN); // quiet + set->status|=DEC_Invalid_operation; + return result; + } + // one or both is a quiet NaN + if (!DFISNAN(dfl)) dfl=dfr; // RHS must be NaN, use it + return decCanonical(result, dfl); // propagate canonical qNaN + } // decNaNs + +/* ------------------------------------------------------------------ */ +/* decNumCompare -- numeric comparison of two decFloats */ +/* */ +/* dfl is the left-hand decFloat, which is not a NaN */ +/* dfr is the right-hand decFloat, which is not a NaN */ +/* tot is 1 for total order compare, 0 for simple numeric */ +/* returns -1, 0, or +1 for dfldfr */ +/* */ +/* No error is possible; status and mode are unchanged. */ +/* ------------------------------------------------------------------ */ +static Int decNumCompare(const decFloat *dfl, const decFloat *dfr, Flag tot) { + Int sigl, sigr; // LHS and RHS non-0 signums + Int shift; // shift needed to align operands + uByte *ub, *uc; // work + uInt uiwork; // for macros + // buffers +2 if Quad (36 digits), need double plus 4 for safe padding + uByte bufl[DECPMAX*2+QUAD*2+4]; // for LHS coefficient + padding + uByte bufr[DECPMAX*2+QUAD*2+4]; // for RHS coefficient + padding + + sigl=1; + if (DFISSIGNED(dfl)) { + if (!DFISSIGNED(dfr)) { // -LHS +RHS + if (DFISZERO(dfl) && DFISZERO(dfr) && !tot) return 0; + return -1; // RHS wins + } + sigl=-1; + } + if (DFISSIGNED(dfr)) { + if (!DFISSIGNED(dfl)) { // +LHS -RHS + if (DFISZERO(dfl) && DFISZERO(dfr) && !tot) return 0; + return +1; // LHS wins + } + } + + // signs are the same; operand(s) could be zero + sigr=-sigl; // sign to return if abs(RHS) wins + + if (DFISINF(dfl)) { + if (DFISINF(dfr)) return 0; // both infinite & same sign + return sigl; // inf > n + } + if (DFISINF(dfr)) return sigr; // n < inf [dfl is finite] + + // here, both are same sign and finite; calculate their offset + shift=GETEXP(dfl)-GETEXP(dfr); // [0 means aligned] + // [bias can be ignored -- the absolute exponent is not relevant] + + if (DFISZERO(dfl)) { + if (!DFISZERO(dfr)) return sigr; // LHS=0, RHS!=0 + // both are zero, return 0 if both same exponent or numeric compare + if (shift==0 || !tot) return 0; + if (shift>0) return sigl; + return sigr; // [shift<0] + } + else { // LHS!=0 + if (DFISZERO(dfr)) return sigl; // LHS!=0, RHS=0 + } + // both are known to be non-zero at this point + + // if the exponents are so different that the coefficients do not + // overlap (by even one digit) then a full comparison is not needed + if (abs(shift)>=DECPMAX) { // no overlap + // coefficients are known to be non-zero + if (shift>0) return sigl; + return sigr; // [shift<0] + } + + // decode the coefficients + // (shift both right two if Quad to make a multiple of four) + #if QUAD + UBFROMUI(bufl, 0); + UBFROMUI(bufr, 0); + #endif + GETCOEFF(dfl, bufl+QUAD*2); // decode from decFloat + GETCOEFF(dfr, bufr+QUAD*2); // .. + if (shift==0) { // aligned; common and easy + // all multiples of four, here + for (ub=bufl, uc=bufr; ub*uc) return sigl; // difference found + if (*ub<*uc) return sigr; // .. + } + } + } // aligned + else if (shift>0) { // lhs to left + ub=bufl; // RHS pointer + // pad bufl so right-aligned; most shifts will fit in 8 + UBFROMUI(bufl+DECPMAX+QUAD*2, 0); // add eight zeros + UBFROMUI(bufl+DECPMAX+QUAD*2+4, 0); // .. + if (shift>8) { + // more than eight; fill the rest, and also worth doing the + // lead-in by fours + uByte *up; // work + uByte *upend=bufl+DECPMAX+QUAD*2+shift; + for (up=bufl+DECPMAX+QUAD*2+8; upbufl+shift-4) break; + } + } + // check remaining leading digits + for (; ub*uc) return sigl; // difference found + if (*ub<*uc) return sigr; // .. + } + } // mismatch + if (uc==bufr+QUAD*2+DECPMAX-4) break; // all checked + } + } // shift>0 + + else { // shift<0) .. RHS is to left of LHS; mirror shift>0 + uc=bufr; // RHS pointer + // pad bufr so right-aligned; most shifts will fit in 8 + UBFROMUI(bufr+DECPMAX+QUAD*2, 0); // add eight zeros + UBFROMUI(bufr+DECPMAX+QUAD*2+4, 0); // .. + if (shift<-8) { + // more than eight; fill the rest, and also worth doing the + // lead-in by fours + uByte *up; // work + uByte *upend=bufr+DECPMAX+QUAD*2-shift; + for (up=bufr+DECPMAX+QUAD*2+8; upbufr-shift-4) break; + } + } + // check remaining leading digits + for (; uc*uc) return sigl; // difference found + if (*ub<*uc) return sigr; // .. + } + } // mismatch + if (ub==bufl+QUAD*2+DECPMAX-4) break; // all checked + } + } // shift<0 + + // Here when compare equal + if (!tot) return 0; // numerically equal + // total ordering .. exponent matters + if (shift>0) return sigl; // total order by exponent + if (shift<0) return sigr; // .. + return 0; + } // decNumCompare + +/* ------------------------------------------------------------------ */ +/* decToInt32 -- local routine to effect ToInteger conversions */ +/* */ +/* df is the decFloat to convert */ +/* set is the context */ +/* rmode is the rounding mode to use */ +/* exact is 1 if Inexact should be signalled */ +/* unsign is 1 if the result a uInt, 0 if an Int (cast to uInt) */ +/* returns 32-bit result as a uInt */ +/* */ +/* Invalid is set is df is a NaN, is infinite, or is out-of-range; in */ +/* these cases 0 is returned. */ +/* ------------------------------------------------------------------ */ +static uInt decToInt32(const decFloat *df, decContext *set, + enum rounding rmode, Flag exact, Flag unsign) { + Int exp; // exponent + uInt sourhi, sourpen, sourlo; // top word from source decFloat .. + uInt hi, lo; // .. penultimate, least, etc. + decFloat zero, result; // work + Int i; // .. + + /* Start decoding the argument */ + sourhi=DFWORD(df, 0); // top word + exp=DECCOMBEXP[sourhi>>26]; // get exponent high bits (in place) + if (EXPISSPECIAL(exp)) { // is special? + set->status|=DEC_Invalid_operation; // signal + return 0; + } + + /* Here when the argument is finite */ + if (GETEXPUN(df)==0) result=*df; // already a true integer + else { // need to round to integer + enum rounding saveround; // saver + uInt savestatus; // .. + saveround=set->round; // save rounding mode .. + savestatus=set->status; // .. and status + set->round=rmode; // set mode + decFloatZero(&zero); // make 0E+0 + set->status=0; // clear + decFloatQuantize(&result, df, &zero, set); // [this may fail] + set->round=saveround; // restore rounding mode .. + if (exact) set->status|=savestatus; // include Inexact + else set->status=savestatus; // .. or just original status + } + + // only the last four declets of the coefficient can contain + // non-zero; check for others (and also NaN or Infinity from the + // Quantize) first (see DFISZERO for explanation): + // decFloatShow(&result, "sofar"); + #if DOUBLE + if ((DFWORD(&result, 0)&0x1c03ff00)!=0 + || (DFWORD(&result, 0)&0x60000000)==0x60000000) { + #elif QUAD + if ((DFWORD(&result, 2)&0xffffff00)!=0 + || DFWORD(&result, 1)!=0 + || (DFWORD(&result, 0)&0x1c003fff)!=0 + || (DFWORD(&result, 0)&0x60000000)==0x60000000) { + #endif + set->status|=DEC_Invalid_operation; // Invalid or out of range + return 0; + } + // get last twelve digits of the coefficent into hi & ho, base + // 10**9 (see GETCOEFFBILL): + sourlo=DFWORD(&result, DECWORDS-1); + lo=DPD2BIN0[sourlo&0x3ff] + +DPD2BINK[(sourlo>>10)&0x3ff] + +DPD2BINM[(sourlo>>20)&0x3ff]; + sourpen=DFWORD(&result, DECWORDS-2); + hi=DPD2BIN0[((sourpen<<2) | (sourlo>>30))&0x3ff]; + + // according to request, check range carefully + if (unsign) { + if (hi>4 || (hi==4 && lo>294967295) || (hi+lo!=0 && DFISSIGNED(&result))) { + set->status|=DEC_Invalid_operation; // out of range + return 0; + } + return hi*BILLION+lo; + } + // signed + if (hi>2 || (hi==2 && lo>147483647)) { + // handle the usual edge case + if (lo==147483648 && hi==2 && DFISSIGNED(&result)) return 0x80000000; + set->status|=DEC_Invalid_operation; // truly out of range + return 0; + } + i=hi*BILLION+lo; + if (DFISSIGNED(&result)) i=-i; + return (uInt)i; + } // decToInt32 + +/* ------------------------------------------------------------------ */ +/* decToIntegral -- local routine to effect ToIntegral value */ +/* */ +/* result gets the result */ +/* df is the decFloat to round */ +/* set is the context */ +/* rmode is the rounding mode to use */ +/* exact is 1 if Inexact should be signalled */ +/* returns result */ +/* ------------------------------------------------------------------ */ +static decFloat * decToIntegral(decFloat *result, const decFloat *df, + decContext *set, enum rounding rmode, + Flag exact) { + Int exp; // exponent + uInt sourhi; // top word from source decFloat + enum rounding saveround; // saver + uInt savestatus; // .. + decFloat zero; // work + + /* Start decoding the argument */ + sourhi=DFWORD(df, 0); // top word + exp=DECCOMBEXP[sourhi>>26]; // get exponent high bits (in place) + + if (EXPISSPECIAL(exp)) { // is special? + // NaNs are handled as usual + if (DFISNAN(df)) return decNaNs(result, df, NULL, set); + // must be infinite; return canonical infinity with sign of df + return decInfinity(result, df); + } + + /* Here when the argument is finite */ + // complete extraction of the exponent + exp+=GETECON(df)-DECBIAS; // .. + continuation and unbias + + if (exp>=0) return decCanonical(result, df); // already integral + + saveround=set->round; // save rounding mode .. + savestatus=set->status; // .. and status + set->round=rmode; // set mode + decFloatZero(&zero); // make 0E+0 + decFloatQuantize(result, df, &zero, set); // 'integrate'; cannot fail + set->round=saveround; // restore rounding mode .. + if (!exact) set->status=savestatus; // .. and status, unless exact + return result; + } // decToIntegral diff --git a/extern/decNumber/decCommon.c b/extern/decNumber/decCommon.c new file mode 100644 index 0000000000..6a0c112c88 --- /dev/null +++ b/extern/decNumber/decCommon.c @@ -0,0 +1,1835 @@ +/* ------------------------------------------------------------------ */ +/* decCommon.c -- common code for all three fixed-size types */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is included in the package as decNumber.pdf. This */ +/* document is also available in HTML, together with specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises code that is shared between all the formats */ +/* (decSingle, decDouble, and decQuad); it includes set and extract */ +/* of format components, widening, narrowing, and string conversions. */ +/* */ +/* Unlike decNumber, parameterization takes place at compile time */ +/* rather than at runtime. The parameters are set in the decDouble.c */ +/* (etc.) files, which then include this one to produce the compiled */ +/* code. The functions here, therefore, are code shared between */ +/* multiple formats. */ +/* ------------------------------------------------------------------ */ +// Names here refer to decFloat rather than to decDouble, etc., and +// the functions are in strict alphabetical order. +// Constants, tables, and debug function(s) are included only for QUAD +// (which will always be compiled if DOUBLE or SINGLE are used). +// +// Whenever a decContext is used, only the status may be set (using +// OR) or the rounding mode read; all other fields are ignored and +// untouched. + +// names for simpler testing and default context +#if DECPMAX==7 + #define SINGLE 1 + #define DOUBLE 0 + #define QUAD 0 + #define DEFCONTEXT DEC_INIT_DECIMAL32 +#elif DECPMAX==16 + #define SINGLE 0 + #define DOUBLE 1 + #define QUAD 0 + #define DEFCONTEXT DEC_INIT_DECIMAL64 +#elif DECPMAX==34 + #define SINGLE 0 + #define DOUBLE 0 + #define QUAD 1 + #define DEFCONTEXT DEC_INIT_DECIMAL128 +#else + #error Unexpected DECPMAX value +#endif + +/* Assertions */ + +#if DECPMAX!=7 && DECPMAX!=16 && DECPMAX!=34 + #error Unexpected Pmax (DECPMAX) value for this module +#endif + +// Assert facts about digit characters, etc. +#if ('9'&0x0f)!=9 + #error This module assumes characters are of the form 0b....nnnn + // where .... are don't care 4 bits and nnnn is 0000 through 1001 +#endif +#if ('9'&0xf0)==('.'&0xf0) + #error This module assumes '.' has a different mask than a digit +#endif + +// Assert ToString lay-out conditions +#if DECSTRING DECSTRING + #error Exponent form can be too long for ToString to lay out safely +#endif +#if DECEMAXD > 4 + #error Exponent form is too long for ToString to lay out + // Note: code for up to 9 digits exists in archives [decOct] +#endif + +/* Private functions used here and possibly in decBasic.c, etc. */ +static decFloat * decFinalize(decFloat *, bcdnum *, decContext *); +static Flag decBiStr(const char *, const char *, const char *); + +/* Macros and private tables; those which are not format-dependent */ +/* are only included if decQuad is being built. */ + +/* ------------------------------------------------------------------ */ +/* Combination field lookup tables (uInts to save measurable work) */ +/* */ +/* DECCOMBEXP - 2 most-significant-bits of exponent (00, 01, or */ +/* 10), shifted left for format, or DECFLOAT_Inf/NaN */ +/* DECCOMBWEXP - The same, for the next-wider format (unless QUAD) */ +/* DECCOMBMSD - 4-bit most-significant-digit */ +/* [0 if the index is a special (Infinity or NaN)] */ +/* DECCOMBFROM - 5-bit combination field from EXP top bits and MSD */ +/* (placed in uInt so no shift is needed) */ +/* */ +/* DECCOMBEXP, DECCOMBWEXP, and DECCOMBMSD are indexed by the sign */ +/* and 5-bit combination field (0-63, the second half of the table */ +/* identical to the first half) */ +/* DECCOMBFROM is indexed by expTopTwoBits*16 + msd */ +/* */ +/* DECCOMBMSD and DECCOMBFROM are not format-dependent and so are */ +/* only included once, when QUAD is being built */ +/* ------------------------------------------------------------------ */ +static const uInt DECCOMBEXP[64]={ + 0, 0, 0, 0, 0, 0, 0, 0, + 1< DPD +#define DEC_BIN2DPD 1 // 0-999 -> DPD +#define DEC_BIN2BCD8 1 // 0-999 -> ddd, len +#define DEC_DPD2BCD8 1 // DPD -> ddd, len +#define DEC_DPD2BIN 1 // DPD -> 0-999 +#define DEC_DPD2BINK 1 // DPD -> 0-999000 +#define DEC_DPD2BINM 1 // DPD -> 0-999000000 +#include "decDPD.h" // source of the lookup tables + +#endif + +/* ----------------------------------------------------------------- */ +/* decBiStr -- compare string with pairwise options */ +/* */ +/* targ is the string to compare */ +/* str1 is one of the strings to compare against (length may be 0) */ +/* str2 is the other; it must be the same length as str1 */ +/* */ +/* returns 1 if strings compare equal, (that is, targ is the same */ +/* length as str1 and str2, and each character of targ is in one */ +/* of str1 or str2 in the corresponding position), or 0 otherwise */ +/* */ +/* This is used for generic caseless compare, including the awkward */ +/* case of the Turkish dotted and dotless Is. Use as (for example): */ +/* if (decBiStr(test, "mike", "MIKE")) ... */ +/* ----------------------------------------------------------------- */ +static Flag decBiStr(const char *targ, const char *str1, const char *str2) { + for (;;targ++, str1++, str2++) { + if (*targ!=*str1 && *targ!=*str2) return 0; + // *targ has a match in one (or both, if terminator) + if (*targ=='\0') break; + } // forever + return 1; + } // decBiStr + +/* ------------------------------------------------------------------ */ +/* decFinalize -- adjust and store a final result */ +/* */ +/* df is the decFloat format number which gets the final result */ +/* num is the descriptor of the number to be checked and encoded */ +/* [its values, including the coefficient, may be modified] */ +/* set is the context to use */ +/* returns df */ +/* */ +/* The num descriptor may point to a bcd8 string of any length; this */ +/* string may have leading insignificant zeros. If it has more than */ +/* DECPMAX digits then the final digit can be a round-for-reround */ +/* digit (i.e., it may include a sticky bit residue). */ +/* */ +/* The exponent (q) may be one of the codes for a special value and */ +/* can be up to 999999999 for conversion from string. */ +/* */ +/* No error is possible, but Inexact, Underflow, and/or Overflow may */ +/* be set. */ +/* ------------------------------------------------------------------ */ +// Constant whose size varies with format; also the check for surprises +static uByte allnines[DECPMAX]= +#if SINGLE + {9, 9, 9, 9, 9, 9, 9}; +#elif DOUBLE + {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; +#elif QUAD + {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; +#endif + +static decFloat * decFinalize(decFloat *df, bcdnum *num, + decContext *set) { + uByte *ub; // work + uInt dpd; // .. + uInt uiwork; // for macros + uByte *umsd=num->msd; // local copy + uByte *ulsd=num->lsd; // .. + uInt encode; // encoding accumulator + Int length; // coefficient length + + #if DECCHECK + Int clen=ulsd-umsd+1; + #if QUAD + #define COEXTRA 2 // extra-long coefficent + #else + #define COEXTRA 0 + #endif + if (clen<1 || clen>DECPMAX*3+2+COEXTRA) + printf("decFinalize: suspect coefficient [length=%ld]\n", (LI)clen); + if (num->sign!=0 && num->sign!=DECFLOAT_Sign) + printf("decFinalize: bad sign [%08lx]\n", (LI)num->sign); + if (!EXPISSPECIAL(num->exponent) + && (num->exponent>1999999999 || num->exponent<-1999999999)) + printf("decFinalize: improbable exponent [%ld]\n", (LI)num->exponent); + // decShowNum(num, "final"); + #endif + + // A special will have an 'exponent' which is very positive and a + // coefficient < DECPMAX + length=(uInt)(ulsd-umsd+1); // coefficient length + + if (!NUMISSPECIAL(num)) { + Int drop; // digits to be dropped + // skip leading insignificant zeros to calculate an exact length + // [this is quite expensive] + if (*umsd==0) { + for (; umsd+3exponent); + // drop can now be > digits for bottom-clamp (subnormal) cases + if (drop>0) { // rounding needed + // (decFloatQuantize has very similar code to this, so any + // changes may need to be made there, too) + uByte *roundat; // -> re-round digit + uByte reround; // reround value + // printf("Rounding; drop=%ld\n", (LI)drop); + + num->exponent+=drop; // always update exponent + + // Three cases here: + // 1. new LSD is in coefficient (almost always) + // 2. new LSD is digit to left of coefficient (so MSD is + // round-for-reround digit) + // 3. new LSD is to left of case 2 (whole coefficient is sticky) + // [duplicate check-stickies code to save a test] + // [by-digit check for stickies as runs of zeros are rare] + if (dropstatus|=DEC_Inexact; + // if adjusted exponent [exp+digits-1] is < EMIN then num is + // subnormal -- so raise Underflow + if (num->exponentexponent+(ulsd-umsd+1)-1)status|=DEC_Underflow; + + // next decide whether increment of the coefficient is needed + if (set->round==DEC_ROUND_HALF_EVEN) { // fastpath slowest case + if (reround>5) bump=1; // >0.5 goes up + else if (reround==5) // exactly 0.5000 .. + bump=*ulsd & 0x01; // .. up iff [new] lsd is odd + } // r-h-e + else switch (set->round) { + case DEC_ROUND_DOWN: { + // no change + break;} // r-d + case DEC_ROUND_HALF_DOWN: { + if (reround>5) bump=1; + break;} // r-h-d + case DEC_ROUND_HALF_UP: { + if (reround>=5) bump=1; + break;} // r-h-u + case DEC_ROUND_UP: { + if (reround>0) bump=1; + break;} // r-u + case DEC_ROUND_CEILING: { + // same as _UP for positive numbers, and as _DOWN for negatives + if (!num->sign && reround>0) bump=1; + break;} // r-c + case DEC_ROUND_FLOOR: { + // same as _UP for negative numbers, and as _DOWN for positive + // [negative reround cannot occur on 0] + if (num->sign && reround>0) bump=1; + break;} // r-f + case DEC_ROUND_05UP: { + if (reround>0) { // anything out there is 'sticky' + // bump iff lsd=0 or 5; this cannot carry so it could be + // effected immediately with no bump -- but the code + // is clearer if this is done the same way as the others + if (*ulsd==0 || *ulsd==5) bump=1; + } + break;} // r-r + default: { // e.g., DEC_ROUND_MAX + set->status|=DEC_Invalid_context; + #if DECCHECK + printf("Unknown rounding mode: %ld\n", (LI)set->round); + #endif + break;} + } // switch (not r-h-e) + // printf("ReRound: %ld bump: %ld\n", (LI)reround, (LI)bump); + + if (bump!=0) { // need increment + // increment the coefficient; this might end up with 1000... + // (after the all nines case) + ub=ulsd; + for(; ub-3>=umsd && UBTOUI(ub-3)==0x09090909; ub-=4) { + UBFROMUI(ub-3, 0); // to 00000000 + } + // [note ub could now be to left of msd, and it is not safe + // to write to the the left of the msd] + // now at most 3 digits left to non-9 (usually just the one) + for (; ub>=umsd; *ub=0, ub--) { + if (*ub==9) continue; // carry + *ub+=1; + break; + } + if (ubexponent++; + } + else { + // if coefficient is shorter than Pmax then num is + // subnormal, so extend it; this is safe as drop>0 + // (or, if the coefficient was supplied above, it could + // not be 9); this may make the result normal. + ulsd++; + *ulsd=0; + // [exponent unchanged] + #if DECCHECK + if (num->exponent!=DECQTINY) // sanity check + printf("decFinalize: bad all-nines extend [^%ld, %ld]\n", + (LI)num->exponent, (LI)(ulsd-umsd+1)); + #endif + } // subnormal extend + } // had all-nines + } // bump needed + } // inexact rounding + + length=ulsd-umsd+1; // recalculate (may be 0) + + // The coefficient will now fit and has final length unless overflow + // decShowNum(num, "rounded"); + + // if exponent is >=emax may have to clamp, overflow, or fold-down + if (num->exponent>DECEMAX-(DECPMAX-1)) { // is edge case + // printf("overflow checks...\n"); + if (*ulsd==0 && ulsd==umsd) { // have zero + num->exponent=DECEMAX-(DECPMAX-1); // clamp to max + } + else if ((num->exponent+length-1)>DECEMAX) { // > Nmax + // Overflow -- these could go straight to encoding, here, but + // instead num is adjusted to keep the code cleaner + Flag needmax=0; // 1 for finite result + set->status|=(DEC_Overflow | DEC_Inexact); + switch (set->round) { + case DEC_ROUND_DOWN: { + needmax=1; // never Infinity + break;} // r-d + case DEC_ROUND_05UP: { + needmax=1; // never Infinity + break;} // r-05 + case DEC_ROUND_CEILING: { + if (num->sign) needmax=1; // Infinity iff non-negative + break;} // r-c + case DEC_ROUND_FLOOR: { + if (!num->sign) needmax=1; // Infinity iff negative + break;} // r-f + default: break; // Infinity in all other cases + } + if (!needmax) { // easy .. set Infinity + num->exponent=DECFLOAT_Inf; + *umsd=0; // be clean: coefficient to 0 + ulsd=umsd; // .. + } + else { // return Nmax + umsd=allnines; // use constant array + ulsd=allnines+DECPMAX-1; + num->exponent=DECEMAX-(DECPMAX-1); + } + } + else { // no overflow but non-zero and may have to fold-down + Int shift=num->exponent-(DECEMAX-(DECPMAX-1)); + if (shift>0) { // fold-down needed + // fold down needed; must copy to buffer in order to pad + // with zeros safely; fortunately this is not the worst case + // path because cannot have had a round + uByte buffer[ROUNDUP(DECPMAX+3, 4)]; // [+3 allows uInt padding] + uByte *s=umsd; // source + uByte *t=buffer; // safe target + uByte *tlsd=buffer+(ulsd-umsd)+shift; // target LSD + // printf("folddown shift=%ld\n", (LI)shift); + for (; s<=ulsd; s+=4, t+=4) UBFROMUI(t, UBTOUI(s)); + for (t=tlsd-shift+1; t<=tlsd; t+=4) UBFROMUI(t, 0); // pad 0s + num->exponent-=shift; + umsd=buffer; + ulsd=tlsd; + } + } // fold-down? + length=ulsd-umsd+1; // recalculate length + } // high-end edge case + } // finite number + + /*------------------------------------------------------------------*/ + /* At this point the result will properly fit the decFloat */ + /* encoding, and it can be encoded with no possibility of error */ + /*------------------------------------------------------------------*/ + // Following code does not alter coefficient (could be allnines array) + + // fast path possible when DECPMAX digits + if (length==DECPMAX) { + return decFloatFromBCD(df, num->exponent, umsd, num->sign); + } // full-length + + // slower path when not a full-length number; must care about length + // [coefficient length here will be < DECPMAX] + if (!NUMISSPECIAL(num)) { // is still finite + // encode the combination field and exponent continuation + uInt uexp=(uInt)(num->exponent+DECBIAS); // biased exponent + uInt code=(uexp>>DECECONL)<<4; // top two bits of exp + // [msd==0] + // look up the combination field and make high word + encode=DECCOMBFROM[code]; // indexed by (0-2)*16+msd + encode|=(uexp<<(32-6-DECECONL)) & 0x03ffffff; // exponent continuation + } + else encode=num->exponent; // special [already in word] + encode|=num->sign; // add sign + + // private macro to extract a declet, n (where 0<=n=umsd) dpd=BCD2DPD[(*ub*256)+(*(ub+1)*16)+*(ub+2)]; \ + else {dpd=*(ub+2); if (ub+1==umsd) dpd+=*(ub+1)*16; dpd=BCD2DPD[dpd];} + + // place the declets in the encoding words and copy to result (df), + // according to endianness; in all cases complete the sign word + // first + #if DECPMAX==7 + getDPDt(dpd, 1); + encode|=dpd<<10; + getDPDt(dpd, 0); + encode|=dpd; + DFWORD(df, 0)=encode; // just the one word + + #elif DECPMAX==16 + getDPDt(dpd, 4); encode|=dpd<<8; + getDPDt(dpd, 3); encode|=dpd>>2; + DFWORD(df, 0)=encode; + encode=dpd<<30; + getDPDt(dpd, 2); encode|=dpd<<20; + getDPDt(dpd, 1); encode|=dpd<<10; + getDPDt(dpd, 0); encode|=dpd; + DFWORD(df, 1)=encode; + + #elif DECPMAX==34 + getDPDt(dpd,10); encode|=dpd<<4; + getDPDt(dpd, 9); encode|=dpd>>6; + DFWORD(df, 0)=encode; + + encode=dpd<<26; + getDPDt(dpd, 8); encode|=dpd<<16; + getDPDt(dpd, 7); encode|=dpd<<6; + getDPDt(dpd, 6); encode|=dpd>>4; + DFWORD(df, 1)=encode; + + encode=dpd<<28; + getDPDt(dpd, 5); encode|=dpd<<18; + getDPDt(dpd, 4); encode|=dpd<<8; + getDPDt(dpd, 3); encode|=dpd>>2; + DFWORD(df, 2)=encode; + + encode=dpd<<30; + getDPDt(dpd, 2); encode|=dpd<<20; + getDPDt(dpd, 1); encode|=dpd<<10; + getDPDt(dpd, 0); encode|=dpd; + DFWORD(df, 3)=encode; + #endif + + // printf("Status: %08lx\n", (LI)set->status); + // decFloatShow(df, "final2"); + return df; + } // decFinalize + +/* ------------------------------------------------------------------ */ +/* decFloatFromBCD -- set decFloat from exponent, BCD8, and sign */ +/* */ +/* df is the target decFloat */ +/* exp is the in-range unbiased exponent, q, or a special value in */ +/* the form returned by decFloatGetExponent */ +/* bcdar holds DECPMAX digits to set the coefficient from, one */ +/* digit in each byte (BCD8 encoding); the first (MSD) is ignored */ +/* if df is a NaN; all are ignored if df is infinite. */ +/* All bytes must be in 0-9; results are undefined otherwise. */ +/* sig is DECFLOAT_Sign to set the sign bit, 0 otherwise */ +/* returns df, which will be canonical */ +/* */ +/* No error is possible, and no status will be set. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatFromBCD(decFloat *df, Int exp, const uByte *bcdar, + Int sig) { + uInt encode, dpd; // work + const uByte *ub; // .. + + if (EXPISSPECIAL(exp)) encode=exp|sig;// specials already encoded + else { // is finite + // encode the combination field and exponent continuation + uInt uexp=(uInt)(exp+DECBIAS); // biased exponent + uInt code=(uexp>>DECECONL)<<4; // top two bits of exp + code+=bcdar[0]; // add msd + // look up the combination field and make high word + encode=DECCOMBFROM[code]|sig; // indexed by (0-2)*16+msd + encode|=(uexp<<(32-6-DECECONL)) & 0x03ffffff; // exponent continuation + } + + // private macro to extract a declet, n (where 0<=n>2; + DFWORD(df, 0)=encode; + encode=dpd<<30; + getDPDb(dpd, 2); encode|=dpd<<20; + getDPDb(dpd, 1); encode|=dpd<<10; + getDPDb(dpd, 0); encode|=dpd; + DFWORD(df, 1)=encode; + + #elif DECPMAX==34 + getDPDb(dpd,10); encode|=dpd<<4; + getDPDb(dpd, 9); encode|=dpd>>6; + DFWORD(df, 0)=encode; + + encode=dpd<<26; + getDPDb(dpd, 8); encode|=dpd<<16; + getDPDb(dpd, 7); encode|=dpd<<6; + getDPDb(dpd, 6); encode|=dpd>>4; + DFWORD(df, 1)=encode; + + encode=dpd<<28; + getDPDb(dpd, 5); encode|=dpd<<18; + getDPDb(dpd, 4); encode|=dpd<<8; + getDPDb(dpd, 3); encode|=dpd>>2; + DFWORD(df, 2)=encode; + + encode=dpd<<30; + getDPDb(dpd, 2); encode|=dpd<<20; + getDPDb(dpd, 1); encode|=dpd<<10; + getDPDb(dpd, 0); encode|=dpd; + DFWORD(df, 3)=encode; + #endif + // decFloatShow(df, "fromB"); + return df; + } // decFloatFromBCD + +/* ------------------------------------------------------------------ */ +/* decFloatFromPacked -- set decFloat from exponent and packed BCD */ +/* */ +/* df is the target decFloat */ +/* exp is the in-range unbiased exponent, q, or a special value in */ +/* the form returned by decFloatGetExponent */ +/* packed holds DECPMAX packed decimal digits plus a sign nibble */ +/* (all 6 codes are OK); the first (MSD) is ignored if df is a NaN */ +/* and all except sign are ignored if df is infinite. For DOUBLE */ +/* and QUAD the first (pad) nibble is also ignored in all cases. */ +/* All coefficient nibbles must be in 0-9 and sign in A-F; results */ +/* are undefined otherwise. */ +/* returns df, which will be canonical */ +/* */ +/* No error is possible, and no status will be set. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatFromPacked(decFloat *df, Int exp, const uByte *packed) { + uByte bcdar[DECPMAX+2]; // work [+1 for pad, +1 for sign] + const uByte *ip; // .. + uByte *op; // .. + Int sig=0; // sign + + // expand coefficient and sign to BCDAR + #if SINGLE + op=bcdar+1; // no pad digit + #else + op=bcdar; // first (pad) digit ignored + #endif + for (ip=packed; ip>4; + *op++=(uByte)(*ip&0x0f); // [final nibble is sign] + } + op--; // -> sign byte + if (*op==DECPMINUS || *op==DECPMINUSALT) sig=DECFLOAT_Sign; + + if (EXPISSPECIAL(exp)) { // Infinity or NaN + if (!EXPISINF(exp)) bcdar[1]=0; // a NaN: ignore MSD + else memset(bcdar+1, 0, DECPMAX); // Infinite: coefficient to 0 + } + return decFloatFromBCD(df, exp, bcdar+1, sig); + } // decFloatFromPacked + +/* ------------------------------------------------------------------ */ +/* decFloatFromPackedChecked -- set from exponent and packed; checked */ +/* */ +/* df is the target decFloat */ +/* exp is the in-range unbiased exponent, q, or a special value in */ +/* the form returned by decFloatGetExponent */ +/* packed holds DECPMAX packed decimal digits plus a sign nibble */ +/* (all 6 codes are OK); the first (MSD) must be 0 if df is a NaN */ +/* and all digits must be 0 if df is infinite. For DOUBLE and */ +/* QUAD the first (pad) nibble must be 0. */ +/* All coefficient nibbles must be in 0-9 and sign in A-F. */ +/* returns df, which will be canonical or NULL if any of the */ +/* requirements are not met (if this case df is unchanged); that */ +/* is, the input data must be as returned by decFloatToPacked, */ +/* except that all six sign codes are acccepted. */ +/* */ +/* No status will be set. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatFromPackedChecked(decFloat *df, Int exp, + const uByte *packed) { + uByte bcdar[DECPMAX+2]; // work [+1 for pad, +1 for sign] + const uByte *ip; // .. + uByte *op; // .. + Int sig=0; // sign + + // expand coefficient and sign to BCDAR + #if SINGLE + op=bcdar+1; // no pad digit + #else + op=bcdar; // first (pad) digit here + #endif + for (ip=packed; ip>4; + if (*op>9) return NULL; + op++; + *op=(uByte)(*ip&0x0f); // [final nibble is sign] + if (*op>9 && ip sign byte + if (*op<=9) return NULL; // bad sign + if (*op==DECPMINUS || *op==DECPMINUSALT) sig=DECFLOAT_Sign; + + #if !SINGLE + if (bcdar[0]!=0) return NULL; // bad pad nibble + #endif + + if (EXPISNAN(exp)) { // a NaN + if (bcdar[1]!=0) return NULL; // bad msd + } // NaN + else if (EXPISINF(exp)) { // is infinite + Int i; + for (i=0; iDECEMAX-DECPMAX+1) return NULL; + if (exp first character of decimal part + const char *c; // work + uByte *ub; // .. + uInt uiwork; // for macros + bcdnum num; // collects data for finishing + uInt error=DEC_Conversion_syntax; // assume the worst + uByte buffer[ROUNDUP(DECSTRING+11, 8)]; // room for most coefficents, + // some common rounding, +3, & pad + #if DECTRACE + // printf("FromString %s ...\n", string); + #endif + + for(;;) { // once-only 'loop' + num.sign=0; // assume non-negative + num.msd=buffer; // MSD is here always + + // detect and validate the coefficient, including any leading, + // trailing, or embedded '.' + // [could test four-at-a-time here (saving 10% for decQuads), + // but that risks storage violation because the position of the + // terminator is unknown] + for (c=string;; c++) { // -> input character + if (((unsigned)(*c-'0'))<=9) continue; // '0' through '9' is good + if (*c=='\0') break; // most common non-digit + if (*c=='.') { + if (dotchar!=NULL) break; // not first '.' + dotchar=c; // record offset into decimal part + continue;} + if (c==string) { // first in string... + if (*c=='-') { // valid - sign + cfirst++; + num.sign=DECFLOAT_Sign; + continue;} + if (*c=='+') { // valid + sign + cfirst++; + continue;} + } + // *c is not a digit, terminator, or a valid +, -, or '.' + break; + } // c loop + + digits=(uInt)(c-cfirst); // digits (+1 if a dot) + + if (digits>0) { // had digits and/or dot + const char *clast=c-1; // note last coefficient char position + Int exp=0; // exponent accumulator + if (*c!='\0') { // something follows the coefficient + uInt edig; // unsigned work + // had some digits and more to come; expect E[+|-]nnn now + const char *firstexp; // exponent first non-zero + if (*c!='E' && *c!='e') break; + c++; // to (optional) sign + if (*c=='-' || *c=='+') c++; // step over sign (c=clast+2) + if (*c=='\0') break; // no digits! (e.g., '1.2E') + for (; *c=='0';) c++; // skip leading zeros [even last] + firstexp=c; // remember start [maybe '\0'] + // gather exponent digits + edig=(uInt)*c-(uInt)'0'; + if (edig<=9) { // [check not bad or terminator] + exp+=edig; // avoid initial X10 + c++; + for (;; c++) { + edig=(uInt)*c-(uInt)'0'; + if (edig>9) break; + exp=exp*10+edig; + } + } + // if not now on the '\0', *c must not be a digit + if (*c!='\0') break; + + // (this next test must be after the syntax checks) + // if definitely more than the possible digits for format then + // the exponent may have wrapped, so simply set it to a certain + // over/underflow value + if (c>firstexp+DECEMAXD) exp=DECEMAX*2; + if (*(clast+2)=='-') exp=-exp; // was negative + } // exponent part + + if (dotchar!=NULL) { // had a '.' + digits--; // remove from digits count + if (digits==0) break; // was dot alone: bad syntax + exp-=(Int)(clast-dotchar); // adjust exponent + // [the '.' can now be ignored] + } + num.exponent=exp; // exponent is good; store it + + // Here when whole string has been inspected and syntax is good + // cfirst->first digit or dot, clast->last digit or dot + error=0; // no error possible now + + // if the number of digits in the coefficient will fit in buffer + // then it can simply be converted to bcd8 and copied -- decFinalize + // will take care of leading zeros and rounding; the buffer is big + // enough for all canonical coefficients, including 0.00000nn... + ub=buffer; + if (digits<=(Int)(sizeof(buffer)-3)) { // [-3 allows by-4s copy] + c=cfirst; + if (dotchar!=NULL) { // a dot to worry about + if (*(c+1)=='.') { // common canonical case + *ub++=(uByte)(*c-'0'); // copy leading digit + c+=2; // prepare to handle rest + } + else for (; c<=clast;) { // '.' could be anywhere + // as usual, go by fours when safe; NB it has been asserted + // that a '.' does not have the same mask as a digit + if (c<=clast-3 // safe for four + && (UBTOUI(c)&0xf0f0f0f0)==CHARMASK) { // test four + UBFROMUI(ub, UBTOUI(c)&0x0f0f0f0f); // to BCD8 + ub+=4; + c+=4; + continue; + } + if (*c=='.') { // found the dot + c++; // step over it .. + break; // .. and handle the rest + } + *ub++=(uByte)(*c++-'0'); + } + } // had dot + // Now no dot; do this by fours (where safe) + for (; c<=clast-3; c+=4, ub+=4) UBFROMUI(ub, UBTOUI(c)&0x0f0f0f0f); + for (; c<=clast; c++, ub++) *ub=(uByte)(*c-'0'); + num.lsd=buffer+digits-1; // record new LSD + } // fits + + else { // too long for buffer + // [This is a rare and unusual case; arbitrary-length input] + // strip leading zeros [but leave final 0 if all 0's] + if (*cfirst=='.') cfirst++; // step past dot at start + if (*cfirst=='0') { // [cfirst always -> digit] + for (; cfirst LSD + for (; c<=clast; c++) { // inspect remaining chars + if (*c!='0') { // sticky bit needed + if (*c=='.') continue; // [ignore] + *ub=DECSTICKYTAB[*ub]; // update round-for-reround + break; // no need to look at more + } + } + num.lsd=ub; // record LSD + // adjust exponent for dropped digits + num.exponent+=digits-(Int)(ub-buffer+1); + } // too long for buffer + } // digits and/or dot + + else { // no digits or dot were found + // only Infinities and NaNs are allowed, here + if (*c=='\0') break; // nothing there is bad + buffer[0]=0; // default a coefficient of 0 + num.lsd=buffer; // .. + if (decBiStr(c, "infinity", "INFINITY") + || decBiStr(c, "inf", "INF")) num.exponent=DECFLOAT_Inf; + else { // should be a NaN + num.exponent=DECFLOAT_qNaN; // assume quiet NaN + if (*c=='s' || *c=='S') { // probably an sNaN + num.exponent=DECFLOAT_sNaN; // effect the 's' + c++; // and step over it + } + if (*c!='N' && *c!='n') break; // check caseless "NaN" + c++; + if (*c!='a' && *c!='A') break; // .. + c++; + if (*c!='N' && *c!='n') break; // .. + c++; + // now either nothing, or nnnn payload (no dots), expected + // -> start of integer, and skip leading 0s [including plain 0] + for (cfirst=c; *cfirst=='0';) cfirst++; + if (*cfirst!='\0') { // not empty or all-0, payload + // payload found; check all valid digits and copy to buffer as bcd8 + ub=buffer; + for (c=cfirst;; c++, ub++) { + if ((unsigned)(*c-'0')>9) break; // quit if not 0-9 + if (c-cfirst==DECPMAX-1) break; // too many digits + *ub=(uByte)(*c-'0'); // good bcd8 + } + if (*c!='\0') break; // not all digits, or too many + num.lsd=ub-1; // record new LSD + } + } // NaN or sNaN + error=0; // syntax is OK + } // digits=0 (special expected) + break; // drop out + } // [for(;;) once-loop] + + // decShowNum(&num, "fromStr"); + + if (error!=0) { + set->status|=error; + num.exponent=DECFLOAT_qNaN; // set up quiet NaN + num.sign=0; // .. with 0 sign + buffer[0]=0; // .. and coefficient + num.lsd=buffer; // .. + // decShowNum(&num, "oops"); + } + + // decShowNum(&num, "dffs"); + decFinalize(result, &num, set); // round, check, and lay out + // decFloatShow(result, "fromString"); + return result; + } // decFloatFromString + +/* ------------------------------------------------------------------ */ +/* decFloatFromWider -- conversion from next-wider format */ +/* */ +/* result is the decFloat format number which gets the result of */ +/* the conversion */ +/* wider is the decFloatWider format number which will be narrowed */ +/* set is the context */ +/* returns result */ +/* */ +/* Narrowing can cause rounding, overflow, etc., but not Invalid */ +/* operation (sNaNs are copied and do not signal). */ +/* ------------------------------------------------------------------ */ +// narrow-to is not possible for decQuad format numbers; simply omit +#if !QUAD +decFloat * decFloatFromWider(decFloat *result, const decFloatWider *wider, + decContext *set) { + bcdnum num; // collects data for finishing + uByte bcdar[DECWPMAX]; // room for wider coefficient + uInt widerhi=DFWWORD(wider, 0); // top word + Int exp; + + GETWCOEFF(wider, bcdar); + + num.msd=bcdar; // MSD is here always + num.lsd=bcdar+DECWPMAX-1; // LSD is here always + num.sign=widerhi&0x80000000; // extract sign [DECFLOAT_Sign=Neg] + + // decode the wider combination field to exponent + exp=DECCOMBWEXP[widerhi>>26]; // decode from wider combination field + // if it is a special there's nothing to do unless sNaN; if it's + // finite then add the (wider) exponent continuation and unbias + if (EXPISSPECIAL(exp)) exp=widerhi&0x7e000000; // include sNaN selector + else exp+=GETWECON(wider)-DECWBIAS; + num.exponent=exp; + + // decShowNum(&num, "dffw"); + return decFinalize(result, &num, set);// round, check, and lay out + } // decFloatFromWider +#endif + +/* ------------------------------------------------------------------ */ +/* decFloatGetCoefficient -- get coefficient as BCD8 */ +/* */ +/* df is the decFloat from which to extract the coefficient */ +/* bcdar is where DECPMAX bytes will be written, one BCD digit in */ +/* each byte (BCD8 encoding); if df is a NaN the first byte will */ +/* be zero, and if it is infinite they will all be zero */ +/* returns the sign of the coefficient (DECFLOAT_Sign if negative, */ +/* 0 otherwise) */ +/* */ +/* No error is possible, and no status will be set. If df is a */ +/* special value the array is set to zeros (for Infinity) or to the */ +/* payload of a qNaN or sNaN. */ +/* ------------------------------------------------------------------ */ +Int decFloatGetCoefficient(const decFloat *df, uByte *bcdar) { + if (DFISINF(df)) memset(bcdar, 0, DECPMAX); + else { + GETCOEFF(df, bcdar); // use macro + if (DFISNAN(df)) bcdar[0]=0; // MSD needs correcting + } + return GETSIGN(df); + } // decFloatGetCoefficient + +/* ------------------------------------------------------------------ */ +/* decFloatGetExponent -- get unbiased exponent */ +/* */ +/* df is the decFloat from which to extract the exponent */ +/* returns the exponent, q. */ +/* */ +/* No error is possible, and no status will be set. If df is a */ +/* special value the first seven bits of the decFloat are returned, */ +/* left adjusted and with the first (sign) bit set to 0 (followed by */ +/* 25 0 bits). e.g., -sNaN would return 0x7e000000 (DECFLOAT_sNaN). */ +/* ------------------------------------------------------------------ */ +Int decFloatGetExponent(const decFloat *df) { + if (DFISSPECIAL(df)) return DFWORD(df, 0)&0x7e000000; + return GETEXPUN(df); + } // decFloatGetExponent + +/* ------------------------------------------------------------------ */ +/* decFloatSetCoefficient -- set coefficient from BCD8 */ +/* */ +/* df is the target decFloat (and source of exponent/special value) */ +/* bcdar holds DECPMAX digits to set the coefficient from, one */ +/* digit in each byte (BCD8 encoding); the first (MSD) is ignored */ +/* if df is a NaN; all are ignored if df is infinite. */ +/* sig is DECFLOAT_Sign to set the sign bit, 0 otherwise */ +/* returns df, which will be canonical */ +/* */ +/* No error is possible, and no status will be set. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatSetCoefficient(decFloat *df, const uByte *bcdar, + Int sig) { + uInt exp; // for exponent + uByte bcdzero[DECPMAX]; // for infinities + + // Exponent/special code is extracted from df + if (DFISSPECIAL(df)) { + exp=DFWORD(df, 0)&0x7e000000; + if (DFISINF(df)) { + memset(bcdzero, 0, DECPMAX); + return decFloatFromBCD(df, exp, bcdzero, sig); + } + } + else exp=GETEXPUN(df); + return decFloatFromBCD(df, exp, bcdar, sig); + } // decFloatSetCoefficient + +/* ------------------------------------------------------------------ */ +/* decFloatSetExponent -- set exponent or special value */ +/* */ +/* df is the target decFloat (and source of coefficient/payload) */ +/* set is the context for reporting status */ +/* exp is the unbiased exponent, q, or a special value in the form */ +/* returned by decFloatGetExponent */ +/* returns df, which will be canonical */ +/* */ +/* No error is possible, but Overflow or Underflow might occur. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatSetExponent(decFloat *df, decContext *set, Int exp) { + uByte bcdcopy[DECPMAX]; // for coefficient + bcdnum num; // work + num.exponent=exp; + num.sign=decFloatGetCoefficient(df, bcdcopy); // extract coefficient + if (DFISSPECIAL(df)) { // MSD or more needs correcting + if (DFISINF(df)) memset(bcdcopy, 0, DECPMAX); + bcdcopy[0]=0; + } + num.msd=bcdcopy; + num.lsd=bcdcopy+DECPMAX-1; + return decFinalize(df, &num, set); + } // decFloatSetExponent + +/* ------------------------------------------------------------------ */ +/* decFloatRadix -- returns the base (10) */ +/* */ +/* df is any decFloat of this format */ +/* ------------------------------------------------------------------ */ +uInt decFloatRadix(const decFloat *df) { + if (df) return 10; // to placate compiler + return 10; + } // decFloatRadix + +/* The following function is not available if DECPRINT=0 */ +#if DECPRINT +/* ------------------------------------------------------------------ */ +/* decFloatShow -- printf a decFloat in hexadecimal and decimal */ +/* df is the decFloat to show */ +/* tag is a tag string displayed with the number */ +/* */ +/* This is a debug aid; the precise format of the string may change. */ +/* ------------------------------------------------------------------ */ +void decFloatShow(const decFloat *df, const char *tag) { + char hexbuf[DECBYTES*2+DECBYTES/4+1]; // NB blank after every fourth + char buff[DECSTRING]; // for value in decimal + Int i, j=0; + + for (i=0; ibytes[DECBYTES-1-i]); + #else + sprintf(&hexbuf[j], "%02x", df->bytes[i]); + #endif + j+=2; + // the next line adds blank (and terminator) after final pair, too + if ((i+1)%4==0) {strcpy(&hexbuf[j], " "); j++;} + } + decFloatToString(df, buff); + printf(">%s> %s [big-endian] %s\n", tag, hexbuf, buff); + return; + } // decFloatShow +#endif + +/* ------------------------------------------------------------------ */ +/* decFloatToBCD -- get sign, exponent, and BCD8 from a decFloat */ +/* */ +/* df is the source decFloat */ +/* exp will be set to the unbiased exponent, q, or to a special */ +/* value in the form returned by decFloatGetExponent */ +/* bcdar is where DECPMAX bytes will be written, one BCD digit in */ +/* each byte (BCD8 encoding); if df is a NaN the first byte will */ +/* be zero, and if it is infinite they will all be zero */ +/* returns the sign of the coefficient (DECFLOAT_Sign if negative, */ +/* 0 otherwise) */ +/* */ +/* No error is possible, and no status will be set. */ +/* ------------------------------------------------------------------ */ +Int decFloatToBCD(const decFloat *df, Int *exp, uByte *bcdar) { + if (DFISINF(df)) { + memset(bcdar, 0, DECPMAX); + *exp=DFWORD(df, 0)&0x7e000000; + } + else { + GETCOEFF(df, bcdar); // use macro + if (DFISNAN(df)) { + bcdar[0]=0; // MSD needs correcting + *exp=DFWORD(df, 0)&0x7e000000; + } + else { // finite + *exp=GETEXPUN(df); + } + } + return GETSIGN(df); + } // decFloatToBCD + +/* ------------------------------------------------------------------ */ +/* decFloatToEngString -- conversion to numeric string, engineering */ +/* */ +/* df is the decFloat format number to convert */ +/* string is the string where the result will be laid out */ +/* */ +/* string must be at least DECPMAX+9 characters (the worst case is */ +/* "-0.00000nnn...nnn\0", which is as long as the exponent form when */ +/* DECEMAXD<=4); this condition is asserted above */ +/* */ +/* No error is possible, and no status will be set */ +/* ------------------------------------------------------------------ */ +char * decFloatToEngString(const decFloat *df, char *string){ + uInt msd; // coefficient MSD + Int exp; // exponent top two bits or full + uInt comb; // combination field + char *cstart; // coefficient start + char *c; // output pointer in string + char *s, *t; // .. (source, target) + Int pre, e; // work + const uByte *u; // .. + uInt uiwork; // for macros [one compiler needs + // volatile here to avoid bug, but + // that doubles execution time] + + // Source words; macro handles endianness + uInt sourhi=DFWORD(df, 0); // word with sign + #if DECPMAX==16 + uInt sourlo=DFWORD(df, 1); + #elif DECPMAX==34 + uInt sourmh=DFWORD(df, 1); + uInt sourml=DFWORD(df, 2); + uInt sourlo=DFWORD(df, 3); + #endif + + c=string; // where result will go + if (((Int)sourhi)<0) *c++='-'; // handle sign + comb=sourhi>>26; // sign+combination field + msd=DECCOMBMSD[comb]; // decode the combination field + exp=DECCOMBEXP[comb]; // .. + + if (EXPISSPECIAL(exp)) { // special + if (exp==DECFLOAT_Inf) { // infinity + strcpy(c, "Inf"); + strcpy(c+3, "inity"); + return string; // easy + } + if (sourhi&0x02000000) *c++='s'; // sNaN + strcpy(c, "NaN"); // complete word + c+=3; // step past + // quick exit if the payload is zero + #if DECPMAX==7 + if ((sourhi&0x000fffff)==0) return string; + #elif DECPMAX==16 + if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; + #elif DECPMAX==34 + if (sourlo==0 && sourml==0 && sourmh==0 + && (sourhi&0x00003fff)==0) return string; + #endif + // otherwise drop through to add integer; set correct exp etc. + exp=0; msd=0; // setup for following code + } + else { // complete exponent; top two bits are in place + exp+=GETECON(df)-DECBIAS; // .. + continuation and unbias + } + + /* convert the digits of the significand to characters */ + cstart=c; // save start of coefficient + if (msd) *c++=(char)('0'+(char)msd); // non-zero most significant digit + + // Decode the declets. After extracting each declet, it is + // decoded to a 4-uByte sequence by table lookup; the four uBytes + // are the three encoded BCD8 digits followed by a 1-byte length + // (significant digits, except that 000 has length 0). This allows + // us to left-align the first declet with non-zero content, then + // the remaining ones are full 3-char length. Fixed-length copies + // are used because variable-length memcpy causes a subroutine call + // in at least two compilers. (The copies are length 4 for speed + // and are safe because the last item in the array is of length + // three and has the length byte following.) + #define dpd2char(dpdin) u=&DPD2BCD8[((dpdin)&0x3ff)*4]; \ + if (c!=cstart) {UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3;} \ + else if (*(u+3)) { \ + UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3);} + + #if DECPMAX==7 + dpd2char(sourhi>>10); // declet 1 + dpd2char(sourhi); // declet 2 + + #elif DECPMAX==16 + dpd2char(sourhi>>8); // declet 1 + dpd2char((sourhi<<2) | (sourlo>>30)); // declet 2 + dpd2char(sourlo>>20); // declet 3 + dpd2char(sourlo>>10); // declet 4 + dpd2char(sourlo); // declet 5 + + #elif DECPMAX==34 + dpd2char(sourhi>>4); // declet 1 + dpd2char((sourhi<<6) | (sourmh>>26)); // declet 2 + dpd2char(sourmh>>16); // declet 3 + dpd2char(sourmh>>6); // declet 4 + dpd2char((sourmh<<4) | (sourml>>28)); // declet 5 + dpd2char(sourml>>18); // declet 6 + dpd2char(sourml>>8); // declet 7 + dpd2char((sourml<<2) | (sourlo>>30)); // declet 8 + dpd2char(sourlo>>20); // declet 9 + dpd2char(sourlo>>10); // declet 10 + dpd2char(sourlo); // declet 11 + #endif + + if (c==cstart) *c++='0'; // all zeros, empty -- make "0" + + if (exp==0) { // integer or NaN case -- easy + *c='\0'; // terminate + return string; + } + /* non-0 exponent */ + + e=0; // assume no E + pre=(Int)(c-cstart)+exp; // length+exp [c->LSD+1] + // [here, pre-exp is the digits count (==1 for zero)] + + if (exp>0 || pre<-5) { // need exponential form + e=pre-1; // calculate E value + pre=1; // assume one digit before '.' + if (e!=0) { // engineering: may need to adjust + Int adj; // adjustment + // The C remainder operator is undefined for negative numbers, so + // a positive remainder calculation must be used here + if (e<0) { + adj=(-e)%3; + if (adj!=0) adj=3-adj; + } + else { // e>0 + adj=e%3; + } + e=e-adj; + // if dealing with zero still produce an exponent which is a + // multiple of three, as expected, but there will only be the + // one zero before the E, still. Otherwise note the padding. + if (!DFISZERO(df)) pre+=adj; + else { // is zero + if (adj!=0) { // 0.00Esnn needed + e=e+3; + pre=-(2-adj); + } + } // zero + } // engineering adjustment + } // exponential form + // printf("e=%ld pre=%ld exp=%ld\n", (LI)e, (LI)pre, (LI)exp); + + /* modify the coefficient, adding 0s, '.', and E+nn as needed */ + if (pre>0) { // ddd.ddd (plain), perhaps with E + // or dd00 padding for engineering + char *dotat=cstart+pre; + if (dotat=dotat; s-=4, t-=4) UBFROMUI(t, UBTOUI(s)); + *dotat='.'; + c++; // length increased by one + } // need dot? + else for (; c0 + else { + /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (may have + E, but only for 0.00E+3 kind of case -- with plenty of spare + space in this case */ + pre=-pre+2; // gap width, including "0." + t=cstart+ROUNDDOWN4(c-cstart)+pre; // preferred first target point + // backoff if too far to the right + if (t>string+DECSTRING-5) t=string+DECSTRING-5; // adjust to fit + // now shift the entire coefficient to the right, being careful not + // to access to the left of string [cannot use memcpy] + for (s=t-pre; s>=string; s-=4, t-=4) UBFROMUI(t, UBTOUI(s)); + // for Quads and Singles there may be a character or two left... + s+=3; // where next would come from + for(; s>=cstart; s--, t--) *(t+3)=*(s); + // now have fill 0. through 0.00000; use overlaps to avoid tests + if (pre>=4) { + memcpy(cstart+pre-4, "0000", 4); + memcpy(cstart, "0.00", 4); + } + else { // 2 or 3 + *(cstart+pre-1)='0'; + memcpy(cstart, "0.", 2); + } + c+=pre; // to end + } + + // finally add the E-part, if needed; it will never be 0, and has + // a maximum length of 3 or 4 digits (asserted above) + if (e!=0) { + memcpy(c, "E+", 2); // starts with E, assume + + c++; + if (e<0) { + *c='-'; // oops, need '-' + e=-e; // uInt, please + } + c++; + // Three-character exponents are easy; 4-character a little trickier + #if DECEMAXD<=3 + u=&BIN2BCD8[e*4]; // -> 3 digits + length byte + // copy fixed 4 characters [is safe], starting at non-zero + // and with character mask to convert BCD to char + UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); + c+=*(u+3); // bump pointer appropriately + #elif DECEMAXD==4 + if (e<1000) { // 3 (or fewer) digits case + u=&BIN2BCD8[e*4]; // -> 3 digits + length byte + UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); // [as above] + c+=*(u+3); // bump pointer appropriately + } + else { // 4-digits + Int thou=((e>>3)*1049)>>17; // e/1000 + Int rem=e-(1000*thou); // e%1000 + *c++=(char)('0'+(char)thou); // the thousands digit + u=&BIN2BCD8[rem*4]; // -> 3 digits + length byte + UBFROMUI(c, UBTOUI(u)|CHARMASK);// copy fixed 3+1 characters [is safe] + c+=3; // bump pointer, always 3 digits + } + #endif + } + *c='\0'; // terminate + //printf("res %s\n", string); + return string; + } // decFloatToEngString + +/* ------------------------------------------------------------------ */ +/* decFloatToPacked -- convert decFloat to Packed decimal + exponent */ +/* */ +/* df is the source decFloat */ +/* exp will be set to the unbiased exponent, q, or to a special */ +/* value in the form returned by decFloatGetExponent */ +/* packed is where DECPMAX nibbles will be written with the sign as */ +/* final nibble (0x0c for +, 0x0d for -); a NaN has a first nibble */ +/* of zero, and an infinity is all zeros. decDouble and decQuad */ +/* have a additional leading zero nibble, leading to result */ +/* lengths of 4, 9, and 18 bytes. */ +/* returns the sign of the coefficient (DECFLOAT_Sign if negative, */ +/* 0 otherwise) */ +/* */ +/* No error is possible, and no status will be set. */ +/* ------------------------------------------------------------------ */ +Int decFloatToPacked(const decFloat *df, Int *exp, uByte *packed) { + uByte bcdar[DECPMAX+2]; // work buffer + uByte *ip=bcdar, *op=packed; // work pointers + if (DFISINF(df)) { + memset(bcdar, 0, DECPMAX+2); + *exp=DECFLOAT_Inf; + } + else { + GETCOEFF(df, bcdar+1); // use macro + if (DFISNAN(df)) { + bcdar[1]=0; // MSD needs clearing + *exp=DFWORD(df, 0)&0x7e000000; + } + else { // finite + *exp=GETEXPUN(df); + } + } + // now pack; coefficient currently at bcdar+1 + #if SINGLE + ip++; // ignore first byte + #else + *ip=0; // need leading zero + #endif + // set final byte to Packed BCD sign value + bcdar[DECPMAX+1]=(DFISSIGNED(df) ? DECPMINUS : DECPPLUS); + // pack an even number of bytes... + for (; op>26; // sign+combination field + msd=DECCOMBMSD[comb]; // decode the combination field + exp=DECCOMBEXP[comb]; // .. + + if (!EXPISSPECIAL(exp)) { // finite + // complete exponent; top two bits are in place + exp+=GETECON(df)-DECBIAS; // .. + continuation and unbias + } + else { // IS special + if (exp==DECFLOAT_Inf) { // infinity + strcpy(c, "Infinity"); + return string; // easy + } + if (sourhi&0x02000000) *c++='s'; // sNaN + strcpy(c, "NaN"); // complete word + c+=3; // step past + // quick exit if the payload is zero + #if DECPMAX==7 + if ((sourhi&0x000fffff)==0) return string; + #elif DECPMAX==16 + if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; + #elif DECPMAX==34 + if (sourlo==0 && sourml==0 && sourmh==0 + && (sourhi&0x00003fff)==0) return string; + #endif + // otherwise drop through to add integer; set correct exp etc. + exp=0; msd=0; // setup for following code + } + + /* convert the digits of the significand to characters */ + cstart=c; // save start of coefficient + if (msd) *c++=(char)('0'+(char)msd); // non-zero most significant digit + + // Decode the declets. After extracting each declet, it is + // decoded to a 4-uByte sequence by table lookup; the four uBytes + // are the three encoded BCD8 digits followed by a 1-byte length + // (significant digits, except that 000 has length 0). This allows + // us to left-align the first declet with non-zero content, then + // the remaining ones are full 3-char length. Fixed-length copies + // are used because variable-length memcpy causes a subroutine call + // in at least two compilers. (The copies are length 4 for speed + // and are safe because the last item in the array is of length + // three and has the length byte following.) + #define dpd2char(dpdin) u=&DPD2BCD8[((dpdin)&0x3ff)*4]; \ + if (c!=cstart) {UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3;} \ + else if (*(u+3)) { \ + UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3);} + + #if DECPMAX==7 + dpd2char(sourhi>>10); // declet 1 + dpd2char(sourhi); // declet 2 + + #elif DECPMAX==16 + dpd2char(sourhi>>8); // declet 1 + dpd2char((sourhi<<2) | (sourlo>>30)); // declet 2 + dpd2char(sourlo>>20); // declet 3 + dpd2char(sourlo>>10); // declet 4 + dpd2char(sourlo); // declet 5 + + #elif DECPMAX==34 + dpd2char(sourhi>>4); // declet 1 + dpd2char((sourhi<<6) | (sourmh>>26)); // declet 2 + dpd2char(sourmh>>16); // declet 3 + dpd2char(sourmh>>6); // declet 4 + dpd2char((sourmh<<4) | (sourml>>28)); // declet 5 + dpd2char(sourml>>18); // declet 6 + dpd2char(sourml>>8); // declet 7 + dpd2char((sourml<<2) | (sourlo>>30)); // declet 8 + dpd2char(sourlo>>20); // declet 9 + dpd2char(sourlo>>10); // declet 10 + dpd2char(sourlo); // declet 11 + #endif + + if (c==cstart) *c++='0'; // all zeros, empty -- make "0" + + //[This fast path is valid but adds 3-5 cycles to worst case length] + //if (exp==0) { // integer or NaN case -- easy + // *c='\0'; // terminate + // return string; + // } + + e=0; // assume no E + pre=(Int)(c-cstart)+exp; // length+exp [c->LSD+1] + // [here, pre-exp is the digits count (==1 for zero)] + + if (exp>0 || pre<-5) { // need exponential form + e=pre-1; // calculate E value + pre=1; // assume one digit before '.' + } // exponential form + + /* modify the coefficient, adding 0s, '.', and E+nn as needed */ + if (pre>0) { // ddd.ddd (plain), perhaps with E + char *dotat=cstart+pre; + if (dotat=dotat; s-=4, t-=4) UBFROMUI(t, UBTOUI(s)); + *dotat='.'; + c++; // length increased by one + } // need dot? + + // finally add the E-part, if needed; it will never be 0, and has + // a maximum length of 3 or 4 digits (asserted above) + if (e!=0) { + memcpy(c, "E+", 2); // starts with E, assume + + c++; + if (e<0) { + *c='-'; // oops, need '-' + e=-e; // uInt, please + } + c++; + // Three-character exponents are easy; 4-character a little trickier + #if DECEMAXD<=3 + u=&BIN2BCD8[e*4]; // -> 3 digits + length byte + // copy fixed 4 characters [is safe], starting at non-zero + // and with character mask to convert BCD to char + UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); + c+=*(u+3); // bump pointer appropriately + #elif DECEMAXD==4 + if (e<1000) { // 3 (or fewer) digits case + u=&BIN2BCD8[e*4]; // -> 3 digits + length byte + UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); // [as above] + c+=*(u+3); // bump pointer appropriately + } + else { // 4-digits + Int thou=((e>>3)*1049)>>17; // e/1000 + Int rem=e-(1000*thou); // e%1000 + *c++=(char)('0'+(char)thou); // the thousands digit + u=&BIN2BCD8[rem*4]; // -> 3 digits + length byte + UBFROMUI(c, UBTOUI(u)|CHARMASK); // copy fixed 3+1 characters [is safe] + c+=3; // bump pointer, always 3 digits + } + #endif + } + *c='\0'; // add terminator + //printf("res %s\n", string); + return string; + } // pre>0 + + /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ + // Surprisingly, this is close to being the worst-case path, so the + // shift is done by fours; this is a little tricky because the + // rightmost character to be written must not be beyond where the + // rightmost terminator could be -- so backoff to not touch + // terminator position if need be (this can make exact alignments + // for full Doubles, but in some cases needs care not to access too + // far to the left) + + pre=-pre+2; // gap width, including "0." + t=cstart+ROUNDDOWN4(c-cstart)+pre; // preferred first target point + // backoff if too far to the right + if (t>string+DECSTRING-5) t=string+DECSTRING-5; // adjust to fit + // now shift the entire coefficient to the right, being careful not + // to access to the left of string [cannot use memcpy] + for (s=t-pre; s>=string; s-=4, t-=4) UBFROMUI(t, UBTOUI(s)); + // for Quads and Singles there may be a character or two left... + s+=3; // where next would come from + for(; s>=cstart; s--, t--) *(t+3)=*(s); + // now have fill 0. through 0.00000; use overlaps to avoid tests + if (pre>=4) { + memcpy(cstart+pre-4, "0000", 4); + memcpy(cstart, "0.00", 4); + } + else { // 2 or 3 + *(cstart+pre-1)='0'; + memcpy(cstart, "0.", 2); + } + *(c+pre)='\0'; // terminate + return string; + } // decFloatToString + +/* ------------------------------------------------------------------ */ +/* decFloatToWider -- conversion to next-wider format */ +/* */ +/* source is the decFloat format number which gets the result of */ +/* the conversion */ +/* wider is the decFloatWider format number which will be narrowed */ +/* returns wider */ +/* */ +/* Widening is always exact; no status is set (sNaNs are copied and */ +/* do not signal). The result will be canonical if the source is, */ +/* and may or may not be if the source is not. */ +/* ------------------------------------------------------------------ */ +// widening is not possible for decQuad format numbers; simply omit +#if !QUAD +decFloatWider * decFloatToWider(const decFloat *source, decFloatWider *wider) { + uInt msd; + + /* Construct and copy the sign word */ + if (DFISSPECIAL(source)) { + // copy sign, combination, and first bit of exponent (sNaN selector) + DFWWORD(wider, 0)=DFWORD(source, 0)&0xfe000000; + msd=0; + } + else { // is finite number + uInt exp=GETEXPUN(source)+DECWBIAS; // get unbiased exponent and rebias + uInt code=(exp>>DECWECONL)<<29; // set two bits of exp [msd=0] + code|=(exp<<(32-6-DECWECONL)) & 0x03ffffff; // add exponent continuation + code|=DFWORD(source, 0)&0x80000000; // add sign + DFWWORD(wider, 0)=code; // .. and place top word in wider + msd=GETMSD(source); // get source coefficient MSD [0-9] + } + /* Copy the coefficient and clear any 'unused' words to left */ + #if SINGLE + DFWWORD(wider, 1)=(DFWORD(source, 0)&0x000fffff)|(msd<<20); + #elif DOUBLE + DFWWORD(wider, 2)=(DFWORD(source, 0)&0x0003ffff)|(msd<<18); + DFWWORD(wider, 3)=DFWORD(source, 1); + DFWWORD(wider, 1)=0; + #endif + return wider; + } // decFloatToWider +#endif + +/* ------------------------------------------------------------------ */ +/* decFloatVersion -- return package version string */ +/* */ +/* returns a constant string describing this package */ +/* ------------------------------------------------------------------ */ +const char *decFloatVersion(void) { + return DECVERSION; + } // decFloatVersion + +/* ------------------------------------------------------------------ */ +/* decFloatZero -- set to canonical (integer) zero */ +/* */ +/* df is the decFloat format number to integer +0 (q=0, c=+0) */ +/* returns df */ +/* */ +/* No error is possible, and no status can be set. */ +/* ------------------------------------------------------------------ */ +decFloat * decFloatZero(decFloat *df){ + DFWORD(df, 0)=ZEROWORD; // set appropriate top word + #if DOUBLE || QUAD + DFWORD(df, 1)=0; + #if QUAD + DFWORD(df, 2)=0; + DFWORD(df, 3)=0; + #endif + #endif + // decFloatShow(df, "zero"); + return df; + } // decFloatZero + +/* ------------------------------------------------------------------ */ +/* Private generic function (not format-specific) for development use */ +/* ------------------------------------------------------------------ */ +// This is included once only, for all to use +#if QUAD && (DECCHECK || DECTRACE) + /* ---------------------------------------------------------------- */ + /* decShowNum -- display bcd8 number in debug form */ + /* */ + /* num is the bcdnum to display */ + /* tag is a string to label the display */ + /* ---------------------------------------------------------------- */ + void decShowNum(const bcdnum *num, const char *tag) { + const char *csign="+"; // sign character + uByte *ub; // work + uInt uiwork; // for macros + if (num->sign==DECFLOAT_Sign) csign="-"; + + printf(">%s> ", tag); + if (num->exponent==DECFLOAT_Inf) printf("%sInfinity", csign); + else if (num->exponent==DECFLOAT_qNaN) printf("%sqNaN", csign); + else if (num->exponent==DECFLOAT_sNaN) printf("%ssNaN", csign); + else { // finite + char qbuf[10]; // for right-aligned q + char *c; // work + const uByte *u; // .. + Int e=num->exponent; // .. exponent + strcpy(qbuf, "q="); + c=&qbuf[2]; // where exponent will go + // lay out the exponent + if (e<0) { + *c++='-'; // add '-' + e=-e; // uInt, please + } + #if DECEMAXD>4 + #error Exponent form is too long for ShowNum to lay out + #endif + if (e==0) *c++='0'; // 0-length case + else if (e<1000) { // 3 (or fewer) digits case + u=&BIN2BCD8[e*4]; // -> 3 digits + length byte + UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); // [as above] + c+=*(u+3); // bump pointer appropriately + } + else { // 4-digits + Int thou=((e>>3)*1049)>>17; // e/1000 + Int rem=e-(1000*thou); // e%1000 + *c++=(char)('0'+(char)thou); // the thousands digit + u=&BIN2BCD8[rem*4]; // -> 3 digits + length byte + UBFROMUI(c, UBTOUI(u)|CHARMASK); // copy fixed 3+1 characters [is safe] + c+=3; // bump pointer, always 3 digits + } + *c='\0'; // add terminator + printf("%7s c=%s", qbuf, csign); + } + + if (!EXPISSPECIAL(num->exponent) || num->msd!=num->lsd || *num->lsd!=0) { + for (ub=num->msd; ub<=num->lsd; ub++) { // coefficient... + printf("%1x", *ub); + if ((num->lsd-ub)%3==0 && ub!=num->lsd) printf(" "); // 4-space + } + } + printf("\n"); + } // decShowNum +#endif diff --git a/extern/decNumber/decContext.c b/extern/decNumber/decContext.c new file mode 100644 index 0000000000..6db29be034 --- /dev/null +++ b/extern/decNumber/decContext.c @@ -0,0 +1,437 @@ +/* ------------------------------------------------------------------ */ +/* Decimal Context module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2009. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises the routines for handling arithmetic */ +/* context structures. */ +/* ------------------------------------------------------------------ */ + +#include // for strcmp +#include // for printf if DECCHECK +#include "decContext.h" // context and base types +#include "decNumberLocal.h" // decNumber local types, etc. + +/* compile-time endian tester [assumes sizeof(Int)>1] */ +static const Int mfcone=1; // constant 1 +static const Flag *mfctop=(const Flag *)&mfcone; // -> top byte +#define LITEND *mfctop // named flag; 1=little-endian + +/* ------------------------------------------------------------------ */ +/* round-for-reround digits */ +/* ------------------------------------------------------------------ */ +const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */ + +/* ------------------------------------------------------------------ */ +/* Powers of ten (powers[n]==10**n, 0<=n<=9) */ +/* ------------------------------------------------------------------ */ +const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000, + 10000000, 100000000, 1000000000}; + +/* ------------------------------------------------------------------ */ +/* decContextClearStatus -- clear bits in current status */ +/* */ +/* context is the context structure to be queried */ +/* mask indicates the bits to be cleared (the status bit that */ +/* corresponds to each 1 bit in the mask is cleared) */ +/* returns context */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decContext *decContextClearStatus(decContext *context, uInt mask) { + context->status&=~mask; + return context; + } // decContextClearStatus + +/* ------------------------------------------------------------------ */ +/* decContextDefault -- initialize a context structure */ +/* */ +/* context is the structure to be initialized */ +/* kind selects the required set of default values, one of: */ +/* DEC_INIT_BASE -- select ANSI X3-274 defaults */ +/* DEC_INIT_DECIMAL32 -- select IEEE 754 defaults, 32-bit */ +/* DEC_INIT_DECIMAL64 -- select IEEE 754 defaults, 64-bit */ +/* DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit */ +/* For any other value a valid context is returned, but with */ +/* Invalid_operation set in the status field. */ +/* returns a context structure with the appropriate initial values. */ +/* ------------------------------------------------------------------ */ +decContext * decContextDefault(decContext *context, Int kind) { + // set defaults... + context->digits=9; // 9 digits + context->emax=DEC_MAX_EMAX; // 9-digit exponents + context->emin=DEC_MIN_EMIN; // .. balanced + context->round=DEC_ROUND_HALF_UP; // 0.5 rises + context->traps=DEC_Errors; // all but informational + context->status=0; // cleared + context->clamp=0; // no clamping + #if DECSUBSET + context->extended=0; // cleared + #endif + switch (kind) { + case DEC_INIT_BASE: + // [use defaults] + break; + case DEC_INIT_DECIMAL32: + context->digits=7; // digits + context->emax=96; // Emax + context->emin=-95; // Emin + context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even + context->traps=0; // no traps set + context->clamp=1; // clamp exponents + #if DECSUBSET + context->extended=1; // set + #endif + break; + case DEC_INIT_DECIMAL64: + context->digits=16; // digits + context->emax=384; // Emax + context->emin=-383; // Emin + context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even + context->traps=0; // no traps set + context->clamp=1; // clamp exponents + #if DECSUBSET + context->extended=1; // set + #endif + break; + case DEC_INIT_DECIMAL128: + context->digits=34; // digits + context->emax=6144; // Emax + context->emin=-6143; // Emin + context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even + context->traps=0; // no traps set + context->clamp=1; // clamp exponents + #if DECSUBSET + context->extended=1; // set + #endif + break; + + default: // invalid Kind + // use defaults, and .. + decContextSetStatus(context, DEC_Invalid_operation); // trap + } + + return context;} // decContextDefault + +/* ------------------------------------------------------------------ */ +/* decContextGetRounding -- return current rounding mode */ +/* */ +/* context is the context structure to be queried */ +/* returns the rounding mode */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +enum rounding decContextGetRounding(decContext *context) { + return context->round; + } // decContextGetRounding + +/* ------------------------------------------------------------------ */ +/* decContextGetStatus -- return current status */ +/* */ +/* context is the context structure to be queried */ +/* returns status */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +uInt decContextGetStatus(decContext *context) { + return context->status; + } // decContextGetStatus + +/* ------------------------------------------------------------------ */ +/* decContextRestoreStatus -- restore bits in current status */ +/* */ +/* context is the context structure to be updated */ +/* newstatus is the source for the bits to be restored */ +/* mask indicates the bits to be restored (the status bit that */ +/* corresponds to each 1 bit in the mask is set to the value of */ +/* the correspnding bit in newstatus) */ +/* returns context */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decContext *decContextRestoreStatus(decContext *context, + uInt newstatus, uInt mask) { + context->status&=~mask; // clear the selected bits + context->status|=(mask&newstatus); // or in the new bits + return context; + } // decContextRestoreStatus + +/* ------------------------------------------------------------------ */ +/* decContextSaveStatus -- save bits in current status */ +/* */ +/* context is the context structure to be queried */ +/* mask indicates the bits to be saved (the status bits that */ +/* correspond to each 1 bit in the mask are saved) */ +/* returns the AND of the mask and the current status */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +uInt decContextSaveStatus(decContext *context, uInt mask) { + return context->status&mask; + } // decContextSaveStatus + +/* ------------------------------------------------------------------ */ +/* decContextSetRounding -- set current rounding mode */ +/* */ +/* context is the context structure to be updated */ +/* newround is the value which will replace the current mode */ +/* returns context */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decContext *decContextSetRounding(decContext *context, + enum rounding newround) { + context->round=newround; + return context; + } // decContextSetRounding + +/* ------------------------------------------------------------------ */ +/* decContextSetStatus -- set status and raise trap if appropriate */ +/* */ +/* context is the context structure to be updated */ +/* status is the DEC_ exception code */ +/* returns the context structure */ +/* */ +/* Control may never return from this routine, if there is a signal */ +/* handler and it takes a long jump. */ +/* ------------------------------------------------------------------ */ +decContext * decContextSetStatus(decContext *context, uInt status) { + context->status|=status; + if (status & context->traps) raise(SIGFPE); + return context;} // decContextSetStatus + +/* ------------------------------------------------------------------ */ +/* decContextSetStatusFromString -- set status from a string + trap */ +/* */ +/* context is the context structure to be updated */ +/* string is a string exactly equal to one that might be returned */ +/* by decContextStatusToString */ +/* */ +/* The status bit corresponding to the string is set, and a trap */ +/* is raised if appropriate. */ +/* */ +/* returns the context structure, unless the string is equal to */ +/* DEC_Condition_MU or is not recognized. In these cases NULL is */ +/* returned. */ +/* ------------------------------------------------------------------ */ +decContext * decContextSetStatusFromString(decContext *context, + const char *string) { + if (strcmp(string, DEC_Condition_CS)==0) + return decContextSetStatus(context, DEC_Conversion_syntax); + if (strcmp(string, DEC_Condition_DZ)==0) + return decContextSetStatus(context, DEC_Division_by_zero); + if (strcmp(string, DEC_Condition_DI)==0) + return decContextSetStatus(context, DEC_Division_impossible); + if (strcmp(string, DEC_Condition_DU)==0) + return decContextSetStatus(context, DEC_Division_undefined); + if (strcmp(string, DEC_Condition_IE)==0) + return decContextSetStatus(context, DEC_Inexact); + if (strcmp(string, DEC_Condition_IS)==0) + return decContextSetStatus(context, DEC_Insufficient_storage); + if (strcmp(string, DEC_Condition_IC)==0) + return decContextSetStatus(context, DEC_Invalid_context); + if (strcmp(string, DEC_Condition_IO)==0) + return decContextSetStatus(context, DEC_Invalid_operation); + #if DECSUBSET + if (strcmp(string, DEC_Condition_LD)==0) + return decContextSetStatus(context, DEC_Lost_digits); + #endif + if (strcmp(string, DEC_Condition_OV)==0) + return decContextSetStatus(context, DEC_Overflow); + if (strcmp(string, DEC_Condition_PA)==0) + return decContextSetStatus(context, DEC_Clamped); + if (strcmp(string, DEC_Condition_RO)==0) + return decContextSetStatus(context, DEC_Rounded); + if (strcmp(string, DEC_Condition_SU)==0) + return decContextSetStatus(context, DEC_Subnormal); + if (strcmp(string, DEC_Condition_UN)==0) + return decContextSetStatus(context, DEC_Underflow); + if (strcmp(string, DEC_Condition_ZE)==0) + return context; + return NULL; // Multiple status, or unknown + } // decContextSetStatusFromString + +/* ------------------------------------------------------------------ */ +/* decContextSetStatusFromStringQuiet -- set status from a string */ +/* */ +/* context is the context structure to be updated */ +/* string is a string exactly equal to one that might be returned */ +/* by decContextStatusToString */ +/* */ +/* The status bit corresponding to the string is set; no trap is */ +/* raised. */ +/* */ +/* returns the context structure, unless the string is equal to */ +/* DEC_Condition_MU or is not recognized. In these cases NULL is */ +/* returned. */ +/* ------------------------------------------------------------------ */ +decContext * decContextSetStatusFromStringQuiet(decContext *context, + const char *string) { + if (strcmp(string, DEC_Condition_CS)==0) + return decContextSetStatusQuiet(context, DEC_Conversion_syntax); + if (strcmp(string, DEC_Condition_DZ)==0) + return decContextSetStatusQuiet(context, DEC_Division_by_zero); + if (strcmp(string, DEC_Condition_DI)==0) + return decContextSetStatusQuiet(context, DEC_Division_impossible); + if (strcmp(string, DEC_Condition_DU)==0) + return decContextSetStatusQuiet(context, DEC_Division_undefined); + if (strcmp(string, DEC_Condition_IE)==0) + return decContextSetStatusQuiet(context, DEC_Inexact); + if (strcmp(string, DEC_Condition_IS)==0) + return decContextSetStatusQuiet(context, DEC_Insufficient_storage); + if (strcmp(string, DEC_Condition_IC)==0) + return decContextSetStatusQuiet(context, DEC_Invalid_context); + if (strcmp(string, DEC_Condition_IO)==0) + return decContextSetStatusQuiet(context, DEC_Invalid_operation); + #if DECSUBSET + if (strcmp(string, DEC_Condition_LD)==0) + return decContextSetStatusQuiet(context, DEC_Lost_digits); + #endif + if (strcmp(string, DEC_Condition_OV)==0) + return decContextSetStatusQuiet(context, DEC_Overflow); + if (strcmp(string, DEC_Condition_PA)==0) + return decContextSetStatusQuiet(context, DEC_Clamped); + if (strcmp(string, DEC_Condition_RO)==0) + return decContextSetStatusQuiet(context, DEC_Rounded); + if (strcmp(string, DEC_Condition_SU)==0) + return decContextSetStatusQuiet(context, DEC_Subnormal); + if (strcmp(string, DEC_Condition_UN)==0) + return decContextSetStatusQuiet(context, DEC_Underflow); + if (strcmp(string, DEC_Condition_ZE)==0) + return context; + return NULL; // Multiple status, or unknown + } // decContextSetStatusFromStringQuiet + +/* ------------------------------------------------------------------ */ +/* decContextSetStatusQuiet -- set status without trap */ +/* */ +/* context is the context structure to be updated */ +/* status is the DEC_ exception code */ +/* returns the context structure */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decContext * decContextSetStatusQuiet(decContext *context, uInt status) { + context->status|=status; + return context;} // decContextSetStatusQuiet + +/* ------------------------------------------------------------------ */ +/* decContextStatusToString -- convert status flags to a string */ +/* */ +/* context is a context with valid status field */ +/* */ +/* returns a constant string describing the condition. If multiple */ +/* (or no) flags are set, a generic constant message is returned. */ +/* ------------------------------------------------------------------ */ +const char *decContextStatusToString(const decContext *context) { + Int status=context->status; + + // test the five IEEE first, as some of the others are ambiguous when + // DECEXTFLAG=0 + if (status==DEC_Invalid_operation ) return DEC_Condition_IO; + if (status==DEC_Division_by_zero ) return DEC_Condition_DZ; + if (status==DEC_Overflow ) return DEC_Condition_OV; + if (status==DEC_Underflow ) return DEC_Condition_UN; + if (status==DEC_Inexact ) return DEC_Condition_IE; + + if (status==DEC_Division_impossible ) return DEC_Condition_DI; + if (status==DEC_Division_undefined ) return DEC_Condition_DU; + if (status==DEC_Rounded ) return DEC_Condition_RO; + if (status==DEC_Clamped ) return DEC_Condition_PA; + if (status==DEC_Subnormal ) return DEC_Condition_SU; + if (status==DEC_Conversion_syntax ) return DEC_Condition_CS; + if (status==DEC_Insufficient_storage ) return DEC_Condition_IS; + if (status==DEC_Invalid_context ) return DEC_Condition_IC; + #if DECSUBSET + if (status==DEC_Lost_digits ) return DEC_Condition_LD; + #endif + if (status==0 ) return DEC_Condition_ZE; + return DEC_Condition_MU; // Multiple errors + } // decContextStatusToString + +/* ------------------------------------------------------------------ */ +/* decContextTestEndian -- test whether DECLITEND is set correctly */ +/* */ +/* quiet is 1 to suppress message; 0 otherwise */ +/* returns 0 if DECLITEND is correct */ +/* 1 if DECLITEND is incorrect and should be 1 */ +/* -1 if DECLITEND is incorrect and should be 0 */ +/* */ +/* A message is displayed if the return value is not 0 and quiet==0. */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +Int decContextTestEndian(Flag quiet) { + Int res=0; // optimist + uInt dle=(uInt)DECLITEND; // unsign + if (dle>1) dle=1; // ensure 0 or 1 + + if (LITEND!=DECLITEND) { + if (!quiet) { // always refer to this + #if DECPRINT + const char *adj; + if (LITEND) adj="little"; + else adj="big"; + printf("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n", + DECLITEND, adj); + #endif + } + res=(Int)LITEND-dle; + } + return res; + } // decContextTestEndian + +/* ------------------------------------------------------------------ */ +/* decContextTestSavedStatus -- test bits in saved status */ +/* */ +/* oldstatus is the status word to be tested */ +/* mask indicates the bits to be tested (the oldstatus bits that */ +/* correspond to each 1 bit in the mask are tested) */ +/* returns 1 if any of the tested bits are 1, or 0 otherwise */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +uInt decContextTestSavedStatus(uInt oldstatus, uInt mask) { + return (oldstatus&mask)!=0; + } // decContextTestSavedStatus + +/* ------------------------------------------------------------------ */ +/* decContextTestStatus -- test bits in current status */ +/* */ +/* context is the context structure to be updated */ +/* mask indicates the bits to be tested (the status bits that */ +/* correspond to each 1 bit in the mask are tested) */ +/* returns 1 if any of the tested bits are 1, or 0 otherwise */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +uInt decContextTestStatus(decContext *context, uInt mask) { + return (context->status&mask)!=0; + } // decContextTestStatus + +/* ------------------------------------------------------------------ */ +/* decContextZeroStatus -- clear all status bits */ +/* */ +/* context is the context structure to be updated */ +/* returns context */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decContext *decContextZeroStatus(decContext *context) { + context->status=0; + return context; + } // decContextZeroStatus + diff --git a/extern/decNumber/decContext.h b/extern/decNumber/decContext.h new file mode 100644 index 0000000000..f5dca1d305 --- /dev/null +++ b/extern/decNumber/decContext.h @@ -0,0 +1,254 @@ +/* ------------------------------------------------------------------ */ +/* Decimal Context module header */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* */ +/* Context variables must always have valid values: */ +/* */ +/* status -- [any bits may be cleared, but not set, by user] */ +/* round -- must be one of the enumerated rounding modes */ +/* */ +/* The following variables are implied for fixed size formats (i.e., */ +/* they are ignored) but should still be set correctly in case used */ +/* with decNumber functions: */ +/* */ +/* clamp -- must be either 0 or 1 */ +/* digits -- must be in the range 1 through 999999999 */ +/* emax -- must be in the range 0 through 999999999 */ +/* emin -- must be in the range 0 through -999999999 */ +/* extended -- must be either 0 or 1 [present only if DECSUBSET] */ +/* traps -- only defined bits may be set */ +/* */ +/* ------------------------------------------------------------------ */ + +#if !defined(DECCONTEXT) + #define DECCONTEXT + #define DECCNAME "decContext" /* Short name */ + #define DECCFULLNAME "Decimal Context Descriptor" /* Verbose name */ + #define DECCAUTHOR "Mike Cowlishaw" /* Who to blame */ + + #if !defined(int32_t) + #include /* C99 standard integers */ + #endif + #include /* for printf, etc. */ + #include /* for traps */ + + /* Extended flags setting -- set this to 0 to use only IEEE flags */ + #if !defined(DECEXTFLAG) + #define DECEXTFLAG 1 /* 1=enable extended flags */ + #endif + + /* Conditional code flag -- set this to 0 for best performance */ + #if !defined(DECSUBSET) + #define DECSUBSET 0 /* 1=enable subset arithmetic */ + #endif + + /* Context for operations, with associated constants */ + enum rounding { + DEC_ROUND_CEILING, /* round towards +infinity */ + DEC_ROUND_UP, /* round away from 0 */ + DEC_ROUND_HALF_UP, /* 0.5 rounds up */ + DEC_ROUND_HALF_EVEN, /* 0.5 rounds to nearest even */ + DEC_ROUND_HALF_DOWN, /* 0.5 rounds down */ + DEC_ROUND_DOWN, /* round towards 0 (truncate) */ + DEC_ROUND_FLOOR, /* round towards -infinity */ + DEC_ROUND_05UP, /* round for reround */ + DEC_ROUND_MAX /* enum must be less than this */ + }; + #define DEC_ROUND_DEFAULT DEC_ROUND_HALF_EVEN; + + typedef struct { + int32_t digits; /* working precision */ + int32_t emax; /* maximum positive exponent */ + int32_t emin; /* minimum negative exponent */ + enum rounding round; /* rounding mode */ + uint32_t traps; /* trap-enabler flags */ + uint32_t status; /* status flags */ + uint8_t clamp; /* flag: apply IEEE exponent clamp */ + #if DECSUBSET + uint8_t extended; /* flag: special-values allowed */ + #endif + } decContext; + + /* Maxima and Minima for context settings */ + #define DEC_MAX_DIGITS 999999999 + #define DEC_MIN_DIGITS 1 + #define DEC_MAX_EMAX 999999999 + #define DEC_MIN_EMAX 0 + #define DEC_MAX_EMIN 0 + #define DEC_MIN_EMIN -999999999 + #define DEC_MAX_MATH 999999 /* max emax, etc., for math funcs. */ + + /* Classifications for decimal numbers, aligned with 754 (note that */ + /* 'normal' and 'subnormal' are meaningful only with a decContext */ + /* or a fixed size format). */ + enum decClass { + DEC_CLASS_SNAN, + DEC_CLASS_QNAN, + DEC_CLASS_NEG_INF, + DEC_CLASS_NEG_NORMAL, + DEC_CLASS_NEG_SUBNORMAL, + DEC_CLASS_NEG_ZERO, + DEC_CLASS_POS_ZERO, + DEC_CLASS_POS_SUBNORMAL, + DEC_CLASS_POS_NORMAL, + DEC_CLASS_POS_INF + }; + /* Strings for the decClasses */ + #define DEC_ClassString_SN "sNaN" + #define DEC_ClassString_QN "NaN" + #define DEC_ClassString_NI "-Infinity" + #define DEC_ClassString_NN "-Normal" + #define DEC_ClassString_NS "-Subnormal" + #define DEC_ClassString_NZ "-Zero" + #define DEC_ClassString_PZ "+Zero" + #define DEC_ClassString_PS "+Subnormal" + #define DEC_ClassString_PN "+Normal" + #define DEC_ClassString_PI "+Infinity" + #define DEC_ClassString_UN "Invalid" + + /* Trap-enabler and Status flags (exceptional conditions), and */ + /* their names. The top byte is reserved for internal use */ + #if DECEXTFLAG + /* Extended flags */ + #define DEC_Conversion_syntax 0x00000001 + #define DEC_Division_by_zero 0x00000002 + #define DEC_Division_impossible 0x00000004 + #define DEC_Division_undefined 0x00000008 + #define DEC_Insufficient_storage 0x00000010 /* [when malloc fails] */ + #define DEC_Inexact 0x00000020 + #define DEC_Invalid_context 0x00000040 + #define DEC_Invalid_operation 0x00000080 + #if DECSUBSET + #define DEC_Lost_digits 0x00000100 + #endif + #define DEC_Overflow 0x00000200 + #define DEC_Clamped 0x00000400 + #define DEC_Rounded 0x00000800 + #define DEC_Subnormal 0x00001000 + #define DEC_Underflow 0x00002000 + #else + /* IEEE flags only */ + #define DEC_Conversion_syntax 0x00000010 + #define DEC_Division_by_zero 0x00000002 + #define DEC_Division_impossible 0x00000010 + #define DEC_Division_undefined 0x00000010 + #define DEC_Insufficient_storage 0x00000010 /* [when malloc fails] */ + #define DEC_Inexact 0x00000001 + #define DEC_Invalid_context 0x00000010 + #define DEC_Invalid_operation 0x00000010 + #if DECSUBSET + #define DEC_Lost_digits 0x00000000 + #endif + #define DEC_Overflow 0x00000008 + #define DEC_Clamped 0x00000000 + #define DEC_Rounded 0x00000000 + #define DEC_Subnormal 0x00000000 + #define DEC_Underflow 0x00000004 + #endif + + /* IEEE 754 groupings for the flags */ + /* [DEC_Clamped, DEC_Lost_digits, DEC_Rounded, and DEC_Subnormal */ + /* are not in IEEE 754] */ + #define DEC_IEEE_754_Division_by_zero (DEC_Division_by_zero) + #if DECSUBSET + #define DEC_IEEE_754_Inexact (DEC_Inexact | DEC_Lost_digits) + #else + #define DEC_IEEE_754_Inexact (DEC_Inexact) + #endif + #define DEC_IEEE_754_Invalid_operation (DEC_Conversion_syntax | \ + DEC_Division_impossible | \ + DEC_Division_undefined | \ + DEC_Insufficient_storage | \ + DEC_Invalid_context | \ + DEC_Invalid_operation) + #define DEC_IEEE_754_Overflow (DEC_Overflow) + #define DEC_IEEE_754_Underflow (DEC_Underflow) + + /* flags which are normally errors (result is qNaN, infinite, or 0) */ + #define DEC_Errors (DEC_IEEE_754_Division_by_zero | \ + DEC_IEEE_754_Invalid_operation | \ + DEC_IEEE_754_Overflow | DEC_IEEE_754_Underflow) + /* flags which cause a result to become qNaN */ + #define DEC_NaNs DEC_IEEE_754_Invalid_operation + + /* flags which are normally for information only (finite results) */ + #if DECSUBSET + #define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact \ + | DEC_Lost_digits) + #else + #define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact) + #endif + + /* IEEE 854 names (for compatibility with older decNumber versions) */ + #define DEC_IEEE_854_Division_by_zero DEC_IEEE_754_Division_by_zero + #define DEC_IEEE_854_Inexact DEC_IEEE_754_Inexact + #define DEC_IEEE_854_Invalid_operation DEC_IEEE_754_Invalid_operation + #define DEC_IEEE_854_Overflow DEC_IEEE_754_Overflow + #define DEC_IEEE_854_Underflow DEC_IEEE_754_Underflow + + /* Name strings for the exceptional conditions */ + #define DEC_Condition_CS "Conversion syntax" + #define DEC_Condition_DZ "Division by zero" + #define DEC_Condition_DI "Division impossible" + #define DEC_Condition_DU "Division undefined" + #define DEC_Condition_IE "Inexact" + #define DEC_Condition_IS "Insufficient storage" + #define DEC_Condition_IC "Invalid context" + #define DEC_Condition_IO "Invalid operation" + #if DECSUBSET + #define DEC_Condition_LD "Lost digits" + #endif + #define DEC_Condition_OV "Overflow" + #define DEC_Condition_PA "Clamped" + #define DEC_Condition_RO "Rounded" + #define DEC_Condition_SU "Subnormal" + #define DEC_Condition_UN "Underflow" + #define DEC_Condition_ZE "No status" + #define DEC_Condition_MU "Multiple status" + #define DEC_Condition_Length 21 /* length of the longest string, */ + /* including terminator */ + + /* Initialization descriptors, used by decContextDefault */ + #define DEC_INIT_BASE 0 + #define DEC_INIT_DECIMAL32 32 + #define DEC_INIT_DECIMAL64 64 + #define DEC_INIT_DECIMAL128 128 + /* Synonyms */ + #define DEC_INIT_DECSINGLE DEC_INIT_DECIMAL32 + #define DEC_INIT_DECDOUBLE DEC_INIT_DECIMAL64 + #define DEC_INIT_DECQUAD DEC_INIT_DECIMAL128 + + /* decContext routines */ + extern decContext * decContextClearStatus(decContext *, uint32_t); + extern decContext * decContextDefault(decContext *, int32_t); + extern enum rounding decContextGetRounding(decContext *); + extern uint32_t decContextGetStatus(decContext *); + extern decContext * decContextRestoreStatus(decContext *, uint32_t, uint32_t); + extern uint32_t decContextSaveStatus(decContext *, uint32_t); + extern decContext * decContextSetRounding(decContext *, enum rounding); + extern decContext * decContextSetStatus(decContext *, uint32_t); + extern decContext * decContextSetStatusFromString(decContext *, const char *); + extern decContext * decContextSetStatusFromStringQuiet(decContext *, const char *); + extern decContext * decContextSetStatusQuiet(decContext *, uint32_t); + extern const char * decContextStatusToString(const decContext *); + extern int32_t decContextTestEndian(uint8_t); + extern uint32_t decContextTestSavedStatus(uint32_t, uint32_t); + extern uint32_t decContextTestStatus(decContext *, uint32_t); + extern decContext * decContextZeroStatus(decContext *); + +#endif diff --git a/extern/decNumber/decDPD.h b/extern/decNumber/decDPD.h new file mode 100644 index 0000000000..4daad4f842 --- /dev/null +++ b/extern/decNumber/decDPD.h @@ -0,0 +1,1185 @@ +/* ------------------------------------------------------------------------ */ +/* Binary Coded Decimal and Densely Packed Decimal conversion lookup tables */ +/* [Automatically generated -- do not edit. 2008.06.21] */ +/* ------------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ +/* ------------------------------------------------------------------------ */ +/* For details, see DPDecimal.html on the General Decimal Arithmetic page. */ +/* */ +/* This include file defines several DPD and BCD conversion tables: */ +/* */ +/* uint16_t BCD2DPD[2458]; -- BCD -> DPD (0x999 => 2457) */ +/* uint16_t BIN2DPD[1000]; -- Bin -> DPD (999 => 2457) */ +/* uint8_t BIN2CHAR[4001]; -- Bin -> CHAR (999 => '\3' '9' '9' '9') */ +/* uint8_t BIN2BCD8[4000]; -- Bin -> bytes (999 => 9 9 9 3) */ +/* uint16_t DPD2BCD[1024]; -- DPD -> BCD (0x3FF => 0x999) */ +/* uint16_t DPD2BIN[1024]; -- DPD -> BIN (0x3FF => 999) */ +/* uint32_t DPD2BINK[1024]; -- DPD -> BIN * 1000 (0x3FF => 999000) */ +/* uint32_t DPD2BINM[1024]; -- DPD -> BIN * 1E+6 (0x3FF => 999000000) */ +/* uint8_t DPD2BCD8[4096]; -- DPD -> bytes (x3FF => 9 9 9 3) */ +/* */ +/* In all cases the result (10 bits or 12 bits, or binary) is right-aligned */ +/* in the table entry. BIN2CHAR entries are a single byte length (0 for */ +/* value 0) followed by three digit characters; a trailing terminator is */ +/* included to allow 4-char moves always. BIN2BCD8 and DPD2BCD8 entries */ +/* are similar with the three BCD8 digits followed by a one-byte length */ +/* (again, length=0 for value 0). */ +/* */ +/* To use a table, its name, prefixed with DEC_, must be defined with a */ +/* value of 1 before this header file is included. For example: */ +/* #define DEC_BCD2DPD 1 */ +/* This mechanism allows software to only include tables that are needed. */ +/* ------------------------------------------------------------------------ */ + +#if defined(DEC_BCD2DPD) && DEC_BCD2DPD==1 && !defined(DECBCD2DPD) +#define DECBCD2DPD + +const uint16_t BCD2DPD[2458]={ 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 0, 0, 0, 0, 0, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 0, 0, 0, 0, 0, + 0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, 0, + 0, 0, 0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 0, 0, 0, 0, 0, 0, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 0, 0, 0, 0, 0, 0, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 0, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 0, 0, 0, + 0, 0, 0, 10, 11, 42, 43, 74, 75, 106, 107, 78, 79, + 0, 0, 0, 0, 0, 0, 26, 27, 58, 59, 90, 91, 122, + 123, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 0, 0, + 0, 0, 0, 0, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 0, 0, 0, 0, 0, 0, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 0, 0, 0, 0, 0, 0, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 0, 0, 0, 0, 0, 0, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 0, 0, 0, + 0, 0, 0, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + 0, 0, 0, 0, 0, 0, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 0, 0, 0, 0, 0, 0, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 0, 0, 0, 0, 0, 0, 138, + 139, 170, 171, 202, 203, 234, 235, 206, 207, 0, 0, 0, 0, + 0, 0, 154, 155, 186, 187, 218, 219, 250, 251, 222, 223, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 0, 0, 0, 0, 0, 0, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 0, 0, 0, + 0, 0, 0, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 0, 0, 0, 0, 0, 0, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 0, 0, 0, 0, 0, 0, 320, 321, 322, 323, + 324, 325, 326, 327, 328, 329, 0, 0, 0, 0, 0, 0, 336, + 337, 338, 339, 340, 341, 342, 343, 344, 345, 0, 0, 0, 0, + 0, 0, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, + 0, 0, 0, 0, 0, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 0, 0, 0, 0, 0, 0, 266, 267, 298, 299, 330, + 331, 362, 363, 334, 335, 0, 0, 0, 0, 0, 0, 282, 283, + 314, 315, 346, 347, 378, 379, 350, 351, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 384, 385, 386, 387, 388, 389, 390, + 391, 392, 393, 0, 0, 0, 0, 0, 0, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 0, 0, 0, 0, 0, 0, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 0, 0, 0, 0, + 0, 0, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 0, + 0, 0, 0, 0, 0, 448, 449, 450, 451, 452, 453, 454, 455, + 456, 457, 0, 0, 0, 0, 0, 0, 464, 465, 466, 467, 468, + 469, 470, 471, 472, 473, 0, 0, 0, 0, 0, 0, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 0, 0, 0, 0, 0, + 0, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 0, 0, + 0, 0, 0, 0, 394, 395, 426, 427, 458, 459, 490, 491, 462, + 463, 0, 0, 0, 0, 0, 0, 410, 411, 442, 443, 474, 475, + 506, 507, 478, 479, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 0, + 0, 0, 0, 0, 0, 528, 529, 530, 531, 532, 533, 534, 535, + 536, 537, 0, 0, 0, 0, 0, 0, 544, 545, 546, 547, 548, + 549, 550, 551, 552, 553, 0, 0, 0, 0, 0, 0, 560, 561, + 562, 563, 564, 565, 566, 567, 568, 569, 0, 0, 0, 0, 0, + 0, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 0, 0, + 0, 0, 0, 0, 592, 593, 594, 595, 596, 597, 598, 599, 600, + 601, 0, 0, 0, 0, 0, 0, 608, 609, 610, 611, 612, 613, + 614, 615, 616, 617, 0, 0, 0, 0, 0, 0, 624, 625, 626, + 627, 628, 629, 630, 631, 632, 633, 0, 0, 0, 0, 0, 0, + 522, 523, 554, 555, 586, 587, 618, 619, 590, 591, 0, 0, 0, + 0, 0, 0, 538, 539, 570, 571, 602, 603, 634, 635, 606, 607, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 640, 641, + 642, 643, 644, 645, 646, 647, 648, 649, 0, 0, 0, 0, 0, + 0, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 0, 0, + 0, 0, 0, 0, 672, 673, 674, 675, 676, 677, 678, 679, 680, + 681, 0, 0, 0, 0, 0, 0, 688, 689, 690, 691, 692, 693, + 694, 695, 696, 697, 0, 0, 0, 0, 0, 0, 704, 705, 706, + 707, 708, 709, 710, 711, 712, 713, 0, 0, 0, 0, 0, 0, + 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 0, 0, 0, + 0, 0, 0, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, + 0, 0, 0, 0, 0, 0, 752, 753, 754, 755, 756, 757, 758, + 759, 760, 761, 0, 0, 0, 0, 0, 0, 650, 651, 682, 683, + 714, 715, 746, 747, 718, 719, 0, 0, 0, 0, 0, 0, 666, + 667, 698, 699, 730, 731, 762, 763, 734, 735, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 768, 769, 770, 771, 772, 773, + 774, 775, 776, 777, 0, 0, 0, 0, 0, 0, 784, 785, 786, + 787, 788, 789, 790, 791, 792, 793, 0, 0, 0, 0, 0, 0, + 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 0, 0, 0, + 0, 0, 0, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, + 0, 0, 0, 0, 0, 0, 832, 833, 834, 835, 836, 837, 838, + 839, 840, 841, 0, 0, 0, 0, 0, 0, 848, 849, 850, 851, + 852, 853, 854, 855, 856, 857, 0, 0, 0, 0, 0, 0, 864, + 865, 866, 867, 868, 869, 870, 871, 872, 873, 0, 0, 0, 0, + 0, 0, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 0, + 0, 0, 0, 0, 0, 778, 779, 810, 811, 842, 843, 874, 875, + 846, 847, 0, 0, 0, 0, 0, 0, 794, 795, 826, 827, 858, + 859, 890, 891, 862, 863, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, + 0, 0, 0, 0, 0, 0, 912, 913, 914, 915, 916, 917, 918, + 919, 920, 921, 0, 0, 0, 0, 0, 0, 928, 929, 930, 931, + 932, 933, 934, 935, 936, 937, 0, 0, 0, 0, 0, 0, 944, + 945, 946, 947, 948, 949, 950, 951, 952, 953, 0, 0, 0, 0, + 0, 0, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 0, + 0, 0, 0, 0, 0, 976, 977, 978, 979, 980, 981, 982, 983, + 984, 985, 0, 0, 0, 0, 0, 0, 992, 993, 994, 995, 996, + 997, 998, 999, 1000, 1001, 0, 0, 0, 0, 0, 0, 1008, 1009, + 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 0, 0, 0, 0, 0, + 0, 906, 907, 938, 939, 970, 971, 1002, 1003, 974, 975, 0, 0, + 0, 0, 0, 0, 922, 923, 954, 955, 986, 987, 1018, 1019, 990, + 991, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, + 13, 268, 269, 524, 525, 780, 781, 46, 47, 0, 0, 0, 0, + 0, 0, 28, 29, 284, 285, 540, 541, 796, 797, 62, 63, 0, + 0, 0, 0, 0, 0, 44, 45, 300, 301, 556, 557, 812, 813, + 302, 303, 0, 0, 0, 0, 0, 0, 60, 61, 316, 317, 572, + 573, 828, 829, 318, 319, 0, 0, 0, 0, 0, 0, 76, 77, + 332, 333, 588, 589, 844, 845, 558, 559, 0, 0, 0, 0, 0, + 0, 92, 93, 348, 349, 604, 605, 860, 861, 574, 575, 0, 0, + 0, 0, 0, 0, 108, 109, 364, 365, 620, 621, 876, 877, 814, + 815, 0, 0, 0, 0, 0, 0, 124, 125, 380, 381, 636, 637, + 892, 893, 830, 831, 0, 0, 0, 0, 0, 0, 14, 15, 270, + 271, 526, 527, 782, 783, 110, 111, 0, 0, 0, 0, 0, 0, + 30, 31, 286, 287, 542, 543, 798, 799, 126, 127, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 140, 141, 396, 397, 652, + 653, 908, 909, 174, 175, 0, 0, 0, 0, 0, 0, 156, 157, + 412, 413, 668, 669, 924, 925, 190, 191, 0, 0, 0, 0, 0, + 0, 172, 173, 428, 429, 684, 685, 940, 941, 430, 431, 0, 0, + 0, 0, 0, 0, 188, 189, 444, 445, 700, 701, 956, 957, 446, + 447, 0, 0, 0, 0, 0, 0, 204, 205, 460, 461, 716, 717, + 972, 973, 686, 687, 0, 0, 0, 0, 0, 0, 220, 221, 476, + 477, 732, 733, 988, 989, 702, 703, 0, 0, 0, 0, 0, 0, + 236, 237, 492, 493, 748, 749, 1004, 1005, 942, 943, 0, 0, 0, + 0, 0, 0, 252, 253, 508, 509, 764, 765, 1020, 1021, 958, 959, + 0, 0, 0, 0, 0, 0, 142, 143, 398, 399, 654, 655, 910, + 911, 238, 239, 0, 0, 0, 0, 0, 0, 158, 159, 414, 415, + 670, 671, 926, 927, 254, 255}; +#endif + +#if defined(DEC_DPD2BCD) && DEC_DPD2BCD==1 && !defined(DECDPD2BCD) +#define DECDPD2BCD + +const uint16_t DPD2BCD[1024]={ 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 128, 129, 2048, 2049, 2176, 2177, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 144, 145, 2064, 2065, 2192, 2193, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 130, 131, 2080, 2081, 2056, + 2057, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 146, 147, + 2096, 2097, 2072, 2073, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 132, 133, 2112, 2113, 136, 137, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 148, 149, 2128, 2129, 152, 153, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 134, 135, 2144, 2145, 2184, 2185, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 150, 151, 2160, + 2161, 2200, 2201, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 384, 385, 2304, 2305, 2432, 2433, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 400, 401, 2320, 2321, 2448, 2449, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 386, 387, 2336, 2337, 2312, 2313, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 402, 403, 2352, 2353, + 2328, 2329, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 388, + 389, 2368, 2369, 392, 393, 336, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 404, 405, 2384, 2385, 408, 409, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 390, 391, 2400, 2401, 2440, 2441, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 406, 407, 2416, 2417, 2456, + 2457, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 640, 641, + 2050, 2051, 2178, 2179, 528, 529, 530, 531, 532, 533, 534, 535, 536, + 537, 656, 657, 2066, 2067, 2194, 2195, 544, 545, 546, 547, 548, 549, + 550, 551, 552, 553, 642, 643, 2082, 2083, 2088, 2089, 560, 561, 562, + 563, 564, 565, 566, 567, 568, 569, 658, 659, 2098, 2099, 2104, 2105, + 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 644, 645, 2114, + 2115, 648, 649, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, + 660, 661, 2130, 2131, 664, 665, 608, 609, 610, 611, 612, 613, 614, + 615, 616, 617, 646, 647, 2146, 2147, 2184, 2185, 624, 625, 626, 627, + 628, 629, 630, 631, 632, 633, 662, 663, 2162, 2163, 2200, 2201, 768, + 769, 770, 771, 772, 773, 774, 775, 776, 777, 896, 897, 2306, 2307, + 2434, 2435, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 912, + 913, 2322, 2323, 2450, 2451, 800, 801, 802, 803, 804, 805, 806, 807, + 808, 809, 898, 899, 2338, 2339, 2344, 2345, 816, 817, 818, 819, 820, + 821, 822, 823, 824, 825, 914, 915, 2354, 2355, 2360, 2361, 832, 833, + 834, 835, 836, 837, 838, 839, 840, 841, 900, 901, 2370, 2371, 904, + 905, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 916, 917, + 2386, 2387, 920, 921, 864, 865, 866, 867, 868, 869, 870, 871, 872, + 873, 902, 903, 2402, 2403, 2440, 2441, 880, 881, 882, 883, 884, 885, + 886, 887, 888, 889, 918, 919, 2418, 2419, 2456, 2457, 1024, 1025, 1026, + 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1152, 1153, 2052, 2053, 2180, 2181, + 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1168, 1169, 2068, + 2069, 2196, 2197, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, + 1154, 1155, 2084, 2085, 2120, 2121, 1072, 1073, 1074, 1075, 1076, 1077, 1078, + 1079, 1080, 1081, 1170, 1171, 2100, 2101, 2136, 2137, 1088, 1089, 1090, 1091, + 1092, 1093, 1094, 1095, 1096, 1097, 1156, 1157, 2116, 2117, 1160, 1161, 1104, + 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1172, 1173, 2132, 2133, + 1176, 1177, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1158, + 1159, 2148, 2149, 2184, 2185, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, + 1144, 1145, 1174, 1175, 2164, 2165, 2200, 2201, 1280, 1281, 1282, 1283, 1284, + 1285, 1286, 1287, 1288, 1289, 1408, 1409, 2308, 2309, 2436, 2437, 1296, 1297, + 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1424, 1425, 2324, 2325, 2452, + 2453, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1410, 1411, + 2340, 2341, 2376, 2377, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, + 1337, 1426, 1427, 2356, 2357, 2392, 2393, 1344, 1345, 1346, 1347, 1348, 1349, + 1350, 1351, 1352, 1353, 1412, 1413, 2372, 2373, 1416, 1417, 1360, 1361, 1362, + 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1428, 1429, 2388, 2389, 1432, 1433, + 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1414, 1415, 2404, + 2405, 2440, 2441, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, + 1430, 1431, 2420, 2421, 2456, 2457, 1536, 1537, 1538, 1539, 1540, 1541, 1542, + 1543, 1544, 1545, 1664, 1665, 2054, 2055, 2182, 2183, 1552, 1553, 1554, 1555, + 1556, 1557, 1558, 1559, 1560, 1561, 1680, 1681, 2070, 2071, 2198, 2199, 1568, + 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1666, 1667, 2086, 2087, + 2152, 2153, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1682, + 1683, 2102, 2103, 2168, 2169, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, + 1608, 1609, 1668, 1669, 2118, 2119, 1672, 1673, 1616, 1617, 1618, 1619, 1620, + 1621, 1622, 1623, 1624, 1625, 1684, 1685, 2134, 2135, 1688, 1689, 1632, 1633, + 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1670, 1671, 2150, 2151, 2184, + 2185, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1686, 1687, + 2166, 2167, 2200, 2201, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, + 1801, 1920, 1921, 2310, 2311, 2438, 2439, 1808, 1809, 1810, 1811, 1812, 1813, + 1814, 1815, 1816, 1817, 1936, 1937, 2326, 2327, 2454, 2455, 1824, 1825, 1826, + 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1922, 1923, 2342, 2343, 2408, 2409, + 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1938, 1939, 2358, + 2359, 2424, 2425, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, + 1924, 1925, 2374, 2375, 1928, 1929, 1872, 1873, 1874, 1875, 1876, 1877, 1878, + 1879, 1880, 1881, 1940, 1941, 2390, 2391, 1944, 1945, 1888, 1889, 1890, 1891, + 1892, 1893, 1894, 1895, 1896, 1897, 1926, 1927, 2406, 2407, 2440, 2441, 1904, + 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1942, 1943, 2422, 2423, + 2456, 2457}; +#endif + +#if defined(DEC_BIN2DPD) && DEC_BIN2DPD==1 && !defined(DECBIN2DPD) +#define DECBIN2DPD + +const uint16_t BIN2DPD[1000]={ 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 10, 11, 42, 43, 74, 75, + 106, 107, 78, 79, 26, 27, 58, 59, 90, 91, 122, 123, 94, + 95, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 138, 139, 170, 171, 202, 203, 234, 235, 206, 207, + 154, 155, 186, 187, 218, 219, 250, 251, 222, 223, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 320, 321, + 322, 323, 324, 325, 326, 327, 328, 329, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 266, + 267, 298, 299, 330, 331, 362, 363, 334, 335, 282, 283, 314, 315, + 346, 347, 378, 379, 350, 351, 384, 385, 386, 387, 388, 389, 390, + 391, 392, 393, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 448, 449, 450, 451, 452, 453, + 454, 455, 456, 457, 464, 465, 466, 467, 468, 469, 470, 471, 472, + 473, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 496, 497, + 498, 499, 500, 501, 502, 503, 504, 505, 394, 395, 426, 427, 458, + 459, 490, 491, 462, 463, 410, 411, 442, 443, 474, 475, 506, 507, + 478, 479, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 528, + 529, 530, 531, 532, 533, 534, 535, 536, 537, 544, 545, 546, 547, + 548, 549, 550, 551, 552, 553, 560, 561, 562, 563, 564, 565, 566, + 567, 568, 569, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, + 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 608, 609, 610, + 611, 612, 613, 614, 615, 616, 617, 624, 625, 626, 627, 628, 629, + 630, 631, 632, 633, 522, 523, 554, 555, 586, 587, 618, 619, 590, + 591, 538, 539, 570, 571, 602, 603, 634, 635, 606, 607, 640, 641, + 642, 643, 644, 645, 646, 647, 648, 649, 656, 657, 658, 659, 660, + 661, 662, 663, 664, 665, 672, 673, 674, 675, 676, 677, 678, 679, + 680, 681, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 704, + 705, 706, 707, 708, 709, 710, 711, 712, 713, 720, 721, 722, 723, + 724, 725, 726, 727, 728, 729, 736, 737, 738, 739, 740, 741, 742, + 743, 744, 745, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, + 650, 651, 682, 683, 714, 715, 746, 747, 718, 719, 666, 667, 698, + 699, 730, 731, 762, 763, 734, 735, 768, 769, 770, 771, 772, 773, + 774, 775, 776, 777, 784, 785, 786, 787, 788, 789, 790, 791, 792, + 793, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 816, 817, + 818, 819, 820, 821, 822, 823, 824, 825, 832, 833, 834, 835, 836, + 837, 838, 839, 840, 841, 848, 849, 850, 851, 852, 853, 854, 855, + 856, 857, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 880, + 881, 882, 883, 884, 885, 886, 887, 888, 889, 778, 779, 810, 811, + 842, 843, 874, 875, 846, 847, 794, 795, 826, 827, 858, 859, 890, + 891, 862, 863, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, + 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 928, 929, 930, + 931, 932, 933, 934, 935, 936, 937, 944, 945, 946, 947, 948, 949, + 950, 951, 952, 953, 960, 961, 962, 963, 964, 965, 966, 967, 968, + 969, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 992, 993, + 994, 995, 996, 997, 998, 999, 1000, 1001, 1008, 1009, 1010, 1011, 1012, + 1013, 1014, 1015, 1016, 1017, 906, 907, 938, 939, 970, 971, 1002, 1003, + 974, 975, 922, 923, 954, 955, 986, 987, 1018, 1019, 990, 991, 12, + 13, 268, 269, 524, 525, 780, 781, 46, 47, 28, 29, 284, 285, + 540, 541, 796, 797, 62, 63, 44, 45, 300, 301, 556, 557, 812, + 813, 302, 303, 60, 61, 316, 317, 572, 573, 828, 829, 318, 319, + 76, 77, 332, 333, 588, 589, 844, 845, 558, 559, 92, 93, 348, + 349, 604, 605, 860, 861, 574, 575, 108, 109, 364, 365, 620, 621, + 876, 877, 814, 815, 124, 125, 380, 381, 636, 637, 892, 893, 830, + 831, 14, 15, 270, 271, 526, 527, 782, 783, 110, 111, 30, 31, + 286, 287, 542, 543, 798, 799, 126, 127, 140, 141, 396, 397, 652, + 653, 908, 909, 174, 175, 156, 157, 412, 413, 668, 669, 924, 925, + 190, 191, 172, 173, 428, 429, 684, 685, 940, 941, 430, 431, 188, + 189, 444, 445, 700, 701, 956, 957, 446, 447, 204, 205, 460, 461, + 716, 717, 972, 973, 686, 687, 220, 221, 476, 477, 732, 733, 988, + 989, 702, 703, 236, 237, 492, 493, 748, 749, 1004, 1005, 942, 943, + 252, 253, 508, 509, 764, 765, 1020, 1021, 958, 959, 142, 143, 398, + 399, 654, 655, 910, 911, 238, 239, 158, 159, 414, 415, 670, 671, + 926, 927, 254, 255}; +#endif + +#if defined(DEC_DPD2BIN) && DEC_DPD2BIN==1 && !defined(DECDPD2BIN) +#define DECDPD2BIN + +const uint16_t DPD2BIN[1024]={ 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 80, 81, 800, 801, 880, 881, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 90, 91, 810, 811, 890, 891, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 82, 83, 820, 821, 808, + 809, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 92, 93, + 830, 831, 818, 819, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 84, 85, 840, 841, 88, 89, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 94, 95, 850, 851, 98, 99, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 86, 87, 860, 861, 888, 889, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 96, 97, 870, + 871, 898, 899, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 180, 181, 900, 901, 980, 981, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 190, 191, 910, 911, 990, 991, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 182, 183, 920, 921, 908, 909, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 192, 193, 930, 931, + 918, 919, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 184, + 185, 940, 941, 188, 189, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 194, 195, 950, 951, 198, 199, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 186, 187, 960, 961, 988, 989, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 196, 197, 970, 971, 998, + 999, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 280, 281, + 802, 803, 882, 883, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 290, 291, 812, 813, 892, 893, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 282, 283, 822, 823, 828, 829, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 292, 293, 832, 833, 838, 839, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 284, 285, 842, + 843, 288, 289, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 294, 295, 852, 853, 298, 299, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 286, 287, 862, 863, 888, 889, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 296, 297, 872, 873, 898, 899, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 380, 381, 902, 903, + 982, 983, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 390, + 391, 912, 913, 992, 993, 320, 321, 322, 323, 324, 325, 326, 327, + 328, 329, 382, 383, 922, 923, 928, 929, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 392, 393, 932, 933, 938, 939, 340, 341, + 342, 343, 344, 345, 346, 347, 348, 349, 384, 385, 942, 943, 388, + 389, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 394, 395, + 952, 953, 398, 399, 360, 361, 362, 363, 364, 365, 366, 367, 368, + 369, 386, 387, 962, 963, 988, 989, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 396, 397, 972, 973, 998, 999, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 480, 481, 804, 805, 884, 885, + 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 490, 491, 814, + 815, 894, 895, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 482, 483, 824, 825, 848, 849, 430, 431, 432, 433, 434, 435, 436, + 437, 438, 439, 492, 493, 834, 835, 858, 859, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 449, 484, 485, 844, 845, 488, 489, 450, + 451, 452, 453, 454, 455, 456, 457, 458, 459, 494, 495, 854, 855, + 498, 499, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 486, + 487, 864, 865, 888, 889, 470, 471, 472, 473, 474, 475, 476, 477, + 478, 479, 496, 497, 874, 875, 898, 899, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 580, 581, 904, 905, 984, 985, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 590, 591, 914, 915, 994, + 995, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 582, 583, + 924, 925, 948, 949, 530, 531, 532, 533, 534, 535, 536, 537, 538, + 539, 592, 593, 934, 935, 958, 959, 540, 541, 542, 543, 544, 545, + 546, 547, 548, 549, 584, 585, 944, 945, 588, 589, 550, 551, 552, + 553, 554, 555, 556, 557, 558, 559, 594, 595, 954, 955, 598, 599, + 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 586, 587, 964, + 965, 988, 989, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, + 596, 597, 974, 975, 998, 999, 600, 601, 602, 603, 604, 605, 606, + 607, 608, 609, 680, 681, 806, 807, 886, 887, 610, 611, 612, 613, + 614, 615, 616, 617, 618, 619, 690, 691, 816, 817, 896, 897, 620, + 621, 622, 623, 624, 625, 626, 627, 628, 629, 682, 683, 826, 827, + 868, 869, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 692, + 693, 836, 837, 878, 879, 640, 641, 642, 643, 644, 645, 646, 647, + 648, 649, 684, 685, 846, 847, 688, 689, 650, 651, 652, 653, 654, + 655, 656, 657, 658, 659, 694, 695, 856, 857, 698, 699, 660, 661, + 662, 663, 664, 665, 666, 667, 668, 669, 686, 687, 866, 867, 888, + 889, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 696, 697, + 876, 877, 898, 899, 700, 701, 702, 703, 704, 705, 706, 707, 708, + 709, 780, 781, 906, 907, 986, 987, 710, 711, 712, 713, 714, 715, + 716, 717, 718, 719, 790, 791, 916, 917, 996, 997, 720, 721, 722, + 723, 724, 725, 726, 727, 728, 729, 782, 783, 926, 927, 968, 969, + 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 792, 793, 936, + 937, 978, 979, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, + 784, 785, 946, 947, 788, 789, 750, 751, 752, 753, 754, 755, 756, + 757, 758, 759, 794, 795, 956, 957, 798, 799, 760, 761, 762, 763, + 764, 765, 766, 767, 768, 769, 786, 787, 966, 967, 988, 989, 770, + 771, 772, 773, 774, 775, 776, 777, 778, 779, 796, 797, 976, 977, + 998, 999}; +#endif + +#if defined(DEC_DPD2BINK) && DEC_DPD2BINK==1 && !defined(DECDPD2BINK) +#define DECDPD2BINK + +const uint32_t DPD2BINK[1024]={ 0, 1000, 2000, 3000, 4000, 5000, + 6000, 7000, 8000, 9000, 80000, 81000, 800000, 801000, 880000, 881000, + 10000, 11000, 12000, 13000, 14000, 15000, 16000, 17000, 18000, 19000, + 90000, 91000, 810000, 811000, 890000, 891000, 20000, 21000, 22000, 23000, + 24000, 25000, 26000, 27000, 28000, 29000, 82000, 83000, 820000, 821000, + 808000, 809000, 30000, 31000, 32000, 33000, 34000, 35000, 36000, 37000, + 38000, 39000, 92000, 93000, 830000, 831000, 818000, 819000, 40000, 41000, + 42000, 43000, 44000, 45000, 46000, 47000, 48000, 49000, 84000, 85000, + 840000, 841000, 88000, 89000, 50000, 51000, 52000, 53000, 54000, 55000, + 56000, 57000, 58000, 59000, 94000, 95000, 850000, 851000, 98000, 99000, + 60000, 61000, 62000, 63000, 64000, 65000, 66000, 67000, 68000, 69000, + 86000, 87000, 860000, 861000, 888000, 889000, 70000, 71000, 72000, 73000, + 74000, 75000, 76000, 77000, 78000, 79000, 96000, 97000, 870000, 871000, + 898000, 899000, 100000, 101000, 102000, 103000, 104000, 105000, 106000, 107000, + 108000, 109000, 180000, 181000, 900000, 901000, 980000, 981000, 110000, 111000, + 112000, 113000, 114000, 115000, 116000, 117000, 118000, 119000, 190000, 191000, + 910000, 911000, 990000, 991000, 120000, 121000, 122000, 123000, 124000, 125000, + 126000, 127000, 128000, 129000, 182000, 183000, 920000, 921000, 908000, 909000, + 130000, 131000, 132000, 133000, 134000, 135000, 136000, 137000, 138000, 139000, + 192000, 193000, 930000, 931000, 918000, 919000, 140000, 141000, 142000, 143000, + 144000, 145000, 146000, 147000, 148000, 149000, 184000, 185000, 940000, 941000, + 188000, 189000, 150000, 151000, 152000, 153000, 154000, 155000, 156000, 157000, + 158000, 159000, 194000, 195000, 950000, 951000, 198000, 199000, 160000, 161000, + 162000, 163000, 164000, 165000, 166000, 167000, 168000, 169000, 186000, 187000, + 960000, 961000, 988000, 989000, 170000, 171000, 172000, 173000, 174000, 175000, + 176000, 177000, 178000, 179000, 196000, 197000, 970000, 971000, 998000, 999000, + 200000, 201000, 202000, 203000, 204000, 205000, 206000, 207000, 208000, 209000, + 280000, 281000, 802000, 803000, 882000, 883000, 210000, 211000, 212000, 213000, + 214000, 215000, 216000, 217000, 218000, 219000, 290000, 291000, 812000, 813000, + 892000, 893000, 220000, 221000, 222000, 223000, 224000, 225000, 226000, 227000, + 228000, 229000, 282000, 283000, 822000, 823000, 828000, 829000, 230000, 231000, + 232000, 233000, 234000, 235000, 236000, 237000, 238000, 239000, 292000, 293000, + 832000, 833000, 838000, 839000, 240000, 241000, 242000, 243000, 244000, 245000, + 246000, 247000, 248000, 249000, 284000, 285000, 842000, 843000, 288000, 289000, + 250000, 251000, 252000, 253000, 254000, 255000, 256000, 257000, 258000, 259000, + 294000, 295000, 852000, 853000, 298000, 299000, 260000, 261000, 262000, 263000, + 264000, 265000, 266000, 267000, 268000, 269000, 286000, 287000, 862000, 863000, + 888000, 889000, 270000, 271000, 272000, 273000, 274000, 275000, 276000, 277000, + 278000, 279000, 296000, 297000, 872000, 873000, 898000, 899000, 300000, 301000, + 302000, 303000, 304000, 305000, 306000, 307000, 308000, 309000, 380000, 381000, + 902000, 903000, 982000, 983000, 310000, 311000, 312000, 313000, 314000, 315000, + 316000, 317000, 318000, 319000, 390000, 391000, 912000, 913000, 992000, 993000, + 320000, 321000, 322000, 323000, 324000, 325000, 326000, 327000, 328000, 329000, + 382000, 383000, 922000, 923000, 928000, 929000, 330000, 331000, 332000, 333000, + 334000, 335000, 336000, 337000, 338000, 339000, 392000, 393000, 932000, 933000, + 938000, 939000, 340000, 341000, 342000, 343000, 344000, 345000, 346000, 347000, + 348000, 349000, 384000, 385000, 942000, 943000, 388000, 389000, 350000, 351000, + 352000, 353000, 354000, 355000, 356000, 357000, 358000, 359000, 394000, 395000, + 952000, 953000, 398000, 399000, 360000, 361000, 362000, 363000, 364000, 365000, + 366000, 367000, 368000, 369000, 386000, 387000, 962000, 963000, 988000, 989000, + 370000, 371000, 372000, 373000, 374000, 375000, 376000, 377000, 378000, 379000, + 396000, 397000, 972000, 973000, 998000, 999000, 400000, 401000, 402000, 403000, + 404000, 405000, 406000, 407000, 408000, 409000, 480000, 481000, 804000, 805000, + 884000, 885000, 410000, 411000, 412000, 413000, 414000, 415000, 416000, 417000, + 418000, 419000, 490000, 491000, 814000, 815000, 894000, 895000, 420000, 421000, + 422000, 423000, 424000, 425000, 426000, 427000, 428000, 429000, 482000, 483000, + 824000, 825000, 848000, 849000, 430000, 431000, 432000, 433000, 434000, 435000, + 436000, 437000, 438000, 439000, 492000, 493000, 834000, 835000, 858000, 859000, + 440000, 441000, 442000, 443000, 444000, 445000, 446000, 447000, 448000, 449000, + 484000, 485000, 844000, 845000, 488000, 489000, 450000, 451000, 452000, 453000, + 454000, 455000, 456000, 457000, 458000, 459000, 494000, 495000, 854000, 855000, + 498000, 499000, 460000, 461000, 462000, 463000, 464000, 465000, 466000, 467000, + 468000, 469000, 486000, 487000, 864000, 865000, 888000, 889000, 470000, 471000, + 472000, 473000, 474000, 475000, 476000, 477000, 478000, 479000, 496000, 497000, + 874000, 875000, 898000, 899000, 500000, 501000, 502000, 503000, 504000, 505000, + 506000, 507000, 508000, 509000, 580000, 581000, 904000, 905000, 984000, 985000, + 510000, 511000, 512000, 513000, 514000, 515000, 516000, 517000, 518000, 519000, + 590000, 591000, 914000, 915000, 994000, 995000, 520000, 521000, 522000, 523000, + 524000, 525000, 526000, 527000, 528000, 529000, 582000, 583000, 924000, 925000, + 948000, 949000, 530000, 531000, 532000, 533000, 534000, 535000, 536000, 537000, + 538000, 539000, 592000, 593000, 934000, 935000, 958000, 959000, 540000, 541000, + 542000, 543000, 544000, 545000, 546000, 547000, 548000, 549000, 584000, 585000, + 944000, 945000, 588000, 589000, 550000, 551000, 552000, 553000, 554000, 555000, + 556000, 557000, 558000, 559000, 594000, 595000, 954000, 955000, 598000, 599000, + 560000, 561000, 562000, 563000, 564000, 565000, 566000, 567000, 568000, 569000, + 586000, 587000, 964000, 965000, 988000, 989000, 570000, 571000, 572000, 573000, + 574000, 575000, 576000, 577000, 578000, 579000, 596000, 597000, 974000, 975000, + 998000, 999000, 600000, 601000, 602000, 603000, 604000, 605000, 606000, 607000, + 608000, 609000, 680000, 681000, 806000, 807000, 886000, 887000, 610000, 611000, + 612000, 613000, 614000, 615000, 616000, 617000, 618000, 619000, 690000, 691000, + 816000, 817000, 896000, 897000, 620000, 621000, 622000, 623000, 624000, 625000, + 626000, 627000, 628000, 629000, 682000, 683000, 826000, 827000, 868000, 869000, + 630000, 631000, 632000, 633000, 634000, 635000, 636000, 637000, 638000, 639000, + 692000, 693000, 836000, 837000, 878000, 879000, 640000, 641000, 642000, 643000, + 644000, 645000, 646000, 647000, 648000, 649000, 684000, 685000, 846000, 847000, + 688000, 689000, 650000, 651000, 652000, 653000, 654000, 655000, 656000, 657000, + 658000, 659000, 694000, 695000, 856000, 857000, 698000, 699000, 660000, 661000, + 662000, 663000, 664000, 665000, 666000, 667000, 668000, 669000, 686000, 687000, + 866000, 867000, 888000, 889000, 670000, 671000, 672000, 673000, 674000, 675000, + 676000, 677000, 678000, 679000, 696000, 697000, 876000, 877000, 898000, 899000, + 700000, 701000, 702000, 703000, 704000, 705000, 706000, 707000, 708000, 709000, + 780000, 781000, 906000, 907000, 986000, 987000, 710000, 711000, 712000, 713000, + 714000, 715000, 716000, 717000, 718000, 719000, 790000, 791000, 916000, 917000, + 996000, 997000, 720000, 721000, 722000, 723000, 724000, 725000, 726000, 727000, + 728000, 729000, 782000, 783000, 926000, 927000, 968000, 969000, 730000, 731000, + 732000, 733000, 734000, 735000, 736000, 737000, 738000, 739000, 792000, 793000, + 936000, 937000, 978000, 979000, 740000, 741000, 742000, 743000, 744000, 745000, + 746000, 747000, 748000, 749000, 784000, 785000, 946000, 947000, 788000, 789000, + 750000, 751000, 752000, 753000, 754000, 755000, 756000, 757000, 758000, 759000, + 794000, 795000, 956000, 957000, 798000, 799000, 760000, 761000, 762000, 763000, + 764000, 765000, 766000, 767000, 768000, 769000, 786000, 787000, 966000, 967000, + 988000, 989000, 770000, 771000, 772000, 773000, 774000, 775000, 776000, 777000, + 778000, 779000, 796000, 797000, 976000, 977000, 998000, 999000}; +#endif + +#if defined(DEC_DPD2BINM) && DEC_DPD2BINM==1 && !defined(DECDPD2BINM) +#define DECDPD2BINM + +const uint32_t DPD2BINM[1024]={0, 1000000, 2000000, 3000000, 4000000, + 5000000, 6000000, 7000000, 8000000, 9000000, 80000000, 81000000, + 800000000, 801000000, 880000000, 881000000, 10000000, 11000000, 12000000, + 13000000, 14000000, 15000000, 16000000, 17000000, 18000000, 19000000, + 90000000, 91000000, 810000000, 811000000, 890000000, 891000000, 20000000, + 21000000, 22000000, 23000000, 24000000, 25000000, 26000000, 27000000, + 28000000, 29000000, 82000000, 83000000, 820000000, 821000000, 808000000, + 809000000, 30000000, 31000000, 32000000, 33000000, 34000000, 35000000, + 36000000, 37000000, 38000000, 39000000, 92000000, 93000000, 830000000, + 831000000, 818000000, 819000000, 40000000, 41000000, 42000000, 43000000, + 44000000, 45000000, 46000000, 47000000, 48000000, 49000000, 84000000, + 85000000, 840000000, 841000000, 88000000, 89000000, 50000000, 51000000, + 52000000, 53000000, 54000000, 55000000, 56000000, 57000000, 58000000, + 59000000, 94000000, 95000000, 850000000, 851000000, 98000000, 99000000, + 60000000, 61000000, 62000000, 63000000, 64000000, 65000000, 66000000, + 67000000, 68000000, 69000000, 86000000, 87000000, 860000000, 861000000, + 888000000, 889000000, 70000000, 71000000, 72000000, 73000000, 74000000, + 75000000, 76000000, 77000000, 78000000, 79000000, 96000000, 97000000, + 870000000, 871000000, 898000000, 899000000, 100000000, 101000000, 102000000, + 103000000, 104000000, 105000000, 106000000, 107000000, 108000000, 109000000, + 180000000, 181000000, 900000000, 901000000, 980000000, 981000000, 110000000, + 111000000, 112000000, 113000000, 114000000, 115000000, 116000000, 117000000, + 118000000, 119000000, 190000000, 191000000, 910000000, 911000000, 990000000, + 991000000, 120000000, 121000000, 122000000, 123000000, 124000000, 125000000, + 126000000, 127000000, 128000000, 129000000, 182000000, 183000000, 920000000, + 921000000, 908000000, 909000000, 130000000, 131000000, 132000000, 133000000, + 134000000, 135000000, 136000000, 137000000, 138000000, 139000000, 192000000, + 193000000, 930000000, 931000000, 918000000, 919000000, 140000000, 141000000, + 142000000, 143000000, 144000000, 145000000, 146000000, 147000000, 148000000, + 149000000, 184000000, 185000000, 940000000, 941000000, 188000000, 189000000, + 150000000, 151000000, 152000000, 153000000, 154000000, 155000000, 156000000, + 157000000, 158000000, 159000000, 194000000, 195000000, 950000000, 951000000, + 198000000, 199000000, 160000000, 161000000, 162000000, 163000000, 164000000, + 165000000, 166000000, 167000000, 168000000, 169000000, 186000000, 187000000, + 960000000, 961000000, 988000000, 989000000, 170000000, 171000000, 172000000, + 173000000, 174000000, 175000000, 176000000, 177000000, 178000000, 179000000, + 196000000, 197000000, 970000000, 971000000, 998000000, 999000000, 200000000, + 201000000, 202000000, 203000000, 204000000, 205000000, 206000000, 207000000, + 208000000, 209000000, 280000000, 281000000, 802000000, 803000000, 882000000, + 883000000, 210000000, 211000000, 212000000, 213000000, 214000000, 215000000, + 216000000, 217000000, 218000000, 219000000, 290000000, 291000000, 812000000, + 813000000, 892000000, 893000000, 220000000, 221000000, 222000000, 223000000, + 224000000, 225000000, 226000000, 227000000, 228000000, 229000000, 282000000, + 283000000, 822000000, 823000000, 828000000, 829000000, 230000000, 231000000, + 232000000, 233000000, 234000000, 235000000, 236000000, 237000000, 238000000, + 239000000, 292000000, 293000000, 832000000, 833000000, 838000000, 839000000, + 240000000, 241000000, 242000000, 243000000, 244000000, 245000000, 246000000, + 247000000, 248000000, 249000000, 284000000, 285000000, 842000000, 843000000, + 288000000, 289000000, 250000000, 251000000, 252000000, 253000000, 254000000, + 255000000, 256000000, 257000000, 258000000, 259000000, 294000000, 295000000, + 852000000, 853000000, 298000000, 299000000, 260000000, 261000000, 262000000, + 263000000, 264000000, 265000000, 266000000, 267000000, 268000000, 269000000, + 286000000, 287000000, 862000000, 863000000, 888000000, 889000000, 270000000, + 271000000, 272000000, 273000000, 274000000, 275000000, 276000000, 277000000, + 278000000, 279000000, 296000000, 297000000, 872000000, 873000000, 898000000, + 899000000, 300000000, 301000000, 302000000, 303000000, 304000000, 305000000, + 306000000, 307000000, 308000000, 309000000, 380000000, 381000000, 902000000, + 903000000, 982000000, 983000000, 310000000, 311000000, 312000000, 313000000, + 314000000, 315000000, 316000000, 317000000, 318000000, 319000000, 390000000, + 391000000, 912000000, 913000000, 992000000, 993000000, 320000000, 321000000, + 322000000, 323000000, 324000000, 325000000, 326000000, 327000000, 328000000, + 329000000, 382000000, 383000000, 922000000, 923000000, 928000000, 929000000, + 330000000, 331000000, 332000000, 333000000, 334000000, 335000000, 336000000, + 337000000, 338000000, 339000000, 392000000, 393000000, 932000000, 933000000, + 938000000, 939000000, 340000000, 341000000, 342000000, 343000000, 344000000, + 345000000, 346000000, 347000000, 348000000, 349000000, 384000000, 385000000, + 942000000, 943000000, 388000000, 389000000, 350000000, 351000000, 352000000, + 353000000, 354000000, 355000000, 356000000, 357000000, 358000000, 359000000, + 394000000, 395000000, 952000000, 953000000, 398000000, 399000000, 360000000, + 361000000, 362000000, 363000000, 364000000, 365000000, 366000000, 367000000, + 368000000, 369000000, 386000000, 387000000, 962000000, 963000000, 988000000, + 989000000, 370000000, 371000000, 372000000, 373000000, 374000000, 375000000, + 376000000, 377000000, 378000000, 379000000, 396000000, 397000000, 972000000, + 973000000, 998000000, 999000000, 400000000, 401000000, 402000000, 403000000, + 404000000, 405000000, 406000000, 407000000, 408000000, 409000000, 480000000, + 481000000, 804000000, 805000000, 884000000, 885000000, 410000000, 411000000, + 412000000, 413000000, 414000000, 415000000, 416000000, 417000000, 418000000, + 419000000, 490000000, 491000000, 814000000, 815000000, 894000000, 895000000, + 420000000, 421000000, 422000000, 423000000, 424000000, 425000000, 426000000, + 427000000, 428000000, 429000000, 482000000, 483000000, 824000000, 825000000, + 848000000, 849000000, 430000000, 431000000, 432000000, 433000000, 434000000, + 435000000, 436000000, 437000000, 438000000, 439000000, 492000000, 493000000, + 834000000, 835000000, 858000000, 859000000, 440000000, 441000000, 442000000, + 443000000, 444000000, 445000000, 446000000, 447000000, 448000000, 449000000, + 484000000, 485000000, 844000000, 845000000, 488000000, 489000000, 450000000, + 451000000, 452000000, 453000000, 454000000, 455000000, 456000000, 457000000, + 458000000, 459000000, 494000000, 495000000, 854000000, 855000000, 498000000, + 499000000, 460000000, 461000000, 462000000, 463000000, 464000000, 465000000, + 466000000, 467000000, 468000000, 469000000, 486000000, 487000000, 864000000, + 865000000, 888000000, 889000000, 470000000, 471000000, 472000000, 473000000, + 474000000, 475000000, 476000000, 477000000, 478000000, 479000000, 496000000, + 497000000, 874000000, 875000000, 898000000, 899000000, 500000000, 501000000, + 502000000, 503000000, 504000000, 505000000, 506000000, 507000000, 508000000, + 509000000, 580000000, 581000000, 904000000, 905000000, 984000000, 985000000, + 510000000, 511000000, 512000000, 513000000, 514000000, 515000000, 516000000, + 517000000, 518000000, 519000000, 590000000, 591000000, 914000000, 915000000, + 994000000, 995000000, 520000000, 521000000, 522000000, 523000000, 524000000, + 525000000, 526000000, 527000000, 528000000, 529000000, 582000000, 583000000, + 924000000, 925000000, 948000000, 949000000, 530000000, 531000000, 532000000, + 533000000, 534000000, 535000000, 536000000, 537000000, 538000000, 539000000, + 592000000, 593000000, 934000000, 935000000, 958000000, 959000000, 540000000, + 541000000, 542000000, 543000000, 544000000, 545000000, 546000000, 547000000, + 548000000, 549000000, 584000000, 585000000, 944000000, 945000000, 588000000, + 589000000, 550000000, 551000000, 552000000, 553000000, 554000000, 555000000, + 556000000, 557000000, 558000000, 559000000, 594000000, 595000000, 954000000, + 955000000, 598000000, 599000000, 560000000, 561000000, 562000000, 563000000, + 564000000, 565000000, 566000000, 567000000, 568000000, 569000000, 586000000, + 587000000, 964000000, 965000000, 988000000, 989000000, 570000000, 571000000, + 572000000, 573000000, 574000000, 575000000, 576000000, 577000000, 578000000, + 579000000, 596000000, 597000000, 974000000, 975000000, 998000000, 999000000, + 600000000, 601000000, 602000000, 603000000, 604000000, 605000000, 606000000, + 607000000, 608000000, 609000000, 680000000, 681000000, 806000000, 807000000, + 886000000, 887000000, 610000000, 611000000, 612000000, 613000000, 614000000, + 615000000, 616000000, 617000000, 618000000, 619000000, 690000000, 691000000, + 816000000, 817000000, 896000000, 897000000, 620000000, 621000000, 622000000, + 623000000, 624000000, 625000000, 626000000, 627000000, 628000000, 629000000, + 682000000, 683000000, 826000000, 827000000, 868000000, 869000000, 630000000, + 631000000, 632000000, 633000000, 634000000, 635000000, 636000000, 637000000, + 638000000, 639000000, 692000000, 693000000, 836000000, 837000000, 878000000, + 879000000, 640000000, 641000000, 642000000, 643000000, 644000000, 645000000, + 646000000, 647000000, 648000000, 649000000, 684000000, 685000000, 846000000, + 847000000, 688000000, 689000000, 650000000, 651000000, 652000000, 653000000, + 654000000, 655000000, 656000000, 657000000, 658000000, 659000000, 694000000, + 695000000, 856000000, 857000000, 698000000, 699000000, 660000000, 661000000, + 662000000, 663000000, 664000000, 665000000, 666000000, 667000000, 668000000, + 669000000, 686000000, 687000000, 866000000, 867000000, 888000000, 889000000, + 670000000, 671000000, 672000000, 673000000, 674000000, 675000000, 676000000, + 677000000, 678000000, 679000000, 696000000, 697000000, 876000000, 877000000, + 898000000, 899000000, 700000000, 701000000, 702000000, 703000000, 704000000, + 705000000, 706000000, 707000000, 708000000, 709000000, 780000000, 781000000, + 906000000, 907000000, 986000000, 987000000, 710000000, 711000000, 712000000, + 713000000, 714000000, 715000000, 716000000, 717000000, 718000000, 719000000, + 790000000, 791000000, 916000000, 917000000, 996000000, 997000000, 720000000, + 721000000, 722000000, 723000000, 724000000, 725000000, 726000000, 727000000, + 728000000, 729000000, 782000000, 783000000, 926000000, 927000000, 968000000, + 969000000, 730000000, 731000000, 732000000, 733000000, 734000000, 735000000, + 736000000, 737000000, 738000000, 739000000, 792000000, 793000000, 936000000, + 937000000, 978000000, 979000000, 740000000, 741000000, 742000000, 743000000, + 744000000, 745000000, 746000000, 747000000, 748000000, 749000000, 784000000, + 785000000, 946000000, 947000000, 788000000, 789000000, 750000000, 751000000, + 752000000, 753000000, 754000000, 755000000, 756000000, 757000000, 758000000, + 759000000, 794000000, 795000000, 956000000, 957000000, 798000000, 799000000, + 760000000, 761000000, 762000000, 763000000, 764000000, 765000000, 766000000, + 767000000, 768000000, 769000000, 786000000, 787000000, 966000000, 967000000, + 988000000, 989000000, 770000000, 771000000, 772000000, 773000000, 774000000, + 775000000, 776000000, 777000000, 778000000, 779000000, 796000000, 797000000, + 976000000, 977000000, 998000000, 999000000}; +#endif + +#if defined(DEC_BIN2CHAR) && DEC_BIN2CHAR==1 && !defined(DECBIN2CHAR) +#define DECBIN2CHAR + +const uint8_t BIN2CHAR[4001]={ + '\0','0','0','0', '\1','0','0','1', '\1','0','0','2', '\1','0','0','3', '\1','0','0','4', + '\1','0','0','5', '\1','0','0','6', '\1','0','0','7', '\1','0','0','8', '\1','0','0','9', + '\2','0','1','0', '\2','0','1','1', '\2','0','1','2', '\2','0','1','3', '\2','0','1','4', + '\2','0','1','5', '\2','0','1','6', '\2','0','1','7', '\2','0','1','8', '\2','0','1','9', + '\2','0','2','0', '\2','0','2','1', '\2','0','2','2', '\2','0','2','3', '\2','0','2','4', + '\2','0','2','5', '\2','0','2','6', '\2','0','2','7', '\2','0','2','8', '\2','0','2','9', + '\2','0','3','0', '\2','0','3','1', '\2','0','3','2', '\2','0','3','3', '\2','0','3','4', + '\2','0','3','5', '\2','0','3','6', '\2','0','3','7', '\2','0','3','8', '\2','0','3','9', + '\2','0','4','0', '\2','0','4','1', '\2','0','4','2', '\2','0','4','3', '\2','0','4','4', + '\2','0','4','5', '\2','0','4','6', '\2','0','4','7', '\2','0','4','8', '\2','0','4','9', + '\2','0','5','0', '\2','0','5','1', '\2','0','5','2', '\2','0','5','3', '\2','0','5','4', + '\2','0','5','5', '\2','0','5','6', '\2','0','5','7', '\2','0','5','8', '\2','0','5','9', + '\2','0','6','0', '\2','0','6','1', '\2','0','6','2', '\2','0','6','3', '\2','0','6','4', + '\2','0','6','5', '\2','0','6','6', '\2','0','6','7', '\2','0','6','8', '\2','0','6','9', + '\2','0','7','0', '\2','0','7','1', '\2','0','7','2', '\2','0','7','3', '\2','0','7','4', + '\2','0','7','5', '\2','0','7','6', '\2','0','7','7', '\2','0','7','8', '\2','0','7','9', + '\2','0','8','0', '\2','0','8','1', '\2','0','8','2', '\2','0','8','3', '\2','0','8','4', + '\2','0','8','5', '\2','0','8','6', '\2','0','8','7', '\2','0','8','8', '\2','0','8','9', + '\2','0','9','0', '\2','0','9','1', '\2','0','9','2', '\2','0','9','3', '\2','0','9','4', + '\2','0','9','5', '\2','0','9','6', '\2','0','9','7', '\2','0','9','8', '\2','0','9','9', + '\3','1','0','0', '\3','1','0','1', '\3','1','0','2', '\3','1','0','3', '\3','1','0','4', + '\3','1','0','5', '\3','1','0','6', '\3','1','0','7', '\3','1','0','8', '\3','1','0','9', + '\3','1','1','0', '\3','1','1','1', '\3','1','1','2', '\3','1','1','3', '\3','1','1','4', + '\3','1','1','5', '\3','1','1','6', '\3','1','1','7', '\3','1','1','8', '\3','1','1','9', + '\3','1','2','0', '\3','1','2','1', '\3','1','2','2', '\3','1','2','3', '\3','1','2','4', + '\3','1','2','5', '\3','1','2','6', '\3','1','2','7', '\3','1','2','8', '\3','1','2','9', + '\3','1','3','0', '\3','1','3','1', '\3','1','3','2', '\3','1','3','3', '\3','1','3','4', + '\3','1','3','5', '\3','1','3','6', '\3','1','3','7', '\3','1','3','8', '\3','1','3','9', + '\3','1','4','0', '\3','1','4','1', '\3','1','4','2', '\3','1','4','3', '\3','1','4','4', + '\3','1','4','5', '\3','1','4','6', '\3','1','4','7', '\3','1','4','8', '\3','1','4','9', + '\3','1','5','0', '\3','1','5','1', '\3','1','5','2', '\3','1','5','3', '\3','1','5','4', + '\3','1','5','5', '\3','1','5','6', '\3','1','5','7', '\3','1','5','8', '\3','1','5','9', + '\3','1','6','0', '\3','1','6','1', '\3','1','6','2', '\3','1','6','3', '\3','1','6','4', + '\3','1','6','5', '\3','1','6','6', '\3','1','6','7', '\3','1','6','8', '\3','1','6','9', + '\3','1','7','0', '\3','1','7','1', '\3','1','7','2', '\3','1','7','3', '\3','1','7','4', + '\3','1','7','5', '\3','1','7','6', '\3','1','7','7', '\3','1','7','8', '\3','1','7','9', + '\3','1','8','0', '\3','1','8','1', '\3','1','8','2', '\3','1','8','3', '\3','1','8','4', + '\3','1','8','5', '\3','1','8','6', '\3','1','8','7', '\3','1','8','8', '\3','1','8','9', + '\3','1','9','0', '\3','1','9','1', '\3','1','9','2', '\3','1','9','3', '\3','1','9','4', + '\3','1','9','5', '\3','1','9','6', '\3','1','9','7', '\3','1','9','8', '\3','1','9','9', + '\3','2','0','0', '\3','2','0','1', '\3','2','0','2', '\3','2','0','3', '\3','2','0','4', + '\3','2','0','5', '\3','2','0','6', '\3','2','0','7', '\3','2','0','8', '\3','2','0','9', + '\3','2','1','0', '\3','2','1','1', '\3','2','1','2', '\3','2','1','3', '\3','2','1','4', + '\3','2','1','5', '\3','2','1','6', '\3','2','1','7', '\3','2','1','8', '\3','2','1','9', + '\3','2','2','0', '\3','2','2','1', '\3','2','2','2', '\3','2','2','3', '\3','2','2','4', + '\3','2','2','5', '\3','2','2','6', '\3','2','2','7', '\3','2','2','8', '\3','2','2','9', + '\3','2','3','0', '\3','2','3','1', '\3','2','3','2', '\3','2','3','3', '\3','2','3','4', + '\3','2','3','5', '\3','2','3','6', '\3','2','3','7', '\3','2','3','8', '\3','2','3','9', + '\3','2','4','0', '\3','2','4','1', '\3','2','4','2', '\3','2','4','3', '\3','2','4','4', + '\3','2','4','5', '\3','2','4','6', '\3','2','4','7', '\3','2','4','8', '\3','2','4','9', + '\3','2','5','0', '\3','2','5','1', '\3','2','5','2', '\3','2','5','3', '\3','2','5','4', + '\3','2','5','5', '\3','2','5','6', '\3','2','5','7', '\3','2','5','8', '\3','2','5','9', + '\3','2','6','0', '\3','2','6','1', '\3','2','6','2', '\3','2','6','3', '\3','2','6','4', + '\3','2','6','5', '\3','2','6','6', '\3','2','6','7', '\3','2','6','8', '\3','2','6','9', + '\3','2','7','0', '\3','2','7','1', '\3','2','7','2', '\3','2','7','3', '\3','2','7','4', + '\3','2','7','5', '\3','2','7','6', '\3','2','7','7', '\3','2','7','8', '\3','2','7','9', + '\3','2','8','0', '\3','2','8','1', '\3','2','8','2', '\3','2','8','3', '\3','2','8','4', + '\3','2','8','5', '\3','2','8','6', '\3','2','8','7', '\3','2','8','8', '\3','2','8','9', + '\3','2','9','0', '\3','2','9','1', '\3','2','9','2', '\3','2','9','3', '\3','2','9','4', + '\3','2','9','5', '\3','2','9','6', '\3','2','9','7', '\3','2','9','8', '\3','2','9','9', + '\3','3','0','0', '\3','3','0','1', '\3','3','0','2', '\3','3','0','3', '\3','3','0','4', + '\3','3','0','5', '\3','3','0','6', '\3','3','0','7', '\3','3','0','8', '\3','3','0','9', + '\3','3','1','0', '\3','3','1','1', '\3','3','1','2', '\3','3','1','3', '\3','3','1','4', + '\3','3','1','5', '\3','3','1','6', '\3','3','1','7', '\3','3','1','8', '\3','3','1','9', + '\3','3','2','0', '\3','3','2','1', '\3','3','2','2', '\3','3','2','3', '\3','3','2','4', + '\3','3','2','5', '\3','3','2','6', '\3','3','2','7', '\3','3','2','8', '\3','3','2','9', + '\3','3','3','0', '\3','3','3','1', '\3','3','3','2', '\3','3','3','3', '\3','3','3','4', + '\3','3','3','5', '\3','3','3','6', '\3','3','3','7', '\3','3','3','8', '\3','3','3','9', + '\3','3','4','0', '\3','3','4','1', '\3','3','4','2', '\3','3','4','3', '\3','3','4','4', + '\3','3','4','5', '\3','3','4','6', '\3','3','4','7', '\3','3','4','8', '\3','3','4','9', + '\3','3','5','0', '\3','3','5','1', '\3','3','5','2', '\3','3','5','3', '\3','3','5','4', + '\3','3','5','5', '\3','3','5','6', '\3','3','5','7', '\3','3','5','8', '\3','3','5','9', + '\3','3','6','0', '\3','3','6','1', '\3','3','6','2', '\3','3','6','3', '\3','3','6','4', + '\3','3','6','5', '\3','3','6','6', '\3','3','6','7', '\3','3','6','8', '\3','3','6','9', + '\3','3','7','0', '\3','3','7','1', '\3','3','7','2', '\3','3','7','3', '\3','3','7','4', + '\3','3','7','5', '\3','3','7','6', '\3','3','7','7', '\3','3','7','8', '\3','3','7','9', + '\3','3','8','0', '\3','3','8','1', '\3','3','8','2', '\3','3','8','3', '\3','3','8','4', + '\3','3','8','5', '\3','3','8','6', '\3','3','8','7', '\3','3','8','8', '\3','3','8','9', + '\3','3','9','0', '\3','3','9','1', '\3','3','9','2', '\3','3','9','3', '\3','3','9','4', + '\3','3','9','5', '\3','3','9','6', '\3','3','9','7', '\3','3','9','8', '\3','3','9','9', + '\3','4','0','0', '\3','4','0','1', '\3','4','0','2', '\3','4','0','3', '\3','4','0','4', + '\3','4','0','5', '\3','4','0','6', '\3','4','0','7', '\3','4','0','8', '\3','4','0','9', + '\3','4','1','0', '\3','4','1','1', '\3','4','1','2', '\3','4','1','3', '\3','4','1','4', + '\3','4','1','5', '\3','4','1','6', '\3','4','1','7', '\3','4','1','8', '\3','4','1','9', + '\3','4','2','0', '\3','4','2','1', '\3','4','2','2', '\3','4','2','3', '\3','4','2','4', + '\3','4','2','5', '\3','4','2','6', '\3','4','2','7', '\3','4','2','8', '\3','4','2','9', + '\3','4','3','0', '\3','4','3','1', '\3','4','3','2', '\3','4','3','3', '\3','4','3','4', + '\3','4','3','5', '\3','4','3','6', '\3','4','3','7', '\3','4','3','8', '\3','4','3','9', + '\3','4','4','0', '\3','4','4','1', '\3','4','4','2', '\3','4','4','3', '\3','4','4','4', + '\3','4','4','5', '\3','4','4','6', '\3','4','4','7', '\3','4','4','8', '\3','4','4','9', + '\3','4','5','0', '\3','4','5','1', '\3','4','5','2', '\3','4','5','3', '\3','4','5','4', + '\3','4','5','5', '\3','4','5','6', '\3','4','5','7', '\3','4','5','8', '\3','4','5','9', + '\3','4','6','0', '\3','4','6','1', '\3','4','6','2', '\3','4','6','3', '\3','4','6','4', + '\3','4','6','5', '\3','4','6','6', '\3','4','6','7', '\3','4','6','8', '\3','4','6','9', + '\3','4','7','0', '\3','4','7','1', '\3','4','7','2', '\3','4','7','3', '\3','4','7','4', + '\3','4','7','5', '\3','4','7','6', '\3','4','7','7', '\3','4','7','8', '\3','4','7','9', + '\3','4','8','0', '\3','4','8','1', '\3','4','8','2', '\3','4','8','3', '\3','4','8','4', + '\3','4','8','5', '\3','4','8','6', '\3','4','8','7', '\3','4','8','8', '\3','4','8','9', + '\3','4','9','0', '\3','4','9','1', '\3','4','9','2', '\3','4','9','3', '\3','4','9','4', + '\3','4','9','5', '\3','4','9','6', '\3','4','9','7', '\3','4','9','8', '\3','4','9','9', + '\3','5','0','0', '\3','5','0','1', '\3','5','0','2', '\3','5','0','3', '\3','5','0','4', + '\3','5','0','5', '\3','5','0','6', '\3','5','0','7', '\3','5','0','8', '\3','5','0','9', + '\3','5','1','0', '\3','5','1','1', '\3','5','1','2', '\3','5','1','3', '\3','5','1','4', + '\3','5','1','5', '\3','5','1','6', '\3','5','1','7', '\3','5','1','8', '\3','5','1','9', + '\3','5','2','0', '\3','5','2','1', '\3','5','2','2', '\3','5','2','3', '\3','5','2','4', + '\3','5','2','5', '\3','5','2','6', '\3','5','2','7', '\3','5','2','8', '\3','5','2','9', + '\3','5','3','0', '\3','5','3','1', '\3','5','3','2', '\3','5','3','3', '\3','5','3','4', + '\3','5','3','5', '\3','5','3','6', '\3','5','3','7', '\3','5','3','8', '\3','5','3','9', + '\3','5','4','0', '\3','5','4','1', '\3','5','4','2', '\3','5','4','3', '\3','5','4','4', + '\3','5','4','5', '\3','5','4','6', '\3','5','4','7', '\3','5','4','8', '\3','5','4','9', + '\3','5','5','0', '\3','5','5','1', '\3','5','5','2', '\3','5','5','3', '\3','5','5','4', + '\3','5','5','5', '\3','5','5','6', '\3','5','5','7', '\3','5','5','8', '\3','5','5','9', + '\3','5','6','0', '\3','5','6','1', '\3','5','6','2', '\3','5','6','3', '\3','5','6','4', + '\3','5','6','5', '\3','5','6','6', '\3','5','6','7', '\3','5','6','8', '\3','5','6','9', + '\3','5','7','0', '\3','5','7','1', '\3','5','7','2', '\3','5','7','3', '\3','5','7','4', + '\3','5','7','5', '\3','5','7','6', '\3','5','7','7', '\3','5','7','8', '\3','5','7','9', + '\3','5','8','0', '\3','5','8','1', '\3','5','8','2', '\3','5','8','3', '\3','5','8','4', + '\3','5','8','5', '\3','5','8','6', '\3','5','8','7', '\3','5','8','8', '\3','5','8','9', + '\3','5','9','0', '\3','5','9','1', '\3','5','9','2', '\3','5','9','3', '\3','5','9','4', + '\3','5','9','5', '\3','5','9','6', '\3','5','9','7', '\3','5','9','8', '\3','5','9','9', + '\3','6','0','0', '\3','6','0','1', '\3','6','0','2', '\3','6','0','3', '\3','6','0','4', + '\3','6','0','5', '\3','6','0','6', '\3','6','0','7', '\3','6','0','8', '\3','6','0','9', + '\3','6','1','0', '\3','6','1','1', '\3','6','1','2', '\3','6','1','3', '\3','6','1','4', + '\3','6','1','5', '\3','6','1','6', '\3','6','1','7', '\3','6','1','8', '\3','6','1','9', + '\3','6','2','0', '\3','6','2','1', '\3','6','2','2', '\3','6','2','3', '\3','6','2','4', + '\3','6','2','5', '\3','6','2','6', '\3','6','2','7', '\3','6','2','8', '\3','6','2','9', + '\3','6','3','0', '\3','6','3','1', '\3','6','3','2', '\3','6','3','3', '\3','6','3','4', + '\3','6','3','5', '\3','6','3','6', '\3','6','3','7', '\3','6','3','8', '\3','6','3','9', + '\3','6','4','0', '\3','6','4','1', '\3','6','4','2', '\3','6','4','3', '\3','6','4','4', + '\3','6','4','5', '\3','6','4','6', '\3','6','4','7', '\3','6','4','8', '\3','6','4','9', + '\3','6','5','0', '\3','6','5','1', '\3','6','5','2', '\3','6','5','3', '\3','6','5','4', + '\3','6','5','5', '\3','6','5','6', '\3','6','5','7', '\3','6','5','8', '\3','6','5','9', + '\3','6','6','0', '\3','6','6','1', '\3','6','6','2', '\3','6','6','3', '\3','6','6','4', + '\3','6','6','5', '\3','6','6','6', '\3','6','6','7', '\3','6','6','8', '\3','6','6','9', + '\3','6','7','0', '\3','6','7','1', '\3','6','7','2', '\3','6','7','3', '\3','6','7','4', + '\3','6','7','5', '\3','6','7','6', '\3','6','7','7', '\3','6','7','8', '\3','6','7','9', + '\3','6','8','0', '\3','6','8','1', '\3','6','8','2', '\3','6','8','3', '\3','6','8','4', + '\3','6','8','5', '\3','6','8','6', '\3','6','8','7', '\3','6','8','8', '\3','6','8','9', + '\3','6','9','0', '\3','6','9','1', '\3','6','9','2', '\3','6','9','3', '\3','6','9','4', + '\3','6','9','5', '\3','6','9','6', '\3','6','9','7', '\3','6','9','8', '\3','6','9','9', + '\3','7','0','0', '\3','7','0','1', '\3','7','0','2', '\3','7','0','3', '\3','7','0','4', + '\3','7','0','5', '\3','7','0','6', '\3','7','0','7', '\3','7','0','8', '\3','7','0','9', + '\3','7','1','0', '\3','7','1','1', '\3','7','1','2', '\3','7','1','3', '\3','7','1','4', + '\3','7','1','5', '\3','7','1','6', '\3','7','1','7', '\3','7','1','8', '\3','7','1','9', + '\3','7','2','0', '\3','7','2','1', '\3','7','2','2', '\3','7','2','3', '\3','7','2','4', + '\3','7','2','5', '\3','7','2','6', '\3','7','2','7', '\3','7','2','8', '\3','7','2','9', + '\3','7','3','0', '\3','7','3','1', '\3','7','3','2', '\3','7','3','3', '\3','7','3','4', + '\3','7','3','5', '\3','7','3','6', '\3','7','3','7', '\3','7','3','8', '\3','7','3','9', + '\3','7','4','0', '\3','7','4','1', '\3','7','4','2', '\3','7','4','3', '\3','7','4','4', + '\3','7','4','5', '\3','7','4','6', '\3','7','4','7', '\3','7','4','8', '\3','7','4','9', + '\3','7','5','0', '\3','7','5','1', '\3','7','5','2', '\3','7','5','3', '\3','7','5','4', + '\3','7','5','5', '\3','7','5','6', '\3','7','5','7', '\3','7','5','8', '\3','7','5','9', + '\3','7','6','0', '\3','7','6','1', '\3','7','6','2', '\3','7','6','3', '\3','7','6','4', + '\3','7','6','5', '\3','7','6','6', '\3','7','6','7', '\3','7','6','8', '\3','7','6','9', + '\3','7','7','0', '\3','7','7','1', '\3','7','7','2', '\3','7','7','3', '\3','7','7','4', + '\3','7','7','5', '\3','7','7','6', '\3','7','7','7', '\3','7','7','8', '\3','7','7','9', + '\3','7','8','0', '\3','7','8','1', '\3','7','8','2', '\3','7','8','3', '\3','7','8','4', + '\3','7','8','5', '\3','7','8','6', '\3','7','8','7', '\3','7','8','8', '\3','7','8','9', + '\3','7','9','0', '\3','7','9','1', '\3','7','9','2', '\3','7','9','3', '\3','7','9','4', + '\3','7','9','5', '\3','7','9','6', '\3','7','9','7', '\3','7','9','8', '\3','7','9','9', + '\3','8','0','0', '\3','8','0','1', '\3','8','0','2', '\3','8','0','3', '\3','8','0','4', + '\3','8','0','5', '\3','8','0','6', '\3','8','0','7', '\3','8','0','8', '\3','8','0','9', + '\3','8','1','0', '\3','8','1','1', '\3','8','1','2', '\3','8','1','3', '\3','8','1','4', + '\3','8','1','5', '\3','8','1','6', '\3','8','1','7', '\3','8','1','8', '\3','8','1','9', + '\3','8','2','0', '\3','8','2','1', '\3','8','2','2', '\3','8','2','3', '\3','8','2','4', + '\3','8','2','5', '\3','8','2','6', '\3','8','2','7', '\3','8','2','8', '\3','8','2','9', + '\3','8','3','0', '\3','8','3','1', '\3','8','3','2', '\3','8','3','3', '\3','8','3','4', + '\3','8','3','5', '\3','8','3','6', '\3','8','3','7', '\3','8','3','8', '\3','8','3','9', + '\3','8','4','0', '\3','8','4','1', '\3','8','4','2', '\3','8','4','3', '\3','8','4','4', + '\3','8','4','5', '\3','8','4','6', '\3','8','4','7', '\3','8','4','8', '\3','8','4','9', + '\3','8','5','0', '\3','8','5','1', '\3','8','5','2', '\3','8','5','3', '\3','8','5','4', + '\3','8','5','5', '\3','8','5','6', '\3','8','5','7', '\3','8','5','8', '\3','8','5','9', + '\3','8','6','0', '\3','8','6','1', '\3','8','6','2', '\3','8','6','3', '\3','8','6','4', + '\3','8','6','5', '\3','8','6','6', '\3','8','6','7', '\3','8','6','8', '\3','8','6','9', + '\3','8','7','0', '\3','8','7','1', '\3','8','7','2', '\3','8','7','3', '\3','8','7','4', + '\3','8','7','5', '\3','8','7','6', '\3','8','7','7', '\3','8','7','8', '\3','8','7','9', + '\3','8','8','0', '\3','8','8','1', '\3','8','8','2', '\3','8','8','3', '\3','8','8','4', + '\3','8','8','5', '\3','8','8','6', '\3','8','8','7', '\3','8','8','8', '\3','8','8','9', + '\3','8','9','0', '\3','8','9','1', '\3','8','9','2', '\3','8','9','3', '\3','8','9','4', + '\3','8','9','5', '\3','8','9','6', '\3','8','9','7', '\3','8','9','8', '\3','8','9','9', + '\3','9','0','0', '\3','9','0','1', '\3','9','0','2', '\3','9','0','3', '\3','9','0','4', + '\3','9','0','5', '\3','9','0','6', '\3','9','0','7', '\3','9','0','8', '\3','9','0','9', + '\3','9','1','0', '\3','9','1','1', '\3','9','1','2', '\3','9','1','3', '\3','9','1','4', + '\3','9','1','5', '\3','9','1','6', '\3','9','1','7', '\3','9','1','8', '\3','9','1','9', + '\3','9','2','0', '\3','9','2','1', '\3','9','2','2', '\3','9','2','3', '\3','9','2','4', + '\3','9','2','5', '\3','9','2','6', '\3','9','2','7', '\3','9','2','8', '\3','9','2','9', + '\3','9','3','0', '\3','9','3','1', '\3','9','3','2', '\3','9','3','3', '\3','9','3','4', + '\3','9','3','5', '\3','9','3','6', '\3','9','3','7', '\3','9','3','8', '\3','9','3','9', + '\3','9','4','0', '\3','9','4','1', '\3','9','4','2', '\3','9','4','3', '\3','9','4','4', + '\3','9','4','5', '\3','9','4','6', '\3','9','4','7', '\3','9','4','8', '\3','9','4','9', + '\3','9','5','0', '\3','9','5','1', '\3','9','5','2', '\3','9','5','3', '\3','9','5','4', + '\3','9','5','5', '\3','9','5','6', '\3','9','5','7', '\3','9','5','8', '\3','9','5','9', + '\3','9','6','0', '\3','9','6','1', '\3','9','6','2', '\3','9','6','3', '\3','9','6','4', + '\3','9','6','5', '\3','9','6','6', '\3','9','6','7', '\3','9','6','8', '\3','9','6','9', + '\3','9','7','0', '\3','9','7','1', '\3','9','7','2', '\3','9','7','3', '\3','9','7','4', + '\3','9','7','5', '\3','9','7','6', '\3','9','7','7', '\3','9','7','8', '\3','9','7','9', + '\3','9','8','0', '\3','9','8','1', '\3','9','8','2', '\3','9','8','3', '\3','9','8','4', + '\3','9','8','5', '\3','9','8','6', '\3','9','8','7', '\3','9','8','8', '\3','9','8','9', + '\3','9','9','0', '\3','9','9','1', '\3','9','9','2', '\3','9','9','3', '\3','9','9','4', + '\3','9','9','5', '\3','9','9','6', '\3','9','9','7', '\3','9','9','8', '\3','9','9','9', '\0'}; +#endif + +#if defined(DEC_DPD2BCD8) && DEC_DPD2BCD8==1 && !defined(DECDPD2BCD8) +#define DECDPD2BCD8 + +const uint8_t DPD2BCD8[4096]={ + 0,0,0,0, 0,0,1,1, 0,0,2,1, 0,0,3,1, 0,0,4,1, 0,0,5,1, 0,0,6,1, 0,0,7,1, 0,0,8,1, + 0,0,9,1, 0,8,0,2, 0,8,1,2, 8,0,0,3, 8,0,1,3, 8,8,0,3, 8,8,1,3, 0,1,0,2, 0,1,1,2, + 0,1,2,2, 0,1,3,2, 0,1,4,2, 0,1,5,2, 0,1,6,2, 0,1,7,2, 0,1,8,2, 0,1,9,2, 0,9,0,2, + 0,9,1,2, 8,1,0,3, 8,1,1,3, 8,9,0,3, 8,9,1,3, 0,2,0,2, 0,2,1,2, 0,2,2,2, 0,2,3,2, + 0,2,4,2, 0,2,5,2, 0,2,6,2, 0,2,7,2, 0,2,8,2, 0,2,9,2, 0,8,2,2, 0,8,3,2, 8,2,0,3, + 8,2,1,3, 8,0,8,3, 8,0,9,3, 0,3,0,2, 0,3,1,2, 0,3,2,2, 0,3,3,2, 0,3,4,2, 0,3,5,2, + 0,3,6,2, 0,3,7,2, 0,3,8,2, 0,3,9,2, 0,9,2,2, 0,9,3,2, 8,3,0,3, 8,3,1,3, 8,1,8,3, + 8,1,9,3, 0,4,0,2, 0,4,1,2, 0,4,2,2, 0,4,3,2, 0,4,4,2, 0,4,5,2, 0,4,6,2, 0,4,7,2, + 0,4,8,2, 0,4,9,2, 0,8,4,2, 0,8,5,2, 8,4,0,3, 8,4,1,3, 0,8,8,2, 0,8,9,2, 0,5,0,2, + 0,5,1,2, 0,5,2,2, 0,5,3,2, 0,5,4,2, 0,5,5,2, 0,5,6,2, 0,5,7,2, 0,5,8,2, 0,5,9,2, + 0,9,4,2, 0,9,5,2, 8,5,0,3, 8,5,1,3, 0,9,8,2, 0,9,9,2, 0,6,0,2, 0,6,1,2, 0,6,2,2, + 0,6,3,2, 0,6,4,2, 0,6,5,2, 0,6,6,2, 0,6,7,2, 0,6,8,2, 0,6,9,2, 0,8,6,2, 0,8,7,2, + 8,6,0,3, 8,6,1,3, 8,8,8,3, 8,8,9,3, 0,7,0,2, 0,7,1,2, 0,7,2,2, 0,7,3,2, 0,7,4,2, + 0,7,5,2, 0,7,6,2, 0,7,7,2, 0,7,8,2, 0,7,9,2, 0,9,6,2, 0,9,7,2, 8,7,0,3, 8,7,1,3, + 8,9,8,3, 8,9,9,3, 1,0,0,3, 1,0,1,3, 1,0,2,3, 1,0,3,3, 1,0,4,3, 1,0,5,3, 1,0,6,3, + 1,0,7,3, 1,0,8,3, 1,0,9,3, 1,8,0,3, 1,8,1,3, 9,0,0,3, 9,0,1,3, 9,8,0,3, 9,8,1,3, + 1,1,0,3, 1,1,1,3, 1,1,2,3, 1,1,3,3, 1,1,4,3, 1,1,5,3, 1,1,6,3, 1,1,7,3, 1,1,8,3, + 1,1,9,3, 1,9,0,3, 1,9,1,3, 9,1,0,3, 9,1,1,3, 9,9,0,3, 9,9,1,3, 1,2,0,3, 1,2,1,3, + 1,2,2,3, 1,2,3,3, 1,2,4,3, 1,2,5,3, 1,2,6,3, 1,2,7,3, 1,2,8,3, 1,2,9,3, 1,8,2,3, + 1,8,3,3, 9,2,0,3, 9,2,1,3, 9,0,8,3, 9,0,9,3, 1,3,0,3, 1,3,1,3, 1,3,2,3, 1,3,3,3, + 1,3,4,3, 1,3,5,3, 1,3,6,3, 1,3,7,3, 1,3,8,3, 1,3,9,3, 1,9,2,3, 1,9,3,3, 9,3,0,3, + 9,3,1,3, 9,1,8,3, 9,1,9,3, 1,4,0,3, 1,4,1,3, 1,4,2,3, 1,4,3,3, 1,4,4,3, 1,4,5,3, + 1,4,6,3, 1,4,7,3, 1,4,8,3, 1,4,9,3, 1,8,4,3, 1,8,5,3, 9,4,0,3, 9,4,1,3, 1,8,8,3, + 1,8,9,3, 1,5,0,3, 1,5,1,3, 1,5,2,3, 1,5,3,3, 1,5,4,3, 1,5,5,3, 1,5,6,3, 1,5,7,3, + 1,5,8,3, 1,5,9,3, 1,9,4,3, 1,9,5,3, 9,5,0,3, 9,5,1,3, 1,9,8,3, 1,9,9,3, 1,6,0,3, + 1,6,1,3, 1,6,2,3, 1,6,3,3, 1,6,4,3, 1,6,5,3, 1,6,6,3, 1,6,7,3, 1,6,8,3, 1,6,9,3, + 1,8,6,3, 1,8,7,3, 9,6,0,3, 9,6,1,3, 9,8,8,3, 9,8,9,3, 1,7,0,3, 1,7,1,3, 1,7,2,3, + 1,7,3,3, 1,7,4,3, 1,7,5,3, 1,7,6,3, 1,7,7,3, 1,7,8,3, 1,7,9,3, 1,9,6,3, 1,9,7,3, + 9,7,0,3, 9,7,1,3, 9,9,8,3, 9,9,9,3, 2,0,0,3, 2,0,1,3, 2,0,2,3, 2,0,3,3, 2,0,4,3, + 2,0,5,3, 2,0,6,3, 2,0,7,3, 2,0,8,3, 2,0,9,3, 2,8,0,3, 2,8,1,3, 8,0,2,3, 8,0,3,3, + 8,8,2,3, 8,8,3,3, 2,1,0,3, 2,1,1,3, 2,1,2,3, 2,1,3,3, 2,1,4,3, 2,1,5,3, 2,1,6,3, + 2,1,7,3, 2,1,8,3, 2,1,9,3, 2,9,0,3, 2,9,1,3, 8,1,2,3, 8,1,3,3, 8,9,2,3, 8,9,3,3, + 2,2,0,3, 2,2,1,3, 2,2,2,3, 2,2,3,3, 2,2,4,3, 2,2,5,3, 2,2,6,3, 2,2,7,3, 2,2,8,3, + 2,2,9,3, 2,8,2,3, 2,8,3,3, 8,2,2,3, 8,2,3,3, 8,2,8,3, 8,2,9,3, 2,3,0,3, 2,3,1,3, + 2,3,2,3, 2,3,3,3, 2,3,4,3, 2,3,5,3, 2,3,6,3, 2,3,7,3, 2,3,8,3, 2,3,9,3, 2,9,2,3, + 2,9,3,3, 8,3,2,3, 8,3,3,3, 8,3,8,3, 8,3,9,3, 2,4,0,3, 2,4,1,3, 2,4,2,3, 2,4,3,3, + 2,4,4,3, 2,4,5,3, 2,4,6,3, 2,4,7,3, 2,4,8,3, 2,4,9,3, 2,8,4,3, 2,8,5,3, 8,4,2,3, + 8,4,3,3, 2,8,8,3, 2,8,9,3, 2,5,0,3, 2,5,1,3, 2,5,2,3, 2,5,3,3, 2,5,4,3, 2,5,5,3, + 2,5,6,3, 2,5,7,3, 2,5,8,3, 2,5,9,3, 2,9,4,3, 2,9,5,3, 8,5,2,3, 8,5,3,3, 2,9,8,3, + 2,9,9,3, 2,6,0,3, 2,6,1,3, 2,6,2,3, 2,6,3,3, 2,6,4,3, 2,6,5,3, 2,6,6,3, 2,6,7,3, + 2,6,8,3, 2,6,9,3, 2,8,6,3, 2,8,7,3, 8,6,2,3, 8,6,3,3, 8,8,8,3, 8,8,9,3, 2,7,0,3, + 2,7,1,3, 2,7,2,3, 2,7,3,3, 2,7,4,3, 2,7,5,3, 2,7,6,3, 2,7,7,3, 2,7,8,3, 2,7,9,3, + 2,9,6,3, 2,9,7,3, 8,7,2,3, 8,7,3,3, 8,9,8,3, 8,9,9,3, 3,0,0,3, 3,0,1,3, 3,0,2,3, + 3,0,3,3, 3,0,4,3, 3,0,5,3, 3,0,6,3, 3,0,7,3, 3,0,8,3, 3,0,9,3, 3,8,0,3, 3,8,1,3, + 9,0,2,3, 9,0,3,3, 9,8,2,3, 9,8,3,3, 3,1,0,3, 3,1,1,3, 3,1,2,3, 3,1,3,3, 3,1,4,3, + 3,1,5,3, 3,1,6,3, 3,1,7,3, 3,1,8,3, 3,1,9,3, 3,9,0,3, 3,9,1,3, 9,1,2,3, 9,1,3,3, + 9,9,2,3, 9,9,3,3, 3,2,0,3, 3,2,1,3, 3,2,2,3, 3,2,3,3, 3,2,4,3, 3,2,5,3, 3,2,6,3, + 3,2,7,3, 3,2,8,3, 3,2,9,3, 3,8,2,3, 3,8,3,3, 9,2,2,3, 9,2,3,3, 9,2,8,3, 9,2,9,3, + 3,3,0,3, 3,3,1,3, 3,3,2,3, 3,3,3,3, 3,3,4,3, 3,3,5,3, 3,3,6,3, 3,3,7,3, 3,3,8,3, + 3,3,9,3, 3,9,2,3, 3,9,3,3, 9,3,2,3, 9,3,3,3, 9,3,8,3, 9,3,9,3, 3,4,0,3, 3,4,1,3, + 3,4,2,3, 3,4,3,3, 3,4,4,3, 3,4,5,3, 3,4,6,3, 3,4,7,3, 3,4,8,3, 3,4,9,3, 3,8,4,3, + 3,8,5,3, 9,4,2,3, 9,4,3,3, 3,8,8,3, 3,8,9,3, 3,5,0,3, 3,5,1,3, 3,5,2,3, 3,5,3,3, + 3,5,4,3, 3,5,5,3, 3,5,6,3, 3,5,7,3, 3,5,8,3, 3,5,9,3, 3,9,4,3, 3,9,5,3, 9,5,2,3, + 9,5,3,3, 3,9,8,3, 3,9,9,3, 3,6,0,3, 3,6,1,3, 3,6,2,3, 3,6,3,3, 3,6,4,3, 3,6,5,3, + 3,6,6,3, 3,6,7,3, 3,6,8,3, 3,6,9,3, 3,8,6,3, 3,8,7,3, 9,6,2,3, 9,6,3,3, 9,8,8,3, + 9,8,9,3, 3,7,0,3, 3,7,1,3, 3,7,2,3, 3,7,3,3, 3,7,4,3, 3,7,5,3, 3,7,6,3, 3,7,7,3, + 3,7,8,3, 3,7,9,3, 3,9,6,3, 3,9,7,3, 9,7,2,3, 9,7,3,3, 9,9,8,3, 9,9,9,3, 4,0,0,3, + 4,0,1,3, 4,0,2,3, 4,0,3,3, 4,0,4,3, 4,0,5,3, 4,0,6,3, 4,0,7,3, 4,0,8,3, 4,0,9,3, + 4,8,0,3, 4,8,1,3, 8,0,4,3, 8,0,5,3, 8,8,4,3, 8,8,5,3, 4,1,0,3, 4,1,1,3, 4,1,2,3, + 4,1,3,3, 4,1,4,3, 4,1,5,3, 4,1,6,3, 4,1,7,3, 4,1,8,3, 4,1,9,3, 4,9,0,3, 4,9,1,3, + 8,1,4,3, 8,1,5,3, 8,9,4,3, 8,9,5,3, 4,2,0,3, 4,2,1,3, 4,2,2,3, 4,2,3,3, 4,2,4,3, + 4,2,5,3, 4,2,6,3, 4,2,7,3, 4,2,8,3, 4,2,9,3, 4,8,2,3, 4,8,3,3, 8,2,4,3, 8,2,5,3, + 8,4,8,3, 8,4,9,3, 4,3,0,3, 4,3,1,3, 4,3,2,3, 4,3,3,3, 4,3,4,3, 4,3,5,3, 4,3,6,3, + 4,3,7,3, 4,3,8,3, 4,3,9,3, 4,9,2,3, 4,9,3,3, 8,3,4,3, 8,3,5,3, 8,5,8,3, 8,5,9,3, + 4,4,0,3, 4,4,1,3, 4,4,2,3, 4,4,3,3, 4,4,4,3, 4,4,5,3, 4,4,6,3, 4,4,7,3, 4,4,8,3, + 4,4,9,3, 4,8,4,3, 4,8,5,3, 8,4,4,3, 8,4,5,3, 4,8,8,3, 4,8,9,3, 4,5,0,3, 4,5,1,3, + 4,5,2,3, 4,5,3,3, 4,5,4,3, 4,5,5,3, 4,5,6,3, 4,5,7,3, 4,5,8,3, 4,5,9,3, 4,9,4,3, + 4,9,5,3, 8,5,4,3, 8,5,5,3, 4,9,8,3, 4,9,9,3, 4,6,0,3, 4,6,1,3, 4,6,2,3, 4,6,3,3, + 4,6,4,3, 4,6,5,3, 4,6,6,3, 4,6,7,3, 4,6,8,3, 4,6,9,3, 4,8,6,3, 4,8,7,3, 8,6,4,3, + 8,6,5,3, 8,8,8,3, 8,8,9,3, 4,7,0,3, 4,7,1,3, 4,7,2,3, 4,7,3,3, 4,7,4,3, 4,7,5,3, + 4,7,6,3, 4,7,7,3, 4,7,8,3, 4,7,9,3, 4,9,6,3, 4,9,7,3, 8,7,4,3, 8,7,5,3, 8,9,8,3, + 8,9,9,3, 5,0,0,3, 5,0,1,3, 5,0,2,3, 5,0,3,3, 5,0,4,3, 5,0,5,3, 5,0,6,3, 5,0,7,3, + 5,0,8,3, 5,0,9,3, 5,8,0,3, 5,8,1,3, 9,0,4,3, 9,0,5,3, 9,8,4,3, 9,8,5,3, 5,1,0,3, + 5,1,1,3, 5,1,2,3, 5,1,3,3, 5,1,4,3, 5,1,5,3, 5,1,6,3, 5,1,7,3, 5,1,8,3, 5,1,9,3, + 5,9,0,3, 5,9,1,3, 9,1,4,3, 9,1,5,3, 9,9,4,3, 9,9,5,3, 5,2,0,3, 5,2,1,3, 5,2,2,3, + 5,2,3,3, 5,2,4,3, 5,2,5,3, 5,2,6,3, 5,2,7,3, 5,2,8,3, 5,2,9,3, 5,8,2,3, 5,8,3,3, + 9,2,4,3, 9,2,5,3, 9,4,8,3, 9,4,9,3, 5,3,0,3, 5,3,1,3, 5,3,2,3, 5,3,3,3, 5,3,4,3, + 5,3,5,3, 5,3,6,3, 5,3,7,3, 5,3,8,3, 5,3,9,3, 5,9,2,3, 5,9,3,3, 9,3,4,3, 9,3,5,3, + 9,5,8,3, 9,5,9,3, 5,4,0,3, 5,4,1,3, 5,4,2,3, 5,4,3,3, 5,4,4,3, 5,4,5,3, 5,4,6,3, + 5,4,7,3, 5,4,8,3, 5,4,9,3, 5,8,4,3, 5,8,5,3, 9,4,4,3, 9,4,5,3, 5,8,8,3, 5,8,9,3, + 5,5,0,3, 5,5,1,3, 5,5,2,3, 5,5,3,3, 5,5,4,3, 5,5,5,3, 5,5,6,3, 5,5,7,3, 5,5,8,3, + 5,5,9,3, 5,9,4,3, 5,9,5,3, 9,5,4,3, 9,5,5,3, 5,9,8,3, 5,9,9,3, 5,6,0,3, 5,6,1,3, + 5,6,2,3, 5,6,3,3, 5,6,4,3, 5,6,5,3, 5,6,6,3, 5,6,7,3, 5,6,8,3, 5,6,9,3, 5,8,6,3, + 5,8,7,3, 9,6,4,3, 9,6,5,3, 9,8,8,3, 9,8,9,3, 5,7,0,3, 5,7,1,3, 5,7,2,3, 5,7,3,3, + 5,7,4,3, 5,7,5,3, 5,7,6,3, 5,7,7,3, 5,7,8,3, 5,7,9,3, 5,9,6,3, 5,9,7,3, 9,7,4,3, + 9,7,5,3, 9,9,8,3, 9,9,9,3, 6,0,0,3, 6,0,1,3, 6,0,2,3, 6,0,3,3, 6,0,4,3, 6,0,5,3, + 6,0,6,3, 6,0,7,3, 6,0,8,3, 6,0,9,3, 6,8,0,3, 6,8,1,3, 8,0,6,3, 8,0,7,3, 8,8,6,3, + 8,8,7,3, 6,1,0,3, 6,1,1,3, 6,1,2,3, 6,1,3,3, 6,1,4,3, 6,1,5,3, 6,1,6,3, 6,1,7,3, + 6,1,8,3, 6,1,9,3, 6,9,0,3, 6,9,1,3, 8,1,6,3, 8,1,7,3, 8,9,6,3, 8,9,7,3, 6,2,0,3, + 6,2,1,3, 6,2,2,3, 6,2,3,3, 6,2,4,3, 6,2,5,3, 6,2,6,3, 6,2,7,3, 6,2,8,3, 6,2,9,3, + 6,8,2,3, 6,8,3,3, 8,2,6,3, 8,2,7,3, 8,6,8,3, 8,6,9,3, 6,3,0,3, 6,3,1,3, 6,3,2,3, + 6,3,3,3, 6,3,4,3, 6,3,5,3, 6,3,6,3, 6,3,7,3, 6,3,8,3, 6,3,9,3, 6,9,2,3, 6,9,3,3, + 8,3,6,3, 8,3,7,3, 8,7,8,3, 8,7,9,3, 6,4,0,3, 6,4,1,3, 6,4,2,3, 6,4,3,3, 6,4,4,3, + 6,4,5,3, 6,4,6,3, 6,4,7,3, 6,4,8,3, 6,4,9,3, 6,8,4,3, 6,8,5,3, 8,4,6,3, 8,4,7,3, + 6,8,8,3, 6,8,9,3, 6,5,0,3, 6,5,1,3, 6,5,2,3, 6,5,3,3, 6,5,4,3, 6,5,5,3, 6,5,6,3, + 6,5,7,3, 6,5,8,3, 6,5,9,3, 6,9,4,3, 6,9,5,3, 8,5,6,3, 8,5,7,3, 6,9,8,3, 6,9,9,3, + 6,6,0,3, 6,6,1,3, 6,6,2,3, 6,6,3,3, 6,6,4,3, 6,6,5,3, 6,6,6,3, 6,6,7,3, 6,6,8,3, + 6,6,9,3, 6,8,6,3, 6,8,7,3, 8,6,6,3, 8,6,7,3, 8,8,8,3, 8,8,9,3, 6,7,0,3, 6,7,1,3, + 6,7,2,3, 6,7,3,3, 6,7,4,3, 6,7,5,3, 6,7,6,3, 6,7,7,3, 6,7,8,3, 6,7,9,3, 6,9,6,3, + 6,9,7,3, 8,7,6,3, 8,7,7,3, 8,9,8,3, 8,9,9,3, 7,0,0,3, 7,0,1,3, 7,0,2,3, 7,0,3,3, + 7,0,4,3, 7,0,5,3, 7,0,6,3, 7,0,7,3, 7,0,8,3, 7,0,9,3, 7,8,0,3, 7,8,1,3, 9,0,6,3, + 9,0,7,3, 9,8,6,3, 9,8,7,3, 7,1,0,3, 7,1,1,3, 7,1,2,3, 7,1,3,3, 7,1,4,3, 7,1,5,3, + 7,1,6,3, 7,1,7,3, 7,1,8,3, 7,1,9,3, 7,9,0,3, 7,9,1,3, 9,1,6,3, 9,1,7,3, 9,9,6,3, + 9,9,7,3, 7,2,0,3, 7,2,1,3, 7,2,2,3, 7,2,3,3, 7,2,4,3, 7,2,5,3, 7,2,6,3, 7,2,7,3, + 7,2,8,3, 7,2,9,3, 7,8,2,3, 7,8,3,3, 9,2,6,3, 9,2,7,3, 9,6,8,3, 9,6,9,3, 7,3,0,3, + 7,3,1,3, 7,3,2,3, 7,3,3,3, 7,3,4,3, 7,3,5,3, 7,3,6,3, 7,3,7,3, 7,3,8,3, 7,3,9,3, + 7,9,2,3, 7,9,3,3, 9,3,6,3, 9,3,7,3, 9,7,8,3, 9,7,9,3, 7,4,0,3, 7,4,1,3, 7,4,2,3, + 7,4,3,3, 7,4,4,3, 7,4,5,3, 7,4,6,3, 7,4,7,3, 7,4,8,3, 7,4,9,3, 7,8,4,3, 7,8,5,3, + 9,4,6,3, 9,4,7,3, 7,8,8,3, 7,8,9,3, 7,5,0,3, 7,5,1,3, 7,5,2,3, 7,5,3,3, 7,5,4,3, + 7,5,5,3, 7,5,6,3, 7,5,7,3, 7,5,8,3, 7,5,9,3, 7,9,4,3, 7,9,5,3, 9,5,6,3, 9,5,7,3, + 7,9,8,3, 7,9,9,3, 7,6,0,3, 7,6,1,3, 7,6,2,3, 7,6,3,3, 7,6,4,3, 7,6,5,3, 7,6,6,3, + 7,6,7,3, 7,6,8,3, 7,6,9,3, 7,8,6,3, 7,8,7,3, 9,6,6,3, 9,6,7,3, 9,8,8,3, 9,8,9,3, + 7,7,0,3, 7,7,1,3, 7,7,2,3, 7,7,3,3, 7,7,4,3, 7,7,5,3, 7,7,6,3, 7,7,7,3, 7,7,8,3, + 7,7,9,3, 7,9,6,3, 7,9,7,3, 9,7,6,3, 9,7,7,3, 9,9,8,3, 9,9,9,3}; +#endif + +#if defined(DEC_BIN2BCD8) && DEC_BIN2BCD8==1 && !defined(DECBIN2BCD8) +#define DECBIN2BCD8 + +const uint8_t BIN2BCD8[4000]={ + 0,0,0,0, 0,0,1,1, 0,0,2,1, 0,0,3,1, 0,0,4,1, 0,0,5,1, 0,0,6,1, 0,0,7,1, 0,0,8,1, + 0,0,9,1, 0,1,0,2, 0,1,1,2, 0,1,2,2, 0,1,3,2, 0,1,4,2, 0,1,5,2, 0,1,6,2, 0,1,7,2, + 0,1,8,2, 0,1,9,2, 0,2,0,2, 0,2,1,2, 0,2,2,2, 0,2,3,2, 0,2,4,2, 0,2,5,2, 0,2,6,2, + 0,2,7,2, 0,2,8,2, 0,2,9,2, 0,3,0,2, 0,3,1,2, 0,3,2,2, 0,3,3,2, 0,3,4,2, 0,3,5,2, + 0,3,6,2, 0,3,7,2, 0,3,8,2, 0,3,9,2, 0,4,0,2, 0,4,1,2, 0,4,2,2, 0,4,3,2, 0,4,4,2, + 0,4,5,2, 0,4,6,2, 0,4,7,2, 0,4,8,2, 0,4,9,2, 0,5,0,2, 0,5,1,2, 0,5,2,2, 0,5,3,2, + 0,5,4,2, 0,5,5,2, 0,5,6,2, 0,5,7,2, 0,5,8,2, 0,5,9,2, 0,6,0,2, 0,6,1,2, 0,6,2,2, + 0,6,3,2, 0,6,4,2, 0,6,5,2, 0,6,6,2, 0,6,7,2, 0,6,8,2, 0,6,9,2, 0,7,0,2, 0,7,1,2, + 0,7,2,2, 0,7,3,2, 0,7,4,2, 0,7,5,2, 0,7,6,2, 0,7,7,2, 0,7,8,2, 0,7,9,2, 0,8,0,2, + 0,8,1,2, 0,8,2,2, 0,8,3,2, 0,8,4,2, 0,8,5,2, 0,8,6,2, 0,8,7,2, 0,8,8,2, 0,8,9,2, + 0,9,0,2, 0,9,1,2, 0,9,2,2, 0,9,3,2, 0,9,4,2, 0,9,5,2, 0,9,6,2, 0,9,7,2, 0,9,8,2, + 0,9,9,2, 1,0,0,3, 1,0,1,3, 1,0,2,3, 1,0,3,3, 1,0,4,3, 1,0,5,3, 1,0,6,3, 1,0,7,3, + 1,0,8,3, 1,0,9,3, 1,1,0,3, 1,1,1,3, 1,1,2,3, 1,1,3,3, 1,1,4,3, 1,1,5,3, 1,1,6,3, + 1,1,7,3, 1,1,8,3, 1,1,9,3, 1,2,0,3, 1,2,1,3, 1,2,2,3, 1,2,3,3, 1,2,4,3, 1,2,5,3, + 1,2,6,3, 1,2,7,3, 1,2,8,3, 1,2,9,3, 1,3,0,3, 1,3,1,3, 1,3,2,3, 1,3,3,3, 1,3,4,3, + 1,3,5,3, 1,3,6,3, 1,3,7,3, 1,3,8,3, 1,3,9,3, 1,4,0,3, 1,4,1,3, 1,4,2,3, 1,4,3,3, + 1,4,4,3, 1,4,5,3, 1,4,6,3, 1,4,7,3, 1,4,8,3, 1,4,9,3, 1,5,0,3, 1,5,1,3, 1,5,2,3, + 1,5,3,3, 1,5,4,3, 1,5,5,3, 1,5,6,3, 1,5,7,3, 1,5,8,3, 1,5,9,3, 1,6,0,3, 1,6,1,3, + 1,6,2,3, 1,6,3,3, 1,6,4,3, 1,6,5,3, 1,6,6,3, 1,6,7,3, 1,6,8,3, 1,6,9,3, 1,7,0,3, + 1,7,1,3, 1,7,2,3, 1,7,3,3, 1,7,4,3, 1,7,5,3, 1,7,6,3, 1,7,7,3, 1,7,8,3, 1,7,9,3, + 1,8,0,3, 1,8,1,3, 1,8,2,3, 1,8,3,3, 1,8,4,3, 1,8,5,3, 1,8,6,3, 1,8,7,3, 1,8,8,3, + 1,8,9,3, 1,9,0,3, 1,9,1,3, 1,9,2,3, 1,9,3,3, 1,9,4,3, 1,9,5,3, 1,9,6,3, 1,9,7,3, + 1,9,8,3, 1,9,9,3, 2,0,0,3, 2,0,1,3, 2,0,2,3, 2,0,3,3, 2,0,4,3, 2,0,5,3, 2,0,6,3, + 2,0,7,3, 2,0,8,3, 2,0,9,3, 2,1,0,3, 2,1,1,3, 2,1,2,3, 2,1,3,3, 2,1,4,3, 2,1,5,3, + 2,1,6,3, 2,1,7,3, 2,1,8,3, 2,1,9,3, 2,2,0,3, 2,2,1,3, 2,2,2,3, 2,2,3,3, 2,2,4,3, + 2,2,5,3, 2,2,6,3, 2,2,7,3, 2,2,8,3, 2,2,9,3, 2,3,0,3, 2,3,1,3, 2,3,2,3, 2,3,3,3, + 2,3,4,3, 2,3,5,3, 2,3,6,3, 2,3,7,3, 2,3,8,3, 2,3,9,3, 2,4,0,3, 2,4,1,3, 2,4,2,3, + 2,4,3,3, 2,4,4,3, 2,4,5,3, 2,4,6,3, 2,4,7,3, 2,4,8,3, 2,4,9,3, 2,5,0,3, 2,5,1,3, + 2,5,2,3, 2,5,3,3, 2,5,4,3, 2,5,5,3, 2,5,6,3, 2,5,7,3, 2,5,8,3, 2,5,9,3, 2,6,0,3, + 2,6,1,3, 2,6,2,3, 2,6,3,3, 2,6,4,3, 2,6,5,3, 2,6,6,3, 2,6,7,3, 2,6,8,3, 2,6,9,3, + 2,7,0,3, 2,7,1,3, 2,7,2,3, 2,7,3,3, 2,7,4,3, 2,7,5,3, 2,7,6,3, 2,7,7,3, 2,7,8,3, + 2,7,9,3, 2,8,0,3, 2,8,1,3, 2,8,2,3, 2,8,3,3, 2,8,4,3, 2,8,5,3, 2,8,6,3, 2,8,7,3, + 2,8,8,3, 2,8,9,3, 2,9,0,3, 2,9,1,3, 2,9,2,3, 2,9,3,3, 2,9,4,3, 2,9,5,3, 2,9,6,3, + 2,9,7,3, 2,9,8,3, 2,9,9,3, 3,0,0,3, 3,0,1,3, 3,0,2,3, 3,0,3,3, 3,0,4,3, 3,0,5,3, + 3,0,6,3, 3,0,7,3, 3,0,8,3, 3,0,9,3, 3,1,0,3, 3,1,1,3, 3,1,2,3, 3,1,3,3, 3,1,4,3, + 3,1,5,3, 3,1,6,3, 3,1,7,3, 3,1,8,3, 3,1,9,3, 3,2,0,3, 3,2,1,3, 3,2,2,3, 3,2,3,3, + 3,2,4,3, 3,2,5,3, 3,2,6,3, 3,2,7,3, 3,2,8,3, 3,2,9,3, 3,3,0,3, 3,3,1,3, 3,3,2,3, + 3,3,3,3, 3,3,4,3, 3,3,5,3, 3,3,6,3, 3,3,7,3, 3,3,8,3, 3,3,9,3, 3,4,0,3, 3,4,1,3, + 3,4,2,3, 3,4,3,3, 3,4,4,3, 3,4,5,3, 3,4,6,3, 3,4,7,3, 3,4,8,3, 3,4,9,3, 3,5,0,3, + 3,5,1,3, 3,5,2,3, 3,5,3,3, 3,5,4,3, 3,5,5,3, 3,5,6,3, 3,5,7,3, 3,5,8,3, 3,5,9,3, + 3,6,0,3, 3,6,1,3, 3,6,2,3, 3,6,3,3, 3,6,4,3, 3,6,5,3, 3,6,6,3, 3,6,7,3, 3,6,8,3, + 3,6,9,3, 3,7,0,3, 3,7,1,3, 3,7,2,3, 3,7,3,3, 3,7,4,3, 3,7,5,3, 3,7,6,3, 3,7,7,3, + 3,7,8,3, 3,7,9,3, 3,8,0,3, 3,8,1,3, 3,8,2,3, 3,8,3,3, 3,8,4,3, 3,8,5,3, 3,8,6,3, + 3,8,7,3, 3,8,8,3, 3,8,9,3, 3,9,0,3, 3,9,1,3, 3,9,2,3, 3,9,3,3, 3,9,4,3, 3,9,5,3, + 3,9,6,3, 3,9,7,3, 3,9,8,3, 3,9,9,3, 4,0,0,3, 4,0,1,3, 4,0,2,3, 4,0,3,3, 4,0,4,3, + 4,0,5,3, 4,0,6,3, 4,0,7,3, 4,0,8,3, 4,0,9,3, 4,1,0,3, 4,1,1,3, 4,1,2,3, 4,1,3,3, + 4,1,4,3, 4,1,5,3, 4,1,6,3, 4,1,7,3, 4,1,8,3, 4,1,9,3, 4,2,0,3, 4,2,1,3, 4,2,2,3, + 4,2,3,3, 4,2,4,3, 4,2,5,3, 4,2,6,3, 4,2,7,3, 4,2,8,3, 4,2,9,3, 4,3,0,3, 4,3,1,3, + 4,3,2,3, 4,3,3,3, 4,3,4,3, 4,3,5,3, 4,3,6,3, 4,3,7,3, 4,3,8,3, 4,3,9,3, 4,4,0,3, + 4,4,1,3, 4,4,2,3, 4,4,3,3, 4,4,4,3, 4,4,5,3, 4,4,6,3, 4,4,7,3, 4,4,8,3, 4,4,9,3, + 4,5,0,3, 4,5,1,3, 4,5,2,3, 4,5,3,3, 4,5,4,3, 4,5,5,3, 4,5,6,3, 4,5,7,3, 4,5,8,3, + 4,5,9,3, 4,6,0,3, 4,6,1,3, 4,6,2,3, 4,6,3,3, 4,6,4,3, 4,6,5,3, 4,6,6,3, 4,6,7,3, + 4,6,8,3, 4,6,9,3, 4,7,0,3, 4,7,1,3, 4,7,2,3, 4,7,3,3, 4,7,4,3, 4,7,5,3, 4,7,6,3, + 4,7,7,3, 4,7,8,3, 4,7,9,3, 4,8,0,3, 4,8,1,3, 4,8,2,3, 4,8,3,3, 4,8,4,3, 4,8,5,3, + 4,8,6,3, 4,8,7,3, 4,8,8,3, 4,8,9,3, 4,9,0,3, 4,9,1,3, 4,9,2,3, 4,9,3,3, 4,9,4,3, + 4,9,5,3, 4,9,6,3, 4,9,7,3, 4,9,8,3, 4,9,9,3, 5,0,0,3, 5,0,1,3, 5,0,2,3, 5,0,3,3, + 5,0,4,3, 5,0,5,3, 5,0,6,3, 5,0,7,3, 5,0,8,3, 5,0,9,3, 5,1,0,3, 5,1,1,3, 5,1,2,3, + 5,1,3,3, 5,1,4,3, 5,1,5,3, 5,1,6,3, 5,1,7,3, 5,1,8,3, 5,1,9,3, 5,2,0,3, 5,2,1,3, + 5,2,2,3, 5,2,3,3, 5,2,4,3, 5,2,5,3, 5,2,6,3, 5,2,7,3, 5,2,8,3, 5,2,9,3, 5,3,0,3, + 5,3,1,3, 5,3,2,3, 5,3,3,3, 5,3,4,3, 5,3,5,3, 5,3,6,3, 5,3,7,3, 5,3,8,3, 5,3,9,3, + 5,4,0,3, 5,4,1,3, 5,4,2,3, 5,4,3,3, 5,4,4,3, 5,4,5,3, 5,4,6,3, 5,4,7,3, 5,4,8,3, + 5,4,9,3, 5,5,0,3, 5,5,1,3, 5,5,2,3, 5,5,3,3, 5,5,4,3, 5,5,5,3, 5,5,6,3, 5,5,7,3, + 5,5,8,3, 5,5,9,3, 5,6,0,3, 5,6,1,3, 5,6,2,3, 5,6,3,3, 5,6,4,3, 5,6,5,3, 5,6,6,3, + 5,6,7,3, 5,6,8,3, 5,6,9,3, 5,7,0,3, 5,7,1,3, 5,7,2,3, 5,7,3,3, 5,7,4,3, 5,7,5,3, + 5,7,6,3, 5,7,7,3, 5,7,8,3, 5,7,9,3, 5,8,0,3, 5,8,1,3, 5,8,2,3, 5,8,3,3, 5,8,4,3, + 5,8,5,3, 5,8,6,3, 5,8,7,3, 5,8,8,3, 5,8,9,3, 5,9,0,3, 5,9,1,3, 5,9,2,3, 5,9,3,3, + 5,9,4,3, 5,9,5,3, 5,9,6,3, 5,9,7,3, 5,9,8,3, 5,9,9,3, 6,0,0,3, 6,0,1,3, 6,0,2,3, + 6,0,3,3, 6,0,4,3, 6,0,5,3, 6,0,6,3, 6,0,7,3, 6,0,8,3, 6,0,9,3, 6,1,0,3, 6,1,1,3, + 6,1,2,3, 6,1,3,3, 6,1,4,3, 6,1,5,3, 6,1,6,3, 6,1,7,3, 6,1,8,3, 6,1,9,3, 6,2,0,3, + 6,2,1,3, 6,2,2,3, 6,2,3,3, 6,2,4,3, 6,2,5,3, 6,2,6,3, 6,2,7,3, 6,2,8,3, 6,2,9,3, + 6,3,0,3, 6,3,1,3, 6,3,2,3, 6,3,3,3, 6,3,4,3, 6,3,5,3, 6,3,6,3, 6,3,7,3, 6,3,8,3, + 6,3,9,3, 6,4,0,3, 6,4,1,3, 6,4,2,3, 6,4,3,3, 6,4,4,3, 6,4,5,3, 6,4,6,3, 6,4,7,3, + 6,4,8,3, 6,4,9,3, 6,5,0,3, 6,5,1,3, 6,5,2,3, 6,5,3,3, 6,5,4,3, 6,5,5,3, 6,5,6,3, + 6,5,7,3, 6,5,8,3, 6,5,9,3, 6,6,0,3, 6,6,1,3, 6,6,2,3, 6,6,3,3, 6,6,4,3, 6,6,5,3, + 6,6,6,3, 6,6,7,3, 6,6,8,3, 6,6,9,3, 6,7,0,3, 6,7,1,3, 6,7,2,3, 6,7,3,3, 6,7,4,3, + 6,7,5,3, 6,7,6,3, 6,7,7,3, 6,7,8,3, 6,7,9,3, 6,8,0,3, 6,8,1,3, 6,8,2,3, 6,8,3,3, + 6,8,4,3, 6,8,5,3, 6,8,6,3, 6,8,7,3, 6,8,8,3, 6,8,9,3, 6,9,0,3, 6,9,1,3, 6,9,2,3, + 6,9,3,3, 6,9,4,3, 6,9,5,3, 6,9,6,3, 6,9,7,3, 6,9,8,3, 6,9,9,3, 7,0,0,3, 7,0,1,3, + 7,0,2,3, 7,0,3,3, 7,0,4,3, 7,0,5,3, 7,0,6,3, 7,0,7,3, 7,0,8,3, 7,0,9,3, 7,1,0,3, + 7,1,1,3, 7,1,2,3, 7,1,3,3, 7,1,4,3, 7,1,5,3, 7,1,6,3, 7,1,7,3, 7,1,8,3, 7,1,9,3, + 7,2,0,3, 7,2,1,3, 7,2,2,3, 7,2,3,3, 7,2,4,3, 7,2,5,3, 7,2,6,3, 7,2,7,3, 7,2,8,3, + 7,2,9,3, 7,3,0,3, 7,3,1,3, 7,3,2,3, 7,3,3,3, 7,3,4,3, 7,3,5,3, 7,3,6,3, 7,3,7,3, + 7,3,8,3, 7,3,9,3, 7,4,0,3, 7,4,1,3, 7,4,2,3, 7,4,3,3, 7,4,4,3, 7,4,5,3, 7,4,6,3, + 7,4,7,3, 7,4,8,3, 7,4,9,3, 7,5,0,3, 7,5,1,3, 7,5,2,3, 7,5,3,3, 7,5,4,3, 7,5,5,3, + 7,5,6,3, 7,5,7,3, 7,5,8,3, 7,5,9,3, 7,6,0,3, 7,6,1,3, 7,6,2,3, 7,6,3,3, 7,6,4,3, + 7,6,5,3, 7,6,6,3, 7,6,7,3, 7,6,8,3, 7,6,9,3, 7,7,0,3, 7,7,1,3, 7,7,2,3, 7,7,3,3, + 7,7,4,3, 7,7,5,3, 7,7,6,3, 7,7,7,3, 7,7,8,3, 7,7,9,3, 7,8,0,3, 7,8,1,3, 7,8,2,3, + 7,8,3,3, 7,8,4,3, 7,8,5,3, 7,8,6,3, 7,8,7,3, 7,8,8,3, 7,8,9,3, 7,9,0,3, 7,9,1,3, + 7,9,2,3, 7,9,3,3, 7,9,4,3, 7,9,5,3, 7,9,6,3, 7,9,7,3, 7,9,8,3, 7,9,9,3, 8,0,0,3, + 8,0,1,3, 8,0,2,3, 8,0,3,3, 8,0,4,3, 8,0,5,3, 8,0,6,3, 8,0,7,3, 8,0,8,3, 8,0,9,3, + 8,1,0,3, 8,1,1,3, 8,1,2,3, 8,1,3,3, 8,1,4,3, 8,1,5,3, 8,1,6,3, 8,1,7,3, 8,1,8,3, + 8,1,9,3, 8,2,0,3, 8,2,1,3, 8,2,2,3, 8,2,3,3, 8,2,4,3, 8,2,5,3, 8,2,6,3, 8,2,7,3, + 8,2,8,3, 8,2,9,3, 8,3,0,3, 8,3,1,3, 8,3,2,3, 8,3,3,3, 8,3,4,3, 8,3,5,3, 8,3,6,3, + 8,3,7,3, 8,3,8,3, 8,3,9,3, 8,4,0,3, 8,4,1,3, 8,4,2,3, 8,4,3,3, 8,4,4,3, 8,4,5,3, + 8,4,6,3, 8,4,7,3, 8,4,8,3, 8,4,9,3, 8,5,0,3, 8,5,1,3, 8,5,2,3, 8,5,3,3, 8,5,4,3, + 8,5,5,3, 8,5,6,3, 8,5,7,3, 8,5,8,3, 8,5,9,3, 8,6,0,3, 8,6,1,3, 8,6,2,3, 8,6,3,3, + 8,6,4,3, 8,6,5,3, 8,6,6,3, 8,6,7,3, 8,6,8,3, 8,6,9,3, 8,7,0,3, 8,7,1,3, 8,7,2,3, + 8,7,3,3, 8,7,4,3, 8,7,5,3, 8,7,6,3, 8,7,7,3, 8,7,8,3, 8,7,9,3, 8,8,0,3, 8,8,1,3, + 8,8,2,3, 8,8,3,3, 8,8,4,3, 8,8,5,3, 8,8,6,3, 8,8,7,3, 8,8,8,3, 8,8,9,3, 8,9,0,3, + 8,9,1,3, 8,9,2,3, 8,9,3,3, 8,9,4,3, 8,9,5,3, 8,9,6,3, 8,9,7,3, 8,9,8,3, 8,9,9,3, + 9,0,0,3, 9,0,1,3, 9,0,2,3, 9,0,3,3, 9,0,4,3, 9,0,5,3, 9,0,6,3, 9,0,7,3, 9,0,8,3, + 9,0,9,3, 9,1,0,3, 9,1,1,3, 9,1,2,3, 9,1,3,3, 9,1,4,3, 9,1,5,3, 9,1,6,3, 9,1,7,3, + 9,1,8,3, 9,1,9,3, 9,2,0,3, 9,2,1,3, 9,2,2,3, 9,2,3,3, 9,2,4,3, 9,2,5,3, 9,2,6,3, + 9,2,7,3, 9,2,8,3, 9,2,9,3, 9,3,0,3, 9,3,1,3, 9,3,2,3, 9,3,3,3, 9,3,4,3, 9,3,5,3, + 9,3,6,3, 9,3,7,3, 9,3,8,3, 9,3,9,3, 9,4,0,3, 9,4,1,3, 9,4,2,3, 9,4,3,3, 9,4,4,3, + 9,4,5,3, 9,4,6,3, 9,4,7,3, 9,4,8,3, 9,4,9,3, 9,5,0,3, 9,5,1,3, 9,5,2,3, 9,5,3,3, + 9,5,4,3, 9,5,5,3, 9,5,6,3, 9,5,7,3, 9,5,8,3, 9,5,9,3, 9,6,0,3, 9,6,1,3, 9,6,2,3, + 9,6,3,3, 9,6,4,3, 9,6,5,3, 9,6,6,3, 9,6,7,3, 9,6,8,3, 9,6,9,3, 9,7,0,3, 9,7,1,3, + 9,7,2,3, 9,7,3,3, 9,7,4,3, 9,7,5,3, 9,7,6,3, 9,7,7,3, 9,7,8,3, 9,7,9,3, 9,8,0,3, + 9,8,1,3, 9,8,2,3, 9,8,3,3, 9,8,4,3, 9,8,5,3, 9,8,6,3, 9,8,7,3, 9,8,8,3, 9,8,9,3, + 9,9,0,3, 9,9,1,3, 9,9,2,3, 9,9,3,3, 9,9,4,3, 9,9,5,3, 9,9,6,3, 9,9,7,3, 9,9,8,3, + 9,9,9,3}; +#endif + diff --git a/extern/decNumber/decDouble.c b/extern/decNumber/decDouble.c new file mode 100644 index 0000000000..e63ef23fab --- /dev/null +++ b/extern/decNumber/decDouble.c @@ -0,0 +1,140 @@ +/* ------------------------------------------------------------------ */ +/* decDouble.c -- decDouble operations module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is included in the package as decNumber.pdf. This */ +/* document is also available in HTML, together with specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises decDouble operations (including conversions) */ +/* ------------------------------------------------------------------ */ + +#include "decContext.h" // public includes +#include "decDouble.h" // .. + +/* Constant mappings for shared code */ +#define DECPMAX DECDOUBLE_Pmax +#define DECEMIN DECDOUBLE_Emin +#define DECEMAX DECDOUBLE_Emax +#define DECEMAXD DECDOUBLE_EmaxD +#define DECBYTES DECDOUBLE_Bytes +#define DECSTRING DECDOUBLE_String +#define DECECONL DECDOUBLE_EconL +#define DECBIAS DECDOUBLE_Bias +#define DECLETS DECDOUBLE_Declets +#define DECQTINY (-DECDOUBLE_Bias) +// parameters of next-wider format +#define DECWBYTES DECQUAD_Bytes +#define DECWPMAX DECQUAD_Pmax +#define DECWECONL DECQUAD_EconL +#define DECWBIAS DECQUAD_Bias + +/* Type and function mappings for shared code */ +#define decFloat decDouble // Type name +#define decFloatWider decQuad // Type name + +// Utilities and conversions (binary results, extractors, etc.) +#define decFloatFromBCD decDoubleFromBCD +#define decFloatFromInt32 decDoubleFromInt32 +#define decFloatFromPacked decDoubleFromPacked +#define decFloatFromPackedChecked decDoubleFromPackedChecked +#define decFloatFromString decDoubleFromString +#define decFloatFromUInt32 decDoubleFromUInt32 +#define decFloatFromWider decDoubleFromWider +#define decFloatGetCoefficient decDoubleGetCoefficient +#define decFloatGetExponent decDoubleGetExponent +#define decFloatSetCoefficient decDoubleSetCoefficient +#define decFloatSetExponent decDoubleSetExponent +#define decFloatShow decDoubleShow +#define decFloatToBCD decDoubleToBCD +#define decFloatToEngString decDoubleToEngString +#define decFloatToInt32 decDoubleToInt32 +#define decFloatToInt32Exact decDoubleToInt32Exact +#define decFloatToPacked decDoubleToPacked +#define decFloatToString decDoubleToString +#define decFloatToUInt32 decDoubleToUInt32 +#define decFloatToUInt32Exact decDoubleToUInt32Exact +#define decFloatToWider decDoubleToWider +#define decFloatZero decDoubleZero + +// Computational (result is a decFloat) +#define decFloatAbs decDoubleAbs +#define decFloatAdd decDoubleAdd +#define decFloatAnd decDoubleAnd +#define decFloatDivide decDoubleDivide +#define decFloatDivideInteger decDoubleDivideInteger +#define decFloatFMA decDoubleFMA +#define decFloatInvert decDoubleInvert +#define decFloatLogB decDoubleLogB +#define decFloatMax decDoubleMax +#define decFloatMaxMag decDoubleMaxMag +#define decFloatMin decDoubleMin +#define decFloatMinMag decDoubleMinMag +#define decFloatMinus decDoubleMinus +#define decFloatMultiply decDoubleMultiply +#define decFloatNextMinus decDoubleNextMinus +#define decFloatNextPlus decDoubleNextPlus +#define decFloatNextToward decDoubleNextToward +#define decFloatOr decDoubleOr +#define decFloatPlus decDoublePlus +#define decFloatQuantize decDoubleQuantize +#define decFloatReduce decDoubleReduce +#define decFloatRemainder decDoubleRemainder +#define decFloatRemainderNear decDoubleRemainderNear +#define decFloatRotate decDoubleRotate +#define decFloatScaleB decDoubleScaleB +#define decFloatShift decDoubleShift +#define decFloatSubtract decDoubleSubtract +#define decFloatToIntegralValue decDoubleToIntegralValue +#define decFloatToIntegralExact decDoubleToIntegralExact +#define decFloatXor decDoubleXor + +// Comparisons +#define decFloatCompare decDoubleCompare +#define decFloatCompareSignal decDoubleCompareSignal +#define decFloatCompareTotal decDoubleCompareTotal +#define decFloatCompareTotalMag decDoubleCompareTotalMag + +// Copies +#define decFloatCanonical decDoubleCanonical +#define decFloatCopy decDoubleCopy +#define decFloatCopyAbs decDoubleCopyAbs +#define decFloatCopyNegate decDoubleCopyNegate +#define decFloatCopySign decDoubleCopySign + +// Non-computational +#define decFloatClass decDoubleClass +#define decFloatClassString decDoubleClassString +#define decFloatDigits decDoubleDigits +#define decFloatIsCanonical decDoubleIsCanonical +#define decFloatIsFinite decDoubleIsFinite +#define decFloatIsInfinite decDoubleIsInfinite +#define decFloatIsInteger decDoubleIsInteger +#define decFloatIsLogical decDoubleIsLogical +#define decFloatIsNaN decDoubleIsNaN +#define decFloatIsNegative decDoubleIsNegative +#define decFloatIsNormal decDoubleIsNormal +#define decFloatIsPositive decDoubleIsPositive +#define decFloatIsSignaling decDoubleIsSignaling +#define decFloatIsSignalling decDoubleIsSignalling +#define decFloatIsSigned decDoubleIsSigned +#define decFloatIsSubnormal decDoubleIsSubnormal +#define decFloatIsZero decDoubleIsZero +#define decFloatRadix decDoubleRadix +#define decFloatSameQuantum decDoubleSameQuantum +#define decFloatVersion decDoubleVersion + +#include "decNumberLocal.h" // local includes (need DECPMAX) +#include "decCommon.c" // non-arithmetic decFloat routines +#include "decBasic.c" // basic formats routines + diff --git a/extern/decNumber/decDouble.h b/extern/decNumber/decDouble.h new file mode 100644 index 0000000000..2e789f6361 --- /dev/null +++ b/extern/decNumber/decDouble.h @@ -0,0 +1,155 @@ +/* ------------------------------------------------------------------ */ +/* decDouble.h -- Decimal 64-bit format module header */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is included in the package as decNumber.pdf. This */ +/* document is also available in HTML, together with specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ + +#if !defined(DECDOUBLE) + #define DECDOUBLE + + #define DECDOUBLENAME "decimalDouble" /* Short name */ + #define DECDOUBLETITLE "Decimal 64-bit datum" /* Verbose name */ + #define DECDOUBLEAUTHOR "Mike Cowlishaw" /* Who to blame */ + + /* parameters for decDoubles */ + #define DECDOUBLE_Bytes 8 /* length */ + #define DECDOUBLE_Pmax 16 /* maximum precision (digits) */ + #define DECDOUBLE_Emin -383 /* minimum adjusted exponent */ + #define DECDOUBLE_Emax 384 /* maximum adjusted exponent */ + #define DECDOUBLE_EmaxD 3 /* maximum exponent digits */ + #define DECDOUBLE_Bias 398 /* bias for the exponent */ + #define DECDOUBLE_String 25 /* maximum string length, +1 */ + #define DECDOUBLE_EconL 8 /* exponent continuation length */ + #define DECDOUBLE_Declets 5 /* count of declets */ + /* highest biased exponent (Elimit-1) */ + #define DECDOUBLE_Ehigh (DECDOUBLE_Emax + DECDOUBLE_Bias - (DECDOUBLE_Pmax-1)) + + /* Required includes */ + #include "decContext.h" + #include "decQuad.h" + + /* The decDouble decimal 64-bit type, accessible by all sizes */ + typedef union { + uint8_t bytes[DECDOUBLE_Bytes]; /* fields: 1, 5, 8, 50 bits */ + uint16_t shorts[DECDOUBLE_Bytes/2]; + uint32_t words[DECDOUBLE_Bytes/4]; + #if DECUSE64 + uint64_t longs[DECDOUBLE_Bytes/8]; + #endif + } decDouble; + + /* ---------------------------------------------------------------- */ + /* Routines -- implemented as decFloat routines in common files */ + /* ---------------------------------------------------------------- */ + + /* Utilities and conversions, extractors, etc.) */ + extern decDouble * decDoubleFromBCD(decDouble *, int32_t, const uint8_t *, int32_t); + extern decDouble * decDoubleFromInt32(decDouble *, int32_t); + extern decDouble * decDoubleFromPacked(decDouble *, int32_t, const uint8_t *); + extern decDouble * decDoubleFromPackedChecked(decDouble *, int32_t, const uint8_t *); + extern decDouble * decDoubleFromString(decDouble *, const char *, decContext *); + extern decDouble * decDoubleFromUInt32(decDouble *, uint32_t); + extern decDouble * decDoubleFromWider(decDouble *, const decQuad *, decContext *); + extern int32_t decDoubleGetCoefficient(const decDouble *, uint8_t *); + extern int32_t decDoubleGetExponent(const decDouble *); + extern decDouble * decDoubleSetCoefficient(decDouble *, const uint8_t *, int32_t); + extern decDouble * decDoubleSetExponent(decDouble *, decContext *, int32_t); + extern void decDoubleShow(const decDouble *, const char *); + extern int32_t decDoubleToBCD(const decDouble *, int32_t *, uint8_t *); + extern char * decDoubleToEngString(const decDouble *, char *); + extern int32_t decDoubleToInt32(const decDouble *, decContext *, enum rounding); + extern int32_t decDoubleToInt32Exact(const decDouble *, decContext *, enum rounding); + extern int32_t decDoubleToPacked(const decDouble *, int32_t *, uint8_t *); + extern char * decDoubleToString(const decDouble *, char *); + extern uint32_t decDoubleToUInt32(const decDouble *, decContext *, enum rounding); + extern uint32_t decDoubleToUInt32Exact(const decDouble *, decContext *, enum rounding); + extern decQuad * decDoubleToWider(const decDouble *, decQuad *); + extern decDouble * decDoubleZero(decDouble *); + + /* Computational (result is a decDouble) */ + extern decDouble * decDoubleAbs(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleAdd(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleAnd(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleDivide(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleDivideInteger(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleFMA(decDouble *, const decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleInvert(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleLogB(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleMax(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleMaxMag(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleMin(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleMinMag(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleMinus(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleMultiply(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleNextMinus(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleNextPlus(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleNextToward(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleOr(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoublePlus(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleQuantize(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleReduce(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleRemainder(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleRemainderNear(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleRotate(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleScaleB(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleShift(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleSubtract(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleToIntegralValue(decDouble *, const decDouble *, decContext *, enum rounding); + extern decDouble * decDoubleToIntegralExact(decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleXor(decDouble *, const decDouble *, const decDouble *, decContext *); + + /* Comparisons */ + extern decDouble * decDoubleCompare(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleCompareSignal(decDouble *, const decDouble *, const decDouble *, decContext *); + extern decDouble * decDoubleCompareTotal(decDouble *, const decDouble *, const decDouble *); + extern decDouble * decDoubleCompareTotalMag(decDouble *, const decDouble *, const decDouble *); + + /* Copies */ + extern decDouble * decDoubleCanonical(decDouble *, const decDouble *); + extern decDouble * decDoubleCopy(decDouble *, const decDouble *); + extern decDouble * decDoubleCopyAbs(decDouble *, const decDouble *); + extern decDouble * decDoubleCopyNegate(decDouble *, const decDouble *); + extern decDouble * decDoubleCopySign(decDouble *, const decDouble *, const decDouble *); + + /* Non-computational */ + extern enum decClass decDoubleClass(const decDouble *); + extern const char * decDoubleClassString(const decDouble *); + extern uint32_t decDoubleDigits(const decDouble *); + extern uint32_t decDoubleIsCanonical(const decDouble *); + extern uint32_t decDoubleIsFinite(const decDouble *); + extern uint32_t decDoubleIsInfinite(const decDouble *); + extern uint32_t decDoubleIsInteger(const decDouble *); + extern uint32_t decDoubleIsLogical(const decDouble *); + extern uint32_t decDoubleIsNaN(const decDouble *); + extern uint32_t decDoubleIsNegative(const decDouble *); + extern uint32_t decDoubleIsNormal(const decDouble *); + extern uint32_t decDoubleIsPositive(const decDouble *); + extern uint32_t decDoubleIsSignaling(const decDouble *); + extern uint32_t decDoubleIsSignalling(const decDouble *); + extern uint32_t decDoubleIsSigned(const decDouble *); + extern uint32_t decDoubleIsSubnormal(const decDouble *); + extern uint32_t decDoubleIsZero(const decDouble *); + extern uint32_t decDoubleRadix(const decDouble *); + extern uint32_t decDoubleSameQuantum(const decDouble *, const decDouble *); + extern const char * decDoubleVersion(void); + + /* decNumber conversions; these are implemented as macros so as not */ + /* to force a dependency on decimal64 and decNumber in decDouble. */ + /* decDoubleFromNumber returns a decimal64 * to avoid warnings. */ + #define decDoubleToNumber(dq, dn) decimal64ToNumber((decimal64 *)(dq), dn) + #define decDoubleFromNumber(dq, dn, set) decimal64FromNumber((decimal64 *)(dq), dn, set) + +#endif diff --git a/extern/decNumber/decNumber.c b/extern/decNumber/decNumber.c new file mode 100644 index 0000000000..2572fac5b1 --- /dev/null +++ b/extern/decNumber/decNumber.c @@ -0,0 +1,8141 @@ +/* ------------------------------------------------------------------ */ +/* Decimal Number arithmetic module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2009. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises the routines for arbitrary-precision General */ +/* Decimal Arithmetic as defined in the specification which may be */ +/* found on the General Decimal Arithmetic pages. It implements both */ +/* the full ('extended') arithmetic and the simpler ('subset') */ +/* arithmetic. */ +/* */ +/* Usage notes: */ +/* */ +/* 1. This code is ANSI C89 except: */ +/* */ +/* a) C99 line comments (double forward slash) are used. (Most C */ +/* compilers accept these. If yours does not, a simple script */ +/* can be used to convert them to ANSI C comments.) */ +/* */ +/* b) Types from C99 stdint.h are used. If you do not have this */ +/* header file, see the User's Guide section of the decNumber */ +/* documentation; this lists the necessary definitions. */ +/* */ +/* c) If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and */ +/* uint64_t types may be used. To avoid these, set DECUSE64=0 */ +/* and DECDPUN<=4 (see documentation). */ +/* */ +/* The code also conforms to C99 restrictions; in particular, */ +/* strict aliasing rules are observed. */ +/* */ +/* 2. The decNumber format which this library uses is optimized for */ +/* efficient processing of relatively short numbers; in particular */ +/* it allows the use of fixed sized structures and minimizes copy */ +/* and move operations. It does, however, support arbitrary */ +/* precision (up to 999,999,999 digits) and arbitrary exponent */ +/* range (Emax in the range 0 through 999,999,999 and Emin in the */ +/* range -999,999,999 through 0). Mathematical functions (for */ +/* example decNumberExp) as identified below are restricted more */ +/* tightly: digits, emax, and -emin in the context must be <= */ +/* DEC_MAX_MATH (999999), and their operand(s) must be within */ +/* these bounds. */ +/* */ +/* 3. Logical functions are further restricted; their operands must */ +/* be finite, positive, have an exponent of zero, and all digits */ +/* must be either 0 or 1. The result will only contain digits */ +/* which are 0 or 1 (and will have exponent=0 and a sign of 0). */ +/* */ +/* 4. Operands to operator functions are never modified unless they */ +/* are also specified to be the result number (which is always */ +/* permitted). Other than that case, operands must not overlap. */ +/* */ +/* 5. Error handling: the type of the error is ORed into the status */ +/* flags in the current context (decContext structure). The */ +/* SIGFPE signal is then raised if the corresponding trap-enabler */ +/* flag in the decContext is set (is 1). */ +/* */ +/* It is the responsibility of the caller to clear the status */ +/* flags as required. */ +/* */ +/* The result of any routine which returns a number will always */ +/* be a valid number (which may be a special value, such as an */ +/* Infinity or NaN). */ +/* */ +/* 6. The decNumber format is not an exchangeable concrete */ +/* representation as it comprises fields which may be machine- */ +/* dependent (packed or unpacked, or special length, for example). */ +/* Canonical conversions to and from strings are provided; other */ +/* conversions are available in separate modules. */ +/* */ +/* 7. Normally, input operands are assumed to be valid. Set DECCHECK */ +/* to 1 for extended operand checking (including NULL operands). */ +/* Results are undefined if a badly-formed structure (or a NULL */ +/* pointer to a structure) is provided, though with DECCHECK */ +/* enabled the operator routines are protected against exceptions. */ +/* (Except if the result pointer is NULL, which is unrecoverable.) */ +/* */ +/* However, the routines will never cause exceptions if they are */ +/* given well-formed operands, even if the value of the operands */ +/* is inappropriate for the operation and DECCHECK is not set. */ +/* (Except for SIGFPE, as and where documented.) */ +/* */ +/* 8. Subset arithmetic is available only if DECSUBSET is set to 1. */ +/* ------------------------------------------------------------------ */ +/* Implementation notes for maintenance of this module: */ +/* */ +/* 1. Storage leak protection: Routines which use malloc are not */ +/* permitted to use return for fastpath or error exits (i.e., */ +/* they follow strict structured programming conventions). */ +/* Instead they have a do{}while(0); construct surrounding the */ +/* code which is protected -- break may be used to exit this. */ +/* Other routines can safely use the return statement inline. */ +/* */ +/* Storage leak accounting can be enabled using DECALLOC. */ +/* */ +/* 2. All loops use the for(;;) construct. Any do construct does */ +/* not loop; it is for allocation protection as just described. */ +/* */ +/* 3. Setting status in the context must always be the very last */ +/* action in a routine, as non-0 status may raise a trap and hence */ +/* the call to set status may not return (if the handler uses long */ +/* jump). Therefore all cleanup must be done first. In general, */ +/* to achieve this status is accumulated and is only applied just */ +/* before return by calling decContextSetStatus (via decStatus). */ +/* */ +/* Routines which allocate storage cannot, in general, use the */ +/* 'top level' routines which could cause a non-returning */ +/* transfer of control. The decXxxxOp routines are safe (do not */ +/* call decStatus even if traps are set in the context) and should */ +/* be used instead (they are also a little faster). */ +/* */ +/* 4. Exponent checking is minimized by allowing the exponent to */ +/* grow outside its limits during calculations, provided that */ +/* the decFinalize function is called later. Multiplication and */ +/* division, and intermediate calculations in exponentiation, */ +/* require more careful checks because of the risk of 31-bit */ +/* overflow (the most negative valid exponent is -1999999997, for */ +/* a 999999999-digit number with adjusted exponent of -999999999). */ +/* */ +/* 5. Rounding is deferred until finalization of results, with any */ +/* 'off to the right' data being represented as a single digit */ +/* residue (in the range -1 through 9). This avoids any double- */ +/* rounding when more than one shortening takes place (for */ +/* example, when a result is subnormal). */ +/* */ +/* 6. The digits count is allowed to rise to a multiple of DECDPUN */ +/* during many operations, so whole Units are handled and exact */ +/* accounting of digits is not needed. The correct digits value */ +/* is found by decGetDigits, which accounts for leading zeros. */ +/* This must be called before any rounding if the number of digits */ +/* is not known exactly. */ +/* */ +/* 7. The multiply-by-reciprocal 'trick' is used for partitioning */ +/* numbers up to four digits, using appropriate constants. This */ +/* is not useful for longer numbers because overflow of 32 bits */ +/* would lead to 4 multiplies, which is almost as expensive as */ +/* a divide (unless a floating-point or 64-bit multiply is */ +/* assumed to be available). */ +/* */ +/* 8. Unusual abbreviations that may be used in the commentary: */ +/* lhs -- left hand side (operand, of an operation) */ +/* lsd -- least significant digit (of coefficient) */ +/* lsu -- least significant Unit (of coefficient) */ +/* msd -- most significant digit (of coefficient) */ +/* msi -- most significant item (in an array) */ +/* msu -- most significant Unit (of coefficient) */ +/* rhs -- right hand side (operand, of an operation) */ +/* +ve -- positive */ +/* -ve -- negative */ +/* ** -- raise to the power */ +/* ------------------------------------------------------------------ */ + +#include // for malloc, free, etc. +#include // for printf [if needed] +#include // for strcpy +#include // for lower +#include "decNumber.h" // base number library +#include "decNumberLocal.h" // decNumber local types, etc. + +/* Constants */ +// Public lookup table used by the D2U macro +const uByte d2utable[DECMAXD2U+1]=D2UTABLE; + +#define DECVERB 1 // set to 1 for verbose DECCHECK +#define powers DECPOWERS // old internal name + +// Local constants +#define DIVIDE 0x80 // Divide operators +#define REMAINDER 0x40 // .. +#define DIVIDEINT 0x20 // .. +#define REMNEAR 0x10 // .. +#define COMPARE 0x01 // Compare operators +#define COMPMAX 0x02 // .. +#define COMPMIN 0x03 // .. +#define COMPTOTAL 0x04 // .. +#define COMPNAN 0x05 // .. [NaN processing] +#define COMPSIG 0x06 // .. [signaling COMPARE] +#define COMPMAXMAG 0x07 // .. +#define COMPMINMAG 0x08 // .. + +#define DEC_sNaN 0x40000000 // local status: sNaN signal +#define BADINT (Int)0x80000000 // most-negative Int; error indicator +// Next two indicate an integer >= 10**6, and its parity (bottom bit) +#define BIGEVEN (Int)0x80000002 +#define BIGODD (Int)0x80000003 + +static Unit uarrone[1]={1}; // Unit array of 1, used for incrementing + +/* Granularity-dependent code */ +#if DECDPUN<=4 + #define eInt Int // extended integer + #define ueInt uInt // unsigned extended integer + // Constant multipliers for divide-by-power-of five using reciprocal + // multiply, after removing powers of 2 by shifting, and final shift + // of 17 [we only need up to **4] + static const uInt multies[]={131073, 26215, 5243, 1049, 210}; + // QUOT10 -- macro to return the quotient of unit u divided by 10**n + #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17) +#else + // For DECDPUN>4 non-ANSI-89 64-bit types are needed. + #if !DECUSE64 + #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4 + #endif + #define eInt Long // extended integer + #define ueInt uLong // unsigned extended integer +#endif + +/* Local routines */ +static decNumber * decAddOp(decNumber *, const decNumber *, const decNumber *, + decContext *, uByte, uInt *); +static Flag decBiStr(const char *, const char *, const char *); +static uInt decCheckMath(const decNumber *, decContext *, uInt *); +static void decApplyRound(decNumber *, decContext *, Int, uInt *); +static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag); +static decNumber * decCompareOp(decNumber *, const decNumber *, + const decNumber *, decContext *, + Flag, uInt *); +static void decCopyFit(decNumber *, const decNumber *, decContext *, + Int *, uInt *); +static decNumber * decDecap(decNumber *, Int); +static decNumber * decDivideOp(decNumber *, const decNumber *, + const decNumber *, decContext *, Flag, uInt *); +static decNumber * decExpOp(decNumber *, const decNumber *, + decContext *, uInt *); +static void decFinalize(decNumber *, decContext *, Int *, uInt *); +static Int decGetDigits(Unit *, Int); +static Int decGetInt(const decNumber *); +static decNumber * decLnOp(decNumber *, const decNumber *, + decContext *, uInt *); +static decNumber * decMultiplyOp(decNumber *, const decNumber *, + const decNumber *, decContext *, + uInt *); +static decNumber * decNaNs(decNumber *, const decNumber *, + const decNumber *, decContext *, uInt *); +static decNumber * decQuantizeOp(decNumber *, const decNumber *, + const decNumber *, decContext *, Flag, + uInt *); +static void decReverse(Unit *, Unit *); +static void decSetCoeff(decNumber *, decContext *, const Unit *, + Int, Int *, uInt *); +static void decSetMaxValue(decNumber *, decContext *); +static void decSetOverflow(decNumber *, decContext *, uInt *); +static void decSetSubnormal(decNumber *, decContext *, Int *, uInt *); +static Int decShiftToLeast(Unit *, Int, Int); +static Int decShiftToMost(Unit *, Int, Int); +static void decStatus(decNumber *, uInt, decContext *); +static void decToString(const decNumber *, char[], Flag); +static decNumber * decTrim(decNumber *, decContext *, Flag, Flag, Int *); +static Int decUnitAddSub(const Unit *, Int, const Unit *, Int, Int, + Unit *, Int); +static Int decUnitCompare(const Unit *, Int, const Unit *, Int, Int); + +#if !DECSUBSET +/* decFinish == decFinalize when no subset arithmetic needed */ +#define decFinish(a,b,c,d) decFinalize(a,b,c,d) +#else +static void decFinish(decNumber *, decContext *, Int *, uInt *); +static decNumber * decRoundOperand(const decNumber *, decContext *, uInt *); +#endif + +/* Local macros */ +// masked special-values bits +#define SPECIALARG (rhs->bits & DECSPECIAL) +#define SPECIALARGS ((lhs->bits | rhs->bits) & DECSPECIAL) + +/* Diagnostic macros, etc. */ +#if DECALLOC +// Handle malloc/free accounting. If enabled, our accountable routines +// are used; otherwise the code just goes straight to the system malloc +// and free routines. +#define malloc(a) decMalloc(a) +#define free(a) decFree(a) +#define DECFENCE 0x5a // corruption detector +// 'Our' malloc and free: +static void *decMalloc(size_t); +static void decFree(void *); +uInt decAllocBytes=0; // count of bytes allocated +// Note that DECALLOC code only checks for storage buffer overflow. +// To check for memory leaks, the decAllocBytes variable must be +// checked to be 0 at appropriate times (e.g., after the test +// harness completes a set of tests). This checking may be unreliable +// if the testing is done in a multi-thread environment. +#endif + +#if DECCHECK +// Optional checking routines. Enabling these means that decNumber +// and decContext operands to operator routines are checked for +// correctness. This roughly doubles the execution time of the +// fastest routines (and adds 600+ bytes), so should not normally be +// used in 'production'. +// decCheckInexact is used to check that inexact results have a full +// complement of digits (where appropriate -- this is not the case +// for Quantize, for example) +#define DECUNRESU ((decNumber *)(void *)0xffffffff) +#define DECUNUSED ((const decNumber *)(void *)0xffffffff) +#define DECUNCONT ((decContext *)(void *)(0xffffffff)) +static Flag decCheckOperands(decNumber *, const decNumber *, + const decNumber *, decContext *); +static Flag decCheckNumber(const decNumber *); +static void decCheckInexact(const decNumber *, decContext *); +#endif + +#if DECTRACE || DECCHECK +// Optional trace/debugging routines (may or may not be used) +void decNumberShow(const decNumber *); // displays the components of a number +static void decDumpAr(char, const Unit *, Int); +#endif + +/* ================================================================== */ +/* Conversions */ +/* ================================================================== */ + +/* ------------------------------------------------------------------ */ +/* from-int32 -- conversion from Int or uInt */ +/* */ +/* dn is the decNumber to receive the integer */ +/* in or uin is the integer to be converted */ +/* returns dn */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberFromInt32(decNumber *dn, Int in) { + uInt unsig; + if (in>=0) unsig=in; + else { // negative (possibly BADINT) + if (in==BADINT) unsig=(uInt)1073741824*2; // special case + else unsig=-in; // invert + } + // in is now positive + decNumberFromUInt32(dn, unsig); + if (in<0) dn->bits=DECNEG; // sign needed + return dn; + } // decNumberFromInt32 + +decNumber * decNumberFromUInt32(decNumber *dn, uInt uin) { + Unit *up; // work pointer + decNumberZero(dn); // clean + if (uin==0) return dn; // [or decGetDigits bad call] + for (up=dn->lsu; uin>0; up++) { + *up=(Unit)(uin%(DECDPUNMAX+1)); + uin=uin/(DECDPUNMAX+1); + } + dn->digits=decGetDigits(dn->lsu, up-dn->lsu); + return dn; + } // decNumberFromUInt32 + +/* ------------------------------------------------------------------ */ +/* to-int32 -- conversion to Int or uInt */ +/* */ +/* dn is the decNumber to convert */ +/* set is the context for reporting errors */ +/* returns the converted decNumber, or 0 if Invalid is set */ +/* */ +/* Invalid is set if the decNumber does not have exponent==0 or if */ +/* it is a NaN, Infinite, or out-of-range. */ +/* ------------------------------------------------------------------ */ +Int decNumberToInt32(const decNumber *dn, decContext *set) { + #if DECCHECK + if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0; + #endif + + // special or too many digits, or bad exponent + if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0) ; // bad + else { // is a finite integer with 10 or fewer digits + Int d; // work + const Unit *up; // .. + uInt hi=0, lo; // .. + up=dn->lsu; // -> lsu + lo=*up; // get 1 to 9 digits + #if DECDPUN>1 // split to higher + hi=lo/10; + lo=lo%10; + #endif + up++; + // collect remaining Units, if any, into hi + for (d=DECDPUN; ddigits; up++, d+=DECDPUN) hi+=*up*powers[d-1]; + // now low has the lsd, hi the remainder + if (hi>214748364 || (hi==214748364 && lo>7)) { // out of range? + // most-negative is a reprieve + if (dn->bits&DECNEG && hi==214748364 && lo==8) return 0x80000000; + // bad -- drop through + } + else { // in-range always + Int i=X10(hi)+lo; + if (dn->bits&DECNEG) return -i; + return i; + } + } // integer + decContextSetStatus(set, DEC_Invalid_operation); // [may not return] + return 0; + } // decNumberToInt32 + +uInt decNumberToUInt32(const decNumber *dn, decContext *set) { + #if DECCHECK + if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0; + #endif + // special or too many digits, or bad exponent, or negative (<0) + if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0 + || (dn->bits&DECNEG && !ISZERO(dn))); // bad + else { // is a finite integer with 10 or fewer digits + Int d; // work + const Unit *up; // .. + uInt hi=0, lo; // .. + up=dn->lsu; // -> lsu + lo=*up; // get 1 to 9 digits + #if DECDPUN>1 // split to higher + hi=lo/10; + lo=lo%10; + #endif + up++; + // collect remaining Units, if any, into hi + for (d=DECDPUN; ddigits; up++, d+=DECDPUN) hi+=*up*powers[d-1]; + + // now low has the lsd, hi the remainder + if (hi>429496729 || (hi==429496729 && lo>5)) ; // no reprieve possible + else return X10(hi)+lo; + } // integer + decContextSetStatus(set, DEC_Invalid_operation); // [may not return] + return 0; + } // decNumberToUInt32 + +/* ------------------------------------------------------------------ */ +/* to-scientific-string -- conversion to numeric string */ +/* to-engineering-string -- conversion to numeric string */ +/* */ +/* decNumberToString(dn, string); */ +/* decNumberToEngString(dn, string); */ +/* */ +/* dn is the decNumber to convert */ +/* string is the string where the result will be laid out */ +/* */ +/* string must be at least dn->digits+14 characters long */ +/* */ +/* No error is possible, and no status can be set. */ +/* ------------------------------------------------------------------ */ +char * decNumberToString(const decNumber *dn, char *string){ + decToString(dn, string, 0); + return string; + } // DecNumberToString + +char * decNumberToEngString(const decNumber *dn, char *string){ + decToString(dn, string, 1); + return string; + } // DecNumberToEngString + +/* ------------------------------------------------------------------ */ +/* to-number -- conversion from numeric string */ +/* */ +/* decNumberFromString -- convert string to decNumber */ +/* dn -- the number structure to fill */ +/* chars[] -- the string to convert ('\0' terminated) */ +/* set -- the context used for processing any error, */ +/* determining the maximum precision available */ +/* (set.digits), determining the maximum and minimum */ +/* exponent (set.emax and set.emin), determining if */ +/* extended values are allowed, and checking the */ +/* rounding mode if overflow occurs or rounding is */ +/* needed. */ +/* */ +/* The length of the coefficient and the size of the exponent are */ +/* checked by this routine, so the correct error (Underflow or */ +/* Overflow) can be reported or rounding applied, as necessary. */ +/* */ +/* If bad syntax is detected, the result will be a quiet NaN. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberFromString(decNumber *dn, const char chars[], + decContext *set) { + Int exponent=0; // working exponent [assume 0] + uByte bits=0; // working flags [assume +ve] + Unit *res; // where result will be built + Unit resbuff[SD2U(DECBUFFER+9)];// local buffer in case need temporary + // [+9 allows for ln() constants] + Unit *allocres=NULL; // -> allocated result, iff allocated + Int d=0; // count of digits found in decimal part + const char *dotchar=NULL; // where dot was found + const char *cfirst=chars; // -> first character of decimal part + const char *last=NULL; // -> last digit of decimal part + const char *c; // work + Unit *up; // .. + #if DECDPUN>1 + Int cut, out; // .. + #endif + Int residue; // rounding residue + uInt status=0; // error code + + #if DECCHECK + if (decCheckOperands(DECUNRESU, DECUNUSED, DECUNUSED, set)) + return decNumberZero(dn); + #endif + + do { // status & malloc protection + for (c=chars;; c++) { // -> input character + if (*c>='0' && *c<='9') { // test for Arabic digit + last=c; + d++; // count of real digits + continue; // still in decimal part + } + if (*c=='.' && dotchar==NULL) { // first '.' + dotchar=c; // record offset into decimal part + if (c==cfirst) cfirst++; // first digit must follow + continue;} + if (c==chars) { // first in string... + if (*c=='-') { // valid - sign + cfirst++; + bits=DECNEG; + continue;} + if (*c=='+') { // valid + sign + cfirst++; + continue;} + } + // *c is not a digit, or a valid +, -, or '.' + break; + } // c + + if (last==NULL) { // no digits yet + status=DEC_Conversion_syntax;// assume the worst + if (*c=='\0') break; // and no more to come... + #if DECSUBSET + // if subset then infinities and NaNs are not allowed + if (!set->extended) break; // hopeless + #endif + // Infinities and NaNs are possible, here + if (dotchar!=NULL) break; // .. unless had a dot + decNumberZero(dn); // be optimistic + if (decBiStr(c, "infinity", "INFINITY") + || decBiStr(c, "inf", "INF")) { + dn->bits=bits | DECINF; + status=0; // is OK + break; // all done + } + // a NaN expected + // 2003.09.10 NaNs are now permitted to have a sign + dn->bits=bits | DECNAN; // assume simple NaN + if (*c=='s' || *c=='S') { // looks like an sNaN + c++; + dn->bits=bits | DECSNAN; + } + if (*c!='n' && *c!='N') break; // check caseless "NaN" + c++; + if (*c!='a' && *c!='A') break; // .. + c++; + if (*c!='n' && *c!='N') break; // .. + c++; + // now either nothing, or nnnn payload, expected + // -> start of integer and skip leading 0s [including plain 0] + for (cfirst=c; *cfirst=='0';) cfirst++; + if (*cfirst=='\0') { // "NaN" or "sNaN", maybe with all 0s + status=0; // it's good + break; // .. + } + // something other than 0s; setup last and d as usual [no dots] + for (c=cfirst;; c++, d++) { + if (*c<'0' || *c>'9') break; // test for Arabic digit + last=c; + } + if (*c!='\0') break; // not all digits + if (d>set->digits-1) { + // [NB: payload in a decNumber can be full length unless + // clamped, in which case can only be digits-1] + if (set->clamp) break; + if (d>set->digits) break; + } // too many digits? + // good; drop through to convert the integer to coefficient + status=0; // syntax is OK + bits=dn->bits; // for copy-back + } // last==NULL + + else if (*c!='\0') { // more to process... + // had some digits; exponent is only valid sequence now + Flag nege; // 1=negative exponent + const char *firstexp; // -> first significant exponent digit + status=DEC_Conversion_syntax;// assume the worst + if (*c!='e' && *c!='E') break; + /* Found 'e' or 'E' -- now process explicit exponent */ + // 1998.07.11: sign no longer required + nege=0; + c++; // to (possible) sign + if (*c=='-') {nege=1; c++;} + else if (*c=='+') c++; + if (*c=='\0') break; + + for (; *c=='0' && *(c+1)!='\0';) c++; // strip insignificant zeros + firstexp=c; // save exponent digit place + for (; ;c++) { + if (*c<'0' || *c>'9') break; // not a digit + exponent=X10(exponent)+(Int)*c-(Int)'0'; + } // c + // if not now on a '\0', *c must not be a digit + if (*c!='\0') break; + + // (this next test must be after the syntax checks) + // if it was too long the exponent may have wrapped, so check + // carefully and set it to a certain overflow if wrap possible + if (c>=firstexp+9+1) { + if (c>firstexp+9+1 || *firstexp>'1') exponent=DECNUMMAXE*2; + // [up to 1999999999 is OK, for example 1E-1000000998] + } + if (nege) exponent=-exponent; // was negative + status=0; // is OK + } // stuff after digits + + // Here when whole string has been inspected; syntax is good + // cfirst->first digit (never dot), last->last digit (ditto) + + // strip leading zeros/dot [leave final 0 if all 0's] + if (*cfirst=='0') { // [cfirst has stepped over .] + for (c=cfirst; cextended) { + decNumberZero(dn); // clean result + break; // [could be return] + } + #endif + } // at least one leading 0 + + // Handle decimal point... + if (dotchar!=NULL && dotchardigits) res=dn->lsu; // fits into supplied decNumber + else { // rounding needed + Int needbytes=D2U(d)*sizeof(Unit);// bytes needed + res=resbuff; // assume use local buffer + if (needbytes>(Int)sizeof(resbuff)) { // too big for local + allocres=(Unit *)malloc(needbytes); + if (allocres==NULL) {status|=DEC_Insufficient_storage; break;} + res=allocres; + } + } + // res now -> number lsu, buffer, or allocated storage for Unit array + + // Place the coefficient into the selected Unit array + // [this is often 70% of the cost of this function when DECDPUN>1] + #if DECDPUN>1 + out=0; // accumulator + up=res+D2U(d)-1; // -> msu + cut=d-(up-res)*DECDPUN; // digits in top unit + for (c=cfirst;; c++) { // along the digits + if (*c=='.') continue; // ignore '.' [don't decrement cut] + out=X10(out)+(Int)*c-(Int)'0'; + if (c==last) break; // done [never get to trailing '.'] + cut--; + if (cut>0) continue; // more for this unit + *up=(Unit)out; // write unit + up--; // prepare for unit below.. + cut=DECDPUN; // .. + out=0; // .. + } // c + *up=(Unit)out; // write lsu + + #else + // DECDPUN==1 + up=res; // -> lsu + for (c=last; c>=cfirst; c--) { // over each character, from least + if (*c=='.') continue; // ignore . [don't step up] + *up=(Unit)((Int)*c-(Int)'0'); + up++; + } // c + #endif + + dn->bits=bits; + dn->exponent=exponent; + dn->digits=d; + + // if not in number (too long) shorten into the number + if (d>set->digits) { + residue=0; + decSetCoeff(dn, set, res, d, &residue, &status); + // always check for overflow or subnormal and round as needed + decFinalize(dn, set, &residue, &status); + } + else { // no rounding, but may still have overflow or subnormal + // [these tests are just for performance; finalize repeats them] + if ((dn->exponent-1emin-dn->digits) + || (dn->exponent-1>set->emax-set->digits)) { + residue=0; + decFinalize(dn, set, &residue, &status); + } + } + // decNumberShow(dn); + } while(0); // [for break] + + if (allocres!=NULL) free(allocres); // drop any storage used + if (status!=0) decStatus(dn, status, set); + return dn; + } /* decNumberFromString */ + +/* ================================================================== */ +/* Operators */ +/* ================================================================== */ + +/* ------------------------------------------------------------------ */ +/* decNumberAbs -- absolute value operator */ +/* */ +/* This computes C = abs(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context */ +/* */ +/* See also decNumberCopyAbs for a quiet bitwise version of this. */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +/* This has the same effect as decNumberPlus unless A is negative, */ +/* in which case it has the same effect as decNumberMinus. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberAbs(decNumber *res, const decNumber *rhs, + decContext *set) { + decNumber dzero; // for 0 + uInt status=0; // accumulator + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + decNumberZero(&dzero); // set 0 + dzero.exponent=rhs->exponent; // [no coefficient expansion] + decAddOp(res, &dzero, rhs, set, (uByte)(rhs->bits & DECNEG), &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberAbs + +/* ------------------------------------------------------------------ */ +/* decNumberAdd -- add two Numbers */ +/* */ +/* This computes C = A + B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X+X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +/* This just calls the routine shared with Subtract */ +decNumber * decNumberAdd(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decAddOp(res, lhs, rhs, set, 0, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberAdd + +/* ------------------------------------------------------------------ */ +/* decNumberAnd -- AND two Numbers, digitwise */ +/* */ +/* This computes C = A & B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X&X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context (used for result length and error report) */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Logical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberAnd(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + const Unit *ua, *ub; // -> operands + const Unit *msua, *msub; // -> operand msus + Unit *uc, *msuc; // -> result and its msu + Int msudigs; // digits in res msu + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs) + || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) { + decStatus(res, DEC_Invalid_operation, set); + return res; + } + + // operands are valid + ua=lhs->lsu; // bottom-up + ub=rhs->lsu; // .. + uc=res->lsu; // .. + msua=ua+D2U(lhs->digits)-1; // -> msu of lhs + msub=ub+D2U(rhs->digits)-1; // -> msu of rhs + msuc=uc+D2U(set->digits)-1; // -> msu of result + msudigs=MSUDIGITS(set->digits); // [faster than remainder] + for (; uc<=msuc; ua++, ub++, uc++) { // Unit loop + Unit a, b; // extract units + if (ua>msua) a=0; + else a=*ua; + if (ub>msub) b=0; + else b=*ub; + *uc=0; // can now write back + if (a|b) { // maybe 1 bits to examine + Int i, j; + *uc=0; // can now write back + // This loop could be unrolled and/or use BIN2BCD tables + for (i=0; i1) { + decStatus(res, DEC_Invalid_operation, set); + return res; + } + if (uc==msuc && i==msudigs-1) break; // just did final digit + } // each digit + } // both OK + } // each unit + // [here uc-1 is the msu of the result] + res->digits=decGetDigits(res->lsu, uc-res->lsu); + res->exponent=0; // integer + res->bits=0; // sign=0 + return res; // [no status to set] + } // decNumberAnd + +/* ------------------------------------------------------------------ */ +/* decNumberCompare -- compare two Numbers */ +/* */ +/* This computes C = A ? B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for one digit (or NaN). */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberCompare(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decCompareOp(res, lhs, rhs, set, COMPARE, &status); + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberCompare + +/* ------------------------------------------------------------------ */ +/* decNumberCompareSignal -- compare, signalling on all NaNs */ +/* */ +/* This computes C = A ? B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for one digit (or NaN). */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberCompareSignal(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decCompareOp(res, lhs, rhs, set, COMPSIG, &status); + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberCompareSignal + +/* ------------------------------------------------------------------ */ +/* decNumberCompareTotal -- compare two Numbers, using total ordering */ +/* */ +/* This computes C = A ? B, under total ordering */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for one digit; the result will always be one of */ +/* -1, 0, or 1. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberCompareTotal(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status); + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberCompareTotal + +/* ------------------------------------------------------------------ */ +/* decNumberCompareTotalMag -- compare, total ordering of magnitudes */ +/* */ +/* This computes C = |A| ? |B|, under total ordering */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for one digit; the result will always be one of */ +/* -1, 0, or 1. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberCompareTotalMag(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + uInt needbytes; // for space calculations + decNumber bufa[D2N(DECBUFFER+1)];// +1 in case DECBUFFER=0 + decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated + decNumber bufb[D2N(DECBUFFER+1)]; + decNumber *allocbufb=NULL; // -> allocated bufb, iff allocated + decNumber *a, *b; // temporary pointers + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + do { // protect allocated storage + // if either is negative, take a copy and absolute + if (decNumberIsNegative(lhs)) { // lhs<0 + a=bufa; + needbytes=sizeof(decNumber)+(D2U(lhs->digits)-1)*sizeof(Unit); + if (needbytes>sizeof(bufa)) { // need malloc space + allocbufa=(decNumber *)malloc(needbytes); + if (allocbufa==NULL) { // hopeless -- abandon + status|=DEC_Insufficient_storage; + break;} + a=allocbufa; // use the allocated space + } + decNumberCopy(a, lhs); // copy content + a->bits&=~DECNEG; // .. and clear the sign + lhs=a; // use copy from here on + } + if (decNumberIsNegative(rhs)) { // rhs<0 + b=bufb; + needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); + if (needbytes>sizeof(bufb)) { // need malloc space + allocbufb=(decNumber *)malloc(needbytes); + if (allocbufb==NULL) { // hopeless -- abandon + status|=DEC_Insufficient_storage; + break;} + b=allocbufb; // use the allocated space + } + decNumberCopy(b, rhs); // copy content + b->bits&=~DECNEG; // .. and clear the sign + rhs=b; // use copy from here on + } + decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status); + } while(0); // end protected + + if (allocbufa!=NULL) free(allocbufa); // drop any storage used + if (allocbufb!=NULL) free(allocbufb); // .. + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberCompareTotalMag + +/* ------------------------------------------------------------------ */ +/* decNumberDivide -- divide one number by another */ +/* */ +/* This computes C = A / B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X/X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberDivide(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decDivideOp(res, lhs, rhs, set, DIVIDE, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberDivide + +/* ------------------------------------------------------------------ */ +/* decNumberDivideInteger -- divide and return integer quotient */ +/* */ +/* This computes C = A # B, where # is the integer divide operator */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X#X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberDivideInteger(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status); + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberDivideInteger + +/* ------------------------------------------------------------------ */ +/* decNumberExp -- exponentiation */ +/* */ +/* This computes C = exp(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context; note that rounding mode has no effect */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Mathematical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* */ +/* Finite results will always be full precision and Inexact, except */ +/* when A is a zero or -Infinity (giving 1 or 0 respectively). */ +/* */ +/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ +/* almost always be correctly rounded, but may be up to 1 ulp in */ +/* error in rare cases. */ +/* ------------------------------------------------------------------ */ +/* This is a wrapper for decExpOp which can handle the slightly wider */ +/* (double) range needed by Ln (which has to be able to calculate */ +/* exp(-a) where a can be the tiniest number (Ntiny). */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberExp(decNumber *res, const decNumber *rhs, + decContext *set) { + uInt status=0; // accumulator + #if DECSUBSET + decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated + #endif + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + // Check restrictions; these restrictions ensure that if h=8 (see + // decExpOp) then the result will either overflow or underflow to 0. + // Other math functions restrict the input range, too, for inverses. + // If not violated then carry out the operation. + if (!decCheckMath(rhs, set, &status)) do { // protect allocation + #if DECSUBSET + if (!set->extended) { + // reduce operand and set lostDigits status, as needed + if (rhs->digits>set->digits) { + allocrhs=decRoundOperand(rhs, set, &status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + } + #endif + decExpOp(res, rhs, set, &status); + } while(0); // end protected + + #if DECSUBSET + if (allocrhs !=NULL) free(allocrhs); // drop any storage used + #endif + // apply significant status + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberExp + +/* ------------------------------------------------------------------ */ +/* decNumberFMA -- fused multiply add */ +/* */ +/* This computes D = (A * B) + C with only one rounding */ +/* */ +/* res is D, the result. D may be A or B or C (e.g., X=FMA(X,X,X)) */ +/* lhs is A */ +/* rhs is B */ +/* fhs is C [far hand side] */ +/* set is the context */ +/* */ +/* Mathematical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberFMA(decNumber *res, const decNumber *lhs, + const decNumber *rhs, const decNumber *fhs, + decContext *set) { + uInt status=0; // accumulator + decContext dcmul; // context for the multiplication + uInt needbytes; // for space calculations + decNumber bufa[D2N(DECBUFFER*2+1)]; + decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated + decNumber *acc; // accumulator pointer + decNumber dzero; // work + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + if (decCheckOperands(res, fhs, DECUNUSED, set)) return res; + #endif + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { // [undefined if subset] + status|=DEC_Invalid_operation; + break;} + #endif + // Check math restrictions [these ensure no overflow or underflow] + if ((!decNumberIsSpecial(lhs) && decCheckMath(lhs, set, &status)) + || (!decNumberIsSpecial(rhs) && decCheckMath(rhs, set, &status)) + || (!decNumberIsSpecial(fhs) && decCheckMath(fhs, set, &status))) break; + // set up context for multiply + dcmul=*set; + dcmul.digits=lhs->digits+rhs->digits; // just enough + // [The above may be an over-estimate for subset arithmetic, but that's OK] + dcmul.emax=DEC_MAX_EMAX; // effectively unbounded .. + dcmul.emin=DEC_MIN_EMIN; // [thanks to Math restrictions] + // set up decNumber space to receive the result of the multiply + acc=bufa; // may fit + needbytes=sizeof(decNumber)+(D2U(dcmul.digits)-1)*sizeof(Unit); + if (needbytes>sizeof(bufa)) { // need malloc space + allocbufa=(decNumber *)malloc(needbytes); + if (allocbufa==NULL) { // hopeless -- abandon + status|=DEC_Insufficient_storage; + break;} + acc=allocbufa; // use the allocated space + } + // multiply with extended range and necessary precision + //printf("emin=%ld\n", dcmul.emin); + decMultiplyOp(acc, lhs, rhs, &dcmul, &status); + // Only Invalid operation (from sNaN or Inf * 0) is possible in + // status; if either is seen than ignore fhs (in case it is + // another sNaN) and set acc to NaN unless we had an sNaN + // [decMultiplyOp leaves that to caller] + // Note sNaN has to go through addOp to shorten payload if + // necessary + if ((status&DEC_Invalid_operation)!=0) { + if (!(status&DEC_sNaN)) { // but be true invalid + decNumberZero(res); // acc not yet set + res->bits=DECNAN; + break; + } + decNumberZero(&dzero); // make 0 (any non-NaN would do) + fhs=&dzero; // use that + } + #if DECCHECK + else { // multiply was OK + if (status!=0) printf("Status=%08lx after FMA multiply\n", (LI)status); + } + #endif + // add the third operand and result -> res, and all is done + decAddOp(res, acc, fhs, set, 0, &status); + } while(0); // end protected + + if (allocbufa!=NULL) free(allocbufa); // drop any storage used + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberFMA + +/* ------------------------------------------------------------------ */ +/* decNumberInvert -- invert a Number, digitwise */ +/* */ +/* This computes C = ~A */ +/* */ +/* res is C, the result. C may be A (e.g., X=~X) */ +/* rhs is A */ +/* set is the context (used for result length and error report) */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Logical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberInvert(decNumber *res, const decNumber *rhs, + decContext *set) { + const Unit *ua, *msua; // -> operand and its msu + Unit *uc, *msuc; // -> result and its msu + Int msudigs; // digits in res msu + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + if (rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) { + decStatus(res, DEC_Invalid_operation, set); + return res; + } + // operand is valid + ua=rhs->lsu; // bottom-up + uc=res->lsu; // .. + msua=ua+D2U(rhs->digits)-1; // -> msu of rhs + msuc=uc+D2U(set->digits)-1; // -> msu of result + msudigs=MSUDIGITS(set->digits); // [faster than remainder] + for (; uc<=msuc; ua++, uc++) { // Unit loop + Unit a; // extract unit + Int i, j; // work + if (ua>msua) a=0; + else a=*ua; + *uc=0; // can now write back + // always need to examine all bits in rhs + // This loop could be unrolled and/or use BIN2BCD tables + for (i=0; i1) { + decStatus(res, DEC_Invalid_operation, set); + return res; + } + if (uc==msuc && i==msudigs-1) break; // just did final digit + } // each digit + } // each unit + // [here uc-1 is the msu of the result] + res->digits=decGetDigits(res->lsu, uc-res->lsu); + res->exponent=0; // integer + res->bits=0; // sign=0 + return res; // [no status to set] + } // decNumberInvert + +/* ------------------------------------------------------------------ */ +/* decNumberLn -- natural logarithm */ +/* */ +/* This computes C = ln(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context; note that rounding mode has no effect */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Notable cases: */ +/* A<0 -> Invalid */ +/* A=0 -> -Infinity (Exact) */ +/* A=+Infinity -> +Infinity (Exact) */ +/* A=1 exactly -> 0 (Exact) */ +/* */ +/* Mathematical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* */ +/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ +/* almost always be correctly rounded, but may be up to 1 ulp in */ +/* error in rare cases. */ +/* ------------------------------------------------------------------ */ +/* This is a wrapper for decLnOp which can handle the slightly wider */ +/* (+11) range needed by Ln, Log10, etc. (which may have to be able */ +/* to calculate at p+e+2). */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberLn(decNumber *res, const decNumber *rhs, + decContext *set) { + uInt status=0; // accumulator + #if DECSUBSET + decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated + #endif + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + // Check restrictions; this is a math function; if not violated + // then carry out the operation. + if (!decCheckMath(rhs, set, &status)) do { // protect allocation + #if DECSUBSET + if (!set->extended) { + // reduce operand and set lostDigits status, as needed + if (rhs->digits>set->digits) { + allocrhs=decRoundOperand(rhs, set, &status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + // special check in subset for rhs=0 + if (ISZERO(rhs)) { // +/- zeros -> error + status|=DEC_Invalid_operation; + break;} + } // extended=0 + #endif + decLnOp(res, rhs, set, &status); + } while(0); // end protected + + #if DECSUBSET + if (allocrhs !=NULL) free(allocrhs); // drop any storage used + #endif + // apply significant status + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberLn + +/* ------------------------------------------------------------------ */ +/* decNumberLogB - get adjusted exponent, by 754 rules */ +/* */ +/* This computes C = adjustedexponent(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context, used only for digits and status */ +/* */ +/* For an unrounded result, digits may need to be 10 (A might have */ +/* 10**9 digits and an exponent of +999999999, or one digit and an */ +/* exponent of -1999999999). */ +/* */ +/* This returns the adjusted exponent of A after (in theory) padding */ +/* with zeros on the right to set->digits digits while keeping the */ +/* same value. The exponent is not limited by emin/emax. */ +/* */ +/* Notable cases: */ +/* A<0 -> Use |A| */ +/* A=0 -> -Infinity (Division by zero) */ +/* A=Infinite -> +Infinity (Exact) */ +/* A=1 exactly -> 0 (Exact) */ +/* NaNs are propagated as usual */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberLogB(decNumber *res, const decNumber *rhs, + decContext *set) { + uInt status=0; // accumulator + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + // NaNs as usual; Infinities return +Infinity; 0->oops + if (decNumberIsNaN(rhs)) decNaNs(res, rhs, NULL, set, &status); + else if (decNumberIsInfinite(rhs)) decNumberCopyAbs(res, rhs); + else if (decNumberIsZero(rhs)) { + decNumberZero(res); // prepare for Infinity + res->bits=DECNEG|DECINF; // -Infinity + status|=DEC_Division_by_zero; // as per 754 + } + else { // finite non-zero + Int ae=rhs->exponent+rhs->digits-1; // adjusted exponent + if (set->digits>=10) decNumberFromInt32(res, ae); // lay it out + else { + decNumber buft[D2N(10)]; // temporary number + decNumber *t=buft; // .. + decNumberFromInt32(t, ae); // lay it out + decNumberPlus(res, t, set); // round as necessary + } + } + + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberLogB + +/* ------------------------------------------------------------------ */ +/* decNumberLog10 -- logarithm in base 10 */ +/* */ +/* This computes C = log10(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context; note that rounding mode has no effect */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Notable cases: */ +/* A<0 -> Invalid */ +/* A=0 -> -Infinity (Exact) */ +/* A=+Infinity -> +Infinity (Exact) */ +/* A=10**n (if n is an integer) -> n (Exact) */ +/* */ +/* Mathematical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* */ +/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ +/* almost always be correctly rounded, but may be up to 1 ulp in */ +/* error in rare cases. */ +/* ------------------------------------------------------------------ */ +/* This calculates ln(A)/ln(10) using appropriate precision. For */ +/* ln(A) this is the max(p, rhs->digits + t) + 3, where p is the */ +/* requested digits and t is the number of digits in the exponent */ +/* (maximum 6). For ln(10) it is p + 3; this is often handled by the */ +/* fastpath in decLnOp. The final division is done to the requested */ +/* precision. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberLog10(decNumber *res, const decNumber *rhs, + decContext *set) { + uInt status=0, ignore=0; // status accumulators + uInt needbytes; // for space calculations + Int p; // working precision + Int t; // digits in exponent of A + + // buffers for a and b working decimals + // (adjustment calculator, same size) + decNumber bufa[D2N(DECBUFFER+2)]; + decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated + decNumber *a=bufa; // temporary a + decNumber bufb[D2N(DECBUFFER+2)]; + decNumber *allocbufb=NULL; // -> allocated bufb, iff allocated + decNumber *b=bufb; // temporary b + decNumber bufw[D2N(10)]; // working 2-10 digit number + decNumber *w=bufw; // .. + #if DECSUBSET + decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated + #endif + + decContext aset; // working context + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + // Check restrictions; this is a math function; if not violated + // then carry out the operation. + if (!decCheckMath(rhs, set, &status)) do { // protect malloc + #if DECSUBSET + if (!set->extended) { + // reduce operand and set lostDigits status, as needed + if (rhs->digits>set->digits) { + allocrhs=decRoundOperand(rhs, set, &status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + // special check in subset for rhs=0 + if (ISZERO(rhs)) { // +/- zeros -> error + status|=DEC_Invalid_operation; + break;} + } // extended=0 + #endif + + decContextDefault(&aset, DEC_INIT_DECIMAL64); // clean context + + // handle exact powers of 10; only check if +ve finite + if (!(rhs->bits&(DECNEG|DECSPECIAL)) && !ISZERO(rhs)) { + Int residue=0; // (no residue) + uInt copystat=0; // clean status + + // round to a single digit... + aset.digits=1; + decCopyFit(w, rhs, &aset, &residue, ©stat); // copy & shorten + // if exact and the digit is 1, rhs is a power of 10 + if (!(copystat&DEC_Inexact) && w->lsu[0]==1) { + // the exponent, conveniently, is the power of 10; making + // this the result needs a little care as it might not fit, + // so first convert it into the working number, and then move + // to res + decNumberFromInt32(w, w->exponent); + residue=0; + decCopyFit(res, w, set, &residue, &status); // copy & round + decFinish(res, set, &residue, &status); // cleanup/set flags + break; + } // not a power of 10 + } // not a candidate for exact + + // simplify the information-content calculation to use 'total + // number of digits in a, including exponent' as compared to the + // requested digits, as increasing this will only rarely cost an + // iteration in ln(a) anyway + t=6; // it can never be >6 + + // allocate space when needed... + p=(rhs->digits+t>set->digits?rhs->digits+t:set->digits)+3; + needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit); + if (needbytes>sizeof(bufa)) { // need malloc space + allocbufa=(decNumber *)malloc(needbytes); + if (allocbufa==NULL) { // hopeless -- abandon + status|=DEC_Insufficient_storage; + break;} + a=allocbufa; // use the allocated space + } + aset.digits=p; // as calculated + aset.emax=DEC_MAX_MATH; // usual bounds + aset.emin=-DEC_MAX_MATH; // .. + aset.clamp=0; // and no concrete format + decLnOp(a, rhs, &aset, &status); // a=ln(rhs) + + // skip the division if the result so far is infinite, NaN, or + // zero, or there was an error; note NaN from sNaN needs copy + if (status&DEC_NaNs && !(status&DEC_sNaN)) break; + if (a->bits&DECSPECIAL || ISZERO(a)) { + decNumberCopy(res, a); // [will fit] + break;} + + // for ln(10) an extra 3 digits of precision are needed + p=set->digits+3; + needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit); + if (needbytes>sizeof(bufb)) { // need malloc space + allocbufb=(decNumber *)malloc(needbytes); + if (allocbufb==NULL) { // hopeless -- abandon + status|=DEC_Insufficient_storage; + break;} + b=allocbufb; // use the allocated space + } + decNumberZero(w); // set up 10... + #if DECDPUN==1 + w->lsu[1]=1; w->lsu[0]=0; // .. + #else + w->lsu[0]=10; // .. + #endif + w->digits=2; // .. + + aset.digits=p; + decLnOp(b, w, &aset, &ignore); // b=ln(10) + + aset.digits=set->digits; // for final divide + decDivideOp(res, a, b, &aset, DIVIDE, &status); // into result + } while(0); // [for break] + + if (allocbufa!=NULL) free(allocbufa); // drop any storage used + if (allocbufb!=NULL) free(allocbufb); // .. + #if DECSUBSET + if (allocrhs !=NULL) free(allocrhs); // .. + #endif + // apply significant status + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberLog10 + +/* ------------------------------------------------------------------ */ +/* decNumberMax -- compare two Numbers and return the maximum */ +/* */ +/* This computes C = A ? B, returning the maximum by 754 rules */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberMax(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decCompareOp(res, lhs, rhs, set, COMPMAX, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberMax + +/* ------------------------------------------------------------------ */ +/* decNumberMaxMag -- compare and return the maximum by magnitude */ +/* */ +/* This computes C = A ? B, returning the maximum by 754 rules */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberMaxMag(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decCompareOp(res, lhs, rhs, set, COMPMAXMAG, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberMaxMag + +/* ------------------------------------------------------------------ */ +/* decNumberMin -- compare two Numbers and return the minimum */ +/* */ +/* This computes C = A ? B, returning the minimum by 754 rules */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberMin(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decCompareOp(res, lhs, rhs, set, COMPMIN, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberMin + +/* ------------------------------------------------------------------ */ +/* decNumberMinMag -- compare and return the minimum by magnitude */ +/* */ +/* This computes C = A ? B, returning the minimum by 754 rules */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberMinMag(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decCompareOp(res, lhs, rhs, set, COMPMINMAG, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberMinMag + +/* ------------------------------------------------------------------ */ +/* decNumberMinus -- prefix minus operator */ +/* */ +/* This computes C = 0 - A */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context */ +/* */ +/* See also decNumberCopyNegate for a quiet bitwise version of this. */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +/* Simply use AddOp for the subtract, which will do the necessary. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberMinus(decNumber *res, const decNumber *rhs, + decContext *set) { + decNumber dzero; + uInt status=0; // accumulator + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + decNumberZero(&dzero); // make 0 + dzero.exponent=rhs->exponent; // [no coefficient expansion] + decAddOp(res, &dzero, rhs, set, DECNEG, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberMinus + +/* ------------------------------------------------------------------ */ +/* decNumberNextMinus -- next towards -Infinity */ +/* */ +/* This computes C = A - infinitesimal, rounded towards -Infinity */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context */ +/* */ +/* This is a generalization of 754 NextDown. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberNextMinus(decNumber *res, const decNumber *rhs, + decContext *set) { + decNumber dtiny; // constant + decContext workset=*set; // work + uInt status=0; // accumulator + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + // +Infinity is the special case + if ((rhs->bits&(DECINF|DECNEG))==DECINF) { + decSetMaxValue(res, set); // is +ve + // there is no status to set + return res; + } + decNumberZero(&dtiny); // start with 0 + dtiny.lsu[0]=1; // make number that is .. + dtiny.exponent=DEC_MIN_EMIN-1; // .. smaller than tiniest + workset.round=DEC_ROUND_FLOOR; + decAddOp(res, rhs, &dtiny, &workset, DECNEG, &status); + status&=DEC_Invalid_operation|DEC_sNaN; // only sNaN Invalid please + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberNextMinus + +/* ------------------------------------------------------------------ */ +/* decNumberNextPlus -- next towards +Infinity */ +/* */ +/* This computes C = A + infinitesimal, rounded towards +Infinity */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context */ +/* */ +/* This is a generalization of 754 NextUp. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberNextPlus(decNumber *res, const decNumber *rhs, + decContext *set) { + decNumber dtiny; // constant + decContext workset=*set; // work + uInt status=0; // accumulator + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + // -Infinity is the special case + if ((rhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) { + decSetMaxValue(res, set); + res->bits=DECNEG; // negative + // there is no status to set + return res; + } + decNumberZero(&dtiny); // start with 0 + dtiny.lsu[0]=1; // make number that is .. + dtiny.exponent=DEC_MIN_EMIN-1; // .. smaller than tiniest + workset.round=DEC_ROUND_CEILING; + decAddOp(res, rhs, &dtiny, &workset, 0, &status); + status&=DEC_Invalid_operation|DEC_sNaN; // only sNaN Invalid please + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberNextPlus + +/* ------------------------------------------------------------------ */ +/* decNumberNextToward -- next towards rhs */ +/* */ +/* This computes C = A +/- infinitesimal, rounded towards */ +/* +/-Infinity in the direction of B, as per 754-1985 nextafter */ +/* modified during revision but dropped from 754-2008. */ +/* */ +/* res is C, the result. C may be A or B. */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* This is a generalization of 754-1985 NextAfter. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberNextToward(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + decNumber dtiny; // constant + decContext workset=*set; // work + Int result; // .. + uInt status=0; // accumulator + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { + decNaNs(res, lhs, rhs, set, &status); + } + else { // Is numeric, so no chance of sNaN Invalid, etc. + result=decCompare(lhs, rhs, 0); // sign matters + if (result==BADINT) status|=DEC_Insufficient_storage; // rare + else { // valid compare + if (result==0) decNumberCopySign(res, lhs, rhs); // easy + else { // differ: need NextPlus or NextMinus + uByte sub; // add or subtract + if (result<0) { // lhsbits&(DECINF|DECNEG))==(DECINF|DECNEG)) { + decSetMaxValue(res, set); + res->bits=DECNEG; // negative + return res; // there is no status to set + } + workset.round=DEC_ROUND_CEILING; + sub=0; // add, please + } // plus + else { // lhs>rhs, do nextminus + // +Infinity is the special case + if ((lhs->bits&(DECINF|DECNEG))==DECINF) { + decSetMaxValue(res, set); + return res; // there is no status to set + } + workset.round=DEC_ROUND_FLOOR; + sub=DECNEG; // subtract, please + } // minus + decNumberZero(&dtiny); // start with 0 + dtiny.lsu[0]=1; // make number that is .. + dtiny.exponent=DEC_MIN_EMIN-1; // .. smaller than tiniest + decAddOp(res, lhs, &dtiny, &workset, sub, &status); // + or - + // turn off exceptions if the result is a normal number + // (including Nmin), otherwise let all status through + if (decNumberIsNormal(res, set)) status=0; + } // unequal + } // compare OK + } // numeric + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberNextToward + +/* ------------------------------------------------------------------ */ +/* decNumberOr -- OR two Numbers, digitwise */ +/* */ +/* This computes C = A | B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X|X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context (used for result length and error report) */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Logical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberOr(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + const Unit *ua, *ub; // -> operands + const Unit *msua, *msub; // -> operand msus + Unit *uc, *msuc; // -> result and its msu + Int msudigs; // digits in res msu + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs) + || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) { + decStatus(res, DEC_Invalid_operation, set); + return res; + } + // operands are valid + ua=lhs->lsu; // bottom-up + ub=rhs->lsu; // .. + uc=res->lsu; // .. + msua=ua+D2U(lhs->digits)-1; // -> msu of lhs + msub=ub+D2U(rhs->digits)-1; // -> msu of rhs + msuc=uc+D2U(set->digits)-1; // -> msu of result + msudigs=MSUDIGITS(set->digits); // [faster than remainder] + for (; uc<=msuc; ua++, ub++, uc++) { // Unit loop + Unit a, b; // extract units + if (ua>msua) a=0; + else a=*ua; + if (ub>msub) b=0; + else b=*ub; + *uc=0; // can now write back + if (a|b) { // maybe 1 bits to examine + Int i, j; + // This loop could be unrolled and/or use BIN2BCD tables + for (i=0; i1) { + decStatus(res, DEC_Invalid_operation, set); + return res; + } + if (uc==msuc && i==msudigs-1) break; // just did final digit + } // each digit + } // non-zero + } // each unit + // [here uc-1 is the msu of the result] + res->digits=decGetDigits(res->lsu, uc-res->lsu); + res->exponent=0; // integer + res->bits=0; // sign=0 + return res; // [no status to set] + } // decNumberOr + +/* ------------------------------------------------------------------ */ +/* decNumberPlus -- prefix plus operator */ +/* */ +/* This computes C = 0 + A */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context */ +/* */ +/* See also decNumberCopy for a quiet bitwise version of this. */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +/* This simply uses AddOp; Add will take fast path after preparing A. */ +/* Performance is a concern here, as this routine is often used to */ +/* check operands and apply rounding and overflow/underflow testing. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberPlus(decNumber *res, const decNumber *rhs, + decContext *set) { + decNumber dzero; + uInt status=0; // accumulator + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + decNumberZero(&dzero); // make 0 + dzero.exponent=rhs->exponent; // [no coefficient expansion] + decAddOp(res, &dzero, rhs, set, 0, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberPlus + +/* ------------------------------------------------------------------ */ +/* decNumberMultiply -- multiply two Numbers */ +/* */ +/* This computes C = A x B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X+X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberMultiply(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decMultiplyOp(res, lhs, rhs, set, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberMultiply + +/* ------------------------------------------------------------------ */ +/* decNumberPower -- raise a number to a power */ +/* */ +/* This computes C = A ** B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X**X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Mathematical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* */ +/* However, if 1999999997<=B<=999999999 and B is an integer then the */ +/* restrictions on A and the context are relaxed to the usual bounds, */ +/* for compatibility with the earlier (integer power only) version */ +/* of this function. */ +/* */ +/* When B is an integer, the result may be exact, even if rounded. */ +/* */ +/* The final result is rounded according to the context; it will */ +/* almost always be correctly rounded, but may be up to 1 ulp in */ +/* error in rare cases. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberPower(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + #if DECSUBSET + decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated + decNumber *allocrhs=NULL; // .., rhs + #endif + decNumber *allocdac=NULL; // -> allocated acc buffer, iff used + decNumber *allocinv=NULL; // -> allocated 1/x buffer, iff used + Int reqdigits=set->digits; // requested DIGITS + Int n; // rhs in binary + Flag rhsint=0; // 1 if rhs is an integer + Flag useint=0; // 1 if can use integer calculation + Flag isoddint=0; // 1 if rhs is an integer and odd + Int i; // work + #if DECSUBSET + Int dropped; // .. + #endif + uInt needbytes; // buffer size needed + Flag seenbit; // seen a bit while powering + Int residue=0; // rounding residue + uInt status=0; // accumulators + uByte bits=0; // result sign if errors + decContext aset; // working context + decNumber dnOne; // work value 1... + // local accumulator buffer [a decNumber, with digits+elength+1 digits] + decNumber dacbuff[D2N(DECBUFFER+9)]; + decNumber *dac=dacbuff; // -> result accumulator + // same again for possible 1/lhs calculation + decNumber invbuff[D2N(DECBUFFER+9)]; + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { // reduce operands and set status, as needed + if (lhs->digits>reqdigits) { + alloclhs=decRoundOperand(lhs, set, &status); + if (alloclhs==NULL) break; + lhs=alloclhs; + } + if (rhs->digits>reqdigits) { + allocrhs=decRoundOperand(rhs, set, &status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + } + #endif + // [following code does not require input rounding] + + // handle NaNs and rhs Infinity (lhs infinity is harder) + if (SPECIALARGS) { + if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { // NaNs + decNaNs(res, lhs, rhs, set, &status); + break;} + if (decNumberIsInfinite(rhs)) { // rhs Infinity + Flag rhsneg=rhs->bits&DECNEG; // save rhs sign + if (decNumberIsNegative(lhs) // lhs<0 + && !decNumberIsZero(lhs)) // .. + status|=DEC_Invalid_operation; + else { // lhs >=0 + decNumberZero(&dnOne); // set up 1 + dnOne.lsu[0]=1; + decNumberCompare(dac, lhs, &dnOne, set); // lhs ? 1 + decNumberZero(res); // prepare for 0/1/Infinity + if (decNumberIsNegative(dac)) { // lhs<1 + if (rhsneg) res->bits|=DECINF; // +Infinity [else is +0] + } + else if (dac->lsu[0]==0) { // lhs=1 + // 1**Infinity is inexact, so return fully-padded 1.0000 + Int shift=set->digits-1; + *res->lsu=1; // was 0, make int 1 + res->digits=decShiftToMost(res->lsu, 1, shift); + res->exponent=-shift; // make 1.0000... + status|=DEC_Inexact|DEC_Rounded; // deemed inexact + } + else { // lhs>1 + if (!rhsneg) res->bits|=DECINF; // +Infinity [else is +0] + } + } // lhs>=0 + break;} + // [lhs infinity drops through] + } // specials + + // Original rhs may be an integer that fits and is in range + n=decGetInt(rhs); + if (n!=BADINT) { // it is an integer + rhsint=1; // record the fact for 1**n + isoddint=(Flag)n&1; // [works even if big] + if (n!=BIGEVEN && n!=BIGODD) // can use integer path? + useint=1; // looks good + } + + if (decNumberIsNegative(lhs) // -x .. + && isoddint) bits=DECNEG; // .. to an odd power + + // handle LHS infinity + if (decNumberIsInfinite(lhs)) { // [NaNs already handled] + uByte rbits=rhs->bits; // save + decNumberZero(res); // prepare + if (n==0) *res->lsu=1; // [-]Inf**0 => 1 + else { + // -Inf**nonint -> error + if (!rhsint && decNumberIsNegative(lhs)) { + status|=DEC_Invalid_operation; // -Inf**nonint is error + break;} + if (!(rbits & DECNEG)) bits|=DECINF; // was not a **-n + // [otherwise will be 0 or -0] + res->bits=bits; + } + break;} + + // similarly handle LHS zero + if (decNumberIsZero(lhs)) { + if (n==0) { // 0**0 => Error + #if DECSUBSET + if (!set->extended) { // [unless subset] + decNumberZero(res); + *res->lsu=1; // return 1 + break;} + #endif + status|=DEC_Invalid_operation; + } + else { // 0**x + uByte rbits=rhs->bits; // save + if (rbits & DECNEG) { // was a 0**(-n) + #if DECSUBSET + if (!set->extended) { // [bad if subset] + status|=DEC_Invalid_operation; + break;} + #endif + bits|=DECINF; + } + decNumberZero(res); // prepare + // [otherwise will be 0 or -0] + res->bits=bits; + } + break;} + + // here both lhs and rhs are finite; rhs==0 is handled in the + // integer path. Next handle the non-integer cases + if (!useint) { // non-integral rhs + // any -ve lhs is bad, as is either operand or context out of + // bounds + if (decNumberIsNegative(lhs)) { + status|=DEC_Invalid_operation; + break;} + if (decCheckMath(lhs, set, &status) + || decCheckMath(rhs, set, &status)) break; // variable status + + decContextDefault(&aset, DEC_INIT_DECIMAL64); // clean context + aset.emax=DEC_MAX_MATH; // usual bounds + aset.emin=-DEC_MAX_MATH; // .. + aset.clamp=0; // and no concrete format + + // calculate the result using exp(ln(lhs)*rhs), which can + // all be done into the accumulator, dac. The precision needed + // is enough to contain the full information in the lhs (which + // is the total digits, including exponent), or the requested + // precision, if larger, + 4; 6 is used for the exponent + // maximum length, and this is also used when it is shorter + // than the requested digits as it greatly reduces the >0.5 ulp + // cases at little cost (because Ln doubles digits each + // iteration so a few extra digits rarely causes an extra + // iteration) + aset.digits=MAXI(lhs->digits, set->digits)+6+4; + } // non-integer rhs + + else { // rhs is in-range integer + if (n==0) { // x**0 = 1 + // (0**0 was handled above) + decNumberZero(res); // result=1 + *res->lsu=1; // .. + break;} + // rhs is a non-zero integer + if (n<0) n=-n; // use abs(n) + + aset=*set; // clone the context + aset.round=DEC_ROUND_HALF_EVEN; // internally use balanced + // calculate the working DIGITS + aset.digits=reqdigits+(rhs->digits+rhs->exponent)+2; + #if DECSUBSET + if (!set->extended) aset.digits--; // use classic precision + #endif + // it's an error if this is more than can be handled + if (aset.digits>DECNUMMAXP) {status|=DEC_Invalid_operation; break;} + } // integer path + + // aset.digits is the count of digits for the accumulator needed + // if accumulator is too long for local storage, then allocate + needbytes=sizeof(decNumber)+(D2U(aset.digits)-1)*sizeof(Unit); + // [needbytes also used below if 1/lhs needed] + if (needbytes>sizeof(dacbuff)) { + allocdac=(decNumber *)malloc(needbytes); + if (allocdac==NULL) { // hopeless -- abandon + status|=DEC_Insufficient_storage; + break;} + dac=allocdac; // use the allocated space + } + // here, aset is set up and accumulator is ready for use + + if (!useint) { // non-integral rhs + // x ** y; special-case x=1 here as it will otherwise always + // reduce to integer 1; decLnOp has a fastpath which detects + // the case of x=1 + decLnOp(dac, lhs, &aset, &status); // dac=ln(lhs) + // [no error possible, as lhs 0 already handled] + if (ISZERO(dac)) { // x==1, 1.0, etc. + // need to return fully-padded 1.0000 etc., but rhsint->1 + *dac->lsu=1; // was 0, make int 1 + if (!rhsint) { // add padding + Int shift=set->digits-1; + dac->digits=decShiftToMost(dac->lsu, 1, shift); + dac->exponent=-shift; // make 1.0000... + status|=DEC_Inexact|DEC_Rounded; // deemed inexact + } + } + else { + decMultiplyOp(dac, dac, rhs, &aset, &status); // dac=dac*rhs + decExpOp(dac, dac, &aset, &status); // dac=exp(dac) + } + // and drop through for final rounding + } // non-integer rhs + + else { // carry on with integer + decNumberZero(dac); // acc=1 + *dac->lsu=1; // .. + + // if a negative power the constant 1 is needed, and if not subset + // invert the lhs now rather than inverting the result later + if (decNumberIsNegative(rhs)) { // was a **-n [hence digits>0] + decNumber *inv=invbuff; // asssume use fixed buffer + decNumberCopy(&dnOne, dac); // dnOne=1; [needed now or later] + #if DECSUBSET + if (set->extended) { // need to calculate 1/lhs + #endif + // divide lhs into 1, putting result in dac [dac=1/dac] + decDivideOp(dac, &dnOne, lhs, &aset, DIVIDE, &status); + // now locate or allocate space for the inverted lhs + if (needbytes>sizeof(invbuff)) { + allocinv=(decNumber *)malloc(needbytes); + if (allocinv==NULL) { // hopeless -- abandon + status|=DEC_Insufficient_storage; + break;} + inv=allocinv; // use the allocated space + } + // [inv now points to big-enough buffer or allocated storage] + decNumberCopy(inv, dac); // copy the 1/lhs + decNumberCopy(dac, &dnOne); // restore acc=1 + lhs=inv; // .. and go forward with new lhs + #if DECSUBSET + } + #endif + } + + // Raise-to-the-power loop... + seenbit=0; // set once a 1-bit is encountered + for (i=1;;i++){ // for each bit [top bit ignored] + // abandon if had overflow or terminal underflow + if (status & (DEC_Overflow|DEC_Underflow)) { // interesting? + if (status&DEC_Overflow || ISZERO(dac)) break; + } + // [the following two lines revealed an optimizer bug in a C++ + // compiler, with symptom: 5**3 -> 25, when n=n+n was used] + n=n<<1; // move next bit to testable position + if (n<0) { // top bit is set + seenbit=1; // OK, significant bit seen + decMultiplyOp(dac, dac, lhs, &aset, &status); // dac=dac*x + } + if (i==31) break; // that was the last bit + if (!seenbit) continue; // no need to square 1 + decMultiplyOp(dac, dac, dac, &aset, &status); // dac=dac*dac [square] + } /*i*/ // 32 bits + + // complete internal overflow or underflow processing + if (status & (DEC_Overflow|DEC_Underflow)) { + #if DECSUBSET + // If subset, and power was negative, reverse the kind of -erflow + // [1/x not yet done] + if (!set->extended && decNumberIsNegative(rhs)) { + if (status & DEC_Overflow) + status^=DEC_Overflow | DEC_Underflow | DEC_Subnormal; + else { // trickier -- Underflow may or may not be set + status&=~(DEC_Underflow | DEC_Subnormal); // [one or both] + status|=DEC_Overflow; + } + } + #endif + dac->bits=(dac->bits & ~DECNEG) | bits; // force correct sign + // round subnormals [to set.digits rather than aset.digits] + // or set overflow result similarly as required + decFinalize(dac, set, &residue, &status); + decNumberCopy(res, dac); // copy to result (is now OK length) + break; + } + + #if DECSUBSET + if (!set->extended && // subset math + decNumberIsNegative(rhs)) { // was a **-n [hence digits>0] + // so divide result into 1 [dac=1/dac] + decDivideOp(dac, &dnOne, dac, &aset, DIVIDE, &status); + } + #endif + } // rhs integer path + + // reduce result to the requested length and copy to result + decCopyFit(res, dac, set, &residue, &status); + decFinish(res, set, &residue, &status); // final cleanup + #if DECSUBSET + if (!set->extended) decTrim(res, set, 0, 1, &dropped); // trailing zeros + #endif + } while(0); // end protected + + if (allocdac!=NULL) free(allocdac); // drop any storage used + if (allocinv!=NULL) free(allocinv); // .. + #if DECSUBSET + if (alloclhs!=NULL) free(alloclhs); // .. + if (allocrhs!=NULL) free(allocrhs); // .. + #endif + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberPower + +/* ------------------------------------------------------------------ */ +/* decNumberQuantize -- force exponent to requested value */ +/* */ +/* This computes C = op(A, B), where op adjusts the coefficient */ +/* of C (by rounding or shifting) such that the exponent (-scale) */ +/* of C has exponent of B. The numerical value of C will equal A, */ +/* except for the effects of any rounding that occurred. */ +/* */ +/* res is C, the result. C may be A or B */ +/* lhs is A, the number to adjust */ +/* rhs is B, the number with exponent to match */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Unless there is an error or the result is infinite, the exponent */ +/* after the operation is guaranteed to be equal to that of B. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberQuantize(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decQuantizeOp(res, lhs, rhs, set, 1, &status); + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberQuantize + +/* ------------------------------------------------------------------ */ +/* decNumberReduce -- remove trailing zeros */ +/* */ +/* This computes C = 0 + A, and normalizes the result */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +// Previously known as Normalize +decNumber * decNumberNormalize(decNumber *res, const decNumber *rhs, + decContext *set) { + return decNumberReduce(res, rhs, set); + } // decNumberNormalize + +decNumber * decNumberReduce(decNumber *res, const decNumber *rhs, + decContext *set) { + #if DECSUBSET + decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated + #endif + uInt status=0; // as usual + Int residue=0; // as usual + Int dropped; // work + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { + // reduce operand and set lostDigits status, as needed + if (rhs->digits>set->digits) { + allocrhs=decRoundOperand(rhs, set, &status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + } + #endif + // [following code does not require input rounding] + + // Infinities copy through; NaNs need usual treatment + if (decNumberIsNaN(rhs)) { + decNaNs(res, rhs, NULL, set, &status); + break; + } + + // reduce result to the requested length and copy to result + decCopyFit(res, rhs, set, &residue, &status); // copy & round + decFinish(res, set, &residue, &status); // cleanup/set flags + decTrim(res, set, 1, 0, &dropped); // normalize in place + // [may clamp] + } while(0); // end protected + + #if DECSUBSET + if (allocrhs !=NULL) free(allocrhs); // .. + #endif + if (status!=0) decStatus(res, status, set);// then report status + return res; + } // decNumberReduce + +/* ------------------------------------------------------------------ */ +/* decNumberRescale -- force exponent to requested value */ +/* */ +/* This computes C = op(A, B), where op adjusts the coefficient */ +/* of C (by rounding or shifting) such that the exponent (-scale) */ +/* of C has the value B. The numerical value of C will equal A, */ +/* except for the effects of any rounding that occurred. */ +/* */ +/* res is C, the result. C may be A or B */ +/* lhs is A, the number to adjust */ +/* rhs is B, the requested exponent */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Unless there is an error or the result is infinite, the exponent */ +/* after the operation is guaranteed to be equal to B. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberRescale(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decQuantizeOp(res, lhs, rhs, set, 0, &status); + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberRescale + +/* ------------------------------------------------------------------ */ +/* decNumberRemainder -- divide and return remainder */ +/* */ +/* This computes C = A % B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X%X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberRemainder(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decDivideOp(res, lhs, rhs, set, REMAINDER, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberRemainder + +/* ------------------------------------------------------------------ */ +/* decNumberRemainderNear -- divide and return remainder from nearest */ +/* */ +/* This computes C = A % B, where % is the IEEE remainder operator */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X%X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberRemainderNear(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + decDivideOp(res, lhs, rhs, set, REMNEAR, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberRemainderNear + +/* ------------------------------------------------------------------ */ +/* decNumberRotate -- rotate the coefficient of a Number left/right */ +/* */ +/* This computes C = A rot B (in base ten and rotating set->digits */ +/* digits). */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=XrotX) */ +/* lhs is A */ +/* rhs is B, the number of digits to rotate (-ve to right) */ +/* set is the context */ +/* */ +/* The digits of the coefficient of A are rotated to the left (if B */ +/* is positive) or to the right (if B is negative) without adjusting */ +/* the exponent or the sign of A. If lhs->digits is less than */ +/* set->digits the coefficient is padded with zeros on the left */ +/* before the rotate. Any leading zeros in the result are removed */ +/* as usual. */ +/* */ +/* B must be an integer (q=0) and in the range -set->digits through */ +/* +set->digits. */ +/* C must have space for set->digits digits. */ +/* NaNs are propagated as usual. Infinities are unaffected (but */ +/* B must be valid). No status is set unless B is invalid or an */ +/* operand is an sNaN. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberRotate(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + Int rotate; // rhs as an Int + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + // NaNs propagate as normal + if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) + decNaNs(res, lhs, rhs, set, &status); + // rhs must be an integer + else if (decNumberIsInfinite(rhs) || rhs->exponent!=0) + status=DEC_Invalid_operation; + else { // both numeric, rhs is an integer + rotate=decGetInt(rhs); // [cannot fail] + if (rotate==BADINT // something bad .. + || rotate==BIGODD || rotate==BIGEVEN // .. very big .. + || abs(rotate)>set->digits) // .. or out of range + status=DEC_Invalid_operation; + else { // rhs is OK + decNumberCopy(res, lhs); + // convert -ve rotate to equivalent positive rotation + if (rotate<0) rotate=set->digits+rotate; + if (rotate!=0 && rotate!=set->digits // zero or full rotation + && !decNumberIsInfinite(res)) { // lhs was infinite + // left-rotate to do; 0 < rotate < set->digits + uInt units, shift; // work + uInt msudigits; // digits in result msu + Unit *msu=res->lsu+D2U(res->digits)-1; // current msu + Unit *msumax=res->lsu+D2U(set->digits)-1; // rotation msu + for (msu++; msu<=msumax; msu++) *msu=0; // ensure high units=0 + res->digits=set->digits; // now full-length + msudigits=MSUDIGITS(res->digits); // actual digits in msu + + // rotation here is done in-place, in three steps + // 1. shift all to least up to one unit to unit-align final + // lsd [any digits shifted out are rotated to the left, + // abutted to the original msd (which may require split)] + // + // [if there are no whole units left to rotate, the + // rotation is now complete] + // + // 2. shift to least, from below the split point only, so that + // the final msd is in the right place in its Unit [any + // digits shifted out will fit exactly in the current msu, + // left aligned, no split required] + // + // 3. rotate all the units by reversing left part, right + // part, and then whole + // + // example: rotate right 8 digits (2 units + 2), DECDPUN=3. + // + // start: 00a bcd efg hij klm npq + // + // 1a 000 0ab cde fgh|ijk lmn [pq saved] + // 1b 00p qab cde fgh|ijk lmn + // + // 2a 00p qab cde fgh|00i jkl [mn saved] + // 2b mnp qab cde fgh|00i jkl + // + // 3a fgh cde qab mnp|00i jkl + // 3b fgh cde qab mnp|jkl 00i + // 3c 00i jkl mnp qab cde fgh + + // Step 1: amount to shift is the partial right-rotate count + rotate=set->digits-rotate; // make it right-rotate + units=rotate/DECDPUN; // whole units to rotate + shift=rotate%DECDPUN; // left-over digits count + if (shift>0) { // not an exact number of units + uInt save=res->lsu[0]%powers[shift]; // save low digit(s) + decShiftToLeast(res->lsu, D2U(res->digits), shift); + if (shift>msudigits) { // msumax-1 needs >0 digits + uInt rem=save%powers[shift-msudigits];// split save + *msumax=(Unit)(save/powers[shift-msudigits]); // and insert + *(msumax-1)=*(msumax-1) + +(Unit)(rem*powers[DECDPUN-(shift-msudigits)]); // .. + } + else { // all fits in msumax + *msumax=*msumax+(Unit)(save*powers[msudigits-shift]); // [maybe *1] + } + } // digits shift needed + + // If whole units to rotate... + if (units>0) { // some to do + // Step 2: the units to touch are the whole ones in rotate, + // if any, and the shift is DECDPUN-msudigits (which may be + // 0, again) + shift=DECDPUN-msudigits; + if (shift>0) { // not an exact number of units + uInt save=res->lsu[0]%powers[shift]; // save low digit(s) + decShiftToLeast(res->lsu, units, shift); + *msumax=*msumax+(Unit)(save*powers[msudigits]); + } // partial shift needed + + // Step 3: rotate the units array using triple reverse + // (reversing is easy and fast) + decReverse(res->lsu+units, msumax); // left part + decReverse(res->lsu, res->lsu+units-1); // right part + decReverse(res->lsu, msumax); // whole + } // whole units to rotate + // the rotation may have left an undetermined number of zeros + // on the left, so true length needs to be calculated + res->digits=decGetDigits(res->lsu, msumax-res->lsu+1); + } // rotate needed + } // rhs OK + } // numerics + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberRotate + +/* ------------------------------------------------------------------ */ +/* decNumberSameQuantum -- test for equal exponents */ +/* */ +/* res is the result number, which will contain either 0 or 1 */ +/* lhs is a number to test */ +/* rhs is the second (usually a pattern) */ +/* */ +/* No errors are possible and no context is needed. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberSameQuantum(decNumber *res, const decNumber *lhs, + const decNumber *rhs) { + Unit ret=0; // return value + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, DECUNCONT)) return res; + #endif + + if (SPECIALARGS) { + if (decNumberIsNaN(lhs) && decNumberIsNaN(rhs)) ret=1; + else if (decNumberIsInfinite(lhs) && decNumberIsInfinite(rhs)) ret=1; + // [anything else with a special gives 0] + } + else if (lhs->exponent==rhs->exponent) ret=1; + + decNumberZero(res); // OK to overwrite an operand now + *res->lsu=ret; + return res; + } // decNumberSameQuantum + +/* ------------------------------------------------------------------ */ +/* decNumberScaleB -- multiply by a power of 10 */ +/* */ +/* This computes C = A x 10**B where B is an integer (q=0) with */ +/* maximum magnitude 2*(emax+digits) */ +/* */ +/* res is C, the result. C may be A or B */ +/* lhs is A, the number to adjust */ +/* rhs is B, the requested power of ten to use */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* The result may underflow or overflow. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberScaleB(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + Int reqexp; // requested exponent change [B] + uInt status=0; // accumulator + Int residue; // work + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + // Handle special values except lhs infinite + if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) + decNaNs(res, lhs, rhs, set, &status); + // rhs must be an integer + else if (decNumberIsInfinite(rhs) || rhs->exponent!=0) + status=DEC_Invalid_operation; + else { + // lhs is a number; rhs is a finite with q==0 + reqexp=decGetInt(rhs); // [cannot fail] + // maximum range is larger than getInt can handle, so this is + // more restrictive than the specification + if (reqexp==BADINT // something bad .. + || reqexp==BIGODD || reqexp==BIGEVEN // it was huge + || (abs(reqexp)+1)/2>(set->digits+set->emax)) // .. or out of range + status=DEC_Invalid_operation; + else { // rhs is OK + decNumberCopy(res, lhs); // all done if infinite lhs + if (!decNumberIsInfinite(res)) { // prepare to scale + Int exp=res->exponent; // save for overflow test + res->exponent+=reqexp; // adjust the exponent + if (((exp^reqexp)>=0) // same sign ... + && ((exp^res->exponent)<0)) { // .. but result had different + // the calculation overflowed, so force right treatment + if (exp<0) res->exponent=DEC_MIN_EMIN-DEC_MAX_DIGITS; + else res->exponent=DEC_MAX_EMAX+1; + } + residue=0; + decFinalize(res, set, &residue, &status); // final check + } // finite LHS + } // rhs OK + } // rhs finite + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberScaleB + +/* ------------------------------------------------------------------ */ +/* decNumberShift -- shift the coefficient of a Number left or right */ +/* */ +/* This computes C = A << B or C = A >> -B (in base ten). */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X<digits through */ +/* +set->digits. */ +/* C must have space for set->digits digits. */ +/* NaNs are propagated as usual. Infinities are unaffected (but */ +/* B must be valid). No status is set unless B is invalid or an */ +/* operand is an sNaN. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberShift(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + Int shift; // rhs as an Int + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + // NaNs propagate as normal + if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) + decNaNs(res, lhs, rhs, set, &status); + // rhs must be an integer + else if (decNumberIsInfinite(rhs) || rhs->exponent!=0) + status=DEC_Invalid_operation; + else { // both numeric, rhs is an integer + shift=decGetInt(rhs); // [cannot fail] + if (shift==BADINT // something bad .. + || shift==BIGODD || shift==BIGEVEN // .. very big .. + || abs(shift)>set->digits) // .. or out of range + status=DEC_Invalid_operation; + else { // rhs is OK + decNumberCopy(res, lhs); + if (shift!=0 && !decNumberIsInfinite(res)) { // something to do + if (shift>0) { // to left + if (shift==set->digits) { // removing all + *res->lsu=0; // so place 0 + res->digits=1; // .. + } + else { // + // first remove leading digits if necessary + if (res->digits+shift>set->digits) { + decDecap(res, res->digits+shift-set->digits); + // that updated res->digits; may have gone to 1 (for a + // single digit or for zero + } + if (res->digits>1 || *res->lsu) // if non-zero.. + res->digits=decShiftToMost(res->lsu, res->digits, shift); + } // partial left + } // left + else { // to right + if (-shift>=res->digits) { // discarding all + *res->lsu=0; // so place 0 + res->digits=1; // .. + } + else { + decShiftToLeast(res->lsu, D2U(res->digits), -shift); + res->digits-=(-shift); + } + } // to right + } // non-0 non-Inf shift + } // rhs OK + } // numerics + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberShift + +/* ------------------------------------------------------------------ */ +/* decNumberSquareRoot -- square root operator */ +/* */ +/* This computes C = squareroot(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context; note that rounding mode has no effect */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +/* This uses the following varying-precision algorithm in: */ +/* */ +/* Properly Rounded Variable Precision Square Root, T. E. Hull and */ +/* A. Abrham, ACM Transactions on Mathematical Software, Vol 11 #3, */ +/* pp229-237, ACM, September 1985. */ +/* */ +/* The square-root is calculated using Newton's method, after which */ +/* a check is made to ensure the result is correctly rounded. */ +/* */ +/* % [Reformatted original Numerical Turing source code follows.] */ +/* function sqrt(x : real) : real */ +/* % sqrt(x) returns the properly rounded approximation to the square */ +/* % root of x, in the precision of the calling environment, or it */ +/* % fails if x < 0. */ +/* % t e hull and a abrham, august, 1984 */ +/* if x <= 0 then */ +/* if x < 0 then */ +/* assert false */ +/* else */ +/* result 0 */ +/* end if */ +/* end if */ +/* var f := setexp(x, 0) % fraction part of x [0.1 <= x < 1] */ +/* var e := getexp(x) % exponent part of x */ +/* var approx : real */ +/* if e mod 2 = 0 then */ +/* approx := .259 + .819 * f % approx to root of f */ +/* else */ +/* f := f/l0 % adjustments */ +/* e := e + 1 % for odd */ +/* approx := .0819 + 2.59 * f % exponent */ +/* end if */ +/* */ +/* var p:= 3 */ +/* const maxp := currentprecision + 2 */ +/* loop */ +/* p := min(2*p - 2, maxp) % p = 4,6,10, . . . , maxp */ +/* precision p */ +/* approx := .5 * (approx + f/approx) */ +/* exit when p = maxp */ +/* end loop */ +/* */ +/* % approx is now within 1 ulp of the properly rounded square root */ +/* % of f; to ensure proper rounding, compare squares of (approx - */ +/* % l/2 ulp) and (approx + l/2 ulp) with f. */ +/* p := currentprecision */ +/* begin */ +/* precision p + 2 */ +/* const approxsubhalf := approx - setexp(.5, -p) */ +/* if mulru(approxsubhalf, approxsubhalf) > f then */ +/* approx := approx - setexp(.l, -p + 1) */ +/* else */ +/* const approxaddhalf := approx + setexp(.5, -p) */ +/* if mulrd(approxaddhalf, approxaddhalf) < f then */ +/* approx := approx + setexp(.l, -p + 1) */ +/* end if */ +/* end if */ +/* end */ +/* result setexp(approx, e div 2) % fix exponent */ +/* end sqrt */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberSquareRoot(decNumber *res, const decNumber *rhs, + decContext *set) { + decContext workset, approxset; // work contexts + decNumber dzero; // used for constant zero + Int maxp; // largest working precision + Int workp; // working precision + Int residue=0; // rounding residue + uInt status=0, ignore=0; // status accumulators + uInt rstatus; // .. + Int exp; // working exponent + Int ideal; // ideal (preferred) exponent + Int needbytes; // work + Int dropped; // .. + + #if DECSUBSET + decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated + #endif + // buffer for f [needs +1 in case DECBUFFER 0] + decNumber buff[D2N(DECBUFFER+1)]; + // buffer for a [needs +2 to match likely maxp] + decNumber bufa[D2N(DECBUFFER+2)]; + // buffer for temporary, b [must be same size as a] + decNumber bufb[D2N(DECBUFFER+2)]; + decNumber *allocbuff=NULL; // -> allocated buff, iff allocated + decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated + decNumber *allocbufb=NULL; // -> allocated bufb, iff allocated + decNumber *f=buff; // reduced fraction + decNumber *a=bufa; // approximation to result + decNumber *b=bufb; // intermediate result + // buffer for temporary variable, up to 3 digits + decNumber buft[D2N(3)]; + decNumber *t=buft; // up-to-3-digit constant or work + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { + // reduce operand and set lostDigits status, as needed + if (rhs->digits>set->digits) { + allocrhs=decRoundOperand(rhs, set, &status); + if (allocrhs==NULL) break; + // [Note: 'f' allocation below could reuse this buffer if + // used, but as this is rare they are kept separate for clarity.] + rhs=allocrhs; + } + } + #endif + // [following code does not require input rounding] + + // handle infinities and NaNs + if (SPECIALARG) { + if (decNumberIsInfinite(rhs)) { // an infinity + if (decNumberIsNegative(rhs)) status|=DEC_Invalid_operation; + else decNumberCopy(res, rhs); // +Infinity + } + else decNaNs(res, rhs, NULL, set, &status); // a NaN + break; + } + + // calculate the ideal (preferred) exponent [floor(exp/2)] + // [It would be nicer to write: ideal=rhs->exponent>>1, but this + // generates a compiler warning. Generated code is the same.] + ideal=(rhs->exponent&~1)/2; // target + + // handle zeros + if (ISZERO(rhs)) { + decNumberCopy(res, rhs); // could be 0 or -0 + res->exponent=ideal; // use the ideal [safe] + // use decFinish to clamp any out-of-range exponent, etc. + decFinish(res, set, &residue, &status); + break; + } + + // any other -x is an oops + if (decNumberIsNegative(rhs)) { + status|=DEC_Invalid_operation; + break; + } + + // space is needed for three working variables + // f -- the same precision as the RHS, reduced to 0.01->0.99... + // a -- Hull's approximation -- precision, when assigned, is + // currentprecision+1 or the input argument precision, + // whichever is larger (+2 for use as temporary) + // b -- intermediate temporary result (same size as a) + // if any is too long for local storage, then allocate + workp=MAXI(set->digits+1, rhs->digits); // actual rounding precision + workp=MAXI(workp, 7); // at least 7 for low cases + maxp=workp+2; // largest working precision + + needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); + if (needbytes>(Int)sizeof(buff)) { + allocbuff=(decNumber *)malloc(needbytes); + if (allocbuff==NULL) { // hopeless -- abandon + status|=DEC_Insufficient_storage; + break;} + f=allocbuff; // use the allocated space + } + // a and b both need to be able to hold a maxp-length number + needbytes=sizeof(decNumber)+(D2U(maxp)-1)*sizeof(Unit); + if (needbytes>(Int)sizeof(bufa)) { // [same applies to b] + allocbufa=(decNumber *)malloc(needbytes); + allocbufb=(decNumber *)malloc(needbytes); + if (allocbufa==NULL || allocbufb==NULL) { // hopeless + status|=DEC_Insufficient_storage; + break;} + a=allocbufa; // use the allocated spaces + b=allocbufb; // .. + } + + // copy rhs -> f, save exponent, and reduce so 0.1 <= f < 1 + decNumberCopy(f, rhs); + exp=f->exponent+f->digits; // adjusted to Hull rules + f->exponent=-(f->digits); // to range + + // set up working context + decContextDefault(&workset, DEC_INIT_DECIMAL64); + workset.emax=DEC_MAX_EMAX; + workset.emin=DEC_MIN_EMIN; + + // [Until further notice, no error is possible and status bits + // (Rounded, etc.) should be ignored, not accumulated.] + + // Calculate initial approximation, and allow for odd exponent + workset.digits=workp; // p for initial calculation + t->bits=0; t->digits=3; + a->bits=0; a->digits=3; + if ((exp & 1)==0) { // even exponent + // Set t=0.259, a=0.819 + t->exponent=-3; + a->exponent=-3; + #if DECDPUN>=3 + t->lsu[0]=259; + a->lsu[0]=819; + #elif DECDPUN==2 + t->lsu[0]=59; t->lsu[1]=2; + a->lsu[0]=19; a->lsu[1]=8; + #else + t->lsu[0]=9; t->lsu[1]=5; t->lsu[2]=2; + a->lsu[0]=9; a->lsu[1]=1; a->lsu[2]=8; + #endif + } + else { // odd exponent + // Set t=0.0819, a=2.59 + f->exponent--; // f=f/10 + exp++; // e=e+1 + t->exponent=-4; + a->exponent=-2; + #if DECDPUN>=3 + t->lsu[0]=819; + a->lsu[0]=259; + #elif DECDPUN==2 + t->lsu[0]=19; t->lsu[1]=8; + a->lsu[0]=59; a->lsu[1]=2; + #else + t->lsu[0]=9; t->lsu[1]=1; t->lsu[2]=8; + a->lsu[0]=9; a->lsu[1]=5; a->lsu[2]=2; + #endif + } + + decMultiplyOp(a, a, f, &workset, &ignore); // a=a*f + decAddOp(a, a, t, &workset, 0, &ignore); // ..+t + // [a is now the initial approximation for sqrt(f), calculated with + // currentprecision, which is also a's precision.] + + // the main calculation loop + decNumberZero(&dzero); // make 0 + decNumberZero(t); // set t = 0.5 + t->lsu[0]=5; // .. + t->exponent=-1; // .. + workset.digits=3; // initial p + for (; workset.digitsexponent+=exp/2; // set correct exponent + rstatus=0; // clear status + residue=0; // .. and accumulator + decCopyFit(a, a, &approxset, &residue, &rstatus); // reduce (if needed) + decFinish(a, &approxset, &residue, &rstatus); // clean and finalize + + // Overflow was possible if the input exponent was out-of-range, + // in which case quit + if (rstatus&DEC_Overflow) { + status=rstatus; // use the status as-is + decNumberCopy(res, a); // copy to result + break; + } + + // Preserve status except Inexact/Rounded + status|=(rstatus & ~(DEC_Rounded|DEC_Inexact)); + + // Carry out the Hull correction + a->exponent-=exp/2; // back to 0.1->1 + + // a is now at final precision and within 1 ulp of the properly + // rounded square root of f; to ensure proper rounding, compare + // squares of (a - l/2 ulp) and (a + l/2 ulp) with f. + // Here workset.digits=maxp and t=0.5, and a->digits determines + // the ulp + workset.digits--; // maxp-1 is OK now + t->exponent=-a->digits-1; // make 0.5 ulp + decAddOp(b, a, t, &workset, DECNEG, &ignore); // b = a - 0.5 ulp + workset.round=DEC_ROUND_UP; + decMultiplyOp(b, b, b, &workset, &ignore); // b = mulru(b, b) + decCompareOp(b, f, b, &workset, COMPARE, &ignore); // b ? f, reversed + if (decNumberIsNegative(b)) { // f < b [i.e., b > f] + // this is the more common adjustment, though both are rare + t->exponent++; // make 1.0 ulp + t->lsu[0]=1; // .. + decAddOp(a, a, t, &workset, DECNEG, &ignore); // a = a - 1 ulp + // assign to approx [round to length] + approxset.emin-=exp/2; // adjust to match a + approxset.emax-=exp/2; + decAddOp(a, &dzero, a, &approxset, 0, &ignore); + } + else { + decAddOp(b, a, t, &workset, 0, &ignore); // b = a + 0.5 ulp + workset.round=DEC_ROUND_DOWN; + decMultiplyOp(b, b, b, &workset, &ignore); // b = mulrd(b, b) + decCompareOp(b, b, f, &workset, COMPARE, &ignore); // b ? f + if (decNumberIsNegative(b)) { // b < f + t->exponent++; // make 1.0 ulp + t->lsu[0]=1; // .. + decAddOp(a, a, t, &workset, 0, &ignore); // a = a + 1 ulp + // assign to approx [round to length] + approxset.emin-=exp/2; // adjust to match a + approxset.emax-=exp/2; + decAddOp(a, &dzero, a, &approxset, 0, &ignore); + } + } + // [no errors are possible in the above, and rounding/inexact during + // estimation are irrelevant, so status was not accumulated] + + // Here, 0.1 <= a < 1 (still), so adjust back + a->exponent+=exp/2; // set correct exponent + + // count droppable zeros [after any subnormal rounding] by + // trimming a copy + decNumberCopy(b, a); + decTrim(b, set, 1, 1, &dropped); // [drops trailing zeros] + + // Set Inexact and Rounded. The answer can only be exact if + // it is short enough so that squaring it could fit in workp + // digits, so this is the only (relatively rare) condition that + // a careful check is needed + if (b->digits*2-1 > workp) { // cannot fit + status|=DEC_Inexact|DEC_Rounded; + } + else { // could be exact/unrounded + uInt mstatus=0; // local status + decMultiplyOp(b, b, b, &workset, &mstatus); // try the multiply + if (mstatus&DEC_Overflow) { // result just won't fit + status|=DEC_Inexact|DEC_Rounded; + } + else { // plausible + decCompareOp(t, b, rhs, &workset, COMPARE, &mstatus); // b ? rhs + if (!ISZERO(t)) status|=DEC_Inexact|DEC_Rounded; // not equal + else { // is Exact + // here, dropped is the count of trailing zeros in 'a' + // use closest exponent to ideal... + Int todrop=ideal-a->exponent; // most that can be dropped + if (todrop<0) status|=DEC_Rounded; // ideally would add 0s + else { // unrounded + // there are some to drop, but emax may not allow all + Int maxexp=set->emax-set->digits+1; + Int maxdrop=maxexp-a->exponent; + if (todrop>maxdrop && set->clamp) { // apply clamping + todrop=maxdrop; + status|=DEC_Clamped; + } + if (dropped0) { // have some to drop + decShiftToLeast(a->lsu, D2U(a->digits), todrop); + a->exponent+=todrop; // maintain numerical value + a->digits-=todrop; // new length + } + } + } + } + } + + // double-check Underflow, as perhaps the result could not have + // been subnormal (initial argument too big), or it is now Exact + if (status&DEC_Underflow) { + Int ae=rhs->exponent+rhs->digits-1; // adjusted exponent + // check if truly subnormal + #if DECEXTFLAG // DEC_Subnormal too + if (ae>=set->emin*2) status&=~(DEC_Subnormal|DEC_Underflow); + #else + if (ae>=set->emin*2) status&=~DEC_Underflow; + #endif + // check if truly inexact + if (!(status&DEC_Inexact)) status&=~DEC_Underflow; + } + + decNumberCopy(res, a); // a is now the result + } while(0); // end protected + + if (allocbuff!=NULL) free(allocbuff); // drop any storage used + if (allocbufa!=NULL) free(allocbufa); // .. + if (allocbufb!=NULL) free(allocbufb); // .. + #if DECSUBSET + if (allocrhs !=NULL) free(allocrhs); // .. + #endif + if (status!=0) decStatus(res, status, set);// then report status + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberSquareRoot + +/* ------------------------------------------------------------------ */ +/* decNumberSubtract -- subtract two Numbers */ +/* */ +/* This computes C = A - B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X-X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* */ +/* C must have space for set->digits digits. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberSubtract(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + uInt status=0; // accumulator + + decAddOp(res, lhs, rhs, set, DECNEG, &status); + if (status!=0) decStatus(res, status, set); + #if DECCHECK + decCheckInexact(res, set); + #endif + return res; + } // decNumberSubtract + +/* ------------------------------------------------------------------ */ +/* decNumberToIntegralExact -- round-to-integral-value with InExact */ +/* decNumberToIntegralValue -- round-to-integral-value */ +/* */ +/* res is the result */ +/* rhs is input number */ +/* set is the context */ +/* */ +/* res must have space for any value of rhs. */ +/* */ +/* This implements the IEEE special operators and therefore treats */ +/* special values as valid. For finite numbers it returns */ +/* rescale(rhs, 0) if rhs->exponent is <0. */ +/* Otherwise the result is rhs (so no error is possible, except for */ +/* sNaN). */ +/* */ +/* The context is used for rounding mode and status after sNaN, but */ +/* the digits setting is ignored. The Exact version will signal */ +/* Inexact if the result differs numerically from rhs; the other */ +/* never signals Inexact. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberToIntegralExact(decNumber *res, const decNumber *rhs, + decContext *set) { + decNumber dn; + decContext workset; // working context + uInt status=0; // accumulator + + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + // handle infinities and NaNs + if (SPECIALARG) { + if (decNumberIsInfinite(rhs)) decNumberCopy(res, rhs); // an Infinity + else decNaNs(res, rhs, NULL, set, &status); // a NaN + } + else { // finite + // have a finite number; no error possible (res must be big enough) + if (rhs->exponent>=0) return decNumberCopy(res, rhs); + // that was easy, but if negative exponent there is work to do... + workset=*set; // clone rounding, etc. + workset.digits=rhs->digits; // no length rounding + workset.traps=0; // no traps + decNumberZero(&dn); // make a number with exponent 0 + decNumberQuantize(res, rhs, &dn, &workset); + status|=workset.status; + } + if (status!=0) decStatus(res, status, set); + return res; + } // decNumberToIntegralExact + +decNumber * decNumberToIntegralValue(decNumber *res, const decNumber *rhs, + decContext *set) { + decContext workset=*set; // working context + workset.traps=0; // no traps + decNumberToIntegralExact(res, rhs, &workset); + // this never affects set, except for sNaNs; NaN will have been set + // or propagated already, so no need to call decStatus + set->status|=workset.status&DEC_Invalid_operation; + return res; + } // decNumberToIntegralValue + +/* ------------------------------------------------------------------ */ +/* decNumberXor -- XOR two Numbers, digitwise */ +/* */ +/* This computes C = A ^ B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X^X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context (used for result length and error report) */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Logical function restrictions apply (see above); a NaN is */ +/* returned with Invalid_operation if a restriction is violated. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberXor(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + const Unit *ua, *ub; // -> operands + const Unit *msua, *msub; // -> operand msus + Unit *uc, *msuc; // -> result and its msu + Int msudigs; // digits in res msu + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs) + || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) { + decStatus(res, DEC_Invalid_operation, set); + return res; + } + // operands are valid + ua=lhs->lsu; // bottom-up + ub=rhs->lsu; // .. + uc=res->lsu; // .. + msua=ua+D2U(lhs->digits)-1; // -> msu of lhs + msub=ub+D2U(rhs->digits)-1; // -> msu of rhs + msuc=uc+D2U(set->digits)-1; // -> msu of result + msudigs=MSUDIGITS(set->digits); // [faster than remainder] + for (; uc<=msuc; ua++, ub++, uc++) { // Unit loop + Unit a, b; // extract units + if (ua>msua) a=0; + else a=*ua; + if (ub>msub) b=0; + else b=*ub; + *uc=0; // can now write back + if (a|b) { // maybe 1 bits to examine + Int i, j; + // This loop could be unrolled and/or use BIN2BCD tables + for (i=0; i1) { + decStatus(res, DEC_Invalid_operation, set); + return res; + } + if (uc==msuc && i==msudigs-1) break; // just did final digit + } // each digit + } // non-zero + } // each unit + // [here uc-1 is the msu of the result] + res->digits=decGetDigits(res->lsu, uc-res->lsu); + res->exponent=0; // integer + res->bits=0; // sign=0 + return res; // [no status to set] + } // decNumberXor + + +/* ================================================================== */ +/* Utility routines */ +/* ================================================================== */ + +/* ------------------------------------------------------------------ */ +/* decNumberClass -- return the decClass of a decNumber */ +/* dn -- the decNumber to test */ +/* set -- the context to use for Emin */ +/* returns the decClass enum */ +/* ------------------------------------------------------------------ */ +enum decClass decNumberClass(const decNumber *dn, decContext *set) { + if (decNumberIsSpecial(dn)) { + if (decNumberIsQNaN(dn)) return DEC_CLASS_QNAN; + if (decNumberIsSNaN(dn)) return DEC_CLASS_SNAN; + // must be an infinity + if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_INF; + return DEC_CLASS_POS_INF; + } + // is finite + if (decNumberIsNormal(dn, set)) { // most common + if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_NORMAL; + return DEC_CLASS_POS_NORMAL; + } + // is subnormal or zero + if (decNumberIsZero(dn)) { // most common + if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_ZERO; + return DEC_CLASS_POS_ZERO; + } + if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_SUBNORMAL; + return DEC_CLASS_POS_SUBNORMAL; + } // decNumberClass + +/* ------------------------------------------------------------------ */ +/* decNumberClassToString -- convert decClass to a string */ +/* */ +/* eclass is a valid decClass */ +/* returns a constant string describing the class (max 13+1 chars) */ +/* ------------------------------------------------------------------ */ +const char *decNumberClassToString(enum decClass eclass) { + if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN; + if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN; + if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ; + if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ; + if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS; + if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS; + if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI; + if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI; + if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN; + if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN; + return DEC_ClassString_UN; // Unknown + } // decNumberClassToString + +/* ------------------------------------------------------------------ */ +/* decNumberCopy -- copy a number */ +/* */ +/* dest is the target decNumber */ +/* src is the source decNumber */ +/* returns dest */ +/* */ +/* (dest==src is allowed and is a no-op) */ +/* All fields are updated as required. This is a utility operation, */ +/* so special values are unchanged and no error is possible. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberCopy(decNumber *dest, const decNumber *src) { + + #if DECCHECK + if (src==NULL) return decNumberZero(dest); + #endif + + if (dest==src) return dest; // no copy required + + // Use explicit assignments here as structure assignment could copy + // more than just the lsu (for small DECDPUN). This would not affect + // the value of the results, but could disturb test harness spill + // checking. + dest->bits=src->bits; + dest->exponent=src->exponent; + dest->digits=src->digits; + dest->lsu[0]=src->lsu[0]; + if (src->digits>DECDPUN) { // more Units to come + const Unit *smsup, *s; // work + Unit *d; // .. + // memcpy for the remaining Units would be safe as they cannot + // overlap. However, this explicit loop is faster in short cases. + d=dest->lsu+1; // -> first destination + smsup=src->lsu+D2U(src->digits); // -> source msu+1 + for (s=src->lsu+1; sdigits digits. */ +/* No exception or error can occur; this is a quiet bitwise operation.*/ +/* See also decNumberAbs for a checking version of this. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberCopyAbs(decNumber *res, const decNumber *rhs) { + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res; + #endif + decNumberCopy(res, rhs); + res->bits&=~DECNEG; // turn off sign + return res; + } // decNumberCopyAbs + +/* ------------------------------------------------------------------ */ +/* decNumberCopyNegate -- quiet negate value operator */ +/* */ +/* This sets C = negate(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* */ +/* C must have space for set->digits digits. */ +/* No exception or error can occur; this is a quiet bitwise operation.*/ +/* See also decNumberMinus for a checking version of this. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberCopyNegate(decNumber *res, const decNumber *rhs) { + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res; + #endif + decNumberCopy(res, rhs); + res->bits^=DECNEG; // invert the sign + return res; + } // decNumberCopyNegate + +/* ------------------------------------------------------------------ */ +/* decNumberCopySign -- quiet copy and set sign operator */ +/* */ +/* This sets C = A with the sign of B */ +/* */ +/* res is C, the result. C may be A */ +/* lhs is A */ +/* rhs is B */ +/* */ +/* C must have space for set->digits digits. */ +/* No exception or error can occur; this is a quiet bitwise operation.*/ +/* ------------------------------------------------------------------ */ +decNumber * decNumberCopySign(decNumber *res, const decNumber *lhs, + const decNumber *rhs) { + uByte sign; // rhs sign + #if DECCHECK + if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res; + #endif + sign=rhs->bits & DECNEG; // save sign bit + decNumberCopy(res, lhs); + res->bits&=~DECNEG; // clear the sign + res->bits|=sign; // set from rhs + return res; + } // decNumberCopySign + +/* ------------------------------------------------------------------ */ +/* decNumberGetBCD -- get the coefficient in BCD8 */ +/* dn is the source decNumber */ +/* bcd is the uInt array that will receive dn->digits BCD bytes, */ +/* most-significant at offset 0 */ +/* returns bcd */ +/* */ +/* bcd must have at least dn->digits bytes. No error is possible; if */ +/* dn is a NaN or Infinite, digits must be 1 and the coefficient 0. */ +/* ------------------------------------------------------------------ */ +uByte * decNumberGetBCD(const decNumber *dn, uByte *bcd) { + uByte *ub=bcd+dn->digits-1; // -> lsd + const Unit *up=dn->lsu; // Unit pointer, -> lsu + + #if DECDPUN==1 // trivial simple copy + for (; ub>=bcd; ub--, up++) *ub=*up; + #else // chopping needed + uInt u=*up; // work + uInt cut=DECDPUN; // downcounter through unit + for (; ub>=bcd; ub--) { + *ub=(uByte)(u%10); // [*6554 trick inhibits, here] + u=u/10; + cut--; + if (cut>0) continue; // more in this unit + up++; + u=*up; + cut=DECDPUN; + } + #endif + return bcd; + } // decNumberGetBCD + +/* ------------------------------------------------------------------ */ +/* decNumberSetBCD -- set (replace) the coefficient from BCD8 */ +/* dn is the target decNumber */ +/* bcd is the uInt array that will source n BCD bytes, most- */ +/* significant at offset 0 */ +/* n is the number of digits in the source BCD array (bcd) */ +/* returns dn */ +/* */ +/* dn must have space for at least n digits. No error is possible; */ +/* if dn is a NaN, or Infinite, or is to become a zero, n must be 1 */ +/* and bcd[0] zero. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberSetBCD(decNumber *dn, const uByte *bcd, uInt n) { + Unit *up=dn->lsu+D2U(dn->digits)-1; // -> msu [target pointer] + const uByte *ub=bcd; // -> source msd + + #if DECDPUN==1 // trivial simple copy + for (; ub=dn->lsu; up--) { // each Unit from msu + *up=0; // will take <=DECDPUN digits + for (; cut>0; ub++, cut--) *up=X10(*up)+*ub; + cut=DECDPUN; // next Unit has all digits + } + #endif + dn->digits=n; // set digit count + return dn; + } // decNumberSetBCD + +/* ------------------------------------------------------------------ */ +/* decNumberIsNormal -- test normality of a decNumber */ +/* dn is the decNumber to test */ +/* set is the context to use for Emin */ +/* returns 1 if |dn| is finite and >=Nmin, 0 otherwise */ +/* ------------------------------------------------------------------ */ +Int decNumberIsNormal(const decNumber *dn, decContext *set) { + Int ae; // adjusted exponent + #if DECCHECK + if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0; + #endif + + if (decNumberIsSpecial(dn)) return 0; // not finite + if (decNumberIsZero(dn)) return 0; // not non-zero + + ae=dn->exponent+dn->digits-1; // adjusted exponent + if (aeemin) return 0; // is subnormal + return 1; + } // decNumberIsNormal + +/* ------------------------------------------------------------------ */ +/* decNumberIsSubnormal -- test subnormality of a decNumber */ +/* dn is the decNumber to test */ +/* set is the context to use for Emin */ +/* returns 1 if |dn| is finite, non-zero, and exponent+dn->digits-1; // adjusted exponent + if (aeemin) return 1; // is subnormal + return 0; + } // decNumberIsSubnormal + +/* ------------------------------------------------------------------ */ +/* decNumberTrim -- remove insignificant zeros */ +/* */ +/* dn is the number to trim */ +/* returns dn */ +/* */ +/* All fields are updated as required. This is a utility operation, */ +/* so special values are unchanged and no error is possible. The */ +/* zeros are removed unconditionally. */ +/* ------------------------------------------------------------------ */ +decNumber * decNumberTrim(decNumber *dn) { + Int dropped; // work + decContext set; // .. + #if DECCHECK + if (decCheckOperands(DECUNRESU, DECUNUSED, dn, DECUNCONT)) return dn; + #endif + decContextDefault(&set, DEC_INIT_BASE); // clamp=0 + return decTrim(dn, &set, 0, 1, &dropped); + } // decNumberTrim + +/* ------------------------------------------------------------------ */ +/* decNumberVersion -- return the name and version of this module */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +const char * decNumberVersion(void) { + return DECVERSION; + } // decNumberVersion + +/* ------------------------------------------------------------------ */ +/* decNumberZero -- set a number to 0 */ +/* */ +/* dn is the number to set, with space for one digit */ +/* returns dn */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +// Memset is not used as it is much slower in some environments. +decNumber * decNumberZero(decNumber *dn) { + + #if DECCHECK + if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn; + #endif + + dn->bits=0; + dn->exponent=0; + dn->digits=1; + dn->lsu[0]=0; + return dn; + } // decNumberZero + +/* ================================================================== */ +/* Local routines */ +/* ================================================================== */ + +/* ------------------------------------------------------------------ */ +/* decToString -- lay out a number into a string */ +/* */ +/* dn is the number to lay out */ +/* string is where to lay out the number */ +/* eng is 1 if Engineering, 0 if Scientific */ +/* */ +/* string must be at least dn->digits+14 characters long */ +/* No error is possible. */ +/* */ +/* Note that this routine can generate a -0 or 0.000. These are */ +/* never generated in subset to-number or arithmetic, but can occur */ +/* in non-subset arithmetic (e.g., -1*0 or 1.234-1.234). */ +/* ------------------------------------------------------------------ */ +// If DECCHECK is enabled the string "?" is returned if a number is +// invalid. +static void decToString(const decNumber *dn, char *string, Flag eng) { + Int exp=dn->exponent; // local copy + Int e; // E-part value + Int pre; // digits before the '.' + Int cut; // for counting digits in a Unit + char *c=string; // work [output pointer] + const Unit *up=dn->lsu+D2U(dn->digits)-1; // -> msu [input pointer] + uInt u, pow; // work + + #if DECCHECK + if (decCheckOperands(DECUNRESU, dn, DECUNUSED, DECUNCONT)) { + strcpy(string, "?"); + return;} + #endif + + if (decNumberIsNegative(dn)) { // Negatives get a minus + *c='-'; + c++; + } + if (dn->bits&DECSPECIAL) { // Is a special value + if (decNumberIsInfinite(dn)) { + strcpy(c, "Inf"); + strcpy(c+3, "inity"); + return;} + // a NaN + if (dn->bits&DECSNAN) { // signalling NaN + *c='s'; + c++; + } + strcpy(c, "NaN"); + c+=3; // step past + // if not a clean non-zero coefficient, that's all there is in a + // NaN string + if (exp!=0 || (*dn->lsu==0 && dn->digits==1)) return; + // [drop through to add integer] + } + + // calculate how many digits in msu, and hence first cut + cut=MSUDIGITS(dn->digits); // [faster than remainder] + cut--; // power of ten for digit + + if (exp==0) { // simple integer [common fastpath] + for (;up>=dn->lsu; up--) { // each Unit from msu + u=*up; // contains DECDPUN digits to lay out + for (; cut>=0; c++, cut--) TODIGIT(u, cut, c, pow); + cut=DECDPUN-1; // next Unit has all digits + } + *c='\0'; // terminate the string + return;} + + /* non-0 exponent -- assume plain form */ + pre=dn->digits+exp; // digits before '.' + e=0; // no E + if ((exp>0) || (pre<-5)) { // need exponential form + e=exp+dn->digits-1; // calculate E value + pre=1; // assume one digit before '.' + if (eng && (e!=0)) { // engineering: may need to adjust + Int adj; // adjustment + // The C remainder operator is undefined for negative numbers, so + // a positive remainder calculation must be used here + if (e<0) { + adj=(-e)%3; + if (adj!=0) adj=3-adj; + } + else { // e>0 + adj=e%3; + } + e=e-adj; + // if dealing with zero still produce an exponent which is a + // multiple of three, as expected, but there will only be the + // one zero before the E, still. Otherwise note the padding. + if (!ISZERO(dn)) pre+=adj; + else { // is zero + if (adj!=0) { // 0.00Esnn needed + e=e+3; + pre=-(2-adj); + } + } // zero + } // eng + } // need exponent + + /* lay out the digits of the coefficient, adding 0s and . as needed */ + u=*up; + if (pre>0) { // xxx.xxx or xx00 (engineering) form + Int n=pre; + for (; pre>0; pre--, c++, cut--) { + if (cut<0) { // need new Unit + if (up==dn->lsu) break; // out of input digits (pre>digits) + up--; + cut=DECDPUN-1; + u=*up; + } + TODIGIT(u, cut, c, pow); + } + if (ndigits) { // more to come, after '.' + *c='.'; c++; + for (;; c++, cut--) { + if (cut<0) { // need new Unit + if (up==dn->lsu) break; // out of input digits + up--; + cut=DECDPUN-1; + u=*up; + } + TODIGIT(u, cut, c, pow); + } + } + else for (; pre>0; pre--, c++) *c='0'; // 0 padding (for engineering) needed + } + else { // 0.xxx or 0.000xxx form + *c='0'; c++; + *c='.'; c++; + for (; pre<0; pre++, c++) *c='0'; // add any 0's after '.' + for (; ; c++, cut--) { + if (cut<0) { // need new Unit + if (up==dn->lsu) break; // out of input digits + up--; + cut=DECDPUN-1; + u=*up; + } + TODIGIT(u, cut, c, pow); + } + } + + /* Finally add the E-part, if needed. It will never be 0, has a + base maximum and minimum of +999999999 through -999999999, but + could range down to -1999999998 for anormal numbers */ + if (e!=0) { + Flag had=0; // 1=had non-zero + *c='E'; c++; + *c='+'; c++; // assume positive + u=e; // .. + if (e<0) { + *(c-1)='-'; // oops, need - + u=-e; // uInt, please + } + // lay out the exponent [_itoa or equivalent is not ANSI C] + for (cut=9; cut>=0; cut--) { + TODIGIT(u, cut, c, pow); + if (*c=='0' && !had) continue; // skip leading zeros + had=1; // had non-0 + c++; // step for next + } // cut + } + *c='\0'; // terminate the string (all paths) + return; + } // decToString + +/* ------------------------------------------------------------------ */ +/* decAddOp -- add/subtract operation */ +/* */ +/* This computes C = A + B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X+X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* negate is DECNEG if rhs should be negated, or 0 otherwise */ +/* status accumulates status for the caller */ +/* */ +/* C must have space for set->digits digits. */ +/* Inexact in status must be 0 for correct Exact zero sign in result */ +/* ------------------------------------------------------------------ */ +/* If possible, the coefficient is calculated directly into C. */ +/* However, if: */ +/* -- a digits+1 calculation is needed because the numbers are */ +/* unaligned and span more than set->digits digits */ +/* -- a carry to digits+1 digits looks possible */ +/* -- C is the same as A or B, and the result would destructively */ +/* overlap the A or B coefficient */ +/* then the result must be calculated into a temporary buffer. In */ +/* this case a local (stack) buffer is used if possible, and only if */ +/* too long for that does malloc become the final resort. */ +/* */ +/* Misalignment is handled as follows: */ +/* Apad: (AExp>BExp) Swap operands and proceed as for BExp>AExp. */ +/* BPad: Apply the padding by a combination of shifting (whole */ +/* units) and multiplication (part units). */ +/* */ +/* Addition, especially x=x+1, is speed-critical. */ +/* The static buffer is larger than might be expected to allow for */ +/* calls from higher-level funtions (notable exp). */ +/* ------------------------------------------------------------------ */ +static decNumber * decAddOp(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set, + uByte negate, uInt *status) { + #if DECSUBSET + decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated + decNumber *allocrhs=NULL; // .., rhs + #endif + Int rhsshift; // working shift (in Units) + Int maxdigits; // longest logical length + Int mult; // multiplier + Int residue; // rounding accumulator + uByte bits; // result bits + Flag diffsign; // non-0 if arguments have different sign + Unit *acc; // accumulator for result + Unit accbuff[SD2U(DECBUFFER*2+20)]; // local buffer [*2+20 reduces many + // allocations when called from + // other operations, notable exp] + Unit *allocacc=NULL; // -> allocated acc buffer, iff allocated + Int reqdigits=set->digits; // local copy; requested DIGITS + Int padding; // work + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { + // reduce operands and set lostDigits status, as needed + if (lhs->digits>reqdigits) { + alloclhs=decRoundOperand(lhs, set, status); + if (alloclhs==NULL) break; + lhs=alloclhs; + } + if (rhs->digits>reqdigits) { + allocrhs=decRoundOperand(rhs, set, status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + } + #endif + // [following code does not require input rounding] + + // note whether signs differ [used all paths] + diffsign=(Flag)((lhs->bits^rhs->bits^negate)&DECNEG); + + // handle infinities and NaNs + if (SPECIALARGS) { // a special bit set + if (SPECIALARGS & (DECSNAN | DECNAN)) // a NaN + decNaNs(res, lhs, rhs, set, status); + else { // one or two infinities + if (decNumberIsInfinite(lhs)) { // LHS is infinity + // two infinities with different signs is invalid + if (decNumberIsInfinite(rhs) && diffsign) { + *status|=DEC_Invalid_operation; + break; + } + bits=lhs->bits & DECNEG; // get sign from LHS + } + else bits=(rhs->bits^negate) & DECNEG;// RHS must be Infinity + bits|=DECINF; + decNumberZero(res); + res->bits=bits; // set +/- infinity + } // an infinity + break; + } + + // Quick exit for add 0s; return the non-0, modified as need be + if (ISZERO(lhs)) { + Int adjust; // work + Int lexp=lhs->exponent; // save in case LHS==RES + bits=lhs->bits; // .. + residue=0; // clear accumulator + decCopyFit(res, rhs, set, &residue, status); // copy (as needed) + res->bits^=negate; // flip if rhs was negated + #if DECSUBSET + if (set->extended) { // exponents on zeros count + #endif + // exponent will be the lower of the two + adjust=lexp-res->exponent; // adjustment needed [if -ve] + if (ISZERO(res)) { // both 0: special IEEE 754 rules + if (adjust<0) res->exponent=lexp; // set exponent + // 0-0 gives +0 unless rounding to -infinity, and -0-0 gives -0 + if (diffsign) { + if (set->round!=DEC_ROUND_FLOOR) res->bits=0; + else res->bits=DECNEG; // preserve 0 sign + } + } + else { // non-0 res + if (adjust<0) { // 0-padding needed + if ((res->digits-adjust)>set->digits) { + adjust=res->digits-set->digits; // to fit exactly + *status|=DEC_Rounded; // [but exact] + } + res->digits=decShiftToMost(res->lsu, res->digits, -adjust); + res->exponent+=adjust; // set the exponent. + } + } // non-0 res + #if DECSUBSET + } // extended + #endif + decFinish(res, set, &residue, status); // clean and finalize + break;} + + if (ISZERO(rhs)) { // [lhs is non-zero] + Int adjust; // work + Int rexp=rhs->exponent; // save in case RHS==RES + bits=rhs->bits; // be clean + residue=0; // clear accumulator + decCopyFit(res, lhs, set, &residue, status); // copy (as needed) + #if DECSUBSET + if (set->extended) { // exponents on zeros count + #endif + // exponent will be the lower of the two + // [0-0 case handled above] + adjust=rexp-res->exponent; // adjustment needed [if -ve] + if (adjust<0) { // 0-padding needed + if ((res->digits-adjust)>set->digits) { + adjust=res->digits-set->digits; // to fit exactly + *status|=DEC_Rounded; // [but exact] + } + res->digits=decShiftToMost(res->lsu, res->digits, -adjust); + res->exponent+=adjust; // set the exponent. + } + #if DECSUBSET + } // extended + #endif + decFinish(res, set, &residue, status); // clean and finalize + break;} + + // [NB: both fastpath and mainpath code below assume these cases + // (notably 0-0) have already been handled] + + // calculate the padding needed to align the operands + padding=rhs->exponent-lhs->exponent; + + // Fastpath cases where the numbers are aligned and normal, the RHS + // is all in one unit, no operand rounding is needed, and no carry, + // lengthening, or borrow is needed + if (padding==0 + && rhs->digits<=DECDPUN + && rhs->exponent>=set->emin // [some normals drop through] + && rhs->exponent<=set->emax-set->digits+1 // [could clamp] + && rhs->digits<=reqdigits + && lhs->digits<=reqdigits) { + Int partial=*lhs->lsu; + if (!diffsign) { // adding + partial+=*rhs->lsu; + if ((partial<=DECDPUNMAX) // result fits in unit + && (lhs->digits>=DECDPUN || // .. and no digits-count change + partial<(Int)powers[lhs->digits])) { // .. + if (res!=lhs) decNumberCopy(res, lhs); // not in place + *res->lsu=(Unit)partial; // [copy could have overwritten RHS] + break; + } + // else drop out for careful add + } + else { // signs differ + partial-=*rhs->lsu; + if (partial>0) { // no borrow needed, and non-0 result + if (res!=lhs) decNumberCopy(res, lhs); // not in place + *res->lsu=(Unit)partial; + // this could have reduced digits [but result>0] + res->digits=decGetDigits(res->lsu, D2U(res->digits)); + break; + } + // else drop out for careful subtract + } + } + + // Now align (pad) the lhs or rhs so they can be added or + // subtracted, as necessary. If one number is much larger than + // the other (that is, if in plain form there is a least one + // digit between the lowest digit of one and the highest of the + // other) padding with up to DIGITS-1 trailing zeros may be + // needed; then apply rounding (as exotic rounding modes may be + // affected by the residue). + rhsshift=0; // rhs shift to left (padding) in Units + bits=lhs->bits; // assume sign is that of LHS + mult=1; // likely multiplier + + // [if padding==0 the operands are aligned; no padding is needed] + if (padding!=0) { + // some padding needed; always pad the RHS, as any required + // padding can then be effected by a simple combination of + // shifts and a multiply + Flag swapped=0; + if (padding<0) { // LHS needs the padding + const decNumber *t; + padding=-padding; // will be +ve + bits=(uByte)(rhs->bits^negate); // assumed sign is now that of RHS + t=lhs; lhs=rhs; rhs=t; + swapped=1; + } + + // If, after pad, rhs would be longer than lhs by digits+1 or + // more then lhs cannot affect the answer, except as a residue, + // so only need to pad up to a length of DIGITS+1. + if (rhs->digits+padding > lhs->digits+reqdigits+1) { + // The RHS is sufficient + // for residue use the relative sign indication... + Int shift=reqdigits-rhs->digits; // left shift needed + residue=1; // residue for rounding + if (diffsign) residue=-residue; // signs differ + // copy, shortening if necessary + decCopyFit(res, rhs, set, &residue, status); + // if it was already shorter, then need to pad with zeros + if (shift>0) { + res->digits=decShiftToMost(res->lsu, res->digits, shift); + res->exponent-=shift; // adjust the exponent. + } + // flip the result sign if unswapped and rhs was negated + if (!swapped) res->bits^=negate; + decFinish(res, set, &residue, status); // done + break;} + + // LHS digits may affect result + rhsshift=D2U(padding+1)-1; // this much by Unit shift .. + mult=powers[padding-(rhsshift*DECDPUN)]; // .. this by multiplication + } // padding needed + + if (diffsign) mult=-mult; // signs differ + + // determine the longer operand + maxdigits=rhs->digits+padding; // virtual length of RHS + if (lhs->digits>maxdigits) maxdigits=lhs->digits; + + // Decide on the result buffer to use; if possible place directly + // into result. + acc=res->lsu; // assume add direct to result + // If destructive overlap, or the number is too long, or a carry or + // borrow to DIGITS+1 might be possible, a buffer must be used. + // [Might be worth more sophisticated tests when maxdigits==reqdigits] + if ((maxdigits>=reqdigits) // is, or could be, too large + || (res==rhs && rhsshift>0)) { // destructive overlap + // buffer needed, choose it; units for maxdigits digits will be + // needed, +1 Unit for carry or borrow + Int need=D2U(maxdigits)+1; + acc=accbuff; // assume use local buffer + if (need*sizeof(Unit)>sizeof(accbuff)) { + // printf("malloc add %ld %ld\n", need, sizeof(accbuff)); + allocacc=(Unit *)malloc(need*sizeof(Unit)); + if (allocacc==NULL) { // hopeless -- abandon + *status|=DEC_Insufficient_storage; + break;} + acc=allocacc; + } + } + + res->bits=(uByte)(bits&DECNEG); // it's now safe to overwrite.. + res->exponent=lhs->exponent; // .. operands (even if aliased) + + #if DECTRACE + decDumpAr('A', lhs->lsu, D2U(lhs->digits)); + decDumpAr('B', rhs->lsu, D2U(rhs->digits)); + printf(" :h: %ld %ld\n", rhsshift, mult); + #endif + + // add [A+B*m] or subtract [A+B*(-m)] + res->digits=decUnitAddSub(lhs->lsu, D2U(lhs->digits), + rhs->lsu, D2U(rhs->digits), + rhsshift, acc, mult) + *DECDPUN; // [units -> digits] + if (res->digits<0) { // borrowed... + res->digits=-res->digits; + res->bits^=DECNEG; // flip the sign + } + #if DECTRACE + decDumpAr('+', acc, D2U(res->digits)); + #endif + + // If a buffer was used the result must be copied back, possibly + // shortening. (If no buffer was used then the result must have + // fit, so can't need rounding and residue must be 0.) + residue=0; // clear accumulator + if (acc!=res->lsu) { + #if DECSUBSET + if (set->extended) { // round from first significant digit + #endif + // remove leading zeros that were added due to rounding up to + // integral Units -- before the test for rounding. + if (res->digits>reqdigits) + res->digits=decGetDigits(acc, D2U(res->digits)); + decSetCoeff(res, set, acc, res->digits, &residue, status); + #if DECSUBSET + } + else { // subset arithmetic rounds from original significant digit + // May have an underestimate. This only occurs when both + // numbers fit in DECDPUN digits and are padding with a + // negative multiple (-10, -100...) and the top digit(s) become + // 0. (This only matters when using X3.274 rules where the + // leading zero could be included in the rounding.) + if (res->digitsdigits))=0; // ensure leading 0 is there + res->digits=maxdigits; + } + else { + // remove leading zeros that added due to rounding up to + // integral Units (but only those in excess of the original + // maxdigits length, unless extended) before test for rounding. + if (res->digits>reqdigits) { + res->digits=decGetDigits(acc, D2U(res->digits)); + if (res->digitsdigits=maxdigits; + } + } + decSetCoeff(res, set, acc, res->digits, &residue, status); + // Now apply rounding if needed before removing leading zeros. + // This is safe because subnormals are not a possibility + if (residue!=0) { + decApplyRound(res, set, residue, status); + residue=0; // did what needed to be done + } + } // subset + #endif + } // used buffer + + // strip leading zeros [these were left on in case of subset subtract] + res->digits=decGetDigits(res->lsu, D2U(res->digits)); + + // apply checks and rounding + decFinish(res, set, &residue, status); + + // "When the sum of two operands with opposite signs is exactly + // zero, the sign of that sum shall be '+' in all rounding modes + // except round toward -Infinity, in which mode that sign shall be + // '-'." [Subset zeros also never have '-', set by decFinish.] + if (ISZERO(res) && diffsign + #if DECSUBSET + && set->extended + #endif + && (*status&DEC_Inexact)==0) { + if (set->round==DEC_ROUND_FLOOR) res->bits|=DECNEG; // sign - + else res->bits&=~DECNEG; // sign + + } + } while(0); // end protected + + if (allocacc!=NULL) free(allocacc); // drop any storage used + #if DECSUBSET + if (allocrhs!=NULL) free(allocrhs); // .. + if (alloclhs!=NULL) free(alloclhs); // .. + #endif + return res; + } // decAddOp + +/* ------------------------------------------------------------------ */ +/* decDivideOp -- division operation */ +/* */ +/* This routine performs the calculations for all four division */ +/* operators (divide, divideInteger, remainder, remainderNear). */ +/* */ +/* C=A op B */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X/X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* op is DIVIDE, DIVIDEINT, REMAINDER, or REMNEAR respectively. */ +/* status is the usual accumulator */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* ------------------------------------------------------------------ */ +/* The underlying algorithm of this routine is the same as in the */ +/* 1981 S/370 implementation, that is, non-restoring long division */ +/* with bi-unit (rather than bi-digit) estimation for each unit */ +/* multiplier. In this pseudocode overview, complications for the */ +/* Remainder operators and division residues for exact rounding are */ +/* omitted for clarity. */ +/* */ +/* Prepare operands and handle special values */ +/* Test for x/0 and then 0/x */ +/* Exp =Exp1 - Exp2 */ +/* Exp =Exp +len(var1) -len(var2) */ +/* Sign=Sign1 * Sign2 */ +/* Pad accumulator (Var1) to double-length with 0's (pad1) */ +/* Pad Var2 to same length as Var1 */ +/* msu2pair/plus=1st 2 or 1 units of var2, +1 to allow for round */ +/* have=0 */ +/* Do until (have=digits+1 OR residue=0) */ +/* if exp<0 then if integer divide/residue then leave */ +/* this_unit=0 */ +/* Do forever */ +/* compare numbers */ +/* if <0 then leave inner_loop */ +/* if =0 then (* quick exit without subtract *) do */ +/* this_unit=this_unit+1; output this_unit */ +/* leave outer_loop; end */ +/* Compare lengths of numbers (mantissae): */ +/* If same then tops2=msu2pair -- {units 1&2 of var2} */ +/* else tops2=msu2plus -- {0, unit 1 of var2} */ +/* tops1=first_unit_of_Var1*10**DECDPUN +second_unit_of_var1 */ +/* mult=tops1/tops2 -- Good and safe guess at divisor */ +/* if mult=0 then mult=1 */ +/* this_unit=this_unit+mult */ +/* subtract */ +/* end inner_loop */ +/* if have\=0 | this_unit\=0 then do */ +/* output this_unit */ +/* have=have+1; end */ +/* var2=var2/10 */ +/* exp=exp-1 */ +/* end outer_loop */ +/* exp=exp+1 -- set the proper exponent */ +/* if have=0 then generate answer=0 */ +/* Return (Result is defined by Var1) */ +/* */ +/* ------------------------------------------------------------------ */ +/* Two working buffers are needed during the division; one (digits+ */ +/* 1) to accumulate the result, and the other (up to 2*digits+1) for */ +/* long subtractions. These are acc and var1 respectively. */ +/* var1 is a copy of the lhs coefficient, var2 is the rhs coefficient.*/ +/* The static buffers may be larger than might be expected to allow */ +/* for calls from higher-level funtions (notable exp). */ +/* ------------------------------------------------------------------ */ +static decNumber * decDivideOp(decNumber *res, + const decNumber *lhs, const decNumber *rhs, + decContext *set, Flag op, uInt *status) { + #if DECSUBSET + decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated + decNumber *allocrhs=NULL; // .., rhs + #endif + Unit accbuff[SD2U(DECBUFFER+DECDPUN+10)]; // local buffer + Unit *acc=accbuff; // -> accumulator array for result + Unit *allocacc=NULL; // -> allocated buffer, iff allocated + Unit *accnext; // -> where next digit will go + Int acclength; // length of acc needed [Units] + Int accunits; // count of units accumulated + Int accdigits; // count of digits accumulated + + Unit varbuff[SD2U(DECBUFFER*2+DECDPUN)]; // buffer for var1 + Unit *var1=varbuff; // -> var1 array for long subtraction + Unit *varalloc=NULL; // -> allocated buffer, iff used + Unit *msu1; // -> msu of var1 + + const Unit *var2; // -> var2 array + const Unit *msu2; // -> msu of var2 + Int msu2plus; // msu2 plus one [does not vary] + eInt msu2pair; // msu2 pair plus one [does not vary] + + Int var1units, var2units; // actual lengths + Int var2ulen; // logical length (units) + Int var1initpad=0; // var1 initial padding (digits) + Int maxdigits; // longest LHS or required acc length + Int mult; // multiplier for subtraction + Unit thisunit; // current unit being accumulated + Int residue; // for rounding + Int reqdigits=set->digits; // requested DIGITS + Int exponent; // working exponent + Int maxexponent=0; // DIVIDE maximum exponent if unrounded + uByte bits; // working sign + Unit *target; // work + const Unit *source; // .. + uInt const *pow; // .. + Int shift, cut; // .. + #if DECSUBSET + Int dropped; // work + #endif + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { + // reduce operands and set lostDigits status, as needed + if (lhs->digits>reqdigits) { + alloclhs=decRoundOperand(lhs, set, status); + if (alloclhs==NULL) break; + lhs=alloclhs; + } + if (rhs->digits>reqdigits) { + allocrhs=decRoundOperand(rhs, set, status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + } + #endif + // [following code does not require input rounding] + + bits=(lhs->bits^rhs->bits)&DECNEG; // assumed sign for divisions + + // handle infinities and NaNs + if (SPECIALARGS) { // a special bit set + if (SPECIALARGS & (DECSNAN | DECNAN)) { // one or two NaNs + decNaNs(res, lhs, rhs, set, status); + break; + } + // one or two infinities + if (decNumberIsInfinite(lhs)) { // LHS (dividend) is infinite + if (decNumberIsInfinite(rhs) || // two infinities are invalid .. + op & (REMAINDER | REMNEAR)) { // as is remainder of infinity + *status|=DEC_Invalid_operation; + break; + } + // [Note that infinity/0 raises no exceptions] + decNumberZero(res); + res->bits=bits|DECINF; // set +/- infinity + break; + } + else { // RHS (divisor) is infinite + residue=0; + if (op&(REMAINDER|REMNEAR)) { + // result is [finished clone of] lhs + decCopyFit(res, lhs, set, &residue, status); + } + else { // a division + decNumberZero(res); + res->bits=bits; // set +/- zero + // for DIVIDEINT the exponent is always 0. For DIVIDE, result + // is a 0 with infinitely negative exponent, clamped to minimum + if (op&DIVIDE) { + res->exponent=set->emin-set->digits+1; + *status|=DEC_Clamped; + } + } + decFinish(res, set, &residue, status); + break; + } + } + + // handle 0 rhs (x/0) + if (ISZERO(rhs)) { // x/0 is always exceptional + if (ISZERO(lhs)) { + decNumberZero(res); // [after lhs test] + *status|=DEC_Division_undefined;// 0/0 will become NaN + } + else { + decNumberZero(res); + if (op&(REMAINDER|REMNEAR)) *status|=DEC_Invalid_operation; + else { + *status|=DEC_Division_by_zero; // x/0 + res->bits=bits|DECINF; // .. is +/- Infinity + } + } + break;} + + // handle 0 lhs (0/x) + if (ISZERO(lhs)) { // 0/x [x!=0] + #if DECSUBSET + if (!set->extended) decNumberZero(res); + else { + #endif + if (op&DIVIDE) { + residue=0; + exponent=lhs->exponent-rhs->exponent; // ideal exponent + decNumberCopy(res, lhs); // [zeros always fit] + res->bits=bits; // sign as computed + res->exponent=exponent; // exponent, too + decFinalize(res, set, &residue, status); // check exponent + } + else if (op&DIVIDEINT) { + decNumberZero(res); // integer 0 + res->bits=bits; // sign as computed + } + else { // a remainder + exponent=rhs->exponent; // [save in case overwrite] + decNumberCopy(res, lhs); // [zeros always fit] + if (exponentexponent) res->exponent=exponent; // use lower + } + #if DECSUBSET + } + #endif + break;} + + // Precalculate exponent. This starts off adjusted (and hence fits + // in 31 bits) and becomes the usual unadjusted exponent as the + // division proceeds. The order of evaluation is important, here, + // to avoid wrap. + exponent=(lhs->exponent+lhs->digits)-(rhs->exponent+rhs->digits); + + // If the working exponent is -ve, then some quick exits are + // possible because the quotient is known to be <1 + // [for REMNEAR, it needs to be < -1, as -0.5 could need work] + if (exponent<0 && !(op==DIVIDE)) { + if (op&DIVIDEINT) { + decNumberZero(res); // integer part is 0 + #if DECSUBSET + if (set->extended) + #endif + res->bits=bits; // set +/- zero + break;} + // fastpath remainders so long as the lhs has the smaller + // (or equal) exponent + if (lhs->exponent<=rhs->exponent) { + if (op&REMAINDER || exponent<-1) { + // It is REMAINDER or safe REMNEAR; result is [finished + // clone of] lhs (r = x - 0*y) + residue=0; + decCopyFit(res, lhs, set, &residue, status); + decFinish(res, set, &residue, status); + break; + } + // [unsafe REMNEAR drops through] + } + } // fastpaths + + /* Long (slow) division is needed; roll up the sleeves... */ + + // The accumulator will hold the quotient of the division. + // If it needs to be too long for stack storage, then allocate. + acclength=D2U(reqdigits+DECDPUN); // in Units + if (acclength*sizeof(Unit)>sizeof(accbuff)) { + // printf("malloc dvacc %ld units\n", acclength); + allocacc=(Unit *)malloc(acclength*sizeof(Unit)); + if (allocacc==NULL) { // hopeless -- abandon + *status|=DEC_Insufficient_storage; + break;} + acc=allocacc; // use the allocated space + } + + // var1 is the padded LHS ready for subtractions. + // If it needs to be too long for stack storage, then allocate. + // The maximum units needed for var1 (long subtraction) is: + // Enough for + // (rhs->digits+reqdigits-1) -- to allow full slide to right + // or (lhs->digits) -- to allow for long lhs + // whichever is larger + // +1 -- for rounding of slide to right + // +1 -- for leading 0s + // +1 -- for pre-adjust if a remainder or DIVIDEINT + // [Note: unused units do not participate in decUnitAddSub data] + maxdigits=rhs->digits+reqdigits-1; + if (lhs->digits>maxdigits) maxdigits=lhs->digits; + var1units=D2U(maxdigits)+2; + // allocate a guard unit above msu1 for REMAINDERNEAR + if (!(op&DIVIDE)) var1units++; + if ((var1units+1)*sizeof(Unit)>sizeof(varbuff)) { + // printf("malloc dvvar %ld units\n", var1units+1); + varalloc=(Unit *)malloc((var1units+1)*sizeof(Unit)); + if (varalloc==NULL) { // hopeless -- abandon + *status|=DEC_Insufficient_storage; + break;} + var1=varalloc; // use the allocated space + } + + // Extend the lhs and rhs to full long subtraction length. The lhs + // is truly extended into the var1 buffer, with 0 padding, so a + // subtract in place is always possible. The rhs (var2) has + // virtual padding (implemented by decUnitAddSub). + // One guard unit was allocated above msu1 for rem=rem+rem in + // REMAINDERNEAR. + msu1=var1+var1units-1; // msu of var1 + source=lhs->lsu+D2U(lhs->digits)-1; // msu of input array + for (target=msu1; source>=lhs->lsu; source--, target--) *target=*source; + for (; target>=var1; target--) *target=0; + + // rhs (var2) is left-aligned with var1 at the start + var2ulen=var1units; // rhs logical length (units) + var2units=D2U(rhs->digits); // rhs actual length (units) + var2=rhs->lsu; // -> rhs array + msu2=var2+var2units-1; // -> msu of var2 [never changes] + // now set up the variables which will be used for estimating the + // multiplication factor. If these variables are not exact, add + // 1 to make sure that the multiplier is never overestimated. + msu2plus=*msu2; // it's value .. + if (var2units>1) msu2plus++; // .. +1 if any more + msu2pair=(eInt)*msu2*(DECDPUNMAX+1);// top two pair .. + if (var2units>1) { // .. [else treat 2nd as 0] + msu2pair+=*(msu2-1); // .. + if (var2units>2) msu2pair++; // .. +1 if any more + } + + // The calculation is working in units, which may have leading zeros, + // but the exponent was calculated on the assumption that they are + // both left-aligned. Adjust the exponent to compensate: add the + // number of leading zeros in var1 msu and subtract those in var2 msu. + // [This is actually done by counting the digits and negating, as + // lead1=DECDPUN-digits1, and similarly for lead2.] + for (pow=&powers[1]; *msu1>=*pow; pow++) exponent--; + for (pow=&powers[1]; *msu2>=*pow; pow++) exponent++; + + // Now, if doing an integer divide or remainder, ensure that + // the result will be Unit-aligned. To do this, shift the var1 + // accumulator towards least if need be. (It's much easier to + // do this now than to reassemble the residue afterwards, if + // doing a remainder.) Also ensure the exponent is not negative. + if (!(op&DIVIDE)) { + Unit *u; // work + // save the initial 'false' padding of var1, in digits + var1initpad=(var1units-D2U(lhs->digits))*DECDPUN; + // Determine the shift to do. + if (exponent<0) cut=-exponent; + else cut=DECDPUN-exponent%DECDPUN; + decShiftToLeast(var1, var1units, cut); + exponent+=cut; // maintain numerical value + var1initpad-=cut; // .. and reduce padding + // clean any most-significant units which were just emptied + for (u=msu1; cut>=DECDPUN; cut-=DECDPUN, u--) *u=0; + } // align + else { // is DIVIDE + maxexponent=lhs->exponent-rhs->exponent; // save + // optimization: if the first iteration will just produce 0, + // preadjust to skip it [valid for DIVIDE only] + if (*msu1<*msu2) { + var2ulen--; // shift down + exponent-=DECDPUN; // update the exponent + } + } + + // ---- start the long-division loops ------------------------------ + accunits=0; // no units accumulated yet + accdigits=0; // .. or digits + accnext=acc+acclength-1; // -> msu of acc [NB: allows digits+1] + for (;;) { // outer forever loop + thisunit=0; // current unit assumed 0 + // find the next unit + for (;;) { // inner forever loop + // strip leading zero units [from either pre-adjust or from + // subtract last time around]. Leave at least one unit. + for (; *msu1==0 && msu1>var1; msu1--) var1units--; + + if (var1units msu + for (pv1=msu1; ; pv1--, pv2--) { + // v1=*pv1 -- always OK + v2=0; // assume in padding + if (pv2>=var2) v2=*pv2; // in range + if (*pv1!=v2) break; // no longer the same + if (pv1==var1) break; // done; leave pv1 as is + } + // here when all inspected or a difference seen + if (*pv1v2. Prepare for real subtraction; the lengths are equal + // Estimate the multiplier (there's always a msu1-1)... + // Bring in two units of var2 to provide a good estimate. + mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2pair); + } // lengths the same + else { // var1units > var2ulen, so subtraction is safe + // The var2 msu is one unit towards the lsu of the var1 msu, + // so only one unit for var2 can be used. + mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2plus); + } + if (mult==0) mult=1; // must always be at least 1 + // subtraction needed; var1 is > var2 + thisunit=(Unit)(thisunit+mult); // accumulate + // subtract var1-var2, into var1; only the overlap needs + // processing, as this is an in-place calculation + shift=var2ulen-var2units; + #if DECTRACE + decDumpAr('1', &var1[shift], var1units-shift); + decDumpAr('2', var2, var2units); + printf("m=%ld\n", -mult); + #endif + decUnitAddSub(&var1[shift], var1units-shift, + var2, var2units, 0, + &var1[shift], -mult); + #if DECTRACE + decDumpAr('#', &var1[shift], var1units-shift); + #endif + // var1 now probably has leading zeros; these are removed at the + // top of the inner loop. + } // inner loop + + // The next unit has been calculated in full; unless it's a + // leading zero, add to acc + if (accunits!=0 || thisunit!=0) { // is first or non-zero + *accnext=thisunit; // store in accumulator + // account exactly for the new digits + if (accunits==0) { + accdigits++; // at least one + for (pow=&powers[1]; thisunit>=*pow; pow++) accdigits++; + } + else accdigits+=DECDPUN; + accunits++; // update count + accnext--; // ready for next + if (accdigits>reqdigits) break; // have enough digits + } + + // if the residue is zero, the operation is done (unless divide + // or divideInteger and still not enough digits yet) + if (*var1==0 && var1units==1) { // residue is 0 + if (op&(REMAINDER|REMNEAR)) break; + if ((op&DIVIDE) && (exponent<=maxexponent)) break; + // [drop through if divideInteger] + } + // also done enough if calculating remainder or integer + // divide and just did the last ('units') unit + if (exponent==0 && !(op&DIVIDE)) break; + + // to get here, var1 is less than var2, so divide var2 by the per- + // Unit power of ten and go for the next digit + var2ulen--; // shift down + exponent-=DECDPUN; // update the exponent + } // outer loop + + // ---- division is complete --------------------------------------- + // here: acc has at least reqdigits+1 of good results (or fewer + // if early stop), starting at accnext+1 (its lsu) + // var1 has any residue at the stopping point + // accunits is the number of digits collected in acc + if (accunits==0) { // acc is 0 + accunits=1; // show have a unit .. + accdigits=1; // .. + *accnext=0; // .. whose value is 0 + } + else accnext++; // back to last placed + // accnext now -> lowest unit of result + + residue=0; // assume no residue + if (op&DIVIDE) { + // record the presence of any residue, for rounding + if (*var1!=0 || var1units>1) residue=1; + else { // no residue + // Had an exact division; clean up spurious trailing 0s. + // There will be at most DECDPUN-1, from the final multiply, + // and then only if the result is non-0 (and even) and the + // exponent is 'loose'. + #if DECDPUN>1 + Unit lsu=*accnext; + if (!(lsu&0x01) && (lsu!=0)) { + // count the trailing zeros + Int drop=0; + for (;; drop++) { // [will terminate because lsu!=0] + if (exponent>=maxexponent) break; // don't chop real 0s + #if DECDPUN<=4 + if ((lsu-QUOT10(lsu, drop+1) + *powers[drop+1])!=0) break; // found non-0 digit + #else + if (lsu%powers[drop+1]!=0) break; // found non-0 digit + #endif + exponent++; + } + if (drop>0) { + accunits=decShiftToLeast(accnext, accunits, drop); + accdigits=decGetDigits(accnext, accunits); + accunits=D2U(accdigits); + // [exponent was adjusted in the loop] + } + } // neither odd nor 0 + #endif + } // exact divide + } // divide + else /* op!=DIVIDE */ { + // check for coefficient overflow + if (accdigits+exponent>reqdigits) { + *status|=DEC_Division_impossible; + break; + } + if (op & (REMAINDER|REMNEAR)) { + // [Here, the exponent will be 0, because var1 was adjusted + // appropriately.] + Int postshift; // work + Flag wasodd=0; // integer was odd + Unit *quotlsu; // for save + Int quotdigits; // .. + + bits=lhs->bits; // remainder sign is always as lhs + + // Fastpath when residue is truly 0 is worthwhile [and + // simplifies the code below] + if (*var1==0 && var1units==1) { // residue is 0 + Int exp=lhs->exponent; // save min(exponents) + if (rhs->exponentexponent; + decNumberZero(res); // 0 coefficient + #if DECSUBSET + if (set->extended) + #endif + res->exponent=exp; // .. with proper exponent + res->bits=(uByte)(bits&DECNEG); // [cleaned] + decFinish(res, set, &residue, status); // might clamp + break; + } + // note if the quotient was odd + if (*accnext & 0x01) wasodd=1; // acc is odd + quotlsu=accnext; // save in case need to reinspect + quotdigits=accdigits; // .. + + // treat the residue, in var1, as the value to return, via acc + // calculate the unused zero digits. This is the smaller of: + // var1 initial padding (saved above) + // var2 residual padding, which happens to be given by: + postshift=var1initpad+exponent-lhs->exponent+rhs->exponent; + // [the 'exponent' term accounts for the shifts during divide] + if (var1initpadexponent; // exponent is smaller of lhs & rhs + if (rhs->exponentexponent; + + // Now correct the result if doing remainderNear; if it + // (looking just at coefficients) is > rhs/2, or == rhs/2 and + // the integer was odd then the result should be rem-rhs. + if (op&REMNEAR) { + Int compare, tarunits; // work + Unit *up; // .. + // calculate remainder*2 into the var1 buffer (which has + // 'headroom' of an extra unit and hence enough space) + // [a dedicated 'double' loop would be faster, here] + tarunits=decUnitAddSub(accnext, accunits, accnext, accunits, + 0, accnext, 1); + // decDumpAr('r', accnext, tarunits); + + // Here, accnext (var1) holds tarunits Units with twice the + // remainder's coefficient, which must now be compared to the + // RHS. The remainder's exponent may be smaller than the RHS's. + compare=decUnitCompare(accnext, tarunits, rhs->lsu, D2U(rhs->digits), + rhs->exponent-exponent); + if (compare==BADINT) { // deep trouble + *status|=DEC_Insufficient_storage; + break;} + + // now restore the remainder by dividing by two; the lsu + // is known to be even. + for (up=accnext; up0 || (compare==0 && wasodd)) { // adjustment needed + Int exp, expunits, exprem; // work + // This is effectively causing round-up of the quotient, + // so if it was the rare case where it was full and all + // nines, it would overflow and hence division-impossible + // should be raised + Flag allnines=0; // 1 if quotient all nines + if (quotdigits==reqdigits) { // could be borderline + for (up=quotlsu; ; up++) { + if (quotdigits>DECDPUN) { + if (*up!=DECDPUNMAX) break;// non-nines + } + else { // this is the last Unit + if (*up==powers[quotdigits]-1) allnines=1; + break; + } + quotdigits-=DECDPUN; // checked those digits + } // up + } // borderline check + if (allnines) { + *status|=DEC_Division_impossible; + break;} + + // rem-rhs is needed; the sign will invert. Again, var1 + // can safely be used for the working Units array. + exp=rhs->exponent-exponent; // RHS padding needed + // Calculate units and remainder from exponent. + expunits=exp/DECDPUN; + exprem=exp%DECDPUN; + // subtract [A+B*(-m)]; the result will always be negative + accunits=-decUnitAddSub(accnext, accunits, + rhs->lsu, D2U(rhs->digits), + expunits, accnext, -(Int)powers[exprem]); + accdigits=decGetDigits(accnext, accunits); // count digits exactly + accunits=D2U(accdigits); // and recalculate the units for copy + // [exponent is as for original remainder] + bits^=DECNEG; // flip the sign + } + } // REMNEAR + } // REMAINDER or REMNEAR + } // not DIVIDE + + // Set exponent and bits + res->exponent=exponent; + res->bits=(uByte)(bits&DECNEG); // [cleaned] + + // Now the coefficient. + decSetCoeff(res, set, accnext, accdigits, &residue, status); + + decFinish(res, set, &residue, status); // final cleanup + + #if DECSUBSET + // If a divide then strip trailing zeros if subset [after round] + if (!set->extended && (op==DIVIDE)) decTrim(res, set, 0, 1, &dropped); + #endif + } while(0); // end protected + + if (varalloc!=NULL) free(varalloc); // drop any storage used + if (allocacc!=NULL) free(allocacc); // .. + #if DECSUBSET + if (allocrhs!=NULL) free(allocrhs); // .. + if (alloclhs!=NULL) free(alloclhs); // .. + #endif + return res; + } // decDivideOp + +/* ------------------------------------------------------------------ */ +/* decMultiplyOp -- multiplication operation */ +/* */ +/* This routine performs the multiplication C=A x B. */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X*X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* status is the usual accumulator */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* ------------------------------------------------------------------ */ +/* 'Classic' multiplication is used rather than Karatsuba, as the */ +/* latter would give only a minor improvement for the short numbers */ +/* expected to be handled most (and uses much more memory). */ +/* */ +/* There are two major paths here: the general-purpose ('old code') */ +/* path which handles all DECDPUN values, and a fastpath version */ +/* which is used if 64-bit ints are available, DECDPUN<=4, and more */ +/* than two calls to decUnitAddSub would be made. */ +/* */ +/* The fastpath version lumps units together into 8-digit or 9-digit */ +/* chunks, and also uses a lazy carry strategy to minimise expensive */ +/* 64-bit divisions. The chunks are then broken apart again into */ +/* units for continuing processing. Despite this overhead, the */ +/* fastpath can speed up some 16-digit operations by 10x (and much */ +/* more for higher-precision calculations). */ +/* */ +/* A buffer always has to be used for the accumulator; in the */ +/* fastpath, buffers are also always needed for the chunked copies of */ +/* of the operand coefficients. */ +/* Static buffers are larger than needed just for multiply, to allow */ +/* for calls from other operations (notably exp). */ +/* ------------------------------------------------------------------ */ +#define FASTMUL (DECUSE64 && DECDPUN<5) +static decNumber * decMultiplyOp(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set, + uInt *status) { + Int accunits; // Units of accumulator in use + Int exponent; // work + Int residue=0; // rounding residue + uByte bits; // result sign + Unit *acc; // -> accumulator Unit array + Int needbytes; // size calculator + void *allocacc=NULL; // -> allocated accumulator, iff allocated + Unit accbuff[SD2U(DECBUFFER*4+1)]; // buffer (+1 for DECBUFFER==0, + // *4 for calls from other operations) + const Unit *mer, *mermsup; // work + Int madlength; // Units in multiplicand + Int shift; // Units to shift multiplicand by + + #if FASTMUL + // if DECDPUN is 1 or 3 work in base 10**9, otherwise + // (DECDPUN is 2 or 4) then work in base 10**8 + #if DECDPUN & 1 // odd + #define FASTBASE 1000000000 // base + #define FASTDIGS 9 // digits in base + #define FASTLAZY 18 // carry resolution point [1->18] + #else + #define FASTBASE 100000000 + #define FASTDIGS 8 + #define FASTLAZY 1844 // carry resolution point [1->1844] + #endif + // three buffers are used, two for chunked copies of the operands + // (base 10**8 or base 10**9) and one base 2**64 accumulator with + // lazy carry evaluation + uInt zlhibuff[(DECBUFFER*2+1)/8+1]; // buffer (+1 for DECBUFFER==0) + uInt *zlhi=zlhibuff; // -> lhs array + uInt *alloclhi=NULL; // -> allocated buffer, iff allocated + uInt zrhibuff[(DECBUFFER*2+1)/8+1]; // buffer (+1 for DECBUFFER==0) + uInt *zrhi=zrhibuff; // -> rhs array + uInt *allocrhi=NULL; // -> allocated buffer, iff allocated + uLong zaccbuff[(DECBUFFER*2+1)/4+2]; // buffer (+1 for DECBUFFER==0) + // [allocacc is shared for both paths, as only one will run] + uLong *zacc=zaccbuff; // -> accumulator array for exact result + #if DECDPUN==1 + Int zoff; // accumulator offset + #endif + uInt *lip, *rip; // item pointers + uInt *lmsi, *rmsi; // most significant items + Int ilhs, irhs, iacc; // item counts in the arrays + Int lazy; // lazy carry counter + uLong lcarry; // uLong carry + uInt carry; // carry (NB not uLong) + Int count; // work + const Unit *cup; // .. + Unit *up; // .. + uLong *lp; // .. + Int p; // .. + #endif + + #if DECSUBSET + decNumber *alloclhs=NULL; // -> allocated buffer, iff allocated + decNumber *allocrhs=NULL; // -> allocated buffer, iff allocated + #endif + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + // precalculate result sign + bits=(uByte)((lhs->bits^rhs->bits)&DECNEG); + + // handle infinities and NaNs + if (SPECIALARGS) { // a special bit set + if (SPECIALARGS & (DECSNAN | DECNAN)) { // one or two NaNs + decNaNs(res, lhs, rhs, set, status); + return res;} + // one or two infinities; Infinity * 0 is invalid + if (((lhs->bits & DECINF)==0 && ISZERO(lhs)) + ||((rhs->bits & DECINF)==0 && ISZERO(rhs))) { + *status|=DEC_Invalid_operation; + return res;} + decNumberZero(res); + res->bits=bits|DECINF; // infinity + return res;} + + // For best speed, as in DMSRCN [the original Rexx numerics + // module], use the shorter number as the multiplier (rhs) and + // the longer as the multiplicand (lhs) to minimise the number of + // adds (partial products) + if (lhs->digitsdigits) { // swap... + const decNumber *hold=lhs; + lhs=rhs; + rhs=hold; + } + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { + // reduce operands and set lostDigits status, as needed + if (lhs->digits>set->digits) { + alloclhs=decRoundOperand(lhs, set, status); + if (alloclhs==NULL) break; + lhs=alloclhs; + } + if (rhs->digits>set->digits) { + allocrhs=decRoundOperand(rhs, set, status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + } + #endif + // [following code does not require input rounding] + + #if FASTMUL // fastpath can be used + // use the fast path if there are enough digits in the shorter + // operand to make the setup and takedown worthwhile + #define NEEDTWO (DECDPUN*2) // within two decUnitAddSub calls + if (rhs->digits>NEEDTWO) { // use fastpath... + // calculate the number of elements in each array + ilhs=(lhs->digits+FASTDIGS-1)/FASTDIGS; // [ceiling] + irhs=(rhs->digits+FASTDIGS-1)/FASTDIGS; // .. + iacc=ilhs+irhs; + + // allocate buffers if required, as usual + needbytes=ilhs*sizeof(uInt); + if (needbytes>(Int)sizeof(zlhibuff)) { + alloclhi=(uInt *)malloc(needbytes); + zlhi=alloclhi;} + needbytes=irhs*sizeof(uInt); + if (needbytes>(Int)sizeof(zrhibuff)) { + allocrhi=(uInt *)malloc(needbytes); + zrhi=allocrhi;} + + // Allocating the accumulator space needs a special case when + // DECDPUN=1 because when converting the accumulator to Units + // after the multiplication each 8-byte item becomes 9 1-byte + // units. Therefore iacc extra bytes are needed at the front + // (rounded up to a multiple of 8 bytes), and the uLong + // accumulator starts offset the appropriate number of units + // to the right to avoid overwrite during the unchunking. + needbytes=iacc*sizeof(uLong); + #if DECDPUN==1 + zoff=(iacc+7)/8; // items to offset by + needbytes+=zoff*8; + #endif + if (needbytes>(Int)sizeof(zaccbuff)) { + allocacc=(uLong *)malloc(needbytes); + zacc=(uLong *)allocacc;} + if (zlhi==NULL||zrhi==NULL||zacc==NULL) { + *status|=DEC_Insufficient_storage; + break;} + + acc=(Unit *)zacc; // -> target Unit array + #if DECDPUN==1 + zacc+=zoff; // start uLong accumulator to right + #endif + + // assemble the chunked copies of the left and right sides + for (count=lhs->digits, cup=lhs->lsu, lip=zlhi; count>0; lip++) + for (p=0, *lip=0; p0; + p+=DECDPUN, cup++, count-=DECDPUN) + *lip+=*cup*powers[p]; + lmsi=lip-1; // save -> msi + for (count=rhs->digits, cup=rhs->lsu, rip=zrhi; count>0; rip++) + for (p=0, *rip=0; p0; + p+=DECDPUN, cup++, count-=DECDPUN) + *rip+=*cup*powers[p]; + rmsi=rip-1; // save -> msi + + // zero the accumulator + for (lp=zacc; lp0 && rip!=rmsi) continue; + lazy=FASTLAZY; // reset delay count + // spin up the accumulator resolving overflows + for (lp=zacc; lp assume buffer for accumulator + needbytes=(D2U(lhs->digits)+D2U(rhs->digits))*sizeof(Unit); + if (needbytes>(Int)sizeof(accbuff)) { + allocacc=(Unit *)malloc(needbytes); + if (allocacc==NULL) {*status|=DEC_Insufficient_storage; break;} + acc=(Unit *)allocacc; // use the allocated space + } + + /* Now the main long multiplication loop */ + // Unlike the equivalent in the IBM Java implementation, there + // is no advantage in calculating from msu to lsu. So, do it + // by the book, as it were. + // Each iteration calculates ACC=ACC+MULTAND*MULT + accunits=1; // accumulator starts at '0' + *acc=0; // .. (lsu=0) + shift=0; // no multiplicand shift at first + madlength=D2U(lhs->digits); // this won't change + mermsup=rhs->lsu+D2U(rhs->digits); // -> msu+1 of multiplier + + for (mer=rhs->lsu; merlsu, madlength, 0, + &acc[shift], *mer) + + shift; + else { // extend acc with a 0; it will be used shortly + *(acc+accunits)=0; // [this avoids length of <=0 later] + accunits++; + } + // multiply multiplicand by 10**DECDPUN for next Unit to left + shift++; // add this for 'logical length' + } // n + #if FASTMUL + } // unchunked units + #endif + // common end-path + #if DECTRACE + decDumpAr('*', acc, accunits); // Show exact result + #endif + + // acc now contains the exact result of the multiplication, + // possibly with a leading zero unit; build the decNumber from + // it, noting if any residue + res->bits=bits; // set sign + res->digits=decGetDigits(acc, accunits); // count digits exactly + + // There can be a 31-bit wrap in calculating the exponent. + // This can only happen if both input exponents are negative and + // both their magnitudes are large. If there was a wrap, set a + // safe very negative exponent, from which decFinalize() will + // raise a hard underflow shortly. + exponent=lhs->exponent+rhs->exponent; // calculate exponent + if (lhs->exponent<0 && rhs->exponent<0 && exponent>0) + exponent=-2*DECNUMMAXE; // force underflow + res->exponent=exponent; // OK to overwrite now + + + // Set the coefficient. If any rounding, residue records + decSetCoeff(res, set, acc, res->digits, &residue, status); + decFinish(res, set, &residue, status); // final cleanup + } while(0); // end protected + + if (allocacc!=NULL) free(allocacc); // drop any storage used + #if DECSUBSET + if (allocrhs!=NULL) free(allocrhs); // .. + if (alloclhs!=NULL) free(alloclhs); // .. + #endif + #if FASTMUL + if (allocrhi!=NULL) free(allocrhi); // .. + if (alloclhi!=NULL) free(alloclhi); // .. + #endif + return res; + } // decMultiplyOp + +/* ------------------------------------------------------------------ */ +/* decExpOp -- effect exponentiation */ +/* */ +/* This computes C = exp(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context; note that rounding mode has no effect */ +/* */ +/* C must have space for set->digits digits. status is updated but */ +/* not set. */ +/* */ +/* Restrictions: */ +/* */ +/* digits, emax, and -emin in the context must be less than */ +/* 2*DEC_MAX_MATH (1999998), and the rhs must be within these */ +/* bounds or a zero. This is an internal routine, so these */ +/* restrictions are contractual and not enforced. */ +/* */ +/* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */ +/* almost always be correctly rounded, but may be up to 1 ulp in */ +/* error in rare cases. */ +/* */ +/* Finite results will always be full precision and Inexact, except */ +/* when A is a zero or -Infinity (giving 1 or 0 respectively). */ +/* ------------------------------------------------------------------ */ +/* This approach used here is similar to the algorithm described in */ +/* */ +/* Variable Precision Exponential Function, T. E. Hull and */ +/* A. Abrham, ACM Transactions on Mathematical Software, Vol 12 #2, */ +/* pp79-91, ACM, June 1986. */ +/* */ +/* with the main difference being that the iterations in the series */ +/* evaluation are terminated dynamically (which does not require the */ +/* extra variable-precision variables which are expensive in this */ +/* context). */ +/* */ +/* The error analysis in Hull & Abrham's paper applies except for the */ +/* round-off error accumulation during the series evaluation. This */ +/* code does not precalculate the number of iterations and so cannot */ +/* use Horner's scheme. Instead, the accumulation is done at double- */ +/* precision, which ensures that the additions of the terms are exact */ +/* and do not accumulate round-off (and any round-off errors in the */ +/* terms themselves move 'to the right' faster than they can */ +/* accumulate). This code also extends the calculation by allowing, */ +/* in the spirit of other decNumber operators, the input to be more */ +/* precise than the result (the precision used is based on the more */ +/* precise of the input or requested result). */ +/* */ +/* Implementation notes: */ +/* */ +/* 1. This is separated out as decExpOp so it can be called from */ +/* other Mathematical functions (notably Ln) with a wider range */ +/* than normal. In particular, it can handle the slightly wider */ +/* (double) range needed by Ln (which has to be able to calculate */ +/* exp(-x) where x can be the tiniest number (Ntiny). */ +/* */ +/* 2. Normalizing x to be <=0.1 (instead of <=1) reduces loop */ +/* iterations by appoximately a third with additional (although */ +/* diminishing) returns as the range is reduced to even smaller */ +/* fractions. However, h (the power of 10 used to correct the */ +/* result at the end, see below) must be kept <=8 as otherwise */ +/* the final result cannot be computed. Hence the leverage is a */ +/* sliding value (8-h), where potentially the range is reduced */ +/* more for smaller values. */ +/* */ +/* The leverage that can be applied in this way is severely */ +/* limited by the cost of the raise-to-the power at the end, */ +/* which dominates when the number of iterations is small (less */ +/* than ten) or when rhs is short. As an example, the adjustment */ +/* x**10,000,000 needs 31 multiplications, all but one full-width. */ +/* */ +/* 3. The restrictions (especially precision) could be raised with */ +/* care, but the full decNumber range seems very hard within the */ +/* 32-bit limits. */ +/* */ +/* 4. The working precisions for the static buffers are twice the */ +/* obvious size to allow for calls from decNumberPower. */ +/* ------------------------------------------------------------------ */ +decNumber * decExpOp(decNumber *res, const decNumber *rhs, + decContext *set, uInt *status) { + uInt ignore=0; // working status + Int h; // adjusted exponent for 0.xxxx + Int p; // working precision + Int residue; // rounding residue + uInt needbytes; // for space calculations + const decNumber *x=rhs; // (may point to safe copy later) + decContext aset, tset, dset; // working contexts + Int comp; // work + + // the argument is often copied to normalize it, so (unusually) it + // is treated like other buffers, using DECBUFFER, +1 in case + // DECBUFFER is 0 + decNumber bufr[D2N(DECBUFFER*2+1)]; + decNumber *allocrhs=NULL; // non-NULL if rhs buffer allocated + + // the working precision will be no more than set->digits+8+1 + // so for on-stack buffers DECBUFFER+9 is used, +1 in case DECBUFFER + // is 0 (and twice that for the accumulator) + + // buffer for t, term (working precision plus) + decNumber buft[D2N(DECBUFFER*2+9+1)]; + decNumber *allocbuft=NULL; // -> allocated buft, iff allocated + decNumber *t=buft; // term + // buffer for a, accumulator (working precision * 2), at least 9 + decNumber bufa[D2N(DECBUFFER*4+18+1)]; + decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated + decNumber *a=bufa; // accumulator + // decNumber for the divisor term; this needs at most 9 digits + // and so can be fixed size [16 so can use standard context] + decNumber bufd[D2N(16)]; + decNumber *d=bufd; // divisor + decNumber numone; // constant 1 + + #if DECCHECK + Int iterations=0; // for later sanity check + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + do { // protect allocated storage + if (SPECIALARG) { // handle infinities and NaNs + if (decNumberIsInfinite(rhs)) { // an infinity + if (decNumberIsNegative(rhs)) // -Infinity -> +0 + decNumberZero(res); + else decNumberCopy(res, rhs); // +Infinity -> self + } + else decNaNs(res, rhs, NULL, set, status); // a NaN + break;} + + if (ISZERO(rhs)) { // zeros -> exact 1 + decNumberZero(res); // make clean 1 + *res->lsu=1; // .. + break;} // [no status to set] + + // e**x when 0 < x < 0.66 is < 1+3x/2, hence can fast-path + // positive and negative tiny cases which will result in inexact + // 1. This also allows the later add-accumulate to always be + // exact (because its length will never be more than twice the + // working precision). + // The comparator (tiny) needs just one digit, so use the + // decNumber d for it (reused as the divisor, etc., below); its + // exponent is such that if x is positive it will have + // set->digits-1 zeros between the decimal point and the digit, + // which is 4, and if x is negative one more zero there as the + // more precise result will be of the form 0.9999999 rather than + // 1.0000001. Hence, tiny will be 0.0000004 if digits=7 and x>0 + // or 0.00000004 if digits=7 and x<0. If RHS not larger than + // this then the result will be 1.000000 + decNumberZero(d); // clean + *d->lsu=4; // set 4 .. + d->exponent=-set->digits; // * 10**(-d) + if (decNumberIsNegative(rhs)) d->exponent--; // negative case + comp=decCompare(d, rhs, 1); // signless compare + if (comp==BADINT) { + *status|=DEC_Insufficient_storage; + break;} + if (comp>=0) { // rhs < d + Int shift=set->digits-1; + decNumberZero(res); // set 1 + *res->lsu=1; // .. + res->digits=decShiftToMost(res->lsu, 1, shift); + res->exponent=-shift; // make 1.0000... + *status|=DEC_Inexact | DEC_Rounded; // .. inexactly + break;} // tiny + + // set up the context to be used for calculating a, as this is + // used on both paths below + decContextDefault(&aset, DEC_INIT_DECIMAL64); + // accumulator bounds are as requested (could underflow) + aset.emax=set->emax; // usual bounds + aset.emin=set->emin; // .. + aset.clamp=0; // and no concrete format + + // calculate the adjusted (Hull & Abrham) exponent (where the + // decimal point is just to the left of the coefficient msd) + h=rhs->exponent+rhs->digits; + // if h>8 then 10**h cannot be calculated safely; however, when + // h=8 then exp(|rhs|) will be at least exp(1E+7) which is at + // least 6.59E+4342944, so (due to the restriction on Emax/Emin) + // overflow (or underflow to 0) is guaranteed -- so this case can + // be handled by simply forcing the appropriate excess + if (h>8) { // overflow/underflow + // set up here so Power call below will over or underflow to + // zero; set accumulator to either 2 or 0.02 + // [stack buffer for a is always big enough for this] + decNumberZero(a); + *a->lsu=2; // not 1 but < exp(1) + if (decNumberIsNegative(rhs)) a->exponent=-2; // make 0.02 + h=8; // clamp so 10**h computable + p=9; // set a working precision + } + else { // h<=8 + Int maxlever=(rhs->digits>8?1:0); + // [could/should increase this for precisions >40 or so, too] + + // if h is 8, cannot normalize to a lower upper limit because + // the final result will not be computable (see notes above), + // but leverage can be applied whenever h is less than 8. + // Apply as much as possible, up to a MAXLEVER digits, which + // sets the tradeoff against the cost of the later a**(10**h). + // As h is increased, the working precision below also + // increases to compensate for the "constant digits at the + // front" effect. + Int lever=MINI(8-h, maxlever); // leverage attainable + Int use=-rhs->digits-lever; // exponent to use for RHS + h+=lever; // apply leverage selected + if (h<0) { // clamp + use+=h; // [may end up subnormal] + h=0; + } + // Take a copy of RHS if it needs normalization (true whenever x>=1) + if (rhs->exponent!=use) { + decNumber *newrhs=bufr; // assume will fit on stack + needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); + if (needbytes>sizeof(bufr)) { // need malloc space + allocrhs=(decNumber *)malloc(needbytes); + if (allocrhs==NULL) { // hopeless -- abandon + *status|=DEC_Insufficient_storage; + break;} + newrhs=allocrhs; // use the allocated space + } + decNumberCopy(newrhs, rhs); // copy to safe space + newrhs->exponent=use; // normalize; now <1 + x=newrhs; // ready for use + // decNumberShow(x); + } + + // Now use the usual power series to evaluate exp(x). The + // series starts as 1 + x + x^2/2 ... so prime ready for the + // third term by setting the term variable t=x, the accumulator + // a=1, and the divisor d=2. + + // First determine the working precision. From Hull & Abrham + // this is set->digits+h+2. However, if x is 'over-precise' we + // need to allow for all its digits to potentially participate + // (consider an x where all the excess digits are 9s) so in + // this case use x->digits+h+2 + p=MAXI(x->digits, set->digits)+h+2; // [h<=8] + + // a and t are variable precision, and depend on p, so space + // must be allocated for them if necessary + + // the accumulator needs to be able to hold 2p digits so that + // the additions on the second and subsequent iterations are + // sufficiently exact. + needbytes=sizeof(decNumber)+(D2U(p*2)-1)*sizeof(Unit); + if (needbytes>sizeof(bufa)) { // need malloc space + allocbufa=(decNumber *)malloc(needbytes); + if (allocbufa==NULL) { // hopeless -- abandon + *status|=DEC_Insufficient_storage; + break;} + a=allocbufa; // use the allocated space + } + // the term needs to be able to hold p digits (which is + // guaranteed to be larger than x->digits, so the initial copy + // is safe); it may also be used for the raise-to-power + // calculation below, which needs an extra two digits + needbytes=sizeof(decNumber)+(D2U(p+2)-1)*sizeof(Unit); + if (needbytes>sizeof(buft)) { // need malloc space + allocbuft=(decNumber *)malloc(needbytes); + if (allocbuft==NULL) { // hopeless -- abandon + *status|=DEC_Insufficient_storage; + break;} + t=allocbuft; // use the allocated space + } + + decNumberCopy(t, x); // term=x + decNumberZero(a); *a->lsu=1; // accumulator=1 + decNumberZero(d); *d->lsu=2; // divisor=2 + decNumberZero(&numone); *numone.lsu=1; // constant 1 for increment + + // set up the contexts for calculating a, t, and d + decContextDefault(&tset, DEC_INIT_DECIMAL64); + dset=tset; + // accumulator bounds are set above, set precision now + aset.digits=p*2; // double + // term bounds avoid any underflow or overflow + tset.digits=p; + tset.emin=DEC_MIN_EMIN; // [emax is plenty] + // [dset.digits=16, etc., are sufficient] + + // finally ready to roll + for (;;) { + #if DECCHECK + iterations++; + #endif + // only the status from the accumulation is interesting + // [but it should remain unchanged after first add] + decAddOp(a, a, t, &aset, 0, status); // a=a+t + decMultiplyOp(t, t, x, &tset, &ignore); // t=t*x + decDivideOp(t, t, d, &tset, DIVIDE, &ignore); // t=t/d + // the iteration ends when the term cannot affect the result, + // if rounded to p digits, which is when its value is smaller + // than the accumulator by p+1 digits. There must also be + // full precision in a. + if (((a->digits+a->exponent)>=(t->digits+t->exponent+p+1)) + && (a->digits>=p)) break; + decAddOp(d, d, &numone, &dset, 0, &ignore); // d=d+1 + } // iterate + + #if DECCHECK + // just a sanity check; comment out test to show always + if (iterations>p+3) + printf("Exp iterations=%ld, status=%08lx, p=%ld, d=%ld\n", + (LI)iterations, (LI)*status, (LI)p, (LI)x->digits); + #endif + } // h<=8 + + // apply postconditioning: a=a**(10**h) -- this is calculated + // at a slightly higher precision than Hull & Abrham suggest + if (h>0) { + Int seenbit=0; // set once a 1-bit is seen + Int i; // counter + Int n=powers[h]; // always positive + aset.digits=p+2; // sufficient precision + // avoid the overhead and many extra digits of decNumberPower + // as all that is needed is the short 'multipliers' loop; here + // accumulate the answer into t + decNumberZero(t); *t->lsu=1; // acc=1 + for (i=1;;i++){ // for each bit [top bit ignored] + // abandon if have had overflow or terminal underflow + if (*status & (DEC_Overflow|DEC_Underflow)) { // interesting? + if (*status&DEC_Overflow || ISZERO(t)) break;} + n=n<<1; // move next bit to testable position + if (n<0) { // top bit is set + seenbit=1; // OK, have a significant bit + decMultiplyOp(t, t, a, &aset, status); // acc=acc*x + } + if (i==31) break; // that was the last bit + if (!seenbit) continue; // no need to square 1 + decMultiplyOp(t, t, t, &aset, status); // acc=acc*acc [square] + } /*i*/ // 32 bits + // decNumberShow(t); + a=t; // and carry on using t instead of a + } + + // Copy and round the result to res + residue=1; // indicate dirt to right .. + if (ISZERO(a)) residue=0; // .. unless underflowed to 0 + aset.digits=set->digits; // [use default rounding] + decCopyFit(res, a, &aset, &residue, status); // copy & shorten + decFinish(res, set, &residue, status); // cleanup/set flags + } while(0); // end protected + + if (allocrhs !=NULL) free(allocrhs); // drop any storage used + if (allocbufa!=NULL) free(allocbufa); // .. + if (allocbuft!=NULL) free(allocbuft); // .. + // [status is handled by caller] + return res; + } // decExpOp + +/* ------------------------------------------------------------------ */ +/* Initial-estimate natural logarithm table */ +/* */ +/* LNnn -- 90-entry 16-bit table for values from .10 through .99. */ +/* The result is a 4-digit encode of the coefficient (c=the */ +/* top 14 bits encoding 0-9999) and a 2-digit encode of the */ +/* exponent (e=the bottom 2 bits encoding 0-3) */ +/* */ +/* The resulting value is given by: */ +/* */ +/* v = -c * 10**(-e-3) */ +/* */ +/* where e and c are extracted from entry k = LNnn[x-10] */ +/* where x is truncated (NB) into the range 10 through 99, */ +/* and then c = k>>2 and e = k&3. */ +/* ------------------------------------------------------------------ */ +const uShort LNnn[90]={9016, 8652, 8316, 8008, 7724, 7456, 7208, + 6972, 6748, 6540, 6340, 6148, 5968, 5792, 5628, 5464, 5312, + 5164, 5020, 4884, 4748, 4620, 4496, 4376, 4256, 4144, 4032, + 39233, 38181, 37157, 36157, 35181, 34229, 33297, 32389, 31501, 30629, + 29777, 28945, 28129, 27329, 26545, 25777, 25021, 24281, 23553, 22837, + 22137, 21445, 20769, 20101, 19445, 18801, 18165, 17541, 16925, 16321, + 15721, 15133, 14553, 13985, 13421, 12865, 12317, 11777, 11241, 10717, + 10197, 9685, 9177, 8677, 8185, 7697, 7213, 6737, 6269, 5801, + 5341, 4889, 4437, 39930, 35534, 31186, 26886, 22630, 18418, 14254, + 10130, 6046, 20055}; + +/* ------------------------------------------------------------------ */ +/* decLnOp -- effect natural logarithm */ +/* */ +/* This computes C = ln(A) */ +/* */ +/* res is C, the result. C may be A */ +/* rhs is A */ +/* set is the context; note that rounding mode has no effect */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Notable cases: */ +/* A<0 -> Invalid */ +/* A=0 -> -Infinity (Exact) */ +/* A=+Infinity -> +Infinity (Exact) */ +/* A=1 exactly -> 0 (Exact) */ +/* */ +/* Restrictions (as for Exp): */ +/* */ +/* digits, emax, and -emin in the context must be less than */ +/* DEC_MAX_MATH+11 (1000010), and the rhs must be within these */ +/* bounds or a zero. This is an internal routine, so these */ +/* restrictions are contractual and not enforced. */ +/* */ +/* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */ +/* almost always be correctly rounded, but may be up to 1 ulp in */ +/* error in rare cases. */ +/* ------------------------------------------------------------------ */ +/* The result is calculated using Newton's method, with each */ +/* iteration calculating a' = a + x * exp(-a) - 1. See, for example, */ +/* Epperson 1989. */ +/* */ +/* The iteration ends when the adjustment x*exp(-a)-1 is tiny enough. */ +/* This has to be calculated at the sum of the precision of x and the */ +/* working precision. */ +/* */ +/* Implementation notes: */ +/* */ +/* 1. This is separated out as decLnOp so it can be called from */ +/* other Mathematical functions (e.g., Log 10) with a wider range */ +/* than normal. In particular, it can handle the slightly wider */ +/* (+9+2) range needed by a power function. */ +/* */ +/* 2. The speed of this function is about 10x slower than exp, as */ +/* it typically needs 4-6 iterations for short numbers, and the */ +/* extra precision needed adds a squaring effect, twice. */ +/* */ +/* 3. Fastpaths are included for ln(10) and ln(2), up to length 40, */ +/* as these are common requests. ln(10) is used by log10(x). */ +/* */ +/* 4. An iteration might be saved by widening the LNnn table, and */ +/* would certainly save at least one if it were made ten times */ +/* bigger, too (for truncated fractions 0.100 through 0.999). */ +/* However, for most practical evaluations, at least four or five */ +/* iterations will be neede -- so this would only speed up by */ +/* 20-25% and that probably does not justify increasing the table */ +/* size. */ +/* */ +/* 5. The static buffers are larger than might be expected to allow */ +/* for calls from decNumberPower. */ +/* ------------------------------------------------------------------ */ +decNumber * decLnOp(decNumber *res, const decNumber *rhs, + decContext *set, uInt *status) { + uInt ignore=0; // working status accumulator + uInt needbytes; // for space calculations + Int residue; // rounding residue + Int r; // rhs=f*10**r [see below] + Int p; // working precision + Int pp; // precision for iteration + Int t; // work + + // buffers for a (accumulator, typically precision+2) and b + // (adjustment calculator, same size) + decNumber bufa[D2N(DECBUFFER+12)]; + decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated + decNumber *a=bufa; // accumulator/work + decNumber bufb[D2N(DECBUFFER*2+2)]; + decNumber *allocbufb=NULL; // -> allocated bufa, iff allocated + decNumber *b=bufb; // adjustment/work + + decNumber numone; // constant 1 + decNumber cmp; // work + decContext aset, bset; // working contexts + + #if DECCHECK + Int iterations=0; // for later sanity check + if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; + #endif + + do { // protect allocated storage + if (SPECIALARG) { // handle infinities and NaNs + if (decNumberIsInfinite(rhs)) { // an infinity + if (decNumberIsNegative(rhs)) // -Infinity -> error + *status|=DEC_Invalid_operation; + else decNumberCopy(res, rhs); // +Infinity -> self + } + else decNaNs(res, rhs, NULL, set, status); // a NaN + break;} + + if (ISZERO(rhs)) { // +/- zeros -> -Infinity + decNumberZero(res); // make clean + res->bits=DECINF|DECNEG; // set - infinity + break;} // [no status to set] + + // Non-zero negatives are bad... + if (decNumberIsNegative(rhs)) { // -x -> error + *status|=DEC_Invalid_operation; + break;} + + // Here, rhs is positive, finite, and in range + + // lookaside fastpath code for ln(2) and ln(10) at common lengths + if (rhs->exponent==0 && set->digits<=40) { + #if DECDPUN==1 + if (rhs->lsu[0]==0 && rhs->lsu[1]==1 && rhs->digits==2) { // ln(10) + #else + if (rhs->lsu[0]==10 && rhs->digits==2) { // ln(10) + #endif + aset=*set; aset.round=DEC_ROUND_HALF_EVEN; + #define LN10 "2.302585092994045684017991454684364207601" + decNumberFromString(res, LN10, &aset); + *status|=(DEC_Inexact | DEC_Rounded); // is inexact + break;} + if (rhs->lsu[0]==2 && rhs->digits==1) { // ln(2) + aset=*set; aset.round=DEC_ROUND_HALF_EVEN; + #define LN2 "0.6931471805599453094172321214581765680755" + decNumberFromString(res, LN2, &aset); + *status|=(DEC_Inexact | DEC_Rounded); + break;} + } // integer and short + + // Determine the working precision. This is normally the + // requested precision + 2, with a minimum of 9. However, if + // the rhs is 'over-precise' then allow for all its digits to + // potentially participate (consider an rhs where all the excess + // digits are 9s) so in this case use rhs->digits+2. + p=MAXI(rhs->digits, MAXI(set->digits, 7))+2; + + // Allocate space for the accumulator and the high-precision + // adjustment calculator, if necessary. The accumulator must + // be able to hold p digits, and the adjustment up to + // rhs->digits+p digits. They are also made big enough for 16 + // digits so that they can be used for calculating the initial + // estimate. + needbytes=sizeof(decNumber)+(D2U(MAXI(p,16))-1)*sizeof(Unit); + if (needbytes>sizeof(bufa)) { // need malloc space + allocbufa=(decNumber *)malloc(needbytes); + if (allocbufa==NULL) { // hopeless -- abandon + *status|=DEC_Insufficient_storage; + break;} + a=allocbufa; // use the allocated space + } + pp=p+rhs->digits; + needbytes=sizeof(decNumber)+(D2U(MAXI(pp,16))-1)*sizeof(Unit); + if (needbytes>sizeof(bufb)) { // need malloc space + allocbufb=(decNumber *)malloc(needbytes); + if (allocbufb==NULL) { // hopeless -- abandon + *status|=DEC_Insufficient_storage; + break;} + b=allocbufb; // use the allocated space + } + + // Prepare an initial estimate in acc. Calculate this by + // considering the coefficient of x to be a normalized fraction, + // f, with the decimal point at far left and multiplied by + // 10**r. Then, rhs=f*10**r and 0.1<=f<1, and + // ln(x) = ln(f) + ln(10)*r + // Get the initial estimate for ln(f) from a small lookup + // table (see above) indexed by the first two digits of f, + // truncated. + + decContextDefault(&aset, DEC_INIT_DECIMAL64); // 16-digit extended + r=rhs->exponent+rhs->digits; // 'normalised' exponent + decNumberFromInt32(a, r); // a=r + decNumberFromInt32(b, 2302585); // b=ln(10) (2.302585) + b->exponent=-6; // .. + decMultiplyOp(a, a, b, &aset, &ignore); // a=a*b + // now get top two digits of rhs into b by simple truncate and + // force to integer + residue=0; // (no residue) + aset.digits=2; aset.round=DEC_ROUND_DOWN; + decCopyFit(b, rhs, &aset, &residue, &ignore); // copy & shorten + b->exponent=0; // make integer + t=decGetInt(b); // [cannot fail] + if (t<10) t=X10(t); // adjust single-digit b + t=LNnn[t-10]; // look up ln(b) + decNumberFromInt32(b, t>>2); // b=ln(b) coefficient + b->exponent=-(t&3)-3; // set exponent + b->bits=DECNEG; // ln(0.10)->ln(0.99) always -ve + aset.digits=16; aset.round=DEC_ROUND_HALF_EVEN; // restore + decAddOp(a, a, b, &aset, 0, &ignore); // acc=a+b + // the initial estimate is now in a, with up to 4 digits correct. + // When rhs is at or near Nmax the estimate will be low, so we + // will approach it from below, avoiding overflow when calling exp. + + decNumberZero(&numone); *numone.lsu=1; // constant 1 for adjustment + + // accumulator bounds are as requested (could underflow, but + // cannot overflow) + aset.emax=set->emax; + aset.emin=set->emin; + aset.clamp=0; // no concrete format + // set up a context to be used for the multiply and subtract + bset=aset; + bset.emax=DEC_MAX_MATH*2; // use double bounds for the + bset.emin=-DEC_MAX_MATH*2; // adjustment calculation + // [see decExpOp call below] + // for each iteration double the number of digits to calculate, + // up to a maximum of p + pp=9; // initial precision + // [initially 9 as then the sequence starts 7+2, 16+2, and + // 34+2, which is ideal for standard-sized numbers] + aset.digits=pp; // working context + bset.digits=pp+rhs->digits; // wider context + for (;;) { // iterate + #if DECCHECK + iterations++; + if (iterations>24) break; // consider 9 * 2**24 + #endif + // calculate the adjustment (exp(-a)*x-1) into b. This is a + // catastrophic subtraction but it really is the difference + // from 1 that is of interest. + // Use the internal entry point to Exp as it allows the double + // range for calculating exp(-a) when a is the tiniest subnormal. + a->bits^=DECNEG; // make -a + decExpOp(b, a, &bset, &ignore); // b=exp(-a) + a->bits^=DECNEG; // restore sign of a + // now multiply by rhs and subtract 1, at the wider precision + decMultiplyOp(b, b, rhs, &bset, &ignore); // b=b*rhs + decAddOp(b, b, &numone, &bset, DECNEG, &ignore); // b=b-1 + + // the iteration ends when the adjustment cannot affect the + // result by >=0.5 ulp (at the requested digits), which + // is when its value is smaller than the accumulator by + // set->digits+1 digits (or it is zero) -- this is a looser + // requirement than for Exp because all that happens to the + // accumulator after this is the final rounding (but note that + // there must also be full precision in a, or a=0). + + if (decNumberIsZero(b) || + (a->digits+a->exponent)>=(b->digits+b->exponent+set->digits+1)) { + if (a->digits==p) break; + if (decNumberIsZero(a)) { + decCompareOp(&cmp, rhs, &numone, &aset, COMPARE, &ignore); // rhs=1 ? + if (cmp.lsu[0]==0) a->exponent=0; // yes, exact 0 + else *status|=(DEC_Inexact | DEC_Rounded); // no, inexact + break; + } + // force padding if adjustment has gone to 0 before full length + if (decNumberIsZero(b)) b->exponent=a->exponent-p; + } + + // not done yet ... + decAddOp(a, a, b, &aset, 0, &ignore); // a=a+b for next estimate + if (pp==p) continue; // precision is at maximum + // lengthen the next calculation + pp=pp*2; // double precision + if (pp>p) pp=p; // clamp to maximum + aset.digits=pp; // working context + bset.digits=pp+rhs->digits; // wider context + } // Newton's iteration + + #if DECCHECK + // just a sanity check; remove the test to show always + if (iterations>24) + printf("Ln iterations=%ld, status=%08lx, p=%ld, d=%ld\n", + (LI)iterations, (LI)*status, (LI)p, (LI)rhs->digits); + #endif + + // Copy and round the result to res + residue=1; // indicate dirt to right + if (ISZERO(a)) residue=0; // .. unless underflowed to 0 + aset.digits=set->digits; // [use default rounding] + decCopyFit(res, a, &aset, &residue, status); // copy & shorten + decFinish(res, set, &residue, status); // cleanup/set flags + } while(0); // end protected + + if (allocbufa!=NULL) free(allocbufa); // drop any storage used + if (allocbufb!=NULL) free(allocbufb); // .. + // [status is handled by caller] + return res; + } // decLnOp + +/* ------------------------------------------------------------------ */ +/* decQuantizeOp -- force exponent to requested value */ +/* */ +/* This computes C = op(A, B), where op adjusts the coefficient */ +/* of C (by rounding or shifting) such that the exponent (-scale) */ +/* of C has the value B or matches the exponent of B. */ +/* The numerical value of C will equal A, except for the effects of */ +/* any rounding that occurred. */ +/* */ +/* res is C, the result. C may be A or B */ +/* lhs is A, the number to adjust */ +/* rhs is B, the requested exponent */ +/* set is the context */ +/* quant is 1 for quantize or 0 for rescale */ +/* status is the status accumulator (this can be called without */ +/* risk of control loss) */ +/* */ +/* C must have space for set->digits digits. */ +/* */ +/* Unless there is an error or the result is infinite, the exponent */ +/* after the operation is guaranteed to be that requested. */ +/* ------------------------------------------------------------------ */ +static decNumber * decQuantizeOp(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set, + Flag quant, uInt *status) { + #if DECSUBSET + decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated + decNumber *allocrhs=NULL; // .., rhs + #endif + const decNumber *inrhs=rhs; // save original rhs + Int reqdigits=set->digits; // requested DIGITS + Int reqexp; // requested exponent [-scale] + Int residue=0; // rounding residue + Int etiny=set->emin-(reqdigits-1); + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { + // reduce operands and set lostDigits status, as needed + if (lhs->digits>reqdigits) { + alloclhs=decRoundOperand(lhs, set, status); + if (alloclhs==NULL) break; + lhs=alloclhs; + } + if (rhs->digits>reqdigits) { // [this only checks lostDigits] + allocrhs=decRoundOperand(rhs, set, status); + if (allocrhs==NULL) break; + rhs=allocrhs; + } + } + #endif + // [following code does not require input rounding] + + // Handle special values + if (SPECIALARGS) { + // NaNs get usual processing + if (SPECIALARGS & (DECSNAN | DECNAN)) + decNaNs(res, lhs, rhs, set, status); + // one infinity but not both is bad + else if ((lhs->bits ^ rhs->bits) & DECINF) + *status|=DEC_Invalid_operation; + // both infinity: return lhs + else decNumberCopy(res, lhs); // [nop if in place] + break; + } + + // set requested exponent + if (quant) reqexp=inrhs->exponent; // quantize -- match exponents + else { // rescale -- use value of rhs + // Original rhs must be an integer that fits and is in range, + // which could be from -1999999997 to +999999999, thanks to + // subnormals + reqexp=decGetInt(inrhs); // [cannot fail] + } + + #if DECSUBSET + if (!set->extended) etiny=set->emin; // no subnormals + #endif + + if (reqexp==BADINT // bad (rescale only) or .. + || reqexp==BIGODD || reqexp==BIGEVEN // very big (ditto) or .. + || (reqexpset->emax)) { // > emax + *status|=DEC_Invalid_operation; + break;} + + // the RHS has been processed, so it can be overwritten now if necessary + if (ISZERO(lhs)) { // zero coefficient unchanged + decNumberCopy(res, lhs); // [nop if in place] + res->exponent=reqexp; // .. just set exponent + #if DECSUBSET + if (!set->extended) res->bits=0; // subset specification; no -0 + #endif + } + else { // non-zero lhs + Int adjust=reqexp-lhs->exponent; // digit adjustment needed + // if adjusted coefficient will definitely not fit, give up now + if ((lhs->digits-adjust)>reqdigits) { + *status|=DEC_Invalid_operation; + break; + } + + if (adjust>0) { // increasing exponent + // this will decrease the length of the coefficient by adjust + // digits, and must round as it does so + decContext workset; // work + workset=*set; // clone rounding, etc. + workset.digits=lhs->digits-adjust; // set requested length + // [note that the latter can be <1, here] + decCopyFit(res, lhs, &workset, &residue, status); // fit to result + decApplyRound(res, &workset, residue, status); // .. and round + residue=0; // [used] + // If just rounded a 999s case, exponent will be off by one; + // adjust back (after checking space), if so. + if (res->exponent>reqexp) { + // re-check needed, e.g., for quantize(0.9999, 0.001) under + // set->digits==3 + if (res->digits==reqdigits) { // cannot shift by 1 + *status&=~(DEC_Inexact | DEC_Rounded); // [clean these] + *status|=DEC_Invalid_operation; + break; + } + res->digits=decShiftToMost(res->lsu, res->digits, 1); // shift + res->exponent--; // (re)adjust the exponent. + } + #if DECSUBSET + if (ISZERO(res) && !set->extended) res->bits=0; // subset; no -0 + #endif + } // increase + else /* adjust<=0 */ { // decreasing or = exponent + // this will increase the length of the coefficient by -adjust + // digits, by adding zero or more trailing zeros; this is + // already checked for fit, above + decNumberCopy(res, lhs); // [it will fit] + // if padding needed (adjust<0), add it now... + if (adjust<0) { + res->digits=decShiftToMost(res->lsu, res->digits, -adjust); + res->exponent+=adjust; // adjust the exponent + } + } // decrease + } // non-zero + + // Check for overflow [do not use Finalize in this case, as an + // overflow here is a "don't fit" situation] + if (res->exponent>set->emax-res->digits+1) { // too big + *status|=DEC_Invalid_operation; + break; + } + else { + decFinalize(res, set, &residue, status); // set subnormal flags + *status&=~DEC_Underflow; // suppress Underflow [as per 754] + } + } while(0); // end protected + + #if DECSUBSET + if (allocrhs!=NULL) free(allocrhs); // drop any storage used + if (alloclhs!=NULL) free(alloclhs); // .. + #endif + return res; + } // decQuantizeOp + +/* ------------------------------------------------------------------ */ +/* decCompareOp -- compare, min, or max two Numbers */ +/* */ +/* This computes C = A ? B and carries out one of four operations: */ +/* COMPARE -- returns the signum (as a number) giving the */ +/* result of a comparison unless one or both */ +/* operands is a NaN (in which case a NaN results) */ +/* COMPSIG -- as COMPARE except that a quiet NaN raises */ +/* Invalid operation. */ +/* COMPMAX -- returns the larger of the operands, using the */ +/* 754 maxnum operation */ +/* COMPMAXMAG -- ditto, comparing absolute values */ +/* COMPMIN -- the 754 minnum operation */ +/* COMPMINMAG -- ditto, comparing absolute values */ +/* COMTOTAL -- returns the signum (as a number) giving the */ +/* result of a comparison using 754 total ordering */ +/* */ +/* res is C, the result. C may be A and/or B (e.g., X=X?X) */ +/* lhs is A */ +/* rhs is B */ +/* set is the context */ +/* op is the operation flag */ +/* status is the usual accumulator */ +/* */ +/* C must have space for one digit for COMPARE or set->digits for */ +/* COMPMAX, COMPMIN, COMPMAXMAG, or COMPMINMAG. */ +/* ------------------------------------------------------------------ */ +/* The emphasis here is on speed for common cases, and avoiding */ +/* coefficient comparison if possible. */ +/* ------------------------------------------------------------------ */ +decNumber * decCompareOp(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set, + Flag op, uInt *status) { + #if DECSUBSET + decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated + decNumber *allocrhs=NULL; // .., rhs + #endif + Int result=0; // default result value + uByte merged; // work + + #if DECCHECK + if (decCheckOperands(res, lhs, rhs, set)) return res; + #endif + + do { // protect allocated storage + #if DECSUBSET + if (!set->extended) { + // reduce operands and set lostDigits status, as needed + if (lhs->digits>set->digits) { + alloclhs=decRoundOperand(lhs, set, status); + if (alloclhs==NULL) {result=BADINT; break;} + lhs=alloclhs; + } + if (rhs->digits>set->digits) { + allocrhs=decRoundOperand(rhs, set, status); + if (allocrhs==NULL) {result=BADINT; break;} + rhs=allocrhs; + } + } + #endif + // [following code does not require input rounding] + + // If total ordering then handle differing signs 'up front' + if (op==COMPTOTAL) { // total ordering + if (decNumberIsNegative(lhs) & !decNumberIsNegative(rhs)) { + result=-1; + break; + } + if (!decNumberIsNegative(lhs) & decNumberIsNegative(rhs)) { + result=+1; + break; + } + } + + // handle NaNs specially; let infinities drop through + // This assumes sNaN (even just one) leads to NaN. + merged=(lhs->bits | rhs->bits) & (DECSNAN | DECNAN); + if (merged) { // a NaN bit set + if (op==COMPARE); // result will be NaN + else if (op==COMPSIG) // treat qNaN as sNaN + *status|=DEC_Invalid_operation | DEC_sNaN; + else if (op==COMPTOTAL) { // total ordering, always finite + // signs are known to be the same; compute the ordering here + // as if the signs are both positive, then invert for negatives + if (!decNumberIsNaN(lhs)) result=-1; + else if (!decNumberIsNaN(rhs)) result=+1; + // here if both NaNs + else if (decNumberIsSNaN(lhs) && decNumberIsQNaN(rhs)) result=-1; + else if (decNumberIsQNaN(lhs) && decNumberIsSNaN(rhs)) result=+1; + else { // both NaN or both sNaN + // now it just depends on the payload + result=decUnitCompare(lhs->lsu, D2U(lhs->digits), + rhs->lsu, D2U(rhs->digits), 0); + // [Error not possible, as these are 'aligned'] + } // both same NaNs + if (decNumberIsNegative(lhs)) result=-result; + break; + } // total order + + else if (merged & DECSNAN); // sNaN -> qNaN + else { // here if MIN or MAX and one or two quiet NaNs + // min or max -- 754 rules ignore single NaN + if (!decNumberIsNaN(lhs) || !decNumberIsNaN(rhs)) { + // just one NaN; force choice to be the non-NaN operand + op=COMPMAX; + if (lhs->bits & DECNAN) result=-1; // pick rhs + else result=+1; // pick lhs + break; + } + } // max or min + op=COMPNAN; // use special path + decNaNs(res, lhs, rhs, set, status); // propagate NaN + break; + } + // have numbers + if (op==COMPMAXMAG || op==COMPMINMAG) result=decCompare(lhs, rhs, 1); + else result=decCompare(lhs, rhs, 0); // sign matters + } while(0); // end protected + + if (result==BADINT) *status|=DEC_Insufficient_storage; // rare + else { + if (op==COMPARE || op==COMPSIG ||op==COMPTOTAL) { // returning signum + if (op==COMPTOTAL && result==0) { + // operands are numerically equal or same NaN (and same sign, + // tested first); if identical, leave result 0 + if (lhs->exponent!=rhs->exponent) { + if (lhs->exponentexponent) result=-1; + else result=+1; + if (decNumberIsNegative(lhs)) result=-result; + } // lexp!=rexp + } // total-order by exponent + decNumberZero(res); // [always a valid result] + if (result!=0) { // must be -1 or +1 + *res->lsu=1; + if (result<0) res->bits=DECNEG; + } + } + else if (op==COMPNAN); // special, drop through + else { // MAX or MIN, non-NaN result + Int residue=0; // rounding accumulator + // choose the operand for the result + const decNumber *choice; + if (result==0) { // operands are numerically equal + // choose according to sign then exponent (see 754) + uByte slhs=(lhs->bits & DECNEG); + uByte srhs=(rhs->bits & DECNEG); + #if DECSUBSET + if (!set->extended) { // subset: force left-hand + op=COMPMAX; + result=+1; + } + else + #endif + if (slhs!=srhs) { // signs differ + if (slhs) result=-1; // rhs is max + else result=+1; // lhs is max + } + else if (slhs && srhs) { // both negative + if (lhs->exponentexponent) result=+1; + else result=-1; + // [if equal, use lhs, technically identical] + } + else { // both positive + if (lhs->exponent>rhs->exponent) result=+1; + else result=-1; + // [ditto] + } + } // numerically equal + // here result will be non-0; reverse if looking for MIN + if (op==COMPMIN || op==COMPMINMAG) result=-result; + choice=(result>0 ? lhs : rhs); // choose + // copy chosen to result, rounding if need be + decCopyFit(res, choice, set, &residue, status); + decFinish(res, set, &residue, status); + } + } + #if DECSUBSET + if (allocrhs!=NULL) free(allocrhs); // free any storage used + if (alloclhs!=NULL) free(alloclhs); // .. + #endif + return res; + } // decCompareOp + +/* ------------------------------------------------------------------ */ +/* decCompare -- compare two decNumbers by numerical value */ +/* */ +/* This routine compares A ? B without altering them. */ +/* */ +/* Arg1 is A, a decNumber which is not a NaN */ +/* Arg2 is B, a decNumber which is not a NaN */ +/* Arg3 is 1 for a sign-independent compare, 0 otherwise */ +/* */ +/* returns -1, 0, or 1 for AB, or BADINT if failure */ +/* (the only possible failure is an allocation error) */ +/* ------------------------------------------------------------------ */ +static Int decCompare(const decNumber *lhs, const decNumber *rhs, + Flag abs) { + Int result; // result value + Int sigr; // rhs signum + Int compare; // work + + result=1; // assume signum(lhs) + if (ISZERO(lhs)) result=0; + if (abs) { + if (ISZERO(rhs)) return result; // LHS wins or both 0 + // RHS is non-zero + if (result==0) return -1; // LHS is 0; RHS wins + // [here, both non-zero, result=1] + } + else { // signs matter + if (result && decNumberIsNegative(lhs)) result=-1; + sigr=1; // compute signum(rhs) + if (ISZERO(rhs)) sigr=0; + else if (decNumberIsNegative(rhs)) sigr=-1; + if (result > sigr) return +1; // L > R, return 1 + if (result < sigr) return -1; // L < R, return -1 + if (result==0) return 0; // both 0 + } + + // signums are the same; both are non-zero + if ((lhs->bits | rhs->bits) & DECINF) { // one or more infinities + if (decNumberIsInfinite(rhs)) { + if (decNumberIsInfinite(lhs)) result=0;// both infinite + else result=-result; // only rhs infinite + } + return result; + } + // must compare the coefficients, allowing for exponents + if (lhs->exponent>rhs->exponent) { // LHS exponent larger + // swap sides, and sign + const decNumber *temp=lhs; + lhs=rhs; + rhs=temp; + result=-result; + } + compare=decUnitCompare(lhs->lsu, D2U(lhs->digits), + rhs->lsu, D2U(rhs->digits), + rhs->exponent-lhs->exponent); + if (compare!=BADINT) compare*=result; // comparison succeeded + return compare; + } // decCompare + +/* ------------------------------------------------------------------ */ +/* decUnitCompare -- compare two >=0 integers in Unit arrays */ +/* */ +/* This routine compares A ? B*10**E where A and B are unit arrays */ +/* A is a plain integer */ +/* B has an exponent of E (which must be non-negative) */ +/* */ +/* Arg1 is A first Unit (lsu) */ +/* Arg2 is A length in Units */ +/* Arg3 is B first Unit (lsu) */ +/* Arg4 is B length in Units */ +/* Arg5 is E (0 if the units are aligned) */ +/* */ +/* returns -1, 0, or 1 for AB, or BADINT if failure */ +/* (the only possible failure is an allocation error, which can */ +/* only occur if E!=0) */ +/* ------------------------------------------------------------------ */ +static Int decUnitCompare(const Unit *a, Int alength, + const Unit *b, Int blength, Int exp) { + Unit *acc; // accumulator for result + Unit accbuff[SD2U(DECBUFFER*2+1)]; // local buffer + Unit *allocacc=NULL; // -> allocated acc buffer, iff allocated + Int accunits, need; // units in use or needed for acc + const Unit *l, *r, *u; // work + Int expunits, exprem, result; // .. + + if (exp==0) { // aligned; fastpath + if (alength>blength) return 1; + if (alength=a; l--, r--) { + if (*l>*r) return 1; + if (*l<*r) return -1; + } + return 0; // all units match + } // aligned + + // Unaligned. If one is >1 unit longer than the other, padded + // approximately, then can return easily + if (alength>blength+(Int)D2U(exp)) return 1; + if (alength+1sizeof(accbuff)) { + allocacc=(Unit *)malloc(need*sizeof(Unit)); + if (allocacc==NULL) return BADINT; // hopeless -- abandon + acc=allocacc; + } + // Calculate units and remainder from exponent. + expunits=exp/DECDPUN; + exprem=exp%DECDPUN; + // subtract [A+B*(-m)] + accunits=decUnitAddSub(a, alength, b, blength, expunits, acc, + -(Int)powers[exprem]); + // [UnitAddSub result may have leading zeros, even on zero] + if (accunits<0) result=-1; // negative result + else { // non-negative result + // check units of the result before freeing any storage + for (u=acc; u=0 integers in Unit arrays */ +/* */ +/* This routine performs the calculation: */ +/* */ +/* C=A+(B*M) */ +/* */ +/* Where M is in the range -DECDPUNMAX through +DECDPUNMAX. */ +/* */ +/* A may be shorter or longer than B. */ +/* */ +/* Leading zeros are not removed after a calculation. The result is */ +/* either the same length as the longer of A and B (adding any */ +/* shift), or one Unit longer than that (if a Unit carry occurred). */ +/* */ +/* A and B content are not altered unless C is also A or B. */ +/* C may be the same array as A or B, but only if no zero padding is */ +/* requested (that is, C may be B only if bshift==0). */ +/* C is filled from the lsu; only those units necessary to complete */ +/* the calculation are referenced. */ +/* */ +/* Arg1 is A first Unit (lsu) */ +/* Arg2 is A length in Units */ +/* Arg3 is B first Unit (lsu) */ +/* Arg4 is B length in Units */ +/* Arg5 is B shift in Units (>=0; pads with 0 units if positive) */ +/* Arg6 is C first Unit (lsu) */ +/* Arg7 is M, the multiplier */ +/* */ +/* returns the count of Units written to C, which will be non-zero */ +/* and negated if the result is negative. That is, the sign of the */ +/* returned Int is the sign of the result (positive for zero) and */ +/* the absolute value of the Int is the count of Units. */ +/* */ +/* It is the caller's responsibility to make sure that C size is */ +/* safe, allowing space if necessary for a one-Unit carry. */ +/* */ +/* This routine is severely performance-critical; *any* change here */ +/* must be measured (timed) to assure no performance degradation. */ +/* In particular, trickery here tends to be counter-productive, as */ +/* increased complexity of code hurts register optimizations on */ +/* register-poor architectures. Avoiding divisions is nearly */ +/* always a Good Idea, however. */ +/* */ +/* Special thanks to Rick McGuire (IBM Cambridge, MA) and Dave Clark */ +/* (IBM Warwick, UK) for some of the ideas used in this routine. */ +/* ------------------------------------------------------------------ */ +static Int decUnitAddSub(const Unit *a, Int alength, + const Unit *b, Int blength, Int bshift, + Unit *c, Int m) { + const Unit *alsu=a; // A lsu [need to remember it] + Unit *clsu=c; // C ditto + Unit *minC; // low water mark for C + Unit *maxC; // high water mark for C + eInt carry=0; // carry integer (could be Long) + Int add; // work + #if DECDPUN<=4 // myriadal, millenary, etc. + Int est; // estimated quotient + #endif + + #if DECTRACE + if (alength<1 || blength<1) + printf("decUnitAddSub: alen blen m %ld %ld [%ld]\n", alength, blength, m); + #endif + + maxC=c+alength; // A is usually the longer + minC=c+blength; // .. and B the shorter + if (bshift!=0) { // B is shifted; low As copy across + minC+=bshift; + // if in place [common], skip copy unless there's a gap [rare] + if (a==c && bshift<=alength) { + c+=bshift; + a+=bshift; + } + else for (; cmaxC) { // swap + Unit *hold=minC; + minC=maxC; + maxC=hold; + } + + // For speed, do the addition as two loops; the first where both A + // and B contribute, and the second (if necessary) where only one or + // other of the numbers contribute. + // Carry handling is the same (i.e., duplicated) in each case. + for (; c=0) { + est=(((ueInt)carry>>11)*53687)>>18; + *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder + carry=est; // likely quotient [89%] + if (*c>11)*53687)>>18; + *c=(Unit)(carry-est*(DECDPUNMAX+1)); + carry=est-(DECDPUNMAX+1); // correctly negative + if (*c=0) { + est=(((ueInt)carry>>3)*16777)>>21; + *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder + carry=est; // likely quotient [99%] + if (*c>3)*16777)>>21; + *c=(Unit)(carry-est*(DECDPUNMAX+1)); + carry=est-(DECDPUNMAX+1); // correctly negative + if (*c=0) { + est=QUOT10(carry, DECDPUN); + *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder + carry=est; // quotient + continue; + } + // negative case + carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive + est=QUOT10(carry, DECDPUN); + *c=(Unit)(carry-est*(DECDPUNMAX+1)); + carry=est-(DECDPUNMAX+1); // correctly negative + #else + // remainder operator is undefined if negative, so must test + if ((ueInt)carry<(DECDPUNMAX+1)*2) { // fastpath carry +1 + *c=(Unit)(carry-(DECDPUNMAX+1)); // [helps additions] + carry=1; + continue; + } + if (carry>=0) { + *c=(Unit)(carry%(DECDPUNMAX+1)); + carry=carry/(DECDPUNMAX+1); + continue; + } + // negative case + carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive + *c=(Unit)(carry%(DECDPUNMAX+1)); + carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1); + #endif + } // c + + // now may have one or other to complete + // [pretest to avoid loop setup/shutdown] + if (cDECDPUNMAX + #if DECDPUN==4 // use divide-by-multiply + if (carry>=0) { + est=(((ueInt)carry>>11)*53687)>>18; + *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder + carry=est; // likely quotient [79.7%] + if (*c>11)*53687)>>18; + *c=(Unit)(carry-est*(DECDPUNMAX+1)); + carry=est-(DECDPUNMAX+1); // correctly negative + if (*c=0) { + est=(((ueInt)carry>>3)*16777)>>21; + *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder + carry=est; // likely quotient [99%] + if (*c>3)*16777)>>21; + *c=(Unit)(carry-est*(DECDPUNMAX+1)); + carry=est-(DECDPUNMAX+1); // correctly negative + if (*c=0) { + est=QUOT10(carry, DECDPUN); + *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder + carry=est; // quotient + continue; + } + // negative case + carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive + est=QUOT10(carry, DECDPUN); + *c=(Unit)(carry-est*(DECDPUNMAX+1)); + carry=est-(DECDPUNMAX+1); // correctly negative + #else + if ((ueInt)carry<(DECDPUNMAX+1)*2){ // fastpath carry 1 + *c=(Unit)(carry-(DECDPUNMAX+1)); + carry=1; + continue; + } + // remainder operator is undefined if negative, so must test + if (carry>=0) { + *c=(Unit)(carry%(DECDPUNMAX+1)); + carry=carry/(DECDPUNMAX+1); + continue; + } + // negative case + carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive + *c=(Unit)(carry%(DECDPUNMAX+1)); + carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1); + #endif + } // c + + // OK, all A and B processed; might still have carry or borrow + // return number of Units in the result, negated if a borrow + if (carry==0) return c-clsu; // no carry, so no more to do + if (carry>0) { // positive carry + *c=(Unit)carry; // place as new unit + c++; // .. + return c-clsu; + } + // -ve carry: it's a borrow; complement needed + add=1; // temporary carry... + for (c=clsu; c current Unit + + #if DECCHECK + if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn; + #endif + + *dropped=0; // assume no zeros dropped + if ((dn->bits & DECSPECIAL) // fast exit if special .. + || (*dn->lsu & 0x01)) return dn; // .. or odd + if (ISZERO(dn)) { // .. or 0 + dn->exponent=0; // (sign is preserved) + return dn; + } + + // have a finite number which is even + exp=dn->exponent; + cut=1; // digit (1-DECDPUN) in Unit + up=dn->lsu; // -> current Unit + for (d=0; ddigits-1; d++) { // [don't strip the final digit] + // slice by powers + #if DECDPUN<=4 + uInt quot=QUOT10(*up, cut); + if ((*up-quot*powers[cut])!=0) break; // found non-0 digit + #else + if (*up%powers[cut]!=0) break; // found non-0 digit + #endif + // have a trailing 0 + if (!all) { // trimming + // [if exp>0 then all trailing 0s are significant for trim] + if (exp<=0) { // if digit might be significant + if (exp==0) break; // then quit + exp++; // next digit might be significant + } + } + cut++; // next power + if (cut>DECDPUN) { // need new Unit + up++; + cut=1; + } + } // d + if (d==0) return dn; // none to drop + + // may need to limit drop if clamping + if (set->clamp && !noclamp) { + Int maxd=set->emax-set->digits+1-dn->exponent; + if (maxd<=0) return dn; // nothing possible + if (d>maxd) d=maxd; + } + + // effect the drop + decShiftToLeast(dn->lsu, D2U(dn->digits), d); + dn->exponent+=d; // maintain numerical value + dn->digits-=d; // new length + *dropped=d; // report the count + return dn; + } // decTrim + +/* ------------------------------------------------------------------ */ +/* decReverse -- reverse a Unit array in place */ +/* */ +/* ulo is the start of the array */ +/* uhi is the end of the array (highest Unit to include) */ +/* */ +/* The units ulo through uhi are reversed in place (if the number */ +/* of units is odd, the middle one is untouched). Note that the */ +/* digit(s) in each unit are unaffected. */ +/* ------------------------------------------------------------------ */ +static void decReverse(Unit *ulo, Unit *uhi) { + Unit temp; + for (; ulo=uar; source--, target--) *target=*source; + } + else { + first=uar+D2U(digits+shift)-1; // where msu of source will end up + for (; source>=uar; source--, target--) { + // split the source Unit and accumulate remainder for next + #if DECDPUN<=4 + uInt quot=QUOT10(*source, cut); + uInt rem=*source-quot*powers[cut]; + next+=quot; + #else + uInt rem=*source%powers[cut]; + next+=*source/powers[cut]; + #endif + if (target<=first) *target=(Unit)next; // write to target iff valid + next=rem*powers[DECDPUN-cut]; // save remainder for next Unit + } + } // shift-move + + // propagate any partial unit to one below and clear the rest + for (; target>=uar; target--) { + *target=(Unit)next; + next=0; + } + return digits+shift; + } // decShiftToMost + +/* ------------------------------------------------------------------ */ +/* decShiftToLeast -- shift digits in array towards least significant */ +/* */ +/* uar is the array */ +/* units is length of the array, in units */ +/* shift is the number of digits to remove from the lsu end; it */ +/* must be zero or positive and <= than units*DECDPUN. */ +/* */ +/* returns the new length of the integer in the array, in units */ +/* */ +/* Removed digits are discarded (lost). Units not required to hold */ +/* the final result are unchanged. */ +/* ------------------------------------------------------------------ */ +static Int decShiftToLeast(Unit *uar, Int units, Int shift) { + Unit *target, *up; // work + Int cut, count; // work + Int quot, rem; // for division + + if (shift==0) return units; // [fastpath] nothing to do + if (shift==units*DECDPUN) { // [fastpath] little to do + *uar=0; // all digits cleared gives zero + return 1; // leaves just the one + } + + target=uar; // both paths + cut=MSUDIGITS(shift); + if (cut==DECDPUN) { // unit-boundary case; easy + up=uar+D2U(shift); + for (; updigits is > set->digits) */ +/* set is the relevant context */ +/* status is the status accumulator */ +/* */ +/* returns an allocated decNumber with the rounded result. */ +/* */ +/* lostDigits and other status may be set by this. */ +/* */ +/* Since the input is an operand, it must not be modified. */ +/* Instead, return an allocated decNumber, rounded as required. */ +/* It is the caller's responsibility to free the allocated storage. */ +/* */ +/* If no storage is available then the result cannot be used, so NULL */ +/* is returned. */ +/* ------------------------------------------------------------------ */ +static decNumber *decRoundOperand(const decNumber *dn, decContext *set, + uInt *status) { + decNumber *res; // result structure + uInt newstatus=0; // status from round + Int residue=0; // rounding accumulator + + // Allocate storage for the returned decNumber, big enough for the + // length specified by the context + res=(decNumber *)malloc(sizeof(decNumber) + +(D2U(set->digits)-1)*sizeof(Unit)); + if (res==NULL) { + *status|=DEC_Insufficient_storage; + return NULL; + } + decCopyFit(res, dn, set, &residue, &newstatus); + decApplyRound(res, set, residue, &newstatus); + + // If that set Inexact then "lost digits" is raised... + if (newstatus & DEC_Inexact) newstatus|=DEC_Lost_digits; + *status|=newstatus; + return res; + } // decRoundOperand +#endif + +/* ------------------------------------------------------------------ */ +/* decCopyFit -- copy a number, truncating the coefficient if needed */ +/* */ +/* dest is the target decNumber */ +/* src is the source decNumber */ +/* set is the context [used for length (digits) and rounding mode] */ +/* residue is the residue accumulator */ +/* status contains the current status to be updated */ +/* */ +/* (dest==src is allowed and will be a no-op if fits) */ +/* All fields are updated as required. */ +/* ------------------------------------------------------------------ */ +static void decCopyFit(decNumber *dest, const decNumber *src, + decContext *set, Int *residue, uInt *status) { + dest->bits=src->bits; + dest->exponent=src->exponent; + decSetCoeff(dest, set, src->lsu, src->digits, residue, status); + } // decCopyFit + +/* ------------------------------------------------------------------ */ +/* decSetCoeff -- set the coefficient of a number */ +/* */ +/* dn is the number whose coefficient array is to be set. */ +/* It must have space for set->digits digits */ +/* set is the context [for size] */ +/* lsu -> lsu of the source coefficient [may be dn->lsu] */ +/* len is digits in the source coefficient [may be dn->digits] */ +/* residue is the residue accumulator. This has values as in */ +/* decApplyRound, and will be unchanged unless the */ +/* target size is less than len. In this case, the */ +/* coefficient is truncated and the residue is updated to */ +/* reflect the previous residue and the dropped digits. */ +/* status is the status accumulator, as usual */ +/* */ +/* The coefficient may already be in the number, or it can be an */ +/* external intermediate array. If it is in the number, lsu must == */ +/* dn->lsu and len must == dn->digits. */ +/* */ +/* Note that the coefficient length (len) may be < set->digits, and */ +/* in this case this merely copies the coefficient (or is a no-op */ +/* if dn->lsu==lsu). */ +/* */ +/* Note also that (only internally, from decQuantizeOp and */ +/* decSetSubnormal) the value of set->digits may be less than one, */ +/* indicating a round to left. This routine handles that case */ +/* correctly; caller ensures space. */ +/* */ +/* dn->digits, dn->lsu (and as required), and dn->exponent are */ +/* updated as necessary. dn->bits (sign) is unchanged. */ +/* */ +/* DEC_Rounded status is set if any digits are discarded. */ +/* DEC_Inexact status is set if any non-zero digits are discarded, or */ +/* incoming residue was non-0 (implies rounded) */ +/* ------------------------------------------------------------------ */ +// mapping array: maps 0-9 to canonical residues, so that a residue +// can be adjusted in the range [-1, +1] and achieve correct rounding +// 0 1 2 3 4 5 6 7 8 9 +static const uByte resmap[10]={0, 3, 3, 3, 3, 5, 7, 7, 7, 7}; +static void decSetCoeff(decNumber *dn, decContext *set, const Unit *lsu, + Int len, Int *residue, uInt *status) { + Int discard; // number of digits to discard + uInt cut; // cut point in Unit + const Unit *up; // work + Unit *target; // .. + Int count; // .. + #if DECDPUN<=4 + uInt temp; // .. + #endif + + discard=len-set->digits; // digits to discard + if (discard<=0) { // no digits are being discarded + if (dn->lsu!=lsu) { // copy needed + // copy the coefficient array to the result number; no shift needed + count=len; // avoids D2U + up=lsu; + for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN) + *target=*up; + dn->digits=len; // set the new length + } + // dn->exponent and residue are unchanged, record any inexactitude + if (*residue!=0) *status|=(DEC_Inexact | DEC_Rounded); + return; + } + + // some digits must be discarded ... + dn->exponent+=discard; // maintain numerical value + *status|=DEC_Rounded; // accumulate Rounded status + if (*residue>1) *residue=1; // previous residue now to right, so reduce + + if (discard>len) { // everything, +1, is being discarded + // guard digit is 0 + // residue is all the number [NB could be all 0s] + if (*residue<=0) { // not already positive + count=len; // avoids D2U + for (up=lsu; count>0; up++, count-=DECDPUN) if (*up!=0) { // found non-0 + *residue=1; + break; // no need to check any others + } + } + if (*residue!=0) *status|=DEC_Inexact; // record inexactitude + *dn->lsu=0; // coefficient will now be 0 + dn->digits=1; // .. + return; + } // total discard + + // partial discard [most common case] + // here, at least the first (most significant) discarded digit exists + + // spin up the number, noting residue during the spin, until get to + // the Unit with the first discarded digit. When reach it, extract + // it and remember its position + count=0; + for (up=lsu;; up++) { + count+=DECDPUN; + if (count>=discard) break; // full ones all checked + if (*up!=0) *residue=1; + } // up + + // here up -> Unit with first discarded digit + cut=discard-(count-DECDPUN)-1; + if (cut==DECDPUN-1) { // unit-boundary case (fast) + Unit half=(Unit)powers[DECDPUN]>>1; + // set residue directly + if (*up>=half) { + if (*up>half) *residue=7; + else *residue+=5; // add sticky bit + } + else { // digits<=0) { // special for Quantize/Subnormal :-( + *dn->lsu=0; // .. result is 0 + dn->digits=1; // .. + } + else { // shift to least + count=set->digits; // now digits to end up with + dn->digits=count; // set the new length + up++; // move to next + // on unit boundary, so shift-down copy loop is simple + for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN) + *target=*up; + } + } // unit-boundary case + + else { // discard digit is in low digit(s), and not top digit + uInt discard1; // first discarded digit + uInt quot, rem; // for divisions + if (cut==0) quot=*up; // is at bottom of unit + else /* cut>0 */ { // it's not at bottom of unit + #if DECDPUN<=4 + quot=QUOT10(*up, cut); + rem=*up-quot*powers[cut]; + #else + rem=*up%powers[cut]; + quot=*up/powers[cut]; + #endif + if (rem!=0) *residue=1; + } + // discard digit is now at bottom of quot + #if DECDPUN<=4 + temp=(quot*6554)>>16; // fast /10 + // Vowels algorithm here not a win (9 instructions) + discard1=quot-X10(temp); + quot=temp; + #else + discard1=quot%10; + quot=quot/10; + #endif + // here, discard1 is the guard digit, and residue is everything + // else [use mapping array to accumulate residue safely] + *residue+=resmap[discard1]; + cut++; // update cut + // here: up -> Unit of the array with bottom digit + // cut is the division point for each Unit + // quot holds the uncut high-order digits for the current unit + if (set->digits<=0) { // special for Quantize/Subnormal :-( + *dn->lsu=0; // .. result is 0 + dn->digits=1; // .. + } + else { // shift to least needed + count=set->digits; // now digits to end up with + dn->digits=count; // set the new length + // shift-copy the coefficient array to the result number + for (target=dn->lsu; ; target++) { + *target=(Unit)quot; + count-=(DECDPUN-cut); + if (count<=0) break; + up++; + quot=*up; + #if DECDPUN<=4 + quot=QUOT10(quot, cut); + rem=*up-quot*powers[cut]; + #else + rem=quot%powers[cut]; + quot=quot/powers[cut]; + #endif + *target=(Unit)(*target+rem*powers[DECDPUN-cut]); + count-=cut; + if (count<=0) break; + } // shift-copy loop + } // shift to least + } // not unit boundary + + if (*residue!=0) *status|=DEC_Inexact; // record inexactitude + return; + } // decSetCoeff + +/* ------------------------------------------------------------------ */ +/* decApplyRound -- apply pending rounding to a number */ +/* */ +/* dn is the number, with space for set->digits digits */ +/* set is the context [for size and rounding mode] */ +/* residue indicates pending rounding, being any accumulated */ +/* guard and sticky information. It may be: */ +/* 6-9: rounding digit is >5 */ +/* 5: rounding digit is exactly half-way */ +/* 1-4: rounding digit is <5 and >0 */ +/* 0: the coefficient is exact */ +/* -1: as 1, but the hidden digits are subtractive, that */ +/* is, of the opposite sign to dn. In this case the */ +/* coefficient must be non-0. This case occurs when */ +/* subtracting a small number (which can be reduced to */ +/* a sticky bit); see decAddOp. */ +/* status is the status accumulator, as usual */ +/* */ +/* This routine applies rounding while keeping the length of the */ +/* coefficient constant. The exponent and status are unchanged */ +/* except if: */ +/* */ +/* -- the coefficient was increased and is all nines (in which */ +/* case Overflow could occur, and is handled directly here so */ +/* the caller does not need to re-test for overflow) */ +/* */ +/* -- the coefficient was decreased and becomes all nines (in which */ +/* case Underflow could occur, and is also handled directly). */ +/* */ +/* All fields in dn are updated as required. */ +/* */ +/* ------------------------------------------------------------------ */ +static void decApplyRound(decNumber *dn, decContext *set, Int residue, + uInt *status) { + Int bump; // 1 if coefficient needs to be incremented + // -1 if coefficient needs to be decremented + + if (residue==0) return; // nothing to apply + + bump=0; // assume a smooth ride + + // now decide whether, and how, to round, depending on mode + switch (set->round) { + case DEC_ROUND_05UP: { // round zero or five up (for reround) + // This is the same as DEC_ROUND_DOWN unless there is a + // positive residue and the lsd of dn is 0 or 5, in which case + // it is bumped; when residue is <0, the number is therefore + // bumped down unless the final digit was 1 or 6 (in which + // case it is bumped down and then up -- a no-op) + Int lsd5=*dn->lsu%5; // get lsd and quintate + if (residue<0 && lsd5!=1) bump=-1; + else if (residue>0 && lsd5==0) bump=1; + // [bump==1 could be applied directly; use common path for clarity] + break;} // r-05 + + case DEC_ROUND_DOWN: { + // no change, except if negative residue + if (residue<0) bump=-1; + break;} // r-d + + case DEC_ROUND_HALF_DOWN: { + if (residue>5) bump=1; + break;} // r-h-d + + case DEC_ROUND_HALF_EVEN: { + if (residue>5) bump=1; // >0.5 goes up + else if (residue==5) { // exactly 0.5000... + // 0.5 goes up iff [new] lsd is odd + if (*dn->lsu & 0x01) bump=1; + } + break;} // r-h-e + + case DEC_ROUND_HALF_UP: { + if (residue>=5) bump=1; + break;} // r-h-u + + case DEC_ROUND_UP: { + if (residue>0) bump=1; + break;} // r-u + + case DEC_ROUND_CEILING: { + // same as _UP for positive numbers, and as _DOWN for negatives + // [negative residue cannot occur on 0] + if (decNumberIsNegative(dn)) { + if (residue<0) bump=-1; + } + else { + if (residue>0) bump=1; + } + break;} // r-c + + case DEC_ROUND_FLOOR: { + // same as _UP for negative numbers, and as _DOWN for positive + // [negative residue cannot occur on 0] + if (!decNumberIsNegative(dn)) { + if (residue<0) bump=-1; + } + else { + if (residue>0) bump=1; + } + break;} // r-f + + default: { // e.g., DEC_ROUND_MAX + *status|=DEC_Invalid_context; + #if DECTRACE || (DECCHECK && DECVERB) + printf("Unknown rounding mode: %d\n", set->round); + #endif + break;} + } // switch + + // now bump the number, up or down, if need be + if (bump==0) return; // no action required + + // Simply use decUnitAddSub unless bumping up and the number is + // all nines. In this special case set to 100... explicitly + // and adjust the exponent by one (as otherwise could overflow + // the array) + // Similarly handle all-nines result if bumping down. + if (bump>0) { + Unit *up; // work + uInt count=dn->digits; // digits to be checked + for (up=dn->lsu; ; up++) { + if (count<=DECDPUN) { + // this is the last Unit (the msu) + if (*up!=powers[count]-1) break; // not still 9s + // here if it, too, is all nines + *up=(Unit)powers[count-1]; // here 999 -> 100 etc. + for (up=up-1; up>=dn->lsu; up--) *up=0; // others all to 0 + dn->exponent++; // and bump exponent + // [which, very rarely, could cause Overflow...] + if ((dn->exponent+dn->digits)>set->emax+1) { + decSetOverflow(dn, set, status); + } + return; // done + } + // a full unit to check, with more to come + if (*up!=DECDPUNMAX) break; // not still 9s + count-=DECDPUN; + } // up + } // bump>0 + else { // -1 + // here checking for a pre-bump of 1000... (leading 1, all + // other digits zero) + Unit *up, *sup; // work + uInt count=dn->digits; // digits to be checked + for (up=dn->lsu; ; up++) { + if (count<=DECDPUN) { + // this is the last Unit (the msu) + if (*up!=powers[count-1]) break; // not 100.. + // here if have the 1000... case + sup=up; // save msu pointer + *up=(Unit)powers[count]-1; // here 100 in msu -> 999 + // others all to all-nines, too + for (up=up-1; up>=dn->lsu; up--) *up=(Unit)powers[DECDPUN]-1; + dn->exponent--; // and bump exponent + + // iff the number was at the subnormal boundary (exponent=etiny) + // then the exponent is now out of range, so it will in fact get + // clamped to etiny and the final 9 dropped. + // printf(">> emin=%d exp=%d sdig=%d\n", set->emin, + // dn->exponent, set->digits); + if (dn->exponent+1==set->emin-set->digits+1) { + if (count==1 && dn->digits==1) *sup=0; // here 9 -> 0[.9] + else { + *sup=(Unit)powers[count-1]-1; // here 999.. in msu -> 99.. + dn->digits--; + } + dn->exponent++; + *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded; + } + return; // done + } + + // a full unit to check, with more to come + if (*up!=0) break; // not still 0s + count-=DECDPUN; + } // up + + } // bump<0 + + // Actual bump needed. Do it. + decUnitAddSub(dn->lsu, D2U(dn->digits), uarrone, 1, 0, dn->lsu, bump); + } // decApplyRound + +#if DECSUBSET +/* ------------------------------------------------------------------ */ +/* decFinish -- finish processing a number */ +/* */ +/* dn is the number */ +/* set is the context */ +/* residue is the rounding accumulator (as in decApplyRound) */ +/* status is the accumulator */ +/* */ +/* This finishes off the current number by: */ +/* 1. If not extended: */ +/* a. Converting a zero result to clean '0' */ +/* b. Reducing positive exponents to 0, if would fit in digits */ +/* 2. Checking for overflow and subnormals (always) */ +/* Note this is just Finalize when no subset arithmetic. */ +/* All fields are updated as required. */ +/* ------------------------------------------------------------------ */ +static void decFinish(decNumber *dn, decContext *set, Int *residue, + uInt *status) { + if (!set->extended) { + if ISZERO(dn) { // value is zero + dn->exponent=0; // clean exponent .. + dn->bits=0; // .. and sign + return; // no error possible + } + if (dn->exponent>=0) { // non-negative exponent + // >0; reduce to integer if possible + if (set->digits >= (dn->exponent+dn->digits)) { + dn->digits=decShiftToMost(dn->lsu, dn->digits, dn->exponent); + dn->exponent=0; + } + } + } // !extended + + decFinalize(dn, set, residue, status); + } // decFinish +#endif + +/* ------------------------------------------------------------------ */ +/* decFinalize -- final check, clamp, and round of a number */ +/* */ +/* dn is the number */ +/* set is the context */ +/* residue is the rounding accumulator (as in decApplyRound) */ +/* status is the status accumulator */ +/* */ +/* This finishes off the current number by checking for subnormal */ +/* results, applying any pending rounding, checking for overflow, */ +/* and applying any clamping. */ +/* Underflow and overflow conditions are raised as appropriate. */ +/* All fields are updated as required. */ +/* ------------------------------------------------------------------ */ +static void decFinalize(decNumber *dn, decContext *set, Int *residue, + uInt *status) { + Int shift; // shift needed if clamping + Int tinyexp=set->emin-dn->digits+1; // precalculate subnormal boundary + + // Must be careful, here, when checking the exponent as the + // adjusted exponent could overflow 31 bits [because it may already + // be up to twice the expected]. + + // First test for subnormal. This must be done before any final + // round as the result could be rounded to Nmin or 0. + if (dn->exponent<=tinyexp) { // prefilter + Int comp; + decNumber nmin; + // A very nasty case here is dn == Nmin and residue<0 + if (dn->exponentemin; + comp=decCompare(dn, &nmin, 1); // (signless compare) + if (comp==BADINT) { // oops + *status|=DEC_Insufficient_storage; // abandon... + return; + } + if (*residue<0 && comp==0) { // neg residue and dn==Nmin + decApplyRound(dn, set, *residue, status); // might force down + decSetSubnormal(dn, set, residue, status); + return; + } + } + + // now apply any pending round (this could raise overflow). + if (*residue!=0) decApplyRound(dn, set, *residue, status); + + // Check for overflow [redundant in the 'rare' case] or clamp + if (dn->exponent<=set->emax-set->digits+1) return; // neither needed + + + // here when might have an overflow or clamp to do + if (dn->exponent>set->emax-dn->digits+1) { // too big + decSetOverflow(dn, set, status); + return; + } + // here when the result is normal but in clamp range + if (!set->clamp) return; + + // here when need to apply the IEEE exponent clamp (fold-down) + shift=dn->exponent-(set->emax-set->digits+1); + + // shift coefficient (if non-zero) + if (!ISZERO(dn)) { + dn->digits=decShiftToMost(dn->lsu, dn->digits, shift); + } + dn->exponent-=shift; // adjust the exponent to match + *status|=DEC_Clamped; // and record the dirty deed + return; + } // decFinalize + +/* ------------------------------------------------------------------ */ +/* decSetOverflow -- set number to proper overflow value */ +/* */ +/* dn is the number (used for sign [only] and result) */ +/* set is the context [used for the rounding mode, etc.] */ +/* status contains the current status to be updated */ +/* */ +/* This sets the sign of a number and sets its value to either */ +/* Infinity or the maximum finite value, depending on the sign of */ +/* dn and the rounding mode, following IEEE 754 rules. */ +/* ------------------------------------------------------------------ */ +static void decSetOverflow(decNumber *dn, decContext *set, uInt *status) { + Flag needmax=0; // result is maximum finite value + uByte sign=dn->bits&DECNEG; // clean and save sign bit + + if (ISZERO(dn)) { // zero does not overflow magnitude + Int emax=set->emax; // limit value + if (set->clamp) emax-=set->digits-1; // lower if clamping + if (dn->exponent>emax) { // clamp required + dn->exponent=emax; + *status|=DEC_Clamped; + } + return; + } + + decNumberZero(dn); + switch (set->round) { + case DEC_ROUND_DOWN: { + needmax=1; // never Infinity + break;} // r-d + case DEC_ROUND_05UP: { + needmax=1; // never Infinity + break;} // r-05 + case DEC_ROUND_CEILING: { + if (sign) needmax=1; // Infinity if non-negative + break;} // r-c + case DEC_ROUND_FLOOR: { + if (!sign) needmax=1; // Infinity if negative + break;} // r-f + default: break; // Infinity in all other cases + } + if (needmax) { + decSetMaxValue(dn, set); + dn->bits=sign; // set sign + } + else dn->bits=sign|DECINF; // Value is +/-Infinity + *status|=DEC_Overflow | DEC_Inexact | DEC_Rounded; + } // decSetOverflow + +/* ------------------------------------------------------------------ */ +/* decSetMaxValue -- set number to +Nmax (maximum normal value) */ +/* */ +/* dn is the number to set */ +/* set is the context [used for digits and emax] */ +/* */ +/* This sets the number to the maximum positive value. */ +/* ------------------------------------------------------------------ */ +static void decSetMaxValue(decNumber *dn, decContext *set) { + Unit *up; // work + Int count=set->digits; // nines to add + dn->digits=count; + // fill in all nines to set maximum value + for (up=dn->lsu; ; up++) { + if (count>DECDPUN) *up=DECDPUNMAX; // unit full o'nines + else { // this is the msu + *up=(Unit)(powers[count]-1); + break; + } + count-=DECDPUN; // filled those digits + } // up + dn->bits=0; // + sign + dn->exponent=set->emax-set->digits+1; + } // decSetMaxValue + +/* ------------------------------------------------------------------ */ +/* decSetSubnormal -- process value whose exponent is extended) { + decNumberZero(dn); + // always full overflow + *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded; + return; + } + #endif + + // Full arithmetic -- allow subnormals, rounded to minimum exponent + // (Etiny) if needed + etiny=set->emin-(set->digits-1); // smallest allowed exponent + + if ISZERO(dn) { // value is zero + // residue can never be non-zero here + #if DECCHECK + if (*residue!=0) { + printf("++ Subnormal 0 residue %ld\n", (LI)*residue); + *status|=DEC_Invalid_operation; + } + #endif + if (dn->exponentexponent=etiny; + *status|=DEC_Clamped; + } + return; + } + + *status|=DEC_Subnormal; // have a non-zero subnormal + adjust=etiny-dn->exponent; // calculate digits to remove + if (adjust<=0) { // not out of range; unrounded + // residue can never be non-zero here, except in the Nmin-residue + // case (which is a subnormal result), so can take fast-path here + // it may already be inexact (from setting the coefficient) + if (*status&DEC_Inexact) *status|=DEC_Underflow; + return; + } + + // adjust>0, so need to rescale the result so exponent becomes Etiny + // [this code is similar to that in rescale] + workset=*set; // clone rounding, etc. + workset.digits=dn->digits-adjust; // set requested length + workset.emin-=adjust; // and adjust emin to match + // [note that the latter can be <1, here, similar to Rescale case] + decSetCoeff(dn, &workset, dn->lsu, dn->digits, residue, status); + decApplyRound(dn, &workset, *residue, status); + + // Use 754 default rule: Underflow is set iff Inexact + // [independent of whether trapped] + if (*status&DEC_Inexact) *status|=DEC_Underflow; + + // if rounded up a 999s case, exponent will be off by one; adjust + // back if so [it will fit, because it was shortened earlier] + if (dn->exponent>etiny) { + dn->digits=decShiftToMost(dn->lsu, dn->digits, 1); + dn->exponent--; // (re)adjust the exponent. + } + + // if rounded to zero, it is by definition clamped... + if (ISZERO(dn)) *status|=DEC_Clamped; + } // decSetSubnormal + +/* ------------------------------------------------------------------ */ +/* decCheckMath - check entry conditions for a math function */ +/* */ +/* This checks the context and the operand */ +/* */ +/* rhs is the operand to check */ +/* set is the context to check */ +/* status is unchanged if both are good */ +/* */ +/* returns non-zero if status is changed, 0 otherwise */ +/* */ +/* Restrictions enforced: */ +/* */ +/* digits, emax, and -emin in the context must be less than */ +/* DEC_MAX_MATH (999999), and A must be within these bounds if */ +/* non-zero. Invalid_operation is set in the status if a */ +/* restriction is violated. */ +/* ------------------------------------------------------------------ */ +static uInt decCheckMath(const decNumber *rhs, decContext *set, + uInt *status) { + uInt save=*status; // record + if (set->digits>DEC_MAX_MATH + || set->emax>DEC_MAX_MATH + || -set->emin>DEC_MAX_MATH) *status|=DEC_Invalid_context; + else if ((rhs->digits>DEC_MAX_MATH + || rhs->exponent+rhs->digits>DEC_MAX_MATH+1 + || rhs->exponent+rhs->digits<2*(1-DEC_MAX_MATH)) + && !ISZERO(rhs)) *status|=DEC_Invalid_operation; + return (*status!=save); + } // decCheckMath + +/* ------------------------------------------------------------------ */ +/* decGetInt -- get integer from a number */ +/* */ +/* dn is the number [which will not be altered] */ +/* */ +/* returns one of: */ +/* BADINT if there is a non-zero fraction */ +/* the converted integer */ +/* BIGEVEN if the integer is even and magnitude > 2*10**9 */ +/* BIGODD if the integer is odd and magnitude > 2*10**9 */ +/* */ +/* This checks and gets a whole number from the input decNumber. */ +/* The sign can be determined from dn by the caller when BIGEVEN or */ +/* BIGODD is returned. */ +/* ------------------------------------------------------------------ */ +static Int decGetInt(const decNumber *dn) { + Int theInt; // result accumulator + const Unit *up; // work + Int got; // digits (real or not) processed + Int ilength=dn->digits+dn->exponent; // integral length + Flag neg=decNumberIsNegative(dn); // 1 if -ve + + // The number must be an integer that fits in 10 digits + // Assert, here, that 10 is enough for any rescale Etiny + #if DEC_MAX_EMAX > 999999999 + #error GetInt may need updating [for Emax] + #endif + #if DEC_MIN_EMIN < -999999999 + #error GetInt may need updating [for Emin] + #endif + if (ISZERO(dn)) return 0; // zeros are OK, with any exponent + + up=dn->lsu; // ready for lsu + theInt=0; // ready to accumulate + if (dn->exponent>=0) { // relatively easy + // no fractional part [usual]; allow for positive exponent + got=dn->exponent; + } + else { // -ve exponent; some fractional part to check and discard + Int count=-dn->exponent; // digits to discard + // spin up whole units until reach the Unit with the unit digit + for (; count>=DECDPUN; up++) { + if (*up!=0) return BADINT; // non-zero Unit to discard + count-=DECDPUN; + } + if (count==0) got=0; // [a multiple of DECDPUN] + else { // [not multiple of DECDPUN] + Int rem; // work + // slice off fraction digits and check for non-zero + #if DECDPUN<=4 + theInt=QUOT10(*up, count); + rem=*up-theInt*powers[count]; + #else + rem=*up%powers[count]; // slice off discards + theInt=*up/powers[count]; + #endif + if (rem!=0) return BADINT; // non-zero fraction + // it looks good + got=DECDPUN-count; // number of digits so far + up++; // ready for next + } + } + // now it's known there's no fractional part + + // tricky code now, to accumulate up to 9.3 digits + if (got==0) {theInt=*up; got+=DECDPUN; up++;} // ensure lsu is there + + if (ilength<11) { + Int save=theInt; + // collect any remaining unit(s) + for (; got1999999997) ilength=11; + else if (!neg && theInt>999999999) ilength=11; + if (ilength==11) theInt=save; // restore correct low bit + } + } + + if (ilength>10) { // too big + if (theInt&1) return BIGODD; // bottom bit 1 + return BIGEVEN; // bottom bit 0 + } + + if (neg) theInt=-theInt; // apply sign + return theInt; + } // decGetInt + +/* ------------------------------------------------------------------ */ +/* decDecap -- decapitate the coefficient of a number */ +/* */ +/* dn is the number to be decapitated */ +/* drop is the number of digits to be removed from the left of dn; */ +/* this must be <= dn->digits (if equal, the coefficient is */ +/* set to 0) */ +/* */ +/* Returns dn; dn->digits will be <= the initial digits less drop */ +/* (after removing drop digits there may be leading zero digits */ +/* which will also be removed). Only dn->lsu and dn->digits change. */ +/* ------------------------------------------------------------------ */ +static decNumber *decDecap(decNumber *dn, Int drop) { + Unit *msu; // -> target cut point + Int cut; // work + if (drop>=dn->digits) { // losing the whole thing + #if DECCHECK + if (drop>dn->digits) + printf("decDecap called with drop>digits [%ld>%ld]\n", + (LI)drop, (LI)dn->digits); + #endif + dn->lsu[0]=0; + dn->digits=1; + return dn; + } + msu=dn->lsu+D2U(dn->digits-drop)-1; // -> likely msu + cut=MSUDIGITS(dn->digits-drop); // digits to be in use in msu + if (cut!=DECDPUN) *msu%=powers[cut]; // clear left digits + // that may have left leading zero digits, so do a proper count... + dn->digits=decGetDigits(dn->lsu, msu-dn->lsu+1); + return dn; + } // decDecap + +/* ------------------------------------------------------------------ */ +/* decBiStr -- compare string with pairwise options */ +/* */ +/* targ is the string to compare */ +/* str1 is one of the strings to compare against (length may be 0) */ +/* str2 is the other; it must be the same length as str1 */ +/* */ +/* returns 1 if strings compare equal, (that is, it is the same */ +/* length as str1 and str2, and each character of targ is in either */ +/* str1 or str2 in the corresponding position), or 0 otherwise */ +/* */ +/* This is used for generic caseless compare, including the awkward */ +/* case of the Turkish dotted and dotless Is. Use as (for example): */ +/* if (decBiStr(test, "mike", "MIKE")) ... */ +/* ------------------------------------------------------------------ */ +static Flag decBiStr(const char *targ, const char *str1, const char *str2) { + for (;;targ++, str1++, str2++) { + if (*targ!=*str1 && *targ!=*str2) return 0; + // *targ has a match in one (or both, if terminator) + if (*targ=='\0') break; + } // forever + return 1; + } // decBiStr + +/* ------------------------------------------------------------------ */ +/* decNaNs -- handle NaN operand or operands */ +/* */ +/* res is the result number */ +/* lhs is the first operand */ +/* rhs is the second operand, or NULL if none */ +/* context is used to limit payload length */ +/* status contains the current status */ +/* returns res in case convenient */ +/* */ +/* Called when one or both operands is a NaN, and propagates the */ +/* appropriate result to res. When an sNaN is found, it is changed */ +/* to a qNaN and Invalid operation is set. */ +/* ------------------------------------------------------------------ */ +static decNumber * decNaNs(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set, + uInt *status) { + // This decision tree ends up with LHS being the source pointer, + // and status updated if need be + if (lhs->bits & DECSNAN) + *status|=DEC_Invalid_operation | DEC_sNaN; + else if (rhs==NULL); + else if (rhs->bits & DECSNAN) { + lhs=rhs; + *status|=DEC_Invalid_operation | DEC_sNaN; + } + else if (lhs->bits & DECNAN); + else lhs=rhs; + + // propagate the payload + if (lhs->digits<=set->digits) decNumberCopy(res, lhs); // easy + else { // too long + const Unit *ul; + Unit *ur, *uresp1; + // copy safe number of units, then decapitate + res->bits=lhs->bits; // need sign etc. + uresp1=res->lsu+D2U(set->digits); + for (ur=res->lsu, ul=lhs->lsu; urdigits=D2U(set->digits)*DECDPUN; + // maybe still too long + if (res->digits>set->digits) decDecap(res, res->digits-set->digits); + } + + res->bits&=~DECSNAN; // convert any sNaN to NaN, while + res->bits|=DECNAN; // .. preserving sign + res->exponent=0; // clean exponent + // [coefficient was copied/decapitated] + return res; + } // decNaNs + +/* ------------------------------------------------------------------ */ +/* decStatus -- apply non-zero status */ +/* */ +/* dn is the number to set if error */ +/* status contains the current status (not yet in context) */ +/* set is the context */ +/* */ +/* If the status is an error status, the number is set to a NaN, */ +/* unless the error was an overflow, divide-by-zero, or underflow, */ +/* in which case the number will have already been set. */ +/* */ +/* The context status is then updated with the new status. Note that */ +/* this may raise a signal, so control may never return from this */ +/* routine (hence resources must be recovered before it is called). */ +/* ------------------------------------------------------------------ */ +static void decStatus(decNumber *dn, uInt status, decContext *set) { + if (status & DEC_NaNs) { // error status -> NaN + // if cause was an sNaN, clear and propagate [NaN is already set up] + if (status & DEC_sNaN) status&=~DEC_sNaN; + else { + decNumberZero(dn); // other error: clean throughout + dn->bits=DECNAN; // and make a quiet NaN + } + } + decContextSetStatus(set, status); // [may not return] + return; + } // decStatus + +/* ------------------------------------------------------------------ */ +/* decGetDigits -- count digits in a Units array */ +/* */ +/* uar is the Unit array holding the number (this is often an */ +/* accumulator of some sort) */ +/* len is the length of the array in units [>=1] */ +/* */ +/* returns the number of (significant) digits in the array */ +/* */ +/* All leading zeros are excluded, except the last if the array has */ +/* only zero Units. */ +/* ------------------------------------------------------------------ */ +// This may be called twice during some operations. +static Int decGetDigits(Unit *uar, Int len) { + Unit *up=uar+(len-1); // -> msu + Int digits=(len-1)*DECDPUN+1; // possible digits excluding msu + #if DECDPUN>4 + uInt const *pow; // work + #endif + // (at least 1 in final msu) + #if DECCHECK + if (len<1) printf("decGetDigits called with len<1 [%ld]\n", (LI)len); + #endif + + for (; up>=uar; up--) { + if (*up==0) { // unit is all 0s + if (digits==1) break; // a zero has one digit + digits-=DECDPUN; // adjust for 0 unit + continue;} + // found the first (most significant) non-zero Unit + #if DECDPUN>1 // not done yet + if (*up<10) break; // is 1-9 + digits++; + #if DECDPUN>2 // not done yet + if (*up<100) break; // is 10-99 + digits++; + #if DECDPUN>3 // not done yet + if (*up<1000) break; // is 100-999 + digits++; + #if DECDPUN>4 // count the rest ... + for (pow=&powers[4]; *up>=*pow; pow++) digits++; + #endif + #endif + #endif + #endif + break; + } // up + return digits; + } // decGetDigits + +#if DECTRACE | DECCHECK +/* ------------------------------------------------------------------ */ +/* decNumberShow -- display a number [debug aid] */ +/* dn is the number to show */ +/* */ +/* Shows: sign, exponent, coefficient (msu first), digits */ +/* or: sign, special-value */ +/* ------------------------------------------------------------------ */ +// this is public so other modules can use it +void decNumberShow(const decNumber *dn) { + const Unit *up; // work + uInt u, d; // .. + Int cut; // .. + char isign='+'; // main sign + if (dn==NULL) { + printf("NULL\n"); + return;} + if (decNumberIsNegative(dn)) isign='-'; + printf(" >> %c ", isign); + if (dn->bits&DECSPECIAL) { // Is a special value + if (decNumberIsInfinite(dn)) printf("Infinity"); + else { // a NaN + if (dn->bits&DECSNAN) printf("sNaN"); // signalling NaN + else printf("NaN"); + } + // if coefficient and exponent are 0, no more to do + if (dn->exponent==0 && dn->digits==1 && *dn->lsu==0) { + printf("\n"); + return;} + // drop through to report other information + printf(" "); + } + + // now carefully display the coefficient + up=dn->lsu+D2U(dn->digits)-1; // msu + printf("%ld", (LI)*up); + for (up=up-1; up>=dn->lsu; up--) { + u=*up; + printf(":"); + for (cut=DECDPUN-1; cut>=0; cut--) { + d=u/powers[cut]; + u-=d*powers[cut]; + printf("%ld", (LI)d); + } // cut + } // up + if (dn->exponent!=0) { + char esign='+'; + if (dn->exponent<0) esign='-'; + printf(" E%c%ld", esign, (LI)abs(dn->exponent)); + } + printf(" [%ld]\n", (LI)dn->digits); + } // decNumberShow +#endif + +#if DECTRACE || DECCHECK +/* ------------------------------------------------------------------ */ +/* decDumpAr -- display a unit array [debug/check aid] */ +/* name is a single-character tag name */ +/* ar is the array to display */ +/* len is the length of the array in Units */ +/* ------------------------------------------------------------------ */ +static void decDumpAr(char name, const Unit *ar, Int len) { + Int i; + const char *spec; + #if DECDPUN==9 + spec="%09d "; + #elif DECDPUN==8 + spec="%08d "; + #elif DECDPUN==7 + spec="%07d "; + #elif DECDPUN==6 + spec="%06d "; + #elif DECDPUN==5 + spec="%05d "; + #elif DECDPUN==4 + spec="%04d "; + #elif DECDPUN==3 + spec="%03d "; + #elif DECDPUN==2 + spec="%02d "; + #else + spec="%d "; + #endif + printf(" :%c: ", name); + for (i=len-1; i>=0; i--) { + if (i==len-1) printf("%ld ", (LI)ar[i]); + else printf(spec, ar[i]); + } + printf("\n"); + return;} +#endif + +#if DECCHECK +/* ------------------------------------------------------------------ */ +/* decCheckOperands -- check operand(s) to a routine */ +/* res is the result structure (not checked; it will be set to */ +/* quiet NaN if error found (and it is not NULL)) */ +/* lhs is the first operand (may be DECUNRESU) */ +/* rhs is the second (may be DECUNUSED) */ +/* set is the context (may be DECUNCONT) */ +/* returns 0 if both operands, and the context are clean, or 1 */ +/* otherwise (in which case the context will show an error, */ +/* unless NULL). Note that res is not cleaned; caller should */ +/* handle this so res=NULL case is safe. */ +/* The caller is expected to abandon immediately if 1 is returned. */ +/* ------------------------------------------------------------------ */ +static Flag decCheckOperands(decNumber *res, const decNumber *lhs, + const decNumber *rhs, decContext *set) { + Flag bad=0; + if (set==NULL) { // oops; hopeless + #if DECTRACE || DECVERB + printf("Reference to context is NULL.\n"); + #endif + bad=1; + return 1;} + else if (set!=DECUNCONT + && (set->digits<1 || set->round>=DEC_ROUND_MAX)) { + bad=1; + #if DECTRACE || DECVERB + printf("Bad context [digits=%ld round=%ld].\n", + (LI)set->digits, (LI)set->round); + #endif + } + else { + if (res==NULL) { + bad=1; + #if DECTRACE + // this one not DECVERB as standard tests include NULL + printf("Reference to result is NULL.\n"); + #endif + } + if (!bad && lhs!=DECUNUSED) bad=(decCheckNumber(lhs)); + if (!bad && rhs!=DECUNUSED) bad=(decCheckNumber(rhs)); + } + if (bad) { + if (set!=DECUNCONT) decContextSetStatus(set, DEC_Invalid_operation); + if (res!=DECUNRESU && res!=NULL) { + decNumberZero(res); + res->bits=DECNAN; // qNaN + } + } + return bad; + } // decCheckOperands + +/* ------------------------------------------------------------------ */ +/* decCheckNumber -- check a number */ +/* dn is the number to check */ +/* returns 0 if the number is clean, or 1 otherwise */ +/* */ +/* The number is considered valid if it could be a result from some */ +/* operation in some valid context. */ +/* ------------------------------------------------------------------ */ +static Flag decCheckNumber(const decNumber *dn) { + const Unit *up; // work + uInt maxuint; // .. + Int ae, d, digits; // .. + Int emin, emax; // .. + + if (dn==NULL) { // hopeless + #if DECTRACE + // this one not DECVERB as standard tests include NULL + printf("Reference to decNumber is NULL.\n"); + #endif + return 1;} + + // check special values + if (dn->bits & DECSPECIAL) { + if (dn->exponent!=0) { + #if DECTRACE || DECVERB + printf("Exponent %ld (not 0) for a special value [%02x].\n", + (LI)dn->exponent, dn->bits); + #endif + return 1;} + + // 2003.09.08: NaNs may now have coefficients, so next tests Inf only + if (decNumberIsInfinite(dn)) { + if (dn->digits!=1) { + #if DECTRACE || DECVERB + printf("Digits %ld (not 1) for an infinity.\n", (LI)dn->digits); + #endif + return 1;} + if (*dn->lsu!=0) { + #if DECTRACE || DECVERB + printf("LSU %ld (not 0) for an infinity.\n", (LI)*dn->lsu); + #endif + decDumpAr('I', dn->lsu, D2U(dn->digits)); + return 1;} + } // Inf + // 2002.12.26: negative NaNs can now appear through proposed IEEE + // concrete formats (decimal64, etc.). + return 0; + } + + // check the coefficient + if (dn->digits<1 || dn->digits>DECNUMMAXP) { + #if DECTRACE || DECVERB + printf("Digits %ld in number.\n", (LI)dn->digits); + #endif + return 1;} + + d=dn->digits; + + for (up=dn->lsu; d>0; up++) { + if (d>DECDPUN) maxuint=DECDPUNMAX; + else { // reached the msu + maxuint=powers[d]-1; + if (dn->digits>1 && *upmaxuint) { + #if DECTRACE || DECVERB + printf("Bad Unit [%08lx] in %ld-digit number at offset %ld [maxuint %ld].\n", + (LI)*up, (LI)dn->digits, (LI)(up-dn->lsu), (LI)maxuint); + #endif + return 1;} + d-=DECDPUN; + } + + // check the exponent. Note that input operands can have exponents + // which are out of the set->emin/set->emax and set->digits range + // (just as they can have more digits than set->digits). + ae=dn->exponent+dn->digits-1; // adjusted exponent + emax=DECNUMMAXE; + emin=DECNUMMINE; + digits=DECNUMMAXP; + if (ae+emax) { + #if DECTRACE || DECVERB + printf("Adjusted exponent overflow [%ld].\n", (LI)ae); + decNumberShow(dn); + #endif + return 1;} + + return 0; // it's OK + } // decCheckNumber + +/* ------------------------------------------------------------------ */ +/* decCheckInexact -- check a normal finite inexact result has digits */ +/* dn is the number to check */ +/* set is the context (for status and precision) */ +/* sets Invalid operation, etc., if some digits are missing */ +/* [this check is not made for DECSUBSET compilation or when */ +/* subnormal is not set] */ +/* ------------------------------------------------------------------ */ +static void decCheckInexact(const decNumber *dn, decContext *set) { + #if !DECSUBSET && DECEXTFLAG + if ((set->status & (DEC_Inexact|DEC_Subnormal))==DEC_Inexact + && (set->digits!=dn->digits) && !(dn->bits & DECSPECIAL)) { + #if DECTRACE || DECVERB + printf("Insufficient digits [%ld] on normal Inexact result.\n", + (LI)dn->digits); + decNumberShow(dn); + #endif + decContextSetStatus(set, DEC_Invalid_operation); + } + #else + // next is a noop for quiet compiler + if (dn!=NULL && dn->digits==0) set->status|=DEC_Invalid_operation; + #endif + return; + } // decCheckInexact +#endif + +#if DECALLOC +#undef malloc +#undef free +/* ------------------------------------------------------------------ */ +/* decMalloc -- accountable allocation routine */ +/* n is the number of bytes to allocate */ +/* */ +/* Semantics is the same as the stdlib malloc routine, but bytes */ +/* allocated are accounted for globally, and corruption fences are */ +/* added before and after the 'actual' storage. */ +/* ------------------------------------------------------------------ */ +/* This routine allocates storage with an extra twelve bytes; 8 are */ +/* at the start and hold: */ +/* 0-3 the original length requested */ +/* 4-7 buffer corruption detection fence (DECFENCE, x4) */ +/* The 4 bytes at the end also hold a corruption fence (DECFENCE, x4) */ +/* ------------------------------------------------------------------ */ +static void *decMalloc(size_t n) { + uInt size=n+12; // true size + void *alloc; // -> allocated storage + uByte *b, *b0; // work + uInt uiwork; // for macros + + alloc=malloc(size); // -> allocated storage + if (alloc==NULL) return NULL; // out of strorage + b0=(uByte *)alloc; // as bytes + decAllocBytes+=n; // account for storage + UBFROMUI(alloc, n); // save n + // printf(" alloc ++ dAB: %ld (%ld)\n", (LI)decAllocBytes, (LI)n); + for (b=b0+4; b play area + } // decMalloc + +/* ------------------------------------------------------------------ */ +/* decFree -- accountable free routine */ +/* alloc is the storage to free */ +/* */ +/* Semantics is the same as the stdlib malloc routine, except that */ +/* the global storage accounting is updated and the fences are */ +/* checked to ensure that no routine has written 'out of bounds'. */ +/* ------------------------------------------------------------------ */ +/* This routine first checks that the fences have not been corrupted. */ +/* It then frees the storage using the 'truw' storage address (that */ +/* is, offset by 8). */ +/* ------------------------------------------------------------------ */ +static void decFree(void *alloc) { + uInt n; // original length + uByte *b, *b0; // work + uInt uiwork; // for macros + + if (alloc==NULL) return; // allowed; it's a nop + b0=(uByte *)alloc; // as bytes + b0-=8; // -> true start of storage + n=UBTOUI(b0); // lift length + for (b=b0+4; b0 */ + /* and <10; 3 or powers of 2 are best]. */ + + /* DECNUMDIGITS is the default number of digits that can be held in */ + /* the structure. If undefined, 1 is assumed and it is assumed */ + /* that the structure will be immediately followed by extra space, */ + /* as required. DECNUMDIGITS is always >0. */ + #if !defined(DECNUMDIGITS) + #define DECNUMDIGITS 1 + #endif + + /* The size (integer data type) of each unit is determined by the */ + /* number of digits it will hold. */ + #if DECDPUN<=2 + #define decNumberUnit uint8_t + #elif DECDPUN<=4 + #define decNumberUnit uint16_t + #else + #define decNumberUnit uint32_t + #endif + /* The number of units needed is ceil(DECNUMDIGITS/DECDPUN) */ + #define DECNUMUNITS ((DECNUMDIGITS+DECDPUN-1)/DECDPUN) + + /* The data structure... */ + typedef struct { + int32_t digits; /* Count of digits in the coefficient; >0 */ + int32_t exponent; /* Unadjusted exponent, unbiased, in */ + /* range: -1999999997 through 999999999 */ + uint8_t bits; /* Indicator bits (see above) */ + /* Coefficient, from least significant unit */ + decNumberUnit lsu[DECNUMUNITS]; + } decNumber; + + /* Notes: */ + /* 1. If digits is > DECDPUN then there will one or more */ + /* decNumberUnits immediately following the first element of lsu.*/ + /* These contain the remaining (more significant) digits of the */ + /* number, and may be in the lsu array, or may be guaranteed by */ + /* some other mechanism (such as being contained in another */ + /* structure, or being overlaid on dynamically allocated */ + /* storage). */ + /* */ + /* Each integer of the coefficient (except potentially the last) */ + /* contains DECDPUN digits (e.g., a value in the range 0 through */ + /* 99999999 if DECDPUN is 8, or 0 through 999 if DECDPUN is 3). */ + /* */ + /* 2. A decNumber converted to a string may need up to digits+14 */ + /* characters. The worst cases (non-exponential and exponential */ + /* formats) are -0.00000{9...}# and -9.{9...}E+999999999# */ + /* (where # is '\0') */ + + + /* ---------------------------------------------------------------- */ + /* decNumber public functions and macros */ + /* ---------------------------------------------------------------- */ + /* Conversions */ + decNumber * decNumberFromInt32(decNumber *, int32_t); + decNumber * decNumberFromUInt32(decNumber *, uint32_t); + decNumber * decNumberFromString(decNumber *, const char *, decContext *); + char * decNumberToString(const decNumber *, char *); + char * decNumberToEngString(const decNumber *, char *); + uint32_t decNumberToUInt32(const decNumber *, decContext *); + int32_t decNumberToInt32(const decNumber *, decContext *); + uint8_t * decNumberGetBCD(const decNumber *, uint8_t *); + decNumber * decNumberSetBCD(decNumber *, const uint8_t *, uint32_t); + + /* Operators and elementary functions */ + decNumber * decNumberAbs(decNumber *, const decNumber *, decContext *); + decNumber * decNumberAdd(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberAnd(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberCompareSignal(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberCompareTotal(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberCompareTotalMag(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberDivide(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberDivideInteger(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberExp(decNumber *, const decNumber *, decContext *); + decNumber * decNumberFMA(decNumber *, const decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberInvert(decNumber *, const decNumber *, decContext *); + decNumber * decNumberLn(decNumber *, const decNumber *, decContext *); + decNumber * decNumberLogB(decNumber *, const decNumber *, decContext *); + decNumber * decNumberLog10(decNumber *, const decNumber *, decContext *); + decNumber * decNumberMax(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberMaxMag(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberMin(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberMinMag(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberMinus(decNumber *, const decNumber *, decContext *); + decNumber * decNumberMultiply(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberNormalize(decNumber *, const decNumber *, decContext *); + decNumber * decNumberOr(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberPlus(decNumber *, const decNumber *, decContext *); + decNumber * decNumberPower(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberQuantize(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberReduce(decNumber *, const decNumber *, decContext *); + decNumber * decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberRescale(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberRotate(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberSameQuantum(decNumber *, const decNumber *, const decNumber *); + decNumber * decNumberScaleB(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberShift(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberSquareRoot(decNumber *, const decNumber *, decContext *); + decNumber * decNumberSubtract(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberToIntegralExact(decNumber *, const decNumber *, decContext *); + decNumber * decNumberToIntegralValue(decNumber *, const decNumber *, decContext *); + decNumber * decNumberXor(decNumber *, const decNumber *, const decNumber *, decContext *); + + /* Utilities */ + enum decClass decNumberClass(const decNumber *, decContext *); + const char * decNumberClassToString(enum decClass); + decNumber * decNumberCopy(decNumber *, const decNumber *); + decNumber * decNumberCopyAbs(decNumber *, const decNumber *); + decNumber * decNumberCopyNegate(decNumber *, const decNumber *); + decNumber * decNumberCopySign(decNumber *, const decNumber *, const decNumber *); + decNumber * decNumberNextMinus(decNumber *, const decNumber *, decContext *); + decNumber * decNumberNextPlus(decNumber *, const decNumber *, decContext *); + decNumber * decNumberNextToward(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumber * decNumberTrim(decNumber *); + const char * decNumberVersion(void); + decNumber * decNumberZero(decNumber *); + + /* Functions for testing decNumbers (normality depends on context) */ + int32_t decNumberIsNormal(const decNumber *, decContext *); + int32_t decNumberIsSubnormal(const decNumber *, decContext *); + + /* Macros for testing decNumber *dn */ + #define decNumberIsCanonical(dn) (1) /* All decNumbers are saintly */ + #define decNumberIsFinite(dn) (((dn)->bits&DECSPECIAL)==0) + #define decNumberIsInfinite(dn) (((dn)->bits&DECINF)!=0) + #define decNumberIsNaN(dn) (((dn)->bits&(DECNAN|DECSNAN))!=0) + #define decNumberIsNegative(dn) (((dn)->bits&DECNEG)!=0) + #define decNumberIsQNaN(dn) (((dn)->bits&(DECNAN))!=0) + #define decNumberIsSNaN(dn) (((dn)->bits&(DECSNAN))!=0) + #define decNumberIsSpecial(dn) (((dn)->bits&DECSPECIAL)!=0) + #define decNumberIsZero(dn) (*(dn)->lsu==0 \ + && (dn)->digits==1 \ + && (((dn)->bits&DECSPECIAL)==0)) + #define decNumberRadix(dn) (10) + +#endif diff --git a/extern/decNumber/decNumberLocal.h b/extern/decNumber/decNumberLocal.h new file mode 100644 index 0000000000..cfd3e74e23 --- /dev/null +++ b/extern/decNumber/decNumberLocal.h @@ -0,0 +1,757 @@ +/* ------------------------------------------------------------------ */ +/* decNumber package local type, tuning, and macro definitions */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This header file is included by all modules in the decNumber */ +/* library, and contains local type definitions, tuning parameters, */ +/* etc. It should not need to be used by application programs. */ +/* decNumber.h or one of decDouble (etc.) must be included first. */ +/* ------------------------------------------------------------------ */ + +#if !defined(DECNUMBERLOC) + #define DECNUMBERLOC + #define DECVERSION "decNumber 3.68" /* Package Version [16 max.] */ + #define DECNLAUTHOR "Mike Cowlishaw" /* Who to blame */ + + #include /* for abs */ + #include /* for memset, strcpy */ + + /* Conditional code flag -- set this to match hardware platform */ + #if !defined(DECLITEND) + #define DECLITEND 1 /* 1=little-endian, 0=big-endian */ + #endif + + /* Conditional code flag -- set this to 1 for best performance */ + #if !defined(DECUSE64) + #define DECUSE64 1 /* 1=use int64s, 0=int32 & smaller only */ + #endif + + /* Conditional code flag -- set this to 0 to exclude printf calls */ + #if !defined(DECPRINT) + #define DECPRINT 1 /* 1=allow printf calls; 0=no printf */ + #endif + + /* Conditional check flags -- set these to 0 for best performance */ + #if !defined(DECCHECK) + #define DECCHECK 0 /* 1 to enable robust checking */ + #endif + #if !defined(DECALLOC) + #define DECALLOC 0 /* 1 to enable memory accounting */ + #endif + #if !defined(DECTRACE) + #define DECTRACE 0 /* 1 to trace certain internals, etc. */ + #endif + + /* Tuning parameter for decNumber (arbitrary precision) module */ + #if !defined(DECBUFFER) + #define DECBUFFER 36 /* Size basis for local buffers. This */ + /* should be a common maximum precision */ + /* rounded up to a multiple of 4; must */ + /* be zero or positive. */ + #endif + + + /* ---------------------------------------------------------------- */ + /* Check parameter dependencies */ + /* ---------------------------------------------------------------- */ + #if DECCHECK & !DECPRINT + #error DECCHECK needs DECPRINT to be useful + #endif + #if DECALLOC & !DECPRINT + #error DECALLOC needs DECPRINT to be useful + #endif + #if DECTRACE & !DECPRINT + #error DECTRACE needs DECPRINT to be useful + #endif + + /* ---------------------------------------------------------------- */ + /* Definitions for all modules (general-purpose) */ + /* ---------------------------------------------------------------- */ + + /* Local names for common types -- for safety, decNumber modules do */ + /* not use int or long directly. */ + #define Flag uint8_t + #define Byte int8_t + #define uByte uint8_t + #define Short int16_t + #define uShort uint16_t + #define Int int32_t + #define uInt uint32_t + #define Unit decNumberUnit + #if DECUSE64 + #define Long int64_t + #define uLong uint64_t + #endif + + /* Development-use definitions */ + typedef long int LI; /* for printf arguments only */ + #define DECNOINT 0 /* 1 to check no internal use of 'int' */ + /* or stdint types */ + #if DECNOINT + /* if these interfere with your C includes, do not set DECNOINT */ + #define int ? /* enable to ensure that plain C 'int' */ + #define long ?? /* .. or 'long' types are not used */ + #endif + + /* Shared lookup tables */ + extern const uByte DECSTICKYTAB[10]; /* re-round digits if sticky */ + extern const uInt DECPOWERS[10]; /* powers of ten table */ + /* The following are included from decDPD.h */ + extern const uShort DPD2BIN[1024]; /* DPD -> 0-999 */ + extern const uShort BIN2DPD[1000]; /* 0-999 -> DPD */ + extern const uInt DPD2BINK[1024]; /* DPD -> 0-999000 */ + extern const uInt DPD2BINM[1024]; /* DPD -> 0-999000000 */ + extern const uByte DPD2BCD8[4096]; /* DPD -> ddd + len */ + extern const uByte BIN2BCD8[4000]; /* 0-999 -> ddd + len */ + extern const uShort BCD2DPD[2458]; /* 0-0x999 -> DPD (0x999=2457)*/ + + /* LONGMUL32HI -- set w=(u*v)>>32, where w, u, and v are uInts */ + /* (that is, sets w to be the high-order word of the 64-bit result; */ + /* the low-order word is simply u*v.) */ + /* This version is derived from Knuth via Hacker's Delight; */ + /* it seems to optimize better than some others tried */ + #define LONGMUL32HI(w, u, v) { \ + uInt u0, u1, v0, v1, w0, w1, w2, t; \ + u0=u & 0xffff; u1=u>>16; \ + v0=v & 0xffff; v1=v>>16; \ + w0=u0*v0; \ + t=u1*v0 + (w0>>16); \ + w1=t & 0xffff; w2=t>>16; \ + w1=u0*v1 + w1; \ + (w)=u1*v1 + w2 + (w1>>16);} + + /* ROUNDUP -- round an integer up to a multiple of n */ + #define ROUNDUP(i, n) ((((i)+(n)-1)/n)*n) + #define ROUNDUP4(i) (((i)+3)&~3) /* special for n=4 */ + + /* ROUNDDOWN -- round an integer down to a multiple of n */ + #define ROUNDDOWN(i, n) (((i)/n)*n) + #define ROUNDDOWN4(i) ((i)&~3) /* special for n=4 */ + + /* References to multi-byte sequences under different sizes; these */ + /* require locally declared variables, but do not violate strict */ + /* aliasing or alignment (as did the UINTAT simple cast to uInt). */ + /* Variables needed are uswork, uiwork, etc. [so do not use at same */ + /* level in an expression, e.g., UBTOUI(x)==UBTOUI(y) may fail]. */ + + /* Return a uInt, etc., from bytes starting at a char* or uByte* */ + #define UBTOUS(b) (memcpy((void *)&uswork, b, 2), uswork) + #define UBTOUI(b) (memcpy((void *)&uiwork, b, 4), uiwork) + + /* Store a uInt, etc., into bytes starting at a char* or uByte*. */ + /* Returns i, evaluated, for convenience; has to use uiwork because */ + /* i may be an expression. */ + #define UBFROMUS(b, i) (uswork=(i), memcpy(b, (void *)&uswork, 2), uswork) + #define UBFROMUI(b, i) (uiwork=(i), memcpy(b, (void *)&uiwork, 4), uiwork) + + /* X10 and X100 -- multiply integer i by 10 or 100 */ + /* [shifts are usually faster than multiply; could be conditional] */ + #define X10(i) (((i)<<1)+((i)<<3)) + #define X100(i) (((i)<<2)+((i)<<5)+((i)<<6)) + + /* MAXI and MINI -- general max & min (not in ANSI) for integers */ + #define MAXI(x,y) ((x)<(y)?(y):(x)) + #define MINI(x,y) ((x)>(y)?(y):(x)) + + /* Useful constants */ + #define BILLION 1000000000 /* 10**9 */ + /* CHARMASK: 0x30303030 for ASCII/UTF8; 0xF0F0F0F0 for EBCDIC */ + #define CHARMASK ((((((((uInt)'0')<<8)+'0')<<8)+'0')<<8)+'0') + + + /* ---------------------------------------------------------------- */ + /* Definitions for arbitary-precision modules (only valid after */ + /* decNumber.h has been included) */ + /* ---------------------------------------------------------------- */ + + /* Limits and constants */ + #define DECNUMMAXP 999999999 /* maximum precision code can handle */ + #define DECNUMMAXE 999999999 /* maximum adjusted exponent ditto */ + #define DECNUMMINE -999999999 /* minimum adjusted exponent ditto */ + #if (DECNUMMAXP != DEC_MAX_DIGITS) + #error Maximum digits mismatch + #endif + #if (DECNUMMAXE != DEC_MAX_EMAX) + #error Maximum exponent mismatch + #endif + #if (DECNUMMINE != DEC_MIN_EMIN) + #error Minimum exponent mismatch + #endif + + /* Set DECDPUNMAX -- the maximum integer that fits in DECDPUN */ + /* digits, and D2UTABLE -- the initializer for the D2U table */ + #if DECDPUN==1 + #define DECDPUNMAX 9 + #define D2UTABLE {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17, \ + 18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, \ + 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, \ + 48,49} + #elif DECDPUN==2 + #define DECDPUNMAX 99 + #define D2UTABLE {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10, \ + 11,11,12,12,13,13,14,14,15,15,16,16,17,17,18, \ + 18,19,19,20,20,21,21,22,22,23,23,24,24,25} + #elif DECDPUN==3 + #define DECDPUNMAX 999 + #define D2UTABLE {0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7, \ + 8,8,8,9,9,9,10,10,10,11,11,11,12,12,12,13,13, \ + 13,14,14,14,15,15,15,16,16,16,17} + #elif DECDPUN==4 + #define DECDPUNMAX 9999 + #define D2UTABLE {0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6, \ + 6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11, \ + 11,11,11,12,12,12,12,13} + #elif DECDPUN==5 + #define DECDPUNMAX 99999 + #define D2UTABLE {0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5, \ + 5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9, \ + 9,9,10,10,10,10} + #elif DECDPUN==6 + #define DECDPUNMAX 999999 + #define D2UTABLE {0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4, \ + 4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8, \ + 8,8,8,8,8,9} + #elif DECDPUN==7 + #define DECDPUNMAX 9999999 + #define D2UTABLE {0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3, \ + 4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7, \ + 7,7,7,7,7,7} + #elif DECDPUN==8 + #define DECDPUNMAX 99999999 + #define D2UTABLE {0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3, \ + 3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6, \ + 6,6,6,6,6,7} + #elif DECDPUN==9 + #define DECDPUNMAX 999999999 + #define D2UTABLE {0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3, \ + 3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5, \ + 5,5,6,6,6,6} + #elif defined(DECDPUN) + #error DECDPUN must be in the range 1-9 + #endif + + /* ----- Shared data (in decNumber.c) ----- */ + /* Public lookup table used by the D2U macro (see below) */ + #define DECMAXD2U 49 + extern const uByte d2utable[DECMAXD2U+1]; + + /* ----- Macros ----- */ + /* ISZERO -- return true if decNumber dn is a zero */ + /* [performance-critical in some situations] */ + #define ISZERO(dn) decNumberIsZero(dn) /* now just a local name */ + + /* D2U -- return the number of Units needed to hold d digits */ + /* (runtime version, with table lookaside for small d) */ + #if DECDPUN==8 + #define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+7)>>3)) + #elif DECDPUN==4 + #define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+3)>>2)) + #else + #define D2U(d) ((d)<=DECMAXD2U?d2utable[d]:((d)+DECDPUN-1)/DECDPUN) + #endif + /* SD2U -- static D2U macro (for compile-time calculation) */ + #define SD2U(d) (((d)+DECDPUN-1)/DECDPUN) + + /* MSUDIGITS -- returns digits in msu, from digits, calculated */ + /* using D2U */ + #define MSUDIGITS(d) ((d)-(D2U(d)-1)*DECDPUN) + + /* D2N -- return the number of decNumber structs that would be */ + /* needed to contain that number of digits (and the initial */ + /* decNumber struct) safely. Note that one Unit is included in the */ + /* initial structure. Used for allocating space that is aligned on */ + /* a decNumber struct boundary. */ + #define D2N(d) \ + ((((SD2U(d)-1)*sizeof(Unit))+sizeof(decNumber)*2-1)/sizeof(decNumber)) + + /* TODIGIT -- macro to remove the leading digit from the unsigned */ + /* integer u at column cut (counting from the right, LSD=0) and */ + /* place it as an ASCII character into the character pointed to by */ + /* c. Note that cut must be <= 9, and the maximum value for u is */ + /* 2,000,000,000 (as is needed for negative exponents of */ + /* subnormals). The unsigned integer pow is used as a temporary */ + /* variable. */ + #define TODIGIT(u, cut, c, pow) { \ + *(c)='0'; \ + pow=DECPOWERS[cut]*2; \ + if ((u)>pow) { \ + pow*=4; \ + if ((u)>=pow) {(u)-=pow; *(c)+=8;} \ + pow/=2; \ + if ((u)>=pow) {(u)-=pow; *(c)+=4;} \ + pow/=2; \ + } \ + if ((u)>=pow) {(u)-=pow; *(c)+=2;} \ + pow/=2; \ + if ((u)>=pow) {(u)-=pow; *(c)+=1;} \ + } + + /* ---------------------------------------------------------------- */ + /* Definitions for fixed-precision modules (only valid after */ + /* decSingle.h, decDouble.h, or decQuad.h has been included) */ + /* ---------------------------------------------------------------- */ + + /* bcdnum -- a structure describing a format-independent finite */ + /* number, whose coefficient is a string of bcd8 uBytes */ + typedef struct { + uByte *msd; /* -> most significant digit */ + uByte *lsd; /* -> least ditto */ + uInt sign; /* 0=positive, DECFLOAT_Sign=negative */ + Int exponent; /* Unadjusted signed exponent (q), or */ + /* DECFLOAT_NaN etc. for a special */ + } bcdnum; + + /* Test if exponent or bcdnum exponent must be a special, etc. */ + #define EXPISSPECIAL(exp) ((exp)>=DECFLOAT_MinSp) + #define EXPISINF(exp) (exp==DECFLOAT_Inf) + #define EXPISNAN(exp) (exp==DECFLOAT_qNaN || exp==DECFLOAT_sNaN) + #define NUMISSPECIAL(num) (EXPISSPECIAL((num)->exponent)) + + /* Refer to a 32-bit word or byte in a decFloat (df) by big-endian */ + /* (array) notation (the 0 word or byte contains the sign bit), */ + /* automatically adjusting for endianness; similarly address a word */ + /* in the next-wider format (decFloatWider, or dfw) */ + #define DECWORDS (DECBYTES/4) + #define DECWWORDS (DECWBYTES/4) + #if DECLITEND + #define DFBYTE(df, off) ((df)->bytes[DECBYTES-1-(off)]) + #define DFWORD(df, off) ((df)->words[DECWORDS-1-(off)]) + #define DFWWORD(dfw, off) ((dfw)->words[DECWWORDS-1-(off)]) + #else + #define DFBYTE(df, off) ((df)->bytes[off]) + #define DFWORD(df, off) ((df)->words[off]) + #define DFWWORD(dfw, off) ((dfw)->words[off]) + #endif + + /* Tests for sign or specials, directly on DECFLOATs */ + #define DFISSIGNED(df) ((DFWORD(df, 0)&0x80000000)!=0) + #define DFISSPECIAL(df) ((DFWORD(df, 0)&0x78000000)==0x78000000) + #define DFISINF(df) ((DFWORD(df, 0)&0x7c000000)==0x78000000) + #define DFISNAN(df) ((DFWORD(df, 0)&0x7c000000)==0x7c000000) + #define DFISQNAN(df) ((DFWORD(df, 0)&0x7e000000)==0x7c000000) + #define DFISSNAN(df) ((DFWORD(df, 0)&0x7e000000)==0x7e000000) + + /* Shared lookup tables */ + extern const uInt DECCOMBMSD[64]; /* Combination field -> MSD */ + extern const uInt DECCOMBFROM[48]; /* exp+msd -> Combination */ + + /* Private generic (utility) routine */ + #if DECCHECK || DECTRACE + extern void decShowNum(const bcdnum *, const char *); + #endif + + /* Format-dependent macros and constants */ + #if defined(DECPMAX) + + /* Useful constants */ + #define DECPMAX9 (ROUNDUP(DECPMAX, 9)/9) /* 'Pmax' in 10**9s */ + /* Top words for a zero */ + #define SINGLEZERO 0x22500000 + #define DOUBLEZERO 0x22380000 + #define QUADZERO 0x22080000 + /* [ZEROWORD is defined to be one of these in the DFISZERO macro] */ + + /* Format-dependent common tests: */ + /* DFISZERO -- test for (any) zero */ + /* DFISCCZERO -- test for coefficient continuation being zero */ + /* DFISCC01 -- test for coefficient contains only 0s and 1s */ + /* DFISINT -- test for finite and exponent q=0 */ + /* DFISUINT01 -- test for sign=0, finite, exponent q=0, and */ + /* MSD=0 or 1 */ + /* ZEROWORD is also defined here. */ + /* */ + /* In DFISZERO the first test checks the least-significant word */ + /* (most likely to be non-zero); the penultimate tests MSD and */ + /* DPDs in the signword, and the final test excludes specials and */ + /* MSD>7. DFISINT similarly has to allow for the two forms of */ + /* MSD codes. DFISUINT01 only has to allow for one form of MSD */ + /* code. */ + #if DECPMAX==7 + #define ZEROWORD SINGLEZERO + /* [test macros not needed except for Zero] */ + #define DFISZERO(df) ((DFWORD(df, 0)&0x1c0fffff)==0 \ + && (DFWORD(df, 0)&0x60000000)!=0x60000000) + #elif DECPMAX==16 + #define ZEROWORD DOUBLEZERO + #define DFISZERO(df) ((DFWORD(df, 1)==0 \ + && (DFWORD(df, 0)&0x1c03ffff)==0 \ + && (DFWORD(df, 0)&0x60000000)!=0x60000000)) + #define DFISINT(df) ((DFWORD(df, 0)&0x63fc0000)==0x22380000 \ + ||(DFWORD(df, 0)&0x7bfc0000)==0x6a380000) + #define DFISUINT01(df) ((DFWORD(df, 0)&0xfbfc0000)==0x22380000) + #define DFISCCZERO(df) (DFWORD(df, 1)==0 \ + && (DFWORD(df, 0)&0x0003ffff)==0) + #define DFISCC01(df) ((DFWORD(df, 0)&~0xfffc9124)==0 \ + && (DFWORD(df, 1)&~0x49124491)==0) + #elif DECPMAX==34 + #define ZEROWORD QUADZERO + #define DFISZERO(df) ((DFWORD(df, 3)==0 \ + && DFWORD(df, 2)==0 \ + && DFWORD(df, 1)==0 \ + && (DFWORD(df, 0)&0x1c003fff)==0 \ + && (DFWORD(df, 0)&0x60000000)!=0x60000000)) + #define DFISINT(df) ((DFWORD(df, 0)&0x63ffc000)==0x22080000 \ + ||(DFWORD(df, 0)&0x7bffc000)==0x6a080000) + #define DFISUINT01(df) ((DFWORD(df, 0)&0xfbffc000)==0x22080000) + #define DFISCCZERO(df) (DFWORD(df, 3)==0 \ + && DFWORD(df, 2)==0 \ + && DFWORD(df, 1)==0 \ + && (DFWORD(df, 0)&0x00003fff)==0) + + #define DFISCC01(df) ((DFWORD(df, 0)&~0xffffc912)==0 \ + && (DFWORD(df, 1)&~0x44912449)==0 \ + && (DFWORD(df, 2)&~0x12449124)==0 \ + && (DFWORD(df, 3)&~0x49124491)==0) + #endif + + /* Macros to test if a certain 10 bits of a uInt or pair of uInts */ + /* are a canonical declet [higher or lower bits are ignored]. */ + /* declet is at offset 0 (from the right) in a uInt: */ + #define CANONDPD(dpd) (((dpd)&0x300)==0 || ((dpd)&0x6e)!=0x6e) + /* declet is at offset k (a multiple of 2) in a uInt: */ + #define CANONDPDOFF(dpd, k) (((dpd)&(0x300<<(k)))==0 \ + || ((dpd)&(((uInt)0x6e)<<(k)))!=(((uInt)0x6e)<<(k))) + /* declet is at offset k (a multiple of 2) in a pair of uInts: */ + /* [the top 2 bits will always be in the more-significant uInt] */ + #define CANONDPDTWO(hi, lo, k) (((hi)&(0x300>>(32-(k))))==0 \ + || ((hi)&(0x6e>>(32-(k))))!=(0x6e>>(32-(k))) \ + || ((lo)&(((uInt)0x6e)<<(k)))!=(((uInt)0x6e)<<(k))) + + /* Macro to test whether a full-length (length DECPMAX) BCD8 */ + /* coefficient, starting at uByte u, is all zeros */ + /* Test just the LSWord first, then the remainder as a sequence */ + /* of tests in order to avoid same-level use of UBTOUI */ + #if DECPMAX==7 + #define ISCOEFFZERO(u) ( \ + UBTOUI((u)+DECPMAX-4)==0 \ + && UBTOUS((u)+DECPMAX-6)==0 \ + && *(u)==0) + #elif DECPMAX==16 + #define ISCOEFFZERO(u) ( \ + UBTOUI((u)+DECPMAX-4)==0 \ + && UBTOUI((u)+DECPMAX-8)==0 \ + && UBTOUI((u)+DECPMAX-12)==0 \ + && UBTOUI(u)==0) + #elif DECPMAX==34 + #define ISCOEFFZERO(u) ( \ + UBTOUI((u)+DECPMAX-4)==0 \ + && UBTOUI((u)+DECPMAX-8)==0 \ + && UBTOUI((u)+DECPMAX-12)==0 \ + && UBTOUI((u)+DECPMAX-16)==0 \ + && UBTOUI((u)+DECPMAX-20)==0 \ + && UBTOUI((u)+DECPMAX-24)==0 \ + && UBTOUI((u)+DECPMAX-28)==0 \ + && UBTOUI((u)+DECPMAX-32)==0 \ + && UBTOUS(u)==0) + #endif + + /* Macros and masks for the sign, exponent continuation, and MSD */ + /* Get the sign as DECFLOAT_Sign or 0 */ + #define GETSIGN(df) (DFWORD(df, 0)&0x80000000) + /* Get the exponent continuation from a decFloat *df as an Int */ + #define GETECON(df) ((Int)((DFWORD((df), 0)&0x03ffffff)>>(32-6-DECECONL))) + /* Ditto, from the next-wider format */ + #define GETWECON(df) ((Int)((DFWWORD((df), 0)&0x03ffffff)>>(32-6-DECWECONL))) + /* Get the biased exponent similarly */ + #define GETEXP(df) ((Int)(DECCOMBEXP[DFWORD((df), 0)>>26]+GETECON(df))) + /* Get the unbiased exponent similarly */ + #define GETEXPUN(df) ((Int)GETEXP(df)-DECBIAS) + /* Get the MSD similarly (as uInt) */ + #define GETMSD(df) (DECCOMBMSD[DFWORD((df), 0)>>26]) + + /* Compile-time computes of the exponent continuation field masks */ + /* full exponent continuation field: */ + #define ECONMASK ((0x03ffffff>>(32-6-DECECONL))<<(32-6-DECECONL)) + /* same, not including its first digit (the qNaN/sNaN selector): */ + #define ECONNANMASK ((0x01ffffff>>(32-6-DECECONL))<<(32-6-DECECONL)) + + /* Macros to decode the coefficient in a finite decFloat *df into */ + /* a BCD string (uByte *bcdin) of length DECPMAX uBytes. */ + + /* In-line sequence to convert least significant 10 bits of uInt */ + /* dpd to three BCD8 digits starting at uByte u. Note that an */ + /* extra byte is written to the right of the three digits because */ + /* four bytes are moved at a time for speed; the alternative */ + /* macro moves exactly three bytes (usually slower). */ + #define dpd2bcd8(u, dpd) memcpy(u, &DPD2BCD8[((dpd)&0x3ff)*4], 4) + #define dpd2bcd83(u, dpd) memcpy(u, &DPD2BCD8[((dpd)&0x3ff)*4], 3) + + /* Decode the declets. After extracting each one, it is decoded */ + /* to BCD8 using a table lookup (also used for variable-length */ + /* decode). Each DPD decode is 3 bytes BCD8 plus a one-byte */ + /* length which is not used, here). Fixed-length 4-byte moves */ + /* are fast, however, almost everywhere, and so are used except */ + /* for the final three bytes (to avoid overrun). The code below */ + /* is 36 instructions for Doubles and about 70 for Quads, even */ + /* on IA32. */ + + /* Two macros are defined for each format: */ + /* GETCOEFF extracts the coefficient of the current format */ + /* GETWCOEFF extracts the coefficient of the next-wider format. */ + /* The latter is a copy of the next-wider GETCOEFF using DFWWORD. */ + + #if DECPMAX==7 + #define GETCOEFF(df, bcd) { \ + uInt sourhi=DFWORD(df, 0); \ + *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ + dpd2bcd8(bcd+1, sourhi>>10); \ + dpd2bcd83(bcd+4, sourhi);} + #define GETWCOEFF(df, bcd) { \ + uInt sourhi=DFWWORD(df, 0); \ + uInt sourlo=DFWWORD(df, 1); \ + *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ + dpd2bcd8(bcd+1, sourhi>>8); \ + dpd2bcd8(bcd+4, (sourhi<<2) | (sourlo>>30)); \ + dpd2bcd8(bcd+7, sourlo>>20); \ + dpd2bcd8(bcd+10, sourlo>>10); \ + dpd2bcd83(bcd+13, sourlo);} + + #elif DECPMAX==16 + #define GETCOEFF(df, bcd) { \ + uInt sourhi=DFWORD(df, 0); \ + uInt sourlo=DFWORD(df, 1); \ + *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ + dpd2bcd8(bcd+1, sourhi>>8); \ + dpd2bcd8(bcd+4, (sourhi<<2) | (sourlo>>30)); \ + dpd2bcd8(bcd+7, sourlo>>20); \ + dpd2bcd8(bcd+10, sourlo>>10); \ + dpd2bcd83(bcd+13, sourlo);} + #define GETWCOEFF(df, bcd) { \ + uInt sourhi=DFWWORD(df, 0); \ + uInt sourmh=DFWWORD(df, 1); \ + uInt sourml=DFWWORD(df, 2); \ + uInt sourlo=DFWWORD(df, 3); \ + *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ + dpd2bcd8(bcd+1, sourhi>>4); \ + dpd2bcd8(bcd+4, ((sourhi)<<6) | (sourmh>>26)); \ + dpd2bcd8(bcd+7, sourmh>>16); \ + dpd2bcd8(bcd+10, sourmh>>6); \ + dpd2bcd8(bcd+13, ((sourmh)<<4) | (sourml>>28)); \ + dpd2bcd8(bcd+16, sourml>>18); \ + dpd2bcd8(bcd+19, sourml>>8); \ + dpd2bcd8(bcd+22, ((sourml)<<2) | (sourlo>>30)); \ + dpd2bcd8(bcd+25, sourlo>>20); \ + dpd2bcd8(bcd+28, sourlo>>10); \ + dpd2bcd83(bcd+31, sourlo);} + + #elif DECPMAX==34 + #define GETCOEFF(df, bcd) { \ + uInt sourhi=DFWORD(df, 0); \ + uInt sourmh=DFWORD(df, 1); \ + uInt sourml=DFWORD(df, 2); \ + uInt sourlo=DFWORD(df, 3); \ + *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ + dpd2bcd8(bcd+1, sourhi>>4); \ + dpd2bcd8(bcd+4, ((sourhi)<<6) | (sourmh>>26)); \ + dpd2bcd8(bcd+7, sourmh>>16); \ + dpd2bcd8(bcd+10, sourmh>>6); \ + dpd2bcd8(bcd+13, ((sourmh)<<4) | (sourml>>28)); \ + dpd2bcd8(bcd+16, sourml>>18); \ + dpd2bcd8(bcd+19, sourml>>8); \ + dpd2bcd8(bcd+22, ((sourml)<<2) | (sourlo>>30)); \ + dpd2bcd8(bcd+25, sourlo>>20); \ + dpd2bcd8(bcd+28, sourlo>>10); \ + dpd2bcd83(bcd+31, sourlo);} + + #define GETWCOEFF(df, bcd) {??} /* [should never be used] */ + #endif + + /* Macros to decode the coefficient in a finite decFloat *df into */ + /* a base-billion uInt array, with the least-significant */ + /* 0-999999999 'digit' at offset 0. */ + + /* Decode the declets. After extracting each one, it is decoded */ + /* to binary using a table lookup. Three tables are used; one */ + /* the usual DPD to binary, the other two pre-multiplied by 1000 */ + /* and 1000000 to avoid multiplication during decode. These */ + /* tables can also be used for multiplying up the MSD as the DPD */ + /* code for 0 through 9 is the identity. */ + #define DPD2BIN0 DPD2BIN /* for prettier code */ + + #if DECPMAX==7 + #define GETCOEFFBILL(df, buf) { \ + uInt sourhi=DFWORD(df, 0); \ + (buf)[0]=DPD2BIN0[sourhi&0x3ff] \ + +DPD2BINK[(sourhi>>10)&0x3ff] \ + +DPD2BINM[DECCOMBMSD[sourhi>>26]];} + + #elif DECPMAX==16 + #define GETCOEFFBILL(df, buf) { \ + uInt sourhi, sourlo; \ + sourlo=DFWORD(df, 1); \ + (buf)[0]=DPD2BIN0[sourlo&0x3ff] \ + +DPD2BINK[(sourlo>>10)&0x3ff] \ + +DPD2BINM[(sourlo>>20)&0x3ff]; \ + sourhi=DFWORD(df, 0); \ + (buf)[1]=DPD2BIN0[((sourhi<<2) | (sourlo>>30))&0x3ff] \ + +DPD2BINK[(sourhi>>8)&0x3ff] \ + +DPD2BINM[DECCOMBMSD[sourhi>>26]];} + + #elif DECPMAX==34 + #define GETCOEFFBILL(df, buf) { \ + uInt sourhi, sourmh, sourml, sourlo; \ + sourlo=DFWORD(df, 3); \ + (buf)[0]=DPD2BIN0[sourlo&0x3ff] \ + +DPD2BINK[(sourlo>>10)&0x3ff] \ + +DPD2BINM[(sourlo>>20)&0x3ff]; \ + sourml=DFWORD(df, 2); \ + (buf)[1]=DPD2BIN0[((sourml<<2) | (sourlo>>30))&0x3ff] \ + +DPD2BINK[(sourml>>8)&0x3ff] \ + +DPD2BINM[(sourml>>18)&0x3ff]; \ + sourmh=DFWORD(df, 1); \ + (buf)[2]=DPD2BIN0[((sourmh<<4) | (sourml>>28))&0x3ff] \ + +DPD2BINK[(sourmh>>6)&0x3ff] \ + +DPD2BINM[(sourmh>>16)&0x3ff]; \ + sourhi=DFWORD(df, 0); \ + (buf)[3]=DPD2BIN0[((sourhi<<6) | (sourmh>>26))&0x3ff] \ + +DPD2BINK[(sourhi>>4)&0x3ff] \ + +DPD2BINM[DECCOMBMSD[sourhi>>26]];} + + #endif + + /* Macros to decode the coefficient in a finite decFloat *df into */ + /* a base-thousand uInt array (of size DECLETS+1, to allow for */ + /* the MSD), with the least-significant 0-999 'digit' at offset 0.*/ + + /* Decode the declets. After extracting each one, it is decoded */ + /* to binary using a table lookup. */ + #if DECPMAX==7 + #define GETCOEFFTHOU(df, buf) { \ + uInt sourhi=DFWORD(df, 0); \ + (buf)[0]=DPD2BIN[sourhi&0x3ff]; \ + (buf)[1]=DPD2BIN[(sourhi>>10)&0x3ff]; \ + (buf)[2]=DECCOMBMSD[sourhi>>26];} + + #elif DECPMAX==16 + #define GETCOEFFTHOU(df, buf) { \ + uInt sourhi, sourlo; \ + sourlo=DFWORD(df, 1); \ + (buf)[0]=DPD2BIN[sourlo&0x3ff]; \ + (buf)[1]=DPD2BIN[(sourlo>>10)&0x3ff]; \ + (buf)[2]=DPD2BIN[(sourlo>>20)&0x3ff]; \ + sourhi=DFWORD(df, 0); \ + (buf)[3]=DPD2BIN[((sourhi<<2) | (sourlo>>30))&0x3ff]; \ + (buf)[4]=DPD2BIN[(sourhi>>8)&0x3ff]; \ + (buf)[5]=DECCOMBMSD[sourhi>>26];} + + #elif DECPMAX==34 + #define GETCOEFFTHOU(df, buf) { \ + uInt sourhi, sourmh, sourml, sourlo; \ + sourlo=DFWORD(df, 3); \ + (buf)[0]=DPD2BIN[sourlo&0x3ff]; \ + (buf)[1]=DPD2BIN[(sourlo>>10)&0x3ff]; \ + (buf)[2]=DPD2BIN[(sourlo>>20)&0x3ff]; \ + sourml=DFWORD(df, 2); \ + (buf)[3]=DPD2BIN[((sourml<<2) | (sourlo>>30))&0x3ff]; \ + (buf)[4]=DPD2BIN[(sourml>>8)&0x3ff]; \ + (buf)[5]=DPD2BIN[(sourml>>18)&0x3ff]; \ + sourmh=DFWORD(df, 1); \ + (buf)[6]=DPD2BIN[((sourmh<<4) | (sourml>>28))&0x3ff]; \ + (buf)[7]=DPD2BIN[(sourmh>>6)&0x3ff]; \ + (buf)[8]=DPD2BIN[(sourmh>>16)&0x3ff]; \ + sourhi=DFWORD(df, 0); \ + (buf)[9]=DPD2BIN[((sourhi<<6) | (sourmh>>26))&0x3ff]; \ + (buf)[10]=DPD2BIN[(sourhi>>4)&0x3ff]; \ + (buf)[11]=DECCOMBMSD[sourhi>>26];} + #endif + + + /* Macros to decode the coefficient in a finite decFloat *df and */ + /* add to a base-thousand uInt array (as for GETCOEFFTHOU). */ + /* After the addition then most significant 'digit' in the array */ + /* might have a value larger then 10 (with a maximum of 19). */ + #if DECPMAX==7 + #define ADDCOEFFTHOU(df, buf) { \ + uInt sourhi=DFWORD(df, 0); \ + (buf)[0]+=DPD2BIN[sourhi&0x3ff]; \ + if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \ + (buf)[1]+=DPD2BIN[(sourhi>>10)&0x3ff]; \ + if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \ + (buf)[2]+=DECCOMBMSD[sourhi>>26];} + + #elif DECPMAX==16 + #define ADDCOEFFTHOU(df, buf) { \ + uInt sourhi, sourlo; \ + sourlo=DFWORD(df, 1); \ + (buf)[0]+=DPD2BIN[sourlo&0x3ff]; \ + if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \ + (buf)[1]+=DPD2BIN[(sourlo>>10)&0x3ff]; \ + if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \ + (buf)[2]+=DPD2BIN[(sourlo>>20)&0x3ff]; \ + if (buf[2]>999) {buf[2]-=1000; buf[3]++;} \ + sourhi=DFWORD(df, 0); \ + (buf)[3]+=DPD2BIN[((sourhi<<2) | (sourlo>>30))&0x3ff]; \ + if (buf[3]>999) {buf[3]-=1000; buf[4]++;} \ + (buf)[4]+=DPD2BIN[(sourhi>>8)&0x3ff]; \ + if (buf[4]>999) {buf[4]-=1000; buf[5]++;} \ + (buf)[5]+=DECCOMBMSD[sourhi>>26];} + + #elif DECPMAX==34 + #define ADDCOEFFTHOU(df, buf) { \ + uInt sourhi, sourmh, sourml, sourlo; \ + sourlo=DFWORD(df, 3); \ + (buf)[0]+=DPD2BIN[sourlo&0x3ff]; \ + if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \ + (buf)[1]+=DPD2BIN[(sourlo>>10)&0x3ff]; \ + if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \ + (buf)[2]+=DPD2BIN[(sourlo>>20)&0x3ff]; \ + if (buf[2]>999) {buf[2]-=1000; buf[3]++;} \ + sourml=DFWORD(df, 2); \ + (buf)[3]+=DPD2BIN[((sourml<<2) | (sourlo>>30))&0x3ff]; \ + if (buf[3]>999) {buf[3]-=1000; buf[4]++;} \ + (buf)[4]+=DPD2BIN[(sourml>>8)&0x3ff]; \ + if (buf[4]>999) {buf[4]-=1000; buf[5]++;} \ + (buf)[5]+=DPD2BIN[(sourml>>18)&0x3ff]; \ + if (buf[5]>999) {buf[5]-=1000; buf[6]++;} \ + sourmh=DFWORD(df, 1); \ + (buf)[6]+=DPD2BIN[((sourmh<<4) | (sourml>>28))&0x3ff]; \ + if (buf[6]>999) {buf[6]-=1000; buf[7]++;} \ + (buf)[7]+=DPD2BIN[(sourmh>>6)&0x3ff]; \ + if (buf[7]>999) {buf[7]-=1000; buf[8]++;} \ + (buf)[8]+=DPD2BIN[(sourmh>>16)&0x3ff]; \ + if (buf[8]>999) {buf[8]-=1000; buf[9]++;} \ + sourhi=DFWORD(df, 0); \ + (buf)[9]+=DPD2BIN[((sourhi<<6) | (sourmh>>26))&0x3ff]; \ + if (buf[9]>999) {buf[9]-=1000; buf[10]++;} \ + (buf)[10]+=DPD2BIN[(sourhi>>4)&0x3ff]; \ + if (buf[10]>999) {buf[10]-=1000; buf[11]++;} \ + (buf)[11]+=DECCOMBMSD[sourhi>>26];} + #endif + + + /* Set a decFloat to the maximum positive finite number (Nmax) */ + #if DECPMAX==7 + #define DFSETNMAX(df) \ + {DFWORD(df, 0)=0x77f3fcff;} + #elif DECPMAX==16 + #define DFSETNMAX(df) \ + {DFWORD(df, 0)=0x77fcff3f; \ + DFWORD(df, 1)=0xcff3fcff;} + #elif DECPMAX==34 + #define DFSETNMAX(df) \ + {DFWORD(df, 0)=0x77ffcff3; \ + DFWORD(df, 1)=0xfcff3fcf; \ + DFWORD(df, 2)=0xf3fcff3f; \ + DFWORD(df, 3)=0xcff3fcff;} + #endif + + /* [end of format-dependent macros and constants] */ + #endif + +#else + #error decNumberLocal included more than once +#endif diff --git a/extern/decNumber/decPacked.c b/extern/decNumber/decPacked.c new file mode 100644 index 0000000000..90b10715e5 --- /dev/null +++ b/extern/decNumber/decPacked.c @@ -0,0 +1,220 @@ +/* ------------------------------------------------------------------ */ +/* Packed Decimal conversion module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2002. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises the routines for Packed Decimal format */ +/* numbers. Conversions are supplied to and from decNumber, which in */ +/* turn supports: */ +/* conversions to and from string */ +/* arithmetic routines */ +/* utilities. */ +/* Conversions from decNumber to and from densely packed decimal */ +/* formats are provided by the decimal32 through decimal128 modules. */ +/* ------------------------------------------------------------------ */ + +#include // for NULL +#include "decNumber.h" // base number library +#include "decPacked.h" // packed decimal +#include "decNumberLocal.h" // decNumber local types, etc. + +/* ------------------------------------------------------------------ */ +/* decPackedFromNumber -- convert decNumber to BCD Packed Decimal */ +/* */ +/* bcd is the BCD bytes */ +/* length is the length of the BCD array */ +/* scale is the scale result */ +/* dn is the decNumber */ +/* returns bcd, or NULL if error */ +/* */ +/* The number is converted to a BCD packed decimal byte array, */ +/* right aligned in the bcd array, whose length is indicated by the */ +/* second parameter. The final 4-bit nibble in the array will be a */ +/* sign nibble, C (1100) for + and D (1101) for -. Unused bytes and */ +/* nibbles to the left of the number are set to 0. */ +/* */ +/* scale is set to the scale of the number (this is the exponent, */ +/* negated). To force the number to a specified scale, first use the */ +/* decNumberRescale routine, which will round and change the exponent */ +/* as necessary. */ +/* */ +/* If there is an error (that is, the decNumber has too many digits */ +/* to fit in length bytes, or it is a NaN or Infinity), NULL is */ +/* returned and the bcd and scale results are unchanged. Otherwise */ +/* bcd is returned. */ +/* ------------------------------------------------------------------ */ +uByte * decPackedFromNumber(uByte *bcd, Int length, Int *scale, + const decNumber *dn) { + const Unit *up=dn->lsu; // Unit array pointer + uByte obyte, *out; // current output byte, and where it goes + Int indigs=dn->digits; // digits processed + uInt cut=DECDPUN; // downcounter per Unit + uInt u=*up; // work + uInt nib; // .. + #if DECDPUN<=4 + uInt temp; // .. + #endif + + if (dn->digits>length*2-1 // too long .. + ||(dn->bits & DECSPECIAL)) return NULL; // .. or special -- hopeless + + if (dn->bits&DECNEG) obyte=DECPMINUS; // set the sign .. + else obyte=DECPPLUS; + *scale=-dn->exponent; // .. and scale + + // loop from lowest (rightmost) byte + out=bcd+length-1; // -> final byte + for (; out>=bcd; out--) { + if (indigs>0) { + if (cut==0) { + up++; + u=*up; + cut=DECDPUN; + } + #if DECDPUN<=4 + temp=(u*6554)>>16; // fast /10 + nib=u-X10(temp); + u=temp; + #else + nib=u%10; // cannot use *6554 trick :-( + u=u/10; + #endif + obyte|=(nib<<4); + indigs--; + cut--; + } + *out=obyte; + obyte=0; // assume 0 + if (indigs>0) { + if (cut==0) { + up++; + u=*up; + cut=DECDPUN; + } + #if DECDPUN<=4 + temp=(u*6554)>>16; // as above + obyte=(uByte)(u-X10(temp)); + u=temp; + #else + obyte=(uByte)(u%10); + u=u/10; + #endif + indigs--; + cut--; + } + } // loop + + return bcd; + } // decPackedFromNumber + +/* ------------------------------------------------------------------ */ +/* decPackedToNumber -- convert BCD Packed Decimal to a decNumber */ +/* */ +/* bcd is the BCD bytes */ +/* length is the length of the BCD array */ +/* scale is the scale associated with the BCD integer */ +/* dn is the decNumber [with space for length*2 digits] */ +/* returns dn, or NULL if error */ +/* */ +/* The BCD packed decimal byte array, together with an associated */ +/* scale, is converted to a decNumber. The BCD array is assumed full */ +/* of digits, and must be ended by a 4-bit sign nibble in the least */ +/* significant four bits of the final byte. */ +/* */ +/* The scale is used (negated) as the exponent of the decNumber. */ +/* Note that zeros may have a sign and/or a scale. */ +/* */ +/* The decNumber structure is assumed to have sufficient space to */ +/* hold the converted number (that is, up to length*2-1 digits), so */ +/* no error is possible unless the adjusted exponent is out of range, */ +/* no sign nibble was found, or a sign nibble was found before the */ +/* final nibble. In these error cases, NULL is returned and the */ +/* decNumber will be 0. */ +/* ------------------------------------------------------------------ */ +decNumber * decPackedToNumber(const uByte *bcd, Int length, + const Int *scale, decNumber *dn) { + const uByte *last=bcd+length-1; // -> last byte + const uByte *first; // -> first non-zero byte + uInt nib; // work nibble + Unit *up=dn->lsu; // output pointer + Int digits; // digits count + Int cut=0; // phase of output + + decNumberZero(dn); // default result + last=&bcd[length-1]; + nib=*last & 0x0f; // get the sign + if (nib==DECPMINUS || nib==DECPMINUSALT) dn->bits=DECNEG; + else if (nib<=9) return NULL; // not a sign nibble + + // skip leading zero bytes [final byte is always non-zero, due to sign] + for (first=bcd; *first==0;) first++; + digits=(last-first)*2+1; // calculate digits .. + if ((*first & 0xf0)==0) digits--; // adjust for leading zero nibble + if (digits!=0) dn->digits=digits; // count of actual digits [if 0, + // leave as 1] + + // check the adjusted exponent; note that scale could be unbounded + dn->exponent=-*scale; // set the exponent + if (*scale>=0) { // usual case + if ((dn->digits-*scale-1)<-DECNUMMAXE) { // underflow + decNumberZero(dn); + return NULL;} + } + else { // -ve scale; +ve exponent + // need to be careful to avoid wrap, here, also BADINT case + if ((*scale<-DECNUMMAXE) // overflow even without digits + || ((dn->digits-*scale-1)>DECNUMMAXE)) { // overflow + decNumberZero(dn); + return NULL;} + } + if (digits==0) return dn; // result was zero + + // copy the digits to the number's units, starting at the lsu + // [unrolled] + for (;;) { // forever + // left nibble first + nib=(unsigned)(*last & 0xf0)>>4; + // got a digit, in nib + if (nib>9) {decNumberZero(dn); return NULL;} + + if (cut==0) *up=(Unit)nib; + else *up=(Unit)(*up+nib*DECPOWERS[cut]); + digits--; + if (digits==0) break; // got them all + cut++; + if (cut==DECDPUN) { + up++; + cut=0; + } + last--; // ready for next + nib=*last & 0x0f; // get right nibble + if (nib>9) {decNumberZero(dn); return NULL;} + + // got a digit, in nib + if (cut==0) *up=(Unit)nib; + else *up=(Unit)(*up+nib*DECPOWERS[cut]); + digits--; + if (digits==0) break; // got them all + cut++; + if (cut==DECDPUN) { + up++; + cut=0; + } + } // forever + + return dn; + } // decPackedToNumber + diff --git a/extern/decNumber/decPacked.h b/extern/decNumber/decPacked.h new file mode 100644 index 0000000000..929a546253 --- /dev/null +++ b/extern/decNumber/decPacked.h @@ -0,0 +1,52 @@ +/* ------------------------------------------------------------------ */ +/* Packed Decimal conversion module header */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ + +#if !defined(DECPACKED) + #define DECPACKED + #define DECPNAME "decPacked" /* Short name */ + #define DECPFULLNAME "Packed Decimal conversions" /* Verbose name */ + #define DECPAUTHOR "Mike Cowlishaw" /* Who to blame */ + + #define DECPACKED_DefP 32 /* default precision */ + + #ifndef DECNUMDIGITS + #define DECNUMDIGITS DECPACKED_DefP /* size if not already defined*/ + #endif + #include "decNumber.h" /* context and number library */ + + /* Sign nibble constants */ + #if !defined(DECPPLUSALT) + #define DECPPLUSALT 0x0A /* alternate plus nibble */ + #define DECPMINUSALT 0x0B /* alternate minus nibble */ + #define DECPPLUS 0x0C /* preferred plus nibble */ + #define DECPMINUS 0x0D /* preferred minus nibble */ + #define DECPPLUSALT2 0x0E /* alternate plus nibble */ + #define DECPUNSIGNED 0x0F /* alternate plus nibble (unsigned) */ + #endif + + /* ---------------------------------------------------------------- */ + /* decPacked public routines */ + /* ---------------------------------------------------------------- */ + /* Conversions */ + uint8_t * decPackedFromNumber(uint8_t *, int32_t, int32_t *, + const decNumber *); + decNumber * decPackedToNumber(const uint8_t *, int32_t, const int32_t *, + decNumber *); + +#endif diff --git a/extern/decNumber/decQuad.c b/extern/decNumber/decQuad.c new file mode 100644 index 0000000000..c65b30c2af --- /dev/null +++ b/extern/decNumber/decQuad.c @@ -0,0 +1,135 @@ +/* ------------------------------------------------------------------ */ +/* decQuad.c -- decQuad operations module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is included in the package as decNumber.pdf. This */ +/* document is also available in HTML, together with specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises decQuad operations (including conversions) */ +/* ------------------------------------------------------------------ */ + + +/* Constant mappings for shared code */ +#define DECPMAX DECQUAD_Pmax +#define DECEMIN DECQUAD_Emin +#define DECEMAX DECQUAD_Emax +#define DECEMAXD DECQUAD_EmaxD +#define DECBYTES DECQUAD_Bytes +#define DECSTRING DECQUAD_String +#define DECECONL DECQUAD_EconL +#define DECBIAS DECQUAD_Bias +#define DECLETS DECQUAD_Declets +#define DECQTINY (-DECQUAD_Bias) + +/* Type and function mappings for shared code */ +#define decFloat decQuad // Type name + +// Utilities and conversions (binary results, extractors, etc.) +#define decFloatFromBCD decQuadFromBCD +#define decFloatFromInt32 decQuadFromInt32 +#define decFloatFromPacked decQuadFromPacked +#define decFloatFromPackedChecked decQuadFromPackedChecked +#define decFloatFromString decQuadFromString +#define decFloatFromUInt32 decQuadFromUInt32 +#define decFloatFromWider decQuadFromWider +#define decFloatGetCoefficient decQuadGetCoefficient +#define decFloatGetExponent decQuadGetExponent +#define decFloatSetCoefficient decQuadSetCoefficient +#define decFloatSetExponent decQuadSetExponent +#define decFloatShow decQuadShow +#define decFloatToBCD decQuadToBCD +#define decFloatToEngString decQuadToEngString +#define decFloatToInt32 decQuadToInt32 +#define decFloatToInt32Exact decQuadToInt32Exact +#define decFloatToPacked decQuadToPacked +#define decFloatToString decQuadToString +#define decFloatToUInt32 decQuadToUInt32 +#define decFloatToUInt32Exact decQuadToUInt32Exact +#define decFloatToWider decQuadToWider +#define decFloatZero decQuadZero + +// Computational (result is a decFloat) +#define decFloatAbs decQuadAbs +#define decFloatAdd decQuadAdd +#define decFloatAnd decQuadAnd +#define decFloatDivide decQuadDivide +#define decFloatDivideInteger decQuadDivideInteger +#define decFloatFMA decQuadFMA +#define decFloatInvert decQuadInvert +#define decFloatLogB decQuadLogB +#define decFloatMax decQuadMax +#define decFloatMaxMag decQuadMaxMag +#define decFloatMin decQuadMin +#define decFloatMinMag decQuadMinMag +#define decFloatMinus decQuadMinus +#define decFloatMultiply decQuadMultiply +#define decFloatNextMinus decQuadNextMinus +#define decFloatNextPlus decQuadNextPlus +#define decFloatNextToward decQuadNextToward +#define decFloatOr decQuadOr +#define decFloatPlus decQuadPlus +#define decFloatQuantize decQuadQuantize +#define decFloatReduce decQuadReduce +#define decFloatRemainder decQuadRemainder +#define decFloatRemainderNear decQuadRemainderNear +#define decFloatRotate decQuadRotate +#define decFloatScaleB decQuadScaleB +#define decFloatShift decQuadShift +#define decFloatSubtract decQuadSubtract +#define decFloatToIntegralValue decQuadToIntegralValue +#define decFloatToIntegralExact decQuadToIntegralExact +#define decFloatXor decQuadXor + +// Comparisons +#define decFloatCompare decQuadCompare +#define decFloatCompareSignal decQuadCompareSignal +#define decFloatCompareTotal decQuadCompareTotal +#define decFloatCompareTotalMag decQuadCompareTotalMag + +// Copies +#define decFloatCanonical decQuadCanonical +#define decFloatCopy decQuadCopy +#define decFloatCopyAbs decQuadCopyAbs +#define decFloatCopyNegate decQuadCopyNegate +#define decFloatCopySign decQuadCopySign + +// Non-computational +#define decFloatClass decQuadClass +#define decFloatClassString decQuadClassString +#define decFloatDigits decQuadDigits +#define decFloatIsCanonical decQuadIsCanonical +#define decFloatIsFinite decQuadIsFinite +#define decFloatIsInfinite decQuadIsInfinite +#define decFloatIsInteger decQuadIsInteger +#define decFloatIsLogical decQuadIsLogical +#define decFloatIsNaN decQuadIsNaN +#define decFloatIsNegative decQuadIsNegative +#define decFloatIsNormal decQuadIsNormal +#define decFloatIsPositive decQuadIsPositive +#define decFloatIsSignaling decQuadIsSignaling +#define decFloatIsSignalling decQuadIsSignalling +#define decFloatIsSigned decQuadIsSigned +#define decFloatIsSubnormal decQuadIsSubnormal +#define decFloatIsZero decQuadIsZero +#define decFloatRadix decQuadRadix +#define decFloatSameQuantum decQuadSameQuantum +#define decFloatVersion decQuadVersion + +/* And now the code itself */ +#include "decContext.h" // public includes +#include "decQuad.h" // .. +#include "decNumberLocal.h" // local includes (need DECPMAX) +#include "decCommon.c" // non-arithmetic decFloat routines +#include "decBasic.c" // basic formats routines + diff --git a/extern/decNumber/decQuad.h b/extern/decNumber/decQuad.h new file mode 100644 index 0000000000..829f39a0ba --- /dev/null +++ b/extern/decNumber/decQuad.h @@ -0,0 +1,177 @@ +/* ------------------------------------------------------------------ */ +/* decQuad.h -- Decimal 128-bit format module header */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is included in the package as decNumber.pdf. This */ +/* document is also available in HTML, together with specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This include file is always included by decSingle and decDouble, */ +/* and therefore also holds useful constants used by all three. */ + +#if !defined(DECQUAD) + #define DECQUAD + + #define DECQUADNAME "decimalQuad" /* Short name */ + #define DECQUADTITLE "Decimal 128-bit datum" /* Verbose name */ + #define DECQUADAUTHOR "Mike Cowlishaw" /* Who to blame */ + + /* parameters for decQuads */ + #define DECQUAD_Bytes 16 /* length */ + #define DECQUAD_Pmax 34 /* maximum precision (digits) */ + #define DECQUAD_Emin -6143 /* minimum adjusted exponent */ + #define DECQUAD_Emax 6144 /* maximum adjusted exponent */ + #define DECQUAD_EmaxD 4 /* maximum exponent digits */ + #define DECQUAD_Bias 6176 /* bias for the exponent */ + #define DECQUAD_String 43 /* maximum string length, +1 */ + #define DECQUAD_EconL 12 /* exponent continuation length */ + #define DECQUAD_Declets 11 /* count of declets */ + /* highest biased exponent (Elimit-1) */ + #define DECQUAD_Ehigh (DECQUAD_Emax + DECQUAD_Bias - (DECQUAD_Pmax-1)) + + /* Required include */ + #include "decContext.h" + + /* The decQuad decimal 128-bit type, accessible by all sizes */ + typedef union { + uint8_t bytes[DECQUAD_Bytes]; /* fields: 1, 5, 12, 110 bits */ + uint16_t shorts[DECQUAD_Bytes/2]; + uint32_t words[DECQUAD_Bytes/4]; + #if DECUSE64 + uint64_t longs[DECQUAD_Bytes/8]; + #endif + } decQuad; + + /* ---------------------------------------------------------------- */ + /* Shared constants */ + /* ---------------------------------------------------------------- */ + + /* sign and special values [top 32-bits; last two bits are don't-care + for Infinity on input, last bit don't-care for NaNs] */ + #define DECFLOAT_Sign 0x80000000 /* 1 00000 00 Sign */ + #define DECFLOAT_NaN 0x7c000000 /* 0 11111 00 NaN generic */ + #define DECFLOAT_qNaN 0x7c000000 /* 0 11111 00 qNaN */ + #define DECFLOAT_sNaN 0x7e000000 /* 0 11111 10 sNaN */ + #define DECFLOAT_Inf 0x78000000 /* 0 11110 00 Infinity */ + #define DECFLOAT_MinSp 0x78000000 /* minimum special value */ + /* [specials are all >=MinSp] */ + /* Sign nibble constants */ + #if !defined(DECPPLUSALT) + #define DECPPLUSALT 0x0A /* alternate plus nibble */ + #define DECPMINUSALT 0x0B /* alternate minus nibble */ + #define DECPPLUS 0x0C /* preferred plus nibble */ + #define DECPMINUS 0x0D /* preferred minus nibble */ + #define DECPPLUSALT2 0x0E /* alternate plus nibble */ + #define DECPUNSIGNED 0x0F /* alternate plus nibble (unsigned) */ + #endif + + /* ---------------------------------------------------------------- */ + /* Routines -- implemented as decFloat routines in common files */ + /* ---------------------------------------------------------------- */ + + /* Utilities and conversions, extractors, etc.) */ + extern decQuad * decQuadFromBCD(decQuad *, int32_t, const uint8_t *, int32_t); + extern decQuad * decQuadFromInt32(decQuad *, int32_t); + extern decQuad * decQuadFromPacked(decQuad *, int32_t, const uint8_t *); + extern decQuad * decQuadFromPackedChecked(decQuad *, int32_t, const uint8_t *); + extern decQuad * decQuadFromString(decQuad *, const char *, decContext *); + extern decQuad * decQuadFromUInt32(decQuad *, uint32_t); + extern int32_t decQuadGetCoefficient(const decQuad *, uint8_t *); + extern int32_t decQuadGetExponent(const decQuad *); + extern decQuad * decQuadSetCoefficient(decQuad *, const uint8_t *, int32_t); + extern decQuad * decQuadSetExponent(decQuad *, decContext *, int32_t); + extern void decQuadShow(const decQuad *, const char *); + extern int32_t decQuadToBCD(const decQuad *, int32_t *, uint8_t *); + extern char * decQuadToEngString(const decQuad *, char *); + extern int32_t decQuadToInt32(const decQuad *, decContext *, enum rounding); + extern int32_t decQuadToInt32Exact(const decQuad *, decContext *, enum rounding); + extern int32_t decQuadToPacked(const decQuad *, int32_t *, uint8_t *); + extern char * decQuadToString(const decQuad *, char *); + extern uint32_t decQuadToUInt32(const decQuad *, decContext *, enum rounding); + extern uint32_t decQuadToUInt32Exact(const decQuad *, decContext *, enum rounding); + extern decQuad * decQuadZero(decQuad *); + + /* Computational (result is a decQuad) */ + extern decQuad * decQuadAbs(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadAdd(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadAnd(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadDivide(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadDivideInteger(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadFMA(decQuad *, const decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadInvert(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadLogB(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadMax(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadMaxMag(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadMin(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadMinMag(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadMinus(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadMultiply(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadNextMinus(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadNextPlus(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadNextToward(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadOr(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadPlus(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadQuantize(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadReduce(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadRemainder(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadRemainderNear(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadRotate(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadScaleB(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadShift(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadSubtract(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadToIntegralValue(decQuad *, const decQuad *, decContext *, enum rounding); + extern decQuad * decQuadToIntegralExact(decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadXor(decQuad *, const decQuad *, const decQuad *, decContext *); + + /* Comparisons */ + extern decQuad * decQuadCompare(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadCompareSignal(decQuad *, const decQuad *, const decQuad *, decContext *); + extern decQuad * decQuadCompareTotal(decQuad *, const decQuad *, const decQuad *); + extern decQuad * decQuadCompareTotalMag(decQuad *, const decQuad *, const decQuad *); + + /* Copies */ + extern decQuad * decQuadCanonical(decQuad *, const decQuad *); + extern decQuad * decQuadCopy(decQuad *, const decQuad *); + extern decQuad * decQuadCopyAbs(decQuad *, const decQuad *); + extern decQuad * decQuadCopyNegate(decQuad *, const decQuad *); + extern decQuad * decQuadCopySign(decQuad *, const decQuad *, const decQuad *); + + /* Non-computational */ + extern enum decClass decQuadClass(const decQuad *); + extern const char * decQuadClassString(const decQuad *); + extern uint32_t decQuadDigits(const decQuad *); + extern uint32_t decQuadIsCanonical(const decQuad *); + extern uint32_t decQuadIsFinite(const decQuad *); + extern uint32_t decQuadIsInteger(const decQuad *); + extern uint32_t decQuadIsLogical(const decQuad *); + extern uint32_t decQuadIsInfinite(const decQuad *); + extern uint32_t decQuadIsNaN(const decQuad *); + extern uint32_t decQuadIsNegative(const decQuad *); + extern uint32_t decQuadIsNormal(const decQuad *); + extern uint32_t decQuadIsPositive(const decQuad *); + extern uint32_t decQuadIsSignaling(const decQuad *); + extern uint32_t decQuadIsSignalling(const decQuad *); + extern uint32_t decQuadIsSigned(const decQuad *); + extern uint32_t decQuadIsSubnormal(const decQuad *); + extern uint32_t decQuadIsZero(const decQuad *); + extern uint32_t decQuadRadix(const decQuad *); + extern uint32_t decQuadSameQuantum(const decQuad *, const decQuad *); + extern const char * decQuadVersion(void); + + /* decNumber conversions; these are implemented as macros so as not */ + /* to force a dependency on decimal128 and decNumber in decQuad. */ + /* decQuadFromNumber returns a decimal128 * to avoid warnings. */ + #define decQuadToNumber(dq, dn) decimal128ToNumber((decimal128 *)(dq), dn) + #define decQuadFromNumber(dq, dn, set) decimal128FromNumber((decimal128 *)(dq), dn, set) + +#endif diff --git a/extern/decNumber/decSingle.c b/extern/decNumber/decSingle.c new file mode 100644 index 0000000000..85e59d5a14 --- /dev/null +++ b/extern/decNumber/decSingle.c @@ -0,0 +1,71 @@ +/* ------------------------------------------------------------------ */ +/* decSingle.c -- decSingle operations module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is included in the package as decNumber.pdf. This */ +/* document is also available in HTML, together with specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises decSingle operations (including conversions) */ +/* ------------------------------------------------------------------ */ + +#include "decContext.h" // public includes +#include "decSingle.h" // public includes + +/* Constant mappings for shared code */ +#define DECPMAX DECSINGLE_Pmax +#define DECEMIN DECSINGLE_Emin +#define DECEMAX DECSINGLE_Emax +#define DECEMAXD DECSINGLE_EmaxD +#define DECBYTES DECSINGLE_Bytes +#define DECSTRING DECSINGLE_String +#define DECECONL DECSINGLE_EconL +#define DECBIAS DECSINGLE_Bias +#define DECLETS DECSINGLE_Declets +#define DECQTINY (-DECSINGLE_Bias) +// parameters of next-wider format +#define DECWBYTES DECDOUBLE_Bytes +#define DECWPMAX DECDOUBLE_Pmax +#define DECWECONL DECDOUBLE_EconL +#define DECWBIAS DECDOUBLE_Bias + +/* Type and function mappings for shared code */ +#define decFloat decSingle // Type name +#define decFloatWider decDouble // Type name + +// Utility (binary results, extractors, etc.) +#define decFloatFromBCD decSingleFromBCD +#define decFloatFromPacked decSingleFromPacked +#define decFloatFromPackedChecked decSingleFromPackedChecked +#define decFloatFromString decSingleFromString +#define decFloatFromWider decSingleFromWider +#define decFloatGetCoefficient decSingleGetCoefficient +#define decFloatGetExponent decSingleGetExponent +#define decFloatSetCoefficient decSingleSetCoefficient +#define decFloatSetExponent decSingleSetExponent +#define decFloatShow decSingleShow +#define decFloatToBCD decSingleToBCD +#define decFloatToEngString decSingleToEngString +#define decFloatToPacked decSingleToPacked +#define decFloatToString decSingleToString +#define decFloatToWider decSingleToWider +#define decFloatZero decSingleZero + +// Non-computational +#define decFloatRadix decSingleRadix +#define decFloatVersion decSingleVersion + +#include "decNumberLocal.h" // local includes (need DECPMAX) +#include "decCommon.c" // non-basic decFloat routines +// [Do not include decBasic.c for decimal32] + diff --git a/extern/decNumber/decSingle.h b/extern/decNumber/decSingle.h new file mode 100644 index 0000000000..2bd1fdecb0 --- /dev/null +++ b/extern/decNumber/decSingle.h @@ -0,0 +1,86 @@ +/* ------------------------------------------------------------------ */ +/* decSingle.h -- Decimal 32-bit format module header */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is included in the package as decNumber.pdf. This */ +/* document is also available in HTML, together with specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ + +#if !defined(DECSINGLE) + #define DECSINGLE + + #define DECSINGLENAME "decSingle" /* Short name */ + #define DECSINGLETITLE "Decimal 32-bit datum" /* Verbose name */ + #define DECSINGLEAUTHOR "Mike Cowlishaw" /* Who to blame */ + + /* parameters for decSingles */ + #define DECSINGLE_Bytes 4 /* length */ + #define DECSINGLE_Pmax 7 /* maximum precision (digits) */ + #define DECSINGLE_Emin -95 /* minimum adjusted exponent */ + #define DECSINGLE_Emax 96 /* maximum adjusted exponent */ + #define DECSINGLE_EmaxD 3 /* maximum exponent digits */ + #define DECSINGLE_Bias 101 /* bias for the exponent */ + #define DECSINGLE_String 16 /* maximum string length, +1 */ + #define DECSINGLE_EconL 6 /* exponent continuation length */ + #define DECSINGLE_Declets 2 /* count of declets */ + /* highest biased exponent (Elimit-1) */ + #define DECSINGLE_Ehigh (DECSINGLE_Emax + DECSINGLE_Bias - (DECSINGLE_Pmax-1)) + + /* Required includes */ + #include "decContext.h" + #include "decQuad.h" + #include "decDouble.h" + + /* The decSingle decimal 32-bit type, accessible by all sizes */ + typedef union { + uint8_t bytes[DECSINGLE_Bytes]; /* fields: 1, 5, 6, 20 bits */ + uint16_t shorts[DECSINGLE_Bytes/2]; + uint32_t words[DECSINGLE_Bytes/4]; + } decSingle; + + /* ---------------------------------------------------------------- */ + /* Routines -- implemented as decFloat routines in common files */ + /* ---------------------------------------------------------------- */ + + /* Utilities (binary argument(s) or result, extractors, etc.) */ + extern decSingle * decSingleFromBCD(decSingle *, int32_t, const uint8_t *, int32_t); + extern decSingle * decSingleFromPacked(decSingle *, int32_t, const uint8_t *); + extern decSingle * decSingleFromPackedChecked(decSingle *, int32_t, const uint8_t *); + extern decSingle * decSingleFromString(decSingle *, const char *, decContext *); + extern decSingle * decSingleFromWider(decSingle *, const decDouble *, decContext *); + extern int32_t decSingleGetCoefficient(const decSingle *, uint8_t *); + extern int32_t decSingleGetExponent(const decSingle *); + extern decSingle * decSingleSetCoefficient(decSingle *, const uint8_t *, int32_t); + extern decSingle * decSingleSetExponent(decSingle *, decContext *, int32_t); + extern void decSingleShow(const decSingle *, const char *); + extern int32_t decSingleToBCD(const decSingle *, int32_t *, uint8_t *); + extern char * decSingleToEngString(const decSingle *, char *); + extern int32_t decSingleToPacked(const decSingle *, int32_t *, uint8_t *); + extern char * decSingleToString(const decSingle *, char *); + extern decDouble * decSingleToWider(const decSingle *, decDouble *); + extern decSingle * decSingleZero(decSingle *); + + /* (No Arithmetic routines for decSingle) */ + + /* Non-computational */ + extern uint32_t decSingleRadix(const decSingle *); + extern const char * decSingleVersion(void); + + /* decNumber conversions; these are implemented as macros so as not */ + /* to force a dependency on decimal32 and decNumber in decSingle. */ + /* decSingleFromNumber returns a decimal32 * to avoid warnings. */ + #define decSingleToNumber(dq, dn) decimal32ToNumber((decimal32 *)(dq), dn) + #define decSingleFromNumber(dq, dn, set) decimal32FromNumber((decimal32 *)(dq), dn, set) + +#endif diff --git a/extern/decNumber/decimal128.c b/extern/decNumber/decimal128.c new file mode 100644 index 0000000000..4387f4479b --- /dev/null +++ b/extern/decNumber/decimal128.c @@ -0,0 +1,553 @@ +/* ------------------------------------------------------------------ */ +/* Decimal 128-bit format module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises the routines for decimal128 format numbers. */ +/* Conversions are supplied to and from decNumber and String. */ +/* */ +/* This is used when decNumber provides operations, either for all */ +/* operations or as a proxy between decNumber and decSingle. */ +/* */ +/* Error handling is the same as decNumber (qv.). */ +/* ------------------------------------------------------------------ */ +#include // [for memset/memcpy] +#include // [for printf] + +#define DECNUMDIGITS 34 // make decNumbers with space for 34 +#include "decNumber.h" // base number library +#include "decNumberLocal.h" // decNumber local types, etc. +#include "decimal128.h" // our primary include + +/* Utility routines and tables [in decimal64.c] */ +// DPD2BIN and the reverse are renamed to prevent link-time conflict +// if decQuad is also built in the same executable +#define DPD2BIN DPD2BINx +#define BIN2DPD BIN2DPDx +extern const uInt COMBEXP[32], COMBMSD[32]; +extern const uShort DPD2BIN[1024]; +extern const uShort BIN2DPD[1000]; // [not used] +extern const uByte BIN2CHAR[4001]; + +extern void decDigitsFromDPD(decNumber *, const uInt *, Int); +extern void decDigitsToDPD(const decNumber *, uInt *, Int); + +#if DECTRACE || DECCHECK +void decimal128Show(const decimal128 *); // for debug +extern void decNumberShow(const decNumber *); // .. +#endif + +/* Useful macro */ +// Clear a structure (e.g., a decNumber) +#define DEC_clear(d) memset(d, 0, sizeof(*d)) + +/* ------------------------------------------------------------------ */ +/* decimal128FromNumber -- convert decNumber to decimal128 */ +/* */ +/* ds is the target decimal128 */ +/* dn is the source number (assumed valid) */ +/* set is the context, used only for reporting errors */ +/* */ +/* The set argument is used only for status reporting and for the */ +/* rounding mode (used if the coefficient is more than DECIMAL128_Pmax*/ +/* digits or an overflow is detected). If the exponent is out of the */ +/* valid range then Overflow or Underflow will be raised. */ +/* After Underflow a subnormal result is possible. */ +/* */ +/* DEC_Clamped is set if the number has to be 'folded down' to fit, */ +/* by reducing its exponent and multiplying the coefficient by a */ +/* power of ten, or if the exponent on a zero had to be clamped. */ +/* ------------------------------------------------------------------ */ +decimal128 * decimal128FromNumber(decimal128 *d128, const decNumber *dn, + decContext *set) { + uInt status=0; // status accumulator + Int ae; // adjusted exponent + decNumber dw; // work + decContext dc; // .. + uInt comb, exp; // .. + uInt uiwork; // for macros + uInt targar[4]={0,0,0,0}; // target 128-bit + #define targhi targar[3] // name the word with the sign + #define targmh targar[2] // name the words + #define targml targar[1] // .. + #define targlo targar[0] // .. + + // If the number has too many digits, or the exponent could be + // out of range then reduce the number under the appropriate + // constraints. This could push the number to Infinity or zero, + // so this check and rounding must be done before generating the + // decimal128] + ae=dn->exponent+dn->digits-1; // [0 if special] + if (dn->digits>DECIMAL128_Pmax // too many digits + || ae>DECIMAL128_Emax // likely overflow + || aeround; // use supplied rounding + decNumberPlus(&dw, dn, &dc); // (round and check) + // [this changes -0 to 0, so enforce the sign...] + dw.bits|=dn->bits&DECNEG; + status=dc.status; // save status + dn=&dw; // use the work number + } // maybe out of range + + if (dn->bits&DECSPECIAL) { // a special value + if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24; + else { // sNaN or qNaN + if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient + && (dn->digitsbits&DECNAN) targhi|=DECIMAL_NaN<<24; + else targhi|=DECIMAL_sNaN<<24; + } // a NaN + } // special + + else { // is finite + if (decNumberIsZero(dn)) { // is a zero + // set and clamp exponent + if (dn->exponent<-DECIMAL128_Bias) { + exp=0; // low clamp + status|=DEC_Clamped; + } + else { + exp=dn->exponent+DECIMAL128_Bias; // bias exponent + if (exp>DECIMAL128_Ehigh) { // top clamp + exp=DECIMAL128_Ehigh; + status|=DEC_Clamped; + } + } + comb=(exp>>9) & 0x18; // msd=0, exp top 2 bits .. + } + else { // non-zero finite number + uInt msd; // work + Int pad=0; // coefficient pad digits + + // the dn is known to fit, but it may need to be padded + exp=(uInt)(dn->exponent+DECIMAL128_Bias); // bias exponent + if (exp>DECIMAL128_Ehigh) { // fold-down case + pad=exp-DECIMAL128_Ehigh; + exp=DECIMAL128_Ehigh; // [to maximum] + status|=DEC_Clamped; + } + + // [fastpath for common case is not a win, here] + decDigitsToDPD(dn, targar, pad); + // save and clear the top digit + msd=targhi>>14; + targhi&=0x00003fff; + + // create the combination field + if (msd>=8) comb=0x18 | ((exp>>11) & 0x06) | (msd & 0x01); + else comb=((exp>>9) & 0x18) | msd; + } + targhi|=comb<<26; // add combination field .. + targhi|=(exp&0xfff)<<14; // .. and exponent continuation + } // finite + + if (dn->bits&DECNEG) targhi|=0x80000000; // add sign bit + + // now write to storage; this is endian + if (DECLITEND) { + // lo -> hi + UBFROMUI(d128->bytes, targlo); + UBFROMUI(d128->bytes+4, targml); + UBFROMUI(d128->bytes+8, targmh); + UBFROMUI(d128->bytes+12, targhi); + } + else { + // hi -> lo + UBFROMUI(d128->bytes, targhi); + UBFROMUI(d128->bytes+4, targmh); + UBFROMUI(d128->bytes+8, targml); + UBFROMUI(d128->bytes+12, targlo); + } + + if (status!=0) decContextSetStatus(set, status); // pass on status + // decimal128Show(d128); + return d128; + } // decimal128FromNumber + +/* ------------------------------------------------------------------ */ +/* decimal128ToNumber -- convert decimal128 to decNumber */ +/* d128 is the source decimal128 */ +/* dn is the target number, with appropriate space */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decNumber * decimal128ToNumber(const decimal128 *d128, decNumber *dn) { + uInt msd; // coefficient MSD + uInt exp; // exponent top two bits + uInt comb; // combination field + Int need; // work + uInt uiwork; // for macros + uInt sourar[4]; // source 128-bit + #define sourhi sourar[3] // name the word with the sign + #define sourmh sourar[2] // and the mid-high word + #define sourml sourar[1] // and the mod-low word + #define sourlo sourar[0] // and the lowest word + + // load source from storage; this is endian + if (DECLITEND) { + sourlo=UBTOUI(d128->bytes ); // directly load the low int + sourml=UBTOUI(d128->bytes+4 ); // then the mid-low + sourmh=UBTOUI(d128->bytes+8 ); // then the mid-high + sourhi=UBTOUI(d128->bytes+12); // then the high int + } + else { + sourhi=UBTOUI(d128->bytes ); // directly load the high int + sourmh=UBTOUI(d128->bytes+4 ); // then the mid-high + sourml=UBTOUI(d128->bytes+8 ); // then the mid-low + sourlo=UBTOUI(d128->bytes+12); // then the low int + } + + comb=(sourhi>>26)&0x1f; // combination field + + decNumberZero(dn); // clean number + if (sourhi&0x80000000) dn->bits=DECNEG; // set sign if negative + + msd=COMBMSD[comb]; // decode the combination field + exp=COMBEXP[comb]; // .. + + if (exp==3) { // is a special + if (msd==0) { + dn->bits|=DECINF; + return dn; // no coefficient needed + } + else if (sourhi&0x02000000) dn->bits|=DECSNAN; + else dn->bits|=DECNAN; + msd=0; // no top digit + } + else { // is a finite number + dn->exponent=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; // unbiased + } + + // get the coefficient + sourhi&=0x00003fff; // clean coefficient continuation + if (msd) { // non-zero msd + sourhi|=msd<<14; // prefix to coefficient + need=12; // process 12 declets + } + else { // msd=0 + if (sourhi) need=11; // declets to process + else if (sourmh) need=10; + else if (sourml) need=7; + else if (sourlo) need=4; + else return dn; // easy: coefficient is 0 + } //msd=0 + + decDigitsFromDPD(dn, sourar, need); // process declets + // decNumberShow(dn); + return dn; + } // decimal128ToNumber + +/* ------------------------------------------------------------------ */ +/* to-scientific-string -- conversion to numeric string */ +/* to-engineering-string -- conversion to numeric string */ +/* */ +/* decimal128ToString(d128, string); */ +/* decimal128ToEngString(d128, string); */ +/* */ +/* d128 is the decimal128 format number to convert */ +/* string is the string where the result will be laid out */ +/* */ +/* string must be at least 24 characters */ +/* */ +/* No error is possible, and no status can be set. */ +/* ------------------------------------------------------------------ */ +char * decimal128ToEngString(const decimal128 *d128, char *string){ + decNumber dn; // work + decimal128ToNumber(d128, &dn); + decNumberToEngString(&dn, string); + return string; + } // decimal128ToEngString + +char * decimal128ToString(const decimal128 *d128, char *string){ + uInt msd; // coefficient MSD + Int exp; // exponent top two bits or full + uInt comb; // combination field + char *cstart; // coefficient start + char *c; // output pointer in string + const uByte *u; // work + char *s, *t; // .. (source, target) + Int dpd; // .. + Int pre, e; // .. + uInt uiwork; // for macros + + uInt sourar[4]; // source 128-bit + #define sourhi sourar[3] // name the word with the sign + #define sourmh sourar[2] // and the mid-high word + #define sourml sourar[1] // and the mod-low word + #define sourlo sourar[0] // and the lowest word + + // load source from storage; this is endian + if (DECLITEND) { + sourlo=UBTOUI(d128->bytes ); // directly load the low int + sourml=UBTOUI(d128->bytes+4 ); // then the mid-low + sourmh=UBTOUI(d128->bytes+8 ); // then the mid-high + sourhi=UBTOUI(d128->bytes+12); // then the high int + } + else { + sourhi=UBTOUI(d128->bytes ); // directly load the high int + sourmh=UBTOUI(d128->bytes+4 ); // then the mid-high + sourml=UBTOUI(d128->bytes+8 ); // then the mid-low + sourlo=UBTOUI(d128->bytes+12); // then the low int + } + + c=string; // where result will go + if (((Int)sourhi)<0) *c++='-'; // handle sign + + comb=(sourhi>>26)&0x1f; // combination field + msd=COMBMSD[comb]; // decode the combination field + exp=COMBEXP[comb]; // .. + + if (exp==3) { + if (msd==0) { // infinity + strcpy(c, "Inf"); + strcpy(c+3, "inity"); + return string; // easy + } + if (sourhi&0x02000000) *c++='s'; // sNaN + strcpy(c, "NaN"); // complete word + c+=3; // step past + if (sourlo==0 && sourml==0 && sourmh==0 + && (sourhi&0x0003ffff)==0) return string; // zero payload + // otherwise drop through to add integer; set correct exp + exp=0; msd=0; // setup for following code + } + else exp=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; // unbiased + + // convert 34 digits of significand to characters + cstart=c; // save start of coefficient + if (msd) *c++='0'+(char)msd; // non-zero most significant digit + + // Now decode the declets. After extracting each one, it is + // decoded to binary and then to a 4-char sequence by table lookup; + // the 4-chars are a 1-char length (significant digits, except 000 + // has length 0). This allows us to left-align the first declet + // with non-zero content, then remaining ones are full 3-char + // length. We use fixed-length memcpys because variable-length + // causes a subroutine call in GCC. (These are length 4 for speed + // and are safe because the array has an extra terminator byte.) + #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ + if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ + else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} + dpd=(sourhi>>4)&0x3ff; // declet 1 + dpd2char; + dpd=((sourhi&0xf)<<6) | (sourmh>>26); // declet 2 + dpd2char; + dpd=(sourmh>>16)&0x3ff; // declet 3 + dpd2char; + dpd=(sourmh>>6)&0x3ff; // declet 4 + dpd2char; + dpd=((sourmh&0x3f)<<4) | (sourml>>28); // declet 5 + dpd2char; + dpd=(sourml>>18)&0x3ff; // declet 6 + dpd2char; + dpd=(sourml>>8)&0x3ff; // declet 7 + dpd2char; + dpd=((sourml&0xff)<<2) | (sourlo>>30); // declet 8 + dpd2char; + dpd=(sourlo>>20)&0x3ff; // declet 9 + dpd2char; + dpd=(sourlo>>10)&0x3ff; // declet 10 + dpd2char; + dpd=(sourlo)&0x3ff; // declet 11 + dpd2char; + + if (c==cstart) *c++='0'; // all zeros -- make 0 + + if (exp==0) { // integer or NaN case -- easy + *c='\0'; // terminate + return string; + } + + /* non-0 exponent */ + e=0; // assume no E + pre=c-cstart+exp; + // [here, pre-exp is the digits count (==1 for zero)] + if (exp>0 || pre<-5) { // need exponential form + e=pre-1; // calculate E value + pre=1; // assume one digit before '.' + } // exponential form + + /* modify the coefficient, adding 0s, '.', and E+nn as needed */ + s=c-1; // source (LSD) + if (pre>0) { // ddd.ddd (plain), perhaps with E + char *dotat=cstart+pre; + if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap + *t='.'; // insert the dot + c++; // length increased by one + } + + // finally add the E-part, if needed; it will never be 0, and has + // a maximum length of 4 digits + if (e!=0) { + *c++='E'; // starts with E + *c++='+'; // assume positive + if (e<0) { + *(c-1)='-'; // oops, need '-' + e=-e; // uInt, please + } + if (e<1000) { // 3 (or fewer) digits case + u=&BIN2CHAR[e*4]; // -> length byte + memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] + c+=*u; // bump pointer appropriately + } + else { // 4-digits + Int thou=((e>>3)*1049)>>17; // e/1000 + Int rem=e-(1000*thou); // e%1000 + *c++='0'+(char)thou; + u=&BIN2CHAR[rem*4]; // -> length byte + memcpy(c, u+1, 4); // copy fixed 3+1 characters [is safe] + c+=3; // bump pointer, always 3 digits + } + } + *c='\0'; // add terminator + //printf("res %s\n", string); + return string; + } // pre>0 + + /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ + t=c+1-pre; + *(t+1)='\0'; // can add terminator now + for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right + c=cstart; + *c++='0'; // always starts with 0. + *c++='.'; + for (; pre<0; pre++) *c++='0'; // add any 0's after '.' + //printf("res %s\n", string); + return string; + } // decimal128ToString + +/* ------------------------------------------------------------------ */ +/* to-number -- conversion from numeric string */ +/* */ +/* decimal128FromString(result, string, set); */ +/* */ +/* result is the decimal128 format number which gets the result of */ +/* the conversion */ +/* *string is the character string which should contain a valid */ +/* number (which may be a special value) */ +/* set is the context */ +/* */ +/* The context is supplied to this routine is used for error handling */ +/* (setting of status and traps) and for the rounding mode, only. */ +/* If an error occurs, the result will be a valid decimal128 NaN. */ +/* ------------------------------------------------------------------ */ +decimal128 * decimal128FromString(decimal128 *result, const char *string, + decContext *set) { + decContext dc; // work + decNumber dn; // .. + + decContextDefault(&dc, DEC_INIT_DECIMAL128); // no traps, please + dc.round=set->round; // use supplied rounding + + decNumberFromString(&dn, string, &dc); // will round if needed + decimal128FromNumber(result, &dn, &dc); + if (dc.status!=0) { // something happened + decContextSetStatus(set, dc.status); // .. pass it on + } + return result; + } // decimal128FromString + +/* ------------------------------------------------------------------ */ +/* decimal128IsCanonical -- test whether encoding is canonical */ +/* d128 is the source decimal128 */ +/* returns 1 if the encoding of d128 is canonical, 0 otherwise */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +uInt decimal128IsCanonical(const decimal128 *d128) { + decNumber dn; // work + decimal128 canon; // .. + decContext dc; // .. + decContextDefault(&dc, DEC_INIT_DECIMAL128); + decimal128ToNumber(d128, &dn); + decimal128FromNumber(&canon, &dn, &dc);// canon will now be canonical + return memcmp(d128, &canon, DECIMAL128_Bytes)==0; + } // decimal128IsCanonical + +/* ------------------------------------------------------------------ */ +/* decimal128Canonical -- copy an encoding, ensuring it is canonical */ +/* d128 is the source decimal128 */ +/* result is the target (may be the same decimal128) */ +/* returns result */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decimal128 * decimal128Canonical(decimal128 *result, const decimal128 *d128) { + decNumber dn; // work + decContext dc; // .. + decContextDefault(&dc, DEC_INIT_DECIMAL128); + decimal128ToNumber(d128, &dn); + decimal128FromNumber(result, &dn, &dc);// result will now be canonical + return result; + } // decimal128Canonical + +#if DECTRACE || DECCHECK +/* Macros for accessing decimal128 fields. These assume the argument + is a reference (pointer) to the decimal128 structure, and the + decimal128 is in network byte order (big-endian) */ +// Get sign +#define decimal128Sign(d) ((unsigned)(d)->bytes[0]>>7) + +// Get combination field +#define decimal128Comb(d) (((d)->bytes[0] & 0x7c)>>2) + +// Get exponent continuation [does not remove bias] +#define decimal128ExpCon(d) ((((d)->bytes[0] & 0x03)<<10) \ + | ((unsigned)(d)->bytes[1]<<2) \ + | ((unsigned)(d)->bytes[2]>>6)) + +// Set sign [this assumes sign previously 0] +#define decimal128SetSign(d, b) { \ + (d)->bytes[0]|=((unsigned)(b)<<7);} + +// Set exponent continuation [does not apply bias] +// This assumes range has been checked and exponent previously 0; +// type of exponent must be unsigned +#define decimal128SetExpCon(d, e) { \ + (d)->bytes[0]|=(uByte)((e)>>10); \ + (d)->bytes[1] =(uByte)(((e)&0x3fc)>>2); \ + (d)->bytes[2]|=(uByte)(((e)&0x03)<<6);} + +/* ------------------------------------------------------------------ */ +/* decimal128Show -- display a decimal128 in hexadecimal [debug aid] */ +/* d128 -- the number to show */ +/* ------------------------------------------------------------------ */ +// Also shows sign/cob/expconfields extracted +void decimal128Show(const decimal128 *d128) { + char buf[DECIMAL128_Bytes*2+1]; + Int i, j=0; + + if (DECLITEND) { + for (i=0; ibytes[15-i]); + } + printf(" D128> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, + d128->bytes[15]>>7, (d128->bytes[15]>>2)&0x1f, + ((d128->bytes[15]&0x3)<<10)|(d128->bytes[14]<<2)| + (d128->bytes[13]>>6)); + } + else { + for (i=0; ibytes[i]); + } + printf(" D128> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, + decimal128Sign(d128), decimal128Comb(d128), + decimal128ExpCon(d128)); + } + } // decimal128Show +#endif diff --git a/extern/decNumber/decimal128.h b/extern/decNumber/decimal128.h new file mode 100644 index 0000000000..df72acf82b --- /dev/null +++ b/extern/decNumber/decimal128.h @@ -0,0 +1,81 @@ +/* ------------------------------------------------------------------ */ +/* Decimal 128-bit format module header */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ + +#if !defined(DECIMAL128) + #define DECIMAL128 + #define DEC128NAME "decimal128" /* Short name */ + #define DEC128FULLNAME "Decimal 128-bit Number" /* Verbose name */ + #define DEC128AUTHOR "Mike Cowlishaw" /* Who to blame */ + + /* parameters for decimal128s */ + #define DECIMAL128_Bytes 16 /* length */ + #define DECIMAL128_Pmax 34 /* maximum precision (digits) */ + #define DECIMAL128_Emax 6144 /* maximum adjusted exponent */ + #define DECIMAL128_Emin -6143 /* minimum adjusted exponent */ + #define DECIMAL128_Bias 6176 /* bias for the exponent */ + #define DECIMAL128_String 43 /* maximum string length, +1 */ + #define DECIMAL128_EconL 12 /* exp. continuation length */ + /* highest biased exponent (Elimit-1) */ + #define DECIMAL128_Ehigh (DECIMAL128_Emax+DECIMAL128_Bias-DECIMAL128_Pmax+1) + + /* check enough digits, if pre-defined */ + #if defined(DECNUMDIGITS) + #if (DECNUMDIGITS=34 for safe use + #endif + #endif + + #ifndef DECNUMDIGITS + #define DECNUMDIGITS DECIMAL128_Pmax /* size if not already defined*/ + #endif + #ifndef DECNUMBER + #include "decNumber.h" /* context and number library */ + #endif + + /* Decimal 128-bit type, accessible by bytes */ + typedef struct { + uint8_t bytes[DECIMAL128_Bytes]; /* decimal128: 1, 5, 12, 110 bits*/ + } decimal128; + + /* special values [top byte excluding sign bit; last two bits are */ + /* don't-care for Infinity on input, last bit don't-care for NaN] */ + #if !defined(DECIMAL_NaN) + #define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */ + #define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */ + #define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */ + #endif + + /* ---------------------------------------------------------------- */ + /* Routines */ + /* ---------------------------------------------------------------- */ + /* String conversions */ + decimal128 * decimal128FromString(decimal128 *, const char *, decContext *); + char * decimal128ToString(const decimal128 *, char *); + char * decimal128ToEngString(const decimal128 *, char *); + + /* decNumber conversions */ + decimal128 * decimal128FromNumber(decimal128 *, const decNumber *, + decContext *); + decNumber * decimal128ToNumber(const decimal128 *, decNumber *); + + /* Format-dependent utilities */ + uint32_t decimal128IsCanonical(const decimal128 *); + decimal128 * decimal128Canonical(decimal128 *, const decimal128 *); + +#endif diff --git a/extern/decNumber/decimal32.c b/extern/decNumber/decimal32.c new file mode 100644 index 0000000000..2fad512085 --- /dev/null +++ b/extern/decNumber/decimal32.c @@ -0,0 +1,476 @@ +/* ------------------------------------------------------------------ */ +/* Decimal 32-bit format module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises the routines for decimal32 format numbers. */ +/* Conversions are supplied to and from decNumber and String. */ +/* */ +/* This is used when decNumber provides operations, either for all */ +/* operations or as a proxy between decNumber and decSingle. */ +/* */ +/* Error handling is the same as decNumber (qv.). */ +/* ------------------------------------------------------------------ */ +#include // [for memset/memcpy] +#include // [for printf] + +#define DECNUMDIGITS 7 // make decNumbers with space for 7 +#include "decNumber.h" // base number library +#include "decNumberLocal.h" // decNumber local types, etc. +#include "decimal32.h" // our primary include + +/* Utility tables and routines [in decimal64.c] */ +// DPD2BIN and the reverse are renamed to prevent link-time conflict +// if decQuad is also built in the same executable +#define DPD2BIN DPD2BINx +#define BIN2DPD BIN2DPDx +extern const uInt COMBEXP[32], COMBMSD[32]; +extern const uShort DPD2BIN[1024]; +extern const uShort BIN2DPD[1000]; +extern const uByte BIN2CHAR[4001]; + +extern void decDigitsToDPD(const decNumber *, uInt *, Int); +extern void decDigitsFromDPD(decNumber *, const uInt *, Int); + +#if DECTRACE || DECCHECK +void decimal32Show(const decimal32 *); // for debug +extern void decNumberShow(const decNumber *); // .. +#endif + +/* Useful macro */ +// Clear a structure (e.g., a decNumber) +#define DEC_clear(d) memset(d, 0, sizeof(*d)) + +/* ------------------------------------------------------------------ */ +/* decimal32FromNumber -- convert decNumber to decimal32 */ +/* */ +/* ds is the target decimal32 */ +/* dn is the source number (assumed valid) */ +/* set is the context, used only for reporting errors */ +/* */ +/* The set argument is used only for status reporting and for the */ +/* rounding mode (used if the coefficient is more than DECIMAL32_Pmax */ +/* digits or an overflow is detected). If the exponent is out of the */ +/* valid range then Overflow or Underflow will be raised. */ +/* After Underflow a subnormal result is possible. */ +/* */ +/* DEC_Clamped is set if the number has to be 'folded down' to fit, */ +/* by reducing its exponent and multiplying the coefficient by a */ +/* power of ten, or if the exponent on a zero had to be clamped. */ +/* ------------------------------------------------------------------ */ +decimal32 * decimal32FromNumber(decimal32 *d32, const decNumber *dn, + decContext *set) { + uInt status=0; // status accumulator + Int ae; // adjusted exponent + decNumber dw; // work + decContext dc; // .. + uInt comb, exp; // .. + uInt uiwork; // for macros + uInt targ=0; // target 32-bit + + // If the number has too many digits, or the exponent could be + // out of range then reduce the number under the appropriate + // constraints. This could push the number to Infinity or zero, + // so this check and rounding must be done before generating the + // decimal32] + ae=dn->exponent+dn->digits-1; // [0 if special] + if (dn->digits>DECIMAL32_Pmax // too many digits + || ae>DECIMAL32_Emax // likely overflow + || aeround; // use supplied rounding + decNumberPlus(&dw, dn, &dc); // (round and check) + // [this changes -0 to 0, so enforce the sign...] + dw.bits|=dn->bits&DECNEG; + status=dc.status; // save status + dn=&dw; // use the work number + } // maybe out of range + + if (dn->bits&DECSPECIAL) { // a special value + if (dn->bits&DECINF) targ=DECIMAL_Inf<<24; + else { // sNaN or qNaN + if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient + && (dn->digitsbits&DECNAN) targ|=DECIMAL_NaN<<24; + else targ|=DECIMAL_sNaN<<24; + } // a NaN + } // special + + else { // is finite + if (decNumberIsZero(dn)) { // is a zero + // set and clamp exponent + if (dn->exponent<-DECIMAL32_Bias) { + exp=0; // low clamp + status|=DEC_Clamped; + } + else { + exp=dn->exponent+DECIMAL32_Bias; // bias exponent + if (exp>DECIMAL32_Ehigh) { // top clamp + exp=DECIMAL32_Ehigh; + status|=DEC_Clamped; + } + } + comb=(exp>>3) & 0x18; // msd=0, exp top 2 bits .. + } + else { // non-zero finite number + uInt msd; // work + Int pad=0; // coefficient pad digits + + // the dn is known to fit, but it may need to be padded + exp=(uInt)(dn->exponent+DECIMAL32_Bias); // bias exponent + if (exp>DECIMAL32_Ehigh) { // fold-down case + pad=exp-DECIMAL32_Ehigh; + exp=DECIMAL32_Ehigh; // [to maximum] + status|=DEC_Clamped; + } + + // fastpath common case + if (DECDPUN==3 && pad==0) { + targ=BIN2DPD[dn->lsu[0]]; + if (dn->digits>3) targ|=(uInt)(BIN2DPD[dn->lsu[1]])<<10; + msd=(dn->digits==7 ? dn->lsu[2] : 0); + } + else { // general case + decDigitsToDPD(dn, &targ, pad); + // save and clear the top digit + msd=targ>>20; + targ&=0x000fffff; + } + + // create the combination field + if (msd>=8) comb=0x18 | ((exp>>5) & 0x06) | (msd & 0x01); + else comb=((exp>>3) & 0x18) | msd; + } + targ|=comb<<26; // add combination field .. + targ|=(exp&0x3f)<<20; // .. and exponent continuation + } // finite + + if (dn->bits&DECNEG) targ|=0x80000000; // add sign bit + + // now write to storage; this is endian + UBFROMUI(d32->bytes, targ); // directly store the int + + if (status!=0) decContextSetStatus(set, status); // pass on status + // decimal32Show(d32); + return d32; + } // decimal32FromNumber + +/* ------------------------------------------------------------------ */ +/* decimal32ToNumber -- convert decimal32 to decNumber */ +/* d32 is the source decimal32 */ +/* dn is the target number, with appropriate space */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decNumber * decimal32ToNumber(const decimal32 *d32, decNumber *dn) { + uInt msd; // coefficient MSD + uInt exp; // exponent top two bits + uInt comb; // combination field + uInt sour; // source 32-bit + uInt uiwork; // for macros + + // load source from storage; this is endian + sour=UBTOUI(d32->bytes); // directly load the int + + comb=(sour>>26)&0x1f; // combination field + + decNumberZero(dn); // clean number + if (sour&0x80000000) dn->bits=DECNEG; // set sign if negative + + msd=COMBMSD[comb]; // decode the combination field + exp=COMBEXP[comb]; // .. + + if (exp==3) { // is a special + if (msd==0) { + dn->bits|=DECINF; + return dn; // no coefficient needed + } + else if (sour&0x02000000) dn->bits|=DECSNAN; + else dn->bits|=DECNAN; + msd=0; // no top digit + } + else { // is a finite number + dn->exponent=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; // unbiased + } + + // get the coefficient + sour&=0x000fffff; // clean coefficient continuation + if (msd) { // non-zero msd + sour|=msd<<20; // prefix to coefficient + decDigitsFromDPD(dn, &sour, 3); // process 3 declets + return dn; + } + // msd=0 + if (!sour) return dn; // easy: coefficient is 0 + if (sour&0x000ffc00) // need 2 declets? + decDigitsFromDPD(dn, &sour, 2); // process 2 declets + else + decDigitsFromDPD(dn, &sour, 1); // process 1 declet + return dn; + } // decimal32ToNumber + +/* ------------------------------------------------------------------ */ +/* to-scientific-string -- conversion to numeric string */ +/* to-engineering-string -- conversion to numeric string */ +/* */ +/* decimal32ToString(d32, string); */ +/* decimal32ToEngString(d32, string); */ +/* */ +/* d32 is the decimal32 format number to convert */ +/* string is the string where the result will be laid out */ +/* */ +/* string must be at least 24 characters */ +/* */ +/* No error is possible, and no status can be set. */ +/* ------------------------------------------------------------------ */ +char * decimal32ToEngString(const decimal32 *d32, char *string){ + decNumber dn; // work + decimal32ToNumber(d32, &dn); + decNumberToEngString(&dn, string); + return string; + } // decimal32ToEngString + +char * decimal32ToString(const decimal32 *d32, char *string){ + uInt msd; // coefficient MSD + Int exp; // exponent top two bits or full + uInt comb; // combination field + char *cstart; // coefficient start + char *c; // output pointer in string + const uByte *u; // work + char *s, *t; // .. (source, target) + Int dpd; // .. + Int pre, e; // .. + uInt uiwork; // for macros + uInt sour; // source 32-bit + + // load source from storage; this is endian + sour=UBTOUI(d32->bytes); // directly load the int + + c=string; // where result will go + if (((Int)sour)<0) *c++='-'; // handle sign + + comb=(sour>>26)&0x1f; // combination field + msd=COMBMSD[comb]; // decode the combination field + exp=COMBEXP[comb]; // .. + + if (exp==3) { + if (msd==0) { // infinity + strcpy(c, "Inf"); + strcpy(c+3, "inity"); + return string; // easy + } + if (sour&0x02000000) *c++='s'; // sNaN + strcpy(c, "NaN"); // complete word + c+=3; // step past + if ((sour&0x000fffff)==0) return string; // zero payload + // otherwise drop through to add integer; set correct exp + exp=0; msd=0; // setup for following code + } + else exp=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; // unbiased + + // convert 7 digits of significand to characters + cstart=c; // save start of coefficient + if (msd) *c++='0'+(char)msd; // non-zero most significant digit + + // Now decode the declets. After extracting each one, it is + // decoded to binary and then to a 4-char sequence by table lookup; + // the 4-chars are a 1-char length (significant digits, except 000 + // has length 0). This allows us to left-align the first declet + // with non-zero content, then remaining ones are full 3-char + // length. We use fixed-length memcpys because variable-length + // causes a subroutine call in GCC. (These are length 4 for speed + // and are safe because the array has an extra terminator byte.) + #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ + if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ + else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} + + dpd=(sour>>10)&0x3ff; // declet 1 + dpd2char; + dpd=(sour)&0x3ff; // declet 2 + dpd2char; + + if (c==cstart) *c++='0'; // all zeros -- make 0 + + if (exp==0) { // integer or NaN case -- easy + *c='\0'; // terminate + return string; + } + + /* non-0 exponent */ + e=0; // assume no E + pre=c-cstart+exp; + // [here, pre-exp is the digits count (==1 for zero)] + if (exp>0 || pre<-5) { // need exponential form + e=pre-1; // calculate E value + pre=1; // assume one digit before '.' + } // exponential form + + /* modify the coefficient, adding 0s, '.', and E+nn as needed */ + s=c-1; // source (LSD) + if (pre>0) { // ddd.ddd (plain), perhaps with E + char *dotat=cstart+pre; + if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap + *t='.'; // insert the dot + c++; // length increased by one + } + + // finally add the E-part, if needed; it will never be 0, and has + // a maximum length of 3 digits (E-101 case) + if (e!=0) { + *c++='E'; // starts with E + *c++='+'; // assume positive + if (e<0) { + *(c-1)='-'; // oops, need '-' + e=-e; // uInt, please + } + u=&BIN2CHAR[e*4]; // -> length byte + memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] + c+=*u; // bump pointer appropriately + } + *c='\0'; // add terminator + //printf("res %s\n", string); + return string; + } // pre>0 + + /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ + t=c+1-pre; + *(t+1)='\0'; // can add terminator now + for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right + c=cstart; + *c++='0'; // always starts with 0. + *c++='.'; + for (; pre<0; pre++) *c++='0'; // add any 0's after '.' + //printf("res %s\n", string); + return string; + } // decimal32ToString + +/* ------------------------------------------------------------------ */ +/* to-number -- conversion from numeric string */ +/* */ +/* decimal32FromString(result, string, set); */ +/* */ +/* result is the decimal32 format number which gets the result of */ +/* the conversion */ +/* *string is the character string which should contain a valid */ +/* number (which may be a special value) */ +/* set is the context */ +/* */ +/* The context is supplied to this routine is used for error handling */ +/* (setting of status and traps) and for the rounding mode, only. */ +/* If an error occurs, the result will be a valid decimal32 NaN. */ +/* ------------------------------------------------------------------ */ +decimal32 * decimal32FromString(decimal32 *result, const char *string, + decContext *set) { + decContext dc; // work + decNumber dn; // .. + + decContextDefault(&dc, DEC_INIT_DECIMAL32); // no traps, please + dc.round=set->round; // use supplied rounding + + decNumberFromString(&dn, string, &dc); // will round if needed + decimal32FromNumber(result, &dn, &dc); + if (dc.status!=0) { // something happened + decContextSetStatus(set, dc.status); // .. pass it on + } + return result; + } // decimal32FromString + +/* ------------------------------------------------------------------ */ +/* decimal32IsCanonical -- test whether encoding is canonical */ +/* d32 is the source decimal32 */ +/* returns 1 if the encoding of d32 is canonical, 0 otherwise */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +uInt decimal32IsCanonical(const decimal32 *d32) { + decNumber dn; // work + decimal32 canon; // .. + decContext dc; // .. + decContextDefault(&dc, DEC_INIT_DECIMAL32); + decimal32ToNumber(d32, &dn); + decimal32FromNumber(&canon, &dn, &dc);// canon will now be canonical + return memcmp(d32, &canon, DECIMAL32_Bytes)==0; + } // decimal32IsCanonical + +/* ------------------------------------------------------------------ */ +/* decimal32Canonical -- copy an encoding, ensuring it is canonical */ +/* d32 is the source decimal32 */ +/* result is the target (may be the same decimal32) */ +/* returns result */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decimal32 * decimal32Canonical(decimal32 *result, const decimal32 *d32) { + decNumber dn; // work + decContext dc; // .. + decContextDefault(&dc, DEC_INIT_DECIMAL32); + decimal32ToNumber(d32, &dn); + decimal32FromNumber(result, &dn, &dc);// result will now be canonical + return result; + } // decimal32Canonical + +#if DECTRACE || DECCHECK +/* Macros for accessing decimal32 fields. These assume the argument + is a reference (pointer) to the decimal32 structure, and the + decimal32 is in network byte order (big-endian) */ +// Get sign +#define decimal32Sign(d) ((unsigned)(d)->bytes[0]>>7) + +// Get combination field +#define decimal32Comb(d) (((d)->bytes[0] & 0x7c)>>2) + +// Get exponent continuation [does not remove bias] +#define decimal32ExpCon(d) ((((d)->bytes[0] & 0x03)<<4) \ + | ((unsigned)(d)->bytes[1]>>4)) + +// Set sign [this assumes sign previously 0] +#define decimal32SetSign(d, b) { \ + (d)->bytes[0]|=((unsigned)(b)<<7);} + +// Set exponent continuation [does not apply bias] +// This assumes range has been checked and exponent previously 0; +// type of exponent must be unsigned +#define decimal32SetExpCon(d, e) { \ + (d)->bytes[0]|=(uByte)((e)>>4); \ + (d)->bytes[1]|=(uByte)(((e)&0x0F)<<4);} + +/* ------------------------------------------------------------------ */ +/* decimal32Show -- display a decimal32 in hexadecimal [debug aid] */ +/* d32 -- the number to show */ +/* ------------------------------------------------------------------ */ +// Also shows sign/cob/expconfields extracted - valid bigendian only +void decimal32Show(const decimal32 *d32) { + char buf[DECIMAL32_Bytes*2+1]; + Int i, j=0; + + if (DECLITEND) { + for (i=0; ibytes[3-i]); + } + printf(" D32> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, + d32->bytes[3]>>7, (d32->bytes[3]>>2)&0x1f, + ((d32->bytes[3]&0x3)<<4)| (d32->bytes[2]>>4)); + } + else { + for (i=0; ibytes[i]); + } + printf(" D32> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, + decimal32Sign(d32), decimal32Comb(d32), decimal32ExpCon(d32)); + } + } // decimal32Show +#endif diff --git a/extern/decNumber/decimal32.h b/extern/decNumber/decimal32.h new file mode 100644 index 0000000000..faaf9a96e2 --- /dev/null +++ b/extern/decNumber/decimal32.h @@ -0,0 +1,81 @@ +/* ------------------------------------------------------------------ */ +/* Decimal 32-bit format module header */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2006. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ + +#if !defined(DECIMAL32) + #define DECIMAL32 + #define DEC32NAME "decimal32" /* Short name */ + #define DEC32FULLNAME "Decimal 32-bit Number" /* Verbose name */ + #define DEC32AUTHOR "Mike Cowlishaw" /* Who to blame */ + + /* parameters for decimal32s */ + #define DECIMAL32_Bytes 4 /* length */ + #define DECIMAL32_Pmax 7 /* maximum precision (digits) */ + #define DECIMAL32_Emax 96 /* maximum adjusted exponent */ + #define DECIMAL32_Emin -95 /* minimum adjusted exponent */ + #define DECIMAL32_Bias 101 /* bias for the exponent */ + #define DECIMAL32_String 15 /* maximum string length, +1 */ + #define DECIMAL32_EconL 6 /* exp. continuation length */ + /* highest biased exponent (Elimit-1) */ + #define DECIMAL32_Ehigh (DECIMAL32_Emax+DECIMAL32_Bias-DECIMAL32_Pmax+1) + + /* check enough digits, if pre-defined */ + #if defined(DECNUMDIGITS) + #if (DECNUMDIGITS=7 for safe use + #endif + #endif + + #ifndef DECNUMDIGITS + #define DECNUMDIGITS DECIMAL32_Pmax /* size if not already defined*/ + #endif + #ifndef DECNUMBER + #include "decNumber.h" /* context and number library */ + #endif + + /* Decimal 32-bit type, accessible by bytes */ + typedef struct { + uint8_t bytes[DECIMAL32_Bytes]; /* decimal32: 1, 5, 6, 20 bits*/ + } decimal32; + + /* special values [top byte excluding sign bit; last two bits are */ + /* don't-care for Infinity on input, last bit don't-care for NaN] */ + #if !defined(DECIMAL_NaN) + #define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */ + #define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */ + #define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */ + #endif + + /* ---------------------------------------------------------------- */ + /* Routines */ + /* ---------------------------------------------------------------- */ + /* String conversions */ + decimal32 * decimal32FromString(decimal32 *, const char *, decContext *); + char * decimal32ToString(const decimal32 *, char *); + char * decimal32ToEngString(const decimal32 *, char *); + + /* decNumber conversions */ + decimal32 * decimal32FromNumber(decimal32 *, const decNumber *, + decContext *); + decNumber * decimal32ToNumber(const decimal32 *, decNumber *); + + /* Format-dependent utilities */ + uint32_t decimal32IsCanonical(const decimal32 *); + decimal32 * decimal32Canonical(decimal32 *, const decimal32 *); + +#endif diff --git a/extern/decNumber/decimal64.c b/extern/decNumber/decimal64.c new file mode 100644 index 0000000000..4bfc5fb6b5 --- /dev/null +++ b/extern/decNumber/decimal64.c @@ -0,0 +1,839 @@ +/* ------------------------------------------------------------------ */ +/* Decimal 64-bit format module */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2009. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ +/* This module comprises the routines for decimal64 format numbers. */ +/* Conversions are supplied to and from decNumber and String. */ +/* */ +/* This is used when decNumber provides operations, either for all */ +/* operations or as a proxy between decNumber and decSingle. */ +/* */ +/* Error handling is the same as decNumber (qv.). */ +/* ------------------------------------------------------------------ */ +#include // [for memset/memcpy] +#include // [for printf] + +#define DECNUMDIGITS 16 // make decNumbers with space for 16 +#include "decNumber.h" // base number library +#include "decNumberLocal.h" // decNumber local types, etc. +#include "decimal64.h" // our primary include + +/* Utility routines and tables [in decimal64.c]; externs for C++ */ +// DPD2BIN and the reverse are renamed to prevent link-time conflict +// if decQuad is also built in the same executable +#define DPD2BIN DPD2BINx +#define BIN2DPD BIN2DPDx +extern const uInt COMBEXP[32], COMBMSD[32]; +extern const uShort DPD2BIN[1024]; +extern const uShort BIN2DPD[1000]; +extern const uByte BIN2CHAR[4001]; + +extern void decDigitsFromDPD(decNumber *, const uInt *, Int); +extern void decDigitsToDPD(const decNumber *, uInt *, Int); + +#if DECTRACE || DECCHECK +void decimal64Show(const decimal64 *); // for debug +extern void decNumberShow(const decNumber *); // .. +#endif + +/* Useful macro */ +// Clear a structure (e.g., a decNumber) +#define DEC_clear(d) memset(d, 0, sizeof(*d)) + +/* define and include the tables to use for conversions */ +#define DEC_BIN2CHAR 1 +#define DEC_DPD2BIN 1 +#define DEC_BIN2DPD 1 // used for all sizes +#include "decDPD.h" // lookup tables + +/* ------------------------------------------------------------------ */ +/* decimal64FromNumber -- convert decNumber to decimal64 */ +/* */ +/* ds is the target decimal64 */ +/* dn is the source number (assumed valid) */ +/* set is the context, used only for reporting errors */ +/* */ +/* The set argument is used only for status reporting and for the */ +/* rounding mode (used if the coefficient is more than DECIMAL64_Pmax */ +/* digits or an overflow is detected). If the exponent is out of the */ +/* valid range then Overflow or Underflow will be raised. */ +/* After Underflow a subnormal result is possible. */ +/* */ +/* DEC_Clamped is set if the number has to be 'folded down' to fit, */ +/* by reducing its exponent and multiplying the coefficient by a */ +/* power of ten, or if the exponent on a zero had to be clamped. */ +/* ------------------------------------------------------------------ */ +decimal64 * decimal64FromNumber(decimal64 *d64, const decNumber *dn, + decContext *set) { + uInt status=0; // status accumulator + Int ae; // adjusted exponent + decNumber dw; // work + decContext dc; // .. + uInt comb, exp; // .. + uInt uiwork; // for macros + uInt targar[2]={0, 0}; // target 64-bit + #define targhi targar[1] // name the word with the sign + #define targlo targar[0] // and the other + + // If the number has too many digits, or the exponent could be + // out of range then reduce the number under the appropriate + // constraints. This could push the number to Infinity or zero, + // so this check and rounding must be done before generating the + // decimal64] + ae=dn->exponent+dn->digits-1; // [0 if special] + if (dn->digits>DECIMAL64_Pmax // too many digits + || ae>DECIMAL64_Emax // likely overflow + || aeround; // use supplied rounding + decNumberPlus(&dw, dn, &dc); // (round and check) + // [this changes -0 to 0, so enforce the sign...] + dw.bits|=dn->bits&DECNEG; + status=dc.status; // save status + dn=&dw; // use the work number + } // maybe out of range + + if (dn->bits&DECSPECIAL) { // a special value + if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24; + else { // sNaN or qNaN + if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient + && (dn->digitsbits&DECNAN) targhi|=DECIMAL_NaN<<24; + else targhi|=DECIMAL_sNaN<<24; + } // a NaN + } // special + + else { // is finite + if (decNumberIsZero(dn)) { // is a zero + // set and clamp exponent + if (dn->exponent<-DECIMAL64_Bias) { + exp=0; // low clamp + status|=DEC_Clamped; + } + else { + exp=dn->exponent+DECIMAL64_Bias; // bias exponent + if (exp>DECIMAL64_Ehigh) { // top clamp + exp=DECIMAL64_Ehigh; + status|=DEC_Clamped; + } + } + comb=(exp>>5) & 0x18; // msd=0, exp top 2 bits .. + } + else { // non-zero finite number + uInt msd; // work + Int pad=0; // coefficient pad digits + + // the dn is known to fit, but it may need to be padded + exp=(uInt)(dn->exponent+DECIMAL64_Bias); // bias exponent + if (exp>DECIMAL64_Ehigh) { // fold-down case + pad=exp-DECIMAL64_Ehigh; + exp=DECIMAL64_Ehigh; // [to maximum] + status|=DEC_Clamped; + } + + // fastpath common case + if (DECDPUN==3 && pad==0) { + uInt dpd[6]={0,0,0,0,0,0}; + uInt i; + Int d=dn->digits; + for (i=0; d>0; i++, d-=3) dpd[i]=BIN2DPD[dn->lsu[i]]; + targlo =dpd[0]; + targlo|=dpd[1]<<10; + targlo|=dpd[2]<<20; + if (dn->digits>6) { + targlo|=dpd[3]<<30; + targhi =dpd[3]>>2; + targhi|=dpd[4]<<8; + } + msd=dpd[5]; // [did not really need conversion] + } + else { // general case + decDigitsToDPD(dn, targar, pad); + // save and clear the top digit + msd=targhi>>18; + targhi&=0x0003ffff; + } + + // create the combination field + if (msd>=8) comb=0x18 | ((exp>>7) & 0x06) | (msd & 0x01); + else comb=((exp>>5) & 0x18) | msd; + } + targhi|=comb<<26; // add combination field .. + targhi|=(exp&0xff)<<18; // .. and exponent continuation + } // finite + + if (dn->bits&DECNEG) targhi|=0x80000000; // add sign bit + + // now write to storage; this is now always endian + if (DECLITEND) { + // lo int then hi + UBFROMUI(d64->bytes, targar[0]); + UBFROMUI(d64->bytes+4, targar[1]); + } + else { + // hi int then lo + UBFROMUI(d64->bytes, targar[1]); + UBFROMUI(d64->bytes+4, targar[0]); + } + + if (status!=0) decContextSetStatus(set, status); // pass on status + // decimal64Show(d64); + return d64; + } // decimal64FromNumber + +/* ------------------------------------------------------------------ */ +/* decimal64ToNumber -- convert decimal64 to decNumber */ +/* d64 is the source decimal64 */ +/* dn is the target number, with appropriate space */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decNumber * decimal64ToNumber(const decimal64 *d64, decNumber *dn) { + uInt msd; // coefficient MSD + uInt exp; // exponent top two bits + uInt comb; // combination field + Int need; // work + uInt uiwork; // for macros + uInt sourar[2]; // source 64-bit + #define sourhi sourar[1] // name the word with the sign + #define sourlo sourar[0] // and the lower word + + // load source from storage; this is endian + if (DECLITEND) { + sourlo=UBTOUI(d64->bytes ); // directly load the low int + sourhi=UBTOUI(d64->bytes+4); // then the high int + } + else { + sourhi=UBTOUI(d64->bytes ); // directly load the high int + sourlo=UBTOUI(d64->bytes+4); // then the low int + } + + comb=(sourhi>>26)&0x1f; // combination field + + decNumberZero(dn); // clean number + if (sourhi&0x80000000) dn->bits=DECNEG; // set sign if negative + + msd=COMBMSD[comb]; // decode the combination field + exp=COMBEXP[comb]; // .. + + if (exp==3) { // is a special + if (msd==0) { + dn->bits|=DECINF; + return dn; // no coefficient needed + } + else if (sourhi&0x02000000) dn->bits|=DECSNAN; + else dn->bits|=DECNAN; + msd=0; // no top digit + } + else { // is a finite number + dn->exponent=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias; // unbiased + } + + // get the coefficient + sourhi&=0x0003ffff; // clean coefficient continuation + if (msd) { // non-zero msd + sourhi|=msd<<18; // prefix to coefficient + need=6; // process 6 declets + } + else { // msd=0 + if (!sourhi) { // top word 0 + if (!sourlo) return dn; // easy: coefficient is 0 + need=3; // process at least 3 declets + if (sourlo&0xc0000000) need++; // process 4 declets + // [could reduce some more, here] + } + else { // some bits in top word, msd=0 + need=4; // process at least 4 declets + if (sourhi&0x0003ff00) need++; // top declet!=0, process 5 + } + } //msd=0 + + decDigitsFromDPD(dn, sourar, need); // process declets + return dn; + } // decimal64ToNumber + + +/* ------------------------------------------------------------------ */ +/* to-scientific-string -- conversion to numeric string */ +/* to-engineering-string -- conversion to numeric string */ +/* */ +/* decimal64ToString(d64, string); */ +/* decimal64ToEngString(d64, string); */ +/* */ +/* d64 is the decimal64 format number to convert */ +/* string is the string where the result will be laid out */ +/* */ +/* string must be at least 24 characters */ +/* */ +/* No error is possible, and no status can be set. */ +/* ------------------------------------------------------------------ */ +char * decimal64ToEngString(const decimal64 *d64, char *string){ + decNumber dn; // work + decimal64ToNumber(d64, &dn); + decNumberToEngString(&dn, string); + return string; + } // decimal64ToEngString + +char * decimal64ToString(const decimal64 *d64, char *string){ + uInt msd; // coefficient MSD + Int exp; // exponent top two bits or full + uInt comb; // combination field + char *cstart; // coefficient start + char *c; // output pointer in string + const uByte *u; // work + char *s, *t; // .. (source, target) + Int dpd; // .. + Int pre, e; // .. + uInt uiwork; // for macros + + uInt sourar[2]; // source 64-bit + #define sourhi sourar[1] // name the word with the sign + #define sourlo sourar[0] // and the lower word + + // load source from storage; this is endian + if (DECLITEND) { + sourlo=UBTOUI(d64->bytes ); // directly load the low int + sourhi=UBTOUI(d64->bytes+4); // then the high int + } + else { + sourhi=UBTOUI(d64->bytes ); // directly load the high int + sourlo=UBTOUI(d64->bytes+4); // then the low int + } + + c=string; // where result will go + if (((Int)sourhi)<0) *c++='-'; // handle sign + + comb=(sourhi>>26)&0x1f; // combination field + msd=COMBMSD[comb]; // decode the combination field + exp=COMBEXP[comb]; // .. + + if (exp==3) { + if (msd==0) { // infinity + strcpy(c, "Inf"); + strcpy(c+3, "inity"); + return string; // easy + } + if (sourhi&0x02000000) *c++='s'; // sNaN + strcpy(c, "NaN"); // complete word + c+=3; // step past + if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; // zero payload + // otherwise drop through to add integer; set correct exp + exp=0; msd=0; // setup for following code + } + else exp=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias; + + // convert 16 digits of significand to characters + cstart=c; // save start of coefficient + if (msd) *c++='0'+(char)msd; // non-zero most significant digit + + // Now decode the declets. After extracting each one, it is + // decoded to binary and then to a 4-char sequence by table lookup; + // the 4-chars are a 1-char length (significant digits, except 000 + // has length 0). This allows us to left-align the first declet + // with non-zero content, then remaining ones are full 3-char + // length. We use fixed-length memcpys because variable-length + // causes a subroutine call in GCC. (These are length 4 for speed + // and are safe because the array has an extra terminator byte.) + #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ + if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ + else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} + + dpd=(sourhi>>8)&0x3ff; // declet 1 + dpd2char; + dpd=((sourhi&0xff)<<2) | (sourlo>>30); // declet 2 + dpd2char; + dpd=(sourlo>>20)&0x3ff; // declet 3 + dpd2char; + dpd=(sourlo>>10)&0x3ff; // declet 4 + dpd2char; + dpd=(sourlo)&0x3ff; // declet 5 + dpd2char; + + if (c==cstart) *c++='0'; // all zeros -- make 0 + + if (exp==0) { // integer or NaN case -- easy + *c='\0'; // terminate + return string; + } + + /* non-0 exponent */ + e=0; // assume no E + pre=c-cstart+exp; + // [here, pre-exp is the digits count (==1 for zero)] + if (exp>0 || pre<-5) { // need exponential form + e=pre-1; // calculate E value + pre=1; // assume one digit before '.' + } // exponential form + + /* modify the coefficient, adding 0s, '.', and E+nn as needed */ + s=c-1; // source (LSD) + if (pre>0) { // ddd.ddd (plain), perhaps with E + char *dotat=cstart+pre; + if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap + *t='.'; // insert the dot + c++; // length increased by one + } + + // finally add the E-part, if needed; it will never be 0, and has + // a maximum length of 3 digits + if (e!=0) { + *c++='E'; // starts with E + *c++='+'; // assume positive + if (e<0) { + *(c-1)='-'; // oops, need '-' + e=-e; // uInt, please + } + u=&BIN2CHAR[e*4]; // -> length byte + memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] + c+=*u; // bump pointer appropriately + } + *c='\0'; // add terminator + //printf("res %s\n", string); + return string; + } // pre>0 + + /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ + t=c+1-pre; + *(t+1)='\0'; // can add terminator now + for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right + c=cstart; + *c++='0'; // always starts with 0. + *c++='.'; + for (; pre<0; pre++) *c++='0'; // add any 0's after '.' + //printf("res %s\n", string); + return string; + } // decimal64ToString + +/* ------------------------------------------------------------------ */ +/* to-number -- conversion from numeric string */ +/* */ +/* decimal64FromString(result, string, set); */ +/* */ +/* result is the decimal64 format number which gets the result of */ +/* the conversion */ +/* *string is the character string which should contain a valid */ +/* number (which may be a special value) */ +/* set is the context */ +/* */ +/* The context is supplied to this routine is used for error handling */ +/* (setting of status and traps) and for the rounding mode, only. */ +/* If an error occurs, the result will be a valid decimal64 NaN. */ +/* ------------------------------------------------------------------ */ +decimal64 * decimal64FromString(decimal64 *result, const char *string, + decContext *set) { + decContext dc; // work + decNumber dn; // .. + + decContextDefault(&dc, DEC_INIT_DECIMAL64); // no traps, please + dc.round=set->round; // use supplied rounding + + decNumberFromString(&dn, string, &dc); // will round if needed + + decimal64FromNumber(result, &dn, &dc); + if (dc.status!=0) { // something happened + decContextSetStatus(set, dc.status); // .. pass it on + } + return result; + } // decimal64FromString + +/* ------------------------------------------------------------------ */ +/* decimal64IsCanonical -- test whether encoding is canonical */ +/* d64 is the source decimal64 */ +/* returns 1 if the encoding of d64 is canonical, 0 otherwise */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +uInt decimal64IsCanonical(const decimal64 *d64) { + decNumber dn; // work + decimal64 canon; // .. + decContext dc; // .. + decContextDefault(&dc, DEC_INIT_DECIMAL64); + decimal64ToNumber(d64, &dn); + decimal64FromNumber(&canon, &dn, &dc);// canon will now be canonical + return memcmp(d64, &canon, DECIMAL64_Bytes)==0; + } // decimal64IsCanonical + +/* ------------------------------------------------------------------ */ +/* decimal64Canonical -- copy an encoding, ensuring it is canonical */ +/* d64 is the source decimal64 */ +/* result is the target (may be the same decimal64) */ +/* returns result */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +decimal64 * decimal64Canonical(decimal64 *result, const decimal64 *d64) { + decNumber dn; // work + decContext dc; // .. + decContextDefault(&dc, DEC_INIT_DECIMAL64); + decimal64ToNumber(d64, &dn); + decimal64FromNumber(result, &dn, &dc);// result will now be canonical + return result; + } // decimal64Canonical + +#if DECTRACE || DECCHECK +/* Macros for accessing decimal64 fields. These assume the + argument is a reference (pointer) to the decimal64 structure, + and the decimal64 is in network byte order (big-endian) */ +// Get sign +#define decimal64Sign(d) ((unsigned)(d)->bytes[0]>>7) + +// Get combination field +#define decimal64Comb(d) (((d)->bytes[0] & 0x7c)>>2) + +// Get exponent continuation [does not remove bias] +#define decimal64ExpCon(d) ((((d)->bytes[0] & 0x03)<<6) \ + | ((unsigned)(d)->bytes[1]>>2)) + +// Set sign [this assumes sign previously 0] +#define decimal64SetSign(d, b) { \ + (d)->bytes[0]|=((unsigned)(b)<<7);} + +// Set exponent continuation [does not apply bias] +// This assumes range has been checked and exponent previously 0; +// type of exponent must be unsigned +#define decimal64SetExpCon(d, e) { \ + (d)->bytes[0]|=(uByte)((e)>>6); \ + (d)->bytes[1]|=(uByte)(((e)&0x3F)<<2);} + +/* ------------------------------------------------------------------ */ +/* decimal64Show -- display a decimal64 in hexadecimal [debug aid] */ +/* d64 -- the number to show */ +/* ------------------------------------------------------------------ */ +// Also shows sign/cob/expconfields extracted +void decimal64Show(const decimal64 *d64) { + char buf[DECIMAL64_Bytes*2+1]; + Int i, j=0; + + if (DECLITEND) { + for (i=0; ibytes[7-i]); + } + printf(" D64> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, + d64->bytes[7]>>7, (d64->bytes[7]>>2)&0x1f, + ((d64->bytes[7]&0x3)<<6)| (d64->bytes[6]>>2)); + } + else { // big-endian + for (i=0; ibytes[i]); + } + printf(" D64> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, + decimal64Sign(d64), decimal64Comb(d64), decimal64ExpCon(d64)); + } + } // decimal64Show +#endif + +/* ================================================================== */ +/* Shared utility routines and tables */ +/* ================================================================== */ +// define and include the conversion tables to use for shared code +#if DECDPUN==3 + #define DEC_DPD2BIN 1 +#else + #define DEC_DPD2BCD 1 +#endif +#include "decDPD.h" // lookup tables + +// The maximum number of decNumberUnits needed for a working copy of +// the units array is the ceiling of digits/DECDPUN, where digits is +// the maximum number of digits in any of the formats for which this +// is used. decimal128.h must not be included in this module, so, as +// a very special case, that number is defined as a literal here. +#define DECMAX754 34 +#define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN) + +/* ------------------------------------------------------------------ */ +/* Combination field lookup tables (uInts to save measurable work) */ +/* */ +/* COMBEXP - 2-bit most-significant-bits of exponent */ +/* [11 if an Infinity or NaN] */ +/* COMBMSD - 4-bit most-significant-digit */ +/* [0=Infinity, 1=NaN if COMBEXP=11] */ +/* */ +/* Both are indexed by the 5-bit combination field (0-31) */ +/* ------------------------------------------------------------------ */ +const uInt COMBEXP[32]={0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 1, 1, 2, 2, 3, 3}; +const uInt COMBMSD[32]={0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 8, 9, 8, 9, 0, 1}; + +/* ------------------------------------------------------------------ */ +/* decDigitsToDPD -- pack coefficient into DPD form */ +/* */ +/* dn is the source number (assumed valid, max DECMAX754 digits) */ +/* targ is 1, 2, or 4-element uInt array, which the caller must */ +/* have cleared to zeros */ +/* shift is the number of 0 digits to add on the right (normally 0) */ +/* */ +/* The coefficient must be known small enough to fit. The full */ +/* coefficient is copied, including the leading 'odd' digit. This */ +/* digit is retrieved and packed into the combination field by the */ +/* caller. */ +/* */ +/* The target uInts are altered only as necessary to receive the */ +/* digits of the decNumber. When more than one uInt is needed, they */ +/* are filled from left to right (that is, the uInt at offset 0 will */ +/* end up with the least-significant digits). */ +/* */ +/* shift is used for 'fold-down' padding. */ +/* */ +/* No error is possible. */ +/* ------------------------------------------------------------------ */ +#if DECDPUN<=4 +// Constant multipliers for divide-by-power-of five using reciprocal +// multiply, after removing powers of 2 by shifting, and final shift +// of 17 [we only need up to **4] +static const uInt multies[]={131073, 26215, 5243, 1049, 210}; +// QUOT10 -- macro to return the quotient of unit u divided by 10**n +#define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17) +#endif +void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) { + Int cut; // work + Int n; // output bunch counter + Int digits=dn->digits; // digit countdown + uInt dpd; // densely packed decimal value + uInt bin; // binary value 0-999 + uInt *uout=targ; // -> current output uInt + uInt uoff=0; // -> current output offset [from right] + const Unit *inu=dn->lsu; // -> current input unit + Unit uar[DECMAXUNITS]; // working copy of units, iff shifted + #if DECDPUN!=3 // not fast path + Unit in; // current unit + #endif + + if (shift!=0) { // shift towards most significant required + // shift the units array to the left by pad digits and copy + // [this code is a special case of decShiftToMost, which could + // be used instead if exposed and the array were copied first] + const Unit *source; // .. + Unit *target, *first; // .. + uInt next=0; // work + + source=dn->lsu+D2U(digits)-1; // where msu comes from + target=uar+D2U(digits)-1+D2U(shift);// where upper part of first cut goes + cut=DECDPUN-MSUDIGITS(shift); // where to slice + if (cut==0) { // unit-boundary case + for (; source>=dn->lsu; source--, target--) *target=*source; + } + else { + first=uar+D2U(digits+shift)-1; // where msu will end up + for (; source>=dn->lsu; source--, target--) { + // split the source Unit and accumulate remainder for next + #if DECDPUN<=4 + uInt quot=QUOT10(*source, cut); + uInt rem=*source-quot*DECPOWERS[cut]; + next+=quot; + #else + uInt rem=*source%DECPOWERS[cut]; + next+=*source/DECPOWERS[cut]; + #endif + if (target<=first) *target=(Unit)next; // write to target iff valid + next=rem*DECPOWERS[DECDPUN-cut]; // save remainder for next Unit + } + } // shift-move + // propagate remainder to one below and clear the rest + for (; target>=uar; target--) { + *target=(Unit)next; + next=0; + } + digits+=shift; // add count (shift) of zeros added + inu=uar; // use units in working array + } + + /* now densely pack the coefficient into DPD declets */ + + #if DECDPUN!=3 // not fast path + in=*inu; // current unit + cut=0; // at lowest digit + bin=0; // [keep compiler quiet] + #endif + + for(n=0; digits>0; n++) { // each output bunch + #if DECDPUN==3 // fast path, 3-at-a-time + bin=*inu; // 3 digits ready for convert + digits-=3; // [may go negative] + inu++; // may need another + + #else // must collect digit-by-digit + Unit dig; // current digit + Int j; // digit-in-declet count + for (j=0; j<3; j++) { + #if DECDPUN<=4 + Unit temp=(Unit)((uInt)(in*6554)>>16); + dig=(Unit)(in-X10(temp)); + in=temp; + #else + dig=in%10; + in=in/10; + #endif + if (j==0) bin=dig; + else if (j==1) bin+=X10(dig); + else /* j==2 */ bin+=X100(dig); + digits--; + if (digits==0) break; // [also protects *inu below] + cut++; + if (cut==DECDPUN) {inu++; in=*inu; cut=0;} + } + #endif + // here there are 3 digits in bin, or have used all input digits + + dpd=BIN2DPD[bin]; + + // write declet to uInt array + *uout|=dpd<>(10-uoff); // collect top bits + } // n declets + return; + } // decDigitsToDPD + +/* ------------------------------------------------------------------ */ +/* decDigitsFromDPD -- unpack a format's coefficient */ +/* */ +/* dn is the target number, with 7, 16, or 34-digit space. */ +/* sour is a 1, 2, or 4-element uInt array containing only declets */ +/* declets is the number of (right-aligned) declets in sour to */ +/* be processed. This may be 1 more than the obvious number in */ +/* a format, as any top digit is prefixed to the coefficient */ +/* continuation field. It also may be as small as 1, as the */ +/* caller may pre-process leading zero declets. */ +/* */ +/* When doing the 'extra declet' case care is taken to avoid writing */ +/* extra digits when there are leading zeros, as these could overflow */ +/* the units array when DECDPUN is not 3. */ +/* */ +/* The target uInts are used only as necessary to process declets */ +/* declets into the decNumber. When more than one uInt is needed, */ +/* they are used from left to right (that is, the uInt at offset 0 */ +/* provides the least-significant digits). */ +/* */ +/* dn->digits is set, but not the sign or exponent. */ +/* No error is possible [the redundant 888 codes are allowed]. */ +/* ------------------------------------------------------------------ */ +void decDigitsFromDPD(decNumber *dn, const uInt *sour, Int declets) { + + uInt dpd; // collector for 10 bits + Int n; // counter + Unit *uout=dn->lsu; // -> current output unit + Unit *last=uout; // will be unit containing msd + const uInt *uin=sour; // -> current input uInt + uInt uoff=0; // -> current input offset [from right] + + #if DECDPUN!=3 + uInt bcd; // BCD result + uInt nibble; // work + Unit out=0; // accumulator + Int cut=0; // power of ten in current unit + #endif + #if DECDPUN>4 + uInt const *pow; // work + #endif + + // Expand the densely-packed integer, right to left + for (n=declets-1; n>=0; n--) { // count down declets of 10 bits + dpd=*uin>>uoff; + uoff+=10; + if (uoff>32) { // crossed uInt boundary + uin++; + uoff-=32; // [if using this code for wider, check this] + dpd|=*uin<<(10-uoff); // get waiting bits + } + dpd&=0x3ff; // clear uninteresting bits + + #if DECDPUN==3 + if (dpd==0) *uout=0; + else { + *uout=DPD2BIN[dpd]; // convert 10 bits to binary 0-999 + last=uout; // record most significant unit + } + uout++; + } // n + + #else // DECDPUN!=3 + if (dpd==0) { // fastpath [e.g., leading zeros] + // write out three 0 digits (nibbles); out may have digit(s) + cut++; + if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} + if (n==0) break; // [as below, works even if MSD=0] + cut++; + if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} + cut++; + if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} + continue; + } + + bcd=DPD2BCD[dpd]; // convert 10 bits to 12 bits BCD + + // now accumulate the 3 BCD nibbles into units + nibble=bcd & 0x00f; + if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]); + cut++; + if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} + bcd>>=4; + + // if this is the last declet and the remaining nibbles in bcd + // are 00 then process no more nibbles, because this could be + // the 'odd' MSD declet and writing any more Units would then + // overflow the unit array + if (n==0 && !bcd) break; + + nibble=bcd & 0x00f; + if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]); + cut++; + if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} + bcd>>=4; + + nibble=bcd & 0x00f; + if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]); + cut++; + if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} + } // n + if (cut!=0) { // some more left over + *uout=out; // write out final unit + if (out) last=uout; // and note if non-zero + } + #endif + + // here, last points to the most significant unit with digits; + // inspect it to get the final digits count -- this is essentially + // the same code as decGetDigits in decNumber.c + dn->digits=(last-dn->lsu)*DECDPUN+1; // floor of digits, plus + // must be at least 1 digit + #if DECDPUN>1 + if (*last<10) return; // common odd digit or 0 + dn->digits++; // must be 2 at least + #if DECDPUN>2 + if (*last<100) return; // 10-99 + dn->digits++; // must be 3 at least + #if DECDPUN>3 + if (*last<1000) return; // 100-999 + dn->digits++; // must be 4 at least + #if DECDPUN>4 + for (pow=&DECPOWERS[4]; *last>=*pow; pow++) dn->digits++; + #endif + #endif + #endif + #endif + return; + } //decDigitsFromDPD diff --git a/extern/decNumber/decimal64.h b/extern/decNumber/decimal64.h new file mode 100644 index 0000000000..d2782a34d2 --- /dev/null +++ b/extern/decNumber/decimal64.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------ */ +/* Decimal 64-bit format module header */ +/* ------------------------------------------------------------------ */ +/* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ +/* */ +/* This software is made available under the terms of the */ +/* ICU License -- ICU 1.8.1 and later. */ +/* */ +/* The description and User's Guide ("The decNumber C Library") for */ +/* this software is called decNumber.pdf. This document is */ +/* available, together with arithmetic and format specifications, */ +/* testcases, and Web links, on the General Decimal Arithmetic page. */ +/* */ +/* Please send comments, suggestions, and corrections to the author: */ +/* mfc@uk.ibm.com */ +/* Mike Cowlishaw, IBM Fellow */ +/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ +/* ------------------------------------------------------------------ */ + +#if !defined(DECIMAL64) + #define DECIMAL64 + #define DEC64NAME "decimal64" /* Short name */ + #define DEC64FULLNAME "Decimal 64-bit Number" /* Verbose name */ + #define DEC64AUTHOR "Mike Cowlishaw" /* Who to blame */ + + + /* parameters for decimal64s */ + #define DECIMAL64_Bytes 8 /* length */ + #define DECIMAL64_Pmax 16 /* maximum precision (digits) */ + #define DECIMAL64_Emax 384 /* maximum adjusted exponent */ + #define DECIMAL64_Emin -383 /* minimum adjusted exponent */ + #define DECIMAL64_Bias 398 /* bias for the exponent */ + #define DECIMAL64_String 24 /* maximum string length, +1 */ + #define DECIMAL64_EconL 8 /* exp. continuation length */ + /* highest biased exponent (Elimit-1) */ + #define DECIMAL64_Ehigh (DECIMAL64_Emax+DECIMAL64_Bias-DECIMAL64_Pmax+1) + + /* check enough digits, if pre-defined */ + #if defined(DECNUMDIGITS) + #if (DECNUMDIGITS=16 for safe use + #endif + #endif + + + #ifndef DECNUMDIGITS + #define DECNUMDIGITS DECIMAL64_Pmax /* size if not already defined*/ + #endif + #ifndef DECNUMBER + #include "decNumber.h" /* context and number library */ + #endif + + /* Decimal 64-bit type, accessible by bytes */ + typedef struct { + uint8_t bytes[DECIMAL64_Bytes]; /* decimal64: 1, 5, 8, 50 bits*/ + } decimal64; + + /* special values [top byte excluding sign bit; last two bits are */ + /* don't-care for Infinity on input, last bit don't-care for NaN] */ + #if !defined(DECIMAL_NaN) + #define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */ + #define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */ + #define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */ + #endif + + /* ---------------------------------------------------------------- */ + /* Routines */ + /* ---------------------------------------------------------------- */ + /* String conversions */ + decimal64 * decimal64FromString(decimal64 *, const char *, decContext *); + char * decimal64ToString(const decimal64 *, char *); + char * decimal64ToEngString(const decimal64 *, char *); + + /* decNumber conversions */ + decimal64 * decimal64FromNumber(decimal64 *, const decNumber *, + decContext *); + decNumber * decimal64ToNumber(const decimal64 *, decNumber *); + + /* Format-dependent utilities */ + uint32_t decimal64IsCanonical(const decimal64 *); + decimal64 * decimal64Canonical(decimal64 *, const decimal64 *); + +#endif diff --git a/extern/decNumber/decnumber.pdf b/extern/decNumber/decnumber.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f601105beb3031ec5681b5224775e18c371b43f3 GIT binary patch literal 1416382 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Ί%0qHRif{%HZ3_#^OKtOtWrnx=(O%2}Fb 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 literal 0 HcmV?d00001 diff --git a/extern/decNumber/msvc/decNumber_MSVC12.sln b/extern/decNumber/msvc/decNumber_MSVC12.sln new file mode 100644 index 0000000000..e12432872c --- /dev/null +++ b/extern/decNumber/msvc/decNumber_MSVC12.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "decNumber", "decNumber_MSVC12.vcxproj", "{BE4D2DDC-59A0-4CD7-848E-231E13785335}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BE4D2DDC-59A0-4CD7-848E-231E13785335}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE4D2DDC-59A0-4CD7-848E-231E13785335}.Debug|Win32.Build.0 = Debug|Win32 + {BE4D2DDC-59A0-4CD7-848E-231E13785335}.Debug|x64.ActiveCfg = Debug|x64 + {BE4D2DDC-59A0-4CD7-848E-231E13785335}.Debug|x64.Build.0 = Debug|x64 + {BE4D2DDC-59A0-4CD7-848E-231E13785335}.Release|Win32.ActiveCfg = Release|Win32 + {BE4D2DDC-59A0-4CD7-848E-231E13785335}.Release|Win32.Build.0 = Release|Win32 + {BE4D2DDC-59A0-4CD7-848E-231E13785335}.Release|x64.ActiveCfg = Release|x64 + {BE4D2DDC-59A0-4CD7-848E-231E13785335}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extern/decNumber/msvc/decNumber_MSVC12.vcxproj b/extern/decNumber/msvc/decNumber_MSVC12.vcxproj new file mode 100644 index 0000000000..b562e03f55 --- /dev/null +++ b/extern/decNumber/msvc/decNumber_MSVC12.vcxproj @@ -0,0 +1,267 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + true + true + true + true + + + true + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + decNumber + {BE4D2DDC-59A0-4CD7-848E-231E13785335} + decNumber + + + + StaticLibrary + false + MultiByte + v120_xp + + + StaticLibrary + false + MultiByte + v120 + + + StaticLibrary + false + MultiByte + v120_xp + + + StaticLibrary + false + MultiByte + v120 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + ..\lib\$(Platform)\$(Configuration)\ + ..\lib\$(Platform)\$(Configuration)\ + ..\temp\$(Platform)\$(Configuration)\ + ..\temp\$(Platform)\$(Configuration)\ + ..\lib\$(Platform)\$(Configuration)\ + ..\lib\$(Platform)\$(Configuration)\ + ..\temp\$(Platform)\$(Configuration)\ + ..\temp\$(Platform)\$(Configuration)\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + decnumber + decnumber + decnumber + decnumber + + + + Disabled + .;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + EditAndContinue + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)\$(TargetFileName) + true + + + true + .\Debug/libtommath.bsc + + + + + Disabled + .;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + ProgramDatabase + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)\$(TargetFileName) + true + + + true + .\Debug/libtommath.bsc + + + + + MaxSpeed + OnlyExplicitInline + .;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)\$(TargetFileName) + true + + + true + .\Release/libtommath.bsc + + + + + MaxSpeed + OnlyExplicitInline + .;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)\$(TargetFileName) + true + + + true + .\Release/libtommath.bsc + + + + + + \ No newline at end of file diff --git a/extern/decNumber/msvc/decNumber_MSVC12.vcxproj.filters b/extern/decNumber/msvc/decNumber_MSVC12.vcxproj.filters new file mode 100644 index 0000000000..595d745792 --- /dev/null +++ b/extern/decNumber/msvc/decNumber_MSVC12.vcxproj.filters @@ -0,0 +1,84 @@ + + + + + Source files + + + Source files + + + Source files + + + Source files + + + Source files + + + Source files + + + Source files + + + Source files + + + Source files + + + Source files + + + Source files + + + + + Header files + + + Header files + + + Header files + + + Header files + + + Header files + + + Header files + + + Header files + + + Header files + + + Header files + + + Header files + + + Header files + + + + + + + + {638ba91b-1def-4094-a692-752b2ce6f461} + + + {ffbb5d93-e379-40ba-ab58-c62e9e20c810} + + + \ No newline at end of file diff --git a/extern/decNumber/readme.txt b/extern/decNumber/readme.txt new file mode 100644 index 0000000000..1ebc7f397b --- /dev/null +++ b/extern/decNumber/readme.txt @@ -0,0 +1,81 @@ +This is the readme.txt for the decNumber package. It includes +instructions for compiling and testing the package; please read them. +--------------------------------------------------------------------- + +decNumber is distributed in two forms; as a complete package from +the International Components for Unicode (ICU) site (under an as-is +license), or as a collection of Open Source files from the GCC source +repository (under the GPL license). + +If you are using the GCC files, you can obtain the documentation, the +example files mentioned below, and this readme from the General +Decimal Arithmetic web page -- http://speleotrove.com/decimal/ (the +URL for the open source files is also linked from there). + + +The ICU package +--------------- + +The ICU package includes the files: + + * readme.txt (this file) + + * ICU-license.html + + * decNumber.pdf (documentation) + + * The .c and .h file for each module in the package (see the + decNumber documentation), together with other included files. + + * The .c files for each of the examples (example1.c through + example8.c). + +The ICU package is made available under the terms of the ICU License +(ICU 1.8.1 and later) included in the package as ICU-license.html. +Your use of that package indicates your acceptance of the terms and +conditions of that Agreement. + + +To use and check decNumber +-------------------------- + + Please read the appropriate license and documentation before using + this package. If you are upgrading an existing use of decNumber + (with version <= 3.37) please read the Changes Appendix for later + versions -- you may need to change the DECLITEND flag. + + 1. Compile and link example1.c, decNumber.c, and decContext.c + For instance, use: + + gcc -o example1 example1.c decNumber.c decContext.c + + Note: If your compiler does not provide stdint.h or if your C + compiler does not handle line comments (// ...), then see the + User's Guide section in the documentation for further information + (including a sample minimal stdint.h). + + The use of compiler optimization is strongly recommended (e.g., + -O3 for GCC or /O2 for Visual Studio). + + 2. Run example1 with two numeric arguments, for example: + + example1 1.23 1.27 + + this should display: + + 1.23 + 1.27 => 2.50 + + 3. Similarly, try the other examples, at will. + + Examples 2->4 require three files to be compiled, like Example 1. + + Example 5 requires decimal64.c in addition to the core modules. + + Example 6 requires decPacked.c in addition to the core modules. + + Example 7 requires only example7.c decContext.c and decQuad.c + + Example 8 requires example8.c, decContext.c, and decQuad.c, plus + decNumber.c, decimal128.c, and decimal64.c (the latter + for shared tables and code) + diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index ca039252b0..e570469fa0 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -1686,6 +1686,18 @@ C -- PARAMETER (GDS__overriding_user_invalid = 335545136) INTEGER*4 GDS__overriding_system_missing PARAMETER (GDS__overriding_system_missing = 335545137) + INTEGER*4 GDS__decprecision_err + PARAMETER (GDS__decprecision_err = 335545138) + INTEGER*4 GDS__decfloat_divide_by_zero + PARAMETER (GDS__decfloat_divide_by_zero = 335545139) + INTEGER*4 GDS__decfloat_inexact_result + PARAMETER (GDS__decfloat_inexact_result = 335545140) + INTEGER*4 GDS__decfloat_invalid_operation + PARAMETER (GDS__decfloat_invalid_operation = 335545141) + INTEGER*4 GDS__decfloat_overflow + PARAMETER (GDS__decfloat_overflow = 335545142) + INTEGER*4 GDS__decfloat_underflow + PARAMETER (GDS__decfloat_underflow = 335545143) INTEGER*4 GDS__gfix_db_name PARAMETER (GDS__gfix_db_name = 335740929) INTEGER*4 GDS__gfix_invalid_sw diff --git a/lang_helpers/gds_codes.pas b/lang_helpers/gds_codes.pas index 24ffb26fc9..b2a8f54aca 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -1681,6 +1681,18 @@ const gds_overriding_user_invalid = 335545136; isc_overriding_system_missing = 335545137; gds_overriding_system_missing = 335545137; + isc_decprecision_err = 335545138; + gds_decprecision_err = 335545138; + isc_decfloat_divide_by_zero = 335545139; + gds_decfloat_divide_by_zero = 335545139; + isc_decfloat_inexact_result = 335545140; + gds_decfloat_inexact_result = 335545140; + isc_decfloat_invalid_operation = 335545141; + gds_decfloat_invalid_operation = 335545141; + isc_decfloat_overflow = 335545142; + gds_decfloat_overflow = 335545142; + isc_decfloat_underflow = 335545143; + gds_decfloat_underflow = 335545143; isc_gfix_db_name = 335740929; gds_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; diff --git a/src/auth/SecureRemotePassword/manage/SrpManagement.cpp b/src/auth/SecureRemotePassword/manage/SrpManagement.cpp index 5b68c6f5dc..b0b01da4fa 100644 --- a/src/auth/SecureRemotePassword/manage/SrpManagement.cpp +++ b/src/auth/SecureRemotePassword/manage/SrpManagement.cpp @@ -233,6 +233,7 @@ public: Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE); dpb.insertByte(isc_dpb_sec_attach, TRUE); + dpb.insertString(isc_dpb_config, EMBEDDED_PROVIDERS, fb_strlen(EMBEDDED_PROVIDERS)); unsigned int authBlockSize; const unsigned char* authBlock = logonInfo->authBlock(&authBlockSize); diff --git a/src/auth/SecureRemotePassword/server/SrpServer.cpp b/src/auth/SecureRemotePassword/server/SrpServer.cpp index 34916a3f4a..7a2f53a712 100644 --- a/src/auth/SecureRemotePassword/server/SrpServer.cpp +++ b/src/auth/SecureRemotePassword/server/SrpServer.cpp @@ -141,8 +141,7 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); dpb.insertByte(isc_dpb_sec_attach, TRUE); dpb.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME)); - const char* providers = "Providers=" CURRENT_ENGINE; - dpb.insertString(isc_dpb_config, providers, fb_strlen(providers)); + dpb.insertString(isc_dpb_config, EMBEDDED_PROVIDERS, fb_strlen(EMBEDDED_PROVIDERS)); att = p->attachDatabase(status, secDbName, dpb.getBufferLength(), dpb.getBuffer()); check(status); HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP: attached sec db %s\n", secDbName)); diff --git a/src/auth/SecurityDatabase/LegacyManagement.epp b/src/auth/SecurityDatabase/LegacyManagement.epp index 01ea19b9c5..c9c4b0a9d7 100644 --- a/src/auth/SecurityDatabase/LegacyManagement.epp +++ b/src/auth/SecurityDatabase/LegacyManagement.epp @@ -131,6 +131,7 @@ void SecurityDatabaseManagement::start(Firebird::CheckStatusWrapper* st, Firebir Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE); dpb.insertByte(isc_dpb_sec_attach, TRUE); + dpb.insertString(isc_dpb_config, EMBEDDED_PROVIDERS, fb_strlen(EMBEDDED_PROVIDERS)); unsigned int authBlockSize; const unsigned char* authBlock = logonInfo->authBlock(&authBlockSize); @@ -226,6 +227,15 @@ int SecurityDatabaseManagement::release() } #define STR_STORE(to, from) fb_utils::copy_terminate(to, from, sizeof(to)) +#define STR_VSTORE(to, from) string2vary(&to, from, sizeof(to)) +static void string2vary(void* to, Firebird::string& from, size_t to_size) +{ + size_t len = MIN(to_size - sizeof(USHORT), from.size()); + paramvary* v = reinterpret_cast(to); + v->vary_length = len; + memcpy(v->vary_string, from.c_str(), len); +} + int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebird::IUser* user, Firebird::IListUsers* callback) @@ -370,7 +380,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi { ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), LEGACY_PASSWORD_SALT); LegacyHash::hash(encrypted2, user->userName()->get(), &encrypted1[2]); - STR_STORE(U.PLG$PASSWD, encrypted2.c_str()); + STR_VSTORE(U.PLG$PASSWD, encrypted2); U.PLG$PASSWD.NULL = ISC_FALSE; } else @@ -455,7 +465,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi { ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), LEGACY_PASSWORD_SALT); LegacyHash::hash(encrypted2, user->userName()->get(), &encrypted1[2]); - STR_STORE(U.PLG$PASSWD, encrypted2.c_str()); + STR_VSTORE(U.PLG$PASSWD, encrypted2); U.PLG$PASSWD.NULL = ISC_FALSE; } else if (user->password()->specified()) diff --git a/src/auth/SecurityDatabase/LegacyServer.cpp b/src/auth/SecurityDatabase/LegacyServer.cpp index 1c996f1f92..3f513691ca 100644 --- a/src/auth/SecurityDatabase/LegacyServer.cpp +++ b/src/auth/SecurityDatabase/LegacyServer.cpp @@ -293,8 +293,7 @@ void SecurityDatabase::prepare() dpb.insertString(isc_dpb_trusted_auth, DBA_USER_NAME, fb_strlen(DBA_USER_NAME)); // Do not use other providers except current engine - const char* providers = "Providers=" CURRENT_ENGINE; - dpb.insertString(isc_dpb_config, providers, fb_strlen(providers)); + dpb.insertString(isc_dpb_config, EMBEDDED_PROVIDERS, fb_strlen(EMBEDDED_PROVIDERS)); isc_db_handle tempHandle = 0; isc_attach_database(status, 0, secureDbName, &tempHandle, diff --git a/src/burp/backup.epp b/src/burp/backup.epp index cbaa53ad29..7c1df91c46 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -1618,13 +1618,21 @@ void put_data(burp_rel* relation) add_byte(blr, field->fld_type); break; + case blr_dec64: + case blr_dec128: + alignment = type_alignments[dtype]; + add_byte(blr, field->fld_type); + break; + default: BURP_error_redirect(NULL, 26, SafeArg() << field->fld_type); // msg 26 datatype %ld not understood break; } + if (alignment) offset = FB_ALIGN(offset, alignment); + field->fld_offset = offset; field->fld_parameter = count++; offset += length; diff --git a/src/burp/canonical.cpp b/src/burp/canonical.cpp index 634a9bdf1b..5e92e85825 100644 --- a/src/burp/canonical.cpp +++ b/src/burp/canonical.cpp @@ -136,24 +136,34 @@ ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool_t break; case dtype_short: - if (!xdr_short(xdrs, (SSHORT *) p)) + if (!xdr_short(xdrs, (SSHORT*) p)) return FALSE; break; case dtype_long: case dtype_sql_time: case dtype_sql_date: - if (!xdr_long(xdrs, (SLONG *) p)) + if (!xdr_long(xdrs, (SLONG*) p)) return FALSE; break; case dtype_real: - if (!xdr_float(xdrs, (float *) p)) + if (!xdr_float(xdrs, (float*) p)) return FALSE; break; case dtype_double: - if (!xdr_double(xdrs, (double *) p)) + if (!xdr_double(xdrs, (double*) p)) + return FALSE; + break; + + case dtype_dec64: + if (!xdr_dec64(xdrs, (Firebird::Decimal64*) p)) + return FALSE; + break; + + case dtype_dec128: + if (!xdr_dec128(xdrs, (Firebird::Decimal128*) p)) return FALSE; break; diff --git a/src/burp/restore.epp b/src/burp/restore.epp index 77ce97cb05..0ec78f67f3 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -2805,6 +2805,8 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation) case blr_timestamp: case blr_sql_time: case blr_sql_date: + case blr_dec64: + case blr_dec128: add_byte(blr, field->fld_type); break; @@ -7327,8 +7329,8 @@ bool get_relation(BurpGlobals* tdgbl) * * **************************************/ - SLONG rel_flags = 0, sys_flag = 0, type = 0; - bool rel_flags_null = true, type_null = true; + SLONG rel_flags = 0, sys_flag = fb_sysflag_user, type = rel_persistent; + bool rel_flags_null = true; ISC_QUAD view_blr = isc_blob_null, view_src = isc_blob_null, rel_desc = isc_blob_null, ext_desc = isc_blob_null; bool view_blr_null = true, view_src_null = true, rel_desc_null = true, @@ -7344,6 +7346,24 @@ bool get_relation(BurpGlobals* tdgbl) ext_file_name[0] = '\0'; bool ext_file_name_null = true; + // Before starting to restore relations, commit everything that was restored + // prior to this point. This ensures that no pending error can later affect + // other metadata being restored. + + if (!tdgbl->relations) + { + BURP_verbose (68); + // msg 68 committing meta data + COMMIT + ON_ERROR + general_on_error (); + END_ERROR; + + EXEC SQL SET TRANSACTION NO_AUTO_UNDO; + if (gds_status[1]) + EXEC SQL SET TRANSACTION; + } + // Pick up relation attributes burp_rel* relation = (burp_rel*) BURP_alloc_zero (sizeof(burp_rel)); @@ -7446,10 +7466,7 @@ bool get_relation(BurpGlobals* tdgbl) case att_relation_type: if (tdgbl->RESTORE_format >= 8) - { - type_null = false; type = get_int32(tdgbl); - } else bad_attribute(scan_next_attr, attribute, 111); break; @@ -7488,7 +7505,7 @@ bool get_relation(BurpGlobals* tdgbl) X.RDB$RUNTIME.NULL = TRUE; X.RDB$EXTERNAL_DESCRIPTION.NULL = ext_desc_null; X.RDB$EXTERNAL_FILE.NULL = ext_file_name_null; - X.RDB$RELATION_TYPE.NULL = type_null; + X.RDB$RELATION_TYPE.NULL = FALSE; X.RDB$SQL_SECURITY.NULL = sql_security_null; X.RDB$SYSTEM_FLAG = (USHORT) sys_flag; diff --git a/src/common/CharSet.h b/src/common/CharSet.h index dd6aad6e65..8e61b73aff 100644 --- a/src/common/CharSet.h +++ b/src/common/CharSet.h @@ -31,6 +31,7 @@ #define JRD_CHARSET_H #include "CsConvert.h" +#include "IntlUtil.h" namespace Jrd { @@ -42,8 +43,7 @@ public: public: static void clear(charset* cs) { - if (cs->charset_fn_destroy) - cs->charset_fn_destroy(cs); + Firebird::IntlUtil::finiCharset(cs); delete cs; } }; @@ -116,8 +116,7 @@ public: void destroy() { - if (cs->charset_fn_destroy) - cs->charset_fn_destroy(cs); + Firebird::IntlUtil::finiCharset(cs); } const UCHAR* getSqlMatchAny() const { return sqlMatchAny; } diff --git a/src/common/DecFloat.cpp b/src/common/DecFloat.cpp new file mode 100644 index 0000000000..6960bf636b --- /dev/null +++ b/src/common/DecFloat.cpp @@ -0,0 +1,986 @@ +/* + * PROGRAM: Decimal 64 & 128 type. + * MODULE: DecFloat.cpp + * DESCRIPTION: Floating point with decimal exponent. + * + * 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) 2016 Alex Peshkov + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + * + */ + +#include "firebird.h" +#include "DecFloat.h" + +#include "StatusArg.h" +#include "gen/iberror.h" + +extern "C" +{ +#include "../../extern/decNumber/decimal128.h" +#include "../../extern/decNumber/decimal64.h" +#include "../../extern/decNumber/decNumber.h" +} + +#include +#include +#include + +using namespace Firebird; + +namespace { + +struct Dec2fb +{ + USHORT decError; + ISC_STATUS fbError; +}; + +Dec2fb dec2fb[] = { + { DEC_IEEE_754_Division_by_zero, isc_decfloat_divide_by_zero }, + { DEC_IEEE_754_Inexact, isc_decfloat_inexact_result }, + { DEC_IEEE_754_Invalid_operation, isc_decfloat_invalid_operation }, + { DEC_IEEE_754_Overflow, isc_decfloat_overflow }, + { DEC_IEEE_754_Underflow, isc_decfloat_underflow }, + { 0, 0 } +}; + +class DecimalContext : public decContext +{ +public: + DecimalContext(const Decimal64*, DecimalStatus ds) + : decSt(ds) + { + init(DEC_INIT_DECIMAL64); + } + + DecimalContext(const Decimal128*, DecimalStatus ds) + : decSt(ds) + { + init(DEC_INIT_DECIMAL128); + } + + ~DecimalContext() NOEXCEPT_ARG(false) + { + // Typically exceptions should better be not thrown from destructors. + // But in our case there should never be any exception raised inside + // Decimal64/128 functions - C library never throw, i.e. dtor will + // be never called due to exception processing. + // Therefore checking status in destructor is safe. + checkForExceptions(); + } + + void checkForExceptions() + { + USHORT unmaskedExceptions = decSt.decExtFlag & decContextGetStatus(this); + if (!unmaskedExceptions) + return; + + decContextZeroStatus(this); + + for (Dec2fb* e = dec2fb; e->decError; ++e) + { + // Arg::Gds(isc_arith_except) as first vector element ? + if (e->decError & unmaskedExceptions) + Arg::Gds(e->fbError).raise(); + } + } + +private: + DecimalStatus decSt; + + void init(int kind) + { + decContextDefault(this, kind); + fb_assert(decSt.roundingMode < USHORT(DEC_ROUND_MAX)); + enum rounding rMode = rounding(decSt.roundingMode); + decContextSetRounding(this, rMode); + traps = 0; // do not raise SIGFPE + } +}; + +CDecimal128 dmax(DBL_MAX, DecimalStatus(0)), dmin(-DBL_MAX, DecimalStatus(0)); +CDecimal128 i64max(MAX_SINT64, DecimalStatus(0)), i64min(MIN_SINT64, DecimalStatus(0)); + +unsigned digits(const unsigned pMax, unsigned char* const coeff, int& exp) +{ + for (unsigned i = 0; i < pMax; ++i) + { + if (coeff[i]) + { + if (i) + { + memmove(coeff, &coeff[i], pMax - i); + memset(&coeff[pMax - i], 0, i); + exp -= i; + } + + i = pMax - i; + + while (!coeff[i - 1]) + { + fb_assert(i > 0); + --i; + } + + return i; + } + } + + return 0; +} + +void make(ULONG* key, + const unsigned pMax, const int bias, const unsigned decSize, + unsigned char* coeff, int sign, int exp) +{ + // normalize coeff & exponent + unsigned dig = digits(pMax, coeff, exp); + + // exponent bias and sign + if (!dig) + { + exp = 0; + sign = 0; + } + else + { + exp += (bias + 2); + if (sign) + exp = -exp; + } + + *key++ = exp; + + // convert to SLONG + fb_assert(pMax / 9 < decSize / sizeof(int)); + memset(key, 0, decSize); + + for (unsigned i = 0; i < pMax; ++i) + { + unsigned c = i / 9; + key[c] *= 10; + key[c] += (sign ? 9 - coeff[i] : coeff[i]); + } +} + +void grab(ULONG* key, + const unsigned pMax, const int bias, const unsigned decSize, + unsigned char* bcd, int& sign, int& exp) +{ + exp = *key++; + sign = 0; + + // parse exp + if (exp < 0) + { + sign = DECFLOAT_Sign; + exp = -exp; + } + + if (exp != 0) + exp -= (bias + 2); + + // convert from SLONG + for (int i = pMax; i--;) + { + int c = i / 9; + bcd[i] = key[c] % 10; + key[c] /= 10; + + if (sign) + bcd[i] = 9 - bcd[i]; + } + + // normalize + for (unsigned i = pMax; i--; ) + { + if (bcd[i]) + { + if (i < pMax - 1) + { + memmove(&bcd[pMax - 1 - i], bcd, i + 1); + memset(bcd, 0, pMax - 1 - i); + exp += (pMax - 1 - i); + } + + break; + } + } +} + +} // anonymous namespace + + + +namespace Firebird { + +void Decimal64::setScale(DecimalStatus decSt, int scale) +{ + if (scale) + { + DecimalContext context(this, decSt); + scale += decDoubleGetExponent(&dec); + decDoubleSetExponent(&dec, &context, scale); + } +} + +#if SIZEOF_LONG < 8 +Decimal64 Decimal64::set(int value, DecimalStatus decSt, int scale) +{ + return set(SLONG(value), decSt, scale); +} +#endif + +Decimal64 Decimal64::set(SLONG value, DecimalStatus decSt, int scale) +{ + decDoubleFromInt32(&dec, value); + setScale(decSt, -scale); + + return *this; +} + +Decimal64 Decimal64::set(SINT64 value, DecimalStatus decSt, int scale) +{ + { + char s[30]; // for sure enough for int64 + sprintf(s, "%" SQUADFORMAT, value); + DecimalContext context(this, decSt); + decDoubleFromString(&dec, s, &context); + } + + setScale(decSt, -scale); + + return *this; +} + +Decimal64 Decimal64::set(const char* value, DecimalStatus decSt) +{ + DecimalContext context(this, decSt); + decDoubleFromString(&dec, value, &context); + + return *this; +} + +Decimal64 Decimal64::set(double value, DecimalStatus decSt) +{ + char s[50]; + sprintf(s, "%.016e", value); + DecimalContext context(this, decSt); + decDoubleFromString(&dec, s, &context); + + return *this; +} + +void Decimal64::toString(DecimalStatus decSt, unsigned length, char* to) const +{ + DecimalContext context(this, decSt); + + if (length) + { + --length; + char s[IDecFloat16::STRING_SIZE]; + memset(s, 0, sizeof(s)); + decDoubleToString(&dec, s); + + if (strlen(s) > length) + decContextSetStatus(&context, DEC_Invalid_operation); + else + length = strlen(s); + + memcpy(to, s, length + 1); + } + else + decContextSetStatus(&context, DEC_Invalid_operation); +} + +void Decimal64::toString(string& to) const +{ + to.grow(IDecFloat16::STRING_SIZE); + toString(DecimalStatus(0), to.length(), to.begin()); // provide long enough string, i.e. no traps + to.recalculate_length(); +} + +UCHAR* Decimal64::getBytes() +{ + return dec.bytes; +} + +Decimal64 Decimal64::abs() const +{ + Decimal64 rc; + decDoubleCopyAbs(&rc.dec, &dec); + return rc; +} + +Decimal64 Decimal64::ceil(DecimalStatus decSt) const +{ + DecimalContext context(this, decSt); + Decimal64 rc; + decDoubleToIntegralValue(&rc.dec, &dec, &context, DEC_ROUND_CEILING); + return rc; +} + +Decimal64 Decimal64::floor(DecimalStatus decSt) const +{ + DecimalContext context(this, decSt); + Decimal64 rc; + decDoubleToIntegralValue(&rc.dec, &dec, &context, DEC_ROUND_FLOOR); + return rc; +} + +int Decimal64::compare(DecimalStatus decSt, Decimal64 tgt) const +{ + DecimalContext context(this, decSt); + decDouble r; + decDoubleCompare(&r, &dec, &tgt.dec, &context); + return decDoubleToInt32(&r, &context, DEC_ROUND_HALF_UP); +} + +bool Decimal64::isInf() const +{ + switch (decDoubleClass(&dec)) + { + case DEC_CLASS_NEG_INF: + case DEC_CLASS_POS_INF: + return true; + } + + return false; +} + +bool Decimal64::isNan() const +{ + switch (decDoubleClass(&dec)) + { + case DEC_CLASS_SNAN: + case DEC_CLASS_QNAN: + return true; + } + + return false; +} + +int Decimal64::sign() const +{ + if (decDoubleIsZero(&dec)) + return 0; + if (decDoubleIsSigned(&dec)) + return -1; + return 1; +} + +#ifdef DEV_BUILD +int Decimal64::show() +{ + decDoubleShow(&dec, ""); + return 0; +} +#endif + +Decimal64 Decimal64::neg() const +{ + Decimal64 rc; + decDoubleCopyNegate(&rc.dec, &dec); + return rc; +} + +void Decimal64::makeKey(ULONG* key) const +{ + unsigned char coeff[DECDOUBLE_Pmax]; + int sign = decDoubleGetCoefficient(&dec, coeff); + int exp = decDoubleGetExponent(&dec); + + make(key, DECDOUBLE_Pmax, DECDOUBLE_Bias, sizeof(dec), coeff, sign, exp); +} + +void Decimal64::grabKey(ULONG* key) +{ + int exp, sign; + unsigned char bcd[DECDOUBLE_Pmax]; + + grab(key, DECDOUBLE_Pmax, DECDOUBLE_Bias, sizeof(dec), bcd, sign, exp); + + decDoubleFromBCD(&dec, exp, bcd, sign); +} + +Decimal64 Decimal64::quantize(DecimalStatus decSt, Decimal64 op2) const +{ + DecimalContext context(this, decSt); + Decimal64 rc; + decDoubleQuantize(&rc.dec, &dec, &op2.dec, &context); + return rc; +} + +Decimal64 Decimal64::normalize(DecimalStatus decSt) const +{ + DecimalContext context(this, decSt); + Decimal64 rc; + decDoubleReduce(&rc.dec, &dec, &context); + return rc; +} + +short Decimal64::totalOrder(Decimal64 op2) const +{ + decDouble r; + decDoubleCompareTotal(&r, &dec, &op2.dec); + fb_assert(!decDoubleIsNaN(&r)); + + DecimalContext context2(this, 0); + return decDoubleToInt32(&r, &context2, DEC_ROUND_HALF_UP); +} + +/* + * decCompare() implements SQL function COMPARE_DECFLOAT() which has non-traditional return values. + * COMPARE_DECFLOAT (X, Y) + * 0 - X == Y + * 1 - X < Y + * 2 - X > Y + * 3 - values unordered + */ + +short Decimal64::decCompare(Decimal64 op2) const +{ + if (decDoubleIsNaN(&dec) || decDoubleIsNaN(&op2.dec)) + return 3; + + switch (totalOrder(op2)) + { + case -1: + return 1; + case 0: + return 0; + case 1: + return 2; + default: + fb_assert(false); + } + + // warning silencer + return 3; +} + +Decimal128 Decimal128::set(Decimal64 d64) +{ + decDoubleToWider(&d64.dec, &dec); + + return *this; +} + +#if SIZEOF_LONG < 8 +Decimal128 Decimal128::set(int value, DecimalStatus decSt, int scale) +{ + return set(SLONG(value), decSt, scale); +} +#endif + +Decimal128 Decimal128::set(SLONG value, DecimalStatus decSt, int scale) +{ + decQuadFromInt32(&dec, value); + setScale(decSt, -scale); + + return *this; +} + +Decimal128 Decimal128::set(SINT64 value, DecimalStatus decSt, int scale) +{ + { + int high = value >> 32; + 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); + } + + setScale(decSt, -scale); + + return *this; +} + +Decimal128 Decimal128::set(const char* value, DecimalStatus decSt) +{ + DecimalContext context(this, decSt); + decQuadFromString(&dec, value, &context); + + return *this; +} + +Decimal128 Decimal128::set(double value, DecimalStatus decSt) +{ + char s[50]; + sprintf(s, "%.016e", value); + DecimalContext context(this, decSt); + decQuadFromString(&dec, s, &context); + + return *this; +} + +Decimal128 Decimal128::operator=(Decimal64 d64) +{ + decDoubleToWider(&d64.dec, &dec); + return *this; +} + +int Decimal128::toInteger(DecimalStatus decSt, int scale) const +{ + Decimal128 tmp(*this); + tmp.setScale(decSt, -scale); + DecimalContext context(this, decSt); + enum rounding rMode = decContextGetRounding(&context); + return decQuadToInt32(&tmp.dec, &context, rMode); +} + +void Decimal128::toString(DecimalStatus decSt, unsigned length, char* to) const +{ + DecimalContext context(this, decSt); + + if (length) + { + --length; + char s[IDecFloat34::STRING_SIZE]; + memset(s, 0, sizeof(s)); + decQuadToString(&dec, s); + + if (strlen(s) > length) + decContextSetStatus(&context, DEC_Invalid_operation); + else + length = strlen(s); + + memcpy(to, s, length + 1); + } + else + decContextSetStatus(&context, DEC_Invalid_operation); +} + +void Decimal128::toString(string& to) const +{ + to.grow(IDecFloat34::STRING_SIZE); + toString(DecimalStatus(0), to.length(), to.begin()); // provide long enough string, i.e. no traps + to.recalculate_length(); +} + +double Decimal128::toDouble(DecimalStatus decSt) const +{ + DecimalContext context(this, decSt); + + if (compare(decSt, dmin) < 0 || compare(decSt, dmax) > 0) + decContextSetStatus(&context, DEC_Overflow); + else + { + char s[IDecFloat34::STRING_SIZE]; + memset(s, 0, sizeof(s)); + decQuadToString(&dec, s); + return atof(s); + } + + return 0.0; +} + +SINT64 Decimal128::toInt64(DecimalStatus decSt, int scale) const +{ + static CDecimal128 quant(1); + + Decimal128 wrk(*this); + wrk.setScale(decSt, -scale); + wrk = wrk.quantize(decSt, quant); + + if (wrk.compare(decSt, i64min) < 0 || wrk.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(&wrk.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* Decimal128::getBytes() +{ + return dec.bytes; +} + +Decimal64 Decimal128::toDecimal64(DecimalStatus decSt) const +{ + Decimal64 rc; + DecimalContext context(this, decSt); + decDoubleFromWider(&rc.dec, &dec, &context); + return rc; +} + +void Decimal128::setScale(DecimalStatus decSt, int scale) +{ + if (scale) + { + DecimalContext context(this, decSt); + scale += decQuadGetExponent(&dec); + decQuadSetExponent(&dec, &context, scale); + } +} + +int Decimal128::compare(DecimalStatus decSt, Decimal128 tgt) const +{ + DecimalContext context(this, decSt); + decQuad r; + decQuadCompare(&r, &dec, &tgt.dec, &context); + return decQuadToInt32(&r, &context, DEC_ROUND_HALF_UP); +} + +bool Decimal128::isInf() const +{ + switch(decQuadClass(&dec)) + { + case DEC_CLASS_NEG_INF: + case DEC_CLASS_POS_INF: + return true; + } + + return false; +} + +bool Decimal128::isNan() const +{ + switch(decQuadClass(&dec)) + { + case DEC_CLASS_SNAN: + case DEC_CLASS_QNAN: + return true; + } + + return false; +} + +int Decimal128::sign() const +{ + if (decQuadIsZero(&dec)) + return 0; + if (decQuadIsSigned(&dec)) + return -1; + return 1; +} + +Decimal128 Decimal128::abs() const +{ + Decimal128 rc; + decQuadCopyAbs(&rc.dec, &dec); + return rc; +} + +Decimal128 Decimal128::ceil(DecimalStatus decSt) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadToIntegralValue(&rc.dec, &dec, &context, DEC_ROUND_CEILING); + return rc; +} + +Decimal128 Decimal128::floor(DecimalStatus decSt) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadToIntegralValue(&rc.dec, &dec, &context, DEC_ROUND_FLOOR); + return rc; +} + +#ifdef DEV_BUILD +int Decimal128::show() +{ + decQuadShow(&dec, ""); + return 0; +} +#endif + +Decimal128 Decimal128::add(DecimalStatus decSt, Decimal128 op2) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadAdd(&rc.dec, &dec, &op2.dec, &context); + return rc; +} + +Decimal128 Decimal128::sub(DecimalStatus decSt, Decimal128 op2) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadSubtract(&rc.dec, &dec, &op2.dec, &context); + return rc; +} + +Decimal128 Decimal128::mul(DecimalStatus decSt, Decimal128 op2) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadMultiply(&rc.dec, &dec, &op2.dec, &context); + return rc; +} + +Decimal128 Decimal128::div(DecimalStatus decSt, Decimal128 op2) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadDivide(&rc.dec, &dec, &op2.dec, &context); + return rc; +} + +Decimal128 Decimal128::neg() const +{ + Decimal128 rc; + decQuadCopyNegate(&rc.dec, &dec); + return rc; +} + +Decimal128 Decimal128::fma(DecimalStatus decSt, Decimal128 op2, Decimal128 op3) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadFMA(&rc.dec, &op2.dec, &op3.dec, &dec, &context); + return rc; +} + +Decimal128 Decimal128::sqrt(DecimalStatus decSt) const +{ + decNumber dn; + decQuadToNumber(&dec, &dn); + + DecimalContext context(this, decSt); + decNumberSquareRoot(&dn, &dn, &context); + + Decimal128 rc; + decQuadFromNumber(&rc.dec, &dn, &context); + return rc; +} + +Decimal128 Decimal128::pow(DecimalStatus decSt, Decimal128 op2) const +{ + decNumber dn, dn2; + decQuadToNumber(&dec, &dn); + decQuadToNumber(&op2.dec, &dn2); + + DecimalContext context(this, decSt); + decNumberPower(&dn, &dn, &dn2, &context); + + Decimal128 rc; + decQuadFromNumber(&rc.dec, &dn, &context); + return rc; +} + +Decimal128 Decimal128::ln(DecimalStatus decSt) const +{ + decNumber dn; + decQuadToNumber(&dec, &dn); + + DecimalContext context(this, decSt); + decNumberLn(&dn, &dn, &context); + + Decimal128 rc; + decQuadFromNumber(&rc.dec, &dn, &context); + return rc; +} + +Decimal128 Decimal128::log10(DecimalStatus decSt) const +{ + decNumber dn; + decQuadToNumber(&dec, &dn); + + DecimalContext context(this, decSt); + decNumberLog10(&dn, &dn, &context); + + Decimal128 rc; + decQuadFromNumber(&rc.dec, &dn, &context); + return rc; +} + +void Decimal128::makeKey(ULONG* key) const +{ + unsigned char coeff[DECQUAD_Pmax]; + int sign = decQuadGetCoefficient(&dec, coeff); + int exp = decQuadGetExponent(&dec); + + make(key, DECQUAD_Pmax, DECQUAD_Bias, sizeof(dec), coeff, sign, exp); +} + +void Decimal128::grabKey(ULONG* key) +{ + int exp, sign; + unsigned char bcd[DECQUAD_Pmax]; + + grab(key, DECQUAD_Pmax, DECQUAD_Bias, sizeof(dec), bcd, sign, exp); + + decQuadFromBCD(&dec, exp, bcd, sign); +} + +ULONG Decimal128::getIndexKeyLength() +{ + return 17; +} + +ULONG Decimal128::makeIndexKey(vary* buf) +{ + unsigned char coeff[DECQUAD_Pmax + 2]; + int sign = decQuadGetCoefficient(&dec, coeff); + int exp = decQuadGetExponent(&dec); + const int bias = DECQUAD_Bias; + const unsigned pMax = DECQUAD_Pmax; + + // normalize coeff & exponent + unsigned dig = digits(pMax, coeff, exp); + + // exponent bias and sign + exp += (bias + 1); + if (!dig) + exp = 0; + if (sign) + exp = -exp; + exp += 2 * (bias + 1); // make it positive + fb_assert(exp >= 0 && exp < 64 * 1024); + + // encode exp + char* k = buf->vary_string; + *k++ = exp >> 8; + *k++ = exp & 0xff; + + // invert negative + unsigned char* const end = &coeff[dig]; + if (sign && dig) + { + fb_assert(end[-1]); + --end[-1]; + + for (unsigned char* p = coeff; p < end; ++p) + *p = 9 - *p; + } + + // Some 0's in the end - caller, do not forget to reserve additional space on stack + end[0] = end[1] = 0; + + // Avoid bad data in k in case when coeff is zero + *k = 0; + + // Shifts for moving 10-bit values to bytes buffer + struct ShiftTable { UCHAR rshift, lshift; }; + static ShiftTable table[4] = + { + { 2, 6 }, + { 4, 4 }, + { 6, 2 }, + { 8, 0 } + }; + + // compress coeff - 3 decimal digits (999) per 10 bits (1023) + unsigned char* p = coeff; + for (ShiftTable* t = table; p < end; p += 3) + { + USHORT val = p[0] * 100 + p[1] * 10 + p[2]; + fb_assert(val < 1000); // 1024, 10 bit + *k |= (val >> t->rshift); + ++k; + *k = (val << t->lshift); + if (!t->lshift) + { + ++k; + *k = 0; + t = table; + } + else + ++t; + } + if (*k) + ++k; + + // done + buf->vary_length = k - buf->vary_string; + return buf->vary_length; +} + +Decimal128 Decimal128::quantize(DecimalStatus decSt, Decimal128 op2) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadQuantize(&rc.dec, &dec, &op2.dec, &context); + return rc; +} + +Decimal128 Decimal128::normalize(DecimalStatus decSt) const +{ + DecimalContext context(this, decSt); + Decimal128 rc; + decQuadReduce(&rc.dec, &dec, &context); + return rc; +} + +short Decimal128::totalOrder(Decimal128 op2) const +{ + decQuad r; + decQuadCompareTotal(&r, &dec, &op2.dec); + fb_assert(!decQuadIsNaN(&r)); + + DecimalContext context2(this, 0); + return decQuadToInt32(&r, &context2, DEC_ROUND_HALF_UP); +} + +/* + * decCompare() implements SQL function COMPARE_DECFLOAT() which has non-traditional return values. + * COMPARE_DECFLOAT (X, Y) + * 0 - X == Y + * 1 - X < Y + * 2 - X > Y + * 3 - values unordered + */ + +short Decimal128::decCompare(Decimal128 op2) const +{ + if (decQuadIsNaN(&dec) || decQuadIsNaN(&op2.dec)) + return 3; + + switch (totalOrder(op2)) + { + case -1: + return 1; + case 0: + return 0; + case 1: + return 2; + default: + fb_assert(false); + } + + // warning silencer + return 3; +} + +} // namespace Firebird diff --git a/src/common/DecFloat.h b/src/common/DecFloat.h new file mode 100644 index 0000000000..2388ae8661 --- /dev/null +++ b/src/common/DecFloat.h @@ -0,0 +1,195 @@ +/* + * PROGRAM: Decimal 64 & 128 type. + * MODULE: DecFloat.h + * DESCRIPTION: Floating point with decimal exponent. + * + * 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) 2016 Alex Peshkov + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + * + */ + +#ifndef FB_DECIMAL_FLOAT +#define FB_DECIMAL_FLOAT + +#include "firebird/Interface.h" +#include "fb_exception.h" + +#include "classes/fb_string.h" + +extern "C" +{ +#include "../../extern/decNumber/decQuad.h" +#include "../../extern/decNumber/decDouble.h" +} + +namespace Firebird { + +struct DecimalStatus +{ + DecimalStatus(USHORT exc) + : decExtFlag(exc), roundingMode(DEC_ROUND_HALF_UP) + { } + + USHORT decExtFlag, roundingMode; +}; + +struct DecimalBinding +{ + DecimalBinding() + : bind(DEC_NATIVE), numScale(0) + { } + + enum Bind { DEC_NATIVE, DEC_TEXT, DEC_DOUBLE, DEC_NUMERIC }; + + Bind bind; + SCHAR numScale; +}; + +class Decimal64 +{ + friend class Decimal128; + +public: +#if SIZEOF_LONG < 8 + Decimal64 set(int value, DecimalStatus decSt, int scale); +#endif + Decimal64 set(SLONG value, DecimalStatus decSt, int scale); + Decimal64 set(SINT64 value, DecimalStatus decSt, int scale); + Decimal64 set(const char* value, DecimalStatus decSt); + Decimal64 set(double value, DecimalStatus decSt); + + UCHAR* getBytes(); + Decimal64 abs() const; + Decimal64 ceil(DecimalStatus decSt) const; + Decimal64 floor(DecimalStatus decSt) const; + Decimal64 neg() const; + + void toString(DecimalStatus decSt, unsigned length, char* to) const; + void toString(string& to) const; + + int compare(DecimalStatus decSt, Decimal64 tgt) const; + bool isInf() const; + bool isNan() const; + int sign() const; + + void makeKey(ULONG* key) const; + void grabKey(ULONG* key); + + Decimal64 quantize(DecimalStatus decSt, Decimal64 op2) const; + Decimal64 normalize(DecimalStatus decSt) const; + short totalOrder(Decimal64 op2) const; + short decCompare(Decimal64 op2) const; + +#ifdef DEV_BUILD + int show(); +#endif + +private: + decDouble dec; + + void setScale(DecimalStatus decSt, int scale); +}; + +class Decimal128 +{ + friend class Decimal64; + +public: + Decimal128 set(Decimal64 d64); +#if SIZEOF_LONG < 8 + Decimal128 set(int value, DecimalStatus decSt, int scale); +#endif + Decimal128 set(SLONG value, DecimalStatus decSt, int scale); + Decimal128 set(SINT64 value, DecimalStatus decSt, int scale); + Decimal128 set(const char* value, DecimalStatus decSt); + Decimal128 set(double value, DecimalStatus decSt); + + Decimal128 operator=(Decimal64 d64); + + int toInteger(DecimalStatus decSt, int scale) const; + void toString(DecimalStatus decSt, unsigned length, char* to) const; + void toString(string& to) const; + double toDouble(DecimalStatus decSt) const; + SINT64 toInt64(DecimalStatus decSt, int scale) const; + UCHAR* getBytes(); + Decimal64 toDecimal64(DecimalStatus decSt) const; + Decimal128 abs() const; + Decimal128 ceil(DecimalStatus decSt) const; + Decimal128 floor(DecimalStatus decSt) const; + Decimal128 add(DecimalStatus decSt, Decimal128 op2) const; + Decimal128 sub(DecimalStatus decSt, Decimal128 op2) const; + Decimal128 mul(DecimalStatus decSt, Decimal128 op2) const; + Decimal128 div(DecimalStatus decSt, Decimal128 op2) const; + Decimal128 neg() const; + Decimal128 fma(DecimalStatus decSt, Decimal128 op2, Decimal128 op3) const; + Decimal128 sqrt(DecimalStatus decSt) const; + Decimal128 pow(DecimalStatus decSt, Decimal128 op2) const; + Decimal128 ln(DecimalStatus decSt) const; + Decimal128 log10(DecimalStatus decSt) const; + + int compare(DecimalStatus decSt, Decimal128 tgt) const; + 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); + + Decimal128 quantize(DecimalStatus decSt, Decimal128 op2) const; + Decimal128 normalize(DecimalStatus decSt) const; + short totalOrder(Decimal128 op2) const; + short decCompare(Decimal128 op2) const; + +#ifdef DEV_BUILD + int show(); +#endif + +private: + decQuad dec; + + void setScale(DecimalStatus decSt, int scale); +}; + +class CDecimal128 : public Decimal128 +{ +public: + CDecimal128(double value, DecimalStatus decSt) + { + set(value, decSt); + } + + CDecimal128(SINT64 value, DecimalStatus decSt) + { + set(value, decSt, 0); + } + + CDecimal128(int value) + { + set(value, DecimalStatus(0), 0); + } +}; + +} // namespace Firebird + + +#endif // FB_DECIMAL_FLOAT diff --git a/src/common/IntlUtil.cpp b/src/common/IntlUtil.cpp index a9eca194c1..ed6d379399 100644 --- a/src/common/IntlUtil.cpp +++ b/src/common/IntlUtil.cpp @@ -49,8 +49,7 @@ namespace ~TextTypeImpl() { - if (cs->charset_fn_destroy) - cs->charset_fn_destroy(cs); + Firebird::IntlUtil::finiCharset(cs); delete cs; delete collation; @@ -539,6 +538,17 @@ bool IntlUtil::initUnicodeCollation(texttype* tt, charset* cs, const ASCII* name } +void IntlUtil::finiCharset(charset* cs) +{ + if (cs->charset_to_unicode.csconvert_fn_destroy) + cs->charset_to_unicode.csconvert_fn_destroy(&cs->charset_to_unicode); + if (cs->charset_from_unicode.csconvert_fn_destroy) + cs->charset_from_unicode.csconvert_fn_destroy(&cs->charset_from_unicode); + if (cs->charset_fn_destroy) + cs->charset_fn_destroy(cs); +} + + ULONG IntlUtil::toLower(Jrd::CharSet* cs, ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* dst, const ULONG* exceptions) { diff --git a/src/common/IntlUtil.h b/src/common/IntlUtil.h index 1d6fc36ec5..03f4008f80 100644 --- a/src/common/IntlUtil.h +++ b/src/common/IntlUtil.h @@ -80,6 +80,8 @@ public: static bool initUnicodeCollation(texttype* tt, charset* cs, const ASCII* name, USHORT attributes, const UCharBuffer& specificAttributes, const string& configInfo); + static void finiCharset(charset* cs); + static ULONG toLower(Jrd::CharSet* cs, ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* dst, const ULONG* exceptions); static ULONG toUpper(Jrd::CharSet* cs, ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* dst, diff --git a/src/common/MsgMetadata.cpp b/src/common/MsgMetadata.cpp index 932e662ade..05d0084c3a 100644 --- a/src/common/MsgMetadata.cpp +++ b/src/common/MsgMetadata.cpp @@ -286,6 +286,7 @@ void MsgMetadata::addItem(const MetaName& name, bool nullable, const dsc& desc) item.subType = sqlSubType; item.length = sqlLen; item.scale = sqlScale; + item.charSet = desc.getCharSet(); item.finished = true; } diff --git a/src/common/StatementMetadata.cpp b/src/common/StatementMetadata.cpp index 71606873bb..ef6f9ee130 100644 --- a/src/common/StatementMetadata.cpp +++ b/src/common/StatementMetadata.cpp @@ -167,7 +167,7 @@ const char* StatementMetadata::getPlan(bool detailed) if (plan->isEmpty()) { - UCHAR info[] = {detailed ? isc_info_sql_explain_plan : isc_info_sql_get_plan}; + UCHAR info[] = {UCHAR(detailed ? isc_info_sql_explain_plan : isc_info_sql_get_plan)}; UCHAR result[INFO_BUFFER_SIZE]; getAndParse(sizeof(info), info, sizeof(result), result); @@ -484,8 +484,8 @@ void StatementMetadata::fetchParameters(UCHAR code, Parameters* parameters) { isc_info_sql_sqlda_start, 2, - (startIndex & 0xFF), - ((startIndex >> 8) & 0xFF), + UCHAR(startIndex & 0xFF), + UCHAR((startIndex >> 8) & 0xFF), code }; memcpy(items + 5, DESCRIBE_VARS, sizeof(DESCRIBE_VARS)); diff --git a/src/common/classes/Hash.cpp b/src/common/classes/Hash.cpp index 6614708889..afe31c9a84 100644 --- a/src/common/classes/Hash.cpp +++ b/src/common/classes/Hash.cpp @@ -43,12 +43,11 @@ namespace { unsigned int hash_value = 0; - UCHAR* p; + UCHAR* const p = (UCHAR*) &hash_value; const UCHAR* q = value; while (length >= 4) { - p = (UCHAR*) &hash_value; p[0] += q[0]; p[1] += q[1]; p[2] += q[2]; @@ -57,18 +56,16 @@ namespace q += 4; } - p = (UCHAR*) &hash_value; - if (length >= 2) { p[0] += q[0]; p[1] += q[1]; length -= 2; + q += 2; } if (length) { - q += 2; *p += *q; } diff --git a/src/common/classes/ImplementHelper.h b/src/common/classes/ImplementHelper.h index c7647fb9b1..cd2b28a128 100644 --- a/src/common/classes/ImplementHelper.h +++ b/src/common/classes/ImplementHelper.h @@ -117,7 +117,7 @@ protected: void refCntDPrt(char f) { if (mark) - fprintf(stderr, "%s %p %c %lld\n", mark, this, f, refCounter.value()); + fprintf(stderr, "%s %p %c %d\n", mark, this, f, int(refCounter.value())); } AtomicCounter refCounter; diff --git a/src/common/classes/InternalMessageBuffer.cpp b/src/common/classes/InternalMessageBuffer.cpp index 9c784529fe..3c57e39a87 100644 --- a/src/common/classes/InternalMessageBuffer.cpp +++ b/src/common/classes/InternalMessageBuffer.cpp @@ -172,6 +172,16 @@ MetadataFromBlr::MetadataFromBlr(unsigned aBlrLength, const unsigned char* aBlr, item->length = sizeof(UCHAR); break; + case blr_dec64: + item->type = SQL_DEC16; + item->length = sizeof(Decimal64); + break; + + case blr_dec128: + item->type = SQL_DEC34; + item->length = sizeof(Decimal128); + break; + default: (Arg::Gds(isc_sqlerr) << Arg::Num(-804) << Arg::Gds(isc_dsql_sqlda_err) diff --git a/src/common/classes/RefCounted.h b/src/common/classes/RefCounted.h index 674e892f45..1766a6190b 100644 --- a/src/common/classes/RefCounted.h +++ b/src/common/classes/RefCounted.h @@ -193,7 +193,7 @@ namespace Firebird return ptr; } - private: + protected: T* assign(T* const p) { if (ptr != p) @@ -215,6 +215,7 @@ namespace Firebird return ptr; } + private: T* ptr; }; diff --git a/src/common/common.h b/src/common/common.h index 0ee7a33842..9f2c8c067f 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -126,7 +126,7 @@ #define FB_CPU CpuPowerPc #endif -#ifdef i386 +#if defined(i386) || defined(__i386) || defined(__i386__) #define I386 #define FB_CPU CpuIntel #endif /* i386 */ @@ -603,6 +603,13 @@ extern "C" int remove(const char* path); #define FB_EXPORTED #endif +#ifdef HAS_NOEXCEPT +#define NOEXCEPT noexcept +#define NOEXCEPT_ARG(X) noexcept((X)) +#else +#define NOEXCEPT +#define NOEXCEPT_ARG(X) +#endif /* alignment macros */ diff --git a/src/common/cvt.cpp b/src/common/cvt.cpp index 6fffcd3dac..93fa695120 100644 --- a/src/common/cvt.cpp +++ b/src/common/cvt.cpp @@ -137,6 +137,7 @@ enum EXPECT_DATETIME 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 void string_to_datetime(const dsc*, GDS_TIMESTAMP*, const EXPECT_DATETIME, ErrorFunction); static SINT64 hex_to_value(const char*& string, const char* end); @@ -296,7 +297,38 @@ static void float_to_text(const dsc* from, dsc* to, Callbacks* cb) intermediate.dsc_length = chars_printed - 1; } - CVT_move_common(&intermediate, to, cb); + CVT_move_common(&intermediate, to, 0, cb); +} + + +static void decimal_float_to_text(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* cb) +{ + char temp[50]; + + try + { + Decimal128 d; + if (from->dsc_dtype == dtype_dec64) + d = *((Decimal64*) from->dsc_address); + else + d = *((Decimal128*) from->dsc_address); + + d.toString(decSt, sizeof(temp), temp); + } + 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(temp); + intermediate.dsc_length = strlen(temp); + + CVT_move_common(&intermediate, to, 0, cb); } @@ -343,7 +375,7 @@ static void integer_to_text(const dsc* from, dsc* to, Callbacks* cb) intermediate.dsc_scale = scale; intermediate.dsc_address = (UCHAR*) &n; - CVT_move_common(from, &intermediate, cb); + CVT_move_common(from, &intermediate, 0, cb); // Check for negation, then convert the number to a string of digits @@ -528,7 +560,7 @@ static void string_to_datetime(const dsc* desc, VaryStr<100> buffer; // arbitrarily large const char* p = NULL; - const USHORT length = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), err); + const USHORT length = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), 0, err); const char* const end = p + length; @@ -862,7 +894,7 @@ static void string_to_datetime(const dsc* desc, } -SLONG CVT_get_long(const dsc* desc, SSHORT scale, ErrorFunction err) +SLONG CVT_get_long(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err) { /************************************** * @@ -878,6 +910,7 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, ErrorFunction err) SLONG value, high; double d, eps; + Decimal128 d128; SINT64 val64; VaryStr<50> buffer; // long enough to represent largest long in ASCII @@ -940,6 +973,15 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, ErrorFunction err) err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); break; + case dtype_dec64: + case dtype_dec128: + if (desc->dsc_dtype == dtype_dec64) + d128 = *((Decimal64*) p); + else + d128 = *((Decimal128*) p); + + return d128.toInteger(decSt, scale); + case dtype_real: case dtype_double: if (desc->dsc_dtype == dtype_real) @@ -986,7 +1028,7 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, ErrorFunction err) case dtype_text: { USHORT length = - CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), err); + CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); scale -= CVT_decompose(p, length, dtype_long, &value, err); } break; @@ -1054,7 +1096,7 @@ bool CVT_get_boolean(const dsc* desc, ErrorFunction err) { VaryStr<100> buffer; // arbitrarily large const char* p = NULL; - int len = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), err); + int len = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), 0, err); // Remove heading and trailing spaces. @@ -1082,7 +1124,7 @@ bool CVT_get_boolean(const dsc* desc, ErrorFunction err) } -double CVT_get_double(const dsc* desc, ErrorFunction err) +double CVT_get_double(const dsc* desc, DecimalStatus decSt, ErrorFunction err, bool* getNumericOverflow) { /************************************** * @@ -1128,6 +1170,18 @@ double CVT_get_double(const dsc* desc, ErrorFunction err) memcpy(&value, desc->dsc_address, sizeof(double)); return value; + case dtype_dec64: + case dtype_dec128: + { + Decimal128 d128; + if (desc->dsc_dtype == dtype_dec64) + d128 = *((Decimal64*) desc->dsc_address); + else + d128 = *((Decimal128*) desc->dsc_address); + + return d128.toDouble(decSt); + } + case dtype_varying: case dtype_cstring: case dtype_text: @@ -1136,7 +1190,7 @@ double CVT_get_double(const dsc* desc, ErrorFunction err) const char* p; const USHORT length = - CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), err); + CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); value = 0.0; int scale = 0; SSHORT sign = 0; @@ -1217,7 +1271,15 @@ double CVT_get_double(const dsc* desc, ErrorFunction err) // later in this routine. if (exp >= SHORT_LIMIT) + { + if (getNumericOverflow) + { + *getNumericOverflow = true; + return 0; + } + err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); + } } else if (*p == '-' && !digit_seen && !sign) sign = -1; @@ -1250,8 +1312,15 @@ double CVT_get_double(const dsc* desc, ErrorFunction err) // the user know... if (ABSOLUT(scale) > DBL_MAX_10_EXP) - err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); + { + if (getNumericOverflow) + { + *getNumericOverflow = true; + return 0; + } + err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); + } // Repeated division is a good way to mung the least significant bits // of your value, so we have replaced this iterative multiplication/division @@ -1266,7 +1335,15 @@ double CVT_get_double(const dsc* desc, ErrorFunction err) value *= CVT_power_of_ten(-scale); if (isinf(value)) + { + if (getNumericOverflow) + { + *getNumericOverflow = true; + return 0; + } + err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); + } } return value; @@ -1308,7 +1385,7 @@ double CVT_get_double(const dsc* desc, ErrorFunction err) } -void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) +void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* cb) { /************************************** * @@ -1391,6 +1468,8 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) case dtype_real: case dtype_double: case dtype_boolean: + case dtype_dec64: + case dtype_dec128: CVT_conversion_error(from, cb->err); break; } @@ -1424,6 +1503,8 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) case dtype_real: case dtype_double: case dtype_boolean: + case dtype_dec64: + case dtype_dec128: CVT_conversion_error(from, cb->err); break; } @@ -1457,6 +1538,8 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) case dtype_real: case dtype_double: case dtype_boolean: + case dtype_dec64: + case dtype_dec128: CVT_conversion_error(from, cb->err); break; } @@ -1548,7 +1631,7 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) { // scope USHORT strtype_unused; UCHAR *ptr; - length = len = CVT_get_string_ptr_common(from, &strtype_unused, &ptr, NULL, 0, cb); + length = len = CVT_get_string_ptr_common(from, &strtype_unused, &ptr, NULL, 0, decSt, cb); q = ptr; } // end scope @@ -1644,6 +1727,11 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) float_to_text(from, to, cb); return; + case dtype_dec64: + case dtype_dec128: + decimal_float_to_text(from, to, decSt, cb); + return; + case dtype_sql_date: case dtype_sql_time: case dtype_timestamp: @@ -1660,7 +1748,7 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) intermediate.makeText(static_cast(strlen(text)), CS_ASCII, reinterpret_cast(text)); - CVT_move_common(&intermediate, to, cb); + CVT_move_common(&intermediate, to, decSt, cb); return; } @@ -1695,7 +1783,7 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) case dtype_short: { - ULONG lval = CVT_get_long(from, (SSHORT) to->dsc_scale, cb->err); + ULONG lval = CVT_get_long(from, (SSHORT) to->dsc_scale, decSt, cb->err); // TMN: Here we should really have the following fb_assert // fb_assert(lval <= MAX_SSHORT); *(SSHORT*) p = (SSHORT) lval; @@ -1705,11 +1793,11 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) return; case dtype_long: - *(SLONG *) p = CVT_get_long(from, (SSHORT) to->dsc_scale, cb->err); + *(SLONG *) p = CVT_get_long(from, (SSHORT) to->dsc_scale, decSt, cb->err); return; case dtype_int64: - *(SINT64 *) p = CVT_get_int64(from, (SSHORT) to->dsc_scale, cb->err); + *(SINT64 *) p = CVT_get_int64(from, (SSHORT) to->dsc_scale, decSt, cb->err); return; case dtype_quad: @@ -1719,12 +1807,12 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) ((SLONG *) p)[1] = ((SLONG *) q)[1]; return; } - *(SQUAD *) p = CVT_get_quad(from, (SSHORT) to->dsc_scale, cb->err); + *(SQUAD *) p = CVT_get_quad(from, (SSHORT) to->dsc_scale, decSt, cb->err); return; case dtype_real: { - double d_value = CVT_get_double(from, cb->err); + double d_value = CVT_get_double(from, decSt, cb->err); if (ABSOLUT(d_value) > FLOAT_MAX) cb->err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); *(float*) p = (float) d_value; @@ -1736,7 +1824,7 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) { USHORT strtype_unused; UCHAR* ptr; - USHORT len = CVT_get_string_ptr_common(from, &strtype_unused, &ptr, NULL, 0, cb); + USHORT len = CVT_get_string_ptr_common(from, &strtype_unused, &ptr, NULL, 0, decSt, cb); if (len == to->dsc_length) { @@ -1751,14 +1839,22 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) case DEFAULT_DOUBLE: #ifdef HPUX { - const double d_value = CVT_get_double(from, cb->err); + const double d_value = CVT_get_double(from, decSt, cb->err); memcpy(p, &d_value, sizeof(double)); } #else - *(double*) p = CVT_get_double(from, cb->err); + *(double*) p = CVT_get_double(from, decSt, cb->err); #endif return; + case dtype_dec64: + *((Decimal64*) p) = CVT_get_dec64(from, decSt, cb->err); + return; + + case dtype_dec128: + *((Decimal128*) p) = CVT_get_dec128(from, decSt, cb->err); + return; + case dtype_boolean: switch (from->dsc_dtype) { @@ -1779,6 +1875,8 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb) case dtype_quad: case dtype_real: case dtype_double: + case dtype_dec64: + case dtype_dec128: CVT_conversion_error(from, cb->err); break; } @@ -1832,7 +1930,7 @@ void CVT_conversion_error(const dsc* desc, ErrorFunction err) const char* p; VaryStr<128> s; const USHORT length = - CVT_make_string(desc, ttype_ascii, &p, &s, sizeof(s), localError); + CVT_make_string(desc, ttype_ascii, &p, &s, sizeof(s), 0, localError); message.assign(p, length); } /* @@ -1975,7 +2073,49 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb) desc.dsc_length = MIN(desc.dsc_length, (to->dsc_length - l)); } - CVT_move_common(&desc, to, cb); + CVT_move_common(&desc, to, 0, cb); +} + + +void CVT_make_null_string(const dsc* desc, + USHORT to_interp, + const char** address, + vary* temp, + USHORT length, + DecimalStatus decSt, + ErrorFunction err) +{ +/************************************** + * + * C V T _ m a k e _ n u l l _ s t r i n g + * + ************************************** + * + * Functional description + * Convert the data from the desc to a zero-terminated string. + * The pointer to this string is returned in address. + * Data always placed to temp buffer. + * + **************************************/ + fb_assert(temp); + + USHORT len = CVT_make_string(desc, to_interp, address, temp, --length, decSt, err); + + if (*address != temp->vary_string) + { + length -= sizeof(USHORT); // Take into an account VaryStr specifics + if (len > length) + { + err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) << + Arg::Gds(isc_imp_exc) << + Arg::Gds(isc_trunc_limits) << Arg::Num(length) << Arg::Num(len)); + } + memcpy(temp->vary_string, *address, len); + temp->vary_length = len; + } + + fb_assert(temp->vary_length == len); + temp->vary_string[len] = 0; } @@ -1984,6 +2124,7 @@ USHORT CVT_make_string(const dsc* desc, const char** address, vary* temp, USHORT length, + DecimalStatus decSt, ErrorFunction err) { /************************************** @@ -2035,7 +2176,7 @@ USHORT CVT_make_string(const dsc* desc, temp_desc.dsc_address = (UCHAR *) temp; temp_desc.dsc_dtype = dtype_varying; temp_desc.setTextType(to_interp); - CVT_move(desc, &temp_desc, err); + CVT_move(desc, &temp_desc, decSt, err); *address = temp->vary_string; return temp->vary_length; @@ -2305,7 +2446,7 @@ SSHORT CVT_decompose(const char* string, USHORT CVT_get_string_ptr_common(const dsc* desc, USHORT* ttype, UCHAR** address, - vary* temp, USHORT length, Callbacks* cb) + vary* temp, USHORT length, DecimalStatus decSt, Callbacks* cb) { /************************************** * @@ -2371,7 +2512,7 @@ USHORT CVT_get_string_ptr_common(const dsc* desc, USHORT* ttype, UCHAR** address temp_desc.dsc_address = (UCHAR *) temp; temp_desc.dsc_dtype = dtype_varying; temp_desc.setTextType(ttype_ascii); - CVT_move_common(desc, &temp_desc, cb); + CVT_move_common(desc, &temp_desc, decSt, cb); *address = reinterpret_cast(temp->vary_string); *ttype = INTL_TTYPE(&temp_desc); @@ -2379,7 +2520,182 @@ USHORT CVT_get_string_ptr_common(const dsc* desc, USHORT* ttype, UCHAR** address } -SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, ErrorFunction err) +static inline void SINT64_to_SQUAD(const SINT64 input, const SQUAD& value) +{ + ((SLONG*) &value)[LOW_WORD] = (SLONG) (input & 0xffffffff); + ((SLONG*) &value)[HIGH_WORD] = (SLONG) (input >> 32); +} + + +Decimal64 CVT_get_dec64(const dsc* desc, DecimalStatus decSt, ErrorFunction err) +{ +/************************************** + * + * C V T _ g e t _ d e c 6 4 + * + ************************************** + * + * Functional description + * Convert something arbitrary to a DecFloat(16) / (64 bit). + * + **************************************/ + VaryStr<512> buffer; // long enough to represent largest decimal float in ASCII + Decimal64 d64; + + // adjust exact numeric values to same scaling + int scale = 0; + if (DTYPE_IS_EXACT(desc->dsc_dtype)) + scale = -desc->dsc_scale; + + const char* p = reinterpret_cast(desc->dsc_address); + + try + { + switch (desc->dsc_dtype) + { + case dtype_short: + return d64.set(*(SSHORT*) p, decSt, scale); + + case dtype_long: + return d64.set(*(SLONG*) p, decSt, scale); + + case dtype_quad: + return d64.set(CVT_get_int64(desc, 0, decSt, err), decSt, scale); + + case dtype_int64: + return d64.set(*(SINT64*) p, decSt, scale); + + case dtype_varying: + case dtype_cstring: + case dtype_text: + CVT_make_null_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer) - 1, decSt, err); + return d64.set(buffer.vary_string, decSt); + + case dtype_blob: + case dtype_sql_date: + case dtype_sql_time: + case dtype_timestamp: + case dtype_array: + case dtype_dbkey: + case dtype_boolean: + CVT_conversion_error(desc, err); + break; + + case dtype_real: + return d64.set(*((float*) p), decSt); + + case dtype_double: + return d64.set(*((double*) p), decSt); + + case dtype_dec64: + return *(Decimal64*) p; + + case dtype_dec128: + return ((Decimal128*) p)->toDecimal64(decSt); + + default: + fb_assert(false); + err(Arg::Gds(isc_badblk)); // internal error + break; + } + } + catch (const Exception& ex) + { + // reraise using passed error function + Arg::StatusVector v(ex); + err(v); + } + + // compiler silencer + return d64; +} + + +Decimal128 CVT_get_dec128(const dsc* desc, DecimalStatus decSt, ErrorFunction err) +{ +/************************************** + * + * C V T _ g e t _ d e c 1 2 8 + * + ************************************** + * + * Functional description + * Convert something arbitrary to a DecFloat(34) / (128 bit). + * + **************************************/ + VaryStr<1024> buffer; // represents unreasonably long decfloat literal in ASCII + Decimal128 d128; + + // adjust exact numeric values to same scaling + int scale = 0; + if (DTYPE_IS_EXACT(desc->dsc_dtype)) + scale = -desc->dsc_scale; + + const char* p = reinterpret_cast(desc->dsc_address); + + try + { + switch (desc->dsc_dtype) + { + case dtype_short: + return d128.set(*(SSHORT*) p, decSt, scale); + + case dtype_long: + return d128.set(*(SLONG*) p, decSt, scale); + + case dtype_quad: + return d128.set(CVT_get_int64(desc, 0, decSt, err), decSt, scale); + + case dtype_int64: + return d128.set(*(SINT64*) p, decSt, scale); + + case dtype_varying: + case dtype_cstring: + case dtype_text: + CVT_make_null_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer) - 1, decSt, err); + return d128.set(buffer.vary_string, decSt); + + case dtype_blob: + case dtype_sql_date: + case dtype_sql_time: + case dtype_timestamp: + case dtype_array: + case dtype_dbkey: + case dtype_boolean: + CVT_conversion_error(desc, err); + break; + + case dtype_real: + return d128.set(*((float*) p), decSt); + + case dtype_double: + return d128.set(*((double*) p), decSt); + + case dtype_dec64: + return (d128 = (*(Decimal64*) p)); // cast to higher precision never cause rounding/traps + + case dtype_dec128: + return *(Decimal128*) p; + + default: + fb_assert(false); + err(Arg::Gds(isc_badblk)); // internal error + break; + } + } + catch (const Exception& ex) + { + // reraise using passed error function + Arg::StatusVector v(ex); + err(v); + } + + // compiler silencer + return d128; +} + + +SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err) { /************************************** * @@ -2425,11 +2741,7 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, ErrorFunction err) break; case dtype_int64: - { - const SINT64 input = *(SINT64*) p; - ((SLONG*) &value)[LOW_WORD] = (SLONG) (input & 0xffffffff); - ((SLONG*) &value)[HIGH_WORD] = (SLONG) (input >> 32); - } + SINT64_to_SQUAD(*(SINT64*) p, value); break; case dtype_varying: @@ -2437,7 +2749,7 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, ErrorFunction err) case dtype_text: { USHORT length = - CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), err); + CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); scale -= CVT_decompose(p, length, dtype_quad, &value.gds_quad_high, err); } break; @@ -2452,6 +2764,11 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, ErrorFunction err) CVT_conversion_error(desc, err); break; + case dtype_dec64: + case dtype_dec128: + SINT64_to_SQUAD(CVT_get_int64(desc, scale, decSt, err), value); + break; + default: fb_assert(false); err(Arg::Gds(isc_badblk)); // internal error @@ -2470,7 +2787,7 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, ErrorFunction err) } -SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, ErrorFunction err) +SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err) { /************************************** * @@ -2512,6 +2829,18 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, ErrorFunction err) value = (((SINT64) ((SLONG*) p)[HIGH_WORD]) << 32) + (((ULONG*) p)[LOW_WORD]); break; + case dtype_dec64: + case dtype_dec128: + { + Decimal128 d128; + if (desc->dsc_dtype == dtype_dec64) + d128 = *((Decimal64*) p); + else + d128 = *((Decimal128*) p); + + return d128.toInt64(decSt, scale); + } + case dtype_real: case dtype_double: if (desc->dsc_dtype == dtype_real) @@ -2556,7 +2885,7 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, ErrorFunction err) case dtype_text: { USHORT length = - CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), err); + CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); scale -= CVT_decompose(p, length, dtype_int64, (SLONG *) & value, err); } break; @@ -2725,7 +3054,7 @@ namespace USHORT CVT_get_string_ptr(const dsc* desc, USHORT* ttype, UCHAR** address, - vary* temp, USHORT length, ErrorFunction err) + vary* temp, USHORT length, DecimalStatus decSt, ErrorFunction err) { /************************************** * @@ -2752,11 +3081,11 @@ USHORT CVT_get_string_ptr(const dsc* desc, USHORT* ttype, UCHAR** address, fb_assert(err != NULL); CommonCallbacks callbacks(err); - return CVT_get_string_ptr_common(desc, ttype, address, temp, length, &callbacks); + return CVT_get_string_ptr_common(desc, ttype, address, temp, length, decSt, &callbacks); } -void CVT_move(const dsc* from, dsc* to, ErrorFunction err) +void CVT_move(const dsc* from, dsc* to, DecimalStatus decSt, ErrorFunction err) { /************************************** * @@ -2769,5 +3098,5 @@ void CVT_move(const dsc* from, dsc* to, ErrorFunction err) * **************************************/ CommonCallbacks callbacks(err); - CVT_move_common(from, to, &callbacks); + CVT_move_common(from, to, decSt, &callbacks); } diff --git a/src/common/cvt.h b/src/common/cvt.h index f0b72bb85e..ca846413d7 100644 --- a/src/common/cvt.h +++ b/src/common/cvt.h @@ -29,6 +29,8 @@ #ifndef COMMON_CVT_H #define COMMON_CVT_H +#include "../common/DecFloat.h" + namespace Jrd { class CharSet; @@ -70,16 +72,19 @@ public: void CVT_conversion_error(const dsc*, ErrorFunction); double CVT_power_of_ten(const int); -SLONG CVT_get_long(const dsc*, SSHORT, ErrorFunction); +SLONG CVT_get_long(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction); bool CVT_get_boolean(const dsc*, ErrorFunction); -double CVT_get_double(const dsc*, ErrorFunction); -USHORT CVT_make_string(const dsc*, USHORT, const char**, vary*, USHORT, ErrorFunction); -void CVT_move_common(const dsc*, dsc*, Firebird::Callbacks*); -void CVT_move(const dsc*, 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); +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); -USHORT CVT_get_string_ptr(const dsc*, USHORT*, UCHAR**, vary*, USHORT, ErrorFunction); -USHORT CVT_get_string_ptr_common(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::Callbacks*); -SINT64 CVT_get_int64(const dsc*, SSHORT, ErrorFunction); -SQUAD CVT_get_quad(const dsc*, SSHORT, 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); +SQUAD CVT_get_quad(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction); #endif //COMMON_CVT_H diff --git a/src/common/dsc.cpp b/src/common/dsc.cpp index cb1a365cba..d4b7da2157 100644 --- a/src/common/dsc.cpp +++ b/src/common/dsc.cpp @@ -64,7 +64,9 @@ static const USHORT _DSC_convert_to_text_length[DTYPE_TYPE_MAX] = 9, // dtype_array FFFF:FFFF 20, // dtype_int64 -9223372036854775808 0, // dtype_dbkey - 5 // dtype_boolean + 5, // dtype_boolean + 23, // dtype_dec64 1 + 1 + 1 + 1 + 16(34) + 3(4) + 42 // dtype_dec128 +- . e +- coeff + exp }; // blr to dsc type conversions @@ -89,7 +91,9 @@ static const USHORT DSC_blr_type_mapping[] = blr_blob, blr_int64, blr_null, - blr_bool + blr_bool, + blr_dec64, + blr_dec128 }; // Unimplemented names are in lowercase & @@ -117,7 +121,9 @@ static const TEXT* const DSC_dtype_names[] = "ARRAY", "BIGINT", "DB_KEY", - "BOOLEAN" + "BOOLEAN", + "DECFLOAT(16)", + "DECFLOAT(34)" }; @@ -130,12 +136,12 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = { /* - dtype_unknown dtype_text dtype_cstring dtype_varying - 4 (unused) 5 (unused) dtype_packed dtype_byte - dtype_short dtype_long dtype_quad dtype_real + dtype_unknown dtype_text dtype_cstring dtype_varying + 4 (unused) 5 (unused) dtype_packed dtype_byte + dtype_short dtype_long dtype_quad dtype_real dtype_double dtype_d_float dtype_sql_date dtype_sql_time - dtype_timestamp dtype_blob dtype_array dtype_int64 - dtype_dbkey, dtype_boolean + dtype_timestamp dtype_blob dtype_array dtype_int64 + dtype_dbkey dtype_boolean dtype_dec64 dtype_dec128 */ // dtype_unknown @@ -144,7 +150,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_unknown, dtype_unknown, DTYPE_CANNOT, dtype_unknown, dtype_unknown, dtype_unknown, dtype_unknown, dtype_unknown, dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, dtype_unknown, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_unknown, dtype_unknown}, // dtype_text {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -152,7 +158,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_cstring {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -160,7 +166,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_varying {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -168,7 +174,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // 4 (unused) {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -176,7 +182,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // 5 (unused) {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -184,7 +190,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_packed {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -192,7 +198,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_byte {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -200,7 +206,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_short {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -208,7 +214,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_int64, dtype_int64, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_long {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -216,7 +222,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_int64, dtype_int64, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_quad {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -224,7 +230,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_real {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -232,7 +238,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, dtype_double}, // dtype_double {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -240,7 +246,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, dtype_double}, // dtype_d_float -- VMS deprecated {dtype_unknown, dtype_d_float, dtype_d_float, dtype_d_float, @@ -248,7 +254,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_d_float, dtype_d_float, DTYPE_CANNOT, dtype_d_float, dtype_d_float, dtype_d_float, dtype_sql_date, dtype_sql_time, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_d_float, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_d_float, dtype_d_float}, // dtype_sql_date {dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -256,7 +262,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_sql_date, dtype_sql_date, DTYPE_CANNOT, dtype_sql_date, dtype_sql_date, dtype_sql_date, DTYPE_CANNOT, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_sql_date, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_sql_date, dtype_sql_date}, // dtype_sql_time {dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -264,7 +270,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_sql_time, dtype_sql_time, DTYPE_CANNOT, dtype_sql_time, dtype_sql_time, dtype_sql_time, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_sql_time, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_sql_time, dtype_sql_time}, // dtype_timestamp {dtype_unknown, dtype_timestamp, dtype_timestamp, dtype_timestamp, @@ -272,7 +278,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_timestamp, dtype_timestamp, DTYPE_CANNOT, dtype_timestamp, dtype_timestamp, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, dtype_timestamp}, // dtype_blob {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -280,7 +286,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_array {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -288,7 +294,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_int64 {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -296,7 +302,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_int64, dtype_int64, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_dbkey {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -304,7 +310,7 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_boolean {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -312,7 +318,23 @@ const BYTE DSC_add_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT} + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, + + // dtype_dec64 + {dtype_unknown, dtype_dec128, dtype_dec128, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, + dtype_dec128, dtype_dec128, DTYPE_CANNOT, dtype_double, + dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time, + dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, + + // dtype_dec128 + {dtype_unknown, dtype_dec128, dtype_dec128, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, + dtype_dec128, dtype_dec128, DTYPE_CANNOT, dtype_double, + dtype_double, dtype_d_float, dtype_sql_date, dtype_sql_time, + dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128} }; @@ -325,12 +347,12 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = { /* - dtype_unknown dtype_text dtype_cstring dtype_varying - 4 (unused) 5 (unused) dtype_packed dtype_byte - dtype_short dtype_long dtype_quad dtype_real + dtype_unknown dtype_text dtype_cstring dtype_varying + 4 (unused) 5 (unused) dtype_packed dtype_byte + dtype_short dtype_long dtype_quad dtype_real dtype_double dtype_d_float dtype_sql_date dtype_sql_time - dtype_timestamp dtype_blob dtype_array dtype_int64 - dtype_dbkey, dtype_boolean + dtype_timestamp dtype_blob dtype_array dtype_int64 + dtype_dbkey dtype_boolean dtype_dec64 dtype_dec128 */ // dtype_unknown @@ -339,7 +361,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_unknown, dtype_unknown, DTYPE_CANNOT, dtype_unknown, dtype_unknown, dtype_unknown, dtype_unknown, dtype_unknown, dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, dtype_unknown, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_unknown, dtype_unknown}, // dtype_text {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -347,7 +369,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_cstring {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -355,7 +377,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_varying {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -363,7 +385,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // 4 (unused) {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -371,7 +393,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // 5 (unused) {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -379,7 +401,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_packed {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -387,7 +409,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_byte {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -395,7 +417,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_short {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -403,7 +425,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = 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_CANNOT, dtype_dec128, dtype_dec128}, // dtype_long {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -411,7 +433,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = 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_CANNOT, dtype_dec128, dtype_dec128}, // dtype_quad {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -419,7 +441,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_real {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -427,7 +449,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, dtype_double}, // dtype_double {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -435,7 +457,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, dtype_double}, // dtype_d_float -- VMS deprecated {dtype_unknown, dtype_d_float, dtype_d_float, dtype_d_float, @@ -443,7 +465,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_d_float, dtype_d_float, DTYPE_CANNOT, dtype_d_float, dtype_d_float, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_d_float, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_d_float, dtype_d_float}, // dtype_sql_date {dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -451,7 +473,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_sql_date, dtype_sql_date, DTYPE_CANNOT, dtype_sql_date, dtype_sql_date, dtype_sql_date, dtype_long, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_sql_date, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_sql_date, dtype_sql_date}, // dtype_sql_time {dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -459,7 +481,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_sql_time, dtype_sql_time, DTYPE_CANNOT, dtype_sql_time, dtype_sql_time, dtype_sql_time, DTYPE_CANNOT, dtype_long, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_sql_time, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_sql_time, dtype_sql_time}, // dtype_timestamp {dtype_unknown, dtype_timestamp, dtype_timestamp, dtype_timestamp, @@ -467,7 +489,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_timestamp, dtype_timestamp, DTYPE_CANNOT, dtype_timestamp, dtype_timestamp, dtype_timestamp, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_timestamp, dtype_timestamp}, // dtype_blob {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -475,7 +497,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_array {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -483,7 +505,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_int64 {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -491,7 +513,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = 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_CANNOT, dtype_dec128, dtype_dec128}, // dtype_dbkey {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -499,7 +521,7 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_boolean {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -507,7 +529,24 @@ const BYTE DSC_sub_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT} + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, + + // dtype_dec64 + {dtype_unknown, dtype_dec128, dtype_dec128, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, + dtype_dec128, dtype_dec128, DTYPE_CANNOT, dtype_double, + dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, + + // dtype_dec128 + {dtype_unknown, dtype_dec128, dtype_dec128, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, + dtype_dec128, dtype_dec128, DTYPE_CANNOT, dtype_double, + dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128} + }; @@ -520,12 +559,12 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = { /* - dtype_unknown dtype_text dtype_cstring dtype_varying - 4 (unused) 5 (unused) dtype_packed dtype_byte - dtype_short dtype_long dtype_quad dtype_real + dtype_unknown dtype_text dtype_cstring dtype_varying + 4 (unused) 5 (unused) dtype_packed dtype_byte + dtype_short dtype_long dtype_quad dtype_real dtype_double dtype_d_float dtype_sql_date dtype_sql_time - dtype_timestamp dtype_blob dtype_array dtype_int64 - dtype_dbkey, dtype_boolean + dtype_timestamp dtype_blob dtype_array dtype_int64 + dtype_dbkey dtype_boolean dtype_dec64 dtype_dec128 */ // dtype_unknown @@ -534,7 +573,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_unknown, dtype_unknown, DTYPE_CANNOT, dtype_unknown, dtype_unknown, dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_unknown, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_unknown, dtype_unknown}, // dtype_text {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -542,7 +581,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_cstring {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -550,7 +589,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_varying {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -558,7 +597,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // 4 (unused) {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -566,7 +605,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // 5 (unused) {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -574,7 +613,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_packed {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -582,7 +621,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_byte {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -590,7 +629,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_short {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -598,7 +637,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = 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_CANNOT, dtype_dec128, dtype_dec128}, // dtype_long {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -606,7 +645,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = 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_CANNOT, dtype_dec128, dtype_dec128}, // dtype_quad {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -614,7 +653,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_real {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -622,7 +661,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, dtype_double}, // dtype_double {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -630,7 +669,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, dtype_double}, // dtype_d_float -- VMS deprecated {dtype_unknown, dtype_d_float, dtype_d_float, dtype_d_float, @@ -638,7 +677,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_d_float, dtype_d_float, DTYPE_CANNOT, dtype_d_float, dtype_d_float, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_d_float, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_d_float, dtype_d_float}, // dtype_sql_date {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -646,7 +685,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_sql_time {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -654,7 +693,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_timestamp {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -662,7 +701,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_blob {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -670,7 +709,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_array {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -678,7 +717,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_int64 {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -686,7 +725,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = 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_CANNOT, dtype_dec128, dtype_dec128}, // dtype_dbkey {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -694,7 +733,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_boolean {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -702,7 +741,23 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT} + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, + + // dtype_dec64 + {dtype_unknown, dtype_dec128, dtype_dec128, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, + dtype_dec128, dtype_dec128, DTYPE_CANNOT, dtype_double, + dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, + + // dtype_dec128 + {dtype_unknown, dtype_dec128, dtype_dec128, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, + dtype_dec128, dtype_dec128, DTYPE_CANNOT, dtype_double, + dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128} }; @@ -715,12 +770,12 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = { /* - dtype_unknown dtype_text dtype_cstring dtype_varying - 4 (unused) 5 (unused) dtype_packed dtype_byte - dtype_short dtype_long dtype_quad dtype_real + dtype_unknown dtype_text dtype_cstring dtype_varying + 4 (unused) 5 (unused) dtype_packed dtype_byte + dtype_short dtype_long dtype_quad dtype_real dtype_double dtype_d_float dtype_sql_date dtype_sql_time - dtype_timestamp dtype_blob dtype_array dtype_int64 - dtype_dbkey, dtype_boolean + dtype_timestamp dtype_blob dtype_array dtype_int64 + dtype_dbkey dtype_boolean dtype_dec64 dtype_dec128 */ // dtype_unknown @@ -729,7 +784,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_unknown, dtype_unknown, DTYPE_CANNOT, dtype_unknown, dtype_unknown, dtype_unknown, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_unknown, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_unknown, dtype_unknown}, // dtype_text {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -737,7 +792,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_cstring {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -745,7 +800,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_varying {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -753,7 +808,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // 4 (unused) {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -761,7 +816,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // 5 (unused) {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -769,7 +824,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_packed {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -777,7 +832,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_byte {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -785,7 +840,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_short {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -793,7 +848,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_long, dtype_long, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_long {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -801,7 +856,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_long, dtype_long, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_quad {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -809,7 +864,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_real {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -817,7 +872,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, dtype_double}, // dtype_double {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -825,7 +880,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, dtype_double}, // dtype_d_float -- VMS deprecated {dtype_unknown, dtype_d_float, dtype_d_float, dtype_d_float, @@ -833,7 +888,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_d_float, dtype_d_float, DTYPE_CANNOT, dtype_d_float, dtype_d_float, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_d_float, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_d_float, dtype_d_float}, // dtype_sql_date {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -841,7 +896,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_sql_time {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -849,7 +904,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_timestamp {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -857,7 +912,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_blob {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -865,7 +920,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_array {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -873,7 +928,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_int64 {dtype_unknown, dtype_double, dtype_double, dtype_double, @@ -881,7 +936,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = dtype_double, dtype_double, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_double, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, // dtype_dbkey {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -889,7 +944,7 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT}, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, // dtype_boolean {DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, @@ -897,7 +952,23 @@ const BYTE DSC_multiply_blr4_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT} + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, + + // dtype_dec64 + {dtype_unknown, dtype_dec128, dtype_dec128, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, + dtype_dec128, dtype_dec128, DTYPE_CANNOT, dtype_double, + dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128}, + + // dtype_dec128 + {dtype_unknown, dtype_dec128, dtype_dec128, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, + dtype_dec128, dtype_dec128, DTYPE_CANNOT, dtype_double, + dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, + DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128} }; @@ -1003,6 +1074,16 @@ bool DSC_make_descriptor(DSC* desc, desc->dsc_dtype = dtype_double; break; + case blr_dec64: + desc->dsc_length = sizeof(Decimal64); + desc->dsc_dtype = dtype_dec64; + break; + + case blr_dec128: + desc->dsc_length = sizeof(Decimal128); + desc->dsc_dtype = dtype_dec128; + break; + case blr_timestamp: desc->dsc_length = 2 * sizeof(SLONG); desc->dsc_dtype = dtype_timestamp; @@ -1164,6 +1245,10 @@ const char* dsc::typeToText() const return "dbkey"; case dtype_boolean: return "boolean"; + case dtype_dec64: + return "decfloat(16)"; + case dtype_dec128: + return "decfloat(34)"; default: return "out of range"; } @@ -1252,6 +1337,16 @@ void dsc::getSqlInfo(SLONG* sqlLength, SLONG* sqlSubType, SLONG* sqlScale, SLONG *sqlType = SQL_BOOLEAN; break; + case dtype_dec64: + *sqlType = SQL_DEC16; + *sqlScale = 0; + break; + + case dtype_dec128: + *sqlType = SQL_DEC34; + *sqlScale = 0; + break; + default: status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-804) << diff --git a/src/common/dsc.h b/src/common/dsc.h index d2eb5a196e..29e77d16c4 100644 --- a/src/common/dsc.h +++ b/src/common/dsc.h @@ -31,6 +31,7 @@ #include "consts_pub.h" #include "../jrd/ods.h" #include "../intl/charsets.h" +#include "../common/DecFloat.h" // Data type information @@ -67,9 +68,14 @@ inline bool DTYPE_IS_APPROX(UCHAR d) return d == dtype_double || d == dtype_real; } +inline bool DTYPE_IS_DECFLOAT(UCHAR d) +{ + 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; + return (d >= dtype_byte && d <= dtype_d_float) || d == dtype_int64 || DTYPE_IS_DECFLOAT(d); } // Descriptor format @@ -155,6 +161,21 @@ typedef struct dsc return dsc_dtype >= dtype_sql_date && dsc_dtype <= dtype_timestamp; } + bool isDecFloat() const + { + return DTYPE_IS_DECFLOAT(dsc_dtype); + } + + bool isDecOrInt() const + { + return isDecFloat() || isExact(); + } + + bool isApprox() const + { + return DTYPE_IS_APPROX(dsc_dtype); + } + bool isUnknown() const { return dsc_dtype == dtype_unknown; @@ -259,6 +280,22 @@ typedef struct dsc dsc_address = (UCHAR*) address; } + void makeDecimal64(Firebird::Decimal64* address = NULL) + { + clear(); + dsc_dtype = dtype_dec64; + dsc_length = sizeof(Firebird::Decimal64); + dsc_address = (UCHAR*) address; + } + + void makeDecimal128(Firebird::Decimal128* address = NULL) + { + clear(); + dsc_dtype = dtype_dec128; + dsc_length = sizeof(Firebird::Decimal128); + dsc_address = (UCHAR*) address; + } + void makeInt64(SCHAR scale, SINT64* address = NULL) { clear(); diff --git a/src/common/dsc_pub.h b/src/common/dsc_pub.h index 6589b4d09b..57bf375a8a 100644 --- a/src/common/dsc_pub.h +++ b/src/common/dsc_pub.h @@ -61,7 +61,9 @@ #define dtype_int64 19 #define dtype_dbkey 20 #define dtype_boolean 21 -#define DTYPE_TYPE_MAX 22 +#define dtype_dec64 22 +#define dtype_dec128 23 +#define DTYPE_TYPE_MAX 24 #define ISC_TIME_SECONDS_PRECISION 10000 #define ISC_TIME_SECONDS_PRECISION_SCALE (-4) diff --git a/src/common/sdl.cpp b/src/common/sdl.cpp index e935a7583a..e813bc0896 100644 --- a/src/common/sdl.cpp +++ b/src/common/sdl.cpp @@ -845,6 +845,16 @@ static const UCHAR* sdl_desc(const UCHAR* ptr, DSC* desc) desc->dsc_length = sizeof(double); break; + case blr_dec64: + desc->dsc_dtype = dtype_dec64; + desc->dsc_length = sizeof(Decimal64); + break; + + case blr_dec128: + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + break; + case blr_timestamp: desc->dsc_dtype = dtype_timestamp; desc->dsc_length = sizeof(ISC_QUAD); diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 0e06968a7b..76c8cd1758 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -1480,89 +1480,66 @@ void logAndDie(const char* text) #endif } +UCHAR sqlTypeToDscType(SSHORT sqlType) +{ + switch (sqlType) + { + case SQL_VARYING: + return dtype_varying; + case SQL_TEXT: + return dtype_text; + case SQL_NULL: + return dtype_text; + case SQL_DOUBLE: + return dtype_double; + case SQL_FLOAT: + return dtype_real; + case SQL_D_FLOAT: + return dtype_d_float; + case SQL_TYPE_DATE: + return dtype_sql_date; + case SQL_TYPE_TIME: + return dtype_sql_time; + case SQL_TIMESTAMP: + return dtype_timestamp; + case SQL_BLOB: + return dtype_blob; + case SQL_ARRAY: + return dtype_array; + case SQL_LONG: + return dtype_long; + case SQL_SHORT: + return dtype_short; + case SQL_INT64: + return dtype_int64; + case SQL_QUAD: + return dtype_quad; + case SQL_BOOLEAN: + return dtype_boolean; + case SQL_DEC16: + return dtype_dec64; + case SQL_DEC34: + return dtype_dec128; + default: + return dtype_unknown; + } +} + unsigned sqlTypeToDsc(unsigned runOffset, unsigned sqlType, unsigned sqlLength, unsigned* dtype, unsigned* len, unsigned* offset, unsigned* nullOffset) { sqlType &= ~1; - unsigned dscType; + unsigned dscType = sqlTypeToDscType(sqlType); - switch (sqlType) + if (dscType == dtype_unknown) { - case SQL_VARYING: - dscType = dtype_varying; - break; - - case SQL_TEXT: - dscType = dtype_text; - break; - - case SQL_DOUBLE: - dscType = dtype_double; - break; - - case SQL_FLOAT: - dscType = dtype_real; - break; - - case SQL_D_FLOAT: - dscType = dtype_d_float; - break; - - case SQL_TYPE_DATE: - dscType = dtype_sql_date; - break; - - case SQL_TYPE_TIME: - dscType = dtype_sql_time; - break; - - case SQL_TIMESTAMP: - dscType = dtype_timestamp; - break; - - case SQL_BLOB: - dscType = dtype_blob; - break; - - case SQL_ARRAY: - dscType = dtype_array; - break; - - case SQL_LONG: - dscType = dtype_long; - break; - - case SQL_SHORT: - dscType = dtype_short; - break; - - case SQL_INT64: - dscType = dtype_int64; - break; - - case SQL_QUAD: - dscType = dtype_quad; - break; - - case SQL_BOOLEAN: - dscType = dtype_boolean; - break; - - case SQL_NULL: - dscType = dtype_text; - break; - - default: fb_assert(false); // keep old yvalve logic dscType = sqlType; - break; } if (dtype) - { *dtype = dscType; - } if (sqlType == SQL_VARYING) sqlLength += sizeof(USHORT); diff --git a/src/common/utils_proto.h b/src/common/utils_proto.h index 6acfa9e63d..e92efb5abe 100644 --- a/src/common/utils_proto.h +++ b/src/common/utils_proto.h @@ -184,6 +184,9 @@ namespace fb_utils void logAndDie(const char* text); + // On incorrect sqlType returns dsc_unknown + UCHAR sqlTypeToDscType(SSHORT sqlType); + // Returns next offset value unsigned sqlTypeToDsc(unsigned prevOffset, unsigned sqlType, unsigned sqlLength, unsigned* dtype, unsigned* len, unsigned* offset, unsigned* nullOffset); diff --git a/src/common/xdr.cpp b/src/common/xdr.cpp index 1dfff76e99..48cf627d7e 100644 --- a/src/common/xdr.cpp +++ b/src/common/xdr.cpp @@ -30,6 +30,7 @@ #include "../common/xdr_proto.h" #include "../yvalve/gds_proto.h" #include "../common/gdsassert.h" +#include "../common/DecFloat.h" inline UCHAR* XDR_ALLOC(ULONG size) { @@ -104,7 +105,7 @@ bool_t xdr_hyper( XDR* xdrs, void* pi64) { /************************************** * - * x d r _ h y p e r ( n o n - S O L A R I S ) + * x d r _ h y p e r * ************************************** * @@ -112,13 +113,6 @@ bool_t xdr_hyper( XDR* xdrs, void* pi64) * Map a 64-bit Integer from external to internal representation * (or vice versa). * - * Enable this for all platforms except Solaris (since it is - * available in the XDR library on Solaris). This function (normally) - * would have been implemented in REMOTE/xdr.c. Since some system - * XDR libraries (HP-UX) do not implement this function, we have it - * in this module. At a later date, when the function is available - * on all platforms, we can start using the system-provided version. - * * Handles "swapping" of the 2 long's to be "Endian" sensitive. * **************************************/ @@ -259,6 +253,18 @@ bool_t xdr_datum( XDR* xdrs, const dsc* desc, UCHAR* buffer) return FALSE; break; + case dtype_dec64: + fb_assert(desc->dsc_length >= sizeof(Firebird::Decimal64)); + if (!xdr_dec64(xdrs, reinterpret_cast(p))) + return FALSE; + break; + + case dtype_dec128: + fb_assert(desc->dsc_length >= sizeof(Firebird::Decimal128)); + if (!xdr_dec128(xdrs, reinterpret_cast(p))) + return FALSE; + break; + case dtype_timestamp: fb_assert(desc->dsc_length >= 2 * sizeof(SLONG)); if (!xdr_long(xdrs, &((SLONG*) p)[0])) @@ -337,6 +343,25 @@ bool_t xdr_double(XDR* xdrs, double* ip) } +bool_t xdr_dec64(XDR* xdrs, Firebird::Decimal64* ip) +{ + return xdr_hyper(xdrs, ip->getBytes()); +} + + +bool_t xdr_dec128(XDR* xdrs, Firebird::Decimal128* 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) { /************************************** diff --git a/src/common/xdr_proto.h b/src/common/xdr_proto.h index 0e063b2395..b9387e5363 100644 --- a/src/common/xdr_proto.h +++ b/src/common/xdr_proto.h @@ -27,12 +27,10 @@ #include "../common/dsc.h" #include "../common/xdr.h" -// 15 Jan 2003. Nickolay Samofatov -// Functions below need to have C++ linkage to avoid name clash with -// standard XDR. Firebird XDR is NOT compatible with Sun XDR at interface level - 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_enum(XDR*, xdr_op*); bool_t xdr_float(XDR*, float*); bool_t xdr_int(XDR*, int*); diff --git a/src/dsql/AggNodes.cpp b/src/dsql/AggNodes.cpp index f290728268..c095a0bc2b 100644 --- a/src/dsql/AggNodes.cpp +++ b/src/dsql/AggNodes.cpp @@ -281,7 +281,7 @@ bool AggNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const AggNode* o = other->as(); + const AggNode* o = nodeAs(other); fb_assert(o); // ASF: We compare name address. That should be ok, as we have only one AggInfo instance @@ -385,7 +385,7 @@ bool AggNode::aggPass(thread_db* tdbb, jrd_req* request) const to.dsc_sub_type = 0; to.dsc_scale = 0; to.dsc_ttype() = ttype_sort_key; - to.dsc_length = asb->keyItems[0].skd_length; + to.dsc_length = asb->keyItems[0].getSkdLength(); to.dsc_address = data; INTL_string_to_key(tdbb, INTL_TEXT_TO_INDEX(desc->getTextType()), desc, &to, INTL_KEY_UNIQUE); @@ -393,7 +393,7 @@ bool AggNode::aggPass(thread_db* tdbb, jrd_req* request) const dsc toDesc = asb->desc; toDesc.dsc_address = data + - (asb->intl ? asb->keyItems[1].skd_offset : 0); + (asb->intl ? asb->keyItems[1].getSkdOffset() : 0); MOV_move(tdbb, desc, &toDesc); // dimitr: Here we add a monotonically increasing value to the sort record. @@ -455,7 +455,7 @@ dsc* AggNode::execute(thread_db* tdbb, jrd_req* request) const break; } - desc.dsc_address = data + (asb->intl ? asb->keyItems[1].skd_offset : 0); + desc.dsc_address = data + (asb->intl ? asb->keyItems[1].getSkdOffset() : 0); aggPass(tdbb, request, &desc); } @@ -494,7 +494,12 @@ void AvgAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) if (desc->isNull()) return; - if (dialect1) + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + { + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + } + else if (dialect1) { if (!DTYPE_IS_NUMERIC(desc->dsc_dtype) && !DTYPE_IS_TEXT(desc->dsc_dtype)) { @@ -531,6 +536,17 @@ void AvgAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { arg->getDesc(tdbb, csb, desc); + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + { + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + nodFlags |= FLAG_DECFLOAT; + return; + } + if (dialect1) { if (!(DTYPE_IS_NUMERIC(desc->dsc_dtype) || DTYPE_IS_TEXT(desc->dsc_dtype))) @@ -601,7 +617,7 @@ AggNode* AvgAggNode::pass2(thread_db* tdbb, CompilerScratch* csb) { AggNode::pass2(tdbb, csb); - if (dialect1) + if (dialect1 && !(nodFlags & FLAG_DECFLOAT)) nodFlags |= FLAG_DOUBLE; // We need a second descriptor in the impure area for AVG. @@ -659,15 +675,23 @@ dsc* AvgAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const dsc temp; SINT64 i; double d; + Decimal128 dec; 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 (DTYPE_IS_DECFLOAT(impure->vlu_desc.dsc_dtype)) + { + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + dec.set(impure->vlux_count, decSt, 0); + dec = MOV_get_dec128(tdbb, &impure->vlu_desc).div(decSt, dec); + temp.makeDecimal128(&dec); + } else { - d = MOV_get_double(&impure->vlu_desc) / impure->vlux_count; + d = MOV_get_double(tdbb, &impure->vlu_desc) / impure->vlux_count; temp.makeDouble(&d); } @@ -961,7 +985,12 @@ void SumAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) if (desc->isNull()) return; - if (dialect1) + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + { + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + } + else if (dialect1) { if (!DTYPE_IS_NUMERIC(desc->dsc_dtype) && !DTYPE_IS_TEXT(desc->dsc_dtype)) { @@ -1008,6 +1037,16 @@ void SumAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { arg->getDesc(tdbb, csb, desc); + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + { + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + nodFlags |= FLAG_DECFLOAT; + return; + } + if (dialect1) { switch (desc->dsc_dtype) @@ -1237,7 +1276,7 @@ void MaxMinAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const return; } - const int result = MOV_compare(desc, &impure->vlu_desc); + const int result = MOV_compare(tdbb, desc, &impure->vlu_desc); if ((type == TYPE_MAX && result > 0) || (type == TYPE_MIN && result < 0)) EVL_make_value(tdbb, desc, impure); @@ -1290,13 +1329,32 @@ void StdDevAggNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /* void StdDevAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) { - desc->makeDouble(); + MAKE_desc(dsqlScratch, desc, arg); desc->setNullable(true); + + if (desc->isNull()) + return; + + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + desc->makeDecimal128(); + else + desc->makeDouble(); } void StdDevAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { - desc->makeDouble(); + arg->getDesc(tdbb, csb, desc); + + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + { + desc->makeDecimal128(); + nodFlags |= FLAG_DECFLOAT; + } + else + { + desc->makeDouble(); + nodFlags |= FLAG_DOUBLE; + } } ValueExprNode* StdDevAggNode::copy(thread_db* tdbb, NodeCopier& copier) const @@ -1331,10 +1389,18 @@ void StdDevAggNode::aggInit(thread_db* tdbb, jrd_req* request) const AggNode::aggInit(tdbb, request); impure_value_ex* impure = request->getImpure(impureOffset); - impure->make_double(0); - StdDevImpure* impure2 = request->getImpure(impure2Offset); - impure2->x = impure2->x2 = 0.0; + + if (nodFlags & FLAG_DECFLOAT) + { + impure->make_decimal128(CDecimal128(0)); + impure2->dec.x = impure2->dec.x2 = CDecimal128(0); + } + else + { + impure->make_double(0); + impure2->dbl.x = impure2->dbl.x2 = 0.0; + } } void StdDevAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const @@ -1342,11 +1408,22 @@ void StdDevAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const impure_value_ex* impure = request->getImpure(impureOffset); ++impure->vlux_count; - const double d = MOV_get_double(desc); - StdDevImpure* impure2 = request->getImpure(impure2Offset); - impure2->x += d; - impure2->x2 += d * d; + if (nodFlags & FLAG_DECFLOAT) + { + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + const Decimal128 d = MOV_get_dec128(tdbb, desc); + + impure2->dec.x = impure2->dec.x.add(decSt, d); + impure2->dec.x2 = impure2->dec.x2.fma(decSt, d, d); + } + else + { + const double d = MOV_get_double(tdbb, desc); + + impure2->dbl.x += d; + impure2->dbl.x2 += d * d; + } } dsc* StdDevAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const @@ -1354,6 +1431,12 @@ dsc* StdDevAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const impure_value_ex* impure = request->getImpure(impureOffset); StdDevImpure* impure2 = request->getImpure(impure2Offset); double d; + Decimal128 dec; + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + Decimal128 cnt; + if (nodFlags & FLAG_DECFLOAT) + cnt.set(impure->vlux_count, decSt, 0); switch (type) { @@ -1362,11 +1445,25 @@ dsc* StdDevAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const if (impure->vlux_count < 2) return NULL; - d = (impure2->x2 - impure2->x * impure2->x / impure->vlux_count) / - (impure->vlux_count - 1); + if (nodFlags & FLAG_DECFLOAT) + { + Decimal128 cntMinus1; + cntMinus1.set(impure->vlux_count - 1, decSt, 0); + dec = impure2->dec.x.mul(decSt, impure2->dec.x).div(decSt, cnt); + dec = impure2->dec.x2.sub(decSt, dec); + dec = dec.div(decSt, cntMinus1); - if (type == TYPE_STDDEV_SAMP) - d = sqrt(d); + if (type == TYPE_STDDEV_SAMP) + dec = dec.sqrt(decSt); + } + else + { + d = (impure2->dbl.x2 - impure2->dbl.x * impure2->dbl.x / impure->vlux_count) / + (impure->vlux_count - 1); + + if (type == TYPE_STDDEV_SAMP) + d = sqrt(d); + } break; case TYPE_STDDEV_POP: @@ -1374,18 +1471,33 @@ dsc* StdDevAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const if (impure->vlux_count == 0) return NULL; - d = (impure2->x2 - impure2->x * impure2->x / impure->vlux_count) / - impure->vlux_count; + if (nodFlags & FLAG_DECFLOAT) + { + dec = impure2->dec.x.mul(decSt, impure2->dec.x).div(decSt, cnt); + dec = impure2->dec.x2.sub(decSt, dec); + dec = dec.div(decSt, cnt); - if (type == TYPE_STDDEV_POP) - d = sqrt(d); + if (type == TYPE_STDDEV_SAMP) + dec = dec.sqrt(decSt); + } + else + { + d = (impure2->dbl.x2 - impure2->dbl.x * impure2->dbl.x / impure->vlux_count) / + impure->vlux_count; + + if (type == TYPE_STDDEV_POP) + d = sqrt(d); + } break; } dsc temp; - temp.makeDouble(&d); - EVL_make_value(tdbb, &temp, impure); + if (nodFlags & FLAG_DECFLOAT) + temp.makeDecimal128(&dec); + else + temp.makeDouble(&d); + EVL_make_value(tdbb, &temp, impure); return &impure->vlu_desc; } @@ -1426,13 +1538,32 @@ void CorrAggNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /*co void CorrAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) { - desc->makeDouble(); + MAKE_desc(dsqlScratch, desc, arg); desc->setNullable(true); + + if (desc->isNull()) + return; + + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + desc->makeDecimal128(); + else + desc->makeDouble(); } void CorrAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { - desc->makeDouble(); + arg->getDesc(tdbb, csb, desc); + + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + { + desc->makeDecimal128(); + nodFlags |= FLAG_DECFLOAT; + } + else + { + desc->makeDouble(); + nodFlags |= FLAG_DOUBLE; + } } ValueExprNode* CorrAggNode::copy(thread_db* tdbb, NodeCopier& copier) const @@ -1468,10 +1599,18 @@ void CorrAggNode::aggInit(thread_db* tdbb, jrd_req* request) const AggNode::aggInit(tdbb, request); impure_value_ex* impure = request->getImpure(impureOffset); - impure->make_double(0); - CorrImpure* impure2 = request->getImpure(impure2Offset); - impure2->x = impure2->x2 = impure2->y = impure2->y2 = impure2->xy = 0.0; + + if (nodFlags & FLAG_DECFLOAT) + { + impure->make_decimal128(CDecimal128(0)); + impure2->dec.x = impure2->dec.x2 = impure2->dec.y = impure2->dec.y2 = impure2->dec.xy = CDecimal128(0); + } + else + { + impure->make_double(0); + impure2->dbl.x = impure2->dbl.x2 = impure2->dbl.y = impure2->dbl.y2 = impure2->dbl.xy = 0.0; + } } bool CorrAggNode::aggPass(thread_db* tdbb, jrd_req* request) const @@ -1490,16 +1629,30 @@ bool CorrAggNode::aggPass(thread_db* tdbb, jrd_req* request) const return false; ++impure->vlux_count; - - const double y = MOV_get_double(desc); - const double x = MOV_get_double(desc2); - CorrImpure* impure2 = request->getImpure(impure2Offset); - impure2->x += x; - impure2->x2 += x * x; - impure2->y += y; - impure2->y2 += y * y; - impure2->xy += x * y; + + if (nodFlags & FLAG_DECFLOAT) + { + const Decimal128 y = MOV_get_dec128(tdbb, desc); + const Decimal128 x = MOV_get_dec128(tdbb, desc2); + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + impure2->dec.x = impure2->dec.x.add(decSt, x); + impure2->dec.x2 = impure2->dec.x2.fma(decSt, x, x); + impure2->dec.y = impure2->dec.y.add(decSt, y); + impure2->dec.y2 = impure2->dec.y2.fma(decSt, y, y); + impure2->dec.xy = impure2->dec.xy.fma(decSt, x, y); + } + else + { + const double y = MOV_get_double(tdbb, desc); + const double x = MOV_get_double(tdbb, desc2); + impure2->dbl.x += x; + impure2->dbl.x2 += x * x; + impure2->dbl.y += y; + impure2->dbl.y2 += y * y; + impure2->dbl.xy += x * y; + } return true; } @@ -1514,19 +1667,43 @@ dsc* CorrAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const impure_value_ex* impure = request->getImpure(impureOffset); CorrImpure* impure2 = request->getImpure(impure2Offset); double d; + Decimal128 dec; + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + Decimal128 cnt; + if (nodFlags & FLAG_DECFLOAT) + cnt.set(impure->vlux_count, decSt, 0); switch (type) { case TYPE_COVAR_SAMP: if (impure->vlux_count < 2) return NULL; - d = (impure2->xy - impure2->y * impure2->x / impure->vlux_count) / (impure->vlux_count - 1); + + if (nodFlags & FLAG_DECFLOAT) + { + Decimal128 cntMinus1; + cntMinus1.set(impure->vlux_count - 1, decSt, 0); + dec = impure2->dec.x.mul(decSt, impure2->dec.y).div(decSt, cnt); + dec = impure2->dec.xy.sub(decSt, dec); + dec = dec.div(decSt, cntMinus1); + } + else + d = (impure2->dbl.xy - impure2->dbl.y * impure2->dbl.x / impure->vlux_count) / (impure->vlux_count - 1); break; case TYPE_COVAR_POP: if (impure->vlux_count == 0) return NULL; - d = (impure2->xy - impure2->y * impure2->x / impure->vlux_count) / impure->vlux_count; + + if (nodFlags & FLAG_DECFLOAT) + { + dec = impure2->dec.x.mul(decSt, impure2->dec.y).div(decSt, cnt); + dec = impure2->dec.xy.sub(decSt, dec); + dec = dec.div(decSt, cnt); + } + else + d = (impure2->dbl.xy - impure2->dbl.y * impure2->dbl.x / impure->vlux_count) / impure->vlux_count; break; case TYPE_CORR: @@ -1535,24 +1712,51 @@ dsc* CorrAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const if (impure->vlux_count == 0) return NULL; - const double covarPop = (impure2->xy - impure2->y * impure2->x / impure->vlux_count) / - impure->vlux_count; - const double varPopX = (impure2->x2 - impure2->x * impure2->x / impure->vlux_count) / - impure->vlux_count; - const double varPopY = (impure2->y2 - impure2->y * impure2->y / impure->vlux_count) / - impure->vlux_count; - const double divisor = sqrt(varPopX) * sqrt(varPopY); + if (nodFlags & FLAG_DECFLOAT) + { + dec = impure2->dec.x.mul(decSt, impure2->dec.y).div(decSt, cnt); + dec = impure2->dec.xy.sub(decSt, dec); + const Decimal128 covarPop = dec.div(decSt, cnt); - if (divisor == 0.0) - return NULL; + dec = impure2->dec.x.mul(decSt, impure2->dec.x).div(decSt, cnt); + dec = impure2->dec.x2.sub(decSt, dec); + const Decimal128 varPopX = dec.div(decSt, cnt); - d = covarPop / divisor; + dec = impure2->dec.y.mul(decSt, impure2->dec.y).div(decSt, cnt); + dec = impure2->dec.y2.sub(decSt, dec); + const Decimal128 varPopY = dec.div(decSt, cnt); + + const Decimal128 divisor = varPopX.sqrt(decSt).mul(decSt, varPopY.sqrt(decSt)); + + if (divisor.compare(decSt, CDecimal128(0)) == 0) + return NULL; + + dec = covarPop.div(decSt, divisor); + } + else + { + const double covarPop = (impure2->dbl.xy - impure2->dbl.y * impure2->dbl.x / impure->vlux_count) / + impure->vlux_count; + const double varPopX = (impure2->dbl.x2 - impure2->dbl.x * impure2->dbl.x / impure->vlux_count) / + impure->vlux_count; + const double varPopY = (impure2->dbl.y2 - impure2->dbl.y * impure2->dbl.y / impure->vlux_count) / + impure->vlux_count; + const double divisor = sqrt(varPopX) * sqrt(varPopY); + + if (divisor == 0.0) + return NULL; + + d = covarPop / divisor; + } break; } } dsc temp; - temp.makeDouble(&d); + if (nodFlags & FLAG_DECFLOAT) + temp.makeDecimal128(&dec); + else + temp.makeDouble(&d); EVL_make_value(tdbb, &temp, impure); @@ -1612,13 +1816,32 @@ void RegrAggNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /*co void RegrAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) { - desc->makeDouble(); + MAKE_desc(dsqlScratch, desc, arg); desc->setNullable(true); + + if (desc->isNull()) + return; + + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + desc->makeDecimal128(); + else + desc->makeDouble(); } void RegrAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { - desc->makeDouble(); + arg->getDesc(tdbb, csb, desc); + + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + { + desc->makeDecimal128(); + nodFlags |= FLAG_DECFLOAT; + } + else + { + desc->makeDouble(); + nodFlags |= FLAG_DOUBLE; + } } ValueExprNode* RegrAggNode::copy(thread_db* tdbb, NodeCopier& copier) const @@ -1654,10 +1877,18 @@ void RegrAggNode::aggInit(thread_db* tdbb, jrd_req* request) const AggNode::aggInit(tdbb, request); impure_value_ex* impure = request->getImpure(impureOffset); - impure->make_double(0); - RegrImpure* impure2 = request->getImpure(impure2Offset); - impure2->x = impure2->x2 = impure2->y = impure2->y2 = impure2->xy = 0.0; + + if (nodFlags & FLAG_DECFLOAT) + { + impure->make_decimal128(CDecimal128(0)); + impure2->dec.x = impure2->dec.x2 = impure2->dec.y = impure2->dec.y2 = impure2->dec.xy = CDecimal128(0); + } + else + { + impure->make_double(0); + impure2->dbl.x = impure2->dbl.x2 = impure2->dbl.y = impure2->dbl.y2 = impure2->dbl.xy = 0.0; + } } bool RegrAggNode::aggPass(thread_db* tdbb, jrd_req* request) const @@ -1676,16 +1907,31 @@ bool RegrAggNode::aggPass(thread_db* tdbb, jrd_req* request) const return false; ++impure->vlux_count; - - const double y = MOV_get_double(desc); - const double x = MOV_get_double(desc2); - RegrImpure* impure2 = request->getImpure(impure2Offset); - impure2->x += x; - impure2->x2 += x * x; - impure2->y += y; - impure2->y2 += y * y; - impure2->xy += x * y; + + if (nodFlags & FLAG_DECFLOAT) + { + const Decimal128 y = MOV_get_dec128(tdbb, desc); + const Decimal128 x = MOV_get_dec128(tdbb, desc2); + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + impure2->dec.x = impure2->dec.x.add(decSt, x); + impure2->dec.x2 = impure2->dec.x2.fma(decSt, x, x); + impure2->dec.y = impure2->dec.y.add(decSt, y); + impure2->dec.y2 = impure2->dec.y2.fma(decSt, y, y); + impure2->dec.xy = impure2->dec.xy.fma(decSt, x, y); + } + else + { + const double y = MOV_get_double(tdbb, desc); + const double x = MOV_get_double(tdbb, desc2); + + impure2->dbl.x += x; + impure2->dbl.x2 += x * x; + impure2->dbl.y += y; + impure2->dbl.y2 += y * y; + impure2->dbl.xy += x * y; + } return true; } @@ -1699,74 +1945,148 @@ dsc* RegrAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const { impure_value_ex* impure = request->getImpure(impureOffset); RegrImpure* impure2 = request->getImpure(impure2Offset); + dsc temp; if (impure->vlux_count == 0) return NULL; - const double varPopX = (impure2->x2 - impure2->x * impure2->x / impure->vlux_count) / impure->vlux_count; - const double varPopY = (impure2->y2 - impure2->y * impure2->y / impure->vlux_count) / impure->vlux_count; - const double covarPop = (impure2->xy - impure2->y * impure2->x / impure->vlux_count) / impure->vlux_count; - const double avgX = impure2->x / impure->vlux_count; - const double avgY = impure2->y / impure->vlux_count; - const double slope = covarPop / varPopX; - const double sq = sqrt(varPopX) * sqrt(varPopY); - const double corr = covarPop / sq; - - double d; - - switch (type) + if (nodFlags & FLAG_DECFLOAT) { - case TYPE_REGR_AVGX: - d = avgX; - break; + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + Decimal128 cnt; + cnt.set(impure->vlux_count, decSt, 0); + DecimalStatus safeDivide = decSt; + safeDivide.decExtFlag &= ~DEC_Division_by_zero; - case TYPE_REGR_AVGY: - d = avgY; - break; + const Decimal128 sxx = impure2->dec.x2.sub(decSt, impure2->dec.x.mul(decSt, impure2->dec.x).div(decSt, cnt)); + const Decimal128 syy = impure2->dec.y2.sub(decSt, impure2->dec.y.mul(decSt, impure2->dec.y).div(decSt, cnt)); + const Decimal128 sxy = impure2->dec.xy.sub(decSt, impure2->dec.x.mul(decSt, impure2->dec.y).div(decSt, cnt)); + const Decimal128 varPopX = sxx.div(decSt, cnt); + const Decimal128 varPopY = syy.div(decSt, cnt); + const Decimal128 covarPop = sxy.div(decSt, cnt); + const Decimal128 avgX = impure2->dec.x.div(decSt, cnt); + const Decimal128 avgY = impure2->dec.y.div(decSt, cnt); + const Decimal128 slope = covarPop.div(safeDivide, varPopX); + const Decimal128 sq = varPopX.sqrt(decSt).mul(decSt, varPopY.sqrt(decSt)); + const Decimal128 corr = covarPop.div(safeDivide, sq); - case TYPE_REGR_INTERCEPT: - if (varPopX == 0.0) - return NULL; - else - d = avgY - slope * avgX; - break; + Decimal128 d; - case TYPE_REGR_R2: - if (varPopX == 0.0) - return NULL; - else if (varPopY == 0.0) - d = 1.0; - else if (sq == 0.0) - return NULL; - else - d = corr * corr; - break; + switch (type) + { + case TYPE_REGR_AVGX: + d = avgX; + break; - case TYPE_REGR_SLOPE: - if (varPopX == 0.0) - return NULL; - else - d = covarPop / varPopX; - break; + case TYPE_REGR_AVGY: + d = avgY; + break; - case TYPE_REGR_SXX: - d = impure->vlux_count * varPopX; - break; + case TYPE_REGR_INTERCEPT: + if (varPopX.compare(decSt, CDecimal128(0)) == 0) + return NULL; + else + d = avgY.sub(decSt, slope.mul(decSt, avgX)); + break; - case TYPE_REGR_SXY: - d = impure->vlux_count * covarPop; - break; + case TYPE_REGR_R2: + if (varPopX.compare(decSt, CDecimal128(0)) == 0) + return NULL; + else if (varPopY.compare(decSt, CDecimal128(0)) == 0) + d.set(1, decSt, 0); + else if (sq.compare(decSt, CDecimal128(0)) == 0) + return NULL; + else + d = corr.mul(decSt, corr); + break; - case TYPE_REGR_SYY: - d = impure->vlux_count * varPopY; - break; + case TYPE_REGR_SLOPE: + if (varPopX.compare(decSt, CDecimal128(0)) == 0) + return NULL; + else + d = slope; + break; + + case TYPE_REGR_SXX: + d = sxx; + break; + + case TYPE_REGR_SXY: + d = sxy; + break; + + case TYPE_REGR_SYY: + d = syy; + break; + } + + temp.makeDecimal128(&d); + } + else + { + const double varPopX = (impure2->dbl.x2 - impure2->dbl.x * impure2->dbl.x / impure->vlux_count) / impure->vlux_count; + const double varPopY = (impure2->dbl.y2 - impure2->dbl.y * impure2->dbl.y / impure->vlux_count) / impure->vlux_count; + const double covarPop = (impure2->dbl.xy - impure2->dbl.y * impure2->dbl.x / impure->vlux_count) / impure->vlux_count; + const double avgX = impure2->dbl.x / impure->vlux_count; + const double avgY = impure2->dbl.y / impure->vlux_count; + const double slope = covarPop / varPopX; + const double sq = sqrt(varPopX) * sqrt(varPopY); + const double corr = covarPop / sq; + + double d; + + switch (type) + { + case TYPE_REGR_AVGX: + d = avgX; + break; + + case TYPE_REGR_AVGY: + d = avgY; + break; + + case TYPE_REGR_INTERCEPT: + if (varPopX == 0.0) + return NULL; + else + d = avgY - slope * avgX; + break; + + case TYPE_REGR_R2: + if (varPopX == 0.0) + return NULL; + else if (varPopY == 0.0) + d = 1.0; + else if (sq == 0.0) + return NULL; + else + d = corr * corr; + break; + + case TYPE_REGR_SLOPE: + if (varPopX == 0.0) + return NULL; + else + d = covarPop / varPopX; + break; + + case TYPE_REGR_SXX: + d = impure->vlux_count * varPopX; + break; + + case TYPE_REGR_SXY: + d = impure->vlux_count * covarPop; + break; + + case TYPE_REGR_SYY: + d = impure->vlux_count * varPopY; + break; + } + + temp.makeDouble(&d); } - dsc temp; - temp.makeDouble(&d); - EVL_make_value(tdbb, &temp, impure); - return &impure->vlu_desc; } diff --git a/src/dsql/AggNodes.h b/src/dsql/AggNodes.h index 09ea54eb49..8dceaad48c 100644 --- a/src/dsql/AggNodes.h +++ b/src/dsql/AggNodes.h @@ -186,9 +186,16 @@ public: TYPE_VAR_POP }; - struct StdDevImpure + union StdDevImpure { - double x, x2; + struct + { + double x, x2; + } dbl; + struct + { + Firebird::Decimal128 x, x2; + } dec; }; explicit StdDevAggNode(MemoryPool& pool, StdDevType aType, ValueExprNode* aArg = NULL); @@ -230,9 +237,16 @@ public: TYPE_CORR }; - struct CorrImpure + union CorrImpure { - double x, x2, y, y2, xy; + struct + { + double x, x2, y, y2, xy; + } dbl; + struct + { + Firebird::Decimal128 x, x2, y, y2, xy; + } dec; }; explicit CorrAggNode(MemoryPool& pool, CorrType aType, @@ -282,9 +296,16 @@ public: TYPE_REGR_SYY }; - struct RegrImpure + union RegrImpure { - double x, x2, y, y2, xy; + struct + { + double x, x2, y, y2, xy; + } dbl; + struct + { + Firebird::Decimal128 x, x2, y, y2, xy; + } dec; }; explicit RegrAggNode(MemoryPool& pool, RegrType aType, diff --git a/src/dsql/BoolNodes.cpp b/src/dsql/BoolNodes.cpp index 9f6cefa3ee..0070c3067f 100644 --- a/src/dsql/BoolNodes.cpp +++ b/src/dsql/BoolNodes.cpp @@ -73,7 +73,7 @@ BoolExprNode* BoolExprNode::pass2(thread_db* tdbb, CompilerScratch* csb) if (csb->csb_current_nodes.hasData()) { - RseNode* topRseNode = csb->csb_current_nodes[0]->as(); + RseNode* topRseNode = nodeAs(csb->csb_current_nodes[0]); fb_assert(topRseNode); if (!topRseNode->rse_invariants) @@ -144,7 +144,7 @@ bool BinaryBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!BoolExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const BinaryBoolNode* o = other->as(); + const BinaryBoolNode* o = nodeAs(other); fb_assert(o); return blrOp == o->blrOp; @@ -152,7 +152,7 @@ bool BinaryBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const bool BinaryBoolNode::sameAs(const ExprNode* other, bool ignoreStreams) const { - const BinaryBoolNode* const otherNode = other->as(); + const BinaryBoolNode* const otherNode = nodeAs(other); if (!otherNode || blrOp != otherNode->blrOp) return false; @@ -366,7 +366,7 @@ BoolExprNode* ComparativeBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (dsqlSpecialArg) { - ValueListNode* listNode = dsqlSpecialArg->as(); + ValueListNode* listNode = nodeAs(dsqlSpecialArg); if (listNode) { int listItemCount = 0; @@ -392,7 +392,7 @@ BoolExprNode* ComparativeBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) return resultNode->dsqlPass(dsqlScratch); } - SelectExprNode* selNode = dsqlSpecialArg->as(); + SelectExprNode* selNode = nodeAs(dsqlSpecialArg); if (selNode) { fb_assert(!(selNode->dsqlFlags & RecordSourceNode::DFLAG_SINGLETON)); @@ -495,7 +495,7 @@ bool ComparativeBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) c if (!BoolExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const ComparativeBoolNode* o = other->as(); + const ComparativeBoolNode* o = nodeAs(other); fb_assert(o); return dsqlFlag == o->dsqlFlag && blrOp == o->blrOp; @@ -503,7 +503,7 @@ bool ComparativeBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) c bool ComparativeBoolNode::sameAs(const ExprNode* other, bool ignoreStreams) const { - const ComparativeBoolNode* const otherNode = other->as(); + const ComparativeBoolNode* const otherNode = nodeAs(other); if (!otherNode || blrOp != otherNode->blrOp) return false; @@ -582,7 +582,7 @@ BoolExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb) // If there is no top-level RSE present and patterns are not constant, unmark node as invariant // because it may be dependent on data or variables. if ((nodFlags & FLAG_INVARIANT) && - (!arg2->is() || (arg3 && !arg3->is()))) + (!nodeIs(arg2) || (arg3 && !nodeIs(arg3)))) { ExprNode* const* ctx_node; ExprNode* const* end; @@ -590,7 +590,7 @@ BoolExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb) for (ctx_node = csb->csb_current_nodes.begin(), end = csb->csb_current_nodes.end(); ctx_node != end; ++ctx_node) { - if ((*ctx_node)->as()) + if (nodeAs(*ctx_node)) break; } @@ -614,7 +614,7 @@ void ComparativeBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb) if (arg3) { - if ((keyNode = arg3->as()) && keyNode->aggregate) + if ((keyNode = nodeAs(arg3)) && keyNode->aggregate) ERR_post(Arg::Gds(isc_bad_dbkey)); dsc descriptor_c; @@ -627,8 +627,8 @@ void ComparativeBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb) } } - if (((keyNode = arg1->as()) && keyNode->aggregate) || - ((keyNode = arg2->as()) && keyNode->aggregate)) + if (((keyNode = nodeAs(arg1)) && keyNode->aggregate) || + ((keyNode = nodeAs(arg2)) && keyNode->aggregate)) { ERR_post(Arg::Gds(isc_bad_dbkey)); } @@ -768,13 +768,13 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const case blr_leq: case blr_neq: case blr_between: - comparison = MOV_compare(desc[0], desc[1]); + comparison = MOV_compare(tdbb, desc[0], desc[1]); } // If we are checking equality of record_version // and same transaction updated the record, force equality. - const RecordKeyNode* recVersionNode = arg1->as(); + const RecordKeyNode* recVersionNode = nodeAs(arg1); if (recVersionNode && recVersionNode->blrOp == blr_record_version && force_equal) comparison = 0; @@ -806,7 +806,7 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const desc[1] = EVL_expr(tdbb, request, arg3); if (request->req_flags & req_null) return false; - return comparison >= 0 && MOV_compare(desc[0], desc[1]) <= 0; + return comparison >= 0 && MOV_compare(tdbb, desc[0], desc[1]) <= 0; case blr_containing: case blr_starting: @@ -849,7 +849,7 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc* VaryStr<256> temp1; USHORT xtype1; - const USHORT l1 = MOV_get_string_ptr(desc1, &xtype1, &p1, &temp1, sizeof(temp1)); + const USHORT l1 = MOV_get_string_ptr(tdbb, desc1, &xtype1, &p1, &temp1, sizeof(temp1)); fb_assert(xtype1 == type1); @@ -915,7 +915,7 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc* break; } - escape_length = MOV_make_string(desc, type1, + escape_length = MOV_make_string(tdbb, desc, type1, reinterpret_cast(&escape_str), &temp3, sizeof(temp3)); if (!escape_length || charset->length(escape_length, escape_str, true) != 1) @@ -1124,7 +1124,7 @@ bool ComparativeBoolNode::stringFunction(thread_db* tdbb, jrd_req* request, return false; } - escape_length = MOV_make_string(desc, ttype, + escape_length = MOV_make_string(tdbb, desc, ttype, reinterpret_cast(&escape_str), &temp3, sizeof(temp3)); if (!escape_length || charset->length(escape_length, escape_str, true) != 1) @@ -1375,7 +1375,7 @@ BoolExprNode* MissingBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb) void MissingBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb) { - RecordKeyNode* keyNode = arg->as(); + RecordKeyNode* keyNode = nodeAs(arg); if (keyNode && keyNode->aggregate) ERR_post(Arg::Gds(isc_bad_dbkey)); @@ -1448,7 +1448,7 @@ BoolExprNode* NotBoolNode::copy(thread_db* tdbb, NodeCopier& copier) const BoolExprNode* NotBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb) { - RseBoolNode* rseBoolean = arg->as(); + RseBoolNode* rseBoolean = nodeAs(arg); if (rseBoolean) { @@ -1475,7 +1475,7 @@ bool NotBoolNode::execute(thread_db* tdbb, jrd_req* request) const // Get rid of redundant nested NOT predicates. BoolExprNode* NotBoolNode::process(DsqlCompilerScratch* dsqlScratch, bool invert) { - NotBoolNode* notArg = arg->as(); + NotBoolNode* notArg = nodeAs(arg); if (notArg) { @@ -1486,12 +1486,12 @@ BoolExprNode* NotBoolNode::process(DsqlCompilerScratch* dsqlScratch, bool invert if (!invert) return arg->dsqlPass(dsqlScratch); - ComparativeBoolNode* cmpArg = arg->as(); - BinaryBoolNode* binArg = arg->as(); + ComparativeBoolNode* cmpArg = nodeAs(arg); + BinaryBoolNode* binArg = nodeAs(arg); // Do not handle special case: NOT IN - if (cmpArg && (!cmpArg->dsqlSpecialArg || !cmpArg->dsqlSpecialArg->is())) + if (cmpArg && (!cmpArg->dsqlSpecialArg || !nodeIs(cmpArg->dsqlSpecialArg))) { // Invert the given boolean. switch (cmpArg->blrOp) @@ -1646,7 +1646,7 @@ BoolExprNode* RseBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) const DsqlContextStack::iterator base(*dsqlScratch->context); RseBoolNode* node = FB_NEW_POOL(getPool()) RseBoolNode(getPool(), blrOp, - PASS1_rse(dsqlScratch, dsqlRse->as(), false)); + PASS1_rse(dsqlScratch, nodeAs(dsqlRse), false)); // Finish off by cleaning up contexts dsqlScratch->context->clear(base); @@ -1657,7 +1657,7 @@ BoolExprNode* RseBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) void RseBoolNode::genBlr(DsqlCompilerScratch* dsqlScratch) { dsqlScratch->appendUChar(blrOp); - GEN_rse(dsqlScratch, dsqlRse->as()); + GEN_rse(dsqlScratch, nodeAs(dsqlRse)); } bool RseBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const @@ -1665,7 +1665,7 @@ bool RseBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!BoolExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const RseBoolNode* o = other->as(); + const RseBoolNode* o = nodeAs(other); fb_assert(o); return blrOp == o->blrOp; @@ -1676,7 +1676,7 @@ bool RseBoolNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!BoolExprNode::sameAs(other, ignoreStreams)) return false; - const RseBoolNode* const otherNode = other->as(); + const RseBoolNode* const otherNode = nodeAs(other); fb_assert(otherNode); return blrOp == otherNode->blrOp; @@ -1730,7 +1730,7 @@ BoolExprNode* RseBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb) BoolExprNode* boolean = rse->rse_boolean; if (boolean) { - BinaryBoolNode* const binaryNode = boolean->as(); + BinaryBoolNode* const binaryNode = nodeAs(boolean); if (binaryNode && binaryNode->blrOp == blr_and) boolean = binaryNode->arg2; @@ -1856,7 +1856,7 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc if (!outerRse || outerRse->type != RseNode::TYPE || outerRse->rse_relations.getCount() != 1 || !outerRse->rse_boolean || - !(outerRseNeq = outerRse->rse_boolean->as()) || + !(outerRseNeq = nodeAs(outerRse->rse_boolean)) || outerRseNeq->blrOp != blr_neq) { return NULL; diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 87d6a53476..a3fbff3880 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -393,26 +393,8 @@ void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relati field->subType = desc.dsc_sub_type; } - if (field && field->precision == 0 && field->scale != 0) - { - switch (field->dtype) - { - case dtype_short: - field->precision = 4; - break; - - case dtype_long: - field->precision = 9; - break; - - case dtype_int64: - field->precision = 18; - break; - - default: - fb_assert(!DTYPE_IS_EXACT(field->dtype)); - } - } + if (field) + field->setExactPrecision(); dsqlScratch->resetContextStack(); @@ -1043,9 +1025,9 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& ++ptr, ++position) { const ValueExprNode* element = *ptr++; - const SLONG lrange = element->as()->getSlong(); + const SLONG lrange = nodeAs(element)->getSlong(); element = *ptr; - const SLONG hrange = element->as()->getSlong(); + const SLONG hrange = nodeAs(element)->getSlong(); if (lrange >= hrange) { @@ -1565,7 +1547,7 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) const NestConst* ptr = variables->statements.begin(); for (const NestConst* const end = variables->statements.end(); ptr != end; ++ptr) { - const DeclareVariableNode* varNode = (*ptr)->as(); + const DeclareVariableNode* varNode = nodeAs(*ptr); if (varNode) { @@ -2011,9 +1993,11 @@ void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch ARG.RDB$MECHANISM.NULL = TRUE; ARG.RDB$FIELD_TYPE.NULL = TRUE; ARG.RDB$FIELD_LENGTH.NULL = TRUE; + ARG.RDB$FIELD_SUB_TYPE.NULL = TRUE; ARG.RDB$FIELD_PRECISION.NULL = TRUE; ARG.RDB$FIELD_SCALE.NULL = TRUE; ARG.RDB$CHARACTER_SET_ID.NULL = TRUE; + ARG.RDB$CHARACTER_LENGTH.NULL = TRUE; ARG.RDB$COLLATION_ID.NULL = TRUE; ARG.RDB$ARGUMENT_MECHANISM.NULL = TRUE; @@ -2569,7 +2553,7 @@ DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) const NestConst* ptr = variables->statements.begin(); for (const NestConst* const end = variables->statements.end(); ptr != end; ++ptr) { - const DeclareVariableNode* varNode = (*ptr)->as(); + const DeclareVariableNode* varNode = nodeAs(*ptr); if (varNode) { @@ -3878,6 +3862,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra { if (MET_get_char_coll_subtype_info(tdbb, INTL_CS_COLL_TO_TTYPE(forCharSetId, fromCollationId), &info) && + forCharSetId != CS_METADATA && info.specificAttributes.hasData()) { UCharBuffer temp; @@ -4475,6 +4460,8 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld) case blr_d_float: case blr_double: case blr_float: + case blr_dec64: + case blr_dec128: switch (newFld.dyn_dtype) { case blr_blob: @@ -4571,6 +4558,44 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld) } break; + case blr_dec64: + switch (origFld.dyn_dtype) + { + case blr_short: + case blr_long: + case blr_float: + case blr_d_float: + case blr_double: + case blr_dec64: + break; + + default: + // Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported. + errorCode = isc_dyn_invalid_dtype_conversion; + break; + } + break; + + case blr_dec128: + switch (origFld.dyn_dtype) + { + case blr_short: + case blr_long: + case blr_int64: + case blr_float: + case blr_d_float: + case blr_double: + case blr_dec64: + case blr_dec128: + break; + + default: + // Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported. + errorCode = isc_dyn_invalid_dtype_conversion; + break; + } + break; + // If the original field is a numeric field and the new field is a character field, // is there enough space in the new field? case blr_text: @@ -6365,7 +6390,7 @@ bool RelationNode::defineDefault(thread_db* /*tdbb*/, DsqlCompilerScratch* dsqlS value.assign(dsqlScratch->getBlrData()); - return ExprNode::is(input); + return nodeIs(input); } // Make a constraint object from a legacy node. @@ -8641,22 +8666,21 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra ValueExprNode* nameNode = fieldNode; const char* aliasName = NULL; - while (nameNode->is() || nameNode->is() || - nameNode->is()) + while (nodeIs(nameNode) || nodeIs(nameNode) || nodeIs(nameNode)) { DsqlAliasNode* aliasNode; DsqlMapNode* mapNode; DerivedFieldNode* derivedField; - if ((aliasNode = nameNode->as())) + if ((aliasNode = nodeAs(nameNode))) { if (!aliasName) aliasName = aliasNode->name.c_str(); nameNode = aliasNode->value; } - else if ((mapNode = nameNode->as())) + else if ((mapNode = nodeAs(nameNode))) nameNode = mapNode->map->map_node; - else if ((derivedField = nameNode->as())) + else if ((derivedField = nodeAs(nameNode))) { if (!aliasName) aliasName = derivedField->name.c_str(); @@ -8665,7 +8689,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra } const dsql_fld* nameField = NULL; - const FieldNode* fieldNameNode = nameNode->as(); + const FieldNode* fieldNameNode = nodeAs(nameNode); if (fieldNameNode) nameField = fieldNameNode->dsqlField; @@ -8679,7 +8703,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra // Check if this is a field or an expression. - DsqlAliasNode* aliasNode = fieldNode->as(); + DsqlAliasNode* aliasNode = nodeAs(fieldNode); if (aliasNode) fieldNode = aliasNode->value; @@ -8687,7 +8711,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra dsql_fld* field = NULL; const dsql_ctx* context = NULL; - fieldNameNode = fieldNode->as(); + fieldNameNode = nodeAs(fieldNode); if (fieldNameNode) { @@ -8714,7 +8738,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra if (ptr) { if (ptr < end) - fieldStr = (*ptr)->as()->dsqlName.c_str(); + fieldStr = nodeAs(*ptr)->dsqlName.c_str(); else { // Generate an error when going out of this loop. @@ -8830,6 +8854,8 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra else newField.subType = desc.dsc_sub_type; + newField.setExactPrecision(); + if (relField) // modifying a view { AutoRequest request2; @@ -8925,11 +8951,11 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra Arg::Gds(isc_col_name_err)); } - RseNode* querySpec = selectExpr->querySpec->as(); + RseNode* querySpec = nodeAs(selectExpr->querySpec); fb_assert(querySpec); if (querySpec->dsqlFrom->items.getCount() != 1 || - !querySpec->dsqlFrom->items[0]->is()) + !nodeIs(querySpec->dsqlFrom->items[0])) { // Only one table allowed for VIEW WITH CHECK OPTION status_exception::raise( @@ -8997,10 +9023,10 @@ void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratc dsqlScratch->resetContextStack(); - RseNode* querySpec = selectExpr->querySpec->as(); + RseNode* querySpec = nodeAs(selectExpr->querySpec); fb_assert(querySpec); - ProcedureSourceNode* sourceNode = querySpec->dsqlFrom->items[0]->as(); + ProcedureSourceNode* sourceNode = nodeAs(querySpec->dsqlFrom->items[0]); if (triggerType == PRE_MODIFY_TRIGGER) { @@ -9069,14 +9095,14 @@ void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratc NestConst valueNod = *ptr2; DsqlAliasNode* aliasNode; - if ((aliasNode = fieldNod->as())) + if ((aliasNode = nodeAs(fieldNod))) fieldNod = aliasNode->value; - if ((aliasNode = valueNod->as())) + if ((aliasNode = nodeAs(valueNod))) valueNod = aliasNode->value; - FieldNode* fieldNode = fieldNod->as(); - FieldNode* valueNode = valueNod->as(); + FieldNode* fieldNode = nodeAs(fieldNod); + FieldNode* valueNode = nodeAs(valueNod); // Generate the actual comparisons. @@ -9135,10 +9161,10 @@ void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratc ValueExprNode* valueNode = *ptr; DsqlAliasNode* aliasNode; - if ((aliasNode = valueNode->as())) + if ((aliasNode = nodeAs(valueNode))) valueNode = aliasNode->value; - FieldNode* fieldNode = valueNode->as(); + FieldNode* fieldNode = nodeAs(valueNode); fb_assert(fieldNode); savedNames.add(field->fld_name); @@ -9577,7 +9603,7 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, for (; ptr != end; ++ptr) { MetaName& column = definition.columns.add(); - column = (*ptr)->as()->dsqlName; + column = nodeAs(*ptr)->dsqlName; } } else if (computed) @@ -10613,7 +10639,7 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd if (ddlTriggerAction > 0) executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); - DFW_post_work(transaction, dfw_clear_cache, NULL, MAPPING_CACHE); + DFW_post_work(transaction, dfw_clear_cache, NULL, Mapping::MAPPING_CACHE); savePoint.release(); // everything is ok } @@ -11005,7 +11031,7 @@ void GrantRevokeNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, } // Invalidate system privileges cache - DFW_post_work(transaction, dfw_clear_cache, NULL, SYSTEM_PRIVILEGES_CACHE); + DFW_post_work(transaction, dfw_clear_cache, NULL, Mapping::SYSTEM_PRIVILEGES_CACHE); } } @@ -11123,7 +11149,7 @@ void GrantRevokeNode::modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SS for (NestConst* ptr = fields->items.begin(); ptr != fields->items.end(); ++ptr) { grantRevoke(tdbb, transaction, object, user, privs0, - (*ptr)->as()->dsqlName, option); + nodeAs(*ptr)->dsqlName, option); } } else diff --git a/src/dsql/DsqlCompilerScratch.cpp b/src/dsql/DsqlCompilerScratch.cpp index 352a94fa86..7d6800e56f 100644 --- a/src/dsql/DsqlCompilerScratch.cpp +++ b/src/dsql/DsqlCompilerScratch.cpp @@ -278,7 +278,7 @@ void DsqlCompilerScratch::putLocalVariables(CompoundStmtNode* parameters, USHORT DeclareVariableNode* varNode; - if ((varNode = parameter->as())) + if ((varNode = nodeAs(parameter))) { dsql_fld* field = varNode->dsqlDef->type; const NestConst* rest = ptr; @@ -287,7 +287,7 @@ void DsqlCompilerScratch::putLocalVariables(CompoundStmtNode* parameters, USHORT { const DeclareVariableNode* varNode2; - if ((varNode2 = (*rest)->as())) + if ((varNode2 = nodeAs(*rest))) { const dsql_fld* rest_field = varNode2->dsqlDef->type; @@ -607,11 +607,11 @@ void DsqlCompilerScratch::checkUnusedCTEs() const SelectExprNode* DsqlCompilerScratch::pass1RecursiveCte(SelectExprNode* input) { RecordSourceNode* const query = input->querySpec; - UnionSourceNode* unionQuery = query->as(); + UnionSourceNode* unionQuery = nodeAs(query); if (!unionQuery) { - if (!pass1RseIsRecursive(query->as())) + if (!pass1RseIsRecursive(nodeAs(query))) return input; ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << @@ -640,7 +640,7 @@ SelectExprNode* DsqlCompilerScratch::pass1RecursiveCte(SelectExprNode* input) if (iter == unionQuery->dsqlClauses->items.begin()) { - unionQuery = clause->as(); + unionQuery = nodeAs(clause); if (unionQuery) { @@ -654,7 +654,7 @@ SelectExprNode* DsqlCompilerScratch::pass1RecursiveCte(SelectExprNode* input) } } - RseNode* const rse = clause->as(); + RseNode* const rse = nodeAs(clause); fb_assert(rse); RseNode* const newRse = pass1RseIsRecursive(rse); @@ -815,7 +815,7 @@ RseNode* DsqlCompilerScratch::pass1RseIsRecursive(RseNode* input) { *prev++ = *pDstTable = *pSrcTable; - RseNode* rseNode = (*pDstTable)->as(); + RseNode* rseNode = nodeAs(*pDstTable); if (rseNode) { @@ -841,7 +841,7 @@ RseNode* DsqlCompilerScratch::pass1RseIsRecursive(RseNode* input) result->dsqlWhere = PASS1_compose(result->dsqlWhere, joinBool, blr_and); } } - else if ((*pDstTable)->is() || (*pDstTable)->is()) + else if (nodeIs(*pDstTable) || nodeIs(*pDstTable)) { if (pass1RelProcIsRecursive(*pDstTable)) { @@ -858,9 +858,7 @@ RseNode* DsqlCompilerScratch::pass1RseIsRecursive(RseNode* input) } } else - { - fb_assert((*pDstTable)->is()); - } + fb_assert(nodeIs(*pDstTable)); } if (found) @@ -877,12 +875,12 @@ bool DsqlCompilerScratch::pass1RelProcIsRecursive(RecordSourceNode* input) ProcedureSourceNode* procNode; RelationSourceNode* relNode; - if ((procNode = input->as())) + if ((procNode = nodeAs(input))) { relName = procNode->dsqlName.identifier; relAlias = procNode->alias; } - else if ((relNode = input->as())) + else if ((relNode = nodeAs(input))) { relName = relNode->dsqlName; relAlias = relNode->alias; @@ -906,7 +904,7 @@ bool DsqlCompilerScratch::pass1RelProcIsRecursive(RecordSourceNode* input) // outer join or more than one recursive reference is found BoolExprNode* DsqlCompilerScratch::pass1JoinIsRecursive(RecordSourceNode*& input) { - RseNode* inputRse = input->as(); + RseNode* inputRse = nodeAs(input); fb_assert(inputRse); const UCHAR joinType = inputRse->rse_jointype; @@ -917,7 +915,7 @@ BoolExprNode* DsqlCompilerScratch::pass1JoinIsRecursive(RecordSourceNode*& input NestConst* joinTable = &inputRse->dsqlFrom->items[0]; RseNode* joinRse; - if ((joinRse = (*joinTable)->as()) && joinRse->dsqlExplicitJoin) + if ((joinRse = nodeAs(*joinTable)) && joinRse->dsqlExplicitJoin) { leftBool = pass1JoinIsRecursive(*joinTable->getAddress()); leftRecursive = (leftBool != NULL); @@ -943,7 +941,7 @@ BoolExprNode* DsqlCompilerScratch::pass1JoinIsRecursive(RecordSourceNode*& input joinTable = &inputRse->dsqlFrom->items[1]; - if ((joinRse = (*joinTable)->as()) && joinRse->dsqlExplicitJoin) + if ((joinRse = nodeAs(*joinTable)) && joinRse->dsqlExplicitJoin) { rightBool = pass1JoinIsRecursive(*joinTable->getAddress()); rightRecursive = (rightBool != NULL); diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 7fe34cf928..b182d78b0f 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -48,6 +48,7 @@ #include "../jrd/mov_proto.h" #include "../jrd/pag_proto.h" #include "../jrd/par_proto.h" +#include "../jrd/cvt2_proto.h" #include "../dsql/ddl_proto.h" #include "../dsql/errd_proto.h" #include "../dsql/gen_proto.h" @@ -147,7 +148,7 @@ namespace for (ExprNode** node = csb->csb_current_nodes.end() - 1; node >= csb->csb_current_nodes.begin(); --node) { - RseNode* const rseNode = (*node)->as(); + RseNode* const rseNode = nodeAs(*node); if (rseNode) { @@ -194,7 +195,7 @@ void NodeRef::pass2(thread_db* tdbb, CompilerScratch* csb) { if (csb->csb_current_nodes.hasData()) { - RseNode* topRseNode = csb->csb_current_nodes[0]->as(); + RseNode* topRseNode = nodeAs(csb->csb_current_nodes[0]); fb_assert(topRseNode); if (!topRseNode->rse_invariants) @@ -485,7 +486,7 @@ void ArithmeticNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) desc2.setNull(); } - if (arg1->is() && arg2->is()) + if (nodeIs(arg1) && nodeIs(arg2)) { // NULL + NULL = NULL of INT desc->makeLong(0); @@ -647,6 +648,14 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2) desc->dsc_length = sizeof(double); break; + case dtype_dec64: + case dtype_dec128: + desc->dsc_dtype = dtype_dec128; + desc->dsc_sub_type = 0; + desc->dsc_scale = 0; + desc->dsc_length = sizeof(Decimal128); + break; + default: desc->dsc_dtype = dtype_long; desc->dsc_sub_type = 0; @@ -670,6 +679,13 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2) switch (dtype) { + case dtype_dec128: + desc->dsc_dtype = dtype_dec128; + desc->dsc_sub_type = 0; + desc->dsc_scale = 0; + desc->dsc_length = sizeof(Decimal128); + break; + case dtype_double: desc->dsc_dtype = dtype_double; desc->dsc_sub_type = 0; @@ -709,6 +725,15 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2) dtype = MAX(dtype1, dtype2); + if (DTYPE_IS_DECFLOAT(dtype)) + { + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable; + break; + } + if (!DTYPE_IS_NUMERIC(dtype)) { ERRD_post(Arg::Gds(isc_expression_eval_err) << @@ -755,6 +780,8 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2) // arithmetic, but returns a if (DTYPE_IS_EXACT(dtype1) && DTYPE_IS_EXACT(dtype2)) dtype = dtype_int64; + else if (desc1.isDecOrInt() && desc2.isDecOrInt()) + dtype = dtype_dec128; else if (DTYPE_IS_NUMERIC(dtype1) && DTYPE_IS_NUMERIC(dtype2)) { fb_assert(DTYPE_IS_APPROX(dtype1) || DTYPE_IS_APPROX(dtype2)); @@ -771,7 +798,7 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2) if (dtype_int64 == dtype2) dtype2 = dtype_double; - dtype = MAX(dtype1, dtype2); + dtype = CVT2_compare_priority[dtype1] > CVT2_compare_priority[dtype2] ? dtype1 : dtype2; } desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable; @@ -875,6 +902,14 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2) desc->dsc_length = sizeof(double); break; + case dtype_dec64: + case dtype_dec128: + desc->dsc_dtype = dtype_dec128; + desc->dsc_sub_type = 0; + desc->dsc_scale = 0; + desc->dsc_length = sizeof(Decimal128); + break; + case dtype_short: case dtype_long: case dtype_int64: @@ -920,6 +955,13 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2) switch (dtype) { + case dtype_dec128: + desc->dsc_dtype = dtype_dec128; + desc->dsc_sub_type = 0; + desc->dsc_scale = 0; + desc->dsc_length = sizeof(Decimal128); + break; + case dtype_double: desc->dsc_dtype = dtype_double; desc->dsc_sub_type = 0; @@ -973,6 +1015,11 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2) desc->dsc_scale = 0; break; + case dtype_dec128: + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + break; + default: ERRD_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_dsql_invalid_type_div_dial3)); @@ -1168,6 +1215,16 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1, desc->dsc_flags = 0; return; + case dtype_dec64: + case dtype_dec128: + nodFlags |= FLAG_DECFLOAT; + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + break; + case dtype_unknown: desc->dsc_dtype = dtype_unknown; desc->dsc_length = 0; @@ -1210,6 +1267,15 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1, desc->dsc_flags = 0; return; + case dtype_dec128: + nodFlags |= FLAG_DECFLOAT; + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + break; + case dtype_unknown: desc->dsc_dtype = dtype_unknown; desc->dsc_length = 0; @@ -1230,6 +1296,18 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1, break; case blr_divide: + /*** + if (desc1.isDecOrInt() && desc2.isDecOrInt()) + { + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + return; + } + ***/ + // for compatibility with older versions of the product, we accept // text types for division in blr_version4 (dialect <= 1) only if (!(DTYPE_IS_NUMERIC(desc1.dsc_dtype) || DTYPE_IS_TEXT(desc1.dsc_dtype))) @@ -1270,7 +1348,7 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1, USHORT dtype1 = desc1.dsc_dtype; USHORT dtype2 = desc2.dsc_dtype; - // In Dialect 2 or 3, strings can never partipate in addition / sub + // In Dialect 2 or 3, strings can never participate in addition / sub // (use a specific cast instead) if (DTYPE_IS_TEXT(dtype1) || DTYPE_IS_TEXT(dtype2)) ERR_post(Arg::Gds(isc_expression_eval_err)); @@ -1281,6 +1359,8 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1, if (DTYPE_IS_EXACT(desc1.dsc_dtype) && DTYPE_IS_EXACT(desc2.dsc_dtype)) dtype = dtype_int64; + else if (desc1.isDecOrInt() && desc2.isDecOrInt()) + dtype = dtype_dec128; else if (DTYPE_IS_NUMERIC(desc1.dsc_dtype) && DTYPE_IS_NUMERIC(desc2.dsc_dtype)) dtype = dtype_double; else @@ -1411,6 +1491,16 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1, desc->dsc_flags = 0; return; + case dtype_dec64: + case dtype_dec128: + nodFlags |= FLAG_DECFLOAT; + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + return; + case dtype_short: case dtype_long: case dtype_int64: @@ -1460,6 +1550,15 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1, desc->dsc_flags = 0; return; + case dtype_dec128: + nodFlags |= FLAG_DECFLOAT; + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + return; + case dtype_int64: desc->dsc_dtype = dtype_int64; desc->dsc_length = sizeof(SINT64); @@ -1509,7 +1608,7 @@ bool ArithmeticNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const ArithmeticNode* o = other->as(); + const ArithmeticNode* o = nodeAs(other); fb_assert(o); return dialect1 == o->dialect1 && blrOp == o->blrOp; @@ -1517,7 +1616,7 @@ bool ArithmeticNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const bool ArithmeticNode::sameAs(const ExprNode* other, bool ignoreStreams) const { - const ArithmeticNode* const otherNode = other->as(); + const ArithmeticNode* const otherNode = nodeAs(other); if (!otherNode || blrOp != otherNode->blrOp || dialect1 != otherNode->dialect1) return false; @@ -1590,7 +1689,7 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const case blr_divide: { - const double divisor = MOV_get_double(desc2); + const double divisor = MOV_get_double(tdbb, desc2); if (divisor == 0) { @@ -1598,7 +1697,7 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const Arg::Gds(isc_exception_float_divide_by_zero)); } - impure->vlu_misc.vlu_double = MOV_get_double(desc1) / divisor; + impure->vlu_misc.vlu_double = MOV_get_double(tdbb, desc1) / divisor; if (isinf(impure->vlu_misc.vlu_double)) { @@ -1633,7 +1732,7 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const } } - BUGCHECK(232); // msg 232 EVL_expr: invalid operation + SOFT_BUGCHECK(232); // msg 232 EVL_expr: invalid operation return NULL; } @@ -1641,14 +1740,15 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const // This function can be removed when dialect-3 becomes the lowest supported dialect. (Version 7.0?) dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNode* node, const UCHAR blrOp) { - const ArithmeticNode* arithmeticNode = node->as(); + const ArithmeticNode* arithmeticNode = nodeAs(node); + thread_db* tdbb = JRD_get_thread_data(); #ifdef DEV_BUILD - const SubQueryNode* subQueryNode = node->as(); + const SubQueryNode* subQueryNode = nodeAs(node); fb_assert( (arithmeticNode && arithmeticNode->dialect1 && (arithmeticNode->blrOp == blr_add || arithmeticNode->blrOp == blr_subtract)) || - node->is() || + nodeIs(node) || (subQueryNode && (subQueryNode->blrOp == blr_total || subQueryNode->blrOp == blr_average))); #endif @@ -1662,12 +1762,31 @@ dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNo return arithmeticNode->addDateTime(desc, value); } + // Handle decimal arithmetic + + if (node->nodFlags & FLAG_DECFLOAT) + { + const Decimal128 d1 = MOV_get_dec128(tdbb, desc); + const Decimal128 d2 = MOV_get_dec128(tdbb, &value->vlu_desc); + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + value->vlu_misc.vlu_dec128 = (blrOp == blr_subtract) ? d2.sub(decSt, d1) : d1.add(decSt, d2); + + result->dsc_dtype = dtype_dec128; + result->dsc_length = sizeof(Decimal128); + result->dsc_scale = 0; + result->dsc_sub_type = 0; + result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec128; + + return result; + } + // Handle floating arithmetic if (node->nodFlags & FLAG_DOUBLE) { - const double d1 = MOV_get_double(desc); - const double d2 = MOV_get_double(&value->vlu_desc); + const double d1 = MOV_get_double(tdbb, desc); + const double d2 = MOV_get_double(tdbb, &value->vlu_desc); value->vlu_misc.vlu_double = (blrOp == blr_subtract) ? d2 - d1 : d1 + d2; @@ -1688,8 +1807,8 @@ dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNo // CVC: Maybe we should upgrade the sum to double if it doesn't fit? // This is what was done for multiplicaton in dialect 1. - const SLONG l1 = MOV_get_long(desc, node->nodScale); - const SINT64 l2 = MOV_get_long(&value->vlu_desc, node->nodScale); + const SLONG l1 = MOV_get_long(tdbb, desc, node->nodScale); + const SINT64 l2 = MOV_get_long(tdbb, &value->vlu_desc, node->nodScale); const SINT64 rc = (blrOp == blr_subtract) ? l2 - l1 : l2 + l1; if (rc < MIN_SLONG || rc > MAX_SLONG) @@ -1704,12 +1823,12 @@ dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNo // the blr_add, blr_subtract, and blr_agg_total verbs following a blr_version5. dsc* ArithmeticNode::add2(const dsc* desc, impure_value* value, const ValueExprNode* node, const UCHAR blrOp) { - const ArithmeticNode* arithmeticNode = node->as(); + const ArithmeticNode* arithmeticNode = nodeAs(node); fb_assert( (arithmeticNode && !arithmeticNode->dialect1 && (arithmeticNode->blrOp == blr_add || arithmeticNode->blrOp == blr_subtract)) || - node->is()); + nodeIs(node)); dsc* result = &value->vlu_desc; @@ -1721,12 +1840,33 @@ dsc* ArithmeticNode::add2(const dsc* desc, impure_value* value, const ValueExprN return arithmeticNode->addDateTime(desc, value); } + thread_db* tdbb = JRD_get_thread_data(); + + // Handle decimal arithmetic + + if (node->nodFlags & FLAG_DECFLOAT) + { + const Decimal128 d1 = MOV_get_dec128(tdbb, desc); + const Decimal128 d2 = MOV_get_dec128(tdbb, &value->vlu_desc); + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + value->vlu_misc.vlu_dec128 = (blrOp == blr_subtract) ? d2.sub(decSt, d1) : d1.add(decSt, d2); + + result->dsc_dtype = dtype_dec128; + result->dsc_length = sizeof(Decimal128); + result->dsc_scale = 0; + result->dsc_sub_type = 0; + result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec128; + + return result; + } + // Handle floating arithmetic if (node->nodFlags & FLAG_DOUBLE) { - const double d1 = MOV_get_double(desc); - const double d2 = MOV_get_double(&value->vlu_desc); + const double d1 = MOV_get_double(tdbb, desc); + const double d2 = MOV_get_double(tdbb, &value->vlu_desc); value->vlu_misc.vlu_double = (blrOp == blr_subtract) ? d2 - d1 : d1 + d2; @@ -1744,8 +1884,8 @@ dsc* ArithmeticNode::add2(const dsc* desc, impure_value* value, const ValueExprN // Everything else defaults to int64 - SINT64 i1 = MOV_get_int64(desc, node->nodScale); - const SINT64 i2 = MOV_get_int64(&value->vlu_desc, node->nodScale); + SINT64 i1 = MOV_get_int64(tdbb, desc, node->nodScale); + const SINT64 i2 = MOV_get_int64(tdbb, &value->vlu_desc, node->nodScale); result->dsc_dtype = dtype_int64; result->dsc_length = sizeof(SINT64); @@ -1785,14 +1925,34 @@ dsc* ArithmeticNode::add2(const dsc* desc, impure_value* value, const ValueExprN // This function can be removed when dialect-3 becomes the lowest supported dialect. (Version 7.0?) dsc* ArithmeticNode::multiply(const dsc* desc, impure_value* value) const { + thread_db* tdbb = JRD_get_thread_data(); DEV_BLKCHK(node, type_nod); + // Handle decimal arithmetic + + if (nodFlags & FLAG_DECFLOAT) + { + const Decimal128 d1 = MOV_get_dec128(tdbb, desc); + const Decimal128 d2 = MOV_get_dec128(tdbb, &value->vlu_desc); + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + value->vlu_misc.vlu_dec128 = d1.mul(decSt, d2); + + value->vlu_desc.dsc_dtype = dtype_dec128; + value->vlu_desc.dsc_length = sizeof(Decimal128); + value->vlu_desc.dsc_scale = 0; + value->vlu_desc.dsc_sub_type = 0; + value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec128; + + return &value->vlu_desc; + } + // Handle floating arithmetic if (nodFlags & FLAG_DOUBLE) { - const double d1 = MOV_get_double(desc); - const double d2 = MOV_get_double(&value->vlu_desc); + const double d1 = MOV_get_double(tdbb, desc); + const double d2 = MOV_get_double(tdbb, &value->vlu_desc); value->vlu_misc.vlu_double = d1 * d2; if (isinf(value->vlu_misc.vlu_double)) @@ -1820,8 +1980,8 @@ dsc* ArithmeticNode::multiply(const dsc* desc, impure_value* value) const // SLONG l1, l2; //{ const SSHORT scale = NUMERIC_SCALE(value->vlu_desc); - const SINT64 i1 = MOV_get_long(desc, nodScale - scale); - const SINT64 i2 = MOV_get_long(&value->vlu_desc, scale); + const SINT64 i1 = MOV_get_long(tdbb, desc, nodScale - scale); + const SINT64 i2 = MOV_get_long(tdbb, &value->vlu_desc, scale); value->vlu_desc.dsc_dtype = dtype_long; value->vlu_desc.dsc_length = sizeof(SLONG); value->vlu_desc.dsc_scale = nodScale; @@ -1833,7 +1993,7 @@ dsc* ArithmeticNode::multiply(const dsc* desc, impure_value* value) const value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_int64; value->vlu_desc.dsc_dtype = dtype_int64; value->vlu_desc.dsc_length = sizeof(SINT64); - value->vlu_misc.vlu_double = MOV_get_double(&value->vlu_desc); + value->vlu_misc.vlu_double = MOV_get_double(tdbb, &value->vlu_desc); /* This is the Borland solution instead of the five lines above. d1 = MOV_get_double (desc); d2 = MOV_get_double (&value->vlu_desc); @@ -1859,14 +2019,34 @@ dsc* ArithmeticNode::multiply(const dsc* desc, impure_value* value) const // Multiply two numbers, with dialect-3 semantics, implementing blr_version5 ... blr_multiply. dsc* ArithmeticNode::multiply2(const dsc* desc, impure_value* value) const { + thread_db* tdbb = JRD_get_thread_data(); DEV_BLKCHK(node, type_nod); + // Handle decimal arithmetic + + if (nodFlags & FLAG_DECFLOAT) + { + const Decimal128 d1 = MOV_get_dec128(tdbb, desc); + const Decimal128 d2 = MOV_get_dec128(tdbb, &value->vlu_desc); + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + value->vlu_misc.vlu_dec128 = d1.mul(decSt, d2); + + value->vlu_desc.dsc_dtype = dtype_dec128; + value->vlu_desc.dsc_length = sizeof(Decimal128); + value->vlu_desc.dsc_scale = 0; + value->vlu_desc.dsc_sub_type = 0; + value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec128; + + return &value->vlu_desc; + } + // Handle floating arithmetic if (nodFlags & FLAG_DOUBLE) { - const double d1 = MOV_get_double(desc); - const double d2 = MOV_get_double(&value->vlu_desc); + const double d1 = MOV_get_double(tdbb, desc); + const double d2 = MOV_get_double(tdbb, &value->vlu_desc); value->vlu_misc.vlu_double = d1 * d2; if (isinf(value->vlu_misc.vlu_double)) @@ -1886,8 +2066,8 @@ dsc* ArithmeticNode::multiply2(const dsc* desc, impure_value* value) const // Everything else defaults to int64 const SSHORT scale = NUMERIC_SCALE(value->vlu_desc); - const SINT64 i1 = MOV_get_int64(desc, nodScale - scale); - const SINT64 i2 = MOV_get_int64(&value->vlu_desc, scale); + const SINT64 i1 = MOV_get_int64(tdbb, desc, nodScale - scale); + const SINT64 i2 = MOV_get_int64(tdbb, &value->vlu_desc, scale); /* We need to report an overflow if @@ -1935,19 +2115,39 @@ dsc* ArithmeticNode::multiply2(const dsc* desc, impure_value* value) const // blr_version5 ... blr_average .... dsc* ArithmeticNode::divide2(const dsc* desc, impure_value* value) const { + thread_db* tdbb = JRD_get_thread_data(); DEV_BLKCHK(node, type_nod); + // Handle decimal arithmetic + + if (nodFlags & FLAG_DECFLOAT) + { + const Decimal128 d1 = MOV_get_dec128(tdbb, desc); + const Decimal128 d2 = MOV_get_dec128(tdbb, &value->vlu_desc); + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + value->vlu_misc.vlu_dec128 = d2.div(decSt, d1); + + value->vlu_desc.dsc_dtype = dtype_dec128; + value->vlu_desc.dsc_length = sizeof(Decimal128); + value->vlu_desc.dsc_scale = 0; + value->vlu_desc.dsc_sub_type = 0; + value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec128; + + return &value->vlu_desc; + } + // Handle floating arithmetic if (nodFlags & FLAG_DOUBLE) { - const double d2 = MOV_get_double(desc); + const double d2 = MOV_get_double(tdbb, desc); if (d2 == 0.0) { ERR_post(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_float_divide_by_zero)); } - const double d1 = MOV_get_double(&value->vlu_desc); + const double d1 = MOV_get_double(tdbb, &value->vlu_desc); value->vlu_misc.vlu_double = d1 / d2; if (isinf(value->vlu_misc.vlu_double)) { @@ -1998,14 +2198,14 @@ dsc* ArithmeticNode::divide2(const dsc* desc, impure_value* value) const * Who'da thunk that 9th-grade algebra would prove so useful. * -- Chris Jewell, December 1998 */ - SINT64 i2 = MOV_get_int64(desc, desc->dsc_scale); + SINT64 i2 = MOV_get_int64(tdbb, desc, desc->dsc_scale); if (i2 == 0) { ERR_post(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_integer_divide_by_zero)); } - SINT64 i1 = MOV_get_int64(&value->vlu_desc, nodScale - desc->dsc_scale); + SINT64 i1 = MOV_get_int64(tdbb, &value->vlu_desc, nodScale - desc->dsc_scale); // MIN_SINT64 / -1 = (MAX_SINT64 + 1), which overflows in SINT64. if ((i1 == MIN_SINT64) && (i2 == -1)) @@ -2141,6 +2341,7 @@ dsc* ArithmeticNode::addSqlDate(const dsc* desc, impure_value* value) const fb_assert(blrOp == blr_add || blrOp == blr_subtract); dsc* result = &value->vlu_desc; + thread_db* tdbb = JRD_get_thread_data(); fb_assert(value->vlu_desc.dsc_dtype == dtype_sql_date || desc->dsc_dtype == dtype_sql_date); @@ -2153,7 +2354,7 @@ dsc* ArithmeticNode::addSqlDate(const dsc* desc, impure_value* value) const op1_is_date = true; } else - d1 = MOV_get_int64(&value->vlu_desc, 0); + d1 = MOV_get_int64(tdbb, &value->vlu_desc, 0); SINT64 d2; // Coerce operand2 to a count of days @@ -2164,7 +2365,7 @@ dsc* ArithmeticNode::addSqlDate(const dsc* desc, impure_value* value) const op2_is_date = true; } else - d2 = MOV_get_int64(desc, 0); + d2 = MOV_get_int64(tdbb, desc, 0); if (blrOp == blr_subtract && op1_is_date && op2_is_date) { @@ -2210,6 +2411,7 @@ dsc* ArithmeticNode::addSqlTime(const dsc* desc, impure_value* value) const fb_assert(blrOp == blr_add || blrOp == blr_subtract); dsc* result = &value->vlu_desc; + thread_db* tdbb = JRD_get_thread_data(); fb_assert(value->vlu_desc.dsc_dtype == dtype_sql_time || desc->dsc_dtype == dtype_sql_time); @@ -2223,7 +2425,7 @@ dsc* ArithmeticNode::addSqlTime(const dsc* desc, impure_value* value) const fb_assert(d1 >= 0 && d1 < ISC_TICKS_PER_DAY); } else - d1 = MOV_get_int64(&value->vlu_desc, ISC_TIME_SECONDS_PRECISION_SCALE); + d1 = MOV_get_int64(tdbb, &value->vlu_desc, ISC_TIME_SECONDS_PRECISION_SCALE); SINT64 d2; // Coerce operand2 to a count of seconds @@ -2235,7 +2437,7 @@ dsc* ArithmeticNode::addSqlTime(const dsc* desc, impure_value* value) const fb_assert(d2 >= 0 && d2 < ISC_TICKS_PER_DAY); } else - d2 = MOV_get_int64(desc, ISC_TIME_SECONDS_PRECISION_SCALE); + d2 = MOV_get_int64(tdbb, desc, ISC_TIME_SECONDS_PRECISION_SCALE); if (blrOp == blr_subtract && op1_is_time && op2_is_time) { @@ -2702,7 +2904,7 @@ bool CastNode::setParameterType(DsqlCompilerScratch* /*dsqlScratch*/, { // ASF: Attention: CastNode::dsqlPass calls us with NULL node. - ParameterNode* paramNode = source->as(); + ParameterNode* paramNode = nodeAs(source); if (paramNode) { @@ -2780,7 +2982,7 @@ bool CastNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const CastNode* o = other->as(); + const CastNode* o = nodeAs(other); fb_assert(o); return dsqlField == o->dsqlField; @@ -2791,7 +2993,7 @@ bool CastNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const CastNode* const otherNode = other->as(); + const CastNode* const otherNode = nodeAs(other); fb_assert(otherNode); return DSC_EQUIV(&castDesc, &otherNode->castDesc, true); @@ -3967,13 +4169,13 @@ bool DecodeNode::setParameterType(DsqlCompilerScratch* dsqlScratch, const dsc* desc, bool /*forceVarChar*/) { // Check if there is a parameter in the test/conditions. - bool setParameters = test->is(); + bool setParameters = nodeIs(test); if (!setParameters) { for (auto& condition : conditions->items) { - if (condition->is()) + if (nodeIs(condition)) { setParameters = true; break; @@ -4101,7 +4303,7 @@ dsc* DecodeNode::execute(thread_db* tdbb, jrd_req* request) const { dsc* desc = EVL_expr(tdbb, request, condition); - if (desc && !(request->req_flags & req_null) && MOV_compare(testDesc, desc) == 0) + if (desc && !(request->req_flags & req_null) && MOV_compare(tdbb, testDesc, desc) == 0) return EVL_expr(tdbb, request, *valuesPtr); ++valuesPtr; @@ -4250,7 +4452,7 @@ bool DefaultNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const DefaultNode* o = other->as(); + const DefaultNode* o = nodeAs(other); fb_assert(o); return relationName == o->relationName && fieldName == o->fieldName; @@ -4568,7 +4770,7 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) case blr_extract_weekday: case blr_extract_yearday: case blr_extract_week: - if (!ExprNode::is(sub1) && + if (!nodeIs(sub1) && sub1->nodDesc.dsc_dtype != dtype_sql_date && sub1->nodDesc.dsc_dtype != dtype_timestamp) { @@ -4581,7 +4783,7 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) case blr_extract_minute: case blr_extract_second: case blr_extract_millisecond: - if (!ExprNode::is(sub1) && + if (!nodeIs(sub1) && sub1->nodDesc.dsc_dtype != dtype_sql_time && sub1->nodDesc.dsc_dtype != dtype_timestamp) { @@ -4671,7 +4873,7 @@ bool ExtractNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const ExtractNode* o = other->as(); + const ExtractNode* o = nodeAs(other); fb_assert(o); return blrSubOp == o->blrSubOp; @@ -4682,7 +4884,7 @@ bool ExtractNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const ExtractNode* const otherNode = other->as(); + const ExtractNode* const otherNode = nodeAs(other); fb_assert(otherNode); return blrSubOp == otherNode->blrSubOp; @@ -5333,7 +5535,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec for (auto& rseItem : rseItems->items) { - DerivedFieldNode* selectItem = rseItem->as(); + DerivedFieldNode* selectItem = nodeAs(rseItem); // select-item should always be a alias! if (selectItem) @@ -5614,7 +5816,7 @@ bool FieldNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const FieldNode* o = other->as(); + const FieldNode* o = nodeAs(other); fb_assert(o); if (dsqlField != o->dsqlField || dsqlContext != o->dsqlContext) @@ -5631,7 +5833,7 @@ bool FieldNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const FieldNode* const otherNode = other->as(); + const FieldNode* const otherNode = nodeAs(other); fb_assert(otherNode); return fieldId == otherNode->fieldId && @@ -6173,7 +6375,7 @@ bool GenIdNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const GenIdNode* o = other->as(); + const GenIdNode* o = nodeAs(other); fb_assert(o); // I'm not sure if I should include "implicit" in the comparison, but it means different BLR code @@ -6187,7 +6389,7 @@ bool GenIdNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const GenIdNode* const otherNode = other->as(); + const GenIdNode* const otherNode = nodeAs(other); fb_assert(otherNode); // I'm not sure if I should include "implicit" in the comparison, but it means different BLR code @@ -6234,7 +6436,7 @@ dsc* GenIdNode::execute(thread_db* tdbb, jrd_req* request) const if (request->req_flags & req_null) return NULL; - change = MOV_get_int64(value, 0); + change = MOV_get_int64(tdbb, value, 0); } if (sysGen && change != 0) @@ -6289,7 +6491,7 @@ DmlNode* InternalInfoNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScra node->arg = PAR_parse_value(tdbb, csb); - LiteralNode* literal = node->arg->as(); + LiteralNode* literal = nodeAs(node->arg); if (!literal || literal->litDesc.dsc_dtype != dtype_long) { @@ -6311,7 +6513,7 @@ string InternalInfoNode::internalPrint(NodePrinter& printer) const void InternalInfoNode::setParameterName(dsql_par* parameter) const { - SLONG infoType = arg->as()->getSlong(); + SLONG infoType = nodeAs(arg)->getSlong(); parameter->par_name = parameter->par_alias = INFO_TYPE_ATTRIBUTES[infoType].alias; } @@ -6323,7 +6525,7 @@ void InternalInfoNode::genBlr(DsqlCompilerScratch* dsqlScratch) void InternalInfoNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc) { - const InfoType infoType = static_cast(arg->as()->getSlong()); + const InfoType infoType = static_cast(nodeAs(arg)->getSlong()); switch (infoType) { @@ -6358,7 +6560,7 @@ void InternalInfoNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc) void InternalInfoNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { - fb_assert(arg->is()); + fb_assert(nodeIs(arg)); dsc argDesc; arg->getDesc(tdbb, csb, &argDesc); @@ -6499,7 +6701,7 @@ dsc* InternalInfoNode::execute(thread_db* tdbb, jrd_req* request) const result32 = request->req_trigger_action; break; default: - BUGCHECK(232); // msg 232 EVL_expr: invalid operation + SOFT_BUGCHECK(232); // msg 232 EVL_expr: invalid operation } dsc desc; @@ -6515,7 +6717,7 @@ dsc* InternalInfoNode::execute(thread_db* tdbb, jrd_req* request) const ValueExprNode* InternalInfoNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { - SLONG infoType = arg->as()->getSlong(); + SLONG infoType = nodeAs(arg)->getSlong(); const InfoAttr& attr = INFO_TYPE_ATTRIBUTES[infoType]; if (attr.mask && !(dsqlScratch->flags & attr.mask)) @@ -6549,11 +6751,14 @@ DmlNode* LiteralNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* PAR_desc(tdbb, csb, &node->litDesc); - UCHAR* p = FB_NEW_POOL(csb->csb_pool) UCHAR[node->litDesc.dsc_length]; + USHORT l = node->litDesc.dsc_length; + USHORT dataLen = l; + if (node->litDesc.dsc_dtype == dtype_double && dataLen < sizeof(Decimal128)) + dataLen = sizeof(Decimal128); + UCHAR* p = FB_NEW_POOL(csb->csb_pool) UCHAR[dataLen]; node->litDesc.dsc_address = p; node->litDesc.dsc_flags = 0; const UCHAR* q = csb->csb_blr_reader.getPos(); - USHORT l = node->litDesc.dsc_length; switch (node->litDesc.dsc_dtype) { @@ -6583,6 +6788,7 @@ DmlNode* LiteralNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* break; case dtype_double: + case dtype_dec128: { SSHORT scale; UCHAR dtype; @@ -6593,7 +6799,7 @@ DmlNode* LiteralNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* l = csb->csb_blr_reader.getWord(); q = csb->csb_blr_reader.getPos(); - dtype = CVT_get_numeric(q, l, &scale, (double*) p); + dtype = CVT_get_numeric(q, l, &scale, p); node->litDesc.dsc_dtype = dtype; switch (dtype) @@ -6601,6 +6807,9 @@ DmlNode* LiteralNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* case dtype_double: node->litDesc.dsc_length = sizeof(double); break; + case dtype_dec128: + node->litDesc.dsc_length = sizeof(Decimal128); + break; case dtype_long: node->litDesc.dsc_length = sizeof(SLONG); node->litDesc.dsc_scale = (SCHAR) scale; @@ -6668,13 +6877,15 @@ void LiteralNode::genConstant(DsqlCompilerScratch* dsqlScratch, const dsc* desc, break; case dtype_double: + case dtype_dec128: { // this is used for approximate/large numeric literal // which is transmitted to the engine as a string. GEN_descriptor(dsqlScratch, desc, true); - // Length of string literal, cast because it could be > 127 bytes. - const USHORT l = (USHORT)(UCHAR) desc->dsc_scale; + + // Length of string literal - keep it in sub_type which is unused + const USHORT l = desc->dsc_sub_type; if (negateValue) { @@ -6933,7 +7144,7 @@ bool LiteralNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const LiteralNode* o = other->as(); + const LiteralNode* o = nodeAs(other); fb_assert(o); if (!DSC_EQUIV(&litDesc, &o->litDesc, true)) @@ -6949,10 +7160,11 @@ bool LiteralNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const LiteralNode* const otherNode = other->as(); + const LiteralNode* const otherNode = nodeAs(other); fb_assert(otherNode); + thread_db* tdbb = JRD_get_thread_data(); - return !MOV_compare(&litDesc, &otherNode->litDesc); + return !MOV_compare(tdbb, &litDesc, &otherNode->litDesc); } ValueExprNode* LiteralNode::pass2(thread_db* tdbb, CompilerScratch* csb) @@ -6971,6 +7183,43 @@ dsc* LiteralNode::execute(thread_db* /*tdbb*/, jrd_req* /*request*/) const return const_cast(&litDesc); } +void LiteralNode::fixMinSInt64() +{ + // MIN_SINT64 should be stored as BIGINT, not DECFLOAT + + const UCHAR* s = litDesc.dsc_address; + const char* minSInt64 = "9223372036854775808"; + bool hasDot = false; + int scale = 0; + + for (const UCHAR* s = litDesc.dsc_address; *s; ++s) + { + if (*s == '.') + { + if (hasDot) + return; + hasDot = true; + } + else if (*s == *minSInt64++) + { + if (hasDot) + scale--; + } + else + return; + } + + if (*minSInt64) + return; + + SINT64* valuePtr = FB_NEW_POOL(getPool()) SINT64(QUADCONST(0x8000000000000000)); + litDesc.dsc_dtype = dtype_int64; + litDesc.dsc_length = sizeof(SINT64); + litDesc.dsc_scale = scale; + litDesc.dsc_sub_type = 0; + litDesc.dsc_address = reinterpret_cast(valuePtr); +} + //-------------------- @@ -7101,7 +7350,7 @@ void DsqlMapNode::setParameterName(dsql_par* parameter) const const ValueExprNode* nestNode = map->map_node; const DsqlMapNode* mapNode; - while ((mapNode = ExprNode::as(nestNode))) + while ((mapNode = nodeAs(nestNode))) { // Skip all the DsqlMapNodes. nestNode = mapNode->map->map_node; @@ -7117,25 +7366,25 @@ void DsqlMapNode::setParameterName(dsql_par* parameter) const const DerivedFieldNode* derivedField; const RecordKeyNode* dbKeyNode; - if ((aggNode = ExprNode::as(nestNode))) + if ((aggNode = nodeAs(nestNode))) aggNode->setParameterName(parameter); - else if ((aliasNode = ExprNode::as(nestNode))) + else if ((aliasNode = nodeAs(nestNode))) { parameter->par_alias = aliasNode->name; alias = aliasNode->value; - fieldNode = ExprNode::as(alias); + fieldNode = nodeAs(alias); } - else if ((literalNode = ExprNode::as(nestNode))) + else if ((literalNode = nodeAs(nestNode))) literalNode->setParameterName(parameter); - else if ((dbKeyNode = ExprNode::as(nestNode))) + else if ((dbKeyNode = nodeAs(nestNode))) nameAlias = dbKeyNode->getAlias(false); - else if ((derivedField = ExprNode::as(nestNode))) + else if ((derivedField = nodeAs(nestNode))) { parameter->par_alias = derivedField->name; alias = derivedField->value; - fieldNode = ExprNode::as(alias); + fieldNode = nodeAs(alias); } - else if ((fieldNode = ExprNode::as(nestNode))) + else if ((fieldNode = nodeAs(nestNode))) nameAlias = fieldNode->dsqlField->fld_name.c_str(); const dsql_ctx* context = NULL; @@ -7177,7 +7426,7 @@ void DsqlMapNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) bool DsqlMapNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const { - const DsqlMapNode* o = other->as(); + const DsqlMapNode* o = nodeAs(other); return o && PASS1_node_match(map->map_node, o->map->map_node, ignoreMapCast); } @@ -7296,12 +7545,12 @@ void DerivedFieldNode::setParameterName(dsql_par* parameter) const const FieldNode* fieldNode; const RecordKeyNode* dbKeyNode; - if ((fieldNode = value->as())) + if ((fieldNode = nodeAs(value))) { parameter->par_name = fieldNode->dsqlField->fld_name.c_str(); context = fieldNode->dsqlContext; } - else if ((dbKeyNode = value->as())) + else if ((dbKeyNode = nodeAs(value))) dbKeyNode->setParameterName(parameter); parameter->par_alias = name; @@ -7317,11 +7566,11 @@ void DerivedFieldNode::genBlr(DsqlCompilerScratch* dsqlScratch) ValueExprNode* val = value; - while (val->is()) - val = val->as()->value; + while (nodeIs(val)) + val = nodeAs(val)->value; - if (!val->is() && !val->is() && - !val->is() && !val->is()) + if (!nodeIs(val) && !nodeIs(val) && + !nodeIs(val) && !nodeIs(val)) { if (context->ctx_main_derived_contexts.hasData()) { @@ -7368,7 +7617,7 @@ void DerivedFieldNode::genBlr(DsqlCompilerScratch* dsqlScratch) else if (!(dsqlScratch->flags & DsqlCompilerScratch::FLAG_FETCH) && !(context->ctx_flags & CTX_system) && (context->ctx_flags & CTX_cursor) && - val->is()) + nodeIs(val)) { // ASF: FieldNode::execute does not verify rpb_number.isValid(), and due to system triggers // and also singular queries, we cannot start to do it. So to fix CORE-4488, we introduce @@ -7376,7 +7625,7 @@ void DerivedFieldNode::genBlr(DsqlCompilerScratch* dsqlScratch) // FieldNode::execute by a test of rpb_number.isValid(). dsqlScratch->appendUChar(blr_derived_expr); dsqlScratch->appendUChar(1); - GEN_stuff_context(dsqlScratch, val->as()->dsqlContext); + GEN_stuff_context(dsqlScratch, nodeAs(val)->dsqlContext); } GEN_expr(dsqlScratch, value); @@ -7398,6 +7647,10 @@ NegateNode::NegateNode(MemoryPool& pool, ValueExprNode* aArg) arg(aArg) { addChildNode(arg, arg); + + LiteralNode* literal = nodeAs(arg); + if (literal && literal->litDesc.dsc_dtype == dtype_dec128) + literal->fixMinSInt64(); } DmlNode* NegateNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/) @@ -7428,17 +7681,17 @@ void NegateNode::setParameterName(dsql_par* parameter) const const ValueExprNode* innerNode = arg; const NegateNode* innerNegateNode; - while ((innerNegateNode = ExprNode::as(innerNode))) + while ((innerNegateNode = nodeAs(innerNode))) { innerNode = innerNegateNode->arg; ++level; } - if (ExprNode::is(innerNode) || ExprNode::is(innerNode)) + if (nodeIs(innerNode) || nodeIs(innerNode)) parameter->par_name = parameter->par_alias = "CONSTANT"; else if (!level) { - const ArithmeticNode* arithmeticNode = ExprNode::as(innerNode); + const ArithmeticNode* arithmeticNode = nodeAs(innerNode); if (arithmeticNode && ( /*arithmeticNode->blrOp == blr_add || @@ -7459,7 +7712,7 @@ bool NegateNode::setParameterType(DsqlCompilerScratch* dsqlScratch, void NegateNode::genBlr(DsqlCompilerScratch* dsqlScratch) { - LiteralNode* literal = arg->as(); + LiteralNode* literal = nodeAs(arg); if (literal && DTYPE_IS_NUMERIC(literal->litDesc.dsc_dtype)) LiteralNode::genConstant(dsqlScratch, &literal->litDesc, true); @@ -7474,7 +7727,7 @@ void NegateNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) { MAKE_desc(dsqlScratch, desc, arg); - if (arg->is()) + if (nodeIs(arg)) { // -NULL = NULL of INT desc->makeLong(0); @@ -7511,7 +7764,7 @@ void NegateNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) void NegateNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { arg->getDesc(tdbb, csb, desc); - nodFlags = arg->nodFlags & FLAG_DOUBLE; + nodFlags = arg->nodFlags & (FLAG_DOUBLE | FLAG_DECFLOAT); if (desc->dsc_dtype == dtype_quad) IBERROR(224); // msg 224 quad word arithmetic not supported @@ -7568,6 +7821,14 @@ dsc* NegateNode::execute(thread_db* tdbb, jrd_req* request) const impure->vlu_misc.vlu_double = -impure->vlu_misc.vlu_double; break; + case dtype_dec64: + impure->vlu_misc.vlu_dec64 = impure->vlu_misc.vlu_dec64.neg(); + break; + + case dtype_dec128: + impure->vlu_misc.vlu_dec128 = impure->vlu_misc.vlu_dec128.neg(); + break; + case dtype_int64: if (impure->vlu_misc.vlu_int64 == MIN_SINT64) ERR_post(Arg::Gds(isc_exception_integer_overflow)); @@ -7575,7 +7836,7 @@ dsc* NegateNode::execute(thread_db* tdbb, jrd_req* request) const break; default: - impure->vlu_misc.vlu_double = -MOV_get_double(&impure->vlu_desc); + impure->vlu_misc.vlu_double = -MOV_get_double(tdbb, &impure->vlu_desc); impure->vlu_desc.dsc_dtype = DEFAULT_DOUBLE; impure->vlu_desc.dsc_length = sizeof(double); impure->vlu_desc.dsc_scale = 0; @@ -7702,7 +7963,7 @@ bool OrderNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const OrderNode* o = other->as(); + const OrderNode* o = nodeAs(other); return o && descending == o->descending && nullsPlacement == o->nullsPlacement; } @@ -7716,7 +7977,7 @@ bool WindowClause::Frame::sameAs(const ExprNode* other, bool ignoreStreams) cons if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const Frame* const otherNode = other->as(); + const Frame* const otherNode = nodeAs(other); fb_assert(otherNode); return bound == otherNode->bound; @@ -7748,7 +8009,7 @@ bool WindowClause::FrameExtent::sameAs(const ExprNode* other, bool ignoreStreams if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const FrameExtent* const otherNode = other->as(); + const FrameExtent* const otherNode = nodeAs(other); fb_assert(otherNode); return unit == otherNode->unit; @@ -7857,7 +8118,7 @@ WindowClause* WindowClause::dsqlPass(DsqlCompilerScratch* dsqlScratch) } else { - OrderNode* key = node->order->items[0]->as(); + OrderNode* key = nodeAs(node->order->items[0]); fb_assert(key); dsc desc; @@ -8086,7 +8347,7 @@ ValueExprNode* OverNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) OverNode* node = FB_NEW_POOL(getPool()) OverNode(getPool(), static_cast(doDsqlPass(dsqlScratch, aggExpr)), doDsqlPass(dsqlScratch, refWindow)); - const AggNode* aggNode = node->aggExpr->as(); + const AggNode* aggNode = nodeAs(node->aggExpr); if (node->window && node->window->extent && @@ -8346,7 +8607,7 @@ void ParameterNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc) bool ParameterNode::dsqlMatch(const ExprNode* other, bool /*ignoreMapCast*/) const { - const ParameterNode* o = other->as(); + const ParameterNode* o = nodeAs(other); return o && dsqlParameter->par_index == o->dsqlParameter->par_index; } @@ -8412,7 +8673,7 @@ dsc* ParameterNode::execute(thread_db* tdbb, jrd_req* request) const if (argFlag) { desc = EVL_expr(tdbb, request, argFlag); - if (MOV_get_long(desc, 0)) + if (MOV_get_long(tdbb, desc, 0)) request->req_flags |= req_null; } @@ -8788,7 +9049,7 @@ bool RecordKeyNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const RecordKeyNode* o = other->as(); + const RecordKeyNode* o = nodeAs(other); fb_assert(o); return blrOp == o->blrOp; @@ -8799,7 +9060,7 @@ bool RecordKeyNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const RecordKeyNode* const otherNode = other->as(); + const RecordKeyNode* const otherNode = nodeAs(other); fb_assert(otherNode); return blrOp == otherNode->blrOp && (ignoreStreams || recStream == otherNode->recStream); @@ -8836,7 +9097,7 @@ ValueExprNode* RecordKeyNode::pass1(thread_db* tdbb, CompilerScratch* csb) for (ValueExprNodeStack::iterator i(stack); i.hasData(); ++i) { #ifdef CMP_DEBUG - csb->dump(" %d", ExprNode::as(i.object())->recStream); + csb->dump(" %d", nodeAs(i.object())->recStream); #endif ValueIfNode* valueIfNode = FB_NEW_POOL(csb->csb_pool) ValueIfNode(csb->csb_pool); @@ -9090,7 +9351,7 @@ DmlNode* ScalarNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* c void ScalarNode::getDesc(thread_db* /*tdbb*/, CompilerScratch* csb, dsc* desc) { - FieldNode* fieldNode = field->as(); + FieldNode* fieldNode = nodeAs(field); fb_assert(fieldNode); jrd_rel* relation = csb->csb_rpt[fieldNode->fieldStream].csb_relation; @@ -9151,7 +9412,7 @@ dsc* ScalarNode::execute(thread_db* tdbb, jrd_req* request) const const dsc* temp = EVL_expr(tdbb, request, subscript); if (temp && !(request->req_flags & req_null)) - numSubscripts[iter++] = MOV_get_long(temp, 0); + numSubscripts[iter++] = MOV_get_long(tdbb, temp, 0); else return NULL; } @@ -9176,18 +9437,18 @@ DmlNode* StmtExprNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* node->expr = PAR_parse_value(tdbb, csb); // Avoid blr_stmt_expr in a BLR expression header - CompoundStmtNode* const stmt = node->stmt->as(); + CompoundStmtNode* const stmt = nodeAs(node->stmt); if (stmt) { if (stmt->statements.getCount() != 2 || - !stmt->statements[0]->is() || - !stmt->statements[1]->is()) + !nodeIs(stmt->statements[0]) || + !nodeIs(stmt->statements[1])) { return node->expr; } } - else if (!node->stmt->is()) + else if (!nodeIs(node->stmt)) return node->expr; return node; @@ -9316,7 +9577,7 @@ bool StrCaseNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const StrCaseNode* o = other->as(); + const StrCaseNode* o = nodeAs(other); fb_assert(o); return blrOp == o->blrOp; @@ -9327,7 +9588,7 @@ bool StrCaseNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const StrCaseNode* const otherNode = other->as(); + const StrCaseNode* const otherNode = nodeAs(other); fb_assert(otherNode); return blrOp == otherNode->blrOp; @@ -9399,7 +9660,7 @@ dsc* StrCaseNode::execute(thread_db* tdbb, jrd_req* request) const USHORT ttype; dsc desc; - desc.dsc_length = MOV_get_string_ptr(value, &ttype, &ptr, &temp, sizeof(temp)); + desc.dsc_length = MOV_get_string_ptr(tdbb, value, &ttype, &ptr, &temp, sizeof(temp)); desc.dsc_dtype = dtype_text; desc.dsc_address = NULL; desc.setTextType(ttype); @@ -9531,7 +9792,7 @@ bool StrLenNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const StrLenNode* o = other->as(); + const StrLenNode* o = nodeAs(other); fb_assert(o); return blrSubOp == o->blrSubOp; @@ -9542,7 +9803,7 @@ bool StrLenNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const StrLenNode* const otherNode = other->as(); + const StrLenNode* const otherNode = nodeAs(other); fb_assert(otherNode); return blrSubOp == otherNode->blrSubOp; @@ -9629,7 +9890,7 @@ dsc* StrLenNode::execute(thread_db* tdbb, jrd_req* request) const USHORT ttype; UCHAR* p; - length = MOV_get_string_ptr(value, &ttype, &p, &temp, sizeof(temp)); + length = MOV_get_string_ptr(tdbb, value, &ttype, &p, &temp, sizeof(temp)); switch (blrSubOp) { @@ -9734,7 +9995,7 @@ ValueExprNode* SubQueryNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) const DsqlContextStack::iterator base(*dsqlScratch->context); - RseNode* rse = PASS1_rse(dsqlScratch, dsqlRse->as(), false); + RseNode* rse = PASS1_rse(dsqlScratch, nodeAs(dsqlRse), false); SubQueryNode* node = FB_NEW_POOL(getPool()) SubQueryNode(getPool(), blrOp, rse, rse->dsqlSelectList->items[0], FB_NEW_POOL(getPool()) NullNode(getPool())); @@ -9791,7 +10052,7 @@ bool SubQueryNode::dsqlFieldFinder(FieldFinder& visitor) ValueExprNode* SubQueryNode::dsqlFieldRemapper(FieldRemapper& visitor) { doDsqlFieldRemapper(visitor, dsqlRse); - value1 = dsqlRse->as()->dsqlSelectList->items[0]; + value1 = nodeAs(dsqlRse)->dsqlSelectList->items[0]; return this; } @@ -9835,6 +10096,17 @@ void SubQueryNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) if (blrOp == blr_average) { + if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) + { + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + nodFlags |= FLAG_DECFLOAT; + return; + } + if (!(DTYPE_IS_NUMERIC(desc->dsc_dtype) || DTYPE_IS_TEXT(desc->dsc_dtype))) { if (desc->dsc_dtype != dtype_unknown) @@ -9884,6 +10156,16 @@ void SubQueryNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) nodFlags |= FLAG_DOUBLE; return; + case dtype_dec64: + case dtype_dec128: + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + desc->dsc_scale = 0; + desc->dsc_sub_type = 0; + desc->dsc_flags = 0; + nodFlags |= FLAG_DECFLOAT; + return; + case dtype_sql_time: case dtype_sql_date: case dtype_timestamp: @@ -9954,18 +10236,17 @@ ValueExprNode* SubQueryNode::pass2(thread_db* tdbb, CompilerScratch* csb) impureOffset = CMP_impure(csb, sizeof(impure_value_ex)); - if (blrOp == blr_average) - nodFlags |= FLAG_DOUBLE; - else if (blrOp == blr_total) { dsc desc; getDesc(tdbb, csb, &desc); } + if (blrOp == blr_average && !(nodFlags & FLAG_DECFLOAT)) + nodFlags |= FLAG_DOUBLE; // Bind values of invariant nodes to top-level RSE (if present). if ((nodFlags & FLAG_INVARIANT) && csb->csb_current_nodes.hasData()) { - RseNode* topRseNode = csb->csb_current_nodes[0]->as(); + RseNode* topRseNode = nodeAs(csb->csb_current_nodes[0]); fb_assert(topRseNode); if (!topRseNode->rse_invariants) @@ -10049,7 +10330,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, jrd_req* request) const int result; - if (flag || ((result = MOV_compare(value, desc)) < 0 && blrOp == blr_minimum) || + if (flag || ((result = MOV_compare(tdbb, value, desc)) < 0 && blrOp == blr_minimum) || (blrOp != blr_minimum && result > 0)) { flag = 0; @@ -10086,7 +10367,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, jrd_req* request) const if (!count) break; - d = MOV_get_double(&impure->vlu_desc); + d = MOV_get_double(tdbb, &impure->vlu_desc); impure->vlu_misc.vlu_double = d / count; impure->vlu_desc.dsc_dtype = DEFAULT_DOUBLE; impure->vlu_desc.dsc_length = sizeof(double); @@ -10109,7 +10390,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, jrd_req* request) const break; default: - BUGCHECK(233); // msg 233 eval_statistical: invalid operation + SOFT_BUGCHECK(233); // msg 233 eval_statistical: invalid operation } } catch (const Exception&) @@ -10243,7 +10524,7 @@ void SubstringNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) { MAKE_desc(dsqlScratch, &desc3, length); - if (!length->is()) + if (!nodeIs(length)) desc3.dsc_address = NULL; } @@ -10258,7 +10539,7 @@ void SubstringNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) ValueExprNode* offsetNode = start; ValueExprNode* decrementNode = NULL; - ArithmeticNode* arithmeticNode = offsetNode->as(); + ArithmeticNode* arithmeticNode = nodeAs(offsetNode); // ASF: This code is very strange. The DSQL node is created as dialect 1, but only the dialect // 3 is verified here. Also, this task seems unnecessary here, as it must be done during @@ -10282,9 +10563,9 @@ void SubstringNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) desc->dsc_flags |= DSC_null; else { - if (length->is() && desc2.dsc_dtype == dtype_long) + if (nodeIs(length) && desc2.dsc_dtype == dtype_long) { - const SLONG len = MOV_get_long(&desc2, 0); + const SLONG len = MOV_get_long(tdbb, &desc2, 0); if (len < 0) ERR_post(Arg::Gds(isc_bad_substring_length) << Arg::Num(len)); @@ -10338,8 +10619,8 @@ dsc* SubstringNode::execute(thread_db* tdbb, jrd_req* request) const dsc* SubstringNode::perform(thread_db* tdbb, impure_value* impure, const dsc* valueDsc, const dsc* startDsc, const dsc* lengthDsc) { - SINT64 sStart = MOV_get_long(startDsc, 0); - SINT64 sLength = MOV_get_long(lengthDsc, 0); + SINT64 sStart = MOV_get_long(tdbb, startDsc, 0); + SINT64 sLength = MOV_get_long(tdbb, lengthDsc, 0); if (sLength < 0) status_exception::raise(Arg::Gds(isc_bad_substring_length) << Arg::Num(sLength)); @@ -10434,7 +10715,7 @@ dsc* SubstringNode::perform(thread_db* tdbb, impure_value* impure, const dsc* va // they aren't accepted, so they will cause error() to be called anyway. VaryStr<32> temp; USHORT ttype; - desc.dsc_length = MOV_get_string_ptr(valueDsc, &ttype, &desc.dsc_address, + desc.dsc_length = MOV_get_string_ptr(tdbb, valueDsc, &ttype, &desc.dsc_address, &temp, sizeof(temp)); desc.setTextType(ttype); @@ -10588,11 +10869,11 @@ ValueExprNode* SubstringSimilarNode::pass1(thread_db* tdbb, CompilerScratch* csb // If there is no top-level RSE present and patterns are not constant, unmark node as invariant // because it may be dependent on data or variables. - if ((nodFlags & FLAG_INVARIANT) && (!pattern->is() || !escape->is())) + if ((nodFlags & FLAG_INVARIANT) && (!nodeIs(pattern) || !nodeIs(escape))) { for (const auto& ctxNode : csb->csb_current_nodes) { - if (ctxNode->as()) + if (nodeAs(ctxNode)) return this; } @@ -10821,7 +11102,7 @@ void SysFuncCallNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) // dsc_address is verified in makeFunc to get literals. If the node is not a // literal, set it to NULL, to prevent wrong interpretation of offsets as // pointers - CORE-2612. - if (!arg->is()) + if (!nodeIs(arg)) targetDesc->dsc_address = NULL; } @@ -10846,7 +11127,7 @@ bool SysFuncCallNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const SysFuncCallNode* otherNode = other->as(); + const SysFuncCallNode* otherNode = nodeAs(other); return name == otherNode->name; } @@ -10856,7 +11137,7 @@ bool SysFuncCallNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const SysFuncCallNode* const otherNode = other->as(); + const SysFuncCallNode* const otherNode = nodeAs(other); fb_assert(otherNode); return function && function == otherNode->function; @@ -11077,7 +11358,7 @@ bool TrimNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const TrimNode* o = other->as(); + const TrimNode* o = nodeAs(other); fb_assert(o); return where == o->where; @@ -11088,7 +11369,7 @@ bool TrimNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const TrimNode* const otherNode = other->as(); + const TrimNode* const otherNode = nodeAs(other); fb_assert(otherNode); return where == otherNode->where; @@ -11443,7 +11724,7 @@ bool UdfCallNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const if (!ExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const UdfCallNode* otherNode = other->as(); + const UdfCallNode* otherNode = nodeAs(other); return name == otherNode->name; } @@ -11453,7 +11734,7 @@ bool UdfCallNode::sameAs(const ExprNode* other, bool ignoreStreams) const if (!ExprNode::sameAs(other, ignoreStreams)) return false; - const UdfCallNode* const otherNode = other->as(); + const UdfCallNode* const otherNode = nodeAs(other); fb_assert(otherNode); return function && function == otherNode->function; @@ -11805,31 +12086,31 @@ DmlNode* ValueIfNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* // Get rid of blr_stmt_expr expressions. // Coalesce. - MissingBoolNode* missing = node->condition->as(); + MissingBoolNode* missing = nodeAs(node->condition); if (missing) { - StmtExprNode* missingCond = missing->arg->as(); + StmtExprNode* missingCond = nodeAs(missing->arg); if (!missingCond) return node; - CompoundStmtNode* stmt = missingCond->stmt->as(); + CompoundStmtNode* stmt = nodeAs(missingCond->stmt); DeclareVariableNode* declStmt = NULL; AssignmentNode* assignStmt; if (stmt) { if (stmt->statements.getCount() != 2 || - !(declStmt = stmt->statements[0]->as()) || - !(assignStmt = stmt->statements[1]->as())) + !(declStmt = nodeAs(stmt->statements[0])) || + !(assignStmt = nodeAs(stmt->statements[1]))) { return node; } } - else if (!(assignStmt = missingCond->stmt->as())) + else if (!(assignStmt = nodeAs(missingCond->stmt))) return node; - VariableNode* var = node->falseValue->as(); - VariableNode* var2 = assignStmt->asgnTo->as(); + VariableNode* var = nodeAs(node->falseValue); + VariableNode* var2 = nodeAs(assignStmt->asgnTo); if (!var || !var2 || var->varId != var2->varId || (declStmt && declStmt->varId != var->varId)) return node; @@ -11843,30 +12124,30 @@ DmlNode* ValueIfNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* } // Decode. - ComparativeBoolNode* cmp = node->condition->as(); + ComparativeBoolNode* cmp = nodeAs(node->condition); if (cmp && cmp->blrOp == blr_eql) { - StmtExprNode* cmpCond = cmp->arg1->as(); + StmtExprNode* cmpCond = nodeAs(cmp->arg1); if (!cmpCond) return node; - CompoundStmtNode* stmt = cmpCond->stmt->as(); + CompoundStmtNode* stmt = nodeAs(cmpCond->stmt); DeclareVariableNode* declStmt = NULL; AssignmentNode* assignStmt; if (stmt) { if (stmt->statements.getCount() != 2 || - !(declStmt = stmt->statements[0]->as()) || - !(assignStmt = stmt->statements[1]->as())) + !(declStmt = nodeAs(stmt->statements[0])) || + !(assignStmt = nodeAs(stmt->statements[1]))) { return node; } } - else if (!(assignStmt = cmpCond->stmt->as())) + else if (!(assignStmt = nodeAs(cmpCond->stmt))) return node; - VariableNode* var = assignStmt->asgnTo->as(); + VariableNode* var = nodeAs(assignStmt->asgnTo); if (!var || (declStmt && declStmt->varId != var->varId)) return node; @@ -11880,13 +12161,13 @@ DmlNode* ValueIfNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* decodeNode->values->add(node->trueValue); ValueExprNode* last = node->falseValue; - while ((node = last->as())) + while ((node = nodeAs(last))) { - ComparativeBoolNode* cmp = node->condition->as(); + ComparativeBoolNode* cmp = nodeAs(node->condition); if (!cmp || cmp->blrOp != blr_eql) break; - VariableNode* var2 = cmp->arg1->as(); + VariableNode* var2 = nodeAs(cmp->arg1); if (!var2 || var2->varId != var->varId) break; @@ -11969,7 +12250,7 @@ void ValueIfNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) void ValueIfNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { - ValueExprNode* val = trueValue->is() ? falseValue : trueValue; + ValueExprNode* val = nodeIs(trueValue) ? falseValue : trueValue; val->getDesc(tdbb, csb, desc); } @@ -12088,7 +12369,7 @@ void VariableNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc) bool VariableNode::dsqlMatch(const ExprNode* other, bool /*ignoreMapCast*/) const { - const VariableNode* o = other->as(); + const VariableNode* o = nodeAs(other); if (!o) return false; @@ -12215,6 +12496,7 @@ static SINT64 getDayFraction(const dsc* d) { dsc result; double result_days; + thread_db* tdbb = JRD_get_thread_data(); result.dsc_dtype = dtype_double; result.dsc_scale = 0; @@ -12224,7 +12506,7 @@ static SINT64 getDayFraction(const dsc* d) result.dsc_address = reinterpret_cast(&result_days); // Convert the input number to a double - CVT_move(d, &result); + CVT_move(d, &result, tdbb->getAttachment()->att_dec_status); // There's likely some loss of precision here due to rounding of number @@ -12256,6 +12538,7 @@ static SINT64 getDayFraction(const dsc* d) // This is derived from the ISC_TIME_SECONDS_PRECISION. static SINT64 getTimeStampToIscTicks(const dsc* d) { + thread_db* tdbb = JRD_get_thread_data(); dsc result; GDS_TIMESTAMP result_timestamp; @@ -12266,7 +12549,7 @@ static SINT64 getTimeStampToIscTicks(const dsc* d) result.dsc_length = sizeof(GDS_TIMESTAMP); result.dsc_address = reinterpret_cast(&result_timestamp); - CVT_move(d, &result); + CVT_move(d, &result, tdbb->getAttachment()->att_dec_status); return ((SINT64) result_timestamp.timestamp_date) * ISC_TICKS_PER_DAY + (SINT64) result_timestamp.timestamp_time; diff --git a/src/dsql/ExprNodes.h b/src/dsql/ExprNodes.h index 3eea3b08f3..b490a9c0b5 100644 --- a/src/dsql/ExprNodes.h +++ b/src/dsql/ExprNodes.h @@ -797,6 +797,8 @@ public: return *reinterpret_cast(litDesc.dsc_address); } + void fixMinSInt64(); + public: const IntlString* dsqlStr; dsc litDesc; @@ -1059,7 +1061,7 @@ public: if (!ListExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const Frame* o = other->as(); + const Frame* o = nodeAs(other); fb_assert(o); return bound == o->bound; @@ -1128,7 +1130,7 @@ public: if (!ListExprNode::dsqlMatch(other, ignoreMapCast)) return false; - const FrameExtent* o = other->as(); + const FrameExtent* o = nodeAs(other); fb_assert(o); return unit == o->unit; @@ -1197,7 +1199,7 @@ public: if (!DsqlNode::dsqlMatch(other, ignoreMapCast)) return false; - const WindowClause* o = other->as(); + const WindowClause* o = nodeAs(other); fb_assert(o); return exclusion == o->exclusion; diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h index 25380047d7..97cebccb46 100644 --- a/src/dsql/Nodes.h +++ b/src/dsql/Nodes.h @@ -281,21 +281,25 @@ public: }; -class SetSessionNode : public Node +class SessionManagementNode : public Node { public: - enum Type { TYPE_IDLE_TIMEOUT, TYPE_STMT_TIMEOUT }; - - SetSessionNode(MemoryPool& pool, Type aType, ULONG aVal, UCHAR blr_timepart); + explicit SessionManagementNode(MemoryPool& pool) + : Node(pool) + { + } public: - virtual Firebird::string internalPrint(NodePrinter& printer) const; - virtual SetSessionNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); - virtual void execute(thread_db* tdbb, dsql_req* request) const; + virtual SessionManagementNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) + { + Node::dsqlPass(dsqlScratch); -private: - Type m_type; - ULONG m_value; + dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_SESSION_MANAGEMENT); + + return this; + } + + virtual void execute(thread_db* tdbb, dsql_req* request) const = 0; }; @@ -352,6 +356,37 @@ public: }; +template static To* nodeAs(From* fromNode) +{ + return fromNode && fromNode->type == To::TYPE ? static_cast(fromNode) : NULL; +} + +template static To* nodeAs(NestConst& fromNode) +{ + return fromNode && fromNode->type == To::TYPE ? static_cast(fromNode.getObject()) : NULL; +} + +template static const To* nodeAs(const From* fromNode) +{ + return fromNode && fromNode->type == To::TYPE ? static_cast(fromNode) : NULL; +} + +template static const To* nodeAs(const NestConst& fromNode) +{ + return fromNode && fromNode->type == To::TYPE ? static_cast(fromNode.getObject()) : NULL; +} + +template static bool nodeIs(const From* fromNode) +{ + return fromNode && fromNode->type == To::TYPE; +} + +template static bool nodeIs(const NestConst& fromNode) +{ + return fromNode && fromNode->type == To::TYPE; +} + + // Stores a reference to a specialized ExprNode. // This class and NodeRefImpl exists for nodes to replace themselves (eg. pass1) in a type-safe way. class NodeRef @@ -489,7 +524,8 @@ public: // Value flags. static const unsigned FLAG_DOUBLE = 0x10; static const unsigned FLAG_DATE = 0x20; - static const unsigned FLAG_VALUE = 0x40; // Full value area required in impure space. + static const unsigned FLAG_DECFLOAT = 0x40; + static const unsigned FLAG_VALUE = 0x80; // Full value area required in impure space. explicit ExprNode(Type aType, MemoryPool& pool, Kind aKind) : DmlNode(pool, aKind), @@ -502,39 +538,6 @@ public: { } - template T* as() - { - const ExprNode* const thisPointer = this; // avoid warning - return thisPointer && type == T::TYPE ? static_cast(this) : NULL; - } - - template const T* as() const - { - const ExprNode* const thisPointer = this; // avoid warning - return thisPointer && type == T::TYPE ? static_cast(this) : NULL; - } - - template bool is() const - { - const ExprNode* const thisPointer = this; // avoid warning - return thisPointer && type == T::TYPE; - } - - template static T* as(LegacyType* node) - { - return node ? node->template as() : NULL; - } - - template static const T* as(const LegacyType* node) - { - return node ? node->template as() : NULL; - } - - template static bool is(const LegacyType* node) - { - return node ? node->template is() : false; - } - // Allocate and assign impure space for various nodes. template static void doPass2(thread_db* tdbb, CompilerScratch* csb, T** node) { diff --git a/src/dsql/Parser.cpp b/src/dsql/Parser.cpp index c650aa5a02..5b005417a9 100644 --- a/src/dsql/Parser.cpp +++ b/src/dsql/Parser.cpp @@ -22,6 +22,7 @@ #include "firebird.h" #include +#include #include "../dsql/Parser.h" #include "../dsql/chars.h" #include "../jrd/jrd.h" @@ -29,6 +30,12 @@ #include "../yvalve/keywords.h" #include "../jrd/intl_proto.h" +#ifdef HAVE_FLOAT_H +#include +#else +#define DBL_MAX_10_EXP 308 +#endif + using namespace Firebird; using namespace Jrd; @@ -925,15 +932,19 @@ int Parser::yylexAux() { // The following variables are used to recognize kinds of numbers. - bool have_error = false; // syntax error or value too large - bool have_digit = false; // we've seen a digit - bool have_decimal = false; // we've seen a '.' - bool have_exp = false; // digit ... [eE] - bool have_exp_sign = false; // digit ... [eE] {+-] - bool have_exp_digit = false; // digit ... [eE] ... digit + bool have_error = false; // syntax error or value too large + bool have_digit = false; // we've seen a digit + bool have_decimal = false; // we've seen a '.' + bool have_exp = false; // digit ... [eE] + bool have_exp_sign = false; // digit ... [eE] {+-] + bool have_exp_digit = false; // digit ... [eE] ... digit + bool have_overflow = false; // value of digits > MAX_SINT64 + bool positive_overflow = false; // number is exactly (MAX_SINT64 + 1) FB_UINT64 number = 0; + int expVal = 0; FB_UINT64 limit_by_10 = MAX_SINT64 / 10; - SCHAR scale = 0; + int scale = 0; + int expSign = 1; for (--lex.ptr; lex.ptr < lex.end; lex.ptr++) { @@ -953,10 +964,22 @@ int Parser::yylexAux() { // We've seen e or E, but nothing beyond that. if ( ('-' == c) || ('+' == c) ) + { have_exp_sign = true; + if ('-' == c) + expSign = -1; + } else if ( classes(c) & CHR_DIGIT ) + { // We have a digit: we haven't seen a sign yet, but it's too late now. have_exp_digit = have_exp_sign = true; + if (!have_overflow) + { + expVal = expVal * 10 + (c - '0'); + if (expVal > DBL_MAX_10_EXP) + have_overflow = true; + } + } else { // end of the token @@ -978,19 +1001,26 @@ int Parser::yylexAux() { // Before computing the next value, make sure there will be no overflow. - have_digit = true; - - if (number >= limit_by_10) + if (!have_overflow) { - // possibility of an overflow - if ((number > limit_by_10) || (c > '8')) + have_digit = true; + + if (number >= limit_by_10) { - have_error = true; - break; + // possibility of an overflow + if ((number > limit_by_10) || (c >= '8')) + { + have_overflow = true; + if ((number == limit_by_10) && (c == '8')) + positive_overflow = true; + } } } + else + positive_overflow = false; - number = number * 10 + (c - '0'); + if (!have_overflow) + number = number * 10 + (c - '0'); if (have_decimal) --scale; @@ -1009,15 +1039,48 @@ int Parser::yylexAux() { fb_assert(have_digit); - if (have_exp_digit) + if (positive_overflow) + have_overflow = false; + + if (scale < MIN_SCHAR || scale > MAX_SCHAR) { + have_overflow = true; + positive_overflow = false; + } + + // check for a more complex overflow case + if ((!have_overflow) && (expSign > 0) && (expVal > -scale)) + { + expVal += scale; + double maxNum = DBL_MAX / pow(10.0, expVal); + if (double(number) > maxNum) + { + have_overflow = true; + positive_overflow = false; + } + } + + // Should we use floating point type? + if (have_exp_digit || have_overflow || positive_overflow) + { + if (positive_overflow && scale) + { + yylval.lim64ptr = newLim64String( + Firebird::string(lex.last_token, lex.ptr - lex.last_token), scale); + lex.last_token_bk = lex.last_token; + lex.line_start_bk = lex.line_start; + lex.lines_bk = lex.lines; + + return TOK_LIMIT64_NUMBER; + } + yylval.stringPtr = newString( Firebird::string(lex.last_token, lex.ptr - lex.last_token)); lex.last_token_bk = lex.last_token; lex.line_start_bk = lex.line_start; lex.lines_bk = lex.lines; - return TOK_FLOAT_NUMBER; + return positive_overflow ? TOK_LIMIT64_INT : have_overflow ? TOK_DECIMAL_NUMBER : TOK_FLOAT_NUMBER; } if (!have_exp) diff --git a/src/dsql/Parser.h b/src/dsql/Parser.h index 7d195914e9..54fa694ec2 100644 --- a/src/dsql/Parser.h +++ b/src/dsql/Parser.h @@ -144,6 +144,11 @@ public: return FB_NEW_POOL(getPool()) Firebird::string(getPool(), s); } + Lim64String* newLim64String(const Firebird::string& s, int scale) + { + return FB_NEW_POOL(getPool()) Lim64String(getPool(), s, scale); + } + IntlString* newIntlString(const Firebird::string& s, const char* charSet = NULL) { return FB_NEW_POOL(getPool()) IntlString(getPool(), s, charSet); @@ -209,7 +214,7 @@ private: BoolExprNode* valueToBool(ValueExprNode* value) { - BoolAsValueNode* node = value->as(); + BoolAsValueNode* node = nodeAs(value); if (node) return node->boolean; diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 41ce5ebb91..04e2a29979 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -195,7 +195,7 @@ namespace return NULL; // nod_returning was already processed - CompoundStmtNode* processedStmt = processed->as(); + CompoundStmtNode* processedStmt = nodeAs(processed); fb_assert(processed); // And we create a RETURNING node where the targets are already processed. @@ -211,7 +211,7 @@ namespace { AssignmentNode* temp = FB_NEW_POOL(scratch->getPool()) AssignmentNode(scratch->getPool()); temp->asgnFrom = *srcPtr; - temp->asgnTo = (*dstPtr)->as()->asgnTo; + temp->asgnTo = nodeAs(*dstPtr)->asgnTo; newNode->statements.add(temp); } @@ -291,7 +291,7 @@ void AssignmentNode::validateTarget(CompilerScratch* csb, const ValueExprNode* t { const FieldNode* fieldNode; - if ((fieldNode = target->as())) + if ((fieldNode = nodeAs(target))) { CompilerScratch::csb_repeat* tail = &csb->csb_rpt[fieldNode->fieldStream]; @@ -311,13 +311,13 @@ void AssignmentNode::validateTarget(CompilerScratch* csb, const ValueExprNode* t if (fieldNode->cursorNumber.specified) ERR_post(Arg::Gds(isc_read_only_field)); } - else if (!(target->is() || target->is() || target->is())) + else if (!(nodeIs(target) || nodeIs(target) || nodeIs(target))) ERR_post(Arg::Gds(isc_read_only_field)); } void AssignmentNode::dsqlValidateTarget(const ValueExprNode* target) { - const DerivedFieldNode* fieldNode = target->as(); + const DerivedFieldNode* fieldNode = nodeAs(target); if (fieldNode && fieldNode->context && (fieldNode->context->ctx_flags & (CTX_system | CTX_cursor)) == CTX_cursor) @@ -381,7 +381,7 @@ AssignmentNode* AssignmentNode::pass1(thread_db* tdbb, CompilerScratch* csb) StreamType stream; CompilerScratch::csb_repeat* tail; - if ((fieldNode = sub->as())) + if ((fieldNode = nodeAs(sub))) { stream = fieldNode->fieldStream; jrd_fld* field = MET_get_field(csb->csb_rpt[stream].csb_relation, fieldNode->fieldId); @@ -392,7 +392,7 @@ AssignmentNode* AssignmentNode::pass1(thread_db* tdbb, CompilerScratch* csb) sub = asgnTo; - if ((fieldNode = sub->as())) + if ((fieldNode = nodeAs(sub))) { stream = fieldNode->fieldStream; tail = &csb->csb_rpt[stream]; @@ -603,7 +603,7 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState* ptr != end; ++ptr) { - const ErrorHandlerNode* const handlerNode = (*ptr)->as(); + const ErrorHandlerNode* const handlerNode = nodeAs(*ptr); if (testAndFixupError(tdbb, request, handlerNode->conditions)) { @@ -1189,7 +1189,7 @@ const StmtNode* CursorStmtNode::execute(thread_db* tdbb, jrd_req* request, ExeSt const dsc* desc = EVL_expr(tdbb, request, scrollExpr); const bool unknown = !desc || (request->req_flags & req_null); - const SINT64 offset = unknown ? 0 : MOV_get_int64(desc, 0); + const SINT64 offset = unknown ? 0 : MOV_get_int64(tdbb, desc, 0); switch (scrollOp) { @@ -2115,7 +2115,7 @@ StmtNode* EraseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) rse->dsqlFlags |= RecordSourceNode::DFLAG_SINGLETON; node->dsqlRse = rse; - node->dsqlRelation = rse->dsqlStreams->items[0]->as(); + node->dsqlRelation = nodeAs(rse->dsqlStreams->items[0]); node->statement = dsqlProcessReturning(dsqlScratch, dsqlReturning, statement); @@ -5153,9 +5153,9 @@ StmtNode* MergeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) forNode->dsqlForceSingular = true; // Get the already processed relations. - RseNode* processedRse = forNode->rse->dsqlStreams->items[0]->as(); + RseNode* processedRse = nodeAs(forNode->rse->dsqlStreams->items[0]); source = processedRse->dsqlStreams->items[0]; - target = processedRse->dsqlStreams->items[1]->as(); + target = nodeAs(processedRse->dsqlStreams->items[1]); DsqlContextStack usingCtxs; dsqlGetContexts(usingCtxs, source); @@ -5181,7 +5181,7 @@ StmtNode* MergeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) // Separate the new and org values to process in correct contexts. for (FB_SIZE_T i = 0; i < stmts->statements.getCount(); ++i) { - AssignmentNode* const assign = stmts->statements[i]->as(); + AssignmentNode* const assign = nodeAs(stmts->statements[i]); fb_assert(assign); orgValues.add(assign->asgnFrom); newValues.add(assign->asgnTo); @@ -5345,7 +5345,7 @@ StmtNode* MergeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) store->overrideClause = notMatched->overrideClause; bool needSavePoint; // unused - thisIf->trueAction = store = store->internalDsqlPass(dsqlScratch, false, needSavePoint)->as(); + thisIf->trueAction = store = nodeAs(store->internalDsqlPass(dsqlScratch, false, needSavePoint)); fb_assert(store); if (notMatched->condition) @@ -5521,11 +5521,8 @@ void MessageNode::setup(thread_db* tdbb, CompilerScratch* csb, USHORT message, U // So we only check even indexes, which is the actual parameter. if (itemInfo.isSpecial() && index % 2 == 0) { - csb->csb_dbg_info->argInfoToName.get( - ArgumentInfo(csb->csb_msg_number, index / 2), itemInfo.name); - - csb->csb_map_item_info.put(Item(Item::TYPE_PARAMETER, csb->csb_msg_number, index), - itemInfo); + csb->csb_dbg_info->argInfoToName.get(ArgumentInfo(csb->csb_msg_number, index / 2), itemInfo.name); + csb->csb_map_item_info.put(Item(Item::TYPE_PARAMETER, message, index), itemInfo); } } @@ -5654,18 +5651,18 @@ StmtNode* ModifyNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, bool up Array > orgValues, newValues; - CompoundStmtNode* assignments = statement->as(); + CompoundStmtNode* assignments = nodeAs(statement); fb_assert(assignments); for (FB_SIZE_T i = 0; i < assignments->statements.getCount(); ++i) { - AssignmentNode* const assign = assignments->statements[i]->as(); + AssignmentNode* const assign = nodeAs(assignments->statements[i]); fb_assert(assign); orgValues.add(assign->asgnFrom); newValues.add(assign->asgnTo); } - NestConst relation = dsqlRelation->as(); + NestConst relation = nodeAs(dsqlRelation); fb_assert(relation); NestConst* ptr; @@ -5854,7 +5851,7 @@ string ModifyNode::internalPrint(NodePrinter& printer) const void ModifyNode::genBlr(DsqlCompilerScratch* dsqlScratch) { - RseNode* rse = dsqlRse->as(); + RseNode* rse = nodeAs(dsqlRse); const dsql_msg* message = dsqlGenDmlHeader(dsqlScratch, rse); @@ -5884,7 +5881,7 @@ void ModifyNode::genBlr(DsqlCompilerScratch* dsqlScratch) ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb) { - preprocessAssignments(tdbb, csb, newStream, statement->as(), NULL); + preprocessAssignments(tdbb, csb, newStream, nodeAs(statement), NULL); pass1Modify(tdbb, csb, this); @@ -6449,7 +6446,7 @@ DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs const UCHAR* blrPos = csb->csb_blr_reader.getPos(); - node->relationSource = PAR_parseRecordSource(tdbb, csb)->as(); + node->relationSource = nodeAs(PAR_parseRecordSource(tdbb, csb)); if (!node->relationSource) { @@ -6489,7 +6486,7 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, if (dsqlRse) { - SelectExprNode* selExpr = dsqlRse->as(); + SelectExprNode* selExpr = nodeAs(dsqlRse); fb_assert(selExpr); if (dsqlReturning || statement2) @@ -6540,13 +6537,13 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, const FieldNode* fieldNode; const DerivedFieldNode* derivedField; - if ((fieldNode = ExprNode::as(temp2))) + if ((fieldNode = nodeAs(temp2))) { tmp_ctx = fieldNode->dsqlContext; if (fieldNode->dsqlField) tmp_name = fieldNode->dsqlField->fld_name.c_str(); } - else if ((derivedField = ExprNode::as(temp2))) + else if ((derivedField = nodeAs(temp2))) { tmp_ctx = derivedField->context; tmp_name = derivedField->name.nullStr(); @@ -6594,7 +6591,7 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, if (!*ptr2) { - const FieldNode* field = (*ptr)->as(); + const FieldNode* field = nodeAs(*ptr); if (field && field->dsqlField) { @@ -6661,7 +6658,7 @@ StmtNode* StoreNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) StmtNode* node = SavepointEncloseNode::make(getPool(), dsqlScratch, internalDsqlPass(dsqlScratch, false, needSavePoint)); - if (!needSavePoint || node->is()) + if (!needSavePoint || nodeIs(node)) return node; return FB_NEW SavepointEncloseNode(getPool(), node); @@ -6687,7 +6684,7 @@ string StoreNode::internalPrint(NodePrinter& printer) const void StoreNode::genBlr(DsqlCompilerScratch* dsqlScratch) { - const dsql_msg* message = dsqlGenDmlHeader(dsqlScratch, dsqlRse->as()); + const dsql_msg* message = dsqlGenDmlHeader(dsqlScratch, nodeAs(dsqlRse)); dsqlScratch->appendUChar(overrideClause.specified ? blr_store3 : (statement2 ? blr_store2 : blr_store)); @@ -6709,7 +6706,7 @@ void StoreNode::genBlr(DsqlCompilerScratch* dsqlScratch) StoreNode* StoreNode::pass1(thread_db* tdbb, CompilerScratch* csb) { - preprocessAssignments(tdbb, csb, relationSource->getStream(), statement->as(), &overrideClause); + preprocessAssignments(tdbb, csb, relationSource->getStream(), nodeAs(statement), &overrideClause); if (pass1Store(tdbb, csb, this)) makeDefaults(tdbb, csb); @@ -6871,7 +6868,7 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb) if (assign) { - const FieldNode* fieldNode = assign->asgnTo->as(); + const FieldNode* fieldNode = nodeAs(assign->asgnTo); fb_assert(fieldNode); if (fieldNode && fieldNode->fieldStream == stream && fieldNode->fieldId == fieldId) @@ -6984,7 +6981,7 @@ const StmtNode* StoreNode::store(thread_db* tdbb, jrd_req* request, WhichTrigger switch (request->req_operation) { case jrd_req::req_evaluate: - if (!parentStmt->is()) + if (!nodeIs(parentStmt)) request->req_records_affected.clear(); request->req_records_affected.bumpModified(false); @@ -7208,7 +7205,7 @@ const StmtNode* UserSavepointNode::execute(thread_db* tdbb, jrd_req* request, Ex } default: - BUGCHECK(232); + SOFT_BUGCHECK(232); // msg 232 EVL_expr: invalid operation break; } @@ -7260,7 +7257,7 @@ SelectNode* SelectNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) // stored procedure occurs in the select list. In these cases all of stored procedure is // executed under savepoint for open cursor. - RseNode* rseNode = node->dsqlRse->as(); + RseNode* rseNode = nodeAs(node->dsqlRse); if (rseNode->dsqlOrder || rseNode->dsqlDistinct) { @@ -7288,7 +7285,7 @@ string SelectNode::internalPrint(NodePrinter& printer) const // Generate BLR for a SELECT statement. void SelectNode::genBlr(DsqlCompilerScratch* dsqlScratch) { - RseNode* const rse = dsqlRse->as(); + RseNode* const rse = nodeAs(dsqlRse); fb_assert(rse); DsqlCompiledStatement* const statement = dsqlScratch->getStatement(); @@ -7326,7 +7323,7 @@ void SelectNode::genBlr(DsqlCompilerScratch* dsqlScratch) RecordSourceNode* const item = *ptr2; RelationSourceNode* relNode; - if (item && (relNode = ExprNode::as(item))) + if (item && (relNode = nodeAs(item))) { context = relNode->dsqlContext; const dsql_rel* const relation = context->ctx_relation; @@ -7532,7 +7529,7 @@ const StmtNode* SetGeneratorNode::execute(thread_db* tdbb, jrd_req* request, Exe DDL_TRIGGER_ALTER_SEQUENCE, generator.name, NULL, *request->getStatement()->sqlText); dsc* const desc = EVL_expr(tdbb, request, value); - DPM_gen_id(tdbb, generator.id, true, MOV_get_int64(desc, 0)); + DPM_gen_id(tdbb, generator.id, true, MOV_get_int64(tdbb, desc, 0)); DdlNode::executeDdlTrigger(tdbb, transaction, DdlNode::DTW_AFTER, DDL_TRIGGER_ALTER_SEQUENCE, generator.name, NULL, *request->getStatement()->sqlText); @@ -7685,11 +7682,11 @@ const StmtNode* SuspendNode::execute(thread_db* tdbb, jrd_req* request, ExeState if (!(request->req_flags & req_proc_fetch)) return statement; - const CompoundStmtNode* list = parentStmt->as(); + const CompoundStmtNode* list = nodeAs(parentStmt); if (list && !list->parentStmt && list->statements[list->statements.getCount() - 1] == this) { - list = statement->as(); + list = nodeAs(statement); if (list && list->onlyAssignments && list->statements.hasData()) { @@ -7957,14 +7954,7 @@ void SetTransactionNode::genTableLock(DsqlCompilerScratch* dsqlScratch, //-------------------- -SetRoleNode* SetRoleNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) -{ - dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_SET_ROLE); - - return this; -} - -void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const +void SetRoleNode::execute(thread_db* tdbb, dsql_req* request) const { SET_TDBB(tdbb); Attachment* const attachment = tdbb->getAttachment(); @@ -7988,8 +7978,122 @@ void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transact //-------------------- +namespace +{ + +struct TextCode +{ + const char* name; + USHORT val; +}; + +//#define FB_TEXTCODE(x) { STRINGIZE(x), x } +#define FB_TEXTCODE(x) { #x, x } + +const TextCode roundModes[] = { + FB_TEXTCODE(DEC_ROUND_CEILING), + FB_TEXTCODE(DEC_ROUND_UP), + FB_TEXTCODE(DEC_ROUND_HALF_UP), + FB_TEXTCODE(DEC_ROUND_HALF_EVEN), + FB_TEXTCODE(DEC_ROUND_HALF_DOWN), + FB_TEXTCODE(DEC_ROUND_DOWN), + FB_TEXTCODE(DEC_ROUND_FLOOR), + { "DEC_ROUND_REROUND", DEC_ROUND_05UP }, + { NULL, 0 } +}; + +//DEC_ROUND_ +//0123456789 +const unsigned FB_RMODE_OFFSET = 10; + +const TextCode ieeeTraps[] = { + FB_TEXTCODE(DEC_IEEE_754_Division_by_zero), + FB_TEXTCODE(DEC_IEEE_754_Inexact), + FB_TEXTCODE(DEC_IEEE_754_Invalid_operation), + FB_TEXTCODE(DEC_IEEE_754_Overflow), + FB_TEXTCODE(DEC_IEEE_754_Underflow), + { NULL, 0 } +}; + +//DEC_IEEE_754_ +//0123456789012 +const unsigned FB_TRAPS_OFFSET = 13; + +#undef FB_TEXTCODE + +const TextCode* getCodeByText(const MetaName& text, const TextCode* textCode, unsigned offset) +{ + NoCaseString name(text.c_str(), text.length()); + + for (const TextCode* tc = textCode; tc->name; ++tc) + { + if (name == &tc->name[offset]) + return tc; + } + + return nullptr; +} + +} + + +//-------------------- + + +SetRoundNode::SetRoundNode(MemoryPool& pool, Firebird::MetaName* name) + : SessionManagementNode(pool) +{ + fb_assert(name); + const TextCode* mode = getCodeByText(*name, roundModes, FB_RMODE_OFFSET); + if (!mode) + (Arg::Gds(isc_random) << "Invalid round mode for decfloat").raise(); + rndMode = mode->val; +} + +void SetRoundNode::execute(thread_db* tdbb, dsql_req* /*request*/) const +{ + SET_TDBB(tdbb); + Attachment* const attachment = tdbb->getAttachment(); + attachment->att_dec_status.roundingMode = rndMode; +} + + +//-------------------- + + +void SetTrapsNode::trap(Firebird::MetaName* name) +{ + fb_assert(name); + const TextCode* trap = getCodeByText(*name, ieeeTraps, FB_TRAPS_OFFSET); + if (!trap) + (Arg::Gds(isc_random) << "Invalid decfloat trap").raise(); + traps |= trap->val; +} + +void SetTrapsNode::execute(thread_db* tdbb, dsql_req* /*request*/) const +{ + SET_TDBB(tdbb); + Attachment* const attachment = tdbb->getAttachment(); + attachment->att_dec_status.decExtFlag = traps; +} + + +//-------------------- + + +void SetBindNode::execute(thread_db* tdbb, dsql_req* /*request*/) const +{ + SET_TDBB(tdbb); + Attachment* const attachment = tdbb->getAttachment(); + attachment->att_dec_binding = bind; +} + + +//-------------------- + + SetSessionNode::SetSessionNode(MemoryPool& pool, Type aType, ULONG aVal, UCHAR blr_timepart) - : Node(pool), + : SessionManagementNode(pool), m_type(aType), m_value(0) { @@ -8036,12 +8140,6 @@ string SetSessionNode::internalPrint(NodePrinter& printer) const return "SetSessionNode"; } -SetSessionNode* SetSessionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) -{ - dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_SET_SESSION); - return this; -} - void SetSessionNode::execute(thread_db* tdbb, dsql_req* request) const { Attachment* att = tdbb->getAttachment(); @@ -8070,7 +8168,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (!dsqlScratch->isPsql()) dsqlScratch->flags |= DsqlCompilerScratch::FLAG_UPDATE_OR_INSERT; - const MetaName& relation_name = relation->as()->dsqlName; + const MetaName& relation_name = nodeAs(relation)->dsqlName; MetaName base_name = relation_name; bool needSavePoint; @@ -8082,7 +8180,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) insert->dsqlValues = values; insert->dsqlReturning = returning; insert->overrideClause = overrideClause; - insert = insert->internalDsqlPass(dsqlScratch, true, needSavePoint)->as(); + insert = nodeAs(insert->internalDsqlPass(dsqlScratch, true, needSavePoint)); fb_assert(insert); dsql_ctx* context = insert->dsqlRelation->dsqlContext; @@ -8154,7 +8252,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) NestConst* valuePtr = values->items.begin(); Array >& insertStatements = - insert->statement->as()->statements; + nodeAs(insert->statement)->statements; for (; fieldPtr != fieldsCopy.end(); ++fieldPtr, ++valuePtr) { @@ -8192,7 +8290,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) ++matchCount; const FB_SIZE_T fieldPos = fieldPtr - fieldsCopy.begin(); - AssignmentNode* assign2 = insertStatements[fieldPos]->as(); + AssignmentNode* assign2 = nodeAs(insertStatements[fieldPos]); NestConst& expr = assign2->asgnFrom; ValueExprNode* var = dsqlPassHiddenVariable(dsqlScratch, expr); @@ -8240,7 +8338,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) dsqlScratch, returning, insert->statement2); } - update = update->internalDsqlPass(dsqlScratch, true)->as(); + update = nodeAs(update->internalDsqlPass(dsqlScratch, true)); fb_assert(update); // test if ROW_COUNT = 0 @@ -8269,7 +8367,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_INSERT); StmtNode* ret = SavepointEncloseNode::make(getPool(), dsqlScratch, list); - if (!needSavePoint || ret->is()) + if (!needSavePoint || nodeIs(ret)) return ret; return FB_NEW SavepointEncloseNode(getPool(), ret); @@ -8415,13 +8513,13 @@ static dsql_ctx* dsqlGetContext(const RecordSourceNode* node) const RelationSourceNode* relNode; const RseNode* rseNode; - if ((procNode = ExprNode::as(node))) + if ((procNode = nodeAs(node))) return procNode->dsqlContext; - if ((relNode = ExprNode::as(node))) + if ((relNode = nodeAs(node))) return relNode->dsqlContext; - if ((rseNode = ExprNode::as(node))) + if ((rseNode = nodeAs(node))) return rseNode->dsqlContext; fb_assert(false); @@ -8435,11 +8533,11 @@ static void dsqlGetContexts(DsqlContextStack& contexts, const RecordSourceNode* const RelationSourceNode* relNode; const RseNode* rseNode; - if ((procNode = ExprNode::as(node))) + if ((procNode = nodeAs(node))) contexts.push(procNode->dsqlContext); - else if ((relNode = ExprNode::as(node))) + else if ((relNode = nodeAs(node))) contexts.push(relNode->dsqlContext); - else if ((rseNode = ExprNode::as(node))) + else if ((rseNode = nodeAs(node))) { if (rseNode->dsqlContext) // derived table contexts.push(rseNode->dsqlContext); @@ -8472,11 +8570,11 @@ static StmtNode* dsqlNullifyReturning(DsqlCompilerScratch* dsqlScratch, StmtNode ModifyNode* modifyNode; StoreNode* storeNode; - if (eraseNode = input->as()) + if (eraseNode = nodeAs(input)) returning = eraseNode->statement; - else if (modifyNode = input->as()) + else if (modifyNode = nodeAs(input)) returning = modifyNode->statement2; - else if (storeNode = input->as()) + else if (storeNode = nodeAs(input)) returning = storeNode->statement2; else { @@ -8493,7 +8591,7 @@ static StmtNode* dsqlNullifyReturning(DsqlCompilerScratch* dsqlScratch, StmtNode // completely removed. // nod_returning was already processed - CompoundStmtNode* returningStmt = returning->as(); + CompoundStmtNode* returningStmt = nodeAs(returning); fb_assert(returningStmt); CompoundStmtNode* nullAssign = FB_NEW_POOL(pool) CompoundStmtNode(pool); @@ -8507,7 +8605,7 @@ static StmtNode* dsqlNullifyReturning(DsqlCompilerScratch* dsqlScratch, StmtNode { AssignmentNode* assign = FB_NEW_POOL(pool) AssignmentNode(pool); assign->asgnFrom = FB_NEW_POOL(pool) NullNode(pool); - assign->asgnTo = (*ret_ptr)->as()->asgnTo; + assign->asgnTo = nodeAs(*ret_ptr)->asgnTo; *null_ptr = assign; } @@ -8529,7 +8627,7 @@ static void dsqlFieldAppearsOnce(const Array >& values, { for (FB_SIZE_T i = 0; i < values.getCount(); ++i) { - const FieldNode* field1 = values[i]->as(); + const FieldNode* field1 = nodeAs(values[i]); if (!field1) continue; @@ -8537,7 +8635,7 @@ static void dsqlFieldAppearsOnce(const Array >& values, for (FB_SIZE_T j = i + 1; j < values.getCount(); ++j) { - const FieldNode* field2 = values[j]->as(); + const FieldNode* field2 = nodeAs(values[j]); if (!field2) continue; @@ -8589,7 +8687,7 @@ static dsql_ctx* dsqlPassCursorContext(DsqlCompilerScratch* dsqlScratch, const M DeclareCursorNode::CUR_TYPE_ALL, true); fb_assert(node); - const RseNode* nodeRse = node->rse->as(); + const RseNode* nodeRse = nodeAs(node->rse); fb_assert(nodeRse); if (nodeRse->dsqlDistinct) @@ -8607,7 +8705,7 @@ static dsql_ctx* dsqlPassCursorContext(DsqlCompilerScratch* dsqlScratch, const M for (const NestConst* const end = temp->items.end(); ptr != end; ++ptr) { RecordSourceNode* r_node = *ptr; - RelationSourceNode* relNode = ExprNode::as(r_node); + RelationSourceNode* relNode = nodeAs(r_node); if (relNode) { @@ -8628,7 +8726,7 @@ static dsql_ctx* dsqlPassCursorContext(DsqlCompilerScratch* dsqlScratch, const M context = candidate; } } - else if (ExprNode::as(r_node)) + else if (nodeAs(r_node)) { // cursor with aggregation is not updatable ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-510) << @@ -8694,8 +8792,7 @@ static RseNode* dsqlPassCursorReference(DsqlCompilerScratch* dsqlScratch, const RseNode* rse = FB_NEW_POOL(pool) RseNode(pool); rse->dsqlStreams = FB_NEW_POOL(pool) RecSourceListNode(pool, 1); - RelationSourceNode* relation_node = - PASS1_relation(dsqlScratch, relation_name)->as(); + RelationSourceNode* relation_node = nodeAs(PASS1_relation(dsqlScratch, relation_name)); rse->dsqlStreams->items[0] = relation_node; RecordKeyNode* dbKeyNode = FB_NEW_POOL(pool) RecordKeyNode(pool, blr_dbkey); @@ -8961,7 +9058,7 @@ static void dsqlSetParameterName(ExprNode* exprNode, const ValueExprNode* fld_no if (!exprNode) return; - const FieldNode* fieldNode = ExprNode::as(fld_node); + const FieldNode* fieldNode = nodeAs(fld_node); fb_assert(fieldNode); // Could it be something else ??? if (fieldNode->nodDesc.dsc_dtype != dtype_array) @@ -8984,7 +9081,7 @@ static void dsqlSetParameterName(ExprNode* exprNode, const ValueExprNode* fld_no case ExprNode::TYPE_PARAMETER: { - ParameterNode* paramNode = exprNode->as(); + ParameterNode* paramNode = nodeAs(exprNode); dsql_par* parameter = paramNode->dsqlParameter; parameter->par_name = fieldNode->dsqlField->fld_name.c_str(); parameter->par_rel_name = relation->rel_name.c_str(); @@ -9005,7 +9102,7 @@ static void dsqlSetParametersName(CompoundStmtNode* statements, const RecordSour for (NestConst* const end = ptr + count; ptr != end; ++ptr) { - AssignmentNode* assign = (*ptr)->as(); + AssignmentNode* assign = nodeAs(*ptr); if (assign) dsqlSetParameterName(assign->asgnFrom, assign->asgnTo, relation); @@ -9154,7 +9251,7 @@ static StmtNode* pass1ExpandView(thread_db* tdbb, CompilerScratch* csb, StreamTy const jrd_fld* field = MET_get_field(relation, id); if (field->fld_source) - newId = field->fld_source->as()->fieldId; + newId = nodeAs(field->fld_source)->fieldId; else newId = id; } @@ -9353,13 +9450,13 @@ static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb, for (size_t i = compoundNode->statements.getCount(); i--; ) { - const AssignmentNode* assign = compoundNode->statements[i]->as(); + const AssignmentNode* assign = nodeAs(compoundNode->statements[i]); fb_assert(assign); if (!assign) continue; const ExprNode* assignFrom = assign->asgnFrom; - const FieldNode* assignToField = assign->asgnTo->as(); + const FieldNode* assignToField = nodeAs(assign->asgnTo); if (assignToField) { @@ -9374,7 +9471,7 @@ static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb, { if (insertOverride && fld->fld_identity_type.specified) { - if (insertOverride->specified || !assignFrom->is()) + if (insertOverride->specified || !nodeIs(assignFrom)) identityType = fld->fld_identity_type; if (*insertOverride == OverrideClause::USER_VALUE) @@ -9386,7 +9483,7 @@ static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb, if (fld->fld_computation) { - if (assignFrom->is()) + if (nodeIs(assignFrom)) compoundNode->statements.remove(i); } else if (relation->rel_view_rse && fld->fld_source_rel_field.first.hasData()) @@ -9447,7 +9544,7 @@ static void validateExpressions(thread_db* tdbb, const Array& vali const dsc* desc = EVL_expr(tdbb, request, i->value); const USHORT length = (desc && !(request->req_flags & req_null)) ? - MOV_make_string(desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1) : 0; + MOV_make_string(tdbb, desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1) : 0; if (!desc || (request->req_flags & req_null)) value = NULL_STRING_MARK; @@ -9457,7 +9554,7 @@ static void validateExpressions(thread_db* tdbb, const Array& vali const_cast(value)[length] = 0; // safe cast - data is actually on the stack string name; - const FieldNode* fieldNode = i->value->as(); + const FieldNode* fieldNode = nodeAs(i->value); if (fieldNode) { diff --git a/src/dsql/StmtNodes.h b/src/dsql/StmtNodes.h index 57329a08e0..60c0d1f475 100644 --- a/src/dsql/StmtNodes.h +++ b/src/dsql/StmtNodes.h @@ -1556,22 +1556,18 @@ public: }; -// This node should better be session management node, -// but as long as we do not have other session management and -// node is rather similiar internally to transaction management -// let it for now be transaction management node. -class SetRoleNode : public TransactionNode +class SetRoleNode : public SessionManagementNode { public: explicit SetRoleNode(MemoryPool& pool) - : TransactionNode(pool), + : SessionManagementNode(pool), trusted(true), roleName(pool) { } SetRoleNode(MemoryPool& pool, Firebird::MetaName* name) - : TransactionNode(pool), + : SessionManagementNode(pool), trusted(false), roleName(pool, *name) { @@ -1580,7 +1576,7 @@ public: public: virtual Firebird::string internalPrint(NodePrinter& printer) const { - TransactionNode::internalPrint(printer); + SessionManagementNode::internalPrint(printer); NODE_PRINT(printer, trusted); NODE_PRINT(printer, roleName); @@ -1588,8 +1584,7 @@ public: return "SetRoleNode"; } - virtual SetRoleNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); - virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const; + virtual void execute(thread_db* tdbb, dsql_req* request) const; public: bool trusted; @@ -1597,6 +1592,99 @@ public: }; +class SetSessionNode : public SessionManagementNode +{ +public: + enum Type { TYPE_IDLE_TIMEOUT, TYPE_STMT_TIMEOUT }; + + SetSessionNode(MemoryPool& pool, Type aType, ULONG aVal, UCHAR blr_timepart); + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const; + virtual void execute(thread_db* tdbb, dsql_req* request) const; + +private: + Type m_type; + ULONG m_value; +}; + + +class SetRoundNode : public SessionManagementNode +{ +public: + SetRoundNode(MemoryPool& pool, Firebird::MetaName* name); + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const + { + SessionManagementNode::internalPrint(printer); + + NODE_PRINT(printer, rndMode); + + return "SetRoundNode"; + } + + virtual void execute(thread_db* tdbb, dsql_req* request) const; + +public: + USHORT rndMode; +}; + + +class SetTrapsNode : public SessionManagementNode +{ +public: + SetTrapsNode(MemoryPool& pool) + : SessionManagementNode(pool), + traps(0u) + { + } + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const + { + SessionManagementNode::internalPrint(printer); + + NODE_PRINT(printer, traps); + + return "SetTrapsNode"; + } + + virtual void execute(thread_db* tdbb, dsql_req* request) const; + + void trap(Firebird::MetaName* name); + +public: + USHORT traps; +}; + + +class SetBindNode : public SessionManagementNode +{ +public: + SetBindNode(MemoryPool& pool) + : SessionManagementNode(pool) + { + } + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const + { + SessionManagementNode::internalPrint(printer); + + NODE_PRINT(printer, bind.bind); + NODE_PRINT(printer, bind.numScale); + + return "SetBindNode"; + } + + virtual void execute(thread_db* tdbb, dsql_req* request) const; + +public: + Firebird::DecimalBinding bind; +}; + + class UpdateOrInsertNode : public TypedNode { public: diff --git a/src/dsql/WinNodes.cpp b/src/dsql/WinNodes.cpp index 2766f16aed..e04c452792 100644 --- a/src/dsql/WinNodes.cpp +++ b/src/dsql/WinNodes.cpp @@ -599,7 +599,7 @@ dsc* NthValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* if (!desc || (request->req_flags & req_null)) return NULL; - SINT64 records = MOV_get_int64(desc, 0); + SINT64 records = MOV_get_int64(tdbb, desc, 0); if (records <= 0) { status_exception::raise(Arg::Gds(isc_sysf_argnmustbe_positive) << @@ -607,7 +607,7 @@ dsc* NthValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* } desc = EVL_expr(tdbb, request, from); - const SLONG fromPos = desc ? MOV_get_long(desc, 0) : FROM_FIRST; + const SLONG fromPos = desc ? MOV_get_long(tdbb, desc, 0) : FROM_FIRST; if (fromPos == FROM_FIRST) records += -(window->getRecordPosition() - window->getFrameStart()) - 1; @@ -688,7 +688,7 @@ dsc* LagLeadWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* w if (!desc || (request->req_flags & req_null)) return NULL; - SINT64 records = MOV_get_int64(desc, 0); + SINT64 records = MOV_get_int64(tdbb, desc, 0); if (records < 0) { status_exception::raise(Arg::Gds(isc_sysf_argnmustbe_nonneg) << @@ -850,7 +850,7 @@ void NTileWinNode::aggInit(thread_db* tdbb, jrd_req* request) const Arg::Num(1) << Arg::Str(aggInfo.name)); } - thisImpure->buckets = MOV_get_int64(desc, 0); + thisImpure->buckets = MOV_get_int64(tdbb, desc, 0); if (thisImpure->buckets <= 0) { diff --git a/src/dsql/ddl_proto.h b/src/dsql/ddl_proto.h index 5f93c1e934..206c0e1d09 100644 --- a/src/dsql/ddl_proto.h +++ b/src/dsql/ddl_proto.h @@ -57,7 +57,9 @@ const USHORT blr_dtypes[] = { blr_short, // dtype_array blr_int64, // dtype_int64 0, // DB_KEY - blr_bool // dtype_boolean + blr_bool, // dtype_boolean + blr_dec64, // dtype_dec64 + blr_dec128 // dtype_dec128 }; bool DDL_ids(const Jrd::DsqlCompilerScratch*); diff --git a/src/dsql/dsql.cpp b/src/dsql/dsql.cpp index 2be813f0bb..21c8de18a4 100644 --- a/src/dsql/dsql.cpp +++ b/src/dsql/dsql.cpp @@ -151,7 +151,7 @@ void DSQL_execute(thread_db* tdbb, if (!*tra_handle && statement->getType() != DsqlCompiledStatement::TYPE_START_TRANS && - statement->getType() != DsqlCompiledStatement::TYPE_SET_SESSION) + statement->getType() != DsqlCompiledStatement::TYPE_SESSION_MANAGEMENT) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) << Arg::Gds(isc_bad_trans_handle)); @@ -548,7 +548,7 @@ void DSQL_execute_immediate(thread_db* tdbb, Jrd::Attachment* attachment, jrd_tr if (!*tra_handle && statement->getType() != DsqlCompiledStatement::TYPE_START_TRANS && - statement->getType() != DsqlCompiledStatement::TYPE_SET_SESSION) + statement->getType() != DsqlCompiledStatement::TYPE_SESSION_MANAGEMENT) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) << Arg::Gds(isc_bad_trans_handle)); @@ -922,15 +922,7 @@ void DsqlTransactionRequest::execute(thread_db* tdbb, jrd_tra** traHandle, } -void SetSessionRequest::execute(thread_db* tdbb, jrd_tra** /*traHandle*/, - IMessageMetadata* /*inMetadata*/, const UCHAR* /*inMsg*/, - IMessageMetadata* /*outMetadata*/, UCHAR* /*outMsg*/, - bool /*singleton*/) -{ - node->execute(tdbb, this); -} - -void SetSessionRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, +void DsqlSessionManagementRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, ntrace_result_t* /*traceResult*/) { node = Node::doDsqlPass(scratch, node); @@ -939,6 +931,15 @@ void SetSessionRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, req_traced = false; } +// Execute a dynamic SQL statement. +void DsqlSessionManagementRequest::execute(thread_db* tdbb, jrd_tra** traHandle, + Firebird::IMessageMetadata* inMetadata, const UCHAR* inMsg, + Firebird::IMessageMetadata* outMetadata, UCHAR* outMsg, + bool singleton) +{ + node->execute(tdbb, this); +} + /** @@ -1875,8 +1876,6 @@ static void sql_info(thread_db* tdbb, break; case DsqlCompiledStatement::TYPE_CREATE_DB: case DsqlCompiledStatement::TYPE_DDL: - case DsqlCompiledStatement::TYPE_SET_ROLE: - case DsqlCompiledStatement::TYPE_SET_SESSION: number = isc_info_sql_stmt_ddl; break; case DsqlCompiledStatement::TYPE_COMMIT: @@ -1890,6 +1889,9 @@ static void sql_info(thread_db* tdbb, case DsqlCompiledStatement::TYPE_START_TRANS: number = isc_info_sql_stmt_start_trans; break; + case DsqlCompiledStatement::TYPE_SESSION_MANAGEMENT: + number = isc_info_sql_stmt_ddl; // ????????????????? + break; case DsqlCompiledStatement::TYPE_INSERT: number = isc_info_sql_stmt_insert; break; diff --git a/src/dsql/dsql.h b/src/dsql/dsql.h index 53c03c9e41..21ce846320 100644 --- a/src/dsql/dsql.h +++ b/src/dsql/dsql.h @@ -80,7 +80,7 @@ namespace Jrd class RseNode; class StmtNode; class TransactionNode; - class SetSessionNode; + class SessionManagementNode; class ValueExprNode; class ValueListNode; class WindowClause; @@ -237,6 +237,31 @@ public: { } +public: + void setExactPrecision() + { + if (precision != 0) + return; + + switch (dtype) + { + case dtype_short: + precision = 4; + break; + + case dtype_long: + precision = 9; + break; + + case dtype_int64: + precision = 18; + break; + + default: + fb_assert(!DTYPE_IS_EXACT(dtype)); + } + } + public: USHORT dtype; FLD_LENGTH length; @@ -433,7 +458,7 @@ public: TYPE_SELECT, TYPE_SELECT_UPD, TYPE_INSERT, TYPE_DELETE, TYPE_UPDATE, TYPE_UPDATE_CURSOR, TYPE_DELETE_CURSOR, TYPE_COMMIT, TYPE_ROLLBACK, TYPE_CREATE_DB, TYPE_DDL, TYPE_START_TRANS, TYPE_EXEC_PROCEDURE, TYPE_COMMIT_RETAIN, TYPE_ROLLBACK_RETAIN, TYPE_SET_GENERATOR, - TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK, TYPE_SET_ROLE, TYPE_SET_SESSION + TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK, TYPE_SESSION_MANAGEMENT }; // Statement flags. @@ -686,10 +711,10 @@ private: NestConst node; }; -class SetSessionRequest : public dsql_req +class DsqlSessionManagementRequest : public dsql_req { public: - explicit SetSessionRequest(MemoryPool& pool, SetSessionNode* aNode) + explicit DsqlSessionManagementRequest(MemoryPool& pool, SessionManagementNode* aNode) : dsql_req(pool), node(aNode) { @@ -705,7 +730,7 @@ public: bool singleton); private: - NestConst node; + NestConst node; }; //! Implicit (NATURAL and USING) joins @@ -958,6 +983,23 @@ private: Firebird::string s; }; +class Lim64String : public Firebird::string +{ +public: + Lim64String(Firebird::MemoryPool& p, const Firebird::string& str, int sc) + : Firebird::string(p, str), + scale(sc) + { } + + int getScale() + { + return scale; + } + +private: + int scale; +}; + } // namespace /*! \var unsigned DSQL_debug diff --git a/src/dsql/gen.cpp b/src/dsql/gen.cpp index b68977a00a..cde7b3a118 100644 --- a/src/dsql/gen.cpp +++ b/src/dsql/gen.cpp @@ -108,7 +108,7 @@ void GEN_hidden_variables(DsqlCompilerScratch* dsqlScratch) **/ void GEN_expr(DsqlCompilerScratch* dsqlScratch, ExprNode* node) { - RseNode* rseNode = node->as(); + RseNode* rseNode = nodeAs(node); if (rseNode) { GEN_rse(dsqlScratch, rseNode); @@ -201,6 +201,25 @@ void GEN_port(DsqlCompilerScratch* dsqlScratch, dsql_msg* message) if (fromCharSet != toCharSet) parameter->par_desc.setTextType(toCharSet); } + else if (parameter->par_desc.isDecFloat()) + { + const DecimalBinding& b = tdbb->getAttachment()->att_dec_binding; + switch (b.bind) + { + case DecimalBinding::DEC_NATIVE: + break; + case DecimalBinding::DEC_TEXT: + parameter->par_desc.makeText((parameter->par_desc.dsc_dtype == dtype_dec64 ? + IDecFloat16::STRING_SIZE : IDecFloat34::STRING_SIZE) - 1, ttype_ascii); + break; + case DecimalBinding::DEC_DOUBLE: + parameter->par_desc.makeDouble(); + break; + case DecimalBinding::DEC_NUMERIC: + parameter->par_desc.makeInt64(b.numScale); + break; + } + } if (parameter->par_desc.dsc_dtype == dtype_text && parameter->par_index != 0) { @@ -366,6 +385,14 @@ void GEN_descriptor( DsqlCompilerScratch* dsqlScratch, const dsc* desc, bool tex dsqlScratch->appendUChar(blr_double); break; + case dtype_dec64: + dsqlScratch->appendUChar(blr_dec64); + break; + + case dtype_dec128: + dsqlScratch->appendUChar(blr_dec128); + break; + case dtype_sql_date: dsqlScratch->appendUChar(blr_sql_date); break; @@ -598,7 +625,7 @@ void GEN_sort(DsqlCompilerScratch* dsqlScratch, UCHAR blrVerb, ValueListNode* li for (const NestConst* const end = list->items.end(); ptr != end; ++ptr) { - OrderNode* orderNode = (*ptr)->as(); + OrderNode* orderNode = nodeAs(*ptr); switch (orderNode->nullsPlacement) { diff --git a/src/dsql/make.cpp b/src/dsql/make.cpp index 29a7ea633e..a41c22ef14 100644 --- a/src/dsql/make.cpp +++ b/src/dsql/make.cpp @@ -118,19 +118,25 @@ ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag) switch (numeric_flag) { case CONSTANT_DOUBLE: + case CONSTANT_DECIMAL: // This is a numeric value which is transported to the engine as - // a string. The engine will convert it. Use dtype_double so that - // the engine can distinguish it from an actual string. - // Note: Due to the size of dsc_scale we are limited to numeric - // constants of less than 256 bytes. + // a string. The engine will convert it. Use dtype_double/dec128 + // so that the engine can distinguish it from an actual string. + // Note: Due to the size of dsc_sub_type literal length is limited + // to constants less than 32K - 1 bytes. Not real problem. - literal->litDesc.dsc_dtype = dtype_double; - // Scale has no use for double - literal->litDesc.dsc_scale = static_cast(strlen(str)); - literal->litDesc.dsc_sub_type = 0; - literal->litDesc.dsc_length = sizeof(double); - literal->litDesc.dsc_address = (UCHAR*) str; - literal->litDesc.dsc_ttype() = ttype_ascii; + { + literal->litDesc.dsc_dtype = numeric_flag == CONSTANT_DOUBLE ? dtype_double : dtype_dec128; + literal->litDesc.dsc_scale = 0; + size_t l = strlen(str); + if (l > MAX_SSHORT) + { + ERRD_post(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_random) << "Numeric literal too long"); + } + literal->litDesc.dsc_sub_type = static_cast(l); // Keep length in sub_type which is unused + literal->litDesc.dsc_length = numeric_flag == CONSTANT_DOUBLE ? sizeof(double) : sizeof(Decimal128); + literal->litDesc.dsc_address = (UCHAR*) str; + } break; case CONSTANT_DATE: @@ -169,7 +175,7 @@ ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag) // Now invoke the string_to_date/time/timestamp routines - CVT_move(&tmp, &literal->litDesc, ERRD_post); + CVT_move(&tmp, &literal->litDesc, tdbb->getAttachment()->att_dec_status, ERRD_post); break; } diff --git a/src/dsql/make_proto.h b/src/dsql/make_proto.h index f14db35302..7e6311c467 100644 --- a/src/dsql/make_proto.h +++ b/src/dsql/make_proto.h @@ -46,6 +46,7 @@ namespace Jrd { // Parameters to MAKE_constant enum dsql_constant_type { CONSTANT_DOUBLE = 1, // stored as a string + CONSTANT_DECIMAL, // stored as a string CONSTANT_DATE, // stored as a SLONG CONSTANT_TIME, // stored as a ULONG CONSTANT_TIMESTAMP, // stored as a QUAD diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 214515b423..723b7c2471 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -332,7 +332,8 @@ using namespace Firebird; %token WORK %token WRITE -%token FLOAT_NUMBER +%token FLOAT_NUMBER DECIMAL_NUMBER LIMIT64_INT +%token LIMIT64_NUMBER %token SYMBOL %token NUMBER @@ -592,19 +593,25 @@ using namespace Firebird; // tokens added for Firebird 4.0 %token BINARY +%token BIND +%token COMPARE_DECFLOAT %token CUME_DIST +%token DECFLOAT %token DEFINER %token EXCLUDE %token FOLLOWING %token IDLE %token INVOKER %token MESSAGE +%token NATIVE +%token NORMALIZE_DECFLOAT %token NTILE %token OTHERS %token OVERRIDING %token PERCENT_RANK %token PRECEDING %token PRIVILEGE +%token QUANTIZE %token RANGE %token RDB_ERROR %token RDB_ROLE_IN_USE @@ -614,6 +621,8 @@ using namespace Firebird; %token SQL %token SYSTEM %token TIES +%token TOTALORDER +%token TRAPS %token UNBOUNDED %token VARBINARY %token WINDOW @@ -673,6 +682,7 @@ using namespace Firebird; Firebird::QualifiedName* qualifiedNamePtr; Firebird::string* stringPtr; Jrd::IntlString* intlStringPtr; + Jrd::Lim64String* lim64ptr; Jrd::DbFileClause* dbFileClause; Firebird::Array >* dbFilesClause; Jrd::ExternalClause* externalClause; @@ -704,6 +714,7 @@ using namespace Firebird; Jrd::NamedWindowClause* namedWindowClause; Jrd::NamedWindowsClause* namedWindowsClause; Jrd::TransactionNode* traNode; + Jrd::SessionManagementNode* mngNode; Firebird::Array* privilegeArray; Jrd::GranteeClause* granteeClause; Firebird::Array* granteeArray; @@ -762,6 +773,9 @@ using namespace Firebird; Jrd::SetRoleNode* setRoleNode; Jrd::SetSessionNode* setSessionNode; Jrd::CreateAlterRoleNode* createAlterRoleNode; + Jrd::SetRoundNode* setRoundNode; + Jrd::SetTrapsNode* setTrapsNode; + Jrd::SetBindNode* setBindNode; } %include types.y @@ -780,7 +794,7 @@ statement : dml_statement { $$ = newNode($1); } | ddl_statement { $$ = newNode($1); } | tra_statement { $$ = newNode($1); } - | session_statement { $$ = newNode($1); } + | mng_statement { $$ = newNode($1); } ; %type dml_statement @@ -815,6 +829,14 @@ tra_statement : set_transaction { $$ = $1; } | commit { $$ = $1; } | rollback { $$ = $1; } + ; + +%type mng_statement +mng_statement + : set_round { $$ = $1; } + | set_traps { $$ = $1; } + | set_bind { $$ = $1; } + | session_statement { $$ = $1; } | set_role { $$ = $1; } ; @@ -1826,6 +1848,10 @@ sequence_value $$ = -signedNumber; } + | '-' LIMIT64_INT + { + $$ = MIN_SINT64; + } ; @@ -2349,7 +2375,7 @@ column_constraint($addColumnClause) const NestConst* ptr = refColumns->items.begin(); for (const NestConst* const end = refColumns->items.end(); ptr != end; ++ptr) - constraint.refColumns.add((*ptr)->as()->dsqlName); + constraint.refColumns.add(nodeAs(*ptr)->dsqlName); } constraint.index = $5; @@ -2400,7 +2426,7 @@ table_constraint($relationNode) const NestConst* ptr = columns->items.begin(); for (const NestConst* const end = columns->items.end(); ptr != end; ++ptr) - constraint.columns.add((*ptr)->as()->dsqlName); + constraint.columns.add(nodeAs(*ptr)->dsqlName); constraint.index = $3; @@ -2415,7 +2441,7 @@ table_constraint($relationNode) const NestConst* ptr = columns->items.begin(); for (const NestConst* const end = columns->items.end(); ptr != end; ++ptr) - constraint.columns.add((*ptr)->as()->dsqlName); + constraint.columns.add(nodeAs(*ptr)->dsqlName); constraint.index = $4; @@ -2431,7 +2457,7 @@ table_constraint($relationNode) const NestConst* ptr = columns->items.begin(); for (const NestConst* const end = columns->items.end(); ptr != end; ++ptr) - constraint.columns.add((*ptr)->as()->dsqlName); + constraint.columns.add(nodeAs(*ptr)->dsqlName); constraint.refRelation = *$5; constraint.refAction = $7; @@ -2442,7 +2468,7 @@ table_constraint($relationNode) const NestConst* ptr = refColumns->items.begin(); for (const NestConst* const end = refColumns->items.end(); ptr != end; ++ptr) - constraint.refColumns.add((*ptr)->as()->dsqlName); + constraint.refColumns.add(nodeAs(*ptr)->dsqlName); } constraint.index = $8; @@ -3572,78 +3598,45 @@ check_opt %type trigger_clause trigger_clause - : symbol_trigger_name trigger_active trigger_type trigger_position trg_sql_security_clause - AS local_declaration_list full_proc_block + : create_trigger_start trg_sql_security_clause AS local_declaration_list full_proc_block { - $$ = newNode(*$1); - $$->active = $2; - $$->type = $3; - $$->position = $4; - $$->ssDefiner = $5; - $$->source = makeParseStr(YYPOSNARG(6), YYPOSNARG(8)); - $$->localDeclList = $7; - $$->body = $8; + $$ = $1; + $$->ssDefiner = $2; + $$->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(5)); + $$->localDeclList = $4; + $$->body = $5; } - | symbol_trigger_name trigger_active trigger_type trigger_position - external_clause external_body_clause_opt + | create_trigger_start external_clause external_body_clause_opt { - $$ = newNode(*$1); - $$->active = $2; - $$->type = $3; - $$->position = $4; - $$->external = $5; - if ($6) - $$->source = *$6; + $$ = $1; + $$->external = $2; + if ($3) + $$->source = *$3; } - | symbol_trigger_name trigger_active trigger_type trigger_position ON symbol_table_name trg_sql_security_clause - AS local_declaration_list full_proc_block + ; + +%type create_trigger_start +create_trigger_start + : symbol_trigger_name + { $$ = newNode(*$1); } + create_trigger_common(NOTRIAL($2)) + { $$ = $2; } + ; + +%type create_trigger_common() +create_trigger_common($trigger) + : trigger_active trigger_type(NOTRIAL($trigger)) trigger_position { - $$ = newNode(*$1); - $$->active = $2; - $$->type = $3; - $$->position = $4; - $$->relationName = *$6; - $$->ssDefiner = $7; - $$->source = makeParseStr(YYPOSNARG(8), YYPOSNARG(10)); - $$->localDeclList = $9; - $$->body = $10; + $trigger->active = $1; + $trigger->type = $2; + $trigger->position = $3; } - | symbol_trigger_name trigger_active trigger_type trigger_position ON symbol_table_name - external_clause external_body_clause_opt + | FOR symbol_table_name trigger_active table_trigger_type trigger_position { - $$ = newNode(*$1); - $$->active = $2; - $$->type = $3; - $$->position = $4; - $$->relationName = *$6; - $$->external = $7; - if ($8) - $$->source = *$8; - } - | symbol_trigger_name FOR symbol_table_name trigger_active trigger_type trigger_position trg_sql_security_clause - AS local_declaration_list full_proc_block - { - $$ = newNode(*$1); - $$->active = $4; - $$->type = $5; - $$->position = $6; - $$->relationName = *$3; - $$->ssDefiner = $7; - $$->source = makeParseStr(YYPOSNARG(8), YYPOSNARG(10)); - $$->localDeclList = $9; - $$->body = $10; - } - | symbol_trigger_name FOR symbol_table_name trigger_active trigger_type trigger_position - external_clause external_body_clause_opt - { - $$ = newNode(*$1); - $$->active = $4; - $$->type = $5; - $$->position = $6; - $$->relationName = *$3; - $$->external = $7; - if ($8) - $$->source = *$8; + $trigger->relationName = *$2; + $trigger->active = $3; + $trigger->type = $4; + $trigger->position = $5; } ; @@ -3666,11 +3659,22 @@ trigger_active { $$ = Nullable::empty(); } ; -%type trigger_type -trigger_type +%type trigger_type() +trigger_type($trigger) + : table_trigger_type ON symbol_table_name + { + $$ = $1; + $trigger->relationName = *$3; + } + | ON trigger_db_type + { $$ = $2; } + | trigger_type_prefix trigger_ddl_type + { $$ = $1 + $2; } + ; + +%type table_trigger_type +table_trigger_type : trigger_type_prefix trigger_type_suffix { $$ = $1 + $2 - 1; } - | ON trigger_db_type { $$ = $2; } - | trigger_type_prefix trigger_ddl_type { $$ = $1 + $2; } ; %type trigger_db_type @@ -4466,6 +4470,7 @@ non_charset_simple_type | binary_character_type | numeric_type | float_type + | decfloat_type | BIGINT { $$ = newNode(); @@ -4733,6 +4738,20 @@ varbinary_character_keyword // numeric type +%type decfloat_type +decfloat_type + : DECFLOAT '(' signed_long_integer ')' + { + if ($3 != 16 && $3 != 34) + yyabandon(YYPOSNARG(3), -842, isc_decprecision_err); // DecFloat precision must be 16 or 34. + + $$ = newNode(); + $$->precision = $3; + $$->dtype = $3 == 16 ? dtype_dec64 : dtype_dec128; + $$->length = $3 == 16 ? sizeof(Decimal64) : sizeof(Decimal128); + } + ; + %type numeric_type numeric_type : NUMERIC prec_scale @@ -5017,6 +5036,68 @@ set_role { $$ = newNode(); } ; +%type set_round +set_round + : SET DECFLOAT ROUND valid_symbol_name + { $$ = newNode($4); } + ; + +%type set_traps +set_traps + : SET DECFLOAT TRAPS TO + { $$ = newNode(); } + traps_list_opt($5) + { $$ = $5; } + ; + +%type set_bind +set_bind + : SET DECFLOAT BIND + { $$ = newNode(); } + bind_clause($4) + { $$ = $4; } + ; + +%type traps_list_opt() +traps_list_opt($setTrapsNode) + : // nothing + | traps_list($setTrapsNode) + ; + +%type traps_list() +traps_list($setTrapsNode) + : trap($setTrapsNode) + | traps_list ',' trap($setTrapsNode) + ; + +%type trap() +trap($setTrapsNode) + : valid_symbol_name + { $setTrapsNode->trap($1); } + ; + +%type bind_clause() +bind_clause($setBindNode) + : NATIVE + // do nothing + | character_keyword + { $setBindNode->bind.bind = DecimalBinding::DEC_TEXT; } + | DOUBLE PRECISION + { $setBindNode->bind.bind = DecimalBinding::DEC_DOUBLE; } + | BIGINT scale_clause($setBindNode) + { $setBindNode->bind.bind = DecimalBinding::DEC_NUMERIC; } + ; + +%type scale_clause() +scale_clause($setBindNode) + : // nothing + | ',' signed_long_integer + { + if ($2 > 18 || $2 < 0) + yyabandon(YYPOSNARG(2), -842, isc_scale_nogt); // Scale must be between 0 and precision + $setBindNode->bind.numScale = -$2; + } + %type session_statement session_statement : SET SESSION IDLE TIMEOUT long_integer timepart_sesion_idle_tout @@ -5380,7 +5461,7 @@ select_expr_body { $$ = $1; } | select_expr_body UNION distinct_noise query_term { - UnionSourceNode* node = $1->as(); + UnionSourceNode* node = nodeAs($1); if (node && !node->dsqlAll) node->dsqlClauses->add($4); else @@ -5392,7 +5473,7 @@ select_expr_body } | select_expr_body UNION ALL query_term { - UnionSourceNode* node = $1->as(); + UnionSourceNode* node = nodeAs($1); if (node && node->dsqlAll) node->dsqlClauses->add($4); else @@ -7044,16 +7125,30 @@ value_list %type constant constant : u_constant - | '-' u_numeric_constant { $$ = newNode($2); } + | '-' ul_numeric_constant { $$ = newNode($2); } + | '-' LIMIT64_INT { $$ = MAKE_const_sint64(MIN_SINT64, 0); } + | '-' LIMIT64_NUMBER { $$ = MAKE_const_sint64(MIN_SINT64, $2->getScale()); } | boolean_literal ; %type u_numeric_constant u_numeric_constant + : ul_numeric_constant + { $$ = $1; } + | LIMIT64_NUMBER + { $$ = MAKE_constant($1->c_str(), CONSTANT_DECIMAL); } + | LIMIT64_INT + { $$ = MAKE_constant($1->c_str(), CONSTANT_DECIMAL); } + ; + +%type ul_numeric_constant +ul_numeric_constant : NUMBER { $$ = MAKE_const_slong($1); } | FLOAT_NUMBER { $$ = MAKE_constant($1->c_str(), CONSTANT_DOUBLE); } + | DECIMAL_NUMBER + { $$ = MAKE_constant($1->c_str(), CONSTANT_DECIMAL); } | NUMBER64BIT { SINT64 signedNumber = (SINT64) $1.number; @@ -7586,6 +7681,10 @@ system_function_std_syntax | TANH | TRUNC | UUID_TO_CHAR + | QUANTIZE + | TOTALORDER + | NORMALIZE_DECFLOAT + | COMPARE_DECFLOAT ; %type system_function_special_syntax @@ -7808,10 +7907,10 @@ searched_case ValueIfNode* last = $2; ValueIfNode* next; - while ((next = last->falseValue->as())) + while ((next = nodeAs(last->falseValue))) last = next; - fb_assert(last->falseValue->is()); + fb_assert(nodeIs(last->falseValue)); last->falseValue = $4; $$ = $2; @@ -7828,10 +7927,10 @@ searched_when_clause ValueIfNode* last = $1; ValueIfNode* next; - while ((next = last->falseValue->as())) + while ((next = nodeAs(last->falseValue))) last = next; - fb_assert(last->falseValue->is()); + fb_assert(nodeIs(last->falseValue)); last->falseValue = cond; $$ = $1; @@ -8284,25 +8383,33 @@ non_reserved_word | SERVERWIDE | INCREMENT | TRUSTED - | CUME_DIST // added in FB 4.0 + | BIND // added in FB 4.0 + | COMPARE_DECFLOAT + | CUME_DIST + | DECFLOAT | DEFINER | EXCLUDE | FOLLOWING | IDLE | INVOKER | MESSAGE + | NATIVE + | NORMALIZE_DECFLOAT | NTILE | OTHERS | OVERRIDING | PERCENT_RANK | PRECEDING | PRIVILEGE + | QUANTIZE | RANGE | SECURITY | SESSION | SQL | SYSTEM | TIES + | TOTALORDER + | TRAPS | CONSISTENCY ; diff --git a/src/dsql/pass1.cpp b/src/dsql/pass1.cpp index a2f330aae3..74ed71b620 100644 --- a/src/dsql/pass1.cpp +++ b/src/dsql/pass1.cpp @@ -351,11 +351,11 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* RelationSourceNode* relNode = NULL; SelectExprNode* selNode = NULL; - if ((procNode = relationNode->as())) + if ((procNode = nodeAs(relationNode))) relation_name = procNode->dsqlName.identifier; - else if ((relNode = relationNode->as())) + else if ((relNode = nodeAs(relationNode))) relation_name = relNode->dsqlName; - else if ((selNode = relationNode->as())) + else if ((selNode = nodeAs(relationNode))) relation_name = selNode->alias.c_str(); SelectExprNode* cte = NULL; @@ -445,11 +445,11 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* // find the context alias name, if it exists. string str; - if ((procNode = relationNode->as())) + if ((procNode = nodeAs(relationNode))) str = procNode->alias; - else if ((relNode = relationNode->as())) + else if ((relNode = nodeAs(relationNode))) str = relNode->alias; - else if ((selNode = relationNode->as())) + else if ((selNode = nodeAs(relationNode))) { str = selNode->alias; // ASF: In the case of a UNION contained in a CTE, selNode->querySpec will be a @@ -668,11 +668,11 @@ void PASS1_check_unique_fields_names(StrArray& names, const CompoundStmtNode* fi const DeclareVariableNode* varNode; const DeclareCursorNode* cursorNode; - if ((varNode = (*ptr)->as())) + if ((varNode = nodeAs(*ptr))) name = varNode->dsqlDef->name.c_str(); - else if ((cursorNode = (*ptr)->as())) + else if ((cursorNode = nodeAs(*ptr))) name = cursorNode->dsqlName.c_str(); - else if ((*ptr)->as() || (*ptr)->as()) + else if (nodeAs(*ptr) || nodeAs(*ptr)) continue; fb_assert(name); @@ -796,11 +796,11 @@ bool PASS1_node_match(const ExprNode* node1, const ExprNode* node2, bool ignoreM if (!node1 || !node2) return false; - const CastNode* castNode1 = node1->as(); + const CastNode* castNode1 = nodeAs(node1); if (ignoreMapCast && castNode1) { - const CastNode* castNode2 = node2->as(); + const CastNode* castNode2 = nodeAs(node2); // If node2 is also cast and same type continue with both sources. if (castNode2 && @@ -815,11 +815,11 @@ bool PASS1_node_match(const ExprNode* node1, const ExprNode* node2, bool ignoreM return PASS1_node_match(castNode1->source, node2, ignoreMapCast); } - const DsqlMapNode* mapNode1 = node1->as(); + const DsqlMapNode* mapNode1 = nodeAs(node1); if (ignoreMapCast && mapNode1) { - const DsqlMapNode* mapNode2 = node2->as(); + const DsqlMapNode* mapNode2 = nodeAs(node2); if (mapNode2) { @@ -832,8 +832,8 @@ bool PASS1_node_match(const ExprNode* node1, const ExprNode* node2, bool ignoreM return PASS1_node_match(mapNode1->map->map_node, node2, ignoreMapCast); } - const DsqlAliasNode* aliasNode1 = node1->as(); - const DsqlAliasNode* aliasNode2 = node2->as(); + const DsqlAliasNode* aliasNode1 = nodeAs(node1); + const DsqlAliasNode* aliasNode2 = nodeAs(node2); // We don't care about the alias itself but only about its field. if (aliasNode1 || aliasNode2) @@ -850,8 +850,8 @@ bool PASS1_node_match(const ExprNode* node1, const ExprNode* node2, bool ignoreM // Handle derived fields. - const DerivedFieldNode* derivedField1 = node1->as(); - const DerivedFieldNode* derivedField2 = node2->as(); + const DerivedFieldNode* derivedField1 = nodeAs(node1); + const DerivedFieldNode* derivedField2 = nodeAs(node2); if (derivedField1 || derivedField2) { @@ -998,7 +998,7 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i dsqlScratch->aliasRelationPrefix = pass1_alias_concat(aliasRelationPrefix, alias); RecordSourceNode* query = input->querySpec; - UnionSourceNode* unionQuery = query->as(); + UnionSourceNode* unionQuery = nodeAs(query); RseNode* rse = NULL; const bool isRecursive = unionQuery && unionQuery->recursive; USHORT recursive_map_ctx = 0; @@ -1046,7 +1046,7 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i // the worse thing is that a UNION currently can't be used in // deciding the JOIN order. bool foundSubSelect = false; - RseNode* queryNode = query->as(); + RseNode* queryNode = nodeAs(query); if (queryNode) foundSubSelect = SubSelectFinder::find(queryNode->dsqlSelectList); @@ -1146,7 +1146,7 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i rse->dsqlSelectList->items[count]); // Auto-create dummy column name for pass1_any() - if (ignoreColumnChecks && !ExprNode::is(select_item)) + if (ignoreColumnChecks && !nodeIs(select_item)) { MAKE_desc(dsqlScratch, &select_item->nodDesc, select_item); @@ -1174,7 +1174,7 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i ValueExprNode* select_item = rse->dsqlSelectList->items[count]; DerivedFieldNode* derivedField; - if ((derivedField = ExprNode::as(select_item))) + if ((derivedField = nodeAs(select_item))) derivedField->context = context; else { @@ -1190,13 +1190,11 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i // Check for ambiguous column names inside this derived table. for (count = 0; count < rse->dsqlSelectList->items.getCount(); ++count) { - const DerivedFieldNode* selectItem1 = - rse->dsqlSelectList->items[count]->as(); + const DerivedFieldNode* selectItem1 = nodeAs(rse->dsqlSelectList->items[count]); for (FB_SIZE_T count2 = (count + 1); count2 < rse->dsqlSelectList->items.getCount(); ++count2) { - const DerivedFieldNode* selectItem2 = - rse->dsqlSelectList->items[count2]->as(); + const DerivedFieldNode* selectItem2 = nodeAs(rse->dsqlSelectList->items[count2]); if (selectItem1->name == selectItem2->name) { @@ -1252,10 +1250,10 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i ValueExprNode* map_item = items->items[0]; DerivedFieldNode* derivedField; - if ((derivedField = ExprNode::as(map_item))) + if ((derivedField = nodeAs(map_item))) map_item = derivedField->value; - dsql_ctx* map_context = ExprNode::as(map_item)->context; + dsql_ctx* map_context = nodeAs(map_item)->context; map_context->ctx_flags |= CTX_recursive; map_context->ctx_recursive = recursive_map_ctx; @@ -1314,7 +1312,7 @@ void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node, RelationSourceNode* relNode; FieldNode* fieldNode; - if ((rseNode = ExprNode::as(node))) + if ((rseNode = nodeAs(node))) { ValueListNode* sub_items = rseNode->dsqlSelectList; @@ -1331,7 +1329,7 @@ void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node, DerivedFieldNode* derivedField; - if (!(derivedField = select_item->as())) + if (!(derivedField = nodeAs(select_item))) { // Internal dsql error: alias type expected by PASS1_expand_select_node ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << @@ -1358,7 +1356,7 @@ void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node, } } } - else if ((procNode = ExprNode::as(node))) + else if ((procNode = nodeAs(node))) { dsql_ctx* context = procNode->dsqlContext; @@ -1378,7 +1376,7 @@ void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node, } } } - else if ((relNode = ExprNode::as(node))) + else if ((relNode = nodeAs(node))) { dsql_ctx* context = relNode->dsqlContext; @@ -1398,7 +1396,7 @@ void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node, } } } - else if ((fieldNode = ExprNode::as(node))) + else if ((fieldNode = nodeAs(node))) { RecordSourceNode* recSource = NULL; ValueExprNode* value = fieldNode->internalDsqlPass(dsqlScratch, &recSource); @@ -1455,7 +1453,7 @@ static ValueListNode* pass1_group_by_list(DsqlCompilerScratch* dsqlScratch, Valu FieldNode* field; LiteralNode* literal; - if ((field = ExprNode::as(sub))) + if ((field = nodeAs(sub))) { // check for alias or field node if (selectList && field->dsqlQualifier.isEmpty() && field->dsqlName.hasData()) @@ -1469,7 +1467,7 @@ static ValueListNode* pass1_group_by_list(DsqlCompilerScratch* dsqlScratch, Valu if (!frnode) frnode = field->internalDsqlPass(dsqlScratch, NULL); } - else if ((literal = ExprNode::as(sub)) && (literal->litDesc.dsc_dtype == dtype_long)) + else if ((literal = nodeAs(sub)) && (literal->litDesc.dsc_dtype == dtype_long)) { const ULONG position = literal->getSlong(); @@ -1532,17 +1530,17 @@ ValueExprNode* PASS1_lookup_alias(DsqlCompilerScratch* dsqlScratch, const MetaNa FieldNode* fieldNode; DerivedFieldNode* derivedField; - if ((aliasNode = node->as())) + if ((aliasNode = nodeAs(node))) { if (aliasNode->name == name) matchingNode = node; } - else if ((fieldNode = node->as())) + else if ((fieldNode = nodeAs(node))) { if (fieldNode->dsqlField->fld_name == name.c_str()) matchingNode = node; } - else if ((derivedField = node->as())) + else if ((derivedField = nodeAs(node))) { if (derivedField->name == name) matchingNode = node; @@ -1559,11 +1557,11 @@ ValueExprNode* PASS1_lookup_alias(DsqlCompilerScratch* dsqlScratch, const MetaNa TEXT buffer1[256]; buffer1[0] = 0; - if (returnNode->is()) + if (nodeIs(returnNode)) strcat(buffer1, "an alias"); - else if (returnNode->is()) + else if (nodeIs(returnNode)) strcat(buffer1, "a field"); - else if (returnNode->is()) + else if (nodeIs(returnNode)) strcat(buffer1, "a derived field"); else strcat(buffer1, "an item"); @@ -1571,11 +1569,11 @@ ValueExprNode* PASS1_lookup_alias(DsqlCompilerScratch* dsqlScratch, const MetaNa TEXT buffer2[256]; buffer2[0] = 0; - if (matchingNode->is()) + if (nodeIs(matchingNode)) strcat(buffer2, "an alias"); - else if (matchingNode->is()) + else if (nodeIs(matchingNode)) strcat(buffer2, "a field"); - else if (matchingNode->is()) + else if (nodeIs(matchingNode)) strcat(buffer2, "a derived field"); else strcat(buffer2, "an item"); @@ -1617,7 +1615,7 @@ static ValueExprNode* pass1_make_derived_field(thread_db* tdbb, DsqlCompilerScra FieldNode* fieldNode; DerivedFieldNode* derivedField; - if ((aliasNode = ExprNode::as(select_item))) + if ((aliasNode = nodeAs(select_item))) { // Create a derived field and ignore alias node. DerivedFieldNode* newField = FB_NEW_POOL(pool) DerivedFieldNode(pool, @@ -1625,25 +1623,25 @@ static ValueExprNode* pass1_make_derived_field(thread_db* tdbb, DsqlCompilerScra newField->nodDesc = aliasNode->value->nodDesc; return newField; } - else if ((subQueryNode = ExprNode::as(select_item))) + else if ((subQueryNode = nodeAs(select_item))) { // Try to generate derived field from sub-select ValueExprNode* derived_field = pass1_make_derived_field(tdbb, dsqlScratch, subQueryNode->value1); - if ((derivedField = ExprNode::as(derived_field))) + if ((derivedField = nodeAs(derived_field))) { derivedField->value = select_item; return derived_field; } } - else if ((mapNode = ExprNode::as(select_item))) + else if ((mapNode = nodeAs(select_item))) { // Aggregate's have map on top. ValueExprNode* derived_field = pass1_make_derived_field(tdbb, dsqlScratch, mapNode->map->map_node); // If we had succesfully made a derived field node change it with orginal map. - if ((derivedField = ExprNode::as(derived_field))) + if ((derivedField = nodeAs(derived_field))) { derivedField->value = select_item; derivedField->scope = dsqlScratch->scopeLevel; @@ -1651,7 +1649,7 @@ static ValueExprNode* pass1_make_derived_field(thread_db* tdbb, DsqlCompilerScra return derived_field; } } - else if ((fieldNode = ExprNode::as(select_item))) + else if ((fieldNode = nodeAs(select_item))) { // Create a derived field and hook in. @@ -1660,7 +1658,7 @@ static ValueExprNode* pass1_make_derived_field(thread_db* tdbb, DsqlCompilerScra newField->nodDesc = fieldNode->nodDesc; return newField; } - else if ((derivedField = ExprNode::as(select_item))) + else if ((derivedField = nodeAs(select_item))) { // Create a derived field that points to a derived field. @@ -1729,7 +1727,7 @@ static RseNode* pass1_rse(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* in ValueListNode* order, RowsClause* rows, bool updateLock, USHORT flags) { string save_alias; - RseNode* rseNode = input->as(); + RseNode* rseNode = nodeAs(input); const bool isRecursive = rseNode && (rseNode->dsqlFlags & RecordSourceNode::DFLAG_RECURSIVE); AutoSetRestore autoScopeLevel(&dsqlScratch->scopeLevel, dsqlScratch->scopeLevel); @@ -1764,8 +1762,8 @@ static RseNode* pass1_rse_impl(DsqlCompilerScratch* dsqlScratch, RecordSourceNod thread_db* tdbb = JRD_get_thread_data(); MemoryPool& pool = *tdbb->getDefaultPool(); - SelectExprNode* selNode = input->as(); - UnionSourceNode* unionNode = input->as(); + SelectExprNode* selNode = nodeAs(input); + UnionSourceNode* unionNode = nodeAs(input); if (selNode) { @@ -1799,7 +1797,7 @@ static RseNode* pass1_rse_impl(DsqlCompilerScratch* dsqlScratch, RecordSourceNod return pass1_union(dsqlScratch, unionNode, order, rows, updateLock, flags); } - RseNode* inputRse = input->as(); + RseNode* inputRse = nodeAs(input); fb_assert(inputRse); // Save the original base of the context stack and process relations @@ -1819,7 +1817,7 @@ static RseNode* pass1_rse_impl(DsqlCompilerScratch* dsqlScratch, RecordSourceNod if (updateLock && (streamList->items.getCount() != 1 || - !(relNode = streamList->items[0]->as()) || + !(relNode = nodeAs(streamList->items[0])) || !(relation = relNode->dsqlContext->ctx_relation) || (relation->rel_flags & (REL_view | REL_external)))) { @@ -2308,7 +2306,7 @@ ValueListNode* PASS1_sort(DsqlCompilerScratch* dsqlScratch, ValueListNode* input for (FB_SIZE_T sortloop = 0; sortloop < input->items.getCount(); ++sortloop) { DEV_BLKCHK(input->items[sortloop], dsql_type_nod); - NestConst node1 = input->items[sortloop]->as(); + NestConst node1 = nodeAs(input->items[sortloop]); if (!node1) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << @@ -2320,7 +2318,7 @@ ValueListNode* PASS1_sort(DsqlCompilerScratch* dsqlScratch, ValueListNode* input // get node of value to be ordered by NestConst orderValue = node1->value; - NestConst collateNode = orderValue->as(); + NestConst collateNode = nodeAs(orderValue); if (collateNode) { @@ -2331,7 +2329,7 @@ ValueListNode* PASS1_sort(DsqlCompilerScratch* dsqlScratch, ValueListNode* input FieldNode* field; LiteralNode* literal; - if ((field = orderValue->as())) + if ((field = nodeAs(orderValue))) { ValueExprNode* aliasNode = NULL; @@ -2346,7 +2344,7 @@ ValueListNode* PASS1_sort(DsqlCompilerScratch* dsqlScratch, ValueListNode* input orderValue = aliasNode ? aliasNode : field->internalDsqlPass(dsqlScratch, NULL); } - else if ((literal = orderValue->as()) && literal->litDesc.dsc_dtype == dtype_long) + else if ((literal = nodeAs(orderValue)) && literal->litDesc.dsc_dtype == dtype_long) { const ULONG position = literal->getSlong(); @@ -2444,7 +2442,7 @@ static RseNode* pass1_union(DsqlCompilerScratch* dsqlScratch, UnionSourceNode* i dsqlScratch->scopeLevel--; if (updateLock) - (*uptr)->as()->flags &= ~RseNode::FLAG_WRITELOCK; + nodeAs(*uptr)->flags &= ~RseNode::FLAG_WRITELOCK; while (*(dsqlScratch->context) != base) dsqlScratch->unionContext.push(dsqlScratch->context->pop()); @@ -2457,14 +2455,14 @@ static RseNode* pass1_union(DsqlCompilerScratch* dsqlScratch, UnionSourceNode* i } // end scope block // generate the list of fields to select. - ValueListNode* items = unionSource->dsqlClauses->items[0]->as()->dsqlSelectList; + ValueListNode* items = nodeAs(unionSource->dsqlClauses->items[0])->dsqlSelectList; // loop through the list nodes, checking to be sure that they have the // same number of items for (FB_SIZE_T i = 1; i < unionSource->dsqlClauses->items.getCount(); ++i) { - const ValueListNode* nod1 = unionSource->dsqlClauses->items[i]->as()->dsqlSelectList; + const ValueListNode* nod1 = nodeAs(unionSource->dsqlClauses->items[i])->dsqlSelectList; if (items->items.getCount() != nod1->items.getCount()) { @@ -2495,7 +2493,7 @@ static RseNode* pass1_union(DsqlCompilerScratch* dsqlScratch, UnionSourceNode* i { for (FB_SIZE_T i = 0; i < unionSource->dsqlClauses->items.getCount(); ++i) { - ValueListNode* nod1 = unionSource->dsqlClauses->items[i]->as()->dsqlSelectList; + ValueListNode* nod1 = nodeAs(unionSource->dsqlClauses->items[i])->dsqlSelectList; MAKE_desc(dsqlScratch, &nod1->items[j]->nodDesc, nod1->items[j]); tmp_list->items[i] = nod1->items[j]; @@ -2520,7 +2518,7 @@ static RseNode* pass1_union(DsqlCompilerScratch* dsqlScratch, UnionSourceNode* i pass1_union_auto_cast(dsqlScratch, unionSource->dsqlClauses, desc, j); } - items = unionSource->dsqlClauses->items[0]->as()->dsqlSelectList; + items = nodeAs(unionSource->dsqlClauses->items[0])->dsqlSelectList; // Create mappings for union. @@ -2559,14 +2557,14 @@ static RseNode* pass1_union(DsqlCompilerScratch* dsqlScratch, UnionSourceNode* i ptr != end; ++ptr, ++uptr) { - OrderNode* order1 = (*ptr)->as(); + OrderNode* order1 = nodeAs(*ptr); const ValueExprNode* position = order1->value; - const CollateNode* collateNode = position->as(); + const CollateNode* collateNode = nodeAs(position); if (collateNode) position = collateNode->arg; - const LiteralNode* literal = position->as(); + const LiteralNode* literal = nodeAs(position); if (!literal || literal->litDesc.dsc_dtype != dtype_long) { @@ -2645,26 +2643,26 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in RseNode* rseNode; UnionSourceNode* unionNode; - if ((recSourceList = input->as())) + if ((recSourceList = nodeAs(input))) { NestConst* ptr = recSourceList->items.begin(); for (const NestConst* const end = recSourceList->items.end(); ptr != end; ++ptr) pass1_union_auto_cast(dsqlScratch, *ptr, desc, position); } - else if ((rseNode = input->as()) && !rseNode->dsqlExplicitJoin && + else if ((rseNode = nodeAs(input)) && !rseNode->dsqlExplicitJoin && !rseNode->dsqlContext) // not derived table { pass1_union_auto_cast(dsqlScratch, rseNode->dsqlStreams, desc, position); if (rseNode->dsqlStreams->items.getCount() == 1 && - (unionNode = rseNode->dsqlStreams->items[0]->as()) && + (unionNode = nodeAs(rseNode->dsqlStreams->items[0])) && unionNode->dsqlParentRse == rseNode) { // We're now in a UNION under a UNION so don't change the existing mappings. // Only replace the node where the map points to, because they could be changed. ValueListNode* sub_rse_items = - unionNode->dsqlClauses->items[0]->as()->dsqlSelectList; - dsql_map* map = rseNode->dsqlSelectList->items[position]->as()->map; + nodeAs(unionNode->dsqlClauses->items[0])->dsqlSelectList; + dsql_map* map = nodeAs(rseNode->dsqlSelectList->items[position])->map; map->map_node = sub_rse_items->items[position]; rseNode->dsqlSelectList->items[position]->nodDesc = desc; } @@ -2697,15 +2695,15 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in DerivedFieldNode* derivedField; // Pick a existing cast if available else make a new one. - if ((aliasNode = ExprNode::as(select_item)) && - aliasNode->value && (castNode = aliasNode->value->as())) + if ((aliasNode = nodeAs(select_item)) && + aliasNode->value && (castNode = nodeAs(aliasNode->value))) { } - else if ((derivedField = ExprNode::as(select_item)) && - (castNode = derivedField->value->as())) + else if ((derivedField = nodeAs(select_item)) && + (castNode = nodeAs(derivedField->value))) { } - else if ((castNode = ExprNode::as(select_item))) + else if ((castNode = nodeAs(select_item))) { } else @@ -2719,9 +2717,9 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in // We want to leave the ALIAS node on his place, because a UNION // uses the select_items from the first sub-rse to determine the // columnname. - if ((aliasNode = ExprNode::as(select_item))) + if ((aliasNode = nodeAs(select_item))) castNode->source = aliasNode->value; - else if ((derivedField = ExprNode::as(select_item))) + else if ((derivedField = nodeAs(select_item))) castNode->source = derivedField->value; else castNode->source = select_item; @@ -2731,7 +2729,7 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in const ValueExprNode* name_node = select_item; const DsqlMapNode* mapNode; - while ((mapNode = ExprNode::as(name_node))) + while ((mapNode = nodeAs(name_node))) { // Skip all the DsqlMapNodes. name_node = mapNode->map->map_node; @@ -2739,7 +2737,7 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in const FieldNode* fieldNode; - if ((fieldNode = ExprNode::as(name_node))) + if ((fieldNode = nodeAs(name_node))) { // Create new node for alias and copy fieldname. newAliasNode = FB_NEW_POOL(*tdbb->getDefaultPool()) DsqlAliasNode( @@ -2776,13 +2774,13 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in if (select_item->nodDesc.dsc_flags & DSC_nullable) castNode->nodDesc.dsc_flags |= DSC_nullable; - if ((aliasNode = ExprNode::as(select_item))) + if ((aliasNode = nodeAs(select_item))) { aliasNode->value = castNode; aliasNode->value->nodDesc = desc; select_item->nodDesc = desc; } - else if ((derivedField = ExprNode::as(select_item))) + else if ((derivedField = nodeAs(select_item))) { derivedField->value = castNode; derivedField->value->nodDesc = desc; @@ -2805,7 +2803,7 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in } } } - else if ((unionNode = input->as())) + else if ((unionNode = nodeAs(input))) { recSourceList = unionNode->dsqlClauses; @@ -2884,28 +2882,28 @@ static void remap_streams_to_parent_context(ExprNode* input, dsql_ctx* parent_co RseNode* rseNode; UnionSourceNode* unionNode; - if ((listNode = input->as())) + if ((listNode = nodeAs(input))) { NestConst* ptr = listNode->items.begin(); for (const NestConst* const end = listNode->items.end(); ptr != end; ++ptr) remap_streams_to_parent_context(*ptr, parent_context); } - else if ((procNode = input->as())) + else if ((procNode = nodeAs(input))) { DEV_BLKCHK(procNode->dsqlContext, dsql_type_ctx); procNode->dsqlContext->ctx_parent = parent_context; } - else if ((relNode = input->as())) + else if ((relNode = nodeAs(input))) { DEV_BLKCHK(relNode->dsqlContext, dsql_type_ctx); relNode->dsqlContext->ctx_parent = parent_context; } - else if ((rseNode = input->as())) + else if ((rseNode = nodeAs(input))) remap_streams_to_parent_context(rseNode->dsqlStreams, parent_context); - else if ((unionNode = input->as())) + else if ((unionNode = nodeAs(input))) remap_streams_to_parent_context(unionNode->dsqlClauses, parent_context); else - fb_assert(input->as()); + fb_assert(nodeAs(input)); } diff --git a/src/dsql/sqlda_pub.h b/src/dsql/sqlda_pub.h index 1f6ecf4243..e2505e5ea9 100644 --- a/src/dsql/sqlda_pub.h +++ b/src/dsql/sqlda_pub.h @@ -78,6 +78,8 @@ typedef struct #define SQL_TYPE_TIME 560 #define SQL_TYPE_DATE 570 #define SQL_INT64 580 +#define SQL_DEC16 32760 +#define SQL_DEC34 32762 #define SQL_BOOLEAN 32764 #define SQL_NULL 32766 diff --git a/src/gpre/c_cxx.cpp b/src/gpre/c_cxx.cpp index 8c667cf645..292492ebec 100644 --- a/src/gpre/c_cxx.cpp +++ b/src/gpre/c_cxx.cpp @@ -1901,7 +1901,11 @@ static void gen_emodify( const act* action, int column) align(column); gen_name(s1, source, true); gen_name(s2, reference, true); - if (field->fld_dtype > dtype_cstring || (field->fld_sub_type == 1 && field->fld_length == 1)) + if (field->fld_dtype == dtype_varying && field->fld_sub_type == dsc_text_type_fixed) + { + fprintf(gpreGlob.out_file, "memcpy (&%s, &%s, %d);", s2, s1, field->fld_length + sizeof(USHORT)); + } + else if (field->fld_dtype > dtype_cstring || (field->fld_sub_type == dsc_text_type_fixed && field->fld_length == 1)) { fprintf(gpreGlob.out_file, "%s = %s;", s2, s1); } @@ -3717,6 +3721,10 @@ static void make_port(const gpre_port* port, int column) dtype = DCL_LONG; break; + case dtype_varying: + fprintf(gpreGlob.out_file, " struct { ISC_USHORT length; ISC_UCHAR data[%d]; } isc_%d;\t/* %s */", field->fld_length, reference->ref_ident, name); + continue; + case dtype_cstring: case dtype_text: dtype = "char "; diff --git a/src/gpre/cmp.cpp b/src/gpre/cmp.cpp index e10d2693aa..77953e4100 100644 --- a/src/gpre/cmp.cpp +++ b/src/gpre/cmp.cpp @@ -788,7 +788,7 @@ static void cmp_field( gpre_req* request, const gpre_fld* field, break; case dtype_varying: - if (!(field->fld_flags & FLD_charset) && field->fld_ttype) + if (!(field->fld_flags & FLD_charset) && field->fld_ttype >= dsc_text_type_metadata) { request->add_byte(blr_varying); request->add_word(field->fld_length); @@ -1731,17 +1731,20 @@ static gpre_port* make_port( gpre_req* request, ref* reference) CPR_bugcheck("missing prototype field for value"); if (temp->ref_value && (temp->ref_flags & REF_array_elem)) field = field->fld_array; - if ((field->fld_length & 7) == 0) + FLD_LENGTH len = field->fld_length; + if (field->fld_dtype == dtype_varying) + len += sizeof(USHORT); + if ((len & 7) == 0) { temp->ref_next = alignments[2]; alignments[2] = temp; } - else if ((field->fld_length & 3) == 0) + else if ((len & 3) == 0) { temp->ref_next = alignments[1]; alignments[1] = temp; } - else if ((field->fld_length & 1) == 0) + else if ((len & 1) == 0) { temp->ref_next = alignments[0]; alignments[0] = temp; @@ -1774,7 +1777,10 @@ static gpre_port* make_port( gpre_req* request, ref* reference) #ifdef GPRE_FORTRAN reference->ref_offset = port->por_length; #endif - port->por_length += field->fld_length; + FLD_LENGTH len = field->fld_length; + if (field->fld_dtype == dtype_varying) + len += sizeof(USHORT); + port->por_length += len; } return port; diff --git a/src/gpre/movg.cpp b/src/gpre/movg.cpp index 1b2c20cbda..1abe62e9e5 100644 --- a/src/gpre/movg.cpp +++ b/src/gpre/movg.cpp @@ -49,7 +49,7 @@ static void post_error(const Firebird::Arg::StatusVector&); void MOVG_move(const dsc* from, dsc* to) { - CVT_move(from, to, post_error); + CVT_move(from, to, 0, post_error); } diff --git a/src/gpre/std/gpre_meta.epp b/src/gpre/std/gpre_meta.epp index b345894492..bfe9e0092f 100644 --- a/src/gpre/std/gpre_meta.epp +++ b/src/gpre/std/gpre_meta.epp @@ -878,85 +878,94 @@ USHORT MET_get_dtype(USHORT blr_dtype, USHORT sub_type, USHORT char_length, USHO { USHORT dtype; - USHORT l = *length; + USHORT corr_length = *length; switch (blr_dtype) { case blr_varying: case blr_text: - if (char_length != 0 && sub_type != dsc_text_type_none) - l = char_length * 4; + if (char_length != 0 && sub_type >= dsc_text_type_metadata) // subtypes below are single byte characters + corr_length = char_length * 4; dtype = dtype_text; - if (gpreGlob.sw_cstring && sub_type != dsc_text_type_fixed) + if (sub_type == dsc_text_type_fixed) { - ++l; + if (blr_dtype == blr_varying) + { + dtype = dtype_varying; + // Round up size of field to get right alignment and workaround message length mismatch error + corr_length = (corr_length + 1) & ~1U; + } + } + else if (gpreGlob.sw_cstring) + { + ++corr_length; dtype = dtype_cstring; } break; case blr_cstring: dtype = dtype_cstring; - if (char_length != 0 && sub_type != dsc_text_type_none) - l = char_length * 4; - ++l; + if (char_length != 0 && sub_type >= dsc_text_type_metadata) // subtypes below are single byte characters + corr_length = char_length * 4; + ++corr_length; break; case blr_short: dtype = dtype_short; - l = sizeof(SSHORT); + corr_length = sizeof(SSHORT); break; case blr_long: dtype = dtype_long; - l = sizeof(SLONG); + corr_length = sizeof(SLONG); break; case blr_quad: dtype = dtype_quad; - l = sizeof(ISC_QUAD); + corr_length = sizeof(ISC_QUAD); break; case blr_float: dtype = dtype_real; - l = sizeof(float); + corr_length = sizeof(float); break; case blr_double: dtype = dtype_double; - l = sizeof(double); + corr_length = sizeof(double); break; case blr_blob: dtype = dtype_blob; - l = sizeof(ISC_QUAD); + corr_length = sizeof(ISC_QUAD); break; // Begin sql date/time/timestamp case blr_sql_date: dtype = dtype_sql_date; - l = sizeof(ISC_DATE); + corr_length = sizeof(ISC_DATE); break; case blr_sql_time: dtype = dtype_sql_time; - l = sizeof(ISC_TIME); + corr_length = sizeof(ISC_TIME); break; case blr_timestamp: dtype = dtype_timestamp; - l = sizeof(ISC_TIMESTAMP); + corr_length = sizeof(ISC_TIMESTAMP); break; // End sql date/time/timestamp case blr_int64: dtype = dtype_int64; - l = sizeof(ISC_INT64); + corr_length = sizeof(ISC_INT64); break; case blr_bool: dtype = dtype_boolean; - l = sizeof(UCHAR); + corr_length = sizeof(UCHAR); break; default: @@ -964,7 +973,7 @@ USHORT MET_get_dtype(USHORT blr_dtype, USHORT sub_type, USHORT char_length, USHO return 0; // silence non initialized warning } - *length = l; + *length = corr_length; return dtype; } diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index 9760a94b4b..5739224c5b 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -29,6 +29,8 @@ typedef ISC_DATE; typedef ISC_QUAD; typedef ISC_TIME; +typedef FB_DEC16; +typedef FB_DEC34; // Versioned interface - base for all FB interfaces interface Versioned @@ -983,8 +985,10 @@ interface Util : Versioned XpbBuilder getXpbBuilder(Status status, uint kind, const uchar* buf, uint len); uint setOffsets(Status status, MessageMetadata metadata, OffsetsCallback callback); -version: +version: // 3.0 => 4.0 EventBlock createEventBlock(Status status, const string* events); + DecFloat16 getDecFloat16(Status status); + DecFloat34 getDecFloat34(Status status); } interface OffsetsCallback : Versioned @@ -1366,3 +1370,23 @@ interface UdrPlugin : Versioned void registerProcedure(Status status, const string name, UdrProcedureFactory factory); void registerTrigger(Status status, const string name, UdrTriggerFactory factory); } + +interface DecFloat16 : Versioned +{ + const uint BCD_SIZE = 16; + const uint STRING_SIZE = 24; // includes terminating \0 + void toBcd(const FB_DEC16* from, int* sign, uchar* bcd, int* exp); + void toString(Status status, const FB_DEC16* from, uint bufferLength, string buffer); + void fromBcd(int sign, const uchar* bcd, int exp, FB_DEC16* to); + void fromString(Status status, const string from, FB_DEC16* to); +} + +interface DecFloat34 : Versioned +{ + const uint BCD_SIZE = 34; + const uint STRING_SIZE = 43; // includes terminating \0 + void toBcd(const FB_DEC34* from, int* sign, uchar* bcd, int* exp); + void toString(Status status, const FB_DEC34* from, uint bufferLength, string buffer); + void fromBcd(int sign, const uchar* bcd, int exp, FB_DEC34* to); + void fromString(Status status, const string from, FB_DEC34* to); +} diff --git a/src/include/firebird/IdlFbInterfaces.h b/src/include/firebird/IdlFbInterfaces.h index 4f9fa90c7b..423c01322f 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -111,6 +111,8 @@ namespace Firebird class IUdrProcedureFactory; class IUdrTriggerFactory; class IUdrPlugin; + class IDecFloat16; + class IDecFloat34; // Interfaces declarations @@ -3695,6 +3697,8 @@ namespace Firebird IXpbBuilder* (CLOOP_CARG *getXpbBuilder)(IUtil* self, IStatus* status, unsigned kind, const unsigned char* buf, unsigned len) throw(); unsigned (CLOOP_CARG *setOffsets)(IUtil* self, IStatus* status, IMessageMetadata* metadata, IOffsetsCallback* callback) throw(); IEventBlock* (CLOOP_CARG *createEventBlock)(IUtil* self, IStatus* status, const char** events) throw(); + IDecFloat16* (CLOOP_CARG *getDecFloat16)(IUtil* self, IStatus* status) throw(); + IDecFloat34* (CLOOP_CARG *getDecFloat34)(IUtil* self, IStatus* status) throw(); }; protected: @@ -3809,6 +3813,34 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template IDecFloat16* getDecFloat16(StatusType* status) + { + if (cloopVTable->version < 3) + { + StatusType::setVersionError(status, "IUtil", cloopVTable->version, 3); + StatusType::checkException(status); + return 0; + } + StatusType::clearException(status); + IDecFloat16* ret = static_cast(this->cloopVTable)->getDecFloat16(this, status); + StatusType::checkException(status); + return ret; + } + + template IDecFloat34* getDecFloat34(StatusType* status) + { + if (cloopVTable->version < 3) + { + StatusType::setVersionError(status, "IUtil", cloopVTable->version, 3); + StatusType::checkException(status); + return 0; + } + StatusType::clearException(status); + IDecFloat34* ret = static_cast(this->cloopVTable)->getDecFloat34(this, status); + StatusType::checkException(status); + return ret; + } }; class IOffsetsCallback : public IVersioned @@ -5270,6 +5302,110 @@ namespace Firebird } }; + class IDecFloat16 : public IVersioned + { + public: + struct VTable : public IVersioned::VTable + { + void (CLOOP_CARG *toBcd)(IDecFloat16* self, const FB_DEC16* from, int* sign, unsigned char* bcd, int* exp) throw(); + void (CLOOP_CARG *toString)(IDecFloat16* self, IStatus* status, const FB_DEC16* from, unsigned bufferLength, char* buffer) throw(); + void (CLOOP_CARG *fromBcd)(IDecFloat16* self, int sign, const unsigned char* bcd, int exp, FB_DEC16* to) throw(); + void (CLOOP_CARG *fromString)(IDecFloat16* self, IStatus* status, const char* from, FB_DEC16* to) throw(); + }; + + protected: + IDecFloat16(DoNotInherit) + : IVersioned(DoNotInherit()) + { + } + + ~IDecFloat16() + { + } + + public: + static const unsigned VERSION = 2; + + static const unsigned BCD_SIZE = 16; + static const unsigned STRING_SIZE = 24; + + void toBcd(const FB_DEC16* from, int* sign, unsigned char* bcd, int* exp) + { + static_cast(this->cloopVTable)->toBcd(this, from, sign, bcd, exp); + } + + template void toString(StatusType* status, const FB_DEC16* from, unsigned bufferLength, char* buffer) + { + StatusType::clearException(status); + static_cast(this->cloopVTable)->toString(this, status, from, bufferLength, buffer); + StatusType::checkException(status); + } + + void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC16* to) + { + static_cast(this->cloopVTable)->fromBcd(this, sign, bcd, exp, to); + } + + template void fromString(StatusType* status, const char* from, FB_DEC16* to) + { + StatusType::clearException(status); + static_cast(this->cloopVTable)->fromString(this, status, from, to); + StatusType::checkException(status); + } + }; + + class IDecFloat34 : public IVersioned + { + public: + struct VTable : public IVersioned::VTable + { + void (CLOOP_CARG *toBcd)(IDecFloat34* self, const FB_DEC34* from, int* sign, unsigned char* bcd, int* exp) throw(); + void (CLOOP_CARG *toString)(IDecFloat34* self, IStatus* status, const FB_DEC34* from, unsigned bufferLength, char* buffer) throw(); + void (CLOOP_CARG *fromBcd)(IDecFloat34* self, int sign, const unsigned char* bcd, int exp, FB_DEC34* to) throw(); + void (CLOOP_CARG *fromString)(IDecFloat34* self, IStatus* status, const char* from, FB_DEC34* to) throw(); + }; + + protected: + IDecFloat34(DoNotInherit) + : IVersioned(DoNotInherit()) + { + } + + ~IDecFloat34() + { + } + + public: + static const unsigned VERSION = 2; + + static const unsigned BCD_SIZE = 34; + static const unsigned STRING_SIZE = 43; + + void toBcd(const FB_DEC34* from, int* sign, unsigned char* bcd, int* exp) + { + static_cast(this->cloopVTable)->toBcd(this, from, sign, bcd, exp); + } + + template void toString(StatusType* status, const FB_DEC34* from, unsigned bufferLength, char* buffer) + { + StatusType::clearException(status); + static_cast(this->cloopVTable)->toString(this, status, from, bufferLength, buffer); + StatusType::checkException(status); + } + + void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC34* to) + { + static_cast(this->cloopVTable)->fromBcd(this, sign, bcd, exp, to); + } + + template void fromString(StatusType* status, const char* from, FB_DEC34* to) + { + StatusType::clearException(status); + static_cast(this->cloopVTable)->fromString(this, status, from, to); + StatusType::checkException(status); + } + }; + // Interfaces implementations template @@ -12941,6 +13077,8 @@ namespace Firebird this->getXpbBuilder = &Name::cloopgetXpbBuilderDispatcher; this->setOffsets = &Name::cloopsetOffsetsDispatcher; this->createEventBlock = &Name::cloopcreateEventBlockDispatcher; + this->getDecFloat16 = &Name::cloopgetDecFloat16Dispatcher; + this->getDecFloat34 = &Name::cloopgetDecFloat34Dispatcher; } } vTable; @@ -13138,6 +13276,36 @@ namespace Firebird return static_cast(0); } } + + static IDecFloat16* CLOOP_CARG cloopgetDecFloat16Dispatcher(IUtil* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::getDecFloat16(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } + + static IDecFloat34* CLOOP_CARG cloopgetDecFloat34Dispatcher(IUtil* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::getDecFloat34(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } }; template > > @@ -13167,6 +13335,8 @@ namespace Firebird virtual IXpbBuilder* getXpbBuilder(StatusType* status, unsigned kind, const unsigned char* buf, unsigned len) = 0; virtual unsigned setOffsets(StatusType* status, IMessageMetadata* metadata, IOffsetsCallback* callback) = 0; virtual IEventBlock* createEventBlock(StatusType* status, const char** events) = 0; + virtual IDecFloat16* getDecFloat16(StatusType* status) = 0; + virtual IDecFloat34* getDecFloat34(StatusType* status) = 0; }; template @@ -16357,6 +16527,196 @@ namespace Firebird virtual void registerProcedure(StatusType* status, const char* name, IUdrProcedureFactory* factory) = 0; virtual void registerTrigger(StatusType* status, const char* name, IUdrTriggerFactory* factory) = 0; }; + + template + class IDecFloat16BaseImpl : public Base + { + public: + typedef IDecFloat16 Declaration; + + IDecFloat16BaseImpl(DoNotInherit = DoNotInherit()) + { + static struct VTableImpl : Base::VTable + { + VTableImpl() + { + this->version = Base::VERSION; + this->toBcd = &Name::clooptoBcdDispatcher; + this->toString = &Name::clooptoStringDispatcher; + this->fromBcd = &Name::cloopfromBcdDispatcher; + this->fromString = &Name::cloopfromStringDispatcher; + } + } vTable; + + this->cloopVTable = &vTable; + } + + static void CLOOP_CARG clooptoBcdDispatcher(IDecFloat16* self, const FB_DEC16* from, int* sign, unsigned char* bcd, int* exp) throw() + { + try + { + static_cast(self)->Name::toBcd(from, sign, bcd, exp); + } + catch (...) + { + StatusType::catchException(0); + } + } + + static void CLOOP_CARG clooptoStringDispatcher(IDecFloat16* self, IStatus* status, const FB_DEC16* from, unsigned bufferLength, char* buffer) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::toString(&status2, from, bufferLength, buffer); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopfromBcdDispatcher(IDecFloat16* self, int sign, const unsigned char* bcd, int exp, FB_DEC16* to) throw() + { + try + { + static_cast(self)->Name::fromBcd(sign, bcd, exp, to); + } + catch (...) + { + StatusType::catchException(0); + } + } + + static void CLOOP_CARG cloopfromStringDispatcher(IDecFloat16* self, IStatus* status, const char* from, FB_DEC16* to) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::fromString(&status2, from, to); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + }; + + template > > + class IDecFloat16Impl : public IDecFloat16BaseImpl + { + protected: + IDecFloat16Impl(DoNotInherit = DoNotInherit()) + { + } + + public: + virtual ~IDecFloat16Impl() + { + } + + virtual void toBcd(const FB_DEC16* from, int* sign, unsigned char* bcd, int* exp) = 0; + virtual void toString(StatusType* status, const FB_DEC16* from, unsigned bufferLength, char* buffer) = 0; + virtual void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC16* to) = 0; + virtual void fromString(StatusType* status, const char* from, FB_DEC16* to) = 0; + }; + + template + class IDecFloat34BaseImpl : public Base + { + public: + typedef IDecFloat34 Declaration; + + IDecFloat34BaseImpl(DoNotInherit = DoNotInherit()) + { + static struct VTableImpl : Base::VTable + { + VTableImpl() + { + this->version = Base::VERSION; + this->toBcd = &Name::clooptoBcdDispatcher; + this->toString = &Name::clooptoStringDispatcher; + this->fromBcd = &Name::cloopfromBcdDispatcher; + this->fromString = &Name::cloopfromStringDispatcher; + } + } vTable; + + this->cloopVTable = &vTable; + } + + static void CLOOP_CARG clooptoBcdDispatcher(IDecFloat34* self, const FB_DEC34* from, int* sign, unsigned char* bcd, int* exp) throw() + { + try + { + static_cast(self)->Name::toBcd(from, sign, bcd, exp); + } + catch (...) + { + StatusType::catchException(0); + } + } + + static void CLOOP_CARG clooptoStringDispatcher(IDecFloat34* self, IStatus* status, const FB_DEC34* from, unsigned bufferLength, char* buffer) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::toString(&status2, from, bufferLength, buffer); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopfromBcdDispatcher(IDecFloat34* self, int sign, const unsigned char* bcd, int exp, FB_DEC34* to) throw() + { + try + { + static_cast(self)->Name::fromBcd(sign, bcd, exp, to); + } + catch (...) + { + StatusType::catchException(0); + } + } + + static void CLOOP_CARG cloopfromStringDispatcher(IDecFloat34* self, IStatus* status, const char* from, FB_DEC34* to) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::fromString(&status2, from, to); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + }; + + template > > + class IDecFloat34Impl : public IDecFloat34BaseImpl + { + protected: + IDecFloat34Impl(DoNotInherit = DoNotInherit()) + { + } + + public: + virtual ~IDecFloat34Impl() + { + } + + virtual void toBcd(const FB_DEC34* from, int* sign, unsigned char* bcd, int* exp) = 0; + virtual void toString(StatusType* status, const FB_DEC34* from, unsigned bufferLength, char* buffer) = 0; + virtual void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC34* to) = 0; + virtual void fromString(StatusType* status, const char* from, FB_DEC34* to) = 0; + }; }; diff --git a/src/include/firebird/Message.h b/src/include/firebird/Message.h index 7d529d7ce9..fcb8a56916 100644 --- a/src/include/firebird/Message.h +++ b/src/include/firebird/Message.h @@ -133,6 +133,14 @@ builder->setType(status, index, SQL_DOUBLE); \ builder->setLength(status, index, sizeof(double)); +#define FB__META_FB_DECFLOAT16 \ + builder->setType(status, index, SQL_DEC16); \ + builder->setLength(status, index, sizeof(FB_DEC16)); + +#define FB__META_FB_DECFLOAT34 \ + builder->setType(status, index, SQL_DEC34); \ + builder->setLength(status, index, sizeof(FB_DEC34)); + #define FB__META_FB_BLOB \ builder->setType(status, index, SQL_BLOB); \ builder->setLength(status, index, sizeof(ISC_QUAD)); @@ -185,6 +193,8 @@ #define FB__TYPE_FB_BIGINT ISC_INT64 #define FB__TYPE_FB_FLOAT float #define FB__TYPE_FB_DOUBLE double +#define FB__TYPE_FB_DECFLOAT16 FB_DEC16 +#define FB__TYPE_FB_DECFLOAT34 FB_DEC34 #define FB__TYPE_FB_BLOB ISC_QUAD #define FB__TYPE_FB_BOOLEAN ISC_UCHAR #define FB__TYPE_FB_DATE ::Firebird::FbDate diff --git a/src/include/firebird/UdrCppEngine.h b/src/include/firebird/UdrCppEngine.h index ce949bdcf0..26ef5a0e90 100644 --- a/src/include/firebird/UdrCppEngine.h +++ b/src/include/firebird/UdrCppEngine.h @@ -330,13 +330,13 @@ public: { CheckStatusWrapper statusWrapper(status); - if (!run(&statusWrapper, plugin, &IUdrPlugin::registerFunction, regFunctions)) + if (!run(&statusWrapper, plugin, &IUdrPlugin::registerFunction, regFunctions)) return; - if (!run(&statusWrapper, plugin, &IUdrPlugin::registerProcedure, regProcedures)) + if (!run(&statusWrapper, plugin, &IUdrPlugin::registerProcedure, regProcedures)) return; - if (!run(&statusWrapper, plugin, &IUdrPlugin::registerTrigger, regTriggers)) + if (!run(&statusWrapper, plugin, &IUdrPlugin::registerTrigger, regTriggers)) return; } diff --git a/src/include/gen/autoconfig_msvc.h b/src/include/gen/autoconfig_msvc.h index 81ef61a6b7..f750cf18b4 100644 --- a/src/include/gen/autoconfig_msvc.h +++ b/src/include/gen/autoconfig_msvc.h @@ -207,6 +207,11 @@ #define isnan _isnan #endif +#if !defined(HAS_NOEXCEPT) +#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 +#define HAS_NOEXCEPT +#endif +#endif /* Types */ #undef HAVE_SOCKLEN_T diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index 9b314540e1..6d1069a761 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -839,6 +839,12 @@ static const struct { {"overriding_system_invalid", 335545135}, {"overriding_user_invalid", 335545136}, {"overriding_system_missing", 335545137}, + {"decprecision_err", 335545138}, + {"decfloat_divide_by_zero", 335545139}, + {"decfloat_inexact_result", 335545140}, + {"decfloat_invalid_operation", 335545141}, + {"decfloat_overflow", 335545142}, + {"decfloat_underflow", 335545143}, {"gfix_db_name", 335740929}, {"gfix_invalid_sw", 335740930}, {"gfix_incmp_sw", 335740932}, diff --git a/src/include/gen/iberror.h b/src/include/gen/iberror.h index 36794b0a8d..142dd0db2a 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -873,6 +873,12 @@ const ISC_STATUS isc_overriding_without_identity = 335545134L; const ISC_STATUS isc_overriding_system_invalid = 335545135L; const ISC_STATUS isc_overriding_user_invalid = 335545136L; const ISC_STATUS isc_overriding_system_missing = 335545137L; +const ISC_STATUS isc_decprecision_err = 335545138L; +const ISC_STATUS isc_decfloat_divide_by_zero = 335545139L; +const ISC_STATUS isc_decfloat_inexact_result = 335545140L; +const ISC_STATUS isc_decfloat_invalid_operation = 335545141L; +const ISC_STATUS isc_decfloat_overflow = 335545142L; +const ISC_STATUS isc_decfloat_underflow = 335545143L; const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L; @@ -1347,7 +1353,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L; const ISC_STATUS isc_trace_switch_param_miss = 337182758L; const ISC_STATUS isc_trace_param_act_notcompat = 337182759L; const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L; -const ISC_STATUS isc_err_max = 1291; +const ISC_STATUS isc_err_max = 1297; #else /* c definitions */ @@ -2190,6 +2196,12 @@ const ISC_STATUS isc_err_max = 1291; #define isc_overriding_system_invalid 335545135L #define isc_overriding_user_invalid 335545136L #define isc_overriding_system_missing 335545137L +#define isc_decprecision_err 335545138L +#define isc_decfloat_divide_by_zero 335545139L +#define isc_decfloat_inexact_result 335545140L +#define isc_decfloat_invalid_operation 335545141L +#define isc_decfloat_overflow 335545142L +#define isc_decfloat_underflow 335545143L #define isc_gfix_db_name 335740929L #define isc_gfix_invalid_sw 335740930L #define isc_gfix_incmp_sw 335740932L @@ -2664,7 +2676,7 @@ const ISC_STATUS isc_err_max = 1291; #define isc_trace_switch_param_miss 337182758L #define isc_trace_param_act_notcompat 337182759L #define isc_trace_mandatory_switch_miss 337182760L -#define isc_err_max 1291 +#define isc_err_max 1297 #endif diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index 6da69e955b..6fe2b426d3 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -474,7 +474,7 @@ static const struct { {335544770, "Array bounds exceeded. The code attempted to access an array element that is out of bounds."}, /* exception_array_bounds_exceeded */ {335544771, "Float denormal operand. One of the floating-point operands is too small to represent a standard float value."}, /* exception_float_denormal_operand */ {335544772, "Floating-point divide by zero. The code attempted to divide a floating-point value by zero."}, /* exception_float_divide_by_zero */ - {335544773, "Floating-point inexact result. The result of a floating-point operation cannot be represented as a deciaml fraction."}, /* exception_float_inexact_result */ + {335544773, "Floating-point inexact result. The result of a floating-point operation cannot be represented as a decimal fraction."}, /* exception_float_inexact_result */ {335544774, "Floating-point invalid operand. An indeterminant error occurred during a floating-point operation."}, /* exception_float_invalid_operand */ {335544775, "Floating-point overflow. The exponent of a floating-point operation is greater than the magnitude allowed."}, /* exception_float_overflow */ {335544776, "Floating-point stack check. The stack overflowed or underflowed as the result of a floating-point operation."}, /* exception_float_stack_check */ @@ -842,6 +842,12 @@ Data source : @4"}, /* eds_statement */ {335545135, "OVERRIDING SYSTEM VALUE can be used only for identity column defined as 'GENERATED ALWAYS' in INSERT for table/view @1"}, /* overriding_system_invalid */ {335545136, "OVERRIDING USER VALUE can be used only for identity column defined as 'GENERATED BY DEFAULT' in INSERT for table/view @1"}, /* overriding_user_invalid */ {335545137, "OVERRIDING SYSTEM VALUE should be used to override the value of an identity column defined as 'GENERATED ALWAYS' in table/view @1"}, /* overriding_system_missing */ + {335545138, "DecFloat precision must be 16 or 34"}, /* decprecision_err */ + {335545139, "Decimal float divide by zero. The code attempted to divide a DECFLOAT value by zero."}, /* decfloat_divide_by_zero */ + {335545140, "Decimal float inexact result. The result of an operation cannot be represented as a decimal fraction."}, /* decfloat_inexact_result */ + {335545141, "Decimal float invalid operation. An indeterminant error occurred during an operation."}, /* decfloat_invalid_operation */ + {335545142, "Decimal float overflow. The exponent of a result is greater than the magnitude allowed."}, /* decfloat_overflow */ + {335545143, "Decimal float underflow. The exponent of a result is less than the magnitude allowed."}, /* decfloat_underflow */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ diff --git a/src/include/gen/sql_code.h b/src/include/gen/sql_code.h index 092c9bbd6d..fd926c2db2 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -838,6 +838,12 @@ static const struct { {335545135, -902}, /* 815 overriding_system_invalid */ {335545136, -902}, /* 816 overriding_user_invalid */ {335545137, -902}, /* 817 overriding_system_missing */ + {335545138, -842}, /* 818 decprecision_err */ + {335545139, -901}, /* 819 decfloat_divide_by_zero */ + {335545140, -901}, /* 820 decfloat_inexact_result */ + {335545141, -901}, /* 821 decfloat_invalid_operation */ + {335545142, -901}, /* 822 decfloat_overflow */ + {335545143, -901}, /* 823 decfloat_underflow */ {335740929, -901}, /* 1 gfix_db_name */ {335740930, -901}, /* 2 gfix_invalid_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */ diff --git a/src/include/gen/sql_state.h b/src/include/gen/sql_state.h index 06be5f599a..17bd675509 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -838,6 +838,12 @@ static const struct { {335545135, "42000"}, // 815 overriding_system_invalid {335545136, "42000"}, // 816 overriding_user_invalid {335545137, "42000"}, // 817 overriding_system_missing + {335545138, "HY104"}, // 818 decprecision_err + {335545139, "22012"}, // 819 decfloat_divide_by_zero + {335545140, "22000"}, // 820 decfloat_inexact_result + {335545141, "22000"}, // 821 decfloat_invalid_operation + {335545142, "22003"}, // 822 decfloat_overflow + {335545143, "22003"}, // 823 decfloat_underflow {335740929, "00000"}, // 1 gfix_db_name {335740930, "00000"}, // 2 gfix_invalid_sw {335740932, "00000"}, // 4 gfix_incmp_sw diff --git a/src/include/types_pub.h b/src/include/types_pub.h index 89c4ca6472..a3adda32e6 100644 --- a/src/include/types_pub.h +++ b/src/include/types_pub.h @@ -170,4 +170,15 @@ typedef struct GDS_QUAD_t ISC_QUAD; typedef int (*FB_SHUTDOWN_CALLBACK)(const int reason, const int mask, void* arg); +struct FB_DEC16_t { + ISC_UINT64 fb_data[1]; +}; + +struct FB_DEC34_t { + ISC_UINT64 fb_data[2]; +}; + +typedef struct FB_DEC16_t FB_DEC16; +typedef struct FB_DEC34_t FB_DEC34; + #endif /* INCLUDE_TYPES_PUB_H */ diff --git a/src/intl/lc_ascii.cpp b/src/intl/lc_ascii.cpp index 89667d9618..22cc9b9d9d 100644 --- a/src/intl/lc_ascii.cpp +++ b/src/intl/lc_ascii.cpp @@ -64,8 +64,7 @@ static void famasc_destroy(texttype* obj) if (impl) { - if (impl->cs.charset_fn_destroy) - impl->cs.charset_fn_destroy(&impl->cs); + Firebird::IntlUtil::finiCharset(&impl->cs); delete impl->charSet; delete impl; diff --git a/src/intl/lc_icu.cpp b/src/intl/lc_icu.cpp index cf547e5f69..a2d748b732 100644 --- a/src/intl/lc_icu.cpp +++ b/src/intl/lc_icu.cpp @@ -57,8 +57,7 @@ static bool texttype_default_init(texttype* tt, // test if that ICU charset exist if (CSICU_charset_init(&cs, charSetName)) { - if (cs.charset_fn_destroy) - cs.charset_fn_destroy(&cs); + IntlUtil::finiCharset(&cs); } else return false; diff --git a/src/intl/ld.cpp b/src/intl/ld.cpp index 202d70ecec..cf2e90fbcd 100644 --- a/src/intl/ld.cpp +++ b/src/intl/ld.cpp @@ -539,8 +539,7 @@ INTL_BOOL FB_DLL_EXPORT LD_lookup_texttype(texttype* tt, const ASCII* texttype_n INTL_BOOL ret = collations[i].ptr(tt, &cs, texttype_name, charset_name, attributes, specific_attributes, specific_attributes_length, config_info); - if (cs.charset_fn_destroy) - cs.charset_fn_destroy(&cs); + IntlUtil::finiCharset(&cs); return ret; } diff --git a/src/isql/isql.epp b/src/isql/isql.epp index fb08616d68..0dc1f6bfaa 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -309,6 +309,16 @@ static inline int fb_isdigit(const char c) } +IsqlGlobals::IsqlGlobals() +{ + Firebird::AutoPtr > + status_vector(fbMaster->getStatus()); + Firebird::CheckStatusWrapper statusWrapper(status_vector); + + df16 = Firebird::UtilInterfacePtr()->getDecFloat16(&statusWrapper); + df34 = Firebird::UtilInterfacePtr()->getDecFloat34(&statusWrapper); +} + // I s q l G l o b a l s : : p r i n t f // Output to the Out stream. void IsqlGlobals::printf(const char* buffer, ...) @@ -1825,11 +1835,14 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int case SMALLINT: case INTEGER: case BIGINT: + case DOUBLE_PRECISION: // Handle Integral subtypes NUMERIC and DECIMAL // We are ODS >= 10 and could be any Dialect // We are Dialect >=3 since FIELD_PRECISION is non-NULL - if (isqlGlob.major_ods >= ODS_VERSION10 && fieldPrecision != 0 && + if (isqlGlob.major_ods >= ODS_VERSION10 && + fieldPrecision != 0 && + fieldType != DOUBLE_PRECISION && fieldSubType > 0 && fieldSubType <= MAX_INTSUBTYPES) { isqlGlob.printf("%s(%d, %d)", @@ -2223,6 +2236,8 @@ static processing_state add_row(TEXT* tabname) SINT64 n; float* fvalue; double* dvalue; + FB_DEC16* d64value; + FB_DEC34* d128value; UCHAR* boolean; ISC_QUAD* blobid; vary* avary; @@ -2289,6 +2304,28 @@ static processing_state add_row(TEXT* tabname) } break; + case SQL_DEC16: + d64value = (FB_DEC16*) datap; + if (isqlGlob.df16) + isqlGlob.df16->fromString(fbStatus, lastInputLine, d64value); + if ((!isqlGlob.df16) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS)) + { + STDERROUT("Input parsing problem"); + done = true; + } + break; + + case SQL_DEC34: + d128value = (FB_DEC34*) datap; + if (isqlGlob.df34) + isqlGlob.df34->fromString(fbStatus, lastInputLine, d128value); + if ((!isqlGlob.df34) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS)) + { + STDERROUT("Input parsing problem"); + done = true; + } + break; + case SQL_TYPE_DATE: if (3 != sscanf(lastInputLine, "%d/%d/%d", ×.tm_year, ×.tm_mon, ×.tm_mday) || @@ -2978,6 +3015,8 @@ static processing_state bulk_insert_hack(const char* command) vary* avary; char* achar; tm times; + FB_DEC16* d64value; + FB_DEC34* d128value; // Initialize the time structure. memset(×, 0, sizeof(times)); char msec_str[5] = ""; @@ -3037,6 +3076,28 @@ static processing_state bulk_insert_hack(const char* command) } break; + case SQL_DEC16: + d64value = (FB_DEC16*) datap; + if (isqlGlob.df16) + isqlGlob.df16->fromString(fbStatus, lastInputLine, d64value); + if ((!isqlGlob.df16) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS)) + { + STDERROUT("Input parsing problem"); + done = true; + } + break; + + case SQL_DEC34: + d128value = (FB_DEC34*) datap; + if (isqlGlob.df34) + isqlGlob.df34->fromString(fbStatus, lastInputLine, d128value); + if ((!isqlGlob.df34) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS)) + { + STDERROUT("Input parsing problem"); + done = true; + } + break; + case SQL_TYPE_DATE: if (3 != sscanf(lastPos, "%d-%d-%d", ×.tm_year, ×.tm_mon, ×.tm_mday) || @@ -4807,6 +4868,7 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, {SetOptions::sqlCont, "ROLE", 0}, {SetOptions::sqlCont, "TRUSTED", 0}, // TRUSTED ROLE, will get DSQL error other case {SetOptions::stmtTimeout, "LOCAL_TIMEOUT", 0}, + {SetOptions::sqlCont, "DECFLOAT", 0}, }; // Display current set options @@ -5433,7 +5495,7 @@ void ISQL_get_version(bool call_by_create_db) isc_info_ods_minor_version, isc_info_db_sql_dialect, frb_info_att_charset, - Version_info ? isc_info_firebird_version: isc_info_end, + UCHAR(Version_info ? isc_info_firebird_version: isc_info_end), isc_info_end }; /* @@ -6945,8 +7007,8 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length) * Print an SQL data item as described. * **************************************/ + const char* convErr = "Conversion error"; TEXT d[32]; - TEXT* p = *s; *p = '\0'; @@ -7173,6 +7235,44 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length) } break; + case SQL_DEC16: + { + char decStr[Firebird::IDecFloat16::STRING_SIZE]; + if (isqlGlob.df16) + { + isqlGlob.df16->toString(fbStatus, var->value.asDec16, sizeof(decStr), decStr); + if (ISQL_errmsg(fbStatus)) + strcpy(decStr, convErr); + } + else + strcpy(decStr, convErr); + + if (setValues.List) + isqlGlob.printf("%*.*s%s", sizeof(decStr) - 1, sizeof(decStr) - 1, decStr, NEWLINE); + else + sprintf(p, "%*.*s ", sizeof(decStr) - 1, sizeof(decStr) - 1, decStr); + } + break; + + case SQL_DEC34: + { + char decStr[Firebird::IDecFloat34::STRING_SIZE]; + if (isqlGlob.df34) + { + isqlGlob.df34->toString(fbStatus, var->value.asDec34, sizeof(decStr), decStr); + if (ISQL_errmsg(fbStatus)) + strcpy(decStr, convErr); + } + else + strcpy(decStr, convErr); + + if (setValues.List) + isqlGlob.printf("%*.*s%s", sizeof(decStr) - 1, sizeof(decStr) - 1, decStr, NEWLINE); + else + sprintf(p, "%*.*s ", sizeof(decStr) - 1, sizeof(decStr) - 1, decStr); + } + break; + case SQL_TEXT: str2 = var->value.asChar; // See if it is character set OCTETS @@ -7949,6 +8049,7 @@ static unsigned process_message_display(Firebird::IMessageMetadata* message, uns namelength = NULL_DISP_LEN; const unsigned type = var.type; + const SSHORT charSet = TTYPE_TO_CHARSET(var.charSet); switch (type) { @@ -7976,26 +8077,32 @@ static unsigned process_message_display(Firebird::IMessageMetadata* message, uns case SQL_DOUBLE: disp_length = DOUBLE_LEN; break; + case SQL_DEC16: + disp_length = Firebird::IDecFloat16::STRING_SIZE - 1; + break; + case SQL_DEC34: + disp_length = Firebird::IDecFloat34::STRING_SIZE - 1; + break; case SQL_TEXT: alignment = 1; data_length++; // OCTETS data is displayed in hex - if (var.charSet == CS_BINARY) + if (charSet == CS_BINARY) disp_length = 2 * var.length; - else if (var.charSet == CS_UNICODE_FSS) + else if (charSet == CS_UNICODE_FSS) disp_length /= 3; - else if (var.charSet == CS_UTF8) + else if (charSet == CS_UTF8) disp_length /= 4; break; case SQL_VARYING: data_length += sizeof(USHORT) + 1; alignment = sizeof(USHORT); // OCTETS data is displayed in hex - if (var.charSet == CS_BINARY) + if (charSet == CS_BINARY) disp_length = 2 * var.length; - else if (var.charSet == CS_UNICODE_FSS) + else if (charSet == CS_UNICODE_FSS) disp_length /= 3; - else if (var.charSet == CS_UTF8) + else if (charSet == CS_UTF8) disp_length /= 4; break; case SQL_SHORT: @@ -8037,7 +8144,7 @@ static unsigned process_message_display(Firebird::IMessageMetadata* message, uns pad[i] = setValues.global_Col_default; disp_length = pad[i]; - if (var.charSet == 4) + if (charSet == CS_UTF8) disp_length *= 4; } @@ -8628,6 +8735,10 @@ static const char* sqltype_to_string(unsigned sqltype) return "FLOAT"; case SQL_DOUBLE: return "DOUBLE"; + case SQL_DEC16: + return "DECFLOAT(16)"; + case SQL_DEC34: + return "DECFLOAT(34)"; case SQL_D_FLOAT: return "D_FLOAT"; case SQL_TIMESTAMP: diff --git a/src/isql/isql.h b/src/isql/isql.h index 37142759b8..328754d10b 100644 --- a/src/isql/isql.h +++ b/src/isql/isql.h @@ -35,6 +35,7 @@ #include "../jrd/flags.h" #include +#include // Define lengths used in isql.e @@ -294,6 +295,8 @@ const int BLOB = 261; //const int SQL_TIME = 13; const int BIGINT = 16; const int BOOLEAN_TYPE = 23; +const int DEC64_TYPE = 24; +const int DEC128_TYPE = 25; static const sqltypes Column_types[] = { {SMALLINT, "SMALLINT"}, // keyword @@ -311,6 +314,8 @@ static const sqltypes Column_types[] = { {blr_timestamp, "TIMESTAMP"}, // keyword {BIGINT, "BIGINT"}, // keyword {BOOLEAN_TYPE, "BOOLEAN"}, // keyword + {DEC64_TYPE, "DECFLOAT(16)"}, + {DEC128_TYPE, "DECFLOAT(34)"}, {0, ""} }; @@ -397,8 +402,12 @@ public: USHORT major_ods; USHORT minor_ods; USHORT att_charset; + Firebird::IDecFloat16* df16; + Firebird::IDecFloat34* df34; void printf(const char* buffer, ...); void prints(const char* buffer); + + IsqlGlobals(); }; extern IsqlGlobals isqlGlob; @@ -452,6 +461,8 @@ struct IsqlVar ISC_QUAD* blobid; vary* asVary; char* asChar; + FB_DEC16* asDec16; + FB_DEC34* asDec34; void* setPtr; }; TypeMix value; diff --git a/src/isql/show.epp b/src/isql/show.epp index ef31406b40..d9b0edddd4 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -3845,7 +3845,7 @@ static processing_state show_domains(const SCHAR* domain_name) first = false; // Print the name of the domain fb_utils::exact_name(FLD.RDB$FIELD_NAME); - isqlGlob.printf("%-32s", FLD.RDB$FIELD_NAME); + isqlGlob.printf("%-31s ", FLD.RDB$FIELD_NAME); // Array dimensions if (!FLD.RDB$DIMENSIONS.NULL) @@ -4841,7 +4841,7 @@ static processing_state show_packages(const SCHAR* package_name) first = false; // Print the name of the package fb_utils::exact_name(PACK.RDB$PACKAGE_NAME); - isqlGlob.printf("%-32s", PACK.RDB$PACKAGE_NAME); + isqlGlob.printf("%-31s ", PACK.RDB$PACKAGE_NAME); isqlGlob.printf(NEWLINE); diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index 22d3ec93c2..0070a800c9 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -203,6 +203,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb) att_functions(*pool), att_internal(*pool), att_dyn_req(*pool), + att_dec_status(DEC_Errors), att_charsets(*pool), att_charset_ids(*pool), att_pools(*pool), diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index 1989731f37..4795bfc5c5 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -349,6 +349,8 @@ public: Firebird::Array att_internal; // internal statements Firebird::Array 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 jrd_req* findSystemRequest(thread_db* tdbb, USHORT id, USHORT which); diff --git a/src/jrd/CryptoManager.cpp b/src/jrd/CryptoManager.cpp index 5a7e70702c..dc0024f990 100644 --- a/src/jrd/CryptoManager.cpp +++ b/src/jrd/CryptoManager.cpp @@ -812,7 +812,7 @@ namespace Jrd { if (!down) { RefPtr jAtt(REF_NO_INCR, dbb.dbb_provider->attachDatabase(&status_vector, - dbb.dbb_filename.c_str(), writer.getBufferLength(), writer.getBuffer())); + dbb.dbb_database_name.c_str(), writer.getBufferLength(), writer.getBuffer())); check(&status_vector); MutexLockGuard attGuard(*(jAtt->getStable()->getMutex()), FB_FUNCTION); diff --git a/src/jrd/DataTypeUtil.cpp b/src/jrd/DataTypeUtil.cpp index c88c0f89ec..8024d47373 100644 --- a/src/jrd/DataTypeUtil.cpp +++ b/src/jrd/DataTypeUtil.cpp @@ -306,7 +306,7 @@ void DataTypeUtilBase::makeSubstr(dsc* result, const dsc* value, const dsc* offs if (length->dsc_address) // constant { - SLONG constant = CVT_get_long(length, 0, ERR_post); + SLONG constant = CVT_get_long(length, 0, JRD_get_thread_data()->getAttachment()->att_dec_status, ERR_post); fb_assert(constant >= 0); len = MIN(len, MIN(MAX_STR_SIZE, ULONG(constant)) * maxBytesPerChar(result->getCharSet())); } diff --git a/src/jrd/DbCreators.cpp b/src/jrd/DbCreators.cpp index fea7c0dcc3..57af406871 100644 --- a/src/jrd/DbCreators.cpp +++ b/src/jrd/DbCreators.cpp @@ -73,6 +73,7 @@ bool openDb(const char* securityDb, RefPtr& att, RefPtr >& aParameters, const Format* aFormat) : MessageNode(pool), parameters(aParameters), - format(aFormat), - isSpecial(pool) + format(aFormat) { setup(tdbb, csb, message, format->fmt_count); } @@ -104,13 +103,34 @@ namespace if (!param->prm_nullable) itemInfo->nullable = false; - - isSpecial.getBuffer(index / 2 + 1)[index / 2] = itemInfo->isSpecial(); } return type_alignments[desc->dsc_dtype]; } + public: + Array >& parameters; + const Format* format; + }; + + // External message node. + class ExtMessageNode : public MessageNode + { + public: + ExtMessageNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, USHORT message, const Format* aFormat) + : MessageNode(pool), + format(aFormat) + { + setup(tdbb, csb, message, format->fmt_count); + } + + virtual USHORT setupDesc(thread_db* tdbb, CompilerScratch* csb, USHORT index, + dsc* desc, ItemInfo* itemInfo) + { + *desc = format->fmt_desc[index]; + return type_alignments[desc->dsc_dtype]; + } + virtual const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const { if (request->req_operation == jrd_req::req_evaluate) @@ -124,32 +144,34 @@ namespace } public: - Array >& parameters; const Format* format; - Array isSpecial; }; // Initialize output parameters with their domains default value or NULL. // Kind of blr_init_variable, but for parameters. - class ExtInitParameterNode : public TypedNode + class InitParameterNode : public TypedNode { public: - ExtInitParameterNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, - ExtMessageNode* aMessage, USHORT aArgNumber) + InitParameterNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, + Array >& parameters, MessageNode* aMessage, USHORT aArgNumber) : TypedNode(pool), message(aMessage), argNumber(aArgNumber) { - Parameter* parameter = message->parameters[argNumber / 2]; + Parameter* parameter = parameters[argNumber / 2]; + defaultValueNode = NULL; - if (parameter->prm_mechanism == prm_mech_type_of || - fb_utils::implicit_domain(parameter->prm_field_source.c_str()) || - !parameter->prm_default_value) + if (parameter->prm_mechanism != prm_mech_type_of && + !fb_utils::implicit_domain(parameter->prm_field_source.c_str())) { - defaultValueNode = NULL; + MetaNamePair namePair(parameter->prm_field_source, ""); + + FieldInfo fieldInfo; + bool exist = csb->csb_map_field_info.get(namePair, fieldInfo); + + if (exist && fieldInfo.defaultValue) + defaultValueNode = CMP_clone_node(tdbb, csb, fieldInfo.defaultValue); } - else - defaultValueNode = CMP_clone_node(tdbb, csb, parameter->prm_default_value); } string internalPrint(NodePrinter& printer) const @@ -160,20 +182,20 @@ namespace NODE_PRINT(printer, argNumber); NODE_PRINT(printer, defaultValueNode); - return "ExtInitParameterNode"; + return "InitParameterNode"; } void genBlr(DsqlCompilerScratch* /*dsqlScratch*/) { } - ExtInitParameterNode* pass1(thread_db* tdbb, CompilerScratch* csb) + InitParameterNode* pass1(thread_db* tdbb, CompilerScratch* csb) { doPass1(tdbb, csb, &defaultValueNode); return this; } - ExtInitParameterNode* pass2(thread_db* tdbb, CompilerScratch* csb) + InitParameterNode* pass2(thread_db* tdbb, CompilerScratch* csb) { ExprNode::doPass2(tdbb, csb, &defaultValueNode); return this; @@ -224,48 +246,45 @@ namespace } private: - ExtMessageNode* message; + MessageNode* message; USHORT argNumber; ValueExprNode* defaultValueNode; }; - // External output parameters initialization. - class ExtInitOutputNode : public CompoundStmtNode + // Output parameters initialization. + class InitOutputNode : public CompoundStmtNode { public: - ExtInitOutputNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, - ExtMessageNode* message) + InitOutputNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, + Array >& parameters, MessageNode* message) : CompoundStmtNode(pool) { // Iterate over the format items, except the EOF item. for (USHORT i = 0; i < (message->format->fmt_count / 2) * 2; i += 2) { - ExtInitParameterNode* init = FB_NEW_POOL(pool) ExtInitParameterNode( - tdbb, pool, csb, message, i); + InitParameterNode* init = FB_NEW_POOL(pool) InitParameterNode( + tdbb, pool, csb, parameters, message, i); statements.add(init); } } }; - // External parameters validation. - class ExtValidationNode : public CompoundStmtNode + // Move parameters from a message to another, validating theirs values. + class MessageMoverNode : public CompoundStmtNode { public: - ExtValidationNode(MemoryPool& pool, ExtMessageNode* message, bool procedure, bool input) + MessageMoverNode(MemoryPool& pool, MessageNode* fromMessage, MessageNode* toMessage) : CompoundStmtNode(pool) { // Iterate over the format items, except the EOF item. - for (USHORT i = 0; i < (message->format->fmt_count / 2) * 2; i += 2) + for (USHORT i = 0; i < (fromMessage->format->fmt_count / 2) * 2; i += 2) { - if (!message->isSpecial[i / 2]) - continue; - ParameterNode* flag = FB_NEW_POOL(pool) ParameterNode(pool); - flag->message = message; + flag->message = fromMessage; flag->argNumber = i + 1; ParameterNode* param = FB_NEW_POOL(pool) ParameterNode(pool); - param->message = message; + param->message = fromMessage; param->argNumber = i; param->argFlag = flag; @@ -273,28 +292,17 @@ namespace assign->asgnFrom = param; statements.add(assign); - // It's sufficient to assign input parameters to NULL, but output parameters - // need to be assigned to themselves to validate correctly. - if (input) - assign->asgnTo = FB_NEW_POOL(pool) NullNode(pool); - else - { - flag = FB_NEW_POOL(pool) ParameterNode(pool); - flag->message = message; - flag->argNumber = i + 1; + flag = FB_NEW_POOL(pool) ParameterNode(pool); + flag->message = toMessage; + flag->argNumber = i + 1; - param = FB_NEW_POOL(pool) ParameterNode(pool); - param->message = message; - param->argNumber = i; - param->argFlag = flag; + param = FB_NEW_POOL(pool) ParameterNode(pool); + param->message = toMessage; + param->argNumber = i; + param->argFlag = flag; - assign->asgnTo = param; - } + assign->asgnTo = param; } - - // A stall is required to read req_proc_fetch state correctly. - if (procedure) - statements.add(FB_NEW_POOL(pool) StallNode(pool)); } }; @@ -302,10 +310,11 @@ namespace class ExtFunctionNode : public SuspendNode { public: - ExtFunctionNode(MemoryPool& pool, const ReceiveNode* aReceiveNode, + ExtFunctionNode(MemoryPool& pool, const MessageNode* aExtInMessageNode, const MessageNode* aExtOutMessageNode, const ExtEngineManager::Function* aFunction) : SuspendNode(pool), - receiveNode(aReceiveNode), + extInMessageNode(aExtInMessageNode), + extOutMessageNode(aExtOutMessageNode), function(aFunction) { } @@ -314,9 +323,8 @@ namespace { if (request->req_operation == jrd_req::req_evaluate) { - UCHAR* inMsg = receiveNode ? - request->getImpure(receiveNode->message->impureOffset) : NULL; - UCHAR* outMsg = request->getImpure(message->impureOffset); + UCHAR* inMsg = extInMessageNode ? request->getImpure(extInMessageNode->impureOffset) : NULL; + UCHAR* outMsg = request->getImpure(extOutMessageNode->impureOffset); function->execute(tdbb, inMsg, outMsg); } @@ -325,83 +333,87 @@ namespace } private: - const ReceiveNode* receiveNode; + const MessageNode* extInMessageNode; + const MessageNode* extOutMessageNode; const ExtEngineManager::Function* function; }; // External procedure node. - class ExtProcedureNode : public SuspendNode + class ExtProcedureNode : public CompoundStmtNode { public: - ExtProcedureNode(MemoryPool& pool, const ReceiveNode* aReceiveNode, - const ExtEngineManager::Procedure* aProcedure) - : SuspendNode(pool), - receiveNode(aReceiveNode), + ExtProcedureNode(MemoryPool& pool, MessageNode* aExtInMessageNode, MessageNode* aExtOutMessageNode, + MessageNode* aIntOutMessageNode, const ExtEngineManager::Procedure* aProcedure) + : CompoundStmtNode(pool), + extInMessageNode(aExtInMessageNode), + extOutMessageNode(aExtOutMessageNode), + intOutMessageNode(aIntOutMessageNode), procedure(aProcedure) { + SuspendNode* suspend = FB_NEW_POOL(pool) SuspendNode(pool); + suspend->message = intOutMessageNode; + suspend->statement = FB_NEW_POOL(getPool()) MessageMoverNode(pool, extOutMessageNode, intOutMessageNode); + + statements.add(suspend); + statements.add(FB_NEW_POOL(getPool()) StallNode(pool)); } virtual const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const { + impure_state* const impure = request->getImpure(impureOffset); ExtEngineManager::ResultSet*& resultSet = request->req_ext_resultset; - UCHAR* inMsg = receiveNode ? - request->getImpure(receiveNode->message->impureOffset) : NULL; - UCHAR* outMsg = request->getImpure(message->impureOffset); - USHORT* eof = (USHORT*) (outMsg + (IPTR) message->format->fmt_desc.back().dsc_address); + UCHAR* extInMsg = extInMessageNode ? request->getImpure(extInMessageNode->impureOffset) : NULL; + UCHAR* extOutMsg = extOutMessageNode ? request->getImpure(extOutMessageNode->impureOffset) : NULL; + UCHAR* intOutMsg = intOutMessageNode ? request->getImpure(intOutMessageNode->impureOffset) : NULL; + SSHORT* eof = intOutMsg ? + (SSHORT*) (intOutMsg + (IPTR) intOutMessageNode->format->fmt_desc.back().dsc_address) : NULL; switch (request->req_operation) { case jrd_req::req_evaluate: - fb_assert(!resultSet && *eof == 0); - resultSet = procedure->open(tdbb, inMsg, outMsg); + fb_assert(!resultSet); + resultSet = procedure->open(tdbb, extInMsg, extOutMsg); - if (resultSet) - *eof = -1; - else + if (!resultSet) { - if (!(request->req_flags & req_proc_fetch)) + *eof = 0; + break; + } + else + *eof = -1; + // fall into + + case jrd_req::req_proceed: + case jrd_req::req_sync: + if (resultSet) + { + if (resultSet->fetch(tdbb) && (request->req_flags & req_proc_fetch)) + *eof = -1; + else { - request->req_operation = jrd_req::req_evaluate; - return statement; + *eof = 0; + delete resultSet; + resultSet = NULL; } } - request->req_operation = jrd_req::req_return; - // fall into - - case jrd_req::req_return: - if (*eof == 0) - { - fb_assert(!resultSet); - return parentStmt; - } - - fb_assert(resultSet); - - if (!resultSet->fetch(tdbb) || !(request->req_flags & req_proc_fetch)) - { - *eof = 0; - delete resultSet; - resultSet = NULL; - } - + impure->sta_state = 0; // suspend node + request->req_operation = jrd_req::req_sync; break; - case jrd_req::req_proceed: - request->req_operation = jrd_req::req_evaluate; - return statement; - case jrd_req::req_unwind: delete resultSet; resultSet = NULL; break; } - return SuspendNode::execute(tdbb, request, exeState); + return CompoundStmtNode::execute(tdbb, request, exeState); } private: - const ReceiveNode* receiveNode; + MessageNode* extInMessageNode; + MessageNode* extOutMessageNode; + MessageNode* intOutMessageNode; const ExtEngineManager::Procedure* procedure; }; @@ -628,10 +640,10 @@ void ExtEngineManager::ExternalContextImpl::setTransaction(thread_db* tdbb) if ((internalTransaction = newTransaction)) { - internalTransaction->getInterface()->addRef(); + internalTransaction->getInterface(true)->addRef(); externalTransaction = MasterInterfacePtr()->registerTransaction(externalAttachment, - internalTransaction->getInterface()); + internalTransaction->getInterface(true)); } } @@ -776,7 +788,8 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* out firstFetch(true) { attInfo = procedure->extManager->getEngineAttachment(tdbb, procedure->engine); - const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ? procedure->prc->owner : ""; + const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ? + procedure->prc->owner : ""; ContextManager ctxManager(tdbb, attInfo, procedure->procedure, (procedure->prc->getName().package.isEmpty() ? CallerName(obj_procedure, procedure->prc->getName().identifier, userName) : @@ -810,7 +823,8 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb) if (!resultSet) return wasFirstFetch; - const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ? procedure->prc->owner : ""; + const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ? + procedure->prc->owner : ""; ContextManager ctxManager(tdbb, attInfo, charSet, (procedure->prc->getName().package.isEmpty() ? CallerName(obj_procedure, procedure->prc->getName().identifier, userName) : @@ -1078,6 +1092,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd:: status.check(); IExternalFunction* externalFunction; + RefPtr extInputParameters, extOutputParameters; { // scope EngineCheckout cout(tdbb, FB_FUNCTION); @@ -1092,16 +1107,19 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd:: Arg::Gds(isc_eem_func_not_returned) << udf->getName().toString() << engine); } - metadata->inputParameters = inBuilder->getMetadata(&status); + extInputParameters = inBuilder->getMetadata(&status); status.check(); - metadata->outputParameters = outBuilder->getMetadata(&status); + extOutputParameters = outBuilder->getMetadata(&status); status.check(); } udf->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); udf->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); + const Format* extInputFormat = Routine::createFormat(pool, extInputParameters, false); + const Format* extOutputFormat = Routine::createFormat(pool, extOutputParameters, true); + try { udf->fun_external = FB_NEW_POOL(getPool()) Function(tdbb, this, attInfo->engine, @@ -1109,38 +1127,48 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd:: CompoundStmtNode* mainNode = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool()); - ExtMessageNode* inMessageNode = udf->getInputFields().hasData() ? - FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 0, + IntMessageNode* intInMessageNode = udf->getInputFields().hasData() ? + FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 0, udf->getInputFields(), udf->getInputFormat()) : NULL; - if (inMessageNode) - mainNode->statements.add(inMessageNode); + ExtMessageNode* extInMessageNode = NULL; - ExtMessageNode* outMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 1, + if (intInMessageNode) + { + mainNode->statements.add(intInMessageNode); + + extInMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 2, extInputFormat); + mainNode->statements.add(extInMessageNode); + } + + IntMessageNode* intOutMessageNode = FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 1, udf->getOutputFields(), udf->getOutputFormat()); - mainNode->statements.add(outMessageNode); + mainNode->statements.add(intOutMessageNode); - ExtInitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) ExtInitOutputNode( - tdbb, getPool(), csb, outMessageNode); + ExtMessageNode* extOutMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 3, + extOutputFormat); + mainNode->statements.add(extOutMessageNode); + + // Initialize the output fields into the external message. + InitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) InitOutputNode( + tdbb, getPool(), csb, udf->getOutputFields(), extOutMessageNode); mainNode->statements.add(initOutputNode); - ReceiveNode* receiveNode = inMessageNode ? - FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL; - - if (inMessageNode) + if (intInMessageNode) { - receiveNode->message = inMessageNode; - receiveNode->statement = FB_NEW_POOL(getPool()) ExtValidationNode( - getPool(), inMessageNode, false, true); + ReceiveNode* receiveNode = intInMessageNode ? FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL; + receiveNode->message = intInMessageNode; + receiveNode->statement = FB_NEW_POOL(getPool()) MessageMoverNode( + getPool(), intInMessageNode, extInMessageNode); mainNode->statements.add(receiveNode); } ExtFunctionNode* extFunctionNode = FB_NEW_POOL(getPool()) ExtFunctionNode(getPool(), - receiveNode, udf->fun_external); + extInMessageNode, extOutMessageNode, udf->fun_external); mainNode->statements.add(extFunctionNode); - extFunctionNode->message = outMessageNode; - extFunctionNode->statement = FB_NEW_POOL(getPool()) ExtValidationNode( - getPool(), outMessageNode, false, false); + extFunctionNode->message = intOutMessageNode; + extFunctionNode->statement = FB_NEW_POOL(getPool()) MessageMoverNode( + getPool(), extOutMessageNode, intOutMessageNode); JrdStatement* statement = udf->getStatement(); PAR_preparsed_node(tdbb, NULL, mainNode, NULL, &csb, &statement, false, 0); @@ -1188,6 +1216,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ status.check(); IExternalProcedure* externalProcedure; + RefPtr extInputParameters, extOutputParameters; { // scope EngineCheckout cout(tdbb, FB_FUNCTION); @@ -1203,16 +1232,19 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ prc->getName().toString() << engine); } - metadata->inputParameters = inBuilder->getMetadata(&status); + extInputParameters = inBuilder->getMetadata(&status); status.check(); - metadata->outputParameters = outBuilder->getMetadata(&status); + extOutputParameters = outBuilder->getMetadata(&status); status.check(); } prc->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); prc->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); + const Format* extInputFormat = Routine::createFormat(pool, extInputParameters, false); + const Format* extOutputFormat = Routine::createFormat(pool, extOutputParameters, true); + try { prc->setExternal(FB_NEW_POOL(getPool()) Procedure(tdbb, this, attInfo->engine, @@ -1220,38 +1252,54 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ CompoundStmtNode* mainNode = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool()); - ExtMessageNode* inMessageNode = prc->getInputFields().hasData() ? - FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 0, + IntMessageNode* intInMessageNode = prc->getInputFields().hasData() ? + FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 0, prc->getInputFields(), prc->getInputFormat()) : NULL; - if (inMessageNode) - mainNode->statements.add(inMessageNode); + ExtMessageNode* extInMessageNode = NULL; - ExtMessageNode* outMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 1, - prc->getOutputFields(), prc->getOutputFormat()); - mainNode->statements.add(outMessageNode); - - ExtInitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) ExtInitOutputNode( - tdbb, getPool(), csb, outMessageNode); - mainNode->statements.add(initOutputNode); - - ReceiveNode* receiveNode = inMessageNode ? - FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL; - - if (inMessageNode) + if (intInMessageNode) { - receiveNode->message = inMessageNode; - receiveNode->statement = FB_NEW_POOL(getPool()) ExtValidationNode( - getPool(), inMessageNode, true, true); - mainNode->statements.add(receiveNode); + mainNode->statements.add(intInMessageNode); + + extInMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 2, extInputFormat); + mainNode->statements.add(extInMessageNode); } + IntMessageNode* intOutMessageNode = FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 1, + prc->getOutputFields(), prc->getOutputFormat()); + mainNode->statements.add(intOutMessageNode); + + ExtMessageNode* extOutMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), + csb, 3, extOutputFormat); + mainNode->statements.add(extOutMessageNode); + + // Initialize the output fields into the external message. + InitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) InitOutputNode( + tdbb, getPool(), csb, prc->getOutputFields(), extOutMessageNode); + mainNode->statements.add(initOutputNode); + + ReceiveNode* receiveNode = intInMessageNode ? + FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL; + + if (intInMessageNode) + { + CompoundStmtNode* receiveSubStatement = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool()); + receiveSubStatement->statements.add(FB_NEW_POOL(getPool()) MessageMoverNode( + getPool(), intInMessageNode, extInMessageNode)); + receiveSubStatement->statements.add(FB_NEW_POOL(getPool()) StallNode(getPool())); + + receiveNode->statement = receiveSubStatement; + receiveNode->message = intInMessageNode; + + mainNode->statements.add(receiveNode); + } + else + mainNode->statements.add(FB_NEW_POOL(getPool()) StallNode(getPool())); + ExtProcedureNode* extProcedureNode = FB_NEW_POOL(getPool()) ExtProcedureNode(getPool(), - receiveNode, prc->getExternal()); + extInMessageNode, extOutMessageNode, intOutMessageNode, prc->getExternal()); mainNode->statements.add(extProcedureNode); - extProcedureNode->message = outMessageNode; - extProcedureNode->statement = FB_NEW_POOL(getPool()) ExtValidationNode( - getPool(), outMessageNode, true, false); JrdStatement* statement = prc->getStatement(); PAR_preparsed_node(tdbb, NULL, mainNode, NULL, &csb, &statement, false, 0); diff --git a/src/jrd/JrdStatement.cpp b/src/jrd/JrdStatement.cpp index ce8ec26b9e..78295afd5b 100644 --- a/src/jrd/JrdStatement.cpp +++ b/src/jrd/JrdStatement.cpp @@ -761,7 +761,7 @@ template static void makeSubRoutines(thread_db* tdbb, JrdStatement* Routine* subRoutine = subNode->routine; CompilerScratch*& subCsb = subNode->subCsb; - JrdStatement* subStatement = JrdStatement::makeStatement(tdbb, subCsb, true); + JrdStatement* subStatement = JrdStatement::makeStatement(tdbb, subCsb, false); subStatement->parentStatement = statement; subRoutine->setStatement(subStatement); diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index 4fbca24a92..254b353118 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -32,10 +32,7 @@ #include "gen/iberror.h" #include "../jrd/constants.h" -#include "../common/classes/ClumpletWriter.h" #include "../common/classes/init.h" -#include "../common/classes/Hash.h" -#include "../common/classes/GenericMap.h" #include "../common/classes/RefMutex.h" #include "../common/classes/SyncObject.h" #include "../common/classes/MetaName.h" @@ -62,11 +59,15 @@ using namespace Jrd; namespace { -const unsigned FLAG_DB = 1; -const unsigned FLAG_SEC = 2; +// internalFlags bits +const ULONG FLAG_DB = 1; +const ULONG FLAG_SEC = 2; +const ULONG FLAG_DOWN_DB = 4; +const ULONG FLAG_DOWN_SEC = 8; -const unsigned FLAG_USER = 1; -const unsigned FLAG_ROLE = 2; +// flagRolUsr values +const ULONG FLAG_USER = 1; +const ULONG FLAG_ROLE = 2; const char* NM_ROLE = "Role"; const char* NM_USER = "User"; @@ -82,6 +83,10 @@ void check(const char* s, IStatus* st) newStatus.raise(); } +} // anonymous namespace + +namespace Jrd { + class AuthWriter : public ClumpletWriter { public: @@ -145,377 +150,415 @@ private: unsigned char sequence; }; -class Map; -typedef HashTable, Map> MapHash; +} // namespace Jrd -class Map : public MapHash::Entry, public GlobalStorage + +Mapping::DbHandle::DbHandle() +{ } + +void Mapping::DbHandle::setAttachment(IAttachment* att) { -public: - static FB_SIZE_T hash(const Map& value, FB_SIZE_T hashSize) + if (att) { - NoCaseString key = value.makeHashKey(); - return DefaultHash::hash(key.c_str(), key.length(), hashSize); + MAP_DEBUG(fprintf(stderr, "Using existing db handle %p\n", att)); + assign(att); } +} - NoCaseString makeHashKey() const - { - NoCaseString key; - key += usng; - MAP_DEBUG(key += ':'); - key += plugin; - MAP_DEBUG(key += ':'); - key += db; - MAP_DEBUG(key += ':'); - key += fromType; - MAP_DEBUG(key += ':'); - key += from; - - key.upper(); - return key; - } - - NoCaseString plugin, db, fromType, from, to; - bool toRole; - char usng; - - Map(const char* aUsing, const char* aPlugin, const char* aDb, - const char* aFromType, const char* aFrom, - SSHORT aRole, const char* aTo) - : plugin(getPool()), db(getPool()), fromType(getPool()), - from(getPool()), to(getPool()), toRole(aRole ? true : false), usng(aUsing[0]) - { - plugin = aPlugin; - db = aDb; - fromType = aFromType; - from = aFrom; - to = aTo; - - trimAll(); - } - - explicit Map(AuthReader::Info& info) //type, name, plugin, secDb - : plugin(getPool()), db(getPool()), - fromType(getPool()), from(getPool()), to(getPool()), - toRole(false), usng(info.plugin.hasData() ? 'P' : 'M') - { - plugin = info.plugin.hasData() ? info.plugin.c_str() : "*"; - db = info.secDb.hasData() ? info.secDb.c_str() : "*"; - fromType = info.type; - from = info.name.hasData() ? info.name.c_str() : "*"; - - trimAll(); - } - - void trimAll() - { - plugin.rtrim(); - db.rtrim(); - fromType.rtrim(); - from.rtrim(); - to.rtrim(); - } - - virtual bool isEqual(const Map& k) const - { - return usng == k.usng && - plugin == k.plugin && - db == k.db && - fromType == k.fromType && - from == k.from ; - } - - virtual Map* get() - { - return this; - } -}; - -class Cache : public MapHash, public GlobalStorage +void Mapping::DbHandle::clear() { -public: - Cache(const NoCaseString& aliasDb, const NoCaseString& db) - : alias(getPool(), aliasDb), name(getPool(), db), - dataFlag(false), downFlag(false) + assign(nullptr); +} + +bool Mapping::DbHandle::attach(const char* aliasDb, ICryptKeyCallback* cryptCb) +{ + FbLocalStatus st; + bool down = false; // true if on attach db is shutdown + + if (hasData()) { - enableDuplicates(); + MAP_DEBUG(fprintf(stderr, "Already attached %s\n", aliasDb)); + return down; } - void populate(IAttachment *att, bool isDown) + DispatcherPtr prov; + if (cryptCb) { - FbLocalStatus st; + prov->setDbCryptCallback(&st, cryptCb); + check("IProvider::setDbCryptCallback", &st); + } - if (dataFlag) + ClumpletWriter embeddedSysdba(ClumpletWriter::Tagged, 1024, isc_dpb_version1); + embeddedSysdba.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME)); + embeddedSysdba.insertByte(isc_dpb_sec_attach, TRUE); + embeddedSysdba.insertString(isc_dpb_config, EMBEDDED_PROVIDERS, fb_strlen(EMBEDDED_PROVIDERS)); + embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE); + embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE); + + MAP_DEBUG(fprintf(stderr, "Attach %s\n", aliasDb)); + IAttachment* att = prov->attachDatabase(&st, aliasDb, + embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer()); + + if (st->getState() & IStatus::STATE_ERRORS) + { + const ISC_STATUS* s = st->getErrors(); + MAP_DEBUG(isc_print_status(s)); + bool missing = fb_utils::containsErrorCode(s, isc_io_error); + down = fb_utils::containsErrorCode(s, isc_shutdown); + if (!(missing || down)) + check("IProvider::attachDatabase", &st); + + // down/missing security DB is not a reason to fail mapping + } + else + assignRefNoIncr(att); + + MAP_DEBUG(fprintf(stderr, "Att=%p\n", att)); + + return down; +} + + +FB_SIZE_T Mapping::Map::hash(const Map& value, FB_SIZE_T hashSize) +{ + NoCaseString key = value.makeHashKey(); + return DefaultHash::hash(key.c_str(), key.length(), hashSize); +} + +NoCaseString Mapping::Map::makeHashKey() const +{ + NoCaseString key; + key += usng; + MAP_DEBUG(key += ':'); + key += plugin; + MAP_DEBUG(key += ':'); + key += db; + MAP_DEBUG(key += ':'); + key += fromType; + MAP_DEBUG(key += ':'); + key += from; + + key.upper(); + return key; +} + +Mapping::Map::Map(const char* aUsing, const char* aPlugin, const char* aDb, + const char* aFromType, const char* aFrom, + SSHORT aRole, const char* aTo) + : plugin(getPool()), db(getPool()), fromType(getPool()), + from(getPool()), to(getPool()), toRole(aRole ? true : false), usng(aUsing[0]) +{ + plugin = aPlugin; + db = aDb; + fromType = aFromType; + from = aFrom; + to = aTo; + + trimAll(); +} + +Mapping::Map::Map(AuthReader::Info& info) //type, name, plugin, secDb + : plugin(getPool()), db(getPool()), + fromType(getPool()), from(getPool()), to(getPool()), + toRole(false), usng(info.plugin.hasData() ? 'P' : 'M') +{ + plugin = info.plugin.hasData() ? info.plugin.c_str() : "*"; + db = info.secDb.hasData() ? info.secDb.c_str() : "*"; + fromType = info.type; + from = info.name.hasData() ? info.name.c_str() : "*"; + + trimAll(); +} + +void Mapping::Map::trimAll() +{ + plugin.rtrim(); + db.rtrim(); + fromType.rtrim(); + from.rtrim(); + to.rtrim(); +} + +bool Mapping::Map::isEqual(const Map& k) const +{ + return usng == k.usng && + plugin == k.plugin && + db == k.db && + fromType == k.fromType && + from == k.from ; +} + +Mapping::Map* Mapping::Map::get() +{ + return this; +} + + +Mapping::Cache::Cache(const NoCaseString& aliasDb, const NoCaseString& db) + : alias(getPool(), aliasDb), name(getPool(), db), + dataFlag(false) +{ + enableDuplicates(); +} + +Mapping::Cache::~Cache() +{ + cleanup(eraseEntry); +} + +bool Mapping::Cache::populate(IAttachment *att) +{ + FbLocalStatus st; + + if (dataFlag) + { + return false; + } + + if (!att) + { + dataFlag = true; + return false; + } + + MAP_DEBUG(fprintf(stderr, "Populate cache for %s\n", name.c_str())); + + ITransaction* tra = nullptr; + IResultSet* curs = nullptr; + + try + { + ClumpletWriter readOnly(ClumpletWriter::Tpb, MAX_DPB_SIZE, isc_tpb_version1); + readOnly.insertTag(isc_tpb_read); + readOnly.insertTag(isc_tpb_wait); + tra = att->startTransaction(&st, readOnly.getBufferLength(), readOnly.getBuffer()); + check("IAttachment::startTransaction", &st); + + Message mMap; + Field usng(mMap, 1); + Field plugin(mMap, MAX_SQL_IDENTIFIER_SIZE); + Field db(mMap, MAX_SQL_IDENTIFIER_SIZE); + Field fromType(mMap, MAX_SQL_IDENTIFIER_SIZE); + Field from(mMap, 255); + Field role(mMap); + Field to(mMap, MAX_SQL_IDENTIFIER_SIZE); + + curs = att->openCursor(&st, tra, 0, + "SELECT RDB$MAP_USING, RDB$MAP_PLUGIN, RDB$MAP_DB, RDB$MAP_FROM_TYPE, " + " RDB$MAP_FROM, RDB$MAP_TO_TYPE, RDB$MAP_TO " + "FROM RDB$AUTH_MAPPING", + 3, nullptr, nullptr, mMap.getMetadata(), nullptr, 0); + if (st->getState() & IStatus::STATE_ERRORS) { - return; - } - - if (!att) - { - dataFlag = true; - downFlag = isDown; - return; - } - - MAP_DEBUG(fprintf(stderr, "Populate cache for %s\n", name.c_str())); - - ITransaction* tra = NULL; - IResultSet* curs = NULL; - - try - { - cleanup(eraseEntry); - - ClumpletWriter readOnly(ClumpletWriter::Tpb, MAX_DPB_SIZE, isc_tpb_version1); - readOnly.insertTag(isc_tpb_read); - readOnly.insertTag(isc_tpb_wait); - tra = att->startTransaction(&st, readOnly.getBufferLength(), readOnly.getBuffer()); - check("IAttachment::startTransaction", &st); - - Message mMap; - Field usng(mMap, 1); - Field plugin(mMap, MAX_SQL_IDENTIFIER_SIZE); - Field db(mMap, MAX_SQL_IDENTIFIER_SIZE); - Field fromType(mMap, MAX_SQL_IDENTIFIER_SIZE); - Field from(mMap, 255); - Field role(mMap); - Field to(mMap, MAX_SQL_IDENTIFIER_SIZE); - - curs = att->openCursor(&st, tra, 0, - "SELECT RDB$MAP_USING, RDB$MAP_PLUGIN, RDB$MAP_DB, RDB$MAP_FROM_TYPE, " - " RDB$MAP_FROM, RDB$MAP_TO_TYPE, RDB$MAP_TO " - "FROM RDB$AUTH_MAPPING", - 3, NULL, NULL, mMap.getMetadata(), NULL, 0); - if (st->getState() & IStatus::STATE_ERRORS) + if (fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err)) { - if (fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err)) - { - // isc_dsql_relation_err when opening cursor - i.e. table RDB$AUTH_MAPPING - // is missing due to non-FB3 security DB - tra->release(); - dataFlag = true; - return; - } - check("IAttachment::openCursor", &st); - } - - while (curs->fetchNext(&st, mMap.getBuffer()) == IStatus::RESULT_OK) - { - const char* expandedDb = "*"; - PathName target; - if (!db.null) - { - expandedDb = db; - MAP_DEBUG(fprintf(stderr, "non-expandedDb '%s'\n", expandedDb)); - expandDatabaseName(expandedDb, target, NULL); - expandedDb = target.c_str(); - MAP_DEBUG(fprintf(stderr, "expandedDb '%s'\n", expandedDb)); - } - - Map* map = FB_NEW Map(usng, plugin.null ? "*" : plugin, expandedDb, - fromType, from, role, to.null ? "*" : to); - MAP_DEBUG(fprintf(stderr, "Add = %s\n", map->makeHashKey().c_str())); - add(map); - } - check("IResultSet::fetchNext", &st); - - curs->close(&st); - check("IResultSet::close", &st); - curs = NULL; - - tra->rollback(&st); - check("ITransaction::rollback", &st); - tra = NULL; - - dataFlag = true; - downFlag = false; - } - catch (const Exception& ex) - { - if (curs) - curs->release(); - if (tra) + // isc_dsql_relation_err when opening cursor - i.e. table RDB$AUTH_MAPPING + // is missing due to non-FB3 security DB tra->release(); + dataFlag = true; + return false; + } + check("IAttachment::openCursor", &st); + } - // If database is shutdown it's not a reason to fail mapping - StaticStatusVector status; - ex.stuffException(status); - - const ISC_STATUS* s = status.begin(); - - if (fb_utils::containsErrorCode(s, isc_shutdown)) + while (curs->fetchNext(&st, mMap.getBuffer()) == IStatus::RESULT_OK) + { + const char* expandedDb = "*"; + PathName target; + if (!db.null) { - downFlag = true; - return; + expandedDb = db; + MAP_DEBUG(fprintf(stderr, "non-expandedDb '%s'\n", expandedDb)); + expandDatabaseName(expandedDb, target, nullptr); + expandedDb = target.c_str(); + MAP_DEBUG(fprintf(stderr, "expandedDb '%s'\n", expandedDb)); } - throw; + Map* map = FB_NEW Map(usng, plugin.null ? "*" : plugin, expandedDb, + fromType, from, role, to.null ? "*" : to); + MAP_DEBUG(fprintf(stderr, "Add = %s\n", map->makeHashKey().c_str())); + add(map); } + check("IResultSet::fetchNext", &st); + + curs->close(&st); + check("IResultSet::close", &st); + curs = nullptr; + + tra->rollback(&st); + check("ITransaction::rollback", &st); + tra = nullptr; + + dataFlag = true; + } + catch (const Exception& ex) + { + if (curs) + curs->release(); + if (tra) + tra->release(); + + // If database is shutdown it's not a reason to fail mapping + StaticStatusVector status; + ex.stuffException(status); + + const ISC_STATUS* s = status.begin(); + + if (fb_utils::containsErrorCode(s, isc_shutdown)) + return true; + + throw; } - void map(bool flagWild, AuthReader::Info& info, AuthWriter& newBlock) + return false; +} + +void Mapping::Cache::map(bool flagWild, AuthReader::Info& info, AuthWriter& newBlock) +{ + if (info.type == TYPE_SEEN) + return; + + Map from(info); + + if (from.from == "*") + Arg::Gds(isc_map_aster).raise(); + + if (!flagWild) + search(info, from, newBlock, from.from); + else + varUsing(info, from, newBlock); +} + +void Mapping::Cache::search(AuthReader::Info& info, const Map& from, AuthWriter& newBlock, + const NoCaseString& originalUserName) +{ + MAP_DEBUG(fprintf(stderr, "Key = %s\n", from.makeHashKey().c_str())); + if (!dataFlag) + return; + + for (Map* to = lookup(from); to; to = to->next(from)) { - if (info.type == TYPE_SEEN) - return; + MAP_DEBUG(fprintf(stderr, "Match!!\n")); + unsigned flagRolUsr = to->toRole ? FLAG_ROLE : FLAG_USER; + if (info.found & flagRolUsr) + continue; + if (info.current & flagRolUsr) + (Arg::Gds(isc_map_multi) << originalUserName).raise(); - Map from(info); + info.current |= flagRolUsr; - if (from.from == "*") - Arg::Gds(isc_map_aster).raise(); - - if (!flagWild) - search(info, from, newBlock, from.from); - else - varUsing(info, from, newBlock); + AuthReader::Info newInfo; + newInfo.type = to->toRole ? NM_ROLE : NM_USER; + newInfo.name = to->to == "*" ? originalUserName : to->to; + newInfo.secDb = this->name; + newInfo.origPlug = info.origPlug.hasData() ? info.origPlug : info.plugin; + newBlock.add(newInfo); } +} - void search(AuthReader::Info& info, const Map& from, AuthWriter& newBlock, - const NoCaseString& originalUserName) - { - MAP_DEBUG(fprintf(stderr, "Key = %s\n", from.makeHashKey().c_str())); - if (!dataFlag) - return; - - for (Map* to = lookup(from); to; to = to->next(from)) - { - MAP_DEBUG(fprintf(stderr, "Match!!\n")); - unsigned flagRolUsr = to->toRole ? FLAG_ROLE : FLAG_USER; - if (info.found & flagRolUsr) - continue; - if (info.current & flagRolUsr) - (Arg::Gds(isc_map_multi) << originalUserName).raise(); - - info.current |= flagRolUsr; - - AuthReader::Info newInfo; - newInfo.type = to->toRole ? NM_ROLE : NM_USER; - newInfo.name = to->to == "*" ? originalUserName : to->to; - newInfo.secDb = this->name; - newInfo.origPlug = info.origPlug.hasData() ? info.origPlug : info.plugin; - newBlock.add(newInfo); - } - } - - void varPlugin(AuthReader::Info& info, Map from, AuthWriter& newBlock) +void Mapping::Cache::varPlugin(AuthReader::Info& info, Map from, AuthWriter& newBlock) +{ + varDb(info, from, newBlock); + if (from.plugin != "*") { + from.plugin = "*"; varDb(info, from, newBlock); - if (from.plugin != "*") + } +} + +void Mapping::Cache::varDb(AuthReader::Info& info, Map from, AuthWriter& newBlock) +{ + varFrom(info, from, newBlock); + if (from.db != "*") + { + from.db = "*"; + varFrom(info, from, newBlock); + } +} + +void Mapping::Cache::varFrom(AuthReader::Info& info, Map from, AuthWriter& newBlock) +{ + NoCaseString originalUserName = from.from; + search(info, from, newBlock, originalUserName); + from.from = "*"; + search(info, from, newBlock, originalUserName); +} + +void Mapping::Cache::varUsing(AuthReader::Info& info, Map from, AuthWriter& newBlock) +{ + if (from.usng == 'P') + { + varPlugin(info, from, newBlock); + + from.usng = '*'; + varPlugin(info, from, newBlock); + + if (!info.secDb.hasData()) { + from.usng = 'S'; from.plugin = "*"; varDb(info, from, newBlock); } } - - void varDb(AuthReader::Info& info, Map from, AuthWriter& newBlock) + else if (from.usng == 'M') { - varFrom(info, from, newBlock); - if (from.db != "*") - { - from.db = "*"; - varFrom(info, from, newBlock); - } + varDb(info, from, newBlock); + + from.usng = '*'; + varDb(info, from, newBlock); } + else + fb_assert(false); +} - void varFrom(AuthReader::Info& info, Map from, AuthWriter& newBlock) +bool Mapping::Cache::map4(bool flagWild, unsigned flagSet, AuthReader& rdr, AuthReader::Info& info, AuthWriter& newBlock) +{ + if (!flagSet) { - NoCaseString originalUserName = from.from; - search(info, from, newBlock, originalUserName); - from.from = "*"; - search(info, from, newBlock, originalUserName); - } + AuthWriter workBlock; - void varUsing(AuthReader::Info& info, Map from, AuthWriter& newBlock) - { - if (from.usng == 'P') + for (rdr.rewind(); rdr.getInfo(info); rdr.moveNext()) { - varPlugin(info, from, newBlock); - - from.usng = '*'; - varPlugin(info, from, newBlock); - - if (!info.secDb.hasData()) - { - from.usng = 'S'; - from.plugin = "*"; - varDb(info, from, newBlock); - } - } - else if (from.usng == 'M') - { - varDb(info, from, newBlock); - - from.usng = '*'; - varDb(info, from, newBlock); - } - else - fb_assert(false); - } - - bool map4(bool flagWild, unsigned flagSet, AuthReader& rdr, AuthReader::Info& info, AuthWriter& newBlock) - { - if (!flagSet) - { - AuthWriter workBlock; - - for (rdr.rewind(); rdr.getInfo(info); rdr.moveNext()) - { - map(flagWild, info, workBlock); - } - - info.found |= info.current; - info.current = 0; - newBlock.append(workBlock); + map(flagWild, info, workBlock); } - unsigned mapMask = FLAG_USER | FLAG_ROLE; - return (info.found & mapMask) == mapMask; + info.found |= info.current; + info.current = 0; + newBlock.append(workBlock); } - static void eraseEntry(Map* m) - { - delete m; - } + unsigned mapMask = FLAG_USER | FLAG_ROLE; + return (info.found & mapMask) == mapMask; +} - void makeEmpty() - { - if (!dataFlag) - return; +void Mapping::Cache::eraseEntry(Map* m) +{ + delete m; +} - dataFlag = false; - cleanup(eraseEntry); - } -public: - SyncObject syncObject; - NoCaseString alias, name; - bool dataFlag, downFlag; -}; +namespace +{ -typedef GenericMap > > CacheTree; +typedef GenericMap > > > CacheTree; InitInstance tree; GlobalPtr treeMutex; void setupIpc(); -Cache* locate(const NoCaseString& target) +void locate(RefPtr& cache, const NoCaseString& alias, const NoCaseString& target) { fb_assert(treeMutex->locked()); - Cache* c; - return tree().get(target, c) ? c : NULL; -} - -Cache* locate(const NoCaseString& alias, const NoCaseString& target) -{ - fb_assert(treeMutex->locked()); - Cache* c = locate(target); - if (!c) + fb_assert(!cache); + tree().get(target, cache); + if (!cache) { - c = FB_NEW Cache(alias, target); - *(tree().put(target)) = c; + cache = FB_NEW Mapping::Cache(alias, target); + *(tree().put(target)) = cache; setupIpc(); } - return c; } class Found @@ -550,18 +593,7 @@ public: void resetMap(const char* securityDb) { MutexLockGuard g(treeMutex, FB_FUNCTION); - - Cache* cache = locate(securityDb); - if (!cache) - { - MAP_DEBUG(fprintf(stderr, "Cache not found for %s\n", securityDb)); - return; - } - - Sync sync(&cache->syncObject, FB_FUNCTION); - sync.lock(SYNC_EXCLUSIVE); - cache->makeEmpty(); - MAP_DEBUG(fprintf(stderr, "Empty cache for %s\n", securityDb)); + tree().remove(securityDb); } void resetMap(const char* securityDb, ULONG index); @@ -642,13 +674,13 @@ public: sharedMemory->removeMapFile(); } - sharedMemory = NULL; + sharedMemory = nullptr; } void clearCache(const char* dbName, USHORT index) { PathName target; - expandDatabaseName(dbName, target, NULL); + expandDatabaseName(dbName, target, nullptr); setup(); @@ -746,7 +778,7 @@ public: { if (!(sMem->process[process].flags & MappingHeader::FLAG_ACTIVE)) break; - if (!ISC_check_process_existence(processId)) + if (!ISC_check_process_existence(sMem->process[process].id)) { sharedMemory->eventFini(&sMem->process[process].notifyEvent); sharedMemory->eventFini(&sMem->process[process].callbackEvent); @@ -832,7 +864,7 @@ private: } catch (const Exception& ex) { - exceptionHandler(ex, NULL); + exceptionHandler(ex, nullptr); } } @@ -907,70 +939,6 @@ void setupIpc() mappingIpc->setup(); } -class DbHandle : public AutoPtr > -{ -public: - DbHandle() - : AutoPtr() - { } - - DbHandle(IAttachment* att) - : AutoPtr(att) - { - if (att) - { - MAP_DEBUG(fprintf(stderr, "Using existing db handle %p\n", att)); - att->addRef(); - } - } - - bool attach(FbLocalStatus& st, const char* aliasDb, ICryptKeyCallback* cryptCb) - { - bool down = false; // true if on attach db is shutdown - - if (hasData()) - { - MAP_DEBUG(fprintf(stderr, "Already attached %s\n", aliasDb)); - return down; - } - - DispatcherPtr prov; - if (cryptCb) - { - prov->setDbCryptCallback(&st, cryptCb); - check("IProvider::setDbCryptCallback", &st); - } - - ClumpletWriter embeddedSysdba(ClumpletWriter::Tagged, 1024, isc_dpb_version1); - embeddedSysdba.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME)); - embeddedSysdba.insertByte(isc_dpb_sec_attach, TRUE); - embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE); - embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE); - - MAP_DEBUG(fprintf(stderr, "Attach %s\n", aliasDb)); - IAttachment* att = prov->attachDatabase(&st, aliasDb, - embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer()); - - if (st->getState() & IStatus::STATE_ERRORS) - { - const ISC_STATUS* s = st->getErrors(); - MAP_DEBUG(isc_print_status(s)); - bool missing = fb_utils::containsErrorCode(s, isc_io_error); - down = fb_utils::containsErrorCode(s, isc_shutdown); - if (!(missing || down)) - check("IProvider::attachDatabase", &st); - - // down/missing security DB is not a reason to fail mapping - } - else - reset(att); - MAP_DEBUG(fprintf(stderr, "Att=%p\n", att)); - - return down; - } -}; - - const char* roleSql = "with recursive role_tree as ( " " select rdb$role_name as nm from rdb$roles " @@ -1008,14 +976,14 @@ public: return &sync; } - bool getPrivileges(const PathName& db, const string& name, const string& sql_role, + bool getPrivileges(const PathName& db, const string& name, const string* sqlRole, const string& trusted_role, UserId::Privileges& system_privileges) { DbCache* c; - return databases.get(db, c) && c->getPrivileges(name, sql_role, trusted_role, system_privileges); + return databases.get(db, c) && c->getPrivileges(name, sqlRole, trusted_role, system_privileges); } - void populate(const PathName& db, DbHandle& iDb, const string& name, const string& sql_role, + void populate(const PathName& db, Mapping::DbHandle& iDb, const string& name, const string* sqlRole, const string& trusted_role) { DbCache* c; @@ -1024,7 +992,7 @@ public: c = FB_NEW_POOL(getPool()) DbCache(getPool()); *(databases.put(db)) = c; } - c->populate(iDb, name, sql_role, trusted_role); + c->populate(iDb, name, sqlRole, trusted_role); setupIpc(); } @@ -1046,7 +1014,7 @@ private: pairs(p) { } - bool getPrivileges(const string& name, const string& sql_role, const string& trusted_role, + bool getPrivileges(const string& name, const string* sqlRole, const string& trusted_role, UserId::Privileges& system_privileges) { system_privileges.clearAll(); @@ -1056,20 +1024,21 @@ private: MAP_DEBUG(fprintf(stderr, "name=%s\n", name.c_str())); bool granted = false; - if (!pairs.isRoleGranted(name, sql_role, granted)) + if (!pairs.isRoleGranted(name, sqlRole, granted)) return false; MAP_DEBUG(fprintf(stderr, "granted=%d\n", granted)); - return roles.getPrivileges((granted ? sql_role : trusted_role), system_privileges); + return roles.getPrivileges((granted ? *sqlRole : trusted_role), system_privileges); } - void populate(DbHandle& iDb, const string& name, const string& sql_role, + void populate(Mapping::DbHandle& iDb, const string& name, const string* sqlRole, const string& trusted_role) { logins.populate(name, iDb); roles.populate(trusted_role, iDb); - roles.populate(sql_role, iDb); - pairs.populate(name, sql_role, iDb); + if (sqlRole) + roles.populate(*sqlRole, iDb); + pairs.populate(name, sqlRole, iDb); } void invalidate() @@ -1101,7 +1070,7 @@ private: return true; } - void populate(const string& key, DbHandle& iDb) + void populate(const string& key, Mapping::DbHandle& iDb) { if (!key.hasData()) return; @@ -1110,14 +1079,14 @@ private: return; ThrowLocalStatus st; - RefPtr tra(REF_NO_INCR, iDb->startTransaction(&st, 0, NULL)); + RefPtr tra(REF_NO_INCR, iDb->startTransaction(&st, 0, nullptr)); Message par; Field user(par, MAX_SQL_IDENTIFIER_SIZE); user = key.c_str(); RefPtr curs(REF_NO_INCR, iDb->openCursor(&st, tra, 0, sql, 3, - par.getMetadata(), par.getBuffer(), NULL, NULL, 0)); + par.getMetadata(), par.getBuffer(), nullptr, nullptr, 0)); RefPtr meta(curs->getMetadata(&st)); AutoPtr > buffer(FB_NEW UCHAR[meta->getMessageLength(&st)]); @@ -1153,9 +1122,9 @@ private: : GenericMap(p) { } - bool isRoleGranted(const string& name, const string& role, bool& granted) + bool isRoleGranted(const string& name, const string* role, bool& granted) { - if (!(name.hasData() && role.hasData())) + if (!(name.hasData() && role)) { granted = false; return true; @@ -1167,23 +1136,23 @@ private: string zRole; zRole += ROLESEP; - zRole += role; + zRole += *role; zRole += ROLESEP; - MAP_DEBUG(fprintf(stderr, "isRoleGranted '%s' '%s'\n", r->c_str(), role.c_str())); + MAP_DEBUG(fprintf(stderr, "isRoleGranted '%s' '%s'\n", r->c_str(), role->c_str())); granted = r->find(zRole) != string::npos; return true; } - void populate(const string& name, const string& /*role*/, DbHandle& iDb) + void populate(const string& name, const string* /*role*/, Mapping::DbHandle& iDb) { MAP_DEBUG(fprintf(stderr, "populate %s\n", name.c_str())); if (!name.hasData()) return; ThrowLocalStatus st; - RefPtr tra(REF_NO_INCR, iDb->startTransaction(&st, 0, NULL)); + RefPtr tra(REF_NO_INCR, iDb->startTransaction(&st, 0, nullptr)); Message par; Field user(par, MAX_SQL_IDENTIFIER_SIZE); @@ -1196,7 +1165,7 @@ private: "where RDB$USER = ? and RDB$PRIVILEGE = 'M' and RDB$USER_TYPE = 8 and RDB$OBJECT_TYPE = 13"; RefPtr curs(REF_NO_INCR, iDb->openCursor(&st, tra, 0, sql, 3, - par.getMetadata(), par.getBuffer(), cols.getMetadata(), NULL, 0)); + par.getMetadata(), par.getBuffer(), cols.getMetadata(), nullptr, 0)); void* buffer = cols.getBuffer(); string z; @@ -1234,11 +1203,11 @@ void resetMap(const char* db, ULONG index) { switch(index) { - case MAPPING_CACHE: + case Mapping::MAPPING_CACHE: resetMap(db); break; - case SYSTEM_PRIVILEGES_CACHE: + case Mapping::SYSTEM_PRIVILEGES_CACHE: spCache().invalidate(db); break; @@ -1252,177 +1221,249 @@ void resetMap(const char* db, ULONG index) namespace Jrd { -ULONG mapUser(const bool throwNotFoundError, - string& name, string& trusted_role, Firebird::string* auth_method, - AuthReader::AuthBlock* newAuthBlock, UserId::Privileges* system_privileges, - const AuthReader::AuthBlock& authBlock, const char* alias, const char* db, - const char* securityAlias, const string& sql_role, - ICryptKeyCallback* cryptCb, Firebird::IAttachment* att) +Mapping::Mapping(const ULONG f, Firebird::ICryptKeyCallback* cryptCb) + : flags(f), + internalFlags(0), + cryptCallback(cryptCb), + authMethod(nullptr), + newAuthBlock(nullptr), + systemPrivileges(nullptr), + authBlock(nullptr), + mainAlias(nullptr), + mainDb(nullptr), + securityAlias(nullptr), + errorMessagesContext(nullptr), + sqlRole(nullptr) +{ } + +bool Mapping::ensureCachePresence(RefPtr& cache, const char* alias, const char* target, + Mapping::DbHandle& hdb, ICryptKeyCallback* cryptCb, Mapping::Cache* c2) +{ + fb_assert(!cache); + fb_assert(authBlock); + + if (!(authBlock && authBlock->hasData())) + return false; + + MutexEnsureUnlock g(treeMutex, FB_FUNCTION); + g.enter(); + + // Find cache in the tree or create new one + locate(cache, alias, target); + fb_assert(cache); + + // If we use self security database no sense performing checks on it twice + if (cache == c2) + { + cache = nullptr; + return false; + } + + // Required cache(s) are locked somehow - release treeMutex + g.leave(); + + // Std safe check for data presence in cache + if (cache->dataFlag) + return false; + MutexLockGuard g2(cache->populateMutex, FB_FUNCTION); + if (cache->dataFlag) + return false; + + // Create db attachment if missing it and populate cache from it + bool down = hdb.attach(alias, cryptCb) || cache->populate(hdb); + if (down) + cache = nullptr; + return down; +} + + +void Mapping::needAuthMethod(Firebird::string& method) +{ + fb_assert(!authMethod); + authMethod = &method; +} + +void Mapping::needAuthBlock(Firebird::AuthReader::AuthBlock& block) +{ + fb_assert(!newAuthBlock); + newAuthBlock = █ +} + +void Mapping::needSystemPrivileges(UserId::Privileges& privileges) +{ + fb_assert(!systemPrivileges); + systemPrivileges = &privileges; +} + +void Mapping::setAuthBlock(const Firebird::AuthReader::AuthBlock& block) +{ + fb_assert(!authBlock); + authBlock = █ +} + +void Mapping::setInternalFlags() +{ + internalFlags &= ~(FLAG_DB | FLAG_SEC); + + if (!mainDb) + internalFlags |= FLAG_DB; + if (!securityAlias) + internalFlags |= FLAG_SEC; + + // detect presence of this databases mapping in authBlock + // in that case mapUser was already invoked for it + if (authBlock) + { + AuthReader::Info info; + for (AuthReader rdr(*authBlock); rdr.getInfo(info); rdr.moveNext()) + { + if (mainDb && info.secDb == mainDb) + internalFlags |= FLAG_DB; + if (securityAlias && info.secDb == secExpanded.c_str()) + internalFlags |= FLAG_SEC; + } + } +} + +void Mapping::setSqlRole(const Firebird::string& role) +{ + fb_assert(!sqlRole); + sqlRole = &role; +} + +void Mapping::setDb(const char* a, const char* d, Firebird::IAttachment* attachment) +{ + fb_assert(!mainAlias); + fb_assert(!mainDb); + fb_assert(!mainHandle); + fb_assert(authBlock); + + mainAlias = a; + mainDb = d; + mainHandle.setAttachment(attachment); + setInternalFlags(); + + if ((!(internalFlags & FLAG_DB)) && + ensureCachePresence(dbCache, mainAlias, mainDb, mainHandle, cryptCallback, secCache)) + { + internalFlags |= FLAG_DOWN_DB; + } +} + +void Mapping::clearMainHandle() +{ + mainHandle.clear(); +} + +Mapping::~Mapping() +{ + MAP_DEBUG(if (mainHandle) {mainHandle->addRef(); int r = mainHandle->release();) + MAP_DEBUG(fprintf(stderr, "~M:Drop MH with refcount %d\n", r);} else fprintf(stderr, "~M:No MH\n");) +} + +void Mapping::setSecurityDbAlias(const char* a, const char* mainExpandedName) +{ + fb_assert(!securityAlias); + fb_assert(authBlock); + + securityAlias = a; + expandDatabaseName(securityAlias, secExpanded, nullptr); + setInternalFlags(); + + if (mainExpandedName && secExpanded == mainExpandedName) + return; + + Mapping::DbHandle secHandle; + if ((!(internalFlags & FLAG_SEC)) && + ensureCachePresence(secCache, securityAlias, secExpanded.c_str(), secHandle, cryptCallback, dbCache)) + { + internalFlags |= FLAG_DOWN_SEC; + } +} + +void Mapping::setErrorMessagesContextName(const char* context) +{ + errorMessagesContext = context; +} + + +ULONG Mapping::mapUser(string& name, string& trustedRole) { AuthReader::Info info; - if (!securityAlias) + if (flags & MAP_ERROR_HANDLER) { // We are in the error handler - perform minimum processing - trusted_role = ""; + trustedRole = ""; name = ""; - for (AuthReader rdr(authBlock); rdr.getInfo(info); rdr.moveNext()) + if (authBlock) { - if (info.type == NM_USER && info.name.hasData()) + for (AuthReader rdr(*authBlock); rdr.getInfo(info); rdr.moveNext()) { - name = info.name.ToString(); - break; + if (info.type == NM_USER && info.name.hasData()) + { + name = info.name.ToString(); + break; + } } } return 0; } - // expand security database name (db is expected to be expanded, alias - original) - PathName secExpanded; - expandDatabaseName(securityAlias, secExpanded, NULL); - const char* securityDb = secExpanded.c_str(); - bool secDown = false; - bool dbDown = false; - DbHandle iDb(att); - FbLocalStatus st; - // Create new writer AuthWriter newBlock; - // detect presence of this databases mapping in authBlock - // in that case mapUser was already invoked for it - unsigned flags = db ? 0 : FLAG_DB; - for (AuthReader rdr(authBlock); rdr.getInfo(info); rdr.moveNext()) - { - if (db && info.secDb == db) - flags |= FLAG_DB; - if (info.secDb == securityDb) - flags |= FLAG_SEC; - } - - // Perform lock & map only when needed - if ((flags != (FLAG_DB | FLAG_SEC)) && authBlock.hasData()) + // Map it only when needed + if (authBlock && authBlock->hasData() && (dbCache || secCache)) { AuthReader::Info info; - SyncType syncType = SYNC_SHARED; - DbHandle iSec; - for (;;) + // Caches are ready somehow - proceed with analysis + AuthReader auth(*authBlock); + + // Map in simple mode first main, next security db + if (!(dbCache && dbCache->map4(false, internalFlags & FLAG_DB, auth, info, newBlock))) { - if (syncType == SYNC_EXCLUSIVE) + if (!(secCache && secCache->map4(false, internalFlags & FLAG_SEC, auth, info, newBlock))) { - if (!iSec) - iSec.attach(st, securityAlias, cryptCb); - - if (db && !iDb) - iDb.attach(st, alias, cryptCb); - } - - MutexEnsureUnlock g(treeMutex, FB_FUNCTION); - g.enter(); - - Cache* cDb = NULL; - if (db) - cDb = locate(alias, db); - Cache* cSec = locate(securityAlias, securityDb); - if (cDb == cSec) - cDb = NULL; - - SyncObject dummySync1, dummySync2; - Sync sDb(((!(flags & FLAG_DB)) && cDb) ? &cDb->syncObject : &dummySync1, FB_FUNCTION); - Sync sSec((!(flags & FLAG_SEC)) ? &cSec->syncObject : &dummySync2, FB_FUNCTION); - - sSec.lock(syncType); - if (!sDb.lockConditional(syncType)) - { - // Avoid deadlocks cause hell knows which db is security for which - sSec.unlock(); - // Now safely wait for sSec - sDb.lock(syncType); - // and repeat whole operation - continue; - } - - // Required cache(s) are locked somehow - release treeMutex - g.leave(); - - // Check is it required to populate caches from DB - if ((cDb && !cDb->dataFlag) || !cSec->dataFlag) - { - if (syncType != SYNC_EXCLUSIVE) + // Map in wildcard mode first main, next security db + if (!(dbCache && dbCache->map4(true, internalFlags & FLAG_DB, auth, info, newBlock))) { - syncType = SYNC_EXCLUSIVE; - sSec.unlock(); - sDb.unlock(); - - continue; + if (secCache) + secCache->map4(true, internalFlags & FLAG_SEC, auth, info, newBlock); } - - if (cDb) - { - MAP_DEBUG(fprintf(stderr, "Populate cache for main DB %p\n", iDb.get())); - cDb->populate(iDb, dbDown); - } - - MAP_DEBUG(fprintf(stderr, "Populate cache for sec DB %p\n", iSec.get())); - - cSec->populate(iSec, secDown); - - sSec.downgrade(SYNC_SHARED); - sDb.downgrade(SYNC_SHARED); } - - // use down flags from caches - if (cDb) - dbDown = cDb->downFlag; - secDown = cSec->downFlag; - - // Caches are ready somehow - proceed with analysis - AuthReader auth(authBlock); - - // Map in simple mode first main, next security db - if (cDb && cDb->map4(false, flags & FLAG_DB, auth, info, newBlock)) - break; - if (cSec->map4(false, flags & FLAG_SEC, auth, info, newBlock)) - break; - - // Map in wildcard mode first main, next security db - if (cDb && cDb->map4(true, flags & FLAG_DB, auth, info, newBlock)) - break; - cSec->map4(true, flags & FLAG_SEC, auth, info, newBlock); - - break; - } - - for (AuthReader rdr(newBlock); rdr.getInfo(info); rdr.moveNext()) - { - if (db && info.secDb == db) - flags |= FLAG_DB; - if (info.secDb == securityDb) - flags |= FLAG_SEC; - } - - // mark both DBs as 'seen' - info.plugin = ""; - info.name = ""; - info.type = TYPE_SEEN; - - if (!(flags & FLAG_DB)) - { - info.secDb = db; - newBlock.add(info); - } - - if (!(flags & FLAG_SEC)) - { - info.secDb = securityDb; - newBlock.add(info); } } - newBlock.append(authBlock); + for (AuthReader rdr(newBlock); rdr.getInfo(info); rdr.moveNext()) + { + if (mainDb && info.secDb == mainDb) + internalFlags |= FLAG_DB; + if (info.secDb == secExpanded.c_str()) + internalFlags |= FLAG_SEC; + } + + // mark both DBs as 'seen' + info.plugin = ""; + info.name = ""; + info.type = TYPE_SEEN; + + if (!(internalFlags & FLAG_DB)) + { + info.secDb = mainDb; + newBlock.add(info); + } + + if (!(internalFlags & FLAG_SEC)) + { + info.secDb = secExpanded.c_str(); + newBlock.add(info); + } + + newBlock.append(*authBlock); Found fName, fRole; MAP_DEBUG(fprintf(stderr, "Starting newblock scan\n")); @@ -1432,8 +1473,8 @@ ULONG mapUser(const bool throwNotFoundError, info.secDb.c_str(), info.plugin.c_str(), info.type.c_str(), info.name.c_str(), info.origPlug.c_str())); Found::What recordWeight = - (db && info.secDb == db) ? Found::FND_DB : - (info.secDb == securityDb) ? Found::FND_SEC : + (mainDb && info.secDb == mainDb) ? Found::FND_DB : + (securityAlias && info.secDb == secExpanded.c_str()) ? Found::FND_SEC : Found::FND_NOTHING; if (recordWeight != Found::FND_NOTHING) @@ -1445,26 +1486,26 @@ ULONG mapUser(const bool throwNotFoundError, } } - ULONG rc = secDown || dbDown ? MAPUSER_MAP_DOWN : 0; + ULONG rc = (internalFlags & (FLAG_DOWN_DB | FLAG_DOWN_SEC)) ? MAP_DOWN : 0; if (fName.found == Found::FND_NOTHING) { - if (throwNotFoundError) + if (flags & MAP_THROW_NOT_FOUND) { Arg::Gds v(isc_sec_context); - v << alias; - if (rc & MAPUSER_MAP_DOWN) + v << (errorMessagesContext ? errorMessagesContext : mainAlias ? mainAlias : ""); + if (rc & MAP_DOWN) v << Arg::Gds(isc_map_down); v.raise(); } - rc |= MAPUSER_ERROR_NOT_THROWN; + rc |= MAP_ERROR_NOT_THROWN; } else { name = fName.value.ToString(); - trusted_role = fRole.value.ToString(); - MAP_DEBUG(fprintf(stderr, "login=%s tr=%s\n", name.c_str(), trusted_role.c_str())); - if (auth_method) - *auth_method = fName.method.ToString(); + trustedRole = fRole.value.ToString(); + MAP_DEBUG(fprintf(stderr, "login=%s tr=%s\n", name.c_str(), trustedRole.c_str())); + if (authMethod) + *authMethod = fName.method.ToString(); if (newAuthBlock) { @@ -1475,32 +1516,31 @@ ULONG mapUser(const bool throwNotFoundError, } } - if (name.hasData() || trusted_role.hasData()) + if (name.hasData() || trustedRole.hasData()) { - if (system_privileges && db) + if (systemPrivileges && mainDb) { - system_privileges->clearAll(); + systemPrivileges->clearAll(); Sync sync(spCache().getSync(), FB_FUNCTION); sync.lock(SYNC_SHARED); MAP_DEBUG(fprintf(stderr, "GP: name=%s sql=%s trusted=%s\n", - name.c_str(), sql_role.c_str(), trusted_role.c_str())); + name.c_str(), sqlRole ? sqlRole->c_str() : "", trustedRole.c_str())); - if (!spCache().getPrivileges(db, name, sql_role, trusted_role, *system_privileges)) + if (!spCache().getPrivileges(mainDb, name, sqlRole, trustedRole, *systemPrivileges)) { sync.unlock(); sync.lock(SYNC_EXCLUSIVE); - if (!spCache().getPrivileges(db, name, sql_role, trusted_role, *system_privileges)) + if (!spCache().getPrivileges(mainDb, name, sqlRole, trustedRole, *systemPrivileges)) { - if (!iDb) - iDb.attach(st, alias, cryptCb); + mainHandle.attach(mainAlias, cryptCallback); - if (iDb) + if (mainHandle) { - spCache().populate(db, iDb, name, sql_role, trusted_role); - spCache().getPrivileges(db, name, sql_role, trusted_role, *system_privileges); + spCache().populate(mainDb, mainHandle, name, sqlRole, trustedRole); + spCache().getPrivileges(mainDb, name, sqlRole, trustedRole, *systemPrivileges); } } } @@ -1510,11 +1550,12 @@ ULONG mapUser(const bool throwNotFoundError, return rc; } -void clearMappingCache(const char* dbName, USHORT index) +void Mapping::clearCache(const char* dbName, USHORT index) { mappingIpc->clearCache(dbName, index); } + const Format* GlobalMappingScan::getFormat(thread_db* tdbb, jrd_rel* relation) const { jrd_tra* const transaction = tdbb->getTransaction(); @@ -1552,17 +1593,16 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation) FbLocalStatus st; DispatcherPtr prov; - IAttachment* att = NULL; - ITransaction* tra = NULL; - IResultSet* curs = NULL; + IAttachment* att = nullptr; + ITransaction* tra = nullptr; + IResultSet* curs = nullptr; try { - ClumpletWriter embeddedSysdba(ClumpletWriter::Tagged, - MAX_DPB_SIZE, isc_dpb_version1); - embeddedSysdba.insertString(isc_dpb_user_name, DBA_USER_NAME, - fb_strlen(DBA_USER_NAME)); + ClumpletWriter embeddedSysdba(ClumpletWriter::Tagged, MAX_DPB_SIZE, isc_dpb_version1); + embeddedSysdba.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME)); embeddedSysdba.insertByte(isc_dpb_sec_attach, TRUE); + embeddedSysdba.insertString(isc_dpb_config, EMBEDDED_PROVIDERS, fb_strlen(EMBEDDED_PROVIDERS)); embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE); const char* dbName = tdbb->getDatabase()->dbb_config->getSecurityDatabase(); @@ -1600,7 +1640,7 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation) "SELECT RDB$MAP_NAME, RDB$MAP_USING, RDB$MAP_PLUGIN, RDB$MAP_DB, " " RDB$MAP_FROM_TYPE, RDB$MAP_FROM, RDB$MAP_TO_TYPE, RDB$MAP_TO " "FROM RDB$AUTH_MAPPING", - 3, NULL, NULL, mMap.getMetadata(), NULL, 0); + 3, nullptr, nullptr, mMap.getMetadata(), nullptr, 0); if (st->getState() & IStatus::STATE_ERRORS) { if (!fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err)) @@ -1674,15 +1714,15 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation) curs->close(&st); check("IResultSet::close", &st); - curs = NULL; + curs = nullptr; tra->rollback(&st); check("ITransaction::rollback", &st); - tra = NULL; + tra = nullptr; att->detach(&st); check("IAttachment::detach", &st); - att = NULL; + att = nullptr; } catch (const Exception&) { @@ -1700,7 +1740,7 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation) return getData(relation); } -void shutdownMappingIpc() +void Mapping::shutdownIpc() { mappingIpc->shutdown(); } diff --git a/src/jrd/Mapping.h b/src/jrd/Mapping.h index 1838da6ba9..7c3f2aeca1 100644 --- a/src/jrd/Mapping.h +++ b/src/jrd/Mapping.h @@ -31,29 +31,137 @@ #include "../common/classes/alloc.h" #include "../common/classes/fb_string.h" -#include "../common/classes/ClumpletReader.h" +#include "../common/classes/ClumpletWriter.h" +#include "../common/classes/Hash.h" +#include "../common/classes/GenericMap.h" #include "../jrd/recsrc/RecordSource.h" #include "../jrd/Monitoring.h" #include "../jrd/scl.h" namespace Jrd { -ULONG mapUser(const bool throwNotFoundError, - Firebird::string& name, Firebird::string& trusted_role, Firebird::string* auth_method, - Firebird::AuthReader::AuthBlock* newAuthBlock, UserId::Privileges* system_privileges, - const Firebird::AuthReader::AuthBlock& authBlock, const char* alias, const char* db, - const char* securityDb, const Firebird::string& sql_role, - Firebird::ICryptKeyCallback* cryptCb, Firebird::IAttachment* att); -// bits returned by mapUser -const ULONG MAPUSER_ERROR_NOT_THROWN = 1; -const ULONG MAPUSER_MAP_DOWN = 2; +class AuthWriter; -void clearMappingCache(const char* dbName, USHORT index); -// possible index values -const USHORT MAPPING_CACHE = 0; -const USHORT SYSTEM_PRIVILEGES_CACHE = 1; +class Mapping +{ +public: + // constructor's flags + static const ULONG MAP_NO_FLAGS = 0; + static const ULONG MAP_THROW_NOT_FOUND = 1; + static const ULONG MAP_ERROR_HANDLER = 2; + Mapping(const ULONG flags, Firebird::ICryptKeyCallback* cryptCb); -void shutdownMappingIpc(); + ~Mapping(); + + // First provide the main input information - old auth block ... + void setAuthBlock(const Firebird::AuthReader::AuthBlock& authBlock); + + // ... and finally specify additional information when available. + void setSqlRole(const Firebird::string& sqlRole); + void setDb(const char* alias, const char* db, Firebird::IAttachment* att); + void setSecurityDbAlias(const char* alias, const char* mainExpandedName); + void setErrorMessagesContextName(const char* context); + + // This should be done before mapUser(). + void needAuthMethod(Firebird::string& authMethod); + void needAuthBlock(Firebird::AuthReader::AuthBlock& newAuthBlock); + void needSystemPrivileges(UserId::Privileges& systemPrivileges); + + // bits returned by mapUser + static const ULONG MAP_ERROR_NOT_THROWN = 1; + static const ULONG MAP_DOWN = 2; + // Now mapper is ready to perform main task and provide mapped login and trusted role. + ULONG mapUser(Firebird::string& name, Firebird::string& trustedRole); + + // Do not keep mainHandle opened longer than needed + void clearMainHandle(); + + // possible clearCache() flags + static const USHORT MAPPING_CACHE = 0; + static const USHORT SYSTEM_PRIVILEGES_CACHE = 1; + // Helper statuc functions to perform cleanup & shutdown. + static void clearCache(const char* dbName, USHORT id); + static void shutdownIpc(); + +private: + const ULONG flags; + ULONG internalFlags; + Firebird::ICryptKeyCallback* cryptCallback; + Firebird::string* authMethod; + Firebird::AuthReader::AuthBlock* newAuthBlock; + UserId::Privileges* systemPrivileges; + const Firebird::AuthReader::AuthBlock* authBlock; + const char* mainAlias; + const char* mainDb; + const char* securityAlias; + const char* errorMessagesContext; + const Firebird::string* sqlRole; + +public: + class DbHandle : public Firebird::RefPtr + { + public: + DbHandle(); + void setAttachment(Firebird::IAttachment* att); + void clear(); + bool attach(const char* aliasDb, Firebird::ICryptKeyCallback* cryptCb); + }; + + class Map; + typedef Firebird::HashTable, Map> MapHash; + + class Map : public MapHash::Entry, public Firebird::GlobalStorage + { + public: + Map(const char* aUsing, const char* aPlugin, const char* aDb, + const char* aFromType, const char* aFrom, + SSHORT aRole, const char* aTo); + explicit Map(Firebird::AuthReader::Info& info); //type, name, plugin, secDb + + static FB_SIZE_T hash(const Map& value, FB_SIZE_T hashSize); + Firebird::NoCaseString makeHashKey() const; + void trimAll(); + virtual bool isEqual(const Map& k) const; + virtual Map* get(); + + Firebird::NoCaseString plugin, db, fromType, from, to; + bool toRole; + char usng; + }; + + class Cache : public MapHash, public Firebird::GlobalStorage, public Firebird::RefCounted + { + public: + Cache(const Firebird::NoCaseString& aliasDb, const Firebird::NoCaseString& db); + ~Cache(); + + bool populate(Firebird::IAttachment *att); + void map(bool flagWild, Firebird::AuthReader::Info& info, AuthWriter& newBlock); + void search(Firebird::AuthReader::Info& info, const Map& from, AuthWriter& newBlock, + const Firebird::NoCaseString& originalUserName); + void varPlugin(Firebird::AuthReader::Info& info, Map from, AuthWriter& newBlock); + void varDb(Firebird::AuthReader::Info& info, Map from, AuthWriter& newBlock); + void varFrom(Firebird::AuthReader::Info& info, Map from, AuthWriter& newBlock); + void varUsing(Firebird::AuthReader::Info& info, Map from, AuthWriter& newBlock); + bool map4(bool flagWild, unsigned flagSet, Firebird::AuthReader& rdr, + Firebird::AuthReader::Info& info, AuthWriter& newBlock); + static void eraseEntry(Map* m); + + public: + Firebird::Mutex populateMutex; + Firebird::NoCaseString alias, name; + bool dataFlag; + }; + +private: + Firebird::PathName secExpanded; + Firebird::RefPtr dbCache, secCache; + DbHandle mainHandle; + + void setInternalFlags(); + bool ensureCachePresence(Firebird::RefPtr& cache, const char* alias, + const char* target, DbHandle& hdb, Firebird::ICryptKeyCallback* cryptCb, Cache* c2); +}; class GlobalMappingScan: public VirtualTableScan { diff --git a/src/jrd/Optimizer.cpp b/src/jrd/Optimizer.cpp index 149932e1c2..4943fb387a 100644 --- a/src/jrd/Optimizer.cpp +++ b/src/jrd/Optimizer.cpp @@ -70,8 +70,8 @@ bool checkExpressionIndex(const index_desc* idx, ValueExprNode* node, StreamType // so try to recover it (see CORE-4118). while (!idx->idx_expression->sameAs(node, true)) { - DerivedExprNode* const derivedExpr = node->as(); - CastNode* const cast = node->as(); + DerivedExprNode* const derivedExpr = nodeAs(node); + CastNode* const cast = nodeAs(node); if (derivedExpr) node = derivedExpr->arg; @@ -490,7 +490,7 @@ InversionCandidate* OptimizerRetrieval::generateInversion() for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end; tail++) { BoolExprNode* const node = tail->opt_conjunct_node; - BinaryBoolNode* booleanNode = node->as(); + BinaryBoolNode* booleanNode = nodeAs(node); if (!(tail->opt_conjunct_flags & opt_conjunct_used) && node && (!booleanNode || booleanNode->blrOp != blr_or)) @@ -505,7 +505,7 @@ InversionCandidate* OptimizerRetrieval::generateInversion() for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end; tail++) { BoolExprNode* const node = tail->opt_conjunct_node; - BinaryBoolNode* booleanNode = node->as(); + BinaryBoolNode* booleanNode = nodeAs(node); if (!(tail->opt_conjunct_flags & opt_conjunct_used) && node && (booleanNode && booleanNode->blrOp == blr_or)) @@ -566,7 +566,7 @@ InversionCandidate* OptimizerRetrieval::generateInversion() node->computable(csb, stream, true) && !invCandidate->matches.exist(node)) { - const ComparativeBoolNode* const cmpNode = node->as(); + const ComparativeBoolNode* const cmpNode = nodeAs(node); const double factor = (cmpNode && cmpNode->blrOp == blr_eql) ? REDUCE_SELECTIVITY_FACTOR_EQUALITY : REDUCE_SELECTIVITY_FACTOR_INEQUALITY; @@ -716,7 +716,7 @@ void OptimizerRetrieval::analyzeNavigation() break; } } - else if (!(fieldNode = node->as()) || fieldNode->fieldStream != stream) + else if (!(fieldNode = nodeAs(node)) || fieldNode->fieldStream != stream) { usableIndex = false; break; @@ -1029,7 +1029,7 @@ ValueExprNode* OptimizerRetrieval::findDbKey(ValueExprNode* dbkey, SLONG* positi * **************************************/ - const RecordKeyNode* keyNode = dbkey->as(); + const RecordKeyNode* keyNode = nodeAs(dbkey); if (keyNode && keyNode->blrOp == blr_dbkey) { @@ -1040,7 +1040,7 @@ ValueExprNode* OptimizerRetrieval::findDbKey(ValueExprNode* dbkey, SLONG* positi return NULL; } - ConcatenateNode* concatNode = dbkey->as(); + ConcatenateNode* concatNode = nodeAs(dbkey); if (concatNode) { @@ -1652,10 +1652,10 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* if (boolean->nodFlags & ExprNode::FLAG_DEOPTIMIZE) return false; - ComparativeBoolNode* cmpNode = boolean->as(); - MissingBoolNode* missingNode = boolean->as(); - NotBoolNode* notNode = boolean->as(); - RseBoolNode* rseNode = boolean->as(); + ComparativeBoolNode* cmpNode = nodeAs(boolean); + MissingBoolNode* missingNode = nodeAs(boolean); + NotBoolNode* notNode = nodeAs(boolean); + RseBoolNode* rseNode = nodeAs(boolean); bool forward = true; ValueExprNode* value = NULL; ValueExprNode* match = NULL; @@ -1707,7 +1707,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* FieldNode* fieldNode; - if (!(fieldNode = match->as()) || + if (!(fieldNode = nodeAs(match)) || fieldNode->fieldStream != stream || (value && !value->computable(csb, stream, false))) { @@ -1715,7 +1715,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* match = value; value = temp; - if ((!match || !(fieldNode = match->as())) || + if ((!match || !(fieldNode = nodeAs(match))) || fieldNode->fieldStream != stream || !value->computable(csb, stream, false)) { @@ -1778,7 +1778,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* for (int i = 0; i < indexScratch->idx->idx_count; i++) { - FieldNode* fieldNode = match->as(); + FieldNode* fieldNode = nodeAs(match); if (!(indexScratch->idx->idx_flags & idx_expressn)) { @@ -1996,7 +1996,7 @@ InversionCandidate* OptimizerRetrieval::matchDbKey(BoolExprNode* boolean) const **************************************/ // If this isn't an equality, it isn't even interesting - ComparativeBoolNode* cmpNode = boolean->as(); + ComparativeBoolNode* cmpNode = nodeAs(boolean); if (!cmpNode || cmpNode->blrOp != blr_eql) return NULL; @@ -2007,15 +2007,15 @@ InversionCandidate* OptimizerRetrieval::matchDbKey(BoolExprNode* boolean) const ValueExprNode* dbkey = cmpNode->arg1; ValueExprNode* value = cmpNode->arg2; - const RecordKeyNode* keyNode = dbkey->as(); + const RecordKeyNode* keyNode = nodeAs(dbkey); if (!(keyNode && keyNode->blrOp == blr_dbkey && keyNode->recStream == stream) && - !dbkey->is()) + !nodeIs(dbkey)) { - keyNode = value->as(); + keyNode = nodeAs(value); if (!(keyNode && keyNode->blrOp == blr_dbkey && keyNode->recStream == stream) && - !value->is()) + !nodeIs(value)) { return NULL; } @@ -2032,7 +2032,7 @@ InversionCandidate* OptimizerRetrieval::matchDbKey(BoolExprNode* boolean) const // If this is a concatenation, find an appropriate dbkey SLONG n = 0; - if (dbkey->is()) + if (nodeIs(dbkey)) { dbkey = findDbKey(dbkey, &n); if (!dbkey) @@ -2041,7 +2041,7 @@ InversionCandidate* OptimizerRetrieval::matchDbKey(BoolExprNode* boolean) const // Make sure we have the correct stream - keyNode = dbkey->as(); + keyNode = nodeAs(dbkey); if (!keyNode || keyNode->blrOp != blr_dbkey || keyNode->recStream != stream) return NULL; @@ -2083,7 +2083,7 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes( * inversion candidate could be returned. * **************************************/ - BinaryBoolNode* binaryNode = boolean->as(); + BinaryBoolNode* binaryNode = nodeAs(boolean); // Handle the "OR" case up front if (binaryNode && binaryNode->blrOp == blr_or) @@ -2114,7 +2114,7 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes( if (invCandidate1) inversions.add(invCandidate1); - BinaryBoolNode* childBoolNode = binaryNode->arg1->as(); + BinaryBoolNode* childBoolNode = nodeAs(binaryNode->arg1); // Get usable inversions based on indexOrScratches and scope if (!childBoolNode || childBoolNode->blrOp != blr_or) @@ -2144,7 +2144,7 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes( if (invCandidate2) inversions.add(invCandidate2); - childBoolNode = binaryNode->arg2->as(); + childBoolNode = nodeAs(binaryNode->arg2); // Make inversion based on indexOrScratches and scope if (!childBoolNode || childBoolNode->blrOp != blr_or) @@ -2404,7 +2404,7 @@ bool OptimizerRetrieval::validateStarts(IndexScratch* indexScratch, ComparativeB } else { - FieldNode* fieldNode = field->as(); + FieldNode* fieldNode = nodeAs(field); if (!fieldNode) { @@ -2414,7 +2414,7 @@ bool OptimizerRetrieval::validateStarts(IndexScratch* indexScratch, ComparativeB // this must include many matches (think about empty string) return false; /* - if (!value->is()) + if (!nodeIs(value)) return NULL; field = value; value = cmpNode->arg1; @@ -2422,7 +2422,7 @@ bool OptimizerRetrieval::validateStarts(IndexScratch* indexScratch, ComparativeB } // Every string starts with an empty string so don't bother using an index in that case. - LiteralNode* literal = value->as(); + LiteralNode* literal = nodeAs(value); if (literal) { diff --git a/src/jrd/PreparedStatement.cpp b/src/jrd/PreparedStatement.cpp index 3dfd30697a..2b2f06a918 100644 --- a/src/jrd/PreparedStatement.cpp +++ b/src/jrd/PreparedStatement.cpp @@ -99,6 +99,16 @@ namespace item.length = sizeof(double); break; + case dtype_dec64: + item.type = SQL_DEC16; + item.length = sizeof(Decimal64); + break; + + case dtype_dec128: + item.type = SQL_DEC34; + item.length = sizeof(Decimal128); + break; + case dtype_sql_date: item.type = SQL_TYPE_DATE; item.length = sizeof(SLONG); diff --git a/src/jrd/RecordSourceNodes.cpp b/src/jrd/RecordSourceNodes.cpp index 50bcd79230..9ecb738b8d 100644 --- a/src/jrd/RecordSourceNodes.cpp +++ b/src/jrd/RecordSourceNodes.cpp @@ -561,7 +561,7 @@ RecordSourceNode* RelationSourceNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) bool RelationSourceNode::dsqlMatch(const ExprNode* other, bool /*ignoreMapCast*/) const { - const RelationSourceNode* o = other->as(); + const RelationSourceNode* o = nodeAs(other); return o && dsqlContext == o->dsqlContext; } @@ -1029,7 +1029,7 @@ RecordSourceNode* ProcedureSourceNode::dsqlFieldRemapper(FieldRemapper& visitor) bool ProcedureSourceNode::dsqlMatch(const ExprNode* other, bool /*ignoreMapCast*/) const { - const ProcedureSourceNode* o = other->as(); + const ProcedureSourceNode* o = nodeAs(other); return o && dsqlContext == o->dsqlContext; } @@ -1321,7 +1321,7 @@ RecordSourceNode* AggregateSourceNode::dsqlFieldRemapper(FieldRemapper& visitor) bool AggregateSourceNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const { - const AggregateSourceNode* o = other->as(); + const AggregateSourceNode* o = nodeAs(other); return o && dsqlContext == o->dsqlContext && PASS1_node_match(dsqlGroup, o->dsqlGroup, ignoreMapCast) && @@ -1606,7 +1606,7 @@ RecordSource* AggregateSourceNode::generate(thread_db* tdbb, OptimizerBlk* opt, AggNode* aggNode = NULL; if (map->sourceList.getCount() == 1 && (ptr = map->sourceList.begin()) && - (aggNode = (*ptr)->as()) && + (aggNode = nodeAs(*ptr)) && (aggNode->aggInfo.blr == blr_agg_min || aggNode->aggInfo.blr == blr_agg_max)) { // generate a sort block which the optimizer will try to map to an index @@ -1750,15 +1750,15 @@ void UnionSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) ValueExprNode* mapItem = dsqlParentRse->dsqlSelectList->items[0]; // AB: First item could be a virtual field generated by derived table. - DerivedFieldNode* derivedField = mapItem->as(); + DerivedFieldNode* derivedField = nodeAs(mapItem); if (derivedField) mapItem = derivedField->value; - if (mapItem->is()) - mapItem = mapItem->as()->source; + if (nodeIs(mapItem)) + mapItem = nodeAs(mapItem)->source; - DsqlMapNode* mapNode = mapItem->as(); + DsqlMapNode* mapNode = nodeAs(mapItem); fb_assert(mapNode); if (!mapNode) @@ -1780,7 +1780,7 @@ void UnionSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) NestConst* ptr = streams->items.begin(); for (const NestConst* const end = streams->items.end(); ptr != end; ++ptr) { - RseNode* sub_rse = (*ptr)->as(); + RseNode* sub_rse = nodeAs(*ptr); GEN_rse(dsqlScratch, sub_rse); ValueListNode* items = sub_rse->dsqlSelectList; @@ -2506,7 +2506,7 @@ RseNode* RseNode::dsqlFieldRemapper(FieldRemapper& visitor) bool RseNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const { - const RseNode* o = other->as(); + const RseNode* o = nodeAs(other); if (!o) return false; @@ -2611,11 +2611,11 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { const TEXT* name = NULL; - if (auto* aliasNode = item->as()) + if (auto* aliasNode = nodeAs(item)) name = aliasNode->name.c_str(); - else if (auto* fieldNode = item->as()) + else if (auto* fieldNode = nodeAs(item)) name = fieldNode->dsqlField->fld_name.c_str(); - else if (auto* derivedField = item->as()) + else if (auto* derivedField = nodeAs(item)) name = derivedField->name.c_str(); if (name) @@ -2650,7 +2650,7 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) for (FB_SIZE_T i = 0; i < usingList->items.getCount(); ++i) { - const FieldNode* field = usingList->items[i]->as(); + const FieldNode* field = nodeAs(usingList->items[i]); // verify if the column was already used FB_SIZE_T pos; @@ -2710,7 +2710,7 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) ValueListNode* stack = FB_NEW_POOL(getPool()) ValueListNode(getPool(), 0u); NestConst tempNode = impJoinLeft->value; - NestConst aliasNode = tempNode->as(); + NestConst aliasNode = nodeAs(tempNode); NestConst coalesceNode; if (aliasNode) @@ -2719,7 +2719,7 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { // scope PsqlChanger changer(dsqlScratch, false); - if ((coalesceNode = tempNode->as())) + if ((coalesceNode = nodeAs(tempNode))) { ValueListNode* list = coalesceNode->args; @@ -2735,10 +2735,10 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) tempNode = impJoinRight->value; - if ((aliasNode = tempNode->as())) + if ((aliasNode = nodeAs(tempNode))) tempNode = aliasNode->value; - if ((coalesceNode = tempNode->as())) + if ((coalesceNode = nodeAs(tempNode))) { ValueListNode* list = coalesceNode->args; @@ -2836,7 +2836,7 @@ RseNode* RseNode::pass1(thread_db* tdbb, CompilerScratch* csb) for (ExprNode** node = csb->csb_current_nodes.begin(); node != csb->csb_current_nodes.end(); ++node) { - if ((*node)->as()) + if (nodeAs(*node)) { topLevelRse = false; break; @@ -3431,8 +3431,8 @@ RseNode* SelectExprNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* source) { - ProcedureSourceNode* procNode = source->as(); - RelationSourceNode* relNode = source->as(); + ProcedureSourceNode* procNode = nodeAs(source); + RelationSourceNode* relNode = nodeAs(source); fb_assert(procNode || relNode); @@ -3483,7 +3483,7 @@ static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, Recor } RecordSourceNode* const query = cte->querySpec; - UnionSourceNode* unionQuery = ExprNode::as(query); + UnionSourceNode* unionQuery = nodeAs(query); const bool isRecursive = unionQuery && unionQuery->recursive; const string saveCteName = cte->alias; @@ -3576,7 +3576,7 @@ static void processMap(thread_db* tdbb, CompilerScratch* csb, MapNode* map, Form source != sourceEnd; ++source, ++target) { - FieldNode* field = (*target)->as(); + FieldNode* field = nodeAs(*target); const USHORT id = field->fieldId; if (id >= format->fmt_count) @@ -3677,7 +3677,7 @@ static void genDeliverUnmapped(thread_db* tdbb, BoolExprNodeStack* deliverStack, // Handle the "OR" case first - BinaryBoolNode* const binaryNode = boolean->as(); + BinaryBoolNode* const binaryNode = nodeAs(boolean); if (binaryNode && binaryNode->blrOp == blr_or) { BoolExprNodeStack orgStack, newStack; @@ -3708,8 +3708,8 @@ static void genDeliverUnmapped(thread_db* tdbb, BoolExprNodeStack* deliverStack, // Reduce to simple comparisons - ComparativeBoolNode* const cmpNode = boolean->as(); - MissingBoolNode* const missingNode = boolean->as(); + ComparativeBoolNode* const cmpNode = nodeAs(boolean); + MissingBoolNode* const missingNode = nodeAs(boolean); HalfStaticArray children; if (cmpNode && @@ -3732,7 +3732,7 @@ static void genDeliverUnmapped(thread_db* tdbb, BoolExprNodeStack* deliverStack, for (indexArg = 0; (indexArg < children.getCount()) && !mappingFound; ++indexArg) { - FieldNode* fieldNode = children[indexArg]->as(); + FieldNode* fieldNode = nodeAs(children[indexArg]); if (fieldNode && fieldNode->fieldStream == shellStream) mappingFound = true; @@ -3777,7 +3777,7 @@ static void genDeliverUnmapped(thread_db* tdbb, BoolExprNodeStack* deliverStack, // forget to leave aggregate-functions alone in case of aggregate rse). // Because this is only to help using an index we keep it simple. - FieldNode* fieldNode = children[indexArg]->as(); + FieldNode* fieldNode = nodeAs(children[indexArg]); if (fieldNode && fieldNode->fieldStream == shellStream) { @@ -3827,16 +3827,14 @@ static ValueExprNode* resolveUsingField(DsqlCompilerScratch* dsqlScratch, const FieldNode* fieldNode; DerivedFieldNode* derivedField; - if ((aliasNode = ExprNode::as(node))) + if ((aliasNode = nodeAs(node))) ctx = aliasNode->implicitJoin->visibleInContext; - else if ((fieldNode = ExprNode::as(node))) + else if ((fieldNode = nodeAs(node))) ctx = fieldNode->dsqlContext; - else if ((derivedField = ExprNode::as(node))) + else if ((derivedField = nodeAs(node))) ctx = derivedField->context; else - { fb_assert(false); - } return node; } diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index 3a8e93e36a..a72f23bf66 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -76,7 +76,9 @@ enum Function funLPad, funRPad, funLnat, - funLog10 + funLog10, + funTotalOrd, + funCmpDec }; enum TrigonFunction @@ -107,6 +109,8 @@ double fbcot(double value) throw(); // generic setParams functions void setParamsDouble(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); +void setParamsDblDec(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); +void setParamsDecFloat(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsFromList(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsInteger(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsSecondInteger(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); @@ -124,6 +128,8 @@ void setParamsUuidToChar(DataTypeUtilBase* dataTypeUtil, const SysFunction* func // generic make functions void makeDoubleResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); +void makeDblDecResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); +void makeDecFloatResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeFromListResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeInt64Result(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeLongResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); @@ -142,6 +148,7 @@ void makeLeftRight(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, void makeMod(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeOverlay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makePad(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); +void makePi(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeReplace(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeReverse(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeRound(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); @@ -305,6 +312,77 @@ void setParamsDouble(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** } +template +bool areParamsDouble(int argsCount, DSC** args) +{ + bool decSeen = false; + + for (int i = 0; i < argsCount; ++i) + { + if (args[i]->isApprox()) + return true; + if (args[i]->isDecFloat()) + decSeen = true; + } + + return !decSeen; +} + + +bool areParamsDec64(int argsCount, dsc** args) +{ + bool f64 = false; + + for (int i = 0; i < argsCount; ++i) + { + switch (args[i]->dsc_dtype) + { + case dtype_dec64: + f64 = true; + break; + case dtype_dec128: + return false; + } + } + + return f64; +} + + +void setParamsDblDec(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) +{ + bool fDbl = areParamsDouble(argsCount, args); + + for (int i = 0; i < argsCount; ++i) + { + if (args[i]->isUnknown()) + { + if (fDbl) + args[i]->makeDouble(); + else + args[i]->makeDecimal128(); + } + } +} + + +void setParamsDecFloat(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) +{ + bool f64 = areParamsDec64(argsCount, args); + + for (int i = 0; i < argsCount; ++i) + { + if (args[i]->isUnknown()) + { + if (f64) + args[i]->makeDecimal64(); + else + args[i]->makeDecimal128(); + } + } +} + + void setParamsFromList(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args) { @@ -358,7 +436,7 @@ void setParamsDateAdd(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc* if (argsCount >= 1 && args[0]->isUnknown()) { if (args[1]->dsc_address && // constant - CVT_get_long(args[1], 0, ERR_post) == blr_extract_millisecond) + CVT_get_long(args[1], 0, JRD_get_thread_data()->getAttachment()->att_dec_status, ERR_post) == blr_extract_millisecond) { args[0]->makeInt64(ISC_TIME_SECONDS_PRECISION_SCALE + 3); } @@ -490,6 +568,46 @@ void makeDoubleResult(DataTypeUtilBase*, const SysFunction*, dsc* result, } +void makeDblDecResult(DataTypeUtilBase*, const SysFunction*, dsc* result, + int argsCount, const dsc** args) +{ + if (argsCount == 0 || areParamsDouble(argsCount, args)) + result->makeDouble(); + else + result->makeDecimal128(); + + bool isNullable; + if (initResult(result, argsCount, args, &isNullable)) + return; + + result->setNullable(isNullable); +} + + +void makeDecFloatResult(DataTypeUtilBase*, const SysFunction*, dsc* result, + int argsCount, const dsc** args) +{ + if (argsCount == 0 || args[0]->dsc_dtype == dtype_dec128) + result->makeDecimal128(); + else + result->makeDecimal64(); + + bool isNullable; + if (initResult(result, argsCount, args, &isNullable)) + return; + + result->setNullable(isNullable); +} + + +void makePi(DataTypeUtilBase*, const SysFunction*, dsc* result, int, const dsc**) +{ + result->makeDouble(); + result->clearNull(); + result->setNullable(false); +} + + void makeFromListResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args) { @@ -595,6 +713,8 @@ void makeAbs(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* r case dtype_real: case dtype_double: case dtype_int64: + case dtype_dec64: + case dtype_dec128: *result = *value; break; @@ -736,6 +856,11 @@ void makeCeilFloor(DataTypeUtilBase*, const SysFunction* function, dsc* result, result->makeInt64(0); break; + case dtype_dec128: + case dtype_dec64: + result->makeDecimal128(0); + break; + default: result->makeDouble(); break; @@ -908,7 +1033,7 @@ void makePad(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* r if (length->dsc_address) // constant { result->dsc_length = static_cast(sizeof(USHORT)) + dataTypeUtil->fixLength(result, - CVT_get_long(length, 0, ERR_post) * + CVT_get_long(length, 0, JRD_get_thread_data()->getAttachment()->att_dec_status, ERR_post) * dataTypeUtil->maxBytesPerChar(result->getCharSet())); } else @@ -1019,7 +1144,8 @@ void makeRound(DataTypeUtilBase*, const SysFunction* function, dsc* result, return; } - if (value1->isExact() || value1->dsc_dtype == dtype_real || value1->dsc_dtype == dtype_double) + if (value1->isExact() || value1->dsc_dtype == dtype_real || value1->dsc_dtype == dtype_double || + value1->dsc_dtype == dtype_dec64 || value1->dsc_dtype == dtype_dec128) { *result = *value1; if (argsCount == 1) @@ -1111,7 +1237,7 @@ dsc* evlStdMath(thread_db* tdbb, const SysFunction* function, const NestValueArr if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - const double v = MOV_get_double(value); + const double v = MOV_get_double(tdbb, value); double rc; // CVC: Apparently, gcc has built-in inverse hyperbolic functions, but since @@ -1223,10 +1349,18 @@ dsc* evlAbs(thread_db* tdbb, const SysFunction*, const NestValueArray& args, imp impure->vlu_misc.vlu_double = fabs(impure->vlu_misc.vlu_double); break; + case dtype_dec64: + impure->vlu_misc.vlu_dec64 = impure->vlu_misc.vlu_dec64.abs(); + break; + + case dtype_dec128: + impure->vlu_misc.vlu_dec128 = impure->vlu_misc.vlu_dec128.abs(); + break; + case dtype_short: case dtype_long: case dtype_int64: - impure->vlu_misc.vlu_int64 = MOV_get_int64(value, value->dsc_scale); + impure->vlu_misc.vlu_int64 = MOV_get_int64(tdbb, value, value->dsc_scale); if (impure->vlu_misc.vlu_int64 == MIN_SINT64) status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); @@ -1237,7 +1371,7 @@ dsc* evlAbs(thread_db* tdbb, const SysFunction*, const NestValueArray& args, imp break; default: - impure->vlu_misc.vlu_double = fabs(MOV_get_double(&impure->vlu_desc)); + impure->vlu_misc.vlu_double = fabs(MOV_get_double(tdbb, &impure->vlu_desc)); impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); break; } @@ -1257,7 +1391,7 @@ dsc* evlAsciiChar(thread_db* tdbb, const SysFunction*, const NestValueArray& arg if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - const SLONG code = MOV_get_long(value, 0); + const SLONG code = MOV_get_long(tdbb, value, 0); if (!(code >= 0 && code <= 255)) status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); @@ -1318,8 +1452,8 @@ dsc* evlAtan2(thread_db* tdbb, const SysFunction* function, const NestValueArray if (request->req_flags & req_null) // return NULL if desc2 is NULL return NULL; - double value1 = MOV_get_double(desc1); - double value2 = MOV_get_double(desc2); + double value1 = MOV_get_double(tdbb, desc1); + double value2 = MOV_get_double(tdbb, desc2); if (value1 == 0 && value2 == 0) { @@ -1351,24 +1485,24 @@ dsc* evlBin(thread_db* tdbb, const SysFunction* function, const NestValueArray& if (i == 0) { if ((Function)(IPTR) function->misc == funBinNot) - impure->vlu_misc.vlu_int64 = ~MOV_get_int64(value, 0); + impure->vlu_misc.vlu_int64 = ~MOV_get_int64(tdbb, value, 0); else - impure->vlu_misc.vlu_int64 = MOV_get_int64(value, 0); + impure->vlu_misc.vlu_int64 = MOV_get_int64(tdbb, value, 0); } else { switch ((Function)(IPTR) function->misc) { case funBinAnd: - impure->vlu_misc.vlu_int64 &= MOV_get_int64(value, 0); + impure->vlu_misc.vlu_int64 &= MOV_get_int64(tdbb, value, 0); break; case funBinOr: - impure->vlu_misc.vlu_int64 |= MOV_get_int64(value, 0); + impure->vlu_misc.vlu_int64 |= MOV_get_int64(tdbb, value, 0); break; case funBinXor: - impure->vlu_misc.vlu_int64 ^= MOV_get_int64(value, 0); + impure->vlu_misc.vlu_int64 ^= MOV_get_int64(tdbb, value, 0); break; default: @@ -1399,7 +1533,7 @@ dsc* evlBinShift(thread_db* tdbb, const SysFunction* function, const NestValueAr if (request->req_flags & req_null) // return NULL if value2 is NULL return NULL; - const SINT64 shift = MOV_get_int64(value2, 0); + const SINT64 shift = MOV_get_int64(tdbb, value2, 0); if (shift < 0) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << @@ -1409,7 +1543,7 @@ dsc* evlBinShift(thread_db* tdbb, const SysFunction* function, const NestValueAr const SINT64 rotshift = shift % sizeof(SINT64); SINT64 tempbits = 0; - const SINT64 target = MOV_get_int64(value1, 0); + const SINT64 target = MOV_get_int64(tdbb, value1, 0); switch ((Function)(IPTR) function->misc) { @@ -1466,8 +1600,8 @@ dsc* evlCeil(thread_db* tdbb, const SysFunction*, const NestValueArray& args, for (int i = -impure->vlu_desc.dsc_scale; i > 0; --i) scale *= 10; - const SINT64 v1 = MOV_get_int64(&impure->vlu_desc, impure->vlu_desc.dsc_scale); - const SINT64 v2 = MOV_get_int64(&impure->vlu_desc, 0) * scale; + const SINT64 v1 = MOV_get_int64(tdbb, &impure->vlu_desc, impure->vlu_desc.dsc_scale); + const SINT64 v2 = MOV_get_int64(tdbb, &impure->vlu_desc, 0) * scale; impure->vlu_misc.vlu_int64 = v1 / scale; @@ -1483,13 +1617,23 @@ dsc* evlCeil(thread_db* tdbb, const SysFunction*, const NestValueArray& args, break; default: - impure->vlu_misc.vlu_double = MOV_get_double(&impure->vlu_desc); + impure->vlu_misc.vlu_double = MOV_get_double(tdbb, &impure->vlu_desc); // fall through case dtype_double: impure->vlu_misc.vlu_double = ceil(impure->vlu_misc.vlu_double); impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); break; + + case dtype_dec64: + impure->vlu_misc.vlu_dec64 = impure->vlu_misc.vlu_dec64.ceil(tdbb->getAttachment()->att_dec_status); + impure->vlu_desc.makeDecimal64(&impure->vlu_misc.vlu_dec64); + break; + + case dtype_dec128: + impure->vlu_misc.vlu_dec128 = impure->vlu_misc.vlu_dec128.ceil(tdbb->getAttachment()->att_dec_status); + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); + break; } return &impure->vlu_desc; @@ -1522,7 +1666,7 @@ dsc* evlCharToUuid(thread_db* tdbb, const SysFunction* function, const NestValue } UCHAR* data_temp; - USHORT len = MOV_get_string(value, &data_temp, NULL, 0); + USHORT len = MOV_get_string(tdbb, value, &data_temp, NULL, 0); const UCHAR* data; if (len > GUID_BODY_SIZE) @@ -1651,7 +1795,7 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr if (request->req_flags & req_null) // return NULL if valueDsc is NULL return NULL; - const SLONG part = MOV_get_long(partDsc, 0); + const SLONG part = MOV_get_long(tdbb, partDsc, 0); TimeStamp timestamp; @@ -1701,7 +1845,7 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr static const SSHORT milliScale = ISC_TIME_SECONDS_PRECISION_SCALE + 3; static const int milliPow = NoThrowTimeStamp::POW_10_TABLE[-milliScale]; - const SINT64 quantity = MOV_get_int64(quantityDsc, + const SINT64 quantity = MOV_get_int64(tdbb, quantityDsc, (part == blr_extract_millisecond ? milliScale : 0)); switch (part) @@ -1911,7 +2055,7 @@ dsc* evlDateDiff(thread_db* tdbb, const SysFunction* function, const NestValueAr timestamp1.decode(×1); timestamp2.decode(×2); - const SLONG part = MOV_get_long(partDsc, 0); + const SLONG part = MOV_get_long(tdbb, partDsc, 0); switch (part) { @@ -2062,14 +2206,27 @@ dsc* evlExp(thread_db* tdbb, const SysFunction*, const NestValueArray& args, if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - const double rc = exp(MOV_get_double(value)); - if (rc == HUGE_VAL) // unlikely to trap anything - status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_float_overflow)); - if (isinf(rc)) - status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_float_overflow)); + if (value->isDecFloat()) + { + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + impure->vlu_misc.vlu_dec128 = MOV_get_dec128(tdbb, value); - impure->vlu_misc.vlu_double = rc; - impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); + Decimal128 e; + e.set("2.718281828459045235360287471352662497757", decSt); + impure->vlu_misc.vlu_dec128 = e.pow(decSt, impure->vlu_misc.vlu_dec128); + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); + } + else + { + const double rc = exp(MOV_get_double(tdbb, value)); + if (rc == HUGE_VAL) // unlikely to trap anything + status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_float_overflow)); + if (isinf(rc)) + status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_float_overflow)); + + impure->vlu_misc.vlu_double = rc; + impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); + } return &impure->vlu_desc; } @@ -2100,8 +2257,8 @@ dsc* evlFloor(thread_db* tdbb, const SysFunction*, const NestValueArray& args, for (int i = -impure->vlu_desc.dsc_scale; i > 0; --i) scale *= 10; - const SINT64 v1 = MOV_get_int64(&impure->vlu_desc, impure->vlu_desc.dsc_scale); - const SINT64 v2 = MOV_get_int64(&impure->vlu_desc, 0) * scale; + const SINT64 v1 = MOV_get_int64(tdbb, &impure->vlu_desc, impure->vlu_desc.dsc_scale); + const SINT64 v2 = MOV_get_int64(tdbb, &impure->vlu_desc, 0) * scale; impure->vlu_misc.vlu_int64 = v1 / scale; @@ -2117,13 +2274,23 @@ dsc* evlFloor(thread_db* tdbb, const SysFunction*, const NestValueArray& args, break; default: - impure->vlu_misc.vlu_double = MOV_get_double(&impure->vlu_desc); + impure->vlu_misc.vlu_double = MOV_get_double(tdbb, &impure->vlu_desc); // fall through case dtype_double: impure->vlu_misc.vlu_double = floor(impure->vlu_misc.vlu_double); impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); break; + + case dtype_dec64: + impure->vlu_misc.vlu_dec64 = impure->vlu_misc.vlu_dec64.floor(tdbb->getAttachment()->att_dec_status); + impure->vlu_desc.makeDecimal64(&impure->vlu_misc.vlu_dec64); + break; + + case dtype_dec128: + impure->vlu_misc.vlu_dec128 = impure->vlu_misc.vlu_dec128.floor(tdbb->getAttachment()->att_dec_status); + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); + break; } return &impure->vlu_desc; @@ -2566,32 +2733,63 @@ dsc* evlLnLog10(thread_db* tdbb, const SysFunction* function, const NestValueArr if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - const double v = MOV_get_double(value); - - if (v <= 0) + if (value->isDecFloat()) { - status_exception::raise(Arg::Gds(isc_expression_eval_err) << - Arg::Gds(isc_sysf_argmustbe_positive) << - Arg::Str(function->name)); + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + Decimal128 d = MOV_get_dec128(tdbb, value); + + if (d.compare(decSt, CDecimal128(0)) <= 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_argmustbe_positive) << + Arg::Str(function->name)); + } + + switch ((Function)(IPTR) function->misc) + { + case funLnat: + d = d.ln(decSt); + break; + case funLog10: + d = d.log10(decSt); + break; + default: + fb_assert(0); + return NULL; + } + + impure->vlu_misc.vlu_dec128 = d; + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); } - - double rc; - - switch ((Function)(IPTR) function->misc) + else { - case funLnat: - rc = log(v); - break; - case funLog10: - rc = log10(v); - break; - default: - fb_assert(0); - return NULL; - } + const double v = MOV_get_double(tdbb, value); - impure->vlu_misc.vlu_double = rc; - impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); + if (v <= 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_argmustbe_positive) << + Arg::Str(function->name)); + } + + double rc; + + switch ((Function)(IPTR) function->misc) + { + case funLnat: + rc = log(v); + break; + case funLog10: + rc = log10(v); + break; + default: + fb_assert(0); + return NULL; + } + + impure->vlu_misc.vlu_double = rc; + impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); + } return &impure->vlu_desc; } @@ -2604,33 +2802,188 @@ dsc* evlLog(thread_db* tdbb, const SysFunction* function, const NestValueArray& jrd_req* request = tdbb->getRequest(); - const dsc* value1 = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value1 is NULL + const dsc* value[2]; + value[0] = EVL_expr(tdbb, request, args[0]); + if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - const dsc* value2 = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value2 is NULL + value[1] = EVL_expr(tdbb, request, args[1]); + if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - const double v1 = MOV_get_double(value1); - const double v2 = MOV_get_double(value2); - - if (v1 <= 0) + if (!areParamsDouble(2, value)) { - status_exception::raise(Arg::Gds(isc_expression_eval_err) << - Arg::Gds(isc_sysf_basemustbe_positive) << - Arg::Str(function->name)); + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + Decimal128 v1 = MOV_get_dec128(tdbb, value[0]); + Decimal128 v2 = MOV_get_dec128(tdbb, value[1]); + + if (v1.compare(decSt, CDecimal128(0)) <= 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_basemustbe_positive) << + Arg::Str(function->name)); + } + + if (v2.compare(decSt, CDecimal128(0)) <= 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_argmustbe_positive) << + Arg::Str(function->name)); + } + + impure->vlu_misc.vlu_dec128 = v2.ln(decSt).div(decSt, v1.ln(decSt)); + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); + } + else + { + const double v1 = MOV_get_double(tdbb, value[0]); + const double v2 = MOV_get_double(tdbb, value[1]); + + if (v1 <= 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_basemustbe_positive) << + Arg::Str(function->name)); + } + + if (v2 <= 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_argmustbe_positive) << + Arg::Str(function->name)); + } + + impure->vlu_misc.vlu_double = log(v2) / log(v1); + impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); } - if (v2 <= 0) + return &impure->vlu_desc; +} + + +dsc* evlQuantize(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, + impure_value* impure) +{ + fb_assert(args.getCount() == 2); + + jrd_req* request = tdbb->getRequest(); + + const dsc* value[2]; + value[0] = EVL_expr(tdbb, request, args[0]); + if (request->req_flags & req_null) // return NULL if value is NULL + return NULL; + + value[1] = EVL_expr(tdbb, request, args[1]); + if (request->req_flags & req_null) // return NULL if value is NULL + return NULL; + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + + if (value[0]->dsc_dtype == dtype_dec64) { - status_exception::raise(Arg::Gds(isc_expression_eval_err) << - Arg::Gds(isc_sysf_argmustbe_positive) << - Arg::Str(function->name)); + Decimal64 v1 = MOV_get_dec64(tdbb, value[0]); + Decimal64 v2 = MOV_get_dec64(tdbb, value[1]); + + impure->vlu_misc.vlu_dec64 = v1.quantize(decSt, v2); + impure->vlu_desc.makeDecimal64(&impure->vlu_misc.vlu_dec64); + } + else + { + Decimal128 v1 = MOV_get_dec128(tdbb, value[0]); + Decimal128 v2 = MOV_get_dec128(tdbb, value[1]); + + impure->vlu_misc.vlu_dec128 = v1.quantize(decSt, v2); + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); } - impure->vlu_misc.vlu_double = log(v2) / log(v1); - impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); + return &impure->vlu_desc; +} + + +dsc* evlCompare(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, + impure_value* impure) +{ + fb_assert(args.getCount() == 2); + + jrd_req* request = tdbb->getRequest(); + + const dsc* value[2]; + value[0] = EVL_expr(tdbb, request, args[0]); + if (request->req_flags & req_null) // return NULL if value is NULL + return NULL; + + value[1] = EVL_expr(tdbb, request, args[1]); + if (request->req_flags & req_null) // return NULL if value is NULL + return NULL; + + if (value[0]->dsc_dtype == dtype_dec64) + { + Decimal64 v1 = MOV_get_dec64(tdbb, value[0]); + Decimal64 v2 = MOV_get_dec64(tdbb, value[1]); + + switch ((Function)(IPTR) function->misc) + { + case funTotalOrd: + impure->vlu_misc.vlu_short = v1.totalOrder(v2); + break; + case funCmpDec: + impure->vlu_misc.vlu_short = v1.decCompare(v2); + break; + default: + fb_assert(false); + } + } + else + { + Decimal128 v1 = MOV_get_dec128(tdbb, value[0]); + Decimal128 v2 = MOV_get_dec128(tdbb, value[1]); + + switch ((Function)(IPTR) function->misc) + { + case funTotalOrd: + impure->vlu_misc.vlu_short = v1.totalOrder(v2); + break; + case funCmpDec: + impure->vlu_misc.vlu_short = v1.decCompare(v2); + break; + default: + fb_assert(false); + } + } + + impure->vlu_desc.makeShort(0, &impure->vlu_misc.vlu_short); + return &impure->vlu_desc; +} + + +dsc* evlNormDec(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, + impure_value* impure) +{ + fb_assert(args.getCount() == 1); + + jrd_req* request = tdbb->getRequest(); + + const dsc* value; + value = EVL_expr(tdbb, request, args[0]); + if (request->req_flags & req_null) // return NULL if value is NULL + return NULL; + + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + + if (value->dsc_dtype == dtype_dec64) + { + Decimal64 v = MOV_get_dec64(tdbb, value); + + impure->vlu_misc.vlu_dec64 = v.normalize(decSt); + impure->vlu_desc.makeDecimal64(&impure->vlu_misc.vlu_dec64); + } + else + { + Decimal128 v = MOV_get_dec128(tdbb, value); + + impure->vlu_misc.vlu_dec128 = v.normalize(decSt); + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); + } return &impure->vlu_desc; } @@ -2658,12 +3011,12 @@ dsc* evlMaxMinValue(thread_db* tdbb, const SysFunction* function, const NestValu switch ((Function)(IPTR) function->misc) { case funMaxValue: - if (MOV_compare(value, result) > 0) + if (MOV_compare(tdbb, value, result) > 0) result = value; break; case funMinValue: - if (MOV_compare(value, result) < 0) + if (MOV_compare(tdbb, value, result) < 0) result = value; break; @@ -2695,12 +3048,12 @@ dsc* evlMod(thread_db* tdbb, const SysFunction*, const NestValueArray& args, EVL_make_value(tdbb, value1, impure); impure->vlu_desc.dsc_scale = 0; - const SINT64 divisor = MOV_get_int64(value2, 0); + const SINT64 divisor = MOV_get_int64(tdbb, value2, 0); if (divisor == 0) status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_integer_divide_by_zero)); - const SINT64 result = MOV_get_int64(value1, 0) % divisor; + const SINT64 result = MOV_get_int64(tdbb, value1, 0) % divisor; switch (impure->vlu_desc.dsc_dtype) { @@ -2754,7 +3107,7 @@ dsc* evlOverlay(thread_db* tdbb, const SysFunction* function, const NestValueArr if (request->req_flags & req_null) // return NULL if lengthDsc is NULL return NULL; - const SLONG auxlen = MOV_get_long(lengthDsc, 0); + const SLONG auxlen = MOV_get_long(tdbb, lengthDsc, 0); if (auxlen < 0) { @@ -2767,7 +3120,7 @@ dsc* evlOverlay(thread_db* tdbb, const SysFunction* function, const NestValueArr length = auxlen; } - SLONG from = MOV_get_long(fromDsc, 0); + SLONG from = MOV_get_long(tdbb, fromDsc, 0); if (from <= 0) { @@ -2925,7 +3278,7 @@ dsc* evlPad(thread_db* tdbb, const SysFunction* function, const NestValueArray& if (request->req_flags & req_null) // return NULL if padLenDsc is NULL return NULL; - const SLONG padLenArg = MOV_get_long(padLenDsc, 0); + const SLONG padLenArg = MOV_get_long(tdbb, padLenDsc, 0); if (padLenArg < 0) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << @@ -3108,7 +3461,7 @@ dsc* evlPosition(thread_db* tdbb, const SysFunction* function, const NestValueAr if (request->req_flags & req_null) // return NULL if value3 is NULL return NULL; - start = MOV_get_long(value3, 0); + start = MOV_get_long(tdbb, value3, 0); if (start <= 0) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << @@ -3218,42 +3571,55 @@ dsc* evlPower(thread_db* tdbb, const SysFunction* function, const NestValueArray jrd_req* request = tdbb->getRequest(); - const dsc* value1 = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value1 is NULL + const dsc* value[2]; + value[0] = EVL_expr(tdbb, request, args[0]); + if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - const dsc* value2 = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value2 is NULL + value[1] = EVL_expr(tdbb, request, args[1]); + if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); - - const double v1 = MOV_get_double(value1); - const double v2 = MOV_get_double(value2); - - if (v1 == 0 && v2 < 0) + if (!areParamsDouble(2, value)) { - status_exception::raise(Arg::Gds(isc_expression_eval_err) << - Arg::Gds(isc_sysf_invalid_zeropowneg) << - Arg::Str(function->name)); - } + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + impure->vlu_misc.vlu_dec128 = MOV_get_dec128(tdbb, value[0]); + Decimal128 v2 = MOV_get_dec128(tdbb, value[1]); - if (v1 < 0 && - (!value2->isExact() || - MOV_get_int64(value2, 0) * SINT64(CVT_power_of_ten(-value2->dsc_scale)) != - MOV_get_int64(value2, value2->dsc_scale))) + impure->vlu_misc.vlu_dec128 = impure->vlu_misc.vlu_dec128.pow(decSt, v2); + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); + } + else { - status_exception::raise(Arg::Gds(isc_expression_eval_err) << - Arg::Gds(isc_sysf_invalid_negpowfp) << - Arg::Str(function->name)); + impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); + + const double v1 = MOV_get_double(tdbb, value[0]); + const double v2 = MOV_get_double(tdbb, value[1]); + + if (v1 == 0 && v2 < 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_invalid_zeropowneg) << + Arg::Str(function->name)); + } + + if (v1 < 0 && + (!value[1]->isExact() || + MOV_get_int64(tdbb, value[1], 0) * SINT64(CVT_power_of_ten(-value[1]->dsc_scale)) != + MOV_get_int64(tdbb, value[1], value[1]->dsc_scale))) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_invalid_negpowfp) << + Arg::Str(function->name)); + } + + const double rc = pow(v1, v2); + if (isinf(rc)) + status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_float_overflow)); + + impure->vlu_misc.vlu_double = rc; } - const double rc = pow(v1, v2); - if (isinf(rc)) - status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_float_overflow)); - - impure->vlu_misc.vlu_double = rc; - return &impure->vlu_desc; } @@ -3578,7 +3944,7 @@ dsc* evlRight(thread_db* tdbb, const SysFunction*, const NestValueArray& args, start = charSet->length(start, p, true); } - start -= MOV_get_long(len, 0); + start -= MOV_get_long(tdbb, len, 0); start = MAX(0, start); dsc startDsc; @@ -3607,7 +3973,7 @@ dsc* evlRound(thread_db* tdbb, const SysFunction* function, const NestValueArray if (request->req_flags & req_null) // return NULL if scaleDsc is NULL return NULL; - scale = -MOV_get_long(scaleDsc, 0); + scale = -MOV_get_long(tdbb, scaleDsc, 0); if (!(scale >= MIN_SCHAR && scale <= MAX_SCHAR)) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << @@ -3616,7 +3982,7 @@ dsc* evlRound(thread_db* tdbb, const SysFunction* function, const NestValueArray } } - impure->vlu_misc.vlu_int64 = MOV_get_int64(value, scale); + impure->vlu_misc.vlu_int64 = MOV_get_int64(tdbb, value, scale); impure->vlu_desc.makeInt64(scale, &impure->vlu_misc.vlu_int64); return &impure->vlu_desc; @@ -3634,14 +4000,19 @@ dsc* evlSign(thread_db* tdbb, const SysFunction*, const NestValueArray& args, if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - const double val = MOV_get_double(value); + if (value->isDecFloat()) + impure->vlu_misc.vlu_short = MOV_get_dec128(tdbb, value).sign(); + else + { + const double val = MOV_get_double(tdbb, value); - if (val > 0) - impure->vlu_misc.vlu_short = 1; - else if (val < 0) - impure->vlu_misc.vlu_short = -1; - else // val == 0 - impure->vlu_misc.vlu_short = 0; + if (val > 0) + impure->vlu_misc.vlu_short = 1; + else if (val < 0) + impure->vlu_misc.vlu_short = -1; + else // val == 0 + impure->vlu_misc.vlu_short = 0; + } impure->vlu_desc.makeShort(0, &impure->vlu_misc.vlu_short); @@ -3660,16 +4031,33 @@ dsc* evlSqrt(thread_db* tdbb, const SysFunction* function, const NestValueArray& if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - impure->vlu_misc.vlu_double = MOV_get_double(value); - - if (impure->vlu_misc.vlu_double < 0) + if (value->isDecFloat()) { - status_exception::raise(Arg::Gds(isc_expression_eval_err) << - Arg::Gds(isc_sysf_argmustbe_nonneg) << Arg::Str(function->name)); - } + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + impure->vlu_misc.vlu_dec128 = MOV_get_dec128(tdbb, value); - impure->vlu_misc.vlu_double = sqrt(impure->vlu_misc.vlu_double); - impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); + if (impure->vlu_misc.vlu_dec128.compare(decSt, CDecimal128(0)) < 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_argmustbe_nonneg) << Arg::Str(function->name)); + } + + impure->vlu_misc.vlu_dec128 = impure->vlu_misc.vlu_dec128.sqrt(decSt); + impure->vlu_desc.makeDecimal128(&impure->vlu_misc.vlu_dec128); + } + else + { + impure->vlu_misc.vlu_double = MOV_get_double(tdbb, value); + + if (impure->vlu_misc.vlu_double < 0) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_sysf_argmustbe_nonneg) << Arg::Str(function->name)); + } + + impure->vlu_misc.vlu_double = sqrt(impure->vlu_misc.vlu_double); + impure->vlu_desc.makeDouble(&impure->vlu_misc.vlu_double); + } return &impure->vlu_desc; } @@ -3693,7 +4081,7 @@ dsc* evlTrunc(thread_db* tdbb, const SysFunction* function, const NestValueArray if (request->req_flags & req_null) // return NULL if scaleDsc is NULL return NULL; - resultScale = -MOV_get_long(scaleDsc, 0); + resultScale = -MOV_get_long(tdbb, scaleDsc, 0); if (!(resultScale >= MIN_SCHAR && resultScale <= MAX_SCHAR)) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << @@ -3705,7 +4093,7 @@ dsc* evlTrunc(thread_db* tdbb, const SysFunction* function, const NestValueArray if (value->isExact()) { SSHORT scale = value->dsc_scale; - impure->vlu_misc.vlu_int64 = MOV_get_int64(value, scale); + impure->vlu_misc.vlu_int64 = MOV_get_int64(tdbb, value, scale); if (resultScale < scale) resultScale = scale; @@ -3725,7 +4113,7 @@ dsc* evlTrunc(thread_db* tdbb, const SysFunction* function, const NestValueArray } else { - impure->vlu_misc.vlu_double = MOV_get_double(value); + impure->vlu_misc.vlu_double = MOV_get_double(tdbb, value); SINT64 v = 1; @@ -3781,7 +4169,7 @@ dsc* evlUuidToChar(thread_db* tdbb, const SysFunction* function, const NestValue } UCHAR* data; - const USHORT len = MOV_get_string(value, &data, NULL, 0); + const USHORT len = MOV_get_string(tdbb, value, &data, NULL, 0); if (len != sizeof(Guid)) { @@ -3856,7 +4244,7 @@ dsc* evlSystemPrivilege(thread_db* tdbb, const SysFunction*, const NestValueArra const SysFunction SysFunction::functions[] = { - {"ABS", 1, 1, setParamsDouble, makeAbs, evlAbs, NULL}, + {"ABS", 1, 1, setParamsDblDec, makeAbs, evlAbs, NULL}, {"ACOS", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfAcos}, {"ACOSH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfAcosh}, {"ASCII_CHAR", 1, 1, setParamsInteger, makeAsciiChar, evlAsciiChar, NULL}, @@ -3874,30 +4262,33 @@ const SysFunction SysFunction::functions[] = {"BIN_SHL_ROT", 2, 2, setParamsInteger, makeBinShift, evlBinShift, (void*) funBinShlRot}, {"BIN_SHR_ROT", 2, 2, setParamsInteger, makeBinShift, evlBinShift, (void*) funBinShrRot}, {"BIN_XOR", 2, -1, setParamsInteger, makeBin, evlBin, (void*) funBinXor}, - {"CEIL", 1, 1, setParamsDouble, makeCeilFloor, evlCeil, NULL}, - {"CEILING", 1, 1, setParamsDouble, makeCeilFloor, evlCeil, NULL}, + {"CEIL", 1, 1, setParamsDblDec, makeCeilFloor, evlCeil, NULL}, + {"CEILING", 1, 1, setParamsDblDec, makeCeilFloor, evlCeil, NULL}, {"CHAR_TO_UUID", 1, 1, setParamsCharToUuid, makeUuid, evlCharToUuid, NULL}, + {"COMPARE_DECFLOAT", 2, 2, setParamsDecFloat, makeShortResult, evlCompare, (void*) funCmpDec}, {"COS", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCos}, {"COSH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCosh}, {"COT", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCot}, {"DATEADD", 3, 3, setParamsDateAdd, makeDateAdd, evlDateAdd, NULL}, {"DATEDIFF", 3, 3, setParamsDateDiff, makeInt64Result, evlDateDiff, NULL}, - {"EXP", 1, 1, setParamsDouble, makeDoubleResult, evlExp, NULL}, - {"FLOOR", 1, 1, setParamsDouble, makeCeilFloor, evlFloor, NULL}, + {"EXP", 1, 1, setParamsDblDec, makeDblDecResult, evlExp, NULL}, + {"FLOOR", 1, 1, setParamsDblDec, makeCeilFloor, evlFloor, NULL}, {"GEN_UUID", 0, 0, NULL, makeUuid, evlGenUuid, NULL}, {"HASH", 1, 1, NULL, makeInt64Result, evlHash, NULL}, {"LEFT", 2, 2, setParamsSecondInteger, makeLeftRight, evlLeft, NULL}, - {"LN", 1, 1, setParamsDouble, makeDoubleResult, evlLnLog10, (void*) funLnat}, - {"LOG", 2, 2, setParamsDouble, makeDoubleResult, evlLog, NULL}, - {"LOG10", 1, 1, setParamsDouble, makeDoubleResult, evlLnLog10, (void*) funLog10}, + {"LN", 1, 1, setParamsDblDec, makeDblDecResult, evlLnLog10, (void*) funLnat}, + {"LOG", 2, 2, setParamsDblDec, makeDblDecResult, evlLog, NULL}, + {"LOG10", 1, 1, setParamsDblDec, makeDblDecResult, evlLnLog10, (void*) funLog10}, {"LPAD", 2, 3, setParamsSecondInteger, makePad, evlPad, (void*) funLPad}, {"MAXVALUE", 1, -1, setParamsFromList, makeFromListResult, evlMaxMinValue, (void*) funMaxValue}, {"MINVALUE", 1, -1, setParamsFromList, makeFromListResult, evlMaxMinValue, (void*) funMinValue}, {"MOD", 2, 2, setParamsFromList, makeMod, evlMod, NULL}, + {"NORMALIZE_DECFLOAT", 1, 1, setParamsDecFloat, makeDecFloatResult, evlNormDec, NULL}, {"OVERLAY", 3, 4, setParamsOverlay, makeOverlay, evlOverlay, NULL}, - {"PI", 0, 0, NULL, makeDoubleResult, evlPi, NULL}, + {"PI", 0, 0, NULL, makePi, evlPi, NULL}, {"POSITION", 2, 3, setParamsPosition, makeLongResult, evlPosition, NULL}, - {"POWER", 2, 2, setParamsDouble, makeDoubleResult, evlPower, NULL}, + {"POWER", 2, 2, setParamsDblDec, makeDblDecResult, evlPower, NULL}, + {"QUANTIZE", 2, 2, setParamsDecFloat, makeDecFloatResult, evlQuantize, NULL}, {"RAND", 0, 0, NULL, makeDoubleResult, evlRand, NULL}, {RDB_GET_CONTEXT, 2, 2, setParamsGetSetContext, makeGetSetContext, evlGetContext, NULL}, {"RDB$ROLE_IN_USE", 1, 1, setParamsAsciiVal, makeBooleanResult, evlRoleInUse, NULL}, @@ -3908,12 +4299,13 @@ const SysFunction SysFunction::functions[] = {"RIGHT", 2, 2, setParamsSecondInteger, makeLeftRight, evlRight, NULL}, {"ROUND", 1, 2, setParamsRoundTrunc, makeRound, evlRound, NULL}, {"RPAD", 2, 3, setParamsSecondInteger, makePad, evlPad, (void*) funRPad}, - {"SIGN", 1, 1, setParamsDouble, makeShortResult, evlSign, NULL}, + {"SIGN", 1, 1, setParamsDblDec, makeShortResult, evlSign, NULL}, {"SIN", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfSin}, {"SINH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfSinh}, - {"SQRT", 1, 1, setParamsDouble, makeDoubleResult, evlSqrt, NULL}, + {"SQRT", 1, 1, setParamsDblDec, makeDblDecResult, evlSqrt, NULL}, {"TAN", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfTan}, {"TANH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfTanh}, + {"TOTALORDER", 2, 2, setParamsDecFloat, makeShortResult, evlCompare, (void*) funTotalOrd}, {"TRUNC", 1, 2, setParamsRoundTrunc, makeTrunc, evlTrunc, NULL}, {"UUID_TO_CHAR", 1, 1, setParamsUuidToChar, makeUuidToChar, evlUuidToChar, NULL}, {"", 0, 0, NULL, NULL, NULL, NULL} diff --git a/src/jrd/VirtualTable.cpp b/src/jrd/VirtualTable.cpp index 03e304825c..7a782f5cb4 100644 --- a/src/jrd/VirtualTable.cpp +++ b/src/jrd/VirtualTable.cpp @@ -70,7 +70,7 @@ void VirtualTable::erase(thread_db* tdbb, record_param* rpb) // Ignore attempt to stop system attachment dsc sysFlag; if (EVL_field(relation, rpb->rpb_record, f_mon_att_sys_flag, &sysFlag) && - MOV_get_long(&sysFlag, 0) != 0) + MOV_get_long(tdbb, &sysFlag, 0) != 0) { return; } @@ -90,7 +90,7 @@ void VirtualTable::erase(thread_db* tdbb, record_param* rpb) return; } - const SINT64 id = MOV_get_int64(&desc, 0); + const SINT64 id = MOV_get_int64(tdbb, &desc, 0); // Post a blocking request Lock temp_lock(tdbb, sizeof(SINT64), lock_type); diff --git a/src/jrd/align.h b/src/jrd/align.h index a93e556b72..66d739915c 100644 --- a/src/jrd/align.h +++ b/src/jrd/align.h @@ -32,6 +32,7 @@ Maximum alignments for corresponding data types are defined in dsc.h */ +#include "../common/DecFloat.h" #include "../jrd/blr.h" /* The following macro must be defined as the highest-numericly-valued @@ -67,7 +68,9 @@ static const USHORT gds_cvt_blr_dtype[DTYPE_BLR_MAX + 1] = dtype_int64, /* blr_int64 == 16 */ 0, 0, 0, 0, 0, 0, dtype_boolean, // blr_bool == 23 - 0, 0, 0, + dtype_dec64, /* blr_dec64 == 24 */ + dtype_dec128, /* blr_dec128 == 25 */ + 0, dtype_double, /* blr_double == 27 */ 0, 0, 0, 0, 0, 0, 0, dtype_timestamp, /* blr_timestamp == 35 */ @@ -103,7 +106,9 @@ static const USHORT type_alignments[DTYPE_TYPE_MAX] = sizeof(SLONG), /* dtype_array */ sizeof(SINT64), /* dtype_int64 */ sizeof(ULONG), /* dtype_dbkey */ - sizeof(UCHAR) /* dtype_boolean */ + sizeof(UCHAR), /* dtype_boolean */ + sizeof(Firebird::Decimal64),/* dtype_dec64 */ + sizeof(Firebird::Decimal64) /* dtype_dec128 */ }; static const USHORT type_lengths[DTYPE_TYPE_MAX] = @@ -129,7 +134,9 @@ static const USHORT type_lengths[DTYPE_TYPE_MAX] = sizeof(ISC_QUAD), /* dtype_array */ sizeof(SINT64), /* dtype_int64 */ sizeof(RecordNumber::Packed), /*dtype_dbkey */ - sizeof(UCHAR) /* dtype_boolean */ + sizeof(UCHAR), /* dtype_boolean */ + sizeof(Firebird::Decimal64),/* dtype_dec64 */ + sizeof(Firebird::Decimal128)/* dtype_dec128 */ }; @@ -158,7 +165,9 @@ static const USHORT type_significant_bits[DTYPE_TYPE_MAX] = sizeof(ISC_QUAD) * 8, /* dtype_array */ sizeof(SINT64) * 8, /* dtype_int64 */ 0, // dtype_dbkey - 0 // dtype_boolean + 0, // dtype_boolean + 0, // dtype_dec64 + 0 // dtype_dec128 }; #endif /* JRD_ALIGN_H */ diff --git a/src/jrd/blb.cpp b/src/jrd/blb.cpp index 6dbb7221e0..e0febf31fd 100644 --- a/src/jrd/blb.cpp +++ b/src/jrd/blb.cpp @@ -999,13 +999,13 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, const ValueExprNod if (field) { - if ((fieldNode = ExprNode::as(field))) + if ((fieldNode = nodeAs(field))) { // We should not materialize the blob if the destination field // stream (nod_union, for example) doesn't have a relation. simpleMove = tdbb->getRequest()->req_rpb[fieldNode->fieldStream].rpb_relation == NULL; } - else if (!(ExprNode::is(field) || ExprNode::is(field))) + else if (!(nodeIs(field) || nodeIs(field))) BUGCHECK(199); // msg 199 expected field node } @@ -2791,7 +2791,7 @@ static void slice_callback(array_slice* arg, ULONG /*count*/, DSC* descriptors) DynamicVaryStr<1024> tmp_buffer; const USHORT tmp_len = array_desc->dsc_length; const char* p; - const USHORT len = MOV_make_string(slice_desc, INTL_TEXT_TYPE(*array_desc), &p, + const USHORT len = MOV_make_string(tdbb, slice_desc, INTL_TEXT_TYPE(*array_desc), &p, tmp_buffer.getBuffer(tmp_len), tmp_len); memcpy(array_desc->dsc_address, &len, sizeof(USHORT)); memcpy(array_desc->dsc_address + sizeof(USHORT), p, (int) len); diff --git a/src/jrd/blr.h b/src/jrd/blr.h index b586a5e10f..912af5e809 100644 --- a/src/jrd/blr.h +++ b/src/jrd/blr.h @@ -59,7 +59,7 @@ #define blr_blob_id (unsigned char)45 /* added from gds.h */ #define blr_sql_date (unsigned char)12 #define blr_sql_time (unsigned char)13 -#define blr_int64 (unsigned char)16 +#define blr_int64 (unsigned char)16 #define blr_blob2 (unsigned char)17 #define blr_domain_name (unsigned char)18 #define blr_domain_name2 (unsigned char)19 @@ -67,6 +67,8 @@ #define blr_column_name (unsigned char)21 #define blr_column_name2 (unsigned char)22 #define blr_bool (unsigned char)23 +#define blr_dec64 (unsigned char)24 +#define blr_dec128 (unsigned char)25 // first sub parameter for blr_domain_name[2] #define blr_domain_type_of (unsigned char)0 diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 707e411b2b..97a05f4ff4 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -1373,6 +1373,10 @@ USHORT BTR_key_length(thread_db* tdbb, jrd_rel* relation, index_desc* idx) length = sizeof(UCHAR); break; + case idx_decimal: + length = Decimal128::getIndexKeyLength(); + break; + default: if (idx->idx_flags & idx_expressn) { @@ -1425,6 +1429,9 @@ USHORT BTR_key_length(thread_db* tdbb, jrd_rel* relation, index_desc* idx) case idx_boolean: length = sizeof(UCHAR); break; + case idx_decimal: + length = Decimal128::getIndexKeyLength(); + break; default: length = format->fmt_desc[tail->idx_field].dsc_length; if (format->fmt_desc[tail->idx_field].dsc_dtype == dtype_varying) @@ -2219,7 +2226,7 @@ bool BTR_types_comparable(const dsc& target, const dsc& source) return (source.dsc_dtype <= dtype_long || source.dsc_dtype == dtype_int64); if (DTYPE_IS_NUMERIC(target.dsc_dtype)) - return (source.dsc_dtype <= dtype_double || source.dsc_dtype == dtype_int64); + return (source.dsc_dtype <= dtype_double || source.dsc_dtype == dtype_int64); //!!!!!!!! if (target.dsc_dtype == dtype_sql_date) return (source.dsc_dtype <= dtype_sql_date || source.dsc_dtype == dtype_timestamp); @@ -2424,7 +2431,7 @@ static void compress(thread_db* tdbb, } if (itype == idx_string || itype == idx_byte_array || itype == idx_metadata || - itype >= idx_first_intl_string) + itype == idx_decimal || itype >= idx_first_intl_string) { VaryStr buffer; const UCHAR pad = (itype == idx_string) ? ' ' : 0; @@ -2432,7 +2439,13 @@ static void compress(thread_db* tdbb, size_t length; - if (itype >= idx_first_intl_string || itype == idx_metadata) + if (itype == idx_decimal) + { + Decimal128 dec = MOV_get_dec128(tdbb, desc); + length = dec.makeIndexKey(&buffer); + ptr = reinterpret_cast(buffer.vary_string); + } + else if (itype >= idx_first_intl_string || itype == idx_metadata) { DSC to; @@ -2447,7 +2460,7 @@ static void compress(thread_db* tdbb, length = INTL_string_to_key(tdbb, itype, desc, &to, key_type); } else - length = MOV_get_string(desc, &ptr, &buffer, MAX_KEY); + length = MOV_get_string(tdbb, desc, &ptr, &buffer, MAX_KEY); if (length) { @@ -2501,7 +2514,7 @@ static void compress(thread_db* tdbb, if (itype == idx_numeric) { - temp.temp_double = MOV_get_double(desc); + temp.temp_double = MOV_get_double(tdbb, desc); temp_is_negative = (temp.temp_double < 0); #ifdef DEBUG_INDEXKEY @@ -2511,7 +2524,7 @@ static void compress(thread_db* tdbb, else if (itype == idx_numeric2) { int64_key_op = true; - temp.temp_int64_key = make_int64_key(MOV_get_int64(desc, desc->dsc_scale), desc->dsc_scale); + temp.temp_int64_key = make_int64_key(MOV_get_int64(tdbb, desc, desc->dsc_scale), desc->dsc_scale); temp_copy_length = sizeof(temp.temp_int64_key.d_part); temp_is_negative = (temp.temp_int64_key.d_part < 0); @@ -2586,7 +2599,7 @@ static void compress(thread_db* tdbb, } else { - temp.temp_double = MOV_get_double(desc); + temp.temp_double = MOV_get_double(tdbb, desc); temp_is_negative = (temp.temp_double < 0); #ifdef DEBUG_INDEXKEY diff --git a/src/jrd/btr.h b/src/jrd/btr.h index 0459205c91..e930584669 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -99,6 +99,7 @@ const int idx_sql_time = 6; const int idx_timestamp = 7; const int idx_numeric2 = 8; // Introduced for 64-bit Integer support const int idx_boolean = 9; +const int idx_decimal = 10; // idx_itype space for future expansion const int idx_first_intl_string = 64; // .. MAX (short) Range of computed key strings diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 345837b0ec..a457bfe524 100644 --- a/src/jrd/build_no.h +++ b/src/jrd/build_no.h @@ -3,16 +3,16 @@ *** DO NOT EDIT *** TO CHANGE ANY INFORMATION IN HERE PLEASE EDIT src/misc/writeBuildNum.sh - FORMAL BUILD NUMBER:582 + FORMAL BUILD NUMBER:686 */ -#define PRODUCT_VER_STRING "4.0.0.582" -#define FILE_VER_STRING "WI-T4.0.0.582" -#define LICENSE_VER_STRING "WI-T4.0.0.582" -#define FILE_VER_NUMBER 4, 0, 0, 582 +#define PRODUCT_VER_STRING "4.0.0.686" +#define FILE_VER_STRING "WI-T4.0.0.686" +#define LICENSE_VER_STRING "WI-T4.0.0.686" +#define FILE_VER_NUMBER 4, 0, 0, 686 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "582" +#define FB_BUILD_NO "686" #define FB_BUILD_TYPE "T" -#define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" +#define FB_BUILD_SUFFIX "Firebird 4.0 Alpha 1" diff --git a/src/jrd/cmp.cpp b/src/jrd/cmp.cpp index 5ead14d8ac..150d132453 100644 --- a/src/jrd/cmp.cpp +++ b/src/jrd/cmp.cpp @@ -120,7 +120,7 @@ ValueExprNode* CMP_clone_node_opt(thread_db* tdbb, CompilerScratch* csb, ValueEx DEV_BLKCHK(csb, type_csb); - if (node->is()) + if (nodeIs(node)) return node; SubExprNodeCopier copier(csb); diff --git a/src/jrd/constants.h b/src/jrd/constants.h index f070a8b1d9..ed6e38e3e2 100644 --- a/src/jrd/constants.h +++ b/src/jrd/constants.h @@ -451,6 +451,7 @@ const TraNumber MAX_TRA_NUMBER = 0x0000FFFFFFFFFFFF; // ~2.8 * 10^14 const int OPT_STATIC_ITEMS = 64; #define CURRENT_ENGINE "Engine13" +#define EMBEDDED_PROVIDERS "Providers=" CURRENT_ENGINE const int WITH_GRANT_OPTION = 1; const int WITH_ADMIN_OPTION = 2; diff --git a/src/jrd/cvt.cpp b/src/jrd/cvt.cpp index c0ffb2e122..aa9ad6374b 100644 --- a/src/jrd/cvt.cpp +++ b/src/jrd/cvt.cpp @@ -136,7 +136,7 @@ double CVT_date_to_double(const dsc* desc) temp_desc.dsc_length = sizeof(temp); date = temp; temp_desc.dsc_address = (UCHAR*) date; - CVT_move(desc, &temp_desc); + CVT_move(desc, &temp_desc, 0); } } @@ -173,7 +173,7 @@ void CVT_double_to_date(double real, SLONG fixed[2]) } -UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, double* ptr) +UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, void* ptr) { /************************************** * @@ -207,7 +207,7 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, d SINT64 value = 0; SSHORT local_scale = 0, sign = 0; - bool digit_seen = false, fraction = false; + bool digit_seen = false, fraction = false, over = false; const UCHAR* p = string; const UCHAR* const end = p + length; @@ -225,11 +225,11 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, d if (value >= NUMERIC_LIMIT) { // possibility of an overflow - if (value > NUMERIC_LIMIT) - break; - - if ((*p > '8' && sign == -1) || (*p > '7' && sign != -1)) + if ((value > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1)) + { + over = true; break; + } } // Force the subtraction to be performed before the addition, @@ -258,12 +258,23 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, d if (!digit_seen) CVT_conversion_error(&desc, ERR_post); - if ((p < end) || // there is an exponent - ((value < 0) && (sign != -1))) // MAX_SINT64+1 wrapped around + if ((local_scale > MAX_SCHAR) || (local_scale < MIN_SCHAR)) + over = true; + + if ((!over) && ((p < end) || // there is an exponent + ((value < 0) && (sign != -1)))) // MAX_SINT64+1 wrapped around { // convert to double - *ptr = CVT_get_double(&desc, ERR_post); - return dtype_double; + *(double*) ptr = CVT_get_double(&desc, 0, ERR_post, &over); + if (!over) + return dtype_double; + } + + if (over) + { + thread_db* tdbb = JRD_get_thread_data(); + *(Decimal128*) ptr = CVT_get_dec128(&desc, tdbb->getAttachment()->att_dec_status, ERR_post); + return dtype_dec128; } *scale = local_scale; @@ -313,7 +324,7 @@ GDS_DATE CVT_get_sql_date(const dsc* desc) memset(&temp_desc, 0, sizeof(temp_desc)); temp_desc.dsc_dtype = dtype_sql_date; temp_desc.dsc_address = (UCHAR *) &value; - CVT_move(desc, &temp_desc); + CVT_move(desc, &temp_desc, 0); return value; } @@ -338,7 +349,7 @@ GDS_TIME CVT_get_sql_time(const dsc* desc) memset(&temp_desc, 0, sizeof(temp_desc)); temp_desc.dsc_dtype = dtype_sql_time; temp_desc.dsc_address = (UCHAR *) &value; - CVT_move(desc, &temp_desc); + CVT_move(desc, &temp_desc, 0); return value; } @@ -363,7 +374,7 @@ GDS_TIMESTAMP CVT_get_timestamp(const dsc* desc) memset(&temp_desc, 0, sizeof(temp_desc)); temp_desc.dsc_dtype = dtype_timestamp; temp_desc.dsc_address = (UCHAR *) &value; - CVT_move(desc, &temp_desc); + CVT_move(desc, &temp_desc, 0); return value; } diff --git a/src/jrd/cvt2.cpp b/src/jrd/cvt2.cpp index 06c1b842f1..7840fe7f7b 100644 --- a/src/jrd/cvt2.cpp +++ b/src/jrd/cvt2.cpp @@ -65,11 +65,10 @@ using namespace Firebird; comparison purpose, even though isc_int64 had to get number 19, which is otherwise too high. - This table is used in CVT2_compare, is indexed by dsc_dtype, and - returns the relative priority of types for use when different types - are compared. + This table is indexed by dsc_dtype, and returns the relative priority + of types for use when different types are compared. */ -static const BYTE compare_priority[] = +const BYTE CVT2_compare_priority[] = { dtype_unknown, // dtype_unknown through dtype_varying dtype_text, // have their natural values stored @@ -80,18 +79,20 @@ static const BYTE compare_priority[] = dtype_byte, // their natural values in the table dtype_short, dtype_long, - dtype_quad + 1, // quad through array all move up - dtype_real + 1, // by one to make room for int64 - dtype_double + 1, // at its proper place in the table. - dtype_d_float + 1, - dtype_sql_date + 1, - dtype_sql_time + 1, - dtype_timestamp + 1, - dtype_blob + 1, - dtype_array + 1, + dtype_quad + 1, // Move quad up by one to make room for int64 at its proper place in the table. + dtype_real + 3, // Also leave space for dec64 and dec 128. + dtype_double + 3, + dtype_d_float + 3, + dtype_sql_date + 3, + dtype_sql_time + 3, + dtype_timestamp + 3, + dtype_blob + 3, + dtype_array + 3, dtype_long + 1, // int64 goes right after long dtype_dbkey, // compares with nothing except itself - dtype_boolean // compares with nothing except itself + dtype_boolean, // compares with nothing except itself + dtype_quad + 2, // dec64 and dec128 go after quad before real + dtype_quad + 3 }; static inline int QUAD_COMPARE(const SQUAD* arg1, const SQUAD* arg2) @@ -177,7 +178,7 @@ bool CVT2_get_binary_comparable_desc(dsc* result, const dsc* arg1, const dsc* ar else { // Arguments are of different data types - *result = (compare_priority[arg1->dsc_dtype] > compare_priority[arg2->dsc_dtype]) ? *arg1 : *arg2; + *result = (CVT2_compare_priority[arg1->dsc_dtype] > CVT2_compare_priority[arg2->dsc_dtype]) ? *arg1 : *arg2; if (arg1->isExact() && arg2->isExact()) result->dsc_scale = MIN(arg1->dsc_scale, arg2->dsc_scale); @@ -187,7 +188,7 @@ bool CVT2_get_binary_comparable_desc(dsc* result, const dsc* arg1, const dsc* ar } -int CVT2_compare(const dsc* arg1, const dsc* arg2) +int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt) { /************************************** * @@ -285,6 +286,12 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) return 1; return -1; + case dtype_dec64: + return ((Decimal64*) p1)->compare(decSt, *(Decimal64*) p2); + + case dtype_dec128: + return ((Decimal128*) p1)->compare(decSt, *(Decimal128*) p2); + case dtype_boolean: return *p1 == *p2 ? 0 : *p1 < *p2 ? -1 : 1; @@ -342,8 +349,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) UCHAR* p1 = NULL; UCHAR* p2 = NULL; USHORT t1, t2; // unused later - USHORT length = CVT_get_string_ptr(arg1, &t1, &p1, NULL, 0); - USHORT length2 = CVT_get_string_ptr(arg2, &t2, &p2, NULL, 0); + USHORT length = CVT_get_string_ptr(arg1, &t1, &p1, NULL, 0, decSt); + USHORT length2 = CVT_get_string_ptr(arg2, &t2, &p2, NULL, 0, decSt); int fill = length - length2; const UCHAR pad = charset1 == ttype_binary || charset2 == ttype_binary ? '\0' : ' '; @@ -391,8 +398,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) // Handle heterogeneous compares - if (compare_priority[arg1->dsc_dtype] < compare_priority[arg2->dsc_dtype]) - return -CVT2_compare(arg2, arg1); + if (CVT2_compare_priority[arg1->dsc_dtype] < CVT2_compare_priority[arg2->dsc_dtype]) + return -CVT2_compare(arg2, arg1, decSt); // At this point, the type of arg1 is guaranteed to be "greater than" arg2, // in the sense that it is the preferred type for comparing the two. @@ -407,8 +414,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) SLONG datetime[2]; desc.dsc_length = sizeof(datetime); desc.dsc_address = (UCHAR*) datetime; - CVT_move(arg2, &desc); - return CVT2_compare(arg1, &desc); + CVT_move(arg2, &desc, 0); + return CVT2_compare(arg1, &desc, 0); } case dtype_sql_time: @@ -419,8 +426,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) SLONG atime; desc.dsc_length = sizeof(atime); desc.dsc_address = (UCHAR*) &atime; - CVT_move(arg2, &desc); - return CVT2_compare(arg1, &desc); + CVT_move(arg2, &desc, 0); + return CVT2_compare(arg1, &desc, 0); } case dtype_sql_date: @@ -431,8 +438,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) SLONG date; desc.dsc_length = sizeof(date); desc.dsc_address = (UCHAR*) &date; - CVT_move(arg2, &desc); - return CVT2_compare(arg1, &desc); + CVT_move(arg2, &desc, 0); + return CVT2_compare(arg1, &desc, 0); } case dtype_short: @@ -442,8 +449,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) scale = MIN(arg1->dsc_scale, arg2->dsc_scale); else scale = arg1->dsc_scale; - const SLONG temp1 = CVT_get_long(arg1, scale, ERR_post); - const SLONG temp2 = CVT_get_long(arg2, scale, ERR_post); + const SLONG temp1 = CVT_get_long(arg1, scale, decSt, ERR_post); + const SLONG temp2 = CVT_get_long(arg2, scale, decSt, ERR_post); if (temp1 == temp2) return 0; if (temp1 > temp2) @@ -460,8 +467,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) scale = MIN(arg1->dsc_scale, arg2->dsc_scale); else scale = arg1->dsc_scale; - const SINT64 temp1 = CVT_get_int64(arg1, scale, ERR_post); - const SINT64 temp2 = CVT_get_int64(arg2, scale, ERR_post); + const SINT64 temp1 = CVT_get_int64(arg1, scale, decSt, ERR_post); + const SINT64 temp2 = CVT_get_int64(arg2, scale, decSt, ERR_post); if (temp1 == temp2) return 0; if (temp1 > temp2) @@ -476,15 +483,15 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) scale = MIN(arg1->dsc_scale, arg2->dsc_scale); else scale = arg1->dsc_scale; - const SQUAD temp1 = CVT_get_quad(arg1, scale, ERR_post); - const SQUAD temp2 = CVT_get_quad(arg2, scale, ERR_post); + const SQUAD temp1 = CVT_get_quad(arg1, scale, decSt, ERR_post); + const SQUAD temp2 = CVT_get_quad(arg2, scale, decSt, ERR_post); return QUAD_COMPARE(&temp1, &temp2); } case dtype_real: { - const float temp1 = (float) CVT_get_double(arg1, ERR_post); - const float temp2 = (float) CVT_get_double(arg2, ERR_post); + const float temp1 = (float) CVT_get_double(arg1, decSt, ERR_post); + const float temp2 = (float) CVT_get_double(arg2, decSt, ERR_post); if (temp1 == temp2) return 0; if (temp1 > temp2) @@ -494,8 +501,8 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) case dtype_double: { - const double temp1 = CVT_get_double(arg1, ERR_post); - const double temp2 = CVT_get_double(arg2, ERR_post); + const double temp1 = CVT_get_double(arg1, decSt, ERR_post); + const double temp2 = CVT_get_double(arg2, decSt, ERR_post); if (temp1 == temp2) return 0; if (temp1 > temp2) @@ -503,8 +510,22 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) return -1; } + case dtype_dec64: + { + const Decimal64 temp1 = CVT_get_dec64(arg1, decSt, ERR_post); + const Decimal64 temp2 = CVT_get_dec64(arg2, decSt, ERR_post); + return temp1.compare(decSt, temp2); + } + + case dtype_dec128: + { + const Decimal128 temp1 = CVT_get_dec128(arg1, decSt, ERR_post); + const Decimal128 temp2 = CVT_get_dec128(arg2, decSt, ERR_post); + return temp1.compare(decSt, temp2); + } + case dtype_blob: - return CVT2_blob_compare(arg1, arg2); + return CVT2_blob_compare(arg1, arg2, decSt); case dtype_array: ERR_post(Arg::Gds(isc_wish_list) << Arg::Gds(isc_blobnotsup) << "compare"); @@ -515,7 +536,7 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) { UCHAR* p = NULL; USHORT t; // unused later - USHORT length = CVT_get_string_ptr(arg2, &t, &p, NULL, 0); + USHORT length = CVT_get_string_ptr(arg2, &t, &p, NULL, 0, decSt); USHORT l = MIN(arg1->dsc_length, length); int rc = memcmp(arg1->dsc_address, p, l); @@ -548,7 +569,7 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2) } -int CVT2_blob_compare(const dsc* arg1, const dsc* arg2) +int CVT2_blob_compare(const dsc* arg1, const dsc* arg2, DecimalStatus decSt) { /************************************** * @@ -709,7 +730,7 @@ int CVT2_blob_compare(const dsc* arg1, const dsc* arg2) UCHAR* p; MoveBuffer temp_str; - l2 = CVT2_make_string2(arg2, ttype1, &p, temp_str); + l2 = CVT2_make_string2(arg2, ttype1, &p, temp_str, decSt); blb* blob1 = blb::open(tdbb, tdbb->getRequest()->req_transaction, (bid*) arg1->dsc_address); @@ -734,7 +755,7 @@ int CVT2_blob_compare(const dsc* arg1, const dsc* arg2) } -USHORT CVT2_make_string2(const dsc* desc, USHORT to_interp, UCHAR** address, Jrd::MoveBuffer& temp) +USHORT CVT2_make_string2(const dsc* desc, USHORT to_interp, UCHAR** address, MoveBuffer& temp, DecimalStatus decSt) { /************************************** * @@ -813,7 +834,7 @@ USHORT CVT2_make_string2(const dsc* desc, USHORT to_interp, UCHAR** address, Jrd vary* vtmp = reinterpret_cast(temp_desc.dsc_address); temp_desc.dsc_dtype = dtype_varying; temp_desc.setTextType(to_interp); - CVT_move(desc, &temp_desc); + CVT_move(desc, &temp_desc, decSt); *address = reinterpret_cast(vtmp->vary_string); return vtmp->vary_length; diff --git a/src/jrd/cvt2_proto.h b/src/jrd/cvt2_proto.h index 95b3299065..c04f62439c 100644 --- a/src/jrd/cvt2_proto.h +++ b/src/jrd/cvt2_proto.h @@ -26,9 +26,11 @@ #include "../jrd/jrd.h" +extern const BYTE CVT2_compare_priority[]; + bool CVT2_get_binary_comparable_desc(dsc*, const dsc*, const dsc*); -int CVT2_compare(const dsc*, const dsc*); -int CVT2_blob_compare(const dsc*, const dsc*); -USHORT CVT2_make_string2(const dsc*, USHORT, UCHAR**, Jrd::MoveBuffer&); +int CVT2_compare(const dsc*, const dsc*, Firebird::DecimalStatus); +int CVT2_blob_compare(const dsc*, const dsc*, Firebird::DecimalStatus); +USHORT CVT2_make_string2(const dsc*, USHORT, UCHAR**, Jrd::MoveBuffer&, Firebird::DecimalStatus); #endif // JRD_CVT2_PROTO_H diff --git a/src/jrd/cvt_proto.h b/src/jrd/cvt_proto.h index e103910b12..2fee524a09 100644 --- a/src/jrd/cvt_proto.h +++ b/src/jrd/cvt_proto.h @@ -30,7 +30,7 @@ double CVT_date_to_double(const dsc*); void CVT_double_to_date(double, SLONG[2]); -UCHAR CVT_get_numeric(const UCHAR*, const USHORT, SSHORT*, double*); +UCHAR CVT_get_numeric(const UCHAR*, const USHORT, SSHORT*, void*); GDS_DATE CVT_get_sql_date(const dsc*); GDS_TIME CVT_get_sql_time(const dsc*); GDS_TIMESTAMP CVT_get_timestamp(const dsc*); @@ -65,15 +65,15 @@ namespace Jrd }; } -inline void CVT_move(const dsc* from, dsc* to) +inline void CVT_move(const dsc* from, dsc* to, Firebird::DecimalStatus decSt) { - CVT_move_common(from, to, &Jrd::EngineCallbacks::instance); + CVT_move_common(from, to, decSt, &Jrd::EngineCallbacks::instance); } inline USHORT CVT_get_string_ptr(const dsc* desc, USHORT* ttype, UCHAR** address, - vary* temp, USHORT length) + vary* temp, USHORT length, Firebird::DecimalStatus decSt) { - return CVT_get_string_ptr_common(desc, ttype, address, temp, length, + return CVT_get_string_ptr_common(desc, ttype, address, temp, length, decSt, &Jrd::EngineCallbacks::instance); } diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index e9ffc856cd..90b3d16123 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -1241,6 +1241,9 @@ USHORT DFW_assign_index_type(thread_db* tdbb, const Firebird::MetaName& name, SS return idx_numeric2; case dtype_boolean: return idx_boolean; + case dtype_dec64: + case dtype_dec128: + return idx_decimal; default: return idx_numeric; } @@ -1274,7 +1277,7 @@ void DFW_delete_deferred( jrd_tra* transaction, SavNumber sav_number) if (sav_number == -1) { DeferredWork* work; - while (work = transaction->tra_deferred_job->work) + while ((work = transaction->tra_deferred_job->work)) { delete work; } @@ -2264,7 +2267,7 @@ static bool clear_cache(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_t return true; case 3: - clearMappingCache(dbb->dbb_filename.c_str(), work->dfw_id); + Mapping::clearCache(dbb->dbb_filename.c_str(), work->dfw_id); break; } @@ -3714,13 +3717,14 @@ static bool create_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr // ASF: arg->dfw_id is RDB$TRIGGER_TYPE truncated to USHORT if ((arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB) { - MET_load_trigger(tdbb, NULL, work->dfw_name, - &tdbb->getAttachment()->att_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB]); + unsigned triggerKind = arg->dfw_id & ~TRIGGER_TYPE_DB; + MET_release_triggers(tdbb, &tdbb->getAttachment()->att_triggers[triggerKind]); + MET_load_db_triggers(tdbb, triggerKind); } else if ((arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DDL) { - MET_load_trigger(tdbb, NULL, work->dfw_name, - &tdbb->getAttachment()->att_ddl_triggers); + MET_release_triggers(tdbb, &tdbb->getAttachment()->att_ddl_triggers); + MET_load_ddl_triggers(tdbb); } } } @@ -6017,12 +6021,14 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr // ASF: arg->dfw_id is RDB$TRIGGER_TYPE truncated to USHORT if (arg && (arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB) { - MET_release_trigger(tdbb, - &tdbb->getAttachment()->att_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB], - work->dfw_name); - - MET_load_trigger(tdbb, NULL, work->dfw_name, - &tdbb->getAttachment()->att_triggers[arg->dfw_id & ~TRIGGER_TYPE_DB]); + unsigned triggerKind = arg->dfw_id & ~TRIGGER_TYPE_DB; + MET_release_triggers(tdbb, &tdbb->getAttachment()->att_triggers[triggerKind]); + MET_load_db_triggers(tdbb, triggerKind); + } + else if ((arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DDL) + { + MET_release_triggers(tdbb, &tdbb->getAttachment()->att_ddl_triggers); + MET_load_ddl_triggers(tdbb); } } } @@ -6452,7 +6458,7 @@ static string get_string(const dsc* desc) // Find the actual length of the string, searching until the claimed // end of the string, or the terminating \0, whichever comes first. - USHORT length = MOV_make_string(desc, ttype_metadata, &str, &temp, sizeof(temp)); + USHORT length = MOV_make_string(JRD_get_thread_data(), desc, ttype_metadata, &str, &temp, sizeof(temp)); const char* p = str; const char* const q = str + length; diff --git a/src/jrd/err.cpp b/src/jrd/err.cpp index 0f428ac2d4..4bea1b95ff 100644 --- a/src/jrd/err.cpp +++ b/src/jrd/err.cpp @@ -102,6 +102,26 @@ void ERR_bugcheck_msg(const TEXT* msg) } +void ERR_soft_bugcheck(int number, const TEXT* file, int line) +{ +/************************************** + * + * E R R _ s o f t _ b u g c h e c k + * + ************************************** + * + * Functional description + * Things seem to be going poorly today. + * Use this function instead of ERR_bugcheck in bugcheck conditions that do not affect + * whole server/database/attachment state. + * + **************************************/ + + fb_assert(false); + internal_error(isc_bug_check, number, file, line); +} + + void ERR_corrupt(int number) { /************************************** diff --git a/src/jrd/err_proto.h b/src/jrd/err_proto.h index c5964b6592..f6d28a6ede 100644 --- a/src/jrd/err_proto.h +++ b/src/jrd/err_proto.h @@ -50,6 +50,7 @@ void ERR_post_warning(const Firebird::Arg::StatusVector& v); void ERR_assert(const TEXT*, int); void ERR_bugcheck(int, const TEXT* = NULL, int = 0); void ERR_bugcheck_msg(const TEXT*); +void ERR_soft_bugcheck(int, const TEXT*, int); void ERR_corrupt(int); void ERR_error(int); void ERR_post(const Firebird::Arg::StatusVector& v); diff --git a/src/jrd/evl.cpp b/src/jrd/evl.cpp index 3f9f599193..99ea09aed4 100644 --- a/src/jrd/evl.cpp +++ b/src/jrd/evl.cpp @@ -148,7 +148,7 @@ dsc* EVL_assign_to(thread_db* tdbb, const ValueExprNode* node) const VariableNode* varNode; const FieldNode* fieldNode; - if ((paramNode = ExprNode::as(node))) + if ((paramNode = nodeAs(node))) { message = paramNode->message; arg_number = paramNode->argNumber; @@ -175,15 +175,15 @@ dsc* EVL_assign_to(thread_db* tdbb, const ValueExprNode* node) return &impure->vlu_desc; } - else if (ExprNode::is(node)) + else if (nodeIs(node)) return NULL; - else if ((varNode = ExprNode::as(node))) + else if ((varNode = nodeAs(node))) { // Calculate descriptor impure = request->getImpure(varNode->varDecl->impureOffset); return &impure->vlu_desc; } - else if ((fieldNode = ExprNode::as(node))) + else if ((fieldNode = nodeAs(node))) { record = request->req_rpb[fieldNode->fieldStream].rpb_record; @@ -202,7 +202,7 @@ dsc* EVL_assign_to(thread_db* tdbb, const ValueExprNode* node) return &impure->vlu_desc; } - BUGCHECK(229); // msg 229 EVL_assign_to: invalid operation + SOFT_BUGCHECK(229); // msg 229 EVL_assign_to: invalid operation return NULL; } @@ -261,7 +261,7 @@ RecordBitmap** EVL_bitmap(thread_db* tdbb, const InversionNode* node, RecordBitm (desc->isText() || desc->isDbKey())) { UCHAR* ptr = NULL; - const int length = MOV_get_string(desc, &ptr, NULL, 0); + const int length = MOV_get_string(tdbb, desc, &ptr, NULL, 0); if (length == sizeof(RecordNumber::Packed)) { @@ -290,7 +290,7 @@ RecordBitmap** EVL_bitmap(thread_db* tdbb, const InversionNode* node, RecordBitm } default: - BUGCHECK(230); // msg 230 EVL_bitmap: invalid operation + SOFT_BUGCHECK(230); // msg 230 EVL_bitmap: invalid operation } return NULL; @@ -426,6 +426,14 @@ void EVL_make_value(thread_db* tdbb, const dsc* desc, impure_value* value, Memor value->vlu_misc.vlu_double = *((double*) from.dsc_address); return; + case dtype_dec64: + value->vlu_misc.vlu_dec64 = *((Decimal64*) from.dsc_address); + return; + + case dtype_dec128: + value->vlu_misc.vlu_dec128 = *((Decimal128*) from.dsc_address); + return; + case dtype_timestamp: case dtype_quad: value->vlu_misc.vlu_dbkey[0] = ((SLONG*) from.dsc_address)[0]; @@ -459,7 +467,7 @@ void EVL_make_value(thread_db* tdbb, const dsc* desc, impure_value* value, Memor // temporary buffer. Since this will always be the result of a conversion, // this isn't a serious problem. - const USHORT length = MOV_get_string_ptr(&from, &ttype, &address, &temp, sizeof(temp)); + const USHORT length = MOV_get_string_ptr(tdbb, &from, &ttype, &address, &temp, sizeof(temp)); // Allocate a string block of sufficient size. @@ -539,7 +547,7 @@ void EVL_validate(thread_db* tdbb, const Item& item, const ItemInfo* itemInfo, d if (!fieldInfo.validationExpr->execute(tdbb, request) && !(request->req_flags & req_null)) { const USHORT length = desc_is_null ? 0 : - MOV_make_string(desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1); + MOV_make_string(tdbb, desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1); if (desc_is_null) value = NULL_STRING_MARK; diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index 910287d837..0c64c4d1f2 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -280,14 +280,14 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo SSHORT null = from_null ? -1 : 0; - if (!null && missing && MOV_compare(missing, from_desc) == 0) + if (!null && missing && MOV_compare(tdbb, missing, from_desc) == 0) null = -1; USHORT* impure_flags = NULL; const ParameterNode* toParam; const VariableNode* toVar; - if ((toParam = ExprNode::as(to))) + if ((toParam = nodeAs(to))) { const MessageNode* message = toParam->message; @@ -300,7 +300,7 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo impure_flags = request->getImpure( message->impureFlags + (sizeof(USHORT) * toParam->argNumber)); } - else if ((toVar = ExprNode::as(to))) + else if ((toVar = nodeAs(to))) { if (toVar->varInfo) { @@ -432,7 +432,7 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo // Handle the null flag as appropriate for fields and message arguments. - const FieldNode* toField = ExprNode::as(to); + const FieldNode* toField = nodeAs(to); if (toField) { Record* record = request->req_rpb[toField->fieldStream].rpb_record; @@ -793,10 +793,10 @@ void EXE_send(thread_db* tdbb, jrd_req* request, USHORT msg, ULONG length, const for (const NestConst* end = selectNode->statements.end(); ptr != end; ++ptr) { - const ReceiveNode* receiveNode = (*ptr)->as(); + const ReceiveNode* receiveNode = nodeAs(*ptr); message = receiveNode->message; - if (message->as()->messageNumber == msg) + if (nodeAs(message)->messageNumber == msg) { request->req_next = *ptr; break; @@ -911,7 +911,7 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request) { const JrdStatement* statement = request->getStatement(); - if (statement->fors.getCount() || request->req_ext_stmt) + if (statement->fors.getCount() || request->req_ext_resultset || request->req_ext_stmt) { Jrd::ContextPoolHolder context(tdbb, request->req_pool); jrd_req* old_request = tdbb->getRequest(); @@ -927,7 +927,10 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request) } if (request->req_ext_resultset) + { delete request->req_ext_resultset; + request->req_ext_resultset = NULL; + } while (request->req_ext_stmt) request->req_ext_stmt->close(tdbb); diff --git a/src/jrd/ext.cpp b/src/jrd/ext.cpp index dae4dfe752..bea2873a19 100644 --- a/src/jrd/ext.cpp +++ b/src/jrd/ext.cpp @@ -346,7 +346,7 @@ void EXT_fini(jrd_rel* relation, bool close_only) } -bool EXT_get(thread_db* /*tdbb*/, record_param* rpb, FB_UINT64& position) +bool EXT_get(thread_db* tdbb, record_param* rpb, FB_UINT64& position) { /************************************** * @@ -432,14 +432,14 @@ bool EXT_get(thread_db* /*tdbb*/, record_param* rpb, FB_UINT64& position) if (!desc_ptr->dsc_length || !field) continue; - const LiteralNode* literal = ExprNode::as(field->fld_missing_value); + const LiteralNode* literal = nodeAs(field->fld_missing_value); if (literal) { desc = *desc_ptr; desc.dsc_address = record->getData() + (IPTR) desc.dsc_address; - if (!MOV_compare(&literal->litDesc, &desc)) + if (!MOV_compare(tdbb, &literal->litDesc, &desc)) continue; } @@ -534,7 +534,7 @@ void EXT_store(thread_db* tdbb, record_param* rpb) if (field && !field->fld_computation && desc_ptr->dsc_length && record->isNull(i)) { UCHAR* p = record->getData() + (IPTR) desc_ptr->dsc_address; - LiteralNode* literal = ExprNode::as(field->fld_missing_value); + LiteralNode* literal = nodeAs(field->fld_missing_value); if (literal) { diff --git a/src/jrd/extds/InternalDS.cpp b/src/jrd/extds/InternalDS.cpp index e868604f17..0f2791086c 100644 --- a/src/jrd/extds/InternalDS.cpp +++ b/src/jrd/extds/InternalDS.cpp @@ -285,7 +285,7 @@ void InternalTransaction::doStart(FbStatusVector* status, thread_db* tdbb, Clump fb_assert(localTran); if (m_scope == traCommon && m_IntConnection.isCurrent()) - m_transaction = localTran->getInterface(); + m_transaction = localTran->getInterface(true); else { JAttachment* att = m_IntConnection.getJrdAtt(); diff --git a/src/jrd/extds/IscDS.cpp b/src/jrd/extds/IscDS.cpp index b11eb163ab..84152b9cbc 100644 --- a/src/jrd/extds/IscDS.cpp +++ b/src/jrd/extds/IscDS.cpp @@ -63,7 +63,6 @@ static RegisterFBProvider reg; static bool isConnectionBrokenError(FbStatusVector* status); static void parseSQLDA(XSQLDA* xsqlda, UCharBuffer& buff, Firebird::Array& descs); -static UCHAR sqlTypeToDscType(SSHORT sqlType); // IscProvider @@ -1658,7 +1657,7 @@ static void parseSQLDA(XSQLDA* xsqlda, UCharBuffer& buff, Firebird::Array & for (int i = 0; i < xsqlda->sqld; xVar++, i++) { - const UCHAR dtype = sqlTypeToDscType(xVar->sqltype & ~1); + const UCHAR dtype = fb_utils::sqlTypeToDscType(xVar->sqltype & ~1); xVar->sqltype |= 1; if (type_alignments[dtype]) @@ -1683,7 +1682,7 @@ static void parseSQLDA(XSQLDA* xsqlda, UCharBuffer& buff, Firebird::Array & for (int i = 0; i < xsqlda->sqld; xVar++, i++) { - const UCHAR dtype = sqlTypeToDscType(xVar->sqltype & ~1); + const UCHAR dtype = fb_utils::sqlTypeToDscType(xVar->sqltype & ~1); if (type_alignments[dtype]) offset = FB_ALIGN(offset, type_alignments[dtype]); @@ -1720,47 +1719,5 @@ static void parseSQLDA(XSQLDA* xsqlda, UCharBuffer& buff, Firebird::Array & } -static UCHAR sqlTypeToDscType(SSHORT sqlType) -{ - switch (sqlType) - { - case SQL_VARYING: - return dtype_varying; - case SQL_TEXT: - return dtype_text; - case SQL_NULL: - return dtype_text; - case SQL_DOUBLE: - return dtype_double; - case SQL_FLOAT: - return dtype_real; - case SQL_D_FLOAT: - return dtype_d_float; - case SQL_TYPE_DATE: - return dtype_sql_date; - case SQL_TYPE_TIME: - return dtype_sql_time; - case SQL_TIMESTAMP: - return dtype_timestamp; - case SQL_BLOB: - return dtype_blob; - case SQL_ARRAY: - return dtype_array; - case SQL_LONG: - return dtype_long; - case SQL_SHORT: - return dtype_short; - case SQL_INT64: - return dtype_int64; - case SQL_QUAD: - return dtype_quad; - case SQL_BOOLEAN: - return dtype_boolean; - default: - return dtype_unknown; - } -} - - } // namespace EDS diff --git a/src/jrd/flu.cpp b/src/jrd/flu.cpp index 9c15e47090..60d5d7e735 100644 --- a/src/jrd/flu.cpp +++ b/src/jrd/flu.cpp @@ -268,11 +268,20 @@ namespace Jrd return Module(); } + Module::~Module() + { + if (interMod) + { + Firebird::MutexLockGuard lg(modulesMutex, FB_FUNCTION); + interMod = NULL; // This makes RefPtr call release() + } + } + Module::InternalModule::~InternalModule() { - delete handle; + fb_assert(modulesMutex->locked()); - Firebird::MutexLockGuard lg(modulesMutex, FB_FUNCTION); + delete handle; for (FB_SIZE_T m = 0; m < loadedModules().getCount(); m++) { diff --git a/src/jrd/flu.h b/src/jrd/flu.h index 3dd8fc0dbc..9faabd0926 100644 --- a/src/jrd/flu.h +++ b/src/jrd/flu.h @@ -102,6 +102,8 @@ namespace Jrd : interMod(m.interMod) { } + ~Module(); + // used for UDF/BLOB Filter static FPTR_INT lookup(const char*, const char*, Firebird::SortedObjectsArray&); diff --git a/src/jrd/fun.epp b/src/jrd/fun.epp index 2efedbacb1..13521232ec 100644 --- a/src/jrd/fun.epp +++ b/src/jrd/fun.epp @@ -486,7 +486,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra { case dtype_short: { - const SSHORT s = MOV_get_long(input, (SSHORT) parameter->prm_desc.dsc_scale); + const SSHORT s = MOV_get_long(tdbb, input, (SSHORT) parameter->prm_desc.dsc_scale); if (parameter->prm_fun_mechanism == FUN_value) { // For (apparent) portability reasons, SHORT by value @@ -505,7 +505,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra break; case dtype_long: - l = MOV_get_long(input, (SSHORT) parameter->prm_desc.dsc_scale); + l = MOV_get_long(tdbb, input, (SSHORT) parameter->prm_desc.dsc_scale); if (parameter->prm_fun_mechanism == FUN_value) { *arg_ptr++ = (UDF_ARG)(IPTR) l; @@ -540,7 +540,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra case dtype_int64: { SINT64* pi64; - const SINT64 i64 = MOV_get_int64(input, (SSHORT) parameter->prm_desc.dsc_scale); + const SINT64 i64 = MOV_get_int64(tdbb, input, (SSHORT) parameter->prm_desc.dsc_scale); if (parameter->prm_fun_mechanism == FUN_value) { @@ -556,7 +556,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra case dtype_real: { - const float f = (float) MOV_get_double(input); + const float f = (float) MOV_get_double(tdbb, input); if (parameter->prm_fun_mechanism == FUN_value) { // For (apparent) portability reasons, FLOAT by value @@ -576,7 +576,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra break; case dtype_double: - d = MOV_get_double(input); + d = MOV_get_double(tdbb, input); double* dp; if (parameter->prm_fun_mechanism == FUN_value) { @@ -589,6 +589,36 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra *dp = d; break; + case dtype_dec64: + { + const Decimal64 d = MOV_get_dec64(tdbb, input); + if (parameter->prm_fun_mechanism == FUN_value) + { + Decimal64* dp = reinterpret_cast(arg_ptr); + *dp++ = d; + arg_ptr = reinterpret_cast(dp); + continue; + } + Decimal64* fp = (Decimal64*) temp_ptr; + *fp = d; + } + break; + + case dtype_dec128: + { + const Decimal128 d = MOV_get_dec128(tdbb, input); + if (parameter->prm_fun_mechanism == FUN_value) + { + Decimal128* dp = reinterpret_cast(arg_ptr); + *dp++ = d; + arg_ptr = reinterpret_cast(dp); + continue; + } + Decimal128* fp = (Decimal128*) temp_ptr; + *fp = d; + } + break; + case dtype_text: case dtype_dbkey: case dtype_cstring: @@ -742,8 +772,9 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra } else { - if (value->vlu_desc.dsc_dtype == dtype_double) + switch (value->vlu_desc.dsc_dtype) { + case dtype_double: if (isinf(value->vlu_misc.vlu_double)) { status_exception::raise(Arg::Gds(isc_expression_eval_err) << @@ -756,14 +787,45 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra Arg::Gds(isc_udf_fp_nan) << Arg::Str(function->getName().toString())); } + break; + + case dtype_dec64: + if (value->vlu_misc.vlu_dec64.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_dec64.isNan()) + { + status_exception::raise(Arg::Gds(isc_expression_eval_err) << + Arg::Gds(isc_udf_fp_nan) << + Arg::Str(function->getName().toString())); + } + break; + + case dtype_dec128: + if (value->vlu_misc.vlu_dec128.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_dec128.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; } while (array_stack.hasData()) - { delete[] array_stack.pop(); - } + blob_stack.close(); } // try @@ -1050,6 +1112,14 @@ static void invoke(thread_db* tdbb, value->vlu_misc.vlu_double = CALL_UDF(tdbb, function->fun_entrypoint, args); break; + case dtype_dec64: + value->vlu_misc.vlu_dec64 = CALL_UDF(tdbb, function->fun_entrypoint, args); + break; + + case dtype_dec128: + value->vlu_misc.vlu_dec128 = CALL_UDF(tdbb, function->fun_entrypoint, args); + break; + case dtype_timestamp: default: udfError = UeUnsupDtype; diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index ee5a32e159..1418e7ea61 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -314,16 +314,14 @@ void IDX_create_index(thread_db* tdbb, sort_key_def key_desc[2]; // Key sort description - key_desc[0].skd_dtype = SKD_bytes; + key_desc[0].setSkdLength(SKD_bytes, key_length); key_desc[0].skd_flags = SKD_ascending; - key_desc[0].skd_length = key_length; - key_desc[0].skd_offset = 0; + key_desc[0].setSkdOffset(); key_desc[0].skd_vary_offset = 0; // RecordNumber sort description - key_desc[1].skd_dtype = SKD_int64; + key_desc[1].setSkdLength(SKD_int64, sizeof(RecordNumber)); key_desc[1].skd_flags = SKD_ascending; - key_desc[1].skd_length = sizeof(RecordNumber); - key_desc[1].skd_offset = key_length; + key_desc[1].setSkdOffset(key_desc); key_desc[1].skd_vary_offset = 0; FPTR_REJECT_DUP_CALLBACK callback = (idx->idx_flags & idx_unique) ? duplicate_key : NULL; @@ -1110,7 +1108,7 @@ static idx_e check_duplicates(thread_db* tdbb, bool flag_rec = false; const dsc* desc_rec = BTR_eval_expression(tdbb, insertion_idx, rpb.rpb_record, flag_rec); - if (flag_rec && flag_idx && (MOV_compare(desc_rec, &desc1) == 0)) + if (flag_rec && flag_idx && (MOV_compare(tdbb, desc_rec, &desc1) == 0)) { result = idx_e_duplicate; break; @@ -1131,7 +1129,7 @@ static idx_e check_duplicates(thread_db* tdbb, field_id = record_idx->idx_rpt[i].idx_field; const bool flag_idx = EVL_field(relation_2, record, field_id, &desc2); - if (flag_rec != flag_idx || (flag_rec && (MOV_compare(&desc1, &desc2) != 0) )) + if (flag_rec != flag_idx || (flag_rec && (MOV_compare(tdbb, &desc1, &desc2) != 0) )) break; all_nulls = all_nulls && !flag_rec && !flag_idx; @@ -1564,7 +1562,7 @@ void IDX_modify_flag_uk_modified(thread_db* tdbb, const bool flag_org = EVL_field(org_rpb->rpb_relation, org_rpb->rpb_record, idx_desc->idx_field, &desc1); const bool flag_new = EVL_field(new_rpb->rpb_relation, new_rpb->rpb_record, idx_desc->idx_field, &desc2); - if (flag_org != flag_new || MOV_compare(&desc1, &desc2) != 0) + if (flag_org != flag_new || MOV_compare(tdbb, &desc1, &desc2) != 0) { new_rpb->rpb_flags |= rpb_uk_modified; CCH_RELEASE(tdbb, &window); diff --git a/src/jrd/inf.cpp b/src/jrd/inf.cpp index 66e3c97636..2373c90042 100644 --- a/src/jrd/inf.cpp +++ b/src/jrd/inf.cpp @@ -936,7 +936,7 @@ ULONG INF_request_info(const jrd_req* request, const ULONG item_length, const UC { const StmtNode* node = request->req_next; - if (node->is()) + if (nodeIs(node)) state = isc_info_req_select; else state = isc_info_req_receive; diff --git a/src/jrd/intl.cpp b/src/jrd/intl.cpp index bab0949ef2..a81c402b3d 100644 --- a/src/jrd/intl.cpp +++ b/src/jrd/intl.cpp @@ -609,11 +609,11 @@ int INTL_compare(thread_db* tdbb, const dsc* pText1, const dsc* pText2, ErrorFun UCHAR* p1; USHORT t1; - ULONG length1 = CVT_get_string_ptr(pText1, &t1, &p1, NULL, 0, err); + ULONG length1 = CVT_get_string_ptr(pText1, &t1, &p1, NULL, 0, tdbb->getAttachment()->att_dec_status, err); UCHAR* p2; USHORT t2; - ULONG length2 = CVT_get_string_ptr(pText2, &t2, &p2, NULL, 0, err); + ULONG length2 = CVT_get_string_ptr(pText2, &t2, &p2, NULL, 0, tdbb->getAttachment()->att_dec_status, err); // YYY - by SQL II compare_type must be explicit in the // SQL statement if there is any doubt @@ -819,7 +819,7 @@ int INTL_convert_string(dsc* to, const dsc* from, ErrorFunction err) UCHAR* from_ptr; USHORT from_type; - const USHORT from_len = CVT_get_string_ptr(from, &from_type, &from_ptr, NULL, 0, err); + const USHORT from_len = CVT_get_string_ptr(from, &from_type, &from_ptr, NULL, 0, tdbb->getAttachment()->att_dec_status, err); const ULONG to_size = TEXT_LEN(to); ULONG from_fill, to_fill; diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index c169f53c17..7e0bba6f64 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -279,13 +279,15 @@ void JAttachment::addRef() int JAttachment::release() { +#ifdef DEV_BUILD + int r = --refCounter; #ifdef DEBUG_ATT_COUNTERS - int x = --refCounter; ReferenceCounterDebugger* my = ReferenceCounterDebugger::get(DEB_RLS_JATT); const char* point = my ? my->rcd_point : " "; - fprintf(stderr, "Release from <%s> att %p cnt=%d\n", point, this, x); - if (x != 0) - return 1; + fprintf(stderr, "Release from <%s> att %p cnt=%d\n", point, this, r); +#endif + if (r != 0) + return r; #else if (--refCounter != 0) return 1; @@ -1066,8 +1068,8 @@ static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tr static void release_attachment(thread_db*, Jrd::Attachment*); static void rollback(thread_db*, jrd_tra*, const bool); static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0); -static void getUserInfo(UserId&, const DatabaseOptions&, const char*, const char*, - const RefPtr*, bool, IAttachment*, ICryptKeyCallback*); +static void getUserInfo(UserId&, const DatabaseOptions&, const char*, + const RefPtr*, bool, Mapping& mapping); static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM); @@ -1080,7 +1082,9 @@ TraceFailedConnection::TraceFailedConnection(const char* filename, const Databas m_filename(filename), m_options(options) { - getUserInfo(m_id, *m_options, m_filename, NULL, NULL, false, NULL, NULL); + Mapping mapping(Mapping::MAP_ERROR_HANDLER, NULL); + mapping.setAuthBlock(m_options->dpb_auth_block); + getUserInfo(m_id, *m_options, m_filename, NULL, false, mapping); } @@ -1359,12 +1363,16 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch PathName org_filename, expanded_name; bool is_alias = false; MutexEnsureUnlock guardDbInit(dbInitMutex, FB_FUNCTION); + Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, cryptCallback); try { // Process database parameter block options.get(dpb, dpb_length, invalid_client_SQL_dialect); + // And provide info about auth block to mapping + mapping.setAuthBlock(options.dpb_auth_block); + if (options.dpb_org_filename.hasData()) org_filename = options.dpb_org_filename; else @@ -1396,6 +1404,9 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch if (ISC_check_if_remote(expanded_name, true)) ERR_post(Arg::Gds(isc_unavailable)); + // We are ready to setup security database - before entering guardDbInit!!! + mapping.setSecurityDbAlias(config->getSecurityDatabase(), expanded_name.c_str()); + #ifdef WIN_NT guardDbInit.enter(); // Required to correctly expand name of just created database @@ -1660,8 +1671,8 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch jAtt->getStable()->manualUnlock(attachment->att_flags); try { - getUserInfo(userId, options, filename, expanded_name.c_str(), - &config, false, jAtt, cryptCallback); + mapping.setDb(filename, expanded_name.c_str(), jAtt); + getUserInfo(userId, options, filename, &config, false, mapping); } catch(const Exception&) { @@ -1953,6 +1964,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch filename, options, false, user_status); } + mapping.clearMainHandle(); unwindAttach(tdbb, ex, user_status, attachment, dbb, existingId); } } @@ -2447,12 +2459,14 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch PathName org_filename, expanded_name; bool is_alias = false; Firebird::RefPtr config; + Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, cryptCallback); try { // Process database parameter block bool invalid_client_SQL_dialect = false; options.get(dpb, dpb_length, invalid_client_SQL_dialect); + mapping.setAuthBlock(options.dpb_auth_block); if (!invalid_client_SQL_dialect && options.dpb_sql_dialect == 99) { options.dpb_sql_dialect = 0; } @@ -2490,7 +2504,9 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch ERR_post(Arg::Gds(isc_unavailable)); // Check for correct credentials supplied - getUserInfo(userId, options, filename, NULL, &config, true, nullptr, cryptCallback); + mapping.setSecurityDbAlias(config->getSecurityDatabase(), expanded_name.c_str()); + mapping.setDb(filename, expanded_name.c_str(), nullptr); + getUserInfo(userId, options, filename, &config, true, mapping); #ifdef WIN_NT guardDbInit.enter(); // Required to correctly expand name of just created database @@ -2817,6 +2833,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch trace_failed_attach(attachment ? attachment->att_trace_manager : NULL, filename, options, true, user_status); + mapping.clearMainHandle(); unwindAttach(tdbb, ex, user_status, attachment, dbb, false); } } @@ -4188,7 +4205,7 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const // Do not put it into separate shutdown thread - during shutdown of TraceManager // PluginManager wants to lock a mutex, which is sometimes already locked in current thread TraceManager::shutdown(); - shutdownMappingIpc(); + Mapping::shutdownIpc(); } catch (const Exception& ex) { @@ -4235,9 +4252,17 @@ JTransaction* JAttachment::startTransaction(CheckStatusWrapper* user_status, successful_completion(user_status); - JTransaction* jt = FB_NEW JTransaction(tra, getStable()); - tra->setInterface(jt); - jt->addRef(); + JTransaction* jt = tra->getInterface(false); + + if (jt) + tra->tra_flags &= ~TRA_own_interface; + else + { + jt = FB_NEW JTransaction(tra, getStable()); + tra->setInterface(jt); + jt->addRef(); + } + return jt; } @@ -7337,9 +7362,8 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status @param cryptCb **/ -static void getUserInfo(UserId& user, const DatabaseOptions& options, - const char* aliasName, const char* dbName, const RefPtr* config, bool creating, - IAttachment* iAtt, ICryptKeyCallback* cryptCb) +static void getUserInfo(UserId& user, const DatabaseOptions& options, const char* aliasName, + const RefPtr* config, bool creating, Mapping& mapping) { bool wheel = false; int id = -1, group = -1; // CVC: This var contained trash @@ -7365,9 +7389,10 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, } else if (options.dpb_auth_block.hasData()) { - if (mapUser(true, name, trusted_role, &auth_method, &user.usr_auth_block, NULL, - options.dpb_auth_block, aliasName, dbName, - (config ? (*config)->getSecurityDatabase() : NULL), "", cryptCb, iAtt) & MAPUSER_MAP_DOWN) + mapping.needAuthMethod(auth_method); + mapping.needAuthBlock(user.usr_auth_block); + + if (mapping.mapUser(name, trusted_role) & Mapping::MAP_DOWN) { user.setFlag(USR_mapdown); } diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index d07c209fe1..16aca4f54a 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -67,9 +67,10 @@ #endif #define DEBUG -#define BUGCHECK(number) ERR_bugcheck (number, __FILE__, __LINE__) -#define CORRUPT(number) ERR_corrupt (number) -#define IBERROR(number) ERR_error (number) +#define BUGCHECK(number) ERR_bugcheck(number, __FILE__, __LINE__) +#define SOFT_BUGCHECK(number) ERR_soft_bugcheck(number, __FILE__, __LINE__) +#define CORRUPT(number) ERR_corrupt(number) +#define IBERROR(number) ERR_error(number) #define BLKCHK(blk, type) if (!blk->checkHandle()) BUGCHECK(147) diff --git a/src/jrd/mov.cpp b/src/jrd/mov.cpp index 816daa1409..1b9d85803c 100644 --- a/src/jrd/mov.cpp +++ b/src/jrd/mov.cpp @@ -42,7 +42,7 @@ using namespace Firebird; -int MOV_compare(const dsc* arg1, const dsc* arg2) +int MOV_compare(Jrd::thread_db* tdbb, const dsc* arg1, const dsc* arg2) { /************************************** * @@ -55,7 +55,7 @@ int MOV_compare(const dsc* arg1, const dsc* arg2) * **************************************/ - return CVT2_compare(arg1, arg2); + return CVT2_compare(arg1, arg2, tdbb->getAttachment()->att_dec_status); } @@ -102,7 +102,7 @@ bool MOV_get_boolean(const dsc* desc) } -double MOV_get_double(const dsc* desc) +double MOV_get_double(Jrd::thread_db* tdbb, const dsc* desc) { /************************************** * @@ -115,11 +115,11 @@ double MOV_get_double(const dsc* desc) * **************************************/ - return CVT_get_double(desc, ERR_post); + return CVT_get_double(desc, tdbb->getAttachment()->att_dec_status, ERR_post); } -SLONG MOV_get_long(const dsc* desc, SSHORT scale) +SLONG MOV_get_long(Jrd::thread_db* tdbb, const dsc* desc, SSHORT scale) { /************************************** * @@ -133,11 +133,11 @@ SLONG MOV_get_long(const dsc* desc, SSHORT scale) * **************************************/ - return CVT_get_long(desc, scale, ERR_post); + return CVT_get_long(desc, scale, tdbb->getAttachment()->att_dec_status, ERR_post); } -SINT64 MOV_get_int64(const dsc* desc, SSHORT scale) +SINT64 MOV_get_int64(Jrd::thread_db* tdbb, const dsc* desc, SSHORT scale) { /************************************** * @@ -151,11 +151,11 @@ SINT64 MOV_get_int64(const dsc* desc, SSHORT scale) * **************************************/ - return CVT_get_int64(desc, scale, ERR_post); + return CVT_get_int64(desc, scale, tdbb->getAttachment()->att_dec_status, ERR_post); } -void MOV_get_metaname(const dsc* desc, MetaName& name) +void MOV_get_metaname(Jrd::thread_db* tdbb, const dsc* desc, MetaName& name) { /************************************** * @@ -172,7 +172,7 @@ void MOV_get_metaname(const dsc* desc, MetaName& name) USHORT ttype; UCHAR* ptr = NULL; - const USHORT length = CVT_get_string_ptr(desc, &ttype, &ptr, NULL, 0); + const USHORT length = CVT_get_string_ptr(desc, &ttype, &ptr, NULL, 0, tdbb->getAttachment()->att_dec_status); fb_assert(length && ptr); fb_assert(length <= MAX_SQL_IDENTIFIER_LEN); @@ -182,7 +182,7 @@ void MOV_get_metaname(const dsc* desc, MetaName& name) } -SQUAD MOV_get_quad(const dsc* desc, SSHORT scale) +SQUAD MOV_get_quad(Jrd::thread_db* tdbb, const dsc* desc, SSHORT scale) { /************************************** * @@ -196,11 +196,12 @@ SQUAD MOV_get_quad(const dsc* desc, SSHORT scale) * **************************************/ - return CVT_get_quad(desc, scale, ERR_post); + return CVT_get_quad(desc, scale, tdbb->getAttachment()->att_dec_status, ERR_post); } -int MOV_get_string_ptr(const dsc* desc, +int MOV_get_string_ptr(Jrd::thread_db* tdbb, + const dsc* desc, USHORT* ttype, UCHAR** address, vary* temp, USHORT length) { @@ -221,11 +222,11 @@ int MOV_get_string_ptr(const dsc* desc, * **************************************/ - return CVT_get_string_ptr(desc, ttype, address, temp, length); + return CVT_get_string_ptr(desc, ttype, address, temp, length, tdbb->getAttachment()->att_dec_status); } -int MOV_get_string(const dsc* desc, UCHAR** address, vary* temp, USHORT length) +int MOV_get_string(Jrd::thread_db* tdbb, const dsc* desc, UCHAR** address, vary* temp, USHORT length) { /************************************** * @@ -238,7 +239,7 @@ int MOV_get_string(const dsc* desc, UCHAR** address, vary* temp, USHORT length) **************************************/ USHORT ttype; - return MOV_get_string_ptr(desc, &ttype, address, temp, length); + return MOV_get_string_ptr(tdbb, desc, &ttype, address, temp, length); } @@ -293,7 +294,8 @@ GDS_TIMESTAMP MOV_get_timestamp(const dsc* desc) } -int MOV_make_string(const dsc* desc, +int MOV_make_string(Jrd::thread_db* tdbb, + const dsc* desc, USHORT ttype, const char** address, vary* temp, @@ -318,7 +320,7 @@ int MOV_make_string(const dsc* desc, * **************************************/ - return CVT_make_string(desc, ttype, address, temp, length, ERR_post); + return CVT_make_string(desc, ttype, address, temp, length, tdbb->getAttachment()->att_dec_status, ERR_post); } @@ -380,7 +382,7 @@ int MOV_make_string2(Jrd::thread_db* tdbb, return size; } - return CVT2_make_string2(desc, ttype, address, buffer); + return CVT2_make_string2(desc, ttype, address, buffer, tdbb->getAttachment()->att_dec_status); } @@ -410,9 +412,34 @@ void MOV_move(Jrd::thread_db* tdbb, /*const*/ dsc* from, dsc* to) if (DTYPE_IS_BLOB_OR_QUAD(from->dsc_dtype) || DTYPE_IS_BLOB_OR_QUAD(to->dsc_dtype)) Jrd::blb::move(tdbb, from, to, NULL); else - CVT_move(from, to); + CVT_move(from, to, tdbb->getAttachment()->att_dec_status); } + +Decimal64 MOV_get_dec64(Jrd::thread_db* tdbb, const dsc* desc) +{ +/************************************** + * + * M O V _ g e t _ d e c 6 4 + * + **************************************/ + + return CVT_get_dec64(desc, tdbb->getAttachment()->att_dec_status, ERR_post); +} + + +Decimal128 MOV_get_dec128(Jrd::thread_db* tdbb, const dsc* desc) +{ +/************************************** + * + * M O V _ g e t _ d e c 1 2 8 + * + **************************************/ + + return CVT_get_dec128(desc, tdbb->getAttachment()->att_dec_status, ERR_post); +} + + namespace Jrd { diff --git a/src/jrd/mov_proto.h b/src/jrd/mov_proto.h index 7d97076ec7..b68002a5ba 100644 --- a/src/jrd/mov_proto.h +++ b/src/jrd/mov_proto.h @@ -31,26 +31,27 @@ struct dsc; struct vary; -int MOV_compare(const dsc*, const dsc*); +int MOV_compare(Jrd::thread_db*, const dsc*, const dsc*); double MOV_date_to_double(const dsc*); void MOV_double_to_date(double, SLONG[2]); bool MOV_get_boolean(const dsc*); -double MOV_get_double(const dsc*); -SLONG MOV_get_long(const dsc*, SSHORT); -void MOV_get_metaname(const dsc*, Firebird::MetaName&); -SQUAD MOV_get_quad(const dsc*, SSHORT); -SINT64 MOV_get_int64(const dsc*, SSHORT); -int MOV_get_string_ptr(const dsc*, USHORT*, UCHAR**, vary*, - USHORT); -int MOV_get_string(const dsc*, UCHAR**, vary*, USHORT); +double MOV_get_double(Jrd::thread_db*, const dsc*); +SLONG MOV_get_long(Jrd::thread_db*, const dsc*, SSHORT); +void MOV_get_metaname(Jrd::thread_db*, const dsc*, Firebird::MetaName&); +SQUAD MOV_get_quad(Jrd::thread_db*, const dsc*, SSHORT); +SINT64 MOV_get_int64(Jrd::thread_db*, const dsc*, SSHORT); +int MOV_get_string_ptr(Jrd::thread_db*, const dsc*, USHORT*, UCHAR**, vary*, USHORT); +int MOV_get_string(Jrd::thread_db*, const dsc*, UCHAR**, vary*, USHORT); GDS_DATE MOV_get_sql_date(const dsc*); GDS_TIME MOV_get_sql_time(const dsc*); GDS_TIMESTAMP MOV_get_timestamp(const dsc*); -int MOV_make_string(const dsc*, USHORT, const char**, vary*, USHORT); +int MOV_make_string(Jrd::thread_db*, const dsc*, USHORT, const char**, vary*, USHORT); int MOV_make_string2(Jrd::thread_db*, const dsc*, USHORT, UCHAR**, Jrd::MoveBuffer&, bool = true); 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*); +Firebird::Decimal64 MOV_get_dec64(Jrd::thread_db*, const dsc*); +Firebird::Decimal128 MOV_get_dec128(Jrd::thread_db*, const dsc*); namespace Jrd { diff --git a/src/jrd/opt.cpp b/src/jrd/opt.cpp index aa70131986..dd4442255f 100644 --- a/src/jrd/opt.cpp +++ b/src/jrd/opt.cpp @@ -394,7 +394,9 @@ static const UCHAR sort_dtypes[] = 0, // dtype_array SKD_int64, // dtype_int64 SKD_text, // dtype_dbkey - use text sort for backward compatibility - SKD_bytes // dtype_boolean + SKD_bytes, // dtype_boolean + SKD_dec64, // dtype_dec64 + SKD_dec128 // dtype_dec128 }; @@ -1115,8 +1117,8 @@ static void check_sorts(RseNode* rse) for (; project_ptr != project_end; ++project_ptr) { - const FieldNode* sortField = (*sort_ptr)->as(); - const FieldNode* projectField = (*project_ptr)->as(); + const FieldNode* sortField = nodeAs(*sort_ptr); + const FieldNode* projectField = nodeAs(*project_ptr); if (sortField && projectField && sortField->fieldStream == projectField->fieldStream && @@ -1155,7 +1157,7 @@ static void check_sorts(RseNode* rse) { const FieldNode* sortField; - if ((sortField = (*sort_ptr)->as())) + if ((sortField = nodeAs(*sort_ptr))) { // Get stream for this field at this position. const StreamType current_stream = sortField->fieldStream; @@ -1327,8 +1329,8 @@ static SLONG decompose(thread_db* tdbb, BoolExprNode* boolNode, BoolExprNodeStac **************************************/ DEV_BLKCHK(csb, type_csb); - BinaryBoolNode* binaryNode = boolNode->as(); - ComparativeBoolNode* cmpNode = boolNode->as(); + BinaryBoolNode* binaryNode = nodeAs(boolNode); + ComparativeBoolNode* cmpNode = nodeAs(boolNode); if (binaryNode) { @@ -1467,17 +1469,17 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc if (boolean->nodFlags & ExprNode::FLAG_DEOPTIMIZE) continue; - ComparativeBoolNode* const cmpNode = boolean->as(); + ComparativeBoolNode* const cmpNode = nodeAs(boolean); if (!cmpNode || cmpNode->blrOp != blr_eql) continue; ValueExprNode* const node1 = cmpNode->arg1; - if (!node1->is()) + if (!nodeIs(node1)) continue; ValueExprNode* const node2 = cmpNode->arg2; - if (!node2->is()) + if (!nodeIs(node2)) continue; for (eq_class = classes.begin(); eq_class != classes.end(); ++eq_class) @@ -1560,7 +1562,7 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc for (BoolExprNodeStack::iterator iter(org_stack); iter.hasData(); ++iter) { BoolExprNode* const boolean = iter.object(); - ComparativeBoolNode* const cmpNode = boolean->as(); + ComparativeBoolNode* const cmpNode = nodeAs(boolean); ValueExprNode* node1; ValueExprNode* node2; @@ -1578,7 +1580,7 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc bool reverse = false; - if (!node1->is()) + if (!nodeIs(node1)) { ValueExprNode* swap_node = node1; node1 = node2; @@ -1586,10 +1588,10 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc reverse = true; } - if (!node1->is()) + if (!nodeIs(node1)) continue; - if (!node2->is() && !node2->is() && !node2->is()) + if (!nodeIs(node2) && !nodeIs(node2) && !nodeIs(node2)) continue; for (eq_class = classes.begin(); eq_class != classes.end(); ++eq_class) @@ -1881,7 +1883,7 @@ void OPT_gen_aggregate_distincts(thread_db* tdbb, CompilerScratch* csb, MapNode* for (const NestConst* const end = map->sourceList.end(); ptr != end; ++ptr) { ValueExprNode* from = *ptr; - AggNode* aggNode = from->as(); + AggNode* aggNode = nodeAs(from); if (aggNode && aggNode->distinct) { @@ -1900,39 +1902,36 @@ void OPT_gen_aggregate_distincts(thread_db* tdbb, CompilerScratch* csb, MapNode* desc->getTextType() != ttype_binary && desc->getTextType() != ttype_ascii; sort_key_def* sort_key = asb->keyItems.getBuffer(asb->intl ? 2 : 1); - sort_key->skd_offset = 0; + sort_key->setSkdOffset(); if (asb->intl) { const USHORT key_length = ROUNDUP(INTL_key_length(tdbb, INTL_TEXT_TO_INDEX(desc->getTextType()), desc->getStringLength()), sizeof(SINT64)); - sort_key->skd_dtype = SKD_bytes; + sort_key->setSkdLength(SKD_bytes, key_length); sort_key->skd_flags = SKD_ascending; - sort_key->skd_length = key_length; - sort_key->skd_offset = 0; sort_key->skd_vary_offset = 0; ++sort_key; - asb->length = sort_key->skd_offset = key_length; + sort_key->setSkdOffset(&sort_key[-1]); + asb->length = sort_key->getSkdOffset(); } fb_assert(desc->dsc_dtype < FB_NELEM(sort_dtypes)); - sort_key->skd_dtype = sort_dtypes[desc->dsc_dtype]; + sort_key->setSkdLength(sort_dtypes[desc->dsc_dtype], desc->dsc_length); if (!sort_key->skd_dtype) ERR_post(Arg::Gds(isc_invalid_sort_datatype) << Arg::Str(DSC_dtype_tostring(desc->dsc_dtype))); - sort_key->skd_length = desc->dsc_length; - if (desc->dsc_dtype == dtype_varying) { // allocate space to store varying length - sort_key->skd_vary_offset = sort_key->skd_offset + ROUNDUP(desc->dsc_length, sizeof(SLONG)); + sort_key->skd_vary_offset = sort_key->getSkdOffset() + ROUNDUP(desc->dsc_length, sizeof(SLONG)); asb->length = sort_key->skd_vary_offset + sizeof(USHORT); } else - asb->length += sort_key->skd_length; + asb->length += sort_key->getSkdLength(); asb->length = ROUNDUP(asb->length, sizeof(SLONG)); // dimitr: allocate an extra longword for the purely artificial counter, @@ -2446,7 +2445,7 @@ SortedStream* OPT_gen_sort(thread_db* tdbb, CompilerScratch* csb, const StreamLi node_ptr != end_node; ++node_ptr) { - FieldNode* fieldNode = (*node_ptr)->as(); + FieldNode* fieldNode = nodeAs(*node_ptr); if (fieldNode && fieldNode->fieldStream == *ptr && fieldNode->fieldId == id) { @@ -2454,7 +2453,8 @@ SortedStream* OPT_gen_sort(thread_db* tdbb, CompilerScratch* csb, const StreamLi fieldNode->getDesc(tdbb, csb, desc); // International type text has a computed key - if (IS_INTL_DATA(desc)) + // Different decimal float values sometimes have same keys + if (IS_INTL_DATA(desc) || desc->isDecFloat()) break; --items; @@ -2478,7 +2478,7 @@ SortedStream* OPT_gen_sort(thread_db* tdbb, CompilerScratch* csb, const StreamLi if (sort->unique) map->flags |= SortedStream::FLAG_UNIQUE; - ULONG map_length = 0; + sort_key_def* prev_key = nullptr; // Loop thru sort keys building sort keys. Actually, to handle null values // correctly, two sort keys are made for each field, one for the null flag @@ -2519,14 +2519,9 @@ SortedStream* OPT_gen_sort(thread_db* tdbb, CompilerScratch* csb, const StreamLi } // Make key for null flag + sort_key->setSkdLength(SKD_text, 1); + sort_key->setSkdOffset(prev_key); -#ifndef WORDS_BIGENDIAN - map_length = ROUNDUP(map_length, sizeof(SLONG)); -#endif - const ULONG flag_offset = map_length++; - sort_key->skd_offset = flag_offset; - sort_key->skd_dtype = SKD_text; - sort_key->skd_length = 1; // Handle nulls placement sort_key->skd_flags = SKD_ascending; @@ -2534,22 +2529,15 @@ SortedStream* OPT_gen_sort(thread_db* tdbb, CompilerScratch* csb, const StreamLi if ((*nullOrder == rse_nulls_default && !*descending) || *nullOrder == rse_nulls_first) sort_key->skd_flags |= SKD_descending; - ++sort_key; + prev_key = sort_key++; // Make key for sort key proper -#ifndef WORDS_BIGENDIAN - map_length = ROUNDUP(map_length, sizeof(SLONG)); -#else - if (desc->dsc_dtype >= dtype_aligned) - map_length = FB_ALIGN(map_length, type_alignments[desc->dsc_dtype]); -#endif - - sort_key->skd_offset = map_length; + fb_assert(desc->dsc_dtype < FB_NELEM(sort_dtypes)); + sort_key->setSkdLength(sort_dtypes[desc->dsc_dtype], desc->dsc_length); + sort_key->setSkdOffset(&sort_key[-1], desc); sort_key->skd_flags = SKD_ascending; if (*descending) sort_key->skd_flags |= SKD_descending; - fb_assert(desc->dsc_dtype < FB_NELEM(sort_dtypes)); - sort_key->skd_dtype = sort_dtypes[desc->dsc_dtype]; if (!sort_key->skd_dtype) ERR_post(Arg::Gds(isc_invalid_sort_datatype) << Arg::Str(DSC_dtype_tostring(desc->dsc_dtype))); @@ -2560,25 +2548,25 @@ SortedStream* OPT_gen_sort(thread_db* tdbb, CompilerScratch* csb, const StreamLi sort_key->skd_flags |= SKD_binary; } - sort_key->skd_length = desc->dsc_length; - ++sort_key; map_item->clear(); map_item->node = node; - map_item->flagOffset = flag_offset; + map_item->flagOffset = prev_key->getSkdOffset(); map_item->desc = *desc; - map_item->desc.dsc_address = (UCHAR*)(IPTR) map_length; - map_length += desc->dsc_length; + map_item->desc.dsc_address = (UCHAR*)(IPTR) sort_key->getSkdOffset(); + + prev_key = sort_key++; FieldNode* fieldNode; - if ((fieldNode = node->as())) + if ((fieldNode = nodeAs(node))) { map_item->stream = fieldNode->fieldStream; map_item->fieldId = fieldNode->fieldId; } } - map_length = ROUNDUP(map_length, sizeof(SLONG)); + fb_assert(prev_key); + ULONG map_length = prev_key ? ROUNDUP(prev_key->getSkdOffset() + prev_key->getSkdLength(), sizeof(SLONG)) : 0; map->keyLength = map_length; ULONG flag_offset = map_length; map_length += stream_list.getCount(); @@ -2596,6 +2584,7 @@ SortedStream* OPT_gen_sort(thread_db* tdbb, CompilerScratch* csb, const StreamLi IBERROR(157); // msg 157 cannot sort on a field that does not exist if (desc->dsc_dtype >= dtype_aligned) map_length = FB_ALIGN(map_length, type_alignments[desc->dsc_dtype]); + map_item->clear(); map_item->fieldId = (SSHORT) id; map_item->stream = stream; @@ -2759,7 +2748,7 @@ static bool gen_equi_join(thread_db* tdbb, OptimizerBlk* opt, RiverList& org_riv continue; BoolExprNode* const node = tail->opt_conjunct_node; - ComparativeBoolNode* cmpNode = node->as(); + ComparativeBoolNode* cmpNode = nodeAs(node); if (!cmpNode || (cmpNode->blrOp != blr_eql && cmpNode->blrOp != blr_equiv)) continue; @@ -3088,7 +3077,7 @@ static BoolExprNode* make_inference_node(CompilerScratch* csb, BoolExprNode* boo thread_db* tdbb = JRD_get_thread_data(); DEV_BLKCHK(csb, type_csb); - ComparativeBoolNode* cmpNode = boolean->as(); + ComparativeBoolNode* cmpNode = nodeAs(boolean); fb_assert(cmpNode); // see our caller // Clone the input predicate @@ -3136,8 +3125,8 @@ static bool map_equal(const ValueExprNode* field1, const ValueExprNode* field2, * Order of the input fields is important. * **************************************/ - const FieldNode* fieldNode1 = field1->as(); - const FieldNode* fieldNode2 = field2->as(); + const FieldNode* fieldNode1 = nodeAs(field1); + const FieldNode* fieldNode2 = nodeAs(field2); if (!fieldNode1 || !fieldNode2) return false; @@ -3150,8 +3139,8 @@ static bool map_equal(const ValueExprNode* field1, const ValueExprNode* field2, sourcePtr != sourceEnd; ++sourcePtr, ++targetPtr) { - const FieldNode* mapFrom = (*sourcePtr)->as(); - const FieldNode* mapTo = (*targetPtr)->as(); + const FieldNode* mapFrom = nodeAs(*sourcePtr); + const FieldNode* mapTo = nodeAs(*targetPtr); if (!mapFrom || !mapTo) continue; @@ -3241,8 +3230,8 @@ static bool node_equality(const ValueExprNode* node1, const ValueExprNode* node2 if (node1 == node2) return true; - const FieldNode* fieldNode1 = node1->as(); - const FieldNode* fieldNode2 = node2->as(); + const FieldNode* fieldNode1 = nodeAs(node1); + const FieldNode* fieldNode2 = nodeAs(node2); if (fieldNode1 && fieldNode2) { @@ -3267,8 +3256,8 @@ static bool node_equality(const BoolExprNode* node1, const BoolExprNode* node2) if (node1 == node2) return true; - const ComparativeBoolNode* cmpNode = node1->as(); - const ComparativeBoolNode* cmpNode2 = node2->as(); + const ComparativeBoolNode* cmpNode = nodeAs(node1); + const ComparativeBoolNode* cmpNode2 = nodeAs(node2); if (cmpNode && cmpNode2 && cmpNode->blrOp == cmpNode2->blrOp && (cmpNode->blrOp == blr_eql || cmpNode->blrOp == blr_equiv)) @@ -3318,17 +3307,17 @@ static ValueExprNode* optimize_like(thread_db* tdbb, CompilerScratch* csb, Compa // if the pattern string or the escape string can't be // evaluated at compile time, forget it - if (!pattern_node->is() || (escape_node && !escape_node->is())) + if (!nodeIs(pattern_node) || (escape_node && !nodeIs(escape_node))) return NULL; dsc match_desc; match_node->getDesc(tdbb, csb, &match_desc); - dsc* pattern_desc = &pattern_node->as()->litDesc; + dsc* pattern_desc = &nodeAs(pattern_node)->litDesc; dsc* escape_desc = NULL; if (escape_node) - escape_desc = &escape_node->as()->litDesc; + escape_desc = &nodeAs(escape_node)->litDesc; // if either is not a character expression, forget it if ((match_desc.dsc_dtype > dtype_any_text) || @@ -3555,8 +3544,8 @@ static void set_position(const SortNode* from_clause, SortNode* to_clause, const for (const NestConst* const to_end = to_ptr + count; to_ptr != to_end; ++to_ptr) { - const FieldNode* fromField = (*from_ptr)->as(); - const FieldNode* toField = (*to_ptr)->as(); + const FieldNode* fromField = nodeAs(*from_ptr); + const FieldNode* toField = nodeAs(*to_ptr); if ((map && map_equal(*to_ptr, *from_ptr, map)) || (!map && diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 2f80da4c6e..a00321ac56 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -1712,6 +1712,14 @@ void PAG_set_db_readonly(thread_db* tdbb, bool flag) // for WRITE operations header->hdr_flags &= ~hdr_read_only; dbb->dbb_flags &= ~DBB_read_only; + + // This is necessary as dbb's Next could be less than OAT. + // And this is safe as we currently in exclusive attachment and + // all executed transactions was read-only. + dbb->dbb_next_transaction = Ods::getNT(header); + dbb->dbb_oldest_transaction = Ods::getOIT(header); + dbb->dbb_oldest_active = Ods::getOAT(header); + dbb->dbb_oldest_snapshot = Ods::getOST(header); } CCH_MARK_MUST_WRITE(tdbb, &window); diff --git a/src/jrd/par.cpp b/src/jrd/par.cpp index 1e93c6a1ca..06a2e9eb13 100644 --- a/src/jrd/par.cpp +++ b/src/jrd/par.cpp @@ -385,6 +385,16 @@ USHORT PAR_datatype(BlrReader& blrReader, dsc* desc) desc->dsc_length = sizeof(double); break; + case blr_dec64: + desc->dsc_dtype = dtype_dec64; + desc->dsc_length = sizeof(Decimal64); + break; + + case blr_dec128: + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + break; + case blr_blob2: desc->dsc_dtype = dtype_blob; desc->dsc_length = sizeof(ISC_QUAD); diff --git a/src/jrd/recsrc/AggregatedStream.cpp b/src/jrd/recsrc/AggregatedStream.cpp index 709cd31014..c3d2985f7c 100644 --- a/src/jrd/recsrc/AggregatedStream.cpp +++ b/src/jrd/recsrc/AggregatedStream.cpp @@ -205,11 +205,11 @@ void BaseAggWinStream::aggInit(thread_db* tdbb, jrd_req* req source != sourceEnd; ++source, ++target) { - const AggNode* aggNode = (*source)->as(); + const AggNode* aggNode = nodeAs(*source); if (aggNode) aggNode->aggInit(tdbb, request); - else if ((*source)->is()) + else if (nodeIs(*source)) EXE_assignment(tdbb, *source, *target); } } @@ -227,7 +227,7 @@ bool BaseAggWinStream::aggPass(thread_db* tdbb, jrd_req* req source != sourceEnd; ++source, ++target) { - const AggNode* aggNode = (*source)->as(); + const AggNode* aggNode = nodeAs(*source); if (aggNode) { @@ -256,11 +256,11 @@ void BaseAggWinStream::aggExecute(thread_db* tdbb, jrd_req* source != sourceEnd; ++source, ++target) { - const AggNode* aggNode = (*source)->as(); + const AggNode* aggNode = nodeAs(*source); if (aggNode) { - const FieldNode* field = (*target)->as(); + const FieldNode* field = nodeAs(*target); const USHORT id = field->fieldId; Record* record = request->req_rpb[field->fieldStream].rpb_record; @@ -287,7 +287,7 @@ void BaseAggWinStream::aggFinish(thread_db* tdbb, jrd_req* r source != sourceEnd; ++source) { - const AggNode* aggNode = (*source)->as(); + const AggNode* aggNode = nodeAs(*source); if (aggNode) aggNode->aggFinish(tdbb, request); @@ -334,7 +334,7 @@ int BaseAggWinStream::lookForChange(thread_db* tdbb, jrd_req } else if (!vtemp->vlu_desc.dsc_address) return 1 * nullDirection; - else if ((n = MOV_compare(desc, &vtemp->vlu_desc)) != 0) + else if ((n = MOV_compare(tdbb, desc, &vtemp->vlu_desc)) != 0) return n * direction; } diff --git a/src/jrd/recsrc/FilteredStream.cpp b/src/jrd/recsrc/FilteredStream.cpp index e9586abdac..f4dd0c3f82 100644 --- a/src/jrd/recsrc/FilteredStream.cpp +++ b/src/jrd/recsrc/FilteredStream.cpp @@ -159,7 +159,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const { // see if there's a select node to work with - const BinaryBoolNode* booleanNode = column_node->as(); + const BinaryBoolNode* booleanNode = nodeAs(column_node); if (booleanNode && booleanNode->blrOp == blr_and) { diff --git a/src/jrd/recsrc/FirstRowsStream.cpp b/src/jrd/recsrc/FirstRowsStream.cpp index bbb6bf1ec1..c7566b8ef7 100644 --- a/src/jrd/recsrc/FirstRowsStream.cpp +++ b/src/jrd/recsrc/FirstRowsStream.cpp @@ -52,7 +52,7 @@ void FirstRowsStream::open(thread_db* tdbb) const impure->irsb_flags = 0; const dsc* desc = EVL_expr(tdbb, request, m_value); - const SINT64 value = (desc && !(request->req_flags & req_null)) ? MOV_get_int64(desc, 0) : 0; + const SINT64 value = (desc && !(request->req_flags & req_null)) ? MOV_get_int64(tdbb, desc, 0) : 0; if (value < 0) status_exception::raise(Arg::Gds(isc_bad_limit_param)); diff --git a/src/jrd/recsrc/MergeJoin.cpp b/src/jrd/recsrc/MergeJoin.cpp index e5aff52dbc..50c47e31bf 100644 --- a/src/jrd/recsrc/MergeJoin.cpp +++ b/src/jrd/recsrc/MergeJoin.cpp @@ -409,7 +409,7 @@ int MergeJoin::compare(thread_db* tdbb, const NestValueArray* node1, if (!null1 && !null2) { - const int result = MOV_compare(desc1, desc2); + const int result = MOV_compare(tdbb, desc1, desc2); if (result != 0) return result; diff --git a/src/jrd/recsrc/SkipRowsStream.cpp b/src/jrd/recsrc/SkipRowsStream.cpp index 7528389dc7..975bbe85db 100644 --- a/src/jrd/recsrc/SkipRowsStream.cpp +++ b/src/jrd/recsrc/SkipRowsStream.cpp @@ -52,7 +52,7 @@ void SkipRowsStream::open(thread_db* tdbb) const impure->irsb_flags = irsb_open; const dsc* desc = EVL_expr(tdbb, request, m_value); - const SINT64 value = (desc && !(request->req_flags & req_null)) ? MOV_get_int64(desc, 0) : 0; + const SINT64 value = (desc && !(request->req_flags & req_null)) ? MOV_get_int64(tdbb, desc, 0) : 0; if (value < 0) { diff --git a/src/jrd/recsrc/SortedStream.cpp b/src/jrd/recsrc/SortedStream.cpp index 57caf47de2..aa0e5ad638 100644 --- a/src/jrd/recsrc/SortedStream.cpp +++ b/src/jrd/recsrc/SortedStream.cpp @@ -276,6 +276,7 @@ bool SortedStream::compareKeys(const UCHAR* p, const UCHAR* q) const fb_assert(m_map->keyItems.getCount() % 2 == 0); const USHORT count = m_map->keyItems.getCount() / 2; + thread_db* tdbb = JRD_get_thread_data(); for (USHORT i = 0; i < count; i++) { @@ -295,7 +296,7 @@ bool SortedStream::compareKeys(const UCHAR* p, const UCHAR* q) const dsc desc2 = item->desc; desc2.dsc_address = const_cast(q) + (IPTR) desc2.dsc_address; - if (MOV_compare(&desc1, &desc2)) + if (MOV_compare(tdbb, &desc1, &desc2)) return false; } } @@ -328,7 +329,7 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const from = item->desc; from.dsc_address = data + (IPTR) from.dsc_address; - if (item->node && !item->node->is()) + if (item->node && !nodeIs(item->node)) continue; // if moving a TEXT item into the key portion of the sort record, @@ -338,7 +339,7 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const // a sort key, there is a later nod_field in the item // list that contains the data to send back - if (IS_INTL_DATA(&item->desc) && + if ((IS_INTL_DATA(&item->desc) || item->desc.isDecFloat()) && (ULONG)(IPTR) item->desc.dsc_address < m_map->keyLength) { continue; diff --git a/src/jrd/recsrc/WindowedStream.cpp b/src/jrd/recsrc/WindowedStream.cpp index 9ed08f033e..faf18764ce 100644 --- a/src/jrd/recsrc/WindowedStream.cpp +++ b/src/jrd/recsrc/WindowedStream.cpp @@ -205,7 +205,7 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb, source != end; ++source) { - const AggNode* aggNode = (*source)->as(); + const AggNode* aggNode = nodeAs(*source); if (aggNode) { @@ -443,7 +443,7 @@ WindowedStream::WindowStream::WindowStream(thread_db* tdbb, CompilerScratch* csb source != sourceEnd; ++source, ++target) { - const AggNode* aggNode = (*source)->as(); + const AggNode* aggNode = nodeAs(*source); if (aggNode) { @@ -494,9 +494,9 @@ WindowedStream::WindowStream::WindowStream(thread_db* tdbb, CompilerScratch* csb //// TODO: Better check for invariants. if (frame->value && - (frame->value->is() || - frame->value->is() || - frame->value->is())) + (nodeIs(frame->value) || + nodeIs(frame->value) || + nodeIs(frame->value))) { m_invariantOffsets |= i == 0 ? 0x1 : 0x2; } @@ -839,9 +839,9 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const source != sourceEnd; ++source, ++target) { - const AggNode* aggNode = (*source)->as(); + const AggNode* aggNode = nodeAs(*source); - const FieldNode* field = (*target)->as(); + const FieldNode* field = nodeAs(*target); const USHORT id = field->fieldId; Record* record = request->req_rpb[field->fieldStream].rpb_record; @@ -869,7 +869,7 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const source != sourceEnd; ++source, ++target) { - const AggNode* aggNode = (*source)->as(); + const AggNode* aggNode = nodeAs(*source); if (!aggNode) EXE_assignment(tdbb, *source, *target); @@ -916,7 +916,7 @@ const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req* if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS) { // Purposedly used 32-bit here. So long distance will complicate things for no gain. - impureValue->vlux_count = MOV_get_long(desc, 0); + impureValue->vlux_count = MOV_get_long(tdbb, desc, 0); if (impureValue->vlux_count < 0) error = true; @@ -924,7 +924,7 @@ const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req* if (frame->bound == WindowClause::Frame::Bound::PRECEDING) impureValue->vlux_count = -impureValue->vlux_count; } - else if (MOV_compare(desc, &zeroDsc) < 0) + else if (MOV_compare(tdbb, desc, &zeroDsc) < 0) error = true; if (!error) diff --git a/src/jrd/sort.cpp b/src/jrd/sort.cpp index 856b390c74..8a5e03cfa2 100644 --- a/src/jrd/sort.cpp +++ b/src/jrd/sort.cpp @@ -213,7 +213,7 @@ Sort::Sort(Database* dbb, const sort_key_def* p = m_description.end() - 1; - m_key_length = ROUNDUP(p->skd_offset + p->skd_length, sizeof(SLONG)) >> SHIFTLONG; + m_key_length = ROUNDUP(p->getSkdOffset() + p->getSkdLength(), sizeof(SLONG)) >> SHIFTLONG; while (unique_keys < keys) { @@ -221,7 +221,7 @@ Sort::Sort(Database* dbb, unique_keys++; } - m_unique_length = ROUNDUP(p->skd_offset + p->skd_length, sizeof(SLONG)) >> SHIFTLONG; + m_unique_length = ROUNDUP(p->getSkdOffset() + p->getSkdLength(), sizeof(SLONG)) >> SHIFTLONG; // Next, try to allocate a "big block". How big? Big enough! @@ -711,8 +711,8 @@ void Sort::diddleKey(UCHAR* record, bool direction) for (sort_key_def* key = m_description.begin(), *end = m_description.end(); key < end; key++) { - UCHAR* p = record + key->skd_offset; - USHORT n = key->skd_length; + UCHAR* p = record + key->getSkdOffset(); + USHORT n = key->getSkdLength(); USHORT complement = key->skd_flags & SKD_descending; // This trick replaces possibly negative zero with positive zero, so that both @@ -806,6 +806,49 @@ void Sort::diddleKey(UCHAR* record, bool direction) *p ^= 1 << 7; break; + case SKD_dec64: + if (direction) + { + ((Decimal64*) p)->makeKey(lwp); + *p ^= 1 << 7; + } + else + { + if (complement && n) + { + UCHAR* pp = p; + do { + *pp++ ^= -1; + } while (--n); + } + + *p ^= 1 << 7; + ((Decimal64*) p)->grabKey(lwp); + } + break; + + case SKD_dec128: + fb_assert(false); // diddleKey for Dec64/128 not tested on bigendians! + if (direction) + { + ((Decimal128*) p)->makeKey(lwp); + *p ^= 1 << 7; + } + else + { + if (complement && n) + { + UCHAR* pp = p; + do { + *pp++ ^= -1; + } while (--n); + } + + *p ^= 1 << 7; + ((Decimal128*) p)->grabKey(lwp); + } + break; + default: fb_assert(false); break; @@ -824,13 +867,13 @@ void Sort::diddleKey(UCHAR* record, bool direction) if (key->skd_dtype == SKD_varying && !direction) { - p = record + key->skd_offset; + p = record + key->getSkdOffset(); ((vary*) p)->vary_length = *((USHORT*) (record + key->skd_vary_offset)); } if (key->skd_dtype == SKD_cstring && !direction) { - p = record + key->skd_offset; + p = record + key->getSkdOffset(); USHORT l = *((USHORT*) (record + key->skd_vary_offset)); *(p + l) = 0; } @@ -858,11 +901,11 @@ void Sort::diddleKey(UCHAR* record, bool direction) for (sort_key_def* key = m_description.begin(), *end = m_description.end(); key < end; key++) { - UCHAR* p = (UCHAR*) record + key->skd_offset; + UCHAR* p = (UCHAR*) record + key->getSkdOffset(); USHORT* wp = (USHORT*) p; SORTP* lwp = (SORTP*) p; USHORT complement = key->skd_flags & SKD_descending; - USHORT n = ROUNDUP(key->skd_length, sizeof(SLONG)); + USHORT n = ROUNDUP(key->getSkdLength(), sizeof(SLONG)); // This trick replaces possibly negative zero with positive zero, so that both // would be transformed into the same sort key and thus properly compared (see CORE-3547). @@ -1039,27 +1082,71 @@ void Sort::diddleKey(UCHAR* record, bool direction) break; #endif // IEEE + case SKD_dec64: + if (direction) + { + ((Decimal64*) p)->makeKey(lwp); + p[3] ^= 1 << 7; + } + else + { + if (complement && n) + { + UCHAR* pp = p; + do { + *pp++ ^= -1; + } while (--n); + } + + p[3] ^= 1 << 7; + ((Decimal64*) p)->grabKey(lwp); + } + break; + + case SKD_dec128: + if (direction) + { + ((Decimal128*) p)->makeKey(lwp); + p[3] ^= 1 << 7; + } + else + { + if (complement && n) + { + UCHAR* pp = p; + do { + *pp++ ^= -1; + } while (--n); + } + + p[3] ^= 1 << 7; + ((Decimal128*) p)->grabKey(lwp); + } + break; + default: fb_assert(false); break; } if (complement && n) + { do { *p++ ^= -1; } while (--n); + } // Flatter but don't complement control info for non-fixed // data types when restoring the data if (key->skd_dtype == SKD_varying && !direction) { - p = (UCHAR*) record + key->skd_offset; + p = (UCHAR*) record + key->getSkdOffset(); ((vary*) p)->vary_length = *((USHORT*) (record + key->skd_vary_offset)); } if (key->skd_dtype == SKD_cstring && !direction) { - p = (UCHAR*) record + key->skd_offset; + p = (UCHAR*) record + key->getSkdOffset(); USHORT l = *((USHORT*) (record + key->skd_vary_offset)); *(p + l) = 0; } diff --git a/src/jrd/sort.h b/src/jrd/sort.h index 45d876530d..e6e95ac151 100644 --- a/src/jrd/sort.h +++ b/src/jrd/sort.h @@ -124,18 +124,6 @@ until we are out of records to sort or memory. */ -// Sort key definition block - -struct sort_key_def -{ - UCHAR skd_dtype; // Data type - UCHAR skd_flags; // Flags - USHORT skd_length; // Length if string - ULONG skd_offset; // Offset from beginning - ULONG skd_vary_offset; // Offset to varying/cstring length -}; - - // skd_dtype const int SKD_long = 1; @@ -153,12 +141,62 @@ const int SKD_cstring = 12; // non-international const int SKD_sql_time = 13; const int SKD_sql_date = 14; const int SKD_int64 = 15; +const int SKD_dec64 = 16; +const int SKD_dec128 = 17; // skd_flags const UCHAR SKD_ascending = 0; // default initializer const UCHAR SKD_descending = 1; const UCHAR SKD_binary = 2; +// Sort key definition block + +struct sort_key_def +{ + UCHAR skd_dtype; // Data type + UCHAR skd_flags; // Flags + +private: + USHORT skd_length; // Length if string + ULONG skd_offset; // Offset from beginning + +public: + ULONG skd_vary_offset; // Offset to varying/cstring length + + USHORT getSkdLength() const { return skd_length; } + + void setSkdLength(UCHAR dtype, USHORT v) + { + skd_dtype = dtype; + skd_length = v; + switch (dtype) + { + case SKD_dec64: + case SKD_dec128: + skd_length += sizeof(SLONG); + break; + } + } + + ULONG getSkdOffset() const { return skd_offset; } + + void setSkdOffset(const sort_key_def* prev = nullptr, dsc* desc = nullptr) + { + skd_offset = 0; + if (prev) + { + skd_offset = prev->skd_offset + prev->skd_length; +#ifndef WORDS_BIGENDIAN + skd_offset = ROUNDUP(skd_offset, sizeof(SLONG)); +#else + if (desc && desc->dsc_dtype >= dtype_aligned) + skd_offset = FB_ALIGN(skd_offset, type_alignments[desc->dsc_dtype]); +#endif + } + } +}; + + // Run/merge common block header struct run_merge_hdr diff --git a/src/jrd/svc.cpp b/src/jrd/svc.cpp index 98e21eea5f..14ea142796 100644 --- a/src/jrd/svc.cpp +++ b/src/jrd/svc.cpp @@ -567,8 +567,7 @@ unsigned int Service::getAuthBlock(const unsigned char** bytes) void Service::fillDpb(ClumpletWriter& dpb) { - const char* providers = "Providers=" CURRENT_ENGINE; - dpb.insertString(isc_dpb_config, providers, fb_strlen(providers)); + dpb.insertString(isc_dpb_config, EMBEDDED_PROVIDERS, fb_strlen(EMBEDDED_PROVIDERS)); if (svc_address_path.hasData()) { dpb.insertString(isc_dpb_address_path, svc_address_path); @@ -728,14 +727,20 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d { if (svc_auth_block.hasData()) { + // remote connection - use svc_auth_block PathName dummy; RefPtr config; expandDatabaseName(svc_expected_db, dummy, &config); + Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, svc_crypt_callback); + mapping.needAuthBlock(svc_auth_block); + + mapping.setAuthBlock(svc_auth_block); + mapping.setErrorMessagesContextName("services manager"); + mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr); + string trusted_role; - mapUser(true, svc_username, trusted_role, NULL, &svc_auth_block, NULL, - svc_auth_block, "services manager", NULL, config->getSecurityDatabase(), "", - svc_crypt_callback, NULL); + mapping.mapUser(svc_username, trusted_role); trusted_role.upper(); svc_trusted_role = trusted_role == ADMIN_ROLE; } diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index 0dd4ee3c32..0ae6e1b81d 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -487,7 +487,7 @@ void TRA_commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_flag status_exception::raise(&st); secContext->tra = NULL; - clearMappingCache(tdbb->getDatabase()->dbb_config->getSecurityDatabase(), MAPPING_CACHE); + Mapping::clearCache(tdbb->getDatabase()->dbb_config->getSecurityDatabase(), Mapping::MAPPING_CACHE); transaction->eraseSecDbContext(); } @@ -906,20 +906,31 @@ void TRA_update_counters(thread_db* tdbb, Database* dbb) WIN window(HEADER_PAGE_NUMBER); header_page* header = (header_page*)CCH_FETCH(tdbb, &window, LCK_write, pag_header); - if (dbb->dbb_oldest_active > header->hdr_oldest_active || - dbb->dbb_oldest_transaction > header->hdr_oldest_transaction || - dbb->dbb_oldest_snapshot > header->hdr_oldest_snapshot) + const TraNumber next_transaction = Ods::getNT(header); + const TraNumber oldest_transaction = Ods::getOIT(header); + const TraNumber oldest_active = Ods::getOAT(header); + const TraNumber oldest_snapshot = Ods::getOST(header); + + fb_assert(dbb->dbb_next_transaction <= next_transaction); + + if (dbb->dbb_oldest_active > oldest_active || + dbb->dbb_oldest_transaction > oldest_transaction || + dbb->dbb_oldest_snapshot > oldest_snapshot || + dbb->dbb_next_transaction > next_transaction) { CCH_MARK_MUST_WRITE(tdbb, &window); if (dbb->dbb_oldest_active > header->hdr_oldest_active) - header->hdr_oldest_active = dbb->dbb_oldest_active; + Ods::writeOAT(header, dbb->dbb_oldest_active); if (dbb->dbb_oldest_transaction > header->hdr_oldest_transaction) - header->hdr_oldest_transaction = dbb->dbb_oldest_transaction; + Ods::writeOIT(header, dbb->dbb_oldest_transaction); if (dbb->dbb_oldest_snapshot > header->hdr_oldest_snapshot) - header->hdr_oldest_snapshot = dbb->dbb_oldest_snapshot; + Ods::writeOST(header, dbb->dbb_oldest_snapshot); + + if (dbb->dbb_next_transaction > next_transaction) + Ods::writeNT(header, dbb->dbb_next_transaction); } CCH_RELEASE(tdbb, &window); @@ -1320,7 +1331,7 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr // Release the transaction and its pool tdbb->setTransaction(NULL); - JTransaction* jTra = transaction->getInterface(); + JTransaction* jTra = transaction->getInterface(true); // ASF: maybe it's better to pass false? if (jTra) { jTra->setHandle(NULL); @@ -3442,9 +3453,9 @@ jrd_tra::~jrd_tra() } -JTransaction* jrd_tra::getInterface() +JTransaction* jrd_tra::getInterface(bool create) { - if (!tra_interface) + if (!tra_interface && create) { tra_flags |= TRA_own_interface; tra_interface = FB_NEW JTransaction(this, tra_attachment->getStable()); diff --git a/src/jrd/tra.h b/src/jrd/tra.h index 54e9fcaa85..9f37c5dd43 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -262,7 +262,7 @@ public: return tra_attachment->att_dsql_instance; } - JTransaction* getInterface(); + JTransaction* getInterface(bool create); void setInterface(JTransaction* jt); FB_API_HANDLE tra_public_handle; // Public handle diff --git a/src/jrd/trace/TraceManager.cpp b/src/jrd/trace/TraceManager.cpp index 00f7b915c7..fe7089a8e1 100644 --- a/src/jrd/trace/TraceManager.cpp +++ b/src/jrd/trace/TraceManager.cpp @@ -260,15 +260,19 @@ void TraceManager::update_session(const TraceSession& session) Database* dbb = attachment->att_database; fb_assert(dbb); - mapResult = mapUser(false, s_user, t_role, NULL, NULL, &priv, session.ses_auth, - attachment->att_filename.c_str(), dbb->dbb_filename.c_str(), - dbb->dbb_config->getSecurityDatabase(), session.ses_role, - dbb->dbb_provider->getCryptCallback(), attachment->getInterface()); + Mapping mapping(Mapping::MAP_NO_FLAGS, dbb->dbb_provider->getCryptCallback()); + mapping.needSystemPrivileges(priv); + mapping.setAuthBlock(session.ses_auth); + mapping.setSqlRole(session.ses_role); + mapping.setSecurityDbAlias(dbb->dbb_config->getSecurityDatabase(), dbb->dbb_filename.c_str()); + mapping.setDb(attachment->att_filename.c_str(), dbb->dbb_filename.c_str(), + attachment->getInterface()); + mapResult = mapping.mapUser(s_user, t_role); } if (session.ses_auth.hasData()) { - if (mapResult & MAPUSER_ERROR_NOT_THROWN) + if (mapResult & Mapping::MAP_ERROR_NOT_THROWN) return; // Error in mapUser() means missing context t_role.upper(); @@ -291,9 +295,13 @@ void TraceManager::update_session(const TraceSession& session) RefPtr config; expandDatabaseName(service->getExpectedDb(), dummy, &config); - if (mapUser(false, s_user, t_role, NULL, NULL, NULL, session.ses_auth, "services manager", - NULL, config->getSecurityDatabase(), session.ses_role, service->getCryptCallback(), - NULL) & MAPUSER_ERROR_NOT_THROWN) + Mapping mapping(Mapping::MAP_NO_FLAGS, service->getCryptCallback()); + mapping.setAuthBlock(session.ses_auth); + mapping.setErrorMessagesContextName("services manager"); + mapping.setSqlRole(session.ses_role); + mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr); + + if (mapping.mapUser(s_user, t_role) & Mapping::MAP_ERROR_NOT_THROWN) { // Error in mapUser() means missing context, therefore... return; diff --git a/src/jrd/trace/TraceObjects.cpp b/src/jrd/trace/TraceObjects.cpp index 8a8ed61415..b43e819101 100644 --- a/src/jrd/trace/TraceObjects.cpp +++ b/src/jrd/trace/TraceObjects.cpp @@ -333,7 +333,7 @@ void TraceDscFromValues::fillParams() const VariableNode* var; const LiteralNode* literal; - if ((param = prm->as())) + if ((param = nodeAs(prm))) { //const impure_value* impure = m_request->getImpure(param->impureOffset) const MessageNode* message = param->message; @@ -349,18 +349,18 @@ void TraceDscFromValues::fillParams() if (param->argFlag) { const dsc* flag = EVL_expr(tdbb, m_request, param->argFlag); - if (MOV_get_long(flag, 0)) + if (MOV_get_long(tdbb, flag, 0)) desc.dsc_flags |= DSC_null; } } - else if ((var = prm->as())) + else if ((var = nodeAs(prm))) { impure_value* impure = m_request->getImpure(var->impureOffset); from_desc = &impure->vlu_desc; } - else if ((literal = prm->as())) + else if ((literal = nodeAs(prm))) from_desc = &literal->litDesc; - else if (prm->is()) + else if (nodeIs(prm)) { desc.clear(); desc.setNull(); diff --git a/src/jrd/trig.h b/src/jrd/trig.h index 3a42468d4d..359fe3f756 100644 --- a/src/jrd/trig.h +++ b/src/jrd/trig.h @@ -41,7 +41,7 @@ struct jrd_trg USHORT trg_length; const UCHAR* trg_blr; USHORT trg_flags; - UCHAR trg_ods_version; + USHORT trg_ods_version; }; /* trigger message structure */ @@ -51,7 +51,7 @@ struct trigger_msg const SCHAR* trigmsg_name; USHORT trigmsg_number; const SCHAR* trigmsg_text; - UCHAR trg_ods_version; + USHORT trg_ods_version; }; /* generator definition structure */ diff --git a/src/jrd/types.h b/src/jrd/types.h index e16f7c5c6d..63b38ea2e0 100644 --- a/src/jrd/types.h +++ b/src/jrd/types.h @@ -41,6 +41,8 @@ TYPE("DATE", blr_sql_date, nam_f_type) TYPE("TIME", blr_sql_time, nam_f_type) TYPE("INT64", blr_int64, nam_f_type) TYPE("BOOLEAN", blr_bool, nam_f_type) +TYPE("DECFLOAT(16)", blr_dec64, nam_f_type) +TYPE("DECFLOAT(34)", blr_dec128, nam_f_type) TYPE("BINARY", 0, nam_f_sub_type) TYPE("TEXT", 1, nam_f_sub_type) diff --git a/src/jrd/val.h b/src/jrd/val.h index b6b5f81c24..bf7bd94306 100644 --- a/src/jrd/val.h +++ b/src/jrd/val.h @@ -82,6 +82,8 @@ struct impure_value SLONG vlu_dbkey[2]; float vlu_float; double vlu_double; + Firebird::Decimal64 vlu_dec64; + Firebird::Decimal128 vlu_dec128; GDS_TIMESTAMP vlu_timestamp; GDS_TIME vlu_sql_time; GDS_DATE vlu_sql_date; @@ -94,6 +96,7 @@ struct impure_value void make_long(const SLONG val, const signed char scale = 0); void make_int64(const SINT64 val, const signed char scale = 0); void make_double(const double val); + void make_decimal128(const Firebird::Decimal128 val); }; // Do not use these methods where dsc_sub_type is not explicitly set to zero. @@ -127,6 +130,16 @@ inline void impure_value::make_double(const double val) this->vlu_desc.dsc_address = reinterpret_cast(&this->vlu_misc.vlu_double); } +inline void impure_value::make_decimal128(const Firebird::Decimal128 val) +{ + this->vlu_misc.vlu_dec128 = val; + this->vlu_desc.dsc_dtype = dtype_dec128; + this->vlu_desc.dsc_length = sizeof(Firebird::Decimal128); + this->vlu_desc.dsc_scale = 0; + this->vlu_desc.dsc_sub_type = 0; + this->vlu_desc.dsc_address = reinterpret_cast(&this->vlu_misc.vlu_dec128); +} + struct impure_value_ex : public impure_value { SINT64 vlux_count; diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 07b4109739..74322633c3 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -103,7 +103,7 @@ static void check_rel_field_class(thread_db*, record_param*, SecurityClass::flag static void delete_record(thread_db*, record_param*, ULONG, MemoryPool*); static UCHAR* delete_tail(thread_db*, record_param*, ULONG, UCHAR*, const UCHAR*); static void expunge(thread_db*, record_param*, const jrd_tra*, ULONG); -static bool dfw_should_know(record_param* org_rpb, record_param* new_rpb, +static bool dfw_should_know(thread_db*, record_param* org_rpb, record_param* new_rpb, USHORT irrelevant_field, bool void_update_is_relevant = false); static void garbage_collect(thread_db*, record_param*, ULONG, RecordStack&); @@ -1445,7 +1445,6 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) jrd_rel* relation = rpb->rpb_relation; tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_DELETES); // Special case system transaction @@ -1485,7 +1484,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_types: if (!tdbb->getAttachment()->locksmith(tdbb, CREATE_USER_TYPES)) protect_system_table_delupd(tdbb, relation, "DELETE", true); - if (EVL_field(0, rpb->rpb_record, f_typ_sys_flag, &desc) && MOV_get_long(&desc, 0)) + if (EVL_field(0, rpb->rpb_record, f_typ_sys_flag, &desc) && MOV_get_long(tdbb, &desc, 0)) protect_system_table_delupd(tdbb, relation, "DELETE", true); break; @@ -1521,7 +1520,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (EVL_field(0, rpb->rpb_record, f_rel_id, &desc2)) { - id = MOV_get_long(&desc2, 0); + id = MOV_get_long(tdbb, &desc2, 0); if (id < (int) rel_MAX) { IBERROR(187); // msg 187 cannot delete system relations @@ -1542,11 +1541,11 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_procedures: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_prc_id, &desc2); - id = MOV_get_long(&desc2, 0); + id = MOV_get_long(tdbb, &desc2, 0); if (EVL_field(0, rpb->rpb_record, f_prc_pkg_name, &desc2)) { - MOV_get_metaname(&desc2, package_name); + MOV_get_metaname(tdbb, &desc2, package_name); SCL_check_package(tdbb, &desc2, SCL_drop); } @@ -1560,20 +1559,20 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_charsets: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_cs_cs_name, &desc); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); SCL_check_charset(tdbb, object_name, SCL_drop); break; case rel_collations: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_coll_cs_id, &desc2); - id = MOV_get_long(&desc2, 0); + id = MOV_get_long(tdbb, &desc2, 0); EVL_field(0, rpb->rpb_record, f_coll_id, &desc2); - id = INTL_CS_COLL_TO_TTYPE(id, MOV_get_long(&desc2, 0)); + id = INTL_CS_COLL_TO_TTYPE(id, MOV_get_long(tdbb, &desc2, 0)); EVL_field(0, rpb->rpb_record, f_coll_name, &desc); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); SCL_check_collation(tdbb, object_name, SCL_drop); DFW_post_work(transaction, dfw_delete_collation, &desc, id); break; @@ -1581,7 +1580,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_exceptions: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_xcp_name, &desc); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); SCL_check_exception(tdbb, object_name, SCL_drop); DFW_post_work(transaction, dfw_delete_exception, &desc, 0); break; @@ -1589,7 +1588,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_gens: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_gen_name, &desc); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); SCL_check_generator(tdbb, object_name, SCL_drop); DFW_post_work(transaction, dfw_delete_generator, &desc, 0); break; @@ -1600,7 +1599,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (EVL_field(0, rpb->rpb_record, f_fun_pkg_name, &desc2)) { - MOV_get_metaname(&desc2, package_name); + MOV_get_metaname(tdbb, &desc2, package_name); SCL_check_package(tdbb, &desc2, SCL_drop); } else @@ -1609,7 +1608,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) } EVL_field(0, rpb->rpb_record, f_fun_id, &desc2); - id = MOV_get_long(&desc2, 0); + id = MOV_get_long(tdbb, &desc2, 0); DFW_post_work(transaction, dfw_delete_function, &desc, id, package_name); Function::lookup(tdbb, id, false, true, 0); @@ -1620,10 +1619,10 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) EVL_field(0, rpb->rpb_record, f_idx_relation, &desc); SCL_check_relation(tdbb, &desc, SCL_control); EVL_field(0, rpb->rpb_record, f_idx_id, &desc2); - if ( (id = MOV_get_long(&desc2, 0)) ) + if ( (id = MOV_get_long(tdbb, &desc2, 0)) ) { MetaName relation_name; - MOV_get_metaname(&desc, relation_name); + MOV_get_metaname(tdbb, &desc, relation_name); r2 = MET_lookup_relation(tdbb, relation_name); fb_assert(r2); @@ -1650,7 +1649,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) EVL_field(0, rpb->rpb_record, f_idx_name, &desc3); MetaName index_name; - MOV_get_metaname(&desc3, index_name); + MOV_get_metaname(tdbb, &desc3, index_name); jrd_rel *partner; index_desc idx; @@ -1679,7 +1678,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) SCL_check_relation(tdbb, &desc, SCL_control); DFW_post_work(transaction, dfw_update_format, &desc, 0); EVL_field(0, rpb->rpb_record, f_rfr_fname, &desc2); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); if ( (r2 = MET_lookup_relation(tdbb, object_name)) ) { DFW_post_work(transaction, dfw_delete_rfr, &desc2, r2->rel_id); @@ -1692,7 +1691,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) protect_system_table_delupd(tdbb, relation, "DELETE"); if (EVL_field(0, rpb->rpb_record, f_arg_pkg_name, &desc2)) { - MOV_get_metaname(&desc2, package_name); + MOV_get_metaname(tdbb, &desc2, package_name); SCL_check_package(tdbb, &desc2, SCL_control); } else @@ -1709,7 +1708,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (EVL_field(0, rpb->rpb_record, f_prm_pkg_name, &desc2)) { - MOV_get_metaname(&desc2, package_name); + MOV_get_metaname(tdbb, &desc2, package_name); SCL_check_package(tdbb, &desc2, SCL_control); } else @@ -1718,7 +1717,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) } EVL_field(0, rpb->rpb_record, f_prm_name, &desc2); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); if ( (procedure = MET_lookup_procedure(tdbb, QualifiedName(object_name, package_name), true)) ) @@ -1736,7 +1735,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_fields: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_fld_name, &desc); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); SCL_check_domain(tdbb, object_name, SCL_drop); DFW_post_work(transaction, dfw_delete_field, &desc, 0); MET_change_fields(tdbb, transaction, &desc); @@ -1748,7 +1747,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) SCL_check_database(tdbb, SCL_alter); const bool name_defined = EVL_field(0, rpb->rpb_record, f_file_name, &desc); const USHORT file_flags = EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) ? - MOV_get_long(&desc2, 0) : 0; + MOV_get_long(tdbb, &desc2, 0) : 0; if (file_flags & FILE_difference) { if (file_flags & FILE_backing_up) @@ -1757,7 +1756,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) DFW_post_work(transaction, dfw_delete_difference, &desc, 0); } else if (EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) && - (id = MOV_get_long(&desc2, 0))) + (id = MOV_get_long(tdbb, &desc2, 0))) { if (!(file_flags & FILE_inactive)) { @@ -1796,7 +1795,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (EVL_field(0, rpb->rpb_record, f_trg_type, &desc2)) { DFW_post_work_arg(transaction, work, &desc2, - (USHORT) MOV_get_int64(&desc2, 0), dfw_arg_trg_type); + (USHORT) MOV_get_int64(tdbb, &desc2, 0), dfw_arg_trg_type); } break; @@ -1816,7 +1815,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) } EVL_field(0, rpb->rpb_record, f_prv_rname, &desc); EVL_field(0, rpb->rpb_record, f_prv_o_type, &desc2); - id = MOV_get_long(&desc2, 0); + id = MOV_get_long(tdbb, &desc2, 0); DFW_post_work(transaction, dfw_grant, &desc, id); break; @@ -1891,13 +1890,13 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if ((RIDS) relation->rel_id == rel_priv) { EVL_field(0, rpb->rpb_record, f_prv_rname, &desc); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); EVL_field(0, rpb->rpb_record, f_prv_grant, &desc2); - if (MOV_get_long(&desc2, 0) == WITH_GRANT_OPTION) // ADMIN option should not cause cascade + if (MOV_get_long(tdbb, &desc2, 0) == WITH_GRANT_OPTION) // ADMIN option should not cause cascade { EVL_field(0, rpb->rpb_record, f_prv_user, &desc2); MetaName revokee; - MOV_get_metaname(&desc2, revokee); + MOV_get_metaname(tdbb, &desc2, revokee); EVL_field(0, rpb->rpb_record, f_prv_priv, &desc2); const string privilege = MOV_make_string2(tdbb, &desc2, ttype_ascii); MET_revoke(tdbb, transaction, object_name, revokee, privilege); @@ -2594,6 +2593,11 @@ bool VIO_get_current(thread_db* tdbb, VIO_data(tdbb, rpb, pool); return true; + case tra_limbo: + if (!(transaction->tra_flags & TRA_ignore_limbo)) + ERR_post(Arg::Gds(isc_rec_in_limbo) << Arg::Num(rpb->rpb_transaction_nr)); + // fall thru + case tra_active: // clear lock error from status vector fb_utils::init_status(tdbb->tdbb_status_vector); @@ -2638,10 +2642,6 @@ bool VIO_get_current(thread_db* tdbb, } break; - case tra_limbo: - BUGCHECK(184); // limbo impossible - break; - default: fb_assert(false); } @@ -2803,7 +2803,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j case rel_types: if (!tdbb->getAttachment()->locksmith(tdbb, CREATE_USER_TYPES)) protect_system_table_delupd(tdbb, relation, "UPDATE", true); - if (EVL_field(0, org_rpb->rpb_record, f_typ_sys_flag, &desc1) && MOV_get_long(&desc1, 0)) + if (EVL_field(0, org_rpb->rpb_record, f_typ_sys_flag, &desc1) && MOV_get_long(tdbb, &desc1, 0)) protect_system_table_delupd(tdbb, relation, "UPDATE", true); break; @@ -2830,7 +2830,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j check_class(tdbb, transaction, org_rpb, new_rpb, f_dat_class); EVL_field(0, org_rpb->rpb_record, f_dat_linger, &desc1); EVL_field(0, new_rpb->rpb_record, f_dat_linger, &desc2); - if (MOV_compare(&desc1, &desc2)) + if (MOV_compare(tdbb, &desc1, &desc2)) { DFW_post_work(transaction, dfw_set_linger, &desc2, 0); } @@ -2862,7 +2862,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if (EVL_field(0, org_rpb->rpb_record, f_prc_pkg_name, &desc2)) { - MOV_get_metaname(&desc2, package_name); + MOV_get_metaname(tdbb, &desc2, package_name); SCL_check_package(tdbb, &desc2, SCL_alter); } else @@ -2873,10 +2873,10 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j check_class(tdbb, transaction, org_rpb, new_rpb, f_prc_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_prc_owner); - if (dfw_should_know(org_rpb, new_rpb, f_prc_desc, true)) + if (dfw_should_know(tdbb, org_rpb, new_rpb, f_prc_desc, true)) { EVL_field(0, org_rpb->rpb_record, f_prc_id, &desc2); - const USHORT id = MOV_get_long(&desc2, 0); + const USHORT id = MOV_get_long(tdbb, &desc2, 0); DFW_post_work(transaction, dfw_modify_procedure, &desc1, id, package_name); } break; @@ -2888,7 +2888,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if (EVL_field(0, org_rpb->rpb_record, f_fun_pkg_name, &desc2)) { - MOV_get_metaname(&desc2, package_name); + MOV_get_metaname(tdbb, &desc2, package_name); SCL_check_package(tdbb, &desc2, SCL_alter); } else @@ -2899,10 +2899,10 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j check_class(tdbb, transaction, org_rpb, new_rpb, f_fun_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_fun_owner); - if (dfw_should_know(org_rpb, new_rpb, f_fun_desc, true)) + if (dfw_should_know(tdbb, org_rpb, new_rpb, f_fun_desc, true)) { EVL_field(0, org_rpb->rpb_record, f_fun_id, &desc2); - const USHORT id = MOV_get_long(&desc2, 0); + const USHORT id = MOV_get_long(tdbb, &desc2, 0); DFW_post_work(transaction, dfw_modify_function, &desc1, id, package_name); } break; @@ -2910,7 +2910,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j case rel_gens: protect_system_table_delupd(tdbb, relation, "UPDATE"); EVL_field(0, org_rpb->rpb_record, f_gen_name, &desc1); - MOV_get_metaname(&desc1, object_name); + MOV_get_metaname(tdbb, &desc1, object_name); SCL_check_generator(tdbb, object_name, SCL_alter); check_class(tdbb, transaction, org_rpb, new_rpb, f_gen_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_gen_owner); @@ -2925,15 +2925,15 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j bool rc1 = EVL_field(NULL, org_rpb->rpb_record, f_rfr_null_flag, &desc1); - if ((!rc1 || MOV_get_long(&desc1, 0) == 0)) + if ((!rc1 || MOV_get_long(tdbb, &desc1, 0) == 0)) { dsc desc3, desc4; bool rc2 = EVL_field(NULL, new_rpb->rpb_record, f_rfr_null_flag, &desc2); bool rc3 = EVL_field(NULL, org_rpb->rpb_record, f_rfr_sname, &desc3); bool rc4 = EVL_field(NULL, new_rpb->rpb_record, f_rfr_sname, &desc4); - if ((rc2 && MOV_get_long(&desc2, 0) != 0) || - (rc3 && rc4 && MOV_compare(&desc3, &desc4) != 0)) + if ((rc2 && MOV_get_long(tdbb, &desc2, 0) != 0) || + (rc3 && rc4 && MOV_compare(tdbb, &desc3, &desc4) != 0)) { EVL_field(0, new_rpb->rpb_record, f_rfr_rname, &desc1); EVL_field(0, new_rpb->rpb_record, f_rfr_id, &desc2); @@ -2941,7 +2941,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j DeferredWork* work = DFW_post_work(transaction, dfw_check_not_null, &desc1, 0); SortedArray& ids = DFW_get_ids(work); - int id = MOV_get_long(&desc2, 0); + int id = MOV_get_long(tdbb, &desc2, 0); FB_SIZE_T pos; if (!ids.find(id, pos)) ids.insert(pos, id); @@ -2953,10 +2953,10 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j case rel_fields: protect_system_table_delupd(tdbb, relation, "UPDATE"); EVL_field(0, org_rpb->rpb_record, f_fld_name, &desc1); - MOV_get_metaname(&desc1, object_name); + MOV_get_metaname(tdbb, &desc1, object_name); SCL_check_domain(tdbb, object_name, SCL_alter); - if (dfw_should_know(org_rpb, new_rpb, f_fld_desc, true)) + if (dfw_should_know(tdbb, org_rpb, new_rpb, f_fld_desc, true)) { MET_change_fields(tdbb, transaction, &desc1); EVL_field(0, new_rpb->rpb_record, f_fld_name, &desc2); @@ -2973,7 +2973,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j // and hence it can be used only by a single field and therefore one relation. rc1 = EVL_field(0, org_rpb->rpb_record, f_fld_computed, &desc3); rc2 = EVL_field(0, new_rpb->rpb_record, f_fld_computed, &desc4); - if (rc1 != rc2 || rc1 && MOV_compare(&desc3, &desc4)) { + if (rc1 != rc2 || rc1 && MOV_compare(tdbb, &desc3, &desc4)) { DFW_post_work_arg(transaction, dw, &desc1, 0, dfw_arg_force_computed); } } @@ -2984,7 +2984,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j rc1 = EVL_field(NULL, org_rpb->rpb_record, f_fld_null_flag, &desc3); rc2 = EVL_field(NULL, new_rpb->rpb_record, f_fld_null_flag, &desc4); - if ((!rc1 || MOV_get_long(&desc3, 0) == 0) && rc2 && MOV_get_long(&desc4, 0) != 0) + if ((!rc1 || MOV_get_long(tdbb, &desc3, 0) == 0) && rc2 && MOV_get_long(tdbb, &desc4, 0) != 0) DFW_post_work_arg(transaction, dw, &desc2, 0, dfw_arg_field_not_null); } check_class(tdbb, transaction, org_rpb, new_rpb, f_fld_class); @@ -3004,7 +3004,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j EVL_field(0, new_rpb->rpb_record, f_idx_relation, &desc1); SCL_check_relation(tdbb, &desc1, SCL_control, false); - if (dfw_should_know(org_rpb, new_rpb, f_idx_desc, true)) + if (dfw_should_know(tdbb, org_rpb, new_rpb, f_idx_desc, true)) { EVL_field(0, new_rpb->rpb_record, f_idx_name, &desc1); @@ -3027,7 +3027,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j EVL_field(0, new_rpb->rpb_record, f_trg_rname, &desc1); SCL_check_relation(tdbb, &desc1, SCL_control); - if (dfw_should_know(org_rpb, new_rpb, f_trg_desc, true)) + if (dfw_should_know(tdbb, org_rpb, new_rpb, f_trg_desc, true)) { EVL_field(0, new_rpb->rpb_record, f_trg_rname, &desc1); DFW_post_work(transaction, dfw_update_format, &desc1, 0); @@ -3042,7 +3042,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if (EVL_field(0, new_rpb->rpb_record, f_trg_type, &desc2)) { DFW_post_work_arg(transaction, dw, &desc2, - (USHORT) MOV_get_int64(&desc2, 0), dfw_arg_trg_type); + (USHORT) MOV_get_int64(tdbb, &desc2, 0), dfw_arg_trg_type); } } break; @@ -3054,9 +3054,9 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j SSHORT new_rel_flags, old_rel_flags; EVL_field(0, new_rpb->rpb_record, f_file_name, &desc1); if (EVL_field(0, new_rpb->rpb_record, f_file_flags, &desc2) && - ((new_rel_flags = MOV_get_long(&desc2, 0)) & FILE_difference) && + ((new_rel_flags = MOV_get_long(tdbb, &desc2, 0)) & FILE_difference) && EVL_field(0, org_rpb->rpb_record, f_file_flags, &desc2) && - ((old_rel_flags = MOV_get_long(&desc2, 0)) != new_rel_flags)) + ((old_rel_flags = MOV_get_long(tdbb, &desc2, 0)) != new_rel_flags)) { DFW_post_work(transaction, (new_rel_flags & FILE_backing_up ? dfw_begin_backup : dfw_end_backup), @@ -3068,7 +3068,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j case rel_charsets: protect_system_table_delupd(tdbb, relation, "UPDATE"); EVL_field(0, new_rpb->rpb_record, f_cs_cs_name, &desc1); - MOV_get_metaname(&desc1, object_name); + MOV_get_metaname(tdbb, &desc1, object_name); SCL_check_charset(tdbb, object_name, SCL_alter); check_class(tdbb, transaction, org_rpb, new_rpb, f_cs_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_cs_owner); @@ -3077,7 +3077,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j case rel_collations: protect_system_table_delupd(tdbb, relation, "UPDATE"); EVL_field(0, new_rpb->rpb_record, f_coll_name, &desc1); - MOV_get_metaname(&desc1, object_name); + MOV_get_metaname(tdbb, &desc1, object_name); SCL_check_collation(tdbb, object_name, SCL_alter); check_class(tdbb, transaction, org_rpb, new_rpb, f_coll_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_coll_owner); @@ -3086,7 +3086,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j case rel_exceptions: protect_system_table_delupd(tdbb, relation, "UPDATE"); EVL_field(0, new_rpb->rpb_record, f_xcp_name, &desc1); - MOV_get_metaname(&desc1, object_name); + MOV_get_metaname(tdbb, &desc1, object_name); SCL_check_exception(tdbb, object_name, SCL_alter); check_class(tdbb, transaction, org_rpb, new_rpb, f_xcp_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_xcp_owner); @@ -3457,7 +3457,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { if (!tdbb->getAttachment()->locksmith(tdbb, CREATE_USER_TYPES)) protect_system_table_insert(tdbb, request, relation, true); - else if (EVL_field(0, rpb->rpb_record, f_typ_sys_flag, &desc) && MOV_get_long(&desc, 0)) + else if (EVL_field(0, rpb->rpb_record, f_typ_sys_flag, &desc) && MOV_get_long(tdbb, &desc, 0)) protect_system_table_insert(tdbb, request, relation, true); } break; @@ -3498,7 +3498,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) EVL_field(0, rpb->rpb_record, f_prc_name, &desc); if (EVL_field(0, rpb->rpb_record, f_prc_pkg_name, &desc2)) - MOV_get_metaname(&desc2, package_name); + MOV_get_metaname(tdbb, &desc2, package_name); object_id = set_metadata_id(tdbb, rpb->rpb_record, f_prc_id, drq_g_nxt_prc_id, "RDB$PROCEDURES"); @@ -3507,7 +3507,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { // scope bool check_blr = true; if (EVL_field(0, rpb->rpb_record, f_prc_valid_blr, &desc2)) - check_blr = MOV_get_long(&desc2, 0) != 0; + check_blr = MOV_get_long(tdbb, &desc2, 0) != 0; if (check_blr) DFW_post_work_arg(transaction, work, NULL, 0, dfw_arg_check_blr); @@ -3528,7 +3528,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) EVL_field(0, rpb->rpb_record, f_fun_name, &desc); if (EVL_field(0, rpb->rpb_record, f_fun_pkg_name, &desc2)) - MOV_get_metaname(&desc2, package_name); + MOV_get_metaname(tdbb, &desc2, package_name); object_id = set_metadata_id(tdbb, rpb->rpb_record, f_fun_id, drq_g_nxt_fun_id, "RDB$FUNCTIONS"); @@ -3537,7 +3537,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { // scope bool check_blr = true; if (EVL_field(0, rpb->rpb_record, f_fun_valid_blr, &desc2)) - check_blr = MOV_get_long(&desc2, 0) != 0; + check_blr = MOV_get_long(tdbb, &desc2, 0) != 0; if (check_blr) DFW_post_work_arg(transaction, work, NULL, 0, dfw_arg_check_blr); @@ -3585,7 +3585,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_fields: EVL_field(0, rpb->rpb_record, f_fld_name, &desc); - MOV_get_metaname(&desc, object_name); + MOV_get_metaname(tdbb, &desc, object_name); SCL_check_domain(tdbb, object_name, SCL_create); DFW_post_work(transaction, dfw_create_field, &desc, 0); set_system_flag(tdbb, rpb->rpb_record, f_fld_sys_flag); @@ -3606,10 +3606,10 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { const bool name_defined = EVL_field(0, rpb->rpb_record, f_file_name, &desc); if (EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) && - MOV_get_long(&desc2, 0)) + MOV_get_long(tdbb, &desc2, 0)) { EVL_field(0, rpb->rpb_record, f_file_flags, &desc2); - if (!(MOV_get_long(&desc2, 0) & FILE_inactive)) { + if (!(MOV_get_long(tdbb, &desc2, 0) & FILE_inactive)) { DFW_post_work(transaction, dfw_add_shadow, &desc, 0); } } @@ -3617,7 +3617,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { USHORT rel_flags; if (EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) && - ((rel_flags = MOV_get_long(&desc2, 0)) & FILE_difference)) + ((rel_flags = MOV_get_long(tdbb, &desc2, 0)) & FILE_difference)) { if (name_defined) { DFW_post_work(transaction, dfw_add_difference, &desc, 0); @@ -3653,7 +3653,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (EVL_field(0, rpb->rpb_record, f_trg_type, &desc2)) { DFW_post_work_arg(transaction, work, &desc2, - (USHORT) MOV_get_int64(&desc2, 0), dfw_arg_trg_type); + (USHORT) MOV_get_int64(tdbb, &desc2, 0), dfw_arg_trg_type); } set_system_flag(tdbb, rpb->rpb_record, f_trg_sys_flag); break; @@ -3662,7 +3662,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) protect_system_table_insert(tdbb, request, relation); EVL_field(0, rpb->rpb_record, f_prv_rname, &desc); EVL_field(0, rpb->rpb_record, f_prv_o_type, &desc2); - object_id = MOV_get_long(&desc2, 0); + object_id = MOV_get_long(tdbb, &desc2, 0); DFW_post_work(transaction, dfw_grant, &desc, object_id); break; @@ -3674,7 +3674,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (EVL_field(0, rpb->rpb_record, f_vrl_vname, &desc) && EVL_field(0, rpb->rpb_record, f_vrl_context, &desc2)) { - const USHORT id = MOV_get_long(&desc2, 0); + const USHORT id = MOV_get_long(tdbb, &desc2, 0); DFW_post_work(transaction, dfw_store_view_context_type, &desc, id); } } @@ -3741,10 +3741,10 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_collations: { EVL_field(0, rpb->rpb_record, f_coll_cs_id, &desc); - USHORT id = MOV_get_long(&desc, 0); + USHORT id = MOV_get_long(tdbb, &desc, 0); EVL_field(0, rpb->rpb_record, f_coll_id, &desc); - id = INTL_CS_COLL_TO_TTYPE(id, MOV_get_long(&desc, 0)); + id = INTL_CS_COLL_TO_TTYPE(id, MOV_get_long(tdbb, &desc, 0)); EVL_field(0, rpb->rpb_record, f_coll_name, &desc); DFW_post_work(transaction, dfw_create_collation, &desc, id); @@ -3999,7 +3999,10 @@ bool VIO_writelock(thread_db* tdbb, record_param* org_rpb, jrd_tra* transaction) case PREPARE_LOCKERR: // We got some kind of locking error (deadlock, timeout or lock_conflict) // Error details should be stuffed into status vector at this point - ERR_post(Arg::Gds(isc_concurrent_transaction) << Arg::Num(org_rpb->rpb_transaction_nr)); + // hvlad: we have no details as TRA_wait has already cleared the status vector + ERR_post(Arg::Gds(isc_deadlock) << + Arg::Gds(isc_update_conflict) << + Arg::Gds(isc_concurrent_transaction) << Arg::Num(org_rpb->rpb_transaction_nr)); } // Old record was restored and re-fetched for write. Now replace it. @@ -4010,7 +4013,8 @@ bool VIO_writelock(thread_db* tdbb, record_param* org_rpb, jrd_tra* transaction) org_rpb->rpb_b_line = temp.rpb_line; org_rpb->rpb_address = new_rpb.rpb_address; org_rpb->rpb_length = new_rpb.rpb_length; - org_rpb->rpb_flags |= rpb_delta; + org_rpb->rpb_flags &= ~(rpb_delta | rpb_uk_modified); + org_rpb->rpb_flags |= new_rpb.rpb_flags & rpb_delta; replace_record(tdbb, org_rpb, &stack, transaction); @@ -4138,7 +4142,7 @@ static void check_class(thread_db* tdbb, DSC desc1, desc2; EVL_field(0, old_rpb->rpb_record, id, &desc1); EVL_field(0, new_rpb->rpb_record, id, &desc2); - if (!MOV_compare(&desc1, &desc2)) + if (!MOV_compare(tdbb, &desc1, &desc2)) return; DFW_post_work(transaction, dfw_compute_security, &desc2, 0); @@ -4184,7 +4188,7 @@ static bool check_nullify_source(thread_db* tdbb, record_param* org_rpb, record_ } } - if (org_null != new_null || MOV_compare(&org_desc, &new_desc)) + if (org_null != new_null || MOV_compare(tdbb, &org_desc, &new_desc)) return false; } @@ -4213,7 +4217,7 @@ static void check_owner(thread_db* tdbb, DSC desc1, desc2; EVL_field(0, old_rpb->rpb_record, id, &desc1); EVL_field(0, new_rpb->rpb_record, id, &desc2); - if (!MOV_compare(&desc1, &desc2)) + if (!MOV_compare(tdbb, &desc1, &desc2)) return; const Jrd::Attachment* const attachment = tdbb->getAttachment(); @@ -4221,7 +4225,7 @@ static void check_owner(thread_db* tdbb, { const Firebird::MetaName name(attachment->att_user->getUserName()); desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str()); - if (!MOV_compare(&desc1, &desc2)) + if (!MOV_compare(tdbb, &desc1, &desc2)) return; } @@ -4403,7 +4407,7 @@ static UCHAR* delete_tail(thread_db* tdbb, // recreate index after field type change). So we must return true // if relevant field changed or if no fields changed. Or we must // return false if only irrelevant field changed. -static bool dfw_should_know(record_param* org_rpb, record_param* new_rpb, +static bool dfw_should_know(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, USHORT irrelevant_field, bool void_update_is_relevant) { dsc desc2, desc3; @@ -4412,7 +4416,7 @@ static bool dfw_should_know(record_param* org_rpb, record_param* new_rpb, { const bool a = EVL_field(0, org_rpb->rpb_record, iter, &desc2); const bool b = EVL_field(0, new_rpb->rpb_record, iter, &desc3); - if (a != b || MOV_compare(&desc2, &desc3)) + if (a != b || MOV_compare(tdbb, &desc2, &desc3)) { if (iter != irrelevant_field) return true; @@ -5699,11 +5703,14 @@ static int prepare_update( thread_db* tdbb, Arg::Gds(isc_update_conflict) << Arg::Gds(isc_concurrent_transaction) << Arg::Num(update_conflict_trans)); } - case tra_active: - return PREPARE_LOCKERR; case tra_limbo: - ERR_post(Arg::Gds(isc_deadlock) << Arg::Gds(isc_trainlim)); + if (!(transaction->tra_flags & TRA_ignore_limbo)) + ERR_post(Arg::Gds(isc_rec_in_limbo) << Arg::Num(rpb->rpb_transaction_nr)); + // fall thru + + case tra_active: + return PREPARE_LOCKERR; case tra_dead: break; @@ -5988,7 +5995,7 @@ static void refresh_fk_fields(thread_db* tdbb, Record* old_rec, record_param* cu // If field was not changed by user - pick up possible modification by // system cascade trigger if (flag_old == flag_new && - (!flag_old || flag_old && MOV_compare(&desc1, &desc2) == 0)) + (!flag_old || flag_old && MOV_compare(tdbb, &desc1, &desc2) == 0)) { const bool flag_tmp = EVL_field(relation, cur_rpb->rpb_record, fld, &desc1); if (flag_tmp) @@ -6017,7 +6024,7 @@ static SSHORT set_metadata_id(thread_db* tdbb, Record* record, USHORT field_id, dsc desc1; if (EVL_field(0, record, field_id, &desc1)) - return MOV_get_long(&desc1, 0); + return MOV_get_long(tdbb, &desc1, 0); SSHORT value = (SSHORT) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name); dsc desc2; diff --git a/src/lock/print.cpp b/src/lock/print.cpp index e654fe2ffd..12b27cec13 100644 --- a/src/lock/print.cpp +++ b/src/lock/print.cpp @@ -360,7 +360,7 @@ int CLIB_ROUTINE main( int argc, char *argv[]) exit(FINI_OK); } SCHAR c; - while (c = *p++) + while ((c = *p++)) switch (c) { case '?': diff --git a/src/misc/pascal/Pascal.interface.pas b/src/misc/pascal/Pascal.interface.pas index e3e665fb03..17babbee1a 100644 --- a/src/misc/pascal/Pascal.interface.pas +++ b/src/misc/pascal/Pascal.interface.pas @@ -15,6 +15,8 @@ ISC_DATE = Integer; ISC_TIME = Integer; ISC_QUAD = array [1..2] of Integer; + FB_DEC16 = array [1..1] of Int64; + FB_DEC34 = array [1..2] of Int64; ntrace_relation_t = Integer; TraceCounts = Record diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index f4d0686241..b64176978b 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=4 MinorVer=0 RevNo=0 -BuildNum=582 +BuildNum=686 NowAt=`pwd` cd `dirname $0` @@ -20,8 +20,8 @@ Root=`dirname $Root` if [ "$SPECIAL_BUILD_SUFFIX" = "" ]; then # Normal builds -SuffixKind="Unstable" -SuffixVer="" +SuffixKind="Alpha" +SuffixVer="1" BuildSuffix="Firebird 4.0" [ "$SuffixKind" = "" ] || BuildSuffix="$BuildSuffix $SuffixKind" [ "$SuffixVer" = "" ] || BuildSuffix="$BuildSuffix $SuffixVer" @@ -94,10 +94,11 @@ eof createMakeVersion() { +TmpDir="${TMPDIR:-/tmp}" OdsH="${Root}/src/jrd/ods.h" -Mini="/tmp/miniods.h" -TestCpp="/tmp/test.cpp" -AOut="/tmp/a.out" +Mini="${TmpDir}/miniods.h" +TestCpp="${TmpDir}/test.cpp" +AOut="${TmpDir}/a.out" grep ODS_VERSION $OdsH | grep -v ENCODE_ODS >$Mini diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index b7e2149d6c..fe9b3794e2 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -1,7 +1,7 @@ /* MAX_NUMBER is the next number to be used, always one more than the highest message number. */ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?); -- -('2017-02-24 22:00:00', 'JRD', 0, 818) +('2017-05-23 16:08:00', 'JRD', 0, 824) ('2015-03-17 18:33:00', 'QLI', 1, 533) ('2015-01-07 18:01:51', 'GFIX', 3, 134) ('1996-11-07 13:39:40', 'GPRE', 4, 1) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index 555363cf9a..1cc8b62e52 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -549,7 +549,7 @@ without specifying a character set.', NULL); ('exception_array_bounds_exceeded', 'POST_EXCEPTIONS and POST_EXTRENA', 'common.h', NULL, 0, 450, NULL, 'Array bounds exceeded. The code attempted to access an array element that is out of bounds.', NULL, NULL); ('exception_float_denormal_operand', 'POST_EXCEPTIONS and POST_EXTRENA', 'common.h', NULL, 0, 451, NULL, 'Float denormal operand. One of the floating-point operands is too small to represent a standard float value.', NULL, NULL); ('exception_float_divide_by_zero', 'POST_EXCEPTIONS and POST_EXTRENA', 'common.h', NULL, 0, 452, NULL, 'Floating-point divide by zero. The code attempted to divide a floating-point value by zero.', NULL, NULL); -('exception_float_inexact_result', 'POST_EXCEPTIONS and POST_EXTRENA', 'common.h', NULL, 0, 453, NULL, 'Floating-point inexact result. The result of a floating-point operation cannot be represented as a deciaml fraction.', NULL, NULL); +('exception_float_inexact_result', 'POST_EXCEPTIONS and POST_EXTRENA', 'common.h', NULL, 0, 453, NULL, 'Floating-point inexact result. The result of a floating-point operation cannot be represented as a decimal fraction.', NULL, NULL); ('exception_float_invalid_operand', 'POST_EXCEPTIONS and POST_EXTRENA', 'common.h', NULL, 0, 454, NULL, 'Floating-point invalid operand. An indeterminant error occurred during a floating-point operation.', NULL, NULL); ('exception_float_overflow', 'POST_EXCEPTIONS and POST_EXTRENA', 'common.h', NULL, 0, 455, NULL, 'Floating-point overflow. The exponent of a floating-point operation is greater than the magnitude allowed.', NULL, NULL); ('exception_float_stack_check', 'POST_EXCEPTIONS and POST_EXTRENA', 'common.h', NULL, 0, 456, NULL, 'Floating-point stack check. The stack overflowed or underflowed as the result of a floating-point operation.', NULL, NULL); @@ -925,6 +925,12 @@ Data source : @4', NULL, NULL) ('overriding_system_invalid', NULL, 'StmtNodes.cpp', NULL, 0, 815, NULL, 'OVERRIDING SYSTEM VALUE can be used only for identity column defined as ''GENERATED ALWAYS'' in INSERT for table/view @1', NULL, NULL); ('overriding_user_invalid', NULL, 'StmtNodes.cpp', NULL, 0, 816, NULL, 'OVERRIDING USER VALUE can be used only for identity column defined as ''GENERATED BY DEFAULT'' in INSERT for table/view @1', NULL, NULL); ('overriding_system_missing', NULL, 'StmtNodes.cpp', NULL, 0, 817, NULL, 'OVERRIDING SYSTEM VALUE should be used to override the value of an identity column defined as ''GENERATED ALWAYS'' in table/view @1', NULL, NULL); +('decprecision_err', NULL, 'dsql parse.y', NULL, 0, 818, NULL, 'DecFloat precision must be 16 or 34', NULL, NULL); +('decfloat_divide_by_zero', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 819, NULL, 'Decimal float divide by zero. The code attempted to divide a DECFLOAT value by zero.', NULL, NULL); +('decfloat_inexact_result', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 820, NULL, 'Decimal float inexact result. The result of an operation cannot be represented as a decimal fraction.', NULL, NULL); +('decfloat_invalid_operation', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 821, NULL, 'Decimal float invalid operation. An indeterminant error occurred during an operation.', NULL, NULL); +('decfloat_overflow', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 822, NULL, 'Decimal float overflow. The exponent of a result is greater than the magnitude allowed.', NULL, NULL); +('decfloat_underflow', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 823, NULL, 'Decimal float underflow. The exponent of a result is less than the magnitude allowed.', NULL, NULL); -- QLI (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL); diff --git a/src/msgs/system_errors2.sql b/src/msgs/system_errors2.sql index 00a86ba11f..d8a425cd72 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -824,6 +824,12 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-902, '42', '000', 0, 815, 'overriding_system_invalid', NULL, NULL) (-902, '42', '000', 0, 816, 'overriding_user_invalid', NULL, NULL) (-902, '42', '000', 0, 817, 'overriding_system_missing', NULL, NULL) +(-842, 'HY', '104', 0, 818, 'decprecision_err', NULL, NULL) +(-901, '22', '012', 0, 819, 'decfloat_divide_by_zero', NULL, NULL) +(-901, '22', '000', 0, 820, 'decfloat_inexact_result', NULL, NULL) +(-901, '22', '000', 0, 821, 'decfloat_invalid_operation', NULL, NULL) +(-901, '22', '003', 0, 822, 'decfloat_overflow', NULL, NULL) +(-901, '22', '003', 0, 823, 'decfloat_underflow', NULL, NULL) -- GFIX (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL) diff --git a/src/qli/show.epp b/src/qli/show.epp index 715678cf6e..cb26851c71 100644 --- a/src/qli/show.epp +++ b/src/qli/show.epp @@ -213,7 +213,7 @@ void SHOW_stuff( qli_syntax* node) case show_system_relations: // No need to define a buffer here; we are interested in its length. width = get_window_size(buf_len - 1); - if (dbb = (qli_dbb*) value) + if ((dbb = (qli_dbb*) value)) show_rels(dbb, sw, width); else { @@ -1116,7 +1116,7 @@ static void show_fields( qli_rel* relation, qli_fld* fields) USHORT l = symbol->sym_length; printf(" %s", symbol->sym_string); - if (symbol = field->fld_query_name) + if ((symbol = field->fld_query_name)) { l += symbol->sym_length + 3; printf(" (%s)", symbol->sym_string); diff --git a/src/remote/client/BlrFromMessage.cpp b/src/remote/client/BlrFromMessage.cpp index 1c4b81120f..214495d913 100644 --- a/src/remote/client/BlrFromMessage.cpp +++ b/src/remote/client/BlrFromMessage.cpp @@ -117,6 +117,16 @@ void BlrFromMessage::buildBlr(IMessageMetadata* metadata) dtype = dtype_text; break; + case SQL_DEC16: + appendUChar(blr_dec64); + dtype = dtype_dec64; + break; + + case SQL_DEC34: + appendUChar(blr_dec128); + dtype = dtype_dec128; + break; + case SQL_DOUBLE: appendUChar(blr_double); dtype = dtype_double; diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp index d4c88583f2..b6784f6914 100644 --- a/src/remote/client/interface.cpp +++ b/src/remote/client/interface.cpp @@ -6616,7 +6616,7 @@ static void mov_dsql_message(const UCHAR* from_msg, // Safe const cast, we are going to move from it to anywhere. from.dsc_address = const_cast(from_msg) + (IPTR) from.dsc_address; to.dsc_address = to_msg + (IPTR) to.dsc_address; - CVT_move(&from, &to, move_error); + CVT_move(&from, &to, DecimalStatus(DEC_Errors), move_error); } } diff --git a/src/remote/os/win32/wnet_proto.h b/src/remote/os/win32/wnet_proto.h index ab1723d1f8..8808852a1d 100644 --- a/src/remote/os/win32/wnet_proto.h +++ b/src/remote/os/win32/wnet_proto.h @@ -26,20 +26,10 @@ #include "../common/classes/fb_string.h" -#ifdef __cplusplus -extern "C" { -#endif - - rem_port* WNET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*, bool, Firebird::RefPtr*, const Firebird::PathName*); rem_port* WNET_connect(const TEXT*, struct packet*, USHORT, Firebird::RefPtr*); rem_port* WNET_reconnect(HANDLE); -#ifdef __cplusplus -} /* extern "C" */ -#endif - - #endif // REMOTE_WNET_PROTO_H diff --git a/src/remote/parser.cpp b/src/remote/parser.cpp index 9b7dbbef6a..cf7516bba5 100644 --- a/src/remote/parser.cpp +++ b/src/remote/parser.cpp @@ -30,11 +30,13 @@ #include "../jrd/align.h" #include "../common/gdsassert.h" #include "../remote/parse_proto.h" +#include "../common/DecFloat.h" #if !defined(DEV_BUILD) || (defined(DEV_BUILD) && defined(WIN_NT)) #include "../yvalve/gds_proto.h" // gds__log() #endif +using namespace Firebird; static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length); @@ -156,7 +158,7 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length) USHORT count = *blr++; count += (*blr++) << 8; - Firebird::AutoPtr format(FB_NEW rem_fmt(count)); + AutoPtr format(FB_NEW rem_fmt(count)); ULONG net_length = 0; ULONG offset = 0; @@ -286,6 +288,18 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length) align = type_alignments[dtype_double]; break; + case blr_dec64: + desc->dsc_dtype = dtype_dec64; + desc->dsc_length = sizeof(Decimal64); + align = type_alignments[dtype_dec64]; + break; + + case blr_dec128: + desc->dsc_dtype = dtype_dec128; + desc->dsc_length = sizeof(Decimal128); + align = type_alignments[dtype_dec128]; + break; + // this case cannot occur as switch paramater is char and blr_blob // is 261. blob_ids are actually passed around as blr_quad. diff --git a/src/remote/remote.h b/src/remote/remote.h index c2fca51dfc..5e188b2e2a 100644 --- a/src/remote/remote.h +++ b/src/remote/remote.h @@ -257,6 +257,9 @@ public: { if (rbl_self && *rbl_self == this) *rbl_self = NULL; + + if (rbl_iface) + rbl_iface->release(); } static ISC_STATUS badHandle() { return isc_bad_segstr_handle; } @@ -392,6 +395,9 @@ public: { if (rrq_self && *rrq_self == this) *rrq_self = NULL; + + if (rrq_iface) + rrq_iface->release(); } Rrq* clone() const @@ -507,6 +513,12 @@ public: if (rsr_self && *rsr_self == this) *rsr_self = NULL; + if (rsr_cursor) + rsr_cursor->release(); + + if (rsr_iface) + rsr_iface->release(); + delete rsr_status; } diff --git a/src/remote/server/server.cpp b/src/remote/server/server.cpp index b1accd8efd..bd7550668c 100644 --- a/src/remote/server/server.cpp +++ b/src/remote/server/server.cpp @@ -917,6 +917,19 @@ public: if (!allowCancel) return; + if (!(port->port_flags & PORT_disconnect)) + { + PACKET packet; + packet.p_operation = op_event; + P_EVENT* p_event = &packet.p_event; + p_event->p_event_database = rdb->rdb_id; + p_event->p_event_items.cstr_length = length; + p_event->p_event_items.cstr_address = items; + p_event->p_event_rid = event->rvnt_id; + + port->send(&packet); + } + if (event->rvnt_iface) { LocalStatus ls; @@ -924,19 +937,6 @@ public: event->rvnt_iface->cancel(&status_vector); event->rvnt_iface = NULL; } - - if (port->port_flags & PORT_disconnect) - return; - - PACKET packet; - packet.p_operation = op_event; - P_EVENT* p_event = &packet.p_event; - p_event->p_event_database = rdb->rdb_id; - p_event->p_event_items.cstr_length = length; - p_event->p_event_items.cstr_address = items; - p_event->p_event_rid = event->rvnt_id; - - port->send(&packet); } int release() @@ -2966,7 +2966,10 @@ ISC_STATUS rem_port::end_blob(P_OP operation, P_RLSE * release, PACKET* sendL) blob->rbl_iface->cancel(&status_vector); if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS)) + { + blob->rbl_iface = NULL; release_blob(blob); + } return this->send_response(sendL, 0, 0, &status_vector, false); } @@ -3045,7 +3048,10 @@ ISC_STATUS rem_port::end_request(P_RLSE * release, PACKET* sendL) requestL->rrq_iface->free(&status_vector); if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS)) + { + requestL->rrq_iface = NULL; release_request(requestL); + } return this->send_response(sendL, 0, 0, &status_vector, true); } @@ -4743,8 +4749,8 @@ ISC_STATUS rem_port::que_events(P_EVENT * stuff, PACKET* sendL) { if (!event->rvnt_iface) { - event->rvnt_destroyed = 0; - break; + if (event->rvnt_destroyed.compareExchange(1, 0)) + break; } } @@ -5168,6 +5174,7 @@ static void release_transaction( Rtr* transaction) { Rsr* const statement = transaction->rtr_cursors.pop(); fb_assert(statement->rsr_cursor); + statement->rsr_cursor->release(); statement->rsr_cursor = NULL; } diff --git a/src/utilities/nbackup/nbackup.cpp b/src/utilities/nbackup/nbackup.cpp index faa383076b..6871fd3ea7 100644 --- a/src/utilities/nbackup/nbackup.cpp +++ b/src/utilities/nbackup/nbackup.cpp @@ -682,7 +682,15 @@ void NBackup::create_backup() } else { - backup = CreateFile(nm.c_str(), GENERIC_WRITE, FILE_SHARE_DELETE, + // See CORE-4913 and "Create File" article on MSDN: + // When an application creates a file across a network, it is better to use + // GENERIC_READ | GENERIC_WRITE for dwDesiredAccess than to use GENERIC_WRITE + // alone. The resulting code is faster, because the redirector can use the + // cache manager and send fewer SMBs with more data. This combination also + // avoids an issue where writing to a file across a network can occasionally + // return ERROR_ACCESS_DENIED. + + backup = CreateFile(nm.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); } if (backup != INVALID_HANDLE_VALUE) diff --git a/src/utilities/ntrace/TracePluginImpl.cpp b/src/utilities/ntrace/TracePluginImpl.cpp index a3ee1b48c6..ce9c50f4ab 100644 --- a/src/utilities/ntrace/TracePluginImpl.cpp +++ b/src/utilities/ntrace/TracePluginImpl.cpp @@ -725,21 +725,12 @@ void TracePluginImpl::appendParams(ITraceParams* params) else paramtype = "smallint"; break; - case dtype_long: if (parameters->dsc_scale) paramtype.printf("integer(*, %d)", parameters->dsc_scale); else paramtype = "integer"; break; - - case dtype_double: - if (parameters->dsc_scale) - paramtype.printf("double precision(*, %d)", parameters->dsc_scale); - else - paramtype = "double precision"; - break; - case dtype_int64: if (parameters->dsc_scale) paramtype.printf("bigint(*, %d)", parameters->dsc_scale); @@ -750,6 +741,20 @@ void TracePluginImpl::appendParams(ITraceParams* params) case dtype_real: paramtype = "float"; break; + case dtype_double: + if (parameters->dsc_scale) + paramtype.printf("double precision(*, %d)", parameters->dsc_scale); + else + paramtype = "double precision"; + break; + + case dtype_dec64: + paramtype = "decfloat(16)"; + break; + case dtype_dec128: + paramtype = "decfloat(34)"; + break; + case dtype_sql_date: paramtype = "date"; break; @@ -759,9 +764,11 @@ void TracePluginImpl::appendParams(ITraceParams* params) case dtype_timestamp: paramtype = "timestamp"; break; + case dtype_dbkey: paramtype = "db_key"; break; + case dtype_boolean: paramtype = "boolean"; break; @@ -839,6 +846,14 @@ void TracePluginImpl::appendParams(ITraceParams* params) } break; + case dtype_dec64: + ((Decimal64*) parameters->dsc_address)->toString(paramvalue); + break; + + case dtype_dec128: + ((Decimal128*) parameters->dsc_address)->toString(paramvalue); + break; + case dtype_sql_date: { struct tm times; diff --git a/src/yvalve/YObjects.h b/src/yvalve/YObjects.h index 1162b4d46e..269930c4e9 100644 --- a/src/yvalve/YObjects.h +++ b/src/yvalve/YObjects.h @@ -588,6 +588,8 @@ public: unsigned setOffsets(Firebird::CheckStatusWrapper* status, Firebird::IMessageMetadata* metadata, Firebird::IOffsetsCallback* callback); Firebird::IEventBlock* createEventBlock(Firebird::CheckStatusWrapper* status, const char** events); + Firebird::IDecFloat16* getDecFloat16(Firebird::CheckStatusWrapper* status); + Firebird::IDecFloat34* getDecFloat34(Firebird::CheckStatusWrapper* status); }; } // namespace Why diff --git a/src/yvalve/keywords.cpp b/src/yvalve/keywords.cpp index adbf0e8012..113248e800 100644 --- a/src/yvalve/keywords.cpp +++ b/src/yvalve/keywords.cpp @@ -95,6 +95,7 @@ static const TOK tokens[] = {TOK_BIN_SHR, "BIN_SHR", true}, {TOK_BIN_XOR, "BIN_XOR", true}, {TOK_BINARY, "BINARY", false}, + {TOK_BIND, "BIND", true}, {TOK_BIT_LENGTH, "BIT_LENGTH", false}, {TOK_BLOB, "BLOB", false}, {TOK_BLOCK, "BLOCK", true}, @@ -124,6 +125,7 @@ static const TOK tokens[] = {TOK_COMMIT, "COMMIT", false}, {TOK_COMMITTED, "COMMITTED", true}, {TOK_COMMON, "COMMON", true}, + {TOK_COMPARE_DECFLOAT, "COMPARE_DECFLOAT", true}, {TOK_COMPUTED, "COMPUTED", true}, {TOK_CONDITIONAL, "CONDITIONAL", true}, {TOK_CONNECT, "CONNECT", false}, @@ -159,6 +161,7 @@ static const TOK tokens[] = {TOK_DAY, "DAY", false}, {TOK_DDL, "DDL", true}, {TOK_DEC, "DEC", false}, + {TOK_DECFLOAT, "DECFLOAT", true}, {TOK_DECIMAL, "DECIMAL", false}, {TOK_DECLARE, "DECLARE", false}, {TOK_DECODE, "DECODE", true}, @@ -283,10 +286,12 @@ static const TOK tokens[] = {TOK_NAME, "NAME", true}, {TOK_NAMES, "NAMES", true}, {TOK_NATIONAL, "NATIONAL", false}, + {TOK_NATIVE, "NATIVE", true}, {TOK_NATURAL, "NATURAL", false}, {TOK_NCHAR, "NCHAR", false}, {TOK_NEXT, "NEXT", true}, {TOK_NO, "NO", false}, + {TOK_NORMALIZE_DECFLOAT, "NORMALIZE_DECFLOAT", true}, {TOK_NOT, "NOT", false}, {TOK_NTH_VALUE, "NTH_VALUE", true}, {TOK_NTILE, "NTILE", true}, @@ -336,6 +341,7 @@ static const TOK tokens[] = {TOK_PRIVILEGES, "PRIVILEGES", true}, {TOK_PROCEDURE, "PROCEDURE", false}, {TOK_PROTECTED, "PROTECTED", true}, + {TOK_QUANTIZE, "QUANTIZE", true}, {TOK_RAND, "RAND", true}, {TOK_RANGE, "RANGE", true}, {TOK_RANK, "RANK", true}, @@ -441,8 +447,10 @@ static const TOK tokens[] = {TOK_TIMESTAMP, "TIMESTAMP", false}, {TOK_TIMEOUT, "TIMEOUT", true}, {TOK_TO, "TO", false}, + {TOK_TOTALORDER, "TOTALORDER", true}, {TOK_TRAILING, "TRAILING", false}, {TOK_TRANSACTION, "TRANSACTION", true}, + {TOK_TRAPS, "TRAPS", true}, {TOK_TRIGGER, "TRIGGER", false}, {TOK_TRIM, "TRIM", false}, {TOK_TRUE, "TRUE", false}, diff --git a/src/yvalve/utl.cpp b/src/yvalve/utl.cpp index ee313712d0..825d83a595 100644 --- a/src/yvalve/utl.cpp +++ b/src/yvalve/utl.cpp @@ -1057,6 +1057,128 @@ IXpbBuilder* UtilInterface::getXpbBuilder(CheckStatusWrapper* status, } } +class DecFloat16 FB_FINAL : public AutoIface > +{ +public: + // IDecFloat16 implementation + void toBcd(const FB_DEC16* from, int* sign, unsigned char* bcd, int* exp) + { + *sign = decDoubleToBCD(reinterpret_cast(from), exp, bcd); + } + + void toString(CheckStatusWrapper* status, const FB_DEC16* from, unsigned bufSize, char* buffer) + { + try + { + if (bufSize >= STRING_SIZE) + decDoubleToString(reinterpret_cast(from), buffer); + else + { + char temp[STRING_SIZE]; + decDoubleToString(reinterpret_cast(from), temp); + int len = strlen(temp); + if (len < bufSize) + strncpy(buffer, temp, bufSize); + else + { + (Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) << + Arg::Gds(isc_trunc_limits) << Arg::Num(bufSize) << Arg::Num(len)); + } + } + } + catch (const Exception& ex) + { + ex.stuffException(status); + } + } + + void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC16* to) + { + decDoubleFromBCD(reinterpret_cast(to), exp, bcd, sign ? DECFLOAT_Sign : 0); + } + + void fromString(CheckStatusWrapper* status, const char* from, FB_DEC16* to) + { + try + { + DecimalStatus decSt(DEC_Errors); + Decimal64* val = reinterpret_cast(to); + val->set(from, decSt); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } + } +}; + +IDecFloat16* UtilInterface::getDecFloat16(CheckStatusWrapper* status) +{ + static DecFloat16 decFloat16; + return &decFloat16; +} + +class DecFloat34 FB_FINAL : public AutoIface > +{ +public: + // IDecFloat34 implementation + void toBcd(const FB_DEC34* from, int* sign, unsigned char* bcd, int* exp) + { + *sign = decQuadToBCD(reinterpret_cast(from), exp, bcd); + } + + void toString(CheckStatusWrapper* status, const FB_DEC34* from, unsigned bufSize, char* buffer) + { + try + { + if (bufSize >= STRING_SIZE) + decQuadToString(reinterpret_cast(from), buffer); + else + { + char temp[STRING_SIZE]; + decQuadToString(reinterpret_cast(from), temp); + int len = strlen(temp); + if (len < bufSize) + strncpy(buffer, temp, bufSize); + else + { + (Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) << + Arg::Gds(isc_trunc_limits) << Arg::Num(bufSize) << Arg::Num(len)); + } + } + } + catch (const Exception& ex) + { + ex.stuffException(status); + } + } + + void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC34* to) + { + decQuadFromBCD(reinterpret_cast(to), exp, bcd, sign ? DECFLOAT_Sign : 0); + } + + void fromString(CheckStatusWrapper* status, const char* from, FB_DEC34* to) + { + try + { + DecimalStatus decSt(DEC_Errors); + Decimal128* val = reinterpret_cast(to); + val->set(from, decSt); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } + } +}; + +IDecFloat34* UtilInterface::getDecFloat34(CheckStatusWrapper* status) +{ + static DecFloat34 decFloat34; + return &decFloat34; +} + unsigned UtilInterface::setOffsets(CheckStatusWrapper* status, IMessageMetadata* metadata, IOffsetsCallback* callback) {