contrib/isn: Make weak mode a GUC setting, and fix related functions.

isn's weak mode used to be a simple static variable, settable only
via the isn_weak(boolean) function.  This wasn't optimal, as this
means it doesn't respect transactions nor respond to RESET ALL.

This patch makes isn.weak a GUC parameter instead, so that
it acts like any other user-settable parameter.

The isn_weak() functions are retained for backwards compatibility.
But we must fix their volatility markings: they were marked IMMUTABLE
which is surely incorrect, and PARALLEL RESTRICTED which isn't right
for GUC-related functions either.  Mark isn_weak(boolean) as
VOLATILE and PARALLEL UNSAFE, matching set_config().  Mark isn_weak()
as STABLE and PARALLEL SAFE, matching current_setting().

Reported-by: Viktor Holmberg <v@viktorh.net>
Diagnosed-by: Daniel Gustafsson <daniel@yesql.se>
Author: Viktor Holmberg <v@viktorh.net>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/790bc1f9-74dc-4b50-94d2-8147315b1556@Spark
pull/207/head
Tom Lane 10 months ago
parent 682c5be25c
commit 4489044239
  1. 4
      contrib/isn/Makefile
  2. 44
      contrib/isn/expected/isn.out
  3. 7
      contrib/isn/isn--1.2--1.3.sql
  4. 27
      contrib/isn/isn.c
  5. 2
      contrib/isn/isn.control
  6. 1
      contrib/isn/isn.h
  7. 3
      contrib/isn/meson.build
  8. 13
      contrib/isn/sql/isn.sql
  9. 71
      doc/src/sgml/isn.sgml

@ -3,8 +3,8 @@
MODULES = isn
EXTENSION = isn
DATA = isn--1.1.sql isn--1.1--1.2.sql \
isn--1.0--1.1.sql
DATA = isn--1.0--1.1.sql isn--1.1.sql \
isn--1.1--1.2.sql isn--1.2--1.3.sql
PGFILEDESC = "isn - data types for international product numbering standards"
# the other .h files are data tables, we don't install those

@ -279,6 +279,50 @@ FROM (VALUES ('9780123456786', 'UPC'),
9771234567003 | ISSN | t | | | |
(3 rows)
--
-- test weak mode
--
SELECT '2222222222221'::ean13; -- fail
ERROR: invalid check digit for EAN13 number: "2222222222221", should be 2
LINE 1: SELECT '2222222222221'::ean13;
^
SET isn.weak TO TRUE;
SELECT '2222222222221'::ean13;
ean13
------------------
222-222222222-2!
(1 row)
SELECT is_valid('2222222222221'::ean13);
is_valid
----------
f
(1 row)
SELECT make_valid('2222222222221'::ean13);
make_valid
-----------------
222-222222222-2
(1 row)
SELECT isn_weak(); -- backwards-compatibility wrappers for accessing the GUC
isn_weak
----------
t
(1 row)
SELECT isn_weak(false);
isn_weak
----------
f
(1 row)
SHOW isn.weak;
isn.weak
----------
off
(1 row)
--
-- cleanup
--

@ -0,0 +1,7 @@
/* contrib/isn/isn--1.2--1.3.sql */
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION isn UPDATE TO '1.3'" to load this file. \quit
ALTER FUNCTION isn_weak(boolean) VOLATILE PARALLEL UNSAFE;
ALTER FUNCTION isn_weak() STABLE PARALLEL SAFE;

@ -21,6 +21,7 @@
#include "UPC.h"
#include "fmgr.h"
#include "isn.h"
#include "utils/guc.h"
PG_MODULE_MAGIC;
@ -39,6 +40,7 @@ enum isn_type
static const char *const isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC"};
/* GUC value */
static bool g_weak = false;
@ -929,6 +931,20 @@ _PG_init(void)
if (!check_table(UPC_range, UPC_index))
elog(ERROR, "UPC failed check");
}
/* Define a GUC variable for weak mode. */
DefineCustomBoolVariable("isn.weak",
"Accept input with invalid ISN check digits.",
NULL,
&g_weak,
false,
PGC_USERSET,
0,
NULL,
NULL,
NULL);
MarkGUCPrefixReserved("isn");
}
/* isn_out
@ -1109,17 +1125,16 @@ make_valid(PG_FUNCTION_ARGS)
/* this function temporarily sets weak input flag
* (to lose the strictness of check digit acceptance)
* It's a helper function, not intended to be used!!
*/
PG_FUNCTION_INFO_V1(accept_weak_input);
Datum
accept_weak_input(PG_FUNCTION_ARGS)
{
#ifdef ISN_WEAK_MODE
g_weak = PG_GETARG_BOOL(0);
#else
/* function has no effect */
#endif /* ISN_WEAK_MODE */
bool newvalue = PG_GETARG_BOOL(0);
(void) set_config_option("isn.weak", newvalue ? "on" : "off",
PGC_USERSET, PGC_S_SESSION,
GUC_ACTION_SET, true, 0, false);
PG_RETURN_BOOL(g_weak);
}

@ -1,6 +1,6 @@
# isn extension
comment = 'data types for international product numbering standards'
default_version = '1.2'
default_version = '1.3'
module_pathname = '$libdir/isn'
relocatable = true
trusted = true

@ -18,7 +18,6 @@
#include "fmgr.h"
#undef ISN_DEBUG
#define ISN_WEAK_MODE
/*
* uint64 is the internal storage format for ISNs.

@ -19,8 +19,9 @@ contrib_targets += isn
install_data(
'isn.control',
'isn--1.0--1.1.sql',
'isn--1.1--1.2.sql',
'isn--1.1.sql',
'isn--1.1--1.2.sql',
'isn--1.2--1.3.sql',
kwargs: contrib_data_args,
)

@ -120,6 +120,19 @@ FROM (VALUES ('9780123456786', 'UPC'),
AS a(str,typ),
LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
--
-- test weak mode
--
SELECT '2222222222221'::ean13; -- fail
SET isn.weak TO TRUE;
SELECT '2222222222221'::ean13;
SELECT is_valid('2222222222221'::ean13);
SELECT make_valid('2222222222221'::ean13);
SELECT isn_weak(); -- backwards-compatibility wrappers for accessing the GUC
SELECT isn_weak(false);
SHOW isn.weak;
--
-- cleanup
--

@ -230,7 +230,7 @@
<para>
The <filename>isn</filename> module provides the standard comparison operators,
plus B-tree and hash indexing support for all these data types. In
addition there are several specialized functions; shown in <xref linkend="isn-functions"/>.
addition, there are several specialized functions, shown in <xref linkend="isn-functions"/>.
In this table,
<type>isn</type> means any one of the module's data types.
</para>
@ -252,55 +252,78 @@
<tbody>
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm><primary>isn_weak</primary></indexterm>
<function>isn_weak</function> ( <type>boolean</type> )
<returnvalue>boolean</returnvalue>
<indexterm><primary>make_valid</primary></indexterm>
<function>make_valid</function> ( <type>isn</type> )
<returnvalue>isn</returnvalue>
</para>
<para>
Sets the weak input mode, and returns new setting.
Clears the invalid-check-digit flag of the value.
</para></entry>
</row>
<row>
<entry role="func_table_entry"><para role="func_signature">
<function>isn_weak</function> ()
<indexterm><primary>is_valid</primary></indexterm>
<function>is_valid</function> ( <type>isn</type> )
<returnvalue>boolean</returnvalue>
</para>
<para>
Returns the current status of the weak mode.
Checks for the presence of the invalid-check-digit flag.
</para></entry>
</row>
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm><primary>make_valid</primary></indexterm>
<function>make_valid</function> ( <type>isn</type> )
<returnvalue>isn</returnvalue>
<indexterm><primary>isn_weak</primary></indexterm>
<function>isn_weak</function> ( <type>boolean</type> )
<returnvalue>boolean</returnvalue>
</para>
<para>
Validates an invalid number (clears the invalid flag).
Sets the weak input mode, and returns the new setting.
This function is retained for backward compatibility.
The recommended way to set weak mode is via
the <varname>isn.weak</varname> configuration parameter.
</para></entry>
</row>
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm><primary>is_valid</primary></indexterm>
<function>is_valid</function> ( <type>isn</type> )
<function>isn_weak</function> ()
<returnvalue>boolean</returnvalue>
</para>
<para>
Checks for the presence of the invalid flag.
Returns the current status of the weak mode.
This function is retained for backward compatibility.
The recommended way to check weak mode is via
the <varname>isn.weak</varname> configuration parameter.
</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<para>
<firstterm>Weak</firstterm> mode is used to be able to insert invalid data
into a table. Invalid means the check digit is wrong, not that there are
missing numbers.
</para>
<sect2 id="isn-configuration-parameters">
<title>Configuration Parameters</title>
<variablelist>
<varlistentry id="isn-configuration-parameters-weak">
<term>
<varname>isn.weak</varname> (<type>boolean</type>)
<indexterm>
<primary><varname>isn.weak</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
<varname>isn.weak</varname> enables the weak input mode, which allows
ISN input values to be accepted even when their check digit is wrong.
The default is <literal>false</literal>, which rejects invalid check
digits.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Why would you want to use the weak mode? Well, it could be that
@ -325,9 +348,9 @@
</para>
<para>
You can also force the insertion of invalid numbers even when not in the
weak mode, by appending the <literal>!</literal> character at the end of the
number.
You can also force the insertion of marked-as-invalid numbers even when not
in the weak mode, by appending the <literal>!</literal> character at the
end of the number.
</para>
<para>
@ -366,11 +389,11 @@ SELECT issn('3251231?');
SELECT ismn('979047213542?');
--Using the weak mode:
SELECT isn_weak(true);
SET isn.weak TO true;
INSERT INTO test VALUES('978-0-11-000533-4');
INSERT INTO test VALUES('9780141219307');
INSERT INTO test VALUES('2-205-00876-X');
SELECT isn_weak(false);
SET isn.weak TO false;
SELECT id FROM test WHERE NOT is_valid(id);
UPDATE test SET id = make_valid(id) WHERE id = '2-205-00876-X!';

Loading…
Cancel
Save