Convert a few more datatype input functions to report errors softly.

Convert assorted internal-ish datatypes, namely aclitemin,
int2vectorin, oidin, oidvectorin, pg_lsn_in, pg_snapshot_in,
and tidin to the new style.

(Some others you might expect to find in this group, such as
cidin and xidin, need no changes because they never throw
errors at all.  That seems a little cheesy ... but it is not in
the charter of this patch series to add new error conditions.)

Amul Sul, minor mods by me

Discussion: https://postgr.es/m/CAAJ_b97KeDWUdpTKGOaFYPv0OicjOu6EW+QYWj-Ywrgj_aEy1g@mail.gmail.com
This commit is contained in:
Tom Lane 2022-12-14 17:50:24 -05:00
parent 332741e739
commit 47f3f97fcd
18 changed files with 323 additions and 41 deletions

View File

@ -81,11 +81,11 @@ static List *cached_roles[] = {NIL, NIL, NIL};
static uint32 cached_db_hash;
static const char *getid(const char *s, char *n);
static const char *getid(const char *s, char *n, Node *escontext);
static void putid(char *p, const char *s);
static Acl *allocacl(int n);
static void check_acl(const Acl *acl);
static const char *aclparse(const char *s, AclItem *aip);
static const char *aclparse(const char *s, AclItem *aip, Node *escontext);
static bool aclitem_match(const AclItem *a1, const AclItem *a2);
static int aclitemComparator(const void *arg1, const void *arg2);
static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
@ -135,9 +135,12 @@ static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue
* in 's', after any quotes. Also:
* - loads the identifier into 'n'. (If no identifier is found, 'n'
* contains an empty string.) 'n' must be NAMEDATALEN bytes.
*
* Errors are reported via ereport, unless escontext is an ErrorSaveData node,
* in which case we log the error there and return NULL.
*/
static const char *
getid(const char *s, char *n)
getid(const char *s, char *n, Node *escontext)
{
int len = 0;
bool in_quotes = false;
@ -169,7 +172,7 @@ getid(const char *s, char *n)
/* Add the character to the string */
if (len >= NAMEDATALEN - 1)
ereport(ERROR,
ereturn(escontext, NULL,
(errcode(ERRCODE_NAME_TOO_LONG),
errmsg("identifier too long"),
errdetail("Identifier must be less than %d characters.",
@ -236,9 +239,12 @@ putid(char *p, const char *s)
* specification. Also:
* - loads the structure pointed to by 'aip' with the appropriate
* UID/GID, id type identifier and mode type values.
*
* Errors are reported via ereport, unless escontext is an ErrorSaveData node,
* in which case we log the error there and return NULL.
*/
static const char *
aclparse(const char *s, AclItem *aip)
aclparse(const char *s, AclItem *aip, Node *escontext)
{
AclMode privs,
goption,
@ -248,25 +254,30 @@ aclparse(const char *s, AclItem *aip)
Assert(s && aip);
s = getid(s, name);
s = getid(s, name, escontext);
if (s == NULL)
return NULL;
if (*s != '=')
{
/* we just read a keyword, not a name */
if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
ereport(ERROR,
ereturn(escontext, NULL,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("unrecognized key word: \"%s\"", name),
errhint("ACL key word must be \"group\" or \"user\".")));
s = getid(s, name); /* move s to the name beyond the keyword */
/* move s to the name beyond the keyword */
s = getid(s, name, escontext);
if (s == NULL)
return NULL;
if (name[0] == '\0')
ereport(ERROR,
ereturn(escontext, NULL,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("missing name"),
errhint("A name must follow the \"group\" or \"user\" key word.")));
}
if (*s != '=')
ereport(ERROR,
ereturn(escontext, NULL,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("missing \"=\" sign")));
@ -328,7 +339,7 @@ aclparse(const char *s, AclItem *aip)
read = 0;
break;
default:
ereport(ERROR,
ereturn(escontext, NULL,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid mode character: must be one of \"%s\"",
ACL_ALL_RIGHTS_STR)));
@ -340,7 +351,13 @@ aclparse(const char *s, AclItem *aip)
if (name[0] == '\0')
aip->ai_grantee = ACL_ID_PUBLIC;
else
aip->ai_grantee = get_role_oid(name, false);
{
aip->ai_grantee = get_role_oid(name, true);
if (!OidIsValid(aip->ai_grantee))
ereturn(escontext, NULL,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", name)));
}
/*
* XXX Allow a degree of backward compatibility by defaulting the grantor
@ -348,12 +365,18 @@ aclparse(const char *s, AclItem *aip)
*/
if (*s == '/')
{
s = getid(s + 1, name2);
s = getid(s + 1, name2, escontext);
if (s == NULL)
return NULL;
if (name2[0] == '\0')
ereport(ERROR,
ereturn(escontext, NULL,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("a name must follow the \"/\" sign")));
aip->ai_grantor = get_role_oid(name2, false);
aip->ai_grantor = get_role_oid(name2, true);
if (!OidIsValid(aip->ai_grantor))
ereturn(escontext, NULL,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", name2)));
}
else
{
@ -569,14 +592,19 @@ Datum
aclitemin(PG_FUNCTION_ARGS)
{
const char *s = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
AclItem *aip;
aip = (AclItem *) palloc(sizeof(AclItem));
s = aclparse(s, aip);
s = aclparse(s, aip, escontext);
if (s == NULL)
PG_RETURN_NULL();
while (isspace((unsigned char) *s))
++s;
if (*s)
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("extra garbage at the end of the ACL specification")));

View File

@ -141,6 +141,7 @@ Datum
int2vectorin(PG_FUNCTION_ARGS)
{
char *intString = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
int2vector *result;
int n;
@ -160,19 +161,19 @@ int2vectorin(PG_FUNCTION_ARGS)
l = strtol(intString, &endp, 10);
if (intString == endp)
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"smallint", intString)));
if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s", intString,
"smallint")));
if (*endp && *endp != ' ')
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"integer", intString)));
@ -183,7 +184,7 @@ int2vectorin(PG_FUNCTION_ARGS)
while (*intString && isspace((unsigned char) *intString))
intString++;
if (*intString)
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("int2vector has too many elements")));

View File

@ -19,6 +19,7 @@
#include "catalog/pg_type.h"
#include "libpq/pqformat.h"
#include "nodes/miscnodes.h"
#include "nodes/value.h"
#include "utils/array.h"
#include "utils/builtins.h"
@ -31,15 +32,26 @@
* USER I/O ROUTINES *
*****************************************************************************/
/*
* Parse a single OID and return its value.
*
* If endloc isn't NULL, store a pointer to the rest of the string there,
* so that caller can parse the rest. Otherwise, it's an error if anything
* but whitespace follows.
*
* If escontext points to an ErrorSaveContext node, that is filled instead
* of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
* to detect errors.
*/
static Oid
oidin_subr(const char *s, char **endloc)
oidin_subr(const char *s, char **endloc, Node *escontext)
{
unsigned long cvt;
char *endptr;
Oid result;
if (*s == '\0')
ereport(ERROR,
ereturn(escontext, InvalidOid,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"oid", s)));
@ -53,19 +65,19 @@ oidin_subr(const char *s, char **endloc)
* handled by the second "if" consistent across platforms.
*/
if (errno && errno != ERANGE && errno != EINVAL)
ereport(ERROR,
ereturn(escontext, InvalidOid,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"oid", s)));
if (endptr == s && *s != '\0')
ereport(ERROR,
ereturn(escontext, InvalidOid,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"oid", s)));
if (errno == ERANGE)
ereport(ERROR,
ereturn(escontext, InvalidOid,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
s, "oid")));
@ -81,7 +93,7 @@ oidin_subr(const char *s, char **endloc)
while (*endptr && isspace((unsigned char) *endptr))
endptr++;
if (*endptr)
ereport(ERROR,
ereturn(escontext, InvalidOid,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"oid", s)));
@ -104,7 +116,7 @@ oidin_subr(const char *s, char **endloc)
#if OID_MAX != ULONG_MAX
if (cvt != (unsigned long) result &&
cvt != (unsigned long) ((int) result))
ereport(ERROR,
ereturn(escontext, InvalidOid,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
s, "oid")));
@ -119,7 +131,7 @@ oidin(PG_FUNCTION_ARGS)
char *s = PG_GETARG_CSTRING(0);
Oid result;
result = oidin_subr(s, NULL);
result = oidin_subr(s, NULL, fcinfo->context);
PG_RETURN_OID(result);
}
@ -194,6 +206,7 @@ Datum
oidvectorin(PG_FUNCTION_ARGS)
{
char *oidString = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
oidvector *result;
int n;
@ -205,12 +218,14 @@ oidvectorin(PG_FUNCTION_ARGS)
oidString++;
if (*oidString == '\0')
break;
result->values[n] = oidin_subr(oidString, &oidString);
result->values[n] = oidin_subr(oidString, &oidString, escontext);
if (SOFT_ERROR_OCCURRED(escontext))
PG_RETURN_NULL();
}
while (*oidString && isspace((unsigned char) *oidString))
oidString++;
if (*oidString)
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("oidvector has too many elements")));
@ -324,7 +339,7 @@ oidparse(Node *node)
* constants by the lexer. Accept these if they are valid OID
* strings.
*/
return oidin_subr(castNode(Float, node)->fval, NULL);
return oidin_subr(castNode(Float, node)->fval, NULL, NULL);
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
}

View File

@ -69,7 +69,7 @@ pg_lsn_in(PG_FUNCTION_ARGS)
result = pg_lsn_in_internal(str, &have_error);
if (have_error)
ereport(ERROR,
ereturn(fcinfo->context, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"pg_lsn", str)));

View File

@ -57,6 +57,7 @@ Datum
tidin(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
char *p,
*coord[NTIDARGS];
int i;
@ -71,7 +72,7 @@ tidin(PG_FUNCTION_ARGS)
coord[i++] = p + 1;
if (i < NTIDARGS)
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"tid", str)));
@ -79,7 +80,7 @@ tidin(PG_FUNCTION_ARGS)
errno = 0;
cvt = strtoul(coord[0], &badp, 10);
if (errno || *badp != DELIM)
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"tid", str)));
@ -93,7 +94,7 @@ tidin(PG_FUNCTION_ARGS)
#if SIZEOF_LONG > 4
if (cvt != (unsigned long) blockNumber &&
cvt != (unsigned long) ((int32) blockNumber))
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"tid", str)));
@ -102,7 +103,7 @@ tidin(PG_FUNCTION_ARGS)
cvt = strtoul(coord[1], &badp, 10);
if (errno || *badp != RDELIM ||
cvt > USHRT_MAX)
ereport(ERROR,
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"tid", str)));

View File

@ -285,7 +285,7 @@ buf_finalize(StringInfo buf)
* parse snapshot from cstring
*/
static pg_snapshot *
parse_snapshot(const char *str)
parse_snapshot(const char *str, Node *escontext)
{
FullTransactionId xmin;
FullTransactionId xmax;
@ -341,11 +341,10 @@ parse_snapshot(const char *str)
return buf_finalize(buf);
bad_format:
ereport(ERROR,
ereturn(escontext, NULL,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"pg_snapshot", str_start)));
return NULL; /* keep compiler quiet */
}
/*
@ -447,7 +446,7 @@ pg_snapshot_in(PG_FUNCTION_ARGS)
char *str = PG_GETARG_CSTRING(0);
pg_snapshot *snap;
snap = parse_snapshot(str);
snap = parse_snapshot(str, fcinfo->context);
PG_RETURN_POINTER(snap);
}

View File

@ -70,6 +70,25 @@ SELECT pg_input_error_message('50000', 'int2');
value "50000" is out of range for type smallint
(1 row)
-- While we're here, check int2vector as well
SELECT pg_input_is_valid(' 1 3 5 ', 'int2vector');
pg_input_is_valid
-------------------
t
(1 row)
SELECT pg_input_error_message('1 asdf', 'int2vector');
pg_input_error_message
------------------------------------------------
invalid input syntax for type smallint: "asdf"
(1 row)
SELECT pg_input_error_message('50000', 'int2vector');
pg_input_error_message
-------------------------------------------------
value "50000" is out of range for type smallint
(1 row)
SELECT * FROM INT2_TBL AS f(a, b);
ERROR: table "f" has 1 columns available but 2 columns specified
SELECT * FROM (TABLE int2_tbl) AS s (a, b);

View File

@ -65,6 +65,68 @@ SELECT * FROM OID_TBL;
15
(8 rows)
-- Also try it with non-error-throwing API
SELECT pg_input_is_valid('1234', 'oid');
pg_input_is_valid
-------------------
t
(1 row)
SELECT pg_input_is_valid('01XYZ', 'oid');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('01XYZ', 'oid');
pg_input_error_message
--------------------------------------------
invalid input syntax for type oid: "01XYZ"
(1 row)
SELECT pg_input_is_valid('9999999999', 'oid');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('9999999999', 'oid');
pg_input_error_message
-------------------------------------------------
value "9999999999" is out of range for type oid
(1 row)
-- While we're here, check oidvector as well
SELECT pg_input_is_valid(' 1 2 4 ', 'oidvector');
pg_input_is_valid
-------------------
t
(1 row)
SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('01 01XYZ', 'oidvector');
pg_input_error_message
------------------------------------------
invalid input syntax for type oid: "XYZ"
(1 row)
SELECT pg_input_is_valid('01 9999999999', 'oidvector');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('01 9999999999', 'oidvector');
pg_input_error_message
-------------------------------------------------
value "9999999999" is out of range for type oid
(1 row)
SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
f1
------

View File

@ -26,6 +26,19 @@ INSERT INTO PG_LSN_TBL VALUES ('/ABCD');
ERROR: invalid input syntax for type pg_lsn: "/ABCD"
LINE 1: INSERT INTO PG_LSN_TBL VALUES ('/ABCD');
^
-- Also try it with non-error-throwing API
SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
pg_input_error_message
-------------------------------------------------
invalid input syntax for type pg_lsn: "16AE7F7"
(1 row)
-- Min/Max aggregation
SELECT MIN(f1), MAX(f1) FROM PG_LSN_TBL;
min | max

View File

@ -2233,6 +2233,49 @@ SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
'SELECT, fake_privilege', FALSE); -- error
ERROR: unrecognized privilege type: "fake_privilege"
-- Test non-throwing aclitem I/O
SELECT pg_input_is_valid('regress_priv_user1=r/regress_priv_user2', 'aclitem');
pg_input_is_valid
-------------------
t
(1 row)
SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
pg_input_error_message
---------------------------------
a name must follow the "/" sign
(1 row)
SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
pg_input_error_message
--------------------------------------------
role "regress_no_such_user" does not exist
(1 row)
SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
pg_input_error_message
----------------------------------------------------------
invalid mode character: must be one of "arwdDxtXUCTcsAm"
(1 row)
--
-- Testing blanket default grants is very hazardous since it might change
-- the privileges attached to objects created by concurrent regression tests.

View File

@ -17,6 +17,31 @@ SELECT '(1,65536)'::tid; -- error
ERROR: invalid input syntax for type tid: "(1,65536)"
LINE 1: SELECT '(1,65536)'::tid;
^
-- Also try it with non-error-throwing API
SELECT pg_input_is_valid('(0)', 'tid');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('(0)', 'tid');
pg_input_error_message
------------------------------------------
invalid input syntax for type tid: "(0)"
(1 row)
SELECT pg_input_is_valid('(0,-1)', 'tid');
pg_input_is_valid
-------------------
f
(1 row)
SELECT pg_input_error_message('(0,-1)', 'tid');
pg_input_error_message
---------------------------------------------
invalid input syntax for type tid: "(0,-1)"
(1 row)
-- tests for functions related to TID handling
CREATE TABLE tid_tab (a int);
-- min() and max() for TIDs

View File

@ -181,6 +181,37 @@ select '12:16:14,13'::pg_snapshot;
ERROR: invalid input syntax for type pg_snapshot: "12:16:14,13"
LINE 1: select '12:16:14,13'::pg_snapshot;
^
-- also try it with non-error-throwing API
select pg_input_is_valid('12:13:', 'pg_snapshot');
pg_input_is_valid
-------------------
t
(1 row)
select pg_input_is_valid('31:12:', 'pg_snapshot');
pg_input_is_valid
-------------------
f
(1 row)
select pg_input_error_message('31:12:', 'pg_snapshot');
pg_input_error_message
-----------------------------------------------------
invalid input syntax for type pg_snapshot: "31:12:"
(1 row)
select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
pg_input_is_valid
-------------------
f
(1 row)
select pg_input_error_message('12:16:14,13', 'pg_snapshot');
pg_input_error_message
----------------------------------------------------------
invalid input syntax for type pg_snapshot: "12:16:14,13"
(1 row)
create temp table snapshot_test (
nr integer,
snap pg_snapshot

View File

@ -23,6 +23,11 @@ SELECT pg_input_is_valid('asdf', 'int2');
SELECT pg_input_is_valid('50000', 'int2');
SELECT pg_input_error_message('50000', 'int2');
-- While we're here, check int2vector as well
SELECT pg_input_is_valid(' 1 3 5 ', 'int2vector');
SELECT pg_input_error_message('1 asdf', 'int2vector');
SELECT pg_input_error_message('50000', 'int2vector');
SELECT * FROM INT2_TBL AS f(a, b);
SELECT * FROM (TABLE int2_tbl) AS s (a, b);

View File

@ -28,6 +28,20 @@ INSERT INTO OID_TBL(f1) VALUES ('-23582358720398502385');
SELECT * FROM OID_TBL;
-- Also try it with non-error-throwing API
SELECT pg_input_is_valid('1234', 'oid');
SELECT pg_input_is_valid('01XYZ', 'oid');
SELECT pg_input_error_message('01XYZ', 'oid');
SELECT pg_input_is_valid('9999999999', 'oid');
SELECT pg_input_error_message('9999999999', 'oid');
-- While we're here, check oidvector as well
SELECT pg_input_is_valid(' 1 2 4 ', 'oidvector');
SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
SELECT pg_input_error_message('01 01XYZ', 'oidvector');
SELECT pg_input_is_valid('01 9999999999', 'oidvector');
SELECT pg_input_error_message('01 9999999999', 'oidvector');
SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
SELECT o.* FROM OID_TBL o WHERE o.f1 <> '1234';

View File

@ -15,6 +15,10 @@ INSERT INTO PG_LSN_TBL VALUES (' 0/12345678');
INSERT INTO PG_LSN_TBL VALUES ('ABCD/');
INSERT INTO PG_LSN_TBL VALUES ('/ABCD');
-- Also try it with non-error-throwing API
SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
-- Min/Max aggregation
SELECT MIN(f1), MAX(f1) FROM PG_LSN_TBL;

View File

@ -1430,6 +1430,15 @@ SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
'SELECT, fake_privilege', FALSE); -- error
-- Test non-throwing aclitem I/O
SELECT pg_input_is_valid('regress_priv_user1=r/regress_priv_user2', 'aclitem');
SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
--
-- Testing blanket default grants is very hazardous since it might change
-- the privileges attached to objects created by concurrent regression tests.

View File

@ -9,6 +9,12 @@ SELECT
SELECT '(4294967296,1)'::tid; -- error
SELECT '(1,65536)'::tid; -- error
-- Also try it with non-error-throwing API
SELECT pg_input_is_valid('(0)', 'tid');
SELECT pg_input_error_message('(0)', 'tid');
SELECT pg_input_is_valid('(0,-1)', 'tid');
SELECT pg_input_error_message('(0,-1)', 'tid');
-- tests for functions related to TID handling

View File

@ -68,6 +68,13 @@ select '0:1:'::pg_snapshot;
select '12:13:0'::pg_snapshot;
select '12:16:14,13'::pg_snapshot;
-- also try it with non-error-throwing API
select pg_input_is_valid('12:13:', 'pg_snapshot');
select pg_input_is_valid('31:12:', 'pg_snapshot');
select pg_input_error_message('31:12:', 'pg_snapshot');
select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
select pg_input_error_message('12:16:14,13', 'pg_snapshot');
create temp table snapshot_test (
nr integer,
snap pg_snapshot