Line data Source code
1 : /*--------------------------------------------------------------------------
2 : *
3 : * test_custom_types.c
4 : * Test module for a set of functions for custom types.
5 : *
6 : * The custom type used in this module is similar to int4 for simplicity,
7 : * except that it is able to use various typanalyze functions to enforce
8 : * check patterns with ANALYZE.
9 : *
10 : * Copyright (c) 1996-2026, PostgreSQL Global Development Group
11 : *
12 : * IDENTIFICATION
13 : * src/test/modules/test_custom_types/test_custom_types.c
14 : *
15 : *--------------------------------------------------------------------------
16 : */
17 :
18 : #include "postgres.h"
19 :
20 : #include "fmgr.h"
21 : #include "commands/vacuum.h"
22 : #include "utils/builtins.h"
23 :
24 1 : PG_MODULE_MAGIC;
25 :
26 : /* Function declarations */
27 2 : PG_FUNCTION_INFO_V1(int_custom_in);
28 2 : PG_FUNCTION_INFO_V1(int_custom_out);
29 2 : PG_FUNCTION_INFO_V1(int_custom_typanalyze_false);
30 2 : PG_FUNCTION_INFO_V1(int_custom_typanalyze_invalid);
31 2 : PG_FUNCTION_INFO_V1(int_custom_eq);
32 2 : PG_FUNCTION_INFO_V1(int_custom_ne);
33 2 : PG_FUNCTION_INFO_V1(int_custom_lt);
34 2 : PG_FUNCTION_INFO_V1(int_custom_le);
35 2 : PG_FUNCTION_INFO_V1(int_custom_gt);
36 2 : PG_FUNCTION_INFO_V1(int_custom_ge);
37 2 : PG_FUNCTION_INFO_V1(int_custom_cmp);
38 :
39 : /*
40 : * int_custom_in - input function for int_custom type
41 : *
42 : * Converts a string to a int_custom (which is just an int32 internally).
43 : */
44 : Datum
45 15 : int_custom_in(PG_FUNCTION_ARGS)
46 : {
47 15 : char *num = PG_GETARG_CSTRING(0);
48 :
49 15 : PG_RETURN_INT32(pg_strtoint32_safe(num, fcinfo->context));
50 : }
51 :
52 : /*
53 : * int_custom_out - output function for int_custom type
54 : *
55 : * Converts a int_custom to a string.
56 : */
57 : Datum
58 3 : int_custom_out(PG_FUNCTION_ARGS)
59 : {
60 3 : int32 arg1 = PG_GETARG_INT32(0);
61 3 : char *result = (char *) palloc(12); /* sign, 10 digits, '\0' */
62 :
63 3 : pg_ltoa(arg1, result);
64 3 : PG_RETURN_CSTRING(result);
65 : }
66 :
67 : /*
68 : * int_custom_typanalyze_false - typanalyze function that returns false
69 : *
70 : * This function returns false, to simulate a type that cannot be analyzed.
71 : */
72 : Datum
73 4 : int_custom_typanalyze_false(PG_FUNCTION_ARGS)
74 : {
75 4 : PG_RETURN_BOOL(false);
76 : }
77 :
78 : /*
79 : * Callback used to compute invalid statistics.
80 : */
81 : static void
82 3 : int_custom_invalid_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
83 : int samplerows, double totalrows)
84 : {
85 : /* We are not valid, and do not want to be. */
86 3 : stats->stats_valid = false;
87 3 : }
88 :
89 : /*
90 : * int_custom_typanalyze_invalid
91 : *
92 : * This function sets some invalid stats data, letting the caller know that
93 : * we are safe for an analyze, returning true.
94 : */
95 : Datum
96 6 : int_custom_typanalyze_invalid(PG_FUNCTION_ARGS)
97 : {
98 6 : VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0);
99 :
100 : /* If the attstattarget column is negative, use the default value */
101 6 : if (stats->attstattarget < 0)
102 4 : stats->attstattarget = default_statistics_target;
103 :
104 : /* Buggy number, no need to care as long as it is positive */
105 6 : stats->minrows = 300;
106 :
107 : /* Set callback to compute some invalid stats */
108 6 : stats->compute_stats = int_custom_invalid_stats;
109 :
110 6 : PG_RETURN_BOOL(true);
111 : }
112 :
113 : /*
114 : * Comparison functions for int_custom type
115 : */
116 : Datum
117 3 : int_custom_eq(PG_FUNCTION_ARGS)
118 : {
119 3 : int32 arg1 = PG_GETARG_INT32(0);
120 3 : int32 arg2 = PG_GETARG_INT32(1);
121 :
122 3 : PG_RETURN_BOOL(arg1 == arg2);
123 : }
124 :
125 : Datum
126 1 : int_custom_ne(PG_FUNCTION_ARGS)
127 : {
128 1 : int32 arg1 = PG_GETARG_INT32(0);
129 1 : int32 arg2 = PG_GETARG_INT32(1);
130 :
131 1 : PG_RETURN_BOOL(arg1 != arg2);
132 : }
133 :
134 : Datum
135 1 : int_custom_lt(PG_FUNCTION_ARGS)
136 : {
137 1 : int32 arg1 = PG_GETARG_INT32(0);
138 1 : int32 arg2 = PG_GETARG_INT32(1);
139 :
140 1 : PG_RETURN_BOOL(arg1 < arg2);
141 : }
142 :
143 : Datum
144 1 : int_custom_le(PG_FUNCTION_ARGS)
145 : {
146 1 : int32 arg1 = PG_GETARG_INT32(0);
147 1 : int32 arg2 = PG_GETARG_INT32(1);
148 :
149 1 : PG_RETURN_BOOL(arg1 <= arg2);
150 : }
151 :
152 : Datum
153 1 : int_custom_gt(PG_FUNCTION_ARGS)
154 : {
155 1 : int32 arg1 = PG_GETARG_INT32(0);
156 1 : int32 arg2 = PG_GETARG_INT32(1);
157 :
158 1 : PG_RETURN_BOOL(arg1 > arg2);
159 : }
160 :
161 : Datum
162 1 : int_custom_ge(PG_FUNCTION_ARGS)
163 : {
164 1 : int32 arg1 = PG_GETARG_INT32(0);
165 1 : int32 arg2 = PG_GETARG_INT32(1);
166 :
167 1 : PG_RETURN_BOOL(arg1 >= arg2);
168 : }
169 :
170 : Datum
171 46 : int_custom_cmp(PG_FUNCTION_ARGS)
172 : {
173 46 : int32 arg1 = PG_GETARG_INT32(0);
174 46 : int32 arg2 = PG_GETARG_INT32(1);
175 :
176 46 : if (arg1 < arg2)
177 30 : PG_RETURN_INT32(-1);
178 16 : else if (arg1 > arg2)
179 4 : PG_RETURN_INT32(1);
180 : else
181 12 : PG_RETURN_INT32(0);
182 : }
|