Age Owner Branch data TLA Line data Source code
1 : : /*------------------------------------------------------------------------
2 : : *
3 : : * regress.c
4 : : * Code for various C-language functions defined as part of the
5 : : * regression tests.
6 : : *
7 : : * This code is released under the terms of the PostgreSQL License.
8 : : *
9 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
10 : : * Portions Copyright (c) 1994, Regents of the University of California
11 : : *
12 : : * src/test/regress/regress.c
13 : : *
14 : : *-------------------------------------------------------------------------
15 : : */
16 : :
17 : : #include "postgres.h"
18 : :
19 : : #include <math.h>
20 : : #include <signal.h>
21 : :
22 : : #include "access/detoast.h"
23 : : #include "access/htup_details.h"
24 : : #include "catalog/catalog.h"
25 : : #include "catalog/namespace.h"
26 : : #include "catalog/pg_operator.h"
27 : : #include "catalog/pg_type.h"
28 : : #include "commands/sequence.h"
29 : : #include "commands/trigger.h"
30 : : #include "common/pg_lzcompress.h"
31 : : #include "executor/executor.h"
32 : : #include "executor/functions.h"
33 : : #include "executor/spi.h"
34 : : #include "funcapi.h"
35 : : #include "mb/pg_wchar.h"
36 : : #include "miscadmin.h"
37 : : #include "nodes/supportnodes.h"
38 : : #include "optimizer/optimizer.h"
39 : : #include "optimizer/plancat.h"
40 : : #include "parser/parse_coerce.h"
41 : : #include "port/atomics.h"
42 : : #include "portability/instr_time.h"
43 : : #include "postmaster/postmaster.h" /* for MAX_BACKENDS */
44 : : #include "storage/spin.h"
45 : : #include "tcop/tcopprot.h"
46 : : #include "utils/array.h"
47 : : #include "utils/builtins.h"
48 : : #include "utils/geo_decls.h"
49 : : #include "utils/memutils.h"
50 : : #include "utils/rel.h"
51 : : #include "utils/typcache.h"
52 : :
53 : : /* define our text domain for translations */
54 : : #undef TEXTDOMAIN
55 : : #define TEXTDOMAIN PG_TEXTDOMAIN("postgresql-regress")
56 : :
57 : : #define EXPECT_TRUE(expr) \
58 : : do { \
59 : : if (!(expr)) \
60 : : elog(ERROR, \
61 : : "%s was unexpectedly false in file \"%s\" line %u", \
62 : : #expr, __FILE__, __LINE__); \
63 : : } while (0)
64 : :
65 : : #define EXPECT_EQ_U32(result_expr, expected_expr) \
66 : : do { \
67 : : uint32 actual_result = (result_expr); \
68 : : uint32 expected_result = (expected_expr); \
69 : : if (actual_result != expected_result) \
70 : : elog(ERROR, \
71 : : "%s yielded %u, expected %s in file \"%s\" line %u", \
72 : : #result_expr, actual_result, #expected_expr, __FILE__, __LINE__); \
73 : : } while (0)
74 : :
75 : : #define EXPECT_EQ_U64(result_expr, expected_expr) \
76 : : do { \
77 : : uint64 actual_result = (result_expr); \
78 : : uint64 expected_result = (expected_expr); \
79 : : if (actual_result != expected_result) \
80 : : elog(ERROR, \
81 : : "%s yielded " UINT64_FORMAT ", expected %s in file \"%s\" line %u", \
82 : : #result_expr, actual_result, #expected_expr, __FILE__, __LINE__); \
83 : : } while (0)
84 : :
85 : : #define LDELIM '('
86 : : #define RDELIM ')'
87 : : #define DELIM ','
88 : :
89 : : static void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
90 : :
430 tgl@sss.pgh.pa.us 91 :CBC 95 : PG_MODULE_MAGIC_EXT(
92 : : .name = "regress",
93 : : .version = PG_VERSION
94 : : );
95 : :
96 : :
97 : : /* return the point where two paths intersect, or NULL if no intersection. */
9322 98 : 9 : PG_FUNCTION_INFO_V1(interpt_pp);
99 : :
100 : : Datum
9435 101 : 3584 : interpt_pp(PG_FUNCTION_ARGS)
102 : : {
103 : 3584 : PATH *p1 = PG_GETARG_PATH_P(0);
104 : 3584 : PATH *p2 = PG_GETARG_PATH_P(1);
105 : : int i,
106 : : j;
107 : : LSEG seg1,
108 : : seg2;
109 : : bool found; /* We've found the intersection */
110 : :
10492 bruce@momjian.us 111 : 3584 : found = false; /* Haven't found it yet */
112 : :
113 [ + + + + ]: 11764 : for (i = 0; i < p1->npts - 1 && !found; i++)
114 : : {
9435 tgl@sss.pgh.pa.us 115 : 8180 : regress_lseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
10492 bruce@momjian.us 116 [ + + + + ]: 25092 : for (j = 0; j < p2->npts - 1 && !found; j++)
117 : : {
118 : 16912 : regress_lseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
9435 tgl@sss.pgh.pa.us 119 [ + + ]: 16912 : if (DatumGetBool(DirectFunctionCall2(lseg_intersect,
120 : : LsegPGetDatum(&seg1),
121 : : LsegPGetDatum(&seg2))))
10492 bruce@momjian.us 122 : 3576 : found = true;
123 : : }
124 : : }
125 : :
9435 tgl@sss.pgh.pa.us 126 [ + + ]: 3584 : if (!found)
127 : 8 : PG_RETURN_NULL();
128 : :
129 : : /*
130 : : * Note: DirectFunctionCall2 will kick out an error if lseg_interpt()
131 : : * returns NULL, but that should be impossible since we know the two
132 : : * segments intersect.
133 : : */
134 : 3576 : PG_RETURN_DATUM(DirectFunctionCall2(lseg_interpt,
135 : : LsegPGetDatum(&seg1),
136 : : LsegPGetDatum(&seg2)));
137 : : }
138 : :
139 : :
140 : : /* like lseg_construct, but assume space already allocated */
141 : : static void
8472 bruce@momjian.us 142 : 25092 : regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
143 : : {
10492 144 : 25092 : lseg->p[0].x = pt1->x;
145 : 25092 : lseg->p[0].y = pt1->y;
146 : 25092 : lseg->p[1].x = pt2->x;
147 : 25092 : lseg->p[1].y = pt2->y;
10917 scrappy@hub.org 148 : 25092 : }
149 : :
9322 tgl@sss.pgh.pa.us 150 : 9 : PG_FUNCTION_INFO_V1(overpaid);
151 : :
152 : : Datum
9490 153 : 24 : overpaid(PG_FUNCTION_ARGS)
154 : : {
8094 155 : 24 : HeapTupleHeader tuple = PG_GETARG_HEAPTUPLEHEADER(0);
156 : : bool isnull;
157 : : int32 salary;
158 : :
9410 159 : 24 : salary = DatumGetInt32(GetAttributeByName(tuple, "salary", &isnull));
9490 160 [ - + ]: 24 : if (isnull)
9490 tgl@sss.pgh.pa.us 161 :UBC 0 : PG_RETURN_NULL();
9490 tgl@sss.pgh.pa.us 162 :CBC 24 : PG_RETURN_BOOL(salary > 699);
163 : : }
164 : :
165 : : /*
166 : : * New type "widget"
167 : : * This used to be "circle", but I added circle to builtins,
168 : : * so needed to make sure the names do not collide. - tgl 97/04/21
169 : : */
170 : :
171 : : typedef struct
172 : : {
173 : : Point center;
174 : : double radius;
175 : : } WIDGET;
176 : :
3349 andres@anarazel.de 177 : 13 : PG_FUNCTION_INFO_V1(widget_in);
178 : 9 : PG_FUNCTION_INFO_V1(widget_out);
179 : :
180 : : #define NARGS 3
181 : :
182 : : Datum
183 : 44 : widget_in(PG_FUNCTION_ARGS)
184 : : {
185 : 44 : char *str = PG_GETARG_CSTRING(0);
186 : : char *p,
187 : : *coord[NARGS];
188 : : int i;
189 : : WIDGET *result;
190 : :
10917 scrappy@hub.org 191 [ + + + + : 252 : for (i = 0, p = str; *p && i < NARGS && *p != RDELIM; p++)
+ + ]
192 : : {
3794 tgl@sss.pgh.pa.us 193 [ + + + + : 208 : if (*p == DELIM || (*p == LDELIM && i == 0))
+ - ]
10917 scrappy@hub.org 194 : 108 : coord[i++] = p + 1;
195 : : }
196 : :
197 : : /*
198 : : * Note: DON'T convert this error to "soft" style (errsave/ereturn). We
199 : : * want this data type to stay permanently in the hard-error world so that
200 : : * it can be used for testing that such cases still work reasonably.
201 : : */
3794 tgl@sss.pgh.pa.us 202 [ + + ]: 44 : if (i < NARGS)
203 [ + - ]: 16 : ereport(ERROR,
204 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
205 : : errmsg("invalid input syntax for type %s: \"%s\"",
206 : : "widget", str)));
207 : :
172 michael@paquier.xyz 208 :GNC 28 : result = palloc_object(WIDGET);
10917 scrappy@hub.org 209 :CBC 28 : result->center.x = atof(coord[0]);
210 : 28 : result->center.y = atof(coord[1]);
211 : 28 : result->radius = atof(coord[2]);
212 : :
3349 andres@anarazel.de 213 : 28 : PG_RETURN_POINTER(result);
214 : : }
215 : :
216 : : Datum
217 : 8 : widget_out(PG_FUNCTION_ARGS)
218 : : {
3300 bruce@momjian.us 219 : 8 : WIDGET *widget = (WIDGET *) PG_GETARG_POINTER(0);
220 : 8 : char *str = psprintf("(%g,%g,%g)",
221 : : widget->center.x, widget->center.y, widget->radius);
222 : :
3349 andres@anarazel.de 223 : 8 : PG_RETURN_CSTRING(str);
224 : : }
225 : :
9322 tgl@sss.pgh.pa.us 226 : 9 : PG_FUNCTION_INFO_V1(pt_in_widget);
227 : :
228 : : Datum
9482 229 : 8 : pt_in_widget(PG_FUNCTION_ARGS)
230 : : {
231 : 8 : Point *point = PG_GETARG_POINT_P(0);
232 : 8 : WIDGET *widget = (WIDGET *) PG_GETARG_POINTER(1);
233 : : float8 distance;
234 : :
2862 tomas.vondra@postgre 235 : 8 : distance = DatumGetFloat8(DirectFunctionCall2(point_distance,
236 : : PointPGetDatum(point),
237 : : PointPGetDatum(&widget->center)));
238 : :
239 : 8 : PG_RETURN_BOOL(distance < widget->radius);
240 : : }
241 : :
3349 andres@anarazel.de 242 : 9 : PG_FUNCTION_INFO_V1(reverse_name);
243 : :
244 : : Datum
245 : 32 : reverse_name(PG_FUNCTION_ARGS)
246 : : {
247 : 32 : char *string = PG_GETARG_CSTRING(0);
248 : : int i;
249 : : int len;
250 : : char *new_string;
251 : :
8343 tgl@sss.pgh.pa.us 252 : 32 : new_string = palloc0(NAMEDATALEN);
10176 bruce@momjian.us 253 [ + - + + ]: 224 : for (i = 0; i < NAMEDATALEN && string[i]; ++i)
254 : : ;
255 [ + - + - ]: 32 : if (i == NAMEDATALEN || !string[i])
10492 256 : 32 : --i;
257 : 32 : len = i;
258 [ + + ]: 224 : for (; i >= 0; --i)
259 : 192 : new_string[len - i] = string[i];
3349 andres@anarazel.de 260 : 32 : PG_RETURN_CSTRING(new_string);
261 : : }
262 : :
3014 tgl@sss.pgh.pa.us 263 : 9 : PG_FUNCTION_INFO_V1(trigger_return_old);
264 : :
265 : : Datum
266 : 60 : trigger_return_old(PG_FUNCTION_ARGS)
267 : : {
268 : 60 : TriggerData *trigdata = (TriggerData *) fcinfo->context;
269 : : HeapTuple tuple;
270 : :
271 [ + - - + ]: 60 : if (!CALLED_AS_TRIGGER(fcinfo))
3014 tgl@sss.pgh.pa.us 272 [ # # ]:UBC 0 : elog(ERROR, "trigger_return_old: not fired by trigger manager");
273 : :
3014 tgl@sss.pgh.pa.us 274 :CBC 60 : tuple = trigdata->tg_trigtuple;
275 : :
276 : 60 : return PointerGetDatum(tuple);
277 : : }
278 : :
279 : :
280 : : /*
281 : : * Type int44 has no real-world use, but the regression tests use it
282 : : * (under the alias "city_budget"). It's a four-element vector of int4's.
283 : : */
284 : :
285 : : /*
286 : : * int44in - converts "num, num, ..." to internal form
287 : : *
288 : : * Note: Fills any missing positions with zeroes.
289 : : */
290 : 9 : PG_FUNCTION_INFO_V1(int44in);
291 : :
292 : : Datum
293 : 8 : int44in(PG_FUNCTION_ARGS)
294 : : {
8682 295 : 8 : char *input_string = PG_GETARG_CSTRING(0);
296 : 8 : int32 *result = (int32 *) palloc(4 * sizeof(int32));
297 : : int i;
298 : :
299 : 8 : i = sscanf(input_string,
300 : : "%d, %d, %d, %d",
301 : : &result[0],
302 : : &result[1],
303 : : &result[2],
304 : : &result[3]);
305 [ + + ]: 12 : while (i < 4)
306 : 4 : result[i++] = 0;
307 : :
308 : 8 : PG_RETURN_POINTER(result);
309 : : }
310 : :
311 : : /*
312 : : * int44out - converts internal form to "num, num, ..."
313 : : */
3014 314 : 13 : PG_FUNCTION_INFO_V1(int44out);
315 : :
316 : : Datum
317 : 16 : int44out(PG_FUNCTION_ARGS)
318 : : {
8682 319 : 16 : int32 *an_array = (int32 *) PG_GETARG_POINTER(0);
3014 320 : 16 : char *result = (char *) palloc(16 * 4);
321 : :
322 : 16 : snprintf(result, 16 * 4, "%d,%d,%d,%d",
323 : : an_array[0],
324 : 16 : an_array[1],
325 : 16 : an_array[2],
326 : 16 : an_array[3]);
327 : :
8682 328 : 16 : PG_RETURN_CSTRING(result);
329 : : }
330 : :
1580 331 : 9 : PG_FUNCTION_INFO_V1(test_canonicalize_path);
332 : : Datum
333 : 110 : test_canonicalize_path(PG_FUNCTION_ARGS)
334 : : {
335 : 110 : char *path = text_to_cstring(PG_GETARG_TEXT_PP(0));
336 : :
337 : 110 : canonicalize_path(path);
338 : 110 : PG_RETURN_TEXT_P(cstring_to_text(path));
339 : : }
340 : :
4715 rhaas@postgresql.org 341 : 9 : PG_FUNCTION_INFO_V1(make_tuple_indirect);
342 : : Datum
343 : 84 : make_tuple_indirect(PG_FUNCTION_ARGS)
344 : : {
345 : 84 : HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
346 : : HeapTupleData tuple;
347 : : int ncolumns;
348 : : Datum *values;
349 : : bool *nulls;
350 : :
351 : : Oid tupType;
352 : : int32 tupTypmod;
353 : : TupleDesc tupdesc;
354 : :
355 : : HeapTuple newtup;
356 : :
357 : : int i;
358 : :
359 : : MemoryContext old_context;
360 : :
361 : : /* Extract type info from the tuple itself */
362 : 84 : tupType = HeapTupleHeaderGetTypeId(rec);
363 : 84 : tupTypmod = HeapTupleHeaderGetTypMod(rec);
364 : 84 : tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
365 : 84 : ncolumns = tupdesc->natts;
366 : :
367 : : /* Build a temporary HeapTuple control structure */
368 : 84 : tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
369 : 84 : ItemPointerSetInvalid(&(tuple.t_self));
370 : 84 : tuple.t_tableOid = InvalidOid;
371 : 84 : tuple.t_data = rec;
372 : :
373 : 84 : values = (Datum *) palloc(ncolumns * sizeof(Datum));
374 : 84 : nulls = (bool *) palloc(ncolumns * sizeof(bool));
375 : :
376 : 84 : heap_deform_tuple(&tuple, tupdesc, values, nulls);
377 : :
378 : 84 : old_context = MemoryContextSwitchTo(TopTransactionContext);
379 : :
380 [ + + ]: 420 : for (i = 0; i < ncolumns; i++)
381 : : {
382 : : varlena *attr;
383 : : varlena *new_attr;
384 : : varatt_indirect redirect_pointer;
385 : :
386 : : /* only work on existing, not-null varlenas */
3205 andres@anarazel.de 387 [ + - ]: 336 : if (TupleDescAttr(tupdesc, i)->attisdropped ||
4715 rhaas@postgresql.org 388 [ + + ]: 336 : nulls[i] ||
712 michael@paquier.xyz 389 [ + + ]: 292 : TupleDescAttr(tupdesc, i)->attlen != -1 ||
390 [ - + ]: 208 : TupleDescAttr(tupdesc, i)->attstorage == TYPSTORAGE_PLAIN)
4715 rhaas@postgresql.org 391 : 128 : continue;
392 : :
108 michael@paquier.xyz 393 :GNC 208 : attr = (varlena *) DatumGetPointer(values[i]);
394 : :
395 : : /* don't recursively indirect */
4715 rhaas@postgresql.org 396 [ - + ]:CBC 208 : if (VARATT_IS_EXTERNAL_INDIRECT(attr))
[ - + - - ]
4715 rhaas@postgresql.org 397 :UBC 0 : continue;
398 : :
399 : : /* copy datum, so it still lives later */
4715 rhaas@postgresql.org 400 [ - + ]:CBC 208 : if (VARATT_IS_EXTERNAL_ONDISK(attr))
[ - + - - ]
2430 rhaas@postgresql.org 401 :UBC 0 : attr = detoast_external_attr(attr);
402 : : else
403 : : {
108 michael@paquier.xyz 404 :GNC 208 : varlena *oldattr = attr;
405 : :
4715 rhaas@postgresql.org 406 [ - + - - :CBC 208 : attr = palloc0(VARSIZE_ANY(oldattr));
- - - - +
+ ]
407 [ - + - - : 208 : memcpy(attr, oldattr, VARSIZE_ANY(oldattr));
- - - - +
+ ]
408 : : }
409 : :
410 : : /* build indirection Datum */
108 michael@paquier.xyz 411 :GNC 208 : new_attr = (varlena *) palloc0(INDIRECT_POINTER_SIZE);
4715 rhaas@postgresql.org 412 :CBC 208 : redirect_pointer.pointer = attr;
413 : 208 : SET_VARTAG_EXTERNAL(new_attr, VARTAG_INDIRECT);
414 : 208 : memcpy(VARDATA_EXTERNAL(new_attr), &redirect_pointer,
415 : : sizeof(redirect_pointer));
416 : :
417 : 208 : values[i] = PointerGetDatum(new_attr);
418 : : }
419 : :
420 : 84 : newtup = heap_form_tuple(tupdesc, values, nulls);
421 : 84 : pfree(values);
422 : 84 : pfree(nulls);
423 [ + - ]: 84 : ReleaseTupleDesc(tupdesc);
424 : :
425 : 84 : MemoryContextSwitchTo(old_context);
426 : :
427 : : /*
428 : : * We intentionally don't use PG_RETURN_HEAPTUPLEHEADER here, because that
429 : : * would cause the indirect toast pointers to be flattened out of the
430 : : * tuple immediately, rendering subsequent testing irrelevant. So just
431 : : * return the HeapTupleHeader pointer as-is. This violates the general
432 : : * rule that composite Datums shouldn't contain toast pointers, but so
433 : : * long as the regression test scripts don't insert the result of this
434 : : * function into a container type (record, array, etc) it should be OK.
435 : : */
4412 tgl@sss.pgh.pa.us 436 : 84 : PG_RETURN_POINTER(newtup->t_data);
437 : : }
438 : :
565 noah@leadboat.com 439 : 2 : PG_FUNCTION_INFO_V1(get_environ);
440 : :
441 : : Datum
442 : 1 : get_environ(PG_FUNCTION_ARGS)
443 : : {
444 : : #if !defined(WIN32)
445 : : extern char **environ;
446 : : #endif
447 : 1 : int nvals = 0;
448 : : ArrayType *result;
449 : : Datum *env;
450 : :
451 [ + + ]: 146 : for (char **s = environ; *s; s++)
452 : 145 : nvals++;
453 : :
454 : 1 : env = palloc(nvals * sizeof(Datum));
455 : :
456 [ + + ]: 146 : for (int i = 0; i < nvals; i++)
457 : 145 : env[i] = CStringGetTextDatum(environ[i]);
458 : :
459 : 1 : result = construct_array_builtin(env, nvals, TEXTOID);
460 : :
461 : 1 : PG_RETURN_POINTER(result);
462 : : }
463 : :
1977 tgl@sss.pgh.pa.us 464 : 2 : PG_FUNCTION_INFO_V1(regress_setenv);
465 : :
466 : : Datum
467 : 1 : regress_setenv(PG_FUNCTION_ARGS)
468 : : {
469 : 1 : char *envvar = text_to_cstring(PG_GETARG_TEXT_PP(0));
470 : 1 : char *envval = text_to_cstring(PG_GETARG_TEXT_PP(1));
471 : :
4330 noah@leadboat.com 472 [ - + ]: 1 : if (!superuser())
4330 noah@leadboat.com 473 [ # # ]:UBC 0 : elog(ERROR, "must be superuser to change environment variables");
474 : :
1977 tgl@sss.pgh.pa.us 475 [ - + ]:CBC 1 : if (setenv(envvar, envval, 1) != 0)
4330 noah@leadboat.com 476 [ # # ]:UBC 0 : elog(ERROR, "could not set environment variable: %m");
477 : :
4330 noah@leadboat.com 478 :CBC 1 : PG_RETURN_VOID();
479 : : }
480 : :
481 : : /* Sleep until no process has a given PID. */
482 : 5 : PG_FUNCTION_INFO_V1(wait_pid);
483 : :
484 : : Datum
485 : 2 : wait_pid(PG_FUNCTION_ARGS)
486 : : {
487 : 2 : int pid = PG_GETARG_INT32(0);
488 : :
489 [ - + ]: 2 : if (!superuser())
4330 noah@leadboat.com 490 [ # # ]:UBC 0 : elog(ERROR, "must be superuser to check PID liveness");
491 : :
4330 noah@leadboat.com 492 [ + + ]:CBC 7 : while (kill(pid, 0) == 0)
493 : : {
4102 494 [ - + ]: 5 : CHECK_FOR_INTERRUPTS();
4330 495 : 5 : pg_usleep(50000);
496 : : }
497 : :
498 [ - + ]: 2 : if (errno != ESRCH)
4330 noah@leadboat.com 499 [ # # ]:UBC 0 : elog(ERROR, "could not check PID %d liveness: %m", pid);
500 : :
4330 noah@leadboat.com 501 :CBC 2 : PG_RETURN_VOID();
502 : : }
503 : :
504 : : static void
4265 andres@anarazel.de 505 : 4 : test_atomic_flag(void)
506 : : {
507 : : pg_atomic_flag flag;
508 : :
509 : 4 : pg_atomic_init_flag(&flag);
2429 noah@leadboat.com 510 [ - + - - ]: 4 : EXPECT_TRUE(pg_atomic_unlocked_test_flag(&flag));
511 [ - + - - ]: 4 : EXPECT_TRUE(pg_atomic_test_set_flag(&flag));
512 [ - + - - ]: 4 : EXPECT_TRUE(!pg_atomic_unlocked_test_flag(&flag));
513 [ - + - - ]: 4 : EXPECT_TRUE(!pg_atomic_test_set_flag(&flag));
4265 andres@anarazel.de 514 : 4 : pg_atomic_clear_flag(&flag);
2429 noah@leadboat.com 515 [ - + - - ]: 4 : EXPECT_TRUE(pg_atomic_unlocked_test_flag(&flag));
516 [ - + - - ]: 4 : EXPECT_TRUE(pg_atomic_test_set_flag(&flag));
4265 andres@anarazel.de 517 : 4 : pg_atomic_clear_flag(&flag);
518 : 4 : }
519 : :
520 : : static void
521 : 4 : test_atomic_uint32(void)
522 : : {
523 : : pg_atomic_uint32 var;
524 : : uint32 expected;
525 : : int i;
526 : :
527 : 4 : pg_atomic_init_u32(&var, 0);
2429 noah@leadboat.com 528 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_read_u32(&var), 0);
4265 andres@anarazel.de 529 : 4 : pg_atomic_write_u32(&var, 3);
2429 noah@leadboat.com 530 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_read_u32(&var), 3);
531 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_add_u32(&var, pg_atomic_read_u32(&var) - 2),
532 : : 3);
533 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_sub_u32(&var, 1), 4);
534 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_sub_fetch_u32(&var, 3), 0);
535 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_add_fetch_u32(&var, 10), 10);
536 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_exchange_u32(&var, 5), 10);
537 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_exchange_u32(&var, 0), 5);
538 : :
539 : : /* test around numerical limits */
540 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_add_u32(&var, INT_MAX), 0);
541 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_add_u32(&var, INT_MAX), INT_MAX);
2451 542 : 4 : pg_atomic_fetch_add_u32(&var, 2); /* wrap to 0 */
2429 543 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_add_u32(&var, PG_INT16_MAX), 0);
544 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_add_u32(&var, PG_INT16_MAX + 1),
545 : : PG_INT16_MAX);
546 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_add_u32(&var, PG_INT16_MIN),
547 : : 2 * PG_INT16_MAX + 1);
548 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_add_u32(&var, PG_INT16_MIN - 1),
549 : : PG_INT16_MAX);
4025 bruce@momjian.us 550 : 4 : pg_atomic_fetch_add_u32(&var, 1); /* top up to UINT_MAX */
2429 noah@leadboat.com 551 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_read_u32(&var), UINT_MAX);
552 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_sub_u32(&var, INT_MAX), UINT_MAX);
553 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_read_u32(&var), (uint32) INT_MAX + 1);
554 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_sub_fetch_u32(&var, INT_MAX), 1);
4265 andres@anarazel.de 555 : 4 : pg_atomic_sub_fetch_u32(&var, 1);
2057 noah@leadboat.com 556 : 4 : expected = PG_INT16_MAX;
557 [ - + - - ]: 4 : EXPECT_TRUE(!pg_atomic_compare_exchange_u32(&var, &expected, 1));
558 : 4 : expected = PG_INT16_MAX + 1;
559 [ - + - - ]: 4 : EXPECT_TRUE(!pg_atomic_compare_exchange_u32(&var, &expected, 1));
560 : 4 : expected = PG_INT16_MIN;
561 [ - + - - ]: 4 : EXPECT_TRUE(!pg_atomic_compare_exchange_u32(&var, &expected, 1));
562 : 4 : expected = PG_INT16_MIN - 1;
563 [ - + - - ]: 4 : EXPECT_TRUE(!pg_atomic_compare_exchange_u32(&var, &expected, 1));
564 : :
565 : : /* fail exchange because of old expected */
4265 andres@anarazel.de 566 : 4 : expected = 10;
2429 noah@leadboat.com 567 [ - + - - ]: 4 : EXPECT_TRUE(!pg_atomic_compare_exchange_u32(&var, &expected, 1));
568 : :
569 : : /* CAS is allowed to fail due to interrupts, try a couple of times */
4265 andres@anarazel.de 570 [ + - ]: 8 : for (i = 0; i < 1000; i++)
571 : : {
572 : 8 : expected = 0;
573 [ + + ]: 8 : if (!pg_atomic_compare_exchange_u32(&var, &expected, 1))
574 : 4 : break;
575 : : }
576 [ - + ]: 4 : if (i == 1000)
4265 andres@anarazel.de 577 [ # # ]:UBC 0 : elog(ERROR, "atomic_compare_exchange_u32() never succeeded");
2429 noah@leadboat.com 578 [ - + - - ]:CBC 4 : EXPECT_EQ_U32(pg_atomic_read_u32(&var), 1);
4265 andres@anarazel.de 579 : 4 : pg_atomic_write_u32(&var, 0);
580 : :
581 : : /* try setting flagbits */
2429 noah@leadboat.com 582 [ - + - - ]: 4 : EXPECT_TRUE(!(pg_atomic_fetch_or_u32(&var, 1) & 1));
583 [ - + - - ]: 4 : EXPECT_TRUE(pg_atomic_fetch_or_u32(&var, 2) & 1);
584 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_read_u32(&var), 3);
585 : : /* try clearing flagbits */
586 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_and_u32(&var, ~2) & 3, 3);
587 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_and_u32(&var, ~1), 1);
588 : : /* no bits set anymore */
589 [ - + - - ]: 4 : EXPECT_EQ_U32(pg_atomic_fetch_and_u32(&var, ~0), 0);
4265 andres@anarazel.de 590 : 4 : }
591 : :
592 : : static void
593 : 4 : test_atomic_uint64(void)
594 : : {
595 : : pg_atomic_uint64 var;
596 : : uint64 expected;
597 : : int i;
598 : :
599 : 4 : pg_atomic_init_u64(&var, 0);
2429 noah@leadboat.com 600 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_read_u64(&var), 0);
4265 andres@anarazel.de 601 : 4 : pg_atomic_write_u64(&var, 3);
2429 noah@leadboat.com 602 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_read_u64(&var), 3);
603 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_fetch_add_u64(&var, pg_atomic_read_u64(&var) - 2),
604 : : 3);
605 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_fetch_sub_u64(&var, 1), 4);
606 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_sub_fetch_u64(&var, 3), 0);
607 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_add_fetch_u64(&var, 10), 10);
608 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_exchange_u64(&var, 5), 10);
609 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_exchange_u64(&var, 0), 5);
610 : :
611 : : /* fail exchange because of old expected */
4265 andres@anarazel.de 612 : 4 : expected = 10;
2429 noah@leadboat.com 613 [ - + - - ]: 4 : EXPECT_TRUE(!pg_atomic_compare_exchange_u64(&var, &expected, 1));
614 : :
615 : : /* CAS is allowed to fail due to interrupts, try a couple of times */
4265 andres@anarazel.de 616 [ + - ]: 8 : for (i = 0; i < 100; i++)
617 : : {
618 : 8 : expected = 0;
619 [ + + ]: 8 : if (!pg_atomic_compare_exchange_u64(&var, &expected, 1))
620 : 4 : break;
621 : : }
622 [ - + ]: 4 : if (i == 100)
4265 andres@anarazel.de 623 [ # # ]:UBC 0 : elog(ERROR, "atomic_compare_exchange_u64() never succeeded");
2429 noah@leadboat.com 624 [ - + - - ]:CBC 4 : EXPECT_EQ_U64(pg_atomic_read_u64(&var), 1);
625 : :
4265 andres@anarazel.de 626 : 4 : pg_atomic_write_u64(&var, 0);
627 : :
628 : : /* try setting flagbits */
2429 noah@leadboat.com 629 [ - + - - ]: 4 : EXPECT_TRUE(!(pg_atomic_fetch_or_u64(&var, 1) & 1));
630 [ - + - - ]: 4 : EXPECT_TRUE(pg_atomic_fetch_or_u64(&var, 2) & 1);
631 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_read_u64(&var), 3);
632 : : /* try clearing flagbits */
633 [ - + - - ]: 4 : EXPECT_EQ_U64((pg_atomic_fetch_and_u64(&var, ~2) & 3), 3);
634 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_fetch_and_u64(&var, ~1), 1);
635 : : /* no bits set anymore */
636 [ - + - - ]: 4 : EXPECT_EQ_U64(pg_atomic_fetch_and_u64(&var, ~0), 0);
4265 andres@anarazel.de 637 : 4 : }
638 : :
639 : : /*
640 : : * Perform, fairly minimal, testing of the spinlock implementation.
641 : : *
642 : : * It's likely worth expanding these to actually test concurrency etc, but
643 : : * having some regularly run tests is better than none.
644 : : */
645 : : static void
2182 646 : 4 : test_spinlock(void)
647 : : {
648 : : /*
649 : : * Basic tests for spinlocks, as well as the underlying operations.
650 : : *
651 : : * We embed the spinlock in a struct with other members to test that the
652 : : * spinlock operations don't perform too wide writes.
653 : : */
654 : : {
655 : : struct test_lock_struct
656 : : {
657 : : char data_before[4];
658 : : slock_t lock;
659 : : char data_after[4];
660 : : } struct_w_lock;
661 : :
662 : 4 : memcpy(struct_w_lock.data_before, "abcd", 4);
663 : 4 : memcpy(struct_w_lock.data_after, "ef12", 4);
664 : :
665 : : /* test basic operations via the SpinLock* API */
666 : 4 : SpinLockInit(&struct_w_lock.lock);
667 [ - + ]: 4 : SpinLockAcquire(&struct_w_lock.lock);
668 : 4 : SpinLockRelease(&struct_w_lock.lock);
669 : :
670 : : /* test basic operations via underlying S_* API */
671 : 4 : S_INIT_LOCK(&struct_w_lock.lock);
672 [ - + ]: 4 : S_LOCK(&struct_w_lock.lock);
673 : 4 : S_UNLOCK(&struct_w_lock.lock);
674 : :
675 : : /* and that "contended" acquisition works */
676 : 4 : s_lock(&struct_w_lock.lock, "testfile", 17, "testfunc");
677 : 4 : S_UNLOCK(&struct_w_lock.lock);
678 : :
679 : : /*
680 : : * Check, using TAS directly, that a single spin cycle doesn't block
681 : : * when acquiring an already acquired lock.
682 : : */
683 : : #ifdef TAS
684 [ - + ]: 4 : S_LOCK(&struct_w_lock.lock);
685 : :
686 [ - + ]: 4 : if (!TAS(&struct_w_lock.lock))
2182 andres@anarazel.de 687 [ # # ]:UBC 0 : elog(ERROR, "acquired already held spinlock");
688 : :
689 : : #ifdef TAS_SPIN
2182 andres@anarazel.de 690 [ - + - - ]:CBC 4 : if (!TAS_SPIN(&struct_w_lock.lock))
2182 andres@anarazel.de 691 [ # # ]:UBC 0 : elog(ERROR, "acquired already held spinlock");
692 : : #endif /* defined(TAS_SPIN) */
693 : :
2182 andres@anarazel.de 694 :CBC 4 : S_UNLOCK(&struct_w_lock.lock);
695 : : #endif /* defined(TAS) */
696 : :
697 : : /*
698 : : * Verify that after all of this the non-lock contents are still
699 : : * correct.
700 : : */
701 [ - + ]: 4 : if (memcmp(struct_w_lock.data_before, "abcd", 4) != 0)
2182 andres@anarazel.de 702 [ # # ]:UBC 0 : elog(ERROR, "padding before spinlock modified");
2182 andres@anarazel.de 703 [ - + ]:CBC 4 : if (memcmp(struct_w_lock.data_after, "ef12", 4) != 0)
2182 andres@anarazel.de 704 [ # # ]:UBC 0 : elog(ERROR, "padding after spinlock modified");
705 : : }
2182 andres@anarazel.de 706 :CBC 4 : }
707 : :
4265 708 : 9 : PG_FUNCTION_INFO_V1(test_atomic_ops);
709 : : Datum
710 : 4 : test_atomic_ops(PG_FUNCTION_ARGS)
711 : : {
712 : 4 : test_atomic_flag();
713 : :
714 : 4 : test_atomic_uint32();
715 : :
716 : 4 : test_atomic_uint64();
717 : :
718 : : /*
719 : : * Arguably this shouldn't be tested as part of this function, but it's
720 : : * closely enough related that that seems ok for now.
721 : : */
2182 722 : 4 : test_spinlock();
723 : :
4265 724 : 4 : PG_RETURN_BOOL(true);
725 : : }
726 : :
3179 rhaas@postgresql.org 727 : 5 : PG_FUNCTION_INFO_V1(test_fdw_handler);
728 : : Datum
3179 rhaas@postgresql.org 729 :UBC 0 : test_fdw_handler(PG_FUNCTION_ARGS)
730 : : {
3014 tgl@sss.pgh.pa.us 731 [ # # ]: 0 : elog(ERROR, "test_fdw_handler is not implemented");
732 : : PG_RETURN_NULL();
733 : : }
734 : :
85 jdavis@postgresql.or 735 :GNC 13 : PG_FUNCTION_INFO_V1(test_fdw_connection);
736 : : Datum
737 : 8 : test_fdw_connection(PG_FUNCTION_ARGS)
738 : : {
739 : 8 : PG_RETURN_TEXT_P(cstring_to_text("dbname=regress_doesnotexist user=doesnotexist password=secret"));
740 : : }
741 : :
408 noah@leadboat.com 742 :CBC 9 : PG_FUNCTION_INFO_V1(is_catalog_text_unique_index_oid);
743 : : Datum
744 : 888 : is_catalog_text_unique_index_oid(PG_FUNCTION_ARGS)
745 : : {
295 peter@eisentraut.org 746 :GNC 888 : return BoolGetDatum(IsCatalogTextUniqueIndexOid(PG_GETARG_OID(0)));
747 : : }
748 : :
2667 tgl@sss.pgh.pa.us 749 :CBC 9 : PG_FUNCTION_INFO_V1(test_support_func);
750 : : Datum
751 : 60 : test_support_func(PG_FUNCTION_ARGS)
752 : : {
753 : 60 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
754 : 60 : Node *ret = NULL;
755 : :
756 [ + + ]: 60 : if (IsA(rawreq, SupportRequestSelectivity))
757 : : {
758 : : /*
759 : : * Assume that the target is int4eq; that's safe as long as we don't
760 : : * attach this to any other boolean-returning function.
761 : : */
762 : 5 : SupportRequestSelectivity *req = (SupportRequestSelectivity *) rawreq;
763 : : Selectivity s1;
764 : :
765 [ - + ]: 5 : if (req->is_join)
2667 tgl@sss.pgh.pa.us 766 :UBC 0 : s1 = join_selectivity(req->root, Int4EqualOperator,
767 : : req->args,
768 : : req->inputcollid,
769 : : req->jointype,
2667 tgl@sss.pgh.pa.us 770 :EUB : req->sjinfo);
771 : : else
2667 tgl@sss.pgh.pa.us 772 :CBC 5 : s1 = restriction_selectivity(req->root, Int4EqualOperator,
773 : : req->args,
774 : : req->inputcollid,
775 : : req->varRelid);
776 : :
777 : 5 : req->selectivity = s1;
778 : 5 : ret = (Node *) req;
779 : : }
780 : :
781 [ + + ]: 60 : if (IsA(rawreq, SupportRequestCost))
782 : : {
783 : : /* Provide some generic estimate */
784 : 15 : SupportRequestCost *req = (SupportRequestCost *) rawreq;
785 : :
786 : 15 : req->startup = 0;
787 : 15 : req->per_tuple = 2 * cpu_operator_cost;
788 : 15 : ret = (Node *) req;
789 : : }
790 : :
791 [ + + ]: 60 : if (IsA(rawreq, SupportRequestRows))
792 : : {
793 : : /*
794 : : * Assume that the target is generate_series_int4; that's safe as long
795 : : * as we don't attach this to any other set-returning function.
796 : : */
797 : 10 : SupportRequestRows *req = (SupportRequestRows *) rawreq;
798 : :
799 [ + - + - ]: 10 : if (req->node && IsA(req->node, FuncExpr)) /* be paranoid */
800 : : {
801 : 10 : List *args = ((FuncExpr *) req->node)->args;
802 : 10 : Node *arg1 = linitial(args);
803 : 10 : Node *arg2 = lsecond(args);
804 : :
805 [ + - ]: 10 : if (IsA(arg1, Const) &&
806 [ + - ]: 10 : !((Const *) arg1)->constisnull &&
807 [ + - ]: 10 : IsA(arg2, Const) &&
808 [ + - ]: 10 : !((Const *) arg2)->constisnull)
809 : : {
810 : 10 : int32 val1 = DatumGetInt32(((Const *) arg1)->constvalue);
811 : 10 : int32 val2 = DatumGetInt32(((Const *) arg2)->constvalue);
812 : :
813 : 10 : req->rows = val2 - val1 + 1;
814 : 10 : ret = (Node *) req;
815 : : }
816 : : }
817 : : }
818 : :
819 : 60 : PG_RETURN_POINTER(ret);
820 : : }
821 : :
189 tgl@sss.pgh.pa.us 822 :GNC 9 : PG_FUNCTION_INFO_V1(test_inline_in_from_support_func);
823 : : Datum
824 : 40 : test_inline_in_from_support_func(PG_FUNCTION_ARGS)
825 : : {
826 : 40 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
827 : :
828 [ + + ]: 40 : if (IsA(rawreq, SupportRequestInlineInFrom))
829 : : {
830 : : /*
831 : : * Assume that the target is foo_from_bar; that's safe as long as we
832 : : * don't attach this to any other function.
833 : : */
834 : 20 : SupportRequestInlineInFrom *req = (SupportRequestInlineInFrom *) rawreq;
835 : : StringInfoData sql;
836 : 20 : RangeTblFunction *rtfunc = req->rtfunc;
837 : 20 : FuncExpr *expr = (FuncExpr *) rtfunc->funcexpr;
838 : : Node *node;
839 : : Const *c;
840 : : char *colname;
841 : : char *tablename;
842 : : SQLFunctionParseInfoPtr pinfo;
843 : : List *raw_parsetree_list;
844 : : List *querytree_list;
845 : : Query *querytree;
846 : :
847 [ - + ]: 20 : if (list_length(expr->args) != 3)
848 : : {
189 tgl@sss.pgh.pa.us 849 [ # # ]:UNC 0 : ereport(WARNING, (errmsg("test_inline_in_from_support_func called with %d args but expected 3", list_length(expr->args))));
850 : 0 : PG_RETURN_POINTER(NULL);
851 : : }
852 : :
853 : : /* Get colname */
189 tgl@sss.pgh.pa.us 854 :GNC 20 : node = linitial(expr->args);
855 [ - + ]: 20 : if (!IsA(node, Const))
856 : : {
189 tgl@sss.pgh.pa.us 857 [ # # ]:UNC 0 : ereport(WARNING, (errmsg("test_inline_in_from_support_func called with non-Const parameters")));
858 : 0 : PG_RETURN_POINTER(NULL);
859 : : }
860 : :
189 tgl@sss.pgh.pa.us 861 :GNC 20 : c = (Const *) node;
862 [ + - - + ]: 20 : if (c->consttype != TEXTOID || c->constisnull)
863 : : {
189 tgl@sss.pgh.pa.us 864 [ # # ]:UNC 0 : ereport(WARNING, (errmsg("test_inline_in_from_support_func called with non-TEXT parameters")));
865 : 0 : PG_RETURN_POINTER(NULL);
866 : : }
189 tgl@sss.pgh.pa.us 867 :GNC 20 : colname = TextDatumGetCString(c->constvalue);
868 : :
869 : : /* Get tablename */
870 : 20 : node = lsecond(expr->args);
871 [ - + ]: 20 : if (!IsA(node, Const))
872 : : {
189 tgl@sss.pgh.pa.us 873 [ # # ]:UNC 0 : ereport(WARNING, (errmsg("test_inline_in_from_support_func called with non-Const parameters")));
874 : 0 : PG_RETURN_POINTER(NULL);
875 : : }
876 : :
189 tgl@sss.pgh.pa.us 877 :GNC 20 : c = (Const *) node;
878 [ + - - + ]: 20 : if (c->consttype != TEXTOID || c->constisnull)
879 : : {
189 tgl@sss.pgh.pa.us 880 [ # # ]:UNC 0 : ereport(WARNING, (errmsg("test_inline_in_from_support_func called with non-TEXT parameters")));
881 : 0 : PG_RETURN_POINTER(NULL);
882 : : }
189 tgl@sss.pgh.pa.us 883 :GNC 20 : tablename = TextDatumGetCString(c->constvalue);
884 : :
885 : : /* Begin constructing replacement SELECT query. */
886 : 20 : initStringInfo(&sql);
887 : 20 : appendStringInfo(&sql, "SELECT %s::text FROM %s",
888 : : quote_identifier(colname),
889 : : quote_identifier(tablename));
890 : :
891 : : /* Add filter expression if present. */
892 : 20 : node = lthird(expr->args);
893 [ + - + + ]: 20 : if (!(IsA(node, Const) && ((Const *) node)->constisnull))
894 : : {
895 : : /*
896 : : * We only filter if $3 is not constant-NULL. This is not a very
897 : : * exact implementation of the PL/pgSQL original, but it's close
898 : : * enough for demonstration purposes.
899 : : */
900 : 10 : appendStringInfo(&sql, " WHERE %s::text = $3",
901 : : quote_identifier(colname));
902 : : }
903 : :
904 : : /* Build a SQLFunctionParseInfo with the parameters of my function. */
905 : 20 : pinfo = prepare_sql_fn_parse_info(req->proc,
906 : : (Node *) expr,
907 : : expr->inputcollid);
908 : :
909 : : /* Parse the generated SQL. */
910 : 20 : raw_parsetree_list = pg_parse_query(sql.data);
911 [ - + ]: 20 : if (list_length(raw_parsetree_list) != 1)
912 : : {
189 tgl@sss.pgh.pa.us 913 [ # # ]:UNC 0 : ereport(WARNING, (errmsg("test_inline_in_from_support_func parsed to more than one node")));
914 : 0 : PG_RETURN_POINTER(NULL);
915 : : }
916 : :
917 : : /* Analyze the parse tree as if it were a SQL-language body. */
189 tgl@sss.pgh.pa.us 918 :GNC 20 : querytree_list = pg_analyze_and_rewrite_withcb(linitial(raw_parsetree_list),
919 : 20 : sql.data,
920 : : (ParserSetupHook) sql_fn_parser_setup,
921 : : pinfo, NULL);
922 [ - + ]: 20 : if (list_length(querytree_list) != 1)
923 : : {
189 tgl@sss.pgh.pa.us 924 [ # # ]:UNC 0 : ereport(WARNING, (errmsg("test_inline_in_from_support_func rewrote to more than one node")));
925 : 0 : PG_RETURN_POINTER(NULL);
926 : : }
927 : :
189 tgl@sss.pgh.pa.us 928 :GNC 20 : querytree = linitial(querytree_list);
929 [ - + ]: 20 : if (!IsA(querytree, Query))
930 : : {
189 tgl@sss.pgh.pa.us 931 [ # # ]:UNC 0 : ereport(WARNING, (errmsg("test_inline_in_from_support_func didn't parse to a Query")));
932 : 0 : PG_RETURN_POINTER(NULL);
933 : : }
934 : :
189 tgl@sss.pgh.pa.us 935 :GNC 20 : PG_RETURN_POINTER(querytree);
936 : : }
937 : :
938 : 20 : PG_RETURN_POINTER(NULL);
939 : : }
940 : :
2252 akorotkov@postgresql 941 :CBC 5 : PG_FUNCTION_INFO_V1(test_opclass_options_func);
942 : : Datum
2252 akorotkov@postgresql 943 :UBC 0 : test_opclass_options_func(PG_FUNCTION_ARGS)
944 : : {
945 : 0 : PG_RETURN_NULL();
946 : : }
947 : :
948 : : /* one-time tests for encoding infrastructure */
474 andres@anarazel.de 949 :CBC 9 : PG_FUNCTION_INFO_V1(test_enc_setup);
950 : : Datum
951 : 4 : test_enc_setup(PG_FUNCTION_ARGS)
952 : : {
953 : : /* Test pg_encoding_set_invalid() */
954 [ + + ]: 172 : for (int i = 0; i < _PG_LAST_ENCODING_; i++)
955 : : {
956 : : char buf[2],
957 : : bigbuf[16];
958 : : int len,
959 : : mblen,
960 : : valid;
961 : :
52 tmunro@postgresql.or 962 [ + - + - :GNC 168 : if (!PG_VALID_ENCODING(i))
+ + ]
963 : 116 : continue;
474 andres@anarazel.de 964 [ + + ]:CBC 164 : if (pg_encoding_max_length(i) == 1)
965 : 112 : continue;
966 : 52 : pg_encoding_set_invalid(i, buf);
967 : 52 : len = strnlen(buf, 2);
968 [ - + ]: 52 : if (len != 2)
474 andres@anarazel.de 969 [ # # ]:UBC 0 : elog(WARNING,
970 : : "official invalid string for encoding \"%s\" has length %d",
971 : : pg_enc2name_tbl[i].name, len);
474 andres@anarazel.de 972 :CBC 52 : mblen = pg_encoding_mblen(i, buf);
973 [ - + ]: 52 : if (mblen != 2)
474 andres@anarazel.de 974 [ # # ]:UBC 0 : elog(WARNING,
975 : : "official invalid string for encoding \"%s\" has mblen %d",
976 : : pg_enc2name_tbl[i].name, mblen);
474 andres@anarazel.de 977 :CBC 52 : valid = pg_encoding_verifymbstr(i, buf, len);
978 [ - + ]: 52 : if (valid != 0)
474 andres@anarazel.de 979 [ # # ]:UBC 0 : elog(WARNING,
980 : : "official invalid string for encoding \"%s\" has valid prefix of length %d",
981 : : pg_enc2name_tbl[i].name, valid);
474 andres@anarazel.de 982 :CBC 52 : valid = pg_encoding_verifymbstr(i, buf, 1);
983 [ - + ]: 52 : if (valid != 0)
474 andres@anarazel.de 984 [ # # ]:UBC 0 : elog(WARNING,
985 : : "first byte of official invalid string for encoding \"%s\" has valid prefix of length %d",
986 : : pg_enc2name_tbl[i].name, valid);
474 andres@anarazel.de 987 :CBC 52 : memset(bigbuf, ' ', sizeof(bigbuf));
988 : 52 : bigbuf[0] = buf[0];
989 : 52 : bigbuf[1] = buf[1];
990 : 52 : valid = pg_encoding_verifymbstr(i, bigbuf, sizeof(bigbuf));
991 [ - + ]: 52 : if (valid != 0)
474 andres@anarazel.de 992 [ # # ]:UBC 0 : elog(WARNING,
993 : : "trailing data changed official invalid string for encoding \"%s\" to have valid prefix of length %d",
994 : : pg_enc2name_tbl[i].name, valid);
995 : : }
996 : :
474 andres@anarazel.de 997 :CBC 4 : PG_RETURN_VOID();
998 : : }
999 : :
1000 : : /*
1001 : : * Call an encoding conversion or verification function.
1002 : : *
1003 : : * Arguments:
1004 : : * string bytea -- string to convert
1005 : : * src_enc name -- source encoding
1006 : : * dest_enc name -- destination encoding
1007 : : * noError bool -- if set, don't ereport() on invalid or untranslatable
1008 : : * input
1009 : : *
1010 : : * Result is a tuple with two attributes:
1011 : : * int4 -- number of input bytes successfully converted
1012 : : * bytea -- converted string
1013 : : */
1885 heikki.linnakangas@i 1014 : 9 : PG_FUNCTION_INFO_V1(test_enc_conversion);
1015 : : Datum
1016 : 5152 : test_enc_conversion(PG_FUNCTION_ARGS)
1017 : : {
1018 : 5152 : bytea *string = PG_GETARG_BYTEA_PP(0);
1019 : 5152 : char *src_encoding_name = NameStr(*PG_GETARG_NAME(1));
1020 : 5152 : int src_encoding = pg_char_to_encoding(src_encoding_name);
1021 : 5152 : char *dest_encoding_name = NameStr(*PG_GETARG_NAME(2));
1022 : 5152 : int dest_encoding = pg_char_to_encoding(dest_encoding_name);
1023 : 5152 : bool noError = PG_GETARG_BOOL(3);
1024 : : TupleDesc tupdesc;
1025 : : char *src;
1026 : : char *dst;
1027 : : bytea *retval;
1028 : : Size srclen;
1029 : : Size dstsize;
1030 : : Oid proc;
1031 : : int convertedbytes;
1032 : : int dstlen;
1033 : : Datum values[2];
1414 peter@eisentraut.org 1034 : 5152 : bool nulls[2] = {0};
1035 : : HeapTuple tuple;
1036 : :
1885 heikki.linnakangas@i 1037 [ - + ]: 5152 : if (src_encoding < 0)
1885 heikki.linnakangas@i 1038 [ # # ]:UBC 0 : ereport(ERROR,
1039 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1040 : : errmsg("invalid source encoding name \"%s\"",
1041 : : src_encoding_name)));
1885 heikki.linnakangas@i 1042 [ - + ]:CBC 5152 : if (dest_encoding < 0)
1885 heikki.linnakangas@i 1043 [ # # ]:UBC 0 : ereport(ERROR,
1044 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1045 : : errmsg("invalid destination encoding name \"%s\"",
1046 : : dest_encoding_name)));
1047 : :
1048 : : /* Build a tuple descriptor for our result type */
1885 heikki.linnakangas@i 1049 [ - + ]:CBC 5152 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1885 heikki.linnakangas@i 1050 [ # # ]:UBC 0 : elog(ERROR, "return type must be a row type");
1885 heikki.linnakangas@i 1051 :CBC 5152 : tupdesc = BlessTupleDesc(tupdesc);
1052 : :
1053 [ - + - - : 5152 : srclen = VARSIZE_ANY_EXHDR(string);
- - - - +
+ ]
1054 [ + + ]: 5152 : src = VARDATA_ANY(string);
1055 : :
1056 [ + + ]: 5152 : if (src_encoding == dest_encoding)
1057 : : {
1058 : : /* just check that the source string is valid */
1059 : : int oklen;
1060 : :
1061 : 2572 : oklen = pg_encoding_verifymbstr(src_encoding, src, srclen);
1062 : :
1063 [ + + ]: 2572 : if (oklen == srclen)
1064 : : {
1065 : 652 : convertedbytes = oklen;
1066 : 652 : retval = string;
1067 : : }
1068 [ + + ]: 1920 : else if (!noError)
1069 : : {
1070 : 960 : report_invalid_encoding(src_encoding, src + oklen, srclen - oklen);
1071 : : }
1072 : : else
1073 : : {
1074 : : /*
1075 : : * build bytea data type structure.
1076 : : */
1077 [ - + ]: 960 : Assert(oklen < srclen);
1078 : 960 : convertedbytes = oklen;
1079 : 960 : retval = (bytea *) palloc(oklen + VARHDRSZ);
1080 : 960 : SET_VARSIZE(retval, oklen + VARHDRSZ);
1081 : 960 : memcpy(VARDATA(retval), src, oklen);
1082 : : }
1083 : : }
1084 : : else
1085 : : {
1086 : 2580 : proc = FindDefaultConversionProc(src_encoding, dest_encoding);
1087 [ - + ]: 2580 : if (!OidIsValid(proc))
1885 heikki.linnakangas@i 1088 [ # # ]:UBC 0 : ereport(ERROR,
1089 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
1090 : : errmsg("default conversion function for encoding \"%s\" to \"%s\" does not exist",
1091 : : pg_encoding_to_char(src_encoding),
1092 : : pg_encoding_to_char(dest_encoding))));
1093 : :
1885 heikki.linnakangas@i 1094 [ - + ]:CBC 2580 : if (srclen >= (MaxAllocSize / (Size) MAX_CONVERSION_GROWTH))
1885 heikki.linnakangas@i 1095 [ # # ]:UBC 0 : ereport(ERROR,
1096 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1097 : : errmsg("out of memory"),
1098 : : errdetail("String of %d bytes is too long for encoding conversion.",
1099 : : (int) srclen)));
1100 : :
1885 heikki.linnakangas@i 1101 :CBC 2580 : dstsize = (Size) srclen * MAX_CONVERSION_GROWTH + 1;
1102 : 2580 : dst = MemoryContextAlloc(CurrentMemoryContext, dstsize);
1103 : :
1104 : : /* perform conversion */
1105 : 2580 : convertedbytes = pg_do_encoding_conversion_buf(proc,
1106 : : src_encoding,
1107 : : dest_encoding,
1108 : : (unsigned char *) src, srclen,
1109 : : (unsigned char *) dst, dstsize,
1110 : : noError);
1111 : 1548 : dstlen = strlen(dst);
1112 : :
1113 : : /*
1114 : : * build bytea data type structure.
1115 : : */
1116 : 1548 : retval = (bytea *) palloc(dstlen + VARHDRSZ);
1117 : 1548 : SET_VARSIZE(retval, dstlen + VARHDRSZ);
1118 : 1548 : memcpy(VARDATA(retval), dst, dstlen);
1119 : :
1120 : 1548 : pfree(dst);
1121 : : }
1122 : :
1123 : 3160 : values[0] = Int32GetDatum(convertedbytes);
1124 : 3160 : values[1] = PointerGetDatum(retval);
1125 : 3160 : tuple = heap_form_tuple(tupdesc, values, nulls);
1126 : :
1127 : 3160 : PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
1128 : : }
1129 : :
1130 : : /* Convert bytea to text without validation for corruption tests from SQL. */
138 tmunro@postgresql.or 1131 : 8 : PG_FUNCTION_INFO_V1(test_bytea_to_text);
1132 : : Datum
1133 : 220 : test_bytea_to_text(PG_FUNCTION_ARGS)
1134 : : {
1135 : 220 : PG_RETURN_TEXT_P(PG_GETARG_BYTEA_PP(0));
1136 : : }
1137 : :
1138 : : /* And the reverse. */
1139 : 8 : PG_FUNCTION_INFO_V1(test_text_to_bytea);
1140 : : Datum
1141 : 200 : test_text_to_bytea(PG_FUNCTION_ARGS)
1142 : : {
1143 : 200 : PG_RETURN_BYTEA_P(PG_GETARG_TEXT_PP(0));
1144 : : }
1145 : :
1146 : : /* Corruption tests in C. */
1147 : 8 : PG_FUNCTION_INFO_V1(test_mblen_func);
1148 : : Datum
1149 : 24 : test_mblen_func(PG_FUNCTION_ARGS)
1150 : : {
1151 : 24 : const char *func = text_to_cstring(PG_GETARG_BYTEA_PP(0));
1152 : 24 : const char *encoding = text_to_cstring(PG_GETARG_BYTEA_PP(1));
1153 : 24 : text *string = PG_GETARG_BYTEA_PP(2);
1154 : 24 : int offset = PG_GETARG_INT32(3);
1155 [ + - ]: 24 : const char *data = VARDATA_ANY(string);
1156 [ - + - - : 24 : size_t size = VARSIZE_ANY_EXHDR(string);
- - - - +
- ]
1157 : 24 : int result = 0;
1158 : :
1159 [ + + ]: 24 : if (strcmp(func, "pg_mblen_unbounded") == 0)
1160 : 8 : result = pg_mblen_unbounded(data + offset);
1161 [ + + ]: 16 : else if (strcmp(func, "pg_mblen_cstr") == 0)
1162 : 4 : result = pg_mblen_cstr(data + offset);
1163 [ + + ]: 12 : else if (strcmp(func, "pg_mblen_with_len") == 0)
1164 : 4 : result = pg_mblen_with_len(data + offset, size - offset);
1165 [ + + ]: 8 : else if (strcmp(func, "pg_mblen_range") == 0)
1166 : 4 : result = pg_mblen_range(data + offset, data + size);
1167 [ + - ]: 4 : else if (strcmp(func, "pg_encoding_mblen") == 0)
1168 : 4 : result = pg_encoding_mblen(pg_char_to_encoding(encoding), data + offset);
1169 : : else
138 tmunro@postgresql.or 1170 [ # # ]:UBC 0 : elog(ERROR, "unknown function");
1171 : :
138 tmunro@postgresql.or 1172 :CBC 12 : PG_RETURN_INT32(result);
1173 : : }
1174 : :
1175 : 8 : PG_FUNCTION_INFO_V1(test_text_to_wchars);
1176 : : Datum
1177 : 200 : test_text_to_wchars(PG_FUNCTION_ARGS)
1178 : : {
1179 : 200 : const char *encoding_name = text_to_cstring(PG_GETARG_BYTEA_PP(0));
1180 : 200 : text *string = PG_GETARG_TEXT_PP(1);
1181 [ + - ]: 200 : const char *data = VARDATA_ANY(string);
1182 [ - + - - : 200 : size_t size = VARSIZE_ANY_EXHDR(string);
- - - - +
- ]
1183 : 200 : pg_wchar *wchars = palloc(sizeof(pg_wchar) * (size + 1));
1184 : : Datum *datums;
1185 : : int wlen;
1186 : : int encoding;
1187 : :
1188 : 200 : encoding = pg_char_to_encoding(encoding_name);
1189 [ - + ]: 200 : if (encoding < 0)
138 tmunro@postgresql.or 1190 [ # # ]:UBC 0 : elog(ERROR, "unknown encoding name: %s", encoding_name);
1191 : :
138 tmunro@postgresql.or 1192 [ + - ]:CBC 200 : if (size > 0)
1193 : : {
1194 : 200 : datums = palloc(sizeof(Datum) * size);
1195 : 200 : wlen = pg_encoding_mb2wchar_with_len(encoding,
1196 : : data,
1197 : : wchars,
1198 : : size);
1199 [ - + ]: 200 : Assert(wlen >= 0);
1200 [ - + ]: 200 : Assert(wlen <= size);
1201 [ - + ]: 200 : Assert(wchars[wlen] == 0);
1202 : :
1203 [ + + ]: 416 : for (int i = 0; i < wlen; ++i)
1204 : 216 : datums[i] = UInt32GetDatum(wchars[i]);
1205 : : }
1206 : : else
1207 : : {
138 tmunro@postgresql.or 1208 :UBC 0 : datums = NULL;
1209 : 0 : wlen = 0;
1210 : : }
1211 : :
138 tmunro@postgresql.or 1212 :CBC 200 : PG_RETURN_ARRAYTYPE_P(construct_array_builtin(datums, wlen, INT4OID));
1213 : : }
1214 : :
1215 : 8 : PG_FUNCTION_INFO_V1(test_wchars_to_text);
1216 : : Datum
1217 : 200 : test_wchars_to_text(PG_FUNCTION_ARGS)
1218 : : {
1219 : 200 : const char *encoding_name = text_to_cstring(PG_GETARG_BYTEA_PP(0));
1220 : 200 : ArrayType *array = PG_GETARG_ARRAYTYPE_P(1);
1221 : : Datum *datums;
1222 : : bool *nulls;
1223 : : char *mb;
1224 : : text *result;
1225 : : int wlen;
1226 : : int bytes;
1227 : : int encoding;
1228 : :
1229 : 200 : encoding = pg_char_to_encoding(encoding_name);
1230 [ - + ]: 200 : if (encoding < 0)
138 tmunro@postgresql.or 1231 [ # # ]:UBC 0 : elog(ERROR, "unknown encoding name: %s", encoding_name);
1232 : :
138 tmunro@postgresql.or 1233 :CBC 200 : deconstruct_array_builtin(array, INT4OID, &datums, &nulls, &wlen);
1234 : :
1235 [ + + ]: 200 : if (wlen > 0)
1236 : : {
1237 : 116 : pg_wchar *wchars = palloc(sizeof(pg_wchar) * wlen);
1238 : :
1239 [ + + ]: 332 : for (int i = 0; i < wlen; ++i)
1240 : : {
1241 [ - + ]: 216 : if (nulls[i])
138 tmunro@postgresql.or 1242 [ # # ]:UBC 0 : elog(ERROR, "unexpected NULL in array");
138 tmunro@postgresql.or 1243 :CBC 216 : wchars[i] = DatumGetInt32(datums[i]);
1244 : : }
1245 : :
1246 : 116 : mb = palloc(pg_encoding_max_length(encoding) * wlen + 1);
1247 : 116 : bytes = pg_encoding_wchar2mb_with_len(encoding, wchars, mb, wlen);
1248 : : }
1249 : : else
1250 : : {
1251 : 84 : mb = "";
1252 : 84 : bytes = 0;
1253 : : }
1254 : :
1255 : 200 : result = palloc(bytes + VARHDRSZ);
1256 : 200 : SET_VARSIZE(result, bytes + VARHDRSZ);
1257 : 200 : memcpy(VARDATA(result), mb, bytes);
1258 : :
1259 : 200 : PG_RETURN_TEXT_P(result);
1260 : : }
1261 : :
1262 : 8 : PG_FUNCTION_INFO_V1(test_valid_server_encoding);
1263 : : Datum
1264 : 200 : test_valid_server_encoding(PG_FUNCTION_ARGS)
1265 : : {
102 1266 : 200 : PG_RETURN_BOOL(pg_valid_server_encoding(text_to_cstring(PG_GETARG_TEXT_PP(0))) >= 0);
1267 : : }
1268 : :
1269 : : /* Provide SQL access to IsBinaryCoercible() */
1845 tgl@sss.pgh.pa.us 1270 : 9 : PG_FUNCTION_INFO_V1(binary_coercible);
1271 : : Datum
1272 : 25336 : binary_coercible(PG_FUNCTION_ARGS)
1273 : : {
1274 : 25336 : Oid srctype = PG_GETARG_OID(0);
1275 : 25336 : Oid targettype = PG_GETARG_OID(1);
1276 : :
1277 : 25336 : PG_RETURN_BOOL(IsBinaryCoercible(srctype, targettype));
1278 : : }
1279 : :
1280 : : /*
1281 : : * Sanity checks for functions in relpath.h
1282 : : */
459 andres@anarazel.de 1283 : 9 : PG_FUNCTION_INFO_V1(test_relpath);
1284 : : Datum
1285 : 4 : test_relpath(PG_FUNCTION_ARGS)
1286 : : {
1287 : : RelPathStr rpath;
1288 : :
1289 : : /*
1290 : : * Verify that PROCNUMBER_CHARS and MAX_BACKENDS stay in sync.
1291 : : * Unfortunately I don't know how to express that in a way suitable for a
1292 : : * static assert.
1293 : : */
1294 : : if ((int) ceil(log10(MAX_BACKENDS)) != PROCNUMBER_CHARS)
1295 : : elog(WARNING, "mismatch between MAX_BACKENDS and PROCNUMBER_CHARS");
1296 : :
1297 : : /* verify that the max-length relpath is generated ok */
1298 : 4 : rpath = GetRelationPath(OID_MAX, OID_MAX, OID_MAX, MAX_BACKENDS - 1,
1299 : : INIT_FORKNUM);
1300 : :
1301 [ - + ]: 4 : if (strlen(rpath.str) != REL_PATH_STR_MAXLEN)
459 andres@anarazel.de 1302 [ # # ]:UBC 0 : elog(WARNING, "maximum length relpath is if length %zu instead of %zu",
1303 : : strlen(rpath.str), REL_PATH_STR_MAXLEN);
1304 : :
459 andres@anarazel.de 1305 :CBC 4 : PG_RETURN_VOID();
1306 : : }
1307 : :
1308 : : /*
1309 : : * Simple test to verify NLS support, particularly that the PRI* macros work.
1310 : : *
1311 : : * A secondary objective is to verify that <inttypes.h>'s values for the
1312 : : * PRI* macros match what our snprintf.c code will do. Therefore, we run
1313 : : * the ereport() calls even when we know that translation will not happen.
1314 : : */
167 tgl@sss.pgh.pa.us 1315 :GNC 9 : PG_FUNCTION_INFO_V1(test_translation);
1316 : : Datum
1317 : 4 : test_translation(PG_FUNCTION_ARGS)
1318 : : {
1319 : : #ifdef ENABLE_NLS
1320 : : static bool inited = false;
1321 : :
1322 : : /*
1323 : : * Ideally we'd do this bit in a _PG_init() hook. However, it seems best
1324 : : * that the Solaris hack only get applied in the nls.sql test, so it
1325 : : * doesn't risk affecting other tests that load this module.
1326 : : */
1327 [ + - ]: 4 : if (!inited)
1328 : : {
1329 : : /*
1330 : : * Solaris' built-in gettext is not bright about associating locales
1331 : : * with message catalogs that are named after just the language.
1332 : : * Apparently the customary workaround is for users to set the
1333 : : * LANGUAGE environment variable to provide a mapping. Do so here to
1334 : : * ensure that the nls.sql regression test will work.
1335 : : */
1336 : : #if defined(__sun__)
1337 : : setenv("LANGUAGE", "es_ES.UTF-8:es", 1);
1338 : : #endif
1339 : 4 : pg_bindtextdomain(TEXTDOMAIN);
1340 : 4 : inited = true;
1341 : : }
1342 : :
1343 : : /*
1344 : : * If nls.sql failed to select a non-C locale, no translation will happen.
1345 : : * Report that so that we can distinguish this outcome from brokenness.
1346 : : * (We do this here, not in nls.sql, so as to need only 3 expected files.)
1347 : : */
165 1348 [ - + ]: 4 : if (strcmp(GetConfigOption("lc_messages", false, false), "C") == 0)
165 tgl@sss.pgh.pa.us 1349 [ # # ]:UNC 0 : elog(NOTICE, "lc_messages is 'C'");
1350 : : #else
1351 : : elog(NOTICE, "NLS is not enabled");
1352 : : #endif
1353 : :
167 tgl@sss.pgh.pa.us 1354 [ + - ]:GNC 4 : ereport(NOTICE,
1355 : : errmsg("translated PRId64 = %" PRId64, (int64) 424242424242));
1356 [ + - ]: 4 : ereport(NOTICE,
1357 : : errmsg("translated PRId32 = %" PRId32, (int32) -1234));
1358 [ + - ]: 4 : ereport(NOTICE,
1359 : : errmsg("translated PRIdMAX = %" PRIdMAX, (intmax_t) -123456789012));
1360 [ + - ]: 4 : ereport(NOTICE,
1361 : : errmsg("translated PRIdPTR = %" PRIdPTR, (intptr_t) -9999));
1362 : :
1363 [ + - ]: 4 : ereport(NOTICE,
1364 : : errmsg("translated PRIu64 = %" PRIu64, (uint64) 424242424242));
1365 [ + - ]: 4 : ereport(NOTICE,
1366 : : errmsg("translated PRIu32 = %" PRIu32, (uint32) -1234));
1367 [ + - ]: 4 : ereport(NOTICE,
1368 : : errmsg("translated PRIuMAX = %" PRIuMAX, (uintmax_t) 123456789012));
1369 [ + - ]: 4 : ereport(NOTICE,
1370 : : errmsg("translated PRIuPTR = %" PRIuPTR, (uintptr_t) 9999));
1371 : :
1372 [ + - ]: 4 : ereport(NOTICE,
1373 : : errmsg("translated PRIx64 = %" PRIx64, (uint64) 424242424242));
1374 [ + - ]: 4 : ereport(NOTICE,
1375 : : errmsg("translated PRIx32 = %" PRIx32, (uint32) -1234));
1376 [ + - ]: 4 : ereport(NOTICE,
1377 : : errmsg("translated PRIxMAX = %" PRIxMAX, (uintmax_t) 123456789012));
1378 [ + - ]: 4 : ereport(NOTICE,
1379 : : errmsg("translated PRIxPTR = %" PRIxPTR, (uintptr_t) 9999));
1380 : :
1381 [ + - ]: 4 : ereport(NOTICE,
1382 : : errmsg("translated PRIX64 = %" PRIX64, (uint64) 424242424242));
1383 [ + - ]: 4 : ereport(NOTICE,
1384 : : errmsg("translated PRIX32 = %" PRIX32, (uint32) -1234));
1385 [ + - ]: 4 : ereport(NOTICE,
1386 : : errmsg("translated PRIXMAX = %" PRIXMAX, (uintmax_t) 123456789012));
1387 [ + - ]: 4 : ereport(NOTICE,
1388 : : errmsg("translated PRIXPTR = %" PRIXPTR, (uintptr_t) 9999));
1389 : :
1390 : 4 : PG_RETURN_VOID();
1391 : : }
1392 : :
1393 : : /* Verify that pg_ticks_to_ns behaves correct, including overflow */
53 andres@anarazel.de 1394 : 9 : PG_FUNCTION_INFO_V1(test_instr_time);
1395 : : Datum
1396 : 4 : test_instr_time(PG_FUNCTION_ARGS)
1397 : : {
1398 : : instr_time t;
1399 : 4 : int64 test_ns[] = {0, 1000, INT64CONST(1000000000000000)};
1400 : : int64 max_err;
1401 : :
1402 : : /*
1403 : : * The ns-to-ticks-to-ns roundtrip may lose precision due to integer
1404 : : * truncation in the fixed-point conversion. The maximum error depends on
1405 : : * ticks_per_ns_scaled relative to the shift factor.
1406 : : */
1407 : 4 : max_err = (ticks_per_ns_scaled >> TICKS_TO_NS_SHIFT) + 1;
1408 : :
1409 [ + + ]: 16 : for (int i = 0; i < lengthof(test_ns); i++)
1410 : : {
1411 : : int64 result;
1412 : :
1413 : 12 : INSTR_TIME_SET_ZERO(t);
1414 : 12 : INSTR_TIME_ADD_NANOSEC(t, test_ns[i]);
1415 : 12 : result = INSTR_TIME_GET_NANOSEC(t);
1416 : :
1417 [ + - - + ]: 12 : if (result < test_ns[i] - max_err || result > test_ns[i])
53 andres@anarazel.de 1418 [ # # ]:UNC 0 : elog(ERROR,
1419 : : "INSTR_TIME_GET_NANOSEC(t) yielded " INT64_FORMAT
1420 : : ", expected " INT64_FORMAT " (max_err " INT64_FORMAT
1421 : : ") in file \"%s\" line %u",
1422 : : result, test_ns[i], max_err, __FILE__, __LINE__);
1423 : : }
1424 : :
53 andres@anarazel.de 1425 :GNC 4 : PG_RETURN_BOOL(true);
1426 : : }
1427 : :
1428 : : /*
1429 : : * test_pglz_compress
1430 : : *
1431 : : * Compress the input using pglz_compress(). Only the "always" strategy is
1432 : : * currently supported.
1433 : : *
1434 : : * Returns the compressed data, or NULL if compression fails.
1435 : : */
45 michael@paquier.xyz 1436 :CBC 8 : PG_FUNCTION_INFO_V1(test_pglz_compress);
1437 : : Datum
1438 : 16 : test_pglz_compress(PG_FUNCTION_ARGS)
1439 : : {
1440 : 16 : bytea *input = PG_GETARG_BYTEA_PP(0);
1441 [ - + ]: 16 : char *source = VARDATA_ANY(input);
1442 [ - + - - : 16 : int32 slen = VARSIZE_ANY_EXHDR(input);
- - - - -
+ ]
1443 : 16 : int32 maxout = PGLZ_MAX_OUTPUT(slen);
1444 : : bytea *result;
1445 : : int32 clen;
1446 : :
1447 : 16 : result = (bytea *) palloc(maxout + VARHDRSZ);
1448 : 16 : clen = pglz_compress(source, slen, VARDATA(result),
1449 : : PGLZ_strategy_always);
1450 [ - + ]: 16 : if (clen < 0)
45 michael@paquier.xyz 1451 :UBC 0 : PG_RETURN_NULL();
1452 : :
45 michael@paquier.xyz 1453 :CBC 16 : SET_VARSIZE(result, clen + VARHDRSZ);
1454 : 16 : PG_RETURN_BYTEA_P(result);
1455 : : }
1456 : :
1457 : : /*
1458 : : * test_pglz_decompress
1459 : : *
1460 : : * Decompress the input using pglz_decompress().
1461 : : *
1462 : : * The second argument is the expected uncompressed data size. The third
1463 : : * argument is here for the check_complete flag.
1464 : : *
1465 : : * Returns the decompressed data, or raises an error if decompression fails.
1466 : : */
1467 : 8 : PG_FUNCTION_INFO_V1(test_pglz_decompress);
1468 : : Datum
1469 : 56 : test_pglz_decompress(PG_FUNCTION_ARGS)
1470 : : {
1471 : 56 : bytea *input = PG_GETARG_BYTEA_PP(0);
1472 : 56 : int32 rawsize = PG_GETARG_INT32(1);
1473 : 56 : bool check_complete = PG_GETARG_BOOL(2);
1474 [ - + ]: 56 : char *source = VARDATA_ANY(input);
1475 [ - + - - : 56 : int32 slen = VARSIZE_ANY_EXHDR(input);
- - - - -
+ ]
1476 : : bytea *result;
1477 : : int32 dlen;
1478 : :
1479 [ - + ]: 56 : if (rawsize < 0)
45 michael@paquier.xyz 1480 [ # # ]:UBC 0 : elog(ERROR, "rawsize must not be negative");
1481 : :
45 michael@paquier.xyz 1482 :CBC 56 : result = (bytea *) palloc(rawsize + VARHDRSZ);
1483 : :
1484 : 56 : dlen = pglz_decompress(source, slen, VARDATA(result),
1485 : : rawsize, check_complete);
1486 [ + + ]: 56 : if (dlen < 0)
1487 [ + - ]: 44 : elog(ERROR, "pglz_decompress failed");
1488 : :
1489 : 12 : SET_VARSIZE(result, dlen + VARHDRSZ);
1490 : 12 : PG_RETURN_BYTEA_P(result);
1491 : : }
|