@@ -383,40 +383,51 @@ DECLARE_PG_FUNCTION(pgduckdb_recycle_ddb) {
383383}
384384
385385Node *
386- CoerceRowSubscriptToText (struct ParseState *pstate, A_Indices *subscript) {
386+ CoerceSubscriptToText (struct ParseState *pstate, A_Indices *subscript, const char *type_name ) {
387387 if (!subscript->uidx ) {
388- elog (ERROR, " Creating a slice out of duckdb.row is not supported" );
388+ elog (ERROR, " Creating a slice out of %s is not supported" , type_name );
389389 }
390390
391391 Node *subscript_expr = transformExpr (pstate, subscript->uidx , pstate->p_expr_kind );
392392 int expr_location = exprLocation (subscript->uidx );
393393 Oid subscript_expr_type = exprType (subscript_expr);
394394
395395 if (subscript->lidx ) {
396- elog (ERROR, " Creating a slice out of duckdb.row is not supported" );
396+ elog (ERROR, " Creating a slice out of %s is not supported" , type_name );
397397 }
398398
399399 Node *coerced_expr = coerce_to_target_type (pstate, subscript_expr, subscript_expr_type, TEXTOID, -1 ,
400400 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, expr_location);
401401 if (!coerced_expr) {
402- ereport (ERROR, (errcode (ERRCODE_DATATYPE_MISMATCH), errmsg (" duckdb.row subscript must have text type" ),
402+ ereport (ERROR, (errcode (ERRCODE_DATATYPE_MISMATCH), errmsg (" %s subscript must have text type" , type_name ),
403403 parser_errposition (pstate, expr_location)));
404404 }
405405
406406 if (!IsA (subscript_expr, Const)) {
407- ereport (ERROR, (errcode (ERRCODE_DATATYPE_MISMATCH), errmsg (" duckdb.row subscript must be a constant" ),
407+ ereport (ERROR, (errcode (ERRCODE_DATATYPE_MISMATCH), errmsg (" %s subscript must be a constant" , type_name ),
408408 parser_errposition (pstate, expr_location)));
409409 }
410410
411411 Const *subscript_const = castNode (Const, subscript_expr);
412412 if (subscript_const->constisnull ) {
413- ereport (ERROR, (errcode (ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg (" duckdb.row subscript cannot be NULL" ),
413+ ereport (ERROR, (errcode (ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg (" %s subscript cannot be NULL" , type_name ),
414414 parser_errposition (pstate, expr_location)));
415415 }
416416
417417 return coerced_expr;
418418}
419419
420+ Node *
421+ CoerceRowSubscriptToText (struct ParseState *pstate, A_Indices *subscript) {
422+ return CoerceSubscriptToText (pstate, subscript, " duckdb.row" );
423+ }
424+
425+ // Cloned implementation from CoerceRowSubscriptToText
426+ Node *
427+ CoerceStructSubscriptToText (struct ParseState *pstate, A_Indices *subscript) {
428+ return CoerceSubscriptToText (pstate, subscript, " duckdb.struct" );
429+ }
430+
420431/*
421432 * In Postgres all index operations in a row ar all slices or all plain
422433 * index operations. If you mix them, all are converted to slices.
@@ -456,29 +467,29 @@ AddSubscriptExpressions(SubscriptingRef *sbsref, struct ParseState *pstate, A_In
456467}
457468
458469/*
459- * DuckdbRowSubscriptTransform is called by the parser when a subscripting
470+ * DuckdbSubscriptTransform is called by the parser when a subscripting
460471 * operation is performed on a duckdb.row. It has two main puprposes:
461472 * 1. Ensure that the row is being indexed using a string literal
462473 * 2. Ensure that the return type of this index operation is duckdb.unresolved_type
463474 */
464475void
465- DuckdbRowSubscriptTransform (SubscriptingRef *sbsref, List *indirection, struct ParseState *pstate, bool isSlice,
466- bool isAssignment ) {
476+ DuckdbSubscriptTransform (SubscriptingRef *sbsref, List *indirection, struct ParseState *pstate, bool isSlice,
477+ bool isAssignment, const char *type_name ) {
467478 /*
468479 * We need to populate our cache for some of the code below. Normally this
469480 * cache is populated at the start of our planner hook, but this function
470481 * is being called from the parser.
471482 */
472483 if (!pgduckdb::IsExtensionRegistered ()) {
473- elog (ERROR, " BUG: Using duckdb.row but the pg_duckdb extension is not installed" );
484+ elog (ERROR, " BUG: Using %s but the pg_duckdb extension is not installed" , type_name );
474485 }
475486
476487 if (isAssignment) {
477- elog (ERROR, " Assignment to duckdb.row is not supported" );
488+ elog (ERROR, " Assignment to %s is not supported" , type_name );
478489 }
479490
480491 if (indirection == NIL) {
481- elog (ERROR, " Subscripting duckdb.row with an empty subscript is not supported" );
492+ elog (ERROR, " Subscripting %s with an empty subscript is not supported" , type_name );
482493 }
483494
484495 bool first = true ;
@@ -505,6 +516,18 @@ DuckdbRowSubscriptTransform(SubscriptingRef *sbsref, List *indirection, struct P
505516 sbsref->reftypmod = -1 ;
506517}
507518
519+ void
520+ DuckdbRowSubscriptTransform (SubscriptingRef *sbsref, List *indirection, struct ParseState *pstate, bool isSlice,
521+ bool isAssignment) {
522+ DuckdbSubscriptTransform (sbsref, indirection, pstate, isSlice, isAssignment, " duckdb.row" );
523+ }
524+
525+ void
526+ DuckdbStructSubscriptTransform (SubscriptingRef *sbsref, List *indirection, struct ParseState *pstate, bool isSlice,
527+ bool isAssignment) {
528+ DuckdbSubscriptTransform (sbsref, indirection, pstate, isSlice, isAssignment, " duckdb.struct" );
529+ }
530+
508531/*
509532 * DuckdbRowSubscriptExecSetup is called by the executor when a subscripting
510533 * operation is performed on a duckdb.row. This should never happen, because
@@ -529,6 +552,24 @@ DECLARE_PG_FUNCTION(duckdb_row_subscript) {
529552 PG_RETURN_POINTER (&duckdb_row_subscript_routines);
530553}
531554
555+ void
556+ DuckdbStructSubscriptExecSetup (const SubscriptingRef * /* sbsref*/ , SubscriptingRefState * /* sbsrefstate*/ ,
557+ SubscriptExecSteps * /* exprstate*/ ) {
558+ elog (ERROR, " Subscripting duckdb.struct is not supported in the Postgres Executor" );
559+ }
560+
561+ static SubscriptRoutines duckdb_struct_subscript_routines = {
562+ .transform = DuckdbStructSubscriptTransform,
563+ .exec_setup = DuckdbStructSubscriptExecSetup,
564+ .fetch_strict = false ,
565+ .fetch_leakproof = true ,
566+ .store_leakproof = true ,
567+ };
568+
569+ DECLARE_PG_FUNCTION (duckdb_struct_subscript) {
570+ PG_RETURN_POINTER (&duckdb_struct_subscript_routines);
571+ }
572+
532573/*
533574 * DuckdbUnresolvedTypeSubscriptTransform is called by the parser when a
534575 * subscripting operation is performed on a duckdb.unresolved_type. All this
@@ -597,6 +638,14 @@ DECLARE_PG_FUNCTION(duckdb_row_out) {
597638 elog (ERROR, " Converting a duckdb.row to a string is not supported" );
598639}
599640
641+ DECLARE_PG_FUNCTION (duckdb_struct_in) {
642+ elog (ERROR, " Creating the duckdb.struct type is not supported" );
643+ }
644+
645+ DECLARE_PG_FUNCTION (duckdb_struct_out) {
646+ return textout (fcinfo);
647+ }
648+
600649DECLARE_PG_FUNCTION (duckdb_unresolved_type_in) {
601650 return textin (fcinfo);
602651}
0 commit comments