44#include "access/htup.h"
55#include "access/htup_details.h"
66#include "catalog/dependency.h"
7+ #include "catalog/pg_operator_d.h"
78#include "catalog/pg_proc.h"
89#include "catalog/pg_type.h"
910#include "commands/defrem.h"
5051#define F_EXTRACT_TEXT_TIMESTAMP 6202
5152#define F_EXTRACT_TEXT_TIMESTAMPTZ 6203
5253#define F_EXTRACT_TEXT_DATE 6199
54+ #define F_TRIM_ARRAY 6172
55+ #define F_STRING_TO_ARRAY_TEXT_TEXT 394
56+ #define F_STRING_TO_ARRAY_TEXT_TEXT_TEXT 376
57+ #define F_ARRAY_TO_STRING_ANYARRAY_TEXT 395
58+ #define F_ARRAY_TO_STRING_ANYARRAY_TEXT_TEXT 384
59+ #define F_ARRAY_FILL_ANYELEMENT__INT4 F_ARRAY_FILL
60+ #define F_ARRAY_FILL_ANYELEMENT__INT4__INT4 F_ARRAY_FILL_WITH_LOWER_BOUNDS
61+ #define F_CARDINALITY F_ARRAY_CARDINALITY
5362#endif
54- /* regexp_like was added in Postgres 15; Mock it for earlier versions. */
63+ /* regexp_like was added in Postgres 15 */
5564#if PG_VERSION_NUM < 150000
5665#define F_REGEXP_LIKE_TEXT_TEXT 6263
5766#define F_REGEXP_LIKE_TEXT_TEXT_TEXT 6264
5867#endif
68+ /* array_shuffle, array_sample added in Postgres 16 */
69+ #if PG_VERSION_NUM < 160000
70+ #define F_ARRAY_SHUFFLE 6215
71+ #define F_ARRAY_SAMPLE 6216
72+ #endif
73+ /* array_reverse, array_sort added in Postgres 18 */
74+ #if PG_VERSION_NUM < 180000
75+ #define F_ARRAY_REVERSE 6381
76+ #define F_ARRAY_SORT_ANYARRAY 6388
77+ #define F_ARRAY_SORT_ANYARRAY_BOOL 6389
78+ #define F_ARRAY_SORT_ANYARRAY_BOOL_BOOL 6390
79+ #endif
5980
6081#define STR_STARTS_WITH (str , sub ) strncmp(str, sub, strlen(sub)) == 0
6182#define STR_EQUAL (a , b ) strcmp(a, b) == 0
@@ -217,6 +238,34 @@ chfdw_check_for_custom_function(Oid funcid)
217238 case F_CLOCK_TIMESTAMP :
218239 case F_CURRENT_SCHEMA :
219240 case F_CURRENT_DATABASE :
241+ /* array functions: simple mappings */
242+ case F_ARRAY_CAT :
243+ case F_ARRAY_APPEND :
244+ case F_ARRAY_REMOVE :
245+ case F_ARRAY_TO_STRING_ANYARRAY_TEXT :
246+ case F_CARDINALITY :
247+ case F_ARRAY_REVERSE :
248+ case F_ARRAY_SORT_ANYARRAY :
249+ case F_ARRAY_SHUFFLE :
250+ case F_ARRAY_SAMPLE :
251+ /* array functions: arg rewriting */
252+ case F_ARRAY_LENGTH :
253+ case F_ARRAY_PREPEND :
254+ case F_STRING_TO_ARRAY_TEXT_TEXT :
255+ case F_TRIM_ARRAY :
256+ case F_ARRAY_FILL_ANYELEMENT__INT4 :
257+ case F_ARRAY_SORT_ANYARRAY_BOOL :
258+ /* array functions: unshippable */
259+ case F_ARRAY_DIMS :
260+ case F_ARRAY_NDIMS :
261+ case F_ARRAY_LOWER :
262+ case F_ARRAY_UPPER :
263+ case F_ARRAY_REPLACE :
264+ case F_ARRAY_POSITIONS :
265+ case F_ARRAY_TO_STRING_ANYARRAY_TEXT_TEXT :
266+ case F_STRING_TO_ARRAY_TEXT_TEXT_TEXT :
267+ case F_ARRAY_FILL_ANYELEMENT__INT4__INT4 :
268+ case F_ARRAY_SORT_ANYARRAY_BOOL_BOOL :
220269 special_builtin = true;
221270 break ;
222271 default :
@@ -363,6 +412,69 @@ chfdw_check_for_custom_function(Oid funcid)
363412 entry -> custom_name [0 ] = '\1' ;
364413 break ;
365414 }
415+ /* array functions: unshippable */
416+ case F_ARRAY_DIMS :
417+ case F_ARRAY_NDIMS :
418+ case F_ARRAY_LOWER :
419+ case F_ARRAY_UPPER :
420+ case F_ARRAY_REPLACE :
421+ case F_ARRAY_POSITIONS :
422+ case F_ARRAY_TO_STRING_ANYARRAY_TEXT_TEXT :
423+ case F_STRING_TO_ARRAY_TEXT_TEXT_TEXT :
424+ case F_ARRAY_FILL_ANYELEMENT__INT4__INT4 :
425+ case F_ARRAY_SORT_ANYARRAY_BOOL_BOOL :
426+ entry -> cf_type = CF_UNSHIPPABLE ;
427+ break ;
428+ /* array functions: simple mappings */
429+ case F_ARRAY_CAT :
430+ strcpy (entry -> custom_name , "arrayConcat" );
431+ break ;
432+ case F_ARRAY_APPEND :
433+ strcpy (entry -> custom_name , "arrayPushBack" );
434+ break ;
435+ case F_ARRAY_REMOVE :
436+ strcpy (entry -> custom_name , "arrayRemove" );
437+ break ;
438+ case F_ARRAY_TO_STRING_ANYARRAY_TEXT :
439+ strcpy (entry -> custom_name , "arrayStringConcat" );
440+ break ;
441+ case F_CARDINALITY :
442+ case F_ARRAY_LENGTH :
443+ entry -> cf_type = CF_ARRAY_LENGTH ;
444+ strcpy (entry -> custom_name , "length" );
445+ break ;
446+ case F_ARRAY_REVERSE :
447+ strcpy (entry -> custom_name , "arrayReverse" );
448+ break ;
449+ case F_ARRAY_SORT_ANYARRAY :
450+ strcpy (entry -> custom_name , "arraySort" );
451+ break ;
452+ case F_ARRAY_SHUFFLE :
453+ strcpy (entry -> custom_name , "arrayShuffle" );
454+ break ;
455+ case F_ARRAY_SAMPLE :
456+ strcpy (entry -> custom_name , "arrayRandomSample" );
457+ break ;
458+ case F_ARRAY_PREPEND :
459+ entry -> cf_type = CF_ARRAY_PREPEND ;
460+ strcpy (entry -> custom_name , "arrayPushFront" );
461+ break ;
462+ case F_STRING_TO_ARRAY_TEXT_TEXT :
463+ entry -> cf_type = CF_STRING_TO_ARRAY ;
464+ strcpy (entry -> custom_name , "splitByString" );
465+ break ;
466+ case F_TRIM_ARRAY :
467+ entry -> cf_type = CF_TRIM_ARRAY ;
468+ strcpy (entry -> custom_name , "arrayResize" );
469+ break ;
470+ case F_ARRAY_FILL_ANYELEMENT__INT4 :
471+ entry -> cf_type = CF_ARRAY_FILL ;
472+ strcpy (entry -> custom_name , "arrayWithConstant" );
473+ break ;
474+ case F_ARRAY_SORT_ANYARRAY_BOOL :
475+ entry -> cf_type = CF_ARRAY_SORT_DESC ;
476+ entry -> custom_name [0 ] = '\1' ;
477+ break ;
366478 }
367479
368480 if (special_builtin )
@@ -426,39 +538,42 @@ chfdw_check_for_custom_type(Oid typeoid)
426538 return entry ;
427539}
428540
429- /*
430- * Operator-name to custom_object_type mapping table, searched linearly by
431- * classify_builtin_operator(). Keep in sync with the CF_* enum in fdw.h.
432- */
433- typedef struct
434- {
435- const char * oprname ;
436- custom_object_type ctype ;
437- } BuiltinOperatorMap ;
438-
439- static const BuiltinOperatorMap builtin_operator_map [] = {
440- {"~" , CF_REGEX_MATCH },
441- {"!~" , CF_REGEX_NO_MATCH },
442- {"~*" , CF_REGEX_ICASE_MATCH },
443- {"!~*" , CF_REGEX_ICASE_NO_MATCH },
444- {"->" , CF_JSONB_FETCHVAL },
445- {"->>" , CF_JSONB_FETCHVAL_TEXT },
446- };
541+ /* pg_operator_d.h only has oid_symbol for some operators */
542+ #define OID_TEXT_REGEX_NE_OP 642
543+ #define OID_TEXT_IREGEX_NE_OP 1229
544+ #define OID_JSONB_FETCHVAL_OP 3211
545+ #define OID_JSONB_FETCHVAL_TEXT_OP 3477
447546
448547/*
449- * Map a builtin operator name to its custom_object_type. Returns CF_USUAL
450- * when the operator needs no special handling and should follow the normal
451- * builtin shortcut (i.e. be presumed shippable with no rewrite).
548+ * Map a builtin operator OID to its custom_object_type. Returns CF_USUAL
549+ * when the operator needs no special handling.
452550 */
453551static custom_object_type
454- classify_builtin_operator (const char * oprname )
552+ classify_builtin_operator (Oid opoid )
455553{
456- for ( int i = 0 ; i < lengthof ( builtin_operator_map ); i ++ )
554+ switch ( opoid )
457555 {
458- if (strcmp (oprname , builtin_operator_map [i ].oprname ) == 0 )
459- return builtin_operator_map [i ].ctype ;
556+ case OID_TEXT_REGEXEQ_OP :
557+ return CF_REGEX_MATCH ;
558+ case OID_TEXT_REGEX_NE_OP :
559+ return CF_REGEX_NO_MATCH ;
560+ case OID_TEXT_ICREGEXEQ_OP :
561+ return CF_REGEX_ICASE_MATCH ;
562+ case OID_TEXT_IREGEX_NE_OP :
563+ return CF_REGEX_ICASE_NO_MATCH ;
564+ case OID_JSONB_FETCHVAL_OP :
565+ return CF_JSONB_FETCHVAL ;
566+ case OID_JSONB_FETCHVAL_TEXT_OP :
567+ return CF_JSONB_FETCHVAL_TEXT ;
568+ case OID_ARRAY_CONTAINS_OP :
569+ return CF_ARRAY_CONTAINS ;
570+ case OID_ARRAY_CONTAINED_OP :
571+ return CF_ARRAY_CONTAINED_BY ;
572+ case OID_ARRAY_OVERLAP_OP :
573+ return CF_ARRAY_OVERLAP ;
574+ default :
575+ return CF_USUAL ;
460576 }
461- return CF_USUAL ;
462577}
463578
464579CustomObjectDef *
@@ -474,31 +589,10 @@ chfdw_check_for_custom_operator(Oid opoid, Form_pg_operator form)
474589
475590 if (chfdw_is_builtin (opoid ))
476591 {
477- switch (opoid )
592+ ctype = classify_builtin_operator (opoid );
593+ if (ctype == CF_USUAL && opoid != F_TIMESTAMPTZ_PL_INTERVAL )
478594 {
479- /* timestamptz + interval */
480- case F_TIMESTAMPTZ_PL_INTERVAL :
481- break ;
482- default :
483-
484- /* Look up the operator name so we can classify it. */
485- if (!form )
486- {
487- tuple = SearchSysCache1 (OPEROID , ObjectIdGetDatum (opoid ));
488- if (!HeapTupleIsValid (tuple ))
489- ereport (ERROR ,
490- errcode (ERRCODE_INTERNAL_ERROR ),
491- errmsg ("pg_clickhouse: cache lookup failed for operator %u" , opoid ));
492- form = (Form_pg_operator ) GETSTRUCT (tuple );
493- }
494-
495- ctype = classify_builtin_operator (NameStr (form -> oprname ));
496- if (ctype != CF_USUAL )
497- break ; /* fall through to cache + classify below */
498-
499- if (tuple )
500- ReleaseSysCache (tuple );
501- return NULL ;
595+ return NULL ;
502596 }
503597 }
504598
@@ -516,10 +610,11 @@ chfdw_check_for_custom_operator(Oid opoid, Form_pg_operator form)
516610 entry = hash_search (custom_objects_cache , (void * ) & opoid , HASH_ENTER , NULL );
517611 init_custom_entry (entry );
518612
613+ ctype = classify_builtin_operator (opoid );
519614 if (opoid == F_TIMESTAMPTZ_PL_INTERVAL )
520615 entry -> cf_type = CF_TIMESTAMPTZ_PL_INTERVAL ;
521- else if (form && classify_builtin_operator ( NameStr ( form -> oprname )) != CF_USUAL )
522- entry -> cf_type = classify_builtin_operator ( NameStr ( form -> oprname )) ;
616+ else if (ctype != CF_USUAL )
617+ entry -> cf_type = ctype ;
523618 else
524619 {
525620 Oid extoid = getExtensionOfObject (OperatorRelationId , opoid );
0 commit comments