diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c index 333f4bc..3b4c605 100644 --- a/src/backend/utils/adt/mac.c +++ b/src/backend/utils/adt/mac.c @@ -31,39 +31,60 @@ macaddr_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); macaddr *result; - int a, - b, - c, - d, - e, - f; - char junk[2]; - int count; - - /* %1s matches iff there is trailing non-whitespace garbage */ - - count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s", - &a, &b, &c, &d, &e, &f, junk); - if (count != 6) - count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s", - &a, &b, &c, &d, &e, &f, junk); - if (count != 6) - count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s", - &a, &b, &c, &d, &e, &f, junk); - if (count != 6) - count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s", - &a, &b, &c, &d, &e, &f, junk); - if (count != 6) - count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s", - &a, &b, &c, &d, &e, &f, junk); - if (count != 6) - count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s", - &a, &b, &c, &d, &e, &f, junk); + + int count; + char buf[6][13]; + char sep[2]; + int a, b, c, d, e, f; + char junk[2]; + char *pattern = 0; + + /* The first sscanf matches several different MAC representations. + * We select the pattern to use for further matching based on the + * length of the sequences of hex digits and the first separator character. + * + * The patterns that are recognized are: + * 01:02:03:04:05:06 + * 01-02-03-04-05-06 + * 010203:040506 + * 010203-040506 + * 0102.0304.0506 + * 010203040506 + * + * In patterns that have a separator between every octet, single digit + * octets are also recognized, for other patterns all sequences of + * digits have to be padded with zeroes. + * (If this is undesired behavior, we could check strlen(buf[0])==2 etc. + * there as well of course.) + */ + count = sscanf(str, " %12[0-9a-fA-F]%1[:-.]%6[0-9a-fA-F]%*1[:-.]%4[0-9a-fA-F]%*1[:-]%2[0-9a-fA-F]%*1[:-]%2[0-9a-fA-F]%*1[:-]%2[0-9a-fA-F]", buf[0], sep, buf[1], buf[2], buf[3], buf[4], buf[5]); + if( count == 7 && sep[0] == ':') { + pattern = "%2x:%2x:%2x:%2x:%2x:%2x%1s"; + } else if (count == 7 && sep[0] == '-') { + pattern = "%2x-%2x-%2x-%2x-%2x-%2x%1s"; + } else if (count == 3 && sep[0] == ':' && strlen(buf[0]) == 6 && strlen(buf[1]) == 6) { + pattern = "%2x%2x%2x:%2x%2x%2x%1s"; + } else if (count == 3 && sep[0] == '-' && strlen(buf[0]) == 6 && strlen(buf[1]) == 6) { + pattern = "%2x%2x%2x-%2x%2x%2x%1s"; + } else if (count == 4 && sep[0] == '.' && strlen(buf[0]) == 4 && strlen(buf[1]) == 4 && strlen(buf[2]) == 4) { + pattern = "%2x%2x.%2x%2x.%2x%2x%1s"; + } else if (count == 1 && strlen(buf[0]) == 12) { + pattern = "%2x%2x%2x%2x%2x%2x%1s"; + } + + /* We reuse the count variable to check for a valid syntax below even if we don't have a pattern. */ + count = 0; + if (pattern) { + /* %1s matches iff there is trailing non-whitespace garbage */ + count = sscanf(str, pattern, &a, &b, &c, &d, &e, &f, junk); + } + if (count != 6) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type macaddr: \"%s\"", str))); + /* Make sure all octets are valid, even though we probably can't match invalid octets using our patterns. */ if ((a < 0) || (a > 255) || (b < 0) || (b > 255) || (c < 0) || (c > 255) || (d < 0) || (d > 255) || (e < 0) || (e > 255) || (f < 0) || (f > 255)) diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out index 0b2a96d..2465279 100644 --- a/src/test/regress/expected/macaddr.out +++ b/src/test/regress/expected/macaddr.out @@ -3,7 +3,7 @@ -- CREATE TABLE macaddr_data (a int, b macaddr); INSERT INTO macaddr_data VALUES (1, '08:00:2b:01:02:03'); -INSERT INTO macaddr_data VALUES (2, '08-00-2b-01-02-03'); +INSERT INTO macaddr_data VALUES (2, '8-0-2b-1-02-3'); INSERT INTO macaddr_data VALUES (3, '08002b:010203'); INSERT INTO macaddr_data VALUES (4, '08002b-010203'); INSERT INTO macaddr_data VALUES (5, '0800.2b01.0203'); @@ -16,11 +16,19 @@ INSERT INTO macaddr_data VALUES (8, 'not even close'); -- invalid ERROR: invalid input syntax for type macaddr: "not even close" LINE 1: INSERT INTO macaddr_data VALUES (8, 'not even close'); ^ -INSERT INTO macaddr_data VALUES (10, '08:00:2b:01:02:04'); -INSERT INTO macaddr_data VALUES (11, '08:00:2b:01:02:02'); -INSERT INTO macaddr_data VALUES (12, '08:00:2a:01:02:03'); -INSERT INTO macaddr_data VALUES (13, '08:00:2c:01:02:03'); -INSERT INTO macaddr_data VALUES (14, '08:00:2a:01:02:04'); +INSERT INTO macaddr_data VALUES (9, '08002b-01203'); -- invalid +ERROR: invalid input syntax for type macaddr: "08002b-01203" +LINE 1: INSERT INTO macaddr_data VALUES (9, '08002b-01203'); + ^ +INSERT INTO macaddr_data VALUES (10, '08002b-1203'); -- invalid +ERROR: invalid input syntax for type macaddr: "08002b-1203" +LINE 1: INSERT INTO macaddr_data VALUES (10, '08002b-1203'); + ^ +INSERT INTO macaddr_data VALUES (11, '08:00:2b:01:02:04'); +INSERT INTO macaddr_data VALUES (12, '08:00:2b:01:02:02'); +INSERT INTO macaddr_data VALUES (13, '08:00:2a:01:02:03'); +INSERT INTO macaddr_data VALUES (14, '08:00:2c:01:02:03'); +INSERT INTO macaddr_data VALUES (15, '08:00:2a:01:02:04'); SELECT * FROM macaddr_data; a | b ----+------------------- @@ -30,11 +38,11 @@ SELECT * FROM macaddr_data; 4 | 08:00:2b:01:02:03 5 | 08:00:2b:01:02:03 6 | 08:00:2b:01:02:03 - 10 | 08:00:2b:01:02:04 - 11 | 08:00:2b:01:02:02 - 12 | 08:00:2a:01:02:03 - 13 | 08:00:2c:01:02:03 - 14 | 08:00:2a:01:02:04 + 11 | 08:00:2b:01:02:04 + 12 | 08:00:2b:01:02:02 + 13 | 08:00:2a:01:02:03 + 14 | 08:00:2c:01:02:03 + 15 | 08:00:2a:01:02:04 (11 rows) CREATE INDEX macaddr_data_btree ON macaddr_data USING btree (b); @@ -42,17 +50,17 @@ CREATE INDEX macaddr_data_hash ON macaddr_data USING hash (b); SELECT a, b, trunc(b) FROM macaddr_data ORDER BY 2, 1; a | b | trunc ----+-------------------+------------------- - 12 | 08:00:2a:01:02:03 | 08:00:2a:00:00:00 - 14 | 08:00:2a:01:02:04 | 08:00:2a:00:00:00 - 11 | 08:00:2b:01:02:02 | 08:00:2b:00:00:00 + 13 | 08:00:2a:01:02:03 | 08:00:2a:00:00:00 + 15 | 08:00:2a:01:02:04 | 08:00:2a:00:00:00 + 12 | 08:00:2b:01:02:02 | 08:00:2b:00:00:00 1 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00 2 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00 3 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00 4 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00 5 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00 6 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00 - 10 | 08:00:2b:01:02:04 | 08:00:2b:00:00:00 - 13 | 08:00:2c:01:02:03 | 08:00:2c:00:00:00 + 11 | 08:00:2b:01:02:04 | 08:00:2b:00:00:00 + 14 | 08:00:2c:01:02:03 | 08:00:2c:00:00:00 (11 rows) SELECT b < '08:00:2b:01:02:04' FROM macaddr_data WHERE a = 1; -- true diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql index ce8d920..8c13f06 100644 --- a/src/test/regress/sql/macaddr.sql +++ b/src/test/regress/sql/macaddr.sql @@ -5,19 +5,21 @@ CREATE TABLE macaddr_data (a int, b macaddr); INSERT INTO macaddr_data VALUES (1, '08:00:2b:01:02:03'); -INSERT INTO macaddr_data VALUES (2, '08-00-2b-01-02-03'); +INSERT INTO macaddr_data VALUES (2, '8-0-2b-1-02-3'); INSERT INTO macaddr_data VALUES (3, '08002b:010203'); INSERT INTO macaddr_data VALUES (4, '08002b-010203'); INSERT INTO macaddr_data VALUES (5, '0800.2b01.0203'); INSERT INTO macaddr_data VALUES (6, '08002b010203'); INSERT INTO macaddr_data VALUES (7, '0800:2b01:0203'); -- invalid INSERT INTO macaddr_data VALUES (8, 'not even close'); -- invalid - -INSERT INTO macaddr_data VALUES (10, '08:00:2b:01:02:04'); -INSERT INTO macaddr_data VALUES (11, '08:00:2b:01:02:02'); -INSERT INTO macaddr_data VALUES (12, '08:00:2a:01:02:03'); -INSERT INTO macaddr_data VALUES (13, '08:00:2c:01:02:03'); -INSERT INTO macaddr_data VALUES (14, '08:00:2a:01:02:04'); +INSERT INTO macaddr_data VALUES (9, '08002b-01203'); -- invalid +INSERT INTO macaddr_data VALUES (10, '08002b-1203'); -- invalid + +INSERT INTO macaddr_data VALUES (11, '08:00:2b:01:02:04'); +INSERT INTO macaddr_data VALUES (12, '08:00:2b:01:02:02'); +INSERT INTO macaddr_data VALUES (13, '08:00:2a:01:02:03'); +INSERT INTO macaddr_data VALUES (14, '08:00:2c:01:02:03'); +INSERT INTO macaddr_data VALUES (15, '08:00:2a:01:02:04'); SELECT * FROM macaddr_data;