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 "executor/spi.h"
22#include "access/htup_details.h"
23
24#include "provsql_utils.h"
25#include "agg_token.h"
26
27PG_FUNCTION_INFO_V1(agg_token_in);
28/**
29 * @brief Parse an @c agg_token value from its text representation.
30 *
31 * Expected format: @c "( UUID , value )" with a single space around the
32 * comma and at the outer parentheses. Raises @c ERROR on malformed input.
33 * @return Pointer to the newly allocated @c agg_token.
34 */
35Datum
36agg_token_in(PG_FUNCTION_ARGS)
37{
38 char *str = PG_GETARG_CSTRING(0);
39 agg_token* result;
40 const unsigned toklen=sizeof(result->tok)-1;
41 unsigned vallen;
42
43 result = (agg_token *)palloc(sizeof(agg_token));
44
45 // str is ( UUID , string ) with UUID starting at 2 and with length
46 // 20 (2*UUID-LEN=16) plus 4 hashes; then three characters we can
47 // ignore (two spaces and comma) then the string then two ignored
48 // spaces at the end
49 if(strlen(str)<toklen+7 ||
50 str[0]!='(' || str[1]!=' ' || str[2+toklen] != ' ' || str[2+toklen+1] != ','
51 || str[2+toklen+2] != ' ' || str[strlen(str)-2] != ' '
52 || str[strlen(str)-1] != ')')
53 ereport(ERROR,
54 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
55 errmsg("invalid input syntax for agg_token: \"%s\"",
56 str)));
57
58 strncpy(result->tok, str+2, toklen);
59 result->tok[toklen]='\0';
60
61 vallen=strlen(str)-toklen-2-3-2;
62 if(vallen>=sizeof(result->val))
63 vallen=sizeof(result->val)-1;
64 strncpy(result->val, str+2+toklen+3, vallen);
65 result->val[vallen]='\0';
66
67 PG_RETURN_POINTER(result);
68}
69
70PG_FUNCTION_INFO_V1(agg_token_out);
71/**
72 * @brief Produce a display string for an @c agg_token.
73 *
74 * Default: returns @c "value (*)" (the running value followed by
75 * @c " (*)"), matching @c EXPLAIN and direct @c CAST to text.
76 *
77 * When the @c provsql.aggtoken_text_as_uuid GUC is on, returns the
78 * underlying provenance UUID instead. This is the form ProvSQL
79 * Studio enables per session so agg_token cells in a result table
80 * expose the circuit root UUID for click-through; the user-facing
81 * @c "value (*)" string is recovered via the
82 * @c provsql.agg_token_value_text(uuid) helper.
83 *
84 * @return C-string representation of the agg_token.
85 */
86Datum
87agg_token_out(PG_FUNCTION_ARGS)
88{
89 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
90 char *result;
91
93 result = psprintf("%s", aggtok->tok);
94 else
95 result = psprintf("%s (*)", aggtok->val);
96
97 PG_RETURN_CSTRING(result);
98}
99
100PG_FUNCTION_INFO_V1(agg_token_cast);
101/**
102 * @brief Cast an @c agg_token to @c text, returning only the UUID part.
103 *
104 * This is used when the caller needs the provenance circuit UUID
105 * stored in the token rather than the aggregate value.
106 * @return Text datum containing the UUID string of the token.
107 */
108Datum
109agg_token_cast(PG_FUNCTION_ARGS)
110{
111 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
112 char *result;
113 text *txt_result;
114 int len;
115
116 result = psprintf("%s", aggtok->tok);
117 len = strlen(result);
118
119 txt_result = (text *) palloc(len + ((int32) sizeof(int32)));
120
121 SET_VARSIZE(txt_result, len + ((int32) sizeof(int32)));
122 memcpy(VARDATA(txt_result), result, len);
123
124 PG_RETURN_TEXT_P(txt_result);
125}
126
127PG_FUNCTION_INFO_V1(agg_token_to_numeric);
128/**
129 * @brief Cast an @c agg_token to @c numeric, extracting only the value.
130 *
131 * Emits a WARNING that provenance information is lost during the conversion.
132 * @return Numeric datum parsed from the aggregate value string.
133 */
134Datum
135agg_token_to_numeric(PG_FUNCTION_ARGS)
136{
137 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
138 Datum result;
139
140 provsql_warning("converting agg_token to numeric: provenance information is lost");
141
142 result = DirectFunctionCall3(numeric_in,
143 CStringGetDatum(aggtok->val),
144 ObjectIdGetDatum(InvalidOid),
145 Int32GetDatum(-1));
146 PG_RETURN_DATUM(result);
147}
148
149PG_FUNCTION_INFO_V1(agg_token_to_float8);
150/**
151 * @brief Cast an @c agg_token to @c double precision, extracting only the value.
152 *
153 * Emits a WARNING that provenance information is lost during the conversion.
154 * @return Float8 datum parsed from the aggregate value string.
155 */
156Datum
157agg_token_to_float8(PG_FUNCTION_ARGS)
158{
159 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
160 Datum result;
161
162 provsql_warning("converting agg_token to double precision: provenance information is lost");
163
164 result = DirectFunctionCall1(float8in,
165 CStringGetDatum(aggtok->val));
166 PG_RETURN_DATUM(result);
167}
168
169PG_FUNCTION_INFO_V1(agg_token_to_int4);
170/**
171 * @brief Cast an @c agg_token to @c integer, extracting only the value.
172 *
173 * Emits a WARNING that provenance information is lost during the conversion.
174 * @return Int32 datum parsed from the aggregate value string.
175 */
176Datum
177agg_token_to_int4(PG_FUNCTION_ARGS)
178{
179 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
180 Datum result;
181
182 provsql_warning("converting agg_token to integer: provenance information is lost");
183
184 result = DirectFunctionCall1(int4in,
185 CStringGetDatum(aggtok->val));
186 PG_RETURN_DATUM(result);
187}
188
189PG_FUNCTION_INFO_V1(agg_token_to_int8);
190/**
191 * @brief Cast an @c agg_token to @c bigint, extracting only the value.
192 *
193 * Emits a WARNING that provenance information is lost during the conversion.
194 * @return Int64 datum parsed from the aggregate value string.
195 */
196Datum
197agg_token_to_int8(PG_FUNCTION_ARGS)
198{
199 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
200 Datum result;
201
202 provsql_warning("converting agg_token to bigint: provenance information is lost");
203
204 result = DirectFunctionCall1(int8in,
205 CStringGetDatum(aggtok->val));
206 PG_RETURN_DATUM(result);
207}
208
209PG_FUNCTION_INFO_V1(agg_token_to_text);
210/**
211 * @brief Cast an @c agg_token to @c text, extracting only the value.
212 *
213 * Unlike @c agg_token_cast which returns the UUID part, this returns
214 * the aggregate value as text.
215 * Emits a WARNING that provenance information is lost during the conversion.
216 * @return Text datum containing the aggregate value string.
217 */
218Datum
219agg_token_to_text(PG_FUNCTION_ARGS)
220{
221 agg_token *aggtok = (agg_token *) PG_GETARG_POINTER(0);
222 text *txt_result;
223 int len;
224
225 provsql_warning("converting agg_token to text: provenance information is lost");
226
227 len = strlen(aggtok->val);
228 txt_result = (text *) palloc(len + VARHDRSZ);
229 SET_VARSIZE(txt_result, len + VARHDRSZ);
230 memcpy(VARDATA(txt_result), aggtok->val, len);
231
232 PG_RETURN_TEXT_P(txt_result);
233}
Datum agg_token_to_numeric(PG_FUNCTION_ARGS)
Cast an agg_token to numeric, extracting only the value.
Definition agg_token.c:135
Datum agg_token_out(PG_FUNCTION_ARGS)
Produce a display string for an agg_token.
Definition agg_token.c:87
Datum agg_token_cast(PG_FUNCTION_ARGS)
Cast an agg_token to text, returning only the UUID part.
Definition agg_token.c:109
Datum agg_token_to_int4(PG_FUNCTION_ARGS)
Cast an agg_token to integer, extracting only the value.
Definition agg_token.c:177
Datum agg_token_to_int8(PG_FUNCTION_ARGS)
Cast an agg_token to bigint, extracting only the value.
Definition agg_token.c:197
Datum agg_token_to_text(PG_FUNCTION_ARGS)
Cast an agg_token to text, extracting only the value.
Definition agg_token.c:219
Datum agg_token_to_float8(PG_FUNCTION_ARGS)
Cast an agg_token to double precision, extracting only the value.
Definition agg_token.c:157
Datum agg_token_in(PG_FUNCTION_ARGS)
Parse an agg_token value from its text representation.
Definition agg_token.c:36
Aggregate-provenance token type used in SQL aggregate functions.
bool provsql_aggtoken_text_as_uuid
When true, agg_token::text emits the underlying provenance UUID instead of "value (*)".
Definition provsql.c:80
#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:29
char val[80]
Aggregate running value as a text string.
Definition agg_token.h:31
char tok[2 *UUID_LEN+5]
Provenance UUID as a text string.
Definition agg_token.h:30