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"
38 if(len <
sizeof(aggtok->
val) - 1) {
39 memcpy(aggtok->
val, val, len);
40 aggtok->
val[len] =
'\0';
57 MemoryContext caller = CurrentMemoryContext;
58 Oid argtypes[1] = {TEXTOID};
66 args[0] = CStringGetTextDatum(aggtok->
tok);
67 if(SPI_connect() != SPI_OK_CONNECT)
69 if(SPI_execute_with_args(
"SELECT provsql.agg_token_value_text($1::uuid)",
70 1, argtypes, args, NULL,
true, 1) == SPI_OK_SELECT &&
72 char *v = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
77 strcmp(v + n - 4,
" (*)") == 0 &&
80 full = MemoryContextStrdup(caller, v);
84 return full != NULL ? full : aggtok->
val;
98 char *str = PG_GETARG_CSTRING(0);
100 const unsigned toklen=
sizeof(result->
tok)-1;
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] !=
')')
114 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
115 errmsg(
"invalid input syntax for agg_token: \"%s\"",
118 strncpy(result->
tok, str+2, toklen);
119 result->
tok[toklen]=
'\0';
121 vallen=strlen(str)-toklen-2-3-2;
124 PG_RETURN_POINTER(result);
153 result = psprintf(
"%s", aggtok->
tok);
154 else if (strcmp(aggtok->
val,
"NULL") == 0)
166 result = pstrdup(
"(*)");
170 PG_RETURN_CSTRING(result);
189 result = psprintf(
"%s", aggtok->
tok);
190 len = strlen(result);
192 txt_result = (text *) palloc(len + ((int32)
sizeof(int32)));
194 SET_VARSIZE(txt_result, len + ((int32)
sizeof(int32)));
195 memcpy(VARDATA(txt_result), result, len);
197 PG_RETURN_TEXT_P(txt_result);
210 return aggtok->
val[0] ==
'\0' || strcmp(aggtok->
val,
"NULL") == 0;
226 static const char *seen_target[8];
227 static unsigned seen_serial[8];
228 static int nseen = 0;
238 for (i = 0; i < nseen; ++i)
239 if (seen_target[i] == target) {
247 if (nseen < (
int)(
sizeof(seen_target) /
sizeof(seen_target[0]))) {
248 seen_target[nseen] = target;
260 static unsigned seen = (unsigned)-1;
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");
280 while (*p ==
' ') ++p;
281 if (*p ==
'+' || *p ==
'-') ++p;
282 while (*p >=
'0' && *p <=
'9') { ++p; digits =
true; }
285 while (*p >=
'0' && *p <=
'9') { ++p; digits =
true; }
287 if (digits && (*p ==
'e' || *p ==
'E')) {
289 if (*p ==
'+' || *p ==
'-') ++p;
290 if (!(*p >=
'0' && *p <=
'9'))
return false;
291 while (*p >=
'0' && *p <=
'9') ++p;
293 while (*p ==
' ') ++p;
294 return digits && *p ==
'\0';
323 if (a_null || b_null)
324 PG_RETURN_INT32(a_null && b_null ? 0 : (a_null ? -1 : 1));
328 Datum na = DirectFunctionCall3(numeric_in, CStringGetDatum(av),
329 ObjectIdGetDatum(InvalidOid),
331 Datum nb = DirectFunctionCall3(numeric_in, CStringGetDatum(bv),
332 ObjectIdGetDatum(InvalidOid),
334 PG_RETURN_INT32(DatumGetInt32(DirectFunctionCall2(numeric_cmp, na, nb)));
337 int c = strcmp(av, bv);
338 PG_RETURN_INT32(c < 0 ? -1 : (c > 0 ? 1 : 0));
360 result = DirectFunctionCall3(numeric_in,
362 ObjectIdGetDatum(InvalidOid),
364 PG_RETURN_DATUM(result);
387 result = DirectFunctionCall3(numeric_in,
389 ObjectIdGetDatum(InvalidOid),
391 PG_RETURN_DATUM(result);
412 result = DirectFunctionCall1(float8in,
414 PG_RETURN_DATUM(result);
435 result = DirectFunctionCall1(int4in,
437 PG_RETURN_DATUM(result);
458 result = DirectFunctionCall1(int8in,
460 PG_RETURN_DATUM(result);
505 txt_result = (text *) palloc(len + VARHDRSZ);
506 SET_VARSIZE(txt_result, len + VARHDRSZ);
507 memcpy(VARDATA(txt_result), val, len);
509 PG_RETURN_TEXT_P(txt_result);
547 static TimestampTz warned = 0;
549 int64 row_number = PG_GETARG_INT64(1);
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 "
559 PG_RETURN_POINTER(rank);
Datum agg_token_to_numeric(PG_FUNCTION_ARGS)
Cast an agg_token to numeric, extracting only the value.
Datum agg_token_btree_cmp(PG_FUNCTION_ARGS)
Order two agg_token values by the value each carries.
Datum agg_token_value(PG_FUNCTION_ARGS)
Extract the running value of an agg_token as numeric.
static bool agg_token_val_is_null(const agg_token *aggtok)
True when an agg_token value string cannot carry a number.
static void warn_ordering_once(void)
The "sorted on the plain value" warning, once for a statement.
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.
Datum agg_token_out(PG_FUNCTION_ARGS)
Produce a display string for an agg_token.
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...
const char * agg_token_value_cstring(const agg_token *aggtok)
The value of aggtok, as a C string.
Datum agg_token_cast(PG_FUNCTION_ARGS)
Cast an agg_token to text, returning only the UUID part.
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...
Datum agg_token_to_int4(PG_FUNCTION_ARGS)
Cast an agg_token to integer, extracting only the value.
Datum agg_token_to_int8(PG_FUNCTION_ARGS)
Cast an agg_token to bigint, extracting only the value.
Datum agg_token_to_text(PG_FUNCTION_ARGS)
Cast an agg_token to text, extracting only the value.
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...
Datum agg_token_to_float8(PG_FUNCTION_ARGS)
Cast an agg_token to double precision, extracting only the value.
Datum agg_token_to_bool(PG_FUNCTION_ARGS)
Cast an agg_token to boolean, extracting only the value.
Datum row_number_as_rank(PG_FUNCTION_ARGS)
The agg_token of rank() standing for row_number().
Datum agg_token_in(PG_FUNCTION_ARGS)
Parse an agg_token value from its text representation.
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.
#define AGG_TOKEN_TRUNCATED
Last byte of agg_token::val when the value is a prefix.
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...
bool provsql_aggtoken_text_as_uuid
When true, agg_token::text emits the underlying provenance UUID instead of "value (*)".
#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.
char val[80]
Aggregate running value as a text string.
char tok[2 *UUID_LEN+5]
Provenance UUID as a text string.