Compare commits

...

2 Commits

Author SHA1 Message Date
Alexander Korotkov f4a4a18ecb Validate ltree siglen GiST option to be int-aligned
Unaligned siglen could lead to an unaligned access to subsequent key fields.

Backpatch to 13, where opclass options were introduced.

Reported-by: Alexander Lakhin
Bug: 17847
Discussion: https://postgr.es/m/17847-171232970bea406b%40postgresql.org
Reviewed-by: Tom Lane, Pavel Borisov, Alexander Lakhin
Backpatch-through: 13
2023-04-23 14:31:11 +03:00
Alexander Korotkov 9ef5a35837 Fix custom validators call in build_local_reloptions()
We need to call them only when validate == true.

Backpatch to 13, where opclass options were introduced.

Reported-by: Tom Lane
Discussion: https://postgr.es/m/2656633.1681831542%40sss.pgh.pa.us
Reviewed-by: Tom Lane, Pavel Borisov
Backpatch-through: 13
2023-04-23 14:00:13 +03:00
5 changed files with 30 additions and 6 deletions

View File

@ -7821,10 +7821,15 @@ SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc;
drop index tstidx;
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=0));
ERROR: value 0 out of bounds for option "siglen"
DETAIL: Valid values are between "1" and "2024".
DETAIL: Valid values are between "4" and "2024".
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2025));
ERROR: value 2025 out of bounds for option "siglen"
DETAIL: Valid values are between "1" and "2024".
DETAIL: Valid values are between "4" and "2024".
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2028));
ERROR: value 2028 out of bounds for option "siglen"
DETAIL: Valid values are between "4" and "2024".
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2019));
ERROR: siglen value must be a multiple of 4
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2024));
SELECT count(*) FROM ltreetest WHERE t < '12.3';
count

View File

@ -716,6 +716,18 @@ ltree_consistent(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(res);
}
static void
ltree_gist_relopts_validator(void *parsed_options, relopt_value *vals,
int nvals)
{
LtreeGistOptions *options = (LtreeGistOptions *) parsed_options;
if (options->siglen != INTALIGN(options->siglen))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("siglen value must be a multiple of %d", ALIGNOF_INT)));
}
Datum
ltree_gist_options(PG_FUNCTION_ARGS)
{
@ -724,8 +736,11 @@ ltree_gist_options(PG_FUNCTION_ARGS)
init_local_reloptions(relopts, sizeof(LtreeGistOptions));
add_local_int_reloption(relopts, "siglen",
"signature length in bytes",
LTREE_SIGLEN_DEFAULT, 1, LTREE_SIGLEN_MAX,
LTREE_SIGLEN_DEFAULT,
INTALIGN(1),
LTREE_SIGLEN_MAX,
offsetof(LtreeGistOptions, siglen));
register_reloptions_validator(relopts, ltree_gist_relopts_validator);
PG_RETURN_VOID();
}

View File

@ -325,6 +325,8 @@ SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc;
drop index tstidx;
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=0));
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2025));
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2028));
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2019));
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2024));
SELECT count(*) FROM ltreetest WHERE t < '12.3';

View File

@ -636,7 +636,8 @@ Europe &amp; Russia*@ &amp; !Transportation
path labels as a bitmap signature. Its optional integer parameter
<literal>siglen</literal> determines the
signature length in bytes. The default signature length is 8 bytes.
Valid values of signature length are between 1 and 2024 bytes. Longer
The length must be a positive multiple of <type>int</type> alignment
(4 bytes on most machines)) up to 2024. Longer
signatures lead to a more precise search (scanning a smaller fraction of the index and
fewer heap pages), at the cost of a larger index.
</para>

View File

@ -1963,8 +1963,9 @@ build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
fillRelOptions(opts, relopts->relopt_struct_size, vals, noptions, validate,
elems, noptions);
foreach(lc, relopts->validators)
((relopts_validator) lfirst(lc)) (opts, vals, noptions);
if (validate)
foreach(lc, relopts->validators)
((relopts_validator) lfirst(lc)) (opts, vals, noptions);
if (elems)
pfree(elems);