@@ -219,7 +219,7 @@ convert_array(ch_convert_state * state, Datum val)
219219
220220 if (slot -> len == 0 )
221221 val = PointerGetDatum (construct_empty_array (slot -> item_type ));
222- else if (slot -> ndim = = 1 )
222+ else if (slot -> ndim < = 1 )
223223 {
224224 void * arrout = construct_array (slot -> datums , slot -> len , slot -> item_type ,
225225 state -> typlen , state -> typbyval , state -> typalign );
@@ -611,6 +611,49 @@ ch_binary_make_tuple_map(TupleDesc indesc, TupleDesc outdesc, Oid relid)
611611 return states ;
612612}
613613
614+ /*
615+ * Chunk a flat postgres array (already extracted into `flat`/`flatnulls` in
616+ * row-major order) into the nested ch_binary_array_t tree the binary engine
617+ * expects for Array(Array(...)) columns. Each interior node carries
618+ * ndim>1 with datums[i] = PointerGetDatum(child); leaves carry ndim==1 with
619+ * scalar datums copied from the flat buffer.
620+ */
621+ static ch_binary_array_t *
622+ build_nested_binary_array (int level , int ndim , int * dims , Oid item_type ,
623+ Datum * flat , bool * flatnulls , size_t * idx )
624+ {
625+ ch_binary_array_t * arr = palloc (sizeof (ch_binary_array_t ));
626+
627+ arr -> len = dims [level ];
628+ arr -> ndim = ndim - level ;
629+ arr -> item_type = item_type ;
630+ arr -> array_type = InvalidOid ;
631+ arr -> datums = palloc (sizeof (Datum ) * arr -> len );
632+ arr -> nulls = palloc0 (sizeof (bool ) * arr -> len );
633+
634+ if (level + 1 == ndim )
635+ {
636+ for (size_t i = 0 ; i < arr -> len ; i ++ )
637+ {
638+ arr -> datums [i ] = flat [* idx ];
639+ arr -> nulls [i ] = flatnulls [* idx ];
640+ (* idx )++ ;
641+ }
642+ }
643+ else
644+ {
645+ for (size_t i = 0 ; i < arr -> len ; i ++ )
646+ {
647+ ch_binary_array_t * child = build_nested_binary_array (level + 1 , ndim , dims ,
648+ item_type , flat ,
649+ flatnulls , idx );
650+
651+ arr -> datums [i ] = PointerGetDatum (child );
652+ }
653+ }
654+ return arr ;
655+ }
656+
614657void
615658ch_binary_do_output_conversion (ch_binary_insert_state * insert_state ,
616659 TupleTableSlot * slot )
@@ -633,24 +676,51 @@ ch_binary_do_output_conversion(ch_binary_insert_state * insert_state,
633676 AnyArrayType * v = DatumGetAnyArrayP (out_values [i ]);
634677 ch_binary_array_t * arr ;
635678 array_iter iter ;
679+ int ndim = AARR_NDIM (v );
680+ int * dims = AARR_DIMS (v );
681+ size_t total = ArrayGetNItems (ndim , dims );
636682
637- if (AARR_NDIM ( v ) > 1 )
683+ if (ndim > MAXDIM )
638684 ereport (ERROR ,
639- (errcode (ERRCODE_DATATYPE_MISMATCH ),
640- errmsg ("pg_clickhouse: inserted array should have one dimension" )));
641-
642- arr = palloc (sizeof (ch_binary_array_t ));
643- arr -> len = ArrayGetNItems (AARR_NDIM (v ), AARR_DIMS (v ));
644- arr -> ndim = 1 ;
645- arr -> datums = palloc (sizeof (Datum ) * arr -> len );
646- arr -> nulls = palloc (sizeof (bool ) * arr -> len );
647- arr -> item_type = cstate -> innertype ;
648-
649- array_iter_setup (& iter , v );
650- for (size_t j = 0 ; j < arr -> len ; j ++ )
685+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
686+ errmsg ("pg_clickhouse: inserted array depth %d exceeds maximum %d" ,
687+ ndim , MAXDIM )));
688+
689+ if (ndim <= 1 )
690+ {
691+ arr = palloc (sizeof (ch_binary_array_t ));
692+ arr -> len = total ;
693+ arr -> ndim = 1 ;
694+ arr -> item_type = cstate -> innertype ;
695+ arr -> array_type = InvalidOid ;
696+ arr -> datums = total ? palloc (sizeof (Datum ) * total ) : NULL ;
697+ arr -> nulls = total ? palloc (sizeof (bool ) * total ) : NULL ;
698+
699+ array_iter_setup (& iter , v );
700+ for (size_t j = 0 ; j < total ; j ++ )
701+ {
702+ arr -> datums [j ] = array_iter_next (& iter , & arr -> nulls [j ], j ,
703+ cstate -> typlen , cstate -> typbyval , cstate -> typalign );
704+ }
705+ }
706+ else
651707 {
652- arr -> datums [j ] = array_iter_next (& iter , & arr -> nulls [j ], i ,
653- cstate -> typlen , cstate -> typbyval , cstate -> typalign );
708+ Datum * flat = palloc (sizeof (Datum ) * total );
709+ bool * flatnulls = palloc0 (sizeof (bool ) * total );
710+ size_t idx = 0 ;
711+
712+ array_iter_setup (& iter , v );
713+ for (size_t j = 0 ; j < total ; j ++ )
714+ {
715+ flat [j ] = array_iter_next (& iter , & flatnulls [j ], j ,
716+ cstate -> typlen , cstate -> typbyval , cstate -> typalign );
717+ }
718+
719+ arr = build_nested_binary_array (0 , ndim , dims , cstate -> innertype ,
720+ flat , flatnulls , & idx );
721+
722+ pfree (flat );
723+ pfree (flatnulls );
654724 }
655725 out_values [i ] = PointerGetDatum (arr );
656726
0 commit comments