ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
agg_token.c
Go to the documentation of this file.
1/**
2 * @file agg_token.c
3 * @brief PostgreSQL I/O functions and cast for the @c agg_token composite type.
4 *
5 * Implements the three SQL-callable C functions that back the
6 * @c agg_token type:
7 * - @c agg_token_in() – text → agg_token (input function)
8 * - @c agg_token_out() – agg_token → text (output function)
9 * - @c agg_token_cast() – agg_token → text (cast, extracts the UUID part)
10 *
11 * The on-wire text format is @c ( UUID , value ) where @c UUID is the
12 * 36-character hyphenated UUID of the provenance gate and @c value is
13 * the aggregate running value.
14 */
15#include "postgres.h"
16#include "fmgr.h"
17#include "catalog/pg_type.h"
18#include "utils/uuid.h"
19#include "utils/numeric.h"
20#include "utils/fmgrprotos.h"
21#include "utils/builtins.h"
22#include "access/xact.h"
23#include "executor/spi.h"
24#include "access/htup_details.h"
25
26#include "provsql_utils.h"
27#include "agg_token.h"
28
29/**
30 * @brief Set the value of @p aggtok to the @p len first bytes of @p val.
31 *
32 * A value too long for @c agg_token::val keeps its first
33 * @c AGG_TOKEN_PREFIX_LEN bytes, marked by @c AGG_TOKEN_TRUNCATED in the last
34 * byte; @p aggtok must be zeroed.
35 */
36void agg_token_set_value(agg_token *aggtok, const char *val, size_t len)
37{
38 if(len < sizeof(aggtok->val) - 1) {
39 memcpy(aggtok->val, val, len);
40 aggtok->val[len] = '\0';
41 } else {
42 memcpy(aggtok->val, val, AGG_TOKEN_PREFIX_LEN);
43 aggtok->val[AGG_TOKEN_PREFIX_LEN] = '\0';
44 aggtok->val[sizeof(aggtok->val) - 1] = AGG_TOKEN_TRUNCATED;
45 }
46}
47
48/**
49 * @brief The value of @p aggtok, as a C string.
50 *
51 * The value stored in the token, or, when it is only a prefix, the value of
52 * its gate, read with @c provsql.agg_token_value_text; the prefix is returned
53 * if the gate gives none that starts with it.
54 */
55const char *agg_token_value_cstring(const agg_token *aggtok)
56{
57 MemoryContext caller = CurrentMemoryContext;
58 Oid argtypes[1] = {TEXTOID};
59 Datum args[1];
60 char *full = NULL;
61
62 if(aggtok->val[sizeof(aggtok->val) - 1] != AGG_TOKEN_TRUNCATED ||
63 strlen(aggtok->val) != AGG_TOKEN_PREFIX_LEN)
64 return aggtok->val;
65
66 args[0] = CStringGetTextDatum(aggtok->tok);
67 if(SPI_connect() != SPI_OK_CONNECT)
68 return aggtok->val;
69 if(SPI_execute_with_args("SELECT provsql.agg_token_value_text($1::uuid)",
70 1, argtypes, args, NULL, true, 1) == SPI_OK_SELECT &&
71 SPI_processed == 1) {
72 char *v = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
73 size_t n;
74 /* agg_token_value_text gives the value followed by " (*)"; it is that
75 * of the token if it starts with the prefix the token holds. */
76 if(v != NULL && (n = strlen(v)) >= AGG_TOKEN_PREFIX_LEN + 4 &&
77 strcmp(v + n - 4, " (*)") == 0 &&
78 strncmp(v, aggtok->val, AGG_TOKEN_PREFIX_LEN) == 0) {
79 v[n - 4] = '\0';
80 full = MemoryContextStrdup(caller, v);
81 }
82 }
83 SPI_finish();
84 return full != NULL ? full : aggtok->val;
85}
86
87PG_FUNCTION_INFO_V1(agg_token_in);
88/**
89 * @brief Parse an @c agg_token value from its text representation.
90 *
91 * Expected format: @c "( UUID , value )" with a single space around the
92 * comma and at the outer parentheses. Raises @c ERROR on malformed input.
93 * @return Pointer to the newly allocated @c agg_token.
94 */
95Datum
96agg_token_in(PG_FUNCTION_ARGS)
97{
98 char *str = PG_GETARG_CSTRING(0);
99 agg_token* result;
100 const unsigned toklen=sizeof(result->tok)-1;
101 unsigned vallen;
102
103 result = (agg_token *)palloc0(sizeof(agg_token));
104
105 // str is ( UUID , string ) with UUID starting at 2 and with length
106 // 20 (2*UUID-LEN=16) plus 4 hashes; then three characters we can
107 // ignore (two spaces and comma) then the string then two ignored
108 // spaces at the end
109 if(strlen(str)<toklen+7 ||
110 str[0]!='(' || str[1]!=' ' || str[2+toklen] != ' ' || str[2+toklen+1] != ','
111 || str[2+toklen+2] != ' ' || str[strlen(str)-2] != ' '
112 || str[strlen(str)-1] != ')')
113 ereport(ERROR,
114 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
115 errmsg("invalid input syntax for agg_token: \"%s\"",
116 str)));
117
118 strncpy(result->tok, str+2, toklen);
119 result->tok[toklen]='\0';
120
121 vallen=strlen(str)-toklen-2-3-2;
122 agg_token_set_value(result, str+2+toklen+3, vallen);
123
124 PG_RETURN_POINTER(result);
125}
126
127PG_FUNCTION_INFO_V1(agg_token_out);
128/**
129 * @brief Produce a display string for an @c agg_token.
130 *
131 * Default: returns @c "value (*)" (the running value followed by
132 * @c " (*)"), matching @c EXPLAIN and direct @c CAST to text. Where the value
133 * is SQL NULL it is @c "(*)" alone: SQL writes nothing for a NULL, so writing
134 * @c "NULL" would put four characters where a reader expects none, and a text
135 * client would read them as data.
136 *
137 * When the @c provsql.aggtoken_text_as_uuid GUC is on, returns the
138 * underlying provenance UUID instead. This is the form ProvSQL
139 * Studio enables per session so agg_token cells in a result table
140 * expose the circuit root UUID for click-through; the user-facing
141 * @c "value (*)" string is recovered via the
142 * @c provsql.agg_token_value_text(uuid) helper.
143 *
144 * @return C-string representation of the agg_token.
145 */
146Datum
147agg_token_out(PG_FUNCTION_ARGS)
148{
149 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
150 char *result;
151
153 result = psprintf("%s", aggtok->tok);
154 else if (strcmp(aggtok->val, "NULL") == 0)
155 /* The value is SQL NULL here -- an aggregate with no value, or one the
156 * arithmetic has none for (a division whose divisor reads zero, which
157 * ProvSQL answers rather than raising so that the other worlds stay
158 * answerable). SQL never writes the four characters NULL, so neither do
159 * we: the marker alone says the row is tracked and has no value here.
160 *
161 * Only that spelling, NOT the empty value string @c agg_token_val_is_null
162 * also accepts: an aggregate of the empty text has a value, and writing it
163 * as though it had none would lose the difference. The two are already
164 * indistinguishable in what the gate records, which is a separate matter
165 * from printing them alike. */
166 result = pstrdup("(*)");
167 else
168 result = psprintf("%s (*)", agg_token_value_cstring(aggtok));
169
170 PG_RETURN_CSTRING(result);
171}
172
173PG_FUNCTION_INFO_V1(agg_token_cast);
174/**
175 * @brief Cast an @c agg_token to @c text, returning only the UUID part.
176 *
177 * This is used when the caller needs the provenance circuit UUID
178 * stored in the token rather than the aggregate value.
179 * @return Text datum containing the UUID string of the token.
180 */
181Datum
182agg_token_cast(PG_FUNCTION_ARGS)
183{
184 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
185 char *result;
186 text *txt_result;
187 int len;
188
189 result = psprintf("%s", aggtok->tok);
190 len = strlen(result);
191
192 txt_result = (text *) palloc(len + ((int32) sizeof(int32)));
193
194 SET_VARSIZE(txt_result, len + ((int32) sizeof(int32)));
195 memcpy(VARDATA(txt_result), result, len);
196
197 PG_RETURN_TEXT_P(txt_result);
198}
199
200/**
201 * @brief True when an @c agg_token value string cannot carry a number.
202 *
203 * An empty or literal @c "NULL" value string (an aggregate whose value is
204 * SQL NULL) must convert to SQL NULL rather than feed the type-input
205 * function a string it rejects.
206 */
207static bool
209{
210 return aggtok->val[0] == '\0' || strcmp(aggtok->val, "NULL") == 0;
211}
212
213/**
214 * @brief The "provenance information is lost" warning of a conversion, once
215 * for a statement and for each target type.
216 *
217 * A conversion runs for every row, and so did its warning: a query over a
218 * large relation wrote one line per row, which says nothing the first does not
219 * and which has filled a server log before. The statement is identified by
220 * @c provsql_stmt_serial, which the executor hook bumps for the user's
221 * outermost statement; a conversion outside any statement of the user (a
222 * direct call in a function the rewriting runs) warns once as well.
223 */
224static void warn_conversion_once(const char *target) {
225 /* One remembered serial per target type: the list is short and fixed. */
226 static const char *seen_target[8];
227 static unsigned seen_serial[8];
228 static int nseen = 0;
229 int i;
230
231 /* Tagged like a freezing, and scoped deliberate, although nothing is frozen
232 * here: this is the conversion of a token the RELATION holds -- reading
233 * "x::text" of a column an earlier statement wrote -- and the text of a
234 * token is the value on the data as it is, which no rewriting gives a
235 * provenance to. The tag is its own, not the freezing's
236 * (aggregate-read-as-plain-value), so that a survey counting causes does not
237 * take a read of stored data for a fragment ProvSQL failed to track. */
238 for (i = 0; i < nseen; ++i)
239 if (seen_target[i] == target) {
240 if (seen_serial[i] == provsql_stmt_serial)
241 return;
242 seen_serial[i] = provsql_stmt_serial;
243 provsql_warning_tagged(PROVSQL_DELIBERATE, "stored-agg-token-conversion", "converting agg_token to %s: provenance information is "
244 "lost", target);
245 return;
246 }
247 if (nseen < (int)(sizeof(seen_target) / sizeof(seen_target[0]))) {
248 seen_target[nseen] = target;
249 seen_serial[nseen] = provsql_stmt_serial;
250 ++nseen;
251 }
252 provsql_warning_tagged(PROVSQL_DELIBERATE, "stored-agg-token-conversion", "converting agg_token to %s: provenance information is lost",
253 target);
254}
255
256
257/** @brief The "sorted on the plain value" warning, once for a statement. */
258static void warn_ordering_once(void)
259{
260 static unsigned seen = (unsigned)-1;
261
262 if (seen == provsql_stmt_serial)
263 return;
264 seen = provsql_stmt_serial;
265 provsql_warning("ordering or grouping an aggregate result reads its value "
266 "on the data as it is, the one this statement computed: "
267 "another possible world need not order them the same way");
268}
269
270/** @brief Whether @p v is the text of a number, as @c numeric_in would read
271 * it: the check a comparison makes before parsing, since parsing what is not
272 * one would raise where a comparison must not. */
273static bool text_is_number(const char *v)
274{
275 const char *p = v;
276 bool digits = false;
277
278 if (p == NULL)
279 return false;
280 while (*p == ' ') ++p;
281 if (*p == '+' || *p == '-') ++p;
282 while (*p >= '0' && *p <= '9') { ++p; digits = true; }
283 if (*p == '.') {
284 ++p;
285 while (*p >= '0' && *p <= '9') { ++p; digits = true; }
286 }
287 if (digits && (*p == 'e' || *p == 'E')) {
288 ++p;
289 if (*p == '+' || *p == '-') ++p;
290 if (!(*p >= '0' && *p <= '9')) return false;
291 while (*p >= '0' && *p <= '9') ++p;
292 }
293 while (*p == ' ') ++p;
294 return digits && *p == '\0';
295}
296
297PG_FUNCTION_INFO_V1(agg_token_btree_cmp);
298/**
299 * @brief Order two @c agg_token values by the value each carries.
300 *
301 * An @c agg_token is a value and a provenance, and the value is the one the
302 * data as it is gives: ordering by it -- @c ORDER @c BY, @c DISTINCT, a
303 * @c GROUP @c BY that sorts -- is ordering by that one value, which another
304 * possible world need not agree with. The warning says so, once for the
305 * statement rather than once per comparison, since a sort makes n log n of
306 * them.
307 *
308 * A token with no value (an aggregate over no row) sorts first, as a @c NULL
309 * does under @c NULLS @c FIRST; two numbers are compared as numbers and
310 * anything else by its text, so that the order is total whatever the
311 * aggregate's own type.
312 */
313Datum
314agg_token_btree_cmp(PG_FUNCTION_ARGS)
315{
316 agg_token *a = (agg_token *) PG_GETARG_POINTER(0);
317 agg_token *b = (agg_token *) PG_GETARG_POINTER(1);
318 bool a_null = agg_token_val_is_null(a), b_null = agg_token_val_is_null(b);
319 const char *av, *bv;
320
322
323 if (a_null || b_null)
324 PG_RETURN_INT32(a_null && b_null ? 0 : (a_null ? -1 : 1));
327 if (text_is_number(av) && text_is_number(bv)) {
328 Datum na = DirectFunctionCall3(numeric_in, CStringGetDatum(av),
329 ObjectIdGetDatum(InvalidOid),
330 Int32GetDatum(-1));
331 Datum nb = DirectFunctionCall3(numeric_in, CStringGetDatum(bv),
332 ObjectIdGetDatum(InvalidOid),
333 Int32GetDatum(-1));
334 PG_RETURN_INT32(DatumGetInt32(DirectFunctionCall2(numeric_cmp, na, nb)));
335 }
336 {
337 int c = strcmp(av, bv);
338 PG_RETURN_INT32(c < 0 ? -1 : (c > 0 ? 1 : 0));
339 }
340}
341
342PG_FUNCTION_INFO_V1(agg_token_to_numeric);
343/**
344 * @brief Cast an @c agg_token to @c numeric, extracting only the value.
345 *
346 * Emits a WARNING that provenance information is lost during the conversion.
347 * @return Numeric datum parsed from the aggregate value string.
348 */
349Datum
350agg_token_to_numeric(PG_FUNCTION_ARGS)
351{
352 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
353 Datum result;
354
355 warn_conversion_once("numeric");
356
357 if (agg_token_val_is_null(aggtok))
358 PG_RETURN_NULL();
359
360 result = DirectFunctionCall3(numeric_in,
361 CStringGetDatum(agg_token_value_cstring(aggtok)),
362 ObjectIdGetDatum(InvalidOid),
363 Int32GetDatum(-1));
364 PG_RETURN_DATUM(result);
365}
366
367PG_FUNCTION_INFO_V1(agg_token_value);
368/**
369 * @brief Extract the running value of an @c agg_token as @c numeric.
370 *
371 * Unlike @c agg_token_to_numeric, this does @b not emit the
372 * "provenance information is lost" warning: it is the internal accessor
373 * used by the provenance-preserving @c agg_token arithmetic operators
374 * (which keep the provenance in a @c gate_arith circuit), where no
375 * provenance is dropped.
376 * @return Numeric datum parsed from the aggregate value string.
377 */
378Datum
379agg_token_value(PG_FUNCTION_ARGS)
380{
381 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
382 Datum result;
383
384 if (agg_token_val_is_null(aggtok))
385 PG_RETURN_NULL();
386
387 result = DirectFunctionCall3(numeric_in,
388 CStringGetDatum(agg_token_value_cstring(aggtok)),
389 ObjectIdGetDatum(InvalidOid),
390 Int32GetDatum(-1));
391 PG_RETURN_DATUM(result);
392}
393
394PG_FUNCTION_INFO_V1(agg_token_to_float8);
395/**
396 * @brief Cast an @c agg_token to @c double precision, extracting only the value.
397 *
398 * Emits a WARNING that provenance information is lost during the conversion.
399 * @return Float8 datum parsed from the aggregate value string.
400 */
401Datum
402agg_token_to_float8(PG_FUNCTION_ARGS)
403{
404 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
405 Datum result;
406
407 warn_conversion_once("double precision");
408
409 if (agg_token_val_is_null(aggtok))
410 PG_RETURN_NULL();
411
412 result = DirectFunctionCall1(float8in,
413 CStringGetDatum(agg_token_value_cstring(aggtok)));
414 PG_RETURN_DATUM(result);
415}
416
417PG_FUNCTION_INFO_V1(agg_token_to_int4);
418/**
419 * @brief Cast an @c agg_token to @c integer, extracting only the value.
420 *
421 * Emits a WARNING that provenance information is lost during the conversion.
422 * @return Int32 datum parsed from the aggregate value string.
423 */
424Datum
425agg_token_to_int4(PG_FUNCTION_ARGS)
426{
427 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
428 Datum result;
429
430 warn_conversion_once("integer");
431
432 if (agg_token_val_is_null(aggtok))
433 PG_RETURN_NULL();
434
435 result = DirectFunctionCall1(int4in,
436 CStringGetDatum(agg_token_value_cstring(aggtok)));
437 PG_RETURN_DATUM(result);
438}
439
440PG_FUNCTION_INFO_V1(agg_token_to_int8);
441/**
442 * @brief Cast an @c agg_token to @c bigint, extracting only the value.
443 *
444 * Emits a WARNING that provenance information is lost during the conversion.
445 * @return Int64 datum parsed from the aggregate value string.
446 */
447Datum
448agg_token_to_int8(PG_FUNCTION_ARGS)
449{
450 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
451 Datum result;
452
453 warn_conversion_once("bigint");
454
455 if (agg_token_val_is_null(aggtok))
456 PG_RETURN_NULL();
457
458 result = DirectFunctionCall1(int8in,
459 CStringGetDatum(agg_token_value_cstring(aggtok)));
460 PG_RETURN_DATUM(result);
461}
462
463PG_FUNCTION_INFO_V1(agg_token_to_bool);
464/**
465 * @brief Cast an @c agg_token to @c boolean, extracting only the value.
466 *
467 * The value of a boolean aggregate (@c bool_or, @c bool_and, @c every).
468 * Emits a WARNING that provenance information is lost during the conversion.
469 * @return Boolean datum parsed from the aggregate value string.
470 */
471Datum
472agg_token_to_bool(PG_FUNCTION_ARGS)
473{
474 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
475
476 warn_conversion_once("boolean");
477
478 if (agg_token_val_is_null(aggtok))
479 PG_RETURN_NULL();
480
481 return DirectFunctionCall1(boolin, CStringGetDatum(agg_token_value_cstring(aggtok)));
482}
483
484PG_FUNCTION_INFO_V1(agg_token_to_text);
485/**
486 * @brief Cast an @c agg_token to @c text, extracting only the value.
487 *
488 * Unlike @c agg_token_cast which returns the UUID part, this returns
489 * the aggregate value as text.
490 * Emits a WARNING that provenance information is lost during the conversion.
491 * @return Text datum containing the aggregate value string.
492 */
493Datum
494agg_token_to_text(PG_FUNCTION_ARGS)
495{
496 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
497 text *txt_result;
498 const char *val;
499 int len;
500
501 warn_conversion_once("text");
502
503 val = agg_token_value_cstring(aggtok);
504 len = strlen(val);
505 txt_result = (text *) palloc(len + VARHDRSZ);
506 SET_VARSIZE(txt_result, len + VARHDRSZ);
507 memcpy(VARDATA(txt_result), val, len);
508
509 PG_RETURN_TEXT_P(txt_result);
510}
511
512PG_FUNCTION_INFO_V1(agg_token_plain_text);
513/**
514 * @brief The value of an @c agg_token as @c text, NULL for a NULL value,
515 * without the "provenance information is lost" warning.
516 *
517 * The internal accessor of the rewriter's sort keys: an @c ORDER @c BY on an
518 * aggregate result sorts on this value, read in the aggregate's type, while
519 * the column itself keeps its @c agg_token.
520 */
521Datum
522agg_token_plain_text(PG_FUNCTION_ARGS)
523{
524 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
525
526 if (agg_token_val_is_null(aggtok))
527 PG_RETURN_NULL();
528 PG_RETURN_TEXT_P(cstring_to_text(agg_token_value_cstring(aggtok)));
529}
530
531PG_FUNCTION_INFO_V1(row_number_as_rank);
532/**
533 * @brief The @c agg_token of @c rank() standing for @c row_number().
534 *
535 * The two are equal when the @c ORDER @c BY of the window leaves no ties;
536 * with ties, SQL itself does not determine which row gets which number.
537 * The rank is what is tracked: when @p row_number differs from it, a warning
538 * says so, once per statement.
539 *
540 * @param rank The @c agg_token of the rank of the row.
541 * @param row_number The row number PostgreSQL gave the row.
542 * @return @p rank.
543 */
544Datum
545row_number_as_rank(PG_FUNCTION_ARGS)
546{
547 static TimestampTz warned = 0;
548 agg_token *rank = (agg_token *) PG_GETARG_POINTER(0);
549 int64 row_number = PG_GETARG_INT64(1);
550
551 if (!agg_token_val_is_null(rank) &&
552 strtoll(rank->val, NULL, 10) != row_number &&
553 warned != GetCurrentStatementStartTimestamp()) {
554 warned = GetCurrentStatementStartTimestamp();
555 provsql_warning("row_number() / LIMIT / DISTINCT ON is tracked as rank() "
556 "(WITH TIES), which it differs from when rows tie on the "
557 "ORDER BY");
558 }
559 PG_RETURN_POINTER(rank);
560}
Datum agg_token_to_numeric(PG_FUNCTION_ARGS)
Cast an agg_token to numeric, extracting only the value.
Definition agg_token.c:350
Datum agg_token_btree_cmp(PG_FUNCTION_ARGS)
Order two agg_token values by the value each carries.
Definition agg_token.c:314
Datum agg_token_value(PG_FUNCTION_ARGS)
Extract the running value of an agg_token as numeric.
Definition agg_token.c:379
static bool agg_token_val_is_null(const agg_token *aggtok)
True when an agg_token value string cannot carry a number.
Definition agg_token.c:208
static void warn_ordering_once(void)
The "sorted on the plain value" warning, once for a statement.
Definition agg_token.c:258
void agg_token_set_value(agg_token *aggtok, const char *val, size_t len)
Set the value of aggtok to the len first bytes of val.
Definition agg_token.c:36
Datum agg_token_out(PG_FUNCTION_ARGS)
Produce a display string for an agg_token.
Definition agg_token.c:147
static bool text_is_number(const char *v)
Whether v is the text of a number, as numeric_in would read it: the check a comparison makes before p...
Definition agg_token.c:273
const char * agg_token_value_cstring(const agg_token *aggtok)
The value of aggtok, as a C string.
Definition agg_token.c:55
Datum agg_token_cast(PG_FUNCTION_ARGS)
Cast an agg_token to text, returning only the UUID part.
Definition agg_token.c:182
Datum agg_token_plain_text(PG_FUNCTION_ARGS)
The value of an agg_token as text, NULL for a NULL value, without the "provenance information is lost...
Definition agg_token.c:522
Datum agg_token_to_int4(PG_FUNCTION_ARGS)
Cast an agg_token to integer, extracting only the value.
Definition agg_token.c:425
Datum agg_token_to_int8(PG_FUNCTION_ARGS)
Cast an agg_token to bigint, extracting only the value.
Definition agg_token.c:448
Datum agg_token_to_text(PG_FUNCTION_ARGS)
Cast an agg_token to text, extracting only the value.
Definition agg_token.c:494
static void warn_conversion_once(const char *target)
The "provenance information is lost" warning of a conversion, once for a statement and for each targe...
Definition agg_token.c:224
Datum agg_token_to_float8(PG_FUNCTION_ARGS)
Cast an agg_token to double precision, extracting only the value.
Definition agg_token.c:402
Datum agg_token_to_bool(PG_FUNCTION_ARGS)
Cast an agg_token to boolean, extracting only the value.
Definition agg_token.c:472
Datum row_number_as_rank(PG_FUNCTION_ARGS)
The agg_token of rank() standing for row_number().
Definition agg_token.c:545
Datum agg_token_in(PG_FUNCTION_ARGS)
Parse an agg_token value from its text representation.
Definition agg_token.c:96
Aggregate-provenance token type used in SQL aggregate functions.
#define AGG_TOKEN_PREFIX_LEN
Length of the prefix of a value too long for agg_token::val.
Definition agg_token.h:38
#define AGG_TOKEN_TRUNCATED
Last byte of agg_token::val when the value is a prefix.
Definition agg_token.h:40
unsigned provsql_stmt_serial
Counts the user's statements, so that a warning a conversion emits at run time is given once for a st...
Definition provsql.c:224
bool provsql_aggtoken_text_as_uuid
When true, agg_token::text emits the underlying provenance UUID instead of "value (*)".
Definition provsql.c:119
#define PROVSQL_DELIBERATE
What kind of limit a refusal or a freezing is.
#define provsql_warning_tagged(scope, tag, fmt,...)
Emit a ProvSQL warning that names its cause by a stable tag.
#define provsql_warning(fmt,...)
Emit a ProvSQL warning message (execution continues).
Core types, constants, and utilities shared across ProvSQL.
Aggregate token bundling a provenance UUID with a running value.
Definition agg_token.h:32
char val[80]
Aggregate running value as a text string.
Definition agg_token.h:34
char tok[2 *UUID_LEN+5]
Provenance UUID as a text string.
Definition agg_token.h:33