@@ -14,14 +14,17 @@ import (
1414 "github.com/cockroachdb/cockroach/pkg/ccl/changefeedccl/cdctest"
1515 "github.com/cockroachdb/cockroach/pkg/jobs/jobspb"
1616 "github.com/cockroachdb/cockroach/pkg/repstream/streampb"
17+ "github.com/cockroachdb/cockroach/pkg/sql/catalog"
1718 "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
1819 "github.com/cockroachdb/cockroach/pkg/sql/catalog/descs"
20+ "github.com/cockroachdb/cockroach/pkg/sql/randgen"
1921 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
2022 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
2123 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
2224 "github.com/cockroachdb/cockroach/pkg/util/hlc"
2325 "github.com/cockroachdb/cockroach/pkg/util/leaktest"
2426 "github.com/cockroachdb/cockroach/pkg/util/log"
27+ "github.com/cockroachdb/cockroach/pkg/util/randutil"
2528 "github.com/stretchr/testify/require"
2629)
2730
@@ -197,3 +200,81 @@ func TestEventDecoder_DeduplicationWithDiscardDelete(t *testing.T) {
197200 require .Equal (t , tree .NewDString ("inserted" ), events [1 ].row [1 ])
198201 require .Equal (t , tree .DNull , events [1 ].prevRow [1 ])
199202}
203+
204+ func TestEventDecoder_UserDefinedTypes (t * testing.T ) {
205+ defer leaktest .AfterTest (t )()
206+ defer log .Scope (t ).Close (t )
207+
208+ // TODO(jeffswenson): it would be nice if we could implement this test using
209+ // the randgen package, but randgen appears to be missing a utililty that
210+ // lets us create a random table random dependent UDTs.
211+
212+ ctx := context .Background ()
213+ rng , _ := randutil .NewTestRand ()
214+
215+ srv , sqlDB , _ := serverutils .StartServer (t , base.TestServerArgs {})
216+ defer srv .Stopper ().Stop (ctx )
217+ server := srv .ApplicationLayer ()
218+ runner := sqlutils .MakeSQLRunner (sqlDB )
219+
220+ for _ , db := range []string {"srcdb" , "dstdb" } {
221+ runner .Exec (t , "CREATE DATABASE " + db )
222+ runner .Exec (t , "USE " + db )
223+ runner .Exec (t , "CREATE TYPE status_enum AS ENUM ('active', 'inactive')" )
224+ runner .Exec (t , "CREATE TYPE metadata_type AS (key TEXT, value INT)" )
225+ runner .Exec (t , `CREATE TABLE user_types (
226+ id INT PRIMARY KEY,
227+ status status_enum,
228+ tags TEXT[],
229+ metadata metadata_type
230+ )` )
231+ }
232+
233+ srcDesc := cdctest .GetHydratedTableDescriptor (t , server .ExecutorConfig (), "srcdb" , "public" , "user_types" )
234+ dstDesc := cdctest .GetHydratedTableDescriptor (t , server .ExecutorConfig (), "dstdb" , "public" , "user_types" )
235+
236+ decoder , err := newEventDecoder (ctx , server .InternalDB ().(descs.DB ), server .ClusterSettings (), map [descpb.ID ]sqlProcessorTableConfig {
237+ dstDesc .GetID (): {srcDesc : srcDesc },
238+ })
239+ require .NoError (t , err )
240+
241+ eb := newKvEventBuilder (t , srcDesc .TableDesc ())
242+
243+ // Build test row with user-defined types
244+ enumType := catalog .FindColumnByName (srcDesc , "status" ).GetType ()
245+ arrayType := catalog .FindColumnByName (srcDesc , "tags" ).GetType ()
246+ tupleType := catalog .FindColumnByName (srcDesc , "metadata" ).GetType ()
247+ testRow := tree.Datums {
248+ tree .NewDInt (1 ),
249+ & tree.DEnum {
250+ EnumTyp : enumType ,
251+ PhysicalRep : enumType .TypeMeta .EnumData .PhysicalRepresentations [0 ], // Use correct physical rep
252+ LogicalRep : enumType .TypeMeta .EnumData .LogicalRepresentations [0 ], // Use correct logical rep
253+ },
254+ randgen .RandDatum (rng , arrayType , false ).(* tree.DArray ),
255+ randgen .RandDatum (rng , tupleType , false ).(* tree.DTuple ),
256+ }
257+
258+ insertEvent := eb .insertEvent (server .Clock ().Now (), testRow )
259+ events , err := decoder .decodeAndCoalesceEvents (ctx , []streampb.StreamEvent_KV {insertEvent }, jobspb .LogicalReplicationDetails_DiscardNothing )
260+ require .NoError (t , err )
261+ require .Len (t , events , 1 )
262+
263+ row := events [0 ].row
264+ require .Len (t , row , 4 )
265+
266+ // Verify enum type mapping
267+ enum := row [1 ].(* tree.DEnum )
268+ dstEnumType := catalog .FindColumnByName (dstDesc , "status" ).GetType ()
269+ require .Equal (t , dstEnumType , enum .EnumTyp )
270+
271+ // Verify array type mapping
272+ array := row [2 ].(* tree.DArray )
273+ dstArrayType := catalog .FindColumnByName (dstDesc , "tags" ).GetType ()
274+ require .Equal (t , dstArrayType , array .ParamTyp )
275+
276+ // Verify tuple type mapping
277+ tuple := row [3 ].(* tree.DTuple )
278+ dstTupleType := catalog .FindColumnByName (dstDesc , "metadata" ).GetType ()
279+ require .Equal (t , dstTupleType , tuple .ResolvedType ())
280+ }
0 commit comments