| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * pseudotypes.c |
| 4 | * Functions for the system pseudo-types. |
| 5 | * |
| 6 | * A pseudo-type isn't really a type and never has any operations, but |
| 7 | * we do need to supply input and output functions to satisfy the links |
| 8 | * in the pseudo-type's entry in pg_type. In most cases the functions |
| 9 | * just throw an error if invoked. (XXX the error messages here cover |
| 10 | * the most common case, but might be confusing in some contexts. Can |
| 11 | * we do better?) |
| 12 | * |
| 13 | * |
| 14 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 15 | * Portions Copyright (c) 1994, Regents of the University of California |
| 16 | * |
| 17 | * |
| 18 | * IDENTIFICATION |
| 19 | * src/backend/utils/adt/pseudotypes.c |
| 20 | * |
| 21 | *------------------------------------------------------------------------- |
| 22 | */ |
| 23 | #include "postgres.h" |
| 24 | |
| 25 | #include "libpq/pqformat.h" |
| 26 | #include "utils/array.h" |
| 27 | #include "utils/builtins.h" |
| 28 | #include "utils/rangetypes.h" |
| 29 | |
| 30 | |
| 31 | /* |
| 32 | * cstring_in - input routine for pseudo-type CSTRING. |
| 33 | * |
| 34 | * We might as well allow this to support constructs like "foo_in('blah')". |
| 35 | */ |
| 36 | Datum |
| 37 | cstring_in(PG_FUNCTION_ARGS) |
| 38 | { |
| 39 | char *str = PG_GETARG_CSTRING(0); |
| 40 | |
| 41 | PG_RETURN_CSTRING(pstrdup(str)); |
| 42 | } |
| 43 | |
| 44 | /* |
| 45 | * cstring_out - output routine for pseudo-type CSTRING. |
| 46 | * |
| 47 | * We allow this mainly so that "SELECT some_output_function(...)" does |
| 48 | * what the user will expect. |
| 49 | */ |
| 50 | Datum |
| 51 | cstring_out(PG_FUNCTION_ARGS) |
| 52 | { |
| 53 | char *str = PG_GETARG_CSTRING(0); |
| 54 | |
| 55 | PG_RETURN_CSTRING(pstrdup(str)); |
| 56 | } |
| 57 | |
| 58 | /* |
| 59 | * cstring_recv - binary input routine for pseudo-type CSTRING. |
| 60 | */ |
| 61 | Datum |
| 62 | cstring_recv(PG_FUNCTION_ARGS) |
| 63 | { |
| 64 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
| 65 | char *str; |
| 66 | int nbytes; |
| 67 | |
| 68 | str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); |
| 69 | PG_RETURN_CSTRING(str); |
| 70 | } |
| 71 | |
| 72 | /* |
| 73 | * cstring_send - binary output routine for pseudo-type CSTRING. |
| 74 | */ |
| 75 | Datum |
| 76 | cstring_send(PG_FUNCTION_ARGS) |
| 77 | { |
| 78 | char *str = PG_GETARG_CSTRING(0); |
| 79 | StringInfoData buf; |
| 80 | |
| 81 | pq_begintypsend(&buf); |
| 82 | pq_sendtext(&buf, str, strlen(str)); |
| 83 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
| 84 | } |
| 85 | |
| 86 | /* |
| 87 | * anyarray_in - input routine for pseudo-type ANYARRAY. |
| 88 | */ |
| 89 | Datum |
| 90 | anyarray_in(PG_FUNCTION_ARGS) |
| 91 | { |
| 92 | ereport(ERROR, |
| 93 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 94 | errmsg("cannot accept a value of type %s" , "anyarray" ))); |
| 95 | |
| 96 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 97 | } |
| 98 | |
| 99 | /* |
| 100 | * anyarray_out - output routine for pseudo-type ANYARRAY. |
| 101 | * |
| 102 | * We may as well allow this, since array_out will in fact work. |
| 103 | */ |
| 104 | Datum |
| 105 | anyarray_out(PG_FUNCTION_ARGS) |
| 106 | { |
| 107 | return array_out(fcinfo); |
| 108 | } |
| 109 | |
| 110 | /* |
| 111 | * anyarray_recv - binary input routine for pseudo-type ANYARRAY. |
| 112 | * |
| 113 | * XXX this could actually be made to work, since the incoming array |
| 114 | * data will contain the element type OID. Need to think through |
| 115 | * type-safety issues before allowing it, however. |
| 116 | */ |
| 117 | Datum |
| 118 | anyarray_recv(PG_FUNCTION_ARGS) |
| 119 | { |
| 120 | ereport(ERROR, |
| 121 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 122 | errmsg("cannot accept a value of type %s" , "anyarray" ))); |
| 123 | |
| 124 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 125 | } |
| 126 | |
| 127 | /* |
| 128 | * anyarray_send - binary output routine for pseudo-type ANYARRAY. |
| 129 | * |
| 130 | * We may as well allow this, since array_send will in fact work. |
| 131 | */ |
| 132 | Datum |
| 133 | anyarray_send(PG_FUNCTION_ARGS) |
| 134 | { |
| 135 | return array_send(fcinfo); |
| 136 | } |
| 137 | |
| 138 | |
| 139 | /* |
| 140 | * anyenum_in - input routine for pseudo-type ANYENUM. |
| 141 | */ |
| 142 | Datum |
| 143 | anyenum_in(PG_FUNCTION_ARGS) |
| 144 | { |
| 145 | ereport(ERROR, |
| 146 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 147 | errmsg("cannot accept a value of type %s" , "anyenum" ))); |
| 148 | |
| 149 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 150 | } |
| 151 | |
| 152 | /* |
| 153 | * anyenum_out - output routine for pseudo-type ANYENUM. |
| 154 | * |
| 155 | * We may as well allow this, since enum_out will in fact work. |
| 156 | */ |
| 157 | Datum |
| 158 | anyenum_out(PG_FUNCTION_ARGS) |
| 159 | { |
| 160 | return enum_out(fcinfo); |
| 161 | } |
| 162 | |
| 163 | /* |
| 164 | * anyrange_in - input routine for pseudo-type ANYRANGE. |
| 165 | */ |
| 166 | Datum |
| 167 | anyrange_in(PG_FUNCTION_ARGS) |
| 168 | { |
| 169 | ereport(ERROR, |
| 170 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 171 | errmsg("cannot accept a value of type %s" , "anyrange" ))); |
| 172 | |
| 173 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 174 | } |
| 175 | |
| 176 | /* |
| 177 | * anyrange_out - output routine for pseudo-type ANYRANGE. |
| 178 | * |
| 179 | * We may as well allow this, since range_out will in fact work. |
| 180 | */ |
| 181 | Datum |
| 182 | anyrange_out(PG_FUNCTION_ARGS) |
| 183 | { |
| 184 | return range_out(fcinfo); |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | * void_in - input routine for pseudo-type VOID. |
| 189 | * |
| 190 | * We allow this so that PL functions can return VOID without any special |
| 191 | * hack in the PL handler. Whatever value the PL thinks it's returning |
| 192 | * will just be ignored. |
| 193 | */ |
| 194 | Datum |
| 195 | void_in(PG_FUNCTION_ARGS) |
| 196 | { |
| 197 | PG_RETURN_VOID(); /* you were expecting something different? */ |
| 198 | } |
| 199 | |
| 200 | /* |
| 201 | * void_out - output routine for pseudo-type VOID. |
| 202 | * |
| 203 | * We allow this so that "SELECT function_returning_void(...)" works. |
| 204 | */ |
| 205 | Datum |
| 206 | void_out(PG_FUNCTION_ARGS) |
| 207 | { |
| 208 | PG_RETURN_CSTRING(pstrdup("" )); |
| 209 | } |
| 210 | |
| 211 | /* |
| 212 | * void_recv - binary input routine for pseudo-type VOID. |
| 213 | * |
| 214 | * Note that since we consume no bytes, an attempt to send anything but |
| 215 | * an empty string will result in an "invalid message format" error. |
| 216 | */ |
| 217 | Datum |
| 218 | void_recv(PG_FUNCTION_ARGS) |
| 219 | { |
| 220 | PG_RETURN_VOID(); |
| 221 | } |
| 222 | |
| 223 | /* |
| 224 | * void_send - binary output routine for pseudo-type VOID. |
| 225 | * |
| 226 | * We allow this so that "SELECT function_returning_void(...)" works |
| 227 | * even when binary output is requested. |
| 228 | */ |
| 229 | Datum |
| 230 | void_send(PG_FUNCTION_ARGS) |
| 231 | { |
| 232 | StringInfoData buf; |
| 233 | |
| 234 | /* send an empty string */ |
| 235 | pq_begintypsend(&buf); |
| 236 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
| 237 | } |
| 238 | |
| 239 | /* |
| 240 | * shell_in - input routine for "shell" types (those not yet filled in). |
| 241 | */ |
| 242 | Datum |
| 243 | shell_in(PG_FUNCTION_ARGS) |
| 244 | { |
| 245 | ereport(ERROR, |
| 246 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 247 | errmsg("cannot accept a value of a shell type" ))); |
| 248 | |
| 249 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 250 | } |
| 251 | |
| 252 | /* |
| 253 | * shell_out - output routine for "shell" types. |
| 254 | */ |
| 255 | Datum |
| 256 | shell_out(PG_FUNCTION_ARGS) |
| 257 | { |
| 258 | ereport(ERROR, |
| 259 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 260 | errmsg("cannot display a value of a shell type" ))); |
| 261 | |
| 262 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 263 | } |
| 264 | |
| 265 | |
| 266 | /* |
| 267 | * pg_node_tree_in - input routine for type PG_NODE_TREE. |
| 268 | * |
| 269 | * pg_node_tree isn't really a pseudotype --- it's real enough to be a table |
| 270 | * column --- but it presently has no operations of its own, and disallows |
| 271 | * input too, so its I/O functions seem to fit here as much as anywhere. |
| 272 | */ |
| 273 | Datum |
| 274 | pg_node_tree_in(PG_FUNCTION_ARGS) |
| 275 | { |
| 276 | /* |
| 277 | * We disallow input of pg_node_tree values because the SQL functions that |
| 278 | * operate on the type are not secure against malformed input. |
| 279 | */ |
| 280 | ereport(ERROR, |
| 281 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 282 | errmsg("cannot accept a value of type %s" , "pg_node_tree" ))); |
| 283 | |
| 284 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 285 | } |
| 286 | |
| 287 | |
| 288 | /* |
| 289 | * pg_node_tree_out - output routine for type PG_NODE_TREE. |
| 290 | * |
| 291 | * The internal representation is the same as TEXT, so just pass it off. |
| 292 | */ |
| 293 | Datum |
| 294 | pg_node_tree_out(PG_FUNCTION_ARGS) |
| 295 | { |
| 296 | return textout(fcinfo); |
| 297 | } |
| 298 | |
| 299 | /* |
| 300 | * pg_node_tree_recv - binary input routine for type PG_NODE_TREE. |
| 301 | */ |
| 302 | Datum |
| 303 | pg_node_tree_recv(PG_FUNCTION_ARGS) |
| 304 | { |
| 305 | ereport(ERROR, |
| 306 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 307 | errmsg("cannot accept a value of type %s" , "pg_node_tree" ))); |
| 308 | |
| 309 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 310 | } |
| 311 | |
| 312 | /* |
| 313 | * pg_node_tree_send - binary output routine for type PG_NODE_TREE. |
| 314 | */ |
| 315 | Datum |
| 316 | pg_node_tree_send(PG_FUNCTION_ARGS) |
| 317 | { |
| 318 | return textsend(fcinfo); |
| 319 | } |
| 320 | |
| 321 | /* |
| 322 | * pg_ddl_command_in - input routine for type PG_DDL_COMMAND. |
| 323 | * |
| 324 | * Like pg_node_tree, pg_ddl_command isn't really a pseudotype; it's here for |
| 325 | * the same reasons as that one. |
| 326 | */ |
| 327 | Datum |
| 328 | pg_ddl_command_in(PG_FUNCTION_ARGS) |
| 329 | { |
| 330 | /* |
| 331 | * Disallow input of pg_ddl_command value. |
| 332 | */ |
| 333 | ereport(ERROR, |
| 334 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 335 | errmsg("cannot accept a value of type %s" , "pg_ddl_command" ))); |
| 336 | |
| 337 | PG_RETURN_VOID(); /* keep compiler quiet */ |
| 338 | } |
| 339 | |
| 340 | /* |
| 341 | * pg_ddl_command_out - output routine for type PG_DDL_COMMAND. |
| 342 | * |
| 343 | * We don't have any good way to output this type directly, so punt. |
| 344 | */ |
| 345 | Datum |
| 346 | pg_ddl_command_out(PG_FUNCTION_ARGS) |
| 347 | { |
| 348 | ereport(ERROR, |
| 349 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 350 | errmsg("cannot output a value of type %s" , "pg_ddl_command" ))); |
| 351 | |
| 352 | PG_RETURN_VOID(); |
| 353 | } |
| 354 | |
| 355 | /* |
| 356 | * pg_ddl_command_recv - binary input routine for type PG_DDL_COMMAND. |
| 357 | */ |
| 358 | Datum |
| 359 | pg_ddl_command_recv(PG_FUNCTION_ARGS) |
| 360 | { |
| 361 | ereport(ERROR, |
| 362 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 363 | errmsg("cannot accept a value of type %s" , "pg_ddl_command" ))); |
| 364 | |
| 365 | PG_RETURN_VOID(); |
| 366 | } |
| 367 | |
| 368 | /* |
| 369 | * pg_ddl_command_send - binary output routine for type PG_DDL_COMMAND. |
| 370 | */ |
| 371 | Datum |
| 372 | pg_ddl_command_send(PG_FUNCTION_ARGS) |
| 373 | { |
| 374 | ereport(ERROR, |
| 375 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 376 | errmsg("cannot output a value of type %s" , "pg_ddl_command" ))); |
| 377 | |
| 378 | PG_RETURN_VOID(); |
| 379 | } |
| 380 | |
| 381 | |
| 382 | /* |
| 383 | * Generate input and output functions for a pseudotype that will reject all |
| 384 | * input and output attempts. |
| 385 | */ |
| 386 | #define PSEUDOTYPE_DUMMY_IO_FUNCS(typname) \ |
| 387 | \ |
| 388 | Datum \ |
| 389 | typname##_in(PG_FUNCTION_ARGS) \ |
| 390 | { \ |
| 391 | ereport(ERROR, \ |
| 392 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ |
| 393 | errmsg("cannot accept a value of type %s", #typname))); \ |
| 394 | \ |
| 395 | PG_RETURN_VOID(); /* keep compiler quiet */ \ |
| 396 | } \ |
| 397 | \ |
| 398 | Datum \ |
| 399 | typname##_out(PG_FUNCTION_ARGS) \ |
| 400 | { \ |
| 401 | ereport(ERROR, \ |
| 402 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ |
| 403 | errmsg("cannot display a value of type %s", #typname))); \ |
| 404 | \ |
| 405 | PG_RETURN_VOID(); /* keep compiler quiet */ \ |
| 406 | } \ |
| 407 | \ |
| 408 | extern int no_such_variable |
| 409 | |
| 410 | PSEUDOTYPE_DUMMY_IO_FUNCS(any); |
| 411 | PSEUDOTYPE_DUMMY_IO_FUNCS(trigger); |
| 412 | PSEUDOTYPE_DUMMY_IO_FUNCS(event_trigger); |
| 413 | PSEUDOTYPE_DUMMY_IO_FUNCS(language_handler); |
| 414 | PSEUDOTYPE_DUMMY_IO_FUNCS(fdw_handler); |
| 415 | PSEUDOTYPE_DUMMY_IO_FUNCS(index_am_handler); |
| 416 | PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler); |
| 417 | PSEUDOTYPE_DUMMY_IO_FUNCS(internal); |
| 418 | PSEUDOTYPE_DUMMY_IO_FUNCS(opaque); |
| 419 | PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement); |
| 420 | PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray); |
| 421 | PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler); |
| 422 | |