PostgreSQL Source Code git master
Loading...
Searching...
No Matches
test_saslprep.c
Go to the documentation of this file.
1/*--------------------------------------------------------------------------
2 *
3 * test_saslprep.c
4 * Test harness for the SASLprep implementation.
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/test/modules/test_saslprep/test_saslprep.c
10 *
11 * -------------------------------------------------------------------------
12 */
13
14#include "postgres.h"
15
16#include "access/htup_details.h"
17#include "common/saslprep.h"
18#include "fmgr.h"
19#include "funcapi.h"
20#include "mb/pg_wchar.h"
21#include "miscadmin.h"
22#include "utils/builtins.h"
23
25
26static const char *
28{
29 const char *status = "???";
30
31 switch (rc)
32 {
33 case SASLPREP_OOM:
34 status = "OOM";
35 break;
37 status = "SUCCESS";
38 break;
40 status = "INVALID_UTF8";
41 break;
43 status = "PROHIBITED";
44 break;
45 }
46
47 return status;
48}
49
50/*
51 * Simple function to test SASLprep with arbitrary bytes as input.
52 *
53 * This takes a bytea in input, returning in output the generating data as
54 * bytea with the status returned by pg_saslprep().
55 */
59{
60 bytea *string = PG_GETARG_BYTEA_PP(0);
61 char *src;
63 char *input_data;
64 char *result;
67 const char *status = NULL;
69 bool *nulls;
70 TupleDesc tupdesc;
72
73 /* determine result type */
74 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
75 elog(ERROR, "return type must be a row type");
76
77 values = palloc0_array(Datum, tupdesc->natts);
78 nulls = palloc0_array(bool, tupdesc->natts);
79
80 src_len = VARSIZE_ANY_EXHDR(string);
81 src = VARDATA_ANY(string);
82
83 /*
84 * Copy the input given, to make SASLprep() act on a sanitized string.
85 */
88 input_data[src_len] = '\0';
89
91 status = saslprep_status_to_text(rc);
92
93 if (result)
94 {
100 }
101 else
102 nulls[0] = true;
103
104 values[1] = CStringGetTextDatum(status);
105
107}
108
109/* Context structure for set-returning function with ranges */
110typedef struct
111{
115
116/*
117 * UTF-8 code point ranges.
118 */
119typedef struct
120{
124
126 /* 1, 2, 3 bytes */
127 {0x0000, 0xD7FF}, /* Basic Multilingual Plane, before surrogates */
128 {0xE000, 0xFFFF}, /* Basic Multilingual Plane, after surrogates */
129 /* 4 bytes */
130 {0x10000, 0x1FFFF}, /* Supplementary Multilingual Plane */
131 {0x20000, 0x2FFFF}, /* Supplementary Ideographic Plane */
132 {0x30000, 0x3FFFF}, /* Tertiary Ideographic Plane */
133 {0x40000, 0xDFFFF}, /* Unassigned planes */
134 {0xE0000, 0xEFFFF}, /* Supplementary Special-purpose Plane */
135 {0xF0000, 0xFFFFF}, /* Private Use Area A */
136 {0x100000, 0x10FFFF}, /* Private Use Area B */
137};
138
139#define PG_UTF8_TEST_RANGES_LEN \
140 (sizeof(pg_utf8_test_ranges) / sizeof(pg_utf8_test_ranges[0]))
141
142
143/*
144 * test_saslprep_ranges
145 *
146 * Test SASLprep across various UTF-8 ranges.
147 */
149Datum
151{
154 HeapTuple tuple;
156
157 /* First call setup */
158 if (SRF_IS_FIRSTCALL())
159 {
160 MemoryContext oldcontext;
161 TupleDesc tupdesc;
162
164 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
165
166 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
167 elog(ERROR, "return type must be a row type");
168 funcctx->tuple_desc = tupdesc;
169
170 /* Allocate context with range setup */
172 ctx->current_range = 0;
174 funcctx->user_fctx = ctx;
175
176 MemoryContextSwitchTo(oldcontext);
177 }
178
180 ctx = (pg_saslprep_test_context *) funcctx->user_fctx;
181
183 {
184 char32_t codepoint = ctx->current_codepoint;
185 unsigned char utf8_buf[5];
186 char input_str[6];
187 char *output = NULL;
189 int utf8_len;
190 const char *status;
193 char codepoint_str[16];
194 Datum values[4] = {0};
195 bool nulls[4] = {0};
198
200
201 /* Switch to next range if finished with the previous one */
202 if (ctx->current_codepoint > range->end_codepoint)
203 {
204 ctx->current_range++;
206 ctx->current_codepoint =
208 continue;
209 }
210
211 codepoint = ctx->current_codepoint;
212
213 /* Convert code point to UTF-8 */
214 utf8_len = unicode_utf8len(codepoint);
215 if (utf8_len == 0)
216 {
217 ctx->current_codepoint++;
218 continue;
219 }
220 unicode_to_utf8(codepoint, utf8_buf);
221
222 /* Create null-terminated string */
224 input_str[utf8_len] = '\0';
225
226 /* Test with pg_saslprep */
228
229 /* Prepare output values */
230 memset(nulls, false, sizeof(nulls));
231
232 /* codepoint as text U+XXXX format */
233 if (codepoint <= 0xFFFF)
234 snprintf(codepoint_str, sizeof(codepoint_str), "U+%04X", codepoint);
235 else
236 snprintf(codepoint_str, sizeof(codepoint_str), "U+%06X", codepoint);
238
239 /* status */
240 status = saslprep_status_to_text(rc);
241 values[1] = CStringGetTextDatum(status);
242
243 /* input_bytes */
248
249 /* output_bytes */
250 if (output != NULL)
251 {
252 int output_len = strlen(output);
253
258 pfree(output);
259 }
260 else
261 {
262 nulls[3] = true;
263 values[3] = (Datum) 0;
264 }
265
266 /* Build and return tuple */
267 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
268 result = HeapTupleGetDatum(tuple);
269
270 /* Move to next code point */
271 ctx->current_codepoint++;
272
274 }
275
276 /* All done */
278}
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define VARHDRSZ
Definition c.h:781
size_t Size
Definition c.h:689
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define PG_GETARG_BYTEA_PP(n)
Definition fmgr.h:309
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition funcapi.h:328
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
FILE * output
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc0(Size size)
Definition mcxt.c:1417
void * palloc(Size size)
Definition mcxt.c:1387
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static unsigned char * unicode_to_utf8(char32_t c, unsigned char *utf8string)
Definition pg_wchar.h:428
static int unicode_utf8len(char32_t c)
Definition pg_wchar.h:460
#define snprintf
Definition port.h:260
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
static int fb(int x)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
pg_saslprep_rc pg_saslprep(const char *input, char **output)
Definition saslprep.c:1047
pg_saslprep_rc
Definition saslprep.h:21
@ SASLPREP_INVALID_UTF8
Definition saslprep.h:24
@ SASLPREP_PROHIBITED
Definition saslprep.h:25
@ SASLPREP_OOM
Definition saslprep.h:23
@ SASLPREP_SUCCESS
Definition saslprep.h:22
Definition c.h:776
static const char * saslprep_status_to_text(pg_saslprep_rc rc)
PG_MODULE_MAGIC
#define PG_UTF8_TEST_RANGES_LEN
static const pg_utf8_codepoint_range pg_utf8_test_ranges[]
Datum test_saslprep(PG_FUNCTION_ARGS)
Datum test_saslprep_ranges(PG_FUNCTION_ARGS)
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432