GTIN14 support for contrib/isn
Hello hackers,
For a project of ours we need GTIN14 data type support. The isn
extension already supports EAN13, and a '0' prefixed EAN13 is a valid
GTIN14. The leftmost "new" 14th digit is a packaging level indicator
which we need (= using EAN13 and faking a leading 0 in output doesn't
cut it).
Looking at the code I saw every format that isn-extension supports is
stored as an EAN13. Theoretically that can be changed to be GTIN14, but
that would mean quite a lot of rewrite I feared, so I chose to code only
GTIN14 I/O separetely to not interfere with any existing conversion
magic. This yields an easier to understand patch and doesn't touch
existing functionality. However it introduces redundancy to a certain
extent.
Find my patch attached. Please let me know if there are things that need
changes, I'll do my best to get GTIN support into postgresql.
thanks in advance
mike
Attachments:
gtin14.patchtext/plain; charset=UTF-8; name=gtin14.patch; x-mac-creator=0; x-mac-type=0Download
diff --git a/expected/isn.out b/expected/isn.out
index 18fe37a..b313641 100644
--- a/expected/isn.out
+++ b/expected/isn.out
@@ -18,6 +18,8 @@ INFO: operator family "isn_ops" of access method btree is missing cross-type op
INFO: operator family "isn_ops" of access method btree is missing cross-type operator(s)
INFO: operator family "isn_ops" of access method btree is missing cross-type operator(s)
INFO: operator family "isn_ops" of access method btree is missing cross-type operator(s)
+INFO: operator family "isn_ops" of access method btree is missing cross-type operator(s)
+INFO: operator family "isn_ops" of access method hash is missing cross-type operator(s)
INFO: operator family "isn_ops" of access method hash is missing cross-type operator(s)
INFO: operator family "isn_ops" of access method hash is missing cross-type operator(s)
INFO: operator family "isn_ops" of access method hash is missing cross-type operator(s)
@@ -29,6 +31,7 @@ INFO: operator family "isn_ops" of access method hash is missing cross-type ope
amname | opcname
--------+------------
btree | ean13_ops
+ btree | gtin14_ops
btree | isbn13_ops
btree | isbn_ops
btree | ismn13_ops
@@ -37,6 +40,7 @@ INFO: operator family "isn_ops" of access method hash is missing cross-type ope
btree | issn_ops
btree | upc_ops
hash | ean13_ops
+ hash | gtin14_ops
hash | isbn13_ops
hash | isbn_ops
hash | ismn13_ops
@@ -44,11 +48,20 @@ INFO: operator family "isn_ops" of access method hash is missing cross-type ope
hash | issn13_ops
hash | issn_ops
hash | upc_ops
-(16 rows)
+(18 rows)
--
-- test valid conversions
--
+SELECT '1234567890128'::GTIN14, -- EAN is a GTIN14
+ '123456789012?'::GTIN14, -- compute check digit for me
+ '11234567890125'::GTIN14,
+ '01234567890128'::GTIN14;
+ gtin14 | gtin14 | gtin14 | gtin14
+-----------------+-----------------+-----------------+-----------------
+ 0123456789012-8 | 0123456789012-8 | 1123456789012-5 | 0123456789012-8
+(1 row)
+
SELECT '9780123456786'::EAN13, -- old book
'9790123456785'::EAN13, -- music
'9791234567896'::EAN13, -- new book
@@ -249,6 +262,67 @@ SELECT 9780123456786::ISBN;
ERROR: cannot cast type bigint to isbn
LINE 1: SELECT 9780123456786::ISBN;
^
+SELECT '91234567890125'::GTIN14; -- invalid indicator
+ERROR: Indicator digit out of range for GTIN14 number: "91234567890125"
+LINE 1: SELECT '91234567890125'::GTIN14;
+ ^
+SELECT '123456789012'::GTIN14; -- too short
+ERROR: invalid input syntax for GTIN14 number: "123456789012"
+LINE 1: SELECT '123456789012'::GTIN14;
+ ^
+SELECT '1234567890127'::GTIN14; -- wrong checkdigit
+ERROR: invalid check digit for GTIN14 number: "1234567890127", should be 8
+LINE 1: SELECT '1234567890127'::GTIN14;
+ ^
+--
+-- test validity helpers
+--
+SELECT make_valid('1234567890120!'::GTIN14); -- EAN-13
+ make_valid
+-----------------
+ 0123456789012-8
+(1 row)
+
+SELECT make_valid('11234567890120!'::GTIN14); -- GTIN-14
+ make_valid
+-----------------
+ 1123456789012-5
+(1 row)
+
+SELECT is_valid(make_valid('1234567890120!'::GTIN14)); -- EAN-13
+ is_valid
+----------
+ t
+(1 row)
+
+SELECT is_valid(make_valid('11234567890120!'::GTIN14)); -- GTIN-14
+ is_valid
+----------
+ t
+(1 row)
+
+CREATE TABLE gtin_valid (gtin GTIN14 NOT NULL);
+INSERT INTO gtin_valid VALUES
+-- all invalid because of ! marking
+ ('1234567890120!'), -- invalid EAN-13
+ ('1234567890128!'), -- valid EAN-13
+ ('11234567890120!'), -- invalid GTIN-14
+ ('11234567890125!'), -- valid GTIN-14
+-- valid
+ ('1234567890128'::GTIN14), -- valid EAN-13
+ ('11234567890125'::GTIN14); -- valid GTIN-14
+SELECT gtin, is_valid(gtin) FROM gtin_valid;
+ gtin | is_valid
+------------------+----------
+ 0123456789012-8! | f
+ 0123456789012-8! | f
+ 1123456789012-5! | f
+ 1123456789012-5! | f
+ 0123456789012-8 | t
+ 1123456789012-5 | t
+(6 rows)
+
+DROP TABLE gtin_valid;
--
-- test some comparisons, must yield true
--
diff --git a/isn--1.1.sql b/isn--1.1.sql
index 5206961..fd3f157 100644
--- a/isn--1.1.sql
+++ b/isn--1.1.sql
@@ -15,6 +15,26 @@
-- Input and output functions and data types:
--
---------------------------------------------------
+CREATE FUNCTION gtin14_in(cstring)
+ RETURNS gtin14
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+CREATE FUNCTION gtin14_out(gtin14)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+CREATE TYPE gtin14 (
+ INPUT = gtin14_in,
+ OUTPUT = gtin14_out,
+ LIKE = pg_catalog.int8
+);
+COMMENT ON TYPE gtin14
+ IS 'Global Trade Item Number (GTIN-14)';
+
CREATE FUNCTION ean13_in(cstring)
RETURNS ean13
AS 'MODULE_PATHNAME'
@@ -181,6 +201,44 @@ COMMENT ON TYPE upc
-- Operator functions:
--
---------------------------------------------------
+-- GTIN-14:
+CREATE FUNCTION isnlt(gtin14, gtin14)
+ RETURNS boolean
+ AS 'int8lt'
+ LANGUAGE 'internal'
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+CREATE FUNCTION isnle(gtin14, gtin14)
+ RETURNS boolean
+ AS 'int8le'
+ LANGUAGE 'internal'
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+CREATE FUNCTION isneq(gtin14, gtin14)
+ RETURNS boolean
+ AS 'int8eq'
+ LANGUAGE 'internal'
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+CREATE FUNCTION isnge(gtin14, gtin14)
+ RETURNS boolean
+ AS 'int8ge'
+ LANGUAGE 'internal'
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+CREATE FUNCTION isngt(gtin14, gtin14)
+ RETURNS boolean
+ AS 'int8gt'
+ LANGUAGE 'internal'
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+CREATE FUNCTION isnne(gtin14, gtin14)
+ RETURNS boolean
+ AS 'int8ne'
+ LANGUAGE 'internal'
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+
-- EAN13:
CREATE FUNCTION isnlt(ean13, ean13)
RETURNS boolean
@@ -1236,6 +1294,61 @@ CREATE FUNCTION isnne(upc, ean13)
-- Now the operators:
--
+--
+-- GTIN-14 operators:
+--
+---------------------------------------------------
+CREATE OPERATOR < (
+ PROCEDURE = isnlt,
+ LEFTARG = gtin14,
+ RIGHTARG = gtin14,
+ COMMUTATOR = >,
+ NEGATOR = >=,
+ RESTRICT = scalarltsel,
+ JOIN = scalarltjoinsel);
+CREATE OPERATOR <= (
+ PROCEDURE = isnle,
+ LEFTARG = gtin14,
+ RIGHTARG = gtin14,
+ COMMUTATOR = >=,
+ NEGATOR = >,
+ RESTRICT = scalarltsel,
+ JOIN = scalarltjoinsel);
+CREATE OPERATOR = (
+ PROCEDURE = isneq,
+ LEFTARG = gtin14,
+ RIGHTARG = gtin14,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel,
+ MERGES,
+ HASHES);
+CREATE OPERATOR >= (
+ PROCEDURE = isnge,
+ LEFTARG = gtin14,
+ RIGHTARG = gtin14,
+ COMMUTATOR = <=,
+ NEGATOR = <,
+ RESTRICT = scalargtsel,
+ JOIN = scalargtjoinsel );
+CREATE OPERATOR > (
+ PROCEDURE = isngt,
+ LEFTARG = gtin14,
+ RIGHTARG = gtin14,
+ COMMUTATOR = <,
+ NEGATOR = <=,
+ RESTRICT = scalargtsel,
+ JOIN = scalargtjoinsel );
+CREATE OPERATOR <> (
+ PROCEDURE = isnne,
+ LEFTARG = gtin14,
+ RIGHTARG = gtin14,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel);
+
--
-- EAN13 operators:
--
@@ -2708,6 +2821,34 @@ CREATE OPERATOR FAMILY isn_ops USING hash;
-- Operator classes:
--
---------------------------------------------------
+-- GTIN-14:
+CREATE FUNCTION btgtin14cmp(gtin14, gtin14)
+ RETURNS int4
+ AS 'btint8cmp'
+ LANGUAGE 'internal'
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
+
+CREATE OPERATOR CLASS gtin14_ops DEFAULT
+ FOR TYPE gtin14 USING btree FAMILY isn_ops AS
+ OPERATOR 1 <,
+ OPERATOR 2 <=,
+ OPERATOR 3 =,
+ OPERATOR 4 >=,
+ OPERATOR 5 >,
+ FUNCTION 1 btgtin14cmp(gtin14, gtin14);
+
+CREATE FUNCTION hashgtin14(gtin14)
+ RETURNS int4
+ AS 'hashint8'
+ LANGUAGE 'internal' IMMUTABLE STRICT
+ PARALLEL SAFE;
+
+CREATE OPERATOR CLASS gtin14_ops DEFAULT
+ FOR TYPE gtin14 USING hash FAMILY isn_ops AS
+ OPERATOR 1 =,
+ FUNCTION 1 hashgtin14(gtin14);
+
-- EAN13:
CREATE FUNCTION btean13cmp(ean13, ean13)
RETURNS int4
@@ -3314,6 +3455,12 @@ CREATE CAST (issn13 AS issn) WITHOUT FUNCTION AS ASSIGNMENT;
--
-- Validation stuff for lose types:
--
+CREATE FUNCTION make_valid(gtin14)
+ RETURNS gtin14
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
CREATE FUNCTION make_valid(ean13)
RETURNS ean13
AS 'MODULE_PATHNAME'
@@ -3363,6 +3510,12 @@ CREATE FUNCTION make_valid(upc)
IMMUTABLE STRICT
PARALLEL SAFE;
+CREATE FUNCTION is_valid(gtin14)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C
+ IMMUTABLE STRICT
+ PARALLEL SAFE;
CREATE FUNCTION is_valid(ean13)
RETURNS boolean
AS 'MODULE_PATHNAME'
diff --git a/isn.c b/isn.c
index 0c2cac7..d7baa78 100644
--- a/isn.c
+++ b/isn.c
@@ -36,10 +36,10 @@ PG_MODULE_MAGIC;
enum isn_type
{
- INVALID, ANY, EAN13, ISBN, ISMN, ISSN, UPC
+ INVALID, ANY, EAN13, ISBN, ISMN, ISSN, UPC, GTIN14
};
-static const char *const isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC"};
+static const char *const isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC", "GTIN14"};
static bool g_weak = false;
@@ -325,7 +325,10 @@ checkdig(char *num, unsigned size)
}
num++;
}
- check = (check + 3 * check3) % 10;
+ if (pos % 2 == 0) /* for even length strings */
+ check = (check + 3 * check3) % 10;
+ else
+ check = (check3 + 3 * check) % 10;
if (check != 0)
check = 10 - check;
return check;
@@ -500,11 +503,9 @@ ean2UPC(char *isn)
}
/*
- * ean2* --- Converts a string of digits into an ean13 number.
- * Assumes the input string is a string with only digits
- * on it, and that it's within the range of ean13.
+ * str2ean --- Converts a string of digits into binary storage format.
*
- * Returns the ean13 value of the string.
+ * Returns the ean13 with valid-flag set to true.
*/
static ean13
str2ean(const char *num)
@@ -520,6 +521,71 @@ str2ean(const char *num)
return (ean << 1); /* also give room to a flag */
}
+/*
+ * gtin14_2string --- Try to convert GTINumber to a hyphenated string.
+ * Assumes there's enough space in result to hold
+ * the string (maximum MAXEAN13LEN+1 bytes)
+ * This doesn't verify for a valid check digit.
+ *
+ * If errorOK is false, ereport a useful error message if the string is bad.
+ * If errorOK is true, just return "false" for bad input.
+ */
+static bool
+gtin14_2string(ean13 ean, bool errorOK, char *result)
+{
+ enum isn_type type = INVALID;
+
+ char *aux;
+ unsigned digval;
+ unsigned search;
+ char valid = '\0'; /* was the number initially written with a
+ * valid check digit? */
+
+ if ((ean & 1) != 0)
+ valid = '!';
+ ean >>= 1;
+ /* verify it's in the EAN13 range */
+ if (ean > UINT64CONST(99999999999999))
+ goto eantoobig;
+
+ /* convert the number */
+ search = 0;
+ aux = result + MAXEAN13LEN;
+ *aux = '\0'; /* terminate string; aux points to last digit */
+ *--aux = valid; /* append '!' for numbers with invalid but
+ * corrected check digit */
+ do
+ {
+ digval = (unsigned) (ean % 10); /* get the decimal value */
+ ean /= 10; /* get next digit */
+ *--aux = (char) (digval + '0'); /* convert to ascii and store */
+ if (search == 0)
+ *--aux = '-'; /* the check digit is always there */
+ } while (ean && search++ < 14);
+ while (search++ < 14)
+ *--aux = '0'; /* fill the remaining GTIN14 with '0' */
+
+ search = hyphenate(result, result + 2, NULL, NULL);
+
+ return true;
+
+eantoobig:
+ if (!errorOK)
+ {
+ char eanbuf[64];
+
+ /*
+ * Format the number separately to keep the machine-dependent format
+ * code out of the translatable message text
+ */
+ snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for %s type",
+ eanbuf, isn_names[type])));
+ }
+ return false;
+}
/*
* ean2string --- Try to convert an ean13 number to a hyphenated string.
* Assumes there's enough space in result to hold
@@ -673,6 +739,162 @@ eantoobig:
return false;
}
+/*
+ * string2gtin14 --- try to parse a string into an gtin14.
+ *
+ * If errorOK is false, ereport a useful error message if the string is bad.
+ * If errorOK is true, just return "false" for bad input.
+ *
+ * if the input string ends with '!' it will always be treated as invalid
+ * (even if the check digit is valid)
+ */
+static bool
+string2gtin14(const char *str, bool errorOK, ean13 *result,
+ enum isn_type accept)
+{
+ bool digit,
+ last;
+ char buf[17] = " ";
+ char *aux1 = buf + 2; /* leave space for the first part, in case
+ * it's needed */
+ const char *aux2 = str;
+ enum isn_type type = INVALID;
+ unsigned check = 0,
+ rcheck = (unsigned) -1;
+ unsigned length = 0;
+ bool magic = false,
+ valid = true;
+
+ /* recognize and validate the number: */
+ while (*aux2 && length <= 14)
+ {
+ last = (*(aux2 + 1) == '!' || *(aux2 + 1) == '\0'); /* is the last character */
+ digit = (isdigit((unsigned char) *aux2) != 0); /* is current character
+ * a digit? */
+ if (*aux2 == '?' && last) /* automagically calculate check digit if
+ * it's '?' */
+ magic = digit = true;
+ if (*aux2 == '!' && *(aux2 + 1) == '\0')
+ {
+ /* the invalid check digit suffix was found, set it */
+ if (!magic)
+ valid = false;
+ magic = true;
+ }
+ else if (!digit)
+ {
+ goto eaninvalid;
+ }
+ else
+ {
+ *aux1++ = *aux2;
+ if (++length > 14)
+ goto eantoobig;
+ }
+ aux2++;
+ }
+ *aux1 = '\0'; /* terminate the string */
+
+ /* find the current check digit value */
+ if (length == 13)
+ {
+ /* is likely EAN13, prefix with 0 to make valid GTIN14 */
+ type = EAN13;
+ buf[1] = '0'; /* prefix 0 */
+ check = buf[14] - '0';
+ }
+ else if (length == 14)
+ {
+ /* is likely GTIN14 */
+ type = GTIN14;
+ check = buf[15] - '0';
+
+ if (buf[2] - '0' == 9) /* valid range of indicator digit is 0-8 */
+ goto indicatorinvalid;
+ }
+ else
+ goto eaninvalid;
+
+ if (type == INVALID)
+ goto eaninvalid;
+
+ /* compute check digit: */
+ for (aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);
+ rcheck = checkdig(aux1, 14);
+ /* validate check digit and convert to gtin14: */
+ switch (type)
+ {
+ case GTIN14:
+ case EAN13:
+ valid = (valid && (rcheck == check || magic));
+ break;
+ default:
+ break;
+ }
+ /* always fix the check digit: */
+ aux1[13] = rcheck + '0';
+ aux1[14] = '\0';
+
+ if (!valid && !magic)
+ goto eanbadcheck;
+
+ *result = str2ean(aux1);
+ *result |= valid ? 0 : 1;
+ return true;
+
+eanbadcheck:
+ if (g_weak)
+ { /* weak input mode is activated: */
+ /* set the "invalid-check-digit-on-input" flag */
+ *result = str2ean(aux1);
+ *result |= 1;
+ return true;
+ }
+
+ if (!errorOK)
+ {
+ if (rcheck == (unsigned) -1)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid %s number: \"%s\"",
+ isn_names[accept], str)));
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid check digit for %s number: \"%s\", should be %c",
+ isn_names[accept], str, (rcheck == 10) ? ('X') : (rcheck + '0'))));
+ }
+ }
+ return false;
+
+eaninvalid:
+ if (!errorOK)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for %s number: \"%s\"",
+ isn_names[accept], str)));
+ return false;
+
+indicatorinvalid:
+ if (!errorOK)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("Indicator digit out of range for %s number: \"%s\"",
+ isn_names[accept], str)));
+ return false;
+
+eantoobig:
+ if (!errorOK)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for %s type",
+ str, isn_names[accept])));
+ return false;
+}
+
/*
* string2ean --- try to parse a string into an ean13.
*
@@ -990,6 +1212,35 @@ ean13_in(PG_FUNCTION_ARGS)
PG_RETURN_EAN13(result);
}
+/* gtin14_out
+ */
+PG_FUNCTION_INFO_V1(gtin14_out);
+Datum
+gtin14_out(PG_FUNCTION_ARGS)
+{
+ ean13 val = PG_GETARG_EAN13(0);
+ char *result;
+ char buf[MAXEAN13LEN + 1];
+
+ (void) gtin14_2string(val, false, buf);
+
+ result = pstrdup(buf);
+ PG_RETURN_CSTRING(result);
+}
+
+/* gtin14_in
+ */
+PG_FUNCTION_INFO_V1(gtin14_in);
+Datum
+gtin14_in(PG_FUNCTION_ARGS)
+{
+ const char *str = PG_GETARG_CSTRING(0);
+ ean13 result;
+
+ (void) string2gtin14(str, false, &result, GTIN14);
+ PG_RETURN_EAN13(result);
+}
+
/* isbn_in
*/
PG_FUNCTION_INFO_V1(isbn_in);
diff --git a/sql/isn.sql b/sql/isn.sql
index 71577d5..ede461f 100644
--- a/sql/isn.sql
+++ b/sql/isn.sql
@@ -16,6 +16,11 @@ WHERE NOT amvalidate(oid);
--
-- test valid conversions
--
+SELECT '1234567890128'::GTIN14, -- EAN is a GTIN14
+ '123456789012?'::GTIN14, -- compute check digit for me
+ '11234567890125'::GTIN14,
+ '01234567890128'::GTIN14;
+
SELECT '9780123456786'::EAN13, -- old book
'9790123456785'::EAN13, -- music
'9791234567896'::EAN13, -- new book
@@ -100,6 +105,30 @@ SELECT 'postgresql...'::ISBN;
SELECT 9780123456786::EAN13;
SELECT 9780123456786::ISBN;
+SELECT '91234567890125'::GTIN14; -- invalid indicator
+SELECT '123456789012'::GTIN14; -- too short
+SELECT '1234567890127'::GTIN14; -- wrong checkdigit
+
+--
+-- test validity helpers
+--
+SELECT make_valid('1234567890120!'::GTIN14); -- EAN-13
+SELECT make_valid('11234567890120!'::GTIN14); -- GTIN-14
+SELECT is_valid(make_valid('1234567890120!'::GTIN14)); -- EAN-13
+SELECT is_valid(make_valid('11234567890120!'::GTIN14)); -- GTIN-14
+
+CREATE TABLE gtin_valid (gtin GTIN14 NOT NULL);
+INSERT INTO gtin_valid VALUES
+-- all invalid because of ! marking
+ ('1234567890120!'), -- invalid EAN-13
+ ('1234567890128!'), -- valid EAN-13
+ ('11234567890120!'), -- invalid GTIN-14
+ ('11234567890125!'), -- valid GTIN-14
+-- valid
+ ('1234567890128'::GTIN14), -- valid EAN-13
+ ('11234567890125'::GTIN14); -- valid GTIN-14
+SELECT gtin, is_valid(gtin) FROM gtin_valid;
+DROP TABLE gtin_valid;
--
-- test some comparisons, must yield true
--
Michael Kefeder <mike@multiwave.ch> writes:
For a project of ours we need GTIN14 data type support.
Hm, what is that and where would a reviewer find the specification for it?
Looking at the code I saw every format that isn-extension supports is
stored as an EAN13. Theoretically that can be changed to be GTIN14, but
that would mean quite a lot of rewrite I feared, so I chose to code only
GTIN14 I/O separetely to not interfere with any existing conversion
magic. This yields an easier to understand patch and doesn't touch
existing functionality. However it introduces redundancy to a certain
extent.
Yeah, you certainly don't get to change the on-disk format of the existing
types, unfortunately. Not sure what the least messy way of dealing with
that is. I guess we do want this to be part of contrib/isn rather than
an independent module, if there are sane datatype conversions with the
existing isn types.
Find my patch attached. Please let me know if there are things that need
changes, I'll do my best to get GTIN support into postgresql.
Well, two comments immediately:
* where's the documentation changes?
* simply editing the .sql file in-place is not acceptable; that breaks
the versioning conventions for extensions, and leaves users with no
easy upgrade path. What you need to do is create a version upgrade
script that adds the new objects. For examples look for other recent
patches that have added features to contrib modules, eg
Also, I'm afraid you've pretty much missed the deadline to get this
into PG v12; we've already got more timely-submitted patches than
we're likely to be able to finish reviewing. Please add it to the
first v13 commit fest,
https://commitfest.postgresql.org/23/
so that we don't forget about it when the time does come to look at it.
regards, tom lane
Am 15.03.19 um 17:27 schrieb Tom Lane:
Michael Kefeder <mike@multiwave.ch> writes:
For a project of ours we need GTIN14 data type support.
Hm, what is that and where would a reviewer find the specification for it?
specs are from GS1 here https://www.gs1.org/standards/id-keys/gtin
side-note EAN13 is actually called GTIN-13 now. Wikipedia has a quick
overview https://en.wikipedia.org/wiki/Global_Trade_Item_Number
Looking at the code I saw every format that isn-extension supports is
stored as an EAN13. Theoretically that can be changed to be GTIN14, but
that would mean quite a lot of rewrite I feared, so I chose to code only
GTIN14 I/O separetely to not interfere with any existing conversion
magic. This yields an easier to understand patch and doesn't touch
existing functionality. However it introduces redundancy to a certain
extent.Yeah, you certainly don't get to change the on-disk format of the existing
types, unfortunately. Not sure what the least messy way of dealing with
that is. I guess we do want this to be part of contrib/isn rather than
an independent module, if there are sane datatype conversions with the
existing isn types.
the on-disk format does not change (it would support even longer codes
it's just an integer where one bit is used for valid/invalid flag, did
not touch that at all). Putting GTIN14 in isn makes sense I find and is
back/forward compatible.
Find my patch attached. Please let me know if there are things that need
changes, I'll do my best to get GTIN support into postgresql.Well, two comments immediately:
* where's the documentation changes?
* simply editing the .sql file in-place is not acceptable; that breaks
the versioning conventions for extensions, and leaves users with no
easy upgrade path. What you need to do is create a version upgrade
script that adds the new objects. For examples look for other recent
patches that have added features to contrib modules, egAlso, I'm afraid you've pretty much missed the deadline to get this
into PG v12; we've already got more timely-submitted patches than
we're likely to be able to finish reviewing. Please add it to the
first v13 commit fest,https://commitfest.postgresql.org/23/
so that we don't forget about it when the time does come to look at it.
regards, tom lane
thanks for the feedback! will do mentioned documentation changes and
create a separate upgrade sql file. Making it into v13 is fine by me.
br
mike
čt 8. 6. 2023 v 17:20 odesílatel Michael Kefeder <mike@multiwave.ch> napsal:
Am 15.03.19 um 17:27 schrieb Tom Lane:
Michael Kefeder <mike@multiwave.ch> writes:
For a project of ours we need GTIN14 data type support.
Hm, what is that and where would a reviewer find the specification for it?
specs are from GS1 here https://www.gs1.org/standards/id-keys/gtin
side-note EAN13 is actually called GTIN-13 now. Wikipedia has a quick
overview https://en.wikipedia.org/wiki/Global_Trade_Item_NumberLooking at the code I saw every format that isn-extension supports is
stored as an EAN13. Theoretically that can be changed to be GTIN14, but
that would mean quite a lot of rewrite I feared, so I chose to code only
GTIN14 I/O separetely to not interfere with any existing conversion
magic. This yields an easier to understand patch and doesn't touch
existing functionality. However it introduces redundancy to a certain
extent.Yeah, you certainly don't get to change the on-disk format of the existing
types, unfortunately. Not sure what the least messy way of dealing with
that is. I guess we do want this to be part of contrib/isn rather than
an independent module, if there are sane datatype conversions with the
existing isn types.the on-disk format does not change (it would support even longer codes
it's just an integer where one bit is used for valid/invalid flag, did
not touch that at all). Putting GTIN14 in isn makes sense I find and is
back/forward compatible.Find my patch attached. Please let me know if there are things that need
changes, I'll do my best to get GTIN support into postgresql.Well, two comments immediately:
* where's the documentation changes?
* simply editing the .sql file in-place is not acceptable; that breaks
the versioning conventions for extensions, and leaves users with no
easy upgrade path. What you need to do is create a version upgrade
script that adds the new objects. For examples look for other recent
patches that have added features to contrib modules, egAlso, I'm afraid you've pretty much missed the deadline to get this
into PG v12; we've already got more timely-submitted patches than
we're likely to be able to finish reviewing. Please add it to the
first v13 commit fest,https://commitfest.postgresql.org/23/
so that we don't forget about it when the time does come to look at it.
regards, tom lane
thanks for the feedback! will do mentioned documentation changes and
create a separate upgrade sql file. Making it into v13 is fine by me.
Hello!
If I understand it well, this patch wasn't finished and submitted
after this discussion. If there is still interest, I can try to polish
the patch, rebase and submit. I'm interested in GTIN14 support.
Show quoted text
br
mike
------- Original Message -------
On Thursday, June 8th, 2023 at 5:23 PM, Josef Šimánek <josef.simanek@gmail.com> wrote:
čt 8. 6. 2023 v 17:20 odesílatel Michael Kefeder mike@multiwave.ch napsal:
Am 15.03.19 um 17:27 schrieb Tom Lane:
Michael Kefeder mike@multiwave.ch writes:
For a project of ours we need GTIN14 data type support.
Hm, what is that and where would a reviewer find the specification for it?
specs are from GS1 here https://www.gs1.org/standards/id-keys/gtin
side-note EAN13 is actually called GTIN-13 now. Wikipedia has a quick
overview https://en.wikipedia.org/wiki/Global_Trade_Item_NumberLooking at the code I saw every format that isn-extension supports is
stored as an EAN13. Theoretically that can be changed to be GTIN14, but
that would mean quite a lot of rewrite I feared, so I chose to code only
GTIN14 I/O separetely to not interfere with any existing conversion
magic. This yields an easier to understand patch and doesn't touch
existing functionality. However it introduces redundancy to a certain
extent.Yeah, you certainly don't get to change the on-disk format of the existing
types, unfortunately. Not sure what the least messy way of dealing with
that is. I guess we do want this to be part of contrib/isn rather than
an independent module, if there are sane datatype conversions with the
existing isn types.the on-disk format does not change (it would support even longer codes
it's just an integer where one bit is used for valid/invalid flag, did
not touch that at all). Putting GTIN14 in isn makes sense I find and is
back/forward compatible.Find my patch attached. Please let me know if there are things that need
changes, I'll do my best to get GTIN support into postgresql.Well, two comments immediately:
* where's the documentation changes?
* simply editing the .sql file in-place is not acceptable; that breaks
the versioning conventions for extensions, and leaves users with no
easy upgrade path. What you need to do is create a version upgrade
script that adds the new objects. For examples look for other recent
patches that have added features to contrib modules, egAlso, I'm afraid you've pretty much missed the deadline to get this
into PG v12; we've already got more timely-submitted patches than
we're likely to be able to finish reviewing. Please add it to the
first v13 commit fest,https://commitfest.postgresql.org/23/
so that we don't forget about it when the time does come to look at it.
regards, tom lane
thanks for the feedback! will do mentioned documentation changes and
create a separate upgrade sql file. Making it into v13 is fine by me.Hello!
If I understand it well, this patch wasn't finished and submitted
after this discussion. If there is still interest, I can try to polish
the patch, rebase and submit. I'm interested in GTIN14 support.
Hello Josef,
From my side you can finish the patch. Sorry that I didn't follow up on it, the company completely switched product line and then I forgot about it because we no longer needed it.
br
mike