From 46651ce6fe013220ed397add242004d764fc0153 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:15:05 +0200 Subject: Adding upstream version 14.5. Signed-off-by: Daniel Baumann --- src/backend/utils/adt/name.c | 359 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 src/backend/utils/adt/name.c (limited to 'src/backend/utils/adt/name.c') diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c new file mode 100644 index 0000000..602a724 --- /dev/null +++ b/src/backend/utils/adt/name.c @@ -0,0 +1,359 @@ +/*------------------------------------------------------------------------- + * + * name.c + * Functions for the built-in type "name". + * + * name replaces char16 and is carefully implemented so that it + * is a string of physical length NAMEDATALEN. + * DO NOT use hard-coded constants anywhere + * always use NAMEDATALEN as the symbolic constant! - jolly 8/21/95 + * + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/name.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "catalog/namespace.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_type.h" +#include "libpq/pqformat.h" +#include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/varlena.h" + + +/***************************************************************************** + * USER I/O ROUTINES (none) * + *****************************************************************************/ + + +/* + * namein - converts "..." to internal representation + * + * Note: + * [Old] Currently if strlen(s) < NAMEDATALEN, the extra chars are nulls + * Now, always NULL terminated + */ +Datum +namein(PG_FUNCTION_ARGS) +{ + char *s = PG_GETARG_CSTRING(0); + Name result; + int len; + + len = strlen(s); + + /* Truncate oversize input */ + if (len >= NAMEDATALEN) + len = pg_mbcliplen(s, len, NAMEDATALEN - 1); + + /* We use palloc0 here to ensure result is zero-padded */ + result = (Name) palloc0(NAMEDATALEN); + memcpy(NameStr(*result), s, len); + + PG_RETURN_NAME(result); +} + +/* + * nameout - converts internal representation to "..." + */ +Datum +nameout(PG_FUNCTION_ARGS) +{ + Name s = PG_GETARG_NAME(0); + + PG_RETURN_CSTRING(pstrdup(NameStr(*s))); +} + +/* + * namerecv - converts external binary format to name + */ +Datum +namerecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + Name result; + char *str; + int nbytes; + + str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); + if (nbytes >= NAMEDATALEN) + ereport(ERROR, + (errcode(ERRCODE_NAME_TOO_LONG), + errmsg("identifier too long"), + errdetail("Identifier must be less than %d characters.", + NAMEDATALEN))); + result = (NameData *) palloc0(NAMEDATALEN); + memcpy(result, str, nbytes); + pfree(str); + PG_RETURN_NAME(result); +} + +/* + * namesend - converts name to binary format + */ +Datum +namesend(PG_FUNCTION_ARGS) +{ + Name s = PG_GETARG_NAME(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendtext(&buf, NameStr(*s), strlen(NameStr(*s))); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + + +/***************************************************************************** + * COMPARISON/SORTING ROUTINES * + *****************************************************************************/ + +/* + * nameeq - returns 1 iff arguments are equal + * namene - returns 1 iff arguments are not equal + * namelt - returns 1 iff a < b + * namele - returns 1 iff a <= b + * namegt - returns 1 iff a > b + * namege - returns 1 iff a >= b + * + * Note that the use of strncmp with NAMEDATALEN limit is mostly historical; + * strcmp would do as well, because we do not allow NAME values that don't + * have a '\0' terminator. Whatever might be past the terminator is not + * considered relevant to comparisons. + */ +static int +namecmp(Name arg1, Name arg2, Oid collid) +{ + /* Fast path for common case used in system catalogs */ + if (collid == C_COLLATION_OID) + return strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN); + + /* Else rely on the varstr infrastructure */ + return varstr_cmp(NameStr(*arg1), strlen(NameStr(*arg1)), + NameStr(*arg2), strlen(NameStr(*arg2)), + collid); +} + +Datum +nameeq(PG_FUNCTION_ARGS) +{ + Name arg1 = PG_GETARG_NAME(0); + Name arg2 = PG_GETARG_NAME(1); + + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) == 0); +} + +Datum +namene(PG_FUNCTION_ARGS) +{ + Name arg1 = PG_GETARG_NAME(0); + Name arg2 = PG_GETARG_NAME(1); + + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) != 0); +} + +Datum +namelt(PG_FUNCTION_ARGS) +{ + Name arg1 = PG_GETARG_NAME(0); + Name arg2 = PG_GETARG_NAME(1); + + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) < 0); +} + +Datum +namele(PG_FUNCTION_ARGS) +{ + Name arg1 = PG_GETARG_NAME(0); + Name arg2 = PG_GETARG_NAME(1); + + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) <= 0); +} + +Datum +namegt(PG_FUNCTION_ARGS) +{ + Name arg1 = PG_GETARG_NAME(0); + Name arg2 = PG_GETARG_NAME(1); + + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) > 0); +} + +Datum +namege(PG_FUNCTION_ARGS) +{ + Name arg1 = PG_GETARG_NAME(0); + Name arg2 = PG_GETARG_NAME(1); + + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) >= 0); +} + +Datum +btnamecmp(PG_FUNCTION_ARGS) +{ + Name arg1 = PG_GETARG_NAME(0); + Name arg2 = PG_GETARG_NAME(1); + + PG_RETURN_INT32(namecmp(arg1, arg2, PG_GET_COLLATION())); +} + +Datum +btnamesortsupport(PG_FUNCTION_ARGS) +{ + SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); + Oid collid = ssup->ssup_collation; + MemoryContext oldcontext; + + oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt); + + /* Use generic string SortSupport */ + varstr_sortsupport(ssup, NAMEOID, collid); + + MemoryContextSwitchTo(oldcontext); + + PG_RETURN_VOID(); +} + + +/***************************************************************************** + * MISCELLANEOUS PUBLIC ROUTINES * + *****************************************************************************/ + +void +namestrcpy(Name name, const char *str) +{ + /* NB: We need to zero-pad the destination. */ + strncpy(NameStr(*name), str, NAMEDATALEN); + NameStr(*name)[NAMEDATALEN - 1] = '\0'; +} + +/* + * Compare a NAME to a C string + * + * Assumes C collation always; be careful when using this for + * anything but equality checks! + */ +int +namestrcmp(Name name, const char *str) +{ + if (!name && !str) + return 0; + if (!name) + return -1; /* NULL < anything */ + if (!str) + return 1; /* NULL < anything */ + return strncmp(NameStr(*name), str, NAMEDATALEN); +} + + +/* + * SQL-functions CURRENT_USER, SESSION_USER + */ +Datum +current_user(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false)))); +} + +Datum +session_user(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId(), false)))); +} + + +/* + * SQL-functions CURRENT_SCHEMA, CURRENT_SCHEMAS + */ +Datum +current_schema(PG_FUNCTION_ARGS) +{ + List *search_path = fetch_search_path(false); + char *nspname; + + if (search_path == NIL) + PG_RETURN_NULL(); + nspname = get_namespace_name(linitial_oid(search_path)); + list_free(search_path); + if (!nspname) + PG_RETURN_NULL(); /* recently-deleted namespace? */ + PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(nspname))); +} + +Datum +current_schemas(PG_FUNCTION_ARGS) +{ + List *search_path = fetch_search_path(PG_GETARG_BOOL(0)); + ListCell *l; + Datum *names; + int i; + ArrayType *array; + + names = (Datum *) palloc(list_length(search_path) * sizeof(Datum)); + i = 0; + foreach(l, search_path) + { + char *nspname; + + nspname = get_namespace_name(lfirst_oid(l)); + if (nspname) /* watch out for deleted namespace */ + { + names[i] = DirectFunctionCall1(namein, CStringGetDatum(nspname)); + i++; + } + } + list_free(search_path); + + array = construct_array(names, i, + NAMEOID, + NAMEDATALEN, /* sizeof(Name) */ + false, /* Name is not by-val */ + TYPALIGN_CHAR); /* alignment of Name */ + + PG_RETURN_POINTER(array); +} + +/* + * SQL-function nameconcatoid(name, oid) returns name + * + * This is used in the information_schema to produce specific_name columns, + * which are supposed to be unique per schema. We achieve that (in an ugly + * way) by appending the object's OID. The result is the same as + * ($1::text || '_' || $2::text)::name + * except that, if it would not fit in NAMEDATALEN, we make it do so by + * truncating the name input (not the oid). + */ +Datum +nameconcatoid(PG_FUNCTION_ARGS) +{ + Name nam = PG_GETARG_NAME(0); + Oid oid = PG_GETARG_OID(1); + Name result; + char suffix[20]; + int suflen; + int namlen; + + suflen = snprintf(suffix, sizeof(suffix), "_%u", oid); + namlen = strlen(NameStr(*nam)); + + /* Truncate oversize input by truncating name part, not suffix */ + if (namlen + suflen >= NAMEDATALEN) + namlen = pg_mbcliplen(NameStr(*nam), namlen, NAMEDATALEN - 1 - suflen); + + /* We use palloc0 here to ensure result is zero-padded */ + result = (Name) palloc0(NAMEDATALEN); + memcpy(NameStr(*result), NameStr(*nam), namlen); + memcpy(NameStr(*result) + namlen, suffix, suflen); + + PG_RETURN_NAME(result); +} -- cgit v1.2.3