/src/postgres/src/backend/utils/adt/oid.c
Line | Count | Source |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * oid.c |
4 | | * Functions for the built-in type Oid ... also oidvector. |
5 | | * |
6 | | * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group |
7 | | * Portions Copyright (c) 1994, Regents of the University of California |
8 | | * |
9 | | * |
10 | | * IDENTIFICATION |
11 | | * src/backend/utils/adt/oid.c |
12 | | * |
13 | | *------------------------------------------------------------------------- |
14 | | */ |
15 | | #include "postgres.h" |
16 | | |
17 | | #include <ctype.h> |
18 | | #include <limits.h> |
19 | | |
20 | | #include "catalog/pg_type.h" |
21 | | #include "common/int.h" |
22 | | #include "libpq/pqformat.h" |
23 | | #include "nodes/miscnodes.h" |
24 | | #include "nodes/value.h" |
25 | | #include "utils/array.h" |
26 | | #include "utils/builtins.h" |
27 | | |
28 | | |
29 | 0 | #define OidVectorSize(n) (offsetof(oidvector, values) + (n) * sizeof(Oid)) |
30 | | |
31 | | |
32 | | /***************************************************************************** |
33 | | * USER I/O ROUTINES * |
34 | | *****************************************************************************/ |
35 | | |
36 | | Datum |
37 | | oidin(PG_FUNCTION_ARGS) |
38 | 0 | { |
39 | 0 | char *s = PG_GETARG_CSTRING(0); |
40 | 0 | Oid result; |
41 | |
|
42 | 0 | result = uint32in_subr(s, NULL, "oid", fcinfo->context); |
43 | 0 | PG_RETURN_OID(result); |
44 | 0 | } |
45 | | |
46 | | Datum |
47 | | oidout(PG_FUNCTION_ARGS) |
48 | 0 | { |
49 | 0 | Oid o = PG_GETARG_OID(0); |
50 | 0 | char *result = (char *) palloc(12); |
51 | |
|
52 | 0 | snprintf(result, 12, "%u", o); |
53 | 0 | PG_RETURN_CSTRING(result); |
54 | 0 | } |
55 | | |
56 | | /* |
57 | | * oidrecv - converts external binary format to oid |
58 | | */ |
59 | | Datum |
60 | | oidrecv(PG_FUNCTION_ARGS) |
61 | 0 | { |
62 | 0 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
63 | |
|
64 | 0 | PG_RETURN_OID((Oid) pq_getmsgint(buf, sizeof(Oid))); |
65 | 0 | } |
66 | | |
67 | | /* |
68 | | * oidsend - converts oid to binary format |
69 | | */ |
70 | | Datum |
71 | | oidsend(PG_FUNCTION_ARGS) |
72 | 0 | { |
73 | 0 | Oid arg1 = PG_GETARG_OID(0); |
74 | 0 | StringInfoData buf; |
75 | |
|
76 | 0 | pq_begintypsend(&buf); |
77 | 0 | pq_sendint32(&buf, arg1); |
78 | 0 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
79 | 0 | } |
80 | | |
81 | | /* |
82 | | * construct oidvector given a raw array of Oids |
83 | | * |
84 | | * If oids is NULL then caller must fill values[] afterward |
85 | | */ |
86 | | oidvector * |
87 | | buildoidvector(const Oid *oids, int n) |
88 | 0 | { |
89 | 0 | oidvector *result; |
90 | |
|
91 | 0 | result = (oidvector *) palloc0(OidVectorSize(n)); |
92 | |
|
93 | 0 | if (n > 0 && oids) |
94 | 0 | memcpy(result->values, oids, n * sizeof(Oid)); |
95 | | |
96 | | /* |
97 | | * Attach standard array header. For historical reasons, we set the index |
98 | | * lower bound to 0 not 1. |
99 | | */ |
100 | 0 | SET_VARSIZE(result, OidVectorSize(n)); |
101 | 0 | result->ndim = 1; |
102 | 0 | result->dataoffset = 0; /* never any nulls */ |
103 | 0 | result->elemtype = OIDOID; |
104 | 0 | result->dim1 = n; |
105 | 0 | result->lbound1 = 0; |
106 | |
|
107 | 0 | return result; |
108 | 0 | } |
109 | | |
110 | | /* |
111 | | * validate that an array object meets the restrictions of oidvector |
112 | | * |
113 | | * We need this because there are pathways by which a general oid[] array can |
114 | | * be cast to oidvector, allowing the type's restrictions to be violated. |
115 | | * All code that receives an oidvector as a SQL parameter should check this. |
116 | | */ |
117 | | void |
118 | | check_valid_oidvector(const oidvector *oidArray) |
119 | 0 | { |
120 | | /* |
121 | | * We insist on ndim == 1 and dataoffset == 0 (that is, no nulls) because |
122 | | * otherwise the array's layout will not be what calling code expects. We |
123 | | * needn't be picky about the index lower bound though. Checking elemtype |
124 | | * is just paranoia. |
125 | | */ |
126 | 0 | if (oidArray->ndim != 1 || |
127 | 0 | oidArray->dataoffset != 0 || |
128 | 0 | oidArray->elemtype != OIDOID) |
129 | 0 | ereport(ERROR, |
130 | 0 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
131 | 0 | errmsg("array is not a valid oidvector"))); |
132 | 0 | } |
133 | | |
134 | | /* |
135 | | * oidvectorin - converts "num num ..." to internal form |
136 | | */ |
137 | | Datum |
138 | | oidvectorin(PG_FUNCTION_ARGS) |
139 | 0 | { |
140 | 0 | char *oidString = PG_GETARG_CSTRING(0); |
141 | 0 | Node *escontext = fcinfo->context; |
142 | 0 | oidvector *result; |
143 | 0 | int nalloc; |
144 | 0 | int n; |
145 | |
|
146 | 0 | nalloc = 32; /* arbitrary initial size guess */ |
147 | 0 | result = (oidvector *) palloc0(OidVectorSize(nalloc)); |
148 | |
|
149 | 0 | for (n = 0;; n++) |
150 | 0 | { |
151 | 0 | while (*oidString && isspace((unsigned char) *oidString)) |
152 | 0 | oidString++; |
153 | 0 | if (*oidString == '\0') |
154 | 0 | break; |
155 | | |
156 | 0 | if (n >= nalloc) |
157 | 0 | { |
158 | 0 | nalloc *= 2; |
159 | 0 | result = (oidvector *) repalloc(result, OidVectorSize(nalloc)); |
160 | 0 | } |
161 | |
|
162 | 0 | result->values[n] = uint32in_subr(oidString, &oidString, |
163 | 0 | "oid", escontext); |
164 | 0 | if (SOFT_ERROR_OCCURRED(escontext)) |
165 | 0 | PG_RETURN_NULL(); |
166 | 0 | } |
167 | | |
168 | 0 | SET_VARSIZE(result, OidVectorSize(n)); |
169 | 0 | result->ndim = 1; |
170 | 0 | result->dataoffset = 0; /* never any nulls */ |
171 | 0 | result->elemtype = OIDOID; |
172 | 0 | result->dim1 = n; |
173 | 0 | result->lbound1 = 0; |
174 | |
|
175 | 0 | PG_RETURN_POINTER(result); |
176 | 0 | } |
177 | | |
178 | | /* |
179 | | * oidvectorout - converts internal form to "num num ..." |
180 | | */ |
181 | | Datum |
182 | | oidvectorout(PG_FUNCTION_ARGS) |
183 | 0 | { |
184 | 0 | oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0); |
185 | 0 | int num, |
186 | 0 | nnums; |
187 | 0 | char *rp; |
188 | 0 | char *result; |
189 | | |
190 | | /* validate input before fetching dim1 */ |
191 | 0 | check_valid_oidvector(oidArray); |
192 | 0 | nnums = oidArray->dim1; |
193 | | |
194 | | /* assumes sign, 10 digits, ' ' */ |
195 | 0 | rp = result = (char *) palloc(nnums * 12 + 1); |
196 | 0 | for (num = 0; num < nnums; num++) |
197 | 0 | { |
198 | 0 | if (num != 0) |
199 | 0 | *rp++ = ' '; |
200 | 0 | sprintf(rp, "%u", oidArray->values[num]); |
201 | 0 | while (*++rp != '\0') |
202 | 0 | ; |
203 | 0 | } |
204 | 0 | *rp = '\0'; |
205 | 0 | PG_RETURN_CSTRING(result); |
206 | 0 | } |
207 | | |
208 | | /* |
209 | | * oidvectorrecv - converts external binary format to oidvector |
210 | | */ |
211 | | Datum |
212 | | oidvectorrecv(PG_FUNCTION_ARGS) |
213 | 0 | { |
214 | 0 | LOCAL_FCINFO(locfcinfo, 3); |
215 | 0 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
216 | 0 | oidvector *result; |
217 | | |
218 | | /* |
219 | | * Normally one would call array_recv() using DirectFunctionCall3, but |
220 | | * that does not work since array_recv wants to cache some data using |
221 | | * fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo |
222 | | * parameter. |
223 | | */ |
224 | 0 | InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 3, |
225 | 0 | InvalidOid, NULL, NULL); |
226 | |
|
227 | 0 | locfcinfo->args[0].value = PointerGetDatum(buf); |
228 | 0 | locfcinfo->args[0].isnull = false; |
229 | 0 | locfcinfo->args[1].value = ObjectIdGetDatum(OIDOID); |
230 | 0 | locfcinfo->args[1].isnull = false; |
231 | 0 | locfcinfo->args[2].value = Int32GetDatum(-1); |
232 | 0 | locfcinfo->args[2].isnull = false; |
233 | |
|
234 | 0 | result = (oidvector *) DatumGetPointer(array_recv(locfcinfo)); |
235 | |
|
236 | 0 | Assert(!locfcinfo->isnull); |
237 | | |
238 | | /* sanity checks: oidvector must be 1-D, 0-based, no nulls */ |
239 | 0 | if (ARR_NDIM(result) != 1 || |
240 | 0 | ARR_HASNULL(result) || |
241 | 0 | ARR_ELEMTYPE(result) != OIDOID || |
242 | 0 | ARR_LBOUND(result)[0] != 0) |
243 | 0 | ereport(ERROR, |
244 | 0 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), |
245 | 0 | errmsg("invalid oidvector data"))); |
246 | | |
247 | 0 | PG_RETURN_POINTER(result); |
248 | 0 | } |
249 | | |
250 | | /* |
251 | | * oidvectorsend - converts oidvector to binary format |
252 | | */ |
253 | | Datum |
254 | | oidvectorsend(PG_FUNCTION_ARGS) |
255 | 0 | { |
256 | | /* We don't do check_valid_oidvector, since array_send won't care */ |
257 | 0 | return array_send(fcinfo); |
258 | 0 | } |
259 | | |
260 | | /* |
261 | | * oidparse - get OID from ICONST/FCONST node |
262 | | */ |
263 | | Oid |
264 | | oidparse(Node *node) |
265 | 0 | { |
266 | 0 | switch (nodeTag(node)) |
267 | 0 | { |
268 | 0 | case T_Integer: |
269 | 0 | return intVal(node); |
270 | 0 | case T_Float: |
271 | | |
272 | | /* |
273 | | * Values too large for int4 will be represented as Float |
274 | | * constants by the lexer. Accept these if they are valid OID |
275 | | * strings. |
276 | | */ |
277 | 0 | return uint32in_subr(castNode(Float, node)->fval, NULL, |
278 | 0 | "oid", NULL); |
279 | 0 | default: |
280 | 0 | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); |
281 | 0 | } |
282 | 0 | return InvalidOid; /* keep compiler quiet */ |
283 | 0 | } |
284 | | |
285 | | /* qsort comparison function for Oids */ |
286 | | int |
287 | | oid_cmp(const void *p1, const void *p2) |
288 | 0 | { |
289 | 0 | Oid v1 = *((const Oid *) p1); |
290 | 0 | Oid v2 = *((const Oid *) p2); |
291 | |
|
292 | 0 | return pg_cmp_u32(v1, v2); |
293 | 0 | } |
294 | | |
295 | | |
296 | | /***************************************************************************** |
297 | | * PUBLIC ROUTINES * |
298 | | *****************************************************************************/ |
299 | | |
300 | | Datum |
301 | | oideq(PG_FUNCTION_ARGS) |
302 | 0 | { |
303 | 0 | Oid arg1 = PG_GETARG_OID(0); |
304 | 0 | Oid arg2 = PG_GETARG_OID(1); |
305 | |
|
306 | 0 | PG_RETURN_BOOL(arg1 == arg2); |
307 | 0 | } |
308 | | |
309 | | Datum |
310 | | oidne(PG_FUNCTION_ARGS) |
311 | 0 | { |
312 | 0 | Oid arg1 = PG_GETARG_OID(0); |
313 | 0 | Oid arg2 = PG_GETARG_OID(1); |
314 | |
|
315 | 0 | PG_RETURN_BOOL(arg1 != arg2); |
316 | 0 | } |
317 | | |
318 | | Datum |
319 | | oidlt(PG_FUNCTION_ARGS) |
320 | 0 | { |
321 | 0 | Oid arg1 = PG_GETARG_OID(0); |
322 | 0 | Oid arg2 = PG_GETARG_OID(1); |
323 | |
|
324 | 0 | PG_RETURN_BOOL(arg1 < arg2); |
325 | 0 | } |
326 | | |
327 | | Datum |
328 | | oidle(PG_FUNCTION_ARGS) |
329 | 0 | { |
330 | 0 | Oid arg1 = PG_GETARG_OID(0); |
331 | 0 | Oid arg2 = PG_GETARG_OID(1); |
332 | |
|
333 | 0 | PG_RETURN_BOOL(arg1 <= arg2); |
334 | 0 | } |
335 | | |
336 | | Datum |
337 | | oidge(PG_FUNCTION_ARGS) |
338 | 0 | { |
339 | 0 | Oid arg1 = PG_GETARG_OID(0); |
340 | 0 | Oid arg2 = PG_GETARG_OID(1); |
341 | |
|
342 | 0 | PG_RETURN_BOOL(arg1 >= arg2); |
343 | 0 | } |
344 | | |
345 | | Datum |
346 | | oidgt(PG_FUNCTION_ARGS) |
347 | 0 | { |
348 | 0 | Oid arg1 = PG_GETARG_OID(0); |
349 | 0 | Oid arg2 = PG_GETARG_OID(1); |
350 | |
|
351 | 0 | PG_RETURN_BOOL(arg1 > arg2); |
352 | 0 | } |
353 | | |
354 | | Datum |
355 | | oidlarger(PG_FUNCTION_ARGS) |
356 | 0 | { |
357 | 0 | Oid arg1 = PG_GETARG_OID(0); |
358 | 0 | Oid arg2 = PG_GETARG_OID(1); |
359 | |
|
360 | 0 | PG_RETURN_OID((arg1 > arg2) ? arg1 : arg2); |
361 | 0 | } |
362 | | |
363 | | Datum |
364 | | oidsmaller(PG_FUNCTION_ARGS) |
365 | 0 | { |
366 | 0 | Oid arg1 = PG_GETARG_OID(0); |
367 | 0 | Oid arg2 = PG_GETARG_OID(1); |
368 | |
|
369 | 0 | PG_RETURN_OID((arg1 < arg2) ? arg1 : arg2); |
370 | 0 | } |
371 | | |
372 | | Datum |
373 | | oidvectoreq(PG_FUNCTION_ARGS) |
374 | 0 | { |
375 | 0 | int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); |
376 | |
|
377 | 0 | PG_RETURN_BOOL(cmp == 0); |
378 | 0 | } |
379 | | |
380 | | Datum |
381 | | oidvectorne(PG_FUNCTION_ARGS) |
382 | 0 | { |
383 | 0 | int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); |
384 | |
|
385 | 0 | PG_RETURN_BOOL(cmp != 0); |
386 | 0 | } |
387 | | |
388 | | Datum |
389 | | oidvectorlt(PG_FUNCTION_ARGS) |
390 | 0 | { |
391 | 0 | int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); |
392 | |
|
393 | 0 | PG_RETURN_BOOL(cmp < 0); |
394 | 0 | } |
395 | | |
396 | | Datum |
397 | | oidvectorle(PG_FUNCTION_ARGS) |
398 | 0 | { |
399 | 0 | int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); |
400 | |
|
401 | 0 | PG_RETURN_BOOL(cmp <= 0); |
402 | 0 | } |
403 | | |
404 | | Datum |
405 | | oidvectorge(PG_FUNCTION_ARGS) |
406 | 0 | { |
407 | 0 | int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); |
408 | |
|
409 | 0 | PG_RETURN_BOOL(cmp >= 0); |
410 | 0 | } |
411 | | |
412 | | Datum |
413 | | oidvectorgt(PG_FUNCTION_ARGS) |
414 | 0 | { |
415 | 0 | int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); |
416 | |
|
417 | 0 | PG_RETURN_BOOL(cmp > 0); |
418 | 0 | } |