@@ -2,15 +2,16 @@ import { logger } from '@powersync/lib-services-framework';
22import * as sync_rules from '@powersync/service-sync-rules' ;
33import async from 'async' ;
44
5- import { framework , getUuidReplicaIdentityBson , Metrics , storage } from '@powersync/service-core' ;
6- import mysql from 'mysql2' ;
5+ import { ColumnDescriptor , framework , getUuidReplicaIdentityBson , Metrics , storage } from '@powersync/service-core' ;
6+ import mysql , { FieldPacket } from 'mysql2' ;
77
88import { BinLogEvent } from '@powersync/mysql-zongji' ;
99import * as common from '../common/common-index.js' ;
1010import * as zongji_utils from './zongji/zongji-utils.js' ;
1111import { MySQLConnectionManager } from './MySQLConnectionManager.js' ;
12- import { ReplicatedGTID } from '../common/common-index.js' ;
12+ import { isBinlogStillAvailable , ReplicatedGTID } from '../common/common-index.js' ;
1313import mysqlPromise from 'mysql2/promise' ;
14+ import { MySQLTypesMap } from '../utils/mysql_utils.js' ;
1415
1516export interface BinLogStreamOptions {
1617 connections : MySQLConnectionManager ;
@@ -211,10 +212,23 @@ AND table_type = 'BASE TABLE';`,
211212 */
212213 protected async checkInitialReplicated ( ) : Promise < boolean > {
213214 const status = await this . storage . getStatus ( ) ;
215+ const lastKnowGTID = status . checkpoint_lsn ? common . ReplicatedGTID . fromSerialized ( status . checkpoint_lsn ) : null ;
214216 if ( status . snapshot_done && status . checkpoint_lsn ) {
215- logger . info ( `Initial replication already done. MySQL appears healthy` ) ;
217+ logger . info ( `Initial replication already done.` ) ;
218+
219+ if ( lastKnowGTID ) {
220+ // Check if the binlog is still available. If it isn't we need to snapshot again.
221+ const connection = await this . connections . getConnection ( ) ;
222+ try {
223+ return await isBinlogStillAvailable ( connection , lastKnowGTID . position . filename ) ;
224+ } finally {
225+ connection . release ( ) ;
226+ }
227+ }
228+
216229 return true ;
217230 }
231+
218232 return false ;
219233 }
220234
@@ -270,17 +284,24 @@ AND table_type = 'BASE TABLE';`,
270284 logger . info ( `Replicating ${ table . qualifiedName } ` ) ;
271285 // TODO count rows and log progress at certain batch sizes
272286
287+ const columns = new Map < string , ColumnDescriptor > ( ) ;
273288 return new Promise < void > ( ( resolve , reject ) => {
274289 // MAX_EXECUTION_TIME(0) hint disables execution timeout for this query
275290 connection
276291 . query ( `SELECT /*+ MAX_EXECUTION_TIME(0) */ * FROM ${ table . schema } .${ table . table } ` )
277- . stream ( )
278292 . on ( 'error' , ( err ) => {
279293 reject ( err ) ;
280294 } )
281- . on ( 'data' , async ( row ) => {
295+ . on ( 'fields' , ( fields : FieldPacket [ ] ) => {
296+ // Map the columns and their types
297+ fields . forEach ( ( field ) => {
298+ const columnType = MySQLTypesMap [ field . type as number ] ;
299+ columns . set ( field . name , { name : field . name , type : columnType , typeId : field . type } ) ;
300+ } ) ;
301+ } )
302+ . on ( 'result' , async ( row ) => {
282303 connection . pause ( ) ;
283- const record = common . toSQLiteRow ( row ) ;
304+ const record = common . toSQLiteRow ( row , columns ) ;
284305
285306 await batch . save ( {
286307 tag : storage . SaveOperationTag . INSERT ,
0 commit comments