| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * name.c |
| 4 | * Functions for the built-in type "name". |
| 5 | * |
| 6 | * name replaces char16 and is carefully implemented so that it |
| 7 | * is a string of physical length NAMEDATALEN. |
| 8 | * DO NOT use hard-coded constants anywhere |
| 9 | * always use NAMEDATALEN as the symbolic constant! - jolly 8/21/95 |
| 10 | * |
| 11 | * |
| 12 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 13 | * Portions Copyright (c) 1994, Regents of the University of California |
| 14 | * |
| 15 | * |
| 16 | * IDENTIFICATION |
| 17 | * src/backend/utils/adt/name.c |
| 18 | * |
| 19 | *------------------------------------------------------------------------- |
| 20 | */ |
| 21 | #include "postgres.h" |
| 22 | |
| 23 | #include "catalog/namespace.h" |
| 24 | #include "catalog/pg_collation.h" |
| 25 | #include "catalog/pg_type.h" |
| 26 | #include "libpq/pqformat.h" |
| 27 | #include "mb/pg_wchar.h" |
| 28 | #include "miscadmin.h" |
| 29 | #include "utils/array.h" |
| 30 | #include "utils/builtins.h" |
| 31 | #include "utils/lsyscache.h" |
| 32 | #include "utils/varlena.h" |
| 33 | |
| 34 | |
| 35 | /***************************************************************************** |
| 36 | * USER I/O ROUTINES (none) * |
| 37 | *****************************************************************************/ |
| 38 | |
| 39 | |
| 40 | /* |
| 41 | * namein - converts "..." to internal representation |
| 42 | * |
| 43 | * Note: |
| 44 | * [Old] Currently if strlen(s) < NAMEDATALEN, the extra chars are nulls |
| 45 | * Now, always NULL terminated |
| 46 | */ |
| 47 | Datum |
| 48 | namein(PG_FUNCTION_ARGS) |
| 49 | { |
| 50 | char *s = PG_GETARG_CSTRING(0); |
| 51 | Name result; |
| 52 | int len; |
| 53 | |
| 54 | len = strlen(s); |
| 55 | |
| 56 | /* Truncate oversize input */ |
| 57 | if (len >= NAMEDATALEN) |
| 58 | len = pg_mbcliplen(s, len, NAMEDATALEN - 1); |
| 59 | |
| 60 | /* We use palloc0 here to ensure result is zero-padded */ |
| 61 | result = (Name) palloc0(NAMEDATALEN); |
| 62 | memcpy(NameStr(*result), s, len); |
| 63 | |
| 64 | PG_RETURN_NAME(result); |
| 65 | } |
| 66 | |
| 67 | /* |
| 68 | * nameout - converts internal representation to "..." |
| 69 | */ |
| 70 | Datum |
| 71 | nameout(PG_FUNCTION_ARGS) |
| 72 | { |
| 73 | Name s = PG_GETARG_NAME(0); |
| 74 | |
| 75 | PG_RETURN_CSTRING(pstrdup(NameStr(*s))); |
| 76 | } |
| 77 | |
| 78 | /* |
| 79 | * namerecv - converts external binary format to name |
| 80 | */ |
| 81 | Datum |
| 82 | namerecv(PG_FUNCTION_ARGS) |
| 83 | { |
| 84 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
| 85 | Name result; |
| 86 | char *str; |
| 87 | int nbytes; |
| 88 | |
| 89 | str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); |
| 90 | if (nbytes >= NAMEDATALEN) |
| 91 | ereport(ERROR, |
| 92 | (errcode(ERRCODE_NAME_TOO_LONG), |
| 93 | errmsg("identifier too long" ), |
| 94 | errdetail("Identifier must be less than %d characters." , |
| 95 | NAMEDATALEN))); |
| 96 | result = (NameData *) palloc0(NAMEDATALEN); |
| 97 | memcpy(result, str, nbytes); |
| 98 | pfree(str); |
| 99 | PG_RETURN_NAME(result); |
| 100 | } |
| 101 | |
| 102 | /* |
| 103 | * namesend - converts name to binary format |
| 104 | */ |
| 105 | Datum |
| 106 | namesend(PG_FUNCTION_ARGS) |
| 107 | { |
| 108 | Name s = PG_GETARG_NAME(0); |
| 109 | StringInfoData buf; |
| 110 | |
| 111 | pq_begintypsend(&buf); |
| 112 | pq_sendtext(&buf, NameStr(*s), strlen(NameStr(*s))); |
| 113 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
| 114 | } |
| 115 | |
| 116 | |
| 117 | /***************************************************************************** |
| 118 | * COMPARISON/SORTING ROUTINES * |
| 119 | *****************************************************************************/ |
| 120 | |
| 121 | /* |
| 122 | * nameeq - returns 1 iff arguments are equal |
| 123 | * namene - returns 1 iff arguments are not equal |
| 124 | * namelt - returns 1 iff a < b |
| 125 | * namele - returns 1 iff a <= b |
| 126 | * namegt - returns 1 iff a > b |
| 127 | * namege - returns 1 iff a >= b |
| 128 | * |
| 129 | * Note that the use of strncmp with NAMEDATALEN limit is mostly historical; |
| 130 | * strcmp would do as well, because we do not allow NAME values that don't |
| 131 | * have a '\0' terminator. Whatever might be past the terminator is not |
| 132 | * considered relevant to comparisons. |
| 133 | */ |
| 134 | static int |
| 135 | namecmp(Name arg1, Name arg2, Oid collid) |
| 136 | { |
| 137 | /* Fast path for common case used in system catalogs */ |
| 138 | if (collid == C_COLLATION_OID) |
| 139 | return strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN); |
| 140 | |
| 141 | /* Else rely on the varstr infrastructure */ |
| 142 | return varstr_cmp(NameStr(*arg1), strlen(NameStr(*arg1)), |
| 143 | NameStr(*arg2), strlen(NameStr(*arg2)), |
| 144 | collid); |
| 145 | } |
| 146 | |
| 147 | Datum |
| 148 | nameeq(PG_FUNCTION_ARGS) |
| 149 | { |
| 150 | Name arg1 = PG_GETARG_NAME(0); |
| 151 | Name arg2 = PG_GETARG_NAME(1); |
| 152 | |
| 153 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) == 0); |
| 154 | } |
| 155 | |
| 156 | Datum |
| 157 | namene(PG_FUNCTION_ARGS) |
| 158 | { |
| 159 | Name arg1 = PG_GETARG_NAME(0); |
| 160 | Name arg2 = PG_GETARG_NAME(1); |
| 161 | |
| 162 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) != 0); |
| 163 | } |
| 164 | |
| 165 | Datum |
| 166 | namelt(PG_FUNCTION_ARGS) |
| 167 | { |
| 168 | Name arg1 = PG_GETARG_NAME(0); |
| 169 | Name arg2 = PG_GETARG_NAME(1); |
| 170 | |
| 171 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) < 0); |
| 172 | } |
| 173 | |
| 174 | Datum |
| 175 | namele(PG_FUNCTION_ARGS) |
| 176 | { |
| 177 | Name arg1 = PG_GETARG_NAME(0); |
| 178 | Name arg2 = PG_GETARG_NAME(1); |
| 179 | |
| 180 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) <= 0); |
| 181 | } |
| 182 | |
| 183 | Datum |
| 184 | namegt(PG_FUNCTION_ARGS) |
| 185 | { |
| 186 | Name arg1 = PG_GETARG_NAME(0); |
| 187 | Name arg2 = PG_GETARG_NAME(1); |
| 188 | |
| 189 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) > 0); |
| 190 | } |
| 191 | |
| 192 | Datum |
| 193 | namege(PG_FUNCTION_ARGS) |
| 194 | { |
| 195 | Name arg1 = PG_GETARG_NAME(0); |
| 196 | Name arg2 = PG_GETARG_NAME(1); |
| 197 | |
| 198 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) >= 0); |
| 199 | } |
| 200 | |
| 201 | Datum |
| 202 | btnamecmp(PG_FUNCTION_ARGS) |
| 203 | { |
| 204 | Name arg1 = PG_GETARG_NAME(0); |
| 205 | Name arg2 = PG_GETARG_NAME(1); |
| 206 | |
| 207 | PG_RETURN_INT32(namecmp(arg1, arg2, PG_GET_COLLATION())); |
| 208 | } |
| 209 | |
| 210 | Datum |
| 211 | btnamesortsupport(PG_FUNCTION_ARGS) |
| 212 | { |
| 213 | SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); |
| 214 | Oid collid = ssup->ssup_collation; |
| 215 | MemoryContext oldcontext; |
| 216 | |
| 217 | oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt); |
| 218 | |
| 219 | /* Use generic string SortSupport */ |
| 220 | varstr_sortsupport(ssup, NAMEOID, collid); |
| 221 | |
| 222 | MemoryContextSwitchTo(oldcontext); |
| 223 | |
| 224 | PG_RETURN_VOID(); |
| 225 | } |
| 226 | |
| 227 | |
| 228 | /***************************************************************************** |
| 229 | * MISCELLANEOUS PUBLIC ROUTINES * |
| 230 | *****************************************************************************/ |
| 231 | |
| 232 | int |
| 233 | namecpy(Name n1, const NameData *n2) |
| 234 | { |
| 235 | if (!n1 || !n2) |
| 236 | return -1; |
| 237 | StrNCpy(NameStr(*n1), NameStr(*n2), NAMEDATALEN); |
| 238 | return 0; |
| 239 | } |
| 240 | |
| 241 | #ifdef NOT_USED |
| 242 | int |
| 243 | namecat(Name n1, Name n2) |
| 244 | { |
| 245 | return namestrcat(n1, NameStr(*n2)); /* n2 can't be any longer than n1 */ |
| 246 | } |
| 247 | #endif |
| 248 | |
| 249 | int |
| 250 | namestrcpy(Name name, const char *str) |
| 251 | { |
| 252 | if (!name || !str) |
| 253 | return -1; |
| 254 | StrNCpy(NameStr(*name), str, NAMEDATALEN); |
| 255 | return 0; |
| 256 | } |
| 257 | |
| 258 | #ifdef NOT_USED |
| 259 | int |
| 260 | namestrcat(Name name, const char *str) |
| 261 | { |
| 262 | int i; |
| 263 | char *p, |
| 264 | *q; |
| 265 | |
| 266 | if (!name || !str) |
| 267 | return -1; |
| 268 | for (i = 0, p = NameStr(*name); i < NAMEDATALEN && *p; ++i, ++p) |
| 269 | ; |
| 270 | for (q = str; i < NAMEDATALEN; ++i, ++p, ++q) |
| 271 | { |
| 272 | *p = *q; |
| 273 | if (!*q) |
| 274 | break; |
| 275 | } |
| 276 | return 0; |
| 277 | } |
| 278 | #endif |
| 279 | |
| 280 | /* |
| 281 | * Compare a NAME to a C string |
| 282 | * |
| 283 | * Assumes C collation always; be careful when using this for |
| 284 | * anything but equality checks! |
| 285 | */ |
| 286 | int |
| 287 | namestrcmp(Name name, const char *str) |
| 288 | { |
| 289 | if (!name && !str) |
| 290 | return 0; |
| 291 | if (!name) |
| 292 | return -1; /* NULL < anything */ |
| 293 | if (!str) |
| 294 | return 1; /* NULL < anything */ |
| 295 | return strncmp(NameStr(*name), str, NAMEDATALEN); |
| 296 | } |
| 297 | |
| 298 | |
| 299 | /* |
| 300 | * SQL-functions CURRENT_USER, SESSION_USER |
| 301 | */ |
| 302 | Datum |
| 303 | current_user(PG_FUNCTION_ARGS) |
| 304 | { |
| 305 | PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false)))); |
| 306 | } |
| 307 | |
| 308 | Datum |
| 309 | session_user(PG_FUNCTION_ARGS) |
| 310 | { |
| 311 | PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId(), false)))); |
| 312 | } |
| 313 | |
| 314 | |
| 315 | /* |
| 316 | * SQL-functions CURRENT_SCHEMA, CURRENT_SCHEMAS |
| 317 | */ |
| 318 | Datum |
| 319 | current_schema(PG_FUNCTION_ARGS) |
| 320 | { |
| 321 | List *search_path = fetch_search_path(false); |
| 322 | char *nspname; |
| 323 | |
| 324 | if (search_path == NIL) |
| 325 | PG_RETURN_NULL(); |
| 326 | nspname = get_namespace_name(linitial_oid(search_path)); |
| 327 | list_free(search_path); |
| 328 | if (!nspname) |
| 329 | PG_RETURN_NULL(); /* recently-deleted namespace? */ |
| 330 | PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(nspname))); |
| 331 | } |
| 332 | |
| 333 | Datum |
| 334 | current_schemas(PG_FUNCTION_ARGS) |
| 335 | { |
| 336 | List *search_path = fetch_search_path(PG_GETARG_BOOL(0)); |
| 337 | ListCell *l; |
| 338 | Datum *names; |
| 339 | int i; |
| 340 | ArrayType *array; |
| 341 | |
| 342 | names = (Datum *) palloc(list_length(search_path) * sizeof(Datum)); |
| 343 | i = 0; |
| 344 | foreach(l, search_path) |
| 345 | { |
| 346 | char *nspname; |
| 347 | |
| 348 | nspname = get_namespace_name(lfirst_oid(l)); |
| 349 | if (nspname) /* watch out for deleted namespace */ |
| 350 | { |
| 351 | names[i] = DirectFunctionCall1(namein, CStringGetDatum(nspname)); |
| 352 | i++; |
| 353 | } |
| 354 | } |
| 355 | list_free(search_path); |
| 356 | |
| 357 | array = construct_array(names, i, |
| 358 | NAMEOID, |
| 359 | NAMEDATALEN, /* sizeof(Name) */ |
| 360 | false, /* Name is not by-val */ |
| 361 | 'c'); /* alignment of Name */ |
| 362 | |
| 363 | PG_RETURN_POINTER(array); |
| 364 | } |
| 365 | |
| 366 | /* |
| 367 | * SQL-function nameconcatoid(name, oid) returns name |
| 368 | * |
| 369 | * This is used in the information_schema to produce specific_name columns, |
| 370 | * which are supposed to be unique per schema. We achieve that (in an ugly |
| 371 | * way) by appending the object's OID. The result is the same as |
| 372 | * ($1::text || '_' || $2::text)::name |
| 373 | * except that, if it would not fit in NAMEDATALEN, we make it do so by |
| 374 | * truncating the name input (not the oid). |
| 375 | */ |
| 376 | Datum |
| 377 | nameconcatoid(PG_FUNCTION_ARGS) |
| 378 | { |
| 379 | Name nam = PG_GETARG_NAME(0); |
| 380 | Oid oid = PG_GETARG_OID(1); |
| 381 | Name result; |
| 382 | char suffix[20]; |
| 383 | int suflen; |
| 384 | int namlen; |
| 385 | |
| 386 | suflen = snprintf(suffix, sizeof(suffix), "_%u" , oid); |
| 387 | namlen = strlen(NameStr(*nam)); |
| 388 | |
| 389 | /* Truncate oversize input by truncating name part, not suffix */ |
| 390 | if (namlen + suflen >= NAMEDATALEN) |
| 391 | namlen = pg_mbcliplen(NameStr(*nam), namlen, NAMEDATALEN - 1 - suflen); |
| 392 | |
| 393 | /* We use palloc0 here to ensure result is zero-padded */ |
| 394 | result = (Name) palloc0(NAMEDATALEN); |
| 395 | memcpy(NameStr(*result), NameStr(*nam), namlen); |
| 396 | memcpy(NameStr(*result) + namlen, suffix, suflen); |
| 397 | |
| 398 | PG_RETURN_NAME(result); |
| 399 | } |
| 400 | |