Skip to content

Commit

Permalink
[MONGOCRYPT-536] A Toggle for Decimal128 Range Support (#569)
Browse files Browse the repository at this point in the history
* Conditional Decimal128 range support

The configure-time option MONGOCRYPT_ENABLE_DECIMAL128 can be used to
enable/disable Decimal128 range support. This is enabled by default.

- Wrap Decimal128 code in conditions on whether Decimal128 is available.
- Only supports IntelDFP for now.
  • Loading branch information
vector-of-bool authored and rcsanchez97 committed Feb 10, 2023
1 parent 64f93f1 commit 4ffcb39
Show file tree
Hide file tree
Showing 18 changed files with 118 additions and 8 deletions.
19 changes: 13 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ include (GNUInstallDirs)

include (LTO)
include (ImportBSON)
include (ImportDFP)

option (MONGOCRYPT_ENABLE_DECIMAL128 "Enable extended support for Decimal128" ON)
mark_as_advanced (MONGOCRYPT_ENABLE_DECIMAL128)
set (maybe_dfp_library)
if (MONGOCRYPT_ENABLE_DECIMAL128)
include (ImportDFP)
set (maybe_dfp_library mongocrypt::intel_dfp)
endif ()

if (USE_SHARED_LIBBSON AND ENABLE_BUILD_FOR_PPA)
message (FATAL_ERROR "PPA build requires static linking to libbson")
Expand Down Expand Up @@ -281,7 +288,7 @@ target_link_libraries (
kms_message_static
$<BUILD_INTERFACE:mongo::mlib>
PUBLIC
mongocrypt::intel_dfp
${maybe_dfp_library}
${CMAKE_DL_LIBS}
)

Expand Down Expand Up @@ -339,7 +346,7 @@ target_link_libraries (
kms_message_static
$<BUILD_INTERFACE:mongo::mlib>
PUBLIC
mongocrypt::intel_dfp
${maybe_dfp_library}
${CMAKE_THREAD_LIBS_INIT}
${CMAKE_DL_LIBS}
)
Expand All @@ -358,7 +365,7 @@ if (ENABLE_BUILD_FOR_PPA)
endif ()
set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} -pthread")
endif ()
if (MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM")
if (MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM" AND MONGOCRYPT_ENABLE_DECIMAL128)
get_property (SYSTEM_DFP_LOC TARGET intel_dfp PROPERTY IMPORTED_LOCATION)
set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} ${SYSTEM_DFP_LOC}")
endif ()
Expand Down Expand Up @@ -539,7 +546,7 @@ if ("cxx_relaxed_constexpr" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
target_link_libraries ("${exe_name}" PRIVATE
mongocrypt
mongo::mlib
mongocrypt::intel_dfp
${maybe_dfp_library}
Threads::Threads
_mongocrypt::libbson_for_static
)
Expand Down Expand Up @@ -634,7 +641,7 @@ if (ENABLE_BUILD_FOR_PPA)
endif ()
set (PKG_CONFIG_LIBS "${PKG_CONFIG_LIBS} -pthread")
endif ()
if (MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM")
if (MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM" AND MONGOCRYPT_ENABLE_DECIMAL128)
get_property (SYSTEM_DFP_LOC TARGET intel_dfp PROPERTY IMPORTED_LOCATION)
set (PKG_CONFIG_LIBS "${PKG_CONFIG_LIBS} ${SYSTEM_DFP_LOC}")
endif ()
Expand Down
2 changes: 2 additions & 0 deletions cmake/ImportDFP.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,7 @@ elseif (MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM")
# users during find_package()
target_link_libraries (_mongocrypt-intel_dfp INTERFACE $<BUILD_INTERFACE:intel_dfp>)

# Notify in-tree consumers that IntelDFP is available:
target_compile_definitions (_mongocrypt-intel_dfp INTERFACE $<BUILD_INTERFACE:MONGOCRYPT_INTELDFP>)
endif ()

3 changes: 3 additions & 0 deletions cmake/IntelDFP.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,9 @@ target_include_directories(intel_dfp_obj PUBLIC ${intel_dfp_SOURCE_DIR}/LIBRARY/
add_library (_mongocrypt_intel_dfp INTERFACE)
add_library (mongocrypt::intel_dfp ALIAS _mongocrypt_intel_dfp)

# Notify in-tree consumers that IntelDFP is available:
target_compile_definitions (_mongocrypt_intel_dfp INTERFACE $<BUILD_INTERFACE:MONGOCRYPT_INTELDFP>)

target_sources (_mongocrypt_intel_dfp
#[[
For targets *within this build* that link with mongocrypt::intel_dfp,
Expand Down
12 changes: 12 additions & 0 deletions src/mc-dec128.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@
#include <mlib/int128.h>
#include <mlib/endian.h>

// Conditional preprocessor definition set by the usage of an intel_dfp from
// the ImportDFP.cmake script:
#ifndef MONGOCRYPT_INTELDFP
// Notify includers that Decimal128 is not available:
#define MONGOCRYPT_HAVE_DECIMAL128_SUPPORT 0

#else // With IntelDFP:
// Tell includers that Decimal128 is okay:
#define MONGOCRYPT_HAVE_DECIMAL128_SUPPORT 1

// Include the header that declares the DFP functions, which may be macros that
// expand to renamed symbols:
#include <bid_conf.h>
Expand Down Expand Up @@ -728,4 +738,6 @@ mc_dec128_to_bson_decimal128 (mc_dec128 v)

MLIB_C_LINKAGE_END

#endif /// defined MONGOCRYPT_INTELDFP

#endif // MC_DEC128_H_INCLUDED
14 changes: 14 additions & 0 deletions src/mc-dec128.test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include <mc-dec128.h>

#include <cstdio>

#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT

#include <stdlib.h>

#include <mlib/check.hpp>
Expand Down Expand Up @@ -70,3 +74,13 @@ main ()
mc_dec128 nan = MC_DEC128_POSITIVE_NAN;
CHECK (mc_dec128_is_nan (nan));
}

#else

int
main ()
{
std::puts ("@@ctest-skip@@\n Decimal128 support is not enabled\n");
}

#endif
3 changes: 2 additions & 1 deletion src/mc-optional-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ typedef struct {
.set = true, .value = val \
}

#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
typedef struct {
bool set;
mc_dec128 value;
Expand All @@ -113,7 +114,7 @@ typedef struct {
{ \
.set = true, .value = __VA_ARGS__ \
}

#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT

#define OPT_NULLOPT \
{ \
Expand Down
2 changes: 2 additions & 0 deletions src/mc-range-edge-generation-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ typedef struct {
mc_edges_t *
mc_getEdgesDouble (mc_getEdgesDouble_args_t args, mongocrypt_status_t *status);

#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
typedef struct {
mc_dec128 value;
size_t sparsity;
Expand All @@ -87,6 +88,7 @@ typedef struct {
mc_edges_t *
mc_getEdgesDecimal128 (mc_getEdgesDecimal128_args_t args,
mongocrypt_status_t *status);
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT

BSON_STATIC_ASSERT2 (ull_is_u64,
sizeof (uint64_t) == sizeof (unsigned long long));
Expand Down
2 changes: 2 additions & 0 deletions src/mc-range-edge-generation.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ mc_getEdgesDouble (mc_getEdgesDouble_args_t args, mongocrypt_status_t *status)
return ret;
}

#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
mc_edges_t *
mc_getEdgesDecimal128 (mc_getEdgesDecimal128_args_t args,
mongocrypt_status_t *status)
Expand All @@ -238,3 +239,4 @@ mc_getEdgesDecimal128 (mc_getEdgesDecimal128_args_t args,
mc_edges_t *ret = mc_edges_new (leaf, args.sparsity, status);
return ret;
}
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
2 changes: 2 additions & 0 deletions src/mc-range-encoding-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ mc_getTypeInfoDouble (mc_getTypeInfoDouble_args_t args,
mongocrypt_status_t *status)
MONGOCRYPT_WARN_UNUSED_RESULT;

#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
/**
* @brief OST-encoding of a Decimal128
*/
Expand All @@ -122,5 +123,6 @@ mc_getTypeInfoDecimal128 (mc_getTypeInfoDecimal128_args_t args,
mc_OSTType_Decimal128 *out,
mongocrypt_status_t *status)
MONGOCRYPT_WARN_UNUSED_RESULT;
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT

#endif /* MC_RANGE_ENCODING_PRIVATE_H */
3 changes: 3 additions & 0 deletions src/mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ mc_getTypeInfoDouble (mc_getTypeInfoDouble_args_t args,
return true;
}

#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
/**
* @brief There is no shipped algorithm for creating a full 128-bit integer from
* a Decimal128, but it's easy enough to write one of our own.
Expand Down Expand Up @@ -615,3 +616,5 @@ mc_getTypeInfoDecimal128 (mc_getTypeInfoDecimal128_args_t args,

return true;
}

#endif // defined MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
2 changes: 2 additions & 0 deletions src/mc-range-mincover-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ mc_getMincoverDouble (mc_getMincoverDouble_args_t args,
MONGOCRYPT_WARN_UNUSED_RESULT;


#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
typedef struct {
mc_dec128 lowerBound;
bool includeLowerBound;
Expand All @@ -106,5 +107,6 @@ mc_mincover_t *
mc_getMincoverDecimal128 (mc_getMincoverDecimal128_args_t args,
mongocrypt_status_t *status)
MONGOCRYPT_WARN_UNUSED_RESULT;
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT

#endif /* MC_RANGE_MINCOVER_PRIVATE_H */
6 changes: 6 additions & 0 deletions src/mc-range-mincover.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ mc_mincover_destroy (mc_mincover_t *mincover)
#define DECORATE_NAME(N) N##_u64
#include "mc-range-mincover-generator.template.h"

// The 128-bit version is only required for Decimal128, otherwise generates
// unused-fn warnings
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
#define UINT_T mlib_int128
#define UINT_C MLIB_INT128
#define UINT_FMT_S "s"
Expand All @@ -92,6 +95,7 @@ mc_mincover_destroy (mc_mincover_t *mincover)
#define MC_UINT_MAX MLIB_INT128_UMAX
#define UINT_BITOR mlib_int128_bitor
#include "mc-range-mincover-generator.template.h"
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT


// Check bounds and return an error message including the original inputs.
Expand Down Expand Up @@ -283,6 +287,7 @@ mc_getMincoverDouble (mc_getMincoverDouble_args_t args,
return mc;
}

#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
mc_mincover_t *
mc_getMincoverDecimal128 (mc_getMincoverDecimal128_args_t args,
mongocrypt_status_t *status)
Expand Down Expand Up @@ -333,3 +338,4 @@ mc_getMincoverDecimal128 (mc_getMincoverDecimal128_args_t args,
MinCoverGenerator_destroy_u128 (mcg);
return mc;
}
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
12 changes: 12 additions & 0 deletions src/mc-rangeopts.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,18 @@ mc_RangeOpts_appendMin (const mc_RangeOpts_t *ro,
return false;
}
} else if (valueType == BSON_TYPE_DECIMAL128) {
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
const bson_decimal128_t min =
mc_dec128_to_bson_decimal128 (MC_DEC128_LARGEST_NEGATIVE);
if (!BSON_APPEND_DECIMAL128 (out, fieldName, &min)) {
CLIENT_ERR ("failed to append BSON");
return false;
}
#else // ↑↑↑↑↑↑↑↑ With Decimal128 / Without ↓↓↓↓↓↓↓↓↓↓
CLIENT_ERR ("unsupported BSON type (Decimal128) for range: libmongocrypt "
"was built without extended Decimal128 support");
return false;
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
} else {
CLIENT_ERR ("unsupported BSON type: %s for range",
mc_bson_type_to_string (valueType));
Expand Down Expand Up @@ -345,12 +351,18 @@ mc_RangeOpts_appendMax (const mc_RangeOpts_t *ro,
return false;
}
} else if (valueType == BSON_TYPE_DECIMAL128) {
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
const bson_decimal128_t max =
mc_dec128_to_bson_decimal128 (MC_DEC128_LARGEST_POSITIVE);
if (!BSON_APPEND_DECIMAL128 (out, fieldName, &max)) {
CLIENT_ERR ("failed to append BSON");
return false;
}
#else // ↑↑↑↑↑↑↑↑ With Decimal128 / Without ↓↓↓↓↓↓↓↓↓↓
CLIENT_ERR ("unsupported BSON type (Decimal128) for range: libmongocrypt "
"was built without extended Decimal128 support");
return false;
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
} else {
CLIENT_ERR ("unsupported BSON type: %s for range",
mc_bson_type_to_string (valueType));
Expand Down
12 changes: 12 additions & 0 deletions src/mongocrypt-marking.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ get_edges (mc_FLE2RangeInsertSpec_t *insertSpec,
}

else if (value_type == BSON_TYPE_DECIMAL128) {
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
const mc_dec128 value = mc_dec128_from_bson_iter (&insertSpec->v);
mc_getEdgesDecimal128_args_t args = {
.value = value,
Expand All @@ -715,6 +716,11 @@ get_edges (mc_FLE2RangeInsertSpec_t *insertSpec,
args.precision = insertSpec->precision;
}
return mc_getEdgesDecimal128 (args, status);
#else // ↑↑↑↑↑↑↑↑ With Decimal128 / Without ↓↓↓↓↓↓↓↓↓↓
CLIENT_ERR ("unsupported BSON type (Decimal128) for range: libmongocrypt "
"was built without extended Decimal128 support");
return NULL;
#endif
}


Expand Down Expand Up @@ -1177,6 +1183,7 @@ mc_get_mincover_from_FLE2RangeFindSpec (mc_FLE2RangeFindSpec_t *findSpec,
return mc_getMincoverDouble (args, status);
}
case BSON_TYPE_DECIMAL128: {
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
BSON_ASSERT (bson_iter_type (&lowerBound) == BSON_TYPE_DECIMAL128);
BSON_ASSERT (bson_iter_type (&upperBound) == BSON_TYPE_DECIMAL128);
BSON_ASSERT (bson_iter_type (&findSpec->edgesInfo.value.indexMin) ==
Expand All @@ -1199,6 +1206,11 @@ mc_get_mincover_from_FLE2RangeFindSpec (mc_FLE2RangeFindSpec_t *findSpec,
args.precision = findSpec->edgesInfo.value.precision;
}
return mc_getMincoverDecimal128 (args, status);
#else // ↑↑↑↑↑↑↑↑ With Decimal128 / Without ↓↓↓↓↓↓↓↓↓↓
CLIENT_ERR ("FLE2 find is not supported for Decimal128: libmongocrypt "
"was built without Decimal128 support");
return NULL;
#endif
}

case BSON_TYPE_EOD:
Expand Down
4 changes: 4 additions & 0 deletions test/test-mc-range-edge-generation.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ _test_getEdgesDouble (_mongocrypt_tester_t *tester)
}


#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
#define MAX_DEC128_EDGES 129
typedef struct {
mc_dec128 value;
Expand Down Expand Up @@ -334,6 +335,7 @@ _test_getEdgesDecimal128 (_mongocrypt_tester_t *tester)
mongocrypt_status_destroy (status);
}
}
#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT

static void
_test_count_leading_zeros (_mongocrypt_tester_t *tester)
Expand Down Expand Up @@ -458,7 +460,9 @@ _mongocrypt_tester_install_range_edge_generation (_mongocrypt_tester_t *tester)
INSTALL_TEST (_test_getEdgesInt32);
INSTALL_TEST (_test_getEdgesInt64);
INSTALL_TEST (_test_getEdgesDouble);
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
INSTALL_TEST (_test_getEdgesDecimal128);
#endif
INSTALL_TEST (_test_count_leading_zeros);
INSTALL_TEST (_test_convert_to_bitstring);
}
5 changes: 5 additions & 0 deletions test/test-mc-range-encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ _test_RangeTest_Encode_Double (_mongocrypt_tester_t *tester)
}


#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
typedef struct {
mc_dec128 value;
mc_optional_dec128_t min;
Expand Down Expand Up @@ -871,11 +872,15 @@ _test_RangeTest_Encode_Decimal128 (_mongocrypt_tester_t *tester)
}
}

#endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT

void
_mongocrypt_tester_install_range_encoding (_mongocrypt_tester_t *tester)
{
INSTALL_TEST (_test_RangeTest_Encode_Int32);
INSTALL_TEST (_test_RangeTest_Encode_Int64);
INSTALL_TEST (_test_RangeTest_Encode_Double);
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
INSTALL_TEST (_test_RangeTest_Encode_Decimal128);
#endif
}

0 comments on commit 4ffcb39

Please sign in to comment.