Skip to main content

skip to main content

developerWorks  >  Information Management  >

Tailor DB2 Everyplace with custom logic

Examples for key substitution and conflict resolution

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


Rate this page

Help us improve this content


Level: Intermediate

John Casey (jcasey@us.ibm.com), Certified Software IT Specialist, IBM

28 Apr 2005

Custom logic lets you perform specific actions during the IBM® DB2® Everyplace® synchronization and replication process. This article gives you specific detailed examples showing how to implement DB2 Everyplace custom logic for primary key and foreign key substitution, and for conflict resolution.

Note: Please read the disclaimer before you read the article.

Introduction

DB2 Everyplace is a vital piece of IBM's solution for pervasive computing, and gives you the capability to synchronize data between mobile or embedded devices and other data sources in your enterprise. When you set up your DB2 Everyplace solution, you may find that you need to add custom logic to your subscriptions in order to perform actions such as maintaining statistics, performing primary and foreign key substitutions, performing conflict resolution, or initiating an external process.

DB2 Everyplace custom logic is documented in the IBM DB2 Everyplace Sync Server Administration Guide, SC18-7186-02, the section on Custom logic. Begin by reading this section of the manual to get a basic understanding of how you can use custom logic to tailor your DB2 Everyplace Sync Server to meet your unique business requirements.

Once you are familiar with the concepts, it's time to jump in and try it out. To help you get going, this article contains several custom logic examples that address two areas where DB2 Everyplace commonly requires tailoring. The two areas are:

  • Primary key and foreign key substitution
  • Conflict resolution


Back to top


Primary key and foreign key substitution

One of the requirements of a DB2 Everyplace environment is that primary keys be unique across the source database and all of the client databases. There are many way to accomplish this. Some ways to do this are:

  • One of the columns of the primary key is the location of the insert.
  • Use program logic to allocate a range of keys to each database.
  • Use DB2 Everyplace custom logic with a single source for the next key.

In addition to the primary key, this same logic must be applied to other tables that are related to the table through a foreign key.

The following statement is an example of implementing primary key and foreign key substitution using two tables. The first table is the ORD_HDR (order header) table:

CREATE TABLE CL.ORD_HDR ( 
   ORDER_NBR INTEGER NOT NULL, 
   CUSTOMER_NBR INTEGER NOT NULL, 
   TAKEN_DATE DATE NOT NULL, 
   PROMISE_DATE DATE, 
   DELIVERY_DATE DATE, 
   SALESPERSON_NBR INTEGER NOT NULL, 
   PRIMARY KEY (ORDER_NBR))

The single source for the next ORDER_NBR is contained in a table in the source data. The definition for this table is:

CREATE TABLE CL.NEXT_SEQ (NEXT_SEQ INTEGER)

To minimize locking problems on this table, all applications should get a next number by issuing these SQL statements in this order:

  1. UPDATE CL.NEXT_SEQ SET NEXT_SEQ = NEXT_SEQ + 1
  2. SELECT NEXT_SEQ FROM CL.NEXT_SEQ
  3. COMMIT

Since this table will not be available to the client applications, the client applications will use a negative number when inserting a new order header row. This number can be retreived by the following SQL statement:

SELECT -(COUNT(*)+1) FROM ORD_HDR WHERE ORDER_NBR < 0

When the client machine synchronizes, the DB2 Everyplace Custom Logic will recognize that key substitution must be done because the order number is a negative number. This substitution will be done by retrieving a next key from the CL.NEXT_SEQ table in the source database. In addition, the before and after key for this client will be recorded in a table contained in the mirror database. The definition for this table is:

CREATE TABLE CL.ORD_NBR_HOLD ( 
   CLIENT_ID VARCHAR(56) NOT NULL,
   OLD_NBR INTEGER NOT NULL,
   NEW_NBR INTEGER NOT NULL, 
   PRIMARY KEY(CLIENT_ID,OLD_NBR))

This information is recorded so that foreign key substitution can be done for the order detail table. On the client machine, when an application inserts a row into the order detail table, the same negative order number of the order header table will be used. The definition of the order detail table used in this example is:

CREATE TABLE CL.ORD_DET ( 
   ORDER_NBR INTEGER NOT NULL, 
   SEQ_NBR SMALLINT NOT NULL, 
   ITEM_NBR CHAR(16) NOT NULL, 
   ITEM_DESC CHAR(40) NOT NULL, 
   ITEM_QTY INTEGER NOT NULL, 
   ITEM_PRICE DECIMAL(10,2) NOT NULL, 
   ITEM_COST DECIMAL(10,2), 
   PRIMARY KEY(ORDER_NBR, SEQ_NBR))

The DB2 Everyplace Custom Logic associated with the order detail table will do foreign key substitution when the ORDER_NBR value is negative by selecting from the CL.ORD_NBR_HOLD table with predicates that supply the client id and the negative order number to be converted. Since two clients could use the same negative number, the CL.ORD_NBR_HOLD table must contain the client id to distinguish between these identical values.

Since the custom logic module for the CL.ORD_HDR table generates the "real" order number that will be used in both the CL.ORD_HDR table and the CL.ORD_DET table, this custom logic module must be executed first. To ensure that this custom logic module is executed first, the CL.ORD_HDR table must be defined in the subscription before the CL.ORD_DET table.

After the primary key and foreign key substitution has completed successfully, the rows from a client must be deleted from the CL.ORD_NBR_HOLD table. This deletion is handled by DB2 Everyplace custom logic AfterTablePolicy on the order detail table.

One last note about this example. You will see in the DB2 Everyplace custom logic for the order header table that the CL.ORD_NBR_HOLD table is read first to see if the number has already been assigned. This is possible because of how the DB2 Everyplace Sync Server does recovery. With this additonal code, you can handle both normal processing and recovery processing.

So, for this example, we will execute three DB2 Everyplace Custom Logic modules, at these points:

  1. During the synching of the order header table from the client (shown in Listing 1)
  2. During the synching of the order detail table from the client (shown in Listing 2)
  3. After the synching of the order detail table from the client (shown in Listing 3)

Listing 1. OrdHdrTablePolicySyncIn.java
				
package com.jcasey.cl;
import com.ibm.db2ess.cl.*;
import java.sql.*;


/**
 * <pre>
 * Descriptive Name:  Custom Logic during the processing of input synchronization data.
 *
 * Description:
 *    This class is called by Sync Server during the processing of input synchronization 
 *    data for the sample order header table. For inserts coming from the client the 
 *    ORDER_NBR column is reset to the next order number available based upon 
 *    NEXT_ORD_NBR table in the source database (CUSTOM).
 *
 *
 *    @see com.ibm.db2ess.cl.TablePolicy
 * 		@see com.ibm.db2ess.cl.CLException
 */
public class OrdHdrTablePolicySyncIn extends TablePolicy {

  /**
   * This method will be invoked by the SyncServer during the processing of input 
   * synchronization data.
   *
   * @exception com.ibm.db2ess.cl.CLException
   * Custom logic generated or encountered exception.
   */
  public void execute(CLRecord iRecord) throws CLException {

	KCDataLog sdl = KCDataLog.getInstance();
		// Go thru the candidate to look if we need to perform Primary Key mapping
			
		// The primary key column index is 0 in this sample.
		int pkColInd = 0;

		// Get the candidate array and process it
		CLCandidate[] clCandidateArray = iRecord.getCandidates();
		// Scan all the the CLCandidates
		String DSY_user2 = "jcasey";
  		String DSY_pw2   = "songhui";
  		String URL2 = "jdbc:db2:M_CUSTOM";
  		String DSY_user = "jcasey";
  		String DSY_pw   = "songhui";
  		String URL = "jdbc:db2:CUSTOM";
  		String stmtID = "trying to connect to CUSTOM";
        
      	try {
      	   Connection con = DriverManager.getConnection(URL, DSY_user, DSY_pw );
          con.setAutoCommit(false);
          String sqlValue1 = "UPDATE CL.NEXT_SEQ SET NEXT_SEQ = NEXT_SEQ + 1";
          stmtID = "prepare " + sqlValue1;
          PreparedStatement stmt1 = con.prepareStatement(sqlValue1);
          String sqlValue2 = "SELECT NEXT_SEQ FROM CL.NEXT_SEQ";
          stmtID = "prepare " + sqlValue2;
          PreparedStatement stmt2  = con.prepareStatement(sqlValue2); 
          stmtID = "trying to connect to M_CUSTOM";
		Connection con2 = DriverManager.getConnection(URL2, DSY_user2, DSY_pw2 );
		con2.setAutoCommit(false);
		String sqlValue3 = "INSERT INTO CL.ORD_NBR_HOLD VALUES (?,?,?)";
		stmtID = "prepare " + sqlValue3;
		PreparedStatement stmt3  = con2.prepareStatement(sqlValue3);
		String sqlValue4 = "SELECT NEW_NBR FROM CL.ORD_NBR_HOLD 
					WHERE CLIENT_ID = ?" +
		                   " AND OLD_NBR = ?";
		stmtID = "prepare " + sqlValue4;
		PreparedStatement stmt4  = con2.prepareStatement(sqlValue4);
		// Scan all the the CLCandidates
		for (int i=0; i < clCandidateArray.length; i++) {
*	The CLCandidate.getAuthor() method returns a CLCorrespondent object, 
	which has a method getDeviceId(), which in turn returns a String device id.
*/
      		CLCorrespondent myClc = clCandidateArray[i].getAuthor(); 						
		   String deviceId = myClc.getDeviceId();
					
		   if ((clCandidateArray[i].getOp() == CLCandidate.Op.INSERT)
		     && (clCandidateArray[i].fromUser())&&
			   (clCandidateArray[i].getInt(pkColInd) > 0)) {
			int oldINT = clCandidateArray[i].getInt(pkColInd);
			CLCandidate clone = iRecord.createCLCandidate(clCandidateArray[i]);
			// Now we can operate on the clone
			int newINT;
			stmtID = "Setting Parameters for " + sqlValue4;
			stmt4.setString(1,deviceId);
			stmt4.setInt(2,oldINT);
			stmtID = "rs4 " + sqlValue4;
        	ResultSet rs4  = stmt4.executeQuery();
             	stmtID = "rs4.next " + sqlValue4;
             	if (rs4.next()){
             	  stmtID = "rs4.getInt(1) " + sqlValue4;
             	  newINT = rs4.getInt(1);
             	  stmtID = "rs4.close() " + sqlValue4;
             	  rs4.close();
             	}
             	else {
		        stmtID = "update " + sqlValue1;
                stmt1.executeUpdate();
                stmtID = "rs " + sqlValue1;
             	  ResultSet rs  = stmt2.executeQuery();
             	  stmtID = "rs.next " + sqlValue2;
             	  rs.next();
             	  newINT = rs.getInt(1);
             	  stmtID = "rs.close() " + sqlValue2;
             	  rs.close();
             	  stmtID = "con.commit()" ;
             	  con.commit();
             	  // Now record the key substitution
			stmtID = "Setting parms for insert" + sqlValue3;
		 	stmt3.setString(1,deviceId);
			stmt3.setInt(2,oldINT);
			stmt3.setInt(3,newINT);
			stmtID = "executing update " + sqlValue3;
			stmt3.executeUpdate();
			stmtID = "(con2.commit()";
			con2.commit();
             	  }
		  clone.setField(pkColInd, newINT);
		  // Now force the candidate
		  // Sync server is responsible to free the clone when we exit
		  iRecord.force(clone);
		  iRecord.apply();
		  String s = new String( "OrdHdrTablePolicySyncIn for device " + deviceId +
      	"Old value: " + oldINT + " New value: " + newINT);
			sdl.writeOut(s);
		} // end of insert if
		} // end of FOR loop
		stmtID = "close stmts and cons routine";
		stmt1.close();
		stmt2.close();
		stmt3.close();  
		con.close();
		con2.close();
	}
catch (CLCandidateException clCandidateException) {
	sdl.writeOut("!!!CLCandidateException occurs in OrdHdrTablePolicySyncIn!!!");
	}
catch (SQLException e) {
	sdl.writeOut("OrdHdrTablePolicySyncIn Unsuccessful when " + stmtID);
	  sdl.writeOut(e.getMessage());
     	  throw new CLException("OrdHdrTablePolicySyncIn had bad sql return code",e);
	}

	}
}


Listing 2. OrdDetTablePolicySyncIn.java
				
package com.jcasey.cl;
import com.ibm.db2ess.cl.*;
import java.sql.*;


/**
 * <pre>
 * Descriptive Name:  Custom Logic during the processing of input synchronization data.
 *
 * Description:
 *  This class is called by Sync Server during the processing of input synchronization data
 *  for the sample order header table. For inserts coming from the client the ORDER_NBR 
 *  column is reset to the next order number available based upon NEXT_ORD_NBR table in the
 *  source database (CUSTOM).
 *
 *
 *    @see com.ibm.db2ess.cl.TablePolicy
 * 		@see com.ibm.db2ess.cl.CLException
 */
public class OrdDetTablePolicySyncIn extends TablePolicy {

  /**
   * This method will be invoked by the SyncServer during the processing of input 
   *  synchronization data.
   *
   * @exception com.ibm.db2ess.cl.CLException
   * Custom logic generated or encountered exception.
   */
  public void execute(CLRecord iRecord) throws CLException {

   KCDataLog sdl = KCDataLog.getInstance();

        // Go thru the candidate to look if we need to perform Primary Key mapping
	 // The primary key column index is 0 in this sample.
	 int pkColInd = 0;
	 // Get the candidate array and process it
	 CLCandidate[] clCandidateArray = iRecord.getCandidates();
	 // Scan all the the CLCandidates
	 String DSY_user2 = "jcasey";
	 String DSY_pw2   = "songhui";
	 String URL2 = "jdbc:db2:M_CUSTOM";
	 String stmtID = "trying to connect to CUSTOM";
       
   try {
	Connection con = DriverManager.getConnection(URL2, DSY_user2, DSY_pw2 );
			
	String sqlValue = "SELECT NEW_NBR FROM CL.ORD_NBR_HOLD WHERE CLIENT_ID = ?" +
	                   " AND OLD_NBR = ?";
	stmtID = "prepare " + sqlValue;
	PreparedStatement stmt  = con.prepareStatement(sqlValue);
	// Scan all the the CLCandidates
	for (int i=0; i < clCandidateArray.length; i++) {
/*		The CLCandidate.getAuthor() method returns a CLCorrespondent object, 
		which has a method getDeviceId(), which in turn returns a String device id.
*/
      	CLCorrespondent myClc = clCandidateArray[i].getAuthor(); 						
		String deviceId = myClc.getDeviceId();
		if ((clCandidateArray[i].getOp() == CLCandidate.Op.INSERT)
			&& (clCandidateArray[i].fromUser())&&
		   (clCandidateArray[i].getInt(pkColInd) > 0)) {
			int oldINT = clCandidateArray[i].getInt(pkColInd);   				
			CLCandidate clone = iRecord.createCLCandidate(clCandidateArray[i]);
			// Now we can operate on the clone
			stmtID = "Setting Parameters for " + sqlValue;
			stmt.setString(1,deviceId);
			stmt.setInt(2,oldINT);
			stmtID = "rs " + sqlValue;
      		ResultSet rs  = stmt.executeQuery();
      		stmtID = "rs.next " + sqlValue;
      		rs.next();
      		stmtID = "rs.getInt(1) " + sqlValue;
      		int newINT = rs.getInt(1);
      		stmtID = "rs.close() " + sqlValue;
      		rs.close();
		  clone.setField(pkColInd, newINT);
		  // Now force the candidate
		  // Sync server is responsible to free the clone when we exit
		  iRecord.force(clone);
		   iRecord.apply();
		  String s = new String( "OrdDetTablePolicySyncIn for device " + deviceId +
		  " Old value: " + oldINT + " New value: " + newINT);
		  sdl.writeOut(s);
		} // end of insert if
		} // end of FOR loop
	stmtID = "close stmts and cons routine";
		stmt.close();
		con.close();
	}
	catch (CLCandidateException clCandidateException) {
         sdl.writeOut("!!!CLCandidateException occurs in OrdDetTablePolicySyncIn!!!");
	  }
	catch (SQLException e) {
	  sdl.writeOut("OrdDetTablePolicySyncIn Unsuccessful when " + stmtID);
     	  sdl.writeOut(e.getMessage());
     	  throw new CLException("OrdDetTablePolicySyncIn had bad sql return code",e);
	  }
}
}


Listing 3. OrdDetAfterTablePolicySyncIn
				
package com.jcasey.cl;
import com.ibm.db2ess.cl.*;
import java.sql.*;

/**
 * <pre>
 * Descriptive Name:  Custom Logic after completion of handling input synchronization data.
 *
 * Description:
 *    This class is called by Sync Server after completion of handling input 
 *    synchronization data for the sample order header table and 
 *    cleans up the CL.ORD_NBR_HOLD table in the M_CUSTOM database.
 *
 *
 *    @see com.ibm.db2ess.cl.CLCandidate
 *    @see com.ibm.db2ess.cl.CLException
 */
public class OrdDetAfterTablePolicySyncIn extends AfterTablePolicy {

  /**
   * This method will be invoked by the SyncServer after completion of handling 
   *  input synchronization data.
   *
   * @exception com.ibm.db2ess.cl.CLException
   * Custom logic generated or encountered exception.
   */
public void execute(CLCorrespondent[] iCorrespondents,CLResult iCLResult) 
  throws CLException {

  	KCDataLog sdl = KCDataLog.getInstance();
  	String DSY_user = "jcasey";
  	String DSY_pw   = "songhui";     									
  	String URL = "jdbc:db2:M_CUSTOM";
  	String stmtID = "Connection " + URL;
	try {  		
      		Connection con = DriverManager.getConnection(URL, DSY_user, DSY_pw );
     		 for (int i=0; i < iCorrespondents.length; i++) {
      		String deviceId = iCorrespondents[i].getDeviceId();	
      		String sqlValue  = "DELETE FROM CL.ORD_NBR_HOLD WHERE CLIENT_ID = '" +
                       			  	 deviceId + "'" ;
      		stmtID = "Create statement " + sqlValue;
     		Statement stmt = con.createStatement();
     		stmtID = "Execute update " + sqlValue;
     		int deleteCount = stmt.executeUpdate(sqlValue);
     		if (deleteCount > 0){
			sdl.writeOut( "OrdDetAfterTableSyncInPolicy deleted " +
			deleteCount + " rows for device ID = " + deviceId);
			}
		}
	}

  catch (SQLException e) {
	sdl.writeOut("OrdDetAfterTablePolicySyncIn Unsuccessful when " + stmtID);
  sdl.writeOut(e.getMessage());
   throw new CLException("OrdDetAfterTablePolicySyncIn had bad sql return code",e);
        }

	}
}



Back to top


Conflict resolution

In a DB2 Everyplace environment where the same rows exist in the source database and in the client databases, you have the possibility that the same row may be modified at several different locations in the same time frame. DB2 Everyplace Sync Server has a three tier architecture of replicating changes between the source database and the mirror database, and syncrhonizing the changes between the mirror database and the client databases. With this architecture of two asynchronous processes, conflicts are detected during the replication cycle and reported back to the client on the next synchronization of the client.

Because of this complexity of detecting conflicts and resolving and reporting conflicts, a good DB2 Everyplace design avoids or minimizes conflict situations. When a conflict does occur, by default, the modification that took place at the source database wins if the source database is involved in the conflict. In some situations, this default is not what you want to occur.

DB2 Everyplace, for JDBC subscriptions, provides an opportunity for the user to customize the conflict resolution logic by using the DB2 Everyplace Custom Logic Replicate Table Policy. For instance, instead of the modifications coming from the source database winning the conflict, you need to have the modification coming from the client database to win. In the following example, the winner is based upon the modification having the most current timestamp of when the modification occurred. This example requires the following:

  • Clocks on all of the participating computers must be closely synchronized.
  • All modifications of a row update a column in the row that reflects the timestamp of the modification.

This example uses the following table definition:

CREATE TABLE CL.CONTEST (
   C1 INTEGER NOT NULL, D1 CHAR(30), 
   TS_OF_UPDATE TIMESTAMP NOT NULL,
   PRIMARY KEY (C1))

For this example, we will execute a DB2 Everyplace Custom Logic TablePolicy module called ContestTableReplicatePolicy. Listing 4 shows the source code for this module.


Listing 4. ContestTableReplicatePolicy
				\
package com.jcasey.cl;
import com.ibm.db2ess.cl.*;
import java.sql.*;

/**
 * Descriptive Name:  Custom Logic during the replication of one specific table.
 *
 * Description:
 *  This class is called by Sync Server during the replication of one specific table.
 *  For demonstration purpose, this Custom Logic sample demonstrate resolving conflicts
 *  based upon timestamp of the update. This method requires that clocks on all 
 *  participating machines be closely in synch. Custom Logic to resolve conflicts
 *  can only be used for JDBC subscriptions. Custom Logic to resolve conflict CAN NOT 
 *  be used for DPROPR subscriptions.
 *
 */
public class ContestTableReplicatePolicy extends TablePolicy 
	{

  /**
   * This method will be invoked by the SyncServer during the replication of 
   * one specific table.
   *
   * @exception com.ibm.db2ess.cl.CLException
   * Custom logic generated or encountered exception.
   */
public void execute(CLRecord iRecord) throws CLException 
  {

  KCDataLog sdl = KCDataLog.getInstance();
  int tsColInd = 2;
  // The primary key column index is 0 in this example.
  		int pkColInd = 0;
				
  try 
   {
	// Detect the conflict and manage it
	if (iRecord.conflictExists()) 
 	{
	// Go thru the candidate to select the winner
	// Get the candidate array and process it
	CLCandidate[] clCandidateArray = iRecord.getCandidates();
	// select winner logic - begin
	int winner = 0;
	// Scan all the the CLCandidates
	for (int i=0; i+1 < clCandidateArray.length; i++) {
	// Change the default conflict resolution rule by selecting the winner 
	//based upon timestamp
	// of update instead of the source always winning
	// When there are identical timestamps, just pick one
	if (((clCandidateArray[i+1].getDate(tsColInd)).compareTo
		(clCandidateArray[i].getDate(tsColInd)))== 1)
			{
			winner = i + 1;
			}		
	}	
	// select winner logic - end	
	iRecord.force(clCandidateArray[winner]);
	iRecord.apply();
	CLCorrespondent myClc = clCandidateArray[winner].getAuthor(); 						
	String deviceId = myClc.getDeviceId();
	if (deviceId == "null") deviceId = "Source server";
	else deviceId = "Device " + deviceId;
	String s = new String( "ContestTableReplicatePolicy - " + deviceId +
	" was the winner for key value " + clCandidateArray[winner].getInt(pkColInd));
	sdl.writeOut(s);
	}
  }
  catch (CLCandidateException clCandidateException) {
    sdl.writeOut("!!!CLCandidateException occurs in ContestTableReplicatePolicy!!!");
	}
 }				
}



Back to top


Message module

To standardize the recording of the activity of the DB2 Everyplace Custom Logic modules, all of them use a function called KCDataLog. Listing 5 shows the source code for this module.


Listing 5. KCDataLog
				
package com.jcasey.cl;
import com.ibm.db2ess.cl.*;
import java.util.*;
import java.io.*;			// To get the File IO class
import java.text.*;

/**
 * Descriptive Name:  Log messages on screen and file
 *
 * Description:
 *    This class is called by Custom Logic to monitor synchronization/replication 
 *    events
 *
 */
public class KCDataLog {
 private static final String logDataFile =
  "C:\\DB2Everyplace\\server\\logs\\KCDataLog.txt";  
    // For Windows platform

  /**
   * This instantiates the singleton KCDataLog object.
   */
	private static final KCDataLog INSTANCE= new KCDataLog(); 
	// Create the singleton
 /**
  * Private Default Constructor
  */
  private KCDataLog(){}

  /**
     * This method returns the unique instance of the KCDataLog.
   *
   */
  public static KCDataLog getInstance() {
  	return INSTANCE;
  }

	public void writeOut(String logRecord) {
		DateFormat longTimestamp = 
     	DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);
     	String logRecordX = longTimestamp.format(new Date()) + " " + logRecord;
		System.out.println(logRecordX);	// Also print on screen

		// Open the data log file, write to it and close the file
		FileWriter toFile = null;
		try {
			toFile = new FileWriter(logDataFile, true);
			toFile.write(logRecordX + "\n");
		}
		catch (IOException e) {System.out.println("ERROR in KCDataLog");}
		finally {
		  if (toFile != null) try { toFile.close(); 
		  }
		  catch (IOException e) {System.out.println("ERROR2 in KCDataLog");}
		}
	}
}

Listing 6 shows an example of the output generated by these example DB2 Everyplace Custom Logic modules.


Listing 6. Example output from Custom Logic modules
				
Dec 7, 2004 9:31:24 AM OrdHdrTablePolicySyncIn for device GmA@rVzhgYN1LoyMYbQx 
  Old value: -1 New value: 6
Dec 7, 2004 9:31:25 AM OrdHdrTablePolicySyncIn for device GmA@rVzhgYN1LoyMYbQx 
  Old value: -2 New value: 7
Dec 7, 2004 9:31:25 AM OrdDetTablePolicySyncIn for device GmA@rVzhgYN1LoyMYbQx 
  Old value: -1 New value: 6
Dec 7, 2004 9:31:25 AM OrdDetTablePolicySyncIn for device GmA@rVzhgYN1LoyMYbQx 
  Old value: -1 New value: 6
Dec 7, 2004 9:31:25 AM OrdDetTablePolicySyncIn for device GmA@rVzhgYN1LoyMYbQx 
  Old value: -2 New value: 7
Dec 7, 2004 9:31:26 AM OrdDetTablePolicySyncIn for device GmA@rVzhgYN1LoyMYbQx 
  Old value: -2 New value: 7
Dec 7, 2004 9:31:26 AM OrdDetAfterTableSyncInPolicy deleted 2 rows for 
  device ID = GmA@rVzhgYN1LoyMYbQx
Dec 7, 2004 9:32:31 AM ContestTableReplicatePolicy - Device GmA@rVzhgYN1LoyMYbQx 
  was the winner for key value 1



Back to top


Conclusion

DB2 Everyplace custom logic makes it easier for you to design a versatile wireless data solution that meets your needs. If you're ready to try out these examples, you may download the code shown in this article.



Back to top


Disclaimer

This article contains sample code. IBM grants you ("Licensee") a non-exclusive, royalty free, license to use this sample code. However, the sample code is provided as-is and without any warranties, whether express or implied, including any implied warranty of merchantability, fitness for a particular purpose or non-infringement. IBM and its licensors snall not be liable for any damages suffered by licensee that result from your use of the software. In no event will IBM or its licensors be liable for any lost revenue, profit or data, or for the direct, indirect, special, consequential, incidental or punitive damages, however caused and regardless of the theory of liability, arising out of the use of or inability to use software, even if IBM has been advised of the possibility of such damages.




Back to top


Download

DescriptionNameSizeDownload method
sample custom logic codecustom_logic.zip6.6 KBFTP|HTTP
Information about download methods


Resources



About the author

Author photo

John Casey is a Consulting IT Software Specialist with the Program Introduction and Exploration organization within IBM. He started honing his IBM relational database skills 25 years ago with SQL/DS on VSE and VM , and is now a widely recognized DB2 Everyplace and DB2 replication expert. John has provided on-site and remote expertise to countless customers implementing IBM database solutions.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top


IBM, DB2, Everyplace, and SQL/DS are trademarks or registered trademarks of Internatioal Business Machines Corporation in the US, other countries, or both. Other company, product, or service names may be trademarks or service marks of others. Other company, product, or service names may be trademarks or service marks of others.