1From d9bf27e15f4d3ebe73de27fa608c06c5049d34e3 Mon Sep 17 00:00:00 2001 2From: Liu Hongyang <liuhongyang4@huawei.com> 3Date: Fri, 15 Aug 2025 14:28:12 +0800 4Subject: [PATCH 06/12] Support-Binlog 5 6--- 7 src/sqlite3.c | 1522 ++++++++++++++++++++++++++++++++++++++++++++++++- 8 1 file changed, 1513 insertions(+), 9 deletions(-) 9 10diff --git a/src/sqlite3.c b/src/sqlite3.c 11index b433dfb..4105866 100644 12--- a/src/sqlite3.c 13+++ b/src/sqlite3.c 14@@ -2938,7 +2938,9 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); 15 #define SQLITE_DBCONFIG_SET_SHAREDBLOCK 2004 16 #define SQLITE_DBCONFIG_USE_SHAREDBLOCK 2005 17 #endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ 18- 19+#ifdef SQLITE_ENABLE_BINLOG 20+#define SQLITE_DBCONFIG_ENABLE_BINLOG 2006 /* Sqlite3BinlogConfig */ 21+#endif 22 /* 23 ** CAPI3REF: Set the Last Insert Rowid value. 24 ** METHOD: sqlite3 25@@ -5351,6 +5353,19 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*); 26 SQLITE_API int sqlite3_set_droptable_handle(sqlite3*, void (*xFunc)(sqlite3*,const char*,const char*)); 27 #endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ 28 29+#ifdef SQLITE_ENABLE_BINLOG 30+SQLITE_API int sqlite3_is_support_binlog(void); 31+ 32+SQLITE_API int sqlite3_replay_binlog(sqlite3 *srcDb, sqlite3 *destDb); 33+ 34+typedef enum BinlogFileCleanMode { 35+ BINLOG_FILE_CLEAN_ALL_MODE = 0, 36+ BINLOG_FILE_CLEAN_READ_MODE = 1, 37+ BINLOG_FILE_CLEAN_MODE_MAX, 38+} BinlogFileCleanModeE; 39+ 40+SQLITE_API int sqlite3_clean_binlog(sqlite3 *db, BinlogFileCleanModeE mode); 41+#endif 42 /* 43 ** CAPI3REF: Number of columns in a result set 44 ** METHOD: sqlite3_stmt 45@@ -17617,6 +17632,201 @@ typedef struct CodecParameter { 46 } CodecParameter; 47 #endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ 48 49+#ifdef SQLITE_ENABLE_BINLOG 50+/************** Begin of the header file of binlog ************************************/ 51+#define SQLITE_UUID_BLOB_LENGTH 16 52+ 53+typedef enum { 54+ ROW = 0, 55+} Sqlite3BinlogMode; 56+ 57+typedef enum { 58+ GMERR_OK = 0, 59+ GMERR_BASE = 1000000, 60+ GMERR_LOCK_NOT_AVAILABLE = GMERR_BASE + 12002, 61+ GMERR_BINLOG_READ_FINISH = GMERR_BASE + 29200, 62+} BinlogErrnoE; 63+ 64+typedef int BinlogErrno; 65+typedef void (*BinlogOnErrorFuncT)(void *pCtx, BinlogErrno errNo, char *errMsg, const char *dbPath); 66+typedef void (*BinlogOnLogFullFuncT)(void *pCtx, u16 currentCount, const char *dbPath); 67+typedef int (*BinlogOnErrnoTransFuncT)(BinlogErrno errNo); 68+ 69+typedef struct BinlogConfig { 70+ Sqlite3BinlogMode logMode; 71+ u16 fullCallbackThreshold; 72+ u32 maxFileSize; 73+ char *filePath; 74+ BinlogOnErrorFuncT onError; 75+ BinlogOnLogFullFuncT onLogFull; 76+ void *callbackCtx; 77+ u32 readHwmdelay; 78+ BinlogOnErrnoTransFuncT onErrnoTrans; 79+} BinlogConfigT; 80+ 81+typedef enum BinlogEventType { 82+ BINLOG_EVENT_TYPE_UNDEFINED = 0, 83+ BINLOG_EVENT_TYPE_DDL = 64, 84+ BINLOG_EVENT_TYPE_PRAGMA = 65, 85+ BINLOG_EVENT_TYPE_DML = 66, 86+ BINLOG_EVENT_TYPE_ROLLBACK = 67, 87+ BINLOG_EVENT_TYPE_ROW_START = 69, 88+ BINLOG_EVENT_TYPE_ROW_TABLE = 70, 89+ BINLOG_EVENT_TYPE_ROW_FULL_DATA = 71, 90+ BINLOG_EVENT_TYPE_ROW_COMMIT = 72, 91+ BINLOG_EVENT_TYPE_ROW_ROLLBACK = 73, 92+ BINLOG_EVENT_TYPE_BUTT, 93+} BinlogEventTypeE; 94+ 95+typedef u8 BinlogXidT[SQLITE_UUID_BLOB_LENGTH]; 96+ 97+typedef struct BinlogWriteData { 98+ BinlogEventTypeE type; 99+ BinlogXidT xid; 100+ char *data; 101+ u32 dataLength; 102+ int isFinishTrx; 103+} BinlogWriteDataT; 104+ 105+typedef struct BinlogEventHead { 106+ u32 checksum; 107+ u64 timestamp; 108+ u8 eventType; 109+ u32 eventLength; 110+ BinlogXidT xid; 111+ u64 nextEventPos; 112+} BinlogEventHeadT; 113+ 114+typedef struct BinlogEvent { 115+ BinlogEventHeadT head; 116+ u8 *body; 117+} BinlogEventT; 118+ 119+typedef struct BinlogReadResult { 120+ u32 eventNum; 121+ BinlogEventT **sqlEvent; 122+} BinlogReadResultT; 123+ 124+typedef struct BinlogInstanceT BinlogInstanceT; 125+typedef void (*BinlogFreeReadResult)(BinlogInstanceT *instance, BinlogReadResultT *readRes); 126+typedef BinlogErrno (*BinlogOpen)(const BinlogConfigT *, BinlogInstanceT **); 127+typedef BinlogErrno (*BinlogClose)(BinlogInstanceT *instance); 128+typedef BinlogErrno (*BinlogWrite)(BinlogInstanceT *instance, const BinlogWriteDataT *data); 129+typedef BinlogErrno (*BinlogRead)(BinlogInstanceT *instance, BinlogReadResultT **readRes); 130+typedef BinlogErrno (*BinlogFileClean)(BinlogInstanceT *instance, BinlogFileCleanModeE cleanMode); 131+typedef BinlogErrno (*BinlogLockRead)(BinlogInstanceT *instance); 132+typedef BinlogErrno (*BinlogUnlockRead)(BinlogInstanceT *instance); 133+/************** End of the header file of binlog ************************************/ 134+ 135+/************** Binlog typedef in sqlite3 BEGIN ************************************/ 136+#define BINLOG_FLAG_ENABLE 0x00000001 137+#define BINLOG_FLAG_UPDATE_TID 0x00000002 138+ 139+typedef struct Sqlite3BinlogConfig { 140+ Sqlite3BinlogMode mode; 141+ u16 fullCallbackThreshold; 142+ u32 maxFileSize; 143+ void (*xErrorCallback)(void *pCtx, int errNo, char *errMsg, const char *dbPath); 144+ void (*xLogFullCallback)(void *pCtx, u16 currentCount, const char *dbPath); 145+ void *callbackCtx; 146+} Sqlite3BinlogConfig; 147+ 148+typedef struct BinlogRow { 149+ int op; // one of the SQLITE_INSERT, SQLITE_UPDATE, SQLITE_DELETE 150+ sqlite3_int64 rowid; // rowid of changed data, -1 for without rowid table 151+ sqlite3_uint64 nData; // size of pData 152+ const char *pData; // pointer to the row data in record format 153+} BinlogRow; 154+ 155+/* stores the affected rows by one DML statement*/ 156+typedef struct BinlogDMLData { 157+ Table *pTable; // pointer to the table being modified 158+ char *pSavePointName; // savepoint name for all the rows modified by current statment 159+ int isSavePointReleased; // if the savepoint is released, used when free BinlogDMLData 160+} BinlogDMLData; 161+ 162+typedef void* BinlogLib; 163+ 164+typedef struct BinlogApi { 165+ BinlogLib binlogLib; 166+ BinlogOpen binlogOpenApi; 167+ BinlogClose binlogCloseApi; 168+ BinlogWrite binlogWriteApi; 169+ BinlogRead binlogReadApi; 170+ BinlogFreeReadResult binlogFreeReadResultApi; 171+ BinlogFileClean binlogFileCleanApi; 172+ BinlogLockRead binlogLockReadApi; 173+ BinlogUnlockRead binlogUnlockReadApi; 174+} BinlogApi; 175+ 176+typedef struct Sqlite3BinlogHandle { 177+ Sqlite3BinlogMode mode; 178+ void *callbackCtx; 179+ u64 flags; 180+ u8 xTid[SQLITE_UUID_BLOB_LENGTH]; 181+ void (*xErrorCallback)(void *pCtx, int errNo, char *errMsg, const char *dbPath); 182+ void (*xLogFullCallback)(void *pCtx, u16 currentCount, const char *dbPath); 183+ BinlogInstanceT *binlogConn; 184+ BinlogApi binlogApi; 185+ u8 isSkipTrigger; 186+} Sqlite3BinlogHandle; 187+ 188+typedef enum { 189+ STMT_TYPE_DML = 0, 190+ STMT_TYPE_CREATE_TABLE, 191+ STMT_TYPE_CREATE_INDEX, 192+ STMT_TYPE_CREATE_TRIGGER, 193+ STMT_TYPE_CREATE_VIEW, 194+ STMT_TYPE_DROP_TABLE, 195+ STMT_TYPE_DROP_INDEX, 196+ STMT_TYPE_DROP_TRIGGER, 197+ STMT_TYPE_DROP_VIEW, 198+ STMT_TYPE_ALTER_ADD_COL, 199+ STMT_TYPE_ALTER_RENAME_COL, 200+ STMT_TYPE_ALTER_RENAME_TABLE, 201+ STMT_TYPE_ALTER_DROP_COL, 202+ STMT_TYPE_BEGIN_TRANSACTION, 203+ STMT_TYPE_COMMIT_TRANSACTION, 204+ STMT_TYPE_ROLLBACK_TRANSACTION, 205+ STMT_TYPE_PRAGMA, 206+ STMT_TYPE_SAVEPOINT, 207+} StmtType; 208+ 209+typedef struct Sqlite3BinlogStmt { 210+ BinlogReadResultT *cursor; 211+ u32 curIdx; 212+} Sqlite3BinlogStmt; 213+ 214+typedef struct Sqlite3BinlogApiInfo { 215+ void **funcP; 216+ const char *funcN; 217+} Sqlite3BinlogApiInfo; 218+ 219+SQLITE_PRIVATE int sqlite3BinlogStmtPrepare(sqlite3 *db, Sqlite3BinlogStmt *bStmt); 220+SQLITE_PRIVATE int sqlite3BinlogStmtStep(sqlite3 *db, Sqlite3BinlogStmt *bStmt, char **sql, Table **pOutTable); 221+SQLITE_PRIVATE void sqlite3BinlogStmtFinalize(sqlite3 *db, Sqlite3BinlogStmt *bStmt); 222+ 223+SQLITE_PRIVATE int sqlite3BinlogInitApi(sqlite3 *db); 224+SQLITE_PRIVATE int sqlite3SetBinLogConfig(sqlite3 *db, Sqlite3BinlogConfig *bConfig); 225+SQLITE_PRIVATE int sqlite3TransferBinlogErrno(BinlogErrno err); 226+ 227+SQLITE_PRIVATE void sqlite3BinlogWrite(Vdbe *p); 228+SQLITE_PRIVATE int sqlite3BinlogClose(sqlite3 *db); 229+SQLITE_PRIVATE void sqlite3BinlogReset(sqlite3 *db); 230+SQLITE_PRIVATE int sqlite3BinlogReplay(sqlite3 *srcDb, sqlite3 *destDb); 231+SQLITE_PRIVATE int sqlite3BinlogClean(sqlite3 *db, BinlogFileCleanModeE mode); 232+SQLITE_PRIVATE void sqlite3BinlogErrorCallback(sqlite3 *db, int errNo, char *errMsg); 233+SQLITE_PRIVATE BinlogEventTypeE sqlite3TransferLogEventType(StmtType stmtType); 234+SQLITE_PRIVATE int sqlite3IsSkipWriteBinlog(Vdbe *p); 235+SQLITE_PRIVATE int sqlite3IsRowBasedBinlog(Vdbe *p); 236+SQLITE_PRIVATE Table *sqlite3BinlogFindTable(BtCursor *pC); 237+SQLITE_PRIVATE void sqlite3StoreBinlogRowData(Vdbe *p, BtCursor *pCursor, sqlite3_uint64 nData, 238+ const char *pData, int op, sqlite3_int64 rowid); 239+SQLITE_PRIVATE void sqlite3FreeBinlogRowData(Vdbe *p); 240+SQLITE_PRIVATE char *sqlite3BinlogGetNthCol(sqlite3 *db, const Table *pTab, const BinlogRow *pRow, int iCol); 241+/************** Binlog typedef in sqlite3 END ************************************/ 242+#endif 243+ 244 /* 245 ** Each database connection is an instance of the following structure. 246 */ 247@@ -17770,6 +17980,9 @@ struct sqlite3 { 248 #if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) 249 CodecParameter codecParm; 250 #endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ 251+#ifdef SQLITE_ENABLE_BINLOG 252+ Sqlite3BinlogHandle xBinlogHandle; 253+#endif 254 }; 255 256 /* 257@@ -23666,6 +23879,14 @@ struct Vdbe { 258 int startPos; 259 int addedRows; 260 #endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ 261+#ifdef SQLITE_ENABLE_BINLOG 262+/* begin of binlog related field */ 263+ StmtType stmtType; /* Type of binlog statement */ 264+ BinlogDMLData *pBinlogDMLData; /* Data for binlog row-based DML statement */ 265+ const char *pDataTmp; /* Temporary binlog data for op_notfound */ 266+ sqlite3_uint64 nDataTmp; /* Size of pDataTmp */ 267+/* end of binlog related field */ 268+#endif 269 }; 270 271 /* 272@@ -88435,7 +88656,11 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ 273 rc = sqlite3BtreeCommitPhaseOne(pBt, 0); 274 } 275 } 276- 277+#ifdef SQLITE_ENABLE_BINLOG 278+ if ( rc==SQLITE_OK ){ 279+ sqlite3BinlogWrite(p); 280+ } 281+#endif 282 /* Do the commit only if all databases successfully complete phase 1. 283 ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an 284 ** IO error while deleting or truncating a journal file. It is unlikely, 285@@ -88583,6 +88808,9 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ 286 ** transaction is already guaranteed, but some stray 'cold' journals 287 ** may be lying around. Returning an error code won't help matters. 288 */ 289+#ifdef SQLITE_ENABLE_BINLOG 290+ sqlite3BinlogWrite(p); 291+#endif 292 disable_simulated_io_errors(); 293 sqlite3BeginBenignMalloc(); 294 for(i=0; i<db->nDb; i++){ 295@@ -88868,6 +89096,9 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ 296 }else if( eStatementOp==0 ){ 297 if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ 298 eStatementOp = SAVEPOINT_RELEASE; 299+#ifdef SQLITE_ENABLE_BINLOG 300+ sqlite3BinlogWrite(p); 301+#endif 302 }else if( p->errorAction==OE_Abort ){ 303 eStatementOp = SAVEPOINT_ROLLBACK; 304 }else{ 305@@ -89090,6 +89321,9 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ 306 fclose(out); 307 } 308 } 309+#endif 310+#ifdef SQLITE_ENABLE_BINLOG 311+ sqlite3FreeBinlogRowData(p); 312 #endif 313 return p->rc & db->errMask; 314 } 315@@ -89194,6 +89428,9 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ 316 sqlite3DbFree(db, p->aScan); 317 } 318 #endif 319+#ifdef SQLITE_ENABLE_BINLOG 320+ sqlite3FreeBinlogRowData(p); 321+#endif 322 } 323 324 /* 325@@ -91886,6 +92123,44 @@ SQLITE_API int sqlite3_set_droptable_handle(sqlite3 *db, void (*xFunc)(sqlite3*, 326 } 327 #endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ 328 329+#ifdef SQLITE_ENABLE_BINLOG 330+SQLITE_API int sqlite3_is_support_binlog(void) 331+{ 332+ return SQLITE_ERROR; 333+} 334+ 335+SQLITE_API int sqlite3_replay_binlog(sqlite3 *srcDb, sqlite3 *destDb) 336+{ 337+ if (srcDb == NULL || destDb == NULL) { 338+ sqlite3_log(SQLITE_ERROR, "replay binlog parameter is null"); 339+ return SQLITE_ERROR; 340+ } 341+ int rc = SQLITE_OK; 342+ sqlite3_mutex_enter(srcDb->mutex); 343+ rc = sqlite3BinlogReplay(srcDb, destDb); 344+ if (rc != SQLITE_OK) { 345+ sqlite3_log(rc, "replay binlog err:%d", rc); 346+ } 347+ sqlite3_mutex_leave(srcDb->mutex); 348+ return rc; 349+} 350+ 351+SQLITE_API int sqlite3_clean_binlog(sqlite3 *db, BinlogFileCleanModeE mode) 352+{ 353+ if (db == NULL) { 354+ sqlite3_log(SQLITE_ERROR, "clean binlog parameter is null"); 355+ return SQLITE_ERROR; 356+ } 357+ int rc = SQLITE_OK; 358+ sqlite3_mutex_enter(db->mutex); 359+ rc = sqlite3BinlogClean(db, mode); 360+ if (rc != SQLITE_OK) { 361+ sqlite3_log(rc, "clean binlog err:%d", rc); 362+ } 363+ sqlite3_mutex_leave(db->mutex); 364+ return rc; 365+} 366+#endif 367 /* 368 ** This is the top-level implementation of sqlite3_step(). Call 369 ** sqlite3Step() to do most of the work. If a schema error occurs, 370@@ -99189,6 +99464,12 @@ case OP_Found: { /* jump, in3, ncycle */ 371 pC->nullRow = 1-alreadyExists; 372 pC->deferredMoveto = 0; 373 pC->cacheStatus = CACHE_STALE; 374+#ifdef SQLITE_ENABLE_BINLOG 375+ if ( pOp->opcode==OP_NotFound && r.nField==0 && !sqlite3IsSkipWriteBinlog(p)){ 376+ p->nDataTmp = r.aMem->n; 377+ p->pDataTmp = r.aMem->z; 378+ } 379+#endif 380 if( pOp->opcode==OP_Found ){ 381 VdbeBranchTaken(alreadyExists!=0,2); 382 if( alreadyExists ) goto jump_to_p2; 383@@ -99584,6 +99865,15 @@ case OP_Insert: { 384 } 385 x.pKey = 0; 386 assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT ); 387+#ifdef SQLITE_ENABLE_BINLOG 388+ if ( pOp->p4.pTab 389+ && !sqlite3IsSkipWriteBinlog(p) 390+ && sqlite3IsRowBasedBinlog(p) 391+ && sqlite3TransferLogEventType(p->stmtType) == BINLOG_EVENT_TYPE_DML ) { 392+ sqlite3StoreBinlogRowData(p, pC->uc.pCursor, x.nData, pData->z, 393+ (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT, x.nKey); 394+ } 395+#endif 396 rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, 397 (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)), 398 seekResult 399@@ -99699,6 +99989,27 @@ case OP_Delete: { 400 assert( CORRUPT_DB || pC->movetoTarget==iKey ); 401 } 402 #endif 403+#ifdef SQLITE_ENABLE_BINLOG 404+ if( !sqlite3IsSkipWriteBinlog(p) 405+ && sqlite3IsRowBasedBinlog(p) 406+ && sqlite3TransferLogEventType(p->stmtType) == BINLOG_EVENT_TYPE_DML ){ 407+ if (pC->isTable) { 408+ sqlite3StoreBinlogRowData(p, pC->uc.pCursor, 0, NULL, SQLITE_DELETE, sqlite3BtreeIntegerKey(pC->uc.pCursor)); 409+ } else { 410+ Table *pBinlogTab = sqlite3BinlogFindTable(pC->uc.pCursor); 411+ if (pBinlogTab != NULL && !HasRowid(pBinlogTab)) { 412+ /* If pC is not a table, then this is a delete operation in a without rowid table 413+ ** pC may have no row data or invalid row data when deletion has a subquery 414+ ** so we need to get row data from op_notfound, which is stored in p->pDataTmp 415+ */ 416+ int isUseTmpData = pOp->p4type == P4_TABLE && p->nDataTmp != 0 && p->pDataTmp != NULL; 417+ sqlite3_uint64 nData = isUseTmpData ? p->nDataTmp : pC->szRow; 418+ const char *pData = isUseTmpData ? p->pDataTmp : (const char *)pC->aRow; 419+ sqlite3StoreBinlogRowData(p, pC->uc.pCursor, nData, pData, SQLITE_DELETE, -1); 420+ } 421+ } 422+ } 423+#endif 424 425 /* If the update-hook or pre-update-hook will be invoked, set zDb to 426 ** the name of the db to pass as to it. Also set local pTab to a copy 427@@ -100322,6 +100633,14 @@ case OP_IdxInsert: { /* in2 */ 428 x.pKey = pIn2->z; 429 x.aMem = aMem + pOp->p3; 430 x.nMem = (u16)pOp->p4.i; 431+#ifdef SQLITE_ENABLE_BINLOG 432+ if( (pOp->p5 & OPFLAG_NCHANGE) 433+ && !sqlite3IsSkipWriteBinlog(p) 434+ && sqlite3IsRowBasedBinlog(p) 435+ && sqlite3TransferLogEventType(p->stmtType) == BINLOG_EVENT_TYPE_DML ){ 436+ sqlite3StoreBinlogRowData(p, pC->uc.pCursor, x.nKey, pIn2->z, SQLITE_INSERT, -1); 437+ } 438+#endif 439 rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, 440 (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)), 441 ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) 442@@ -116953,7 +117272,11 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( 443 444 renameReloadSchema(pParse, iDb, INITFLAG_AlterRename); 445 renameTestSchema(pParse, zDb, iDb==1, "after rename", 0); 446- 447+#ifdef SQLITE_ENABLE_BINLOG 448+ if( v ){ 449+ v->stmtType = STMT_TYPE_ALTER_RENAME_TABLE; 450+ } 451+#endif 452 exit_rename_table: 453 sqlite3SrcListDelete(db, pSrc); 454 sqlite3DbFree(db, zName); 455@@ -117135,6 +117458,9 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ 456 zTab, zDb 457 ); 458 } 459+#ifdef SQLITE_ENABLE_BINLOG 460+ v->stmtType = STMT_TYPE_ALTER_ADD_COL; 461+#endif 462 } 463 } 464 465@@ -117346,7 +117672,13 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( 466 /* Drop and reload the database schema. */ 467 renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename); 468 renameTestSchema(pParse, zDb, iSchema==1, "after rename", 1); 469- 470+#ifdef SQLITE_ENABLE_BINLOG 471+ Vdbe *v = NULL; 472+ v = sqlite3GetVdbe(pParse); 473+ if( v ){ 474+ v->stmtType = STMT_TYPE_ALTER_RENAME_COL; 475+ } 476+#endif 477 exit_rename_column: 478 sqlite3SrcListDelete(db, pSrc); 479 sqlite3DbFree(db, zOld); 480@@ -118957,7 +119289,13 @@ SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const T 481 sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v); 482 sqlite3VdbeJumpHere(v, addr); 483 } 484- 485+#ifdef SQLITE_ENABLE_BINLOG 486+ Vdbe *v = NULL; 487+ v = sqlite3GetVdbe(pParse); 488+ if( v ){ 489+ v->stmtType = STMT_TYPE_ALTER_DROP_COL; 490+ } 491+#endif 492 exit_drop_column: 493 sqlite3DbFree(db, zCol); 494 sqlite3SrcListDelete(db, pSrc); 495@@ -123295,6 +123633,9 @@ SQLITE_PRIVATE void sqlite3StartTable( 496 sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1); 497 sqlite3VdbeChangeP5(v, OPFLAG_APPEND); 498 sqlite3VdbeAddOp0(v, OP_Close); 499+#ifdef SQLITE_ENABLE_BINLOG 500+ v->stmtType = STMT_TYPE_CREATE_TABLE; 501+#endif 502 } 503 504 /* Normal (non-error) return. */ 505@@ -124963,7 +125304,13 @@ SQLITE_PRIVATE void sqlite3CreateView( 506 507 /* Use sqlite3EndTable() to add the view to the schema table */ 508 sqlite3EndTable(pParse, 0, &sEnd, 0, 0); 509- 510+#ifdef SQLITE_ENABLE_BINLOG 511+ Vdbe *v = NULL; 512+ v = sqlite3GetVdbe(pParse); 513+ if( v ){ 514+ v->stmtType = STMT_TYPE_CREATE_VIEW; 515+ } 516+#endif 517 create_view_fail: 518 sqlite3SelectDelete(db, pSelect); 519 if( IN_RENAME_OBJECT ){ 520@@ -125486,6 +125833,9 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, 521 sqlite3FkDropTable(pParse, pName, pTab); 522 } 523 sqlite3CodeDropTable(pParse, pTab, iDb, isView); 524+#ifdef SQLITE_ENABLE_BINLOG 525+ v->stmtType = (isView > 0) ? STMT_TYPE_DROP_VIEW : STMT_TYPE_DROP_TABLE; 526+#endif 527 } 528 529 exit_drop_table: 530@@ -126344,6 +126694,9 @@ SQLITE_PRIVATE void sqlite3CreateIndex( 531 /* A named index with an explicit CREATE INDEX statement */ 532 zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", 533 onError==OE_None ? "" : " UNIQUE", n, pName->z); 534+#ifdef SQLITE_ENABLE_BINLOG 535+ v->stmtType = STMT_TYPE_CREATE_INDEX; 536+#endif 537 }else{ 538 /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ 539 /* zStmt = sqlite3MPrintf(""); */ 540@@ -126546,6 +126899,9 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists 541 sqlite3ChangeCookie(pParse, iDb); 542 destroyRootPage(pParse, pIndex->tnum, iDb); 543 sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0); 544+#ifdef SQLITE_ENABLE_BINLOG 545+ v->stmtType = STMT_TYPE_DROP_INDEX; 546+#endif 547 } 548 549 exit_drop_index: 550@@ -127070,6 +127426,9 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ 551 } 552 } 553 sqlite3VdbeAddOp0(v, OP_AutoCommit); 554+#ifdef SQLITE_ENABLE_BINLOG 555+ v->stmtType = STMT_TYPE_BEGIN_TRANSACTION; 556+#endif 557 } 558 559 /* 560@@ -127092,6 +127451,9 @@ SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){ 561 v = sqlite3GetVdbe(pParse); 562 if( v ){ 563 sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback); 564+#ifdef SQLITE_ENABLE_BINLOG 565+ v->stmtType = (isRollback > 0) ? STMT_TYPE_ROLLBACK_TRANSACTION : STMT_TYPE_COMMIT_TRANSACTION; 566+#endif 567 } 568 } 569 570@@ -127112,6 +127474,9 @@ SQLITE_PRIVATE void sqlite3Savepoint(Parse *pParse, int op, Token *pName){ 571 return; 572 } 573 sqlite3VdbeAddOp4(v, OP_Savepoint, op, 0, 0, zName, P4_DYNAMIC); 574+#ifdef SQLITE_ENABLE_BINLOG 575+ v->stmtType = STMT_TYPE_SAVEPOINT; 576+#endif 577 } 578 } 579 580@@ -137480,6 +137845,13 @@ typedef int (*sqlite3_loadext_entry)( 581 /* handle after drop table done */ 582 #define sqlite3_set_droptable_handle sqlite3_api->set_droptable_handle 583 #endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ 584+#ifdef SQLITE_ENABLE_BINLOG 585+#define sqlite3_is_support_binlog sqlite3_api->is_support_binlog 586+/* replay binlog from src db to the dest db */ 587+#define sqlite3_replay_binlog sqlite3_api->replay_binlog 588+/* clean the binlog of the db */ 589+#define sqlite3_clean_binlog sqlite3_api->clean_binlog 590+#endif /* SQLITE_ENABLE_BINLOG */ 591 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ 592 593 #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) 594@@ -139533,6 +139905,9 @@ SQLITE_PRIVATE void sqlite3Pragma( 595 if( v==0 ) return; 596 sqlite3VdbeRunOnlyOnce(v); 597 pParse->nMem = 2; 598+#ifdef SQLITE_ENABLE_BINLOG 599+ v->stmtType = STMT_TYPE_PRAGMA; 600+#endif 601 602 /* Interpret the [schema.] part of the pragma statement. iDb is the 603 ** index of the database this pragma is being applied to in db.aDb[]. */ 604@@ -152286,7 +152661,13 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( 605 if (tr_tm == TK_INSTEAD){ 606 tr_tm = TK_BEFORE; 607 } 608- 609+#ifdef SQLITE_ENABLE_BINLOG 610+ Vdbe *v = NULL; 611+ v = sqlite3GetVdbe(pParse); 612+ if( v ){ 613+ v->stmtType = STMT_TYPE_CREATE_TRIGGER; 614+ } 615+#endif 616 /* Build the Trigger object */ 617 pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); 618 if( pTrigger==0 ) goto trigger_cleanup; 619@@ -152681,6 +153062,13 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr) 620 goto drop_trigger_cleanup; 621 } 622 sqlite3DropTriggerPtr(pParse, pTrigger); 623+#ifdef SQLITE_ENABLE_BINLOG 624+ Vdbe *v = NULL; 625+ v = sqlite3GetVdbe(pParse); 626+ if (v) { 627+ v->stmtType = STMT_TYPE_DROP_TRIGGER; 628+ } 629+#endif 630 631 drop_trigger_cleanup: 632 sqlite3SrcListDelete(db, pName); 633@@ -153427,6 +153815,15 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger( 634 assert( tr_tm==TRIGGER_BEFORE || tr_tm==TRIGGER_AFTER ); 635 assert( (op==TK_UPDATE)==(pChanges!=0) ); 636 637+#ifdef SQLITE_ENABLE_BINLOG 638+ /* If this db is a replica for a row-based binlog, the trigger operations 639+ ** will be recorded by the row statements. Therefore, we need to skip the 640+ ** trigger operations on replica database. 641+ */ 642+ if (pParse->db->xBinlogHandle.isSkipTrigger) { 643+ return; 644+ } 645+#endif 646 for(p=pTrigger; p; p=p->pNext){ 647 648 /* Sanity checking: The schema for the trigger and for the table are 649@@ -180656,6 +181053,13 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ 650 break; 651 } 652 #endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ 653+#ifdef SQLITE_ENABLE_BINLOG 654+ case SQLITE_DBCONFIG_ENABLE_BINLOG: { 655+ Sqlite3BinlogConfig *pBinlogConfig = va_arg(ap, Sqlite3BinlogConfig*); 656+ rc = sqlite3SetBinLogConfig(db, pBinlogConfig); 657+ break; 658+ } 659+#endif 660 default: { 661 static const struct { 662 int op; /* The opcode */ 663@@ -181083,6 +181487,9 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ 664 sqlite3CollapseDatabaseArray(db); 665 assert( db->nDb<=2 ); 666 assert( db->aDb==db->aDbStatic ); 667+#ifdef SQLITE_ENABLE_BINLOG 668+ (void)sqlite3BinlogClose(db); 669+#endif 670 671 /* Tell the code in notify.c that the connection no longer holds any 672 ** locks and does not require any further unlock-notify callbacks. 673@@ -183308,6 +183715,9 @@ opendb_out: 674 db->mDropSchemaName = NULL; 675 db->xDropTableHandle = NULL; 676 #endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ 677+#ifdef SQLITE_ENABLE_BINLOG 678+ sqlite3BinlogReset(db); 679+#endif 680 *ppDb = db; 681 #ifdef SQLITE_ENABLE_SQLLOG 682 if( sqlite3GlobalConfig.xSqllog ){ 683@@ -256913,6 +257323,1088 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime 684 } 685 #endif 686 687+#ifdef SQLITE_ENABLE_BINLOG 688+/************** Begin of binlog implement ************************************/ 689+SQLITE_PRIVATE int sqlite3BinlogInitApi(sqlite3 *db) 690+{ 691+ if (db == NULL || db->xBinlogHandle.binlogApi.binlogLib == NULL) { 692+ sqlite3_log(SQLITE_ERROR, "binlog init api parameter is null"); 693+ return SQLITE_ERROR; 694+ } 695+ Sqlite3BinlogApiInfo apiInfo[] = { 696+ {(void **)&db->xBinlogHandle.binlogApi.binlogOpenApi, "BinlogOpen"}, 697+ {(void **)&db->xBinlogHandle.binlogApi.binlogCloseApi, "BinlogClose"}, 698+ {(void **)&db->xBinlogHandle.binlogApi.binlogWriteApi, "BinlogWrite"}, 699+ {(void **)&db->xBinlogHandle.binlogApi.binlogReadApi, "BinlogRead"}, 700+ {(void **)&db->xBinlogHandle.binlogApi.binlogFreeReadResultApi, "BinlogFreeReadResult"}, 701+ {(void **)&db->xBinlogHandle.binlogApi.binlogFileCleanApi, "BinlogFileClean"}, 702+ {(void **)&db->xBinlogHandle.binlogApi.binlogLockReadApi, "BinlogLockRead"}, 703+ {(void **)&db->xBinlogHandle.binlogApi.binlogUnlockReadApi, "BinlogUnlockRead"}, 704+ }; 705+ int apiCount = sizeof(apiInfo) / sizeof(apiInfo[0]); 706+ for (int i = 0; i < apiCount; i++) { 707+ *apiInfo[i].funcP = sqlite3OsDlSym(db->pVfs, db->xBinlogHandle.binlogApi.binlogLib, apiInfo[i].funcN); 708+ if (*apiInfo[i].funcP == NULL) { 709+ sqlite3_log(SQLITE_ERROR, "dlsym binlog err: %s", apiInfo[i].funcN); 710+ return SQLITE_ERROR; 711+ } 712+ } 713+ return SQLITE_OK; 714+} 715+ 716+SQLITE_PRIVATE int sqlite3SetBinLogConfig(sqlite3 *db, Sqlite3BinlogConfig *bConfig) 717+{ 718+ if (db == NULL) { 719+ sqlite3_log(SQLITE_ERROR, "set binlog config parameter is null"); 720+ return SQLITE_ERROR; 721+ } 722+ if (bConfig == NULL) { 723+ return sqlite3BinlogClose(db); 724+ } 725+ 726+ const char *zFile = sqlite3_db_filename(db, 0); 727+ if (zFile == NULL || (db->xBinlogHandle.flags & BINLOG_FLAG_ENABLE)) { 728+ sqlite3_log(SQLITE_ERROR, "set binlog config zFile is null or binlog is already enabled"); 729+ return SQLITE_ERROR; 730+ } 731+ 732+ void *handle = sqlite3OsDlOpen(db->pVfs, "libarkdata_db_core.z.so"); 733+ if (handle == NULL) { 734+ sqlite3_log(SQLITE_ERROR, "dlopen binlog err:%d", errno); 735+ return SQLITE_ERROR; 736+ } 737+ db->xBinlogHandle.binlogApi.binlogLib = handle; 738+ int rc = sqlite3BinlogInitApi(db); 739+ if (rc != SQLITE_OK) { 740+ sqlite3_log(rc, "set binlog config init api err:%d", rc); 741+ sqlite3BinlogReset(db); 742+ return rc; 743+ } 744+ 745+ BinlogConfigT conf; 746+ conf.logMode = bConfig->mode; 747+ conf.fullCallbackThreshold = bConfig->fullCallbackThreshold; 748+ conf.maxFileSize = bConfig->maxFileSize; 749+ conf.filePath = (char *)zFile; 750+ conf.onError = bConfig->xErrorCallback; 751+ conf.onLogFull = bConfig->xLogFullCallback; 752+ conf.onErrnoTrans = sqlite3TransferBinlogErrno; 753+ conf.callbackCtx = bConfig->callbackCtx; 754+ 755+ BinlogInstanceT *inst = NULL; 756+ rc = sqlite3TransferBinlogErrno(db->xBinlogHandle.binlogApi.binlogOpenApi(&conf, &inst)); 757+ if (rc != SQLITE_OK) { 758+ sqlite3_log(SQLITE_ERROR, "binlog open err:%d %d", rc, errno); 759+ sqlite3BinlogReset(db); 760+ return SQLITE_ERROR; 761+ } 762+ 763+ db->xBinlogHandle.mode = bConfig->mode; 764+ db->xBinlogHandle.flags |= (BINLOG_FLAG_ENABLE | BINLOG_FLAG_UPDATE_TID); 765+ db->xBinlogHandle.xErrorCallback = bConfig->xErrorCallback; 766+ db->xBinlogHandle.xLogFullCallback = bConfig->xLogFullCallback; 767+ db->xBinlogHandle.callbackCtx = bConfig->callbackCtx; 768+ db->xBinlogHandle.binlogConn = inst; 769+ db->xBinlogHandle.isSkipTrigger = 0; 770+ return SQLITE_OK; 771+} 772+ 773+SQLITE_PRIVATE int sqlite3GenerateUuid(u8 *aBlobOut) 774+ { 775+ if (aBlobOut == NULL) { 776+ return SQLITE_ERROR; 777+ } 778+ u8 aBlob[SQLITE_UUID_BLOB_LENGTH]; 779+ sqlite3_randomness(SQLITE_UUID_BLOB_LENGTH, aBlob); 780+ aBlob[6] = (aBlob[6] & 0x0f) + 0x40; 781+ aBlob[8] = (aBlob[8] & 0x3f) + 0x80; 782+ 783+ errno_t errNo = EOK; 784+ errNo = memcpy_s(aBlobOut, SQLITE_UUID_BLOB_LENGTH, aBlob, SQLITE_UUID_BLOB_LENGTH); 785+ if (errNo != EOK) { 786+ return SQLITE_ERROR; 787+ } 788+ return SQLITE_OK; 789+} 790+ 791+SQLITE_PRIVATE BinlogEventTypeE sqlite3TransferLogEventType(StmtType stmtType) 792+{ 793+ switch(stmtType) { 794+ case STMT_TYPE_CREATE_TABLE: 795+ case STMT_TYPE_CREATE_INDEX: 796+ case STMT_TYPE_CREATE_TRIGGER: 797+ case STMT_TYPE_CREATE_VIEW: 798+ case STMT_TYPE_DROP_TABLE: 799+ case STMT_TYPE_DROP_INDEX: 800+ case STMT_TYPE_DROP_TRIGGER: 801+ case STMT_TYPE_DROP_VIEW: 802+ case STMT_TYPE_ALTER_ADD_COL: 803+ case STMT_TYPE_ALTER_RENAME_COL: 804+ case STMT_TYPE_ALTER_RENAME_TABLE: 805+ case STMT_TYPE_ALTER_DROP_COL: 806+ return BINLOG_EVENT_TYPE_DDL; 807+ case STMT_TYPE_PRAGMA: 808+ return BINLOG_EVENT_TYPE_PRAGMA; 809+ case STMT_TYPE_ROLLBACK_TRANSACTION: 810+ return BINLOG_EVENT_TYPE_ROLLBACK; 811+ default: 812+ return BINLOG_EVENT_TYPE_DML; 813+ } 814+} 815+ 816+/* Write an sql into binlog with given type and isFinish flag */ 817+SQLITE_PRIVATE int sqlite3DirectWriteBinlog(Vdbe *p, BinlogEventTypeE type, char *zSql, u32 nSql, int isFinishTrx) 818+{ 819+ BinlogWriteDataT logData; 820+ errno_t errNo = memcpy_s(&logData.xid, SQLITE_UUID_BLOB_LENGTH, p->db->xBinlogHandle.xTid, SQLITE_UUID_BLOB_LENGTH); 821+ if (errNo != EOK) { 822+ sqlite3_log(SQLITE_WARNING, "binlog memcpy xid failed"); 823+ return SQLITE_ERROR; 824+ } 825+ 826+ logData.type = type; 827+ logData.data = zSql; 828+ logData.dataLength = nSql; 829+ logData.isFinishTrx = isFinishTrx; 830+ sqlite3 *db = p->db; 831+ int rc = sqlite3TransferBinlogErrno(db->xBinlogHandle.binlogApi.binlogWriteApi(db->xBinlogHandle.binlogConn, 832+ &logData)); 833+ if (rc != SQLITE_OK) { 834+ sqlite3_log(SQLITE_WARNING, "binlog write err:%d", rc); 835+ return SQLITE_ERROR; 836+ } 837+ return SQLITE_OK; 838+} 839+ 840+/* Free the pBinlogDMLData saved on the Vdbe pointer */ 841+SQLITE_PRIVATE void sqlite3FreeBinlogRowData(Vdbe *p) { 842+ if (p == NULL || p->db == NULL || p->pBinlogDMLData == NULL) { 843+ return; 844+ } 845+ int isReleased = p->pBinlogDMLData->isSavePointReleased; 846+ if (!isReleased && p->db->autoCommit > 0 && p->pBinlogDMLData->pSavePointName != NULL) { 847+ u32 len = strlen(p->pBinlogDMLData->pSavePointName) + 1; 848+ sqlite3DirectWriteBinlog(p, BINLOG_EVENT_TYPE_ROW_ROLLBACK, p->pBinlogDMLData->pSavePointName, len, 0); 849+ sqlite3DirectWriteBinlog(p, BINLOG_EVENT_TYPE_ROW_COMMIT, p->pBinlogDMLData->pSavePointName, len, 1); 850+ p->db->xBinlogHandle.flags |= BINLOG_FLAG_UPDATE_TID; 851+ } else if (!isReleased && p->pBinlogDMLData->pSavePointName != NULL) { 852+ /* If not in auto commit mode and savepoint not released, 853+ ** it means this statement failed to execute within a transaction. 854+ ** In this case, we need to rollback to the point before this statement is executed. 855+ ** If the rollback statement failed to write into binlog, then there may be an memory leak 856+ */ 857+ u32 len = strlen(p->pBinlogDMLData->pSavePointName) + 1; 858+ sqlite3DirectWriteBinlog(p, BINLOG_EVENT_TYPE_ROW_ROLLBACK, p->pBinlogDMLData->pSavePointName, len, 0); 859+ } 860+ 861+ if (p->pBinlogDMLData->pSavePointName != NULL) { 862+ sqlite3DbFree(p->db, p->pBinlogDMLData->pSavePointName); 863+ p->pBinlogDMLData->pSavePointName = NULL; 864+ } 865+ 866+ sqlite3DbFree(p->db, p->pBinlogDMLData); 867+ p->pBinlogDMLData = NULL; 868+} 869+ 870+/* Check and create a new binlog xid if needed */ 871+SQLITE_PRIVATE int sqlite3UpdateBinlogXidIfNeeded(sqlite3 *db){ 872+ assert( db!=NULL ); 873+ if ((db->xBinlogHandle.flags & BINLOG_FLAG_UPDATE_TID) != 0) { 874+ if (sqlite3GenerateUuid(db->xBinlogHandle.xTid) != SQLITE_OK) { 875+ sqlite3_log(SQLITE_ERROR, "binlog generate uuid failed"); 876+ return SQLITE_ERROR; 877+ } 878+ db->xBinlogHandle.flags &= ~BINLOG_FLAG_UPDATE_TID; 879+ } 880+ return SQLITE_OK; 881+} 882+ 883+/* Return a delete sql for a regular table, the returned value needs free by caller */ 884+SQLITE_PRIVATE char *sqlite3BinlogRowDelete(Table *pTab, sqlite3_int64 rowid){ 885+ return sqlite3_mprintf("delete from \"%s\" where rowid=%lld;", pTab->zName, rowid); 886+} 887+ 888+/* Return a delete sql for a without rowid table, the returned value needs free by caller */ 889+SQLITE_PRIVATE char *sqlite3BinlogRowDeleteNoRowid(sqlite3 *db, Table *pTab, const BinlogRow *pRow){ 890+ char *whereClause = NULL;; 891+ Index *pIdx = sqlite3PrimaryKeyIndex(pTab); 892+ 893+ for (int i=0; i<pIdx->nKeyCol; i++) { 894+ i16 iCol = pIdx->aiColumn[i]; 895+ Column *pCol = &(pTab->aCol[iCol]); 896+ if (whereClause == NULL) { 897+ char *colValue = sqlite3BinlogGetNthCol(db, pTab, pRow, i); 898+ if (colValue == NULL) { 899+ return NULL; 900+ } 901+ whereClause = sqlite3_mprintf("%s=%s", pCol->zCnName, colValue); 902+ sqlite3DbFree(db, colValue); 903+ } else { 904+ char *colValue = sqlite3BinlogGetNthCol(db, pTab, pRow, i); 905+ if (colValue == NULL) { 906+ sqlite3DbFree(db, whereClause); 907+ return NULL; 908+ } 909+ char *temp = sqlite3_mprintf("%s and %s=%s", whereClause, pCol->zCnName, colValue); 910+ sqlite3DbFree(db, whereClause); 911+ sqlite3DbFree(db, colValue); 912+ whereClause = temp; 913+ } 914+ if (whereClause == NULL) { 915+ return NULL; 916+ } 917+ } 918+ 919+ char *result = sqlite3_mprintf("delete from \"%s\" where %s;", pTab->zName, whereClause); 920+ sqlite3DbFree(db, whereClause); 921+ return result; 922+} 923+ 924+/* Get the field name and field values for a without rowid table, in two comma seperated strings */ 925+SQLITE_PRIVATE int sqlite3BinlogGetFieldDataNoRowid( 926+ sqlite3 *db, /* dB handle */ 927+ Table *pTab, /* Table to which the row belongs */ 928+ const BinlogRow *pRow, /* Row data to be written into binlog */ 929+ char **outNames, /* field names to be returned */ 930+ char **outValues /* field values to be returned */ 931+){ 932+ char *fieldNames = NULL; 933+ char *fieldValues = NULL; 934+ Index *pIdx = sqlite3PrimaryKeyIndex(pTab); 935+ /* Without rowid table fields are rearranged with primary keys at front */ 936+ for (int i=0; i<pIdx->nKeyCol; i++) { 937+ i16 iCol = pIdx->aiColumn[i]; 938+ if (i==0) { 939+ fieldNames = sqlite3_mprintf("%s", pTab->aCol[iCol].zCnName); 940+ } else { 941+ char *temp = sqlite3_mprintf("%s, %s", fieldNames, pTab->aCol[iCol].zCnName); 942+ sqlite3DbFree(db, fieldNames); 943+ fieldNames = temp; 944+ } 945+ if (fieldNames==NULL) goto no_rowid_no_mem; 946+ } 947+ 948+ for (int k=0; k<pTab->nCol; k++) { 949+ if ( (pTab->aCol[k].colFlags & COLFLAG_PRIMKEY) == 0 ) { 950+ char *temp = sqlite3_mprintf("%s, %s", fieldNames, pTab->aCol[k].zCnName); 951+ sqlite3DbFree(db, fieldNames); 952+ fieldNames = temp; 953+ } 954+ if (k==0) { 955+ fieldValues = sqlite3BinlogGetNthCol(db, pTab, pRow, k); 956+ } else { 957+ char *newVal = sqlite3BinlogGetNthCol(db, pTab, pRow, k); 958+ if (newVal==NULL) { 959+ goto no_rowid_no_mem; 960+ } 961+ char *temp = sqlite3_mprintf("%s, %s", fieldValues, newVal); 962+ sqlite3DbFree(db, newVal); 963+ sqlite3DbFree(db, fieldValues); 964+ fieldValues = temp; 965+ } 966+ if (fieldValues == NULL || fieldValues == NULL) { 967+ goto no_rowid_no_mem; 968+ } 969+ } 970+ *outNames = fieldNames; 971+ *outValues = fieldValues; 972+ return SQLITE_OK; 973+ 974+no_rowid_no_mem: 975+ sqlite3DbFree(db, fieldNames); 976+ sqlite3DbFree(db, fieldValues); 977+ return SQLITE_NOMEM; 978+} 979+ 980+/* Get the field name and field values for a regular rowid table, in two comma seperated strings */ 981+SQLITE_PRIVATE int sqlite3BinlogGetFieldData(sqlite3 *db, Table *pTab, const BinlogRow *pRow, char **outNames, char **outValues){ 982+ char *fieldNames = NULL; 983+ char *fieldValues = NULL; 984+ for (int i=0; i<pTab->nCol; i++) { 985+ if (i==0) { 986+ fieldNames = sqlite3_mprintf("%s", pTab->aCol[i].zCnName); 987+ fieldValues = sqlite3BinlogGetNthCol(db, pTab, pRow, i); 988+ } else { 989+ char *temp = sqlite3_mprintf("%s, %s", fieldNames, pTab->aCol[i].zCnName); 990+ sqlite3DbFree(db, fieldNames); 991+ fieldNames = temp; 992+ 993+ char *newVal = sqlite3BinlogGetNthCol(db, pTab, pRow, i); 994+ if (newVal==NULL) goto no_mem; 995+ temp = sqlite3_mprintf("%s, %s", fieldValues, newVal); 996+ sqlite3DbFree(db, newVal); 997+ sqlite3DbFree(db, fieldValues); 998+ fieldValues = temp; 999+ 1000+ } 1001+ if (fieldValues == NULL || fieldValues == NULL) { 1002+ goto no_mem; 1003+ } 1004+ } 1005+ *outNames = fieldNames; 1006+ *outValues = fieldValues; 1007+ return SQLITE_OK; 1008+ 1009+no_mem: 1010+ sqlite3DbFree(db, fieldNames); 1011+ sqlite3DbFree(db, fieldValues); 1012+ return SQLITE_NOMEM; 1013+} 1014+ 1015+/* Return an insert sql based on the binlog row data, the returned value needs free by caller */ 1016+SQLITE_PRIVATE char *sqlite3BinlogRowInsert(sqlite3 *db, Table *pTab, const BinlogRow *pRow){ 1017+ char *fieldNames = NULL; 1018+ char *fieldValues = NULL; 1019+ 1020+ int rc = SQLITE_OK; 1021+ if (HasRowid(pTab)) { 1022+ rc = sqlite3BinlogGetFieldData(db, pTab, pRow, &fieldNames, &fieldValues); 1023+ } else { 1024+ rc = sqlite3BinlogGetFieldDataNoRowid(db, pTab, pRow, &fieldNames, &fieldValues); 1025+ } 1026+ 1027+ if (rc != SQLITE_OK) { 1028+ sqlite3_log(rc, "binlog get field data err:%d", rc); 1029+ return NULL; 1030+ } 1031+ char *result = NULL; 1032+ if (HasRowid(pTab)) { 1033+ result = sqlite3_mprintf( 1034+ "insert into \"%s\" (%s, rowid) values (%s, %lld) on conflict do update set (%s) = (%s);", 1035+ pTab->zName, fieldNames, fieldValues, pRow->rowid, fieldNames, fieldValues 1036+ ); 1037+ } else { 1038+ result = sqlite3_mprintf( 1039+ "insert into \"%s\" (%s) values (%s) on conflict do update set (%s) = (%s);", 1040+ pTab->zName, fieldNames, fieldValues, fieldNames, fieldValues 1041+ ); 1042+ } 1043+ 1044+ sqlite3DbFree(db, fieldNames); 1045+ sqlite3DbFree(db, fieldValues); 1046+ return result; 1047+} 1048+ 1049+/* Return an update sql for a regular table. Without rowid table has no update operation */ 1050+SQLITE_PRIVATE char *sqlite3BinlogRowUpdate(sqlite3 *db, Table *pTab, const BinlogRow *pRow){ 1051+ char *fieldNames = NULL; 1052+ char *fieldValues = NULL; 1053+ if (sqlite3BinlogGetFieldData(db, pTab, pRow, &fieldNames, &fieldValues) != SQLITE_OK) { 1054+ return NULL; 1055+ } 1056+ char *result = sqlite3_mprintf( 1057+ "insert into \"%s\" (%s, rowid) values (%s, %lld) on conflict(rowid) do update set (%s) = (%s);", 1058+ pTab->zName, fieldNames, 1059+ fieldValues, pRow->rowid, 1060+ fieldNames, fieldValues 1061+ ); 1062+ sqlite3DbFree(db, fieldNames); 1063+ sqlite3DbFree(db, fieldValues); 1064+ return result; 1065+} 1066+ 1067+/* Return the sql statement corresponds to a binlog row data, NULL is returned if error occurs */ 1068+SQLITE_PRIVATE char *sqlite3GetBinlogRowStmt(sqlite3 *db, const BinlogRow *pRow, Table *pTab){ 1069+ assert( db!=NULL ); 1070+ assert( pRow!=NULL ); 1071+ assert( pTab!=NULL ); 1072+ 1073+ switch (pRow->op) { 1074+ case SQLITE_DELETE: 1075+ return HasRowid(pTab) ? sqlite3BinlogRowDelete(pTab, pRow->rowid) : sqlite3BinlogRowDeleteNoRowid(db, pTab, pRow); 1076+ case SQLITE_INSERT: 1077+ return sqlite3BinlogRowInsert(db, pTab, pRow); 1078+ case SQLITE_UPDATE: 1079+ return sqlite3BinlogRowUpdate(db, pTab, pRow); 1080+ default: 1081+ return NULL; 1082+ } 1083+} 1084+ 1085+/* Find the table that is pointed by pC, NULL is returned if a valid table can not be found */ 1086+SQLITE_PRIVATE Table *sqlite3BinlogFindTable(BtCursor *pC){ 1087+ if (pC==NULL || pC->pBtree == NULL || pC->pBtree->pBt == NULL || pC->pBtree->pBt->pSchema == NULL) { 1088+ return NULL; 1089+ } 1090+ Schema *pSchema = (Schema *)pC->pBtree->pBt->pSchema; 1091+ Table *pTab = NULL; 1092+ HashElem *k; 1093+ for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ 1094+ Table *tempTab = (Table*)sqliteHashData(k); 1095+ if (tempTab->tnum==pC->pgnoRoot) { 1096+ pTab = tempTab; 1097+ break; 1098+ } 1099+ } 1100+ if (pTab == NULL || sqlite3_stricmp(pTab->zName, LEGACY_SCHEMA_TABLE) == 0) { 1101+ return NULL; 1102+ } 1103+ return pTab; 1104+} 1105+ 1106+SQLITE_PRIVATE int sqlite3BinlogWriteTable(Vdbe *p, Table *pTable){ 1107+ assert( p!=NULL ); 1108+ assert( pTable!=NULL ); 1109+ 1110+ char *tableName = pTable->zName; 1111+ u32 len = strlen(tableName) + 1; 1112+ return sqlite3DirectWriteBinlog(p, BINLOG_EVENT_TYPE_ROW_TABLE, tableName, len, 0); 1113+} 1114+ 1115+SQLITE_PRIVATE int sqlite3BinlogDecodeRowBuffer(char *buffer, u32 nBuffer, u8 *op, 1116+ sqlite3_int64 *rowid, sqlite3_uint64 *nData, char **pData) 1117+{ 1118+ if (nBuffer < sizeof(u8) + sizeof(sqlite3_int64) + sizeof(sqlite3_uint64)) { 1119+ sqlite3_log(SQLITE_WARNING, "Failed to decode binlog row, %u", nBuffer); 1120+ return SQLITE_ERROR; 1121+ } 1122+ 1123+ u64 offset = 0; 1124+ *op = *((u8*)(buffer + offset)); 1125+ offset += sizeof(u8); 1126+ 1127+ errno_t errNo = memcpy_s(rowid, sizeof(sqlite3_int64), buffer + offset, sizeof(sqlite3_int64)); 1128+ if (errNo != EOK) { 1129+ sqlite3_log(SQLITE_WARNING, "Failed to decode binlog row rowid"); 1130+ return SQLITE_ERROR; 1131+ } 1132+ offset += sizeof(sqlite3_int64); 1133+ 1134+ errNo = memcpy_s(nData, sizeof(sqlite3_uint64), buffer + offset, sizeof(sqlite3_uint64)); 1135+ if (errNo != EOK) { 1136+ sqlite3_log(SQLITE_WARNING, "Failed to decode binlog row nData"); 1137+ return SQLITE_ERROR; 1138+ } 1139+ offset += sizeof(sqlite3_uint64); 1140+ 1141+ *pData = buffer + offset; 1142+ return SQLITE_OK; 1143+} 1144+ 1145+SQLITE_PRIVATE int sqlite3BinlogGetRowBuffer(sqlite3_uint64 nData, const char *pData, u8 op, 1146+ sqlite3_int64 rowid, char **pOutBuffer, u64 *nOutBuffer){ 1147+ assert( pOutBuffer!=NULL ); 1148+ assert( nOutBuffer!=NULL ); 1149+ 1150+ u64 nRowBuffer = sizeof(op) + sizeof(rowid) + sizeof(nData) + nData; 1151+ char *pRowBuffer = sqlite3MallocZero(nRowBuffer); 1152+ if (pRowBuffer == NULL) { 1153+ sqlite3_log(SQLITE_ERROR, "Failed to malloc binlog row, %lu", nRowBuffer); 1154+ return SQLITE_ERROR; 1155+ } 1156+ 1157+ errno_t errNo = memcpy_s(pRowBuffer, nRowBuffer, &op, sizeof(op)); 1158+ if (errNo != EOK) { 1159+ goto error_when_memcpy_binlog_row; 1160+ } 1161+ 1162+ u64 offset = sizeof(op); 1163+ errNo = memcpy_s(pRowBuffer + offset, nRowBuffer, &rowid, sizeof(rowid)); 1164+ offset += sizeof(rowid); 1165+ if (errNo != EOK) { 1166+ goto error_when_memcpy_binlog_row; 1167+ } 1168+ 1169+ errNo = memcpy_s(pRowBuffer + offset, nRowBuffer, &nData, sizeof(nData)); 1170+ offset += sizeof(nData); 1171+ if (errNo != EOK) { 1172+ goto error_when_memcpy_binlog_row; 1173+ } 1174+ 1175+ if (nData > 0) { 1176+ errNo = memcpy_s(pRowBuffer + offset, nRowBuffer, pData, nData); 1177+ if (errNo != EOK) { 1178+ goto error_when_memcpy_binlog_row; 1179+ } 1180+ } 1181+ 1182+ *pOutBuffer = pRowBuffer; 1183+ *nOutBuffer = nRowBuffer; 1184+ return SQLITE_OK; 1185+ 1186+error_when_memcpy_binlog_row: 1187+ sqlite3_free(pRowBuffer); 1188+ sqlite3_log(SQLITE_ERROR, "Failed to copy binlog row, %lu", nRowBuffer); 1189+ return SQLITE_ERROR; 1190+} 1191+ 1192+SQLITE_PRIVATE int sqlite3BinlogWriteRowData( 1193+ Vdbe *p, sqlite3_uint64 nData, const char *pData, int op, sqlite3_int64 rowid){ 1194+ if ((nData == 0 || pData == NULL) && op != SQLITE_DELETE) { 1195+ sqlite3_log(SQLITE_ERROR, "binlog row data empty, %llu", nData); 1196+ return SQLITE_ERROR; 1197+ } 1198+ 1199+ u8 opData = op == SQLITE_DELETE ? SQLITE_DELETE: SQLITE_INSERT; 1200+ u64 nRowBuffer = 0; 1201+ char *pRowBuffer = NULL; 1202+ int rc = sqlite3BinlogGetRowBuffer(nData, pData, opData, rowid, &pRowBuffer, &nRowBuffer); 1203+ if (rc != SQLITE_OK) { 1204+ return rc; 1205+ } 1206+ 1207+ rc = sqlite3DirectWriteBinlog(p, BINLOG_EVENT_TYPE_ROW_FULL_DATA, pRowBuffer, nRowBuffer, 0); 1208+ sqlite3_free(pRowBuffer); 1209+ return rc; 1210+} 1211+ 1212+/** 1213+** This is the function called in sqlite3VdbeExec to write a row-based binlog statement. 1214+** If an error occured, then the row data is cleared and the state will be logged in statement mode 1215+**/ 1216+SQLITE_PRIVATE void sqlite3StoreBinlogRowData(Vdbe *p, BtCursor *pCursor, 1217+ sqlite3_uint64 nData, const char *pData, int op, sqlite3_int64 rowid){ 1218+ assert( p!=NULL && pCursor!=NULL ); 1219+ assert( p->db!=NULL ); 1220+ assert( sqlite3IsRowBasedBinlog(p) ); 1221+ assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 1222+ sqlite3 *db = p->db; 1223+ BinlogDMLData *dataContainer = NULL; 1224+ 1225+ Table *pTab = sqlite3BinlogFindTable(pCursor); 1226+ if (pTab == NULL) { 1227+ goto error_when_store_binlog; 1228+ } 1229+ 1230+ if (p->pBinlogDMLData == NULL) { 1231+ /* If pBinlogDMLData is empty, we need to initialize the data by the following steps: 1232+ ** 1. Change the xid if needed 1233+ ** 2. Start a savepoint so that all the rows are in the same transaction 1234+ */ 1235+ dataContainer = (BinlogDMLData *)sqlite3DbMallocZero(db, sizeof(BinlogDMLData)); 1236+ if (dataContainer == NULL) { 1237+ goto error_when_store_binlog; 1238+ } 1239+ 1240+ if (sqlite3UpdateBinlogXidIfNeeded(p->db) != SQLITE_OK) { 1241+ goto error_when_store_binlog; 1242+ } 1243+ 1244+ char xTidStr[SQLITE_UUID_BLOB_LENGTH*2+1] = {0}; 1245+ for (int i=0; i<SQLITE_UUID_BLOB_LENGTH; i++) { 1246+ u8 byte = db->xBinlogHandle.xTid[i]; 1247+ sqlite3_snprintf(3, xTidStr+i*2, "%02x", byte); 1248+ } 1249+ char *savePointName = sqlite3_mprintf("%s%s", "BinlogRow", xTidStr); 1250+ if (savePointName == NULL) { 1251+ goto error_when_store_binlog; 1252+ } 1253+ dataContainer->pSavePointName = savePointName; 1254+ p->pBinlogDMLData = dataContainer; 1255+ int rc = sqlite3DirectWriteBinlog(p, BINLOG_EVENT_TYPE_ROW_START, savePointName, strlen(savePointName)+1, 0); 1256+ if (rc != SQLITE_OK) { 1257+ goto error_when_store_binlog; 1258+ } 1259+ } else { 1260+ dataContainer = p->pBinlogDMLData; 1261+ } 1262+ 1263+ if (dataContainer->pTable != pTab) { 1264+ int rc = sqlite3BinlogWriteTable(p, pTab); 1265+ if (rc != SQLITE_OK) { 1266+ goto error_when_store_binlog; 1267+ } 1268+ dataContainer->pTable = pTab; 1269+ } 1270+ 1271+ if (sqlite3BinlogWriteRowData(p, nData, pData, op, rowid) == SQLITE_OK) { 1272+ return; 1273+ } 1274+ 1275+error_when_store_binlog: 1276+ sqlite3_log(SQLITE_WARNING, "Failed to store row-based binlog data, use statement mode instead."); 1277+ if (p->pBinlogDMLData == NULL && dataContainer != NULL) { 1278+ sqlite3DbFree(db, dataContainer); 1279+ } 1280+ sqlite3FreeBinlogRowData(p); 1281+ return; 1282+} 1283+ 1284+SQLITE_PRIVATE int sqlite3IsRowBasedBinlog(Vdbe *p) { 1285+ return p 1286+ && p->db 1287+ && (p->db->xBinlogHandle.flags & BINLOG_FLAG_ENABLE) 1288+ && (p->db->xBinlogHandle.mode == ROW); 1289+} 1290+ 1291+/* Get i-th column value from a row formated data. i starts from 0 */ 1292+SQLITE_PRIVATE int sqlite3BinlogStat4Column( 1293+ sqlite3 *db, /* Database handle */ 1294+ const void *pRec, /* Pointer to buffer containing record */ 1295+ int nRec, /* Size of buffer pRec in bytes */ 1296+ int iCol, /* Column to extract */ 1297+ sqlite3_value **ppVal /* OUT: Extracted value */ 1298+){ 1299+ u32 t = 0; /* a column type code */ 1300+ u32 nHdr; /* Size of the header in the record */ 1301+ u32 iHdr; /* Next unread header byte */ 1302+ i64 iField; /* Next unread data byte */ 1303+ u32 szField = 0; /* Size of the current data field */ 1304+ int i; /* Column index */ 1305+ u8 *a = (u8*)pRec; /* Typecast byte array */ 1306+ Mem *pMem = *ppVal; /* Write result into this Mem object */ 1307+ 1308+ iHdr = getVarint32(a, nHdr); 1309+ if( nHdr>(u32)nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT; 1310+ iField = nHdr; 1311+ for(i=0; i<=iCol; i++){ 1312+ iHdr += getVarint32(&a[iHdr], t); 1313+ 1314+ if( iHdr>nHdr ) return SQLITE_CORRUPT_BKPT; 1315+ szField = sqlite3VdbeSerialTypeLen(t); 1316+ iField += szField; 1317+ } 1318+ 1319+ if( iField>nRec ) return SQLITE_CORRUPT_BKPT; 1320+ if( pMem==0 ){ 1321+ pMem = *ppVal = sqlite3ValueNew(db); 1322+ if( pMem==0 ) return SQLITE_NOMEM_BKPT; 1323+ } 1324+ sqlite3VdbeSerialGet(&a[iField-szField], t, pMem); 1325+ pMem->enc = ENC(db); 1326+ return SQLITE_OK; 1327+} 1328+ 1329+SQLITE_PRIVATE char *sqlite3BinlogGetHexFromBlobOrStr(sqlite3 *db, sqlite3_value *value) { 1330+ assert( db!=NULL && value!=NULL ); 1331+ size_t strSize = (value->n) * 2 + 1; 1332+ char *zHex, *z; 1333+ z = zHex =sqlite3DbMallocZero(db, strSize); 1334+ if (z == NULL) { 1335+ return NULL; 1336+ } 1337+ for(int i=0; i<value->n; i++) { 1338+ unsigned char c = (value->z)[i]; 1339+ *(z++) = hexdigits[(c>>4)&0xf]; 1340+ *(z++) = hexdigits[c&0xf]; 1341+ } 1342+ *z = 0; 1343+ return zHex; 1344+} 1345+ 1346+SQLITE_PRIVATE char *sqlite3BinlogGetEscapedText(sqlite3 *db, const char *originalStr) { 1347+ sqlite3_str *pStr = sqlite3_str_new(db); 1348+ size_t nOriginal = strlen(originalStr); 1349+ sqlite3_str_appendchar(pStr, 1, '\''); 1350+ for (size_t i=0; i<nOriginal; i++) { 1351+ if (originalStr[i] == '\'') { 1352+ sqlite3_str_appendchar(pStr, 1, '\''); 1353+ } 1354+ sqlite3_str_appendchar(pStr, 1, originalStr[i]); 1355+ } 1356+ sqlite3_str_appendchar(pStr, 1, '\''); 1357+ return sqlite3_str_finish(pStr); 1358+} 1359+ 1360+SQLITE_PRIVATE char *sqlite3BinlogGetNthCol(sqlite3 *db, const Table *pTab, const BinlogRow *pRow, int iCol) { 1361+ assert( db != NULL && pTab != NULL && pRow != NULL ); 1362+ assert( iCol >= 0 ); 1363+ if (HasRowid(pTab) && pTab->iPKey == iCol) { 1364+ return sqlite3_mprintf("%lld", pRow->rowid); 1365+ } 1366+ 1367+ sqlite3_value *tempVal = NULL; 1368+ sqlite3BinlogStat4Column(db, pRow->pData, pRow->nData, iCol, &tempVal); 1369+ if (tempVal == NULL) { 1370+ sqlite3_log(SQLITE_ERROR, "decode data failed"); 1371+ return NULL; 1372+ } 1373+ int type = sqlite3_value_type(tempVal); 1374+ const unsigned char *temp = sqlite3_value_text(tempVal); 1375+ 1376+ char *res = NULL; 1377+ if (type == SQLITE_BLOB) { 1378+ char *hex = sqlite3BinlogGetHexFromBlobOrStr(db, tempVal); 1379+ if (hex != NULL) { 1380+ res = sqlite3_mprintf("x'%s'", hex); 1381+ sqlite3DbFree(db, hex); 1382+ } else { 1383+ res = sqlite3_mprintf("'%s'", temp); 1384+ } 1385+ } else if (type == SQLITE_TEXT) { 1386+ res = sqlite3BinlogGetEscapedText(db, (const char *)temp); 1387+ } else if (type == SQLITE_NULL) { 1388+ res = sqlite3_mprintf("NULL"); 1389+ } else { 1390+ res = sqlite3_mprintf("%s", temp); 1391+ } 1392+ sqlite3ValueFree(tempVal); 1393+ 1394+ return res; 1395+} 1396+ 1397+/* Check if binlog is enabled and the stmtType needs being logged */ 1398+SQLITE_PRIVATE int sqlite3IsSkipWriteBinlog(Vdbe *p) { 1399+ int isBinlogEnabled = (p != NULL) && (p->db != NULL) && 1400+ ((p->db->xBinlogHandle.flags & BINLOG_FLAG_ENABLE) != 0) && 1401+ p->db->xBinlogHandle.binlogApi.binlogWriteApi; 1402+ 1403+ return p == NULL 1404+ || !isBinlogEnabled 1405+ || p->db->nVdbeExec > 1 1406+ || (p->readOnly && p->stmtType != STMT_TYPE_BEGIN_TRANSACTION && p->stmtType != STMT_TYPE_SAVEPOINT && 1407+ p->stmtType != STMT_TYPE_COMMIT_TRANSACTION && p->stmtType != STMT_TYPE_ROLLBACK_TRANSACTION); 1408+} 1409+ 1410+SQLITE_PRIVATE void sqlite3BinlogWrite(Vdbe *p) 1411+{ 1412+ if (sqlite3IsSkipWriteBinlog(p)) { 1413+ sqlite3FreeBinlogRowData(p); 1414+ return; 1415+ } 1416+ 1417+ sqlite3 *db = p->db; 1418+ BinlogWriteDataT logData; 1419+ logData.type = sqlite3TransferLogEventType(p->stmtType); 1420+ 1421+ char *zSql = NULL; 1422+ if (logData.type == BINLOG_EVENT_TYPE_DML && sqlite3IsRowBasedBinlog(p) && p->pBinlogDMLData != NULL) { 1423+ // release savepoint 1424+ zSql = sqlite3_mprintf("%s", p->pBinlogDMLData->pSavePointName); 1425+ logData.type = BINLOG_EVENT_TYPE_ROW_COMMIT; 1426+ p->pBinlogDMLData->isSavePointReleased = 1; 1427+ } else { 1428+ zSql = sqlite3_expanded_sql((sqlite3_stmt *)p); 1429+ } 1430+ if (zSql == NULL) { 1431+ sqlite3_log(SQLITE_ERROR, "binlog get sql failed"); 1432+ sqlite3FreeBinlogRowData(p); 1433+ return; 1434+ } 1435+ 1436+ if (sqlite3UpdateBinlogXidIfNeeded(db) != SQLITE_OK) { 1437+ sqlite3FreeBinlogRowData(p); 1438+ sqlite3BinlogErrorCallback(db, SQLITE_ERROR, "generate tid failed"); 1439+ sqlite3_free(zSql); 1440+ sqlite3BinlogClose(db); 1441+ return; 1442+ } 1443+ errno_t errNo = EOK; 1444+ errNo = memcpy_s(&logData.xid, SQLITE_UUID_BLOB_LENGTH, db->xBinlogHandle.xTid, SQLITE_UUID_BLOB_LENGTH); 1445+ if (errNo != EOK) { 1446+ sqlite3FreeBinlogRowData(p); 1447+ sqlite3BinlogErrorCallback(db, SQLITE_ERROR, "copy tid failed"); 1448+ sqlite3_free(zSql); 1449+ sqlite3BinlogClose(db); 1450+ return; 1451+ } 1452+ logData.data = zSql; 1453+ logData.dataLength = strlen(zSql); 1454+ logData.isFinishTrx = db->autoCommit; 1455+ int rc = sqlite3TransferBinlogErrno(db->xBinlogHandle.binlogApi.binlogWriteApi(db->xBinlogHandle.binlogConn, 1456+ &logData)); 1457+ sqlite3_free(zSql); 1458+ if (rc != SQLITE_OK) { 1459+ sqlite3FreeBinlogRowData(p); 1460+ sqlite3_log(SQLITE_ERROR, "binlog write err:%d len:%u", rc, logData.dataLength); 1461+ sqlite3BinlogClose(db); 1462+ return; 1463+ } 1464+ if (db->autoCommit > 0) { 1465+ db->xBinlogHandle.flags |= BINLOG_FLAG_UPDATE_TID; 1466+ } 1467+ sqlite3FreeBinlogRowData(p); 1468+} 1469+ 1470+SQLITE_PRIVATE int sqlite3TransferBinlogErrno(BinlogErrno err) 1471+{ 1472+ switch (err) { 1473+ case GMERR_OK: 1474+ return SQLITE_OK; 1475+ case GMERR_LOCK_NOT_AVAILABLE: 1476+ return SQLITE_BUSY; 1477+ case GMERR_BINLOG_READ_FINISH: 1478+ return SQLITE_DONE; 1479+ default: 1480+ return SQLITE_ERROR; 1481+ } 1482+} 1483+ 1484+SQLITE_PRIVATE int sqlite3BinlogClose(sqlite3 *db) 1485+{ 1486+ if (db == NULL) { 1487+ sqlite3_log(SQLITE_ERROR, "binlog close parameter is null"); 1488+ return SQLITE_ERROR; 1489+ } 1490+ if ((db->xBinlogHandle.flags & BINLOG_FLAG_ENABLE) == 0) { 1491+ return SQLITE_OK; 1492+ } 1493+ if (db->xBinlogHandle.binlogApi.binlogCloseApi) { 1494+ int rc = sqlite3TransferBinlogErrno(db->xBinlogHandle.binlogApi.binlogCloseApi(db->xBinlogHandle.binlogConn)); 1495+ if (rc != SQLITE_OK) { 1496+ sqlite3_log(rc, "binlog close err:%d", rc); 1497+ return rc; 1498+ } 1499+ } 1500+ sqlite3BinlogReset(db); 1501+ return SQLITE_OK; 1502+} 1503+ 1504+SQLITE_PRIVATE void sqlite3BinlogReset(sqlite3 *db) 1505+{ 1506+ if (db == NULL) { 1507+ sqlite3_log(SQLITE_ERROR, "binlog reset parameter is null"); 1508+ return; 1509+ } 1510+ db->xBinlogHandle.flags = 0; 1511+ (void)memset_s(db->xBinlogHandle.xTid, SQLITE_UUID_BLOB_LENGTH, 0, SQLITE_UUID_BLOB_LENGTH); 1512+ db->xBinlogHandle.xErrorCallback = NULL; 1513+ db->xBinlogHandle.binlogApi.binlogOpenApi = NULL; 1514+ db->xBinlogHandle.binlogApi.binlogCloseApi = NULL; 1515+ db->xBinlogHandle.binlogApi.binlogWriteApi = NULL; 1516+ db->xBinlogHandle.binlogApi.binlogReadApi = NULL; 1517+ db->xBinlogHandle.binlogApi.binlogFileCleanApi = NULL; 1518+ db->xBinlogHandle.binlogApi.binlogFreeReadResultApi = NULL; 1519+ db->xBinlogHandle.binlogApi.binlogLockReadApi = NULL; 1520+ db->xBinlogHandle.binlogApi.binlogUnlockReadApi = NULL; 1521+ db->xBinlogHandle.callbackCtx = NULL; 1522+ db->xBinlogHandle.binlogConn = NULL; 1523+ if (db->xBinlogHandle.binlogApi.binlogLib) { 1524+ sqlite3OsDlClose(db->pVfs, db->xBinlogHandle.binlogApi.binlogLib); 1525+ db->xBinlogHandle.binlogApi.binlogLib = NULL; 1526+ } 1527+ db->xBinlogHandle.isSkipTrigger = 0; 1528+} 1529+ 1530+SQLITE_PRIVATE int sqlite3BinlogStmtPrepare(sqlite3 *db, Sqlite3BinlogStmt *bStmt) 1531+{ 1532+ if (db == NULL || db->xBinlogHandle.binlogApi.binlogReadApi == NULL || bStmt == NULL) { 1533+ sqlite3_log(SQLITE_ERROR, "binlog stmt prepare parameter is null"); 1534+ return SQLITE_ERROR; 1535+ } 1536+ BinlogReadResultT *result = NULL; 1537+ int rc = sqlite3TransferBinlogErrno(db->xBinlogHandle.binlogApi.binlogReadApi(db->xBinlogHandle.binlogConn, 1538+ &result)); 1539+ if (rc != SQLITE_OK) { 1540+ if (rc != SQLITE_DONE) { 1541+ sqlite3_log(rc, "binlog stmt prepare err:%d", rc); 1542+ } 1543+ return rc; 1544+ } 1545+ bStmt->cursor = result; 1546+ bStmt->curIdx = 0; 1547+ return SQLITE_OK; 1548+} 1549+ 1550+SQLITE_PRIVATE char *sqlite3BinlogGetRowSql(sqlite3 *db, Table* pTable, char *buffer, u32 nBuffer, int *rc) 1551+{ 1552+ if (buffer == NULL) { 1553+ *rc = SQLITE_ERROR; 1554+ sqlite3_log(SQLITE_ERROR, "binlog row has no data"); 1555+ return NULL; 1556+ } 1557+ 1558+ u8 op = 0; 1559+ sqlite3_int64 rowid = 0; 1560+ sqlite3_uint64 nData = 0; 1561+ char *pData = NULL; 1562+ *rc = sqlite3BinlogDecodeRowBuffer(buffer, nBuffer, &op, &rowid, &nData, &pData); 1563+ if (*rc != SQLITE_OK) { 1564+ return NULL; 1565+ } 1566+ 1567+ BinlogRow pRow; 1568+ pRow.op = op; 1569+ pRow.nData = nData; 1570+ pRow.pData = pData; 1571+ pRow.rowid = rowid; 1572+ return sqlite3GetBinlogRowStmt(db, &pRow, pTable); 1573+} 1574+ 1575+SQLITE_PRIVATE Table *sqliteBinlogGetTable(sqlite3 *db, const char *pTableName, int *rc) 1576+{ 1577+ assert( db!=NULL ); 1578+ assert( pTableName!=NULL ); 1579+ assert( rc!=NULL ); 1580+ sqlite3_stmt *stmt = NULL; 1581+ *rc = sqlite3_prepare_v2(db, "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table';", -1, &stmt, NULL); 1582+ if (*rc != SQLITE_OK) { 1583+ return NULL; 1584+ } 1585+ *rc = sqlite3_step(stmt); 1586+ Table *pTable = sqlite3FindTable(db, pTableName, NULL); 1587+ sqlite3_finalize(stmt); 1588+ return pTable; 1589+} 1590+ 1591+SQLITE_PRIVATE char *sqlite3BinlogGetEventSql(sqlite3 *db, BinlogEventT *event, Table **pOutTable, int *rc) 1592+{ 1593+ assert( event!=NULL ); 1594+ switch (event->head.eventType) { 1595+ case BINLOG_EVENT_TYPE_ROW_START: 1596+ return sqlite3_mprintf("savepoint %s;", (char *)event->body); 1597+ case BINLOG_EVENT_TYPE_ROW_TABLE: { 1598+ char *pTableName = (char *)event->body; 1599+ *pOutTable = sqliteBinlogGetTable(db, pTableName, rc); 1600+ if (*pOutTable == NULL) { 1601+ *rc = SQLITE_ERROR; 1602+ sqlite3_log(SQLITE_WARNING, "binlog find no table, rc=%d", *rc); 1603+ } else { 1604+ *rc = SQLITE_OK; 1605+ } 1606+ return NULL; 1607+ } 1608+ case BINLOG_EVENT_TYPE_ROW_FULL_DATA: 1609+ if (pOutTable == NULL || *pOutTable == NULL) { 1610+ *rc = SQLITE_ERROR; 1611+ sqlite3_log(SQLITE_ERROR, "binlog row has no table"); 1612+ return NULL; 1613+ } 1614+ return sqlite3BinlogGetRowSql(db, *pOutTable, (char *)event->body, event->head.eventLength, rc); 1615+ case BINLOG_EVENT_TYPE_ROW_COMMIT: 1616+ return sqlite3_mprintf("release %s;", (char *)event->body); 1617+ case BINLOG_EVENT_TYPE_ROW_ROLLBACK: 1618+ return sqlite3_mprintf("rollback to %s;", (char *)event->body); 1619+ default: 1620+ return sqlite3_mprintf("%s", (char *)event->body); 1621+ } 1622+} 1623+ 1624+SQLITE_PRIVATE int sqlite3BinlogStmtStep(sqlite3 *db, Sqlite3BinlogStmt *bStmt, char **sql, Table **pOutTable) 1625+{ 1626+ if (bStmt == NULL || bStmt->cursor == NULL || sql == NULL) { 1627+ sqlite3_log(SQLITE_ERROR, "binlog stmt step parameter is null"); 1628+ return SQLITE_ERROR; 1629+ } 1630+ if (bStmt->curIdx >= bStmt->cursor->eventNum) { 1631+ return SQLITE_DONE; 1632+ } 1633+ BinlogEventT *event = bStmt->cursor->sqlEvent[bStmt->curIdx]; 1634+ if (event == NULL) { 1635+ sqlite3_log(SQLITE_ERROR, "binlog stmt step event is null"); 1636+ return SQLITE_ERROR; 1637+ } 1638+ int rc = SQLITE_OK; 1639+ *sql = sqlite3BinlogGetEventSql(db, event, pOutTable, &rc); 1640+ if (rc != SQLITE_OK){ 1641+ return rc; 1642+ } 1643+ bStmt->curIdx++; 1644+ return SQLITE_ROW; 1645+} 1646+ 1647+SQLITE_PRIVATE void sqlite3BinlogStmtFinalize(sqlite3 *db, Sqlite3BinlogStmt *bStmt) 1648+{ 1649+ if (db == NULL || bStmt == NULL || bStmt->cursor == NULL || 1650+ db->xBinlogHandle.binlogApi.binlogFreeReadResultApi == NULL) { 1651+ sqlite3_log(SQLITE_WARNING, "binlog stmt finalize parameter is null"); 1652+ return; 1653+ } 1654+ db->xBinlogHandle.binlogApi.binlogFreeReadResultApi(db->xBinlogHandle.binlogConn, bStmt->cursor); 1655+ bStmt->cursor = NULL; 1656+ bStmt->curIdx = 0; 1657+} 1658+ 1659+SQLITE_PRIVATE int sqlite3BinlogExecuteReplaySql(sqlite3 *srcDb, sqlite3 *destDb, const char *sql) 1660+{ 1661+ if (srcDb == NULL || destDb == NULL || sql == NULL) { 1662+ sqlite3_log(SQLITE_ERROR, "binlog execute replay sql parameter is null"); 1663+ return SQLITE_ERROR; 1664+ } 1665+ int rc = sqlite3_exec(destDb, sql, NULL, NULL, NULL); 1666+ if (rc == SQLITE_OK || rc == SQLITE_CONSTRAINT) { 1667+ return SQLITE_OK; 1668+ } 1669+ return rc; 1670+} 1671+ 1672+SQLITE_PRIVATE int sqlite3BinlogReplay(sqlite3 *srcDb, sqlite3 *destDb) 1673+{ 1674+ if (srcDb == NULL || destDb == NULL) { 1675+ sqlite3_log(SQLITE_ERROR, "binlog replay parameter is null"); 1676+ return SQLITE_ERROR; 1677+ } 1678+ if ((srcDb->xBinlogHandle.flags & BINLOG_FLAG_ENABLE) == 0) { 1679+ sqlite3_log(SQLITE_ERROR, "binlog replay srcDb not enable binlog"); 1680+ return SQLITE_ERROR; 1681+ } 1682+ const char *srcFile = sqlite3_db_filename(srcDb, 0); 1683+ const char *destFile = sqlite3_db_filename(destDb, 0); 1684+ if (srcFile == NULL || destFile == NULL || strcmp(srcFile, destFile) == 0) { 1685+ return SQLITE_ERROR; 1686+ } 1687+ int res = 1688+ sqlite3TransferBinlogErrno(srcDb->xBinlogHandle.binlogApi.binlogLockReadApi(srcDb->xBinlogHandle.binlogConn)); 1689+ if (res == SQLITE_BUSY) { 1690+ return res; 1691+ } 1692+ if (res != SQLITE_OK) { 1693+ sqlite3BinlogClose(srcDb); 1694+ return res; 1695+ } 1696+ u8 oldIsSkipTrigger = destDb->xBinlogHandle.isSkipTrigger; 1697+ destDb->xBinlogHandle.isSkipTrigger = 1; 1698+ do { 1699+ Sqlite3BinlogStmt bStmt; 1700+ bStmt.curIdx = 0; 1701+ bStmt.cursor = NULL; 1702+ res = sqlite3BinlogStmtPrepare(srcDb, &bStmt); 1703+ if (res != SQLITE_OK) { 1704+ if (res == SQLITE_DONE) { 1705+ res = SQLITE_OK; 1706+ } else { 1707+ sqlite3_log(res, "read binlog failed"); 1708+ } 1709+ break; 1710+ } 1711+ char *bSql = NULL; 1712+ Table *pTab = NULL; 1713+ while ((res = sqlite3BinlogStmtStep(destDb, &bStmt, &bSql, &pTab)) == SQLITE_ROW) { 1714+ if (bSql == NULL) { 1715+ continue; 1716+ } 1717+ int errCode = sqlite3BinlogExecuteReplaySql(srcDb, destDb, bSql); 1718+ sqlite3_free(bSql); 1719+ bSql = NULL; 1720+ if (errCode != SQLITE_OK) { 1721+ res = errCode; 1722+ break; 1723+ } 1724+ } 1725+ sqlite3BinlogStmtFinalize(srcDb, &bStmt); 1726+ if (res != SQLITE_DONE && res != SQLITE_OK) { 1727+ sqlite3BinlogErrorCallback(srcDb, res, "exec replay sql failed"); 1728+ } 1729+ if (res != SQLITE_DONE) { 1730+ break; 1731+ } 1732+ } while (1); 1733+ destDb->xBinlogHandle.isSkipTrigger = oldIsSkipTrigger; 1734+ (void)srcDb->xBinlogHandle.binlogApi.binlogUnlockReadApi(srcDb->xBinlogHandle.binlogConn); 1735+ if (res != SQLITE_OK) { 1736+ sqlite3BinlogClose(srcDb); 1737+ } 1738+ return res; 1739+} 1740+ 1741+SQLITE_PRIVATE int sqlite3BinlogClean(sqlite3 *db, BinlogFileCleanModeE mode) 1742+{ 1743+ if (db == NULL || mode < BINLOG_FILE_CLEAN_ALL_MODE || 1744+ mode >= BINLOG_FILE_CLEAN_MODE_MAX || (db->xBinlogHandle.flags & BINLOG_FLAG_ENABLE) == 0 || 1745+ db->xBinlogHandle.binlogApi.binlogFileCleanApi == NULL) { 1746+ sqlite3_log(SQLITE_ERROR, "binlog clean parameter is invalid"); 1747+ return SQLITE_ERROR; 1748+ } 1749+ 1750+ return sqlite3TransferBinlogErrno(db->xBinlogHandle.binlogApi.binlogFileCleanApi(db->xBinlogHandle.binlogConn, mode)); 1751+} 1752+ 1753+SQLITE_PRIVATE void sqlite3BinlogErrorCallback(sqlite3 *db, int errNo, char *errMsg) 1754+{ 1755+ if (db == NULL || db->xBinlogHandle.xErrorCallback == NULL) { 1756+ return; 1757+ } 1758+ 1759+ const char *zFile = sqlite3_db_filename(db, 0); 1760+ if (zFile == NULL || (db->xBinlogHandle.flags & BINLOG_FLAG_ENABLE) == 0) { 1761+ sqlite3_log(SQLITE_ERROR, "binlog db has no file path"); 1762+ return; 1763+ } 1764+ db->xBinlogHandle.xErrorCallback(db->xBinlogHandle.callbackCtx, errNo, errMsg, zFile); 1765+} 1766+/************** End of binlog implement ************************************/ 1767+#endif /* SQLITE_ENABLE_BINLOG */ 1768+ 1769 // export the symbols 1770 #ifdef SQLITE_EXPORT_SYMBOLS 1771 #ifndef SQLITE_CKSUMVFS_STATIC 1772@@ -256942,6 +258434,9 @@ struct sqlite3_api_routines_extra { 1773 int (*key_v2)(sqlite3*,const char*,const void*,int); 1774 int (*rekey)(sqlite3*,const void*,int); 1775 int (*rekey_v2)(sqlite3*,const char*,const void*,int); 1776+ int (*is_support_binlog)(void); 1777+ int (*replay_binlog)(sqlite3*, sqlite3*); 1778+ int (*clean_binlog)(sqlite3*, BinlogFileCleanModeE); 1779 }; 1780 1781 typedef struct sqlite3_api_routines_extra sqlite3_api_routines_extra; 1782@@ -256952,13 +258447,22 @@ static const sqlite3_api_routines_extra sqlite3ExtraApis = { 1783 sqlite3_key, 1784 sqlite3_key_v2, 1785 sqlite3_rekey, 1786- sqlite3_rekey_v2 1787+ sqlite3_rekey_v2, 1788 #else 1789 0, 1790 0, 1791 0, 1792- 0 1793+ 0, 1794 #endif /* SQLITE_HAS_CODEC */ 1795+#ifdef SQLITE_ENABLE_BINLOG 1796+ sqlite3_is_support_binlog, 1797+ sqlite3_replay_binlog, 1798+ sqlite3_clean_binlog, 1799+#else 1800+ 0, 1801+ 0, 1802+ 0, 1803+#endif/* SQLITE_ENABLE_BINLOG */ 1804 }; 1805 1806 EXPORT_SYMBOLS const sqlite3_api_routines *sqlite3_export_symbols = &sqlite3Apis; 1807-- 18082.47.0.windows.2 1809 1810