@@ -31,7 +31,7 @@ import {
3131} from '@powersync/service-sync-rules' ;
3232
3333import { PgManager } from './PgManager.js' ;
34- import { getPgOutputRelation , getRelId } from './PgRelation.js' ;
34+ import { getPgOutputRelation , getRelId , referencedColumnTypeIds } from './PgRelation.js' ;
3535import { checkSourceConfiguration , checkTableRls , getReplicationIdentityColumns } from './replication-utils.js' ;
3636import { ReplicationMetric } from '@powersync/service-types' ;
3737import {
@@ -188,28 +188,30 @@ export class WalStream {
188188
189189 let tableRows : any [ ] ;
190190 const prefix = tablePattern . isWildcard ? tablePattern . tablePrefix : undefined ;
191- if ( tablePattern . isWildcard ) {
192- const result = await db . query ( {
193- statement : `SELECT c.oid AS relid, c.relname AS table_name
191+
192+ {
193+ let query = `
194+ SELECT
195+ c.oid AS relid,
196+ c.relname AS table_name,
197+ (SELECT
198+ json_agg(DISTINCT a.atttypid)
199+ FROM pg_attribute a
200+ WHERE a.attnum > 0 AND NOT a.attisdropped AND a.attrelid = c.oid)
201+ AS column_types
194202 FROM pg_class c
195203 JOIN pg_namespace n ON n.oid = c.relnamespace
196204 WHERE n.nspname = $1
197- AND c.relkind = 'r'
198- AND c.relname LIKE $2` ,
199- params : [
200- { type : 'varchar' , value : schema } ,
201- { type : 'varchar' , value : tablePattern . tablePattern }
202- ]
203- } ) ;
204- tableRows = pgwire . pgwireRows ( result ) ;
205- } else {
205+ AND c.relkind = 'r'` ;
206+
207+ if ( tablePattern . isWildcard ) {
208+ query += ' AND c.relname LIKE $2' ;
209+ } else {
210+ query += ' AND c.relname = $2' ;
211+ }
212+
206213 const result = await db . query ( {
207- statement : `SELECT c.oid AS relid, c.relname AS table_name
208- FROM pg_class c
209- JOIN pg_namespace n ON n.oid = c.relnamespace
210- WHERE n.nspname = $1
211- AND c.relkind = 'r'
212- AND c.relname = $2` ,
214+ statement : query ,
213215 params : [
214216 { type : 'varchar' , value : schema } ,
215217 { type : 'varchar' , value : tablePattern . tablePattern }
@@ -218,6 +220,7 @@ export class WalStream {
218220
219221 tableRows = pgwire . pgwireRows ( result ) ;
220222 }
223+
221224 let result : storage . SourceTable [ ] = [ ] ;
222225
223226 for ( let row of tableRows ) {
@@ -257,16 +260,18 @@ export class WalStream {
257260
258261 const cresult = await getReplicationIdentityColumns ( db , relid ) ;
259262
260- const table = await this . handleRelation (
263+ const columnTypes = ( JSON . parse ( row . column_types ) as string [ ] ) . map ( ( e ) => Number ( e ) ) ;
264+ const table = await this . handleRelation ( {
261265 batch,
262- {
266+ descriptor : {
263267 name,
264268 schema,
265269 objectId : relid ,
266270 replicaIdColumns : cresult . replicationColumns
267271 } as SourceEntityDescriptor ,
268- false
269- ) ;
272+ snapshot : false ,
273+ referencedTypeIds : columnTypes
274+ } ) ;
270275
271276 result . push ( table ) ;
272277 }
@@ -672,7 +677,14 @@ WHERE oid = $1::regclass`,
672677 }
673678 }
674679
675- async handleRelation ( batch : storage . BucketStorageBatch , descriptor : SourceEntityDescriptor , snapshot : boolean ) {
680+ async handleRelation ( options : {
681+ batch : storage . BucketStorageBatch ;
682+ descriptor : SourceEntityDescriptor ;
683+ snapshot : boolean ;
684+ referencedTypeIds : number [ ] ;
685+ } ) {
686+ const { batch, descriptor, snapshot, referencedTypeIds } = options ;
687+
676688 if ( ! descriptor . objectId && typeof descriptor . objectId != 'number' ) {
677689 throw new ReplicationAssertionError ( `objectId expected, got ${ typeof descriptor . objectId } ` ) ;
678690 }
@@ -698,6 +710,9 @@ WHERE oid = $1::regclass`,
698710 // Truncate this table, in case a previous snapshot was interrupted.
699711 await batch . truncate ( [ result . table ] ) ;
700712
713+ // Ensure we have a description for custom types referenced in the table.
714+ await this . connections . types . fetchTypes ( referencedTypeIds ) ;
715+
701716 // Start the snapshot inside a transaction.
702717 // We use a dedicated connection for this.
703718 const db = await this . connections . snapshotConnection ( ) ;
@@ -939,7 +954,12 @@ WHERE oid = $1::regclass`,
939954
940955 for ( const msg of messages ) {
941956 if ( msg . tag == 'relation' ) {
942- await this . handleRelation ( batch , getPgOutputRelation ( msg ) , true ) ;
957+ await this . handleRelation ( {
958+ batch,
959+ descriptor : getPgOutputRelation ( msg ) ,
960+ snapshot : true ,
961+ referencedTypeIds : referencedColumnTypeIds ( msg )
962+ } ) ;
943963 } else if ( msg . tag == 'begin' ) {
944964 // This may span multiple transactions in the same chunk, or even across chunks.
945965 skipKeepalive = true ;
0 commit comments