#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;
};
}