#pragma once #include "schema.h" namespace scdriver { /// /// Replication type /// enum REPLICATION_TYPE { MERGE = 1, /// Bi-directional (merge) replication. Allows to modify the content in both subscriber and publisher. READ = 2, /// Read replication. Subscriber cannot modify content and it gets incremental changes from publisher }; /// /// Specifies the type of conflict for the row between publisher and subscriber /// enum CONFLICT_TYPE { PUBLISH_INSERT = 1, /// Publisher's new row conflicts (uniqness) with an existing row in a subscriber. DELETE_UPDATE = 2, /// Subscriber deleted row, but publisher updated. UPDATE_DELETE = 3, /// Subscriber updated row that the publisher has deleted. UPDATE_UPDATE = 4, /// Both update the same row and the same column. }; /// /// Specifies the type of conflict resolution /// enum MERGE_TYPE { CUSTOM = 1, /// User already performed it. Simply delete the current conflict log records. AUTO = 2, /// Perform auto merge. Most of the times publisher's changes will win, except PUBLISH_INSERT. REVERT = 3, /// Force publisher's changes. }; struct CONFLICT_ROW_INFO { CONFLICT_ROW_INFO() { nrows = 0; }; CONFLICT_ROW_INFO(const unsigned char &_version, const unsigned char &_cmd) { version[0] = _version; cmd[0] = _cmd; nrows = 1; }; void insert_row(const unsigned char &_version, const unsigned char &_cmd) { if(nrows < 3) { version[nrows] = _version; cmd[nrows] = _cmd; nrows++; } }; unsigned char version[3]; unsigned char cmd[3]; unsigned char nrows; }; typedef std::map CONFLICTS; /// /// If during replication rows are conflicting, the class will provide all information and methods /// to resolve the conflict /// class __declspec( dllexport ) CMergeConflict { public: CMergeConflict(c_table_schema *_schema, CConnection *_conn, const char *_publisher, const unsigned __int64 &_orid, const CONFLICT_ROW_INFO &_rw); CMergeConflict(); /// /// Finalize conflict resolution. /// /// Provides the type of conflict resolution. /// Performs merge conflict resolution, except if CUSTOM specified, and deletes conflict history. If method fails, the node_exception, containing the error message, will be thrown void Resolve(const MERGE_TYPE &type); /// /// Execute SQL command on publisher. /// /// SQL statement text. It cannot contain the input/output parameters. /// Performs merge conflict resolution, except if CUSTOM specified, and deletes conflict history. If method fails, the node_exception, containing the error message, will be thrown void ExecutePublisher(const char *sql); /// /// Make read conflicting row SELECT SQL. The row will be exclusivelly locked. /// /// fill SQL select statement text. /// Row version: 0 - original values, 1 - the newest from subscriber, 2 - the newest from publisher /// If method fails, the node_exception, containing the error message, will be thrown void MakeSQL(char sql[8192], const unsigned char &version); CONFLICT_TYPE type; unsigned __int64 orid; CONFLICT_ROW_INFO rw; CConnection *conn; char *publisher; c_table_schema *schema; }; /// /// DB replication manager class. Used to Subscribe, Unsubscribe and Synchronize tables. /// class __declspec( dllexport ) CTableSynchronize { public: CTableSynchronize(); ~CTableSynchronize(); bool Synchronize(CConnection *sub_conn, const char *pub_conn, const char *sub_table, const char *pub_table,const char *filter); CMergeConflict *ReadNextConflict(); void Commit(); /************************************** * * function: g e t _ c a l l _ s i z e * ************************************** * * Functional description * * return the size of the class **************************************/ int get_class_size(); private: c_table_schema *schema; CConnection *sub_conn; char publisher[128]; CMergeConflict *crw; CONFLICTS *conflicts; char *catalog; char *table; CONFLICTS::iterator iconflicts; }; }