You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
postgres/src/backend/utils/adt/name.c

367 lines
8.1 KiB

/*-------------------------------------------------------------------------
*
* 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-2018, 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.",
23 years ago
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.
*/
Datum
nameeq(PG_FUNCTION_ARGS)
{
Name arg1 = PG_GETARG_NAME(0);
Name arg2 = PG_GETARG_NAME(1);
/* Collation doesn't matter: equal only if bitwise-equal */
PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) == 0);
}
Datum
namene(PG_FUNCTION_ARGS)
{
Name arg1 = PG_GETARG_NAME(0);
Name arg2 = PG_GETARG_NAME(1);
/* Collation doesn't matter: equal only if bitwise-equal */
PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) != 0);
}
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
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 *
*****************************************************************************/
int
namecpy(Name n1, const NameData *n2)
{
if (!n1 || !n2)
return -1;
StrNCpy(NameStr(*n1), NameStr(*n2), NAMEDATALEN);
return 0;
}
#ifdef NOT_USED
int
namecat(Name n1, Name n2)
{
Phase 2 of pgindent updates. Change pg_bsd_indent to follow upstream rules for placement of comments to the right of code, and remove pgindent hack that caused comments following #endif to not obey the general rule. Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using the published version of pg_bsd_indent, but a hacked-up version that tried to minimize the amount of movement of comments to the right of code. The situation of interest is where such a comment has to be moved to the right of its default placement at column 33 because there's code there. BSD indent has always moved right in units of tab stops in such cases --- but in the previous incarnation, indent was working in 8-space tab stops, while now it knows we use 4-space tabs. So the net result is that in about half the cases, such comments are placed one tab stop left of before. This is better all around: it leaves more room on the line for comment text, and it means that in such cases the comment uniformly starts at the next 4-space tab stop after the code, rather than sometimes one and sometimes two tabs after. Also, ensure that comments following #endif are indented the same as comments following other preprocessor commands such as #else. That inconsistency turns out to have been self-inflicted damage from a poorly-thought-through post-indent "fixup" in pgindent. This patch is much less interesting than the first round of indent changes, but also bulkier, so I thought it best to separate the effects. Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
9 years ago
return namestrcat(n1, NameStr(*n2)); /* n2 can't be any longer than n1 */
}
#endif
int
namestrcpy(Name name, const char *str)
{
if (!name || !str)
return -1;
StrNCpy(NameStr(*name), str, NAMEDATALEN);
return 0;
}
#ifdef NOT_USED
int
namestrcat(Name name, const char *str)
{
int i;
char *p,
*q;
if (!name || !str)
return -1;
for (i = 0, p = NameStr(*name); i < NAMEDATALEN && *p; ++i, ++p)
;
for (q = str; i < NAMEDATALEN; ++i, ++p, ++q)
{
*p = *q;
if (!*q)
break;
}
return 0;
}
#endif
/*
* 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)
{
24 years ago
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)
{
24 years ago
List *search_path = fetch_search_path(PG_GETARG_BOOL(0));
ListCell *l;
24 years ago
Datum *names;
int i;
ArrayType *array;
names = (Datum *) palloc(list_length(search_path) * sizeof(Datum));
i = 0;
foreach(l, search_path)
{
24 years ago
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,
Phase 2 of pgindent updates. Change pg_bsd_indent to follow upstream rules for placement of comments to the right of code, and remove pgindent hack that caused comments following #endif to not obey the general rule. Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using the published version of pg_bsd_indent, but a hacked-up version that tried to minimize the amount of movement of comments to the right of code. The situation of interest is where such a comment has to be moved to the right of its default placement at column 33 because there's code there. BSD indent has always moved right in units of tab stops in such cases --- but in the previous incarnation, indent was working in 8-space tab stops, while now it knows we use 4-space tabs. So the net result is that in about half the cases, such comments are placed one tab stop left of before. This is better all around: it leaves more room on the line for comment text, and it means that in such cases the comment uniformly starts at the next 4-space tab stop after the code, rather than sometimes one and sometimes two tabs after. Also, ensure that comments following #endif are indented the same as comments following other preprocessor commands such as #else. That inconsistency turns out to have been self-inflicted damage from a poorly-thought-through post-indent "fixup" in pgindent. This patch is much less interesting than the first round of indent changes, but also bulkier, so I thought it best to separate the effects. Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
9 years ago
NAMEDATALEN, /* sizeof(Name) */
false, /* Name is not by-val */
'c'); /* alignment of Name */
PG_RETURN_POINTER(array);
}