Skip to content

Commit 15714bd

Browse files
authored
MONGOCRYPT-937 restore prefixPreview and suffixPreview (#1191)
1 parent 648e8c8 commit 15714bd

9 files changed

Lines changed: 53 additions & 56 deletions

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## 1.20.0 [Unreleased]
44

5+
### Added
6+
- Restore support for the deprecated `prefixPreview` and `suffixPreview` query types.
7+
58
<!-- TODO: add entries for next release -->
69

710
## 1.19.0

src/mc-efc-private.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ typedef enum _supported_query_type_flags {
3232
SUPPORTS_SUBSTRING_PREVIEW_QUERIES = 1 << 3,
3333
SUPPORTS_SUFFIX_QUERIES = 1 << 4,
3434
SUPPORTS_PREFIX_QUERIES = 1 << 5,
35-
// prefixPreview and suffixPreview are dropped. Setting this results in an error.
35+
// suffixPreview and prefixPreview are deprecated aliases for suffix and prefix, respectively.
3636
SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES = 1 << 6,
3737
SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES = 1 << 7,
3838
} supported_query_type_flags;

src/mc-efc.c

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -178,20 +178,6 @@ static bool _parse_field(mc_EncryptedFieldConfig_t *efc, bson_t *field, mongocry
178178
return false;
179179
}
180180

181-
if (query_types & SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES) {
182-
CLIENT_ERR("Cannot use field '%s' with 'prefixPreview' queries. 'prefixPreview' is unsupported. Use 'prefix' "
183-
"instead.",
184-
field_path);
185-
return false;
186-
}
187-
188-
if (query_types & SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES) {
189-
CLIENT_ERR("Cannot use field '%s' with 'suffixPreview' queries. 'suffixPreview' is unsupported. Use 'suffix' "
190-
"instead.",
191-
field_path);
192-
return false;
193-
}
194-
195181
/* Prepend a new mc_EncryptedField_t */
196182
mc_EncryptedField_t *ef = bson_malloc0(sizeof(mc_EncryptedField_t));
197183
if (has_keyid) {
@@ -258,7 +244,8 @@ bool mc_EncryptedFieldConfig_parse(mc_EncryptedFieldConfig_t *efc,
258244

259245
if (!bson_iter_init_find(&iter, efc_bson, "strEncodeVersion")) {
260246
if (all_supported_queries
261-
& (SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES | SUPPORTS_PREFIX_QUERIES)) {
247+
& (SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES | SUPPORTS_PREFIX_QUERIES
248+
| SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES | SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
262249
// Has at least one text search query type, set to latest by default.
263250
efc->str_encode_version = LATEST_STR_ENCODE_VERSION;
264251
} else {

src/mc-textopts.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,11 +368,13 @@ bool mc_TextOpts_to_FLE2TextSearchInsertSpec_for_query(const mc_TextOpts_t *txo,
368368
CLIENT_ERR("Unexpected query type: %s\n", _mongocrypt_query_type_to_string(query_type));
369369
return false;
370370
}
371-
case MONGOCRYPT_QUERY_TYPE_PREFIX: {
371+
case MONGOCRYPT_QUERY_TYPE_PREFIX:
372+
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED: {
372373
include_prefix = true;
373374
break;
374375
}
375-
case MONGOCRYPT_QUERY_TYPE_SUFFIX: {
376+
case MONGOCRYPT_QUERY_TYPE_SUFFIX:
377+
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED: {
376378
include_suffix = true;
377379
break;
378380
}

src/mongocrypt-ctx-encrypt.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,8 @@ static moe_result must_omit_encryptionInformation(const char *command_name,
891891
for (const mc_EncryptedField_t *ef = efc->fields; ef != NULL; ef = ef->next) {
892892
if (ef->supported_queries
893893
& (SUPPORTS_RANGE_QUERIES | SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES
894-
| SUPPORTS_PREFIX_QUERIES)) {
894+
| SUPPORTS_PREFIX_QUERIES | SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES
895+
| SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
895896
has_fields_requiring_ei = true;
896897
break;
897898
}
@@ -1012,7 +1013,8 @@ static bool _fle2_append_compactionTokens(mongocrypt_t *crypt,
10121013

10131014
if (ptr->supported_queries
10141015
& (SUPPORTS_RANGE_QUERIES | SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES
1015-
| SUPPORTS_PREFIX_QUERIES)) {
1016+
| SUPPORTS_PREFIX_QUERIES | SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES
1017+
| SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
10161018
// Append the document {ecoc: <ECOCToken>, anchorPaddingToken: <AnchorPaddingTokenRoot>}
10171019
esct = mc_ESCToken_new(crypto, cl1t, status);
10181020
if (!esct) {
@@ -1522,6 +1524,8 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
15221524
// fallthrough
15231525
case MONGOCRYPT_QUERY_TYPE_SUFFIX:
15241526
case MONGOCRYPT_QUERY_TYPE_PREFIX:
1527+
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED:
1528+
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED:
15251529
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
15261530
case MONGOCRYPT_QUERY_TYPE_RANGE:
15271531
case MONGOCRYPT_QUERY_TYPE_EQUALITY: marking.u.fle2.type = MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND; break;
@@ -2087,12 +2091,12 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
20872091

20882092
if (ctx->opts.query_type.set) {
20892093
const mongocrypt_query_type_t qt = ctx->opts.query_type.value;
2090-
if (qt == MONGOCRYPT_QUERY_TYPE_PREFIX) {
2094+
if (qt == MONGOCRYPT_QUERY_TYPE_PREFIX || qt == MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED) {
20912095
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
20922096
return _mongocrypt_ctx_fail_w_msg(ctx, "prefix query type requires string index type");
20932097
}
20942098
}
2095-
if (qt == MONGOCRYPT_QUERY_TYPE_SUFFIX) {
2099+
if (qt == MONGOCRYPT_QUERY_TYPE_SUFFIX || qt == MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED) {
20962100
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
20972101
return _mongocrypt_ctx_fail_w_msg(ctx, "suffix query type requires string index type");
20982102
}
@@ -2182,6 +2186,8 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
21822186
// fallthrough
21832187
case MONGOCRYPT_QUERY_TYPE_PREFIX:
21842188
case MONGOCRYPT_QUERY_TYPE_SUFFIX:
2189+
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED:
2190+
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED:
21852191
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
21862192
matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING);
21872193
break;

src/mongocrypt-ctx-private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ typedef enum _mongocrypt_query_type_t {
4747
MONGOCRYPT_QUERY_TYPE_PREFIX = 4,
4848
MONGOCRYPT_QUERY_TYPE_SUFFIX = 5,
4949
MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW = 6,
50+
// prefixPreview and suffixPreview are deprecated aliases for prefix and suffix, respectively. They behave
51+
// identically; the distinct values exist for consistency (cf. rangePreview) and to ease eventual removal.
52+
MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED = 7,
53+
MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED = 8,
5054
} mongocrypt_query_type_t;
5155

5256
const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val);

src/mongocrypt-ctx.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,11 +1028,13 @@ bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t *ctx, const char *query_t
10281028
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUFFIX;
10291029
ctx->opts.query_type.set = true;
10301030
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR))) {
1031-
_mongocrypt_ctx_fail_w_msg(ctx, "Query type 'prefixPreview' is deprecated, please use 'prefix'");
1032-
return false;
1031+
// 'prefixPreview' is a deprecated alias for 'prefix'.
1032+
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED;
1033+
ctx->opts.query_type.set = true;
10331034
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR))) {
1034-
_mongocrypt_ctx_fail_w_msg(ctx, "Query type 'suffixPreview' is deprecated, please use 'suffix'");
1035-
return false;
1035+
// 'suffixPreview' is a deprecated alias for 'suffix'.
1036+
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED;
1037+
ctx->opts.query_type.set = true;
10361038
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_STR))) {
10371039
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW;
10381040
ctx->opts.query_type.set = true;
@@ -1066,6 +1068,8 @@ const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val) {
10661068
case MONGOCRYPT_QUERY_TYPE_RANGE: return "Range";
10671069
case MONGOCRYPT_QUERY_TYPE_PREFIX: return "Prefix";
10681070
case MONGOCRYPT_QUERY_TYPE_SUFFIX: return "Suffix";
1071+
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED: return "PrefixPreview";
1072+
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED: return "SuffixPreview";
10691073
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW: return "SubstringPreview";
10701074
default: return "Unknown";
10711075
}

test/test-mongocrypt-ctx-encrypt.c

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,10 +2511,11 @@ static void _test_encrypt_fle2_explicit(_mongocrypt_tester_t *tester) {
25112511
}
25122512

25132513
{
2514+
// "suffixPreview" is a deprecated alias for "suffix" and must produce identical output.
25142515
ee_testcase tc = {0};
2515-
tc.desc = "find suffix";
2516+
tc.desc = "find suffixPreview";
25162517
tc.algorithm = MONGOCRYPT_ALGORITHM_STRING_STR;
2517-
tc.query_type = MONGOCRYPT_QUERY_TYPE_SUFFIX_STR;
2518+
tc.query_type = MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR;
25182519
tc.contention_factor = OPT_I64(1);
25192520
tc.msg = TEST_BSON("{'v': 'abc'}");
25202521
tc.user_key_id = &keyABC_id;
@@ -2529,10 +2530,11 @@ static void _test_encrypt_fle2_explicit(_mongocrypt_tester_t *tester) {
25292530
}
25302531

25312532
{
2533+
// "prefixPreview" is a deprecated alias for "prefix" and must produce identical output.
25322534
ee_testcase tc = {0};
2533-
tc.desc = "find prefix";
2535+
tc.desc = "find prefixPreview";
25342536
tc.algorithm = MONGOCRYPT_ALGORITHM_STRING_STR;
2535-
tc.query_type = MONGOCRYPT_QUERY_TYPE_PREFIX_STR;
2537+
tc.query_type = MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR;
25362538
tc.contention_factor = OPT_I64(1);
25372539
tc.msg = TEST_BSON("{'v': 'abc'}");
25382540
tc.user_key_id = &keyABC_id;
@@ -4410,8 +4412,9 @@ static void _test_rangePreview_fails(_mongocrypt_tester_t *tester) {
44104412
bson_free(local_kek);
44114413
}
44124414

4413-
// `_test_prefixPreview_suffixPreview_fails` tests that use of "prefixPreview" or "suffixPreview" errors.
4414-
static void _test_prefixPreview_suffixPreview_fails(_mongocrypt_tester_t *tester) {
4415+
// `_test_prefixPreview_suffixPreview_succeeds` tests that "prefixPreview" and "suffixPreview" are accepted as
4416+
// deprecated aliases for "prefix" and "suffix".
4417+
static void _test_prefixPreview_suffixPreview_succeeds(_mongocrypt_tester_t *tester) {
44154418
#define TF(suffix) TEST_FILE("./test/data/fle2-insert-text-search-preview/" suffix)
44164419

44174420
// local_kek is the KEK used to encrypt the keyMaterial in ./test/data/key-document-local.json
@@ -4420,35 +4423,31 @@ static void _test_prefixPreview_suffixPreview_fails(_mongocrypt_tester_t *tester
44204423
mongocrypt_binary_t *kms_providers =
44214424
TEST_BSON(BSON_STR({"local" : {"key" : {"$binary" : {"base64" : "%s", "subType" : "00"}}}}), local_kek);
44224425

4423-
// Test setting 'prefixPreview' as an explicit encryption queryType results in error.
4426+
// Test setting 'prefixPreview' as an explicit encryption queryType succeeds.
44244427
{
44254428
mongocrypt_t *crypt = mongocrypt_new();
44264429
mongocrypt_setopt_kms_providers(crypt, kms_providers);
44274430
ASSERT_OK(mongocrypt_init(crypt), crypt);
44284431
mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
44294432
ASSERT_OK(ctx, crypt);
4430-
ASSERT_FAILS(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR, -1),
4431-
ctx,
4432-
"Query type 'prefixPreview' is deprecated");
4433+
ASSERT_OK(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR, -1), ctx);
44334434
mongocrypt_ctx_destroy(ctx);
44344435
mongocrypt_destroy(crypt);
44354436
}
44364437

4437-
// Test setting 'suffixPreview' as an explicit encryption queryType results in error.
4438+
// Test setting 'suffixPreview' as an explicit encryption queryType succeeds.
44384439
{
44394440
mongocrypt_t *crypt = mongocrypt_new();
44404441
mongocrypt_setopt_kms_providers(crypt, kms_providers);
44414442
ASSERT_OK(mongocrypt_init(crypt), crypt);
44424443
mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
44434444
ASSERT_OK(ctx, crypt);
4444-
ASSERT_FAILS(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR, -1),
4445-
ctx,
4446-
"Query type 'suffixPreview' is deprecated");
4445+
ASSERT_OK(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR, -1), ctx);
44474446
mongocrypt_ctx_destroy(ctx);
44484447
mongocrypt_destroy(crypt);
44494448
}
44504449

4451-
// Test setting 'prefixPreview' from encryptedFields results in error.
4450+
// Test setting 'prefixPreview' from encryptedFields succeeds.
44524451
{
44534452
mongocrypt_t *crypt = mongocrypt_new();
44544453
mongocrypt_setopt_kms_providers(crypt, kms_providers);
@@ -4457,14 +4456,12 @@ static void _test_prefixPreview_suffixPreview_fails(_mongocrypt_tester_t *tester
44574456
ASSERT_OK(mongocrypt_init(crypt), crypt);
44584457
mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
44594458
ASSERT_OK(ctx, crypt);
4460-
ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TF("cmd.json")),
4461-
ctx,
4462-
"Cannot use field 'encrypted' with 'prefixPreview' queries");
4459+
ASSERT_OK(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TF("cmd.json")), ctx);
44634460
mongocrypt_ctx_destroy(ctx);
44644461
mongocrypt_destroy(crypt);
44654462
}
44664463

4467-
// Test setting 'suffixPreview' from encryptedFields results in error.
4464+
// Test setting 'suffixPreview' from encryptedFields succeeds.
44684465
{
44694466
mongocrypt_t *crypt = mongocrypt_new();
44704467
mongocrypt_setopt_kms_providers(crypt, kms_providers);
@@ -4473,9 +4470,7 @@ static void _test_prefixPreview_suffixPreview_fails(_mongocrypt_tester_t *tester
44734470
ASSERT_OK(mongocrypt_init(crypt), crypt);
44744471
mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
44754472
ASSERT_OK(ctx, crypt);
4476-
ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TF("cmd.json")),
4477-
ctx,
4478-
"Cannot use field 'encrypted' with 'suffixPreview' queries");
4473+
ASSERT_OK(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TF("cmd.json")), ctx);
44794474
mongocrypt_ctx_destroy(ctx);
44804475
mongocrypt_destroy(crypt);
44814476
}
@@ -6904,7 +6899,7 @@ void _mongocrypt_tester_install_ctx_encrypt(_mongocrypt_tester_t *tester) {
69046899
INSTALL_TEST(_test_encrypt_fle2_insert_text_search_payload_with_str_encode_version);
69056900
INSTALL_TEST(_test_bulkWrite);
69066901
INSTALL_TEST(_test_rangePreview_fails);
6907-
INSTALL_TEST(_test_prefixPreview_suffixPreview_fails);
6902+
INSTALL_TEST(_test_prefixPreview_suffixPreview_succeeds);
69086903
INSTALL_TEST(_test_textPreview_fails);
69096904
INSTALL_TEST(_test_no_trimFactor);
69106905
INSTALL_TEST(_test_range_sends_cryptoParams);

test/test-mongocrypt-ctx-setopt.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,23 +1041,19 @@ static void _test_setopt_for_explicit_encrypt(_mongocrypt_tester_t *tester) {
10411041
ASSERT_EX_ENCRYPT_INIT_FAILS(bson, "suffix query type requires string index type");
10421042
}
10431043

1044-
// Can't use "prefixPreview" or "suffixPreview".
1044+
// "prefixPreview" and "suffixPreview" are accepted as deprecated aliases for "prefix" and "suffix".
10451045
{
10461046
mongocrypt_destroy(crypt);
10471047
crypt = _mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_DEFAULT);
10481048
REFRESH_CTX;
10491049
ASSERT_KEY_ID_OK(uuid);
1050-
ASSERT_FAILS(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR, -1),
1051-
ctx,
1052-
"'prefixPreview' is deprecated");
1050+
ASSERT_OK(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR, -1), ctx);
10531051

10541052
mongocrypt_destroy(crypt);
10551053
crypt = _mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_DEFAULT);
10561054
REFRESH_CTX;
10571055
ASSERT_KEY_ID_OK(uuid);
1058-
ASSERT_FAILS(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR, -1),
1059-
ctx,
1060-
"'suffixPreview' is deprecated");
1056+
ASSERT_OK(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR, -1), ctx);
10611057
}
10621058

10631059
/* It is an error to set a string algorithm without setting text options */

0 commit comments

Comments
 (0)